My Training Period: xx hours. Before you begin, read someinstruction here. This is continuation fromWindows Access Control Programming 12. All the program examples run in the Debug mode, the WinXp machine logged as normal/restricted user Mike, who is a member of Administrators group except whenever mentioned. Beware the codes that span more than one line.
Finding the Owner of a File Object
The following example uses theGetSecurityInfo() andLookupAccountSid() functions to find and print the name of the owner of a file. The file exists in the current working directory on the local machine.
// Finding the Owner of a File Object #include <windows.h> #include <stdio.h> #include <aclapi.h>
int main(int argc,char *argv[]) { DWORD dwRtnCode = 0; PSID pSidOwner; BOOL bRtnBool = TRUE; // Dummy initial value, no string... LPTSTR AcctName = "", DomainName = ""; DWORD dwAcctName = 1, dwDomainName = 1; // Dummy initial value, just use the defined one but unknown SID_NAME_USE eUse = SidTypeUnknown; HANDLE hFile; PSECURITY_DESCRIPTOR pSD;
// Get the handle of the file object. hFile = CreateFile( "D:\\testfile.doc", // The file name and the path if any GENERIC_READ, // Access right FILE_SHARE_READ, // Share mode NULL, // Security attribute for inherited or not by child OPEN_EXISTING, // Open the file, fail if not exist FILE_ATTRIBUTE_NORMAL,// file attribute flag, Normal NULL); // Handle to template file if GENERIC_READ right access
|
// Check GetLastError() for CreateFile()...
if(hFile == INVALID_HANDLE_VALUE)
{
printf("CreateFile() error = %d\n", GetLastError());
return -1;
}
else
printf("Handle to CreateFile() is OK\n");
// Allocate memory for the SID structure.
pSidOwner = (PSID)GlobalAlloc(GMEM_FIXED,sizeof(PSID));
// Allocate memory for the security descriptor structure.
pSD = (PSECURITY_DESCRIPTOR)GlobalAlloc(GMEM_FIXED,sizeof(PSECURITY_DESCRIPTOR));
// Get the owner SID of the file. Try for other object such as
// SE_SERVICE, SE_PRINTER, SE_REGISTRY_KEY, SE_KERNEL_OBJECT, SE_WINDOW_OBJECT etc.
// for 2nd parameter and 3rd parameter such as DACL_SECURITY_INFORMATION,
// GROUP_SECURITY_INFORMATION and SACL_SECURITY_INFORMATION
dwRtnCode = GetSecurityInfo(
hFile, // Handle to the file
SE_FILE_OBJECT, // Directory or file
OWNER_SECURITY_INFORMATION,// Owner information of the (file) object
&pSidOwner, // Pointer to the owner of the (file) object
NULL,
NULL,
NULL,
&pSD); // Pointer to the security descriptor of the (file) object
// Check GetLastError for GetSecurityInfo error condition.
if(dwRtnCode != ERROR_SUCCESS)
{
printf("GetSecurityInfo error = %d\n", GetLastError());
return -1;
}
else
printf("GetSecurityInfo() is OK\n");
// First call to LookupAccountSid() to get the buffer sizes AcctName.
bRtnBool = LookupAccountSid(
NULL, // Local computer
pSidOwner, // Pointer to the SID to lookup for
AcctName, // The account name of the SID (pSIDOwner)
(LPDWORD)&dwAcctName,// Size of the AcctName in TCHAR
DomainName, // Pointer to the name of the Domain where the account name was found
(LPDWORD)&dwDomainName, // Size of the DomainName in TCHAR
&eUse); // Value of the SID_NAME_USE enum type that specify the SID type
// Reallocate memory for the buffers.
AcctName = (char *)GlobalAlloc(GMEM_FIXED, dwAcctName);
// Check GetLastError() for GlobalAlloc() error condition.
if(AcctName == NULL)
{
printf("GlobalAlloc() error = %d\n", GetLastError());
return -1;
}
else
printf("Buffer allocation for AcctName is OK\n");
DomainName = (char *)GlobalAlloc(GMEM_FIXED, dwDomainName);
// Check GetLastError() for GlobalAlloc() error condition.
if(DomainName == NULL)
{
printf("GlobalAlloc() error = %d\n", GetLastError());
return -1;
}
else
printf("Buffer allocation for DomainName is OK\n");
// Second call to LookupAccountSid() to get the account name.
bRtnBool = LookupAccountSid(
NULL, // name of local or remote computer
pSidOwner, // security identifier, SID
AcctName, // account name buffer
(LPDWORD)&dwAcctName, // size of account name buffer
DomainName, // domain name
(LPDWORD)&dwDomainName, // size of domain name buffer
&eUse); // SID type
// Check GetLastError() for LookupAccountSid() error condition.
if(bRtnBool == FALSE)
{
DWORD dwErrorCode = 0;
dwErrorCode = GetLastError();
if(dwErrorCode == ERROR_NONE_MAPPED)
printf("Account owner not found for specified SID.\n");
else
{
printf("Error in LookupAccountSid().\n");
return -1;
}
} elseif (bRtnBool == TRUE)
// Print the account name.
printf("Account owner = %s\n", AcctName);
CloseHandle(hFile);
return 0;
}
A sample output:
Handle to CreateFile() is OK
GetSecurityInfo() is OK
Buffer allocation for AcctName is OK
Buffer allocation for DomainName is OK
Account owner = Mike
Press any key to continue
Verify through thetestfile.doc file property page and it confirmed that the owner is a local userMike.
Figure 3
Taking Object Ownership
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 theSE_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 testuser, a normal user. Then we create a folder namedTestfolder and verify the folder through the Testfolder property page as shown below.
![]() |
Figure 4
The previous figure shows the property page for theTestfolder directory. It confirmed that it is created by normal user,testuser.
Figure 5
Advanced property page for theTestfolder directory created by normal usertestuser that shows the permission.
Figure 6
Advanced property page for theTestfolder directory created by normal usertestuser that shows the owner.
Then we log off and re login asMike, a user that is a member of Administrators group. Mike tries to open the Testfolder but cannot. The following message was displayed.
Figure 7
So Mike run the following program to take the ownership of theTestfolder and then modify the DACL by addingEveryone group can write and Administrators group with full control.
// 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);
}
//************ Enabling/disabling 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;
LUID luid;
if(!LookupPrivilegeValue(
NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid)) // receives LUID of privilege
{
printf("LookupPrivilegeValue() of %s error: %u\n", lpszPrivilege, GetLastError());
return FALSE;
}
else
printf("LookupPrivilegeValue() of %s is OK\n", lpszPrivilege);
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
// Don't forget to disable the privilege after you enable them,
// don't mess up your system :-). Change the bEnablePrivilege to
// TRUE or FALSE to enable or disable the privilege respectively
if(bEnablePrivilege)
{
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
printf("tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED\n");
}
else
{
tp.Privileges[0].Attributes = 0;
printf("tp.Privileges[0].Attributes = 0\n");
}
// Enable the privilege (or disable all privileges).
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))
{
printf("AdjustTokenPrivileges() error: %u\n\n", GetLastError());
return FALSE;
}
else
{
printf("AdjustTokenPrivileges() is OK, last error if any: %u\n", GetLastError());
printf("Should be 0, means the operation completed successfully = ERROR_SUCCESS\n\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))
{
printf("AllocateAndInitializeSid() for Everyone group error %u\n", GetLastError());
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else
printf("AllocateAndInitializeSid() for Everyone group is OK\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))
{
printf("AllocateAndInitializeSid() for Administrators group error %u\n\n", GetLastError());
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else
printf("AllocateAndInitializeSid() for Administrators group is OK\n\n");
ZeroMemory(&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)
{
printf("SetEntriesInAcl() for Everyone and Administrators group is NOT OK\n");
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else
printf("SetEntriesInAcl() 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)
{
printf("SetNamedSecurityInfo()-Modifying the DACL is OK, return value: %u\n\n", dwRes);
printf("Successfully changed DACL\n");
// No more processing needed.
// Just return/exit
bRetval = TRUE;
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else if (dwRes == ERROR_ACCESS_DENIED)
{
printf("SetNamedSecurityInfo()-Modifying the DACL is NOT OK\n");
printf("If return value is 5, it is \"Access is denied\" (ERROR_ACCESS_DENIED)\n");
printf("Please 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))
{
printf("OpenProcessToken()-Getting the handle to access token failed: %u\n", GetLastError());
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else
printf("OpenProcessToken()-Getting the handle to access token is OK\n");
//**********************************************************************
// Enable the SE_TAKE_OWNERSHIP_NAME privilege.
if(!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME,TRUE))
{
// Verify the login
printf("You must be logged on as Administrator.\n");
printf("SetPrivilege()-Enable the SE_TAKE_OWNERSHIP_NAME privilege is NOT OK\n");
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else
{
printf("Your login credential is OK\n");
printf("SetPrivilege()-Enable the SE_TAKE_OWNERSHIP_NAME privilege is OK\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)
{
printf("SetNamedSecurityInfo()-Could not set the new owner, error: %u\n", dwRes);
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else
printf("SetNamedSecurityInfo()-Changing the owner is OK\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)
{
printf("SetNamedSecurityInfo()-Successfully changed the DACL\n");
bRetval = TRUE;
}
else
{
printf("SetNamedSecurityInfo()-Failed changing the DACL, return value: %u\n", dwRes);
}
//**********************************************************************
// Verify that the SE_TAKE_OWNERSHIP_NAME privilege is disabled.
if(SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME,FALSE))
{
printf("SetPrivilege()-Disable the SE_TAKE_OWNERSHIP_NAME privilege is OK.\n");
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else
{
printf("SetPrivilege()-Disable the SE_TAKE_OWNERSHIP_NAME privilege is NOT OK.\n");
printf("Or the privilege might be already disabled\n");
}
}
return bRetval;
}
//******* main() *******
int main()
{
LPTSTR lpszDir = "E:\\Testfolder";
BOOL test = TakeOwnership(lpszDir);
printf("\nTakeOwnership() return value: %u\n", test);
return 0;
}
A sample output:
AllocateAndInitializeSid() for Everyone group is OK
AllocateAndInitializeSid() for Administrators group is OK
SetEntriesInAcl() Everyone and Administrators group is OK
SetNamedSecurityInfo()-Modifying the DACL is NOT OK
If return value is 5, it is "Access is denied" (ERROR_ACCESS_DENIED)
Please get a proper permission!
OpenProcessToken()-Getting the handle to access token is OK
LookupPrivilegeValue() of SeTakeOwnershipPrivilege is OK
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED
AdjustTokenPrivileges() is OK, last error if any: 0
Should be 0, means the operation completed successfully = ERROR_SUCCESS
Your login credential is OK
SetPrivilege()-Enable the SE_TAKE_OWNERSHIP_NAME privilege is OK
SetNamedSecurityInfo()-Changing the owner is OK
SetNamedSecurityInfo()-Successfully changed the DACL
LookupPrivilegeValue() of SeTakeOwnershipPrivilege is OK
tp.Privileges[0].Attributes = 0
AdjustTokenPrivileges() is OK, last error if any: 0
Should be 0, means the operation completed successfully = ERROR_SUCCESS
SetPrivilege()-Disable the SE_TAKE_OWNERSHIP_NAME privilege is OK.
TakeOwnership() return value: 1
Press any key to continue
Well, let verify through theTestfolder property page. It seems that Mike successfully accomplished his mission!
Figure 8
Figure 9
Figure 10
-------------------------------Windows Access Control program examples, Part IV---------------------------
Further reading and digging:
For Multi-bytes, Unicode characters and Localization please refer to Locale, wide characters & Unicode (Story) and Windows users & groups programming tutorials (Implementation).
Structure, enum, union and typedef story can be foundC/C++ struct, enum, union & typedef.
Check the best selling C, C++ and Windows books at Amazon.com.
Microsoft C references, online MSDN.
Microsoft Visual C++, online MSDN.
ReactOS - Windows binary compatible OS - C/C++ source code repository, Doxygen.
Linux Access Control Lists (ACL) info can be found atAccess Control Lists.
Notation used in MSDN is Hungarian Notation instead of CamelCase and is discussedWindows programming notations.
Windows data type information is inWindows data types used in Win32 programming.