In an effort to automate LAN account creation I have designed a Perl script that will take specific information that is input by a user and create a "personal drive" on a network storage device and the automatically set the permissions on the folder so that the user can access it.
Unfortunately, I am running into issue with not correctly adding the new ACE back to the existing security descriptor. I have found that it is unnecessary to create an array of the existing ACEs as they are all inherited and will be repopulated if a new array of the single new ACE is added. If anyone has any experience with using WMI to set folder permissions in Perl ANY and ALL advice is welcome as I have reached a dead end with every solution I try. Here is the following applicable code for what I am attempting to accomplish:
use Win32::OLE::Variant;
$Win32::OLE::Warn = 3;
# ACE access mask, flag, and type constants
our $ADS_ACCESSMASK_READ_WRITE_EXECUTE_DELETE = -536805376;
our $ADS_ACCESSMASK_FULL = 268435456;
our $ADS_ACEFLAG_UNKNOWN = 0x1;
our $ADS_ACEFLAG_INHERIT_ACE = 0x2;
our $ADS_ACEFLAG_INHERITED_ACE = 0x10;
our $ADS_ACETYPE_ACCESS_ALLOWED = 0;
our $ADS_ACETYPE_ACCESS_DENIED = 0x1;
our $ADS_ACETYPE_ACCESS_ALLOWED_OBJECT = 0x5;
our $ADS_ACETYPE_ACCESS_DENIED_OBJECT = 0x6;
our $NTFS_MODIFY = 0x1245631;
our $NTFS_FULL_CONTROL = 0x2032127;
# get a SWbemLocator object
my $objLocator = Win32::OLE->new('WbemScripting.SWbemLocator') or
die "can't create locator object: ".Win32::OLE->LastError( )."\n";
# set the impersonate level to "impersonate"
$objLocator->{Security_}->{impersonationlevel} = 3;
$objLocator->{Security_}->{Privileges}->AddAsString("seRestorePrivileg
+e");
my $server = "servername.domain.com";
# use it to get a an SWbemServices object
my $objServices = $objLocator->ConnectServer($server, 'root\cimv2') or
+
die "can't create server object: ".Win32::OLE->LastError( )."\n";
my $path = "d:\\userdata\\user";
print "Win32_LogicalFileSecuritySetting.Path='$path'\n";
my $objDirectorySecSetting = $objServices->Get("Win32_LogicalFileSecur
+itySetting.Path='$path'");
my $objSecDescriptor = Win32::OLE::Variant-> new (VT_DISPATCH|VT_BYREF
+);
my $retval = $objDirectorySecSetting->GetSecurityDescriptor($objSecDes
+criptor);
# Get the Win32_SecurityDescriptor from the variant.
my $sd = $objSecDescriptor->Get();
print "$sd\n";
# Get the ACL, which is just an array of Win32_ACE objects.
my @dacl = @{$sd->{'DACL'}};
#open local wmi instance
my $wmi = Win32::OLE->GetObject('WinMgmts:{impersonationlevel=imperson
+ate}!root/cimv2');
my $strName = "USER";
my $strDomain = "DOMAIN";
#create instance of Win32_Account bound to user (doing this so we can
+get the user's SID)
my $account = $wmi->Get('Win32_Account.Domain=\'' . $strDomain . '\',N
+ame=\'' . $strName . '\'');
#create instance of Win32_SID populated using account instance from ab
+ove, this lets us get SID in different formats
my $accountSID = Win32::OLE->GetObject('Winmgmts:{impersonationlevel=i
+mpersonate}!root/cimv2:Win32_SID.SID=\'' . $account->SID . '\'');
#create instance of Win32_Trustee and populate (note: uses Sid instanc
+e from above)
my $objTrustee = $wmi->Get("Win32_Trustee")->SpawnInstance_;
$objTrustee->{Domain} = $strDomain;
$objTrustee->{Name} = $strName;
$objTrustee->{SID} = $accountSID->BinaryRepresentation;
#Create instance of Win32_Ace and populate values (note: uses trustee
+instance from above)
my $newACE = $wmi->Get("Win32_Ace").Spawninstance_;
$newACE->{AccessMask} = $NTFS_MODIFY;
$newACE->{AceFlags} = $ADS_ACEFLAG_UNKNOWN | $ADS_ACEFLAG_INHERIT_ACE;
$newACE->{AceType} = $ADS_ACETYPE_ACCESS_ALLOWED;
$newACE->{Trustee} = $objTrustee;
my $ACEArray;
#Add the newACE above to the ACEArray
push(@$ACEArray,$newACE);
print "New ACE list:\n";
foreach my $ace (@ACEArray)
{
$trustee = $ace->{'Trustee'};
$acetype = $ace->{'AceType'};
$aceflag = $ace->{'AceFlags'};
$acemask = $ace->{'AccessMask'};
$name = $trustee->{'Name'};
print "Name: $name\n";
print "$acetype\n";
print "$aceflag\n";
print "$acemask\n";
}
# Replace the DACL with the ACEArray containing the new ACE
$sd->{DACL} = $ACEArray;
#Write DACL back to security descriptor of the folder
my $retval = $objDirectorySecSetting->SetSecurityDescriptor($sd);
My main issue occurs when attempting to write the new security descriptor back out to the folder. Is this a WMI issue or a Perl issue also?
Thanks,
Derek