我是域管理员,我想在 API(例如 C++)中以编程方式取得我域中某些服务器上某些共享文件夹的所有权。我做了一些阅读工作,发现默认情况下域管理员位于成员计算机的本地管理员组中,本地管理员用户无论如何都可以取得所有权。我只是以这种方式编写了一些代码,但在使用 GetNamedSecurityInfo 获取所有者 sid 时仍然遇到 ERROR_ACCESS_DENIED?问题出在哪里?
有趣的是:当我将 GetNamedSecurityInfo 的第二个参数从 SE_FILE_OBJECT 更改为 SE_LMSHARE 时,它会成功(也设置一个)。但是我没有看到所有者在文件夹属性的“安全”选项卡中发生了变化。我知道“共享”权限与“安全”权限不同。 “共享”权限甚至没有所有者。那么在通过 SE_LMSHARE 参数调用 GetNamedSecurityInfo 时,我得到了什么所有者?
这是我用于获取文件夹“strFileName”所有权的函数,在服务器“strServerName”上,所有者更改为只是称为“strDomainName”“strUserName”“strPassword”的域管理员帐户,保留原始所有者在“pOriginSID”中。 我在 GetNamedSecurityInfo 调用(也是 Set one)中收到错误代码 5。我还写了一个模拟方法“logOnByUserPassword”,但似乎不起作用,我将其粘贴在下面。
处理 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;
}
}
最佳答案
本地管理员需要接受通常的 Windows 安全检查,但有一个异常(exception):无论权限如何,他们始终可以获得 protected 对象的所有权。这可确保管理员始终能够重新获得控制权。
但是,您并不是在尝试获取所有权,而是在尝试读取当前所有者,而您不一定具有这样做的权限。
从您的代码中不清楚您为什么要读取所有者。你似乎没有用它做任何事情。也许完全删除对 GetNamedSecurityInfo 的调用。
更新
目的是编写一个程序来检查每个共享上的 DACL。因此它需要保存当前所有者、获取所有权、读取 DACL 并恢复所有者。但是在取得所有权之前无法读取当前所有者。
我认为这种行为是设计使然。最初的意图是管理员能够获得所有权,但不能向对象的所有者隐瞒他们拥有的事实,尽管有一些方法可以解决这个问题。例如,对于文件,您可以通过启用备份权限、调用 BackupRead 并解析输出(一系列 WIN32_STREAM_ID 结构,每个结构后跟数据)来读取完整的安全描述符(包括所有者)。不知道有没有更简单的方法。
有关共享的信息存储在以下注册表中:
SYSTEM\CurrentControlSet\Services\LanmanServer\Shares
安全信息似乎存储在 Security
子项中,在以共享命名的值中。这个二进制值似乎是一个安全描述符,因此您可以使用 GetSecurityDescriptorOwner
读取所有者.您还可以从此安全描述符中读取所有其他安全信息,因此您根本不需要更改所有者。
关于c++ - 写入远程 Windows 共享文件夹的所有者时,GetNamedSecurityInfo 返回 ERROR_ACCESS_DENIED(5),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11384220/