I've been attempting to use WMI to remove an access control entry (ACE) from the discretionary access control list (DACL) associated with a local printer in Windows 7. The code gets the security descriptor, and iterates through all the ACEs in the DACL. Unless the trustee in the ALE is named "Everyone", the ACE is added to a temporary list.
The temporary list is turned into an array, and replaces the DACL property of the security descriptor. The code then calls SetSecurityDescriptor() with the modified descriptor.
The return value is 0x8007051B, with 0x051B being the Win32 error code: 1307, This security ID may not be assigned as the owner of this object.
The error message is a bit confusing, as nowhere in the code am I (intentionally) changing the owner of the printer.
If I change the method to include every ACE in the temporary list, the call to SetSecurityDescriptor() completes successfully.
Running the application as Administrator makes no difference.
And, of course, the code:
private void ChangeSecurity()
{
var query = String.Format("SELECT * from Win32_Printer where Name like \"%{0}%\"", PrinterName);
var searcher = new ManagementObjectSearcher(query);
var searchResults = searcher.Get();
foreach (ManagementObject printer in searchResults)
{
var result = printer.InvokeMethod("GetSecurityDescriptor", null, null);
var descriptor = (ManagementBaseObject)result["Descriptor"];
var flags = (uint)descriptor["ControlFlags"];
if ((flags & (uint)ControlFlags.DiscretionaryAclPresent) == (uint)ControlFlags.DiscretionaryAclPresent)
{
Console.WriteLine("DACL present");
var dacl = (ManagementBaseObject[])descriptor["DACL"];
var newDaclList = new List<ManagementBaseObject>();
foreach (var ace in dacl)
{
var trustee = (ManagementBaseObject)ace["Trustee"];
var aceType = (uint)ace["AceType"];
if ((aceType & (uint) AceType.AccessAllowed) == (uint) AceType.AccessAllowed)
{
Console.WriteLine("{0}\\{1}", trustee["Domain"], trustee["Name"]);
Console.WriteLine("Access mask {0}", ace["AccessMask"]);
if (trustee["Name"].ToString() == "Everyone" && trustee["Domain"] == null)
{
Console.WriteLine("Remove access");
}
else
{
newDaclList.Add(ace);
}
}
}
descriptor.SetPropertyValue("DACL", newDaclList.ToArray());
var inParams = printer.GetMethodParameters("SetSecurityDescriptor");
inParams["Descriptor"] = descriptor;
result = printer.InvokeMethod("SetSecurityDescriptor", inParams, null);
Console.WriteLine("Result code: {0}", result["ReturnValue"]);
}
}