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

1494 lines
44 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. geninst.c
  5. Abstract:
  6. This modules contains routines to implement GenInstall of an inf section.
  7. This is based on the code from the setupapi. Currently, it only supports
  8. a subset of GenInstall functionality i.e AddReg and DelReg and BitReg.
  9. Author:
  10. Santosh Jodh (santoshj) 08-Aug-1998
  11. Environment:
  12. Kernel mode.
  13. Revision History:
  14. --*/
  15. #include "cmp.h"
  16. #include "stdlib.h"
  17. #include "parseini.h"
  18. #include "geninst.h"
  19. typedef
  20. BOOLEAN
  21. (* PFN_INFRULE)(
  22. IN PVOID InfHandle,
  23. IN PCHAR Section,
  24. IN PVOID RefData
  25. );
  26. typedef
  27. BOOLEAN
  28. (* PFN_REGLINE)(
  29. IN PVOID InfHandle,
  30. IN PCHAR Section,
  31. IN ULONG LineIndex
  32. );
  33. BOOLEAN
  34. CmpProcessReg(
  35. IN PVOID InfHandle,
  36. IN PCHAR Section,
  37. IN PVOID RefData
  38. );
  39. NTSTATUS
  40. CmpProcessAddRegLine(
  41. IN PVOID InfHandle,
  42. IN PCHAR Section,
  43. IN ULONG LineIndex
  44. );
  45. NTSTATUS
  46. CmpProcessDelRegLine(
  47. IN PVOID InfHandle,
  48. IN PCHAR Section,
  49. IN ULONG LineIndex
  50. );
  51. NTSTATUS
  52. CmpProcessBitRegLine(
  53. IN PVOID InfHandle,
  54. IN PCHAR Section,
  55. IN ULONG LineIndex
  56. );
  57. NTSTATUS
  58. CmpGetAddRegInfData(
  59. IN PVOID InfHandle,
  60. IN PCHAR Section,
  61. IN ULONG LineIndex,
  62. IN ULONG ValueIndex,
  63. IN ULONG ValueType,
  64. OUT PVOID *Data,
  65. OUT PULONG DataSize
  66. );
  67. NTSTATUS
  68. CmpOpenRegKey(
  69. IN OUT PHANDLE Key,
  70. IN OUT PULONG Disposition,
  71. IN PCHAR Root,
  72. IN PCHAR SubKey,
  73. IN ULONG DesiredAccess,
  74. IN BOOLEAN Create
  75. );
  76. NTSTATUS
  77. CmpAppendStringToMultiSz(
  78. IN HANDLE Key,
  79. IN PCHAR ValueName,
  80. IN OUT PVOID *Data,
  81. IN OUT PULONG DataSize
  82. );
  83. //
  84. // Copied from setupapi.h
  85. //
  86. // Flags for AddReg section lines in INF. The corresponding value
  87. // is <ValueType> in the AddReg line format given below:
  88. //
  89. // <RegRootString>,<SubKey>,<ValueName>,<ValueType>,<Value>...
  90. //
  91. // The low word contains basic flags concerning the general data type
  92. // and AddReg action. The high word contains values that more specifically
  93. // identify the data type of the registry value. The high word is ignored
  94. // by the 16-bit Windows 95 SETUPX APIs.
  95. //
  96. #define FLG_ADDREG_BINVALUETYPE ( 0x00000001 )
  97. #define FLG_ADDREG_NOCLOBBER ( 0x00000002 )
  98. #define FLG_ADDREG_DELVAL ( 0x00000004 )
  99. #define FLG_ADDREG_APPEND ( 0x00000008 ) // Currently supported only
  100. // for REG_MULTI_SZ values.
  101. #define FLG_ADDREG_KEYONLY ( 0x00000010 ) // Just create the key, ignore value
  102. #define FLG_ADDREG_OVERWRITEONLY ( 0x00000020 ) // Set only if value already exists
  103. #define FLG_ADDREG_TYPE_MASK ( 0xFFFF0000 | FLG_ADDREG_BINVALUETYPE )
  104. #define FLG_ADDREG_TYPE_SZ ( 0x00000000 )
  105. #define FLG_ADDREG_TYPE_MULTI_SZ ( 0x00010000 )
  106. #define FLG_ADDREG_TYPE_EXPAND_SZ ( 0x00020000 )
  107. #define FLG_ADDREG_TYPE_BINARY ( 0x00000000 | FLG_ADDREG_BINVALUETYPE )
  108. #define FLG_ADDREG_TYPE_DWORD ( 0x00010000 | FLG_ADDREG_BINVALUETYPE )
  109. #define FLG_ADDREG_TYPE_NONE ( 0x00020000 | FLG_ADDREG_BINVALUETYPE )
  110. #define FLG_BITREG_CLEAR ( 0x00000000 )
  111. #define FLG_BITREG_SET ( 0x00000001 )
  112. #define FLG_BITREG_TYPE_BINARY ( 0x00000000 )
  113. #define FLG_BITREG_TYPE_DWORD ( 0x00000002 )
  114. //
  115. // We currently only support AddReg and DelReg sections.
  116. //
  117. #define NUM_OF_INF_RULES 3
  118. //
  119. // GenInstall methods we support.
  120. //
  121. #ifdef ALLOC_DATA_PRAGMA
  122. #pragma const_seg("INITCONST")
  123. #endif
  124. struct {
  125. PCHAR Name;
  126. PFN_INFRULE Action;
  127. PVOID RefData;
  128. } const gInfRuleTable[NUM_OF_INF_RULES] =
  129. {
  130. {"AddReg", CmpProcessReg, CmpProcessAddRegLine},
  131. {"DelReg", CmpProcessReg, CmpProcessDelRegLine},
  132. {"BitReg", CmpProcessReg, CmpProcessBitRegLine}
  133. };
  134. static const UNICODE_STRING NullString = {0, 1, L""};
  135. #ifdef ALLOC_PRAGMA
  136. #pragma alloc_text(INIT,CmpAppendStringToMultiSz)
  137. #pragma alloc_text(INIT,CmpOpenRegKey)
  138. #pragma alloc_text(INIT,CmpGetAddRegInfData)
  139. #pragma alloc_text(INIT,CmpProcessReg)
  140. #pragma alloc_text(INIT,CmpProcessAddRegLine)
  141. #pragma alloc_text(INIT,CmpProcessDelRegLine)
  142. #pragma alloc_text(INIT,CmpProcessBitRegLine)
  143. #pragma alloc_text(INIT,CmpGenInstall)
  144. #endif
  145. BOOLEAN
  146. CmpGenInstall(
  147. IN PVOID InfHandle,
  148. IN PCHAR Section
  149. )
  150. /*++
  151. Routine Description:
  152. This routine does a GenInstall of the section in the inf.
  153. Input Parameters:
  154. InfHandle - Handle to the inf to be read.
  155. Section - Name of the section to be read.
  156. Return Value:
  157. TRUE iff the entire section was processed successfully.
  158. --*/
  159. {
  160. ULONG ruleNumber;
  161. ULONG i;
  162. PCHAR ruleName;
  163. PCHAR regSection;
  164. BOOLEAN result = FALSE;
  165. if (CmpSearchInfSection(InfHandle, Section))
  166. {
  167. //
  168. // Go through all the rules in the section and try to process
  169. // each of them.
  170. //
  171. for ( ruleNumber = 0;
  172. ruleName = CmpGetKeyName(InfHandle, Section, ruleNumber);
  173. ruleNumber++)
  174. {
  175. //
  176. // Search for the proceesing function in our table.
  177. //
  178. for ( i = 0;
  179. i < NUM_OF_INF_RULES &&
  180. _stricmp(ruleName, gInfRuleTable[i].Name);
  181. i++);
  182. if ( i >= NUM_OF_INF_RULES ||
  183. (regSection = CmpGetSectionLineIndex( InfHandle,
  184. Section,
  185. ruleNumber,
  186. 0)) == NULL ||
  187. !CmpSearchInfSection(InfHandle, Section))
  188. {
  189. result = FALSE;
  190. break;
  191. }
  192. if (!(*gInfRuleTable[i].Action)(InfHandle, regSection, gInfRuleTable[i].RefData))
  193. {
  194. result = FALSE;
  195. }
  196. }
  197. //
  198. // All inf rules processed.
  199. //
  200. if (ruleNumber)
  201. {
  202. result = TRUE;
  203. }
  204. }
  205. return (result);
  206. }
  207. BOOLEAN
  208. CmpProcessReg(
  209. IN PVOID InfHandle,
  210. IN PCHAR Section,
  211. IN PVOID RefData
  212. )
  213. /*++
  214. Routine Description:
  215. This routine processes a AddReg section in the inf.
  216. Input Parameters:
  217. InfHandle - Handle to the inf to be read.
  218. Section - Name of the section to be read.
  219. Return Value:
  220. TRUE iff the entire section was processed successfully.
  221. --*/
  222. {
  223. ULONG lineIndex;
  224. NTSTATUS status = STATUS_SUCCESS;
  225. NTSTATUS temp;
  226. //
  227. // Process all the lines in the xxxReg Section.
  228. //
  229. for ( lineIndex = 0;
  230. CmpSearchInfLine(InfHandle, Section, lineIndex);
  231. lineIndex++)
  232. {
  233. temp = (*(PFN_REGLINE)RefData)(InfHandle, Section, lineIndex);
  234. if (!NT_SUCCESS(temp))
  235. {
  236. status = temp;
  237. }
  238. }
  239. if (NT_SUCCESS(status))
  240. {
  241. return (TRUE);
  242. }
  243. return (FALSE);
  244. }
  245. NTSTATUS
  246. CmpProcessAddRegLine(
  247. IN PVOID InfHandle,
  248. IN PCHAR Section,
  249. IN ULONG LineIndex
  250. )
  251. /*++
  252. Routine Description:
  253. This routine processes a AddReg line in the inf.
  254. Input Parameters:
  255. InfHandle - Handle to the inf to be read.
  256. Section - Name of the section to be read.
  257. LineIndex - Index of the line to be read.
  258. Return Value:
  259. Standard NT status value.
  260. --*/
  261. {
  262. NTSTATUS status = STATUS_UNSUCCESSFUL;
  263. PCHAR rootKeyName;
  264. PCHAR subKeyName;
  265. PCHAR valueName;
  266. ULONG flags;
  267. ULONG valueType;
  268. PCHAR buffer;
  269. HANDLE key;
  270. ULONG disposition;
  271. BOOLEAN dontSet;
  272. PVOID data = 0;
  273. ULONG dataSize = 0;
  274. ANSI_STRING ansiString;
  275. UNICODE_STRING unicodeString;
  276. OBJECT_ATTRIBUTES objectAttributes;
  277. //
  278. // Get the root-key name.
  279. //
  280. rootKeyName = CmpGetSectionLineIndex( InfHandle,
  281. Section,
  282. LineIndex,
  283. 0);
  284. if (rootKeyName)
  285. {
  286. //
  287. // Get the optional sub-key name.
  288. //
  289. subKeyName = CmpGetSectionLineIndex( InfHandle,
  290. Section,
  291. LineIndex,
  292. 1);
  293. //
  294. // Value name is optional. Can be NULL or "".
  295. //
  296. valueName = CmpGetSectionLineIndex( InfHandle,
  297. Section,
  298. LineIndex,
  299. 2);
  300. //
  301. // If we don't have a value name, the type is REG_SZ to force
  302. // the right behavior in RegSetValueEx. Otherwise get the data type.
  303. //
  304. valueType = REG_SZ;
  305. //
  306. // Read in the flags.
  307. //
  308. if (!CmpGetIntField( InfHandle,
  309. Section,
  310. LineIndex,
  311. 3,
  312. &flags))
  313. {
  314. flags = 0;
  315. }
  316. //
  317. // Convert the flags to the registry type.
  318. //
  319. switch(flags & FLG_ADDREG_TYPE_MASK)
  320. {
  321. case FLG_ADDREG_TYPE_SZ:
  322. valueType = REG_SZ;
  323. break;
  324. case FLG_ADDREG_TYPE_MULTI_SZ:
  325. valueType = REG_MULTI_SZ;
  326. break;
  327. case FLG_ADDREG_TYPE_EXPAND_SZ:
  328. valueType = REG_EXPAND_SZ;
  329. break;
  330. case FLG_ADDREG_TYPE_BINARY:
  331. valueType = REG_BINARY;
  332. break;
  333. case FLG_ADDREG_TYPE_DWORD:
  334. valueType = REG_DWORD;
  335. break;
  336. case FLG_ADDREG_TYPE_NONE:
  337. valueType = REG_NONE;
  338. break;
  339. default :
  340. //
  341. // If the FLG_ADDREG_BINVALUETYPE is set, then the highword
  342. // can contain just about any random reg data type ordinal value.
  343. //
  344. if(flags & FLG_ADDREG_BINVALUETYPE)
  345. {
  346. //
  347. // Disallow the following reg data types:
  348. //
  349. // REG_NONE, REG_SZ, REG_EXPAND_SZ, REG_MULTI_SZ
  350. //
  351. valueType = HIGHWORD(flags);
  352. if(valueType < REG_BINARY || valueType == REG_MULTI_SZ)
  353. {
  354. return (STATUS_INVALID_PARAMETER);
  355. }
  356. }
  357. else
  358. {
  359. return (STATUS_INVALID_PARAMETER);
  360. }
  361. break;
  362. }
  363. //
  364. // Presently, the append behavior flag is only supported for
  365. // REG_MULTI_SZ values.
  366. //
  367. if((flags & FLG_ADDREG_APPEND) && valueType != REG_MULTI_SZ)
  368. {
  369. return (STATUS_INVALID_PARAMETER);
  370. }
  371. //
  372. // W9x compatibility.
  373. //
  374. if( (!valueName || *valueName == '\0') && valueType == REG_EXPAND_SZ)
  375. {
  376. valueType = REG_SZ;
  377. }
  378. //
  379. // Open the specified key if possible.
  380. //
  381. status = CmpOpenRegKey( &key,
  382. &disposition,
  383. rootKeyName,
  384. subKeyName,
  385. KEY_QUERY_VALUE | KEY_SET_VALUE,
  386. (BOOLEAN)!(flags & FLG_ADDREG_OVERWRITEONLY));
  387. if (NT_SUCCESS(status))
  388. {
  389. //
  390. // Respect the key only flag.
  391. //
  392. if (!(flags & FLG_ADDREG_KEYONLY))
  393. {
  394. status = CmpGetAddRegInfData( InfHandle,
  395. Section,
  396. LineIndex,
  397. 4,
  398. valueType,
  399. &data,
  400. &dataSize);
  401. if (NT_SUCCESS(status))
  402. {
  403. //
  404. // This variable gets set to TRUE if we dont actually want to set
  405. // the value.
  406. //
  407. dontSet = FALSE;
  408. if (flags & FLG_ADDREG_APPEND)
  409. {
  410. status = CmpAppendStringToMultiSz( key,
  411. valueName,
  412. &data,
  413. &dataSize);
  414. }
  415. if (NT_SUCCESS(status))
  416. {
  417. //
  418. // W9x compatibility.
  419. //
  420. if (disposition == REG_OPENED_EXISTING_KEY)
  421. {
  422. if ( (flags & FLG_ADDREG_NOCLOBBER) &&
  423. (valueName == NULL || *valueName == '\0'))
  424. {
  425. status = NtQueryValueKey( key,
  426. (PUNICODE_STRING)&NullString,
  427. KeyValueBasicInformation,
  428. NULL,
  429. 0,
  430. &disposition);
  431. if (NT_SUCCESS(status) || status == STATUS_BUFFER_TOO_SMALL)
  432. {
  433. flags &= ~FLG_ADDREG_NOCLOBBER;
  434. }
  435. status = STATUS_SUCCESS;
  436. }
  437. if (flags & FLG_ADDREG_DELVAL)
  438. {
  439. //
  440. // setupx compatibility.
  441. //
  442. dontSet = TRUE;
  443. if (valueName)
  444. {
  445. //
  446. // Delete the specified value.
  447. //
  448. RtlInitAnsiString(&ansiString, valueName);
  449. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
  450. if (NT_SUCCESS(status))
  451. {
  452. status = NtDeleteValueKey(key, &unicodeString);
  453. RtlFreeUnicodeString(&unicodeString);
  454. }
  455. }
  456. }
  457. }
  458. else
  459. {
  460. flags &= ~FLG_ADDREG_NOCLOBBER;
  461. }
  462. if (!dontSet)
  463. {
  464. //
  465. // If no clobber flag is set, make sure that the value does not
  466. // already exist.
  467. //
  468. RtlInitAnsiString(&ansiString, valueName);
  469. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
  470. if (NT_SUCCESS(status))
  471. {
  472. NTSTATUS existStatus;
  473. if (flags & FLG_ADDREG_NOCLOBBER)
  474. {
  475. existStatus = NtQueryValueKey( key,
  476. &unicodeString,
  477. KeyValueBasicInformation,
  478. NULL,
  479. 0,
  480. &disposition);
  481. if (NT_SUCCESS(existStatus) || existStatus == STATUS_BUFFER_TOO_SMALL) {
  482. dontSet = TRUE;
  483. }
  484. }
  485. else
  486. {
  487. if (flags & FLG_ADDREG_OVERWRITEONLY)
  488. {
  489. existStatus = NtQueryValueKey( key,
  490. &unicodeString,
  491. KeyValueBasicInformation,
  492. NULL,
  493. 0,
  494. &disposition);
  495. if (!NT_SUCCESS(existStatus) && existStatus != STATUS_BUFFER_TOO_SMALL) {
  496. dontSet = TRUE;
  497. }
  498. }
  499. }
  500. if (!dontSet)
  501. {
  502. status = NtSetValueKey( key,
  503. &unicodeString,
  504. 0,
  505. valueType,
  506. data,
  507. dataSize);
  508. }
  509. RtlFreeUnicodeString(&unicodeString);
  510. }
  511. }
  512. }
  513. }
  514. }
  515. NtClose(key);
  516. }
  517. else if (flags & FLG_ADDREG_OVERWRITEONLY)
  518. {
  519. status = STATUS_SUCCESS;
  520. }
  521. }
  522. return (status);
  523. }
  524. NTSTATUS
  525. CmpProcessDelRegLine(
  526. IN PVOID InfHandle,
  527. IN PCHAR Section,
  528. IN ULONG LineIndex
  529. )
  530. /*++
  531. Routine Description:
  532. This routine processes a DelReg line in the inf.
  533. Input Parameters:
  534. InfHandle - Handle to the inf to be read.
  535. Section - Name of the section to be read.
  536. LineIndex - Index of the line to be read.
  537. Return Value:
  538. Standard NT status value.
  539. --*/
  540. {
  541. NTSTATUS status = STATUS_UNSUCCESSFUL;
  542. PCHAR rootKeyName;
  543. PCHAR subKeyName;
  544. PCHAR valueName;
  545. HANDLE key;
  546. ULONG disposition;
  547. ANSI_STRING ansiString;
  548. UNICODE_STRING unicodeString;
  549. //
  550. // Read the required fields.
  551. //
  552. rootKeyName = CmpGetSectionLineIndex( InfHandle,
  553. Section,
  554. LineIndex,
  555. 0);
  556. subKeyName = CmpGetSectionLineIndex( InfHandle,
  557. Section,
  558. LineIndex,
  559. 1);
  560. if (rootKeyName && subKeyName)
  561. {
  562. //
  563. // Read the optional field.
  564. //
  565. valueName = CmpGetSectionLineIndex( InfHandle,
  566. Section,
  567. LineIndex,
  568. 2);
  569. //
  570. // Open the specified registry key.
  571. //
  572. status = CmpOpenRegKey( &key,
  573. &disposition,
  574. rootKeyName,
  575. subKeyName,
  576. KEY_ALL_ACCESS,
  577. FALSE);
  578. //
  579. // Proceed if we successfully opened the registry key.
  580. //
  581. if (NT_SUCCESS(status))
  582. {
  583. //
  584. // If the key was successfully opened, do the DelReg.
  585. //
  586. if (valueName)
  587. {
  588. //
  589. // Delete the specified value.
  590. //
  591. RtlInitAnsiString(&ansiString, valueName);
  592. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
  593. if (NT_SUCCESS(status))
  594. {
  595. status = NtDeleteValueKey(key, &unicodeString);
  596. RtlFreeUnicodeString(&unicodeString);
  597. }
  598. }
  599. else
  600. {
  601. //
  602. // No value specified. The subkey needs to be deleted.
  603. //
  604. status = NtDeleteKey(key);
  605. }
  606. //
  607. // Close the key handle.
  608. //
  609. NtClose(key);
  610. }
  611. }
  612. return (status);
  613. }
  614. NTSTATUS
  615. CmpProcessBitRegLine(
  616. IN PVOID InfHandle,
  617. IN PCHAR Section,
  618. IN ULONG LineIndex
  619. )
  620. /*++
  621. Routine Description:
  622. This routine processes a BitReg line in the inf.
  623. Input Parameters:
  624. InfHandle - Handle to the inf to be read.
  625. Section - Name of the section to be read.
  626. LineIndex - Index of the line to be read.
  627. Return Value:
  628. Standard NT status value.
  629. --*/
  630. {
  631. NTSTATUS status = STATUS_UNSUCCESSFUL;
  632. PCHAR rootKeyName;
  633. PCHAR subKeyName;
  634. PCHAR valueName;
  635. ULONG flags;
  636. ULONG mask;
  637. ULONG field;
  638. HANDLE key;
  639. ULONG disposition;
  640. ANSI_STRING ansiString;
  641. UNICODE_STRING unicodeString;
  642. PCHAR buffer;
  643. ULONG size;
  644. PKEY_VALUE_FULL_INFORMATION valueInfo;
  645. //
  646. // Get the root-key name.
  647. //
  648. rootKeyName = CmpGetSectionLineIndex( InfHandle,
  649. Section,
  650. LineIndex,
  651. 0);
  652. if (rootKeyName)
  653. {
  654. //
  655. // Get the optional sub-key name.
  656. //
  657. subKeyName = CmpGetSectionLineIndex( InfHandle,
  658. Section,
  659. LineIndex,
  660. 1);
  661. //
  662. // Value name is optional. Can be NULL or "".
  663. //
  664. valueName = CmpGetSectionLineIndex( InfHandle,
  665. Section,
  666. LineIndex,
  667. 2);
  668. if (valueName && *valueName)
  669. {
  670. //
  671. // Read in the flags.
  672. //
  673. if (!CmpGetIntField( InfHandle,
  674. Section,
  675. LineIndex,
  676. 3,
  677. &flags))
  678. {
  679. flags = 0;
  680. }
  681. if (!CmpGetIntField( InfHandle,
  682. Section,
  683. LineIndex,
  684. 4,
  685. &mask))
  686. {
  687. mask = 0;
  688. }
  689. if (!(flags & FLG_BITREG_TYPE_DWORD))
  690. {
  691. if (!CmpGetIntField( InfHandle,
  692. Section,
  693. LineIndex,
  694. 5,
  695. &field))
  696. {
  697. return (status);
  698. }
  699. }
  700. //
  701. // Open the specified registry key.
  702. //
  703. status = CmpOpenRegKey( &key,
  704. &disposition,
  705. rootKeyName,
  706. subKeyName,
  707. KEY_ALL_ACCESS,
  708. FALSE);
  709. if (NT_SUCCESS(status))
  710. {
  711. //
  712. // Read the existing data.
  713. //
  714. RtlInitAnsiString(&ansiString, valueName);
  715. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
  716. if (NT_SUCCESS(status))
  717. {
  718. size = 0;
  719. status = NtQueryValueKey( key,
  720. &unicodeString,
  721. KeyValueFullInformation,
  722. NULL,
  723. 0,
  724. &size);
  725. if (size)
  726. {
  727. status = STATUS_NO_MEMORY;
  728. buffer = ExAllocatePoolWithTag(PagedPool, size, CM_GENINST_TAG);
  729. if (buffer)
  730. {
  731. status = NtQueryValueKey( key,
  732. &unicodeString,
  733. KeyValueFullInformation,
  734. buffer,
  735. size,
  736. &size);
  737. if (NT_SUCCESS(status))
  738. {
  739. valueInfo = (PKEY_VALUE_FULL_INFORMATION)buffer;
  740. if (flags & FLG_BITREG_TYPE_DWORD)
  741. {
  742. if (valueInfo->Type == REG_DWORD && valueInfo->DataLength == sizeof(ULONG))
  743. {
  744. if (flags & FLG_BITREG_SET)
  745. {
  746. *(PULONG)(buffer + valueInfo->DataOffset) |= mask;
  747. }
  748. else
  749. {
  750. *(PULONG)(buffer + valueInfo->DataOffset) &= ~mask;
  751. }
  752. }
  753. }
  754. else
  755. {
  756. if (valueInfo->Type == REG_BINARY && field < valueInfo->DataLength)
  757. {
  758. if (flags & FLG_BITREG_SET)
  759. {
  760. *(PUCHAR)(buffer + valueInfo->DataOffset + field) |= mask;
  761. }
  762. else
  763. {
  764. *(PUCHAR)(buffer + valueInfo->DataOffset + field) &= ~mask;
  765. }
  766. }
  767. }
  768. status = NtSetValueKey( key,
  769. &unicodeString,
  770. 0,
  771. valueInfo->Type,
  772. buffer + valueInfo->DataOffset,
  773. valueInfo->DataLength);
  774. }
  775. else
  776. {
  777. #ifndef _CM_LDR_
  778. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Value cannot be read for BitReg in %s line %d\n", Section, LineIndex);
  779. #endif //_CM_LDR_
  780. ASSERT(NT_SUCCESS(status));
  781. }
  782. ExFreePool(buffer);
  783. }
  784. else
  785. {
  786. ASSERT(buffer);
  787. status = STATUS_NO_MEMORY;
  788. }
  789. }
  790. RtlFreeUnicodeString(&unicodeString);
  791. }
  792. //
  793. // Close the key handle.
  794. //
  795. NtClose(key);
  796. }
  797. }
  798. }
  799. return (status);
  800. }
  801. NTSTATUS
  802. CmpGetAddRegInfData(
  803. IN PVOID InfHandle,
  804. IN PCHAR Section,
  805. IN ULONG LineIndex,
  806. IN ULONG ValueIndex,
  807. IN ULONG ValueType,
  808. OUT PVOID *Data,
  809. OUT PULONG DataSize
  810. )
  811. /*++
  812. Routine Description:
  813. This routine reads AddReg data from the inf.
  814. Input Parameters:
  815. InfHandle - Handle to the inf to be read.
  816. Section - Name of the section to be read.
  817. LineIndex - Index of the line to be read.
  818. ValueIndex - Index of the value to be read.
  819. ValueType - Data type to be read.
  820. Data - Receives pointer to the buffer in which data has been read.
  821. DataSize - Receives the size of the data buffer.
  822. Return Value:
  823. Standard NT status value.
  824. --*/
  825. {
  826. NTSTATUS status = STATUS_UNSUCCESSFUL;
  827. PCHAR str;
  828. ULONG count;
  829. ULONG i;
  830. ANSI_STRING ansiString;
  831. UNICODE_STRING unicodeString;
  832. //
  833. // Validate the required fields.
  834. //
  835. ASSERT(Data);
  836. ASSERT(DataSize);
  837. switch (ValueType)
  838. {
  839. case REG_DWORD:
  840. *DataSize = sizeof(ULONG);
  841. *Data = ExAllocatePoolWithTag(PagedPool, *DataSize, CM_GENINST_TAG);
  842. if (*Data)
  843. {
  844. //
  845. // DWORD data is specified as four bytes in W9x.
  846. //
  847. if (CmpGetSectionLineIndexValueCount( InfHandle,
  848. Section,
  849. LineIndex) == 8)
  850. {
  851. if (!CmpGetBinaryField( InfHandle,
  852. Section,
  853. LineIndex,
  854. ValueIndex,
  855. *Data,
  856. *DataSize,
  857. NULL))
  858. {
  859. *((PULONG)*Data) = 0;
  860. }
  861. status = STATUS_SUCCESS;
  862. }
  863. else
  864. {
  865. //
  866. // Get the DWORD value.
  867. //
  868. if (!CmpGetIntField( InfHandle,
  869. Section,
  870. LineIndex,
  871. 4,
  872. *Data))
  873. {
  874. *((PULONG)*Data) = 0;
  875. }
  876. status = STATUS_SUCCESS;
  877. }
  878. }
  879. else
  880. {
  881. ASSERT(*Data);
  882. status = STATUS_NO_MEMORY;
  883. }
  884. break;
  885. case REG_SZ:
  886. case REG_EXPAND_SZ:
  887. //
  888. // Null terminated string. Gets converted to unicode before being
  889. // added into the registry.
  890. //
  891. str = CmpGetSectionLineIndex( InfHandle,
  892. Section,
  893. LineIndex,
  894. ValueIndex);
  895. if (str)
  896. {
  897. RtlInitAnsiString(&ansiString, str);
  898. *DataSize = (ansiString.Length << 1) + sizeof(UNICODE_NULL);
  899. unicodeString.MaximumLength = (USHORT)*DataSize;
  900. unicodeString.Buffer = ExAllocatePoolWithTag(PagedPool, *DataSize, CM_GENINST_TAG);
  901. *Data = NULL;
  902. if (unicodeString.Buffer)
  903. {
  904. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE);
  905. if (NT_SUCCESS(status))
  906. {
  907. *Data = unicodeString.Buffer;
  908. status = STATUS_SUCCESS;
  909. }
  910. }
  911. else
  912. {
  913. ASSERT(unicodeString.Buffer);
  914. status = STATUS_NO_MEMORY;
  915. }
  916. }
  917. else
  918. {
  919. ASSERT(str);
  920. status = STATUS_NO_MEMORY;
  921. }
  922. break;
  923. case REG_MULTI_SZ:
  924. *DataSize = 0;
  925. *Data = NULL;
  926. //
  927. // Loop to determine the total memory that needs to be allocated.
  928. //
  929. count = CmpGetSectionLineIndexValueCount( InfHandle,
  930. Section,
  931. LineIndex);
  932. if (count > ValueIndex)
  933. {
  934. count -= ValueIndex;
  935. for (i = 0; i < count; i++)
  936. {
  937. str = CmpGetSectionLineIndex( InfHandle,
  938. Section,
  939. LineIndex,
  940. ValueIndex + i);
  941. if (str == NULL)
  942. {
  943. break;
  944. }
  945. *DataSize += ((strlen(str) * sizeof(WCHAR)) + sizeof(UNICODE_NULL));
  946. }
  947. if (i == count)
  948. {
  949. //
  950. // Account for the terminating NULL.
  951. //
  952. *DataSize += sizeof(UNICODE_NULL);
  953. *Data = ExAllocatePoolWithTag(PagedPool, *DataSize, CM_GENINST_TAG);
  954. if (*Data)
  955. {
  956. for ( i = 0, unicodeString.Buffer = *Data;
  957. i < count;
  958. i++, (PCHAR)unicodeString.Buffer += unicodeString.MaximumLength)
  959. {
  960. str = CmpGetSectionLineIndex( InfHandle,
  961. Section,
  962. LineIndex,
  963. ValueIndex + i);
  964. if (str == NULL)
  965. {
  966. break;
  967. }
  968. RtlInitAnsiString(&ansiString, str);
  969. unicodeString.MaximumLength = (ansiString.Length * sizeof(WCHAR)) + sizeof(UNICODE_NULL);
  970. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE);
  971. if (!NT_SUCCESS(status))
  972. {
  973. break;
  974. }
  975. }
  976. //
  977. // Terminate the multi-sz string.
  978. //
  979. if (i == count)
  980. {
  981. unicodeString.Buffer[0] = UNICODE_NULL;
  982. status = STATUS_SUCCESS;
  983. }
  984. }
  985. else
  986. {
  987. ASSERT(*Data);
  988. status = STATUS_NO_MEMORY;
  989. }
  990. }
  991. }
  992. break;
  993. case REG_BINARY:
  994. default:
  995. //
  996. // Free form binary data.
  997. //
  998. if (CmpGetBinaryField( InfHandle,
  999. Section,
  1000. LineIndex,
  1001. ValueIndex,
  1002. NULL,
  1003. 0,
  1004. DataSize) && *DataSize)
  1005. {
  1006. *Data = ExAllocatePoolWithTag(PagedPool, *DataSize, CM_GENINST_TAG);
  1007. if (*Data)
  1008. {
  1009. if (CmpGetBinaryField( InfHandle,
  1010. Section,
  1011. LineIndex,
  1012. 4,
  1013. *Data,
  1014. *DataSize,
  1015. NULL))
  1016. {
  1017. status = STATUS_SUCCESS;
  1018. }
  1019. }
  1020. else
  1021. {
  1022. ASSERT(*Data);
  1023. status = STATUS_NO_MEMORY;
  1024. }
  1025. }
  1026. else
  1027. {
  1028. status = STATUS_UNSUCCESSFUL;
  1029. }
  1030. break;
  1031. }
  1032. return (status);
  1033. }
  1034. NTSTATUS
  1035. CmpOpenRegKey(
  1036. IN OUT PHANDLE Key,
  1037. IN OUT PULONG Disposition,
  1038. IN PCHAR Root,
  1039. IN PCHAR SubKey,
  1040. IN ULONG DesiredAccess,
  1041. IN BOOLEAN Create
  1042. )
  1043. /*++
  1044. Routine Description:
  1045. This routine opens\creates a handle to the registry key.
  1046. Input Parameters:
  1047. Key - Receives the handle to the key.
  1048. Disposition - Receives the disposition of the key.
  1049. Root - Abbreviated name of the root key.
  1050. SubKey - Name of the subkey under the root.
  1051. DesiredAccess - Desired access flags for the key.
  1052. Create - TRUE if the key needs to be created instead of opened.
  1053. Return Value:
  1054. Standard NT status value.
  1055. --*/
  1056. {
  1057. NTSTATUS status = STATUS_OBJECT_NAME_INVALID;
  1058. ULONG size;
  1059. PCHAR str;
  1060. ANSI_STRING ansiString;
  1061. UNICODE_STRING unicodeString;
  1062. OBJECT_ATTRIBUTES objectAttributes;
  1063. str = NULL;
  1064. size = strlen(SubKey) + 1;
  1065. //
  1066. // Check if we understand the specified root name.
  1067. //
  1068. if (_stricmp(Root, "HKLM") == 0)
  1069. {
  1070. size += (sizeof("\\Registry\\Machine\\") - 1); // Already added one above for NULL
  1071. str = ExAllocatePoolWithTag(PagedPool, size, CM_GENINST_TAG);
  1072. if (str)
  1073. {
  1074. strcpy(str, "\\Registry\\Machine\\");
  1075. strcat(str, SubKey);
  1076. }
  1077. else
  1078. {
  1079. ASSERT(str);
  1080. status = STATUS_NO_MEMORY;
  1081. }
  1082. }
  1083. else
  1084. {
  1085. ASSERT(_stricmp(Root, "HKLM") == 0);
  1086. }
  1087. //
  1088. // Proceed if we have a valid key name.
  1089. //
  1090. if (str)
  1091. {
  1092. RtlInitAnsiString(&ansiString, str);
  1093. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
  1094. if (NT_SUCCESS(status))
  1095. {
  1096. InitializeObjectAttributes( &objectAttributes,
  1097. &unicodeString,
  1098. OBJ_CASE_INSENSITIVE,
  1099. NULL,
  1100. NULL);
  1101. if (Create)
  1102. {
  1103. //
  1104. // Create a new key or open an existing one.
  1105. //
  1106. status = NtCreateKey( Key,
  1107. DesiredAccess,
  1108. &objectAttributes,
  1109. 0,
  1110. NULL,
  1111. REG_OPTION_NON_VOLATILE,
  1112. Disposition ? Disposition : &size);
  1113. }
  1114. else
  1115. {
  1116. //
  1117. // Open existing key.
  1118. //
  1119. if (Disposition)
  1120. {
  1121. *Disposition = REG_OPENED_EXISTING_KEY;
  1122. }
  1123. status = NtOpenKey( Key,
  1124. DesiredAccess,
  1125. &objectAttributes);
  1126. }
  1127. RtlFreeUnicodeString(&unicodeString);
  1128. }
  1129. else
  1130. {
  1131. ASSERT(NT_SUCCESS(status));
  1132. }
  1133. ExFreePool(str);
  1134. }
  1135. return (status);
  1136. }
  1137. NTSTATUS
  1138. CmpAppendStringToMultiSz(
  1139. IN HANDLE Key,
  1140. IN PCHAR ValueName,
  1141. IN OUT PVOID *Data,
  1142. IN OUT PULONG DataSize
  1143. )
  1144. /*++
  1145. Routine Description:
  1146. This routine opens\creates a handle to the registry key.
  1147. Input Parameters:
  1148. Key - Receives the handle to the key.
  1149. ValueName - Name of the value to be appended to.
  1150. Data - Buffer containing the multi-sz to be appended.
  1151. DataSize - Size of the data.
  1152. Return Value:
  1153. Standard NT status value.
  1154. --*/
  1155. {
  1156. NTSTATUS status;
  1157. ULONG size;
  1158. ANSI_STRING ansiString;
  1159. UNICODE_STRING unicodeString;
  1160. PKEY_VALUE_FULL_INFORMATION valueInfo;
  1161. PVOID buffer;
  1162. PVOID str;
  1163. ASSERT(DataSize && *DataSize);
  1164. ASSERT(*Data);
  1165. RtlInitAnsiString(&ansiString, ValueName);
  1166. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
  1167. if (NT_SUCCESS(status))
  1168. {
  1169. size = 0;
  1170. status = NtQueryValueKey( Key,
  1171. &unicodeString,
  1172. KeyValueFullInformation,
  1173. NULL,
  1174. 0,
  1175. &size);
  1176. if (size)
  1177. {
  1178. buffer = ExAllocatePoolWithTag(PagedPool, size, CM_GENINST_TAG);
  1179. if (buffer)
  1180. {
  1181. status = NtQueryValueKey( Key,
  1182. &unicodeString,
  1183. KeyValueFullInformation,
  1184. buffer,
  1185. size,
  1186. &size);
  1187. if (NT_SUCCESS(status))
  1188. {
  1189. valueInfo = (PKEY_VALUE_FULL_INFORMATION)buffer;
  1190. str = ExAllocatePoolWithTag( PagedPool,
  1191. valueInfo->DataLength +
  1192. *DataSize - sizeof(UNICODE_NULL),
  1193. CM_GENINST_TAG);
  1194. if (str)
  1195. {
  1196. memcpy( str,
  1197. (PCHAR)buffer + valueInfo->DataOffset,
  1198. valueInfo->DataLength);
  1199. memcpy( (PCHAR)str + valueInfo->DataLength - sizeof(UNICODE_NULL),
  1200. *Data,
  1201. *DataSize);
  1202. ExFreePool(*Data);
  1203. *Data = str;
  1204. *DataSize += valueInfo->DataLength - sizeof(UNICODE_NULL);
  1205. }
  1206. else
  1207. {
  1208. #ifndef _CM_LDR_
  1209. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpAppendStringToMultiSz: Failed to allocate memory!\n");
  1210. #endif //_CM_LDR_
  1211. ASSERT(str);
  1212. status = STATUS_NO_MEMORY;
  1213. }
  1214. }
  1215. ExFreePool(buffer);
  1216. }
  1217. else
  1218. {
  1219. #ifndef _CM_LDR_
  1220. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpAppendStringToMultiSz: Failed to allocate memory!\n");
  1221. #endif //_CM_LDR_
  1222. ASSERT(buffer);
  1223. status = STATUS_NO_MEMORY;
  1224. }
  1225. }
  1226. RtlFreeUnicodeString(&unicodeString);
  1227. }
  1228. return (status);
  1229. }