2010-01-12 249 views
7

我用这个代码共享文件夹:共享文件夹权限!

Public Sub Share() 
     Dim managementClass As New ManagementClass("Win32_Share") 
     Dim inParams As ManagementBaseObject = managementClass.GetMethodParameters("Create") 
     inParams("Description") = "My Description" 
     inParams("Name") = "Share Name" 
     inParams("Path") = "D:\Folder" 
     inParams("Type") = &H0 
     Dim outParams As ManagementBaseObject = managementClass.InvokeMethod("Create", inParams, Nothing) 
     If Convert.ToUInt32(outParams.Properties("ReturnValue").Value) <> 0 Then MessageBox.Show("Unable to share directory.") 
     MessageBox.Show("Shared folder successfully!") 
    End 
Sub 

现在,我要的是定义用户可以通过网络访问此文件夹? 我该怎么做?

谢谢!

+1

这是一个有点复杂,但是这应该让你开始:http://hamidshahid.blogspot.com/2009/03/adding-permissions-to-共享folder.html – Heinzi 2010-01-12 15:06:23

回答

0

下面请查找NetShare的类似代码,但是这次所有代码都在C#中。 它也正确处理ACL指针的LocalFree(); 用法很简单:

NetShare.Add(pathToShare, shareName, description, sharePermissions); 
NetShare.DeleteIfExist(shareName); 

public class NetShare 
{ 
    #region PInvoke functions, enums and structs 

    [DllImport("netapi32.dll")] 
    private static extern NET_API_STATUS NetShareAdd(
     [In, MarshalAs(UnmanagedType.LPWStr)] string strServer, 
     [In] Int32 dwLevel, 
     [In] ref SHARE_INFO_502 buf, 
     [Out] out uint parm_err); 

    [DllImport("netapi32.dll")] 
    private static extern NET_API_STATUS NetShareDel(
     [In, MarshalAs(UnmanagedType.LPWStr)] string strServer, 
     [In, MarshalAs(UnmanagedType.LPWStr)] string netName, 
     Int32 dwReserved); 

    [DllImport("advapi32.dll", SetLastError = true)] 
    private static extern bool InitializeSecurityDescriptor(
     [Out] out SECURITY_DESCRIPTOR SecurityDescriptor, 
     [In] uint dwRevision); 

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern uint SetEntriesInAcl(
     int cCountOfExplicitEntries, 
     [In] ref EXPLICIT_ACCESS pListOfExplicitEntries, 
     [In] IntPtr OldAcl, 
     out IntPtr NewAcl); 

    [DllImport("advapi32.dll", SetLastError = true)] 
    private static extern bool SetSecurityDescriptorDacl(
     [In] ref SECURITY_DESCRIPTOR sd, 
     [In] bool daclPresent, 
     IntPtr dacl, 
     [In] bool daclDefaulted); 

    [DllImport("advapi32.dll", SetLastError = true)] 
    private static extern bool IsValidSecurityDescriptor(
     [In] ref SECURITY_DESCRIPTOR sd); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    private static extern IntPtr LocalFree(IntPtr hMem); 

    private enum NET_API_STATUS : uint 
    { 
     NERR_Success = 0, 
     ERROR_ACCESS_DENIED = 5, 
     ERROR_NOT_ENOUGH_MEMORY = 8, 
     ERROR_INVALID_PARAMETER = 87, 
     ERROR_INVALID_NAME = 123, 
     ERROR_INVALID_LEVEL = 124, 
     ERROR_MORE_DATA = 234, 
     NERR_BASE = 2100, 
     NERR_UnknownDevDir = (NERR_BASE + 16), 
     NERR_RedirectedPath = (NERR_BASE + 17), 
     NERR_DuplicateShare = (NERR_BASE + 18), 
     NERR_BufTooSmall = (NERR_BASE + 23), 
     NERR_NetNameNotFound = (NERR_BASE + 210) // Sharename not found 
    } 

    private enum SHARE_TYPE : uint 
    { 
     STYPE_DISKTREE = 0, 
     STYPE_PRINTQ = 1, 
     STYPE_DEVICE = 2, 
     STYPE_IPC = 3, 
     STYPE_TEMPORARY = 0x40000000, 
     STYPE_SPECIAL = 0x80000000, 
    } 

