Editing Share Permission

In my previous post, I have shown you how to set up permission on a share. The thing with Win32_Share, when you set the permission, you basically overwrites the existing permission.

If you want to edit permission on the share (grant a new user access to the share, or revoke an existing user's permission), then you have to get the security descriptor for that share, and modify it, and then call Win32_Share.SetShareInfo to set the share permission.

To get security descriptor of a share, you can use Win32_LogicalShareSecuritySetting class. Then update the security descriptor and set that security descriptor back to the share.

When calling ManagementObject.GetSecurityDescriptor, it will return a ManagementBaseObject instance, it has two properties, ReturnValue and Descriptor. ReturnValue is an integer value, that tells you whether the operation is successful or not. Look for the possible value here. The Descriptor property is an instance of SecurityDescriptor.

To summarize (for those who love bullet points):

  • Get the Win32_Ace instance for the new user.
  • Get the current security descriptor.
  • Get the DACL (Array of Win32_Ace) from the security descriptor.
  • Add the Win32_Ace for the new user into the Win32_Ace array.
  • Reassign the edited DACL back to the security descriptor.
  • Call Win32_Share.SetShareInfo to set the permission.

You can delete a particular user, or changing the existing permission, by modifying the DACL or SACL in the Security Descriptor.

This snippet below is just an example on how to read, modify and assign permission on a share, this code was derived from the example on my previous post.

 //Create a new Win32_Ace instance. Please refer to my previous post about creating Win32_Ace.
NTAccount account = new NTAccount("contoso", "janedoe");
SecurityIdentifier sid = (SecurityIdentifier)account.Translate(typeof(SecurityIdentifier));
byte[] sidArray = new byte[sid.BinaryLength];
sid.GetBinaryForm(sidArray, 0);

ManagementObject Trustee = new ManagementClass(new ManagementPath("Win32_Trustee"), null);
Trustee["Domain"] = "contoso";
Trustee["Name"]   = "janedoe";
Trustee["SID"]   = sidArray; 

ManagementObject ACE = new ManagementClass(new ManagementPath("Win32_Ace"), null); 
ACE["AccessMask"] = 2032127; 
ACE["AceFlags"]   = 3; 
ACE["AceType"]    = 0; 
ACE["Trustee"]    = Trustee; 

//After we have the new Win_32Ace, now we need to get the existing Ace instances (DACL).
//Create an instance of Win32_LogicalSecuritySetting, set the path to the server and the share.
ManagementObject Win32LogicalSecuritySetting = new ManagementObject(@"\\ContosoServer\root\cimv2:Win32_LogicalShareSecuritySetting.Name='JohnShare'");

//Call the GetSecurityDescriptor method. This method returns one out parameter.
ManagementBaseObject Return = Win32LogicalSecuritySetting.InvokeMethod("GetSecurityDescriptor", null, null);
    
//The return value of that call above has two properties, ReturnValue, which you can use
//to read the status of the call (failed, success, etc.), and Descriptor, which is an instance
//of Win32_SecurityDescriptor.
Int32 ReturnValue = Convert.ToInt32(Return.Properties["ReturnValue"].Value);

if (ReturnValue != 0)
    throw new Exception(String.Format("Error when calling GetSecurityDescriptor. Error code : {0}.", ReturnValue));

//Retrieve the array of DACL from the Security Descriptor.
ManagementBaseObject SecurityDescriptor = Return.Properties["Descriptor"].Value as ManagementBaseObject;
ManagementBaseObject[] DACL = SecurityDescriptor["DACL"] as ManagementBaseObject[];

if (DACL == null)
    DACL = new ManagementBaseObject[] { ACE };
else
{
    Array.Resize(ref DACL, DACL.Length + 1);
    DACL[DACL.Length - 1] = ACE;
}

//Reassign the new DACL array with the new user Ace back to the Win32_SecurityDescriptor instance, and call the
//SetSecurityDescriptor method.
SecurityDescriptor["DACL"] = DACL;

ManagementObject Share = new ManagementObject(@"\\ContosoServer\root\cimv2:Win32_Share.Name='JohnShare'");
ReturnValue = Convert.ToInt32(Share.InvokeMethod("SetShareInfo", new object[] {Int32.MaxValue, "This is John's share", SecurityDescriptor})); 

if (ReturnValue != 0)
    throw new Exception(String.Format("Error when calling GetSecurityDescriptor. Error code : {0}.", ReturnValue));