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));
Comments
Anonymous
April 23, 2009
This is concise, thorough, complete (with reference links) and easy to understand. What a super article. You good homieAnonymous
April 28, 2010
Hi, Great article, looks very good. I've stumbled onto something strange (it's me probably). When I add a user with for example Full Control, all is fine. When adding the same user again with Change, permissions do not change and remain Full control. The other way around works though. Adding a user with Change, then adding him a second with Full Control, all is well. Am I missing something here ? Thanks. Regards, MarcAnonymous
April 28, 2010
@Marc: I do not have time to investigate this, but if I remember how Windows security works, this may explain it. The order of SecurityDescriptor in the DACL array is important, you need to put the least restrictive permission before the most permissive permission. When you are doing it using Windows interface, the array is sorted properly, but when you are assigning the DACL yourself, you need to order it yourself. In your first case, I guess, you have full permission security descriptor before the more restrictive security descriptor. The OS checks the permission and when it sees that you have full permission, I think it stops there and quit, it does not need to search for more, as that account has full permission. On the second case, the OS sees that you have a restrictive permission and keep on checking until it finds all permission for this user. I hope that make sense.