This may come as a shock, but I would probably use WMI instead.
Below is a Perl script which takes a file or directory as argument and
enumerates the ACL on it. It also removes any ACL entry whose name is
"patl", just for kicks...
The only trouble I had was figuring out the Win32::OLE::Variant stuff
to deal with the call-by-reference semantics of GetSecurityDescriptor.
Sane people might expect a method named "GetSecurityDescriptor" to
return, well, a security descriptor. But not Microsoft.
Anyway, you should be able to use similar code to do whatever you are
trying to do. In particular, see the AceFlags property of Win32_ACE.
- Pat
P.S. Admittedly, this is one example where the WMI interface does not
necessarily result in simpler code :-).
use warnings;
use strict;
use Win32::OLE;
use Win32::OLE::Variant;
# Bomb out completely if COM engine encounters any trouble.
Win32::OLE->Option ('Warn' => 3);
my $path = $ARGV[0];
defined $path
or die "Usage: $0 <filename>\n";
# Get a handle to the SWbemServices object of the local machine.
my $computer = Win32::OLE->GetObject ('WinMgmts:');
# Get the Win32_LogicalFileSecuritySetting for the path.
#
<http://msdn.microsoft.com/library/en-us/wmisdk/wmi/win32_logicalfilesecuritysetting.asp>
my $sec_setting = $computer->Get
("Win32_LogicalFileSecuritySetting.Path='$path'");
# Ask the security setting object for the security descriptor. The
# stupid call-by-reference interface forces us to use a "Variant"
# object here.
my $var = Win32::OLE::Variant->new (VT_DISPATCH|VT_BYREF);
my $ret = $sec_setting->GetSecurityDescriptor ($var);
$ret == 0
or die "Unable to GetSecurityDescriptor; error $ret";
# Get the Win32_SecurityDescriptor from the variant.
# <http://msdn.microsoft.com/library/en-us/wmisdk/wmi/win32_securitydescriptor.asp>
my $sd = $var->Get();
# Get the ACL, which is just an array of Win32_ACE objects.
# <http://msdn.microsoft.com/library/en-us/wmisdk/wmi/win32_ace.asp>
my @dacl = @{$sd->{'DACL'}};
# Iterate through the ACL, printing some stuff and remembering those
# whose Trustee is not named "patl".
# <http://msdn.microsoft.com/library/en-us/wmisdk/wmi/win32_trustee.asp>
my @new_dacl;
foreach my $ace (@dacl) {
my $trustee = $ace->{'Trustee'};
my $domain = $trustee->{'Domain'};
defined $domain
and print "Domain: $domain ";
my $name = $trustee->{'Name'};
print "Name: $name ";
printf "Perms: 0x%x", $ace->{'AccessMask'};
print "\n";
$name eq 'patl'
or push @new_dacl, $ace;
}
# If we aren't making any changes, exit now.
scalar @dacl == scalar @new_dacl
and exit 0;
$sd->{'DACL'} = \@new_dacl;
$ret = $sec_setting->SetSecurityDescriptor ($sd);
$ret == 0
or die "Unable to SetSecurityDescriptor; error $ret";