在写入远程Windows共享文件夹的所有者时,GetNamedSecurityInfo返回ERROR_ACCESS_DE

GetNamedSecurityInfo returns ERROR_ACCESS_DENIED(5) when writting owner of a remote Windows shared folder

本文关键字:GetNamedSecurityInfo 返回 ERROR DE ACCESS 所有者 Windows 文件夹 共享文件 共享      更新时间:2023-10-16

我是一名域管理员,我想在API中以编程方式获得域的某些服务器上的某些共享文件夹的所有权(例如C++)。我做了一些阅读工作,发现默认情况下,域管理员在成员计算机的本地管理员组中,并且本地管理员用户无论如何都可以拥有所有权。我只是用这种方式编写了一些代码,但在使用GetNamedSecurityInfo获取所有者sid时仍然遇到ERROR_ACCESS_DENIED?问题出在哪里?

有趣的是:当我将GetNamedSecurityInfo的secound参数从SE_FILE_OBJECT更改为SE_LMSHARE时,它会成功(也设置了一个)。但在文件夹属性的"安全"选项卡中,我没有看到所有者发生了更改。我知道"共享"权限与"安全"权限不同。"共享"权限甚至没有所有者。那么,当使用SE_LMSHARE参数调用GetNamedSecurityInfo时,我得到了什么所有者呢?

这是我用于获取文件夹"strFileName"的所有权的函数,在服务器"strServerName"上,更改为的所有者只是名为"strDomainName"strUserName"strPassword"的域管理员帐户,原始所有者保留在"pOriginSID"中。我在GetNamedSecurityInfo调用(也是Set调用)中得到了错误代码5。我还写了一个模拟方法"logOnByUserPassword",它似乎不起作用,我把它粘贴在下面。

HANDLE ADPermissionSearch::getAccessTokenByCredential(CString strDomainName、CString strUserName、CSString 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 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 BUILTINAdministrators 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、CSString 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;
    }
}

}

本地管理员要接受常见的Windows安全检查,但有一个例外:无论权限如何,他们都可以获得受保护对象的所有权。这样可以确保管理员始终能够重新获得控制权。

然而,你并不是在试图获得所有权,你是在试图读取当前所有者,但你不一定有这样做的权限。

从您的代码中不清楚您为什么要读取所有者。您似乎对此没有任何操作。也许可以完全删除对GetNamedSecurityInfo的调用。

更新

其目的是编写一个程序来检查每个股票上的DACL。因此,它需要保存当前所有者,取得所有权,读取DACL并恢复所有者。但在取得所有权之前,无法读取当前所有者。

我认为这种行为是故意的。最初的意图是管理员可以获得所有权,但不能向对象的所有者隐瞒他们拥有的事实,尽管有很多方法可以解决这个问题。例如,对于文件,您可以通过启用备份权限、调用BackupRead并解析输出(一系列WIN32_STREAM_ID结构,每个结构后面都跟着数据)来读取完整的安全描述符(包括所有者)。我不知道是否有更简单的方法。

有关股票的信息存储在注册表中的下

SYSTEMCurrentControlSetServicesLanmanServerShares

安全信息似乎存储在Security子密钥中,该值以共享命名。这个二进制值似乎是一个安全描述符,因此您可以使用GetSecurityDescriptorOwner读取所有者。您还可以从此安全描述符中读取所有其他安全信息,因此根本不需要更改所有者。

相关文章:
  • 没有找到相关文章