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.

911 lines
26 KiB

  1. //*************************************************************
  2. //
  3. // Hash table for registry Rsop data
  4. //
  5. // Microsoft Confidential
  6. // Copyright (c) Microsoft Corporation 1999
  7. // All rights reserved
  8. //
  9. // History: 7-Jun-99 SitaramR Created
  10. //
  11. //*************************************************************
  12. #include "uenv.h"
  13. #include "reghash.h"
  14. #include "rsop.h"
  15. #include <strsafe.h>
  16. REGKEYENTRY * AllocRegKeyEntry( WCHAR *pwszKeyName );
  17. void FreeRegKeyEntry( REGKEYENTRY *pKeyEntry );
  18. REGVALUEENTRY *AllocValueEntry( WCHAR *pwszValueName );
  19. void FreeValueEntry( REGVALUEENTRY *pValueEntry );
  20. REGDATAENTRY * AllocDataEntry( REGOPERATION opnType,
  21. DWORD dwType,
  22. DWORD dwLen,
  23. BYTE *pData,
  24. WCHAR *pwszGPO,
  25. WCHAR *pwszSOM,
  26. WCHAR *pwszCommand);
  27. void FreeDataEntry( REGDATAENTRY *pDataEntry );
  28. BOOL DeleteRegTree( REGHASHTABLE *pHashTable,
  29. WCHAR *pwszKeyName,
  30. WCHAR *pwszGPO,
  31. WCHAR *pwszSOM,
  32. WCHAR *szCommand);
  33. REGKEYENTRY * FindRegKeyEntry( REGHASHTABLE *pHashTable,
  34. WCHAR *pwszKeyName,
  35. BOOL bCreate );
  36. REGVALUEENTRY * FindValueEntry( REGHASHTABLE *pHashTable,
  37. WCHAR *pwszKeyName,
  38. WCHAR *pwszValueName,
  39. BOOL bCreate );
  40. BOOL AddDataEntry( REGVALUEENTRY *pValueEntry,
  41. REGOPERATION opnType,
  42. DWORD dwType,
  43. DWORD dwLen,
  44. BYTE *pData,
  45. WCHAR *pwszGPO,
  46. WCHAR *pwszSOM,
  47. WCHAR *pwszCommand);
  48. ////////////////////////////////////////////////////////////////////////
  49. // Hash Table for registry policies
  50. // ----------------------------------
  51. //
  52. // This hash table is used to log rsop data for registry policies.
  53. // A hash table entry is created for each registry entry. The registry entry
  54. // name itself is used to calculate the hash table.
  55. //
  56. // Each Registry entry has a link to each of the values modified by policy.
  57. // These values are in a link list and sorted by the valueNames.
  58. //
  59. // Each Value has the list of Data that are being set on the Values. This
  60. // sorted by the order of execution. The topmost value will contain the final value.
  61. // The Data entries have fields that mark the value as deleted and the Command
  62. // associated with the action. To look for the possible commands look in the
  63. // ParseRegistryFile.
  64. //
  65. // Additionally, in the hash table 2 special case values exist.
  66. // a. **Command Value. The Data under this value will contain all the commands
  67. // that are executed under this key.
  68. //
  69. // b. An ""(Empty ValueName) This valuename represents the modifications happening
  70. // to the key itself. For example a key can deleted or added..
  71. //
  72. // Note:
  73. // The szCommand that is passed in has to be non NULL but can be an empty string.
  74. // There is a dependency on it in AddDataEntry and in logger.cpp. There is an Assert
  75. // for this in AddRegHashEntry
  76. //
  77. ////////////////////////////////////////////////////////////////////////
  78. //*************************************************************
  79. //
  80. // AllocHashTable
  81. //
  82. // Purpose: Allocates a new hash table
  83. //
  84. // Returns: Pointer to hash table
  85. //
  86. //*************************************************************
  87. REGHASHTABLE * AllocHashTable()
  88. {
  89. DWORD i;
  90. REGHASHTABLE *pHashTable = (REGHASHTABLE *) LocalAlloc (LPTR, sizeof(REGHASHTABLE));
  91. if ( pHashTable == NULL ) {
  92. DebugMsg((DM_WARNING, TEXT("AllocHashTable: Failed to alloc hashtable.")));
  93. return NULL;
  94. }
  95. for ( i=0; i<HASH_TABLE_SIZE; i++) {
  96. pHashTable->aHashTable[i] = 0;
  97. }
  98. pHashTable->hrError = S_OK;
  99. return pHashTable;
  100. }
  101. //*************************************************************
  102. //
  103. // FreeHashTable
  104. //
  105. // Purpose: Deletes a hash table
  106. //
  107. // Parameters: pHashTable - Hash table to delete
  108. //
  109. //*************************************************************
  110. void FreeHashTable( REGHASHTABLE *pHashTable )
  111. {
  112. DWORD i;
  113. if ( pHashTable == NULL )
  114. return;
  115. for ( i=0; i<HASH_TABLE_SIZE; i++ ) {
  116. REGKEYENTRY *pKeyEntry = pHashTable->aHashTable[i];
  117. while ( pKeyEntry ) {
  118. REGKEYENTRY *pNext = pKeyEntry->pNext;
  119. FreeRegKeyEntry( pKeyEntry );
  120. pKeyEntry = pNext;
  121. }
  122. }
  123. }
  124. //*************************************************************
  125. //
  126. // AllocRegKey
  127. //
  128. // Purpose: Allocates a new registry key entry
  129. //
  130. // Returns: Pointer to registr key entry
  131. //
  132. //*************************************************************
  133. REGKEYENTRY * AllocRegKeyEntry( WCHAR *pwszKeyName )
  134. {
  135. REGKEYENTRY *pKeyEntry = (REGKEYENTRY *) LocalAlloc (LPTR, sizeof(REGKEYENTRY));
  136. if ( pKeyEntry == NULL ) {
  137. DebugMsg((DM_WARNING, TEXT("AllocRegKeyEntry: Failed to alloc key entry.")));
  138. return NULL;
  139. }
  140. DWORD dwKeyNameLength = lstrlen(pwszKeyName) + 1;
  141. pKeyEntry->pwszKeyName = (WCHAR *) LocalAlloc (LPTR, ( dwKeyNameLength ) * sizeof(WCHAR));
  142. if ( pKeyEntry->pwszKeyName == NULL ) {
  143. DebugMsg((DM_WARNING, TEXT("AllocRegKeyEntry: Failed to alloc key name.")));
  144. LocalFree( pKeyEntry );
  145. return NULL;
  146. }
  147. HRESULT hr = StringCchCopy( pKeyEntry->pwszKeyName, dwKeyNameLength, pwszKeyName );
  148. if(FAILED(hr)){
  149. LocalFree( pKeyEntry->pwszKeyName );
  150. LocalFree( pKeyEntry );
  151. return NULL;
  152. }
  153. return pKeyEntry;
  154. }
  155. //*************************************************************
  156. //
  157. // FreeRegKeyEntry
  158. //
  159. // Purpose: Deletes a registry key entry
  160. //
  161. // Parameters: pKeyEntry - Entry to delete
  162. //
  163. //*************************************************************
  164. void FreeRegKeyEntry( REGKEYENTRY *pKeyEntry )
  165. {
  166. REGVALUEENTRY *pValueEntry = NULL;
  167. if ( pKeyEntry == NULL )
  168. return;
  169. LocalFree( pKeyEntry->pwszKeyName );
  170. pValueEntry = pKeyEntry->pValueList;
  171. while ( pValueEntry ) {
  172. REGVALUEENTRY *pNext = pValueEntry->pNext;
  173. FreeValueEntry( pValueEntry );
  174. pValueEntry = pNext;
  175. }
  176. LocalFree( pKeyEntry );
  177. }
  178. //*************************************************************
  179. //
  180. // AllocValueEntry
  181. //
  182. // Purpose: Allocates a new value entry
  183. //
  184. // Returns: Pointer to value entry
  185. //
  186. //*************************************************************
  187. REGVALUEENTRY *AllocValueEntry( WCHAR *pwszValueName )
  188. {
  189. REGVALUEENTRY *pValueEntry = (REGVALUEENTRY *) LocalAlloc (LPTR, sizeof(REGVALUEENTRY));
  190. if ( pValueEntry == NULL ) {
  191. DebugMsg((DM_WARNING, TEXT("AllocValueEntry: Failed to alloc value entry.")));
  192. return NULL;
  193. }
  194. DWORD dwValNameLength = lstrlen(pwszValueName) + 1;
  195. pValueEntry->pwszValueName = (WCHAR *) LocalAlloc (LPTR, ( dwValNameLength ) * sizeof(WCHAR));
  196. if ( pValueEntry->pwszValueName == NULL ) {
  197. DebugMsg((DM_WARNING, TEXT("AllocValueEntry: Failed to alloc key name.")));
  198. LocalFree( pValueEntry );
  199. return NULL;
  200. }
  201. HRESULT hr = StringCchCopy( pValueEntry->pwszValueName, dwValNameLength, pwszValueName );
  202. if(FAILED(hr)){
  203. LocalFree( pValueEntry->pwszValueName );
  204. LocalFree( pValueEntry );
  205. return NULL;
  206. }
  207. return pValueEntry;
  208. }
  209. //*************************************************************
  210. //
  211. // FreeValueEntry
  212. //
  213. // Purpose: Deletes a value entry
  214. //
  215. // Parameters: pValueEntry - Entry to delete
  216. //
  217. //*************************************************************
  218. void FreeValueEntry( REGVALUEENTRY *pValueEntry )
  219. {
  220. REGDATAENTRY *pDataEntry = NULL;
  221. if ( pValueEntry == NULL )
  222. return;
  223. LocalFree( pValueEntry->pwszValueName );
  224. pDataEntry = pValueEntry->pDataList;
  225. while ( pDataEntry ) {
  226. REGDATAENTRY *pNext = pDataEntry->pNext;
  227. FreeDataEntry( pDataEntry );
  228. pDataEntry = pNext;
  229. }
  230. LocalFree( pValueEntry );
  231. }
  232. //*************************************************************
  233. //
  234. // AllocDataEntry
  235. //
  236. // Purpose: Allocates a new data entry
  237. //
  238. // Returns: Pointer to data entry
  239. //
  240. //*************************************************************
  241. REGDATAENTRY * AllocDataEntry( REGOPERATION opnType,
  242. DWORD dwType,
  243. DWORD dwLen,
  244. BYTE *pData,
  245. WCHAR *pwszGPO,
  246. WCHAR *pwszSOM,
  247. WCHAR *pwszCommand)
  248. {
  249. BOOL bResult = FALSE;
  250. REGDATAENTRY *pDataEntry = (REGDATAENTRY *) LocalAlloc (LPTR, sizeof(REGDATAENTRY));
  251. if ( pDataEntry == NULL ) {
  252. DebugMsg((DM_WARNING, TEXT("AllocDataEntry: Failed to alloc data entry.")));
  253. return NULL;
  254. }
  255. if ( opnType == REG_ADDVALUE )
  256. pDataEntry->bDeleted = FALSE;
  257. else
  258. pDataEntry->bDeleted = TRUE;
  259. pDataEntry->bAdmPolicy = FALSE;
  260. pDataEntry->dwValueType = dwType;
  261. pDataEntry->dwDataLen = dwLen;
  262. if ( pData ) {
  263. pDataEntry->pData = (BYTE *) LocalAlloc (LPTR, dwLen);
  264. if ( pDataEntry->pData == NULL ) {
  265. DebugMsg((DM_WARNING, TEXT("AllocDataEntry: Failed to alloc data.")));
  266. goto Exit;
  267. }
  268. CopyMemory( pDataEntry->pData, pData, dwLen );
  269. }
  270. DmAssert( pwszGPO != NULL && pwszSOM != NULL );
  271. DWORD dwGPOLength = lstrlen(pwszGPO) + 1;
  272. pDataEntry->pwszGPO = (WCHAR *) LocalAlloc (LPTR, ( dwGPOLength ) * sizeof(WCHAR));
  273. if ( pDataEntry->pwszGPO == NULL ) {
  274. DebugMsg((DM_WARNING, TEXT("AllocDataEntry: Failed to alloc Gpo name.")));
  275. goto Exit;
  276. }
  277. HRESULT hr = StringCchCopy( pDataEntry->pwszGPO, dwGPOLength, pwszGPO );
  278. if(FAILED(hr))
  279. goto Exit;
  280. DWORD dwSOMLength = lstrlen(pwszSOM) + 1;
  281. pDataEntry->pwszSOM = (WCHAR *) LocalAlloc (LPTR, ( dwSOMLength ) * sizeof(WCHAR));
  282. if ( pDataEntry->pwszSOM == NULL ) {
  283. DebugMsg((DM_WARNING, TEXT("AllocDataEntry: Failed to alloc Sdou name.")));
  284. goto Exit;
  285. }
  286. hr = StringCchCopy( pDataEntry->pwszSOM, dwSOMLength, pwszSOM );
  287. if(FAILED(hr))
  288. goto Exit;
  289. DWORD dwCmdLength = lstrlen(pwszCommand) + 1;
  290. pDataEntry->pwszCommand = (WCHAR *) LocalAlloc (LPTR, ( dwCmdLength ) * sizeof(WCHAR));
  291. if ( pDataEntry->pwszCommand == NULL ) {
  292. DebugMsg((DM_WARNING, TEXT("AllocDataEntry: Failed to alloc Sdou name.")));
  293. goto Exit;
  294. }
  295. hr = StringCchCopy( pDataEntry->pwszCommand, dwCmdLength, pwszCommand );
  296. if(FAILED(hr))
  297. goto Exit;
  298. bResult = TRUE;
  299. Exit:
  300. if ( !bResult ) {
  301. LocalFree( pDataEntry->pData );
  302. LocalFree( pDataEntry->pwszGPO );
  303. LocalFree( pDataEntry->pwszSOM );
  304. if (pDataEntry->pwszCommand)
  305. LocalFree(pDataEntry->pwszCommand);
  306. LocalFree( pDataEntry);
  307. return NULL;
  308. }
  309. return pDataEntry;
  310. }
  311. //*************************************************************
  312. //
  313. // FreeDataEntry
  314. //
  315. // Purpose: Deletes a data entry
  316. //
  317. // Parameters: pDataEntry - Entry to delete
  318. //
  319. //*************************************************************
  320. void FreeDataEntry( REGDATAENTRY *pDataEntry )
  321. {
  322. if ( pDataEntry ) {
  323. LocalFree( pDataEntry->pData );
  324. LocalFree( pDataEntry->pwszGPO );
  325. LocalFree( pDataEntry->pwszSOM );
  326. LocalFree( pDataEntry);
  327. }
  328. }
  329. //*************************************************************
  330. //
  331. // Hash
  332. //
  333. // Purpose: Maps a key name to a hash bucket
  334. //
  335. // Parameters: pwszName - Key name
  336. //
  337. // Returns: Hash bucket
  338. //
  339. //*************************************************************
  340. DWORD Hash( WCHAR *pwszName )
  341. {
  342. DWORD dwLen = lstrlen( pwszName );
  343. DWORD dwHashValue = 0;
  344. for ( ; dwLen>0; pwszName++ ) {
  345. dwHashValue = toupper(*pwszName) + 31 * dwHashValue;
  346. dwLen--;
  347. }
  348. return dwHashValue % HASH_TABLE_SIZE;
  349. }
  350. //*************************************************************
  351. //
  352. // AddRegHashEntry
  353. //
  354. // Purpose: Adds a registry key to the hash table
  355. //
  356. // Parameters: pwszName - Key name
  357. //
  358. //*************************************************************
  359. BOOL AddRegHashEntry( REGHASHTABLE *pHashTable,
  360. REGOPERATION opnType,
  361. WCHAR *pwszKeyName,
  362. WCHAR *pwszValueName,
  363. DWORD dwType,
  364. DWORD dwDataLen,
  365. BYTE *pData,
  366. WCHAR *pwszGPO,
  367. WCHAR *pwszSOM,
  368. WCHAR *szCommand,
  369. BOOL bCreateCommand)
  370. {
  371. REGVALUEENTRY *pValueEntry = NULL;
  372. BOOL bResult = FALSE;
  373. REGKEYENTRY *pKeyEntry=NULL;
  374. switch (opnType) {
  375. case REG_DELETEKEY:
  376. bResult = DeleteRegTree( pHashTable, pwszKeyName, pwszGPO, pwszSOM, szCommand );
  377. break;
  378. case REG_INTERNAL_DELETESINGLEKEY:
  379. case REG_DELETEALLVALUES:
  380. pKeyEntry = FindRegKeyEntry( pHashTable,
  381. pwszKeyName,
  382. FALSE );
  383. if ( pKeyEntry == NULL ) {
  384. //
  385. // Delete all values is similar to policy being disabled and
  386. // so do nothing.
  387. //
  388. if (opnType == REG_DELETEALLVALUES) {
  389. bResult = TRUE;
  390. break;
  391. }
  392. else
  393. // no command entry in this case.
  394. return TRUE;
  395. }
  396. pValueEntry = pKeyEntry->pValueList;
  397. while ( pValueEntry ) {
  398. if (lstrcmp(pValueEntry->pwszValueName, TEXT("")) != 0) {
  399. if (CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, pValueEntry->pwszValueName, -1, STARCOMMAND, -1) != CSTR_EQUAL) {
  400. //
  401. // Mark the value as deleted
  402. //
  403. bResult = AddDataEntry( pValueEntry, opnType, 0, 0, NULL,
  404. pwszGPO, pwszSOM, szCommand );
  405. if ( !bResult )
  406. return FALSE;
  407. }
  408. }
  409. else {
  410. //
  411. // Mark the key as deleted
  412. //
  413. if (opnType == REG_INTERNAL_DELETESINGLEKEY) {
  414. bResult = AddDataEntry( pValueEntry, opnType, 0, 0, NULL,
  415. pwszGPO, pwszSOM, szCommand );
  416. if ( !bResult )
  417. return FALSE;
  418. }
  419. }
  420. pValueEntry = pValueEntry->pNext;
  421. }
  422. bResult = TRUE;
  423. break;
  424. case REG_ADDVALUE:
  425. case REG_SOFTADDVALUE:
  426. //
  427. // We have to make a value with no name to represent the creation of key itself..
  428. //
  429. pValueEntry = FindValueEntry( pHashTable, pwszKeyName,
  430. TEXT(""), TRUE );
  431. if ( pValueEntry == NULL )
  432. return FALSE;
  433. bResult = AddDataEntry( pValueEntry, opnType, 0, 0, NULL,
  434. pwszGPO, pwszSOM, szCommand );
  435. if (!bResult)
  436. return FALSE;
  437. if ((!pwszValueName) || (!(*pwszValueName)) ||
  438. (dwDataLen == 0) || (dwType == REG_NONE))
  439. break;
  440. // fall through
  441. case REG_DELETEVALUE:
  442. pValueEntry = FindValueEntry( pHashTable, pwszKeyName,
  443. pwszValueName, TRUE );
  444. if ( pValueEntry == NULL )
  445. return FALSE;
  446. //
  447. // In case of SOFTADDVALUE the final decision to add the value is made in
  448. // AddDataEntry
  449. //
  450. bResult = AddDataEntry( pValueEntry, opnType, dwType, dwDataLen, pData,
  451. pwszGPO, pwszSOM, szCommand );
  452. break;
  453. default:
  454. DmAssert(FALSE && "Unknown Case Selector for AddRegHashEntry");
  455. }
  456. DmAssert(szCommand);
  457. //
  458. // If everything succeeded, then log the command if
  459. // bCreateCommand is true. This is done creating or adding
  460. // to a value called **Command. This means that this value is not
  461. // Settable by adm file..
  462. //
  463. if ((bResult) && (bCreateCommand) && (opnType != REG_INTERNAL_DELETESINGLEKEY) && (*szCommand != TEXT('\0'))) {
  464. pValueEntry = FindValueEntry( pHashTable, pwszKeyName,
  465. STARCOMMAND, TRUE );
  466. if ( pValueEntry == NULL )
  467. return FALSE;
  468. bResult = AddDataEntry( pValueEntry, REG_ADDVALUE, 0,
  469. sizeof(TCHAR)*(lstrlen(szCommand)+1), (BYTE *)szCommand,
  470. pwszGPO, pwszSOM, szCommand);
  471. }
  472. return bResult;
  473. }
  474. //*************************************************************
  475. //
  476. // DeleteRegTree
  477. //
  478. // Purpose: Deletes a key and all its subkeys
  479. //
  480. // Parameters: pHashTable - Hash table
  481. // pwszKeyName - Key name to delete
  482. // pwszGPO - Gpo
  483. // pwszSOM - Sdou that the Gpo is linked to
  484. //
  485. //*************************************************************
  486. BOOL DeleteRegTree( REGHASHTABLE *pHashTable,
  487. WCHAR *pwszKeyName,
  488. WCHAR *pwszGPO,
  489. WCHAR *pwszSOM,
  490. WCHAR *szCommand)
  491. {
  492. DWORD i=0;
  493. DWORD dwKeyLen = lstrlen( pwszKeyName );
  494. for ( i=0; i<HASH_TABLE_SIZE; i++ ) {
  495. REGKEYENTRY *pKeyEntry = pHashTable->aHashTable[i];
  496. while ( pKeyEntry ) {
  497. BOOL bAdd = FALSE;
  498. DWORD dwKeyLen2 = lstrlen(pKeyEntry->pwszKeyName);
  499. if ( dwKeyLen2 >= dwKeyLen
  500. && CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  501. pKeyEntry->pwszKeyName, dwKeyLen,
  502. pwszKeyName, dwKeyLen ) == CSTR_EQUAL) {
  503. //
  504. // It's a prefix if length and strings match, or if one
  505. // string is bigger and there is a '\' at the right place.
  506. //
  507. if ( dwKeyLen2 > dwKeyLen ) {
  508. if ( pKeyEntry->pwszKeyName[dwKeyLen] == L'\\' )
  509. bAdd = TRUE;
  510. } else
  511. bAdd = TRUE;
  512. if ( bAdd ) {
  513. BOOL bResult = AddRegHashEntry( pHashTable,
  514. REG_INTERNAL_DELETESINGLEKEY,
  515. pKeyEntry->pwszKeyName,
  516. NULL, 0, 0, NULL,
  517. pwszGPO, pwszSOM, szCommand, FALSE );
  518. if ( !bResult )
  519. return FALSE;
  520. }
  521. } // if dwKeyLen2 >= dwKeyLen
  522. pKeyEntry = pKeyEntry->pNext;
  523. } // while
  524. } // for
  525. return TRUE;
  526. }
  527. //*************************************************************
  528. //
  529. // FindRegKeyEntry
  530. //
  531. // Purpose: Looks up a reg key entry in hash table
  532. //
  533. // Parameters: pHashTable - Hash table
  534. // pwszKeyName - Key name to find
  535. // bCreate - Should key be created if not found ?
  536. //
  537. //*************************************************************
  538. REGKEYENTRY * FindRegKeyEntry( REGHASHTABLE *pHashTable,
  539. WCHAR *pwszKeyName,
  540. BOOL bCreate )
  541. {
  542. DWORD dwHashValue = Hash( pwszKeyName );
  543. REGKEYENTRY *pCurPtr = pHashTable->aHashTable[dwHashValue];
  544. REGKEYENTRY *pTrailPtr = NULL;
  545. while ( pCurPtr != NULL ) {
  546. INT iResult = CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  547. pwszKeyName, -1,
  548. pCurPtr->pwszKeyName, -1 );
  549. if ( iResult == CSTR_EQUAL ) {
  550. return pCurPtr;
  551. } else if ( iResult == CSTR_LESS_THAN ) {
  552. //
  553. // Keys are in ascending order, so insert if bCreate
  554. //
  555. if ( bCreate ) {
  556. REGKEYENTRY *pKeyEntry = AllocRegKeyEntry( pwszKeyName );
  557. if ( pKeyEntry == NULL )
  558. return 0;
  559. pKeyEntry->pNext = pCurPtr;
  560. if ( pTrailPtr == NULL )
  561. pHashTable->aHashTable[dwHashValue] = pKeyEntry;
  562. else
  563. pTrailPtr->pNext = pKeyEntry;
  564. return pKeyEntry;
  565. } else
  566. return NULL;
  567. } else {
  568. //
  569. // Advance down the list
  570. //
  571. pTrailPtr = pCurPtr;
  572. pCurPtr = pCurPtr->pNext;
  573. }
  574. }
  575. //
  576. // End of list or null list case
  577. //
  578. if ( bCreate ) {
  579. REGKEYENTRY *pKeyEntry = AllocRegKeyEntry( pwszKeyName );
  580. if ( pKeyEntry == NULL )
  581. return 0;
  582. pKeyEntry->pNext = 0;
  583. if ( pTrailPtr == NULL )
  584. pHashTable->aHashTable[dwHashValue] = pKeyEntry;
  585. else
  586. pTrailPtr->pNext = pKeyEntry;
  587. return pKeyEntry;
  588. }
  589. return NULL;
  590. }
  591. //*************************************************************
  592. //
  593. // FindValueEntry
  594. //
  595. // Purpose: Looks up a value entry in hash table
  596. //
  597. // Parameters: pHashTable - Hash table
  598. // pwszKeyName - Key name to find
  599. // pwszValueName - Value name to find
  600. // bCreate - Should key be created if not found ?
  601. //
  602. //*************************************************************
  603. REGVALUEENTRY * FindValueEntry( REGHASHTABLE *pHashTable,
  604. WCHAR *pwszKeyName,
  605. WCHAR *pwszValueName,
  606. BOOL bCreate )
  607. {
  608. REGVALUEENTRY *pCurPtr = NULL;
  609. REGVALUEENTRY *pTrailPtr = NULL;
  610. REGKEYENTRY *pKeyEntry = FindRegKeyEntry( pHashTable, pwszKeyName, bCreate );
  611. if ( pKeyEntry == NULL )
  612. return NULL;
  613. pCurPtr = pKeyEntry->pValueList;
  614. pTrailPtr = NULL;
  615. while ( pCurPtr != NULL ) {
  616. INT iResult = CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  617. pwszValueName, -1,
  618. pCurPtr->pwszValueName, -1 );
  619. if ( iResult == CSTR_EQUAL ) {
  620. return pCurPtr;
  621. } else if ( iResult == CSTR_LESS_THAN ) {
  622. //
  623. // Keys are in ascending order, so insert if bCreate
  624. //
  625. if ( bCreate ) {
  626. REGVALUEENTRY *pValueEntry = AllocValueEntry( pwszValueName );
  627. if ( pValueEntry == NULL )
  628. return 0;
  629. pValueEntry->pNext = pCurPtr;
  630. if ( pTrailPtr == NULL )
  631. pKeyEntry->pValueList = pValueEntry;
  632. else
  633. pTrailPtr->pNext = pValueEntry;
  634. return pValueEntry;
  635. } else
  636. return NULL;
  637. } else {
  638. //
  639. // Advance down the list
  640. //
  641. pTrailPtr = pCurPtr;
  642. pCurPtr = pCurPtr->pNext;
  643. }
  644. }
  645. //
  646. // End of list or null list case
  647. //
  648. if ( bCreate ) {
  649. REGVALUEENTRY *pValueEntry = AllocValueEntry( pwszValueName );
  650. if ( pValueEntry == NULL )
  651. return 0;
  652. pValueEntry->pNext = 0;
  653. if ( pTrailPtr == NULL )
  654. pKeyEntry->pValueList = pValueEntry;
  655. else
  656. pTrailPtr->pNext = pValueEntry;
  657. return pValueEntry;
  658. }
  659. return NULL;
  660. }
  661. //*************************************************************
  662. //
  663. // AddDataEntry
  664. //
  665. // Purpose: Adds a data entry to a value entry struct
  666. //
  667. // Parameters: pValueEntry - Value entry
  668. // opnType - Operation type
  669. // dwType - Type of registry data
  670. // dwLen - Length of registry data
  671. // pData - Data
  672. // pwszGPO - Gpo that set this value
  673. // pwszSOM - Sdou that the Gpo is linked to
  674. //
  675. //*************************************************************
  676. BOOL AddDataEntry( REGVALUEENTRY *pValueEntry,
  677. REGOPERATION opnType,
  678. DWORD dwType,
  679. DWORD dwLen,
  680. BYTE *pData,
  681. WCHAR *pwszGPO,
  682. WCHAR *pwszSOM,
  683. WCHAR *pwszCommand)
  684. {
  685. REGDATAENTRY *pDataEntry = NULL;
  686. if (opnType == REG_SOFTADDVALUE) {
  687. //
  688. // if the data list is null or if the first value (highest precedence value is deleted)
  689. // then add it to the list
  690. //
  691. if ((pValueEntry->pDataList == NULL) || (pValueEntry->pDataList->pNext->bDeleted))
  692. opnType = REG_ADDVALUE;
  693. else
  694. return TRUE;
  695. // return without adding the value.
  696. }
  697. pDataEntry = AllocDataEntry( opnType, dwType, dwLen, pData,
  698. pwszGPO, pwszSOM, pwszCommand );
  699. if ( pDataEntry == NULL )
  700. return FALSE;
  701. //
  702. // Prepend to data list because entries at beginning of list have higher precedence
  703. //
  704. pDataEntry->pNext = pValueEntry->pDataList;
  705. pValueEntry->pDataList = pDataEntry;
  706. return TRUE;
  707. }