WINAPI 读取自定义文件或文件夹的所有访问权限
WINAPI Read all access rights for a custom file or a folder
我有一个基于算法的任务来接收某个文件或文件夹的访问权限,我已经尝试实现它,但有些部分似乎不太清楚。
我被要求的内容:
1) Use the function GetNamedSecurityInfo(), for example:
GetNamedSecurityInfo(path,SE_FILE_OBJECT,DACL_SECURITY_INFORMATION,NULL,
NULL,&a,NULL, &pSD)
2) Futher, use an SID to receive the rights: Use
these functions to receive the SID: GetAclInformation(), then GetAce().
3) Now you can use the LookupAccountSid() function and if is was
successfull, compare pACE->Mask with all the constants, for example
"GENERIC_ALL, GENERIC_READ, GENERIC_WRITE, GENERIC_EXECUTE for files
etc." displaying the access rights.
以及我是如何尝试实现这个算法的: // 首先获取进程 SID
PSID g_pSID;
BOOL GetCurrentProcessSID()
{
DWORD dwSize = 0, dwError, dwResult = 0;
HANDLE hToken;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
{
printf("OpenProcessToken Error %u\n", GetLastError());
return FALSE;
}
// Call GetTokenInformation to get the buffer size.
TOKEN_USER tU;
if (!GetTokenInformation(hToken, TokenUser, &tU, 0, &dwSize))
{
dwError = GetLastError();
if (dwError != ERROR_INSUFFICIENT_BUFFER)
{
std::cout << "GetTokenInformation failed, error " << dwError;
CloseHandle(hToken);
return 0;
}
}
PTOKEN_OWNER to = (PTOKEN_OWNER)LocalAlloc(LPTR, dwSize);
if (!to)
{
dwError = GetLastError();
std::cout << "LocalAlloc failed, error " << dwError;
CloseHandle(hToken);
return 0;
}
if (!GetTokenInformation(hToken, TokenOwner, to, dwSize, &dwSize))
{
dwError = GetLastError();
std::cout << "GetTokenInformation failed, error " << dwError;
LocalFree(to);
CloseHandle(hToken);
return 0;
}
g_pSID = to->Owner;
return TRUE;
}
//然后我通过ACL列表使用迭代:
std::stringstream g_TestSecurityResult;
void TestSecurity( wchar_t* path )
{
g_TestSecurityResult = std::stringstream();
GetCurrentProcessSID();
PACL pDacl;
PSECURITY_DESCRIPTOR pSD;
GetNamedSecurityInfoW(path, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pDacl, NULL, &pSD);
ACL_SIZE_INFORMATION aclSizeInfo = { sizeof(ACL) };
BOOL fResult = GetAclInformation( pDacl, &aclSizeInfo, sizeof(ACL_SIZE_INFORMATION), ACL_INFORMATION_CLASS::AclSizeInformation );
if (fResult)
{
for (DWORD dwIndex = 0; dwIndex < aclSizeInfo.AceCount; ++dwIndex)
{
LPVOID pTempAce = nullptr;
fResult = ::GetAce(pDacl, dwIndex, &pTempAce);
if (fResult)
{
PSID pSid = &((ACCESS_ALLOWED_ACE*)pTempAce)->SidStart;
if (EqualSid(pSid, &g_pSID))
{
g_TestSecurityResult << "User: " << userNameFromSid(&g_pSID) << std::endl;
g_TestSecurityResult << "\tAccess mode: " << ((EXPLICIT_ACCESS*)pTempAce)->grfAccessMode << "\n";
g_TestSecurityResult << "\tAccess permissions: " << ((EXPLICIT_ACCESS*)pTempAce)->grfAccessPermissions << "\n";
g_TestSecurityResult << "\tInheritance: " << ((EXPLICIT_ACCESS*)pTempAce)->grfInheritance << "\n";
g_TestSecurityResult << std::endl;
}
}
else
{
g_TestSecurityResult << "GetAce() failed." << GetLastError();
break;
}
}
} else {
g_TestSecurityResult << "Error in GetAclInformation(): " << GetLastError();
}
}
std::string userNameFromSid(PSID userSid)
{
char buffName[MAX_BUFF_SIZE];
DWORD buffNameSize = MAX_BUFF_SIZE;
char buffDomain[MAX_BUFF_SIZE];
DWORD buffDomainSize = MAX_BUFF_SIZE;
SID_NAME_USE SidType;
if (LookupAccountSid(NULL, userSid, buffName, &buffNameSize, buffDomain, &buffDomainSize, &SidType)) {
return buffName;
} else {
DWORD dwResult = GetLastError();
printf("GetTokenInformation Error %u\n", dwResult);
}
/*Here some code to print error in a Message box*/
return "";
}
问题:代码有效,但在行 if (EqualSid(pSid, &g_pSID))调试器通过并跳过我从我的进程收到的 SID。换句话说,我无法从 ACL 列表中获取任何信息,即使我是 运行 进程并且 Visual Studio 在管理员帐户下(不使用 "Run as Administrator",而且我'我会尝试,但仍然......收到的 SID 是有效的,我可以使用上述函数获取进程所有者的名称。我在这里做错了什么?
代码来源:
https://gist.github.com/m4x1m1l14n/37f39c5d25855c2b1d3a6334851f7549
感谢@(Rita Han - MSFT) 的评论,我忘记从 pSID 比较中删除 & 符号
EqualSid(pSid, g_pSID);
而不是
EqualSid(pSid, &g_pSID);
并且目前可以正常工作
我有一个基于算法的任务来接收某个文件或文件夹的访问权限,我已经尝试实现它,但有些部分似乎不太清楚。 我被要求的内容:
1) Use the function GetNamedSecurityInfo(), for example: GetNamedSecurityInfo(path,SE_FILE_OBJECT,DACL_SECURITY_INFORMATION,NULL, NULL,&a,NULL, &pSD)
2) Futher, use an SID to receive the rights: Use these functions to receive the SID: GetAclInformation(), then GetAce().
3) Now you can use the LookupAccountSid() function and if is was successfull, compare pACE->Mask with all the constants, for example "GENERIC_ALL, GENERIC_READ, GENERIC_WRITE, GENERIC_EXECUTE for files etc." displaying the access rights.
以及我是如何尝试实现这个算法的: // 首先获取进程 SID
PSID g_pSID;
BOOL GetCurrentProcessSID()
{
DWORD dwSize = 0, dwError, dwResult = 0;
HANDLE hToken;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
{
printf("OpenProcessToken Error %u\n", GetLastError());
return FALSE;
}
// Call GetTokenInformation to get the buffer size.
TOKEN_USER tU;
if (!GetTokenInformation(hToken, TokenUser, &tU, 0, &dwSize))
{
dwError = GetLastError();
if (dwError != ERROR_INSUFFICIENT_BUFFER)
{
std::cout << "GetTokenInformation failed, error " << dwError;
CloseHandle(hToken);
return 0;
}
}
PTOKEN_OWNER to = (PTOKEN_OWNER)LocalAlloc(LPTR, dwSize);
if (!to)
{
dwError = GetLastError();
std::cout << "LocalAlloc failed, error " << dwError;
CloseHandle(hToken);
return 0;
}
if (!GetTokenInformation(hToken, TokenOwner, to, dwSize, &dwSize))
{
dwError = GetLastError();
std::cout << "GetTokenInformation failed, error " << dwError;
LocalFree(to);
CloseHandle(hToken);
return 0;
}
g_pSID = to->Owner;
return TRUE;
}
//然后我通过ACL列表使用迭代:
std::stringstream g_TestSecurityResult;
void TestSecurity( wchar_t* path )
{
g_TestSecurityResult = std::stringstream();
GetCurrentProcessSID();
PACL pDacl;
PSECURITY_DESCRIPTOR pSD;
GetNamedSecurityInfoW(path, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pDacl, NULL, &pSD);
ACL_SIZE_INFORMATION aclSizeInfo = { sizeof(ACL) };
BOOL fResult = GetAclInformation( pDacl, &aclSizeInfo, sizeof(ACL_SIZE_INFORMATION), ACL_INFORMATION_CLASS::AclSizeInformation );
if (fResult)
{
for (DWORD dwIndex = 0; dwIndex < aclSizeInfo.AceCount; ++dwIndex)
{
LPVOID pTempAce = nullptr;
fResult = ::GetAce(pDacl, dwIndex, &pTempAce);
if (fResult)
{
PSID pSid = &((ACCESS_ALLOWED_ACE*)pTempAce)->SidStart;
if (EqualSid(pSid, &g_pSID))
{
g_TestSecurityResult << "User: " << userNameFromSid(&g_pSID) << std::endl;
g_TestSecurityResult << "\tAccess mode: " << ((EXPLICIT_ACCESS*)pTempAce)->grfAccessMode << "\n";
g_TestSecurityResult << "\tAccess permissions: " << ((EXPLICIT_ACCESS*)pTempAce)->grfAccessPermissions << "\n";
g_TestSecurityResult << "\tInheritance: " << ((EXPLICIT_ACCESS*)pTempAce)->grfInheritance << "\n";
g_TestSecurityResult << std::endl;
}
}
else
{
g_TestSecurityResult << "GetAce() failed." << GetLastError();
break;
}
}
} else {
g_TestSecurityResult << "Error in GetAclInformation(): " << GetLastError();
}
}
std::string userNameFromSid(PSID userSid)
{
char buffName[MAX_BUFF_SIZE];
DWORD buffNameSize = MAX_BUFF_SIZE;
char buffDomain[MAX_BUFF_SIZE];
DWORD buffDomainSize = MAX_BUFF_SIZE;
SID_NAME_USE SidType;
if (LookupAccountSid(NULL, userSid, buffName, &buffNameSize, buffDomain, &buffDomainSize, &SidType)) {
return buffName;
} else {
DWORD dwResult = GetLastError();
printf("GetTokenInformation Error %u\n", dwResult);
}
/*Here some code to print error in a Message box*/
return "";
}
问题:代码有效,但在行 if (EqualSid(pSid, &g_pSID))调试器通过并跳过我从我的进程收到的 SID。换句话说,我无法从 ACL 列表中获取任何信息,即使我是 运行 进程并且 Visual Studio 在管理员帐户下(不使用 "Run as Administrator",而且我'我会尝试,但仍然......收到的 SID 是有效的,我可以使用上述函数获取进程所有者的名称。我在这里做错了什么?
代码来源:
https://gist.github.com/m4x1m1l14n/37f39c5d25855c2b1d3a6334851f7549
感谢@(Rita Han - MSFT) 的评论,我忘记从 pSID 比较中删除 & 符号
EqualSid(pSid, g_pSID);
而不是
EqualSid(pSid, &g_pSID);
并且目前可以正常工作