GetNamedSecurityInfo returns ERROR_ACCESS_DENIED(5

2020-08-09 06:34发布

问题:

I'm a Domain Admin and I want to take ownership of some shared folders on some server of my domain programmatically in API(for example C++). I did some reading work and found that a Domain Admin is in the member machine's Local Admins group by default, and the Local Admins users can take ownership anyway. I just wrtie some code in this way but still encountered ERROR_ACCESS_DENIED when getting the owner sid using GetNamedSecurityInfo? Where's the problem?

Something interesting is: When I changed the GetNamedSecurityInfo's secound argument from SE_FILE_OBJECT to SE_LMSHARE, it would succeed(also set one). But I didn't see the owner changed in the "Security" tab of folder's properties. I know a "share" permission is different with "security" one. a "share" permission even don't have a owner. So what owner did I get when calling GetNamedSecurityInfo by the SE_LMSHARE argument?

Here's the function i use for Taking ownership for the folder "strFileName", on server "strServerName", the owner changed to is just the Domain Admin account known as "strDomainName" "strUserName" "strPassword", orginal owner is reserved in "pOriginSID". I got error code 5 in the GetNamedSecurityInfo call (also the Set one). I also write a impersonation method "logOnByUserPassword" which seems not to work, i paste it below.

HANDLE ADPermissionSearch::getAccessTokenByCredential(CString strDomainName, CString strUserName, CString strPassword) {

CString strUPNUserName = strUserName + _T("@") + strDomainName;

HANDLE hToken;
BOOL bResult;
//bResult = LogonUser(strUserName, strDomainName, strPassword, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT,
//  &hToken);
if (strDomainName != _T(""))
{
    bResult = LogonUser(strUPNUserName, _T(""), strPassword, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, 
        &hToken);
}
else
{
    bResult = LogonUser(strUserName, _T("."), strPassword, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, 
        &hToken);
}
if (bResult == FALSE)
{
    MyMessageBox_Error(_T("getAccessTokenByCredential Error."), _T("Error"));
    return FALSE;
}
else
{
    return hToken;
}

}

int ADPermissionSearch::takeOwnership(CString strServerName, CString strFileName, CString strDomainName, CString strUserName, CString strPassword, __out PSID &pOriginSID) {

CString strUNCFileName = _T("\\\\") + strServerName + _T("\\") + strFileName;
_bstr_t bstrUNCFileName = _bstr_t(strUNCFileName);
PSID pSIDAdmin = NULL;
SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
HANDLE hToken = NULL;
DWORD dwRes;

// Create a SID for the BUILTIN\Administrators group.
if (!AllocateAndInitializeSid(&SIDAuthNT, 2,
    SECURITY_BUILTIN_DOMAIN_RID,
    DOMAIN_ALIAS_RID_ADMINS,
    0, 0, 0, 0, 0, 0,
    &pSIDAdmin))
{
    if (pSIDAdmin)
        FreeSid(pSIDAdmin);
    if (hToken)
        CloseHandle(hToken);
    MyMessageBox_Error(_T("takeOwnership"));
    return 0;
}

// If the preceding call failed because access was denied,
// enable the SE_TAKE_OWNERSHIP_NAME privilege, create a SID for
// the Administrators group, take ownership of the object, and
// disable the privilege. Then try again to set the object's DACL.

// Open a handle to the access token for the calling process.
/*
if (!OpenProcessToken(GetCurrentProcess(),
                      TOKEN_ADJUST_PRIVILEGES,
                      &hToken))
{
    if (pSIDAdmin)
        FreeSid(pSIDAdmin);
    if (hToken)
        CloseHandle(hToken);
    MyMessageBox_Error(_T("takeOwnership"));
    return 0;
}
*/
if ((hToken = getAccessTokenByCredential(strDomainName, strUserName, strPassword)) == NULL)
{
    if (pSIDAdmin)
        FreeSid(pSIDAdmin);
    if (hToken)
        CloseHandle(hToken);
    MyMessageBox_Error(_T("takeOwnership"));
    return 0;
}

// Enable the SE_TAKE_OWNERSHIP_NAME privilege.
if (!setPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, TRUE))
{
    if (pSIDAdmin)
        FreeSid(pSIDAdmin);
    if (hToken)
        CloseHandle(hToken);
    MyMessageBox_Error(_T("takeOwnership"));
    return 0;
}

// Get the original owner in the object's security descriptor.
dwRes = GetNamedSecurityInfo(
    bstrUNCFileName,             // name of the object
    SE_FILE_OBJECT,                  // type of object
    OWNER_SECURITY_INFORMATION,  // change only the object's owner
    &pOriginSID,                 // SID of Administrator group
    NULL,
    NULL,
    NULL,
    NULL);
if (dwRes != ERROR_SUCCESS)
{
    if (pSIDAdmin)
        FreeSid(pSIDAdmin);
    if (hToken)
        CloseHandle(hToken);
    MyMessageBox_Error(_T("takeOwnership"));
    return 0;
}

// Set the owner in the object's security descriptor.
dwRes = SetNamedSecurityInfo(
            bstrUNCFileName,             // name of the object
            SE_FILE_OBJECT,                  // type of object
            OWNER_SECURITY_INFORMATION,  // change only the object's owner
            pSIDAdmin,                   // SID of Administrator group
            NULL,
            NULL,
            NULL);
if (dwRes != ERROR_SUCCESS)
{
    if (pSIDAdmin)
        FreeSid(pSIDAdmin);
    if (hToken)
        CloseHandle(hToken);
    MyMessageBox_Error(_T("takeOwnership"));
    return 0;
}

// Disable the SE_TAKE_OWNERSHIP_NAME privilege.
if (!setPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, FALSE))
{
    if (pSIDAdmin)
        FreeSid(pSIDAdmin);
    if (hToken)
        CloseHandle(hToken);
    MyMessageBox_Error(_T("takeOwnership"));
    return 0;
}