    private enum SHARE_PERMISSIONS : uint 
    { 
     ACCESS_NONE = 0, 
     ACCESS_READ = 1, 
     ACCESS_WRITE = 2, 
     ACCESS_CREATE = 4, 
     ACCESS_EXEC = 8, 
     ACCESS_DELETE = 0x10, 
     ACCESS_ATRIB = 0x20, 
     ACCESS_PERM = 0x40, 
     ACCESS_ALL = ACCESS_READ | ACCESS_WRITE | ACCESS_CREATE | ACCESS_EXEC | ACCESS_DELETE | ACCESS_ATRIB | ACCESS_PERM, 
     ACCESS_GROUP = 0x8000 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    private struct SHARE_INFO_502 
    { 
     [MarshalAs(UnmanagedType.LPWStr)] 
     public string shi502_netname; 
     public SHARE_TYPE shi502_type; 
     [MarshalAs(UnmanagedType.LPWStr)] 
     public string shi502_remark; 
     public SHARE_PERMISSIONS shi502_permissions; 
     public Int32 shi502_max_uses; 
     public Int32 shi502_current_uses; 
     [MarshalAs(UnmanagedType.LPWStr)] 
     public string shi502_path; 
     [MarshalAs(UnmanagedType.LPWStr)] 
     public string shi502_passwd; 
     public Int32 shi502_reserved; 
     public IntPtr shi502_security_descriptor; 
    } 

    [Flags] 
    private enum ACCESS_MASK : uint 
    { 
     DELETE = 0x00010000, 
     READ_CONTROL = 0x00020000, 
     WRITE_DAC = 0x00040000, 
     WRITE_OWNER = 0x00080000, 
     SYNCHRONIZE = 0x00100000, 

     STANDARD_RIGHTS_REQUIRED = 0x000F0000, 

     STANDARD_RIGHTS_READ = 0x00020000, 
     STANDARD_RIGHTS_WRITE = 0x00020000, 
     STANDARD_RIGHTS_EXECUTE = 0x00020000, 

     STANDARD_RIGHTS_ALL = 0x001F0000, 

     SPECIFIC_RIGHTS_ALL = 0x0000FFFF, 

     ACCESS_SYSTEM_SECURITY = 0x01000000, 

     MAXIMUM_ALLOWED = 0x02000000, 

     GENERIC_READ = 0x80000000, 
     GENERIC_WRITE = 0x40000000, 
     GENERIC_EXECUTE = 0x20000000, 
     GENERIC_ALL = 0x10000000, 

     DESKTOP_READOBJECTS = 0x00000001, 
     DESKTOP_CREATEWINDOW = 0x00000002, 
     DESKTOP_CREATEMENU = 0x00000004, 
     DESKTOP_HOOKCONTROL = 0x00000008, 
     DESKTOP_JOURNALRECORD = 0x00000010, 
     DESKTOP_JOURNALPLAYBACK = 0x00000020, 
     DESKTOP_ENUMERATE = 0x00000040, 
     DESKTOP_WRITEOBJECTS = 0x00000080, 
     DESKTOP_SWITCHDESKTOP = 0x00000100, 

     WINSTA_ENUMDESKTOPS = 0x00000001, 
     WINSTA_READATTRIBUTES = 0x00000002, 
     WINSTA_ACCESSCLIPBOARD = 0x00000004, 
     WINSTA_CREATEDESKTOP = 0x00000008, 
     WINSTA_WRITEATTRIBUTES = 0x00000010, 
     WINSTA_ACCESSGLOBALATOMS = 0x00000020, 
     WINSTA_EXITWINDOWS = 0x00000040, 
     WINSTA_ENUMERATE = 0x00000100, 
     WINSTA_READSCREEN = 0x00000200, 

     WINSTA_ALL_ACCESS = 0x0000037F 
    } 

    private enum ACCESS_MODE : uint 
    { 
     NOT_USED_ACCESS, 
     GRANT_ACCESS, 
     SET_ACCESS, 
     DENY_ACCESS, 
     REVOKE_ACCESS, 
     SET_AUDIT_SUCCESS, 
     SET_AUDIT_FAILURE 
    } 

    private enum MULTIPLE_TRUSTEE_OPERATION : uint 
    { 
     NO_MULTIPLE_TRUSTEE, 
     TRUSTEE_IS_IMPERSONATE 
    } 

