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.

621 lines
18 KiB

  1. //
  2. // REGKEY.C
  3. //
  4. // Copyright (C) Microsoft Corporation, 1995-1996
  5. //
  6. // Implementation of RegCreateKey, RegOpenKey, RegCloseKey, and supporting
  7. // functions.
  8. //
  9. #include "pch.h"
  10. //
  11. // RgIsBadSubKey
  12. //
  13. // Returns TRUE if lpSubKey is a invalid subkey string. An invalid subkey
  14. // string may be an invalid pointer or contain double-backslashes or elements
  15. // greater than MAXIMUM_SUB_KEY_LENGTH.
  16. //
  17. BOOL
  18. INTERNAL
  19. RgIsBadSubKey(
  20. LPCSTR lpSubKey
  21. )
  22. {
  23. LPCSTR lpString;
  24. UINT SubSubKeyLength;
  25. BYTE Char;
  26. if (IsNullPtr(lpSubKey))
  27. return FALSE;
  28. if (!IsBadStringPtr(lpSubKey, (UINT) -1)) {
  29. lpString = lpSubKey;
  30. SubSubKeyLength = 0;
  31. while (TRUE) {
  32. Char = *((LPBYTE) lpString);
  33. if (Char == '\0')
  34. return FALSE;
  35. else if (Char == '\\') {
  36. // Catch double-backslashes and leading backslashes. One
  37. // leading backslash is acceptable...
  38. if (SubSubKeyLength == 0 && lpString != lpSubKey)
  39. break;
  40. SubSubKeyLength = 0;
  41. }
  42. else {
  43. if (IsDBCSLeadByte(Char)) {
  44. SubSubKeyLength++;
  45. // Catch an unpaired DBCS pair...
  46. if (*lpString++ == '\0')
  47. break;
  48. }
  49. // Win95 compatibility: don't accept strings with control
  50. // characters.
  51. else if (Char < ' ')
  52. break;
  53. if (++SubSubKeyLength >= MAXIMUM_SUB_KEY_LENGTH)
  54. break;
  55. }
  56. lpString++;
  57. }
  58. }
  59. return TRUE;
  60. }
  61. //
  62. // RgGetNextSubSubKey
  63. //
  64. // Extracts the next subkey component tokenized by backslashes. Works like
  65. // strtok where on the first call, lpSubKey points to the start of the subkey.
  66. // On subsequent calls, lpSubKey is NULL and the last offset is used to find
  67. // the next component.
  68. //
  69. // Returns the length of the SubSubKey string.
  70. //
  71. UINT
  72. INTERNAL
  73. RgGetNextSubSubKey(
  74. LPCSTR lpSubKey,
  75. LPCSTR FAR* lplpSubSubKey,
  76. UINT FAR* lpSubSubKeyLength
  77. )
  78. {
  79. static LPCSTR lpLastSubSubKey = NULL;
  80. LPCSTR lpString;
  81. UINT SubSubKeyLength;
  82. if (!IsNullPtr(lpSubKey))
  83. lpLastSubSubKey = lpSubKey;
  84. lpString = lpLastSubSubKey;
  85. if (*lpString == '\0') {
  86. *lplpSubSubKey = NULL;
  87. *lpSubSubKeyLength = 0;
  88. return 0;
  89. }
  90. if (*lpString == '\\')
  91. lpString++;
  92. *lplpSubSubKey = lpString;
  93. while (*lpString != '\0') {
  94. if (*lpString == '\\')
  95. break;
  96. // The subkey has already been validated, so we know there's a matching
  97. // trail byte.
  98. if (IsDBCSLeadByte(*lpString))
  99. lpString++; // Trail byte skipped immediately below
  100. lpString++;
  101. }
  102. lpLastSubSubKey = lpString;
  103. SubSubKeyLength = lpString - *lplpSubSubKey;
  104. *lpSubSubKeyLength = SubSubKeyLength;
  105. return SubSubKeyLength;
  106. }
  107. //
  108. // RgLookupKey
  109. //
  110. int
  111. INTERNAL
  112. RgLookupKey(
  113. HKEY hKey,
  114. LPCSTR lpSubKey,
  115. LPHKEY lphSubKey,
  116. UINT Flags
  117. )
  118. {
  119. int ErrorCode;
  120. LPCSTR lpSubSubKey;
  121. UINT SubSubKeyLength;
  122. BOOL fCreatedKeynode;
  123. LPFILE_INFO lpFileInfo;
  124. DWORD KeynodeIndex;
  125. #ifdef WANT_HIVE_SUPPORT
  126. LPHIVE_INFO lpHiveInfo;
  127. #endif
  128. BOOL fPrevIsNextIndex;
  129. DWORD SubSubKeyHash;
  130. LPKEYNODE lpKeynode;
  131. LPKEY_RECORD lpKeyRecord;
  132. BOOL fFound;
  133. DWORD PrevKeynodeIndex;
  134. #ifdef WANT_NOTIFY_CHANGE_SUPPORT
  135. DWORD NotifyKeynodeIndex;
  136. #endif
  137. LPKEYNODE lpNewKeynode;
  138. HKEY hSubKey;
  139. #ifdef REALMODE
  140. BOOL secondTry;
  141. #endif
  142. fCreatedKeynode = FALSE;
  143. //
  144. // Check if the caller is trying to open a key with a NULL or zero-length
  145. // sub key string. If so, simply return hKey.
  146. // This also ignores "\"
  147. //
  148. if (IsNullPtr(lpSubKey) || RgGetNextSubSubKey(lpSubKey, &lpSubSubKey,
  149. &SubSubKeyLength) == 0) {
  150. hSubKey = hKey;
  151. goto HaveSubKeyHandle;
  152. }
  153. //
  154. // The next two lines fix the problem with Publisher 97. It tries to open
  155. // HKEY_LOCAL_MACHINE, \KEY_NAME. This was being allowed to succeed by
  156. // this API. That is because, RlGetNextSubSubKey blasts off the starting
  157. // '\' and then this api is equivalent to HKEY_LOCAL_MACHINE, KEY_NAME.
  158. // This is a no-no since Publisher 97 proceeds to blast off the whole
  159. // registry if we let this call succeed.
  160. //
  161. if (!(Flags & LK_CREATE)) {
  162. SubSubKeyLength += (DWORD)lpSubSubKey - (DWORD)lpSubKey;
  163. lpSubSubKey = lpSubKey;
  164. }
  165. lpFileInfo = hKey-> lpFileInfo;
  166. KeynodeIndex = hKey-> ChildKeynodeIndex;
  167. PrevKeynodeIndex = hKey-> KeynodeIndex;
  168. #ifdef WANT_HIVE_SUPPORT
  169. //
  170. // If this key can have hives attached to it, check there for the first
  171. // part of the subkey. If we have a match, then switch into that
  172. // FILE_INFO.
  173. //
  174. if (hKey-> Flags & KEYF_HIVESALLOWED) {
  175. lpHiveInfo = lpFileInfo-> lpHiveInfoList;
  176. while (!IsNullPtr(lpHiveInfo)) {
  177. if (SubSubKeyLength == lpHiveInfo-> NameLength &&
  178. RgStrCmpNI(lpSubSubKey, lpHiveInfo-> Name,
  179. SubSubKeyLength) == 0) {
  180. lpFileInfo = lpHiveInfo-> lpFileInfo;
  181. KeynodeIndex = lpFileInfo-> KeynodeHeader.RootIndex;
  182. if ((ErrorCode = RgLockInUseKeynode(lpFileInfo, KeynodeIndex,
  183. &lpKeynode)) != ERROR_SUCCESS)
  184. return ErrorCode;
  185. if (!RgGetNextSubSubKey(NULL, &lpSubSubKey, &SubSubKeyLength))
  186. goto LookupComplete;
  187. PrevKeynodeIndex = KeynodeIndex;
  188. KeynodeIndex = lpKeynode-> ChildIndex;
  189. RgUnlockKeynode(lpFileInfo, PrevKeynodeIndex, FALSE);
  190. break;
  191. }
  192. lpHiveInfo = lpHiveInfo-> lpNextHiveInfo;
  193. }
  194. }
  195. #endif
  196. //
  197. // Walk as deep as we can into the registry tree using existing key
  198. // records. For each subkey component, move to the child of the current
  199. // tree position and walk each sibling looking for a match. Repeat until
  200. // we're out of subkey components or we hit the end of a branch.
  201. //
  202. fPrevIsNextIndex = FALSE;
  203. for (;;) {
  204. SubSubKeyHash = RgHashString(lpSubSubKey, SubSubKeyLength);
  205. while (!IsNullKeynodeIndex(KeynodeIndex)) {
  206. #ifdef REALMODE
  207. secondTry = FALSE;
  208. tryAgain:
  209. #endif // REALMODE
  210. if ((ErrorCode = RgLockInUseKeynode(lpFileInfo, KeynodeIndex,
  211. &lpKeynode)) != ERROR_SUCCESS)
  212. return ErrorCode;
  213. if (lpKeynode-> Hash == SubSubKeyHash) {
  214. if ((ErrorCode = RgLockKeyRecord(lpFileInfo, lpKeynode->
  215. BlockIndex, (BYTE) lpKeynode-> KeyRecordIndex,
  216. &lpKeyRecord)) != ERROR_SUCCESS) {
  217. RgUnlockKeynode(lpFileInfo, KeynodeIndex, FALSE);
  218. #ifdef REALMODE
  219. if (!secondTry)
  220. {
  221. // What happens in real mode, is that we get wedged with the
  222. // Keynode block allocated and locked in the middle of the free
  223. // space, and there is not a free block large enough for the data block.
  224. // So, by unlocking and freeing the Keynode block and then restarting
  225. // the operation, the Keynode block gets allocated at the bottom of the
  226. // heap, leaving room for the data block.
  227. secondTry = TRUE;
  228. RgEnumFileInfos(RgSweepFileInfo);
  229. RgEnumFileInfos(RgSweepFileInfo);
  230. goto tryAgain;
  231. }
  232. #endif // REALMODE
  233. return ErrorCode;
  234. }
  235. fFound = (!(Flags & LK_BIGKEYEXT) == !(lpKeynode-> Flags & KNF_BIGKEYEXT) &&
  236. SubSubKeyLength == lpKeyRecord-> NameLength &&
  237. RgStrCmpNI(lpSubSubKey, lpKeyRecord-> Name,
  238. SubSubKeyLength) == 0);
  239. RgUnlockDatablock(lpFileInfo, lpKeynode-> BlockIndex, FALSE);
  240. if (fFound)
  241. break;
  242. }
  243. // Unlock the current keynode and advance to its sibling. Set
  244. // fPrevIsNextIndex so that if we have to create, we know that
  245. // we'll be inserting the new keynode as a sibling.
  246. fPrevIsNextIndex = TRUE;
  247. PrevKeynodeIndex = KeynodeIndex;
  248. KeynodeIndex = lpKeynode-> NextIndex;
  249. RgUnlockKeynode(lpFileInfo, PrevKeynodeIndex, FALSE);
  250. }
  251. // Break out if we looped over all the siblings of the previous keynode
  252. // or if the previous keynode didn't have any children. If we're in
  253. // create mode, then fPrevIsNextIndex and PrevKeynodeIndex will
  254. // represent where we need to start inserting.
  255. if (IsNullKeynodeIndex(KeynodeIndex))
  256. break;
  257. // Break out there are no more subkey components to lookup.
  258. // KeynodeIndex represents the index of the matching key. It's
  259. // corresponding keynode is locked.
  260. if (!RgGetNextSubSubKey(NULL, &lpSubSubKey, &SubSubKeyLength))
  261. break;
  262. // Unlock the current keynode and advance to its child. Clear
  263. // fPrevIsNextIndex so that if we have to create, we know that we'll
  264. // be inserting the new keynode as a child.
  265. fPrevIsNextIndex = FALSE;
  266. PrevKeynodeIndex = KeynodeIndex;
  267. KeynodeIndex = lpKeynode-> ChildIndex;
  268. RgUnlockKeynode(lpFileInfo, PrevKeynodeIndex, FALSE);
  269. }
  270. if (IsNullKeynodeIndex(KeynodeIndex)) {
  271. if (!(Flags & LK_CREATE))
  272. return ERROR_CANTOPEN16_FILENOTFOUND32;
  273. if ((IsDynDataKey(hKey) && !(Flags & LK_CREATEDYNDATA)) || (lpFileInfo->
  274. Flags & FI_READONLY))
  275. return ERROR_ACCESS_DENIED;
  276. if ((ErrorCode = RgLockInUseKeynode(lpFileInfo, PrevKeynodeIndex,
  277. &lpKeynode)) != ERROR_SUCCESS) {
  278. TRACE(("RgLookupKey: failed to lock keynode we just had?\n"));
  279. return ErrorCode;
  280. }
  281. #ifdef WANT_NOTIFY_CHANGE_SUPPORT
  282. // Which keynode index we'll notify of the subkeys we're creating
  283. // depends on the state of fPrevIsNextIndex.
  284. NotifyKeynodeIndex = fPrevIsNextIndex ? lpKeynode-> ParentIndex :
  285. PrevKeynodeIndex;
  286. #endif
  287. // See if there's an open handle on the parent so that we can patch up
  288. // its child keynode index member. We only need this on the first
  289. // pass.
  290. hSubKey = RgFindOpenKeyHandle(lpFileInfo, PrevKeynodeIndex);
  291. do {
  292. if ((ErrorCode = RgAllocKeynode(lpFileInfo, &KeynodeIndex,
  293. &lpNewKeynode)) != ERROR_SUCCESS)
  294. goto CreateAllocFailed1;
  295. if ((ErrorCode = RgAllocKeyRecord(lpFileInfo, sizeof(KEY_RECORD) +
  296. SubSubKeyLength - 1, &lpKeyRecord)) != ERROR_SUCCESS) {
  297. RgUnlockKeynode(lpFileInfo, KeynodeIndex, FALSE);
  298. RgFreeKeynode(lpFileInfo, KeynodeIndex);
  299. CreateAllocFailed1:
  300. RgUnlockKeynode(lpFileInfo, PrevKeynodeIndex, fCreatedKeynode);
  301. DEBUG_OUT(("RgLookupKey: allocation failed\n"));
  302. goto SignalAndReturnErrorCode;
  303. }
  304. // Fixup the previous keynode's next offset.
  305. if (fPrevIsNextIndex) {
  306. fPrevIsNextIndex = FALSE;
  307. hSubKey = NULL;
  308. lpNewKeynode-> ParentIndex = lpKeynode-> ParentIndex;
  309. lpKeynode-> NextIndex = KeynodeIndex;
  310. }
  311. // Fixup the previous keynode's child offset.
  312. else {
  313. lpNewKeynode-> ParentIndex = PrevKeynodeIndex;
  314. lpKeynode-> ChildIndex = KeynodeIndex;
  315. // If hSubKey is not NULL, then we may have to patch up the
  316. // child offset cache to point to the newly created keynode.
  317. if (!IsNullPtr(hSubKey)) {
  318. if (IsNullKeynodeIndex(hSubKey-> ChildKeynodeIndex))
  319. hSubKey-> ChildKeynodeIndex = KeynodeIndex;
  320. hSubKey = NULL;
  321. }
  322. }
  323. // Fill in the keynode.
  324. lpNewKeynode-> NextIndex = REG_NULL;
  325. lpNewKeynode-> ChildIndex = REG_NULL;
  326. lpNewKeynode-> BlockIndex = lpKeyRecord-> BlockIndex;
  327. lpNewKeynode-> KeyRecordIndex = lpKeyRecord-> KeyRecordIndex;
  328. lpNewKeynode-> Hash = (WORD) RgHashString(lpSubSubKey,
  329. SubSubKeyLength);
  330. // Fill in the key record.
  331. lpKeyRecord-> RecordSize = sizeof(KEY_RECORD) + SubSubKeyLength - 1;
  332. lpKeyRecord-> NameLength = (WORD) SubSubKeyLength;
  333. MoveMemory(lpKeyRecord-> Name, lpSubSubKey, SubSubKeyLength);
  334. lpKeyRecord-> ValueCount = 0;
  335. lpKeyRecord-> ClassLength = 0;
  336. lpKeyRecord-> Reserved = 0;
  337. // Unlock the keynode that points to the new keynode and advance
  338. // to the next keynode.
  339. RgUnlockKeynode(lpFileInfo, PrevKeynodeIndex, TRUE);
  340. PrevKeynodeIndex = KeynodeIndex;
  341. lpKeynode = lpNewKeynode;
  342. RgUnlockDatablock(lpFileInfo, lpKeyRecord-> BlockIndex, TRUE);
  343. fCreatedKeynode = TRUE;
  344. // Following should already be zeroed for subsequent iterations.
  345. ASSERT(!fPrevIsNextIndex);
  346. ASSERT(IsNullPtr(hSubKey));
  347. } while (RgGetNextSubSubKey(NULL, &lpSubSubKey, &SubSubKeyLength));
  348. }
  349. ASSERT(!IsNullKeynodeIndex(KeynodeIndex));
  350. //
  351. // Now we've got the keynode for the request subkey. Check if it has been
  352. // previously opened. If not, then allocate a new key handle for it and
  353. // initialize it.
  354. //
  355. #ifdef WANT_HIVE_SUPPORT
  356. LookupComplete:
  357. #endif
  358. if (IsNullPtr(hSubKey = RgFindOpenKeyHandle(lpFileInfo, KeynodeIndex))) {
  359. if (IsNullPtr(hSubKey = RgCreateKeyHandle()))
  360. ErrorCode = ERROR_OUTOFMEMORY;
  361. else {
  362. hSubKey-> lpFileInfo = lpFileInfo;
  363. hSubKey-> KeynodeIndex = KeynodeIndex;
  364. hSubKey-> ChildKeynodeIndex = lpKeynode-> ChildIndex;
  365. hSubKey-> BlockIndex = (WORD) lpKeynode-> BlockIndex;
  366. hSubKey-> KeyRecordIndex = (BYTE) lpKeynode-> KeyRecordIndex;
  367. hSubKey-> PredefinedKeyIndex = hKey-> PredefinedKeyIndex;
  368. if (lpKeynode-> Flags & KNF_BIGKEYROOT)
  369. hSubKey-> Flags |= KEYF_BIGKEYROOT;
  370. }
  371. }
  372. RgUnlockKeynode(lpFileInfo, KeynodeIndex, fCreatedKeynode);
  373. //
  374. // Now we've got a key handle that references the requested subkey.
  375. // Increment the reference count on the handle and return it to the caller.
  376. // Note that this differs from NT semantic where they return a unique
  377. // handle for every open.
  378. //
  379. if (!IsNullPtr(hSubKey)) {
  380. HaveSubKeyHandle:
  381. RgIncrementKeyReferenceCount(hSubKey);
  382. *lphSubKey = hSubKey;
  383. ErrorCode = ERROR_SUCCESS;
  384. }
  385. SignalAndReturnErrorCode:
  386. // If we managed to create any keynodes, regardless of what ErrorCode is
  387. // set to now, then we must signal any waiting events.
  388. if (fCreatedKeynode) {
  389. RgSignalWaitingNotifies(lpFileInfo, NotifyKeynodeIndex,
  390. REG_NOTIFY_CHANGE_NAME);
  391. }
  392. return ErrorCode;
  393. }
  394. //
  395. // RgCreateOrOpenKey
  396. //
  397. // Common routine for VMMRegCreateKey and VMMRegOpenKey. Valids parameters,
  398. // locks the registry, and calls the real worker routine.
  399. //
  400. int
  401. INTERNAL
  402. RgCreateOrOpenKey(
  403. HKEY hKey,
  404. LPCSTR lpSubKey,
  405. LPHKEY lphKey,
  406. UINT Flags
  407. )
  408. {
  409. int ErrorCode;
  410. if (RgIsBadSubKey(lpSubKey))
  411. return ERROR_BADKEY;
  412. if (IsBadHugeWritePtr(lphKey, sizeof(HKEY)))
  413. return ERROR_INVALID_PARAMETER;
  414. if (!RgLockRegistry())
  415. return ERROR_LOCK_FAILED;
  416. if ((ErrorCode = RgValidateAndConvertKeyHandle(&hKey)) == ERROR_SUCCESS)
  417. ErrorCode = RgLookupKey(hKey, lpSubKey, lphKey, Flags);
  418. RgUnlockRegistry();
  419. return ErrorCode;
  420. }
  421. //
  422. // VMMRegCreateKey
  423. //
  424. // See Win32 documentation of RegCreateKey.
  425. //
  426. LONG
  427. REGAPI
  428. VMMRegCreateKey(
  429. HKEY hKey,
  430. LPCSTR lpSubKey,
  431. LPHKEY lphKey
  432. )
  433. {
  434. return RgCreateOrOpenKey(hKey, lpSubKey, lphKey, LK_CREATE);
  435. }
  436. //
  437. // VMMRegOpenKey
  438. //
  439. // See Win32 documentation of RegOpenKey.
  440. //
  441. LONG
  442. REGAPI
  443. VMMRegOpenKey(
  444. HKEY hKey,
  445. LPCSTR lpSubKey,
  446. LPHKEY lphKey
  447. )
  448. {
  449. return RgCreateOrOpenKey(hKey, lpSubKey, lphKey, LK_OPEN);
  450. }
  451. //
  452. // VMMRegCloseKey
  453. //
  454. // See Win32 documentation of RegCloseKey.
  455. //
  456. LONG
  457. REGAPI
  458. VMMRegCloseKey(
  459. HKEY hKey
  460. )
  461. {
  462. int ErrorCode;
  463. if (!RgLockRegistry())
  464. return ERROR_LOCK_FAILED;
  465. ErrorCode = RgValidateAndConvertKeyHandle(&hKey);
  466. if (ErrorCode == ERROR_SUCCESS || ErrorCode == ERROR_KEY_DELETED) {
  467. RgDestroyKeyHandle(hKey);
  468. ErrorCode = ERROR_SUCCESS;
  469. }
  470. RgUnlockRegistry();
  471. return ErrorCode;
  472. }