return 1;

}

BOOL ADDirectorySearch::logOnByUserPassword(CString strDomainName, CString strUserName, CString strPassword) {

CString strUPNUserName = strUserName + _T("@") + strDomainName;

HANDLE hToken;
BOOL bResult;
//bResult = LogonUser(strUserName, strDomainName, strPassword, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT,
//  &hToken);
if (strDomainName != _T(""))
{
    bResult = LogonUser(strUPNUserName, _T(""), strPassword, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, 
        &hToken);
}
else
{
    bResult = LogonUser(strUserName, _T("."), strPassword, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, 
        &hToken);
}
if (bResult == FALSE)
{
    MyMessageBox_Error(_T("logOnByUserPassword Error."), _T("Error"));
    return FALSE;
}
else
{
    bResult = ImpersonateLoggedOnUser(hToken);
    if (bResult == FALSE)
    {
        MyMessageBox_Error(_T("logOnByUserPassword Error."), _T("Error"));
        return FALSE;
    }
    else
    {
        return TRUE;
    }
}

}

回答1:

Local admins are subject to the usual Windows security checks with one exception: they can always take ownership of a secured object regardless of the permissions. This ensures that admins are always able to regain control.

However, you are not trying to take ownership, you are trying to read the current owner and you don't necessarily have permission to do that.

It's not clear from your code why you are trying to read the owner. You don't seem to do anything with it. Maybe remove the call to GetNamedSecurityInfo altogether.

Update

The intention is to write a program that checks the DACLs on every share. So it needs to save the current owner, take ownership, read the DACLs and restore the owner. But the current owner cannot be read until ownership has been taken.

I think this behaviour is by design. The original intention was that admins were able to take ownership, but not hide the fact that they had from the owner of an object, though there are ways around this. For example, for files you can read the complete security descriptor (including the owner) by enabling the backup privilege, calling BackupRead and parsing the output (a sequence of WIN32_STREAM_ID structures each followed by data). I don't know if there's a simpler way.

Information about shares is stored in the registry under:

SYSTEM\CurrentControlSet\Services\LanmanServer\Shares

The security info seems to be stored in the Security subkey, in a value named after the share. This binary value seems to be a security descriptor so you can read the owner with GetSecurityDescriptorOwner. You can also read all the other security info from this security descriptor, so you shouldn't need to change the owner at all.