do not call on NtQuerySecurityObject in RegGetKeySecurity for it will always fail...
[reactos.git] / reactos / lib / advapi32 / reg / reg.c
index 8b8f27f..9f14c5e 100644 (file)
@@ -5,6 +5,7 @@
  * FILE:            lib/advapi32/reg/reg.c
  * PURPOSE:         Registry functions
  * PROGRAMMER:      Ariadne ( ariadne@xs4all.nl)
+ *                  Thomas Weidenmueller <w3seek@reactos.com>
  * UPDATE HISTORY:
  *                  Created 01/11/98
  *                  19990309 EA Stubs
@@ -23,9 +24,6 @@
 #define REG_MAX_NAME_SIZE     256
 #define REG_MAX_DATA_SIZE     2048
 
-/* FIXME: should go into msvcrt.h header? */
-#define offsetof(s,m)       (size_t)&(((s*)NULL)->m)
-
 /* GLOBALS ******************************************************************/
 
 static RTL_CRITICAL_SECTION HandleTableCS;
@@ -37,10 +35,14 @@ static BOOLEAN DefaultHandlesDisabled = FALSE;
 
 static NTSTATUS MapDefaultKey (PHANDLE ParentKey, HKEY Key);
 static VOID CloseDefaultKeys(VOID);
-#define CloseDefaultKey(Handle)                                                \
+#define ClosePredefKey(Handle)                                                 \
     if ((ULONG_PTR)Handle & 0x1) {                                             \
         NtClose(Handle);                                                       \
     }
+#define IsPredefKey(HKey)                                                      \
+    (((ULONG)(HKey) & 0xF0000000) == 0x80000000)
+#define GetPredefKeyIndex(HKey)                                                \
+    ((ULONG)(HKey) & 0x0FFFFFFF)
 
 static NTSTATUS OpenClassesRootKey(PHANDLE KeyHandle);
 static NTSTATUS OpenLocalMachineKey (PHANDLE KeyHandle);
@@ -50,7 +52,7 @@ static NTSTATUS OpenCurrentConfigKey(PHANDLE KeyHandle);
 
 /* FUNCTIONS ****************************************************************/
 /* check if value type needs string conversion (Ansi<->Unicode) */
-inline static int is_string( DWORD type )
+__inline static int is_string( DWORD type )
 {
     return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
 }
@@ -87,6 +89,54 @@ RegCleanup (VOID)
 }
 
 
+static NTSTATUS
+OpenPredefinedKey(IN ULONG Index,
+                  OUT HANDLE Handle)
+{
+    NTSTATUS Status;
+
+    switch (Index)
+    {
+        case 0: /* HKEY_CLASSES_ROOT */
+            Status = OpenClassesRootKey (Handle);
+            break;
+
+        case 1: /* HKEY_CURRENT_USER */
+            Status = RtlOpenCurrentUser (MAXIMUM_ALLOWED,
+                                         Handle);
+            break;
+
+        case 2: /* HKEY_LOCAL_MACHINE */
+            Status = OpenLocalMachineKey (Handle);
+            break;
+
+        case 3: /* HKEY_USERS */
+            Status = OpenUsersKey (Handle);
+            break;
+#if 0
+        case 4: /* HKEY_PERFORMANCE_DATA */
+            Status = OpenPerformanceDataKey (Handle);
+            break;
+#endif
+
+        case 5: /* HKEY_CURRENT_CONFIG */
+            Status = OpenCurrentConfigKey (Handle);
+            break;
+
+        case 6: /* HKEY_DYN_DATA */
+            Status = STATUS_NOT_IMPLEMENTED;
+            break;
+
+        default:
+            WARN("MapDefaultHandle() no handle creator\n");
+            Status = STATUS_INVALID_PARAMETER;
+            break;
+    }
+    
+    return Status;
+}
+
+
 static NTSTATUS
 MapDefaultKey (OUT PHANDLE RealKey,
                IN HKEY Key)