    private enum TRUSTEE_FORM : uint 
    { 
     TRUSTEE_IS_SID, 
     TRUSTEE_IS_NAME, 
     TRUSTEE_BAD_FORM, 
     TRUSTEE_IS_OBJECTS_AND_SID, 
     TRUSTEE_IS_OBJECTS_AND_NAME 
    } 

    private enum TRUSTEE_TYPE : uint 
    { 
     TRUSTEE_IS_UNKNOWN, 
     TRUSTEE_IS_USER, 
     TRUSTEE_IS_GROUP, 
     TRUSTEE_IS_DOMAIN, 
     TRUSTEE_IS_ALIAS, 
     TRUSTEE_IS_WELL_KNOWN_GROUP, 
     TRUSTEE_IS_DELETED, 
     TRUSTEE_IS_INVALID, 
     TRUSTEE_IS_COMPUTER 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    private struct TRUSTEE 
    { 
     public IntPtr pMultipleTrustee; 
     public MULTIPLE_TRUSTEE_OPERATION MultipleTrusteeOperation; 
     public TRUSTEE_FORM TrusteeForm; 
     public TRUSTEE_TYPE TrusteeType; 
     [MarshalAs(UnmanagedType.LPTStr)] 
     public string ptstrName; 
    } 

    [StructLayoutAttribute(LayoutKind.Sequential)] 
    private struct SECURITY_DESCRIPTOR 
    { 
     public byte Revision; 
     public byte Size; 
     public ushort Control; 
     public IntPtr Owner; 
     public IntPtr Group; 
     public IntPtr Sacl; 
     public IntPtr Dacl; 
    } 

    [StructLayoutAttribute(LayoutKind.Sequential)] 
    private struct EXPLICIT_ACCESS 
    { 
     public ACCESS_MASK grfAccessPermissions; 
     public ACCESS_MODE grfAccessMode; 
     public UInt32 grfInheritance; 
     public TRUSTEE Trustee; 
    } 

    private const byte SECURITY_DESCRIPTOR_REVISION = 1; 
    private const uint NO_INHERITANCE = 0; 
    private const uint ERROR_NONE_MAPPED = 1332; 

    private class AclPtrSafeHandle : SafeHandle 
    { 
     public AclPtrSafeHandle() : base(IntPtr.Zero, true) { } 

     public override bool IsInvalid 
     { 
      get 
      { 
       return false; 
      } 
     } 

     public void Replace(IntPtr newAclPtr) 
     { 
      ReleaseHandle(); 
      this.handle = newAclPtr; 
     } 

     protected override bool ReleaseHandle() 
     { 
      return (IntPtr.Zero == LocalFree(this.handle)); 
     } 
    } 

    #endregion 

    #region SharePermissionEntry 

    public enum SharePermissions : uint 
    { 
     Read = ACCESS_MASK.GENERIC_READ | ACCESS_MASK.STANDARD_RIGHTS_READ | ACCESS_MASK.GENERIC_EXECUTE, 
     FullControl = ACCESS_MASK.GENERIC_ALL 
    } 

    public class SharePermissionEntry 
    { 
     /// <summary> 
     /// The account name in the following format: [DomainName]\[UserOrGroupName] 
     /// Where DomainName that the user/group in the UserOrGroupName belongs to 
     /// Where UserOrGroupName the user or group that should be granted/denied permission 
     /// Note: DomainName with backslash is optional 
     /// </summary> 
     /// <example> 
     /// Everyone 
     /// REDMOND\elize 
     /// AV\AVSubmit Samples RW 
     /// </example> 
     public readonly string AccountName; 

     /// <summary> 
     /// The share permission to grant or deny for the account in UserOrGroupName 
     /// </summary> 
     public readonly SharePermissions Permission; 

     /// <summary> 
     /// Set to True to allow the rights specified in the Permission property and False to deny the rights specified in the Permission property. 
     /// </summary> 
     public readonly bool AllowOrDeny; 

