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";

Reply via email to