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.

1497 lines
46 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  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, (PVOID)(ULONG_PTR) CmpProcessAddRegLine},
  131. {"DelReg", CmpProcessReg, (PVOID)(ULONG_PTR) CmpProcessDelRegLine},
  132. {"BitReg", CmpProcessReg, (PVOID)(ULONG_PTR) 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)(ULONG_PTR)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. HANDLE key;
  269. ULONG disposition;
  270. BOOLEAN dontSet;
  271. PVOID data = 0;
  272. ULONG dataSize = 0;
  273. ANSI_STRING ansiString;
  274. UNICODE_STRING unicodeString;
  275. //
  276. // Get the root-key name.
  277. //
  278. rootKeyName = CmpGetSectionLineIndex( InfHandle,
  279. Section,
  280. LineIndex,
  281. 0);
  282. if (rootKeyName)
  283. {
  284. //
  285. // Get the optional sub-key name.
  286. //
  287. subKeyName = CmpGetSectionLineIndex( InfHandle,
  288. Section,
  289. LineIndex,
  290. 1);
  291. //
  292. // Value name is optional. Can be NULL or "".
  293. //
  294. valueName = CmpGetSectionLineIndex( InfHandle,
  295. Section,
  296. LineIndex,
  297. 2);
  298. //
  299. // If we don't have a value name, the type is REG_SZ to force
  300. // the right behavior in RegSetValueEx. Otherwise get the data type.
  301. //
  302. valueType = REG_SZ;
  303. //
  304. // Read in the flags.
  305. //
  306. if (!CmpGetIntField( InfHandle,
  307. Section,
  308. LineIndex,
  309. 3,
  310. &flags))
  311. {
  312. flags = 0;
  313. }
  314. //
  315. // Convert the flags to the registry type.
  316. //
  317. switch(flags & FLG_ADDREG_TYPE_MASK)
  318. {
  319. case FLG_ADDREG_TYPE_SZ:
  320. valueType = REG_SZ;
  321. break;
  322. case FLG_ADDREG_TYPE_MULTI_SZ:
  323. valueType = REG_MULTI_SZ;
  324. break;
  325. case FLG_ADDREG_TYPE_EXPAND_SZ:
  326. valueType = REG_EXPAND_SZ;
  327. break;
  328. case FLG_ADDREG_TYPE_BINARY:
  329. valueType = REG_BINARY;
  330. break;
  331. case FLG_ADDREG_TYPE_DWORD:
  332. valueType = REG_DWORD;
  333. break;
  334. case FLG_ADDREG_TYPE_NONE:
  335. valueType = REG_NONE;
  336. break;
  337. default :
  338. //
  339. // If the FLG_ADDREG_BINVALUETYPE is set, then the highword
  340. // can contain just about any random reg data type ordinal value.
  341. //
  342. if(flags & FLG_ADDREG_BINVALUETYPE)
  343. {
  344. //
  345. // Disallow the following reg data types:
  346. //
  347. // REG_NONE, REG_SZ, REG_EXPAND_SZ, REG_MULTI_SZ
  348. //
  349. valueType = HIGHWORD(flags);
  350. if(valueType < REG_BINARY || valueType == REG_MULTI_SZ)
  351. {
  352. return (STATUS_INVALID_PARAMETER);
  353. }
  354. }
  355. else
  356. {
  357. return (STATUS_INVALID_PARAMETER);
  358. }
  359. break;
  360. }
  361. //
  362. // Presently, the append behavior flag is only supported for
  363. // REG_MULTI_SZ values.
  364. //
  365. if((flags & FLG_ADDREG_APPEND) && valueType != REG_MULTI_SZ)
  366. {
  367. return (STATUS_INVALID_PARAMETER);
  368. }
  369. //
  370. // W9x compatibility.
  371. //
  372. if( (!valueName || *valueName == '\0') && valueType == REG_EXPAND_SZ)
  373. {
  374. valueType = REG_SZ;
  375. }
  376. //
  377. // Open the specified key if possible.
  378. //
  379. status = CmpOpenRegKey( &key,
  380. &disposition,
  381. rootKeyName,
  382. subKeyName,
  383. KEY_ALL_ACCESS,
  384. (BOOLEAN)!(flags & FLG_ADDREG_OVERWRITEONLY));
  385. if (NT_SUCCESS(status))
  386. {
  387. //
  388. // Respect the key only flag.
  389. //
  390. if (!(flags & FLG_ADDREG_KEYONLY))
  391. {
  392. status = CmpGetAddRegInfData( InfHandle,
  393. Section,
  394. LineIndex,
  395. 4,
  396. valueType,
  397. &data,
  398. &dataSize);
  399. if (NT_SUCCESS(status))
  400. {
  401. //
  402. // This variable gets set to TRUE if we dont actually want to set
  403. // the value.
  404. //
  405. dontSet = FALSE;
  406. if (flags & FLG_ADDREG_APPEND)
  407. {
  408. status = CmpAppendStringToMultiSz( key,
  409. valueName,
  410. &data,
  411. &dataSize);
  412. }
  413. if (NT_SUCCESS(status))
  414. {
  415. //
  416. // W9x compatibility.
  417. //
  418. if (disposition == REG_OPENED_EXISTING_KEY)
  419. {
  420. if ( (flags & FLG_ADDREG_NOCLOBBER) &&
  421. (valueName == NULL || *valueName == '\0'))
  422. {
  423. status = NtQueryValueKey( key,
  424. (PUNICODE_STRING)&NullString,
  425. KeyValueBasicInformation,
  426. NULL,
  427. 0,
  428. &disposition);
  429. if (NT_SUCCESS(status) || status == STATUS_BUFFER_TOO_SMALL)
  430. {
  431. flags &= ~FLG_ADDREG_NOCLOBBER;
  432. }
  433. status = STATUS_SUCCESS;
  434. }
  435. if (flags & FLG_ADDREG_DELVAL)
  436. {
  437. //
  438. // setupx compatibility.
  439. //
  440. dontSet = TRUE;
  441. if (valueName)
  442. {
  443. //
  444. // Delete the specified value.
  445. //
  446. RtlInitAnsiString(&ansiString, valueName);
  447. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
  448. if (NT_SUCCESS(status))
  449. {
  450. status = NtDeleteValueKey(key, &unicodeString);
  451. RtlFreeUnicodeString(&unicodeString);
  452. }
  453. }
  454. }
  455. }
  456. else
  457. {
  458. flags &= ~FLG_ADDREG_NOCLOBBER;
  459. }
  460. if (!dontSet)
  461. {
  462. //
  463. // If no clobber flag is set, make sure that the value does not
  464. // already exist.
  465. //
  466. RtlInitAnsiString(&ansiString, valueName);
  467. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
  468. if (NT_SUCCESS(status))
  469. {
  470. NTSTATUS existStatus;
  471. if (flags & FLG_ADDREG_NOCLOBBER)
  472. {
  473. existStatus = NtQueryValueKey( key,
  474. &unicodeString,
  475. KeyValueBasicInformation,
  476. NULL,
  477. 0,
  478. &disposition);
  479. if (NT_SUCCESS(existStatus) || existStatus == STATUS_BUFFER_TOO_SMALL) {
  480. dontSet = TRUE;
  481. }
  482. }
  483. else
  484. {
  485. if (flags & FLG_ADDREG_OVERWRITEONLY)
  486. {
  487. existStatus = NtQueryValueKey( key,
  488. &unicodeString,
  489. KeyValueBasicInformation,
  490. NULL,
  491. 0,
  492. &disposition);
  493. if (!NT_SUCCESS(existStatus) && existStatus != STATUS_BUFFER_TOO_SMALL) {
  494. dontSet = TRUE;
  495. }
  496. }
  497. }
  498. if (!dontSet)
  499. {
  500. status = NtSetValueKey( key,
  501. &unicodeString,
  502. 0,
  503. valueType,
  504. data,
  505. dataSize);
  506. }
  507. RtlFreeUnicodeString(&unicodeString);
  508. }
  509. }
  510. }
  511. }
  512. }
  513. NtClose(key);
  514. }
  515. else if (flags & FLG_ADDREG_OVERWRITEONLY)
  516. {
  517. status = STATUS_SUCCESS;
  518. }
  519. }
  520. return (status);
  521. }
  522. NTSTATUS
  523. CmpProcessDelRegLine(
  524. IN PVOID InfHandle,
  525. IN PCHAR Section,
  526. IN ULONG LineIndex
  527. )
  528. /*++
  529. Routine Description:
  530. This routine processes a DelReg line in the inf.
  531. Input Parameters:
  532. InfHandle - Handle to the inf to be read.
  533. Section - Name of the section to be read.
  534. LineIndex - Index of the line to be read.
  535. Return Value:
  536. Standard NT status value.
  537. --*/
  538. {
  539. NTSTATUS status = STATUS_UNSUCCESSFUL;
  540. PCHAR rootKeyName;
  541. PCHAR subKeyName;
  542. PCHAR valueName;
  543. HANDLE key;
  544. ULONG disposition;
  545. ANSI_STRING ansiString;
  546. UNICODE_STRING unicodeString;
  547. //
  548. // Read the required fields.
  549. //
  550. rootKeyName = CmpGetSectionLineIndex( InfHandle,
  551. Section,
  552. LineIndex,
  553. 0);
  554. subKeyName = CmpGetSectionLineIndex( InfHandle,
  555. Section,
  556. LineIndex,
  557. 1);
  558. if (rootKeyName && subKeyName)
  559. {
  560. //
  561. // Read the optional field.
  562. //
  563. valueName = CmpGetSectionLineIndex( InfHandle,
  564. Section,
  565. LineIndex,
  566. 2);
  567. //
  568. // Open the specified registry key.
  569. //
  570. status = CmpOpenRegKey( &key,
  571. &disposition,
  572. rootKeyName,
  573. subKeyName,
  574. KEY_ALL_ACCESS,
  575. FALSE);
  576. //
  577. // Proceed if we successfully opened the registry key.
  578. //
  579. if (NT_SUCCESS(status))
  580. {
  581. //
  582. // If the key was successfully opened, do the DelReg.
  583. //
  584. if (valueName)
  585. {
  586. //
  587. // Delete the specified value.
  588. //
  589. RtlInitAnsiString(&ansiString, valueName);
  590. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
  591. if (NT_SUCCESS(status))
  592. {
  593. status = NtDeleteValueKey(key, &unicodeString);
  594. RtlFreeUnicodeString(&unicodeString);
  595. }
  596. }
  597. else
  598. {
  599. //
  600. // No value specified. The subkey needs to be deleted.
  601. //
  602. status = NtDeleteKey(key);
  603. }
  604. //
  605. // Close the key handle.
  606. //
  607. NtClose(key);
  608. }
  609. }
  610. return (status);
  611. }
  612. NTSTATUS
  613. CmpProcessBitRegLine(
  614. IN PVOID InfHandle,
  615. IN PCHAR Section,
  616. IN ULONG LineIndex
  617. )
  618. /*++
  619. Routine Description:
  620. This routine processes a BitReg line in the inf.
  621. Input Parameters:
  622. InfHandle - Handle to the inf to be read.
  623. Section - Name of the section to be read.
  624. LineIndex - Index of the line to be read.
  625. Return Value:
  626. Standard NT status value.
  627. --*/
  628. {
  629. NTSTATUS status = STATUS_UNSUCCESSFUL;
  630. PCHAR rootKeyName;
  631. PCHAR subKeyName;
  632. PCHAR valueName;
  633. ULONG flags;
  634. ULONG mask;
  635. ULONG field = 0;
  636. HANDLE key;
  637. ULONG disposition;
  638. ANSI_STRING ansiString;
  639. UNICODE_STRING unicodeString;
  640. PCHAR buffer;
  641. ULONG size;
  642. PKEY_VALUE_FULL_INFORMATION valueInfo;
  643. //
  644. // Get the root-key name.
  645. //
  646. rootKeyName = CmpGetSectionLineIndex( InfHandle,
  647. Section,
  648. LineIndex,
  649. 0);
  650. if (rootKeyName)
  651. {
  652. //
  653. // Get the optional sub-key name.
  654. //
  655. subKeyName = CmpGetSectionLineIndex( InfHandle,
  656. Section,
  657. LineIndex,
  658. 1);
  659. //
  660. // Value name is optional. Can be NULL or "".
  661. //
  662. valueName = CmpGetSectionLineIndex( InfHandle,
  663. Section,
  664. LineIndex,
  665. 2);
  666. if (valueName && *valueName)
  667. {
  668. //
  669. // Read in the flags.
  670. //
  671. if (!CmpGetIntField( InfHandle,
  672. Section,
  673. LineIndex,
  674. 3,
  675. &flags))
  676. {
  677. flags = 0;
  678. }
  679. if (!CmpGetIntField( InfHandle,
  680. Section,
  681. LineIndex,
  682. 4,
  683. &mask))
  684. {
  685. mask = 0;
  686. }
  687. if (!(flags & FLG_BITREG_TYPE_DWORD))
  688. {
  689. if (!CmpGetIntField( InfHandle,
  690. Section,
  691. LineIndex,
  692. 5,
  693. &field))
  694. {
  695. return (status);
  696. }
  697. }
  698. //
  699. // Open the specified registry key.
  700. //
  701. status = CmpOpenRegKey( &key,
  702. &disposition,
  703. rootKeyName,
  704. subKeyName,
  705. KEY_QUERY_VALUE | KEY_SET_VALUE,
  706. FALSE);
  707. if (NT_SUCCESS(status))
  708. {
  709. //
  710. // Read the existing data.
  711. //
  712. RtlInitAnsiString(&ansiString, valueName);
  713. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
  714. if (NT_SUCCESS(status))
  715. {
  716. size = 0;
  717. status = NtQueryValueKey( key,
  718. &unicodeString,
  719. KeyValueFullInformation,
  720. NULL,
  721. 0,
  722. &size);
  723. if (size)
  724. {
  725. status = STATUS_NO_MEMORY;
  726. buffer = ExAllocatePoolWithTag(PagedPool, size, CM_GENINST_TAG);
  727. if (buffer)
  728. {
  729. status = NtQueryValueKey( key,
  730. &unicodeString,
  731. KeyValueFullInformation,
  732. buffer,
  733. size,
  734. &size);
  735. if (NT_SUCCESS(status))
  736. {
  737. valueInfo = (PKEY_VALUE_FULL_INFORMATION)buffer;
  738. if (flags & FLG_BITREG_TYPE_DWORD)
  739. {
  740. if (valueInfo->Type == REG_DWORD && valueInfo->DataLength == sizeof(ULONG))
  741. {
  742. if (flags & FLG_BITREG_SET)
  743. {
  744. *(PULONG)(buffer + valueInfo->DataOffset) |= mask;
  745. }
  746. else
  747. {
  748. *(PULONG)(buffer + valueInfo->DataOffset) &= ~mask;
  749. }
  750. }
  751. }
  752. else
  753. {
  754. if (valueInfo->Type == REG_BINARY && field < valueInfo->DataLength)
  755. {
  756. if (flags & FLG_BITREG_SET)
  757. {
  758. *(PUCHAR)(buffer + valueInfo->DataOffset + field) |= mask;
  759. }
  760. else
  761. {
  762. *(PUCHAR)(buffer + valueInfo->DataOffset + field) &= ~mask;
  763. }
  764. }
  765. }
  766. status = NtSetValueKey( key,
  767. &unicodeString,
  768. 0,
  769. valueInfo->Type,
  770. buffer + valueInfo->DataOffset,
  771. valueInfo->DataLength);
  772. }
  773. else
  774. {
  775. #ifndef _CM_LDR_
  776. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Value cannot be read for BitReg in %s line %d\n", Section, LineIndex);
  777. #endif //_CM_LDR_
  778. ASSERT(NT_SUCCESS(status));
  779. }
  780. ExFreePool(buffer);
  781. }
  782. else
  783. {
  784. ASSERT(buffer);
  785. status = STATUS_NO_MEMORY;
  786. }
  787. }
  788. RtlFreeUnicodeString(&unicodeString);
  789. }
  790. //
  791. // Close the key handle.
  792. //
  793. NtClose(key);
  794. }
  795. }
  796. }
  797. return (status);
  798. }
  799. NTSTATUS
  800. CmpGetAddRegInfData(
  801. IN PVOID InfHandle,
  802. IN PCHAR Section,
  803. IN ULONG LineIndex,
  804. IN ULONG ValueIndex,
  805. IN ULONG ValueType,
  806. OUT PVOID *Data,
  807. OUT PULONG DataSize
  808. )
  809. /*++
  810. Routine Description:
  811. This routine reads AddReg data from the inf.
  812. Input Parameters:
  813. InfHandle - Handle to the inf to be read.
  814. Section - Name of the section to be read.
  815. LineIndex - Index of the line to be read.
  816. ValueIndex - Index of the value to be read.
  817. ValueType - Data type to be read.
  818. Data - Receives pointer to the buffer in which data has been read.
  819. DataSize - Receives the size of the data buffer.
  820. Return Value:
  821. Standard NT status value.
  822. --*/
  823. {
  824. NTSTATUS status = STATUS_UNSUCCESSFUL;
  825. PCHAR str;
  826. ULONG count;
  827. ULONG i;
  828. ANSI_STRING ansiString;
  829. UNICODE_STRING unicodeString;
  830. //
  831. // Validate the required fields.
  832. //
  833. ASSERT(Data);
  834. ASSERT(DataSize);
  835. switch (ValueType)
  836. {
  837. case REG_DWORD:
  838. *DataSize = sizeof(ULONG);
  839. *Data = ExAllocatePoolWithTag(PagedPool, *DataSize, CM_GENINST_TAG);
  840. if (*Data)
  841. {
  842. //
  843. // DWORD data is specified as four bytes in W9x.
  844. //
  845. if (CmpGetSectionLineIndexValueCount( InfHandle,
  846. Section,
  847. LineIndex) == 8)
  848. {
  849. if (!CmpGetBinaryField( InfHandle,
  850. Section,
  851. LineIndex,
  852. ValueIndex,
  853. *Data,
  854. *DataSize,
  855. NULL))
  856. {
  857. *((PULONG)*Data) = 0;
  858. }
  859. status = STATUS_SUCCESS;
  860. }
  861. else
  862. {
  863. //
  864. // Get the DWORD value.
  865. //
  866. if (!CmpGetIntField( InfHandle,
  867. Section,
  868. LineIndex,
  869. 4,
  870. *Data))
  871. {
  872. *((PULONG)*Data) = 0;
  873. }
  874. status = STATUS_SUCCESS;
  875. }
  876. }
  877. else
  878. {
  879. ASSERT(*Data);
  880. status = STATUS_NO_MEMORY;
  881. }
  882. break;
  883. case REG_SZ:
  884. case REG_EXPAND_SZ:
  885. //
  886. // Null terminated string. Gets converted to unicode before being
  887. // added into the registry.
  888. //
  889. str = CmpGetSectionLineIndex( InfHandle,
  890. Section,
  891. LineIndex,
  892. ValueIndex);
  893. if (str)
  894. {
  895. RtlInitAnsiString(&ansiString, str);
  896. *DataSize = (ansiString.Length << 1) + sizeof(UNICODE_NULL);
  897. unicodeString.MaximumLength = (USHORT)*DataSize;
  898. unicodeString.Buffer = ExAllocatePoolWithTag(PagedPool, *DataSize, CM_GENINST_TAG);
  899. *Data = NULL;
  900. if (unicodeString.Buffer)
  901. {
  902. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE);
  903. if (NT_SUCCESS(status))
  904. {
  905. *Data = unicodeString.Buffer;
  906. status = STATUS_SUCCESS;
  907. }
  908. }
  909. else
  910. {
  911. ASSERT(unicodeString.Buffer);
  912. status = STATUS_NO_MEMORY;
  913. }
  914. }
  915. else
  916. {
  917. ASSERT(str);
  918. status = STATUS_NO_MEMORY;
  919. }
  920. break;
  921. case REG_MULTI_SZ:
  922. *DataSize = 0;
  923. *Data = NULL;
  924. //
  925. // Loop to determine the total memory that needs to be allocated.
  926. //
  927. count = CmpGetSectionLineIndexValueCount( InfHandle,
  928. Section,
  929. LineIndex);
  930. if (count > ValueIndex)
  931. {
  932. count -= ValueIndex;
  933. for (i = 0; i < count; i++)
  934. {
  935. str = CmpGetSectionLineIndex( InfHandle,
  936. Section,
  937. LineIndex,
  938. ValueIndex + i);
  939. if (str == NULL)
  940. {
  941. break;
  942. }
  943. *DataSize += (ULONG)((strlen(str) * sizeof(WCHAR)) + sizeof(UNICODE_NULL));
  944. }
  945. if (i == count)
  946. {
  947. //
  948. // Account for the terminating NULL.
  949. //
  950. *DataSize += sizeof(UNICODE_NULL);
  951. *Data = ExAllocatePoolWithTag(PagedPool, *DataSize, CM_GENINST_TAG);
  952. if (*Data)
  953. {
  954. for ( i = 0, unicodeString.Buffer = *Data;
  955. i < count;
  956. i++, unicodeString.Buffer = (PWCHAR)((PCHAR)unicodeString.Buffer + unicodeString.MaximumLength))
  957. {
  958. str = CmpGetSectionLineIndex( InfHandle,
  959. Section,
  960. LineIndex,
  961. ValueIndex + i);
  962. if (str == NULL)
  963. {
  964. break;
  965. }
  966. RtlInitAnsiString(&ansiString, str);
  967. unicodeString.MaximumLength = (ansiString.Length * sizeof(WCHAR)) + sizeof(UNICODE_NULL);
  968. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE);
  969. if (!NT_SUCCESS(status))
  970. {
  971. break;
  972. }
  973. }
  974. //
  975. // Terminate the multi-sz string.
  976. //
  977. if (i == count)
  978. {
  979. unicodeString.Buffer[0] = UNICODE_NULL;
  980. status = STATUS_SUCCESS;
  981. }
  982. }
  983. else
  984. {
  985. ASSERT(*Data);
  986. status = STATUS_NO_MEMORY;
  987. }
  988. }
  989. }
  990. break;
  991. case REG_BINARY:
  992. default:
  993. //
  994. // Free form binary data.
  995. //
  996. if (CmpGetBinaryField( InfHandle,
  997. Section,
  998. LineIndex,
  999. ValueIndex,
  1000. NULL,
  1001. 0,
  1002. DataSize) && *DataSize)
  1003. {
  1004. *Data = ExAllocatePoolWithTag(PagedPool, *DataSize, CM_GENINST_TAG);
  1005. if (*Data)
  1006. {
  1007. if (CmpGetBinaryField( InfHandle,
  1008. Section,
  1009. LineIndex,
  1010. 4,
  1011. *Data,
  1012. *DataSize,
  1013. NULL))
  1014. {
  1015. status = STATUS_SUCCESS;
  1016. }
  1017. }
  1018. else
  1019. {
  1020. ASSERT(*Data);
  1021. status = STATUS_NO_MEMORY;
  1022. }
  1023. }
  1024. else
  1025. {
  1026. status = STATUS_UNSUCCESSFUL;
  1027. }
  1028. break;
  1029. }
  1030. return (status);
  1031. }
  1032. NTSTATUS
  1033. CmpOpenRegKey(
  1034. IN OUT PHANDLE Key,
  1035. IN OUT PULONG Disposition,
  1036. IN PCHAR Root,
  1037. IN PCHAR SubKey,
  1038. IN ULONG DesiredAccess,
  1039. IN BOOLEAN Create
  1040. )
  1041. /*++
  1042. Routine Description:
  1043. This routine opens\creates a handle to the registry key.
  1044. Input Parameters:
  1045. Key - Receives the handle to the key.
  1046. Disposition - Receives the disposition of the key.
  1047. Root - Abbreviated name of the root key.
  1048. SubKey - Name of the subkey under the root.
  1049. DesiredAccess - Desired access flags for the key.
  1050. Create - TRUE if the key needs to be created instead of opened.
  1051. Return Value:
  1052. Standard NT status value.
  1053. --*/
  1054. {
  1055. NTSTATUS status = STATUS_OBJECT_NAME_INVALID;
  1056. SIZE_T size;
  1057. PCHAR str;
  1058. ANSI_STRING ansiString;
  1059. UNICODE_STRING unicodeString;
  1060. OBJECT_ATTRIBUTES objectAttributes;
  1061. str = NULL;
  1062. size = strlen(SubKey) + 1;
  1063. //
  1064. // Check if we understand the specified root name.
  1065. //
  1066. if (_stricmp(Root, "HKLM") == 0)
  1067. {
  1068. size += (sizeof("\\Registry\\Machine\\") - 1); // Already added one above for NULL
  1069. str = ExAllocatePoolWithTag(PagedPool, size, CM_GENINST_TAG);
  1070. if (str)
  1071. {
  1072. _snprintf(str, size, "\\Registry\\Machine\\%s", SubKey);
  1073. str[size - 1] = 0;
  1074. }
  1075. else
  1076. {
  1077. ASSERT(str);
  1078. status = STATUS_NO_MEMORY;
  1079. }
  1080. }
  1081. else
  1082. {
  1083. ASSERT(_stricmp(Root, "HKLM") == 0);
  1084. }
  1085. //
  1086. // Proceed if we have a valid key name.
  1087. //
  1088. if (str)
  1089. {
  1090. RtlInitAnsiString(&ansiString, str);
  1091. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
  1092. if (NT_SUCCESS(status))
  1093. {
  1094. InitializeObjectAttributes( &objectAttributes,
  1095. &unicodeString,
  1096. OBJ_CASE_INSENSITIVE,
  1097. NULL,
  1098. NULL);
  1099. if (Create)
  1100. {
  1101. //
  1102. // Create a new key or open an existing one.
  1103. //
  1104. status = NtCreateKey( Key,
  1105. DesiredAccess,
  1106. &objectAttributes,
  1107. 0,
  1108. NULL,
  1109. REG_OPTION_NON_VOLATILE,
  1110. Disposition ? Disposition : (PULONG)&size);
  1111. }
  1112. else
  1113. {
  1114. //
  1115. // Open existing key.
  1116. //
  1117. if (Disposition)
  1118. {
  1119. *Disposition = REG_OPENED_EXISTING_KEY;
  1120. }
  1121. status = NtOpenKey( Key,
  1122. DesiredAccess,
  1123. &objectAttributes);
  1124. }
  1125. RtlFreeUnicodeString(&unicodeString);
  1126. }
  1127. else
  1128. {
  1129. ASSERT(NT_SUCCESS(status));
  1130. }
  1131. ExFreePool(str);
  1132. }
  1133. return (status);
  1134. }
  1135. NTSTATUS
  1136. CmpAppendStringToMultiSz(
  1137. IN HANDLE Key,
  1138. IN PCHAR ValueName,
  1139. IN OUT PVOID *Data,
  1140. IN OUT PULONG DataSize
  1141. )
  1142. /*++
  1143. Routine Description:
  1144. This routine opens\creates a handle to the registry key.
  1145. Input Parameters:
  1146. Key - Receives the handle to the key.
  1147. ValueName - Name of the value to be appended to.
  1148. Data - Buffer containing the multi-sz to be appended.
  1149. DataSize - Size of the data.
  1150. Return Value:
  1151. Standard NT status value.
  1152. --*/
  1153. {
  1154. NTSTATUS status;
  1155. ULONG size;
  1156. ANSI_STRING ansiString;
  1157. UNICODE_STRING unicodeString;
  1158. PKEY_VALUE_FULL_INFORMATION valueInfo;
  1159. PVOID buffer;
  1160. PVOID str;
  1161. ASSERT(DataSize && *DataSize);
  1162. ASSERT(*Data);
  1163. RtlInitAnsiString(&ansiString, ValueName);
  1164. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
  1165. if (NT_SUCCESS(status))
  1166. {
  1167. size = 0;
  1168. status = NtQueryValueKey( Key,
  1169. &unicodeString,
  1170. KeyValueFullInformation,
  1171. NULL,
  1172. 0,
  1173. &size);
  1174. if (size)
  1175. {
  1176. buffer = ExAllocatePoolWithTag(PagedPool, size, CM_GENINST_TAG);
  1177. if (buffer)
  1178. {
  1179. status = NtQueryValueKey( Key,
  1180. &unicodeString,
  1181. KeyValueFullInformation,
  1182. buffer,
  1183. size,
  1184. &size);
  1185. if (NT_SUCCESS(status))
  1186. {
  1187. valueInfo = (PKEY_VALUE_FULL_INFORMATION)buffer;
  1188. str = ExAllocatePoolWithTag( PagedPool,
  1189. valueInfo->DataLength +
  1190. *DataSize - sizeof(UNICODE_NULL),
  1191. CM_GENINST_TAG);
  1192. if (str)
  1193. {
  1194. memcpy( str,
  1195. (PCHAR)buffer + valueInfo->DataOffset,
  1196. valueInfo->DataLength);
  1197. memcpy( (PCHAR)str + valueInfo->DataLength - sizeof(UNICODE_NULL),
  1198. *Data,
  1199. *DataSize);
  1200. ExFreePool(*Data);
  1201. *Data = str;
  1202. *DataSize += valueInfo->DataLength - sizeof(UNICODE_NULL);
  1203. }
  1204. else
  1205. {
  1206. #ifndef _CM_LDR_
  1207. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpAppendStringToMultiSz: Failed to allocate memory!\n");
  1208. #endif //_CM_LDR_
  1209. ASSERT(str);
  1210. status = STATUS_NO_MEMORY;
  1211. }
  1212. }
  1213. ExFreePool(buffer);
  1214. }
  1215. else
  1216. {
  1217. #ifndef _CM_LDR_
  1218. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpAppendStringToMultiSz: Failed to allocate memory!\n");
  1219. #endif //_CM_LDR_
  1220. ASSERT(buffer);
  1221. status = STATUS_NO_MEMORY;
  1222. }
  1223. }
  1224. RtlFreeUnicodeString(&unicodeString);
  1225. }
  1226. return (status);
  1227. }
  1228. #ifdef ALLOC_DATA_PRAGMA
  1229. #pragma const_seg()
  1230. #endif