@@ -98,14 +148,14 @@ MapDefaultKey (OUT PHANDLE RealKey,
 
   TRACE("MapDefaultKey (Key %x)\n", Key);
 
-  if (((ULONG)Key & 0xF0000000) != 0x80000000)
+  if (!IsPredefKey(Key))
     {
       *RealKey = (HANDLE)((ULONG_PTR)Key & ~0x1);
       return STATUS_SUCCESS;
     }
 
   /* Handle special cases here */
-  Index = (ULONG)Key & 0x0FFFFFFF;
+  Index = GetPredefKeyIndex(Key);
   if (Index >= MAX_DEFAULT_HANDLES)
     {
       return STATUS_INVALID_PARAMETER;
@@ -127,42 +177,8 @@ MapDefaultKey (OUT PHANDLE RealKey,
   if (DoOpen)
     {
       /* create/open the default handle */
-      switch (Index)
-       {
-         case 0: /* HKEY_CLASSES_ROOT */
-           Status = OpenClassesRootKey (Handle);
-           break;
-
-         case 1: /* HKEY_CURRENT_USER */
-           Status = RtlOpenCurrentUser (MAXIMUM_ALLOWED,
-                                        Handle);
-           break;
-
-         case 2: /* HKEY_LOCAL_MACHINE */
-           Status = OpenLocalMachineKey (Handle);
-           break;
-
-         case 3: /* HKEY_USERS */
-           Status = OpenUsersKey (Handle);
-           break;
-#if 0
-         case 4: /* HKEY_PERFORMANCE_DATA */
-           Status = OpenPerformanceDataKey (Handle);
-           break;
-#endif
-         case 5: /* HKEY_CURRENT_CONFIG */
-           Status = OpenCurrentConfigKey (Handle);
-           break;
-
-         case 6: /* HKEY_DYN_DATA */
-           Status = STATUS_NOT_IMPLEMENTED;
-           break;
-
-         default:
-           WARN("MapDefaultHandle() no handle creator\n");
-           Status = STATUS_INVALID_PARAMETER;
-           break;
-       }
+      Status = OpenPredefinedKey(Index,
+                                 Handle);
     }
 
    if (NT_SUCCESS(Status))
@@ -293,6 +309,64 @@ RegDisablePredefinedCacheEx(VOID)
 }
 
 
+/************************************************************************
+ *  RegOverridePredefKey
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegOverridePredefKey(IN HKEY hKey,
+                     IN HKEY hNewHKey  OPTIONAL)
+{
+    LONG ErrorCode = ERROR_SUCCESS;
+    
+    if ((hKey == HKEY_CLASSES_ROOT ||
+         hKey == HKEY_CURRENT_CONFIG ||
+         hKey == HKEY_CURRENT_USER ||
+         hKey == HKEY_LOCAL_MACHINE ||
+         hKey == HKEY_PERFORMANCE_DATA ||
+         hKey == HKEY_USERS) &&
+        !IsPredefKey(hNewHKey))
+    {
+        PHANDLE Handle;
+        ULONG Index;
+
+        Index = GetPredefKeyIndex(hKey);
+        Handle = &DefaultHandleTable[Index];
+
+        if (hNewHKey == NULL)
+        {
+            /* restore the default mapping */
+            NTSTATUS Status = OpenPredefinedKey(Index,
+                                                &hNewHKey);
+            if (!NT_SUCCESS(Status))
+            {
+                return RtlNtStatusToDosError(Status);
+            }
+            
+            ASSERT(hNewHKey != NULL);
+        }
+
+        RtlEnterCriticalSection (&HandleTableCS);
+
+        /* close the currently mapped handle if existing */
+        if (*Handle != NULL)
+        {
+            NtClose(*Handle);
+        }
+        
+        /* update the mapping */
+        *Handle = hNewHKey;
+
+        RtlLeaveCriticalSection (&HandleTableCS);
+    }
+    else
+        ErrorCode = ERROR_INVALID_HANDLE;
+
+    return ErrorCode;
+}
+
+
 /************************************************************************
  *  RegCloseKey
  *
@@ -518,7 +592,6 @@ RegpCopyTree(IN HKEY hKeySrc,
                                 NtClose(NewKeyHandle);
                                 
                                 Status2 = STATUS_INSUFFICIENT_RESOURCES;
-                                goto GoNextKey;
                             }
                         }
                         else
@@ -527,7 +600,6 @@ RegpCopyTree(IN HKEY hKeySrc,
                         }
                     }
                     
-GoNextKey:
                     if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
                     {
                         Status = Status2;
@@ -666,9 +738,9 @@ RegCopyTreeW(IN HKEY hKeySrc,
     }
     
 Cleanup:
-    CloseDefaultKey(DestKeyHandle);
+    ClosePredefKey(DestKeyHandle);
 Cleanup2:
-    CloseDefaultKey(KeyHandle);
+    ClosePredefKey(KeyHandle);
     
     if (!NT_SUCCESS(Status))
     {
@@ -921,7 +993,7 @@ RegCreateKeyExA (HKEY hKey,
       RtlFreeUnicodeString (&ClassString);
     }
 
-  CloseDefaultKey(ParentKey);
+  ClosePredefKey(ParentKey);
 
   TRACE("Status %x\n", Status);
   if (!NT_SUCCESS(Status))
@@ -982,7 +1054,7 @@ RegCreateKeyExW (HKEY hKey,
                            samDesired,
                            lpdwDisposition);
 
-  CloseDefaultKey(ParentKey);
+  ClosePredefKey(ParentKey);
 
   TRACE("Status %x\n", Status);
   if (!NT_SUCCESS(Status))
@@ -1081,7 +1153,7 @@ RegDeleteKeyA (HKEY hKey,
   NtClose (TargetKey);
   
 Cleanup:
-  CloseDefaultKey(ParentKey);
+  ClosePredefKey(ParentKey);
 
   if (!NT_SUCCESS(Status))
     {
@@ -1133,7 +1205,7 @@ RegDeleteKeyW (HKEY hKey,
   NtClose (TargetKey);
   
 Cleanup:
-  CloseDefaultKey(ParentKey);
+  ClosePredefKey(ParentKey);
 
   if (!NT_SUCCESS(Status))
     {
@@ -1204,7 +1276,7 @@ RegDeleteKeyValueW(IN HKEY hKey,
     }
     
 Cleanup:
-    CloseDefaultKey(KeyHandle);
+    ClosePredefKey(KeyHandle);
 
     if (!NT_SUCCESS(Status))
     {
@@ -1329,7 +1401,7 @@ ReadFirstSubKey:
 
                 /* open the subkey */
                 Status2 = NtOpenKey(&newDelKeys->KeyHandle,
-                                    DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
+                                    DELETE | KEY_ENUMERATE_SUB_KEYS,
                                     &ObjectAttributes);
                 if (!NT_SUCCESS(Status2))
                 {
@@ -1389,16 +1461,33 @@ ReadFirstSubKey:
                         Status2 = STATUS_INSUFFICIENT_RESOURCES;
                     }
                 }
