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.

1338 lines
35 KiB

  1. /*++
  2. Copyright (c) 1999-2001 Microsoft Corporation
  3. Module Name:
  4. regmisc.c
  5. Abstract:
  6. This module implement some function used in the registry redirector.
  7. Author:
  8. ATM Shafiqul Khalid (askhalid) 29-Oct-1999
  9. Revision History:
  10. --*/
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <windows.h>
  15. #include <stdio.h>
  16. #include <ntregapi.h>
  17. #include "regremap.h"
  18. #include "wow64reg.h"
  19. #include "wow64reg\reflectr.h"
  20. #ifdef _WOW64DLLAPI_
  21. #include "wow64.h"
  22. #else
  23. #define ERRORLOG 1 //this one is completely dummy
  24. #define LOGPRINT(x)
  25. #define WOWASSERT(p)
  26. #endif //_WOW64DLLAPI_
  27. #include "regremap.h"
  28. #include "wow64reg.h"
  29. ASSERTNAME;
  30. //#define LOG_REGISTRY
  31. const WCHAR IsnNodeListPath[]={WOW64_REGISTRY_SETUP_KEY_NAME};
  32. #define KEY_NAME(x) {x,((sizeof (x) / sizeof (WCHAR))-1)}
  33. typedef struct _REGKEY_LIST {
  34. WCHAR KeyPath[256];
  35. DWORD Len;
  36. } REGKEY_LIST;
  37. //
  38. // Table that will have the list of ISN node. Need to allocate runtime.
  39. //
  40. #define WOW64_ISN_NODE_MAX_NUM 12 // this is internal to wow64 setup might use different size of table
  41. NODETYPE IsnNode[WOW64_ISN_NODE_MAX_NUM]={
  42. {L"\\REGISTRY\\MACHINE\\SOFTWARE\\CLASSES"},
  43. {L"\\REGISTRY\\MACHINE\\SOFTWARE"},
  44. {L"\\REGISTRY\\USER\\*\\SOFTWARE\\CLASSES"}, // ISN node table is always upcase.
  45. {L"\\REGISTRY\\USER\\*_CLASSES"},
  46. {L"\\REGISTRY\\MACHINE\\SYSTEM\\TEST"},
  47. {L""}
  48. };
  49. //
  50. // 64bit IE load mail client dll inproc breaking interop functionality.
  51. // The are some Dll get loaded Inproc {L"\\REGISTRY\\MACHINE\\SOFTWARE\\Clients\\mail"}, //Email Client Key
  52. //
  53. // Must keep 32-bit and 64-bit uninstall keys separate to ensure the correct environment
  54. // variables are used for REG_EXPAND_SZ and to make sure we run the correct bitness of rundll32.exe.
  55. // {L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\UnInstall"}, // UnInstall Key
  56. //
  57. REGKEY_LIST ExemptRedirectedKey[]={
  58. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\SystemCertificates"), // Certificate Key
  59. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Cryptography\\Services"), // Cryptography Service
  60. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Classes\\HCP"), // HelpCenter Key
  61. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\EnterpriseCertificates"), // Enterprise Service
  62. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\MSMQ"), // MSMQ registry
  63. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"), // Profiles
  64. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib"), // Performance counters
  65. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print"), // Spooler Printers
  66. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Ports"), // Spooler Ports
  67. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Policies"), // policie keys
  68. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies"), //Policy Keys
  69. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\OC Manager"), //OC Manager Keys
  70. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Software\\Microsoft\\Shared Tools\\MSInfo"), //share MSinfo Key
  71. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup"), //Share setup Keys
  72. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\CTF\\TIP"), //CTF\TIP Key
  73. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\CTF\\SystemShared"),
  74. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"), //Share fonts
  75. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\RAS"), // RAS keys need to be shared
  76. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Driver Signing"), // Share Driver signing Keys
  77. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Non-Driver Signing"), // Share Driver signing Keys
  78. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Cryptography\\Calais\\Current"), // SmartCard subsytem pipe name
  79. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Cryptography\\Calais\\Readers"), // SmartCard installed readers
  80. KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones"), // Share time zone key
  81. KEY_NAME(L""), // Two additional NULL String for additional space.
  82. KEY_NAME(L"")
  83. };
  84. //
  85. // A note about PerfLib... in ntos\config, the init code creates a special
  86. // key called PerfLib\009 and if you call NtOpenKey on that path, it returns
  87. // back HKEY_PERFORMANCE_DATA, not a regular kernel registry handle to
  88. // \\REGISTRY\\MACHINE\\stuff. Instead, HKEY_PERFORMANCE_DATA is intercepted
  89. // in usermode by advapi32.dll. The Counters and Help REG_MULTI_SZ values
  90. // don't really exist - they are synthesized by advapi32 based on the
  91. // contents of the perf*.dat files in system32. This works OK for 32-bit
  92. // advapi32 on WOW64 as advapi opens the *.dat files using NtOpenFile
  93. // with an OBJECT_ATTRIBUTES containing "\SystemRoot\System32\..." which
  94. // doesn't get intercepted by the system32 remapper.
  95. //
  96. PWCHAR
  97. wcsistr(
  98. PWCHAR string1,
  99. PWCHAR string2
  100. )
  101. {
  102. PWCHAR p1;
  103. PWCHAR p2;
  104. if ((NULL == string2) || (NULL == string1))
  105. {
  106. // do whatever wcsstr would do
  107. return wcsstr(string1, string2);
  108. }
  109. while (*string1)
  110. {
  111. for (p1 = string1, p2 = string2;
  112. *p1 && *p2 && towlower(*p1) == towlower(*p2);
  113. ++p1, ++p2)
  114. {
  115. // nothing
  116. }
  117. if (!*p2)
  118. {
  119. // we found a match!
  120. return (PWCHAR)string1; // cast away const!
  121. }
  122. ++string1;
  123. }
  124. return NULL;
  125. }
  126. PWCHAR
  127. wcsstrWow6432Node (
  128. PWCHAR pSrc
  129. )
  130. {
  131. return wcsistr (pSrc, NODE_NAME_32BIT);
  132. }
  133. PWCHAR
  134. wcsstrWithWildCard (
  135. PWCHAR srcStr,
  136. PWCHAR destIsnNode
  137. )
  138. /*++
  139. Routine Description:
  140. a customised version of wcsstr with wild card support. For example the
  141. substring might have '*' character which can be matched with any key name.
  142. Arguments:
  143. srcStr - The string where the substring need to be searched for.
  144. destIsnNode - the string to search.
  145. Return Value:
  146. TRUE if the operation succeed, FALSE otherwise.
  147. --*/
  148. {
  149. //multiple wildcard isn't allowed?
  150. PWCHAR src = srcStr;
  151. PWCHAR dest = destIsnNode;
  152. PWCHAR p, t;
  153. DWORD count;
  154. for (;;) {
  155. if (*dest == UNICODE_NULL)
  156. return ( *src == UNICODE_NULL)? src : src+1; //source might point to SLASH
  157. if (*src == UNICODE_NULL)
  158. return NULL;
  159. count = wcslen (dest);
  160. if ( ( p = wcschr( dest,'*') ) == NULL ) {
  161. if ( _wcsnicmp (src, dest, count) == 0 ){
  162. //
  163. // xx\Test shouldn't show xx\test345 as an ISN node.
  164. //
  165. if ( src [ count ] != UNICODE_NULL && src [ count ] != L'\\' ) //terminator need tobe NULL or slash
  166. return NULL;
  167. return (*(src+count) != UNICODE_NULL ) ? src+count+1: src+count; // xx\test return pointer at test if dest is xx.
  168. }
  169. else
  170. return NULL;
  171. }
  172. count = (DWORD) (p-dest);
  173. // LOGPRINT( (ERRORLOG, "\nFinding [%S] withing %S, p=%S Val%d",dest, src, p, count ));
  174. if (_wcsnicmp (src, dest, count) !=0) // checking the initial state
  175. return NULL;
  176. //
  177. // need to check *_Classes type ISN Node
  178. //
  179. p++; //skip the wild card
  180. t=src+count;
  181. while ( *t != L'\\' && *t != UNICODE_NULL )
  182. t++;
  183. if ( *p != UNICODE_NULL || *p != L'\\') { //*_Classes form
  184. for ( count=0;*p != L'\\' && *p != UNICODE_NULL; p++, count++)
  185. ;
  186. if (_wcsnicmp (p-count, t-count, count) != 0)
  187. return NULL;
  188. }
  189. // LOGPRINT( (ERRORLOG, "\nFinding 2nd[%S] withing %S, p=%S",dest, src, p ));
  190. src = t;
  191. dest = p;
  192. }
  193. return NULL;
  194. }
  195. HKEY
  196. OpenNode (
  197. PWCHAR NodeName
  198. )
  199. /*++
  200. Routine Description:
  201. Open a given key for generic access.
  202. Arguments:
  203. NodeName - name of the key to check.
  204. Return Value:
  205. NULL in case of failure.
  206. Valid handle otherwise.
  207. --*/
  208. {
  209. NTSTATUS st;
  210. HKEY hKey;
  211. OBJECT_ATTRIBUTES Obja;
  212. UNICODE_STRING KeyName;
  213. RtlInitUnicodeString (&KeyName, NodeName);
  214. InitializeObjectAttributes (&Obja, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL );
  215. st = NtOpenKey (&hKey, KEY_ALL_ACCESS, &Obja);
  216. if (!NT_SUCCESS(st))
  217. return NULL;
  218. return hKey;
  219. }
  220. VOID
  221. CloseNode (
  222. HANDLE Key
  223. )
  224. {
  225. NtClose (Key);
  226. }
  227. NTSTATUS
  228. IsNodeExist (
  229. PWCHAR NodeName
  230. )
  231. /*++
  232. Routine Description:
  233. Check if the given key exist if not create the key.
  234. Arguments:
  235. NodeName - name of the key to check.
  236. Return Value:
  237. TRUE if the operation succeed, FALSE otherwise.
  238. --*/
  239. {
  240. NTSTATUS st;
  241. HANDLE hKey;
  242. OBJECT_ATTRIBUTES Obja;
  243. UNICODE_STRING KeyName;
  244. RtlInitUnicodeString (&KeyName, NodeName);
  245. InitializeObjectAttributes (&Obja, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL );
  246. st = NtOpenKey (&hKey, KEY_READ, &Obja);
  247. if (!NT_SUCCESS(st))
  248. return st;
  249. NtClose (hKey);
  250. //LOGPRINT( (ERRORLOG, "\nValid IsnNode [%S]",NodeName ));
  251. return st;
  252. }
  253. BOOL
  254. CreateNode (
  255. PWCHAR Path
  256. )
  257. /*++
  258. Routine Description:
  259. Create all the node along the path if missing. Called by background
  260. thread working on the setup.
  261. Arguments:
  262. Path - name of path to the key.
  263. Return Value:
  264. TRUE if the operation succeed, FALSE otherwise.
  265. --*/
  266. {
  267. //
  268. // isolate individual nodes and backtrack
  269. //
  270. NTSTATUS st;
  271. HANDLE hKey;
  272. HANDLE hKeyCreate;
  273. OBJECT_ATTRIBUTES Obja;
  274. UNICODE_STRING KeyName;
  275. PWCHAR pTrace;
  276. PWCHAR p;
  277. pTrace = Path+wcslen (Path); //pTrace point at the end of path
  278. p=pTrace;
  279. for (;;) {
  280. RtlInitUnicodeString (&KeyName, Path);
  281. InitializeObjectAttributes (&Obja, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL );
  282. st = NtOpenKey (&hKey, KEY_WRITE | KEY_READ, &Obja);
  283. if ( st == STATUS_OBJECT_NAME_NOT_FOUND ) {
  284. //backtrack until you hit the line
  285. while ( *p != L'\\' && p!= Path)
  286. p--;
  287. //LOGPRINT( (ERRORLOG, "\nTest Code[%S]",p ));
  288. if ( p == Path ) break;
  289. *p = UNICODE_NULL;
  290. continue;
  291. }
  292. break;
  293. }
  294. if (!NT_SUCCESS(st)) {
  295. //fixup the string and return
  296. for ( ;p != pTrace;p++ )
  297. if ( *p == UNICODE_NULL) *p=L'\\';
  298. return FALSE;
  299. }
  300. //
  301. // now create key from point p until p hit pTrace
  302. //
  303. while ( p != pTrace ) {
  304. *p = L'\\'; //added the char back
  305. p++; //p will point a non NULL string
  306. RtlInitUnicodeString (&KeyName, p);
  307. InitializeObjectAttributes (&Obja, &KeyName, OBJ_CASE_INSENSITIVE, hKey, NULL );
  308. st = NtCreateKey(
  309. &hKeyCreate,
  310. KEY_WRITE | KEY_READ,
  311. &Obja,
  312. 0,
  313. NULL ,
  314. REG_OPTION_NON_VOLATILE,
  315. NULL
  316. );
  317. if (!NT_SUCCESS(st)) {
  318. LOGPRINT( (ERRORLOG, "\nCouldn't create Key named[%S]",p ));
  319. break;
  320. }
  321. NtClose (hKey);
  322. hKey = hKeyCreate;
  323. while ( *p != UNICODE_NULL ) p++;
  324. }
  325. NtClose (hKey);
  326. if (!NT_SUCCESS(st)) {
  327. for ( ;p != pTrace;p++ )
  328. if ( *p == UNICODE_NULL) *p=L'\\';
  329. return FALSE;
  330. }
  331. return TRUE;
  332. }
  333. BOOL
  334. CheckAndCreateNode (
  335. IN PWCHAR Name
  336. )
  337. /*++
  338. Routine Description:
  339. Check if the given key exist if not create the key. called by background
  340. thread working on the setup.
  341. Arguments:
  342. Name - name of the key to check.
  343. Return Value:
  344. TRUE if the operation succeed, FALSE otherwise.
  345. --*/
  346. {
  347. ISN_NODE_TYPE Node;
  348. PWCHAR p;
  349. //
  350. // if parent doesn't exist you shouldn't create the child
  351. //
  352. if (!NT_SUCCESS(IsNodeExist (Name)) ) {
  353. p = wcsstrWow6432Node (Name);
  354. if ( p != NULL ) {
  355. wcsncpy (Node.NodeValue, Name, p-Name-1);
  356. Node.NodeValue[p-Name-1] = UNICODE_NULL;
  357. }
  358. else
  359. return FALSE;
  360. if (NT_SUCCESS(IsNodeExist (Node.NodeValue)) )
  361. return CreateNode (Name);
  362. }
  363. return TRUE;
  364. }
  365. //
  366. // Opaque field might contain some information about the key on the 32bit side.
  367. //
  368. BOOL
  369. IsIsnNode (
  370. PWCHAR wStr,
  371. PWCHAR *pwStrIsn
  372. )
  373. /*++
  374. Routine Description:
  375. Will determine if the given path has any ISN node.
  376. Arguments:
  377. wStr - string to that might contain some ISN node.
  378. pwStrDest - point to the node after ISN node.
  379. Return Value:
  380. TRUE if the string has any ISN node, FALSE otherwise
  381. --*/
  382. {
  383. int Index=0;
  384. //
  385. // Check if the provided string is already on the 32 bit tree, if so we can
  386. // just ignore that
  387. //
  388. //
  389. // check if input string has any known symbolic link like \registry\user\sid_Classes that need to remap to a different location
  390. //
  391. for (;;) {
  392. if ( IsnNode [Index][0]==UNICODE_NULL ) break;
  393. if ( (*pwStrIsn = wcsstrWithWildCard (wStr, IsnNode[Index] ) ) != NULL )
  394. return TRUE;
  395. Index++;
  396. };
  397. *pwStrIsn = NULL;
  398. return FALSE;
  399. }
  400. NTSTATUS
  401. ObjectAttributesToKeyName (
  402. POBJECT_ATTRIBUTES ObjectAttributes,
  403. PWCHAR AbsPath,
  404. DWORD AbsPathLenIn,
  405. BOOL *bPatched,
  406. DWORD *ParentLen
  407. )
  408. /*++
  409. Routine Description:
  410. Determine the text equivalent for key handle
  411. Arguments:
  412. ObjectAttributes define the object attribute Keyname need to be constracted.
  413. AbsPath Unicode string to receive the Name of the key.
  414. bPatched - TRUE if the Name has been compressed/expanded that
  415. the original object can't refer. Caller need to construct
  416. a new obj attribute.
  417. unchanged otherwise.
  418. ParentLen - Length of the parent name.
  419. Return Value:
  420. NTSTATUS
  421. --*/
  422. {
  423. NTSTATUS Status;
  424. ULONG Length;
  425. ULONG AbsPathLen = 0;
  426. BYTE *pAbsPath = (PBYTE)AbsPath;
  427. POBJECT_NAME_INFORMATION ObjectName = (POBJECT_NAME_INFORMATION)AbsPath; //Smartly use user buffer
  428. if (ParentLen)
  429. *ParentLen = 0;
  430. if (ObjectAttributes->RootDirectory) {
  431. Status = NtQueryObject(ObjectAttributes->RootDirectory,
  432. ObjectNameInformation,
  433. ObjectName,
  434. AbsPathLenIn,
  435. &Length
  436. );
  437. if ( !NT_SUCCESS(Status) )
  438. return Status;
  439. } else {
  440. AbsPathLen = ObjectAttributes->ObjectName->Length;
  441. if (AbsPathLenIn <= AbsPathLen)
  442. return STATUS_BUFFER_OVERFLOW;
  443. memcpy ( pAbsPath, (PBYTE)ObjectAttributes->ObjectName->Buffer, AbsPathLen );
  444. *(WCHAR *)(pAbsPath+AbsPathLen) = UNICODE_NULL;
  445. if (ParentLen)
  446. *ParentLen = AbsPathLen; // length of the parent handle
  447. return STATUS_SUCCESS;
  448. }
  449. //
  450. // copy the root and sub path
  451. //
  452. AbsPathLen = ObjectName->Name.Length;
  453. memcpy ( pAbsPath, (PBYTE)ObjectName->Name.Buffer, AbsPathLen);
  454. if ( ObjectAttributes->ObjectName->Length > 1 ) { // Valid object name need to be greater
  455. *(WCHAR *)(pAbsPath+AbsPathLen) = L'\\';
  456. AbsPathLen += sizeof ( L'\\');
  457. if (AbsPathLenIn <= (AbsPathLen+ObjectAttributes->ObjectName->Length))
  458. return STATUS_BUFFER_OVERFLOW;
  459. memcpy (
  460. pAbsPath+AbsPathLen,
  461. ObjectAttributes->ObjectName->Buffer,
  462. ObjectAttributes->ObjectName->Length
  463. );
  464. AbsPathLen += ObjectAttributes->ObjectName->Length;
  465. }
  466. *(WCHAR *)(pAbsPath+AbsPathLen) = UNICODE_NULL;
  467. //
  468. // Compress the path in case multiple wow6432node exist
  469. //
  470. for (;;) {
  471. PWCHAR p, t;
  472. if ( (p=wcsstrWow6432Node (AbsPath)) != NULL ) {
  473. if ( (t=wcsstrWow6432Node(p+1)) != NULL) {
  474. wcscpy (p,t);
  475. *bPatched = TRUE;
  476. }
  477. else break;
  478. } else break;
  479. }
  480. return STATUS_SUCCESS;
  481. }
  482. BOOL
  483. HandleToKeyName (
  484. HANDLE Key,
  485. PWCHAR KeyName,
  486. DWORD * dwLen
  487. )
  488. /*++
  489. Routine Description:
  490. Determine the text equivalent for key handle
  491. Arguments:
  492. Key - is key handle for which to obtain its text
  493. KeyName - Unicode string to receive the Name of the key.
  494. dwLen - Length of the buffer pointed by KeyName. (Number of unicode char)
  495. Return Value:
  496. TRUE if the handle text is fetched OK. FALSE if not (ie. error or
  497. Key is an illegal handle, etc.)
  498. --*/
  499. {
  500. NTSTATUS Status;
  501. ULONG Length;
  502. DWORD NameLen;
  503. POBJECT_NAME_INFORMATION ObjectName;
  504. ObjectName = (POBJECT_NAME_INFORMATION)KeyName; //use the user buffer to make the call to save space on stack.
  505. KeyName[0]= UNICODE_NULL;
  506. if (Key == NULL) {
  507. KeyName[0]= UNICODE_NULL;
  508. return FALSE;
  509. }
  510. Status = NtQueryObject(Key,
  511. ObjectNameInformation,
  512. ObjectName,
  513. *dwLen-8,
  514. &Length
  515. );
  516. NameLen = ObjectName->Name.Length/sizeof(WCHAR);
  517. if (!NT_SUCCESS(Status) || !Length || Length >= (*dwLen-8)) {
  518. DbgPrint ("\nHandleToKeyName: NtQuery Object failed St:%x, Handle: %x", Status, Key);
  519. KeyName[0]= UNICODE_NULL;
  520. return FALSE;
  521. }
  522. //
  523. // buffer overflow condition check
  524. //
  525. if (*dwLen < ( NameLen + 8+ 2) ) {
  526. *dwLen = 2 + NameLen + 8;
  527. DbgPrint ("\nHandleToKeyName: Buffer over flow.");
  528. KeyName[0]= UNICODE_NULL;
  529. return FALSE; //buffer overflow
  530. }
  531. wcsncpy(KeyName, ObjectName->Name.Buffer, NameLen);
  532. KeyName[NameLen]=UNICODE_NULL;
  533. return TRUE;
  534. }
  535. BOOL
  536. Map32bitTo64bitKeyName (
  537. IN PWCHAR Name32Key,
  538. OUT PWCHAR Name64Key
  539. )
  540. /*++
  541. Routine Description:
  542. Return a key name valid in the 64-bit registry side. It's the caller responsibility
  543. to give enough space in the output buffer. Its internal routine and no boundary
  544. checking is done here.
  545. Arguments:
  546. Name32Key - Input 32bit/64 bit Key name.
  547. Name64Key - Receiving Buffer that will hold the equivalent 64bit Key.
  548. Return Value:
  549. TRUE if the remapping become successful.
  550. FALSE otherwise.
  551. --*/
  552. {
  553. //
  554. // just remove 32bit related patch from the name if anything like that exist.
  555. // If the key is already on the 64bit side don't bother return the whole copy.
  556. //
  557. PWCHAR NodeName32Bit;
  558. DWORD Count;
  559. try {
  560. if ( ( NodeName32Bit = wcsstrWow6432Node (Name32Key)) == NULL) { // nothing to remap
  561. wcscpy (Name64Key, Name32Key);
  562. return TRUE;
  563. }
  564. Count = (DWORD)(NodeName32Bit - Name32Key);
  565. wcsncpy (Name64Key, Name32Key, Count-1);
  566. Name64Key[Count-1]=UNICODE_NULL;
  567. if (NodeName32Bit[NODE_NAME_32BIT_LEN] == L'\\')
  568. wcscpy (
  569. Name64Key + Count-1,
  570. NodeName32Bit + NODE_NAME_32BIT_LEN); //One if to skip the char'/'
  571. } except( NULL, EXCEPTION_EXECUTE_HANDLER){
  572. return FALSE;
  573. }
  574. return TRUE; //any complete path can have only one instance of NODE_NAME_32BIT
  575. }
  576. BOOL
  577. IsExemptRedirectedKey (
  578. IN PWCHAR SrcKey,
  579. OUT PWCHAR DestKey
  580. )
  581. /*++
  582. Routine Description:
  583. Check if the the source key point to the list of exempt key from redirection.
  584. If so DestKey will have the right value.
  585. Arguments:
  586. Name64Key - Input 32bit/64 bit Key name.
  587. Name32Key - Receiving Buffer that will hold the equivalent 32bit Key.
  588. Return Value:
  589. TRUE if the Key is on the list of exempt key from redirection.
  590. FALSE otherwise.
  591. --*/
  592. {
  593. //
  594. // Make 64bit only path
  595. //
  596. PWCHAR NodeName32Bit;
  597. DWORD dwIndex =0;
  598. wcscpy (DestKey, SrcKey);
  599. if ( ( NodeName32Bit = wcsstrWow6432Node (DestKey)) != NULL) { // nothing to remap patch is already there
  600. NodeName32Bit--;
  601. wcscpy (NodeName32Bit, NodeName32Bit+sizeof (NODE_NAME_32BIT)/sizeof (WCHAR));
  602. }
  603. for ( dwIndex = 0; ExemptRedirectedKey[dwIndex].KeyPath[0] != UNICODE_NULL; dwIndex++ )
  604. if (_wcsnicmp (DestKey, ExemptRedirectedKey[dwIndex].KeyPath, ExemptRedirectedKey[dwIndex].Len ) == 0)
  605. return TRUE;
  606. return FALSE;
  607. }
  608. BOOL
  609. Map64bitTo32bitKeyName (
  610. IN PWCHAR Name64Key,
  611. OUT PWCHAR Name32Key
  612. )
  613. /*++
  614. Routine Description:
  615. Return a key name valid in the 32-bit registry side. It's the caller responsibility
  616. to give enough space in the output buffer. Its internal routine and no boundary
  617. checking is done here.
  618. Arguments:
  619. Name64Key - Input 32bit/64 bit Key name.
  620. Name32Key - Receiving Buffer that will hold the equivalent 32bit Key.
  621. Return Value:
  622. TRUE if the remapping become successful.
  623. FALSE otherwise.
  624. --*/
  625. {
  626. //
  627. // just add 32bit related patch from the name if anything like that exist.
  628. // or fall under the ISN nodes.
  629. //
  630. PWCHAR NodeName32Bit;
  631. DWORD Count;
  632. try {
  633. if (IsExemptRedirectedKey (Name64Key, Name32Key) )
  634. return TRUE;
  635. if ( ( NodeName32Bit = wcsstrWow6432Node (Name64Key)) != NULL) { // nothing to remap patch is already there
  636. wcscpy (Name32Key, Name64Key);
  637. return TRUE;
  638. }
  639. if (!IsIsnNode ( Name64Key, &NodeName32Bit)) {
  640. wcscpy (Name32Key, Name64Key);
  641. return TRUE;
  642. }
  643. Count = (DWORD)(NodeName32Bit - Name64Key); // Displacement offset where the patch shoud go.
  644. //
  645. // consider the case when 32bit apps need to create/open the real ISN node which doesn't exist
  646. //
  647. wcsncpy (Name32Key,Name64Key, Count);
  648. if (Name32Key[Count-1] != L'\\') {
  649. Name32Key[Count] = L'\\';
  650. Count++;
  651. }
  652. wcscpy (Name32Key+Count, NODE_NAME_32BIT);
  653. if ( *NodeName32Bit != UNICODE_NULL ) {
  654. wcscat (Name32Key, L"\\");
  655. wcscat (Name32Key, NodeName32Bit);
  656. }
  657. } except( NULL, EXCEPTION_EXECUTE_HANDLER){
  658. return FALSE;
  659. }
  660. return TRUE; //any complete path can have only one instance of NODE_NAME_32BIT
  661. }
  662. NTSTATUS
  663. OpenIsnNodeByObjectAttributes (
  664. POBJECT_ATTRIBUTES ObjectAttributes,
  665. ACCESS_MASK DesiredAccess,
  666. PHANDLE phPatchedHandle
  667. )
  668. /*++
  669. Routine Description:
  670. If this Keyhandle is an open handle to an ISN node then this function
  671. return a handle to the node on the 32 bit tree. If not then we create the whole
  672. path and see if any ISN node is there. If so we Get the path on the 32bit tree and
  673. return Open that key.
  674. Scenario:
  675. 1. Absolute path made from Directory root and relative path don't contain any ISN node.
  676. -Open that normally.
  677. 2. Directory Handle point to the immediate parent of ISN node and the relative path is
  678. just an ISN node.
  679. -if 32 bit equivalent of ISN node exist open that and return that. If the 32 bit node
  680. doesn't exist create one and return that. [Problem open Directory Handle might not
  681. have create access.
  682. 3 Directory Handle point to an ISN node and relative path is just an immediate chield.
  683. - This can never happen. If we follow the algorithm, directory handly can't point on
  684. to an ISN node but on 32 bit equivalent node.
  685. 4. Same as 2 but relative path might be grand child or far bellow.
  686. - If 32 bit equivalent node isn't there just create that and open the rest.
  687. How 32 bit Apps can open an ISN node:
  688. <TBD> the proposal is a s follows:
  689. 1. Redirector will maintain a list of exempt handle that were created to access ISN node.
  690. 2. Any open call relative to those handle will also be on the exemped list.
  691. 3. NtClose thunk will remove
  692. Arguments:
  693. KeyHandle - Handle to the node on the 64 bit tree.
  694. phPatchedHandle - receive the appropriate handle if this function succeed.
  695. Return Value:
  696. NTSTATUS;
  697. --*/
  698. {
  699. UNICODE_STRING Parent;
  700. NTSTATUS st;
  701. OBJECT_ATTRIBUTES Obja;
  702. WCHAR PatchedIsnNode[WOW64_MAX_PATH+256];
  703. WCHAR AbsPath[WOW64_MAX_PATH+256];
  704. BOOL bPatched;
  705. DWORD ParentLen;
  706. //
  707. // Make the complete path in a AbsPath
  708. //
  709. *phPatchedHandle=NULL;
  710. st = ObjectAttributesToKeyName (
  711. ObjectAttributes,
  712. AbsPath,
  713. sizeof (AbsPath),
  714. &bPatched,
  715. &ParentLen );
  716. if (!NT_SUCCESS(st)) {
  717. LOGPRINT( (ERRORLOG, "\nWow64:Extremely Bad!!!!!!!!!!!!!!! Couldn't retrieve object name"));
  718. return st;
  719. }
  720. if (DesiredAccess & KEY_WOW64_64KEY) {
  721. if (!Map32bitTo64bitKeyName ( AbsPath, PatchedIsnNode ))
  722. return -1; //severe problem shouldn't happen
  723. } else {
  724. PWCHAR p;
  725. if (!Map64bitTo32bitKeyName ( AbsPath, PatchedIsnNode ))
  726. return -1; //severe problem shouldn't happen
  727. //
  728. // If parent root immediately point just before or anywhere after the patch don't patch
  729. //
  730. /*if (!(DesiredAccess & KEY_WOW64_32KEY ) ) {
  731. p = wcsstr (PatchedIsnNode, NODE_NAME_32BIT);
  732. if (p) {
  733. DWORD Len;
  734. p--; //back one step to ignore slash before Wow6432Node
  735. Len = (DWORD) (p-PatchedIsnNode);
  736. Len *= sizeof (WCHAR); //get byte
  737. if (Len >= ParentLen ) {
  738. Wow64RegDbgPrint (( "\nRemapNtOpenKeyEx OUT: Will not patch %S", PatchedIsnNode));
  739. return STATUS_SUCCESS;
  740. }
  741. }
  742. } */
  743. }
  744. DesiredAccess = DesiredAccess & (~KEY_WOW64_RES);
  745. //
  746. // Handle the hardlink we have HKLM\Software\wow6432node\classes ==>HKCR\Classes
  747. //
  748. /*if (_wcsnicmp (PatchedIsnNode, L"\\REGISTRY\\MACHINE\\SOFTWARE\\Wow6432Node\\Classes", 19+27) == 0) {
  749. wcsncpy (PatchedIsnNode+27, L"Classes\\Wow6432Node", 19); //sizeof (L"Wow6432Node\\Classes")/2);
  750. bPatched = TRUE;
  751. }*/
  752. //
  753. // no change can be optimize by returning different value from Map64bitTo32bitKeyName
  754. // Caller need to handle this
  755. //
  756. if ( !bPatched)
  757. if ( !wcscmp (AbsPath, PatchedIsnNode ))
  758. return STATUS_SUCCESS;
  759. RtlInitUnicodeString (&Parent, PatchedIsnNode);
  760. InitializeObjectAttributes (&Obja, &Parent, ObjectAttributes->Attributes, NULL, ObjectAttributes->SecurityDescriptor ); //you have to use caller's context
  761. st = NtOpenKey (phPatchedHandle, DesiredAccess, &Obja);
  762. #ifdef WOW64_LOG_REGISTRY
  763. if (!NT_SUCCESS (st))
  764. Wow64RegDbgPrint (( "\nRemapNtOpenKeyEx OUT: couldn't open %S", PatchedIsnNode));
  765. #endif
  766. return st;
  767. }
  768. NTSTATUS
  769. RemapNtCreateKey(
  770. OUT PHANDLE phPatchedHandle,
  771. IN ACCESS_MASK DesiredAccess,
  772. IN POBJECT_ATTRIBUTES ObjectAttributes,
  773. IN ULONG TitleIndex,
  774. IN PUNICODE_STRING Class OPTIONAL,
  775. IN ULONG CreateOptions,
  776. OUT PULONG Disposition OPTIONAL
  777. )
  778. /*++
  779. Routine Description:
  780. An existing registry key may be opened, or a new one created,
  781. with NtCreateKey.
  782. If the specified key does not exist, an attempt is made to create it.
  783. For the create attempt to succeed, the new node must be a direct
  784. child of the node referred to by KeyHandle. If the node exists,
  785. it is opened. Its value is not affected in any way.
  786. Share access is computed from desired access.
  787. NOTE:
  788. If CreateOptions has REG_OPTION_BACKUP_RESTORE set, then
  789. DesiredAccess will be ignored. If the caller has the
  790. privilege SeBackupPrivilege asserted, a handle with
  791. KEY_READ | ACCESS_SYSTEM_SECURITY will be returned.
  792. If SeRestorePrivilege, then same but KEY_WRITE rather
  793. than KEY_READ. If both, then both access sets. If neither
  794. privilege is asserted, then the call will fail.
  795. Arguments:
  796. KeyHandle - Receives a Handle which is used to access the
  797. specified key in the Registration Database.
  798. DesiredAccess - Specifies the access rights desired.
  799. ObjectAttributes - Specifies the attributes of the key being opened.
  800. Note that a key name must be specified. If a Root Directory is
  801. specified, the name is relative to the root. The name of the
  802. object must be within the name space allocated to the Registry,
  803. that is, all names beginning "\Registry". RootHandle, if
  804. present, must be a handle to "\", or "\Registry", or a key
  805. under "\Registry".
  806. RootHandle must have been opened for KEY_CREATE_SUB_KEY access
  807. if a new node is to be created.
  808. NOTE: Object manager will capture and probe this argument.
  809. TitleIndex - Specifies the index of the localized alias for
  810. the name of the key. The title index specifies the index of
  811. the localized alias for the name. Ignored if the key
  812. already exists.
  813. Class - Specifies the object class of the key. (To the registry
  814. this is just a string.) Ignored if NULL.
  815. CreateOptions - Optional control values:
  816. REG_OPTION_VOLATILE - Object is not to be stored across boots.
  817. Disposition - This optional parameter is a pointer to a variable
  818. that will receive a value indicating whether a new Registry
  819. key was created or an existing one opened:
  820. REG_CREATED_NEW_KEY - A new Registry Key was created
  821. REG_OPENED_EXISTING_KEY - An existing Registry Key was opened
  822. Return Value:
  823. NTSTATUS - Result code from call, among the following:
  824. <TBS>
  825. --*/
  826. {
  827. UNICODE_STRING Parent;
  828. NTSTATUS st;
  829. OBJECT_ATTRIBUTES Obja;
  830. WCHAR PatchedIsnNode[WOW64_MAX_PATH];
  831. WCHAR AbsPath[WOW64_MAX_PATH];
  832. BOOL bPatched=FALSE;
  833. DWORD ParentLen;
  834. //
  835. // Make the complete path in a AbsPath
  836. //
  837. if (ARGUMENT_PRESENT(phPatchedHandle)){
  838. *phPatchedHandle=NULL;
  839. }
  840. st = ObjectAttributesToKeyName (
  841. ObjectAttributes,
  842. AbsPath,
  843. sizeof (AbsPath),
  844. &bPatched,
  845. &ParentLen);
  846. if (!NT_SUCCESS(st)) {
  847. WOWASSERT(FALSE );
  848. return st;
  849. }
  850. if (DesiredAccess & KEY_WOW64_64KEY) {
  851. if (!Map32bitTo64bitKeyName ( AbsPath, PatchedIsnNode )) {
  852. WOWASSERT(FALSE );
  853. return STATUS_SUCCESS; //severe problem shouldn't happen
  854. }
  855. } else {
  856. PWCHAR p;
  857. if (!Map64bitTo32bitKeyName ( AbsPath, PatchedIsnNode )){
  858. WOWASSERT(FALSE );
  859. return STATUS_SUCCESS; //severe problem shouldn't happen
  860. }
  861. //
  862. // If parent root immediately point just before or anywhere after the patch don't patch
  863. //
  864. /*
  865. if (!(DesiredAccess & KEY_WOW64_32KEY ) ) { //implied 32bit access
  866. p = wcsstr (PatchedIsnNode, NODE_NAME_32BIT);
  867. if (p) {
  868. DWORD Len;
  869. p--; //back one step to ignore slash before Wow6432Node
  870. Len = (DWORD) (p-PatchedIsnNode);
  871. Len *= sizeof (WCHAR); //get byte
  872. if (Len >= ParentLen ) {
  873. Wow64RegDbgPrint (( "\nRemapNtOpenKeyEx OUT: Will not patch %S", PatchedIsnNode));
  874. return STATUS_SUCCESS;
  875. }
  876. }
  877. }*/
  878. }
  879. DesiredAccess = DesiredAccess & (~KEY_WOW64_RES);
  880. //
  881. // Handle the hardlink we have HKLM\Software\wow6432node\classes ==>HKCR\Classes
  882. //
  883. /*if (_wcsnicmp (PatchedIsnNode, L"\\REGISTRY\\MACHINE\\SOFTWARE\\Wow6432Node\\Classes", 19+27) == 0) {
  884. bPatched = TRUE;
  885. wcsncpy (PatchedIsnNode+27, L"Classes\\Wow6432Node", 19); //sizeof (L"Wow6432Node\\Classes")/2);
  886. }*/
  887. if (!bPatched) // the abspath hasn't been patched
  888. if ( !wcscmp (AbsPath, PatchedIsnNode ))
  889. return STATUS_SUCCESS; // no change can be optimize by returning different value from Map64bitTo32bitKeyName
  890. RtlInitUnicodeString (&Parent, PatchedIsnNode);
  891. InitializeObjectAttributes (&Obja,
  892. &Parent,
  893. ObjectAttributes->Attributes,
  894. NULL,
  895. ObjectAttributes->SecurityDescriptor
  896. ); //you have to use caller's context
  897. st = NtCreateKey(
  898. phPatchedHandle,
  899. DesiredAccess,
  900. &Obja,
  901. TitleIndex,
  902. Class ,
  903. CreateOptions,
  904. Disposition
  905. );
  906. return st;
  907. }
  908. NTSTATUS
  909. Wow64NtPreUnloadKeyNotify(
  910. IN POBJECT_ATTRIBUTES TargetKey
  911. )
  912. /*++
  913. Routine Description:
  914. This call will notify Wow64 service that wow64 need to release any open handle
  915. to the hive that is going to be unloaded.
  916. Drop a subtree (hive) out of the registry.
  917. Will fail if applied to anything other than the root of a hive.
  918. Cannot be applied to core system hives (HARDWARE, SYSTEM, etc.)
  919. Can be applied to user hives loaded via NtRestoreKey or NtLoadKey.
  920. If there are handles open to the hive being dropped, this call
  921. will fail. Terminate relevent processes so that handles are
  922. closed.
  923. This call will flush the hive being dropped.
  924. Caller must have SeRestorePrivilege privilege.
  925. Arguments:
  926. TargetKey - specifies the path to a key to link the hive to.
  927. path must be of the form "\registry\user\<username>"
  928. Return Value:
  929. NTSTATUS - values TBS.
  930. --*/
  931. {
  932. //todo
  933. return 0;
  934. }
  935. NTSTATUS
  936. Wow64NtPostLoadKeyNotify(
  937. IN POBJECT_ATTRIBUTES TargetKey
  938. )
  939. /*++
  940. Routine Description:
  941. If Load operation succeed, it will notify wow64 service that it
  942. can listen to the registry operation on the given hive.
  943. This function can be invoked from NtLoadKey and NtLoadKey2 APIs.
  944. A hive (file in the format created by NtSaveKey) may be linked
  945. into the active registry with this call. UNLIKE NtRestoreKey,
  946. the file specified to NtLoadKey will become the actual backing
  947. store of part of the registry (that is, it will NOT be copied.)
  948. The file may have an associated .log file.
  949. If the hive file is marked as needing a .log file, and one is
  950. not present, the call will fail.
  951. Caller must have SeRestorePrivilege privilege.
  952. This call is used by logon to make the user's profile available
  953. in the registry. It is not intended for use doing backup,
  954. restore, etc. Use NtRestoreKey for that.
  955. Arguments:
  956. TargetKey - specifies the path to a key to link the hive to.
  957. path must be of the form "\registry\user\<username>"
  958. Return Value:
  959. NTSTATUS - values TBS.
  960. --*/
  961. {
  962. //todo
  963. return 0;
  964. }