Вы можете использовать метод Win32_LogicalShareSecuritySetting
. SetSecurityDescriptor()
для изменения разрешений общего ресурса. Изменение существующих разрешений работает следующим образом ...
- Получить требуемый
Win32_LogicalShareSecuritySetting
экземпляр. - Позвонить
GetSecurityDescriptor()
на получить дескриптор безопасности общего ресурса в виде Win32_SecurityDescriptor
экземпляра. - Получить список дискреционного контроля доступа дескриптора безопасности через его свойство
DACL
. - Создать новый элемент управления доступом запись.
- Получить ссылку на
Win32_ACE
класс . - Создать экземпляр
Win32_ACE
класса . - Установите свойства
AccessMask
, AceFlags
, AceType
и Trustee
записи управления доступом. - Получить ссылку на
Win32_Trustee
класс . - Создать экземпляр
Win32_Trustee
класса . - Укажите принципала для записи, установив свойство
SIDString
или Name
(и Domain
) опекуна. - Запрос экземпляров класса
Win32_Account
или его производных будет одним из способов получения этих значений.
- Создайте новый список контроля доступа, объединяющий существующие записи и новую запись.
- Установите
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
предоставленным Administrators
и Read
предоставленным Everyone
, вызывая программу следующим образом ...
SO60271689.exe MyComputer "My Share" MyUser MyPassword AccessDenied "Modify, Synchronize" S-1-5-32-546
... или как this ...
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}");
}
}
}