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.

524 lines
14 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. key.c
  5. Abstract:
  6. This module implements the functions to save references to registry
  7. keys and values for the INSTALER program. Part of each reference is
  8. a a backup copy of a key information and its values that have been
  9. changed/deleted.
  10. Author:
  11. Steve Wood (stevewo) 22-Aug-1994
  12. Revision History:
  13. --*/
  14. #include "instaler.h"
  15. #define DEFAULT_KEY_VALUE_BUFFER_SIZE 512
  16. PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
  17. VOID
  18. BackupKeyInfo(
  19. PKEY_REFERENCE p
  20. )
  21. {
  22. NTSTATUS Status;
  23. UNICODE_STRING KeyName;
  24. OBJECT_ATTRIBUTES ObjectAttributes;
  25. HANDLE KeyHandle;
  26. KEY_FULL_INFORMATION KeyInformation;
  27. ULONG ResultLength;
  28. ULONG ValueIndex;
  29. UNICODE_STRING ValueName;
  30. PVALUE_REFERENCE ValueReference;
  31. RtlInitUnicodeString( &KeyName, p->Name );
  32. InitializeObjectAttributes( &ObjectAttributes,
  33. &KeyName,
  34. OBJ_CASE_INSENSITIVE,
  35. NULL,
  36. NULL
  37. );
  38. Status = NtOpenKey( &KeyHandle,
  39. KEY_READ,
  40. &ObjectAttributes
  41. );
  42. if (!NT_SUCCESS( Status )) {
  43. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  44. p->Created = TRUE;
  45. p->WriteAccess = TRUE;
  46. }
  47. fprintf( InstalerLogFile, "*** Unable to open key %ws (%x)\n", p->Name, Status );
  48. return;
  49. }
  50. if (!p->WriteAccess) {
  51. NtClose( KeyHandle );
  52. return;
  53. }
  54. fprintf( InstalerLogFile, "Saving values for %ws\n", p->Name );
  55. if (KeyValueInformation == NULL) {
  56. KeyValueInformation = AllocMem( DEFAULT_KEY_VALUE_BUFFER_SIZE );
  57. if (KeyValueInformation == NULL) {
  58. fprintf( InstalerLogFile, "*** No memory for key value information\n" );
  59. return;
  60. }
  61. }
  62. Status = NtQueryKey( KeyHandle,
  63. KeyFullInformation,
  64. &KeyInformation,
  65. sizeof( KeyInformation ),
  66. &ResultLength
  67. );
  68. if (!NT_SUCCESS( Status ) && Status != STATUS_BUFFER_OVERFLOW) {
  69. NtClose( KeyHandle );
  70. fprintf( InstalerLogFile, "*** Unable to query key (%x)\n", Status );
  71. return;
  72. }
  73. p->BackupKeyInfo = AllocMem( ResultLength );
  74. if (p->BackupKeyInfo == NULL) {
  75. NtClose( KeyHandle );
  76. fprintf( InstalerLogFile, "*** No memory for backup information\n" );
  77. return;
  78. }
  79. if (!NT_SUCCESS( Status )) {
  80. Status = NtQueryKey( KeyHandle,
  81. KeyFullInformation,
  82. p->BackupKeyInfo,
  83. ResultLength,
  84. &ResultLength
  85. );
  86. if (!NT_SUCCESS( Status )) {
  87. NtClose( KeyHandle );
  88. fprintf( InstalerLogFile, "*** Unable to query key (%x)\n", Status );
  89. return;
  90. }
  91. }
  92. else {
  93. memmove( p->BackupKeyInfo, &KeyInformation, ResultLength );
  94. }
  95. for (ValueIndex = 0; TRUE; ValueIndex++) {
  96. Status = NtEnumerateValueKey( KeyHandle,
  97. ValueIndex,
  98. KeyValueFullInformation,
  99. KeyValueInformation,
  100. DEFAULT_KEY_VALUE_BUFFER_SIZE,
  101. &ResultLength
  102. );
  103. if (!NT_SUCCESS( Status ) && Status != STATUS_BUFFER_OVERFLOW) {
  104. break;
  105. }
  106. ValueReference = AllocMem( FIELD_OFFSET( VALUE_REFERENCE, OriginalValue ) +
  107. FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data ) +
  108. KeyValueInformation->DataLength
  109. );
  110. if (ValueReference == NULL) {
  111. fprintf( InstalerLogFile, "*** No memory for value ref\n", Status );
  112. break;
  113. }
  114. if (KeyValueInformation->NameLength != 0) {
  115. ValueName.Length = (USHORT)KeyValueInformation->NameLength;
  116. ValueName.MaximumLength = ValueName.Length;
  117. ValueName.Buffer = KeyValueInformation->Name;
  118. ValueReference->Name = AddName( &ValueName );
  119. fprintf( InstalerLogFile, " Saving data for '%ws'\n", ValueReference->Name );
  120. }
  121. else {
  122. fprintf( InstalerLogFile, " Saving data for empty value name\n" );
  123. }
  124. if (Status == STATUS_BUFFER_OVERFLOW) {
  125. Status = NtEnumerateValueKey( KeyHandle,
  126. ValueIndex,
  127. KeyValuePartialInformation,
  128. &ValueReference->OriginalValue,
  129. FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data ) +
  130. KeyValueInformation->DataLength,
  131. &ResultLength
  132. );
  133. if (!NT_SUCCESS( Status )) {
  134. FreeMem( &ValueReference );
  135. break;
  136. }
  137. }
  138. else {
  139. ValueReference->OriginalValue.TitleIndex = KeyValueInformation->TitleIndex;
  140. ValueReference->OriginalValue.Type = KeyValueInformation->Type;
  141. ValueReference->OriginalValue.DataLength = KeyValueInformation->DataLength;
  142. memmove( &ValueReference->OriginalValue.Data,
  143. (PUCHAR)KeyValueInformation + KeyValueInformation->DataOffset,
  144. KeyValueInformation->DataLength
  145. );
  146. }
  147. InsertTailList( &p->ValueReferencesListHead, &ValueReference->Entry );
  148. }
  149. NtClose( KeyHandle );
  150. return;
  151. }
  152. BOOLEAN
  153. CreateKeyReference(
  154. PWSTR Name,
  155. BOOLEAN WriteAccess,
  156. PKEY_REFERENCE *ReturnedReference
  157. )
  158. {
  159. PKEY_REFERENCE p;
  160. *ReturnedReference = NULL;
  161. p = FindKeyReference( Name );
  162. if (p != NULL) {
  163. if (p->WriteAccess) {
  164. *ReturnedReference = p;
  165. return TRUE;
  166. }
  167. }
  168. else {
  169. p = AllocMem( sizeof( *p ) );
  170. if (p == NULL) {
  171. return FALSE;
  172. }
  173. p->Name = Name;
  174. InsertTailList( &KeyReferenceListHead, &p->Entry );
  175. NumberOfKeyReferences += 1;
  176. }
  177. InitializeListHead( &p->ValueReferencesListHead );
  178. p->WriteAccess = WriteAccess;
  179. BackupKeyInfo( p );
  180. *ReturnedReference = p;
  181. return TRUE;
  182. }
  183. BOOLEAN
  184. CompleteKeyReference(
  185. PKEY_REFERENCE p,
  186. BOOLEAN CallSuccessful,
  187. BOOLEAN Deleted
  188. )
  189. {
  190. if (!CallSuccessful) {
  191. DestroyKeyReference( p );
  192. return FALSE;
  193. }
  194. if (Deleted && p->Created) {
  195. LogEvent( INSTALER_EVENT_DELETE_TEMP_KEY,
  196. 1,
  197. p->Name
  198. );
  199. DestroyKeyReference( p );
  200. return FALSE;
  201. }
  202. if (Deleted) {
  203. LogEvent( INSTALER_EVENT_DELETE_KEY,
  204. 1,
  205. p->Name
  206. );
  207. }
  208. else
  209. if (p->WriteAccess) {
  210. LogEvent( INSTALER_EVENT_WRITE_KEY,
  211. 1,
  212. p->Name
  213. );
  214. }
  215. else {
  216. LogEvent( INSTALER_EVENT_READ_KEY,
  217. 1,
  218. p->Name
  219. );
  220. }
  221. p->Deleted = Deleted;
  222. return TRUE;
  223. }
  224. BOOLEAN
  225. DestroyKeyReference(
  226. PKEY_REFERENCE p
  227. )
  228. {
  229. RemoveEntryList( &p->Entry );
  230. NumberOfKeyReferences -= 1;
  231. FreeMem( &p );
  232. return TRUE;
  233. }
  234. PKEY_REFERENCE
  235. FindKeyReference(
  236. PWSTR Name
  237. )
  238. {
  239. PKEY_REFERENCE p;
  240. PLIST_ENTRY Head, Next;
  241. Head = &KeyReferenceListHead;
  242. Next = Head->Flink;
  243. while (Head != Next) {
  244. p = CONTAINING_RECORD( Next, KEY_REFERENCE, Entry );
  245. if (p->Name == Name) {
  246. return p;
  247. }
  248. Next = Next->Flink;
  249. }
  250. return NULL;
  251. }
  252. VOID
  253. MarkKeyDeleted(
  254. PKEY_REFERENCE KeyReference
  255. )
  256. {
  257. PVALUE_REFERENCE p;
  258. PLIST_ENTRY Head, Next;
  259. KeyReference->Deleted = TRUE;
  260. Head = &KeyReference->ValueReferencesListHead;
  261. Next = Head->Flink;
  262. while (Head != Next) {
  263. p = CONTAINING_RECORD( Next, VALUE_REFERENCE, Entry );
  264. Next = Next->Flink;
  265. if (p->Created || KeyReference->Created) {
  266. DestroyValueReference( p );
  267. }
  268. else {
  269. p->Deleted = TRUE;
  270. }
  271. }
  272. if (KeyReference->Created) {
  273. DestroyKeyReference( KeyReference );
  274. }
  275. return;
  276. }
  277. BOOLEAN
  278. CreateValueReference(
  279. PPROCESS_INFO Process,
  280. PKEY_REFERENCE KeyReference,
  281. PWSTR Name,
  282. ULONG TitleIndex,
  283. ULONG Type,
  284. PVOID Data,
  285. ULONG DataLength,
  286. PVALUE_REFERENCE *ReturnedValueReference
  287. )
  288. {
  289. PVALUE_REFERENCE p;
  290. PKEY_VALUE_PARTIAL_INFORMATION OldValue, NewValue;
  291. *ReturnedValueReference = NULL;
  292. NewValue = AllocMem( FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data ) +
  293. DataLength
  294. );
  295. if (NewValue == NULL) {
  296. return FALSE;
  297. }
  298. NewValue->TitleIndex = TitleIndex;
  299. NewValue->Type = Type;
  300. NewValue->DataLength = DataLength;
  301. if (!ReadMemory( Process,
  302. Data,
  303. &NewValue->Data[0],
  304. DataLength,
  305. "new value data"
  306. )
  307. ) {
  308. FreeMem( &NewValue );
  309. return FALSE;
  310. }
  311. p = FindValueReference( KeyReference, Name );
  312. if (p != NULL) {
  313. FreeMem( &p->Value );
  314. p->Value = NewValue;
  315. OldValue = &p->OriginalValue;
  316. if (OldValue->TitleIndex == NewValue->TitleIndex &&
  317. OldValue->Type == NewValue->Type &&
  318. OldValue->DataLength == NewValue->DataLength &&
  319. RtlCompareMemory( &OldValue->Data, &NewValue->Data, OldValue->DataLength )
  320. ) {
  321. FreeMem( &p->Value );
  322. }
  323. else {
  324. p->Modified = TRUE;
  325. }
  326. return TRUE;
  327. }
  328. p = AllocMem( FIELD_OFFSET( VALUE_REFERENCE, OriginalValue ) );
  329. if (p == NULL) {
  330. FreeMem( &NewValue );
  331. return FALSE;
  332. }
  333. p->Name = Name;
  334. p->Created = TRUE;
  335. p->Value = NewValue;
  336. InsertTailList( &KeyReference->ValueReferencesListHead, &p->Entry );
  337. *ReturnedValueReference = p;
  338. return TRUE;
  339. }
  340. PVALUE_REFERENCE
  341. FindValueReference(
  342. PKEY_REFERENCE KeyReference,
  343. PWSTR Name
  344. )
  345. {
  346. PVALUE_REFERENCE p;
  347. PLIST_ENTRY Head, Next;
  348. Head = &KeyReference->ValueReferencesListHead;
  349. Next = Head->Flink;
  350. while (Head != Next) {
  351. p = CONTAINING_RECORD( Next, VALUE_REFERENCE, Entry );
  352. if (p->Name == Name) {
  353. return p;
  354. }
  355. Next = Next->Flink;
  356. }
  357. return NULL;
  358. }
  359. BOOLEAN
  360. DestroyValueReference(
  361. PVALUE_REFERENCE p
  362. )
  363. {
  364. RemoveEntryList( &p->Entry );
  365. FreeMem( &p );
  366. return TRUE;
  367. }
  368. VOID
  369. DumpKeyReferenceList(
  370. FILE *LogFile
  371. )
  372. {
  373. PKEY_REFERENCE p;
  374. PLIST_ENTRY Head, Next;
  375. PVALUE_REFERENCE p1;
  376. PLIST_ENTRY Head1, Next1;
  377. PKEY_VALUE_PARTIAL_INFORMATION OldValue, NewValue;
  378. KEY_VALUE_PARTIAL_INFORMATION NullValue;
  379. POFFSET Values;
  380. memset( &NullValue, 0, sizeof( NullValue ) );
  381. NullValue.Type = REG_SZ;
  382. Head = &KeyReferenceListHead;
  383. Next = Head->Flink;
  384. while (Head != Next) {
  385. p = CONTAINING_RECORD( Next, KEY_REFERENCE, Entry );
  386. if (p->Created || p->WriteAccess) {
  387. Values = 0;
  388. Head1 = &p->ValueReferencesListHead;
  389. Next1 = Head1->Flink;
  390. while (Head1 != Next1) {
  391. p1 = CONTAINING_RECORD( Next1, VALUE_REFERENCE, Entry );
  392. NewValue = p1->Value;
  393. if (NewValue == NULL) {
  394. NewValue = &NullValue;
  395. }
  396. OldValue = &p1->OriginalValue;
  397. if (!p1->Deleted) {
  398. if (p1->Created) {
  399. ImlAddValueRecord( pImlNew,
  400. CreateNewValue,
  401. p1->Name,
  402. NewValue->Type,
  403. NewValue->DataLength,
  404. NewValue->Data,
  405. 0,
  406. 0,
  407. NULL,
  408. &Values
  409. );
  410. }
  411. else
  412. if (p1->Modified) {
  413. ImlAddValueRecord( pImlNew,
  414. ModifyOldValue,
  415. p1->Name,
  416. NewValue->Type,
  417. NewValue->DataLength,
  418. NewValue->Data,
  419. OldValue->Type,
  420. OldValue->DataLength,
  421. OldValue->Data,
  422. &Values
  423. );
  424. }
  425. }
  426. else {
  427. ImlAddValueRecord( pImlNew,
  428. DeleteOldValue,
  429. p1->Name,
  430. 0,
  431. 0,
  432. NULL,
  433. OldValue->Type,
  434. OldValue->DataLength,
  435. OldValue->Data,
  436. &Values
  437. );
  438. }
  439. Next1 = Next1->Flink;
  440. }
  441. ImlAddKeyRecord( pImlNew,
  442. p->Created ? CreateNewKey :
  443. p->Deleted ? DeleteOldKey : ModifyKeyValues,
  444. p->Name,
  445. Values
  446. );
  447. }
  448. Next = Next->Flink;
  449. }
  450. return;
  451. }