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.

579 lines
16 KiB

  1. //
  2. // REGKEY.C
  3. //
  4. // Copyright (C) Microsoft Corporation, 1995
  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. fCreatedKeynode = FALSE;
  140. //
  141. // Check if the caller is trying to open a key with a NULL or zero-length
  142. // sub key string. If so, simply return hKey.
  143. //
  144. if (IsNullPtr(lpSubKey) || RgGetNextSubSubKey(lpSubKey, &lpSubSubKey,
  145. &SubSubKeyLength) == 0) {
  146. hSubKey = hKey;
  147. goto HaveSubKeyHandle;
  148. }
  149. lpFileInfo = hKey-> lpFileInfo;
  150. KeynodeIndex = hKey-> ChildKeynodeIndex;
  151. PrevKeynodeIndex = hKey-> KeynodeIndex;
  152. #ifdef WANT_HIVE_SUPPORT
  153. //
  154. // If this key can have hives attached to it, check there for the first
  155. // part of the subkey. If we have a match, then switch into that
  156. // FILE_INFO.
  157. //
  158. if (hKey-> Flags & KEYF_HIVESALLOWED) {
  159. lpHiveInfo = lpFileInfo-> lpHiveInfoList;
  160. while (!IsNullPtr(lpHiveInfo)) {
  161. if (SubSubKeyLength == lpHiveInfo-> NameLength &&
  162. RgStrCmpNI(lpSubSubKey, lpHiveInfo-> Name,
  163. SubSubKeyLength) == 0) {
  164. lpFileInfo = lpHiveInfo-> lpFileInfo;
  165. KeynodeIndex = lpFileInfo-> KeynodeHeader.RootIndex;
  166. if ((ErrorCode = RgLockInUseKeynode(lpFileInfo, KeynodeIndex,
  167. &lpKeynode)) != ERROR_SUCCESS)
  168. return ErrorCode;
  169. if (!RgGetNextSubSubKey(NULL, &lpSubSubKey, &SubSubKeyLength))
  170. goto LookupComplete;
  171. PrevKeynodeIndex = KeynodeIndex;
  172. KeynodeIndex = lpKeynode-> ChildIndex;
  173. RgUnlockKeynode(lpFileInfo, PrevKeynodeIndex, FALSE);
  174. break;
  175. }
  176. lpHiveInfo = lpHiveInfo-> lpNextHiveInfo;
  177. }
  178. }
  179. #endif
  180. //
  181. // Walk as deep as we can into the registry tree using existing key
  182. // records. For each subkey component, move to the child of the current
  183. // tree position and walk each sibling looking for a match. Repeat until
  184. // we're out of subkey components or we hit the end of a branch.
  185. //
  186. fPrevIsNextIndex = FALSE;
  187. for (;;) {
  188. SubSubKeyHash = RgHashString(lpSubSubKey, SubSubKeyLength);
  189. while (!IsNullKeynodeIndex(KeynodeIndex)) {
  190. if ((ErrorCode = RgLockInUseKeynode(lpFileInfo, KeynodeIndex,
  191. &lpKeynode)) != ERROR_SUCCESS)
  192. return ErrorCode;
  193. if (lpKeynode-> Hash == SubSubKeyHash) {
  194. if ((ErrorCode = RgLockKeyRecord(lpFileInfo, lpKeynode->
  195. BlockIndex, (BYTE) lpKeynode-> KeyRecordIndex,
  196. &lpKeyRecord)) != ERROR_SUCCESS) {
  197. RgUnlockKeynode(lpFileInfo, KeynodeIndex, FALSE);
  198. return ErrorCode;
  199. }
  200. fFound = (SubSubKeyLength == lpKeyRecord-> NameLength &&
  201. RgStrCmpNI(lpSubSubKey, lpKeyRecord-> Name,
  202. SubSubKeyLength) == 0);
  203. RgUnlockDatablock(lpFileInfo, lpKeynode-> BlockIndex, FALSE);
  204. if (fFound)
  205. break;
  206. }
  207. // Unlock the current keynode and advance to its sibling. Set
  208. // fPrevIsNextIndex so that if we have to create, we know that
  209. // we'll be inserting the new keynode as a sibling.
  210. fPrevIsNextIndex = TRUE;
  211. PrevKeynodeIndex = KeynodeIndex;
  212. KeynodeIndex = lpKeynode-> NextIndex;
  213. RgUnlockKeynode(lpFileInfo, PrevKeynodeIndex, FALSE);
  214. }
  215. // Break out if we looped over all the siblings of the previous keynode
  216. // or if the previous keynode didn't have any children. If we're in
  217. // create mode, then fPrevIsNextIndex and PrevKeynodeIndex will
  218. // represent where we need to start inserting.
  219. if (IsNullKeynodeIndex(KeynodeIndex))
  220. break;
  221. // Break out there are no more subkey components to lookup.
  222. // KeynodeIndex represents the index of the matching key. It's
  223. // corresponding keynode is locked.
  224. if (!RgGetNextSubSubKey(NULL, &lpSubSubKey, &SubSubKeyLength))
  225. break;
  226. // Unlock the current keynode and advance to its child. Clear
  227. // fPrevIsNextIndex so that if we have to create, we know that we'll
  228. // be inserting the new keynode as a child.
  229. fPrevIsNextIndex = FALSE;
  230. PrevKeynodeIndex = KeynodeIndex;
  231. KeynodeIndex = lpKeynode-> ChildIndex;
  232. RgUnlockKeynode(lpFileInfo, PrevKeynodeIndex, FALSE);
  233. }
  234. if (IsNullKeynodeIndex(KeynodeIndex)) {
  235. if (!(Flags & LK_CREATE))
  236. return ERROR_CANTOPEN16_FILENOTFOUND32;
  237. if (((hKey-> PredefinedKeyIndex == INDEX_DYN_DATA) && !(Flags &
  238. LK_CREATEDYNDATA)) || (lpFileInfo-> Flags & FI_READONLY))
  239. return ERROR_ACCESS_DENIED;
  240. if ((ErrorCode = RgLockInUseKeynode(lpFileInfo, PrevKeynodeIndex,
  241. &lpKeynode)) != ERROR_SUCCESS) {
  242. TRACE(("RgLookupKey: failed to lock keynode we just had?\n"));
  243. return ErrorCode;
  244. }
  245. #ifdef WANT_NOTIFY_CHANGE_SUPPORT
  246. // Which keynode index we'll notify of the subkeys we're creating
  247. // depends on the state of fPrevIsNextIndex.
  248. NotifyKeynodeIndex = fPrevIsNextIndex ? lpKeynode-> ParentIndex :
  249. PrevKeynodeIndex;
  250. #endif
  251. // See if there's an open handle on the parent so that we can patch up
  252. // its child keynode index member. We only need this on the first
  253. // pass.
  254. hSubKey = RgFindOpenKeyHandle(lpFileInfo, PrevKeynodeIndex);
  255. do {
  256. if ((ErrorCode = RgAllocKeynode(lpFileInfo, &KeynodeIndex,
  257. &lpNewKeynode)) != ERROR_SUCCESS)
  258. goto CreateAllocFailed1;
  259. if ((ErrorCode = RgAllocKeyRecord(lpFileInfo, sizeof(KEY_RECORD) +
  260. SubSubKeyLength - 1, &lpKeyRecord)) != ERROR_SUCCESS) {
  261. RgUnlockKeynode(lpFileInfo, KeynodeIndex, FALSE);
  262. RgFreeKeynode(lpFileInfo, KeynodeIndex);
  263. CreateAllocFailed1:
  264. RgUnlockKeynode(lpFileInfo, PrevKeynodeIndex, fCreatedKeynode);
  265. DEBUG_OUT(("RgLookupKey: allocation failed\n"));
  266. goto SignalAndReturnErrorCode;
  267. }
  268. // Fixup the previous keynode's next offset.
  269. if (fPrevIsNextIndex) {
  270. fPrevIsNextIndex = FALSE;
  271. hSubKey = NULL;
  272. lpNewKeynode-> ParentIndex = lpKeynode-> ParentIndex;
  273. lpKeynode-> NextIndex = KeynodeIndex;
  274. }
  275. // Fixup the previous keynode's child offset.
  276. else {
  277. lpNewKeynode-> ParentIndex = PrevKeynodeIndex;
  278. lpKeynode-> ChildIndex = KeynodeIndex;
  279. // If hSubKey is not NULL, then we may have to patch up the
  280. // child offset cache to point to the newly created keynode.
  281. if (!IsNullPtr(hSubKey)) {
  282. if (IsNullKeynodeIndex(hSubKey-> ChildKeynodeIndex))
  283. hSubKey-> ChildKeynodeIndex = KeynodeIndex;
  284. hSubKey = NULL;
  285. }
  286. }
  287. // Fill in the keynode.
  288. lpNewKeynode-> NextIndex = REG_NULL;
  289. lpNewKeynode-> ChildIndex = REG_NULL;
  290. lpNewKeynode-> BlockIndex = lpKeyRecord-> BlockIndex;
  291. lpNewKeynode-> KeyRecordIndex = lpKeyRecord-> KeyRecordIndex;
  292. lpNewKeynode-> Hash = (WORD) RgHashString(lpSubSubKey,
  293. SubSubKeyLength);
  294. // Fill in the key record.
  295. lpKeyRecord-> RecordSize = sizeof(KEY_RECORD) + SubSubKeyLength - 1;
  296. lpKeyRecord-> NameLength = (WORD) SubSubKeyLength;
  297. MoveMemory(lpKeyRecord-> Name, lpSubSubKey, SubSubKeyLength);
  298. lpKeyRecord-> ValueCount = 0;
  299. lpKeyRecord-> ClassLength = 0;
  300. lpKeyRecord-> Reserved = 0;
  301. // Unlock the keynode that points to the new keynode and advance
  302. // to the next keynode.
  303. RgUnlockKeynode(lpFileInfo, PrevKeynodeIndex, TRUE);
  304. PrevKeynodeIndex = KeynodeIndex;
  305. lpKeynode = lpNewKeynode;
  306. RgUnlockDatablock(lpFileInfo, lpKeyRecord-> BlockIndex, TRUE);
  307. fCreatedKeynode = TRUE;
  308. // Following should already be zeroed for subsequent iterations.
  309. ASSERT(!fPrevIsNextIndex);
  310. ASSERT(IsNullPtr(hSubKey));
  311. } while (RgGetNextSubSubKey(NULL, &lpSubSubKey, &SubSubKeyLength));
  312. }
  313. ASSERT(!IsNullKeynodeIndex(KeynodeIndex));
  314. //
  315. // Now we've got the keynode for the request subkey. Check if it has been
  316. // previously opened. If not, then allocate a new key handle for it and
  317. // initialize it.
  318. //
  319. LookupComplete:
  320. if (IsNullPtr(hSubKey = RgFindOpenKeyHandle(lpFileInfo, KeynodeIndex))) {
  321. if (IsNullPtr(hSubKey = RgCreateKeyHandle()))
  322. ErrorCode = ERROR_OUTOFMEMORY;
  323. else {
  324. hSubKey-> lpFileInfo = lpFileInfo;
  325. hSubKey-> KeynodeIndex = KeynodeIndex;
  326. hSubKey-> ChildKeynodeIndex = lpKeynode-> ChildIndex;
  327. hSubKey-> BlockIndex = (WORD) lpKeynode-> BlockIndex;
  328. hSubKey-> KeyRecordIndex = (BYTE) lpKeynode-> KeyRecordIndex;
  329. hSubKey-> PredefinedKeyIndex = hKey-> PredefinedKeyIndex;
  330. }
  331. }
  332. RgUnlockKeynode(lpFileInfo, KeynodeIndex, fCreatedKeynode);
  333. //
  334. // Now we've got a key handle that references the requested subkey.
  335. // Increment the reference count on the handle and return it to the caller.
  336. // Note that this differs from NT semantic where they return a unique
  337. // handle for every open.
  338. //
  339. if (!IsNullPtr(hSubKey)) {
  340. HaveSubKeyHandle:
  341. RgIncrementKeyReferenceCount(hSubKey);
  342. *lphSubKey = hSubKey;
  343. ErrorCode = ERROR_SUCCESS;
  344. }
  345. SignalAndReturnErrorCode:
  346. // If we managed to create any keynodes, regardless of what ErrorCode is
  347. // set to now, then we must signal any waiting events.
  348. if (fCreatedKeynode) {
  349. RgSignalWaitingNotifies(lpFileInfo, NotifyKeynodeIndex,
  350. REG_NOTIFY_CHANGE_NAME);
  351. }
  352. return ErrorCode;
  353. }
  354. //
  355. // RgCreateOrOpenKey
  356. //
  357. // Common routine for VMMRegCreateKey and VMMRegOpenKey. Valids parameters,
  358. // locks the registry, and calls the real worker routine.
  359. //
  360. int
  361. INTERNAL
  362. RgCreateOrOpenKey(
  363. HKEY hKey,
  364. LPCSTR lpSubKey,
  365. LPHKEY lphKey,
  366. UINT Flags
  367. )
  368. {
  369. int ErrorCode;
  370. if (RgIsBadSubKey(lpSubKey))
  371. return ERROR_BADKEY;
  372. if (IsBadHugeWritePtr(lphKey, sizeof(HKEY)))
  373. return ERROR_INVALID_PARAMETER;
  374. if (!RgLockRegistry())
  375. return ERROR_LOCK_FAILED;
  376. if ((ErrorCode = RgValidateAndConvertKeyHandle(&hKey)) == ERROR_SUCCESS)
  377. ErrorCode = RgLookupKey(hKey, lpSubKey, lphKey, Flags);
  378. RgUnlockRegistry();
  379. return ErrorCode;
  380. }
  381. //
  382. // VMMRegCreateKey
  383. //
  384. // See Win32 documentation of RegCreateKey.
  385. //
  386. LONG
  387. REGAPI
  388. VMMRegCreateKey(
  389. HKEY hKey,
  390. LPCSTR lpSubKey,
  391. LPHKEY lphKey
  392. )
  393. {
  394. return RgCreateOrOpenKey(hKey, lpSubKey, lphKey, LK_CREATE);
  395. }
  396. //
  397. // VMMRegOpenKey
  398. //
  399. // See Win32 documentation of RegOpenKey.
  400. //
  401. LONG
  402. REGAPI
  403. VMMRegOpenKey(
  404. HKEY hKey,
  405. LPCSTR lpSubKey,
  406. LPHKEY lphKey
  407. )
  408. {
  409. return RgCreateOrOpenKey(hKey, lpSubKey, lphKey, LK_OPEN);
  410. }
  411. //
  412. // VMMRegCloseKey
  413. //
  414. // See Win32 documentation of RegCloseKey.
  415. //
  416. LONG
  417. REGAPI
  418. VMMRegCloseKey(
  419. HKEY hKey
  420. )
  421. {
  422. int ErrorCode;
  423. if (!RgLockRegistry())
  424. return ERROR_LOCK_FAILED;
  425. ErrorCode = RgValidateAndConvertKeyHandle(&hKey);
  426. if (ErrorCode == ERROR_SUCCESS || ErrorCode == ERROR_KEY_DELETED) {
  427. RgDestroyKeyHandle(hKey);
  428. ErrorCode = ERROR_SUCCESS;
  429. }
  430. RgUnlockRegistry();
  431. return ErrorCode;
  432. }