Taking the Object Ownership Program Example
The following example tries to change the DACL of a file object by taking ownership of that object. This will succeed only if the caller has WRITE_DAC access to the object or is the owner of the object. If the initial attempt to change the DACL fails, an administrator can take ownership of the object. To give the administrator ownership, the example enables the SE_TAKE_OWNERSHIP_NAME privilege in the caller's access token, and makes the local system's Administrators group the new owner of the object. If the caller is a member of the Administrators group, the code will then be able to change the object's DACL. Firstly we login as usergedik, a normal user. Then we create a folder named UserGedikDir and verify the folder through the UserGedikDir property page as shown below.
The previous figure shows the property page for the UserGedikDir directory. It is confirmed that it is created by normal user, usergedik.
The Advanced property page for the UserGedikDir directory shows that the file was created by normal user, usergedik which of course the owner. To make thing 'worse' we remove all the permissions except usergedik.
Un-tick the Inherit from parent the permission entries that apply to the child object. Include these with entries explicitly defined here tick box.
Click Remove button for the following Security message box.
Then, only user usergedik has the full control of the folder.
Then, add the usergedik user for the permission.
Then we log off and re login as Mike spoon, a user that is a member of Administrators group. Mike as Administrators group when trying to open (double click) the folder (owned solely by usergedik), was denied the access.
When opening the folder's property page, the following security alert should be displayed.
The Security page does not show any user. Click the Advanced button.
The Permission of the Advanced page also does not show any user or group.
The owner also cannot be displayed. All this thing happened because Administrators group (which include Mike spoon) has been denied the access to the folder.
Then, Mike spoon run the following program to take the ownership of the UserGedikDir and then modify the DACL by adding Everyone group can write and Administrators group with full control.
Create a new empty Win32 console application project. Give a suitable project name and change the project location if needed.
Then, add the source file and give it a suitable name.
Next, add the following source code.
// Taking object ownership
#include <windows.h>
#include <stdio.h>
#include <accctrl.h>
#include <aclapi.h>
//****** Cleanup routine *******
void Cleanup(PSID pSIDAdmin, PSID pSIDEveryone, PACL pACL, HANDLE hToken)
{
if(pSIDAdmin)
FreeSid(pSIDAdmin);
if(pSIDEveryone)
FreeSid(pSIDEveryone);
if(pACL)
LocalFree(pACL);
if(hToken)
CloseHandle(hToken);
}
//************ Enable/disable the privilege ****************
BOOL SetPrivilege(
HANDLE hToken, // access token handle
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
BOOL bEnablePrivilege // to enable (or disable privilege)
)
{
TOKEN_PRIVILEGES tp = {0};
LUID luid;
if(!LookupPrivilegeValue(
NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid)) // receives LUID of privilege
{
wprintf(LLookupPrivilegeValue() failed, error %u\n, GetLastError());
return FALSE;
}
else
wprintf(LLookupPrivilegeValue() - %s privilege found!\n, lpszPrivilege);
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
// Don't forget to disable the privilege after you enable them,
// Change the bEnablePrivilege to TRUE or FALSE to enable or
// disable the privilege respectively
if(bEnablePrivilege)
{
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
wprintf(LPrivilege was enabled!\n);
}
else
{
tp.Privileges[0].Attributes = 0;
wprintf(LPrivilege was disabled!\n);
}
// Adjust the privilege
if(!AdjustTokenPrivileges(
hToken,
FALSE, // If TRUE, function disables all privileges,
//if FALSE the function modifies privileges based on the tp
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NULL,
(PDWORD) NULL))
{
wprintf(LAdjustTokenPrivileges() failed, error: %u\n, GetLastError());
return FALSE;
}
else
{
wprintf(LAdjustTokenPrivileges() - token privilege was adjusted!\n);
return TRUE;
}
}
//***** Take ownership routine ******
BOOL TakeOwnership(LPTSTR lpszDir)
{
// Return value
BOOL bRetval = FALSE;
// Handle to token
HANDLE hToken = NULL;
// Pointer to SID for Administrators group
PSID pSIDAdmin = NULL;
// Pointer to SID for Everyone group
PSID pSIDEveryone = NULL;
// Pointer to access control list
PACL pACL = NULL;
SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
const int NUM_ACCESS = 2;
// Explicit access arrays structure. Here only two entries. Change the array size for more entries
EXPLICIT_ACCESS ea[NUM_ACCESS];
// Result
DWORD dwRes;
// Specify the DACL to use. Allow write for Everyone and full
// control for Administrators group. Create a SID for the Everyone group.
if(!AllocateAndInitializeSid(&SIDAuthWorld, 1,
SECURITY_WORLD_RID,
0,
0, 0, 0, 0, 0, 0,
&pSIDEveryone))
{
wprintf(LAllocateAndInitializeSid() - Failed to allocate and initilize Everyone SID, error %u\n, GetLastError());
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else
wprintf(LAllocateAndInitializeSid() - Everyone SID was allocated and initialized!\n);
// 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))
{
wprintf(LAllocateAndInitializeSid() - failed to allocate and initialize Administrators group SID, error %u\n, GetLastError());
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else
wprintf(LAllocateAndInitializeSid() - Administrators group SID was allocated and initialized!\n);
SecureZeroMemory(&ea, NUM_ACCESS * sizeof(EXPLICIT_ACCESS));
//***************** EXPLICIT ACCESS structure ******************
// Construct the structure, add other entries as needed by
// changing the array size. Set write access for Everyone.
ea[0].grfAccessPermissions = GENERIC_WRITE;
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(SetEntriesInAcl(NUM_ACCESS, ea, NULL, &pACL) != ERROR_SUCCESS)
{
wprintf(LSetEntriesInAcl() for Everyone and Administrators group failed, error %u\n, GetLastError());
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else
wprintf(LSetEntriesInAcl() for Everyone and Administrators group is OK\n);
//***************************************************************
// Try to modify the object's DACL.
dwRes = SetNamedSecurityInfo(
lpszDir, // name of the object
SE_FILE_OBJECT, // type of object, directory
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)
{
wprintf(LSetNamedSecurityInfo()-Modifying the DACL is OK!\n);
// No more processing needed. Just return/exit
bRetval = TRUE;
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else if (dwRes == ERROR_ACCESS_DENIED)
{
wprintf(LSetNamedSecurityInfo()-Modifying the DACL failed! Error %u\n, dwRes);
wprintf(LPlease get a proper permission!\n\n);
// If the previous 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
// that is the currently login access token
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
wprintf(LOpenProcessToken() failed, error %u\n, GetLastError());
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else
wprintf(LOpenProcessToken()-Got the handle to access token!\n);
//**********************************************************************
// Enable the SE_TAKE_OWNERSHIP_NAME privilege.
if(!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, TRUE))
{
// Verify the login
wprintf(LYou must logged on as Administrator.\n);
wprintf(LSetPrivilege()-Enable the SE_TAKE_OWNERSHIP_NAME privilege failed, error %u\n, GetLastError());
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else
{
wprintf(LYour login credential is fine!\n);
wprintf(LSetPrivilege()-The SE_TAKE_OWNERSHIP_NAME privilege was enabled!\n);
}
//*********************************************************************
// Set the new owner in the object's security descriptor.
dwRes = SetNamedSecurityInfo(
lpszDir, // 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)
{
wprintf(LSetNamedSecurityInfo()-Could not set the new owner, error: %u\n, dwRes);
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else
wprintf(LSetNamedSecurityInfo()-The owner was changed successfully!\n);
//***********************************************************************
// Try again to modify the object's DACL, now that we are the owner.
dwRes = SetNamedSecurityInfo(
lpszDir, // 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)
{
wprintf(LSetNamedSecurityInfo()-The DACL was successfully changed!\n);
bRetval = TRUE;
}
else
{
wprintf(LSetNamedSecurityInfo()-Failed to change the DACL, error %u\n, dwRes);
}
//**********************************************************************
// Verify that the SE_TAKE_OWNERSHIP_NAME privilege is disabled.
if(SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, FALSE))
{
wprintf(LSetPrivilege()-The SE_TAKE_OWNERSHIP_NAME privilege was disabled!\n);
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else
{
wprintf(LSetPrivilege()-Failed to disable the SE_TAKE_OWNERSHIP_NAME privilege!\n);
wprintf(LOr the privilege might be already disabled, error %u\n, GetLastError());
}
}
return bRetval;
}
//***** wmain() *******
int wmain(int argc, WCHAR **argv)
{
LPTSTR lpszDir = L\\\\?\\C:\\UserGedikDir;
wprintf(L\n);
BOOL bRetVal = TakeOwnership(lpszDir);
wprintf(L\nTakeOwnership() returns %u\n\n, bRetVal);
return 0;
}
Build and run the project. The following screenshot is a sample output.
Well, let verify through the UserGedikDir property page. It seems that Mike spoon successfully accomplished his mission!