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.

642 lines
14 KiB

  1. /****************************************************************************/
  2. // keynode.cpp
  3. //
  4. // Copyright (C) 1997-1999 Microsoft Corp.
  5. /****************************************************************************/
  6. #include <stdio.h>
  7. #include "KeyNode.h"
  8. extern ULONG g_length_TERMSRV_USERREGISTRY_DEFAULT;
  9. extern ULONG g_length_TERMSRV_INSTALL;
  10. extern WCHAR g_debugFileName[MAX_PATH];
  11. extern FILE *g_debugFilePointer;
  12. extern BOOLEAN g_debugIO;
  13. KeyBasicInfo::KeyBasicInfo():
  14. pNameSz(NULL)
  15. {
  16. size = sizeof(KEY_BASIC_INFORMATION) + MAX_PATH*sizeof(WCHAR);
  17. pInfo = ( KEY_BASIC_INFORMATION *)RtlAllocateHeap(RtlProcessHeap(), 0, size );
  18. if (!pInfo) {
  19. status = STATUS_NO_MEMORY;
  20. pInfo=NULL;
  21. }
  22. else
  23. status = STATUS_SUCCESS;
  24. }
  25. KeyBasicInfo::~KeyBasicInfo()
  26. {
  27. if (pInfo)
  28. {
  29. RtlFreeHeap( RtlProcessHeap(), 0, pInfo);
  30. }
  31. if (pNameSz)
  32. {
  33. delete pNameSz;
  34. }
  35. }
  36. PCWSTR KeyBasicInfo::NameSz()
  37. {
  38. if (Ptr()->NameLength < 2 * MAX_PATH )
  39. {
  40. if (!pNameSz)
  41. {
  42. pNameSz = new WCHAR [ MAX_PATH + 1 ];
  43. }
  44. // the reason we re do this every call of NameSz() is because
  45. // Ptr() might changes, since KeyBasicInfo is being used as a
  46. // scratch pad and passed around for storing pointers to some
  47. // basic set of info on any key.
  48. // see if allocation was successful
  49. if ( pNameSz )
  50. {
  51. for ( ULONG i=0; i < Ptr()->NameLength / sizeof(WCHAR) ; i++)
  52. {
  53. pNameSz[i] = ( (USHORT)Ptr()->Name[i] );
  54. }
  55. pNameSz[i]=L'\0';
  56. }
  57. }
  58. return pNameSz;
  59. }
  60. #if 0 // NOT USED yet!
  61. KeyNodeInfo::KeyNodeInfo()
  62. {
  63. size = sizeof(KEY_NODE_INFORMATION) + MAX_PATH*sizeof(WCHAR);
  64. pInfo = ( KEY_NODE_INFORMATION *)RtlAllocateHeap(RtlProcessHeap(), 0, size );
  65. if (!pInfo) {
  66. status = STATUS_NO_MEMORY;
  67. pInfo=NULL;
  68. }
  69. else
  70. status = STATUS_SUCCESS;
  71. }
  72. KeyNodeInfo::~KeyNodeInfo()
  73. {
  74. if (pInfo)
  75. {
  76. RtlFreeHeap( RtlProcessHeap(), 0, pInfo);
  77. }
  78. }
  79. #endif
  80. KeyFullInfo::KeyFullInfo() :
  81. pInfo(NULL)
  82. {
  83. size = sizeof(KEY_FULL_INFORMATION) + MAX_PATH*sizeof(WCHAR);
  84. pInfo = ( KEY_FULL_INFORMATION *)RtlAllocateHeap(RtlProcessHeap(), 0, size );
  85. if (!pInfo) {
  86. status = STATUS_NO_MEMORY;
  87. pInfo=NULL;
  88. }
  89. else
  90. status = STATUS_SUCCESS;
  91. }
  92. KeyFullInfo::~KeyFullInfo()
  93. {
  94. if (pInfo)
  95. {
  96. RtlFreeHeap( RtlProcessHeap(), 0, pInfo);
  97. }
  98. }
  99. KeyNode::KeyNode(HANDLE root, ACCESS_MASK access, PCWSTR name ) :
  100. root(NULL), hKey(NULL),
  101. accessMask(NULL),basic(NULL),full(NULL),
  102. pFullPath(NULL), pNameSz(NULL)
  103. {
  104. hKey = NULL;
  105. PCWSTR n = name;
  106. accessMask = access;
  107. RtlInitUnicodeString(&uniName, n);
  108. InitializeObjectAttributes(&ObjAttr,
  109. &uniName,
  110. OBJ_CASE_INSENSITIVE,
  111. root,
  112. NULL);
  113. status=STATUS_SUCCESS;
  114. }
  115. KeyNode::KeyNode(KeyNode *pParent, KeyBasicInfo *pInfo ) :
  116. root(NULL), hKey(NULL),
  117. accessMask(NULL),basic(NULL), full(NULL),
  118. pFullPath(NULL), pNameSz(NULL)
  119. {
  120. hKey = NULL;
  121. PCWSTR n = pInfo->Ptr()->Name;
  122. accessMask = pParent->Masks();
  123. RtlInitUnicodeString(&uniName, n);
  124. uniName.Length = (USHORT) pInfo->Ptr()->NameLength;
  125. InitializeObjectAttributes(&ObjAttr,
  126. &uniName,
  127. OBJ_CASE_INSENSITIVE,
  128. pParent->Key(),
  129. NULL);
  130. status=STATUS_SUCCESS;
  131. }
  132. KeyNode::~KeyNode()
  133. {
  134. Close();
  135. if (basic)
  136. {
  137. delete basic;
  138. }
  139. if (full)
  140. {
  141. delete full;
  142. }
  143. if (pFullPath)
  144. {
  145. RtlFreeHeap(RtlProcessHeap(), 0, pFullPath);
  146. }
  147. if( pNameSz )
  148. {
  149. delete pNameSz;
  150. }
  151. }
  152. NTSTATUS KeyNode::Open()
  153. {
  154. status = NtOpenKey(&hKey,
  155. accessMask,
  156. &ObjAttr);
  157. if ( !NT_SUCCESS( status))
  158. {
  159. hKey=NULL;
  160. // Debug(DBG_OPEN_FAILED );
  161. }
  162. return status;
  163. }
  164. NTSTATUS KeyNode::Close()
  165. {
  166. if ( hKey )
  167. {
  168. status = NtClose( hKey );
  169. hKey = 0;
  170. }
  171. return status;
  172. }
  173. NTSTATUS KeyNode::Create( UNICODE_STRING *uClass)
  174. {
  175. ULONG ultmp;
  176. status = NtCreateKey(&hKey,
  177. accessMask,
  178. &ObjAttr,
  179. 0,
  180. uClass,
  181. REG_OPTION_NON_VOLATILE,
  182. &ultmp);
  183. // Debug(DBG_CREATE);
  184. return status;
  185. }
  186. // Recursively create the reg path given by the uniName member variable
  187. // Upon completion, open the reg key for access.
  188. NTSTATUS KeyNode::CreateEx( UNICODE_STRING *uClass)
  189. {
  190. ULONG wsize = uniName.Length/sizeof(WCHAR);
  191. PWCHAR pTmpFullPath = new WCHAR[ uniName.Length + sizeof( WCHAR ) ];
  192. if(!pTmpFullPath)
  193. {
  194. status = STATUS_NO_MEMORY;
  195. return status;
  196. }
  197. wcsncpy(pTmpFullPath, uniName.Buffer , wsize);
  198. pTmpFullPath[ wsize ] = L'\0';
  199. PWCHAR p;
  200. WCHAR sep[]= {L"\\"};
  201. p = wcstok( pTmpFullPath, sep);
  202. // we know how many keys to create now.
  203. // start over again
  204. wcsncpy(pTmpFullPath, uniName.Buffer , wsize );
  205. pTmpFullPath[ wsize ] = L'\0';
  206. KeyNode *pKN1=NULL, *pKN2=NULL;
  207. p = wcstok( pTmpFullPath, sep);
  208. // the first item is "Registry", make it "\Registry" since we are opening
  209. // from the root.
  210. PWCHAR pTmpName = new WCHAR[ wcslen(p) + sizeof( WCHAR ) ];
  211. if(!pTmpName)
  212. {
  213. DELETE_AND_NULL(pTmpFullPath);
  214. status = STATUS_NO_MEMORY;
  215. return status;
  216. }
  217. wcscpy(pTmpName, L"\\");
  218. wcscat( pTmpName , p );
  219. NTSTATUS st = STATUS_SUCCESS;
  220. while( p != NULL )
  221. {
  222. // @@@
  223. // ADD error handling, else you will create keys in the wrong places instead of bailing out.
  224. // @@@
  225. if ( pKN2 )
  226. {
  227. // ---- STEP 3 ---
  228. // NOT-first time around
  229. p = wcstok( NULL, sep);
  230. if ( p ) // we have more sub keys
  231. {
  232. pKN1 = new KeyNode( pKN2->Key(), accessMask, p );
  233. if (pKN1)
  234. {
  235. st = pKN1->Open();
  236. // if Open fails, then key does not exist, so create it
  237. if ( !NT_SUCCESS( st ))
  238. {
  239. st = pKN1->Create();
  240. }
  241. }
  242. else
  243. {
  244. status = STATUS_NO_MEMORY;
  245. break;
  246. }
  247. }
  248. }
  249. else
  250. {
  251. // ---- STEP 1 ---
  252. // First time around, we are opening \Registry node, use
  253. // pTmpName instead of "p"
  254. pKN1 = new KeyNode( NULL, accessMask , pTmpName );
  255. if (pKN1)
  256. {
  257. st = pKN1->Open();
  258. }
  259. else
  260. {
  261. status = STATUS_NO_MEMORY ;
  262. break;
  263. }
  264. }
  265. p = wcstok( NULL, sep);
  266. if (p) // we have more sub keys
  267. {
  268. // ---- STEP 2 ---
  269. pKN2 = new KeyNode( pKN1->Key(), accessMask, p );
  270. if (pKN2 )
  271. {
  272. st = pKN2->Open();
  273. if ( !NT_SUCCESS( pKN2->Status() ))
  274. {
  275. st = pKN2->Create();
  276. }
  277. }
  278. else
  279. {
  280. status = STATUS_NO_MEMORY;
  281. DELETE_AND_NULL (pKN1);
  282. break;
  283. }
  284. DELETE_AND_NULL (pKN1);
  285. pKN1 = pKN2;
  286. }
  287. }
  288. DELETE_AND_NULL( pKN2 );
  289. // since the last node was created above, now we can open ourselfs incase
  290. // caller wants to use us.
  291. if ( NT_SUCCESS(status) )
  292. {
  293. Open();
  294. }
  295. DELETE_AND_NULL(pTmpName);
  296. DELETE_AND_NULL(pTmpFullPath);
  297. return status;
  298. }
  299. NTSTATUS KeyNode::Delete()
  300. {
  301. if (hKey)
  302. {
  303. status = NtDeleteKey( hKey );
  304. // Debug(DBG_DELETE);
  305. }
  306. return status;
  307. }
  308. NTSTATUS KeyNode::DeleteSubKeys()
  309. {
  310. if (hKey && NT_SUCCESS( status ))
  311. {
  312. KeyBasicInfo basicInfo;
  313. status = basicInfo.Status();
  314. if (NT_SUCCESS( status ))
  315. {
  316. status = EnumerateAndDeleteSubKeys( this, &basicInfo );
  317. }
  318. }
  319. return status;
  320. }
  321. NTSTATUS KeyNode::EnumerateAndDeleteSubKeys(
  322. IN KeyNode *pSource,
  323. IN KeyBasicInfo *pBasicInfo )
  324. {
  325. NTSTATUS st = STATUS_SUCCESS;
  326. ULONG ulCount=0;
  327. ULONG ultemp;
  328. while (NT_SUCCESS(st) && st != STATUS_NO_MORE_ENTRIES )
  329. {
  330. ULONG ultemp;
  331. NTSTATUS st2;
  332. st = NtEnumerateKey( pSource->Key(),
  333. ulCount,
  334. pBasicInfo->Type(),
  335. pBasicInfo->Ptr(),
  336. pBasicInfo->Size(),
  337. &ultemp);
  338. if (NT_SUCCESS(st) && st != STATUS_NO_MORE_ENTRIES )
  339. {
  340. pBasicInfo->Ptr()->Name[ pBasicInfo->Ptr()->NameLength/sizeof(WCHAR) ] = L'\0';
  341. KeyNode SourcesubKey(pSource, pBasicInfo);
  342. if (NT_SUCCESS( SourcesubKey.Open() ) )
  343. {
  344. // enumerate sub key down.
  345. st2 = EnumerateAndDeleteSubKeys(
  346. &SourcesubKey,
  347. pBasicInfo );
  348. }
  349. st = SourcesubKey.Delete();
  350. }
  351. }
  352. return st;
  353. }
  354. #if 0
  355. NTSTATUS KeyNode::Query( KEY_NODE_INFORMATION **result , ULONG *resultSize)
  356. {
  357. if ( hKey )
  358. {
  359. // first time around we allocate memory and keep using it
  360. // as our scratch pad
  361. if (!node )
  362. {
  363. node = new KeyNodeInfo();
  364. }
  365. status = NtQueryKey(hKey,
  366. node->Type(), // Keynode,
  367. node->Ptr(),
  368. node->Size(),
  369. resultSize);
  370. *result = node->Ptr();
  371. }
  372. else
  373. status = STATUS_OBJECT_NAME_NOT_FOUND; // need to call open or key is not found
  374. return status;
  375. }
  376. #endif
  377. NTSTATUS KeyNode::Query( KEY_FULL_INFORMATION **result , ULONG *pResultSize)
  378. {
  379. if ( hKey )
  380. {
  381. // first time around we allocate memory and keep using it
  382. // as our scratch pad
  383. if (!full )
  384. {
  385. full = new KeyFullInfo();
  386. }
  387. if (full)
  388. {
  389. status = NtQueryKey(hKey,
  390. full->Type(), // KeyFullInformation,
  391. full->Ptr(),
  392. full->Size(),
  393. pResultSize);
  394. *result = full->Ptr();
  395. }
  396. else
  397. status = STATUS_NO_MEMORY ;
  398. }
  399. else
  400. status = STATUS_OBJECT_NAME_NOT_FOUND; // need to call open or key is not found
  401. return status;
  402. }
  403. NTSTATUS KeyNode::GetPath( PWCHAR *pwch )
  404. {
  405. ULONG ultemp;
  406. ULONG ulWcharLength; //Keep track of the WCHAR string length
  407. status = STATUS_SUCCESS;
  408. // A key handle or root directory was specified, so get its path
  409. if (hKey)
  410. {
  411. ultemp = sizeof(UNICODE_STRING) + sizeof(WCHAR)*MAX_PATH*2;
  412. pFullPath = RtlAllocateHeap(RtlProcessHeap(),
  413. 0,
  414. ultemp);
  415. // Got the buffer OK, query the path
  416. if (pFullPath)
  417. {
  418. // Get the path for key or root directory
  419. status = NtQueryObject(hKey ,
  420. ObjectNameInformation,
  421. (PVOID)pFullPath,
  422. ultemp,
  423. NULL);
  424. if (!NT_SUCCESS(status))
  425. {
  426. RtlFreeHeap(RtlProcessHeap(), 0, pFullPath);
  427. return(status);
  428. }
  429. }
  430. else
  431. {
  432. return(STATUS_NO_MEMORY);
  433. }
  434. // Build the full path to the key to be created
  435. *pwch = ((PUNICODE_STRING)pFullPath)->Buffer;
  436. // Make sure the string is zero terminated
  437. ulWcharLength = ((PUNICODE_STRING)pFullPath)->Length / sizeof(WCHAR);
  438. (*pwch)[ulWcharLength] = L'\0';
  439. }
  440. else
  441. status = STATUS_OBJECT_NAME_NOT_FOUND; // need to call open or key is not found
  442. return(status);
  443. }
  444. void KeyNode::Debug( DebugType type )
  445. {
  446. if ( debug )
  447. {
  448. ULONG i;
  449. switch( type )
  450. {
  451. case DBG_DELETE :
  452. fwprintf( g_debugFilePointer ,
  453. L"Deleted key=%lx; status=%lx, name=", status, hKey );
  454. DbgPrint("Deleted key=%lx; status=%lx, name=", status, hKey );
  455. break;
  456. case DBG_OPEN_FAILED:
  457. fwprintf( g_debugFilePointer,
  458. L"Unable to Open, status=%lx, name=", hKey, status );
  459. DbgPrint("Unable to Open, status=%lx, name=", hKey, status );
  460. break;
  461. case DBG_KEY_NAME:
  462. fwprintf( g_debugFilePointer,
  463. L"hKey=%lx, name=", hKey);
  464. DbgPrint("hKey=%lx, name=", hKey);
  465. break;
  466. case DBG_CREATE:
  467. fwprintf( g_debugFilePointer,
  468. L"Created hKey=%lx, status=%lx,name=", hKey, status);
  469. DbgPrint("Created hKey=%lx, status=%lx,name=", hKey, status );
  470. break;
  471. }
  472. fwprintf( g_debugFilePointer, L"%s\n",NameSz() );
  473. fflush( g_debugFilePointer );
  474. DbgPrint("%s\n",(char *)NameSz() );
  475. }
  476. }
  477. PCWSTR KeyNode::NameSz()
  478. {
  479. if (!pNameSz)
  480. {
  481. pNameSz = new WCHAR [ uniName.Length / sizeof(WCHAR) + 1 ];
  482. if (pNameSz)
  483. {
  484. for ( ULONG i=0; i < uniName.Length / sizeof(WCHAR) ; i++)
  485. {
  486. pNameSz[i] = ( (USHORT)uniName.Buffer[i] );
  487. }
  488. pNameSz[i]=L'\0';
  489. }
  490. else
  491. {
  492. status = STATUS_NO_MEMORY;
  493. }
  494. }
  495. return pNameSz;
  496. }
  497. NTSTATUS KeyNode::GetFullInfo( KeyFullInfo **p)
  498. {
  499. // do a self query
  500. if ( !full )
  501. {
  502. ULONG size;
  503. KEY_FULL_INFORMATION *tmp;
  504. Query( &tmp , &size );
  505. }
  506. *p = full;
  507. return status;
  508. }