共享文件夹权限!

时间:2010-01-12 14:52:47

标签: .net vb.net wmi

我使用此代码共享文件夹:

 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

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

谢谢!

2 个答案:

答案 0 :(得分:2)

此博客文章介绍了如何为共享设置权限:

http://blogs.msdn.com/helloworld/archive/2008/06/06/programmatically-configuring-permissions-on-a-share-in-c.aspx

代码在C#中,因此将它移植到VB并不是一个问题。

答案 1 :(得分: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.");
        }
    }
}