Share via


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

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