Welcome to MSDN Blogs Sign in | Join | Help

Programmatically Configuring Permissions on a Share

I was asked this problem on how to set up permission for a share programmatically using .Net Framework. Well, I am not aware of any API that can do that. Searching does not return any good result. There are lot of resources on how to configure permission settings for local folder, but not so much for UNC path. At the end, I dug msdn and had my solution, using WMI.

To setup a share, you need these information, the share that you want to setup (securable or trustee), whom you will give the permissions to the share (principal), what kind of permissions you want to give.

Using this scenario, you have a share \\ContosoServer\JohnShare, and you want John Doe (contoso\johndoe) to have full access to this share. The steps to configure the share permissions are as follow:

  • Create a WMI instance of the principal (Win32_Trustee).
    //Getting the Sid value is not required for Vista.
    NTAccount
    account = newNTAccount(Domain, UserName);
    SecurityIdentifiersid = (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"]   = "johndoe";

    Trustee["SID"]    = sidArray;
  • Create a WMI instance of Win32_Ace, assign the Trustee to this Win32_Ace instance.
    ManagementObject AdminACE = new ManagementClass(new ManagementPath("Win32_Ace"), null);
    AdminACE["AccessMask"] = 2032127;
    AdminACE["AceFlags"]   = 3;
    AdminACE["AceType"]    = 0;
    AdminACE["Trustee"]    = Trustee;

    To know what values you need to put there, check msdn (link). I actually encourage you to write an enum flag to encapsulate those values.
    In nut shell, 2032127 is for full access, Access Flags 3 is for non-container and container child objects to inherit the ACE, and Ace Type 0 is to allow the trustee to access it.
  • Create a WMI instance of the security descriptor (Win32_SecurityDescriptor)
    ManagementObject secDescriptor = new ManagementClass(new ManagementPath("Win32_SecurityDescriptor"), null);
    secDescriptor["ControlFlags"] = 4; //SE_DACL_PRESENT
    secDescriptor["DACL"] = new object[] { AdminACE};
  • Now, create a WMI instance of Win32_Share, and setup the security.
    ManagementObject share = new ManagementObject(@"\\ContosoServer\root\cimv2:Win32_Share.Name='JohnShare'");
    share.InvokeMethod("SetShareInfo", new object[] {Int32.MaxValue, "This is John's share", secDescriptor});
    Check the return value of the Invoke, the method returns an Object, convert it to Int32.

That code will overwrite the existing permission, so be careful. WMI stuff are available in System.Management assemblies.

For references, these are the links that you will be interested with, Win32_Trustee, Win32_ACE, Win32_SecurityDescriptor, and Win32_Share.

Update (6/9/2008)

I updated the first step with the code to assign Sid, thanks to David Smith for his email. With Windows Vista, you do not need to supply Sid. You can supply just the domain name and the user name, it will work. Using Server 2003, and most likely XP, you have to supply all three, user name, domain, and Sid.

Published Friday, June 06, 2008 6:38 PM by HelloWorld

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# re: Programmatically Configuring Permissions on a Share in C#

Wow! I can't tell you how grateful I am to have found your How-To. I've been banging my head against the wall on this all morning and the docs have been of little help. I did follow the link and create an enum for AccessMask, but none of the listed values are 2032127. Is this the sum of several values?

I sure wish we could improve those docs.

Sunday, June 08, 2008 7:32 AM by flipdoubt

# re: Programmatically Configuring Permissions on a Share in C#

Just to clarify, I realize the docs say you have to add them together, but coming up with the right combination (as you did here) requires a few more steps.

Sunday, June 08, 2008 7:51 AM by flipdoubt

# re: Programmatically Configuring Permissions on a Share in C#

One last question, this works for individual users but does not seem to work for groups. Does anything need to be different to configure group permissions?

Thanks.

Sunday, June 08, 2008 8:22 AM by flipdoubt

# re: Programmatically Configuring Permissions on a Share in C#

My bad. It works. Just having a devil of a time picking out the right AccessMask.

Again, great tip.

Sunday, June 08, 2008 8:40 AM by flipdoubt

# re: Programmatically Configuring Permissions on a Share in C#

You are welcome. :)

Thanks for your feedback about enum value 2032127, you are correct, that value is sum of several enum values. I am going to write another post on that next week.

Sunday, June 08, 2008 12:50 PM by HelloWorld

# re: Programmatically Configuring Permissions on a Share in C#

The code you provided for configuring the trustee works for local accounts by not for domain accounts. To create both local and domain permissions, I set the SID as follows, where domain and accountName are strings for the obvious values.

NTAccount ntAccount = new NTAccount(domain, accountName);

SecurityIdentifier sid = (SecurityIdentifier) ntAccount.Translate(typeof(SecurityIdentifier));

byte[] sidArray = new byte[sid.BinaryLength];

