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.

1575 lines
39 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. registry.c
  5. Abstract:
  6. Implementation of registry code.
  7. Author:
  8. Wesley Witt (wesw) 18-Dec-1998
  9. Revision History:
  10. Andrew Ritz (andrewr) 7-Jul-1999 : added comments
  11. --*/
  12. #include "sfcp.h"
  13. #pragma hdrstop
  14. //
  15. // this is a list of all of the files that we protect on the system. note that
  16. // there is no such thing as a tier 1 file anymore, only tier 2 files.
  17. //
  18. PPROTECT_FILE_ENTRY Tier2Files;
  19. //
  20. // this is the total number of files we're protecting
  21. //
  22. ULONG CountTier2Files;
  23. //
  24. // used to signal the watcher that the next change
  25. // type is expected to the this type and if so the
  26. // change should be ignored
  27. //
  28. ULONG* IgnoreNextChange = NULL;
  29. ULARGE_INTEGER LastExemptionTime;
  30. NTSTATUS
  31. InitializeUnicodeString(
  32. IN PWSTR StrVal,
  33. IN ULONG StrLen, OPTIONAL
  34. OUT PUNICODE_STRING String
  35. )
  36. /*++
  37. Routine Description:
  38. Initialize a unicode_string given a unicode string pointer. this function
  39. handles NULL strings and initializes the unicode string buffer to NULL in
  40. this case
  41. Arguments:
  42. StrVal - pointer to null terminated unicode string
  43. StrLen - length in characters of unicode string. if not specified,
  44. we use the length of the string.
  45. String - pointer to a UNICODE_STRING structure that is filled in by
  46. this function.
  47. Return Value:
  48. NTSTATUS code indicating outcome.
  49. --*/
  50. {
  51. ASSERT(String != NULL);
  52. if (StrVal == NULL) {
  53. String->Length = 0;
  54. String->MaximumLength = 0;
  55. String->Buffer = NULL;
  56. return STATUS_SUCCESS;
  57. }
  58. //
  59. // if the length was specified by the user, use that, otherwise use the
  60. // string length
  61. //
  62. String->Length = StrLen ? (USHORT)StrLen : (USHORT)UnicodeLen(StrVal);
  63. //
  64. // just say that the length is twice what we calculated as the current
  65. // length.
  66. //
  67. String->MaximumLength = String->Length + (sizeof(WCHAR)*2);
  68. String->Buffer = (PWSTR) MemAlloc( String->MaximumLength );
  69. if (String->Buffer == NULL) {
  70. return STATUS_NO_MEMORY;
  71. }
  72. RtlMoveMemory( String->Buffer, StrVal, String->Length );
  73. return STATUS_SUCCESS;
  74. }
  75. ULONG
  76. SfcQueryRegDword(
  77. PCWSTR KeyNameStr,
  78. PCWSTR ValueNameStr,
  79. ULONG DefaultValue
  80. )
  81. /*++
  82. Routine Description:
  83. retrieve a DWORD from the registry. if the value is not present or cannot
  84. be retrieved, we use a default value. calls registry api's using NT apis
  85. instead of win32 apis.
  86. Arguments:
  87. KeyNameStr - contains registry keyname to look for value under.
  88. ValueNameStr - contains registry value to retreive.
  89. DefaultValue - if we have problems retreiving the registry key or it is
  90. not set, use this default value.
  91. Return Value:
  92. registry DWORD value or default value if registry cannot be retreived.
  93. --*/
  94. {
  95. NTSTATUS Status;
  96. UNICODE_STRING KeyName;
  97. UNICODE_STRING ValueName;
  98. OBJECT_ATTRIBUTES ObjectAttributes;
  99. HANDLE Key;
  100. WCHAR ValueBuffer[VALUE_BUFFER_SIZE];
  101. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
  102. ULONG ValueLength;
  103. //
  104. // Open the registry key.
  105. //
  106. ASSERT((KeyNameStr != NULL) && (ValueNameStr != NULL));
  107. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
  108. RtlInitUnicodeString( &KeyName, KeyNameStr );
  109. InitializeObjectAttributes(
  110. &ObjectAttributes,
  111. &KeyName,
  112. OBJ_CASE_INSENSITIVE,
  113. NULL,
  114. NULL
  115. );
  116. Status = NtOpenKey(&Key, KEY_READ, &ObjectAttributes);
  117. if (!NT_SUCCESS(Status)) {
  118. DebugPrint2( LVL_VERBOSE, L"can't open %ws key: 0x%x", KeyNameStr, Status );
  119. return DefaultValue;
  120. }
  121. //
  122. // Query the key value.
  123. //
  124. RtlInitUnicodeString( &ValueName, ValueNameStr );
  125. Status = NtQueryValueKey(
  126. Key,
  127. &ValueName,
  128. KeyValuePartialInformation,
  129. (PVOID)KeyValueInfo,
  130. VALUE_BUFFER_SIZE,
  131. &ValueLength
  132. );
  133. //
  134. // cleanup
  135. //
  136. NtClose(Key);
  137. if (!NT_SUCCESS(Status)) {
  138. DebugPrint2( LVL_VERBOSE, L"can't query value key (%ws): 0x%x", ValueNameStr, Status );
  139. return DefaultValue;
  140. }
  141. ASSERT(KeyValueInfo->Type == REG_DWORD && KeyValueInfo->DataLength == sizeof(DWORD));
  142. if(KeyValueInfo->Type != REG_DWORD || KeyValueInfo->DataLength != sizeof(DWORD)) {
  143. return DefaultValue;
  144. }
  145. //
  146. // return value
  147. //
  148. return *((PULONG)&KeyValueInfo->Data);
  149. }
  150. ULONG
  151. SfcQueryRegDwordWithAlternate(
  152. IN PCWSTR FirstKey,
  153. IN PCWSTR SecondKey,
  154. IN PCWSTR ValueNameStr,
  155. IN ULONG DefaultValue
  156. )
  157. /*++
  158. Routine Description:
  159. retrieve a DWORD from the registry. if the value is not present in the
  160. first key location, we look in the second key location. If the key cannot
  161. be retrieved, we use a default value. calls registry api's using NT apis
  162. instead of win32 apis.
  163. Arguments:
  164. FirstKey - contains first registry keyname to look for value under.
  165. SecondKey - contains registry keyname to look for value under.
  166. ValueNameStr - contains registry value to retreive.
  167. DefaultValue - if we have problems retreiving the registry key or it is
  168. not set, use this default value.
  169. Return Value:
  170. registry DWORD value or default value if registry cannot be retreived.
  171. --*/
  172. {
  173. NTSTATUS Status;
  174. UNICODE_STRING KeyName;
  175. UNICODE_STRING ValueName;
  176. OBJECT_ATTRIBUTES ObjectAttributes;
  177. HANDLE Key;
  178. WCHAR ValueBuffer[VALUE_BUFFER_SIZE];
  179. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
  180. ULONG ValueLength;
  181. BOOL FirstTime;
  182. PCWSTR p;
  183. //
  184. // Open the registry key.
  185. //
  186. FirstTime = TRUE;
  187. ASSERT((FirstKey != NULL) && (ValueNameStr != NULL) && (SecondKey != NULL));
  188. TryAgain:
  189. p = FirstTime ? FirstKey : SecondKey;
  190. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
  191. RtlInitUnicodeString( &KeyName, p );
  192. InitializeObjectAttributes(
  193. &ObjectAttributes,
  194. &KeyName,
  195. OBJ_CASE_INSENSITIVE,
  196. NULL,
  197. NULL
  198. );
  199. Status = NtOpenKey(&Key, KEY_READ, &ObjectAttributes);
  200. if (!NT_SUCCESS(Status) && !FirstTime) {
  201. DebugPrint2( LVL_VERBOSE, L"can't open %ws key: 0x%x", p, Status );
  202. return DefaultValue;
  203. }
  204. if (!NT_SUCCESS(Status)) {
  205. ASSERT( FirstTime == TRUE );
  206. FirstTime = FALSE;
  207. goto TryAgain;
  208. }
  209. //
  210. // Query the key value.
  211. //
  212. RtlInitUnicodeString( &ValueName, ValueNameStr );
  213. Status = NtQueryValueKey(
  214. Key,
  215. &ValueName,
  216. KeyValuePartialInformation,
  217. (PVOID)KeyValueInfo,
  218. VALUE_BUFFER_SIZE,
  219. &ValueLength
  220. );
  221. //
  222. // cleanup
  223. //
  224. NtClose(Key);
  225. if (!NT_SUCCESS(Status) && !FirstTime) {
  226. DebugPrint2( LVL_VERBOSE, L"can't query value key (%ws): 0x%x", ValueNameStr, Status );
  227. return DefaultValue;
  228. }
  229. if (!NT_SUCCESS(Status)) {
  230. ASSERT( FirstTime == TRUE );
  231. FirstTime = FALSE;
  232. goto TryAgain;
  233. }
  234. ASSERT(KeyValueInfo->Type == REG_DWORD && KeyValueInfo->DataLength == sizeof(DWORD));
  235. if(KeyValueInfo->Type != REG_DWORD || KeyValueInfo->DataLength != sizeof(DWORD)) {
  236. return DefaultValue;
  237. }
  238. //
  239. // return value
  240. //
  241. return *((PULONG)&KeyValueInfo->Data);
  242. }
  243. PWSTR
  244. SfcQueryRegString(
  245. PCWSTR KeyNameStr,
  246. PCWSTR ValueNameStr
  247. )
  248. /*++
  249. Routine Description:
  250. retrieve a string from the registry. if the value is not present or cannot
  251. be retrieved, we return NULL. calls registry api's using NT apis
  252. instead of win32 apis.
  253. Arguments:
  254. KeyNameStr - contains registry keyname to look for value under.
  255. ValueNameStr - contains registry value to retreive.
  256. Return Value:
  257. unicode string pointer or NULL if registry cannot be retreived.
  258. --*/
  259. {
  260. NTSTATUS Status;
  261. UNICODE_STRING KeyName;
  262. UNICODE_STRING ValueName;
  263. OBJECT_ATTRIBUTES ObjectAttributes;
  264. HANDLE Key;
  265. WCHAR ValueBuffer[VALUE_BUFFER_SIZE];
  266. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
  267. ULONG ValueLength;
  268. PWSTR s;
  269. ASSERT((KeyNameStr != NULL) && (ValueNameStr != NULL));
  270. //
  271. // Open the registry key.
  272. //
  273. RtlZeroMemory( (PVOID)ValueBuffer, VALUE_BUFFER_SIZE );
  274. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
  275. RtlInitUnicodeString( &KeyName, KeyNameStr );
  276. InitializeObjectAttributes(
  277. &ObjectAttributes,
  278. &KeyName,
  279. OBJ_CASE_INSENSITIVE,
  280. NULL,
  281. NULL
  282. );
  283. Status = NtOpenKey(&Key, KEY_READ, &ObjectAttributes);
  284. if (!NT_SUCCESS(Status)) {
  285. DebugPrint2( LVL_VERBOSE, L"can't open %ws key: 0x%x", KeyNameStr, Status );
  286. return NULL;
  287. }
  288. //
  289. // Query the key value.
  290. //
  291. RtlInitUnicodeString( &ValueName, ValueNameStr );
  292. Status = NtQueryValueKey(
  293. Key,
  294. &ValueName,
  295. KeyValuePartialInformation,
  296. (PVOID)KeyValueInfo,
  297. VALUE_BUFFER_SIZE,
  298. &ValueLength
  299. );
  300. //
  301. // cleanup
  302. //
  303. NtClose(Key);
  304. if (!NT_SUCCESS(Status)) {
  305. DebugPrint2( LVL_VERBOSE, L"can't query value key (%ws): 0x%x", ValueNameStr, Status );
  306. return 0;
  307. }
  308. if (KeyValueInfo->Type == REG_MULTI_SZ) {
  309. DebugPrint1( LVL_VERBOSE,
  310. L"Warning: value key %ws is REG_MULTI_SZ, we will only return first string in list",
  311. ValueNameStr );
  312. } else {
  313. ASSERT(KeyValueInfo->Type == REG_SZ || KeyValueInfo->Type == REG_EXPAND_SZ);
  314. if(KeyValueInfo->Type != REG_SZ && KeyValueInfo->Type != REG_EXPAND_SZ) {
  315. return NULL;
  316. }
  317. }
  318. //
  319. // string length + 16 for slop
  320. //
  321. s = (PWSTR) MemAlloc( KeyValueInfo->DataLength + 16 );
  322. if (s == NULL) {
  323. return NULL;
  324. }
  325. CopyMemory( s, KeyValueInfo->Data, KeyValueInfo->DataLength );
  326. return s;
  327. }
  328. ULONG
  329. SfcQueryRegPath(
  330. IN PCWSTR KeyNameStr,
  331. IN PCWSTR ValueNameStr,
  332. IN PCWSTR DefaultValue OPTIONAL,
  333. OUT PWSTR Buffer OPTIONAL,
  334. IN ULONG BufferSize OPTIONAL
  335. )
  336. /*++
  337. Routine Description:
  338. retrieves a path from the registry. if the value is not present or cannot be retrieved,
  339. it returns the passed-in default string. The function writes up to BufferSize - 1 characters and appends
  340. a null. calls registry api's using NT apis instead of win32 apis.
  341. Arguments:
  342. KeyNameStr - contains registry keyname to look for value under.
  343. ValueNameStr - contains registry value to retreive.
  344. DefaultValue - the value returned in case of an error
  345. Buffer - the buffer that receives the string
  346. BufferSize - the size of Buffer in chars
  347. Return Value:
  348. the length of the value data in chars, including the null
  349. --*/
  350. {
  351. NTSTATUS Status;
  352. UNICODE_STRING KeyName;
  353. UNICODE_STRING ValueName;
  354. OBJECT_ATTRIBUTES ObjectAttributes;
  355. HANDLE Key;
  356. WCHAR ValueBuffer[VALUE_BUFFER_SIZE];
  357. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION) ValueBuffer;
  358. ULONG ValueLength;
  359. ULONG RequiredSize = 1; // for null
  360. PCWSTR retval = NULL;
  361. ASSERT(KeyNameStr != NULL && ValueNameStr != NULL);
  362. ASSERT(0 == BufferSize || Buffer != NULL);
  363. if(BufferSize != 0)
  364. Buffer[0] = 0;
  365. //
  366. // Open the registry key.
  367. //
  368. RtlInitUnicodeString( &KeyName, KeyNameStr );
  369. InitializeObjectAttributes(
  370. &ObjectAttributes,
  371. &KeyName,
  372. OBJ_CASE_INSENSITIVE,
  373. NULL,
  374. NULL
  375. );
  376. Status = NtOpenKey(&Key, KEY_READ, &ObjectAttributes);
  377. if(NT_SUCCESS(Status))
  378. {
  379. //
  380. // Query the key value.
  381. //
  382. RtlInitUnicodeString( &ValueName, ValueNameStr );
  383. Status = NtQueryValueKey(
  384. Key,
  385. &ValueName,
  386. KeyValuePartialInformation,
  387. (PVOID) KeyValueInfo,
  388. VALUE_BUFFER_SIZE,
  389. &ValueLength
  390. );
  391. NtClose(Key);
  392. if(NT_SUCCESS(Status))
  393. {
  394. ASSERT(KeyValueInfo->Type == REG_SZ || KeyValueInfo->Type == REG_EXPAND_SZ);
  395. if(KeyValueInfo->Type == REG_SZ || KeyValueInfo->Type == REG_EXPAND_SZ) {
  396. retval = (PCWSTR) KeyValueInfo->Data;
  397. }
  398. }
  399. }
  400. if(NULL == retval || 0 == retval[0])
  401. retval = DefaultValue;
  402. if(retval != NULL)
  403. {
  404. RequiredSize = ExpandEnvironmentStrings(retval, Buffer, BufferSize);
  405. if(BufferSize != 0 && BufferSize < RequiredSize)
  406. Buffer[BufferSize - 1] = 0;
  407. }
  408. return RequiredSize;
  409. }
  410. PWSTR
  411. SfcQueryRegStringWithAlternate(
  412. IN PCWSTR FirstKey,
  413. IN PCWSTR SecondKey,
  414. IN PCWSTR ValueNameStr
  415. )
  416. /*++
  417. Routine Description:
  418. retrieve a string from the registry. if the value is not present or cannot
  419. be retrieved, we try the second key, then we return NULL.
  420. This calls registry api's using NT apis instead of win32 apis.
  421. Arguments:
  422. FirstKey - contains registry keyname to look for value under.
  423. SecondKey - 2nd key to look for value under
  424. ValueNameStr - contains registry value to retreive.
  425. Return Value:
  426. unicode string pointer or NULL if registry cannot be retreived.
  427. --*/
  428. {
  429. NTSTATUS Status;
  430. UNICODE_STRING KeyName;
  431. UNICODE_STRING ValueName;
  432. OBJECT_ATTRIBUTES ObjectAttributes;
  433. HANDLE Key;
  434. WCHAR ValueBuffer[VALUE_BUFFER_SIZE];
  435. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
  436. ULONG ValueLength;
  437. PWSTR s;
  438. BOOL FirstTime;
  439. PCWSTR p;
  440. ASSERT((FirstKey != NULL) && (ValueNameStr != NULL) && (SecondKey != NULL));
  441. FirstTime = TRUE;
  442. TryAgain:
  443. p = FirstTime ? FirstKey : SecondKey;
  444. //
  445. // Open the registry key.
  446. //
  447. RtlZeroMemory( (PVOID)ValueBuffer, VALUE_BUFFER_SIZE );
  448. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
  449. RtlInitUnicodeString( &KeyName, p );
  450. InitializeObjectAttributes(
  451. &ObjectAttributes,
  452. &KeyName,
  453. OBJ_CASE_INSENSITIVE,
  454. NULL,
  455. NULL
  456. );
  457. Status = NtOpenKey(&Key, KEY_READ, &ObjectAttributes);
  458. if (!NT_SUCCESS(Status) && !FirstTime) {
  459. DebugPrint2( LVL_VERBOSE, L"can't open %ws key: 0x%x", p, Status );
  460. return NULL;
  461. }
  462. if (!NT_SUCCESS(Status)) {
  463. ASSERT( FirstTime == TRUE );
  464. FirstTime = FALSE;
  465. goto TryAgain;
  466. }
  467. //
  468. // Query the key value.
  469. //
  470. RtlInitUnicodeString( &ValueName, ValueNameStr );
  471. Status = NtQueryValueKey(
  472. Key,
  473. &ValueName,
  474. KeyValuePartialInformation,
  475. (PVOID)KeyValueInfo,
  476. VALUE_BUFFER_SIZE,
  477. &ValueLength
  478. );
  479. //
  480. // cleanup
  481. //
  482. NtClose(Key);
  483. if (!NT_SUCCESS(Status) && !FirstTime) {
  484. DebugPrint2( LVL_VERBOSE, L"can't query value key (%ws): 0x%x", ValueNameStr, Status );
  485. return 0;
  486. }
  487. if (!NT_SUCCESS(Status)) {
  488. ASSERT( FirstTime == TRUE );
  489. FirstTime = FALSE;
  490. goto TryAgain;
  491. }
  492. if (KeyValueInfo->Type == REG_MULTI_SZ) {
  493. DebugPrint1( LVL_VERBOSE,
  494. L"Warning: value key %ws is REG_MULTI_SZ, we will only return first string in list",
  495. ValueNameStr );
  496. } else {
  497. ASSERT(KeyValueInfo->Type == REG_SZ || KeyValueInfo->Type == REG_EXPAND_SZ);
  498. if(KeyValueInfo->Type != REG_SZ && KeyValueInfo->Type != REG_EXPAND_SZ) {
  499. return NULL;
  500. }
  501. }
  502. //
  503. // string length + 16 for slop
  504. //
  505. s = (PWSTR) MemAlloc( KeyValueInfo->DataLength + 16 );
  506. if (s == NULL) {
  507. return NULL;
  508. }
  509. CopyMemory( s, KeyValueInfo->Data, KeyValueInfo->DataLength );
  510. return s;
  511. }
  512. ULONG
  513. SfcWriteRegDword(
  514. PCWSTR KeyNameStr,
  515. PCWSTR ValueNameStr,
  516. ULONG Value
  517. )
  518. /*++
  519. Routine Description:
  520. set a REG_DWORD value in the registry. Calls registry api's using NT apis
  521. instead of win32 apis.
  522. Arguments:
  523. KeyNameStr - contains registry keyname to look for value under.
  524. ValueNameStr - contains registry value to set.
  525. Value - actual value to be set
  526. Return Value:
  527. win32 error code indicating outcome.
  528. --*/
  529. {
  530. NTSTATUS Status;
  531. UNICODE_STRING KeyName;
  532. UNICODE_STRING ValueName;
  533. OBJECT_ATTRIBUTES ObjectAttributes;
  534. HANDLE Key;
  535. ASSERT((KeyNameStr != NULL) && (ValueNameStr != NULL));
  536. //
  537. // Open the registry key.
  538. //
  539. RtlInitUnicodeString( &KeyName, KeyNameStr );
  540. InitializeObjectAttributes(
  541. &ObjectAttributes,
  542. &KeyName,
  543. OBJ_CASE_INSENSITIVE,
  544. NULL,
  545. NULL
  546. );
  547. Status = NtOpenKey(&Key, KEY_SET_VALUE, &ObjectAttributes);
  548. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  549. //
  550. // key doesn't exist, let's try to create one
  551. //
  552. Status = NtCreateKey( &Key,
  553. KEY_SET_VALUE,
  554. &ObjectAttributes,
  555. 0,
  556. NULL,
  557. 0,
  558. NULL
  559. );
  560. }
  561. if (!NT_SUCCESS(Status)) {
  562. DebugPrint2( LVL_VERBOSE, L"can't open %ws key: 0x%x", KeyNameStr, Status );
  563. return(RtlNtStatusToDosError(Status));
  564. }
  565. //
  566. // set the key value.
  567. //
  568. RtlInitUnicodeString( &ValueName, ValueNameStr );
  569. Status = NtSetValueKey(
  570. Key,
  571. &ValueName,
  572. 0,
  573. REG_DWORD,
  574. &Value,
  575. sizeof(ULONG)
  576. );
  577. //
  578. // cleanup and leave
  579. //
  580. NtClose(Key);
  581. if (!NT_SUCCESS(Status)) {
  582. DebugPrint2( LVL_VERBOSE, L"can't set value key (%ws): 0x%x", ValueNameStr, Status );
  583. }
  584. return(RtlNtStatusToDosError(Status));
  585. }
  586. DWORD
  587. SfcWriteRegString(
  588. PCWSTR KeyNameStr,
  589. PCWSTR ValueNameStr,
  590. PCWSTR Value
  591. )
  592. /*++
  593. Routine Description:
  594. set a REG_SZ value in the registry. Calls registry api's using NT apis
  595. instead of win32 apis.
  596. Arguments:
  597. KeyNameStr - contains registry keyname to look for value under.
  598. ValueNameStr - contains registry value to set.
  599. Value - actual value to be set
  600. Return Value:
  601. Win32 error code indicating outcome.
  602. --*/
  603. {
  604. NTSTATUS Status;
  605. UNICODE_STRING KeyName;
  606. UNICODE_STRING ValueName;
  607. OBJECT_ATTRIBUTES ObjectAttributes;
  608. HANDLE Key;
  609. ASSERT((KeyNameStr != NULL) && (ValueNameStr != NULL));
  610. //
  611. // Open the registry key.
  612. //
  613. RtlInitUnicodeString( &KeyName, KeyNameStr );
  614. InitializeObjectAttributes(
  615. &ObjectAttributes,
  616. &KeyName,
  617. OBJ_CASE_INSENSITIVE,
  618. NULL,
  619. NULL
  620. );
  621. Status = NtOpenKey(&Key, KEY_SET_VALUE, &ObjectAttributes);
  622. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  623. //
  624. // key doesn't exist, let's try to create one
  625. //
  626. Status = NtCreateKey( &Key,
  627. KEY_SET_VALUE,
  628. &ObjectAttributes,
  629. 0,
  630. NULL,
  631. 0,
  632. NULL
  633. );
  634. }
  635. if (!NT_SUCCESS(Status)) {
  636. DebugPrint2( LVL_VERBOSE, L"can't open %ws key: 0x%x", KeyNameStr, Status );
  637. return(RtlNtStatusToDosError(Status));
  638. }
  639. //
  640. // set the key value.
  641. //
  642. RtlInitUnicodeString( &ValueName, ValueNameStr );
  643. Status = NtSetValueKey(
  644. Key,
  645. &ValueName,
  646. 0,
  647. REG_SZ,
  648. (PWSTR)Value,
  649. UnicodeLen(Value)
  650. );
  651. //
  652. // cleanup
  653. //
  654. NtClose(Key);
  655. if (!NT_SUCCESS(Status)) {
  656. DebugPrint2( LVL_VERBOSE, L"can't set value key (%ws): 0x%x", ValueNameStr, Status );
  657. return(RtlNtStatusToDosError(Status)) ;
  658. }
  659. return ERROR_SUCCESS;
  660. }
  661. #if 0
  662. DWORD
  663. WsInAWorkgroup(
  664. VOID
  665. )
  666. /*++
  667. Routine Description:
  668. This function determines whether we are a member of a domain, or of
  669. a workgroup. First it checks to make sure we're running on a Windows NT
  670. system (otherwise we're obviously in a domain) and if so, queries LSA
  671. to get the Primary domain SID, if this is NULL, we're in a workgroup.
  672. If we fail for some random unexpected reason, we'll pretend we're in a
  673. domain (it's more restrictive).
  674. Arguments:
  675. None
  676. Return Value:
  677. TRUE - We're in a workgroup
  678. FALSE - We're in a domain
  679. --*/
  680. {
  681. NT_PRODUCT_TYPE ProductType;
  682. OBJECT_ATTRIBUTES ObjectAttributes;
  683. LSA_HANDLE Handle;
  684. NTSTATUS Status;
  685. PPOLICY_PRIMARY_DOMAIN_INFO PolicyPrimaryDomainInfo = NULL;
  686. DWORD Result = FALSE;
  687. Status = RtlGetNtProductType( &ProductType );
  688. if (!NT_SUCCESS( Status )) {
  689. DebugPrint( LVL_MINIMAL, L"Could not get Product type" );
  690. return FALSE;
  691. }
  692. if (ProductType == NtProductLanManNt) {
  693. return FALSE;
  694. }
  695. InitializeObjectAttributes( &ObjectAttributes, NULL, 0, 0, NULL );
  696. Status = LsaOpenPolicy( NULL, &ObjectAttributes, POLICY_VIEW_LOCAL_INFORMATION, &Handle );
  697. if (!NT_SUCCESS(Status)) {
  698. DebugPrint( LVL_MINIMAL, L"Could not open LSA Policy Database" );
  699. return FALSE;
  700. }
  701. Status = LsaQueryInformationPolicy( Handle, PolicyPrimaryDomainInformation, (LPVOID)&PolicyPrimaryDomainInfo );
  702. if (NT_SUCCESS(Status)) {
  703. if (PolicyPrimaryDomainInfo->Sid == NULL) {
  704. Result = TRUE;
  705. } else {
  706. Result = FALSE;
  707. }
  708. }
  709. if (PolicyPrimaryDomainInfo) {
  710. LsaFreeMemory( (PVOID)PolicyPrimaryDomainInfo );
  711. }
  712. LsaClose( Handle );
  713. return Result;
  714. }
  715. BOOL
  716. WaitForMUP(
  717. DWORD dwMaxWait
  718. )
  719. /*++
  720. Routine Description:
  721. Waits for MUP to initialize by looking for the event that is signalled
  722. when MUP is ready
  723. Arguments:
  724. dwMaxWait - amount of time we'll wait for MUP to initialize
  725. Return Value:
  726. TRUE - MUP is initialized
  727. FALSE - could not confirm MUP is initialized
  728. --*/
  729. {
  730. HANDLE hEvent;
  731. BOOL bResult;
  732. INT i = 0;
  733. if (WsInAWorkgroup()) {
  734. return TRUE;
  735. }
  736. DebugPrint(LVL_MINIMAL, L"waiting for mup...");
  737. //
  738. // Try to open the event
  739. //
  740. do {
  741. hEvent = OpenEvent(
  742. SYNCHRONIZE,
  743. FALSE,
  744. L"wkssvc: MUP finished initializing event"
  745. );
  746. if (hEvent) {
  747. DebugPrint(LVL_MINIMAL, L"opened the mup event");
  748. break;
  749. }
  750. if (GetLastError() != ERROR_FILE_NOT_FOUND) {
  751. break;
  752. }
  753. DebugPrint(LVL_MINIMAL, L"mup event does not yet exist, waiting...");
  754. Sleep(2000);
  755. i++;
  756. } while (i < 30);
  757. if (!hEvent) {
  758. DebugPrint1(LVL_MINIMAL, L"Failed to open MUP event, ec=%d\n", GetLastError());
  759. return FALSE;
  760. }
  761. //
  762. // Wait for the event to be signalled
  763. //
  764. bResult = (WaitForSingleObject (hEvent, dwMaxWait) == WAIT_OBJECT_0);
  765. //
  766. // Clean up
  767. //
  768. CloseHandle (hEvent);
  769. return bResult;
  770. }
  771. #endif
  772. NTSTATUS
  773. ExpandPathString(
  774. IN PWSTR PathString,
  775. IN ULONG PathStringLength,
  776. OUT PUNICODE_STRING FileName, OPTIONAL
  777. OUT PUNICODE_STRING PathName,
  778. OUT PUNICODE_STRING FullPathName OPTIONAL
  779. )
  780. /*++
  781. Routine Description:
  782. Routine takes a source string containing environment variables, expand this
  783. into the full path. Then it either copies this into a path, file, and full
  784. path, as requested.
  785. Arguments:
  786. PathString - source path string
  787. PathStringLength - source path string length
  788. FileName - receives filename part of the path if specified. If not
  789. specified, we only want the path part
  790. PathName - receives the path part of the expanded source. If
  791. FileName is not specified, we fill in pathname with the
  792. entire expanded path
  793. FullPathName - if FileName is specified, then this is filled in with
  794. the complete path.
  795. Return Value:
  796. NTSTATUS code indicating outcome.
  797. --*/
  798. {
  799. NTSTATUS Status;
  800. UNICODE_STRING NewPath;
  801. UNICODE_STRING SrcPath;
  802. PWSTR FilePart;
  803. ASSERT((PathString != NULL));
  804. ASSERT((FileName == NULL)
  805. ? (PathName != NULL)
  806. : ((FullPathName != NULL) && (PathName != NULL)));
  807. //
  808. // turn the pathstring and length into a UNICODE_STRING
  809. //
  810. SrcPath.Length = (USHORT)PathStringLength;
  811. SrcPath.MaximumLength = SrcPath.Length;
  812. SrcPath.Buffer = PathString;
  813. //
  814. // create a new scratch UNICODE_STRING
  815. //
  816. NewPath.Length = 0;
  817. NewPath.MaximumLength = (MAX_PATH*2) * sizeof(WCHAR);
  818. NewPath.Buffer = (PWSTR) MemAlloc( NewPath.MaximumLength );
  819. if (NewPath.Buffer == NULL) {
  820. return STATUS_NO_MEMORY;
  821. }
  822. //
  823. // expand source environment string into scratch string
  824. //
  825. Status = RtlExpandEnvironmentStrings_U(
  826. NULL,
  827. &SrcPath,
  828. &NewPath,
  829. NULL
  830. );
  831. if (!NT_SUCCESS(Status)) {
  832. DebugPrint2( LVL_MINIMAL, L"ExpandEnvironmentStrings failed for [%ws], ec=%08x", PathString, Status );
  833. goto exit;
  834. }
  835. //
  836. // convert scratch string to lowercase
  837. //
  838. MyLowerString( NewPath.Buffer, NewPath.Length/sizeof(WCHAR) );
  839. //
  840. // if filename isn't specified, then just copy the string into the pathname
  841. // and exit
  842. //
  843. if (FileName == NULL) {
  844. PathName->Length = NewPath.Length;
  845. PathName->MaximumLength = NewPath.MaximumLength;
  846. PathName->Buffer = NewPath.Buffer;
  847. return(STATUS_SUCCESS);
  848. } else {
  849. //
  850. // copy the full string into the fullpathname
  851. //
  852. Status = InitializeUnicodeString( NewPath.Buffer, NewPath.Length, FullPathName );
  853. if (!NT_SUCCESS(Status)) {
  854. DebugPrint2( LVL_MINIMAL, L"InitializeUnicodeString failed for [%ws], ec=%08x", NewPath.Buffer, Status );
  855. goto exit;
  856. }
  857. //
  858. // separate the path part from the file part
  859. //
  860. FilePart = wcsrchr( NewPath.Buffer, L'\\' );
  861. if (FilePart == NULL) {
  862. Status = STATUS_NO_MEMORY;
  863. goto exit;
  864. }
  865. *FilePart = 0;
  866. FilePart += 1;
  867. Status = InitializeUnicodeString( NewPath.Buffer, 0, PathName );
  868. if (!NT_SUCCESS(Status)) {
  869. DebugPrint2( LVL_MINIMAL, L"InitializeUnicodeString failed for [%ws], ec=%08x", NewPath.Buffer, Status );
  870. goto exit;
  871. }
  872. Status = InitializeUnicodeString( FilePart, 0, FileName );
  873. if (!NT_SUCCESS(Status)) {
  874. DebugPrint2( LVL_MINIMAL, L"InitializeUnicodeString failed for [%ws], ec=%08x", FilePart, Status );
  875. }
  876. }
  877. FilePart -= 1;
  878. *FilePart = L'\\';
  879. exit:
  880. MemFree( NewPath.Buffer );
  881. return Status;
  882. }
  883. BOOL
  884. SfcDisableDllCache(
  885. BOOL LogMessage
  886. )
  887. /*++
  888. Routine Description:
  889. Routine disables the dllcache functionality.
  890. Specifically, we set the dll cache directory to the default and sets the
  891. cache size to zero. So we will never add files in the cache.
  892. We also log an error message if requested.
  893. Arguments:
  894. LogMessage - if TRUE, we log a message indicating the cache is disabled
  895. Return Value:
  896. NTSTATUS code indicating outcome.
  897. --*/
  898. {
  899. PWSTR CacheDefault = DLLCACHE_DIR_DEFAULT;
  900. NTSTATUS Status;
  901. Status = ExpandPathString(
  902. CacheDefault,
  903. UnicodeLen(CacheDefault),
  904. NULL,
  905. &SfcProtectedDllPath,
  906. NULL
  907. );
  908. if (NT_SUCCESS(Status)) {
  909. DebugPrint1(LVL_MINIMAL,
  910. L"default cache dir name=[%ws]",
  911. SfcProtectedDllPath.Buffer);
  912. SfcProtectedDllFileDirectory = SfcOpenDir(
  913. TRUE,
  914. TRUE,
  915. SfcProtectedDllPath.Buffer );
  916. if (SfcProtectedDllFileDirectory == NULL) {
  917. DebugPrint(LVL_MINIMAL,
  918. L"could not open the cache dir, need to create");
  919. SfcProtectedDllFileDirectory = SfcCreateDir(
  920. SfcProtectedDllPath.Buffer,
  921. TRUE );
  922. if (SfcProtectedDllFileDirectory == NULL) {
  923. DebugPrint( LVL_MINIMAL, L"Cannot create ProtectedDllPath" );
  924. }
  925. }
  926. } else {
  927. //
  928. // not enough memory...we're toast
  929. //
  930. DebugPrint( LVL_MINIMAL, L"Cannot open ProtectedDllPath" );
  931. return(FALSE);
  932. }
  933. //
  934. // set the quota to zero
  935. //
  936. SFCQuota = 0;
  937. if (LogMessage) {
  938. SfcReportEvent( MSG_DLLCACHE_INVALID, NULL, NULL, 0 );
  939. }
  940. return(TRUE);
  941. }
  942. NTSTATUS
  943. SfcInitializeDllList(
  944. IN PPROTECT_FILE_ENTRY Files,
  945. IN ULONG NumFiles,
  946. OUT PULONG Count
  947. )
  948. /*++
  949. Routine Description:
  950. Routine takes an empty array of SFC_REGISTRY_VALUE structures stored in the
  951. global SfcProtectedDllsList global and assigns the data from an array of
  952. PROTECT_FILE_ENTRY structures into these structures.
  953. Arguments:
  954. Files - pointer to first element in array of PROTECT_FILE_ENTRY
  955. structures
  956. NumFiles - number of elements in array of structures
  957. Count - receives number of files we correctly setup
  958. Return Value:
  959. NTSTATUS code indicating outcome.
  960. --*/
  961. {
  962. NTSTATUS Status,FinalStatus, LoopStatus;
  963. ULONG Index;
  964. PSFC_REGISTRY_VALUE RegVal;
  965. ASSERT( (Files != NULL)
  966. && (SfcProtectedDllsList != NULL)
  967. && (Count != NULL) );
  968. LoopStatus = FinalStatus = STATUS_SUCCESS;
  969. for (Index=0; Index<NumFiles; Index++) {
  970. RegVal = &SfcProtectedDllsList[*Count];
  971. //
  972. // set the directory name, filename and full path members
  973. //
  974. Status = ExpandPathString(
  975. Files[Index].FileName,
  976. UnicodeLen(Files[Index].FileName),
  977. &RegVal->FileName,
  978. &RegVal->DirName,
  979. &RegVal->FullPathName
  980. );
  981. if (!NT_SUCCESS(Status)) {
  982. //
  983. // if we have a problem initializing one of the array elements
  984. // keep going
  985. //
  986. DebugPrint1( LVL_MINIMAL,
  987. L"ExpandPathString failed, ec=%08x",
  988. Status );
  989. FinalStatus = Status;
  990. continue;
  991. }
  992. //
  993. // set the layout inf name and the source file names if they are present
  994. //
  995. Status = InitializeUnicodeString( Files[Index].InfName,
  996. 0,
  997. &RegVal->InfName );
  998. if (!NT_SUCCESS(Status)) {
  999. DebugPrint1( LVL_MINIMAL,
  1000. L"InitializeUnicodeString failed, ec=%08x",
  1001. Status );
  1002. LoopStatus = FinalStatus = Status;
  1003. }
  1004. Status = InitializeUnicodeString( Files[Index].SourceFileName,
  1005. 0,
  1006. &RegVal->SourceFileName );
  1007. if (!NT_SUCCESS(Status)) {
  1008. DebugPrint1( LVL_MINIMAL,
  1009. L"InitializeUnicodeString failed, ec=%08x",
  1010. Status );
  1011. LoopStatus = FinalStatus = Status;
  1012. }
  1013. if (NT_SUCCESS(Status)) {
  1014. *Count += 1;
  1015. }
  1016. //
  1017. // WinSxs work (jonwis) This is NULL in all cases, unless this entry is
  1018. // added by WinSxs (see dirwatch.c)
  1019. //
  1020. RegVal->pvWinSxsCookie = NULL;
  1021. LoopStatus = STATUS_SUCCESS;
  1022. }
  1023. Status = FinalStatus;
  1024. if (NT_SUCCESS(Status)) {
  1025. ASSERT(*Count == NumFiles);
  1026. }
  1027. return(Status);
  1028. }
  1029. NTSTATUS
  1030. SfcInitializeDllLists(
  1031. PSFC_GET_FILES pfGetFiles
  1032. )
  1033. /*++
  1034. Routine Description:
  1035. Initialize the list of files we're going to protect.
  1036. Arguments:
  1037. None.
  1038. Return Value:
  1039. NTSTATUS code indicating outcome.
  1040. --*/
  1041. {
  1042. NTSTATUS Status;
  1043. PWSTR s;
  1044. BOOL FreeMem = TRUE;
  1045. //
  1046. // make sure we only call this guy once
  1047. //
  1048. if (SfcProtectedDllCount) {
  1049. return STATUS_SUCCESS;
  1050. }
  1051. DebugPrint(LVL_MINIMAL, L"entering SfcInitializeDllLists()");
  1052. //
  1053. // get the dllcache directory and store it into to SfcProtectedDllPath
  1054. // global
  1055. //
  1056. s = SfcQueryRegStringWithAlternate( REGKEY_POLICY, REGKEY_WINLOGON, REGVAL_SFCDLLCACHEDIR );
  1057. if (s == NULL) {
  1058. s = DLLCACHE_DIR_DEFAULT;
  1059. FreeMem = FALSE;
  1060. }
  1061. Status = ExpandPathString(
  1062. s,
  1063. UnicodeLen(s),
  1064. NULL,
  1065. &SfcProtectedDllPath,
  1066. NULL
  1067. );
  1068. if (NT_SUCCESS(Status)) {
  1069. WCHAR DontCare[MAX_PATH];
  1070. DWORD DriveType;
  1071. DebugPrint1(LVL_MINIMAL,
  1072. L"cache dir name=[%ws]",
  1073. SfcProtectedDllPath.Buffer);
  1074. DriveType = SfcGetPathType(
  1075. SfcProtectedDllPath.Buffer,
  1076. DontCare,
  1077. UnicodeChars(DontCare));
  1078. if (DriveType != PATH_LOCAL) {
  1079. DebugPrint2(LVL_MINIMAL,
  1080. L"cache dir %ws does not appear to be a local path (type %d), we are disabling cache functionality",
  1081. SfcProtectedDllPath.Buffer,
  1082. DriveType);
  1083. SfcDisableDllCache( SFCDisable != SFC_DISABLE_SETUP );
  1084. goto init;
  1085. }
  1086. //
  1087. // get a handle to the dll cache directory
  1088. //
  1089. SfcProtectedDllFileDirectory = SfcOpenDir(
  1090. TRUE,
  1091. TRUE,
  1092. SfcProtectedDllPath.Buffer );
  1093. if (SfcProtectedDllFileDirectory == NULL) {
  1094. DebugPrint(LVL_MINIMAL,
  1095. L"could not open the cache dir, need to create");
  1096. SfcProtectedDllFileDirectory = SfcCreateDir(
  1097. SfcProtectedDllPath.Buffer,
  1098. TRUE );
  1099. if (SfcProtectedDllFileDirectory == NULL) {
  1100. DebugPrint( LVL_MINIMAL, L"Cannot open ProtectedDllPath" );
  1101. SfcDisableDllCache( SFCDisable != SFC_DISABLE_SETUP );
  1102. } else {
  1103. //
  1104. // force a scan if we just created the dll cache
  1105. //
  1106. SFCScan = SFC_SCAN_ALWAYS;
  1107. }
  1108. }
  1109. } else {
  1110. //
  1111. // dll cache path in registry must be bogus...use default path and
  1112. // set the quota to zero so the cache is effectively disabled.
  1113. //
  1114. SfcDisableDllCache( SFCDisable != SFC_DISABLE_SETUP );
  1115. }
  1116. init:
  1117. if (FreeMem) {
  1118. MemFree( s );
  1119. }
  1120. DebugPrint1(LVL_MINIMAL,
  1121. L"cache dir name=[%ws]",
  1122. SfcProtectedDllPath.Buffer);
  1123. ASSERT( SfcProtectedDllFileDirectory != NULL );
  1124. //
  1125. // now that we have the dll cache initialized, now retrieve the list of
  1126. // files that we will protect. The list of files currently resides in
  1127. // sfcfiles.dll.
  1128. //
  1129. ASSERT(pfGetFiles != NULL);
  1130. Status = pfGetFiles( &Tier2Files, &CountTier2Files );
  1131. if (!NT_SUCCESS(Status)) {
  1132. return Status;
  1133. }
  1134. //
  1135. // Take the file list (we only have the tier2 list) and build an array of
  1136. // SFC_REGISTRY_VALUE structures and store into the SfcProtectedDllsList
  1137. // global
  1138. //
  1139. SfcProtectedDllsList = (PSFC_REGISTRY_VALUE) MemAlloc( sizeof(SFC_REGISTRY_VALUE)*CountTier2Files );
  1140. if (SfcProtectedDllsList == NULL) {
  1141. return(STATUS_NO_MEMORY);
  1142. }
  1143. ASSERT(SfcProtectedDllCount == 0);
  1144. //
  1145. // now associate the data in our tier2 list with each of these structures
  1146. // in the array
  1147. //
  1148. Status = SfcInitializeDllList( Tier2Files, CountTier2Files, &SfcProtectedDllCount );
  1149. if (CountTier2Files != SfcProtectedDllCount) {
  1150. DebugPrint2( LVL_MINIMAL,
  1151. L"incorrect number of files in list: required count: %d actual count %d",
  1152. CountTier2Files,
  1153. SfcProtectedDllCount );
  1154. ASSERT(!NT_SUCCESS(Status));
  1155. } else {
  1156. IgnoreNextChange = (ULONG*) MemAlloc(SfcProtectedDllCount * sizeof(ULONG));
  1157. if(NULL == IgnoreNextChange) {
  1158. Status = STATUS_NO_MEMORY;
  1159. }
  1160. }
  1161. DebugPrint(LVL_MINIMAL, L"leaving SfcInitializeDllLists()");
  1162. return(Status);
  1163. }
  1164. DWORD
  1165. SfcCopyRegValue(
  1166. IN LPCWSTR SourceKeyName,
  1167. IN LPCWSTR SourceValueName,
  1168. IN LPCWSTR DestinationKeyName,
  1169. IN LPCWSTR DestinationValueName
  1170. )
  1171. /*++
  1172. Routine Description:
  1173. Copies a registry value from one key to another.
  1174. Arguments:
  1175. SourceKeyName -path to the source key name
  1176. SourceValueName -path to the source value name
  1177. DestinationKeyName -path to the destination key name
  1178. DestinationValueName -path to the destination value name
  1179. Return Value:
  1180. Win32 error code.
  1181. --*/
  1182. {
  1183. LONG Error = ERROR_SUCCESS;
  1184. HKEY SourceKey = NULL;
  1185. HKEY DestKey = NULL;
  1186. LPBYTE DataPtr = NULL;
  1187. DWORD ValueType;
  1188. DWORD ValueSize;
  1189. Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, SourceKeyName, 0, KEY_QUERY_VALUE, &SourceKey);
  1190. if(Error != ERROR_SUCCESS) {
  1191. goto exit;
  1192. }
  1193. ValueSize = 0;
  1194. Error = RegQueryValueExW(SourceKey, SourceValueName, NULL, &ValueType, NULL, &ValueSize);
  1195. if(Error != ERROR_SUCCESS) {
  1196. goto exit;
  1197. }
  1198. DataPtr = (LPBYTE) MemAlloc(ValueSize);
  1199. if(NULL == DataPtr) {
  1200. Error = ERROR_NOT_ENOUGH_MEMORY;
  1201. goto exit;
  1202. }
  1203. Error = RegQueryValueExW(SourceKey, SourceValueName, NULL, &ValueType, DataPtr, &ValueSize);
  1204. if(Error != ERROR_SUCCESS) {
  1205. goto exit;
  1206. }
  1207. Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, DestinationKeyName, 0, KEY_SET_VALUE, &DestKey);
  1208. if(Error != ERROR_SUCCESS) {
  1209. goto exit;
  1210. }
  1211. Error = RegSetValueExW(DestKey, DestinationValueName, 0, ValueType, DataPtr, ValueSize);
  1212. if(Error != ERROR_SUCCESS) {
  1213. goto exit;
  1214. }
  1215. exit:
  1216. if(SourceKey != NULL) {
  1217. RegCloseKey(SourceKey);
  1218. }
  1219. if(DestKey != NULL) {
  1220. RegCloseKey(DestKey);
  1221. }
  1222. MemFree(DataPtr);
  1223. return (DWORD) Error;
  1224. }