+                else if (Status2 == STATUS_NO_MORE_ENTRIES)
+                {
+                    /* in some race conditions where another thread would delete
+                       the same tree at the same time, newDelKeys could actually
+                       be != NULL! */
+                    if (newDelKeys != NULL)
+                    {
+                        RtlFreeHeap(ProcessHeap,
+                                    0,
+                                    newDelKeys);
+                    }
+                    break;
+                }
 
 SubKeyFailure:
-                ASSERT(newDelKeys != NULL);
-                RtlFreeHeap(ProcessHeap,
-                            0,
-                            newDelKeys);
+                /* newDelKeys can be NULL here when NtEnumerateKey returned an
+                   error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
+                if (newDelKeys != NULL)
+                {
+                    RtlFreeHeap(ProcessHeap,
+                                0,
+                                newDelKeys);
+                }
 
 SubKeyFailureNoFree:
                 /* don't break, let's try to delete as many keys as possible */
-                if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
+                if (NT_SUCCESS(Status))
                 {
                     Status = Status2;
                 }
@@ -1436,7 +1525,7 @@ SubKeyFailureNoFree:
     }
     else
         Status = STATUS_INSUFFICIENT_RESOURCES;
-    
+
     return Status;
 }
 
@@ -1475,7 +1564,7 @@ RegDeleteTreeW(IN HKEY hKey,
                                    NULL);
 
         Status = NtOpenKey(&SubKeyHandle,
-                           DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
+                           DELETE | KEY_ENUMERATE_SUB_KEYS,
                            &ObjectAttributes);
         if (!NT_SUCCESS(Status))
         {
@@ -1495,7 +1584,7 @@ RegDeleteTreeW(IN HKEY hKey,
            subkey, because the handle would be invalid already! */
         if (CurKey != KeyHandle)
         {
-            CloseDefaultKey(KeyHandle);
+            ClosePredefKey(KeyHandle);
         }
         
         return ERROR_SUCCESS;
@@ -1509,7 +1598,7 @@ RegDeleteTreeW(IN HKEY hKey,
         }
 
 Cleanup:
-        CloseDefaultKey(KeyHandle);
+        ClosePredefKey(KeyHandle);
         
         return RtlNtStatusToDosError(Status);
     }
@@ -1609,7 +1698,7 @@ RegSetKeyValueW(IN HKEY hKey,
     }
     
 Cleanup:
-    CloseDefaultKey(KeyHandle);
+    ClosePredefKey(KeyHandle);
 
     return Ret;
 }