sid.GetBinaryForm(sidArray, 0);

ManagementObject trustee = new ManagementClass(new                      ManagementPath("Win32_Trustee"), null);

trustee["SID"] = sidArray;

Sunday, June 08, 2008 1:30 PM by flipdoubt

# re: Programmatically Configuring Permissions on a Share in C#

Sid is required when the code is executed on Windows Server 2003, Vista does not require Sid property to be assigned.

On Server 2003, you have to supply all, only Sid won't assign the permission correctly.

Monday, June 09, 2008 2:36 PM by HelloWorld

# Common AccessMask value when Configuring Share Permission Programmatically

In my previous post , I have shown you how to modify share permission using .Net framework. Access Mask

Monday, June 09, 2008 7:31 PM by You had me at "Hello World"

# re: Programmatically Configuring Permissions on a Share

Hi

I have been able to CHANGE the EVERYONE to any user or group that I want but I am not being able to ADD another user/group to my share list.

example: Administrators Full controll and domainname\user full control. (not talking NTFS) just shares permissions.

I wonder if you could help me out.

Thursday, June 26, 2008 5:54 AM by foxer

# re: Programmatically Configuring Permissions on a Share

Hello foxer,

I can try to help you out. Please be aware that SetShareInfo will overwrite the security descriptor, so you cannot really add permissions, you define a new security permission.

In order for you to define a full access for Admin and a domain user, what you have to do is to create two instances of Win32_Ace objects like what I have shown you in this blog, let us call it AdminAce and UserAce.

When you create Win32_SecurityDescriptor, create it like this:

ManagementObject secDescriptor = new ManagementClass(new ManagementPath("Win32_SecurityDescriptor"), null);
secDescriptor["ControlFlags"] = 4; //SE_DACL_PRESENT
secDescriptor["DACL"] = new object[] { AdminAce, UserAce};  

Pass both Win32_Ace objects to the DACL property.

Thursday, June 26, 2008 12:14 PM by HelloWorld

# re: Programmatically Configuring Permissions on a Share

Hi Thanks

It worked. At last! I should have thought of it.

Friday, June 27, 2008 3:11 AM by foxer

# re: Programmatically Configuring Permissions on a Share

Great article!

I was interested in getting the list of User,Permission pairs, like in the Sharing->Permissions menu. I've tried using the 'GetAccessMask' in Win32_Share, but that only shows your current computer's access. The idea I had was to get the list of all domain-user/group pairs, then impersonate and use GetAccessmask, but that seems awful. If you had any ideas, I'd be grateful :)

Thursday, July 03, 2008 3:55 PM by tomato

# re: Programmatically Configuring Permissions on a Share

Thanks for your comment, tomato.

That is a great idea for the next article, I do not have time to work on it at this moment, but I will.

Thursday, July 10, 2008 12:17 PM by HelloWorld

# Editing Share Permission

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

Tuesday, July 22, 2008 2:19 AM by You had me at "Hello World"

# re: Programmatically Configuring Permissions on a Share

Hey, if i have to give multiple users permission to the share.How should this be done

Sunday, December 07, 2008 11:39 PM by Bhargavi Venkatesh

# re: Programmatically Configuring Permissions on a Share

Hi Bhargavi,

Each users must be represented by an ace.  Create Trustee for each users, and then assign each trustee to its own ace.

Then when creating security descriptor, assign those aces to the DACL property.  For example:

secDescriptor["DACL"] = new object[] { AdminACE, YourACE, MyAce, ThirdPersonAce };

Monday, December 08, 2008 12:42 AM by HelloWorld

# re: Programmatically Configuring Permissions on a Share

Great post!

I keep getting error in this line:

ManagementObject share = new ManagementObject(@"\\MyRemoteServer\root\cimv2:Win32_Share.Name='TestShare'");

If not my share name TestShare is equals to the shared folder name.

Any ideas how to solve this problem ?

Best Regards subtile

Friday, February 20, 2009 10:02 AM by subtile

# re: Programmatically Configuring Permissions on a Share

@Subtile: What is the error? Is the share on a different machine or on the same machine?

Friday, February 20, 2009 11:13 AM by HelloWorld

# re: Programmatically Configuring Permissions on a Share

Hi!

Thanks for the post, this is really helpful.  However, I'm having some trouble in the following scenario:

In a home network, user A and B are in the same workgroup, but on different machine.  A wants to allow user B (on a different machine) to share a folder residing on user A's machine.

Is there a way to do this?  Both machines run windows XP, with only workgroups, no domains.

--kim

Wednesday, March 25, 2009 10:31 PM by kim

# re: Programmatically Configuring Permissions on a Share

@Kim.

Give this a try.

B must have an account on machine A, and B must be an admin. B's account on both machines must have identical password.

Thursday, April 02, 2009 5:08 PM by HelloWorld

# re: Programmatically Configuring Permissions on a Share

