Search code examples
c++windowssecuritywinapiregistry

C++ windows API GetSecurityInfo invalid handle given


I'm trying to create a new registry key in Windows 10 using the Windows API, namely the RegCreateKeyEx function, and then get its DACL using GetSecurityInfo. All the asserts go smoothly until i get to said GetSecurityInfo function call, which gives an invalid handle value error(error 6). What am I doing wrong?

This is part of a more elaborate project so I will only give the(or what I think it is, but i can add the rest too) relevant part here:

A wrapper to RegCreateKeyEx to make the output easier to work with and set any errors encountered:

inline extern auto RegCreateKeyEx_safe(
    _In_       const HKEY                  hKey,
    _In_       const LPCTSTR               lpSubKey,
    _Reserved_ const DWORD                 Reserved,
    _In_opt_   const LPTSTR                lpClass,
    _In_       const DWORD                 dwOptions,
    _In_       const REGSAM                samDesired,
    _In_opt_   const LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    _Out_      const PHKEY                 phkResult,
    _Out_opt_  const LPDWORD               lpdwDisposition)
{
    const auto result = 
        RegCreateKeyEx(
            hKey,
            lpSubKey,
            Reserved,
            lpClass,
            dwOptions,
            samDesired,
            lpSecurityAttributes,
            phkResult,
            lpdwDisposition);
    if (result != ERROR_SUCCESS)
        SetLastError(result);
    return result == ERROR_SUCCESS;
}

A wrapper to the above function that should return a handle to the created key after checking if it is valid:

inline extern auto CreateNewRegKey(
    HKEY                  hKey,
    LPCTSTR               lpSubKey,
    DWORD                 Reserved,
    LPTSTR                lpClass,
    DWORD                 dwOptions,
    REGSAM                samDesired,
    LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    LPDWORD               lpdwDisposition)
{
    auto createdKey = static_cast<PHKEY>(malloc(sizeof HKEY));

    assert(
        RegCreateKeyEx_safe(
            hKey,
            lpSubKey,
            Reserved,
            lpClass,
            dwOptions,
            samDesired,
            lpSecurityAttributes,
            createdKey,
            lpdwDisposition));

    assert(createdKey != INVALID_HANDLE_VALUE);

    return createdKey;
}

And a wrapper for GetSecurityInfo, same reason and functionality as the RegCreateKey version:

inline extern auto GetSecurityInfo_safe(
    _In_      const HANDLE                handle,
    _In_      const SE_OBJECT_TYPE        ObjectType,
    _In_      const SECURITY_INFORMATION  SecurityInfo,
    _Out_opt_       PSID*                 ppsidOwner,
    _Out_opt_       PSID*                 ppsidGroup,
    _Out_opt_       PACL*                 ppDacl,
    _Out_opt_       PACL*                 ppSacl,
    _Out_opt_       PSECURITY_DESCRIPTOR* ppSecurityDescriptor)
{
    const auto result =
        GetSecurityInfo(
            handle,
            ObjectType,
            SecurityInfo,
            ppsidOwner,
            ppsidGroup,
            ppDacl,
            ppSacl,
            ppSecurityDescriptor);
    if (result != ERROR_SUCCESS)
        SetLastError(result);
    return result == EXIT_SUCCESS;
}

Now the code calling these functions is as follows:

 const auto newRegKey = 
        CreateNewRegKey(
            HKEY_CURRENT_USER, 
            SUBKEY_PATH, 
            NULL, 
            nullptr, 
            REG_OPTION_NON_VOLATILE, 
            KEY_ALL_ACCESS, 
            NULL,  //securityAttributes, 
            nullptr);

    assert(
        GetSecurityInfo_safe(
            newRegKey,
            SE_REGISTRY_KEY,
            DACL_SECURITY_INFORMATION,
            NULL,
            NULL,
            oldDacl,
            NULL,
            NULL));

The output is pretty clear on where the issue is(I implemented a slightly more verbose assert that after checking the condition, it prints it, along with the error text in case the condition failed):

SUCCESS:        RegCreateKeyEx_safe( hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, createdKey, lpdwDisposition)
SUCCESS:        createdKey != INVALID_HANDLE_VALUE
FAILURE:        GetSecurityInfo_safe( newRegKey, SE_REGISTRY_KEY, DACL_SECURITY_INFORMATION, NULL, NULL, oldDacl, NULL, NULL)

ERROR-6:        The handle is invalid.

The assert:

#define _VERBOSE            (1)
#define assert(cond)        if((cond) == TRUE) \
                                { if (_VERBOSE) cout << "SUCCESS:\t" << #cond << endl; } \
                            else \
                                {cout << "FAILURE:\t" << #cond << "\n\nERROR-" << GetLastError() << ":\t" << GetLastErrorAsString() << "\n\n"; exit(EXIT_FAILURE); }

Thank you in advance!


Solution

  • The function CreateNewRegKey is returning a pointer to an HKEY where it should return HKEY by value. You pass this pointer to GetSecurityInfo() which expects a HANDLE instead. The compiler won't notice because HANDLE is declared as typedef void *HANDLE;.

    To correct the error replace:

    auto createdKey = static_cast<PHKEY>(malloc(sizeof HKEY));
    

    with

    HKEY createdKey = NULL;
    

    and call RegCreateKeyEx_safe() with &createdKey to pass the address of the HKEY.