@@ -1687,7 +1776,7 @@ RegSetKeyValueA(IN HKEY hKey,
     }
     
 Cleanup:
-    CloseDefaultKey(KeyHandle);
+    ClosePredefKey(KeyHandle);
 
     return Ret;
 }
@@ -1719,7 +1808,7 @@ RegDeleteValueA (HKEY hKey,
                             &ValueName);
   RtlFreeUnicodeString (&ValueName);
   
-  CloseDefaultKey(KeyHandle);
+  ClosePredefKey(KeyHandle);
   
   if (!NT_SUCCESS(Status))
     {
@@ -1756,7 +1845,7 @@ RegDeleteValueW (HKEY hKey,
   Status = NtDeleteValueKey (KeyHandle,
                             &ValueName);
 
-  CloseDefaultKey(KeyHandle);
+  ClosePredefKey(KeyHandle);
 
   if (!NT_SUCCESS(Status))
     {
@@ -1981,7 +2070,7 @@ RegEnumKeyExA (HKEY hKey,
                KeyInfo);
 
 Cleanup:
-    CloseDefaultKey(KeyHandle);
+    ClosePredefKey(KeyHandle);
 
     return ErrorCode;
 }
@@ -2129,7 +2218,7 @@ RegEnumKeyExW (HKEY hKey,
               KeyInfo);
 
 Cleanup:
-  CloseDefaultKey(KeyHandle);
+  ClosePredefKey(KeyHandle);
 
   return ErrorCode;
 }
@@ -2148,7 +2237,7 @@ RegEnumValueA( HKEY hKey, DWORD index, LPSTR value, LPDWORD val_count,
     DWORD total_size;
     char buffer[256], *buf_ptr = buffer;
     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
-    static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
+    static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name );
 
     //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
       //    hkey, index, value, val_count, reserved, type, data, count );
@@ -2244,7 +2333,7 @@ RegEnumValueA( HKEY hKey, DWORD index, LPSTR value, LPDWORD val_count,
 
  done:
     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
-    CloseDefaultKey(KeyHandle);
+    ClosePredefKey(KeyHandle);
     return RtlNtStatusToDosError(status);
 }
 
@@ -2275,7 +2364,7 @@ RegEnumValueW( HKEY hKey, DWORD index, LPWSTR value, PDWORD val_count,
     DWORD total_size;
     char buffer[256], *buf_ptr = buffer;
     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
-    static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
+    static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name );
 
     //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
     //      hkey, index, value, val_count, reserved, type, data, count );
@@ -2352,7 +2441,7 @@ RegEnumValueW( HKEY hKey, DWORD index, LPWSTR value, PDWORD val_count,
 
  done:
     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
-    CloseDefaultKey(KeyHandle);
+    ClosePredefKey(KeyHandle);
     return RtlNtStatusToDosError(status);
 }
 
@@ -2381,7 +2470,7 @@ RegFlushKey(HKEY hKey)
 
   Status = NtFlushKey (KeyHandle);
   
-  CloseDefaultKey(KeyHandle);
+  ClosePredefKey(KeyHandle);
   
   if (!NT_SUCCESS(Status))
     {
@@ -2418,14 +2507,15 @@ RegGetKeySecurity(HKEY hKey,
       TRACE("MapDefaultKey() failed (Status %lx)\n", Status);
       return RtlNtStatusToDosError (Status);
     }
-
+#ifndef __REACTOS__
   Status = NtQuerySecurityObject(KeyHandle,
                                 SecurityInformation,
                                 pSecurityDescriptor,
                                 *lpcbSecurityDescriptor,
                                 lpcbSecurityDescriptor);
+#endif
 
-  CloseDefaultKey(KeyHandle);
+  ClosePredefKey(KeyHandle);
 
   if (!NT_SUCCESS(Status))
     {
@@ -2497,7 +2587,7 @@ RegLoadKeyW (HKEY hKey,
       return RtlNtStatusToDosError (Status);
     }
 
-  if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFile,
+  if (!RtlDosPathNameToNtPathName_U (lpFile,
                                     &FileName,
                                     NULL,
                                     NULL))
@@ -2533,7 +2623,7 @@ RegLoadKeyW (HKEY hKey,
     }
 
 Cleanup:
-  CloseDefaultKey(KeyHandle);
+  ClosePredefKey(KeyHandle);
 
   return ErrorCode;
 }
@@ -2590,7 +2680,7 @@ RegNotifyChangeKeyValue (HKEY hKey,
       ErrorCode = RtlNtStatusToDosError (Status);
     }
 
-  CloseDefaultKey(KeyHandle);
+  ClosePredefKey(KeyHandle);
 
   return ErrorCode;
 }
@@ -2709,7 +2799,7 @@ RegOpenKeyExA (HKEY hKey,
                ErrorCode = RtlNtStatusToDosError (Status);
        }
        
-       CloseDefaultKey(KeyHandle);
+       ClosePredefKey(KeyHandle);
 
        return ErrorCode;
 }
