您可以使用Win32_LogicalShareSecuritySetting
. SetSecurityDescriptor()
方法来修改共享权限。修改现有权限的工作方式如下...
- 获取所需的
Win32_LogicalShareSecuritySetting
实例。
- 调用
GetSecurityDescriptor()
以获取共享的安全描述符作为Win32_SecurityDescriptor
实例。
DACL
通过其属性获取安全描述符的任意访问控制列表。
- 创建一个新的访问控制条目。
- 获取对类的引用。
Win32_ACE
- 创建
Win32_ACE
类的一个实例。
- 设置访问控制条目的
AccessMask
、AceFlags
、AceType
和Trustee
属性。
- 获取对类的引用。
Win32_Trustee
- 创建
Win32_Trustee
类的一个实例。
- 通过设置受托人
的
SIDString
or Name
(and ) 属性来指定条目的主体。Domain
- 创建一个结合现有条目和新条目的新访问控制列表。
- 将
DACL
安全描述符的属性设置为新的访问控制列表。
- 调用
SetSecurityDescriptor()
以保存共享的安全描述符。
以下类包含获取共享属性的方法,特别是通过该AddAccessControlEntry()
方法添加新的访问控制条目...
Imports System.Management
Imports System.Security.AccessControl
Friend Class ShareSecurity
Private ReadOnly Property ShareName As String
Private ReadOnly Property GetOptions As ObjectGetOptions
Private ReadOnly Property Scope As ManagementScope
Public Sub New(host As String, shareName As String, username As String, password As String)
Me.ShareName = shareName
GetOptions = New ObjectGetOptions()
Scope = New ManagementScope(
New ManagementPath() With {
.NamespacePath = "root\cimv2",
.Server = host
},
New ConnectionOptions() With {
_ ' ***** For demonstration purposes only! *****
_ 'TODO: Find a secure way to store the remote password
.Password = password,
.Username = username
}
)
End Sub
Public Function GetShareProperties() As IDictionary(Of String, Object)
Dim sharePath As New ManagementPath($"Win32_Share.Name=""{ShareName}""")
Using share As New ManagementObject(Scope, sharePath, GetOptions)
Return GetPropertyDictionary(share)
End Using
End Function
Public Function GetShareSecurityDescriptorProperties() As IDictionary(Of String, Object)
Using shareSecurity As ManagementObject = GetShareSecurity()
Using securityDescriptor As ManagementBaseObject = GetShareSecurityDescriptor(shareSecurity)
Return GetPropertyDictionary(securityDescriptor)
End Using
End Using
End Function
Public Sub AddAccessControlEntry(entryType As AceType, entryRights As FileSystemRights, securityIdentifier As String)
AddAccessControlEntry(
entryType,
entryRights,
Sub(trustee)
trustee("SIDString") = securityIdentifier
End Sub
)
End Sub
Public Sub AddAccessControlEntry(entryType As AceType, entryRights As FileSystemRights, domain As String, account As String)
AddAccessControlEntry(
entryType,
entryRights,
Sub(trustee)
trustee("Domain") = domain
trustee("Name") = account
End Sub
)
End Sub
''' <param name="trusteeInitializer">Initializes the Win32_Trustee instance for the access control entry to be added.</param>
Public Sub AddAccessControlEntry(entryType As AceType, entryRights As FileSystemRights, trusteeInitializer As Action(Of ManagementObject))
Using shareSecurity As ManagementObject = GetShareSecurity()
Using securityDescriptor As ManagementBaseObject = GetShareSecurityDescriptor(shareSecurity)
Dim accessControlEntries As ManagementBaseObject() = DirectCast(securityDescriptor("DACL"), ManagementBaseObject())
' The class must not be created in the remote scope otherwise CreateInstance()
' throws "System.UnauthorizedAccessException: 'Access is denied'."
Using accessControlEntryClass As New ManagementClass("Win32_ACE")
Using accessControlEntry As ManagementObject = accessControlEntryClass.CreateInstance()
accessControlEntry("AccessMask") = CUInt(entryRights)
accessControlEntry("AceFlags") = CUInt(AceFlags.None)
accessControlEntry("AceType") = CUInt(entryType)
' The class must not be created in the remote scope otherwise CreateInstance()
' throws "System.UnauthorizedAccessException: 'Access is denied'."
Using trusteeClass As New ManagementClass("Win32_Trustee")
Using trustee As ManagementObject = trusteeClass.CreateInstance()
trusteeInitializer.Invoke(trustee)
accessControlEntry("Trustee") = trustee
' Create a new access control list including the new access control
' entry, sorted with Deny entries first (true sorts after false)
' https://docs.microsoft.com/windows/win32/secauthz/order-of-aces-in-a-dacl
securityDescriptor("DACL") = accessControlEntries _
.Append(accessControlEntry) _
.OrderByDescending(Function(entry) CType(entry("AceType"), AceType)) _
.ToArray()
SetShareSecurityDescriptor(shareSecurity, securityDescriptor)
End Using
End Using
End Using
End Using
End Using
End Using
End Sub
Private Function GetShareSecurity() As ManagementObject
Dim shareSecurityPath As New ManagementPath($"Win32_LogicalShareSecuritySetting.Name=""{ShareName}""")
Return New ManagementObject(Scope, shareSecurityPath, GetOptions)
End Function
Private Function GetShareSecurityDescriptor(shareSecurity As ManagementObject) As ManagementBaseObject
' Create an array to store the output parameter
Dim invokeParameters(0) As ManagementBaseObject
Dim invokeResult As UInteger = shareSecurity.InvokeMethod("GetSecurityDescriptor", invokeParameters)
If invokeResult = 0 Then
Return invokeParameters(0)
Else
'TODO: Handle failure of GetSecurityDescriptor()...
Return Nothing
End If
End Function
Private Sub SetShareSecurityDescriptor(shareSecurity As ManagementObject, securityDescriptor As ManagementBaseObject)
' Create an array to store the input parameter
Dim invokeParameters() As ManagementBaseObject = {securityDescriptor}
Dim invokeResult As UInteger = shareSecurity.InvokeMethod("SetSecurityDescriptor", invokeParameters)
If invokeResult <> 0 Then
'TODO: Handle failure of SetSecurityDescriptor()...
End If
End Sub
Private Shared Function GetPropertyDictionary(obj As ManagementBaseObject) As IDictionary(Of String, Object)
Return obj.Properties _
.Cast(Of PropertyData)() _
.ToDictionary(
Function([property]) [property].Name,
Function([property])
' Recursively create dictionaries in place of management objects
Dim baseObjectArray As ManagementBaseObject() = TryCast([property].Value, ManagementBaseObject())
If baseObjectArray IsNot Nothing Then
Return baseObjectArray.Select(AddressOf GetPropertyDictionary).ToArray()
Else
Dim baseObject As ManagementBaseObject = TryCast([property].Value, ManagementBaseObject)
If baseObject IsNot Nothing Then
Return GetPropertyDictionary(baseObject)
Else
Return [property].Value
End If
End If
End Function
)
End Function
End Class
以下程序使用上述ShareSecurity
类来显示远程共享的属性,并且可以选择向其添加新的访问控制条目...
Imports System.Security.AccessControl
Public Class Program
Public Shared Sub Main(args As String())
If args Is Nothing OrElse args.Length = 0 Then
DisplayUsage()
ElseIf args.Length < 4 Then
DisplayError("Too few arguments.")
Else
Dim host As String = args(0)
Dim shareName As String = args(1)
Dim username As String = args(2)
' ***** For demonstration purposes only! *****
'TODO: Find a secure way to store the remote password
Dim password As String = args(3)
Dim shareSecurity As New ShareSecurity(host, shareName, username, password)
DisplayShareProperties(shareSecurity)
DisplaySecurityDescriptor(shareSecurity)
If args.Length > 4 Then
If args.Length <> 7 AndAlso args.Length <> 8 Then
DisplayError("Argument count mismatch.")
Else
Dim entryType As AceType
If Not [Enum].TryParse(args(4), True, entryType) Then
DisplayError($"Invalid <type> value ""{args(4)}"".")
Else
Dim entryRights As FileSystemRights
If Not [Enum].TryParse(args(5), True, entryRights) Then
DisplayError($"Invalid <rights> value ""{args(5)}"".")
Else
DisplayTextWithSeparator("New access control entry")
Console.WriteLine($" Type: {entryType}")
Console.WriteLine($" Rights: {entryRights}")
If args.Length = 7 Then
Dim securityIdentifier As String = args(6)
Console.WriteLine($" SID: {securityIdentifier}")
shareSecurity.AddAccessControlEntry(entryType, entryRights, securityIdentifier)
Else ' args.Length = 8
Dim domain As String = args(6)
Dim account As String = args(7)
Console.WriteLine($" Domain: {domain}")
Console.WriteLine($"Account: {account}")
shareSecurity.AddAccessControlEntry(entryType, entryRights, domain, account)
End If
Console.WriteLine()
DisplaySecurityDescriptor(shareSecurity)
End If
End If
End If
End If
End If
End Sub
Private Shared Sub DisplayUsage()
Dim entryAssemblyPath As String = System.Reflection.Assembly.GetEntryAssembly().Location
Dim entryAssemblyName As String = System.IO.Path.GetFileName(entryAssemblyPath)
Console.WriteLine("Display share properties:")
Console.WriteLine()
Console.WriteLine($"{entryAssemblyName} <host> <share> <username> <password>")
Console.WriteLine()
Console.WriteLine("Add access control entry:")
Console.WriteLine()
Console.WriteLine($"{entryAssemblyName} <host> <share> <username> <password> <type> <rights> <sid>")
Console.WriteLine($"{entryAssemblyName} <host> <share> <username> <password> <type> <rights> <domain> <account>")
Console.WriteLine()
Console.WriteLine(vbTab & $" <type> - A {GetType(AceType).FullName} enumeration value.")
Console.WriteLine(vbTab & $"<rights> - A {GetType(FileSystemRights).FullName} enumeration value.")
Console.WriteLine(vbTab & " <sid> - An account security identifier.")
Console.WriteLine()
End Sub
Private Shared Sub DisplayError(message As String)
Console.WriteLine($"ERROR: {message}")
Console.WriteLine()
DisplayUsage()
End Sub
Private Shared Sub DisplayTextWithSeparator(text As String)
Console.WriteLine(text)
Console.WriteLine(New String("-"c, text.Length))
End Sub
Private Shared Sub DisplayShareProperties(shareSecurity As ShareSecurity)
Dim shareProperties As IDictionary(Of String, Object) = shareSecurity.GetShareProperties()
DisplayTextWithSeparator("Share properties")
For Each propertyName As String In New String() {"Description", "Name", "Path"}
DisplayProperty(shareProperties, propertyName)
Next
Console.WriteLine()
End Sub
Private Shared Sub DisplaySecurityDescriptor(shareSecurity As ShareSecurity)
Dim securityDescriptorProperties As IDictionary(Of String, Object) = shareSecurity.GetShareSecurityDescriptorProperties()
DisplayTextWithSeparator("Share security descriptor")
DisplayProperty(securityDescriptorProperties, "ControlFlags", Function(value) CType(value, ControlFlags))
Console.WriteLine()
Dim accessControlList As IDictionary(Of String, Object)() = securityDescriptorProperties("DACL")
For i As Integer = 0 To accessControlList.Length - 1
Dim accessControlEntryProperties As IDictionary(Of String, Object) = accessControlList(i)
DisplayTextWithSeparator($"Access control entry #{i}")
DisplayProperty(accessControlEntryProperties, "AccessMask", Function(value) CType(value, FileSystemRights))
DisplayProperty(accessControlEntryProperties, "AceFlags", Function(value) CType(value, AceFlags))
DisplayProperty(accessControlEntryProperties, "AceType", Function(value) CType(value, AceType))
DisplayProperty(accessControlEntryProperties, "Trustee", Function(value) DirectCast(value, IDictionary(Of String, Object))("Name"))
Console.WriteLine()
Next
End Sub
Private Shared Sub DisplayProperty(properties As IDictionary(Of String, Object), propertyName As String)
DisplayProperty(properties, propertyName, Nothing)
End Sub
Private Shared Sub DisplayProperty(properties As IDictionary(Of String, Object), propertyName As String, selector As Func(Of Object, Object))
Dim propertyValue As Object = properties(propertyName)
Dim displayValue As Object = If(
selector IsNot Nothing,
selector.Invoke(propertyValue),
If(propertyValue, "<null>")
)
Console.WriteLine($"{propertyName}: {displayValue}")
End Sub
End Class
鉴于这样的份额...
...与Full Control
grant toAdministrators
和Read
grant to Everyone
,像这样调用程序...
SO60271689.exe MyComputer "My Share" MyUser MyPassword AccessDenied "Modify, Synchronize" S-1-5-32-546
……或者像这样……
SO60271689.exe MyComputer "My Share" MyUser MyPassword AccessDenied "Modify, Synchronize" BUILTIN Guests
...产生这样的输出...
Share properties
----------------
Description: This is the share description.
Name: My Share
Path: C:\My Share
Share security descriptor
-------------------------
ControlFlags: DiscretionaryAclPresent, SelfRelative
Access control entry #0
-----------------------
AccessMask: ReadAndExecute, Synchronize
AceFlags: None
AceType: AccessAllowed
Trustee: Everyone
Access control entry #1
-----------------------
AccessMask: FullControl
AceFlags: None
AceType: AccessAllowed
Trustee: Administrators
New access control entry
------------------------
Type: AccessDenied
Rights: Modify, Synchronize
SID: S-1-5-32-546
Share security descriptor
-------------------------
ControlFlags: DiscretionaryAclPresent, SelfRelative
Access control entry #0
-----------------------
AccessMask: Modify, Synchronize
AceFlags: None
AceType: AccessDenied
Trustee: Guests
Access control entry #1
-----------------------
AccessMask: ReadAndExecute, Synchronize
AceFlags: None
AceType: AccessAllowed
Trustee: Everyone
Access control entry #2
-----------------------
AccessMask: FullControl
AceFlags: None
AceType: AccessAllowed
Trustee: Administrators
由于 VB.NET 不是我的母语,这里是我开始使用的等效 C# 代码以使事情正常运行……
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Security.AccessControl;
namespace SO60271689.CSharp
{
internal class ShareSecurity
{
private string ShareName
{
get;
}
private ObjectGetOptions GetOptions
{
get;
}
private ManagementScope Scope
{
get;
}
public ShareSecurity(string host, string shareName, string username, string password)
{
ShareName = shareName;
GetOptions = new ObjectGetOptions();
Scope = new ManagementScope(
new ManagementPath() {
NamespacePath = @"root\cimv2",
Server = host
},
new ConnectionOptions() {
// ***** For demonstration purposes only! *****
//TODO: Find a secure way to store the remote password
Password = password,
Username = username
}
);
}
public IDictionary<string, object> GetShareProperties()
{
ManagementPath sharePath = new ManagementPath($"Win32_Share.Name=\"{ShareName}\"");
using (ManagementObject share = new ManagementObject(Scope, sharePath, GetOptions))
return GetPropertyDictionary(share);
}
public IDictionary<string, object> GetShareSecurityDescriptorProperties()
{
using (ManagementObject shareSecurity = GetShareSecurity())
using (ManagementBaseObject securityDescriptor = GetShareSecurityDescriptor(shareSecurity))
return GetPropertyDictionary(securityDescriptor);
}
public void AddAccessControlEntry(AceType entryType, FileSystemRights entryRights, string securityIdentifier)
{
AddAccessControlEntry(
entryType,
entryRights,
trustee => trustee["SIDString"] = securityIdentifier
);
}
public void AddAccessControlEntry(AceType entryType, FileSystemRights entryRights, string domain, string account)
{
AddAccessControlEntry(
entryType,
entryRights,
trustee => {
trustee["Domain"] = domain;
trustee["Name"] = account;
}
);
}
/// <param name="trusteeInitializer">Initializes the Win32_Trustee instance for the access control entry to be added.</param>
private void AddAccessControlEntry(AceType entryType, FileSystemRights entryRights, Action<ManagementObject> trusteeInitializer)
{
using (ManagementObject shareSecurity = GetShareSecurity())
using (ManagementBaseObject securityDescriptor = GetShareSecurityDescriptor(shareSecurity))
{
ManagementBaseObject[] accessControlEntries = (ManagementBaseObject[]) securityDescriptor["DACL"];
// The class must not be created in the remote scope otherwise CreateInstance()
// throws "System.UnauthorizedAccessException: 'Access is denied'."
using (ManagementClass accessControlEntryClass = new ManagementClass("Win32_ACE"))
using (ManagementObject accessControlEntry = accessControlEntryClass.CreateInstance())
{
accessControlEntry["AccessMask"] = (uint) entryRights;
accessControlEntry["AceFlags"] = (uint) AceFlags.None;
accessControlEntry["AceType"] = (uint) entryType;
// The class must not be created in the remote scope otherwise CreateInstance()
// throws "System.UnauthorizedAccessException: 'Access is denied'."
using (ManagementClass trusteeClass = new ManagementClass("Win32_Trustee"))
using (ManagementObject trustee = trusteeClass.CreateInstance())
{
trusteeInitializer.Invoke(trustee);
accessControlEntry["Trustee"] = trustee;
// Create a new access control list including the new access control
// entry, sorted with Deny entries first (true sorts after false)
// https://docs.microsoft.com/windows/win32/secauthz/order-of-aces-in-a-dacl
securityDescriptor["DACL"] = accessControlEntries
.Append(accessControlEntry)
.OrderByDescending(entry => (AceType) (uint) entry["AceType"] == AceType.AccessDenied)
.ToArray();
SetShareSecurityDescriptor(shareSecurity, securityDescriptor);
}
}
}
}
private ManagementObject GetShareSecurity()
{
ManagementPath shareSecurityPath = new ManagementPath($"Win32_LogicalShareSecuritySetting.Name=\"{ShareName}\"");
return new ManagementObject(Scope, shareSecurityPath, GetOptions);
}
private ManagementBaseObject GetShareSecurityDescriptor(ManagementObject shareSecurity)
{
// Create an array to store the output parameter
ManagementBaseObject[] invokeParameters = new ManagementBaseObject[1];
uint invokeResult = (uint) shareSecurity.InvokeMethod("GetSecurityDescriptor", invokeParameters);
if (invokeResult == 0)
return invokeParameters[0];
else
{
//TODO: Handle failure of GetSecurityDescriptor()...
return null;
}
}
private void SetShareSecurityDescriptor(ManagementObject shareSecurity, ManagementBaseObject securityDescriptor)
{
// Create an array to store the input parameter
ManagementBaseObject[] invokeParameters = new ManagementBaseObject[1] { securityDescriptor };
uint invokeResult = (uint) shareSecurity.InvokeMethod("SetSecurityDescriptor", invokeParameters);
if (invokeResult != 0)
{
//TODO: Handle failure of SetSecurityDescriptor()...
}
}
private static IDictionary<string, object> GetPropertyDictionary(ManagementBaseObject obj)
{
return obj.Properties
.Cast<PropertyData>()
.ToDictionary(
property => property.Name,
// Recursively create dictionaries in place of management objects
property => property.Value is ManagementBaseObject[] baseObjectArray
? baseObjectArray.Select(GetPropertyDictionary).ToArray()
: property.Value is ManagementBaseObject baseObject
? GetPropertyDictionary(baseObject)
: property.Value
);
}
}
}
using System;
using System.Collections.Generic;
using System.Security.AccessControl;
namespace SO60271689.CSharp
{
class Program
{
public static void Main(string[] args)
{
if (args == null || args.Length == 0)
DisplayUsage();
else if (args.Length < 4)
DisplayError("Too few arguments.");
else
{
string host = args[0];
string shareName = args[1];
string username = args[2];
// ***** For demonstration purposes only! *****
//TODO: Find a secure way to store the remote password
string password = args[3];
ShareSecurity shareSecurity = new ShareSecurity(host, shareName, username, password);
DisplayShareProperties(shareSecurity);
DisplaySecurityDescriptor(shareSecurity);
if (args.Length > 4)
{
if (args.Length != 7 && args.Length != 8)
DisplayError("Argument count mismatch.");
else
{
if (!Enum.TryParse(args[4], true, out AceType entryType))
DisplayError($"Invalid <type> value \"{args[4]}\".");
else if (!Enum.TryParse<FileSystemRights>(args[5], true, out FileSystemRights entryRights))
DisplayError($"Invalid <rights> value \"{args[5]}\".");
else
{
DisplayTextWithSeparator("New access control entry");
Console.WriteLine($" Type: {entryType}");
Console.WriteLine($" Rights: {entryRights}");
if (args.Length == 7)
{
string securityIdentifier = args[6];
Console.WriteLine($" SID: {securityIdentifier}");
shareSecurity.AddAccessControlEntry(entryType, entryRights, securityIdentifier);
}
else // args.Length == 8
{
string domain = args[6];
string account = args[7];
Console.WriteLine($" Domain: {domain}");
Console.WriteLine($"Account: {account}");
shareSecurity.AddAccessControlEntry(entryType, entryRights, domain, account);
}
Console.WriteLine();
DisplaySecurityDescriptor(shareSecurity);
}
}
}
}
}
private static void DisplayUsage()
{
string entryAssemblyPath = System.Reflection.Assembly.GetEntryAssembly().Location;
string entryAssemblyName = System.IO.Path.GetFileName(entryAssemblyPath);
Console.WriteLine("Display share properties:");
Console.WriteLine();
Console.WriteLine($"{entryAssemblyName} <host> <share> <username> <password>");
Console.WriteLine();
Console.WriteLine("Add access control entry:");
Console.WriteLine();
Console.WriteLine($"{entryAssemblyName} <host> <share> <username> <password> <type> <rights> <sid>");
Console.WriteLine($"{entryAssemblyName} <host> <share> <username> <password> <type> <rights> <domain> <account>");
Console.WriteLine();
Console.WriteLine($"\t <type> - A {typeof(AceType).FullName} enumeration value.");
Console.WriteLine($"\t<rights> - A {typeof(FileSystemRights).FullName} enumeration value.");
Console.WriteLine("\t <sid> - An account security identifier.");
Console.WriteLine();
}
private static void DisplayError(string message)
{
Console.WriteLine($"ERROR: {message}");
Console.WriteLine();
DisplayUsage();
}
private static void DisplayTextWithSeparator(string text)
{
Console.WriteLine(text);
Console.WriteLine(new string('=', text.Length));
}
private static void DisplayShareProperties(ShareSecurity shareSecurity)
{
IDictionary<string, object> shareProperties = shareSecurity.GetShareProperties();
DisplayTextWithSeparator("Share properties");
foreach (string propertyName in new string[] { "Description", "Name", "Path" })
DisplayProperty(shareProperties, propertyName);
Console.WriteLine();
}
private static void DisplaySecurityDescriptor(ShareSecurity shareSecurity)
{
IDictionary<string, object> securityDescriptorProperties = shareSecurity.GetShareSecurityDescriptorProperties();
DisplayTextWithSeparator("Share security descriptor");
DisplayProperty(securityDescriptorProperties, "ControlFlags", value => (ControlFlags) (uint) value);
Console.WriteLine();
IDictionary<string, object>[] accessControlList = (IDictionary<string, object>[]) securityDescriptorProperties["DACL"];
for (int i = 0; i < accessControlList.Length; i++)
{
IDictionary<string, object> accessControlEntryProperties = accessControlList[i];
DisplayTextWithSeparator($"Access control entry #{i}");
DisplayProperty(accessControlEntryProperties, "AccessMask", value => (FileSystemRights) (uint) value);
DisplayProperty(accessControlEntryProperties, "AceFlags", value => (AceFlags) (uint) value);
DisplayProperty(accessControlEntryProperties, "AceType", value => (AceType) (uint) value);
DisplayProperty(accessControlEntryProperties, "Trustee", value => ((IDictionary<string, object>) value)["Name"]);
Console.WriteLine();
}
}
private static void DisplayProperty(IDictionary<string, object> properties, string propertyName)
{
DisplayProperty(properties, propertyName, null);
}
private static void DisplayProperty(IDictionary<string, object> properties, string propertyName, Func<object, object> selector)
{
object propertyValue = properties[propertyName];
object displayValue = selector != null
? selector.Invoke(propertyValue)
: propertyValue ?? "<null>";
Console.WriteLine($"{propertyName}: {displayValue}");
}
}
}