     /// <summary> 
     /// Creates a new instance of the SharePermissionEntry class and populates each of the properties within the instance 
     /// </summary> 
     /// <param name="AccountName">[DomainName]\[UserOrGroupName] of username or group name that this permission entry relates to 
     /// You may just pass [UserOrGroupName] if you are specifying a 'well known' identity such as the Everyone group in the AccountName argument 
     /// </param> 
     /// <param name="DesiredPermission">The share permission to grant/deny</param> 
     /// <param name="AlloworDenyPermission">True to allow the permission, False to deny the permission</param> 
     public SharePermissionEntry(string accountName, SharePermissions desiredPermission, bool alloworDenyPermission) 
     { 
      Guard.ArgumentNotNullOrEmptyString(accountName, nameof(accountName)); 
      this.AccountName = accountName; 
      this.Permission = desiredPermission; 
      this.AllowOrDeny = alloworDenyPermission; 
     } 
    } 

    #endregion 

    /// <summary> 
    /// Shares local path with specified share name, description and permissions 
    /// </summary> 
    /// <param name="pathToShare">Local path to folder to share</param> 
    /// <param name="shareName">Name of a shared resource</param> 
    /// <param name="shareDescription">Optional comment about the shared resource</param> 
    /// <param name="sharePermissions">List of share permissions to apply</param> 
    /// <exception cref="Win32Exception">Will throw Win32Exception with relevant error code in case of failure</exception> 
    /// <remarks> 
    /// Only members of the Administrators, System Operators, or Power Users local group can add file shares with a call to the NetShareAdd function. 
    /// </remarks> 
    public static void Add(string pathToShare, string shareName, string shareDescription, IEnumerable<SharePermissionEntry> sharePermissions) 
    { 
     Guard.ArgumentNotNullOrEmptyString(pathToShare, nameof(pathToShare)); 
     Guard.ArgumentNotNullOrEmptyString(shareName, nameof(shareName)); 
     Guard.ArgumentCollectionNotEmpty(sharePermissions, nameof(sharePermissions)); 
     DirectoryInfo di = new DirectoryInfo(pathToShare); 
     if (!di.Exists) 
     { 
      throw new DirectoryNotFoundException(pathToShare); 
     } 
     pathToShare = di.FullName.TrimEnd(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); // Remove last/or \ 

     // This pointer will hold the full ACL (access control list) once the loop below has completed 
     using (AclPtrSafeHandle aclPtr = new AclPtrSafeHandle()) 
     { 
      // Loop through each entry in our list of explicit access rules, build each one and add it to the ACL 
      foreach (SharePermissionEntry spe in sharePermissions) 
      { 
       // Create a TRUSTEE structure and populate it with the user account details 
       TRUSTEE account = new TRUSTEE() 
       { 
        MultipleTrusteeOperation = MULTIPLE_TRUSTEE_OPERATION.NO_MULTIPLE_TRUSTEE, 
        pMultipleTrustee = IntPtr.Zero, 
        TrusteeForm = TRUSTEE_FORM.TRUSTEE_IS_NAME, 
        ptstrName = spe.AccountName, 
        TrusteeType = TRUSTEE_TYPE.TRUSTEE_IS_UNKNOWN 
       }; 
       // Populate the explicit access rule for this user/permission specified in the SharePermissions argument 
       EXPLICIT_ACCESS explicitAccessRule = new EXPLICIT_ACCESS() 
       { 
        // Set this to an Allow or Deny entry based on what was specified in the AllowOrDeny property 
        grfAccessMode = (spe.AllowOrDeny) ? ACCESS_MODE.GRANT_ACCESS : ACCESS_MODE.DENY_ACCESS, 
        // Build the access mask for the share permission specified for this user 
        grfAccessPermissions = (ACCESS_MASK)spe.Permission, 
        // Not relevant for share permissions so just set to NO_INHERITANCE 
        grfInheritance = NetShare.NO_INHERITANCE, 
        // Set the Trustee to the TRUSTEE structure we created earlier in the loop 
        Trustee = account 
       }; 
       // Add this explicit access rule to the ACL 
       IntPtr newAclPtr; 
       uint setEntriesResult = SetEntriesInAcl(1, ref explicitAccessRule, aclPtr.DangerousGetHandle(), out newAclPtr); 
       aclPtr.Replace(newAclPtr); 

       // Check the result of the SetEntriesInAcl API call 
       if (setEntriesResult == ERROR_NONE_MAPPED) 
       { 
        throw new Win32Exception(Marshal.GetLastWin32Error(), $"The account {spe.AccountName} could not be mapped to a security identifier (SID). Check that the account name is correct and that the domain where the account is held is contactable. The share has not been created."); 
       } 
       else if (setEntriesResult != 0) 
       { 
        throw new Win32Exception(Marshal.GetLastWin32Error(), $"The account {spe.AccountName} could not be added to the ACL as the follow error was encountered: {setEntriesResult}. The share has not been created."); 
       } 
      } 
      // Create a SECURITY_DESCRIPTOR structure and set the Revision number 
      SECURITY_DESCRIPTOR secDesc = new SECURITY_DESCRIPTOR() 
      { 
       Revision = NetShare.SECURITY_DESCRIPTOR_REVISION 
      }; 
      // Initialise the SECURITY_DESCRIPTOR instance - returns False if an error was encountered 
      if (!InitializeSecurityDescriptor(out secDesc, NetShare.SECURITY_DESCRIPTOR_REVISION)) 
      { 
       throw new Win32Exception(Marshal.GetLastWin32Error(), "An error was encountered during the call to the InitializeSecurityDescriptor API. The share has not been created."); 
      } 
      // Add the ACL to the SECURITY_DESCRIPTOR 
      if (!SetSecurityDescriptorDacl(ref secDesc, true, aclPtr.DangerousGetHandle(), false)) 
      { 
       throw new Win32Exception(Marshal.GetLastWin32Error(), "An error was encountered during the call to the SetSecurityDescriptorDacl API. The share has not been created."); 
      } 
      // Check to make sure the SECURITY_DESCRIPTOR is valid 
      if (!IsValidSecurityDescriptor(ref secDesc)) 
      { 
       throw new Win32Exception(Marshal.GetLastWin32Error(), "No errors were reported from previous API calls but the security descriptor is not valid. The share has not been created."); 
      } 
      // Create a pointer for the SECURITY_DESCRIPTOR so that we can pass this in to the SHARE_INFO_502 structure 
      IntPtr secDescPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(secDesc)); 
      Marshal.StructureToPtr(secDesc, secDescPtr, false); 
      // Create and populate the SHARE_INFO_502 structure that specifies all of the share settings 
      SHARE_INFO_502 shareInfo = new SHARE_INFO_502() 
      { 
       shi502_netname = shareName, 
       shi502_type = SHARE_TYPE.STYPE_DISKTREE, 
       shi502_remark = shareDescription, 
       shi502_permissions = SHARE_PERMISSIONS.ACCESS_NONE, 
       shi502_max_uses = -1, 
       shi502_current_uses = 0, 
       shi502_path = pathToShare, 
       shi502_passwd = null, 
       shi502_reserved = 0, 
       shi502_security_descriptor = secDescPtr 
      }; 
      // Call the NetShareAdd API to create the share 
      uint parm_error = 0; 
      NET_API_STATUS r = NetShareAdd(null /*localhost*/, 502, ref shareInfo, out parm_error); 
      // Clean up and return the result of NetShareAdd 
      Marshal.FreeCoTaskMem(secDescPtr); 
      if (r != NET_API_STATUS.NERR_Success) 
      { 
       throw new Win32Exception((int)r, $"An error {r} was encountered during the call to the NetShareAdd API. The share has not been created."); 
      } 
     } 
    } 

    /// <summary> 
    /// Deletes a share name from a server's list of shared resources, disconnecting all connections to the shared resource. 
    /// </summary> 
    /// <param name="shareName">Name of a shared resource</param> 
    /// <exception cref="Win32Exception">Will throw Win32Exception with relevant error code in case of failure</exception> 
    /// <remarks> 
    /// Only members of the Administrators, Server Operators, or Power Users local group, or those with Server Operator group membership, 
    /// can successfully delete file shares with a call to the NetShareDel function. 
    /// </remarks> 
    public static void DeleteIfExist(string shareName) 
    { 
     Guard.ArgumentNotNullOrEmptyString(shareName, nameof(shareName)); 
     var r = NetShareDel(null /* localhost */, shareName, 0); 
     if ((r != NET_API_STATUS.NERR_Success) && (r != NET_API_STATUS.NERR_NetNameNotFound)) 
     { 
      throw new Win32Exception((int)r, "An error was encountered during the call to the NetShareDel API. The share has not been deleted."); 
     } 
    } 
}