NetShareGetInfo in C# to read Share Permissions of a File System Object


NetShareGetInfo is a C++ API to read the information of a shared resource (File System Object – FSO). This blog shows how to use this API in C# to read Share Permissions of a shared FSO. For more information on NetShareGetinfo, please go through the below link

http://msdn.microsoft.com/en-us/library/windows/desktop/bb525388(v=vs.85).aspx

I was working with WMI class Win32_Share to read the Share Permissions of a folder in C#. The class read NTFS Permissions successfully, however I was unable to find a way to read the actual Share Permissions of the folder using this WMI class.

I used C++ NetShareGetInfo API earlier to read Share Permissions of a folder and decided to use the same NetShareGetInfo API in my C# application. I wrote C# wrap-up for this API and that successfully read the Share Permissions. A sample of C# application to read Share Permissions of a shared folder using NetShareGetInfo  API is pasted below

  1: using System;
  2: using System.Collections.Generic;
  3: using System.Text;
  4: using System.Runtime.InteropServices;
  5: 
  6: class MainConsole
  7: {
  8:     [DllImport("Netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
  9:     static extern int NetShareGetInfo(
 10:         [MarshalAs(UnmanagedType.LPWStr)] string serverName,
 11:         [MarshalAs(UnmanagedType.LPWStr)] string netName,
 12:         Int32 level,
 13:         out IntPtr bufPtr);
 14: 
 15:     [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
 16:     [return: MarshalAs(UnmanagedType.Bool)]
 17:     static extern bool GetSecurityDescriptorDacl(
 18:         IntPtr pSecurityDescriptor,
 19:         [MarshalAs(UnmanagedType.Bool)] out bool bDaclPresent,
 20:         ref IntPtr pDacl,
 21:         [MarshalAs(UnmanagedType.Bool)] out bool bDaclDefaulted
 22:         );
 23: 
 24:     [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
 25:     [return: MarshalAs(UnmanagedType.Bool)]
 26:     static extern bool GetAclInformation(
 27:         IntPtr pAcl,
 28:         ref ACL_SIZE_INFORMATION pAclInformation,
 29:         uint nAclInformationLength,
 30:         ACL_INFORMATION_CLASS dwAclInformationClass
 31:      );
 32: 
 33:     [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
 34:     static extern int GetAce(
 35:         IntPtr aclPtr,
 36:         int aceIndex,
 37:         out IntPtr acePtr
 38:      );
 39: 
 40:     [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
 41:     static extern int GetLengthSid(
 42:         IntPtr pSID
 43:      );
 44: 
 45:     [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
 46:     [return: MarshalAs(UnmanagedType.Bool)]
 47:     static extern bool ConvertSidToStringSid(
 48:         [MarshalAs(UnmanagedType.LPArray)] byte[] pSID,
 49:         out IntPtr ptrSid
 50:      );
 51: 
 52:     [DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
 53:     static extern int NetApiBufferFree(
 54:         IntPtr buffer
 55:      );
 56: 
 57:     enum SID_NAME_USE
 58:     {
 59:         SidTypeUser = 1,
 60:         SidTypeGroup,
 61:         SidTypeDomain,
 62:         SidTypeAlias,
 63:         SidTypeWellKnownGroup,
 64:         SidTypeDeletedAccount,
 65:         SidTypeInvalid,
 66:         SidTypeUnknown,
 67:         SidTypeComputer
 68:     }
 69: 
 70:     [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
 71:     static extern bool LookupAccountSid(
 72:       string lpSystemName,
 73:       [MarshalAs(UnmanagedType.LPArray)] byte[] Sid,
 74:       System.Text.StringBuilder lpName,
 75:       ref uint cchName,
 76:       System.Text.StringBuilder ReferencedDomainName,
 77:       ref uint cchReferencedDomainName,
 78:       out SID_NAME_USE peUse);
 79: 
 80:     [StructLayout(LayoutKind.Sequential)]
 81:     struct SHARE_INFO_502
 82:     {
 83:         [MarshalAs(UnmanagedType.LPWStr)]
 84:         public string shi502_netname;
 85:         public uint shi502_type;
 86:         [MarshalAs(UnmanagedType.LPWStr)]
 87:         public string shi502_remark;
 88:         public Int32 shi502_permissions;
 89:         public Int32 shi502_max_uses;
 90:         public Int32 shi502_current_uses;
 91:         [MarshalAs(UnmanagedType.LPWStr)]
 92:         public string shi502_path;
 93:         public IntPtr shi502_passwd;
 94:         public Int32 shi502_reserved;
 95:         public IntPtr shi502_security_descriptor;
 96:     }
 97: 
 98:     [StructLayout(LayoutKind.Sequential)]
 99:     struct ACL_SIZE_INFORMATION
100:     {
101:         public uint AceCount;
102:         public uint AclBytesInUse;
103:         public uint AclBytesFree;
104:     }
105: 
106:     [StructLayout(LayoutKind.Sequential)]
107:     public struct ACE_HEADER
108:     {
109:         public byte AceType;
110:         public byte AceFlags;
111:         public short AceSize;
112:     }
113: 
114:     [StructLayout(LayoutKind.Sequential)]
115:     struct ACCESS_ALLOWED_ACE
116:     {
117:         public ACE_HEADER Header;
118:         public int Mask;
119:         public int SidStart;
120:     }
121: 
122:     enum ACL_INFORMATION_CLASS
123:     {
124:         AclRevisionInformation = 1,
125:         AclSizeInformation
126:     }
127: 
128: 
129: 
130:     static void Main(string[] args)
131:     {
132:         IntPtr bufptr = IntPtr.Zero;
133:         int err = NetShareGetInfo("ServerName", "ShareName", 502, out bufptr);
134:         if (0 == err)
135:         {
136:             SHARE_INFO_502 shareInfo = (SHARE_INFO_502)Marshal.PtrToStructure(bufptr, typeof(SHARE_INFO_502));
137: 
138:             bool bDaclPresent;
139:             bool bDaclDefaulted;
140:             IntPtr pAcl = IntPtr.Zero;
141:             GetSecurityDescriptorDacl(shareInfo.shi502_security_descriptor, out bDaclPresent, ref pAcl, out bDaclDefaulted);
142:             if (bDaclPresent)
143:             {
144:                 ACL_SIZE_INFORMATION AclSize = new ACL_SIZE_INFORMATION();
145:                 GetAclInformation(pAcl, ref AclSize, (uint)Marshal.SizeOf(typeof(ACL_SIZE_INFORMATION)), ACL_INFORMATION_CLASS.AclSizeInformation);
146:                 for (int i = 0; i < AclSize.AceCount; i++)
147:                 {
148:                     IntPtr pAce;
149:                     err = GetAce(pAcl, i, out pAce);
150:                     ACCESS_ALLOWED_ACE ace = (ACCESS_ALLOWED_ACE)Marshal.PtrToStructure(pAce, typeof(ACCESS_ALLOWED_ACE));
151: 
152:                     IntPtr iter = (IntPtr)((long)pAce + (long)Marshal.OffsetOf(typeof(ACCESS_ALLOWED_ACE), "SidStart"));
153:                     byte[] bSID = null;
154:                     int size = (int)GetLengthSid(iter);
155:                     bSID = new byte[size];
156:                     Marshal.Copy(iter, bSID, 0, size);
157:                     IntPtr ptrSid;
158:                     ConvertSidToStringSid(bSID, out ptrSid);
159:                     string strSID = Marshal.PtrToStringAuto(ptrSid);
160: 
161:                     Console.WriteLine("The details of ACE number {0} are: ", i+1);
162: 
163:                     StringBuilder name = new StringBuilder();
164:                     uint cchName = (uint)name.Capacity;
165:                     StringBuilder referencedDomainName = new StringBuilder();
166:                     uint cchReferencedDomainName = (uint)referencedDomainName.Capacity;
167:                     SID_NAME_USE sidUse;
168: 
169:                     LookupAccountSid(null, bSID, name, ref cchName, referencedDomainName, ref cchReferencedDomainName, out sidUse);
170: 
171:                     Console.WriteLine("Trustee Name: " + name);
172:                     Console.WriteLine("Domain Name: " + referencedDomainName);
173: 
174:                     if ((ace.Mask & 0x1F01FF) == 0x1F01FF)
175:                     {
176:                         Console.WriteLine("Permission: Full Control");
177:                     }
178:                     else if ((ace.Mask & 0x1301BF) == 0x1301BF)
179:                     {
180:                         Console.WriteLine("Permission: READ and CHANGE");
181:                     }
182:                     else if ((ace.Mask & 0x1200A9) == 0x1200A9)
183:                     {
184:                         Console.WriteLine("Permission: READ only");
185:                     }
186:                     Console.WriteLine("SID: {0} \nHeader AceType: {1} \nAccess Mask: {2} \nHeader AceFlag: {3}", strSID, ace.Header.AceType.ToString(), ace.Mask.ToString(), ace.Header.AceFlags.ToString());
187:                     Console.WriteLine("\n");
188:                 }
189:             }
190:             err = NetApiBufferFree(bufptr);
191:         }
192:     }
193: 
194: }
195: 
196: 

The first parameter of API is the server name and the second parameter is the shared resource name (folder).

Most of the work involved in writing the C# wrap-up for API and defining the structures for ACE flags and types. A sample output of the application is pasted below

The details of ACE number 1 are:
Trustee Name: UserName
Domain Name: DomainName
Permission: Full Control
SID: S-1-5-21-2146773085-903363285-719344707-359738
Header AceType: 0
Access Mask: 2032127
Header AceFlag: 0
Skip to main content