Win32 API: 正在为当前用户创建文件 public 但对其他人私有
Win32 API: Creating file public for current user but private for everyone else
我正在使用 Win32 API 在 C 语言中测试以下代码,目的是创建一个新文件,该文件可供当前用户访问,但对其他所有人私有(不可访问)。
为此我拒绝了所有人 SID 的所有权限,然后为当前的用户 SID 设置了权限。
文件创建成功,权限显然设置成功(见下面的截图),但是当我尝试用记事本打开文件时,它显示"access is denied"(我的文件浏览器是运行 在同一会话下),如果我打开命令提示符并执行 "type file_created.txt" 相同的 "access is denied" 出现。
我当然可以手动恢复权限,因为我是管理员,但我的想法是让它以编程方式工作。
具有所有人权限的图像:
当前用户权限的图像:
代码:
#include <windows.h>
#include <AccCtrl.h>
#include <aclapi.h>
#include <stdio.h>
#include <stdexcept>
#include <string>
#undef UNICODE
int GetCurrentUserSid(PSID* pSID)
{
const int MAX_NAME = 256;
DWORD i, dwSize = 0;
HANDLE hToken;
PTOKEN_USER user;
TOKEN_INFORMATION_CLASS TokenClass = TokenUser;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ | TOKEN_QUERY, &hToken))
return GetLastError();
else
wprintf(L"OpenProcessToken() - got the handle to the access token!\n");
if (!GetTokenInformation(hToken, TokenClass, NULL, 0, &dwSize))
{
DWORD dwResult = GetLastError();
if (dwResult != ERROR_INSUFFICIENT_BUFFER)
{
wprintf(L"GetTokenInformation() failed, error %u\n", dwResult);
return FALSE;
}
else
wprintf(L"GetTokenInformation() - have an ample buffer...\n");
}
else
wprintf(L"GetTokenInformation() - buffer for Token group is OK\n");
user = (PTOKEN_USER)LocalAlloc(GPTR, dwSize);
if (!GetTokenInformation(hToken, TokenClass, user, dwSize, &dwSize))
{
wprintf(L"GetTokenInformation() failed, error %u\n", GetLastError());
return FALSE;
}
else
wprintf(L"GetTokenInformation() for getting the TokenGroups is OK\n");
DWORD dw_sid_len = GetLengthSid(user->User.Sid);
*pSID = (SID*)LocalAlloc(GPTR, dw_sid_len);
CopySid(dw_sid_len, *pSID, user->User.Sid);
return 0;
}
DWORD set_file_security(LPSTR filename)
{
PACL pNewDACL = NULL;
PSID current_user = NULL;
DWORD sid_size = SECURITY_MAX_SID_SIZE;
SID everyone_sid;
DWORD dwRes;
if (CreateWellKnownSid(WinWorldSid, NULL, &everyone_sid, &sid_size) ==
FALSE) {
throw std::runtime_error("CreateWellKnownSid() failed: " +
std::to_string(GetLastError()));
}
GetCurrentUserSid(¤t_user);
EXPLICIT_ACCESSA ea[2];
ZeroMemory(&ea, 2 * sizeof(EXPLICIT_ACCESSA));
ea[0].grfAccessPermissions = ACCESS_SYSTEM_SECURITY | READ_CONTROL | WRITE_DAC | GENERIC_ALL;
ea[0].grfAccessMode = GRANT_ACCESS;
ea[0].grfInheritance = NO_INHERITANCE;
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.ptstrName = reinterpret_cast<char*>(current_user);
ea[1].grfAccessPermissions = ACCESS_SYSTEM_SECURITY | READ_CONTROL | WRITE_DAC | GENERIC_ALL;
ea[1].grfAccessMode = DENY_ACCESS;
ea[1].grfInheritance = NO_INHERITANCE;
ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[1].Trustee.ptstrName = reinterpret_cast<char*>(&everyone_sid);
dwRes = SetEntriesInAclA(2, ea, NULL, &pNewDACL);
if (ERROR_SUCCESS != dwRes) {
printf("SetEntriesInAcl Error %u\n", dwRes);
//TODO: goto Cleanup;
}
PSECURITY_DESCRIPTOR pSD = NULL;
// Initialize a security descriptor.
pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
SECURITY_DESCRIPTOR_MIN_LENGTH);
if (NULL == pSD)
{
_tprintf(_T("LocalAlloc Error %u\n"), GetLastError());
goto Cleanup;
}
if (!InitializeSecurityDescriptor(pSD,
SECURITY_DESCRIPTOR_REVISION))
{
_tprintf(_T("InitializeSecurityDescriptor Error %u\n"),
GetLastError());
goto Cleanup;
}
// Add the ACL to the security descriptor.
if (!SetSecurityDescriptorDacl(pSD,
TRUE, // bDaclPresent flag
pNewDACL,
FALSE)) // not a default DACL
{
_tprintf(_T("SetSecurityDescriptorDacl Error %u\n"),
GetLastError());
goto Cleanup;
}
SECURITY_ATTRIBUTES sa;
// Initialize a security attributes structure.
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE;
HANDLE hFile = CreateFileA(filename, GENERIC_ALL, 0, &sa, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
CloseHandle(hFile);
//dwRes = SetNamedSecurityInfoA(filename, SE_FILE_OBJECT,
// DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL);
//if (ERROR_SUCCESS != dwRes) {
// printf("SetNamedSecurityInfo Error %u\n", dwRes);
// //goto Cleanup;
//}
Cleanup:
if (pNewDACL != NULL)
LocalFree((HLOCAL)pNewDACL);
return dwRes;
}
int main()
{
//return 0;
// Create Everyone SID.
DWORD sid_size = SECURITY_MAX_SID_SIZE;
SID everyone_sid;
if (CreateWellKnownSid(WinWorldSid, NULL, &everyone_sid, &sid_size) ==
FALSE) {
throw std::runtime_error("CreateWellKnownSid() failed: " +
std::to_string(GetLastError()));
}
LPSTR filename = "created_file.txt";
set_file_security(filename);
return 0;
}
注意:我意识到代码存在内存泄漏和其他问题,我只是快速修改以测试这个想法。
在 Windows OS 中,显式拒绝权限优先于显式允许权限。因此,由于 "Everyone" 组包含您的帐户,因此即使您为自己启用了该文件,访问该文件也会被拒绝。事实上你完全不需要拒绝规则,如果某些用户的对象ACL中没有设置访问权限,默认情况下访问将被拒绝。
我正在使用 Win32 API 在 C 语言中测试以下代码,目的是创建一个新文件,该文件可供当前用户访问,但对其他所有人私有(不可访问)。
为此我拒绝了所有人 SID 的所有权限,然后为当前的用户 SID 设置了权限。
文件创建成功,权限显然设置成功(见下面的截图),但是当我尝试用记事本打开文件时,它显示"access is denied"(我的文件浏览器是运行 在同一会话下),如果我打开命令提示符并执行 "type file_created.txt" 相同的 "access is denied" 出现。
我当然可以手动恢复权限,因为我是管理员,但我的想法是让它以编程方式工作。
具有所有人权限的图像:
当前用户权限的图像:
代码:
#include <windows.h>
#include <AccCtrl.h>
#include <aclapi.h>
#include <stdio.h>
#include <stdexcept>
#include <string>
#undef UNICODE
int GetCurrentUserSid(PSID* pSID)
{
const int MAX_NAME = 256;
DWORD i, dwSize = 0;
HANDLE hToken;
PTOKEN_USER user;
TOKEN_INFORMATION_CLASS TokenClass = TokenUser;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ | TOKEN_QUERY, &hToken))
return GetLastError();
else
wprintf(L"OpenProcessToken() - got the handle to the access token!\n");
if (!GetTokenInformation(hToken, TokenClass, NULL, 0, &dwSize))
{
DWORD dwResult = GetLastError();
if (dwResult != ERROR_INSUFFICIENT_BUFFER)
{
wprintf(L"GetTokenInformation() failed, error %u\n", dwResult);
return FALSE;
}
else
wprintf(L"GetTokenInformation() - have an ample buffer...\n");
}
else
wprintf(L"GetTokenInformation() - buffer for Token group is OK\n");
user = (PTOKEN_USER)LocalAlloc(GPTR, dwSize);
if (!GetTokenInformation(hToken, TokenClass, user, dwSize, &dwSize))
{
wprintf(L"GetTokenInformation() failed, error %u\n", GetLastError());
return FALSE;
}
else
wprintf(L"GetTokenInformation() for getting the TokenGroups is OK\n");
DWORD dw_sid_len = GetLengthSid(user->User.Sid);
*pSID = (SID*)LocalAlloc(GPTR, dw_sid_len);
CopySid(dw_sid_len, *pSID, user->User.Sid);
return 0;
}
DWORD set_file_security(LPSTR filename)
{
PACL pNewDACL = NULL;
PSID current_user = NULL;
DWORD sid_size = SECURITY_MAX_SID_SIZE;
SID everyone_sid;
DWORD dwRes;
if (CreateWellKnownSid(WinWorldSid, NULL, &everyone_sid, &sid_size) ==
FALSE) {
throw std::runtime_error("CreateWellKnownSid() failed: " +
std::to_string(GetLastError()));
}
GetCurrentUserSid(¤t_user);
EXPLICIT_ACCESSA ea[2];
ZeroMemory(&ea, 2 * sizeof(EXPLICIT_ACCESSA));
ea[0].grfAccessPermissions = ACCESS_SYSTEM_SECURITY | READ_CONTROL | WRITE_DAC | GENERIC_ALL;
ea[0].grfAccessMode = GRANT_ACCESS;
ea[0].grfInheritance = NO_INHERITANCE;
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.ptstrName = reinterpret_cast<char*>(current_user);
ea[1].grfAccessPermissions = ACCESS_SYSTEM_SECURITY | READ_CONTROL | WRITE_DAC | GENERIC_ALL;
ea[1].grfAccessMode = DENY_ACCESS;
ea[1].grfInheritance = NO_INHERITANCE;
ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[1].Trustee.ptstrName = reinterpret_cast<char*>(&everyone_sid);
dwRes = SetEntriesInAclA(2, ea, NULL, &pNewDACL);
if (ERROR_SUCCESS != dwRes) {
printf("SetEntriesInAcl Error %u\n", dwRes);
//TODO: goto Cleanup;
}
PSECURITY_DESCRIPTOR pSD = NULL;
// Initialize a security descriptor.
pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
SECURITY_DESCRIPTOR_MIN_LENGTH);
if (NULL == pSD)
{
_tprintf(_T("LocalAlloc Error %u\n"), GetLastError());
goto Cleanup;
}
if (!InitializeSecurityDescriptor(pSD,
SECURITY_DESCRIPTOR_REVISION))
{
_tprintf(_T("InitializeSecurityDescriptor Error %u\n"),
GetLastError());
goto Cleanup;
}
// Add the ACL to the security descriptor.
if (!SetSecurityDescriptorDacl(pSD,
TRUE, // bDaclPresent flag
pNewDACL,
FALSE)) // not a default DACL
{
_tprintf(_T("SetSecurityDescriptorDacl Error %u\n"),
GetLastError());
goto Cleanup;
}
SECURITY_ATTRIBUTES sa;
// Initialize a security attributes structure.
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE;
HANDLE hFile = CreateFileA(filename, GENERIC_ALL, 0, &sa, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
CloseHandle(hFile);
//dwRes = SetNamedSecurityInfoA(filename, SE_FILE_OBJECT,
// DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL);
//if (ERROR_SUCCESS != dwRes) {
// printf("SetNamedSecurityInfo Error %u\n", dwRes);
// //goto Cleanup;
//}
Cleanup:
if (pNewDACL != NULL)
LocalFree((HLOCAL)pNewDACL);
return dwRes;
}
int main()
{
//return 0;
// Create Everyone SID.
DWORD sid_size = SECURITY_MAX_SID_SIZE;
SID everyone_sid;
if (CreateWellKnownSid(WinWorldSid, NULL, &everyone_sid, &sid_size) ==
FALSE) {
throw std::runtime_error("CreateWellKnownSid() failed: " +
std::to_string(GetLastError()));
}
LPSTR filename = "created_file.txt";
set_file_security(filename);
return 0;
}
注意:我意识到代码存在内存泄漏和其他问题,我只是快速修改以测试这个想法。
在 Windows OS 中,显式拒绝权限优先于显式允许权限。因此,由于 "Everyone" 组包含您的帐户,因此即使您为自己启用了该文件,访问该文件也会被拒绝。事实上你完全不需要拒绝规则,如果某些用户的对象ACL中没有设置访问权限,默认情况下访问将被拒绝。