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.

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