Hi

Could you tell me how to share a folder to everyone instead of a specific user?

Thanks!

Tuesday, July 07, 2009 3:57 PM by David B

# re: Programmatically Configuring Permissions on a Share

@David B:

If you need Everyone to have read-only access, then what you need to do is to set DACL to null.

secDescriptor["DACL"] = null;

This will give everyone a read access.

If you need to give 'Everyone' read-write access, then you have to create the Win32_Trustee, using WellKnownSidType enum. I need to check my note again about this. I will put this for my next blog post.

Give this a try, when creating Trustee object, try to use 'NT Authority\Everyone'

ManagementObject Trustee = new ManagementClass(new ManagementPath("Win32_Trustee"), null);

Trustee["Domain"] = "NT Authority";

Trustee["Name"]   = "Everyone";

Tuesday, July 07, 2009 5:15 PM by HelloWorld

# re: Programmatically Configuring Permissions on a Share

@HelloWorld

Thanks for the reply. This works on my Vista machine, but it doesn't work on Windows Server 2003. Any thoughts? Here is what I have for code.

protected void CreateShare(string path, string shareName)
{
   // Create a ManagementClass object
   ManagementClass managementClass = new ManagementClass("Win32_Share");
   // Create ManagementBaseObjects for in and out parameters
   ManagementBaseObject inParams = managementClass.GetMethodParameters("Create");
   ManagementBaseObject outParams;
   // Set the input parameters
   inParams["Description"] = "IdeaServer";
   inParams["Name"] = shareName;
   inParams["Path"] = path;
   inParams["Type"] = 0x0; // Disk Drive
   //Another Type:
   //        DISK_DRIVE = 0x0
   //        PRINT_QUEUE = 0x1
   //        DEVICE = 0x2
   //        IPC = 0x3
   //        DISK_DRIVE_ADMIN = 0x80000000
   //        PRINT_QUEUE_ADMIN = 0x80000001
   //        DEVICE_ADMIN = 0x80000002
   //        IPC_ADMIN = 0x8000003
   //inParams["MaximumAllowed"] = int maxConnectionsNum;
   // Invoke the method on the ManagementClass object
   inParams["Access"] = SecurityDescriptor();
   outParams = managementClass.InvokeMethod("Create", inParams, null);
   // Check to see if the method invocation was successful
   uint rVal = (uint)(outParams.Properties["ReturnValue"].Value);
   if (rVal != 0 && rVal != 22) // ok if it already exists
   {
       throw new Exception("Unable to share directory.");
   }
}

private static ManagementBaseObject SecurityDescriptor()
{
   NTAccount account = new NTAccount("NT Authority", "Everyone");
   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"] = "NT Authority";
   Trustee["Name"] = "Everyone";
   Trustee["SID"] = sidArray;
   ManagementObject AdminACE = new ManagementClass(new ManagementPath("Win32_Ace"), null);
   AdminACE["AccessMask"] = 2032127;
   AdminACE["AceFlags"] = 3;
   AdminACE["AceType"] = 0;
   AdminACE["Trustee"] = Trustee;
   ManagementObject SecurityDescriptor = new ManagementClass(new ManagementPath("Win32_SecurityDescriptor"), null);
   SecurityDescriptor["ControlFlags"] = 4; //SE_DACL_PRESENT
   SecurityDescriptor["DACL"] = new object[] { AdminACE };
   return SecurityDescriptor;
}

Thanks a lot!

David

Wednesday, July 08, 2009 9:45 AM by David B

# re: Programmatically Configuring Permissions on a Share

@David:

Try this, update your code from

ManagementObject Trustee = new ManagementClass(new ManagementPath("Win32_Trustee"), null);

Trustee["Domain"] = "NT Authority";

Trustee["Name"] = "Everyone";

Trustee["SID"] = sidArray;

to

SecurityIdentifier Sec = new SecurityIdentifier(System.Security.Principal.WellKnownSidType.WorldSid, null);

byte[] sidArray = new byte[Sec.BinaryLength];

Sec.GetBinaryForm(sidArray, 0);

ManagementObject Trustee = new ManagementClass(new ManagementPath("Win32_Trustee"), null);

Trustee["SID"] = sidArray;

Thursday, July 09, 2009 1:17 PM by HelloWorld

# re: Programmatically Configuring Permissions on a Share

@HelloWorld

Thanks! That worked perfectly!

Tuesday, July 14, 2009 10:56 AM by David B

# re: Programmatically Configuring Permissions on a Share

How do you update the share permissions on an already created share? For example add a new user to the share etc

Saturday, August 29, 2009 10:26 PM by Aditya Bhave

# re: Programmatically Configuring Permissions on a Share

Saturday, August 29, 2009 10:58 PM by HelloWorld

Leave a Comment

(required) 
required 
(required) 

  
Enter Code Here: Required
 
Page view tracker