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

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