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.

4522 lines
144 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. rregprop.c
  5. Abstract:
  6. This module contains the server-side registry property routines.
  7. PNP_GetDeviceRegProp
  8. PNP_SetDeviceRegProp
  9. PNP_GetClassRegProp
  10. PNP_SetClassRegProp
  11. PNP_GetClassInstance
  12. PNP_CreateKey
  13. PNP_DeleteRegistryKey
  14. PNP_GetClassCount
  15. PNP_GetClassName
  16. PNP_DeleteClassKey
  17. PNP_GetInterfaceDeviceAlias
  18. PNP_GetInterfaceDeviceList
  19. PNP_GetInterfaceDeviceListSize
  20. PNP_RegisterDeviceClassAssociation
  21. PNP_UnregisterDeviceClassAssociation
  22. PNP_GetCustomDevProp
  23. This module contains the privately exported registry property routines.
  24. DeleteServicePlugPlayRegKeys
  25. Author:
  26. Paula Tomlinson (paulat) 6-23-1995
  27. Environment:
  28. User-mode only.
  29. Revision History:
  30. 23-June-1995 paulat
  31. Creation and initial implementation.
  32. --*/
  33. //
  34. // includes
  35. //
  36. #include "precomp.h"
  37. #include "umpnpi.h"
  38. #include "umpnpdat.h"
  39. #include "accctrl.h"
  40. #include "aclapi.h"
  41. //
  42. // private prototypes
  43. //
  44. LPWSTR
  45. MapPropertyToString(
  46. ULONG ulProperty
  47. );
  48. ULONG
  49. MapPropertyToNtProperty(
  50. ULONG ulProperty
  51. );
  52. HKEY
  53. FindMostAppropriatePerHwIdSubkey(
  54. IN HKEY hDevKey,
  55. IN REGSAM samDesired,
  56. OUT LPWSTR PerHwIdSubkeyName,
  57. OUT LPDWORD PerHwIdSubkeyLen
  58. );
  59. //
  60. // global data
  61. //
  62. extern HKEY ghEnumKey; // Key to HKLM\CCC\System\Enum - DO NOT MODIFY
  63. extern HKEY ghClassKey; // Key to HKLM\CCC\System\Class - DO NOT MODIFY
  64. extern HKEY ghPerHwIdKey; // Key to HKLM\Software\Microsoft\Windows NT\CurrentVersion\PerHwIdStorage - DO NOT MODIFY
  65. BYTE bDeviceReadPropertyFlags[] = {
  66. 0, // zero-index not used
  67. 1, // CM_DRP_DEVICEDESC
  68. 1, // CM_DRP_HARDWAREID
  69. 1, // CM_DRP_COMPATIBLEIDS
  70. 0, // CM_DRP_UNUSED0
  71. 1, // CM_DRP_SERVICE
  72. 0, // CM_DRP_UNUSED1
  73. 0, // CM_DRP_UNUSED2
  74. 1, // CM_DRP_CLASS
  75. 1, // CM_DRP_CLASSGUID
  76. 1, // CM_DRP_DRIVER
  77. 1, // CM_DRP_CONFIGFLAGS
  78. 1, // CM_DRP_MFG
  79. 1, // CM_DRP_FRIENDLYNAME
  80. 1, // CM_DRP_LOCATION_INFORMATION
  81. 1, // CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME
  82. 1, // CM_DRP_CAPABILITIES
  83. 1, // CM_DRP_UI_NUMBER
  84. 1, // CM_DRP_UPPERFILTERS
  85. 1, // CM_DRP_LOWERFILTERS
  86. 1, // CM_DRP_BUSTYPEGUID
  87. 1, // CM_DRP_LEGACYBUSTYPE
  88. 1, // CM_DRP_BUSNUMBER
  89. 1, // CM_DRP_ENUMERATOR_NAME
  90. 1, // CM_DRP_SECURITY
  91. 0, // CM_DRP_SECURITY_SDS - shouldn't get this far
  92. 1, // CM_DRP_DEVTYPE
  93. 1, // CM_DRP_EXCLUSIVE
  94. 1, // CM_DRP_CHARACTERISTICS
  95. 1, // CM_DRP_ADDRESS
  96. 1, // CM_DRP_UI_NUMBER_DESC_FORMAT
  97. 1, // CM_DRP_DEVICE_POWER_DATA
  98. 1, // CM_DRP_REMOVAL_POLICY
  99. 1, // CM_DRP_REMOVAL_POLICY_HW_DEFAULT
  100. 1, // CM_DRP_REMOVAL_POLICY_OVERRIDE
  101. 1, // CM_DRP_INSTALL_STATE
  102. };
  103. BYTE bDeviceWritePropertyFlags[] = {
  104. 0, // zero-index not used
  105. 1, // CM_DRP_DEVICEDESC
  106. 1, // CM_DRP_HARDWAREID
  107. 1, // CM_DRP_COMPATIBLEIDS
  108. 0, // CM_DRP_UNUSED0
  109. 1, // CM_DRP_SERVICE
  110. 0, // CM_DRP_UNUSED1
  111. 0, // CM_DRP_UNUSED2
  112. 1, // CM_DRP_CLASS
  113. 1, // CM_DRP_CLASSGUID
  114. 1, // CM_DRP_DRIVER
  115. 1, // CM_DRP_CONFIGFLAGS
  116. 1, // CM_DRP_MFG
  117. 1, // CM_DRP_FRIENDLYNAME
  118. 1, // CM_DRP_LOCATION_INFORMATION
  119. 0, // CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME
  120. 0, // CM_DRP_CAPABILITIES
  121. 0, // CM_DRP_UI_NUMBER
  122. 1, // CM_DRP_UPPERFILTERS
  123. 1, // CM_DRP_LOWERFILTERS
  124. 0, // CM_DRP_BUSTYPEGUID
  125. 0, // CM_DRP_LEGACYBUSTYPE
  126. 0, // CM_DRP_BUSNUMBER
  127. 0, // CM_DRP_ENUMERATOR_NAME
  128. 1, // CM_DRP_SECURITY
  129. 0, // CM_DRP_SECURITY_SDS - shouldn't get this far
  130. 1, // CM_DRP_DEVTYPE
  131. 1, // CM_DRP_EXCLUSIVE
  132. 1, // CM_DRP_CHARACTERISTICS
  133. 0, // CM_DRP_ADDRESS
  134. 1, // CM_DRP_UI_NUMBER_DESC_FORMAT
  135. 0, // CM_DRP_DEVICE_POWER_DATA
  136. 0, // CM_DRP_REMOVAL_POLICY
  137. 0, // CM_DRP_REMOVAL_POLICY_HW_DEFAULT
  138. 1, // CM_DRP_REMOVAL_POLICY_OVERRIDE
  139. 0, // CM_DRP_INSTALL_STATE
  140. };
  141. BYTE bClassReadPropertyFlags[] = {
  142. 0, // zero-index not used
  143. 0, // (CM_DRP_DEVICEDESC)
  144. 0, // (CM_DRP_HARDWAREID)
  145. 0, // (CM_DRP_COMPATIBLEIDS)
  146. 0, // (CM_DRP_UNUSED0)
  147. 0, // (CM_DRP_SERVICE)
  148. 0, // (CM_DRP_UNUSED1)
  149. 0, // (CM_DRP_UNUSED2)
  150. 0, // (CM_DRP_CLASS)
  151. 0, // (CM_DRP_CLASSGUID)
  152. 0, // (CM_DRP_DRIVER)
  153. 0, // (CM_DRP_CONFIGFLAGS)
  154. 0, // (CM_DRP_MFG)
  155. 0, // (CM_DRP_FRIENDLYNAME)
  156. 0, // (CM_DRP_LOCATION_INFORMATION)
  157. 0, // (CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME)
  158. 0, // (CM_DRP_CAPABILITIES)
  159. 0, // (CM_DRP_UI_NUMBER)
  160. 0, // (CM_DRP_UPPERFILTERS)
  161. 0, // (CM_DRP_LOWERFILTERS)
  162. 0, // (CM_DRP_BUSTYPEGUID)
  163. 0, // (CM_DRP_LEGACYBUSTYPE)
  164. 0, // (CM_DRP_BUSNUMBER)
  165. 0, // (CM_DRP_ENUMERATOR_NAME)
  166. 1, // CM_CRP_SECURITY
  167. 0, // CM_CRP_SECURITY_SDS - shouldn't get this far
  168. 1, // CM_CRP_DEVTYPE
  169. 1, // CM_CRP_EXCLUSIVE
  170. 1, // CM_CRP_CHARACTERISTICS
  171. 0, // (CM_DRP_ADDRESS)
  172. 0, // (CM_DRP_UI_NUMBER_DESC_FORMAT)
  173. 0, // (CM_DRP_DEVICE_POWER_DATA)
  174. 0, // (CM_DRP_REMOVAL_POLICY)
  175. 0, // (CM_DRP_REMOVAL_POLICY_HW_DEFAULT)
  176. 0, // (CM_DRP_REMOVAL_POLICY_OVERRIDE)
  177. 0, // (CM_DRP_INSTALL_STATE)
  178. };
  179. BYTE bClassWritePropertyFlags[] = {
  180. 0, // zero-index not used
  181. 0, // (CM_DRP_DEVICEDESC)
  182. 0, // (CM_DRP_HARDWAREID)
  183. 0, // (CM_DRP_COMPATIBLEIDS)
  184. 0, // (CM_DRP_UNUSED0)
  185. 0, // (CM_DRP_SERVICE)
  186. 0, // (CM_DRP_UNUSED1)
  187. 0, // (CM_DRP_UNUSED2)
  188. 0, // (CM_DRP_CLASS)
  189. 0, // (CM_DRP_CLASSGUID)
  190. 0, // (CM_DRP_DRIVER)
  191. 0, // (CM_DRP_CONFIGFLAGS)
  192. 0, // (CM_DRP_MFG)
  193. 0, // (CM_DRP_FRIENDLYNAME)
  194. 0, // (CM_DRP_LOCATION_INFORMATION)
  195. 0, // (CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME)
  196. 0, // (CM_DRP_CAPABILITIES)
  197. 0, // (CM_DRP_UI_NUMBER)
  198. 0, // (CM_DRP_UPPERFILTERS)
  199. 0, // (CM_DRP_LOWERFILTERS)
  200. 0, // (CM_DRP_BUSTYPEGUID)
  201. 0, // (CM_DRP_LEGACYBUSTYPE)
  202. 0, // (CM_DRP_BUSNUMBER)
  203. 0, // (CM_DRP_ENUMERATOR_NAME)
  204. 1, // CM_CRP_SECURITY
  205. 0, // CM_CRP_SECURITY_SDS - shouldn't get this far
  206. 1, // CM_CRP_DEVTYPE
  207. 1, // CM_CRP_EXCLUSIVE
  208. 1, // CM_CRP_CHARACTERISTICS
  209. 0, // (CM_DRP_ADDRESS)
  210. 0, // (CM_DRP_UI_NUMBER_DESC_FORMAT)
  211. 0, // (CM_DRP_DEVICE_POWER_DATA)
  212. 0, // (CM_DRP_REMOVAL_POLICY)
  213. 0, // (CM_DRP_REMOVAL_POLICY_HW_DEFAULT)
  214. 0, // (CM_DRP_REMOVAL_POLICY_OVERRIDE)
  215. 0, // (CM_DRP_INSTALL_STATE)
  216. };
  217. CONFIGRET
  218. PNP_GetDeviceRegProp(
  219. IN handle_t hBinding,
  220. IN LPCWSTR pDeviceID,
  221. IN ULONG ulProperty,
  222. OUT PULONG pulRegDataType,
  223. OUT LPBYTE Buffer,
  224. IN OUT PULONG pulTransferLen,
  225. IN OUT PULONG pulLength,
  226. IN ULONG ulFlags
  227. )
  228. /*++
  229. Routine Description:
  230. This is the RPC server entry point for the CM_Get_DevNode_Registry_Property
  231. routine.
  232. Arguments:
  233. hBinding RPC binding handle.
  234. pDeviceID Supplies a string containing the device instance
  235. whose property will be read from.
  236. ulProperty ID specifying which property (the registry value)
  237. to get.
  238. pulRegDataType Supplies the address of a variable that will receive
  239. the registry data type for this property (i.e., the REG_*
  240. constants).
  241. Buffer Supplies the address of the buffer that receives the
  242. registry data. Can be NULL when simply retrieving
  243. data size.
  244. pulTransferLen Used by stubs, indicates how much data to copy back
  245. into user buffer.
  246. pulLength Parameter passed in by caller, on entry it contains
  247. the size, in bytes, of the buffer, on exit it contains
  248. either the amount of data copied to the caller's buffer
  249. (if a transfer occured) or else the size of buffer
  250. required to hold the property data.
  251. ulFlags Not used, must be zero.
  252. Return Value:
  253. If the function succeeds, the return value is CR_SUCCESS.
  254. If the function fails, the return value is one of the following:
  255. CR_INVALID_DEVNODE,
  256. CR_INVALID_FLAG,
  257. CR_INVALID_POINTER,
  258. CR_NO_SUCH_VALUE,
  259. CR_REGISTRY_ERROR, or
  260. CR_BUFFER_SMALL.
  261. Remarks:
  262. The pointer passed in as the pulTransferLen argument must *NOT* be the same
  263. as the pointer passed in for the pulLength argument.
  264. --*/
  265. {
  266. CONFIGRET Status = CR_SUCCESS;
  267. LONG RegStatus = ERROR_SUCCESS;
  268. ULONG ulSize = 0;
  269. HKEY hKey = NULL;
  270. LPWSTR pPropertyName;
  271. NTSTATUS ntStatus = STATUS_SUCCESS;
  272. PLUGPLAY_CONTROL_PROPERTY_DATA ControlData;
  273. LPCWSTR pSeparatorChar;
  274. ULONG bufferLength, guidType;
  275. WCHAR szClassGuid[GUID_STRING_LEN];
  276. GUID guid;
  277. PWCHAR unicodeIDs;
  278. try {
  279. //
  280. // Validate parameters
  281. //
  282. ASSERT(pulTransferLen != pulLength);
  283. if (!ARGUMENT_PRESENT(pulTransferLen) ||
  284. !ARGUMENT_PRESENT(pulLength)) {
  285. Status = CR_INVALID_POINTER;
  286. goto Clean0;
  287. }
  288. if (INVALID_FLAGS(ulFlags, 0)) {
  289. Status = CR_INVALID_FLAG;
  290. goto Clean0;
  291. }
  292. if (!IsLegalDeviceId(pDeviceID)) {
  293. Status = CR_INVALID_DEVNODE;
  294. goto Clean0;
  295. }
  296. //
  297. // Make sure we use no more than either what the caller specified or
  298. // what was allocated by RPC, based on the transfer length.
  299. //
  300. *pulLength = min(*pulLength, *pulTransferLen);
  301. *pulTransferLen = 0;
  302. //
  303. // consistancy checks
  304. //
  305. ASSERT(ARRAY_SIZE(bDeviceReadPropertyFlags) == (CM_DRP_MAX+1));
  306. ASSERT(sizeof(bDeviceReadPropertyFlags) == sizeof(bDeviceWritePropertyFlags));
  307. ASSERT(sizeof(bDeviceReadPropertyFlags) == sizeof(bClassReadPropertyFlags));
  308. //
  309. // validate property is readable
  310. //
  311. if (ulProperty > CM_DRP_MAX || !bDeviceReadPropertyFlags[ulProperty]) {
  312. Status = CR_INVALID_PROPERTY;
  313. goto Clean0;
  314. }
  315. switch (ulProperty) {
  316. //
  317. // for some fields, we need to ask from kernel-mode
  318. //
  319. case CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME:
  320. //
  321. // This property has special checking in kernel-mode to make
  322. // sure the supplied buffer length is even so round it down.
  323. //
  324. *pulLength &= ~1;
  325. // fall through
  326. case CM_DRP_BUSTYPEGUID:
  327. case CM_DRP_LEGACYBUSTYPE:
  328. case CM_DRP_BUSNUMBER:
  329. case CM_DRP_ADDRESS:
  330. case CM_DRP_DEVICE_POWER_DATA:
  331. case CM_DRP_REMOVAL_POLICY:
  332. case CM_DRP_REMOVAL_POLICY_HW_DEFAULT:
  333. case CM_DRP_REMOVAL_POLICY_OVERRIDE:
  334. case CM_DRP_INSTALL_STATE:
  335. if (ulProperty == CM_DRP_DEVICE_POWER_DATA ||
  336. ulProperty == CM_DRP_BUSTYPEGUID) {
  337. *pulRegDataType = REG_BINARY;
  338. } else if (ulProperty == CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME) {
  339. *pulRegDataType = REG_SZ;
  340. } else {
  341. //
  342. // CM_DRP_LEGACYBUSTYPE, CM_DRP_BUSNUMBER, CM_DRP_ADDRESS,
  343. // removal policy properties, and install state are all DWORDs
  344. //
  345. *pulRegDataType = REG_DWORD;
  346. }
  347. //
  348. // For these properties, we zero out unfilled space. This ensures
  349. // deterministic downlevel behavior if we expand any returned
  350. // structures in a later release.
  351. //
  352. bufferLength = *pulLength;
  353. //
  354. // Fill in a control structure for the device list info.
  355. //
  356. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA));
  357. RtlInitUnicodeString(&ControlData.DeviceInstance, pDeviceID);
  358. ControlData.PropertyType = MapPropertyToNtProperty(ulProperty);
  359. ControlData.Buffer = Buffer;
  360. ControlData.BufferSize = bufferLength;
  361. //
  362. // Call kernel-mode to get the device property.
  363. //
  364. ntStatus = NtPlugPlayControl(PlugPlayControlProperty,
  365. &ControlData,
  366. sizeof(ControlData));
  367. if (NT_SUCCESS(ntStatus)) {
  368. ASSERT(bufferLength >= ControlData.BufferSize);
  369. if (bufferLength > ControlData.BufferSize) {
  370. RtlZeroMemory(
  371. Buffer + ControlData.BufferSize,
  372. bufferLength - ControlData.BufferSize
  373. );
  374. }
  375. *pulLength = ControlData.BufferSize; // size in bytes
  376. *pulTransferLen = bufferLength; // size in bytes
  377. } else if (ntStatus == STATUS_BUFFER_TOO_SMALL) {
  378. *pulLength = ControlData.BufferSize;
  379. *pulTransferLen = 0;
  380. Status = CR_BUFFER_SMALL;
  381. } else {
  382. *pulLength = 0;
  383. *pulTransferLen = 0;
  384. Status = MapNtStatusToCmError(ntStatus);
  385. }
  386. break;
  387. case CM_DRP_ENUMERATOR_NAME:
  388. *pulRegDataType = REG_SZ;
  389. pSeparatorChar = wcschr(pDeviceID, L'\\');
  390. ASSERT(pSeparatorChar);
  391. if (!pSeparatorChar) {
  392. Status=CR_INVALID_DATA;
  393. } else {
  394. ulSize = (ULONG)((PBYTE)pSeparatorChar - (PBYTE)pDeviceID) + sizeof(WCHAR);
  395. //
  396. // Fill in the caller's buffer, if it's large enough
  397. //
  398. if (*pulLength >= ulSize) {
  399. lstrcpyn((LPWSTR)Buffer, pDeviceID, ulSize / sizeof(WCHAR));
  400. *pulTransferLen = ulSize;
  401. } else {
  402. *pulTransferLen = 0; // no output data to marshal
  403. Status = CR_BUFFER_SMALL;
  404. }
  405. *pulLength = ulSize;
  406. }
  407. break;
  408. default:
  409. //
  410. // for all the other fields, just get them from the registry
  411. // open a key to the specified device id
  412. //
  413. if (RegOpenKeyEx(ghEnumKey, pDeviceID, 0, KEY_READ,
  414. &hKey) != ERROR_SUCCESS) {
  415. hKey = NULL; // ensure hKey stays NULL so we don't
  416. // erroneously try to close it.
  417. *pulLength = 0; // no size info for caller
  418. Status = CR_INVALID_DEVINST;
  419. goto Clean0;
  420. }
  421. //
  422. // retrieve the string form of the property
  423. //
  424. pPropertyName = MapPropertyToString(ulProperty);
  425. if (pPropertyName) {
  426. //
  427. // retrieve property setting
  428. //
  429. if (*pulLength == 0) {
  430. //
  431. // if length of buffer passed in is zero, just looking
  432. // for how big a buffer is needed to read the property
  433. //
  434. if (RegQueryValueEx(hKey, pPropertyName, NULL, pulRegDataType,
  435. NULL, pulLength) != ERROR_SUCCESS) {
  436. *pulLength = 0;
  437. Status = CR_NO_SUCH_VALUE;
  438. goto Clean0;
  439. }
  440. Status = CR_BUFFER_SMALL; // According to spec
  441. } else {
  442. //
  443. // retrieve the real property value, not just the size
  444. //
  445. RegStatus = RegQueryValueEx(hKey, pPropertyName, NULL,
  446. pulRegDataType, Buffer, pulLength);
  447. if (RegStatus != ERROR_SUCCESS) {
  448. if (RegStatus == ERROR_MORE_DATA) {
  449. Status = CR_BUFFER_SMALL;
  450. goto Clean0;
  451. } else {
  452. *pulLength = 0; // no size info for caller
  453. Status = CR_NO_SUCH_VALUE;
  454. goto Clean0;
  455. }
  456. }
  457. }
  458. } else {
  459. Status = CR_NO_SUCH_VALUE;
  460. goto Clean0;
  461. }
  462. }
  463. Clean0:
  464. //
  465. // Data only needs to be transferred on CR_SUCCESS.
  466. //
  467. if (Status == CR_SUCCESS) {
  468. *pulTransferLen = *pulLength;
  469. } else if (ARGUMENT_PRESENT(pulTransferLen)) {
  470. *pulTransferLen = 0;
  471. }
  472. } except(EXCEPTION_EXECUTE_HANDLER) {
  473. Status = CR_FAILURE;
  474. //
  475. // force compiler to respect statement ordering w.r.t. assignments
  476. // for these variables...
  477. //
  478. hKey = hKey;
  479. }
  480. if (hKey != NULL) {
  481. RegCloseKey(hKey);
  482. }
  483. return Status;
  484. } // PNP_GetDeviceRegProp
  485. CONFIGRET
  486. PNP_SetDeviceRegProp(
  487. IN handle_t hBinding,
  488. IN LPCWSTR pDeviceID,
  489. IN ULONG ulProperty,
  490. IN ULONG ulDataType,
  491. IN LPBYTE Buffer,
  492. IN ULONG ulLength,
  493. IN ULONG ulFlags
  494. )
  495. /*++
  496. Routine Description:
  497. This is the RPC server entry point for the CM_Set_DevNode_Registry_Property
  498. routine.
  499. Arguments:
  500. hBinding RPC binding handle.
  501. pDeviceID Supplies a string containing the device instance
  502. whose property will be written to.
  503. ulProperty ID specifying which property (the registry value)
  504. to set.
  505. ulDataType Supplies the registry data type for the specified
  506. property (i.e., REG_SZ, etc).
  507. Buffer Supplies the address of the buffer that receives the
  508. registry data. Can be NULL when simply retrieving
  509. data size.
  510. pulLength Parameter passed in by caller, on entry it contains
  511. the size, in bytes, of the buffer, on exit it contains
  512. either the amount of data copied to the caller's buffer
  513. (if a transfer occured) or else the size of buffer
  514. required to hold the property data.
  515. ulFlags Not used, must be zero.
  516. Return Value:
  517. If the function succeeds, the return value is CR_SUCCESS.
  518. If the function fails, the return value is one of the following:
  519. CR_ACCESS_DENIED,
  520. CR_INVALID_DEVNODE,
  521. CR_INVALID_FLAG,
  522. CR_INVALID_POINTER,
  523. CR_NO_SUCH_VALUE,
  524. CR_REGISTRY_ERROR, or
  525. CR_BUFFER_SMALL.
  526. --*/
  527. {
  528. CONFIGRET Status = CR_SUCCESS;
  529. LONG RegStatus = ERROR_SUCCESS;
  530. HKEY hKey = NULL;
  531. LPWSTR pPropertyName, p;
  532. NTSTATUS ntStatus = STATUS_SUCCESS;
  533. GUID guid;
  534. ULONG drvInst;
  535. try {
  536. //
  537. // Verify client privilege
  538. //
  539. if (!VerifyClientAccess(hBinding, &gLuidLoadDriverPrivilege)) {
  540. Status = CR_ACCESS_DENIED;
  541. goto Clean0;
  542. }
  543. //
  544. // Validate parameters
  545. //
  546. if (INVALID_FLAGS(ulFlags, 0)) {
  547. Status = CR_INVALID_FLAG;
  548. goto Clean0;
  549. }
  550. if (!IsLegalDeviceId(pDeviceID)) {
  551. Status = CR_INVALID_DEVNODE;
  552. goto Clean0;
  553. }
  554. //
  555. // consistancy checks
  556. //
  557. ASSERT(ARRAY_SIZE(bDeviceWritePropertyFlags) == (CM_DRP_MAX+1));
  558. ASSERT(sizeof(bDeviceWritePropertyFlags) == sizeof(bDeviceReadPropertyFlags));
  559. ASSERT(sizeof(bDeviceWritePropertyFlags) == sizeof(bClassWritePropertyFlags));
  560. //
  561. // validate property is readable
  562. //
  563. if (ulProperty > CM_DRP_MAX || !bDeviceWritePropertyFlags[ulProperty]) {
  564. Status = CR_INVALID_PROPERTY;
  565. goto Clean0;
  566. }
  567. //
  568. // Currently the only writable fields are in the registry
  569. // however do any validation of bits
  570. // this isn't foolproof but can catch some common errors
  571. //
  572. switch(ulProperty) {
  573. case CM_DRP_CONFIGFLAGS: {
  574. DWORD flags = 0;
  575. ULONG ulStatus = 0;
  576. ULONG ulProblem = 0;
  577. //
  578. // DWORD value
  579. // try to catch setting CSCONFIGFLAG_DISABLED on a non-disableable device
  580. // although we should have validated the size stuff elsewhere, it was at
  581. // client-side so double-check here
  582. //
  583. if (ulDataType != REG_DWORD || ulLength != sizeof(DWORD) || Buffer == NULL) {
  584. Status = CR_INVALID_DATA;
  585. goto Clean0;
  586. }
  587. flags = *(DWORD*)Buffer;
  588. if(flags & CONFIGFLAG_DISABLED) {
  589. //
  590. // we're interested in checking this decision to disable device
  591. //
  592. if (IsRootDeviceID(pDeviceID)) {
  593. KdPrintEx((DPFLTR_PNPMGR_ID,
  594. DBGF_ERRORS,
  595. "UMPNPMGR: Cannot set CONFIGFLAG_DISABLED for root device - did caller try to disable device first?\n"));
  596. Status = CR_NOT_DISABLEABLE;
  597. goto Clean0;
  598. }
  599. if((GetDeviceStatus(pDeviceID, &ulStatus, &ulProblem)==CR_SUCCESS)
  600. && !(ulStatus & DN_DISABLEABLE)) {
  601. KdPrintEx((DPFLTR_PNPMGR_ID,
  602. DBGF_ERRORS,
  603. "UMPNPMGR: Cannot set CONFIGFLAG_DISABLED for non-disableable device - did caller try to disable device first?\n"));
  604. Status = CR_NOT_DISABLEABLE;
  605. goto Clean0;
  606. }
  607. //
  608. // ok, looks like we can proceed to disable device
  609. //
  610. }
  611. break;
  612. }
  613. default:
  614. //
  615. // No special handling on other properties
  616. //
  617. break;
  618. }
  619. //
  620. // open a key to the specified device id
  621. //
  622. if (RegOpenKeyEx(ghEnumKey, pDeviceID, 0, KEY_READ | KEY_WRITE,
  623. &hKey) != ERROR_SUCCESS) {
  624. Status = CR_INVALID_DEVINST;
  625. goto Clean0;
  626. }
  627. //
  628. // retrieve the string form of the property
  629. //
  630. pPropertyName = MapPropertyToString(ulProperty);
  631. if (pPropertyName) {
  632. //
  633. // set (or delete) the property value
  634. //
  635. if (ulLength == 0) {
  636. RegStatus = RegDeleteValue(hKey, pPropertyName);
  637. }
  638. else {
  639. RegStatus = RegSetValueEx(hKey, pPropertyName, 0, ulDataType,
  640. Buffer, ulLength);
  641. }
  642. if (RegStatus != ERROR_SUCCESS) {
  643. Status = CR_REGISTRY_ERROR;
  644. goto Clean0;
  645. }
  646. } else {
  647. Status = CR_FAILURE;
  648. goto Clean0;
  649. }
  650. //
  651. // note that changes do not get applied until a reboot / query-remove-remove
  652. //
  653. Clean0:
  654. NOTHING;
  655. } except(EXCEPTION_EXECUTE_HANDLER) {
  656. Status = CR_FAILURE;
  657. //
  658. // force compiler to respect statement ordering w.r.t. assignments
  659. // for these variables...
  660. //
  661. hKey = hKey;
  662. }
  663. if (hKey != NULL) {
  664. RegCloseKey(hKey);
  665. }
  666. return Status;
  667. } // PNP_SetDeviceRegProp
  668. CONFIGRET
  669. PNP_GetClassRegProp(
  670. IN handle_t hBinding,
  671. IN LPCWSTR ClassGuid,
  672. IN ULONG ulProperty,
  673. OUT PULONG pulRegDataType OPTIONAL,
  674. OUT LPBYTE Buffer,
  675. IN OUT PULONG pulTransferLen,
  676. IN OUT PULONG pulLength,
  677. IN ULONG ulFlags
  678. )
  679. /*++
  680. Routine Description:
  681. This is the RPC server entry point for the CM_Get_DevNode_Registry_Property
  682. routine.
  683. Arguments:
  684. hBinding RPC binding handle, not used.
  685. ClassGuid Supplies a string containing the Class Guid
  686. whose property will be read from (Get) or written
  687. to (Set).
  688. ulProperty ID specifying which property (the registry value)
  689. to get or set.
  690. pulRegDataType Optionally, supplies the address of a variable that
  691. will receive the registry data type for this property
  692. (i.e., the REG_* constants).
  693. Buffer Supplies the address of the buffer that receives the
  694. registry data. Can be NULL when simply retrieving
  695. data size.
  696. pulTransferLen Used by stubs, indicates how much data to copy back
  697. into user buffer.
  698. pulLength Parameter passed in by caller, on entry it contains
  699. the size, in bytes, of the buffer, on exit it contains
  700. either the amount of data copied to the caller's buffer
  701. (if a transfer occured) or else the size of buffer
  702. required to hold the property data.
  703. ulFlags Not used, must be zero.
  704. Return Value:
  705. If the function succeeds, the return value is CR_SUCCESS.
  706. If the function fails, the return value is one of the following:
  707. CR_INVALID_DEVNODE,
  708. CR_INVALID_FLAG,
  709. CR_INVALID_POINTER,
  710. CR_NO_SUCH_VALUE,
  711. CR_REGISTRY_ERROR, or
  712. CR_BUFFER_SMALL.
  713. Remarks:
  714. The pointer passed in as the pulTransferLen argument must *NOT* be the same
  715. as the pointer passed in for the pulLength argument.
  716. --*/
  717. {
  718. CONFIGRET Status = CR_SUCCESS;
  719. LONG RegStatus = ERROR_SUCCESS;
  720. ULONG ulSize = 0;
  721. HKEY hKeyClass = NULL;
  722. HKEY hKeyProps = NULL;
  723. LPWSTR pPropertyName;
  724. NTSTATUS ntStatus = STATUS_SUCCESS;
  725. LPCWSTR pSeparatorChar;
  726. UNREFERENCED_PARAMETER(hBinding);
  727. try {
  728. //
  729. // Validate parameters
  730. //
  731. ASSERT(pulTransferLen != pulLength);
  732. if (!ARGUMENT_PRESENT(pulTransferLen) ||
  733. !ARGUMENT_PRESENT(pulLength)) {
  734. Status = CR_INVALID_POINTER;
  735. goto Clean0;
  736. }
  737. if (INVALID_FLAGS(ulFlags, 0)) {
  738. Status = CR_INVALID_FLAG;
  739. goto Clean0;
  740. }
  741. //
  742. // Make sure we use no more than either what the caller specified or
  743. // what was allocated by RPC, based on the transfer length.
  744. //
  745. *pulLength = min(*pulLength, *pulTransferLen);
  746. *pulTransferLen = 0;
  747. //
  748. // consistancy checks
  749. //
  750. ASSERT(ARRAY_SIZE(bClassReadPropertyFlags) == (CM_CRP_MAX+1));
  751. ASSERT(sizeof(bClassReadPropertyFlags) == sizeof(bClassWritePropertyFlags));
  752. ASSERT(sizeof(bClassReadPropertyFlags) == sizeof(bDeviceReadPropertyFlags));
  753. //
  754. // validate property is readable
  755. //
  756. if (ulProperty > CM_CRP_MAX || !bClassReadPropertyFlags[ulProperty]) {
  757. Status = CR_INVALID_PROPERTY;
  758. goto Clean0;
  759. }
  760. //
  761. // open a key to the specified GUID - this should have already been created
  762. //
  763. if (RegOpenKeyEx(ghClassKey, ClassGuid, 0, KEY_READ,
  764. &hKeyClass) != ERROR_SUCCESS) {
  765. *pulTransferLen = 0; // no output data to marshal
  766. *pulLength = 0; // no size info for caller
  767. Status = CR_NO_SUCH_REGISTRY_KEY;
  768. goto Clean0;
  769. }
  770. //
  771. // open a key to parameters - if not created, there's no params
  772. //
  773. if (RegOpenKeyEx(hKeyClass, pszRegKeyProperties, 0, KEY_READ,
  774. &hKeyProps) != ERROR_SUCCESS) {
  775. *pulTransferLen = 0; // no output data to marshal
  776. *pulLength = 0; // no size info for caller
  777. Status = CR_NO_SUCH_VALUE;
  778. goto Clean0;
  779. }
  780. //
  781. // retrieve the string form of the property
  782. //
  783. pPropertyName = MapPropertyToString(ulProperty);
  784. if (pPropertyName) {
  785. //
  786. // retrieve property setting
  787. //
  788. if (*pulLength == 0) {
  789. //
  790. // if length of buffer passed in is zero, just looking
  791. // for how big a buffer is needed to read the property
  792. //
  793. *pulTransferLen = 0;
  794. if (RegQueryValueEx(hKeyProps, pPropertyName, NULL, pulRegDataType,
  795. NULL, pulLength) != ERROR_SUCCESS) {
  796. *pulLength = 0;
  797. Status = CR_NO_SUCH_VALUE;
  798. goto Clean0;
  799. }
  800. Status = CR_BUFFER_SMALL; // According to spec
  801. } else {
  802. //
  803. // retrieve the real property value, not just the size
  804. //
  805. RegStatus = RegQueryValueEx(hKeyProps, pPropertyName, NULL,
  806. pulRegDataType, Buffer, pulLength);
  807. if (RegStatus != ERROR_SUCCESS) {
  808. if (RegStatus == ERROR_MORE_DATA) {
  809. *pulTransferLen = 0; // no output data to marshal
  810. Status = CR_BUFFER_SMALL;
  811. goto Clean0;
  812. }
  813. else {
  814. *pulTransferLen = 0; // no output data to marshal
  815. *pulLength = 0; // no size info for caller
  816. Status = CR_NO_SUCH_VALUE;
  817. goto Clean0;
  818. }
  819. }
  820. *pulTransferLen = *pulLength;
  821. }
  822. } else {
  823. *pulTransferLen = 0; // no output data to marshal
  824. *pulLength = 0; // no size info for caller
  825. Status = CR_NO_SUCH_VALUE;
  826. goto Clean0;
  827. }
  828. Clean0:
  829. NOTHING;
  830. } except(EXCEPTION_EXECUTE_HANDLER) {
  831. Status = CR_FAILURE;
  832. //
  833. // force compiler to respect statement ordering w.r.t. assignments
  834. // for these variables...
  835. //
  836. hKeyProps = hKeyProps;
  837. hKeyClass = hKeyClass;
  838. }
  839. if (hKeyProps != NULL) {
  840. RegCloseKey(hKeyProps);
  841. }
  842. if (hKeyClass != NULL) {
  843. RegCloseKey(hKeyClass);
  844. }
  845. return Status;
  846. } // PNP_GetClassRegProp
  847. CONFIGRET
  848. PNP_SetClassRegProp(
  849. IN handle_t hBinding,
  850. IN LPCWSTR ClassGuid,
  851. IN ULONG ulProperty,
  852. IN ULONG ulDataType,
  853. IN LPBYTE Buffer,
  854. IN ULONG ulLength,
  855. IN ULONG ulFlags
  856. )
  857. /*++
  858. Routine Description:
  859. This is the RPC server entry point for the CM_Set_DevNode_Registry_Property
  860. routine.
  861. Arguments:
  862. hBinding RPC binding handle.
  863. ClassGuid Supplies a string containing the Class Guid
  864. whose property will be read from (Get) or written
  865. to (Set).
  866. ulProperty ID specifying which property (the registry value)
  867. to get or set.
  868. ulDataType Supplies the registry data type for the specified
  869. property (i.e., REG_SZ, etc).
  870. Buffer Supplies the address of the buffer that receives the
  871. registry data. Can be NULL when simply retrieving
  872. data size.
  873. pulLength Parameter passed in by caller, on entry it contains
  874. the size, in bytes, of the buffer, on exit it contains
  875. either the amount of data copied to the caller's buffer
  876. (if a transfer occured) or else the size of buffer
  877. required to hold the property data.
  878. ulFlags Not used, must be zero.
  879. Return Value:
  880. If the function succeeds, the return value is CR_SUCCESS.
  881. If the function fails, the return value is one of the following:
  882. CR_ACCESS_DENIED,
  883. CR_INVALID_DEVNODE,
  884. CR_INVALID_FLAG,
  885. CR_INVALID_POINTER,
  886. CR_NO_SUCH_VALUE,
  887. CR_REGISTRY_ERROR, or
  888. CR_BUFFER_SMALL.
  889. --*/
  890. {
  891. CONFIGRET Status = CR_SUCCESS;
  892. LONG RegStatus = ERROR_SUCCESS;
  893. HKEY hKeyClass = NULL;
  894. HKEY hKeyProps = NULL;
  895. LPWSTR pPropertyName;
  896. NTSTATUS ntStatus = STATUS_SUCCESS;
  897. DWORD dwError;
  898. try {
  899. //
  900. // Verify client privilege
  901. //
  902. if (!VerifyClientAccess(hBinding, &gLuidLoadDriverPrivilege)) {
  903. Status = CR_ACCESS_DENIED;
  904. goto Clean0;
  905. }
  906. //
  907. // Validate parameters
  908. //
  909. if (INVALID_FLAGS(ulFlags, 0)) {
  910. Status = CR_INVALID_FLAG;
  911. goto Clean0;
  912. }
  913. //
  914. // consistancy checks
  915. //
  916. ASSERT(ARRAY_SIZE(bClassWritePropertyFlags) == (CM_CRP_MAX+1));
  917. ASSERT(sizeof(bClassWritePropertyFlags) == sizeof(bClassReadPropertyFlags));
  918. ASSERT(sizeof(bClassWritePropertyFlags) == sizeof(bDeviceWritePropertyFlags));
  919. //
  920. // validate property is readable
  921. //
  922. if (ulProperty > CM_CRP_MAX || !bDeviceWritePropertyFlags[ulProperty]) {
  923. Status = CR_INVALID_PROPERTY;
  924. goto Clean0;
  925. }
  926. //
  927. // Currently the only writable fields are in the registry
  928. //
  929. //
  930. // open a key to the specified GUID - this should have already been created
  931. //
  932. if (RegOpenKeyEx(ghClassKey, ClassGuid, 0, KEY_READ,
  933. &hKeyClass) != ERROR_SUCCESS) {
  934. Status = CR_NO_SUCH_REGISTRY_KEY;
  935. goto Clean0;
  936. }
  937. //
  938. // open a key to parameters - if not created, we need to create it with priv permissions
  939. // this is harmless for a delete, since we "need" it anyway
  940. //
  941. if (RegOpenKeyEx(hKeyClass, pszRegKeyProperties, 0, KEY_ALL_ACCESS,
  942. &hKeyProps) != ERROR_SUCCESS) {
  943. //
  944. // properties key doesn't exist
  945. // we need to create it with secure access (system-only access)
  946. // we don't expect to do this often
  947. //
  948. PSID pSystemSid = NULL;
  949. PACL pSystemAcl = NULL;
  950. SECURITY_DESCRIPTOR SecDesc;
  951. SECURITY_ATTRIBUTES SecAttrib;
  952. BOOL bSuccess;
  953. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  954. EXPLICIT_ACCESS ExplicitAccess;
  955. bSuccess = AllocateAndInitializeSid( &NtAuthority,
  956. 1, // one authority - SYSTEM
  957. SECURITY_LOCAL_SYSTEM_RID, // access to system only
  958. 0, 0, 0, 0, 0, 0, 0, // unused authority locations
  959. &pSystemSid);
  960. if (bSuccess) {
  961. ExplicitAccess.grfAccessMode = SET_ACCESS;
  962. ExplicitAccess.grfInheritance = CONTAINER_INHERIT_ACE;
  963. ExplicitAccess.Trustee.pMultipleTrustee = NULL;
  964. ExplicitAccess.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  965. ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID;
  966. ExplicitAccess.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
  967. ExplicitAccess.grfAccessPermissions = KEY_ALL_ACCESS;
  968. ExplicitAccess.Trustee.ptstrName = (LPTSTR)pSystemSid;
  969. dwError = SetEntriesInAcl( 1,
  970. &ExplicitAccess,
  971. NULL,
  972. &pSystemAcl );
  973. if (dwError != ERROR_SUCCESS) {
  974. bSuccess = FALSE;
  975. }
  976. }
  977. if (bSuccess) {
  978. bSuccess = InitializeSecurityDescriptor( &SecDesc, SECURITY_DESCRIPTOR_REVISION );
  979. }
  980. if (bSuccess) {
  981. bSuccess = SetSecurityDescriptorDacl( &SecDesc,
  982. TRUE,
  983. pSystemAcl,
  984. FALSE);
  985. }
  986. //
  987. // mostly a setup requirement, but good to have
  988. // effectively is a pruning point in the security tree
  989. // child keys inherit our permissions, but not our parents permissions
  990. //
  991. if (bSuccess) {
  992. if(!SetSecurityDescriptorControl(&SecDesc,
  993. SE_DACL_PROTECTED | SE_DACL_AUTO_INHERITED,
  994. SE_DACL_PROTECTED | SE_DACL_AUTO_INHERITED)) {
  995. DWORD LocalErr = GetLastError();
  996. //
  997. // non fatal if this fails
  998. //
  999. }
  1000. }
  1001. if (bSuccess) {
  1002. bSuccess = IsValidSecurityDescriptor( &SecDesc );
  1003. }
  1004. if (bSuccess) {
  1005. SecAttrib.nLength = sizeof(SecAttrib);
  1006. SecAttrib.bInheritHandle = FALSE;
  1007. SecAttrib.lpSecurityDescriptor = &SecDesc;
  1008. if(RegCreateKeyEx(hKeyClass, pszRegKeyProperties, 0, NULL, REG_OPTION_NON_VOLATILE,
  1009. KEY_ALL_ACCESS, &SecAttrib, &hKeyProps, NULL) != ERROR_SUCCESS) {
  1010. bSuccess = FALSE;
  1011. }
  1012. }
  1013. //
  1014. // now cleanup
  1015. //
  1016. if (pSystemAcl) {
  1017. LocalFree(pSystemAcl);
  1018. }
  1019. if (pSystemSid) {
  1020. FreeSid(pSystemSid);
  1021. }
  1022. if (bSuccess == FALSE) {
  1023. Status = CR_FAILURE;
  1024. goto Clean0;
  1025. }
  1026. }
  1027. //
  1028. // retrieve the string form of the property
  1029. //
  1030. pPropertyName = MapPropertyToString(ulProperty);
  1031. if (pPropertyName) {
  1032. //
  1033. // set (or delete) the property value
  1034. //
  1035. if (ulLength == 0) {
  1036. RegStatus = RegDeleteValue(hKeyProps, pPropertyName);
  1037. }
  1038. else {
  1039. RegStatus = RegSetValueEx(hKeyProps, pPropertyName, 0, ulDataType,
  1040. Buffer, ulLength);
  1041. }
  1042. if (RegStatus != ERROR_SUCCESS) {
  1043. Status = CR_REGISTRY_ERROR;
  1044. goto Clean0;
  1045. }
  1046. } else {
  1047. Status = CR_FAILURE;
  1048. goto Clean0;
  1049. }
  1050. //
  1051. // note that changes do not get applied until a reboot / query-remove-remove
  1052. //
  1053. Clean0:
  1054. NOTHING;
  1055. } except(EXCEPTION_EXECUTE_HANDLER) {
  1056. Status = CR_FAILURE;
  1057. //
  1058. // force compiler to respect statement ordering w.r.t. assignments
  1059. // for these variables...
  1060. //
  1061. hKeyProps = hKeyProps;
  1062. hKeyClass = hKeyClass;
  1063. }
  1064. if (hKeyProps != NULL) {
  1065. RegCloseKey(hKeyProps);
  1066. }
  1067. if (hKeyClass != NULL) {
  1068. RegCloseKey(hKeyClass);
  1069. }
  1070. return Status;
  1071. } // PNP_SetClassRegProp
  1072. CONFIGRET
  1073. PNP_GetClassInstance(
  1074. IN handle_t hBinding,
  1075. IN LPCWSTR pDeviceID,
  1076. OUT LPWSTR pszClassInstance,
  1077. IN ULONG ulLength
  1078. )
  1079. /*++
  1080. Routine Description:
  1081. This is the RPC private server entry point, it doesn't not directly
  1082. map one-to-one to any CM routine.
  1083. Arguments:
  1084. hBinding RPC binding handle.
  1085. pDeviceID Supplies a string containing the device instance
  1086. pszClassInstance String to return the class instance in
  1087. ulLength Size of the pszClassInstance string in chars
  1088. Return Value:
  1089. If the function succeeds, the return value is CR_SUCCESS.
  1090. If the function fails, the return value is one of the following:
  1091. CR_INVALID_DEVNODE,
  1092. CR_INVALID_FLAG,
  1093. CR_INVALID_POINTER,
  1094. CR_NO_SUCH_VALUE,
  1095. CR_REGISTRY_ERROR.
  1096. --*/
  1097. {
  1098. CONFIGRET Status;
  1099. WCHAR szInstanceStr[MAX_PATH], szClassGuid[GUID_STRING_LEN];
  1100. DWORD disposition;
  1101. ULONG ulType, ulTransferLength, guidLength, ulInstance;
  1102. HKEY hClassKey = NULL, hInstanceKey = NULL;
  1103. try {
  1104. //
  1105. // Validate parameters
  1106. //
  1107. if (!IsLegalDeviceId(pDeviceID)) {
  1108. Status = CR_INVALID_DEVNODE;
  1109. goto Clean0;
  1110. }
  1111. //
  1112. // Get the class instance key name, if one exists.
  1113. //
  1114. ulTransferLength = ulLength;
  1115. Status = PNP_GetDeviceRegProp(hBinding,
  1116. pDeviceID,
  1117. CM_DRP_DRIVER,
  1118. &ulType,
  1119. (LPBYTE)pszClassInstance,
  1120. &ulTransferLength,
  1121. &ulLength,
  1122. 0);
  1123. if (Status == CR_SUCCESS) {
  1124. //
  1125. // Successfully retrieved class instance key name.
  1126. //
  1127. goto Clean0;
  1128. }
  1129. //
  1130. // Create the class instance since one does not already exist.
  1131. //
  1132. //
  1133. // Verify client privilege before creating any registry keys, because
  1134. // we'll need it to set the driver devnode property anyways (but didn't
  1135. // require it above to check for an existing value). This is better for
  1136. // synchronization than creating the key and deleting it later when we
  1137. // fail to set the devnode property.
  1138. //
  1139. if (!VerifyClientAccess(hBinding, &gLuidLoadDriverPrivilege)) {
  1140. Status = CR_ACCESS_DENIED;
  1141. goto Clean0;
  1142. }
  1143. //
  1144. // Get the class GUID property for the key to create the instance under.
  1145. //
  1146. guidLength = sizeof(szClassGuid);
  1147. ulTransferLength = guidLength;
  1148. Status = PNP_GetDeviceRegProp(hBinding,
  1149. pDeviceID,
  1150. CM_DRP_CLASSGUID,
  1151. &ulType,
  1152. (LPBYTE)szClassGuid,
  1153. &ulTransferLength,
  1154. &guidLength,
  1155. 0);
  1156. if (Status == CR_SUCCESS) {
  1157. //
  1158. // Open the class key.
  1159. //
  1160. if (RegOpenKeyEx(ghClassKey,
  1161. szClassGuid,
  1162. 0,
  1163. KEY_READ | KEY_WRITE,
  1164. &hClassKey) == ERROR_SUCCESS) {
  1165. for (ulInstance = 0; ulInstance < 9999; ulInstance++) {
  1166. //
  1167. // Find the first available class instance key.
  1168. //
  1169. wsprintf(szInstanceStr,
  1170. TEXT("%04u"),
  1171. ulInstance);
  1172. if (RegCreateKeyEx(hClassKey,
  1173. szInstanceStr,
  1174. 0,
  1175. NULL,
  1176. REG_OPTION_NON_VOLATILE,
  1177. KEY_ALL_ACCESS,
  1178. NULL,
  1179. &hInstanceKey,
  1180. &disposition) == ERROR_SUCCESS) {
  1181. RegCloseKey(hInstanceKey);
  1182. hInstanceKey = NULL;
  1183. if (disposition == REG_CREATED_NEW_KEY) {
  1184. //
  1185. // Set the instance and return.
  1186. //
  1187. wsprintf(pszClassInstance,
  1188. TEXT("%s\\%s"),
  1189. szClassGuid,
  1190. szInstanceStr);
  1191. ulLength = (lstrlen(pszClassInstance) + 1) * sizeof(WCHAR);
  1192. Status = PNP_SetDeviceRegProp(hBinding,
  1193. pDeviceID,
  1194. CM_DRP_DRIVER,
  1195. REG_SZ,
  1196. (LPBYTE)pszClassInstance,
  1197. ulLength,
  1198. 0);
  1199. //
  1200. // If we failed to set the devnode property, delete
  1201. // the registry key we just created, or else we'll end
  1202. // up orphaning it.
  1203. //
  1204. if (Status != CR_SUCCESS) {
  1205. RegDeleteKey(hClassKey, szInstanceStr);
  1206. }
  1207. break;
  1208. }
  1209. }
  1210. }
  1211. if (ulInstance == 9999) {
  1212. Status = CR_FAILURE;
  1213. }
  1214. RegCloseKey(hClassKey);
  1215. hClassKey = NULL;
  1216. } else {
  1217. //
  1218. // Unable to open class key.
  1219. //
  1220. Status = CR_FAILURE;
  1221. }
  1222. }
  1223. Clean0:
  1224. NOTHING;
  1225. } except(EXCEPTION_EXECUTE_HANDLER) {
  1226. Status = CR_FAILURE;
  1227. //
  1228. // force compiler to respect statement ordering w.r.t. assignments
  1229. // for these variables...
  1230. //
  1231. hClassKey = hClassKey;
  1232. hInstanceKey = hInstanceKey;
  1233. }
  1234. if (hClassKey != NULL) {
  1235. RegCloseKey(hClassKey);
  1236. }
  1237. if (hInstanceKey != NULL) {
  1238. RegCloseKey(hInstanceKey);
  1239. }
  1240. return Status;
  1241. } // PNP_GetClassInstance
  1242. CONFIGRET
  1243. PNP_CreateKey(
  1244. IN handle_t hBinding,
  1245. IN LPCWSTR pszDeviceID,
  1246. IN REGSAM samDesired,
  1247. IN ULONG ulFlags
  1248. )
  1249. /*++
  1250. Routine Description:
  1251. This is the RPC server entry point for the CM_Open_DevNode_Key_Ex
  1252. routine.
  1253. Arguments:
  1254. hBinding RPC binding handle.
  1255. pszDeviceID Supplies the device instance string.
  1256. samDesired Not used.
  1257. ulFlags Not used, must be zero.
  1258. Return Value:
  1259. If the function succeeds, the return value is CR_SUCCESS.
  1260. If the function fails, the return value is one of the following:
  1261. CR_ACCESS_DENIED,
  1262. CR_INVALID_DEVNODE,
  1263. CR_INVALID_FLAG,
  1264. CR_REGISTRY_ERROR, or
  1265. CR_BUFFER_SMALL.
  1266. --*/
  1267. {
  1268. CONFIGRET Status = CR_SUCCESS;
  1269. LONG RegStatus = ERROR_SUCCESS;
  1270. HKEY hKeyDevice = NULL, hKey = NULL;
  1271. ULONG ulSize = 0, i = 0;
  1272. BOOL bHasDacl, bStatus;
  1273. SECURITY_DESCRIPTOR NewSecDesc;
  1274. ACL_SIZE_INFORMATION AclSizeInfo;
  1275. SID_IDENTIFIER_AUTHORITY Authority = SECURITY_NT_AUTHORITY;
  1276. PSECURITY_DESCRIPTOR pSecDesc = NULL;
  1277. PACL pDacl = NULL, pNewDacl = NULL;
  1278. PSID pAdminSid = NULL;
  1279. PACCESS_ALLOWED_ACE pAce = NULL;
  1280. UNREFERENCED_PARAMETER(samDesired);
  1281. try {
  1282. //
  1283. // Verify client privilege
  1284. //
  1285. if (!VerifyClientAccess(hBinding, &gLuidLoadDriverPrivilege)) {
  1286. Status = CR_ACCESS_DENIED;
  1287. goto Clean0;
  1288. }
  1289. //
  1290. // Validate parameters
  1291. //
  1292. if (INVALID_FLAGS(ulFlags, 0)) {
  1293. Status = CR_INVALID_FLAG;
  1294. goto Clean0;
  1295. }
  1296. if (!IsLegalDeviceId(pszDeviceID)) {
  1297. Status = CR_INVALID_DEVNODE;
  1298. goto Clean0;
  1299. }
  1300. //
  1301. // open a key to the specified device id
  1302. //
  1303. RegStatus = RegOpenKeyEx(ghEnumKey, pszDeviceID, 0, KEY_READ, &hKeyDevice);
  1304. if (RegStatus != ERROR_SUCCESS) {
  1305. Status = CR_INVALID_DEVINST;
  1306. goto Clean0;
  1307. }
  1308. //
  1309. // create the key with security inherited from parent key. Note
  1310. // that I'm not using passed in access mask, in order to set the
  1311. // security later, it must be created with KEY_ALL_ACCESS.
  1312. //
  1313. RegStatus = RegCreateKeyEx( hKeyDevice, pszRegKeyDeviceParam, 0,
  1314. NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
  1315. NULL, &hKey, NULL);
  1316. if (RegStatus != ERROR_SUCCESS) {
  1317. Status = CR_REGISTRY_ERROR;
  1318. goto Clean0;
  1319. }
  1320. //-------------------------------------------------------------
  1321. // add admin-full privilege to the inherited security info
  1322. //-------------------------------------------------------------
  1323. //
  1324. //
  1325. // NOTE: we don't need to do this unless the key was newly created. In
  1326. // theory we only get here when the key doesn't already exist. However
  1327. // there is a remote chance of two threads getting here simultaneously. If
  1328. // this happens we would end up with two admin full control ACEs.
  1329. //
  1330. //
  1331. // create the admin-full SID
  1332. //
  1333. if (!AllocateAndInitializeSid( &Authority, 2,
  1334. SECURITY_BUILTIN_DOMAIN_RID,
  1335. DOMAIN_ALIAS_RID_ADMINS,
  1336. 0, 0, 0, 0, 0, 0,
  1337. &pAdminSid)) {
  1338. Status = CR_FAILURE;
  1339. goto Clean0;
  1340. }
  1341. //
  1342. // get the current security descriptor for the key
  1343. //
  1344. RegStatus = RegGetKeySecurity( hKey, DACL_SECURITY_INFORMATION,
  1345. NULL, &ulSize);
  1346. if (RegStatus != ERROR_INSUFFICIENT_BUFFER &&
  1347. RegStatus != ERROR_SUCCESS) {
  1348. Status = CR_FAILURE;
  1349. goto Clean0;
  1350. }
  1351. pSecDesc = HeapAlloc(ghPnPHeap, 0, ulSize);
  1352. if (pSecDesc == NULL) {
  1353. Status = CR_OUT_OF_MEMORY;
  1354. goto Clean0;
  1355. }
  1356. RegStatus = RegGetKeySecurity( hKey, DACL_SECURITY_INFORMATION,
  1357. pSecDesc, &ulSize);
  1358. if (RegStatus != ERROR_SUCCESS) {
  1359. Status = CR_REGISTRY_ERROR;
  1360. goto Clean0;
  1361. }
  1362. //
  1363. // get the current DACL
  1364. //
  1365. if (!GetSecurityDescriptorDacl(pSecDesc, &bHasDacl, &pDacl, &bStatus)) {
  1366. Status = CR_FAILURE;
  1367. goto Clean0;
  1368. }
  1369. //
  1370. // create a new absolute security descriptor and DACL
  1371. //
  1372. if (!InitializeSecurityDescriptor( &NewSecDesc,
  1373. SECURITY_DESCRIPTOR_REVISION)) {
  1374. Status = CR_FAILURE;
  1375. goto Clean0;
  1376. }
  1377. //
  1378. // calculate the size of the new DACL
  1379. //
  1380. if (bHasDacl) {
  1381. if (!GetAclInformation( pDacl, &AclSizeInfo,
  1382. sizeof(ACL_SIZE_INFORMATION),
  1383. AclSizeInformation)) {
  1384. Status = CR_FAILURE;
  1385. goto Clean0;
  1386. }
  1387. ulSize = AclSizeInfo.AclBytesInUse;
  1388. } else {
  1389. ulSize = sizeof(ACL);
  1390. }
  1391. ulSize += sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pAdminSid) - sizeof(DWORD);
  1392. //
  1393. // create and initialize the new DACL
  1394. //
  1395. pNewDacl = HeapAlloc(ghPnPHeap, 0, ulSize);
  1396. if (pNewDacl == NULL) {
  1397. Status = CR_OUT_OF_MEMORY;
  1398. goto Clean0;
  1399. }
  1400. if (!InitializeAcl(pNewDacl, ulSize, ACL_REVISION2)) {
  1401. Status = CR_FAILURE;
  1402. goto Clean0;
  1403. }
  1404. //
  1405. // copy the current (original) DACL into this new one
  1406. //
  1407. if (bHasDacl) {
  1408. for (i = 0; i < AclSizeInfo.AceCount; i++) {
  1409. if (!GetAce(pDacl, i, (LPVOID *)&pAce)) {
  1410. Status = CR_FAILURE;
  1411. goto Clean0;
  1412. }
  1413. //
  1414. // We need to skip copying any ACEs which refer to the Administrator
  1415. // to ensure that our full control ACE is the one and only.
  1416. //
  1417. if ((pAce->Header.AceType != ACCESS_ALLOWED_ACE_TYPE &&
  1418. pAce->Header.AceType != ACCESS_DENIED_ACE_TYPE) ||
  1419. !EqualSid((PSID)&pAce->SidStart, pAdminSid)) {
  1420. if (!AddAce( pNewDacl, ACL_REVISION2, (DWORD)~0U, pAce,
  1421. pAce->Header.AceSize)) {
  1422. Status = CR_FAILURE;
  1423. goto Clean0;
  1424. }
  1425. }
  1426. }
  1427. }
  1428. //
  1429. // and my new admin-full ace to this new DACL
  1430. //
  1431. if (!AddAccessAllowedAceEx( pNewDacl, ACL_REVISION2,
  1432. CONTAINER_INHERIT_ACE, KEY_ALL_ACCESS,
  1433. pAdminSid)) {
  1434. Status = CR_FAILURE;
  1435. goto Clean0;
  1436. }
  1437. //
  1438. // Set the new DACL in the absolute security descriptor
  1439. //
  1440. if (!SetSecurityDescriptorDacl(&NewSecDesc, TRUE, pNewDacl, FALSE)) {
  1441. Status = CR_FAILURE;
  1442. goto Clean0;
  1443. }
  1444. //
  1445. // validate the new security descriptor
  1446. //
  1447. if (!IsValidSecurityDescriptor(&NewSecDesc)) {
  1448. Status = CR_FAILURE;
  1449. goto Clean0;
  1450. }
  1451. //
  1452. // apply the new security back to the registry key
  1453. //
  1454. RegStatus = RegSetKeySecurity( hKey, DACL_SECURITY_INFORMATION,
  1455. &NewSecDesc);
  1456. if (RegStatus != ERROR_SUCCESS) {
  1457. Status = CR_REGISTRY_ERROR;
  1458. goto Clean0;
  1459. }
  1460. Clean0:
  1461. NOTHING;
  1462. } except(EXCEPTION_EXECUTE_HANDLER) {
  1463. Status = CR_FAILURE;
  1464. //
  1465. // force compiler to respect statement ordering w.r.t. assignments
  1466. // for these variables...
  1467. //
  1468. hKeyDevice = hKeyDevice;
  1469. hKey = hKey;
  1470. pAdminSid = pAdminSid;
  1471. pNewDacl = pNewDacl;
  1472. pSecDesc = pSecDesc;
  1473. }
  1474. if (hKeyDevice != NULL) {
  1475. RegCloseKey(hKeyDevice);
  1476. }
  1477. if (hKey != NULL) {
  1478. RegCloseKey(hKey);
  1479. }
  1480. if (pAdminSid != NULL) {
  1481. FreeSid(pAdminSid);
  1482. }
  1483. if (pNewDacl != NULL) {
  1484. HeapFree(ghPnPHeap, 0, pNewDacl);
  1485. }
  1486. if (pSecDesc != NULL) {
  1487. HeapFree(ghPnPHeap, 0, pSecDesc);
  1488. }
  1489. return Status;
  1490. } // PNP_CreateKey
  1491. CONFIGRET
  1492. PNP_DeleteRegistryKey(
  1493. IN handle_t hBinding,
  1494. IN LPCWSTR pszDeviceID,
  1495. IN LPCWSTR pszParentKey,
  1496. IN LPCWSTR pszChildKey,
  1497. IN ULONG ulFlags
  1498. )
  1499. /*++
  1500. Routine Description:
  1501. This is the RPC server entry point for the CM_Delete_DevNode_Key
  1502. routine.
  1503. Arguments:
  1504. hBinding RPC binding handle.
  1505. pszDeviceID Supplies the device instance string.
  1506. pszParentKey Supplies the parent registry path of the key to be
  1507. deleted.
  1508. pszChildKey Supplies the subkey to be deleted.
  1509. ulFlags If 0xFFFFFFFF then delete for all profiles
  1510. Return Value:
  1511. If the function succeeds, the return value is CR_SUCCESS.
  1512. If the function fails, the return value is one of the following:
  1513. CR_ACCESS_DENIED,
  1514. CR_INVALID_DEVNODE,
  1515. CR_INVALID_FLAG,
  1516. CR_INVALID_POINTER,
  1517. CR_NO_SUCH_VALUE,
  1518. CR_REGISTRY_ERROR.
  1519. --*/
  1520. {
  1521. CONFIGRET Status = ERROR_SUCCESS;
  1522. LONG RegStatus = ERROR_SUCCESS;
  1523. HKEY hKey = NULL;
  1524. WCHAR szProfile[MAX_PROFILE_ID_LEN];
  1525. PWCHAR pszRegStr = NULL, pszRegKey1 = NULL, pszRegKey2 = NULL;
  1526. ULONG ulIndex = 0, ulSize = 0;
  1527. BOOL bPhantom = FALSE;
  1528. ULONG ulStatus, ulProblem;
  1529. PWCHAR pszFormatString = NULL;
  1530. //
  1531. // Note, the service currently cannot access the HKCU branch, so I
  1532. // assume the keys specified are under HKEY_LOCAL_MACHINE.
  1533. //
  1534. try {
  1535. //
  1536. // Verify client privilege
  1537. //
  1538. if (!VerifyClientAccess(hBinding, &gLuidLoadDriverPrivilege)) {
  1539. Status = CR_ACCESS_DENIED;
  1540. goto Clean0;
  1541. }
  1542. //
  1543. // validate parameters
  1544. // (currently, 0 and -1 are the only accepted flags.)
  1545. //
  1546. if ((ulFlags != 0) &&
  1547. (ulFlags != 0xFFFFFFFF)) {
  1548. Status = CR_INVALID_FLAG;
  1549. goto Clean0;
  1550. }
  1551. if (!IsLegalDeviceId(pszDeviceID)) {
  1552. Status = CR_INVALID_DEVNODE;
  1553. goto Clean0;
  1554. }
  1555. //
  1556. // pszParentKey is a registry path to the pszChildKey parameter.
  1557. // pszChildKey may be a single path or a compound path, a compound
  1558. // path is specified if all those subkeys should be deleted (or
  1559. // made volatile). Note that for real keys we never modify anything
  1560. // but the lowest level private key.
  1561. //
  1562. if (!ARGUMENT_PRESENT(pszParentKey) ||
  1563. !ARGUMENT_PRESENT(pszChildKey) ||
  1564. ((lstrlen(pszParentKey) + 1) > MAX_CM_PATH) ||
  1565. ((lstrlen(pszChildKey) + 1) > MAX_CM_PATH)) {
  1566. Status = CR_INVALID_POINTER;
  1567. goto Clean0;
  1568. }
  1569. //
  1570. // Allocate registry path buffers.
  1571. //
  1572. pszRegStr = HeapAlloc(ghPnPHeap, 0, 2*MAX_CM_PATH * sizeof(WCHAR));
  1573. if (pszRegStr == NULL) {
  1574. Status = CR_OUT_OF_MEMORY;
  1575. goto Clean0;
  1576. }
  1577. pszRegKey1 = HeapAlloc(ghPnPHeap, 0, 2*MAX_CM_PATH * sizeof(WCHAR));
  1578. if (pszRegKey1 == NULL) {
  1579. Status = CR_OUT_OF_MEMORY;
  1580. goto Clean0;
  1581. }
  1582. pszRegKey2 = HeapAlloc(ghPnPHeap, 0, 2*MAX_CM_PATH * sizeof(WCHAR));
  1583. if (pszRegKey2 == NULL) {
  1584. Status = CR_OUT_OF_MEMORY;
  1585. goto Clean0;
  1586. }
  1587. //
  1588. // Is the device a phantom?
  1589. //
  1590. bPhantom = IsDevicePhantom((LPWSTR)pszDeviceID) ||
  1591. GetDeviceStatus(pszDeviceID, &ulStatus, &ulProblem) != CR_SUCCESS ||
  1592. !(ulStatus & DN_DRIVER_LOADED);
  1593. if (!bPhantom) {
  1594. //
  1595. // for a real key, we never modify anything but the key
  1596. // where private info is so split if compound. This may
  1597. // end up leaving a dead device key around in some cases
  1598. // but another instance of that device could show at any
  1599. // time so we can't make it volatile.
  1600. //
  1601. if (Split1(pszChildKey, pszRegStr, pszRegKey2)) {
  1602. //
  1603. // compound key, only the last subkey will be affected,
  1604. // tack the rest on as part of the parent key
  1605. //
  1606. wsprintf(pszRegKey1, TEXT("%s\\%s"), pszParentKey, pszRegStr);
  1607. }
  1608. else {
  1609. //
  1610. // wasn't compound so use the whole child key
  1611. //
  1612. lstrcpy(pszRegKey1, pszParentKey);
  1613. lstrcpy(pszRegKey2, pszChildKey);
  1614. }
  1615. }
  1616. //-------------------------------------------------------------
  1617. // SPECIAL CASE: If ulHardwareProfile == -1, then need to
  1618. // delete the private key for all profiles.
  1619. //-------------------------------------------------------------
  1620. if (ulFlags == 0xFFFFFFFF) {
  1621. wsprintf(pszRegStr, TEXT("%s\\%s"),
  1622. pszRegPathIDConfigDB,
  1623. pszRegKeyKnownDockingStates);
  1624. RegStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE, pszRegStr, 0,
  1625. KEY_ALL_ACCESS, &hKey);
  1626. //
  1627. // enumerate the hardware profile keys
  1628. //
  1629. for (ulIndex = 0; RegStatus == ERROR_SUCCESS; ulIndex++) {
  1630. ulSize = MAX_PROFILE_ID_LEN;
  1631. RegStatus = RegEnumKeyEx( hKey, ulIndex, szProfile, &ulSize,
  1632. NULL, NULL, NULL, NULL);
  1633. if (RegStatus == ERROR_SUCCESS) {
  1634. //
  1635. // if phantom, go ahead and delete it
  1636. //
  1637. if (bPhantom) {
  1638. //
  1639. // pszParentKey contains replacement symbol for the profile id, %s
  1640. //
  1641. pszFormatString = wcschr(pszParentKey, L'%');
  1642. ASSERT(pszFormatString && (pszFormatString[1] == L's'));
  1643. if (pszFormatString && (pszFormatString[1] == L's')) {
  1644. wsprintf(pszRegStr, pszParentKey, szProfile);
  1645. Status = DeletePrivateKey( HKEY_LOCAL_MACHINE, pszRegStr,
  1646. pszChildKey);
  1647. } else {
  1648. Status = CR_FAILURE;
  1649. }
  1650. }
  1651. //
  1652. // if real, just make it volatile
  1653. //
  1654. else {
  1655. //
  1656. // pszRegKey1 contains replacement symbol for the profile id, %s
  1657. //
  1658. pszFormatString = wcschr(pszRegKey1, L'%');
  1659. ASSERT(pszFormatString && (pszFormatString[1] == L's'));
  1660. if (pszFormatString && (pszFormatString[1] == L's')) {
  1661. wsprintf(pszRegStr, pszRegKey1, szProfile);
  1662. KdPrintEx((DPFLTR_PNPMGR_ID,
  1663. DBGF_REGISTRY,
  1664. "UMPNPMGR: PNP_DeleteRegistryKey make key %ws\\%ws volatile\n",
  1665. pszRegStr,
  1666. pszRegKey2));
  1667. Status = MakeKeyVolatile(pszRegStr, pszRegKey2);
  1668. } else {
  1669. Status = CR_FAILURE;
  1670. }
  1671. }
  1672. if (Status != CR_SUCCESS) {
  1673. goto Clean0;
  1674. }
  1675. }
  1676. }
  1677. }
  1678. //------------------------------------------------------------------
  1679. // not deleting for all profiles, so just delete the specified key
  1680. //------------------------------------------------------------------
  1681. else {
  1682. if (bPhantom) {
  1683. //
  1684. // if phantom, go ahead and delete it
  1685. //
  1686. Status = DeletePrivateKey( HKEY_LOCAL_MACHINE, pszParentKey,
  1687. pszChildKey);
  1688. }
  1689. else {
  1690. //
  1691. // if real, just make it volatile
  1692. //
  1693. KdPrintEx((DPFLTR_PNPMGR_ID,
  1694. DBGF_REGISTRY,
  1695. "UMPNPMGR: PNP_DeleteRegistryKey make key %ws\\%ws volatile\n",
  1696. pszRegKey1,
  1697. pszRegKey2));
  1698. Status = MakeKeyVolatile(pszRegKey1, pszRegKey2);
  1699. }
  1700. if (Status != CR_SUCCESS) {
  1701. goto Clean0;
  1702. }
  1703. }
  1704. Clean0:
  1705. NOTHING;
  1706. } except(EXCEPTION_EXECUTE_HANDLER) {
  1707. Status = CR_FAILURE;
  1708. //
  1709. // force compiler to respect statement ordering w.r.t. assignments
  1710. // for these variables...
  1711. //
  1712. hKey = hKey;
  1713. pszRegStr = pszRegStr;
  1714. pszRegKey1 = pszRegKey1;
  1715. pszRegKey2 = pszRegKey2;
  1716. }
  1717. if (hKey != NULL) {
  1718. RegCloseKey(hKey);
  1719. }
  1720. if (pszRegStr != NULL) {
  1721. HeapFree(ghPnPHeap, 0, pszRegStr);
  1722. }
  1723. if (pszRegKey1 != NULL) {
  1724. HeapFree(ghPnPHeap, 0, pszRegKey1);
  1725. }
  1726. if (pszRegKey2 != NULL) {
  1727. HeapFree(ghPnPHeap, 0, pszRegKey2);
  1728. }
  1729. return Status;
  1730. } // PNP_DeleteRegistryKey
  1731. CONFIGRET
  1732. PNP_GetClassCount(
  1733. IN handle_t hBinding,
  1734. OUT PULONG pulClassCount,
  1735. IN ULONG ulFlags
  1736. )
  1737. /*++
  1738. Routine Description:
  1739. This is the RPC server entry point for the CM_Get_Class_Count routine.
  1740. It returns the number of valid classes currently installed (listed in
  1741. the registry).
  1742. Arguments:
  1743. hBinding RPC binding handle, not used.
  1744. pulClassCount Supplies the address of a variable that will
  1745. receive the number of classes installed.
  1746. ulFlags Not used.
  1747. Return Value:
  1748. If the function succeeds, the return value is CR_SUCCESS.
  1749. If the function fails, the return value is one of the following:
  1750. CR_INVALID_FLAG,
  1751. CR_INVALID_POINTER, or
  1752. CR_REGISTRY_ERROR
  1753. Notes:
  1754. ** PRESENTLY, ALWAYS RETURNS CR_CALL_NOT_IMPLEMENTED **
  1755. No corresponding CM_Get_Class_Count routine is implemented.
  1756. This routine currently returns CR_CALL_NOT_IMPLEMENTED.
  1757. --*/
  1758. {
  1759. UNREFERENCED_PARAMETER(hBinding);
  1760. UNREFERENCED_PARAMETER(pulClassCount);
  1761. UNREFERENCED_PARAMETER(ulFlags);
  1762. return CR_CALL_NOT_IMPLEMENTED;
  1763. } // PNP_GetClassCount
  1764. CONFIGRET
  1765. PNP_GetClassName(
  1766. IN handle_t hBinding,
  1767. IN PCWSTR pszClassGuid,
  1768. OUT PWSTR Buffer,
  1769. IN OUT PULONG pulLength,
  1770. IN ULONG ulFlags
  1771. )
  1772. /*++
  1773. Routine Description:
  1774. This is the RPC server entry point for the CM_Get_Class_Name routine.
  1775. It returns the name of the class represented by the GUID.
  1776. Arguments:
  1777. hBinding RPC binding handle, not used.
  1778. pszClassGuid String containing the class guid to retrieve a
  1779. class name for.
  1780. Buffer Supplies the address of the buffer that receives the
  1781. class name.
  1782. pulLength On input, this specifies the size of the Buffer in
  1783. characters. On output it contains the number of
  1784. characters actually copied to Buffer.
  1785. ulFlags Not used, must be zero.
  1786. Return Value:
  1787. If the function succeeds, the return value is CR_SUCCESS.
  1788. If the function fails, the return value is one of the following:
  1789. CR_INVALID_FLAG,
  1790. CR_INVALID_POINTER,
  1791. CR_BUFFER_SMALL, or
  1792. CR_REGISTRY_ERROR
  1793. --*/
  1794. {
  1795. CONFIGRET Status = CR_SUCCESS;
  1796. LONG RegStatus = ERROR_SUCCESS;
  1797. WCHAR RegStr[MAX_CM_PATH];
  1798. HKEY hKey = NULL;
  1799. ULONG ulLength;
  1800. UNREFERENCED_PARAMETER(hBinding);
  1801. try {
  1802. //
  1803. // Validate parameters
  1804. //
  1805. if (INVALID_FLAGS(ulFlags, 0)) {
  1806. Status = CR_INVALID_FLAG;
  1807. goto Clean0;
  1808. }
  1809. if ((!ARGUMENT_PRESENT(pulLength)) ||
  1810. (!ARGUMENT_PRESENT(Buffer) && *pulLength != 0)) {
  1811. Status = CR_INVALID_POINTER;
  1812. goto Clean0;
  1813. }
  1814. //
  1815. // Open the key for the specified class guid
  1816. //
  1817. if ((lstrlen (pszRegPathClass) + lstrlen (pszClassGuid) + sizeof (TEXT("\\"))) > MAX_CM_PATH) {
  1818. Status = CR_BUFFER_SMALL;
  1819. goto Clean0;
  1820. }
  1821. wsprintf(RegStr, TEXT("%s\\%s"),
  1822. pszRegPathClass,
  1823. pszClassGuid);
  1824. RegStatus = RegOpenKeyEx(
  1825. HKEY_LOCAL_MACHINE, RegStr, 0, KEY_QUERY_VALUE, &hKey);
  1826. if (RegStatus != ERROR_SUCCESS) {
  1827. Status = CR_REGISTRY_ERROR;
  1828. goto Clean0;
  1829. }
  1830. //
  1831. // Retrieve the class name string value
  1832. //
  1833. ulLength = *pulLength;
  1834. *pulLength *= sizeof(WCHAR); // convert to size in bytes
  1835. RegStatus = RegQueryValueEx(
  1836. hKey, pszRegValueClass, NULL, NULL,
  1837. (LPBYTE)Buffer, pulLength);
  1838. *pulLength /= sizeof(WCHAR); // convert back to chars
  1839. if (RegStatus == ERROR_SUCCESS) {
  1840. Status = CR_SUCCESS;
  1841. }
  1842. else if (RegStatus == ERROR_MORE_DATA) {
  1843. Status = CR_BUFFER_SMALL;
  1844. if ((ARGUMENT_PRESENT(Buffer)) &&
  1845. (ulLength > 0)) {
  1846. *Buffer = L'\0';
  1847. }
  1848. }
  1849. else {
  1850. Status = CR_REGISTRY_ERROR;
  1851. if ((ARGUMENT_PRESENT(Buffer)) &&
  1852. (ulLength > 0)) {
  1853. *Buffer = L'\0';
  1854. *pulLength = 1;
  1855. }
  1856. }
  1857. Clean0:
  1858. NOTHING;
  1859. } except(EXCEPTION_EXECUTE_HANDLER) {
  1860. Status = CR_FAILURE;
  1861. //
  1862. // force compiler to respect statement ordering w.r.t. assignments
  1863. // for these variables...
  1864. //
  1865. hKey = hKey;
  1866. }
  1867. if (hKey != NULL) {
  1868. RegCloseKey(hKey);
  1869. }
  1870. return Status;
  1871. } // PNP_GetClassName
  1872. CONFIGRET
  1873. PNP_DeleteClassKey(
  1874. IN handle_t hBinding,
  1875. IN PCWSTR pszClassGuid,
  1876. IN ULONG ulFlags
  1877. )
  1878. /*++
  1879. Routine Description:
  1880. This is the RPC server entry point for the CM_Delete_Class_Key routine.
  1881. It deletes the corresponding registry key.
  1882. Arguments:
  1883. hBinding RPC binding handle.
  1884. pszClassGuid String containing the class guid to retrieve a
  1885. class name for.
  1886. ulFlags Either CM_DELETE_CLASS_ONLY or CM_DELETE_CLASS_SUBKEYS.
  1887. Return Value:
  1888. If the function succeeds, the return value is CR_SUCCESS.
  1889. If the function fails, the return value is one of the following:
  1890. CR_ACCESS_DENIED,
  1891. CR_INVALID_FLAG,
  1892. CR_INVALID_POINTER,
  1893. CR_REGISTRY_ERROR, or
  1894. CR_FAILURE
  1895. --*/
  1896. {
  1897. CONFIGRET Status = CR_SUCCESS;
  1898. try {
  1899. //
  1900. // Verify client privilege
  1901. //
  1902. if (!VerifyClientAccess(hBinding, &gLuidLoadDriverPrivilege)) {
  1903. Status = CR_ACCESS_DENIED;
  1904. goto Clean0;
  1905. }
  1906. //
  1907. // Validate parameters
  1908. //
  1909. if (INVALID_FLAGS(ulFlags, CM_DELETE_CLASS_BITS)) {
  1910. Status = CR_INVALID_FLAG;
  1911. goto Clean0;
  1912. }
  1913. if (ulFlags == CM_DELETE_CLASS_SUBKEYS) {
  1914. //
  1915. // Delete the class key and any subkeys under it
  1916. //
  1917. if (!RegDeleteNode(ghClassKey, pszClassGuid)) {
  1918. Status = CR_REGISTRY_ERROR;
  1919. }
  1920. } else if (ulFlags == CM_DELETE_CLASS_ONLY) {
  1921. //
  1922. // only delete the class key itself (just attempt to delete
  1923. // using the registry routine, it will fail if any subkeys
  1924. // exist)
  1925. //
  1926. if (RegDeleteKey(ghClassKey, pszClassGuid) != ERROR_SUCCESS) {
  1927. Status = CR_REGISTRY_ERROR;
  1928. }
  1929. }
  1930. Clean0:
  1931. NOTHING;
  1932. } except(EXCEPTION_EXECUTE_HANDLER) {
  1933. Status = CR_FAILURE;
  1934. }
  1935. return Status;
  1936. } // PNP_DeleteClassKey
  1937. CONFIGRET
  1938. PNP_GetInterfaceDeviceAlias(
  1939. IN handle_t hBinding,
  1940. IN PCWSTR pszInterfaceDevice,
  1941. IN LPGUID AliasInterfaceGuid,
  1942. OUT PWSTR pszAliasInterfaceDevice,
  1943. IN OUT PULONG pulLength,
  1944. IN OUT PULONG pulTransferLen,
  1945. IN ULONG ulFlags
  1946. )
  1947. /*++
  1948. Routine Description:
  1949. This is the RPC server entry point for the CM_Get_Interface_Device_Alias routine.
  1950. It returns an alias string for the specified guid and interface device.
  1951. Arguments:
  1952. hBinding RPC binding handle, not used.
  1953. pszInterfaceDevice Specifies the interface device to find an alias for.
  1954. AliasInterfaceGuid Supplies the interface class GUID.
  1955. pszAliasInterfaceDevice Supplies the address of a variable that will
  1956. receive the device interface alias of the specified device
  1957. interface, that is a member of the specified alias
  1958. interface class GUID.
  1959. pulLength Parameter passed in by caller, on entry it contains
  1960. the size, in bytes, of the buffer, on exit it contains
  1961. either the amount of data copied to the caller's buffer
  1962. (if a transfer occured) or else the size of buffer
  1963. required to hold the property data.
  1964. pulTransferLen Used by stubs, indicates how much data to copy back
  1965. into user buffer.
  1966. ulFlags Not used, must be zero.
  1967. Return Value:
  1968. If the function succeeds, the return value is CR_SUCCESS.
  1969. If the function fails, the return value is one of the following:
  1970. CR_INVALID_FLAG,
  1971. CR_INVALID_POINTER, or
  1972. CR_REGISTRY_ERROR
  1973. --*/
  1974. {
  1975. CONFIGRET Status = CR_SUCCESS;
  1976. NTSTATUS ntStatus = STATUS_SUCCESS;
  1977. PLUGPLAY_CONTROL_INTERFACE_ALIAS_DATA ControlData;
  1978. UNREFERENCED_PARAMETER(hBinding);
  1979. try {
  1980. //
  1981. // Validate parameters
  1982. //
  1983. ASSERT(pulTransferLen != pulLength);
  1984. if (!ARGUMENT_PRESENT(pszInterfaceDevice) ||
  1985. !ARGUMENT_PRESENT(AliasInterfaceGuid) ||
  1986. !ARGUMENT_PRESENT(pszAliasInterfaceDevice) ||
  1987. !ARGUMENT_PRESENT(pulTransferLen) ||
  1988. !ARGUMENT_PRESENT(pulLength)) {
  1989. Status = CR_INVALID_POINTER;
  1990. goto Clean0;
  1991. }
  1992. if (INVALID_FLAGS(ulFlags, 0)) {
  1993. Status = CR_INVALID_FLAG;
  1994. goto Clean0;
  1995. }
  1996. //
  1997. // Make sure we use no more than either what the caller specified or
  1998. // what was allocated by RPC, based on the transfer length.
  1999. //
  2000. *pulLength = min(*pulLength, *pulTransferLen);
  2001. //
  2002. // Fill in a control structure for the device list info.
  2003. //
  2004. //
  2005. // Note that AliasInterfaceGuid was already validated above because this
  2006. // buffer is required for the PlugPlayControlGetInterfaceDeviceAlias
  2007. // control, and is probed unconditionally by kernel-mode. Better to
  2008. // fail the call above with a useful status than to return the generic
  2009. // CR_FAILURE after an exception/error from kernel-mode, below.
  2010. //
  2011. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_INTERFACE_ALIAS_DATA));
  2012. RtlInitUnicodeString(&ControlData.SymbolicLinkName, pszInterfaceDevice);
  2013. ControlData.AliasClassGuid = AliasInterfaceGuid;
  2014. ControlData.AliasSymbolicLinkName = pszAliasInterfaceDevice;
  2015. ControlData.AliasSymbolicLinkNameLength = *pulLength; // chars
  2016. //
  2017. // Call kernel-mode to get the device interface alias.
  2018. //
  2019. ntStatus = NtPlugPlayControl(PlugPlayControlGetInterfaceDeviceAlias,
  2020. &ControlData,
  2021. sizeof(ControlData));
  2022. if (NT_SUCCESS(ntStatus)) {
  2023. *pulLength = ControlData.AliasSymbolicLinkNameLength;
  2024. *pulTransferLen = *pulLength + 1;
  2025. } else if (ntStatus == STATUS_BUFFER_TOO_SMALL) {
  2026. *pulLength = ControlData.AliasSymbolicLinkNameLength;
  2027. Status = CR_BUFFER_SMALL;
  2028. } else {
  2029. *pulLength = 0;
  2030. Status = MapNtStatusToCmError(ntStatus);
  2031. }
  2032. Clean0:
  2033. //
  2034. // Initialize output parameters
  2035. //
  2036. if ((Status != CR_SUCCESS) &&
  2037. ARGUMENT_PRESENT(pulTransferLen) &&
  2038. ARGUMENT_PRESENT(pszAliasInterfaceDevice) &&
  2039. (*pulTransferLen > 0)) {
  2040. *pszAliasInterfaceDevice = L'\0';
  2041. *pulTransferLen = 1;
  2042. }
  2043. } except(EXCEPTION_EXECUTE_HANDLER) {
  2044. Status = CR_FAILURE;
  2045. }
  2046. return Status;
  2047. } // PNP_GetInterfaceDeviceAlias
  2048. CONFIGRET
  2049. PNP_GetInterfaceDeviceList(
  2050. IN handle_t hBinding,
  2051. IN LPGUID InterfaceGuid,
  2052. IN LPCWSTR pszDeviceID,
  2053. OUT LPWSTR Buffer,
  2054. IN OUT PULONG pulLength,
  2055. IN ULONG ulFlags
  2056. )
  2057. /*++
  2058. Routine Description:
  2059. This is the RPC server entry point for the CM_Get_Device_Interface_List routine.
  2060. It returns a multi_sz interface device list.
  2061. Arguments:
  2062. hBinding RPC binding handle, not used.
  2063. InterfaceGuid Supplies the interface class GUID.
  2064. pszDeviceID Supplies the device instance string.
  2065. Buffer Supplies the address of the buffer that receives the
  2066. registry data.
  2067. pulLength Specifies the size, in bytes, of the buffer.
  2068. ulFlags Flags specifying which device interfaces to return.
  2069. Currently, may be either:
  2070. CM_GET_DEVICE_INTERFACE_LIST_PRESENT, or
  2071. CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES.
  2072. Return Value:
  2073. If the function succeeds, the return value is CR_SUCCESS.
  2074. If the function fails, the return value is one of the following:
  2075. CR_INVALID_FLAG,
  2076. CR_INVALID_DEVNODE,
  2077. CR_INVALID_POINTER, or
  2078. CR_REGISTRY_ERROR
  2079. --*/
  2080. {
  2081. CONFIGRET Status = CR_SUCCESS;
  2082. NTSTATUS ntStatus = STATUS_SUCCESS;
  2083. PLUGPLAY_CONTROL_INTERFACE_LIST_DATA ControlData;
  2084. UNREFERENCED_PARAMETER(hBinding);
  2085. try {
  2086. //
  2087. // Validate parameters
  2088. //
  2089. if (INVALID_FLAGS(ulFlags, CM_GET_DEVICE_INTERFACE_LIST_BITS)) {
  2090. Status = CR_INVALID_FLAG;
  2091. goto Clean0;
  2092. }
  2093. if (!ARGUMENT_PRESENT(InterfaceGuid) ||
  2094. !ARGUMENT_PRESENT(pulLength) ||
  2095. !ARGUMENT_PRESENT(Buffer) ||
  2096. (*pulLength == 0)) {
  2097. Status = CR_INVALID_POINTER;
  2098. goto Clean0;
  2099. }
  2100. if (!IsLegalDeviceId(pszDeviceID)) {
  2101. Status = CR_INVALID_DEVNODE;
  2102. goto Clean0;
  2103. }
  2104. //
  2105. // Fill in a control structure for the device list info.
  2106. //
  2107. //
  2108. // Note that InterfaceGuid was already validated above because this
  2109. // buffer is required for the PlugPlayControlGetInterfaceDeviceList
  2110. // control, and is probed unconditionally by kernel-mode. Better to
  2111. // fail the call above with a useful status than to return the generic
  2112. // CR_FAILURE after an exception/error from kernel-mode, below.
  2113. //
  2114. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_INTERFACE_LIST_DATA));
  2115. RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceID);
  2116. ControlData.InterfaceGuid = InterfaceGuid;
  2117. ControlData.InterfaceList = Buffer;
  2118. ControlData.InterfaceListSize = *pulLength;
  2119. if (ulFlags == CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES) {
  2120. ControlData.Flags = 0x1; // DEVICE_INTERFACE_INCLUDE_NONACTIVE (ntos\inc\pnp.h)
  2121. } else {
  2122. ControlData.Flags = 0;
  2123. }
  2124. //
  2125. // Call kernel-mode to get the device interface list.
  2126. //
  2127. ntStatus = NtPlugPlayControl(PlugPlayControlGetInterfaceDeviceList,
  2128. &ControlData,
  2129. sizeof(ControlData));
  2130. if (NT_SUCCESS(ntStatus)) {
  2131. *pulLength = ControlData.InterfaceListSize;
  2132. } else {
  2133. *pulLength = 0;
  2134. if (ntStatus == STATUS_BUFFER_TOO_SMALL) {
  2135. Status = CR_BUFFER_SMALL;
  2136. } else {
  2137. Status = CR_FAILURE;
  2138. }
  2139. }
  2140. Clean0:
  2141. NOTHING;
  2142. } except(EXCEPTION_EXECUTE_HANDLER) {
  2143. Status = CR_FAILURE;
  2144. }
  2145. return Status;
  2146. } // PNP_GetInterfaceDeviceList
  2147. CONFIGRET
  2148. PNP_GetInterfaceDeviceListSize(
  2149. IN handle_t hBinding,
  2150. OUT PULONG pulLen,
  2151. IN LPGUID InterfaceGuid,
  2152. IN LPCWSTR pszDeviceID,
  2153. IN ULONG ulFlags
  2154. )
  2155. /*++
  2156. Routine Description:
  2157. This is the RPC server entry point for the CM_Get_Device_Interface_List_Size
  2158. routine. It returns the size (in chars) of a multi_sz interface device list.
  2159. Arguments:
  2160. hBinding RPC binding handle, not used.
  2161. pulLen Supplies the address of a variable that, upon successful
  2162. return, receives the the size of buffer required to hold
  2163. the multi_sz interface device list.
  2164. InterfaceGuid Supplies the interface class GUID.
  2165. pszDeviceID Supplies the device instance string.
  2166. ulFlags Flags specifying which device interfaces to return.
  2167. Currently, may be either:
  2168. CM_GET_DEVICE_INTERFACE_LIST_PRESENT, or
  2169. CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES.
  2170. Return Value:
  2171. If the function succeeds, the return value is CR_SUCCESS.
  2172. If the function fails, the return value is one of the following:
  2173. CR_INVALID_FLAG,
  2174. CR_INVALID_POINTER, or
  2175. CR_REGISTRY_ERROR
  2176. --*/
  2177. {
  2178. CONFIGRET Status = CR_SUCCESS;
  2179. NTSTATUS ntStatus = STATUS_SUCCESS;
  2180. PLUGPLAY_CONTROL_INTERFACE_LIST_DATA ControlData;
  2181. UNREFERENCED_PARAMETER(hBinding);
  2182. try {
  2183. //
  2184. // Validate parameters
  2185. //
  2186. if (INVALID_FLAGS(ulFlags, CM_GET_DEVICE_INTERFACE_LIST_BITS)) {
  2187. Status = CR_INVALID_FLAG;
  2188. goto Clean0;
  2189. }
  2190. if (!ARGUMENT_PRESENT(InterfaceGuid) ||
  2191. !ARGUMENT_PRESENT(pulLen)) {
  2192. Status = CR_INVALID_POINTER;
  2193. goto Clean0;
  2194. }
  2195. if (!IsLegalDeviceId(pszDeviceID)) {
  2196. Status = CR_INVALID_DEVNODE;
  2197. goto Clean0;
  2198. }
  2199. //
  2200. // Initialize the returned output length
  2201. //
  2202. *pulLen = 0;
  2203. //
  2204. // Fill in a control structure for the device list info.
  2205. //
  2206. //
  2207. // Note that InterfaceGuid was already validated above because this
  2208. // buffer is required for the PlugPlayControlGetInterfaceDeviceList
  2209. // control, and is probed unconditionally by kernel-mode. Better to
  2210. // fail the call above with a useful status than to return the generic
  2211. // CR_FAILURE after an exception/error from kernel-mode, below.
  2212. //
  2213. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_INTERFACE_LIST_DATA));
  2214. RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceID);
  2215. ControlData.InterfaceGuid = InterfaceGuid;
  2216. ControlData.InterfaceList = NULL;
  2217. ControlData.InterfaceListSize = 0;
  2218. if (ulFlags == CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES) {
  2219. ControlData.Flags = 0x1; // DEVICE_INTERFACE_INCLUDE_NONACTIVE (ntos\inc\pnp.h)
  2220. } else {
  2221. ControlData.Flags = 0;
  2222. }
  2223. //
  2224. // Call kernel-mode to get the device interface list size.
  2225. //
  2226. ntStatus = NtPlugPlayControl(PlugPlayControlGetInterfaceDeviceList,
  2227. &ControlData,
  2228. sizeof(ControlData));
  2229. if (NT_SUCCESS(ntStatus)) {
  2230. *pulLen = ControlData.InterfaceListSize;
  2231. } else {
  2232. Status = CR_FAILURE;
  2233. }
  2234. Clean0:
  2235. NOTHING;
  2236. } except(EXCEPTION_EXECUTE_HANDLER) {
  2237. Status = CR_FAILURE;
  2238. }
  2239. return Status;
  2240. } // PNP_GetInterfaceDeviceListSize
  2241. CONFIGRET
  2242. PNP_RegisterDeviceClassAssociation(
  2243. IN handle_t hBinding,
  2244. IN LPCWSTR pszDeviceID,
  2245. IN LPGUID InterfaceGuid,
  2246. IN LPCWSTR pszReference OPTIONAL,
  2247. OUT PWSTR pszSymLink,
  2248. IN OUT PULONG pulLength,
  2249. IN OUT PULONG pulTransferLen,
  2250. IN ULONG ulFlags
  2251. )
  2252. /*++
  2253. Routine Description:
  2254. This is the RPC server entry point for the CM_Register_Device_Interface
  2255. routine. It registers a device interface for the specified device and device
  2256. interface class, and returns the symbolic link name for the device interface.
  2257. Arguments:
  2258. hBinding RPC binding handle.
  2259. pszDeviceID Supplies the device instance string.
  2260. InterfaceGuid Supplies the interface class guid.
  2261. pszReference Optionally, supplies the reference string name.
  2262. pszSymLink Receives the symbolic link name.
  2263. pulLength Parameter passed in by caller, on entry it contains
  2264. the size, in bytes, of the buffer, on exit it contains
  2265. either the amount of data copied to the caller's buffer
  2266. (if a transfer occured) or else the size of buffer
  2267. required to hold the property data.
  2268. pulTransferLen Used by stubs, indicates how much data to copy back
  2269. into user buffer.
  2270. ulFlags Not used, must be zero.
  2271. Return Value:
  2272. If the function succeeds, the return value is CR_SUCCESS.
  2273. If the function fails, the return value is one of the following:
  2274. CR_ACCESS_DENIED,
  2275. CR_INVALID_FLAG,
  2276. CR_INVALID_POINTER, or
  2277. CR_REGISTRY_ERROR
  2278. Remarks:
  2279. The pointer passed in as the pulTransferLen argument must *NOT* be the same
  2280. as the pointer passed in for the pulLength argument.
  2281. --*/
  2282. {
  2283. CONFIGRET Status = CR_SUCCESS;
  2284. NTSTATUS ntStatus = STATUS_SUCCESS;
  2285. PLUGPLAY_CONTROL_CLASS_ASSOCIATION_DATA ControlData;
  2286. try {
  2287. //
  2288. // Verify client privilege
  2289. //
  2290. if (!VerifyClientAccess(hBinding, &gLuidLoadDriverPrivilege)) {
  2291. Status = CR_ACCESS_DENIED;
  2292. goto Clean0;
  2293. }
  2294. //
  2295. // Validate parameters
  2296. //
  2297. ASSERT(pulTransferLen != pulLength);
  2298. if (!ARGUMENT_PRESENT(InterfaceGuid) ||
  2299. !ARGUMENT_PRESENT(pszSymLink) ||
  2300. !ARGUMENT_PRESENT(pulTransferLen) ||
  2301. !ARGUMENT_PRESENT(pulLength)) {
  2302. Status = CR_INVALID_POINTER;
  2303. goto Clean0;
  2304. }
  2305. if (INVALID_FLAGS(ulFlags, 0)) {
  2306. Status = CR_INVALID_FLAG;
  2307. goto Clean0;
  2308. }
  2309. if (!IsLegalDeviceId(pszDeviceID)) {
  2310. Status = CR_INVALID_DEVNODE;
  2311. goto Clean0;
  2312. }
  2313. //
  2314. // Make sure we use no more than either what the caller specified or
  2315. // what was allocated by RPC, based on the transfer length.
  2316. //
  2317. *pulLength = min(*pulLength, *pulTransferLen);
  2318. //
  2319. // Fill in a control structure for the device list info.
  2320. //
  2321. //
  2322. // Note that InterfaceGuid was already validated above because this
  2323. // buffer is required for the PlugPlayControlDeviceClassAssociation
  2324. // control, for Registration only.
  2325. //
  2326. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_CLASS_ASSOCIATION_DATA));
  2327. RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceID);
  2328. RtlInitUnicodeString(&ControlData.Reference, pszReference);
  2329. ControlData.InterfaceGuid = InterfaceGuid;
  2330. ControlData.Register = TRUE;
  2331. ControlData.SymLink = pszSymLink;
  2332. ControlData.SymLinkLength = *pulLength;
  2333. //
  2334. // Call kernel-mode to register the device association.
  2335. //
  2336. ntStatus = NtPlugPlayControl(PlugPlayControlDeviceClassAssociation,
  2337. &ControlData,
  2338. sizeof(ControlData));
  2339. if (NT_SUCCESS(ntStatus)) {
  2340. *pulLength = ControlData.SymLinkLength;
  2341. *pulTransferLen = *pulLength;
  2342. } else if (ntStatus == STATUS_BUFFER_TOO_SMALL) {
  2343. *pulLength = ControlData.SymLinkLength;
  2344. Status = CR_BUFFER_SMALL;
  2345. } else {
  2346. *pulLength = 0;
  2347. Status = MapNtStatusToCmError(ntStatus);
  2348. }
  2349. Clean0:
  2350. //
  2351. // Initialize output parameters
  2352. //
  2353. if ((Status != CR_SUCCESS) &&
  2354. ARGUMENT_PRESENT(pszSymLink) &&
  2355. ARGUMENT_PRESENT(pulTransferLen) &&
  2356. (*pulTransferLen > 0)) {
  2357. *pszSymLink = L'\0';
  2358. *pulTransferLen = 1;
  2359. }
  2360. } except(EXCEPTION_EXECUTE_HANDLER) {
  2361. Status = CR_FAILURE;
  2362. }
  2363. return Status;
  2364. } // PNP_RegisterDeviceClassAssociation
  2365. CONFIGRET
  2366. PNP_UnregisterDeviceClassAssociation(
  2367. IN handle_t hBinding,
  2368. IN LPCWSTR pszInterfaceDevice,
  2369. IN ULONG ulFlags
  2370. )
  2371. /*++
  2372. Routine Description:
  2373. This is the RPC server entry point for the CM_Unregister_Device_Interface
  2374. routine.
  2375. Arguments:
  2376. hBinding RPC binding handle.
  2377. pszInterfaceDevice Specifies the interface device to unregister
  2378. ulFlags Not used, must be zero.
  2379. Return Value:
  2380. If the function succeeds, the return value is CR_SUCCESS.
  2381. If the function fails, the return value is one of the following:
  2382. CR_ACCESS_DENIED,
  2383. CR_DEVICE_INTERFACE_ACTIVE, or
  2384. CR_FAILURE.
  2385. --*/
  2386. {
  2387. CONFIGRET Status = CR_SUCCESS;
  2388. NTSTATUS ntStatus = STATUS_SUCCESS;
  2389. PLUGPLAY_CONTROL_CLASS_ASSOCIATION_DATA ControlData;
  2390. try {
  2391. //
  2392. // Verify client privilege
  2393. //
  2394. if (!VerifyClientAccess(hBinding, &gLuidLoadDriverPrivilege)) {
  2395. Status = CR_ACCESS_DENIED;
  2396. goto Clean0;
  2397. }
  2398. //
  2399. // Validate parameters
  2400. //
  2401. if (!ARGUMENT_PRESENT(pszInterfaceDevice)) {
  2402. Status = CR_INVALID_POINTER;
  2403. goto Clean0;
  2404. }
  2405. if (INVALID_FLAGS(ulFlags, 0)) {
  2406. Status = CR_INVALID_FLAG;
  2407. goto Clean0;
  2408. }
  2409. //
  2410. // Fill in a control structure for the device list info.
  2411. //
  2412. //
  2413. // Note that the DeviceInstance, Reference, and InterfaceGuid members
  2414. // are not required for the PlugPlayControlDeviceClassAssociation
  2415. // control, for unregistration only. Only the symbolic link name is
  2416. // required to unregister the device interface.
  2417. //
  2418. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_CLASS_ASSOCIATION_DATA));
  2419. ControlData.Register = FALSE;
  2420. ControlData.SymLink = (LPWSTR)pszInterfaceDevice;
  2421. ControlData.SymLinkLength = lstrlen(pszInterfaceDevice) + 1;
  2422. //
  2423. // Call kernel-mode to deregister the device association.
  2424. //
  2425. ntStatus = NtPlugPlayControl(PlugPlayControlDeviceClassAssociation,
  2426. &ControlData,
  2427. sizeof(ControlData));
  2428. if (!NT_SUCCESS(ntStatus)) {
  2429. if (ntStatus == STATUS_ACCESS_DENIED) {
  2430. Status = CR_DEVICE_INTERFACE_ACTIVE;
  2431. } else {
  2432. Status = MapNtStatusToCmError(ntStatus);
  2433. }
  2434. }
  2435. Clean0:
  2436. NOTHING;
  2437. } except(EXCEPTION_EXECUTE_HANDLER) {
  2438. Status = CR_FAILURE;
  2439. }
  2440. return Status;
  2441. } // PNP_UnregisterDeviceClassAssociation
  2442. //-------------------------------------------------------------------
  2443. // Private export for the Service Controller
  2444. //-------------------------------------------------------------------
  2445. CONFIGRET
  2446. DeleteServicePlugPlayRegKeys(
  2447. IN LPWSTR pszService
  2448. )
  2449. /*++
  2450. Routine Description:
  2451. This routine is called directly and privately by the Service Controller
  2452. whenever a service has been deleted. It allows the SCM to delete any Plug
  2453. and Play registry keys that may have been created for a service.
  2454. Arguments:
  2455. pszService - Specifies the name of the service.
  2456. Return Value:
  2457. Return CR_SUCCESS if the function succeeds, otherwise it returns one
  2458. of the CR_* errors.
  2459. Note:
  2460. This routine is privately exported, and is to be called only by the
  2461. Service Control Manager, during service deletion.
  2462. --*/
  2463. {
  2464. CONFIGRET Status = CR_SUCCESS;
  2465. ULONG ulSize, ulFlags, ulHardwareProfile, ulPass;
  2466. LPWSTR pDeviceList = NULL, pDeviceID;
  2467. WCHAR szParentKey[MAX_CM_PATH], szChildKey[MAX_DEVICE_ID_LEN];
  2468. BOOL RootEnumerationRequired = FALSE;
  2469. ULONG ulProblem, ulStatus;
  2470. try {
  2471. //
  2472. // validate parameters
  2473. //
  2474. if (!ARGUMENT_PRESENT(pszService)) {
  2475. Status = CR_INVALID_POINTER;
  2476. goto Clean0;
  2477. }
  2478. //
  2479. // retreive the maximum size required for a buffer to receive the list
  2480. // of devices that this service is controlling
  2481. //
  2482. Status = PNP_GetDeviceListSize(NULL,
  2483. pszService,
  2484. &ulSize,
  2485. CM_GETIDLIST_FILTER_SERVICE);
  2486. if (Status != CR_SUCCESS) {
  2487. goto Clean0;
  2488. }
  2489. pDeviceList = HeapAlloc(ghPnPHeap, 0, ulSize * sizeof(WCHAR));
  2490. if (pDeviceList == NULL) {
  2491. Status = CR_OUT_OF_MEMORY;
  2492. goto Clean0;
  2493. }
  2494. //
  2495. // retrieve the list of devices that this service is controlling, make
  2496. // sure that we don't generate one if none already exist
  2497. //
  2498. Status = PNP_GetDeviceList(NULL,
  2499. pszService,
  2500. pDeviceList,
  2501. &ulSize,
  2502. CM_GETIDLIST_FILTER_SERVICE |
  2503. CM_GETIDLIST_DONOTGENERATE);
  2504. if (Status != CR_SUCCESS) {
  2505. goto Clean0;
  2506. }
  2507. //
  2508. // delete the registry keys for each device instance for this service
  2509. //
  2510. for (pDeviceID = pDeviceList;
  2511. *pDeviceID;
  2512. pDeviceID += lstrlen(pDeviceID) + 1) {
  2513. for (ulPass = 0; ulPass < 4; ulPass++) {
  2514. //
  2515. // delete the registry keys for all hardware profiles, followed
  2516. // by the system global registry keys
  2517. //
  2518. if (ulPass == 0) {
  2519. ulFlags = CM_REGISTRY_HARDWARE | CM_REGISTRY_CONFIG;
  2520. ulHardwareProfile = 0xFFFFFFFF;
  2521. } else if (ulPass == 1) {
  2522. ulFlags = CM_REGISTRY_SOFTWARE | CM_REGISTRY_CONFIG;
  2523. ulHardwareProfile = 0xFFFFFFFF;
  2524. } else if (ulPass == 2) {
  2525. ulFlags = CM_REGISTRY_HARDWARE;
  2526. ulHardwareProfile = 0;
  2527. } else if (ulPass == 3) {
  2528. ulFlags = CM_REGISTRY_SOFTWARE;
  2529. ulHardwareProfile = 0;
  2530. }
  2531. //
  2532. // form the registry path based on the device id and the flags
  2533. //
  2534. if (GetDevNodeKeyPath(NULL,
  2535. pDeviceID,
  2536. ulFlags,
  2537. ulHardwareProfile,
  2538. szParentKey,
  2539. szChildKey) == CR_SUCCESS) {
  2540. //
  2541. // remove the specified registry key
  2542. //
  2543. PNP_DeleteRegistryKey(
  2544. NULL, // rpc binding handle (NULL)
  2545. pDeviceID, // device id
  2546. szParentKey, // parent of key to delete
  2547. szChildKey, // key to delete
  2548. ulHardwareProfile); // flags, not used
  2549. }
  2550. }
  2551. //
  2552. // Uninstall the device instance (see also PNP_UninstallDevInst).
  2553. //
  2554. //------------------------------------------------------------------
  2555. // Uninstall deletes instance key (and all subkeys) for all
  2556. // the hardware keys (this means the main Enum branch, the
  2557. // config specific keys under HKLM, and the Enum branch under
  2558. // HKCU). In the case of the user hardware keys (under HKCU),
  2559. // I delete those whether it's a phantom or not, but since
  2560. // I can't access the user key from the service side, I have
  2561. // to do that part on the client side. For the main hw Enum key
  2562. // and the config specific hw keys, I only delete them outright
  2563. // if they are phantoms. If not a phantom, then I just make the
  2564. // device instance volatile (by saving the original key, deleting
  2565. // old key, creating new volatile key and restoring the old
  2566. // contents) so at least it will go away during the next boot
  2567. //------------------------------------------------------------------
  2568. if ((GetDeviceStatus(pDeviceID, &ulStatus, &ulProblem) == CR_SUCCESS) &&
  2569. (ulStatus & DN_DRIVER_LOADED)) {
  2570. //-------------------------------------------------------------
  2571. // device is not a phantom
  2572. //-------------------------------------------------------------
  2573. if ((ulStatus & DN_ROOT_ENUMERATED) &&
  2574. !(ulStatus & DN_DISABLEABLE)) {
  2575. //
  2576. // if a device is root enumerated, but not disableable, it is not uninstallable
  2577. //
  2578. KdPrintEx((DPFLTR_PNPMGR_ID,
  2579. DBGF_REGISTRY,
  2580. "UMPNPMGR: DeleteServicePlugPlayRegKeys: "
  2581. "failed uninstall of %ws (this root device is not disableable)\n",
  2582. pDeviceID));
  2583. } else {
  2584. //
  2585. // do the volatile-copy-thing
  2586. //
  2587. KdPrintEx((DPFLTR_PNPMGR_ID,
  2588. DBGF_REGISTRY,
  2589. "UMPNPMGR: DeleteServicePlugPlayRegKeys: "
  2590. "doing volatile key thing on %ws\n",
  2591. pDeviceID));
  2592. UninstallRealDevice(pDeviceID);
  2593. }
  2594. } else {
  2595. //-------------------------------------------------------------
  2596. // device is a phantom so actually delete it
  2597. //-------------------------------------------------------------
  2598. if (UninstallPhantomDevice(pDeviceID) != CR_SUCCESS) {
  2599. continue;
  2600. }
  2601. //
  2602. // if it is a root enumerated device, we need to reenumerate the
  2603. // root (if not planning to do so already) so that the PDO will
  2604. // go away, otherwise a new device could be created and the root
  2605. // enumerator would get very confused.
  2606. //
  2607. if ((!RootEnumerationRequired) &&
  2608. (IsDeviceRootEnumerated(pDeviceID))) {
  2609. RootEnumerationRequired = TRUE;
  2610. }
  2611. }
  2612. }
  2613. //
  2614. // Now that we're done processing all devices, see if we need to
  2615. // reenumerate the root.
  2616. //
  2617. if (RootEnumerationRequired) {
  2618. //
  2619. // Reenumerate the root devnode asynchronously so that the service
  2620. // controller does not block waiting for this routine to complete!!
  2621. // (If we were processing device events at this time, the SCM would
  2622. // be blocked here and not be able to deliver any events for us.
  2623. // That would stall the event queue, preventing a synchronous device
  2624. // enumeration from completing).
  2625. //
  2626. ReenumerateDevInst(pszRegRootEnumerator,
  2627. FALSE,
  2628. CM_REENUMERATE_ASYNCHRONOUS);
  2629. }
  2630. Clean0:
  2631. NOTHING;
  2632. } except(EXCEPTION_EXECUTE_HANDLER) {
  2633. Status = CR_FAILURE;
  2634. //
  2635. // force compiler to respect statement ordering w.r.t. assignments
  2636. // for these variables...
  2637. //
  2638. pDeviceList = pDeviceList;
  2639. }
  2640. if (pDeviceList) {
  2641. HeapFree(ghPnPHeap, 0, pDeviceList);
  2642. }
  2643. return Status;
  2644. } // DeleteServicePlugPlayRegKeys
  2645. //-------------------------------------------------------------------
  2646. // Private utility routines
  2647. //-------------------------------------------------------------------
  2648. LPWSTR
  2649. MapPropertyToString(
  2650. ULONG ulProperty
  2651. )
  2652. {
  2653. switch (ulProperty) {
  2654. case CM_DRP_DEVICEDESC:
  2655. return pszRegValueDeviceDesc;
  2656. case CM_DRP_HARDWAREID:
  2657. return pszRegValueHardwareIDs;
  2658. case CM_DRP_COMPATIBLEIDS:
  2659. return pszRegValueCompatibleIDs;
  2660. case CM_DRP_SERVICE:
  2661. return pszRegValueService;
  2662. case CM_DRP_CLASS:
  2663. return pszRegValueClass;
  2664. case CM_DRP_CLASSGUID:
  2665. return pszRegValueClassGuid;
  2666. case CM_DRP_DRIVER:
  2667. return pszRegValueDriver;
  2668. case CM_DRP_CONFIGFLAGS:
  2669. return pszRegValueConfigFlags;
  2670. case CM_DRP_MFG:
  2671. return pszRegValueMfg;
  2672. case CM_DRP_FRIENDLYNAME:
  2673. return pszRegValueFriendlyName;
  2674. case CM_DRP_LOCATION_INFORMATION:
  2675. return pszRegValueLocationInformation;
  2676. case CM_DRP_CAPABILITIES:
  2677. return pszRegValueCapabilities;
  2678. case CM_DRP_UI_NUMBER:
  2679. return pszRegValueUiNumber;
  2680. case CM_DRP_UPPERFILTERS:
  2681. return pszRegValueUpperFilters;
  2682. case CM_DRP_LOWERFILTERS:
  2683. return pszRegValueLowerFilters;
  2684. case CM_DRP_SECURITY: // and CM_CRP_SECURITY
  2685. return pszRegValueSecurity;
  2686. case CM_DRP_DEVTYPE: // and CM_DRP_DEVTYPE
  2687. return pszRegValueDevType;
  2688. case CM_DRP_EXCLUSIVE: // and CM_DRP_EXCLUSIVE
  2689. return pszRegValueExclusive;
  2690. case CM_DRP_CHARACTERISTICS: // and CM_DRP_CHARACTERISTICS
  2691. return pszRegValueCharacteristics;
  2692. case CM_DRP_UI_NUMBER_DESC_FORMAT:
  2693. return pszRegValueUiNumberDescFormat;
  2694. case CM_DRP_REMOVAL_POLICY_OVERRIDE:
  2695. return pszRegValueRemovalPolicyOverride;
  2696. default:
  2697. return NULL;
  2698. }
  2699. } // MapPropertyToString
  2700. ULONG
  2701. MapPropertyToNtProperty(
  2702. ULONG ulProperty
  2703. )
  2704. {
  2705. switch (ulProperty) {
  2706. case CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME:
  2707. return PNP_PROPERTY_PDONAME;
  2708. case CM_DRP_BUSTYPEGUID:
  2709. return PNP_PROPERTY_BUSTYPEGUID;
  2710. case CM_DRP_LEGACYBUSTYPE:
  2711. return PNP_PROPERTY_LEGACYBUSTYPE;
  2712. case CM_DRP_BUSNUMBER:
  2713. return PNP_PROPERTY_BUSNUMBER;
  2714. case CM_DRP_ADDRESS:
  2715. return PNP_PROPERTY_ADDRESS;
  2716. case CM_DRP_DEVICE_POWER_DATA:
  2717. return PNP_PROPERTY_POWER_DATA;
  2718. case CM_DRP_REMOVAL_POLICY:
  2719. return PNP_PROPERTY_REMOVAL_POLICY;
  2720. case CM_DRP_REMOVAL_POLICY_HW_DEFAULT:
  2721. return PNP_PROPERTY_REMOVAL_POLICY_HARDWARE_DEFAULT;
  2722. case CM_DRP_REMOVAL_POLICY_OVERRIDE:
  2723. return PNP_PROPERTY_REMOVAL_POLICY_OVERRIDE;
  2724. case CM_DRP_INSTALL_STATE:
  2725. return PNP_PROPERTY_INSTALL_STATE;
  2726. default:
  2727. return 0;
  2728. }
  2729. } // MapPropertyToNtProperty
  2730. CONFIGRET
  2731. PNP_GetCustomDevProp(
  2732. IN handle_t hBinding,
  2733. IN LPCWSTR pDeviceID,
  2734. IN LPCWSTR CustomPropName,
  2735. OUT PULONG pulRegDataType,
  2736. OUT LPBYTE Buffer,
  2737. OUT PULONG pulTransferLen,
  2738. IN OUT PULONG pulLength,
  2739. IN ULONG ulFlags
  2740. )
  2741. /*++
  2742. Routine Description:
  2743. This is the RPC server entry point for the CM_Get_DevNode_Custom_Property
  2744. routine.
  2745. Arguments:
  2746. hBinding RPC binding handle, not used.
  2747. pDeviceID Supplies a string containing the device instance
  2748. whose property will be read from.
  2749. CustomPropName Supplies a string identifying the name of the property
  2750. (registry value entry name) to be retrieved.
  2751. pulRegDataType Supplies the address of a variable that will receive
  2752. the registry data type for this property (i.e., the REG_*
  2753. constants).
  2754. Buffer Supplies the address of the buffer that receives the
  2755. registry data. If the caller is simply retrieving the
  2756. required size, pulLength will be zero.
  2757. pulTransferLen Used by stubs, indicates how much data to copy back
  2758. into user buffer.
  2759. pulLength Parameter passed in by caller, on entry it contains
  2760. the size, in bytes, of the buffer, on exit it contains
  2761. either the amount of data copied to the caller's buffer
  2762. (if a transfer occurred) or else the size of buffer
  2763. required to hold the property data.
  2764. ulFlags May be a combination of the following values:
  2765. CM_CUSTOMDEVPROP_MERGE_MULTISZ : merge the
  2766. devnode-specific REG_SZ or REG_MULTI_SZ property (if
  2767. present) with the per-hardware-id REG_SZ or REG_MULTI_SZ
  2768. property (if present). The result will always be a
  2769. REG_MULTI_SZ.
  2770. Note: REG_EXPAND_SZ data is not merged in this manner, as
  2771. there is no way to indicate that the resultant list needs
  2772. environment variable expansion (i.e., there's no such
  2773. registry datatype as REG_EXPAND_MULTI_SZ).
  2774. Return Value:
  2775. If the function succeeds, the return value is CR_SUCCESS.
  2776. If the function fails, the return value is one of the following:
  2777. CR_INVALID_DEVNODE,
  2778. CR_REGISTRY_ERROR,
  2779. CR_BUFFER_SMALL,
  2780. CR_NO_SUCH_VALUE, or
  2781. CR_FAILURE.
  2782. Remarks:
  2783. The pointer passed in as the pulTransferLen argument must *NOT* be the same
  2784. as the pointer passed in for the pulLength argument.
  2785. --*/
  2786. {
  2787. CONFIGRET Status = CR_SUCCESS;
  2788. LONG RegStatus;
  2789. HKEY hDevKey = NULL;
  2790. HKEY hDevParamsKey = NULL;
  2791. HKEY hPerHwIdSubKey = NULL;
  2792. WCHAR PerHwIdSubkeyName[MAX_DEVNODE_ID_LEN];
  2793. ULONG RequiredSize = 0;
  2794. FILETIME CacheDate, LastUpdateTime;
  2795. DWORD RegDataType, RegDataSize;
  2796. LPBYTE PerHwIdBuffer;
  2797. DWORD PerHwIdBufferLen;
  2798. LPWSTR pCurId;
  2799. BOOL MergeMultiSzResult = FALSE;
  2800. UNREFERENCED_PARAMETER(hBinding);
  2801. try {
  2802. //
  2803. // Validate parameters
  2804. //
  2805. if (!ARGUMENT_PRESENT(pulTransferLen) ||
  2806. !ARGUMENT_PRESENT(pulLength)) {
  2807. Status = CR_INVALID_POINTER;
  2808. goto Clean0;
  2809. }
  2810. //
  2811. // We should never have both arguments pointing to the same memory...
  2812. //
  2813. ASSERT(pulTransferLen != pulLength);
  2814. //
  2815. // ...but if we do, fail the call.
  2816. //
  2817. if (pulTransferLen == pulLength) {
  2818. Status = CR_INVALID_POINTER;
  2819. goto Clean0;
  2820. }
  2821. *pulTransferLen = 0;
  2822. if (INVALID_FLAGS(ulFlags, CM_CUSTOMDEVPROP_BITS)) {
  2823. Status = CR_INVALID_FLAG;
  2824. goto Clean0;
  2825. }
  2826. if(!IsLegalDeviceId(pDeviceID)) {
  2827. Status = CR_INVALID_DEVNODE;
  2828. goto Clean0;
  2829. }
  2830. //
  2831. // First, open the device instance key. We'll then open the "Device
  2832. // Parameters" subkey off of that. We do this in two steps, because
  2833. // we're likely to need a handle to the device instance key in order
  2834. // to track down the per-hw-id property.
  2835. //
  2836. if(ERROR_SUCCESS != RegOpenKeyEx(ghEnumKey,
  2837. pDeviceID,
  2838. 0,
  2839. KEY_READ | KEY_WRITE,
  2840. &hDevKey)) {
  2841. hDevKey = NULL; // ensure hDevKey is still NULL so we
  2842. // won't erroneously try to close it.
  2843. RequiredSize = 0; // no size info for caller
  2844. Status = CR_REGISTRY_ERROR;
  2845. goto Clean0;
  2846. }
  2847. if(ERROR_SUCCESS == RegOpenKeyEx(hDevKey,
  2848. pszRegKeyDeviceParam,
  2849. 0,
  2850. KEY_READ,
  2851. &hDevParamsKey)) {
  2852. RequiredSize = *pulLength;
  2853. RegStatus = RegQueryValueEx(hDevParamsKey,
  2854. CustomPropName,
  2855. NULL,
  2856. pulRegDataType,
  2857. Buffer,
  2858. &RequiredSize
  2859. );
  2860. if(RegStatus == ERROR_SUCCESS) {
  2861. //
  2862. // We need to distinguish between the case where we succeeded
  2863. // because the caller supplied a zero-length buffer (we call it
  2864. // CR_BUFFER_SMALL) and the "real" success case.
  2865. //
  2866. if((*pulLength == 0) && (RequiredSize != 0)) {
  2867. Status = CR_BUFFER_SMALL;
  2868. }
  2869. } else {
  2870. if(RegStatus == ERROR_MORE_DATA) {
  2871. Status = CR_BUFFER_SMALL;
  2872. } else {
  2873. RequiredSize = 0;
  2874. Status = CR_NO_SUCH_VALUE;
  2875. }
  2876. }
  2877. //
  2878. // At this point, Status is one of the following:
  2879. //
  2880. // CR_SUCCESS : we found the value and our buffer was
  2881. // sufficiently-sized to hold it,
  2882. // CR_BUFFER_SMALL : we found the value and our buffer wasn't
  2883. // large enough to hold it, or
  2884. // CR_NO_SUCH_VALUE : we didn't find the value.
  2885. //
  2886. // If we found a value (whether or not our buffer was large enough
  2887. // to hold it), we're done, except for cases where the caller
  2888. // has asked us to append the per-hw-id string(s) with the
  2889. // per-devnode string(s).
  2890. //
  2891. if(Status == CR_NO_SUCH_VALUE) {
  2892. //
  2893. // No devnode-specific property, so we use the same buffer and
  2894. // length for retrieval of per-hw-id property...
  2895. //
  2896. PerHwIdBuffer = Buffer;
  2897. PerHwIdBufferLen = *pulLength;
  2898. } else {
  2899. //
  2900. // Figure out if we need to worry about appending results
  2901. // together into a multi-sz list...
  2902. //
  2903. if((ulFlags & CM_CUSTOMDEVPROP_MERGE_MULTISZ) &&
  2904. ((*pulRegDataType == REG_MULTI_SZ) || (*pulRegDataType == REG_SZ))) {
  2905. MergeMultiSzResult = TRUE;
  2906. //
  2907. // Ensure that the size of our string(s) buffer is at least
  2908. // one Unicode character. If we have a buffer of one
  2909. // character, ensure that character is a null.
  2910. //
  2911. if(RequiredSize < sizeof(WCHAR)) {
  2912. RequiredSize = sizeof(WCHAR);
  2913. if(RequiredSize > *pulLength) {
  2914. Status = CR_BUFFER_SMALL;
  2915. } else {
  2916. ASSERT(Status == CR_SUCCESS);
  2917. *(PWSTR)Buffer = L'\0';
  2918. }
  2919. }
  2920. }
  2921. if(!MergeMultiSzResult) {
  2922. //
  2923. // We're outta here!
  2924. //
  2925. if(Status == CR_SUCCESS) {
  2926. //
  2927. // We have data to transfer.
  2928. //
  2929. *pulTransferLen = RequiredSize;
  2930. }
  2931. goto Clean0;
  2932. } else {
  2933. //
  2934. // We're supposed to merge our per-devnode string(s) with
  2935. // any per-hw-id string(s) we find. Make sure our buffer
  2936. // and length reflect a properly-formatted multi-sz list,
  2937. // then setup our per-hw-id buffer info so that we'll
  2938. // append to this list later on...
  2939. //
  2940. if(Status == CR_BUFFER_SMALL) {
  2941. //
  2942. // We won't even try to retrieve any actual data from
  2943. // a per-hw-id key (all we'll get is the additional
  2944. // size requirement).
  2945. //
  2946. PerHwIdBuffer = NULL;
  2947. PerHwIdBufferLen = 0;
  2948. if(*pulRegDataType == REG_SZ) {
  2949. //
  2950. // The data we retrieved from the devnode's "Device
  2951. // Parameters" subkey was a REG_SZ. Add one
  2952. // character width to the required length to
  2953. // reflect the size of the string after conversion
  2954. // to multi-sz (unless the size is 1 character,
  2955. // indicating an empty string, which is also the
  2956. // size of an empty multi-sz list).
  2957. //
  2958. if(RequiredSize > sizeof(WCHAR)) {
  2959. RequiredSize += sizeof(WCHAR);
  2960. }
  2961. *pulRegDataType = REG_MULTI_SZ;
  2962. }
  2963. } else {
  2964. //
  2965. // We actually retrieved a REG_SZ or REG_MULTI_SZ value
  2966. // into our caller-supplied buffer. Ensure that the
  2967. // string(s) contained therein is(are) in proper
  2968. // multi-sz format, and that the size is correct.
  2969. //
  2970. if(*pulRegDataType == REG_SZ) {
  2971. RegDataSize = lstrlen((LPWSTR)Buffer) + 1;
  2972. if((RegDataSize * sizeof(WCHAR)) > RequiredSize) {
  2973. //
  2974. // The string we retrieved is longer than the
  2975. // buffer--this indicates the string wasn't
  2976. // properly null-terminated. Discard this
  2977. // string.
  2978. //
  2979. Status = CR_NO_SUCH_VALUE;
  2980. RequiredSize = 0;
  2981. PerHwIdBuffer = Buffer;
  2982. PerHwIdBufferLen = *pulLength;
  2983. } else {
  2984. //
  2985. // The string was large enough to fit in the
  2986. // buffer. Add another null character to
  2987. // turn this into a multi-sz (if there's room).
  2988. // (Again, we don't need to do increase the
  2989. // length if this is an empty string.)
  2990. //
  2991. if(RegDataSize == 1) {
  2992. RequiredSize = sizeof(WCHAR);
  2993. PerHwIdBuffer = Buffer;
  2994. PerHwIdBufferLen = *pulLength;
  2995. //
  2996. // Assuming no per-hw-id data is found
  2997. // later, this is the size of the data
  2998. // we'll be handing back to the caller.
  2999. //
  3000. *pulTransferLen = RequiredSize;
  3001. } else {
  3002. RequiredSize = (RegDataSize + 1) * sizeof(WCHAR);
  3003. if(RequiredSize > *pulLength) {
  3004. //
  3005. // Oops--while the string fits nicely into
  3006. // the caller-supplied buffer, adding an
  3007. // extra null char pushes it over the limit.
  3008. // Turn this into a CR_BUFFER_SMALL case.
  3009. //
  3010. Status = CR_BUFFER_SMALL;
  3011. PerHwIdBuffer = NULL;
  3012. PerHwIdBufferLen = 0;
  3013. } else {
  3014. //
  3015. // We've got room to add the extra null
  3016. // character. Do so, and setup our
  3017. // per-hw-id buffer to start at the end of
  3018. // our existing (single string) list...
  3019. //
  3020. PerHwIdBuffer =
  3021. (LPBYTE)((LPWSTR)Buffer + RegDataSize);
  3022. PerHwIdBufferLen =
  3023. *pulLength - (RegDataSize * sizeof(WCHAR));
  3024. *((LPWSTR)PerHwIdBuffer) = L'\0';
  3025. //
  3026. // Assuming no per-hw-id data is found
  3027. // later, this is the size of the data
  3028. // we'll be handing back to the caller.
  3029. //
  3030. *pulTransferLen = RequiredSize;
  3031. }
  3032. }
  3033. *pulRegDataType = REG_MULTI_SZ;
  3034. }
  3035. } else {
  3036. //
  3037. // We retrieved a multi-sz list. Step through it
  3038. // to find the end of the list.
  3039. //
  3040. RegDataSize = 0;
  3041. for(pCurId = (LPWSTR)Buffer;
  3042. *pCurId;
  3043. pCurId = (LPWSTR)(Buffer + RegDataSize)) {
  3044. RegDataSize +=
  3045. (lstrlen(pCurId) + 1) * sizeof(WCHAR);
  3046. if(RegDataSize < RequiredSize) {
  3047. //
  3048. // This string fits in the buffer, and
  3049. // there's still space left over (i.e., for
  3050. // at least a terminating null). Move on
  3051. // to the next string in the list.
  3052. //
  3053. continue;
  3054. } else if(RegDataSize > RequiredSize) {
  3055. //
  3056. // This string extends past the end of the
  3057. // buffer, indicating that it wasn't
  3058. // properly null-terminated. This could've
  3059. // caused an exception, in which case we'd
  3060. // have discarded any contents of this
  3061. // value. For consistency, we'll discard
  3062. // the contents anyway. (Note: a multi-sz
  3063. // list that simply ommitted the final
  3064. // terminating NULL will not fall into this
  3065. // category--we deal with that correctly
  3066. // and "fix it up".)
  3067. //
  3068. Status = CR_NO_SUCH_VALUE;
  3069. RequiredSize = 0;
  3070. PerHwIdBuffer = Buffer;
  3071. PerHwIdBufferLen = *pulLength;
  3072. break;
  3073. } else {
  3074. //
  3075. // This string exactly fits into the
  3076. // remaining buffer space, indicating that
  3077. // the multi-sz list wasn't properly
  3078. // double-null terminated. We'll go ahead
  3079. // and do that now...
  3080. //
  3081. RequiredSize = RegDataSize + sizeof(WCHAR);
  3082. if(RequiredSize > *pulLength) {
  3083. //
  3084. // Oops--while the string fits nicely
  3085. // into the caller-supplied buffer,
  3086. // adding an extra null char pushes it
  3087. // over the limit. Turn this into a
  3088. // CR_BUFFER_SMALL case.
  3089. //
  3090. Status = CR_BUFFER_SMALL;
  3091. PerHwIdBuffer = NULL;
  3092. PerHwIdBufferLen = 0;
  3093. } else {
  3094. //
  3095. // We've got room to add the extra null
  3096. // character. Do so, and setup our
  3097. // per-hw-id buffer to start at the end
  3098. // of our existing list...
  3099. //
  3100. PerHwIdBuffer = Buffer + RegDataSize;
  3101. PerHwIdBufferLen =
  3102. *pulLength - RegDataSize;
  3103. *((LPWSTR)PerHwIdBuffer) = L'\0';
  3104. //
  3105. // Assuming no per-hw-id data is found
  3106. // later, this is the size of the data
  3107. // we'll be handing back to the caller.
  3108. //
  3109. *pulTransferLen = RequiredSize;
  3110. }
  3111. //
  3112. // We've reached the end of the list, so we
  3113. // can break out of the loop.
  3114. //
  3115. break;
  3116. }
  3117. }
  3118. //
  3119. // We've now processed all (valid) strings in the
  3120. // multi-sz list we retrieved. If there was a
  3121. // problem (either unterminated string or
  3122. // unterminated list), we fixed that up (and
  3123. // adjusted RequiredSize accordingly). However,
  3124. // if the list was valid, we need to compute
  3125. // RequiredSize (e.g., the buffer might've been
  3126. // larger than the multi-sz list).
  3127. //
  3128. // We can recognize a properly-formatted multi-sz
  3129. // list, because that's the only time we'd have
  3130. // exited the loop with pCurId pointing to a null
  3131. // character...
  3132. //
  3133. if(!*pCurId) {
  3134. ASSERT(RequiredSize >= (RegDataSize + sizeof(WCHAR)));
  3135. RequiredSize = RegDataSize + sizeof(WCHAR);
  3136. PerHwIdBuffer = Buffer + RegDataSize;
  3137. PerHwIdBufferLen = *pulLength - RegDataSize;
  3138. //
  3139. // Assuming no per-hw-id data is found later,
  3140. // this is the size of the data we'll be
  3141. // handing back to the caller.
  3142. //
  3143. *pulTransferLen = RequiredSize;
  3144. }
  3145. }
  3146. }
  3147. }
  3148. }
  3149. } else {
  3150. //
  3151. // We couldn't open the devnode's "Device Parameters" subkey.
  3152. // Ensure hDevParamsKey is still NULL so we won't erroneously try
  3153. // to close it.
  3154. //
  3155. hDevParamsKey = NULL;
  3156. //
  3157. // Setup our pointer for retrieval of per-hw-id value...
  3158. //
  3159. PerHwIdBuffer = Buffer;
  3160. PerHwIdBufferLen = *pulLength;
  3161. //
  3162. // Setup our default return values in case no per-hw-id data is
  3163. // found...
  3164. //
  3165. Status = CR_NO_SUCH_VALUE;
  3166. RequiredSize = 0;
  3167. }
  3168. //
  3169. // From this point on use PerHwIdBuffer/PerHwIdBufferLen instead of
  3170. // caller-supplied Buffer/pulLength, since we may be appending results
  3171. // to those retrieved from the devnode's "Device Parameters" subkey...
  3172. //
  3173. //
  3174. // If we get to here, then we need to go look for the value under
  3175. // the appropriate per-hw-id registry key. First, figure out whether
  3176. // the per-hw-id information has changed since we last cached the
  3177. // most appropriate key.
  3178. //
  3179. RegDataSize = sizeof(LastUpdateTime);
  3180. if((ERROR_SUCCESS != RegQueryValueEx(ghPerHwIdKey,
  3181. pszRegValueLastUpdateTime,
  3182. NULL,
  3183. &RegDataType,
  3184. (PBYTE)&LastUpdateTime,
  3185. &RegDataSize))
  3186. || (RegDataType != REG_BINARY)
  3187. || (RegDataSize != sizeof(FILETIME))) {
  3188. //
  3189. // We can't ascertain when (or even if) the per-hw-id database was
  3190. // last populated. At this point, we bail with whatever status we
  3191. // had after our attempt at retrieving the per-devnode property.
  3192. //
  3193. goto Clean0;
  3194. }
  3195. //
  3196. // (RegDataSize is already set appropriately, no need to initialize it
  3197. // again)
  3198. //
  3199. if(ERROR_SUCCESS == RegQueryValueEx(hDevKey,
  3200. pszRegValueCustomPropertyCacheDate,
  3201. NULL,
  3202. &RegDataType,
  3203. (PBYTE)&CacheDate,
  3204. &RegDataSize)) {
  3205. //
  3206. // Just to be extra paranoid...
  3207. //
  3208. if((RegDataType != REG_BINARY) || (RegDataSize != sizeof(FILETIME))) {
  3209. ZeroMemory(&CacheDate, sizeof(CacheDate));
  3210. }
  3211. } else {
  3212. ZeroMemory(&CacheDate, sizeof(CacheDate));
  3213. }
  3214. if(CompareFileTime(&CacheDate, &LastUpdateTime) == 0) {
  3215. //
  3216. // The Per-Hw-Id database hasn't been updated since we cached away
  3217. // the most-appropriate hardware id subkey. We can now use this
  3218. // subkey to see if there's a per-hw-id value entry contained
  3219. // therein for the requested property.
  3220. //
  3221. RegDataSize = sizeof(PerHwIdSubkeyName);
  3222. if(ERROR_SUCCESS != RegQueryValueEx(hDevKey,
  3223. pszRegValueCustomPropertyHwIdKey,
  3224. NULL,
  3225. &RegDataType,
  3226. (PBYTE)PerHwIdSubkeyName,
  3227. &RegDataSize)) {
  3228. //
  3229. // The value entry wasn't present, indicating there is no
  3230. // applicable per-hw-id key.
  3231. //
  3232. goto Clean0;
  3233. } else if(RegDataType != REG_SZ) {
  3234. //
  3235. // The data isn't a REG_SZ, like we expected. This should never
  3236. // happen, but if it does, go ahead and re-assess the key we
  3237. // should be using.
  3238. //
  3239. *PerHwIdSubkeyName = L'\0';
  3240. } else {
  3241. //
  3242. // We have a per-hw-id subkey to use. Go ahead and attempt to
  3243. // open it up here. If we find someone has tampered with the
  3244. // database and deleted this subkey, then we can at least go
  3245. // re-evaluate below to see if we can find a new key that's
  3246. // applicable for this devnode.
  3247. //
  3248. if(ERROR_SUCCESS != RegOpenKeyEx(ghPerHwIdKey,
  3249. PerHwIdSubkeyName,
  3250. 0,
  3251. KEY_READ,
  3252. &hPerHwIdSubKey)) {
  3253. hPerHwIdSubKey = NULL;
  3254. *PerHwIdSubkeyName = L'\0';
  3255. }
  3256. }
  3257. } else {
  3258. //
  3259. // Per-Hw-Id database has been updated since we last cached away
  3260. // our custom property default key. (Note: The only time CacheDate
  3261. // could be _newer than_ LastUpdateTime would be when a previous
  3262. // update was (re-)applied to the per-hw-id database. In this case,
  3263. // we'd want to re-assess the key we're using, since we always want
  3264. // to be exactly in-sync with the current state of the database.
  3265. //
  3266. *PerHwIdSubkeyName = L'\0';
  3267. }
  3268. if(!(*PerHwIdSubkeyName)) {
  3269. //
  3270. // We need to look for a (new) per-hw-id key from which to retrieve
  3271. // properties applicable for this device.
  3272. //
  3273. hPerHwIdSubKey = FindMostAppropriatePerHwIdSubkey(hDevKey,
  3274. KEY_READ,
  3275. PerHwIdSubkeyName,
  3276. &RegDataSize
  3277. );
  3278. if(hPerHwIdSubKey) {
  3279. RegStatus = RegSetValueEx(hDevKey,
  3280. pszRegValueCustomPropertyHwIdKey,
  3281. 0,
  3282. REG_SZ,
  3283. (PBYTE)PerHwIdSubkeyName,
  3284. RegDataSize * sizeof(WCHAR) // need size in bytes
  3285. );
  3286. } else {
  3287. RegStatus = RegDeleteKey(hDevKey,
  3288. pszRegValueCustomPropertyHwIdKey
  3289. );
  3290. }
  3291. if(RegStatus == ERROR_SUCCESS) {
  3292. //
  3293. // We successfully updated the cached per-hw-id key name. Now
  3294. // update the CustomPropertyCacheDate to reflect the date
  3295. // associated with the per-hw-id database.
  3296. //
  3297. RegSetValueEx(hDevKey,
  3298. pszRegValueCustomPropertyCacheDate,
  3299. 0,
  3300. REG_BINARY,
  3301. (PBYTE)&LastUpdateTime,
  3302. sizeof(LastUpdateTime)
  3303. );
  3304. }
  3305. if(!hPerHwIdSubKey) {
  3306. //
  3307. // We couldn't find an applicable per-hw-id key for this
  3308. // devnode.
  3309. //
  3310. goto Clean0;
  3311. }
  3312. }
  3313. //
  3314. // If we get to here, we have a handle to the per-hw-id subkey from
  3315. // which we can query the requested property.
  3316. //
  3317. RegDataSize = PerHwIdBufferLen; // remember buffer size prior to call
  3318. RegStatus = RegQueryValueEx(hPerHwIdSubKey,
  3319. CustomPropName,
  3320. NULL,
  3321. &RegDataType,
  3322. PerHwIdBuffer,
  3323. &PerHwIdBufferLen
  3324. );
  3325. if(RegStatus == ERROR_SUCCESS) {
  3326. //
  3327. // Again, we need to distinguish between the case where we
  3328. // succeeded because we supplied a zero-length buffer (we call it
  3329. // CR_BUFFER_SMALL) and the "real" success case.
  3330. //
  3331. if(RegDataSize == 0) {
  3332. if(PerHwIdBufferLen != 0) {
  3333. Status = CR_BUFFER_SMALL;
  3334. } else if(MergeMultiSzResult) {
  3335. //
  3336. // We already have the multi-sz results we retrieved from
  3337. // the devnode's "Device Parameters" subkey ready to return
  3338. // to the caller...
  3339. //
  3340. ASSERT(*pulRegDataType == REG_MULTI_SZ);
  3341. ASSERT((Status == CR_SUCCESS) || (Status == CR_BUFFER_SMALL));
  3342. ASSERT(RequiredSize >= sizeof(WCHAR));
  3343. ASSERT((Status != CR_SUCCESS) || (*pulTransferLen >= sizeof(WCHAR)));
  3344. goto Clean0;
  3345. }
  3346. } else {
  3347. //
  3348. // Our success was genuine.
  3349. //
  3350. Status = CR_SUCCESS;
  3351. }
  3352. //
  3353. // It's possible that we're supposed to be merging results into a
  3354. // multi-sz list, but didn't find a value under the devnode's
  3355. // "Device Parameters" subkey. Now that we have found a value
  3356. // under the per-hw-id subkey, we need to ensure the data returned
  3357. // is in multi-sz format.
  3358. //
  3359. if(!MergeMultiSzResult && (RequiredSize == 0)) {
  3360. if((ulFlags & CM_CUSTOMDEVPROP_MERGE_MULTISZ) &&
  3361. ((RegDataType == REG_MULTI_SZ) || (RegDataType == REG_SZ))) {
  3362. MergeMultiSzResult = TRUE;
  3363. *pulRegDataType = REG_MULTI_SZ;
  3364. RequiredSize = sizeof(WCHAR);
  3365. if(RequiredSize > *pulLength) {
  3366. Status = CR_BUFFER_SMALL;
  3367. }
  3368. }
  3369. }
  3370. } else {
  3371. if(RegStatus == ERROR_MORE_DATA) {
  3372. Status = CR_BUFFER_SMALL;
  3373. } else {
  3374. //
  3375. // If we were merging results into our multi-sz list, ensure
  3376. // that our list-terminating null didn't get blown away.
  3377. //
  3378. if(MergeMultiSzResult) {
  3379. if(RegDataSize != 0) {
  3380. *((LPWSTR)PerHwIdBuffer) = L'\0';
  3381. }
  3382. //
  3383. // We already have the multi-sz results we retrieved from
  3384. // the devnode's "Device Parameters" subkey ready to return
  3385. // to the caller...
  3386. //
  3387. ASSERT(*pulRegDataType == REG_MULTI_SZ);
  3388. ASSERT((Status == CR_SUCCESS) || (Status == CR_BUFFER_SMALL));
  3389. ASSERT(RequiredSize >= sizeof(WCHAR));
  3390. ASSERT((Status != CR_SUCCESS) || (*pulTransferLen >= sizeof(WCHAR)));
  3391. } else {
  3392. ASSERT(Status == CR_NO_SUCH_VALUE);
  3393. ASSERT(*pulTransferLen == 0);
  3394. }
  3395. goto Clean0;
  3396. }
  3397. }
  3398. if(!MergeMultiSzResult) {
  3399. *pulRegDataType = RegDataType;
  3400. RequiredSize = PerHwIdBufferLen;
  3401. if(Status == CR_SUCCESS) {
  3402. //
  3403. // We have data to transfer.
  3404. //
  3405. *pulTransferLen = RequiredSize;
  3406. }
  3407. } else {
  3408. ASSERT(*pulRegDataType == REG_MULTI_SZ);
  3409. ASSERT((Status == CR_SUCCESS) || (Status == CR_BUFFER_SMALL));
  3410. ASSERT(RequiredSize >= sizeof(WCHAR));
  3411. //
  3412. // Unless the buffer size we retrieved is greater than one Unicode
  3413. // character, it isn't going to affect the resultant size of our
  3414. // multi-sz list.
  3415. //
  3416. if(PerHwIdBufferLen <= sizeof(WCHAR)) {
  3417. ASSERT((Status != CR_BUFFER_SMALL) || (*pulTransferLen == 0));
  3418. goto Clean0;
  3419. }
  3420. if(Status == CR_BUFFER_SMALL) {
  3421. //
  3422. // We might've previously believed that we could return data to
  3423. // the caller (e.g., because the data retrieved from the
  3424. // devnode's "Device Parameters" subkey fit into our buffer.
  3425. // Now that we see the data isn't going to fit, we need to
  3426. // ensure that *pulTransferLen is zero to indicate no data is
  3427. // being returned.
  3428. //
  3429. *pulTransferLen = 0;
  3430. if(RegDataType == REG_MULTI_SZ) {
  3431. //
  3432. // Just want the lengths of the string(s) plus
  3433. // their terminating nulls, excluding list-
  3434. // terminating null char.
  3435. //
  3436. RequiredSize += (PerHwIdBufferLen - sizeof(WCHAR));
  3437. } else if(RegDataType == REG_SZ) {
  3438. //
  3439. // We can just add the size of this string into our
  3440. // total requirement (unless it's an empty string,
  3441. // in which case we don't need to do anything at
  3442. // all).
  3443. //
  3444. RequiredSize += PerHwIdBufferLen;
  3445. } else {
  3446. //
  3447. // per-hw-id data wasn't a REG_SZ or REG_MULTI_SZ, so
  3448. // ignore it.
  3449. //
  3450. goto Clean0;
  3451. }
  3452. } else {
  3453. //
  3454. // We succeeded in retrieving more data into our multi-sz list.
  3455. // If the data we retrieved is multi-sz, then we don't have any
  3456. // additional work to do. However, if we retrieved a simple
  3457. // REG_SZ, then we need to find the end of the string, and add
  3458. // a second list-terminating null.
  3459. //
  3460. if(RegDataType == REG_MULTI_SZ) {
  3461. RequiredSize += (PerHwIdBufferLen - sizeof(WCHAR));
  3462. } else if(RegDataType == REG_SZ) {
  3463. RegDataSize = lstrlen((LPWSTR)PerHwIdBuffer) + 1;
  3464. if((RegDataSize == 1) ||
  3465. ((RegDataSize * sizeof(WCHAR)) > PerHwIdBufferLen)) {
  3466. //
  3467. // The string we retrieved is either (a) empty or
  3468. // (b) longer than the buffer (the latter indicating
  3469. // that the string wasn't properly null-terminated).
  3470. // In either case, we don't want to append anything to
  3471. // our existing result, but we do need to ensure our
  3472. // list-terminating null character is still there...
  3473. //
  3474. *((LPWSTR)PerHwIdBuffer) = L'\0';
  3475. } else {
  3476. //
  3477. // Compute total size requirement..
  3478. //
  3479. RequiredSize += (RegDataSize * sizeof(WCHAR));
  3480. if(RequiredSize > *pulLength) {
  3481. //
  3482. // Adding the list-terminating null character
  3483. // pushed us over the size of the caller-
  3484. // supplied buffer. :-(
  3485. //
  3486. Status = CR_BUFFER_SMALL;
  3487. *pulTransferLen = 0;
  3488. goto Clean0;
  3489. } else {
  3490. //
  3491. // Add list-terminating null character...
  3492. //
  3493. *((LPWSTR)PerHwIdBuffer + RegDataSize) = L'\0';
  3494. }
  3495. }
  3496. } else {
  3497. //
  3498. // per-hw-id data wasn't a REG_SZ or a REG_MULTI_SZ, so
  3499. // ignore it. (Make sure, though, that we still have our
  3500. // final terminating null character.)
  3501. //
  3502. *((LPWSTR)PerHwIdBuffer) = L'\0';
  3503. }
  3504. *pulTransferLen = RequiredSize;
  3505. }
  3506. }
  3507. Clean0:
  3508. if (ARGUMENT_PRESENT(pulLength)) {
  3509. *pulLength = RequiredSize;
  3510. }
  3511. } except(EXCEPTION_EXECUTE_HANDLER) {
  3512. Status = CR_FAILURE;
  3513. //
  3514. // force compiler to respect statement ordering w.r.t. assignments
  3515. // for these variables...
  3516. //
  3517. hDevKey = hDevKey;
  3518. hDevParamsKey = hDevParamsKey;
  3519. hPerHwIdSubKey = hPerHwIdSubKey;
  3520. }
  3521. if(hDevKey != NULL) {
  3522. RegCloseKey(hDevKey);
  3523. }
  3524. if(hDevParamsKey != NULL) {
  3525. RegCloseKey(hDevParamsKey);
  3526. }
  3527. if(hPerHwIdSubKey != NULL) {
  3528. RegCloseKey(hPerHwIdSubKey);
  3529. }
  3530. return Status;
  3531. } // PNP_GetCustomDevProp
  3532. HKEY
  3533. FindMostAppropriatePerHwIdSubkey(
  3534. IN HKEY hDevKey,
  3535. IN REGSAM samDesired,
  3536. OUT LPWSTR PerHwIdSubkeyName,
  3537. OUT LPDWORD PerHwIdSubkeyLen
  3538. )
  3539. /*++
  3540. Routine Description:
  3541. This routine finds the subkey in the per-hw-id database that is most
  3542. appropriate for the device whose instance key was passed as input. This
  3543. determination is made by taking each of the device's hardware and
  3544. compatible ids, in turn, and forming a subkey name by replacing backslashes
  3545. (\) with hashes (#). An attempt is made to open that subkey under the
  3546. per-hw-id key, and the first such id to succeed, if any, is the most
  3547. appropriate (i.e., most-specific) database entry.
  3548. Note: we must consider both hardware and compatible ids, because some buses
  3549. (such as PCI) may shift hardware ids down into the compatible id list under
  3550. certain circumstances (e.g., PCI\VENxxxxDEVyyyy gets moved into the
  3551. compatible list in the presence of subsys info).
  3552. Arguments:
  3553. hDevKey Supplies a handle to the device instance key for whom the
  3554. most-appropriate per-hw-id subkey is to be ascertained.
  3555. samDesired Supplies an access mask indicating the desired access
  3556. rights to the per-hw-id key being returned.
  3557. PerHwIdSubkeyName Supplies a buffer (that must be at least
  3558. MAX_DEVNODE_ID_LEN characters in length) that, upon
  3559. success, receives the most-appropriate per-hw-id subkey
  3560. name.
  3561. PerHwIdSubkeyLen Supplies the address of a variable that, upon successful
  3562. return, receives the length of the subkey name (in
  3563. characters), including terminating NULL, stored into the
  3564. PerHwIdSubkeyName buffer.
  3565. Return Value:
  3566. If the function succeeds, the return value is a handle to the most-
  3567. appropriate per-hw-id subkey.
  3568. If the function fails, the return value is NULL.
  3569. --*/
  3570. {
  3571. DWORD i;
  3572. DWORD RegDataType;
  3573. PWCHAR IdList;
  3574. HKEY hPerHwIdSubkey;
  3575. PWSTR pCurId, pSrcChar, pDestChar;
  3576. DWORD CurIdLen;
  3577. DWORD idSize;
  3578. WCHAR ids[REGSTR_VAL_MAX_HCID_LEN];
  3579. //
  3580. // Note: we don't need to use structured exception handling in this
  3581. // routine, since if we crash here (e.g., due to retrieval of a bogus
  3582. // hardware or compatible id list), we won't leak any resource. Thus, the
  3583. // caller's try/except is sufficient.
  3584. //
  3585. //
  3586. // First process the hardware id list, and if no appropriate match
  3587. // found there, then examine the compatible id list.
  3588. //
  3589. for(i = 0; i < 2; i++) {
  3590. idSize = sizeof(ids);
  3591. if((ERROR_SUCCESS != RegQueryValueEx(hDevKey,
  3592. (i ? pszRegValueCompatibleIDs
  3593. : pszRegValueHardwareIDs),
  3594. NULL,
  3595. &RegDataType,
  3596. (PBYTE)ids,
  3597. &idSize))
  3598. || (RegDataType != REG_MULTI_SZ)) {
  3599. //
  3600. // Missing or invalid id list--bail now.
  3601. //
  3602. return NULL;
  3603. }
  3604. IdList = ids;
  3605. //
  3606. // Now iterate through each id in our list, trying to open each one
  3607. // in turn under the per-hw-id database key.
  3608. //
  3609. for(pCurId = IdList; *pCurId; pCurId += CurIdLen) {
  3610. CurIdLen = lstrlen(pCurId) + 1;
  3611. if(CurIdLen > MAX_DEVNODE_ID_LEN) {
  3612. //
  3613. // Bogus id in the list--skip it.
  3614. //
  3615. continue;
  3616. }
  3617. //
  3618. // Transfer id into our subkey name buffer, converting path
  3619. // separator characters ('\') to hashes ('#').
  3620. //
  3621. pSrcChar = pCurId;
  3622. pDestChar = PerHwIdSubkeyName;
  3623. do {
  3624. *pDestChar = (*pSrcChar != L'\\') ? *pSrcChar : L'#';
  3625. pDestChar++;
  3626. } while(*(pSrcChar++));
  3627. if(ERROR_SUCCESS == RegOpenKeyEx(ghPerHwIdKey,
  3628. PerHwIdSubkeyName,
  3629. 0,
  3630. samDesired,
  3631. &hPerHwIdSubkey)) {
  3632. //
  3633. // We've found our key!
  3634. //
  3635. *PerHwIdSubkeyLen = CurIdLen;
  3636. return hPerHwIdSubkey;
  3637. }
  3638. }
  3639. }
  3640. //
  3641. // If we get to here, we didn't find an appropriate per-hw-id subkey to
  3642. // return to the caller.
  3643. //
  3644. return NULL;
  3645. }