Network share permissions with WMI

M

mail

Hi guys,

So far I've spent about a week hacking away at this code, and I just
can't get it to add an ACE to a the DACL for a network share using WMI.

Just to set the scene, I'm trying to add an ACL from machine A
(workstation; Saturn) and set it to a UNC path
(\\Mercury\Inetpub\Websites\LocalUser\Test) on machine B (server;
Mercury).

Neither of these machines are on a domain, and the trustee for the new
ACL is a local user on machine B (server; Mercury), lets call him
'test' for now.

I don't want to use xcacls because it's a bit of a hack, and the ADSI
code from Microsoft looks a little offputting as it uses COM
(http://support.microsoft.com/kb/899553/EN-US/).

At this point I'm able to use the following code to apply permissions
to a local resource on machine A (e.g. C:\Test), however when I try it
on a UNC path it throws a ManagementException with the message "Not
Found", which isn't very useful.

I can only presume it's complaing about the UNC path. I've tried
doubling up the slashes, and just having single slashes (which makes no
difference).

// Works when server name is ".", "SATURN" but not "MERCURY".
ManagementScope scope = new ManagementScope(@"\\" + ServerName +
@"\root\cimv2");

// Works when fileName is local directory, but not UNC path.
ManagementPath path = new ManagementPath();
path.RelativePath = @"Win32_LogicalFileSecuritySetting.Path="
+ "'" + fileName + "'";

ManagementObject fileSecurity = new ManagementObject(
scope, path, null);

// When used with UNC path, exception with "Not Found" is thrown.
ManagementBaseObject outParams =
(ManagementBaseObject)fileSecurity.InvokeMethod(
"GetSecurityDescriptor", null, null);

// Get security descriptor and DACL for specified file.
ManagementBaseObject descriptor =
(ManagementBaseObject)outParams.Properties["Descriptor"].Value;
ManagementBaseObject[] dacl =
(ManagementBaseObject[])descriptor.Properties["Dacl"].Value;

// Get the user account to be trustee.
ManagementObject userAccount = new ManagementClass(scope,
new ManagementPath("Win32_Trustee"), null);
userAccount.Properties["Name"].Value = account;

// Create a new ACE for the descriptor.
ManagementObject newAce = new ManagementClass(scope,
new ManagementPath("Win32_ACE"), null);
newAce.Properties["Trustee"].Value = userAccount;

// Low level ace flags.
int FILE_READ_DATA = 0x0;
int FILE_WRITE_DATA = 0x1;
int FILE_APPEND_DATA = 0x4;
int DELETE = 0x10000;

// Translate FileSystemRights to flags.
switch (accessRights)
{
case FileSystemRights.Read:
newAce.Properties["AccessMask"].Value = FILE_READ_DATA;
break;

case FileSystemRights.Modify:
newAce.Properties["AccessMask"].Value = FILE_READ_DATA
| FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE;
break;
}

// ACL will be inherited.
newAce.Properties["AceFlags"].Value = 0x10;

// Allow access to resource.
newAce.Properties["AceType"].Value = 0;

// Add ACE to DACL and set to descriptor.
ArrayList daclArray = new ArrayList(dacl);
daclArray.Add(newAce);

descriptor.Properties["Dacl"].Value = daclArray.ToArray();

// User SetSecurityDescriptor to apply the descriptor.
ManagementBaseObject inParams =
fileSecurity.GetMethodParameters("SetSecurityDescriptor");
inParams["Descriptor"] = descriptor;
fileSecurity.InvokeMethod("SetSecurityDescriptor", inParams, null);
 
W

Willy Denoyette [MVP]

If you connect to MERCURY using ManagementScope, you are effectively
accessing MERCURY's local drives. That means that you should specify the
local path and not a UNC path when executing path.RelativePath =
@"Win32_LogicalFileSecuritySetting.Path=...

If you need to set the ACL's on the "share" you need to query the share
using it's name and look for it's associated
Win32_LogicalShareSecuritySetting. Once you have this one you can set the
security for the share using the same technique as for a local filz objzct.


Willy.



| Hi guys,
|
| So far I've spent about a week hacking away at this code, and I just
| can't get it to add an ACE to a the DACL for a network share using WMI.
|
| Just to set the scene, I'm trying to add an ACL from machine A
| (workstation; Saturn) and set it to a UNC path
| (\\Mercury\Inetpub\Websites\LocalUser\Test) on machine B (server;
| Mercury).
|
| Neither of these machines are on a domain, and the trustee for the new
| ACL is a local user on machine B (server; Mercury), lets call him
| 'test' for now.
|
| I don't want to use xcacls because it's a bit of a hack, and the ADSI
| code from Microsoft looks a little offputting as it uses COM
| (http://support.microsoft.com/kb/899553/EN-US/).
|
| At this point I'm able to use the following code to apply permissions
| to a local resource on machine A (e.g. C:\Test), however when I try it
| on a UNC path it throws a ManagementException with the message "Not
| Found", which isn't very useful.
|
| I can only presume it's complaing about the UNC path. I've tried
| doubling up the slashes, and just having single slashes (which makes no
| difference).
|
| // Works when server name is ".", "SATURN" but not "MERCURY".
| ManagementScope scope = new ManagementScope(@"\\" + ServerName +
| @"\root\cimv2");
|
| // Works when fileName is local directory, but not UNC path.
| ManagementPath path = new ManagementPath();
| path.RelativePath = @"Win32_LogicalFileSecuritySetting.Path="
| + "'" + fileName + "'";
|
| ManagementObject fileSecurity = new ManagementObject(
| scope, path, null);
|
| // When used with UNC path, exception with "Not Found" is thrown.
| ManagementBaseObject outParams =
| (ManagementBaseObject)fileSecurity.InvokeMethod(
| "GetSecurityDescriptor", null, null);
|
| // Get security descriptor and DACL for specified file.
| ManagementBaseObject descriptor =
| (ManagementBaseObject)outParams.Properties["Descriptor"].Value;
| ManagementBaseObject[] dacl =
| (ManagementBaseObject[])descriptor.Properties["Dacl"].Value;
|
| // Get the user account to be trustee.
| ManagementObject userAccount = new ManagementClass(scope,
| new ManagementPath("Win32_Trustee"), null);
| userAccount.Properties["Name"].Value = account;
|
| // Create a new ACE for the descriptor.
| ManagementObject newAce = new ManagementClass(scope,
| new ManagementPath("Win32_ACE"), null);
| newAce.Properties["Trustee"].Value = userAccount;
|
| // Low level ace flags.
| int FILE_READ_DATA = 0x0;
| int FILE_WRITE_DATA = 0x1;
| int FILE_APPEND_DATA = 0x4;
| int DELETE = 0x10000;
|
| // Translate FileSystemRights to flags.
| switch (accessRights)
| {
| case FileSystemRights.Read:
| newAce.Properties["AccessMask"].Value = FILE_READ_DATA;
| break;
|
| case FileSystemRights.Modify:
| newAce.Properties["AccessMask"].Value = FILE_READ_DATA
| | FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE;
| break;
| }
|
| // ACL will be inherited.
| newAce.Properties["AceFlags"].Value = 0x10;
|
| // Allow access to resource.
| newAce.Properties["AceType"].Value = 0;
|
| // Add ACE to DACL and set to descriptor.
| ArrayList daclArray = new ArrayList(dacl);
| daclArray.Add(newAce);
|
| descriptor.Properties["Dacl"].Value = daclArray.ToArray();
|
| // User SetSecurityDescriptor to apply the descriptor.
| ManagementBaseObject inParams =
| fileSecurity.GetMethodParameters("SetSecurityDescriptor");
| inParams["Descriptor"] = descriptor;
| fileSecurity.InvokeMethod("SetSecurityDescriptor", inParams, null);
|
 
N

Nick @ Rensoft

Hi Willy,

Sorry, I just realised that share security exists as well as file
security. I actually meant altering a Win32_LogicalFileSecuritySetting
through a UNC path.

I'm trying to produce the software in such a way that it will run
completely over UNC and not local file paths. This is so I can develop
on a workstation using a virtual server for testing. But then, roll the
application out on to a production server. I'd like to avoid using
local file paths to keep everything simple... Is a good idea?

Also, I tried accessing the Win32_LogicalFileSecuritySetting via a UNC
path, without specifying a server and it threw the same "Not Found"
error as before.

Perhaps you could show me a snippet of code to enumerate the DACL via a
UNC path?

Thanks Willy.

Nick
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top