@@ -2760,7 +2850,7 @@ RegOpenKeyExW (HKEY hKey,
                ErrorCode = RtlNtStatusToDosError (Status);
        }
        
-       CloseDefaultKey(KeyHandle);
+       ClosePredefKey(KeyHandle);
 
        return ErrorCode;
 }
@@ -3095,7 +3185,7 @@ RegQueryInfoKeyW (HKEY hKey,
     {
       *lpcbMaxValueLen = FullInfo->MaxValueDataLen;
     }
-
+#ifndef __REACTOS__ 
   if (lpcbSecurityDescriptor != NULL)
     {
       Status = NtQuerySecurityObject(KeyHandle,
@@ -3118,6 +3208,7 @@ RegQueryInfoKeyW (HKEY hKey,
          goto Cleanup;
        }
     }
+#endif
 
   if (lpftLastWriteTime != NULL)
     {
@@ -3146,7 +3237,7 @@ RegQueryInfoKeyW (HKEY hKey,
     }
 
 Cleanup:
-  CloseDefaultKey(KeyHandle);
+  ClosePredefKey(KeyHandle);
   
   return ErrorCode;
 }
@@ -3396,7 +3487,7 @@ RegQueryValueExW (HKEY hKey,
               ValueInfo);
 
 Cleanup:
-  CloseDefaultKey(KeyHandle);
+  ClosePredefKey(KeyHandle);
 
   return ErrorCode;
 }
@@ -3665,7 +3756,7 @@ RegQueryValueW (HKEY hKey,
     }
 
 Cleanup:
-  CloseDefaultKey(KeyHandle);
+  ClosePredefKey(KeyHandle);
 
   return ErrorCode;
 }
