C++에서 개체 소유권 가져오기
다음 예제에서는 해당 개체의 소유권을 가져와서 파일 개체의 DACL을 변경하려고 합니다. 호출자가 개체에 대한 WRITE_DAC 액세스 권한이 있거나 개체의 소유자인 경우에만 성공합니다. DACL을 변경하려는 초기 시도가 실패하면 관리자가 개체의 소유권을 가져올 수 있습니다. 관리자 소유권을 부여하기 위해 이 예제에서는 호출자의 액세스 토큰에서 SE_TAKE_OWNERSHIP_NAME 권한을 사용하도록 설정하고 로컬 시스템의 Administrators 그룹을 개체의 소유자로 만듭니다. 호출자가 Administrators 그룹의 구성원인 경우 코드는 개체의 DACL을 변경할 수 있습니다.
이 예제에서는 권한을 사용하거나 사용하지 않도록 설정하기 위해 C++에서 권한 사용 및 사용 안 함에서 설명한 SetPrivilege 샘플 함수를 사용합니다.
#include <windows.h>
#include <stdio.h>
#include <accctrl.h>
#include <aclapi.h>
//Forward declaration of SetPrivilege
BOOL SetPrivilege(
HANDLE hToken, // access token handle
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
BOOL bEnablePrivilege // to enable or disable privilege
) ;
BOOL TakeOwnership(LPTSTR lpszOwnFile)
{
BOOL bRetval = FALSE;
HANDLE hToken = NULL;
PSID pSIDAdmin = NULL;
PSID pSIDEveryone = NULL;
PACL pACL = NULL;
SID_IDENTIFIER_AUTHORITY SIDAuthWorld =
SECURITY_WORLD_SID_AUTHORITY;
SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
const int NUM_ACES = 2;
EXPLICIT_ACCESS ea[NUM_ACES];
DWORD dwRes;
// Specify the DACL to use.
// Create a SID for the Everyone group.
if (!AllocateAndInitializeSid(&SIDAuthWorld, 1,
SECURITY_WORLD_RID,
0,
0, 0, 0, 0, 0, 0,
&pSIDEveryone))
{
printf("AllocateAndInitializeSid (Everyone) error %u\n",
GetLastError());
goto Cleanup;
}
// 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))
{
printf("AllocateAndInitializeSid (Admin) error %u\n",
GetLastError());
goto Cleanup;
}
ZeroMemory(&ea, NUM_ACES * sizeof(EXPLICIT_ACCESS));
// Set read access for Everyone.
ea[0].grfAccessPermissions = GENERIC_READ;
ea[0].grfAccessMode = SET_ACCESS;
ea[0].grfInheritance = NO_INHERITANCE;
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ea[0].Trustee.ptstrName = (LPTSTR) pSIDEveryone;
// Set full control for Administrators.
ea[1].grfAccessPermissions = GENERIC_ALL;
ea[1].grfAccessMode = SET_ACCESS;
ea[1].grfInheritance = NO_INHERITANCE;
ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
ea[1].Trustee.ptstrName = (LPTSTR) pSIDAdmin;
if (ERROR_SUCCESS != SetEntriesInAcl(NUM_ACES,
ea,
NULL,
&pACL))
{
printf("Failed SetEntriesInAcl\n");
goto Cleanup;
}
// Try to modify the object's DACL.
dwRes = SetNamedSecurityInfo(
lpszOwnFile, // name of the object
SE_FILE_OBJECT, // type of object
DACL_SECURITY_INFORMATION, // change only the object's DACL
NULL, NULL, // do not change owner or group
pACL, // DACL specified
NULL); // do not change SACL
if (ERROR_SUCCESS == dwRes)
{
printf("Successfully changed DACL\n");
bRetval = TRUE;
// No more processing needed.
goto Cleanup;
}
if (dwRes != ERROR_ACCESS_DENIED)
{
printf("First SetNamedSecurityInfo call failed: %u\n",
dwRes);
goto Cleanup;
}
// 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))
{
printf("OpenProcessToken failed: %u\n", GetLastError());
goto Cleanup;
}
// Enable the SE_TAKE_OWNERSHIP_NAME privilege.
if (!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, TRUE))
{
printf("You must be logged on as Administrator.\n");
goto Cleanup;
}
// Set the owner in the object's security descriptor.
dwRes = SetNamedSecurityInfo(
lpszOwnFile, // 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)
{
printf("Could not set owner. Error: %u\n", dwRes);
goto Cleanup;
}
// Disable the SE_TAKE_OWNERSHIP_NAME privilege.
if (!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, FALSE))
{
printf("Failed SetPrivilege call unexpectedly.\n");
goto Cleanup;
}
// Try again to modify the object's DACL,
// now that we are the owner.
dwRes = SetNamedSecurityInfo(
lpszOwnFile, // name of the object
SE_FILE_OBJECT, // type of object
DACL_SECURITY_INFORMATION, // change only the object's DACL
NULL, NULL, // do not change owner or group
pACL, // DACL specified
NULL); // do not change SACL
if (dwRes == ERROR_SUCCESS)
{
printf("Successfully changed DACL\n");
bRetval = TRUE;
}
else
{
printf("Second SetNamedSecurityInfo call failed: %u\n",
dwRes);
}
Cleanup:
if (pSIDAdmin)
FreeSid(pSIDAdmin);
if (pSIDEveryone)
FreeSid(pSIDEveryone);
if (pACL)
LocalFree(pACL);
if (hToken)
CloseHandle(hToken);
return bRetval;
}