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.

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