@@ -3769,7 +3860,7 @@ RegReplaceKeyW (HKEY hKey,
     }
 
   /* Convert new file name */
-  if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpNewFile,
+  if (!RtlDosPathNameToNtPathName_U (lpNewFile,
                                     &NewFileName,
                                     NULL,
                                     NULL))
@@ -3789,7 +3880,7 @@ RegReplaceKeyW (HKEY hKey,
                              NULL);
 
   /* Convert old file name */
-  if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpOldFile,
+  if (!RtlDosPathNameToNtPathName_U (lpOldFile,
                                     &OldFileName,
                                     NULL,
                                     NULL))
@@ -3827,7 +3918,7 @@ RegReplaceKeyW (HKEY hKey,
     }
 
 Cleanup:
-  CloseDefaultKey(KeyHandle);
+  ClosePredefKey(KeyHandle);
 
   return ErrorCode;
 }
@@ -3888,7 +3979,7 @@ RegRestoreKeyW (HKEY hKey,
       return RtlNtStatusToDosError (Status);
     }
 
-  if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFile,
+  if (!RtlDosPathNameToNtPathName_U (lpFile,
                                     &FileName,
                                     NULL,
                                     NULL))
@@ -3921,7 +4012,7 @@ RegRestoreKeyW (HKEY hKey,
   NtClose (FileHandle);
   
 Cleanup:
-  CloseDefaultKey(KeyHandle);
+  ClosePredefKey(KeyHandle);
 
   if (!NT_SUCCESS(Status))
     {
@@ -3981,7 +4072,7 @@ RegSaveKeyW (HKEY hKey,
       return RtlNtStatusToDosError (Status);
     }
 
-  if (!RtlDosPathNameToNtPathName_U ((PWSTR)lpFile,
+  if (!RtlDosPathNameToNtPathName_U (lpFile,
                                     &FileName,
                                     NULL,
                                     NULL))
@@ -4022,7 +4113,7 @@ RegSaveKeyW (HKEY hKey,
   NtClose (FileHandle);
 
 Cleanup:
-  CloseDefaultKey(KeyHandle);
+  ClosePredefKey(KeyHandle);
 
   if (!NT_SUCCESS(Status))
     {
@@ -4062,7 +4153,7 @@ RegSetKeySecurity (HKEY hKey,
                                SecurityInformation,
                                pSecurityDescriptor);
 
-  CloseDefaultKey(KeyHandle);
+  ClosePredefKey(KeyHandle);
   
   if (!NT_SUCCESS(Status))
     {
@@ -4212,7 +4303,7 @@ RegSetValueExW (HKEY hKey,
                          (PVOID)lpData,
                          (ULONG)cbData);
 
-  CloseDefaultKey(KeyHandle);
+  ClosePredefKey(KeyHandle);
 
   if (!NT_SUCCESS(Status))
     {
@@ -4337,7 +4428,7 @@ RegSetValueW (HKEY hKey,
     }
 
 Cleanup:
-  CloseDefaultKey(KeyHandle);
+  ClosePredefKey(KeyHandle);
 
   return ErrorCode;
 }
@@ -4403,7 +4494,7 @@ RegUnLoadKeyW (HKEY hKey,
 
   Status = NtUnloadKey (&ObjectAttributes);
   
-  CloseDefaultKey(KeyHandle);
+  ClosePredefKey(KeyHandle);
 
   if (!NT_SUCCESS(Status))
     {