Тема: VBS & WMI: безопасность NTFS для каталога, DACL (чтение, изменение)
Сценарий 1.
Получение обобщённого полного списка управления доступом NTFS (DACL) указанного каталога текущего компьютера.
Для каждой записи DACL сценарий позволяет определить:
- идентификатор учётной записи в формате "домен\имя";
- тип;
- режим наследования настроек от родительского каталога;
- маску доступа (в числовой форме, без детализации);
- область действия по отношению к дочерним объектам каталога.
Каталог выбирается с помощью метода BrowseForFolder объекта Shell.Application.
Сценарий ориентирован на работу в графическом режиме.
[code]Option Explicit
Dim objWsNet, strComputer
Dim objShell, objFolder, strPath
Dim objWMI, objSecSettings, objSD, objACE
Dim strList, strTemp, intTemp
Const ACCESS_ALLOWED_ACE_TYPE = 0 'Флаг-признак записи типа "РАЗРЕШЕНИЕ"
Const ACCESS_DENIED_ACE_TYPE = 1 'Флаг-признак записи типа "ЗАПРЕТ"
Const INHERITED_ACE = 16 'Флаг-признак того, что текущая запись DACL унаследована от родительского каталога
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.BrowseForFolder(0, "Выбор каталога", &h10 + &h200, &h11)
If Not objFolder Is Nothing Then
strPath = objFolder.Self.Path
Set objWsNet = CreateObject("WScript.Network")
strComputer = objWsNet.ComputerName
Set objWsNet = Nothing
Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set objSecSettings = objWMI.Get("Win32_LogicalFileSecuritySetting.Path='" & strPath & "'")
If objSecSettings.GetSecurityDescriptor(objSD) = 0 Then 'Чтение содержимого дескриптора безопасности каталога
If Not IsNull(objSD.DACL) Then 'Проверка наличия хотя бы одной записи в DACL каталога
strList = vbNullString
'--- Просмотр DACL каталога
For Each objACE In objSD.DACL
'--- Определение режима наследования записи и области её действия
If CBool(objACE.AceFlags And INHERITED_ACE) Then
strTemp = " - унаследовано "
intTemp = objACE.AceFlags - INHERITED_ACE
Else
strTemp = " - не унаследовано "
intTemp = objACE.AceFlags
End If
Select Case intTemp
Case 0: strTemp = strTemp & "(действует на: только текущий каталог); "
Case 1: strTemp = strTemp & "(действует на: текущий каталог и его файлы); "
Case 2: strTemp = strTemp & "(действует на: текущий каталог и его подкаталоги); "
Case 3: strTemp = strTemp & "(действует на: текущий каталог, его подкаталоги и файлы); "
Case 9: strTemp = strTemp & "(действует на: только файлы текущего каталога); "
Case 10: strTemp = strTemp & "(действует на: только подкаталоги текущего каталога); "
Case 11: strTemp = strTemp & "(действует на: подкаталоги и файлы текущего каталога); "
Case Else: strTemp = strTemp & "(область действия не определена); "
End Select
'------
'--- Определение типа записи
If objACE.AceType = ACCESS_ALLOWED_ACE_TYPE Then
strTemp = strTemp & "Разрешено с маской"
Else
strTemp = strTemp & "Запрещено с маской"
End If
'------
strTemp = strTemp & " -> " & CStr(objACE.AccessMask) & " (&h" & Hex(objACE.AccessMask) & ")"
strList = strList & objACE.Trustee.Domain & "\" & objACE.Trustee.Name & strTemp & vbNewLine & "------" & vbNewLine
Next
Set objACE = Nothing
'------
WScript.Echo strList
Else
WScript.Echo "Список управления доступом к каталогу " & UCase(strPath) & " пуст."
End If
Else
WScript.Echo "Не удалось прочитать дескриптор безопасности каталога " & UCase(strPath)
End If
Set objSD = Nothing
Set objSecSettings = Nothing
Set objWMI = Nothing
Else
WScript.Echo "Каталог не выбран."
End If
Set objFolder = Nothing
Set objShell = Nothing
WScript.Quit 0[/code]
Сценарий 2.
Получение подробного (полного или частичного) списка управления доступом NTFS (DACL) указанного каталога текущего компьютера.
Частичный список составляется в том случае, когда задано NetBIOS-имя пользователя (группы), в противном случае составляется полный список.
Можно указать имя объекта либо доменного, либо локального (для текущего компьютера) уровня. Допустимо указание имён ряда встроенных локальных объектов: "System" (или "Система"), "Все", "Администратор(ы)", "Гост(ь)(и)" и т.п. Имена объектов можно задавать как в кавычках, так и без них.
Для каждой записи DACL сценарий позволяет определить:
- идентификатор учётной записи в формате "домен\имя";
- тип;
- режим наследования настроек от родительского каталога;
- маску доступа (в текстовой форме, с детализацией);
- область действия по отношению к дочерним объектам каталога.
Сценарий требует привилегий локального администратора.
Каталог выбирается с помощью метода BrowseForFolder объекта Shell.Application.
Сценарий ориентирован на работу в графическом режиме.
[code]Option Explicit
Dim objShell, objFolder, strPath
Dim objWsNet, strDomain, strComputer, blnIsDomain, intOSVersion
Dim objWMI, objCollection, objItem, objSecSettings, objSD
Dim strAccount, strSID, strList
Dim intHasAccount 'Флаг-признак режима работы:
'-1 - не составлять список, т.к. указанная "учётка" не найдена;
'0 - составлять полный список;
'1 - составлять частичный список (только для указанной "учётки").
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.BrowseForFolder(0, "Выбор каталога", &h10 + &h200, &h11)
If Not objFolder Is Nothing Then
strPath = objFolder.Self.Path
Set objWsNet = CreateObject("WScript.Network")
strDomain = objWsNet.UserDomain
strComputer = objWsNet.ComputerName
Set objWsNet = Nothing
If StrComp(strDomain, strComputer, vbTextCompare) <> 0 Then blnIsDomain = True
Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
'--- Определение версии ОС
Set objCollection = objWMI.ExecQuery("SELECT Version FROM Win32_OperatingSystem")
For Each objItem In objCollection
intOSVersion = CInt(Replace(Left(objItem.Version, 3), ".", ""))
Next
Set objItem = Nothing
'------
strAccount = Trim(InputBox("Имя пользователя или группы" & vbNewLine & _
"(при составлении полного списка -" & vbNewLine & _
"не указывать):", "Проверка настроек безопасности NTFS"))
intHasAccount = 0
If Len(strAccount) > 0 Then
strAccount = Replace(strAccount, """", "")
'--- Настройка правильного наименования "учётки" локальной ОС в зависимости от версии ОС
If intOSVersion < 61 Then
strAccount = Replace(strAccount, "Система", "System", 1, -1, vbTextCompare)
Else
strAccount = Replace(strAccount, "System", "Система", 1, -1, vbTextCompare)
End If
'------
If StrComp(strAccount, "System", vbTextCompare) = 0 Or StrComp(strAccount, "Система", vbTextCompare) = 0 Or _
StrComp(strAccount, "Все", vbTextCompare) = 0 Then
strDomain = vbNullString
Else
If blnIsDomain Then
If MsgBox("Задана доменная учётная запись?", vbYesNo + vbQuestion, "Проверка настроек безопасности NTFS") = vbNo Then
strDomain = strComputer
End If
Else
strDomain = strComputer
End If
End If
'--- Поиск заданной "учётки" на локальном компьютере или в Active Directory
If Len(strDomain) > 0 Then
Set objCollection = objWMI.ExecQuery("SELECT SID FROM Win32_Account WHERE Domain='" & strDomain & "' AND Name='" & strAccount & "'")
Else
Set objCollection = objWMI.ExecQuery("SELECT SID FROM Win32_Account WHERE Name='" & strAccount & "'")
End If
'------
If objCollection.Count > 0 Then
intHasAccount = 1
'--- Определение SID заданной "учётки"
For Each objItem In objCollection
strSID = UCase(objItem.SID)
Next
'------
Else
intHasAccount = -1
End If
End If
If intHasAccount >=0 Then
Set objSecSettings = objWMI.Get("Win32_LogicalFileSecuritySetting.Path='" & strPath & "'")
If objSecSettings.GetSecurityDescriptor(objSD) = 0 Then 'Чтение содержимого дескриптора безопасности каталога
strList = vbNullString
If Not IsNull(objSD.DACL) Then 'Проверка наличия хотя бы одной записи в DACL каталога
Call Get_DACLInfo(objSD.DACL, strList, intHasAccount, strSID, intOSVersion)
If Len(strList) > 0 Then
WScript.Echo strList
Else
WScript.Echo "В DACL не обнаружено ни одной записи для объекта " & UCase(strDomain & "\" & strAccount)
End If
Else
WScript.Echo "Список управления доступом к каталогу " & UCase(strPath) & " пуст."
End If
Else
WScript.Echo "Не удалось прочитать дескриптор безопасности каталога " & UCase(strPath)
End If
Else
WScript.Echo "Учётная запись объекта " & UCase(strDomain & "\" & strAccount) & " не найдена."
End If
Set objSecSettings = Nothing
Set objCollection = Nothing
Set objWMI = Nothing
Else
WScript.Echo "Каталог не выбран."
End If
Set objFolder = Nothing
Set objShell = Nothing
WScript.Quit 0
'======
Function Get_DACLInfo(arrACE(), strRes, intMode, strAccSID, intVer)
Dim objEntry, strTemp, i, j, lngMask, lngTemp
Dim arrFlagValue, arrFlagName, arrGenericValue, arrGenericName
Dim arrSieveGE, arrSieveGW, arrSieveGR, arrTemp
Const PART_MODE = 1 'Флаг-признак составления частичного списка
'--- Значения универсальных масок
Const GENERIC_ALL = &H10000000
Const GENERIC_EXECUTE = &H20000000
Const GENERIC_WRITE = &H40000000
Const GENERIC_READ = &H80000000
'------
Const ACCESS_ALLOWED_ACE_TYPE = 0 'Флаг-признак записи типа "РАЗРЕШЕНИЕ"
Const ACCESS_DENIED_ACE_TYPE = 1 'Флаг-признак записи типа "ЗАПРЕТ"
Const INHERITED_ACE = 16 'Флаг-признак того, что текущая запись DACL унаследована от родительского каталога
Const FULL_ACCESS = 983551 'Значение маски полного разрешения или запрета
Const FLAG_SYNCHRONIZE = 1048576 'Значение флага синхронизации доступа к объекту файловой системы
'(в версиях ОС "2000/XP", применим только для записей типа "РАЗРЕШЕНИЕ")
'arrFlagValue = Array(&H20, &H1, &H80, &H8, &H2, &H4, &H100, &H10, &H40, &H10000, &H20000, &H40000, &H80000)
arrFlagValue = Array(32, 1, 128, 8, 2, 4, 256, 16, 64, 65536, 131072, 262144, 524288)
arrFlagName = Array("Траверс папок / Выполнение файлов", _
"Содержание папки / Чтение данных", _
"Чтение атрибутов", _
"Чтение дополнительных атрибутов", _
"Создание файлов / Запись данных", _
"Создание папок / Дозапись данных", _
"Запись атрибутов", _
"Запись дополнительных атрибутов", _
"Удаление подпапок и файлов", _
"Удаление", _
"Чтение разрешений", _
"Смена разрешений", _
"Смена владельца")
arrGenericValue = Array(&H20000000, &H40000000, &H80000000)
'arrGenericValue = Array(536870912, 1073741824, 2147483648)
arrGenericName = Array("Выполнение (универсальная маска)", "Запись (универсальная маска)", "Чтение (универсальная маска)")
'--- Вспомогательные массивы, предназначенные для детализации универсальных масок
arrSieveGE = Array(-1, 0, -1, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0)
arrSieveGW = Array(0, 0, 0, 0, -1, -1, -1, -1, 0, 0, -1, 0, 0)
arrSieveGR = Array(0, -1, -1, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0)
'------
'--- Настройка правильного наименования одного из флагов маски доступа в зависимости от версии ОС
If intVer < 60 Then
arrFlagName(0) = "Обзор папок / Выполнение файлов"
End If
'------
For Each objEntry In arrACE
'--- Определение режима наследования записи и области её действия
If CBool(objEntry.AceFlags And INHERITED_ACE) Then
strTemp = " (унаследовано; "
lngTemp = objEntry.AceFlags - INHERITED_ACE
Else
strTemp = " (не унаследовано; "
lngTemp = objEntry.AceFlags
End If
Select Case lngTemp
Case 0: strTemp = strTemp & "действует на: только текущий каталог)"
Case 1: strTemp = strTemp & "действует на: текущий каталог и его файлы)"
Case 2: strTemp = strTemp & "действует на: текущий каталог и его подкаталоги)"
Case 3: strTemp = strTemp & "действует на: текущий каталог, его подкаталоги и файлы)"
Case 9: strTemp = strTemp & "действует на: только файлы текущего каталога)"
Case 10: strTemp = strTemp & "действует на: только подкаталоги текущего каталога)"
Case 11: strTemp = strTemp & "действует на: подкаталоги и файлы текущего каталога)"
Case Else: strTemp = strTemp & "область действия не определена); "
End Select
strTemp = strTemp & vbNewLine & "---" & vbNewLine
'------
'--- Определение типа записи
If objEntry.AceType = ACCESS_ALLOWED_ACE_TYPE Then
strTemp = strTemp & "РАЗРЕШЕНО:" & vbNewLine
ElseIf objEntry.AceType = ACCESS_DENIED_ACE_TYPE Then
strTemp = strTemp & "ЗАПРЕЩЕНО:" & vbNewLine
End If
'------
'--- Определение значения маски "Полный доступ" в зависимости от версии ОС
If intVer < 52 Then
lngTemp = FULL_ACCESS + Abs(objEntry.AceType - 1) * FLAG_SYNCHRONIZE
'Выражение FULL_ACCESS + Abs(objEntry.AceType - 1) * FLAG_SYNCHRONIZE
'учитывает разницу между значениями маски "Полный доступ" у записей разных типов
'в ОС версий "2000/XP"
Else
lngTemp = FULL_ACCESS + FLAG_SYNCHRONIZE
End If
'------
lngMask = objEntry.AccessMask
Select Case Abs(lngMask)
Case lngTemp: strTemp = strTemp & "Полный доступ" & vbNewLine
Case GENERIC_ALL: strTemp = strTemp & "Полный доступ (универсальная маска)" & vbNewLine
Case Else
'--- Детальный анализ маски доступа текущей записи:
'обработка универсальных масок (биты №№ 29 - 31)
If Abs(lngMask) > lngTemp Then
For i = 0 To UBound(arrGenericValue)
If lngMask And arrGenericValue(i) Then
strTemp = strTemp & arrGenericName(i) & vbNewLine & vbTab & "{" & vbNewLine
Select Case arrGenericValue(i)
Case GENERIC_EXECUTE: arrTemp = arrSieveGE
Case GENERIC_WRITE: arrTemp = arrSieveGW
Case GENERIC_READ: arrTemp = arrSieveGR
End Select
For j = 0 To UBound(arrTemp)
If arrTemp(j) Then strTemp = strTemp & vbTab & arrFlagName(j) & vbNewLine
Next
strTemp = strTemp & vbTab & "}" & vbNewLine
End If
Next
End If
'обработка обычных масок (биты №№ 0 - 20)
For i = 0 To UBound(arrFlagValue)
If lngMask And arrFlagValue(i) Then
strTemp = strTemp & arrFlagName(i) & vbNewLine
End If
Next
'------
End Select
strTemp = UCase(objEntry.Trustee.Domain & "\" & objEntry.Trustee.Name) & strTemp & "===" & vbNewLine
If intMode = PART_MODE Then
If StrComp(UCase(objEntry.Trustee.SIDString), strAccSID, vbTextCompare) = 0 Then
strRes = strRes & strTemp
End If
Else
strRes = strRes & strTemp
End If
Next
End Function[/code]
Сценарий 3.
Изменение списка управления доступом NTFS (DACL) указанного каталога текущего компьютера без сохранения настроек, унаследованных от "родителя".
Варианты изменения DACL:
- изменение типа существующей записи и (или) её маски доступа;
- добавление отсутствующей записи заданного типа и с заданной маской;
- удаление существующей записи.
Для работы сценария необходимо задать NetBIOS-имя учётной записи, для которой необходимо изменить соответствующую запись DACL.
Можно указать имя объекта либо доменного, либо локального (для текущего компьютера) уровня. Допустимо указание имён ряда встроенных локальных объектов: "System" (или "Система"), "Все", "Администратор(ы)", "Гост(ь)(и)" и т.п. Имена объектов можно задавать как в кавычках, так и без них.
Сценарий требует привилегий локального администратора.
Каталог выбирается с помощью метода BrowseForFolder объекта Shell.Application.
Сценарий ориентирован на работу в графическом режиме.
Внимание!
1. Ни рациональность, ни, тем более, осмысленность заданного действия сценарием не проверяется.
2. Выбор записей DACL для обработки ведётся только по SID соответствующего объекта. Таким образом, все записи для данного объекта (независимо от их типа и маски) будут преобразованы в полные дубликаты, после чего ОС (в процессе оптимизации DACL) оставит только один экземпляр, удалив все остальные (записи с разной областью действия останутся в списке).
3. Для упрощения кода данная версия сценария не обеспечивает возможности задания произвольной области действия записи при её добавлении в список. Автоматически задаётся область действия по умолчанию (текущий каталог, его подкаталоги и файлы).
4. В Win 2000 Pro с SP ниже 4 возможно ограничение функциональности при попытке удаления записи: запись в DACL может остаться, но не иметь ни одного установленного флага маски доступа.
[code]Option Explicit
Dim objWsNet, strDomain, strComputer, strAccount, blnIsDomain
Dim objShell, objFolder, strPath, xResult, intTemp
Dim objWMI, objCollection, objItem, intOSVersion
Dim arrACEMasks, intACEType, lngACEMask, blnAddACE
Const ACCESS_ALLOWED_ACE_TYPE = 0 'Флаг-признак записи типа "РАЗРЕШЕНИЕ"
Const ACCESS_DENIED_ACE_TYPE = 1 'Флаг-признак записи типа "ЗАПРЕТ"
Const REMOVE_ACE = 0 'Значение маски для удаления записи из DACL
'--- Набор типичных значений масок доступа
Const WRITE_ONLY = 278
Const READ_ONLY = 131209
Const READ_AND_EXECUTE = 131241
Const READ_WRITE = 131487
Const READ_WRITE_EXECUTE = 131519
Const MODIFY = 197055
Const MODIFY_AND_REMOVE_CHILDREN = 197119
Const CHANGE_DACL = 262144
Const ACCESS_WITHOUT_CHANGE_OWNER = 459263
Const CHANGE_OWNER = 524288
Const CHANGE_DACL_AND_OWNER = 786432
Const FULL_ACCESS = 983551
'---
Const FLAG_SYNCHRONIZE = 1048576 'Значение флага синхронизации доступа к объекту файловой системы
'(применим только для записей типа "РАЗРЕШЕНИЕ")
arrACEMasks = Array(REMOVE_ACE, WRITE_ONLY, READ_ONLY, READ_AND_EXECUTE, READ_WRITE, READ_WRITE_EXECUTE, MODIFY, _
MODIFY_AND_REMOVE_CHILDREN, CHANGE_DACL, ACCESS_WITHOUT_CHANGE_OWNER, CHANGE_OWNER, _
CHANGE_DACL_AND_OWNER, FULL_ACCESS)
strAccount = Trim(InputBox("Имя учётной записи:", "Настройка безопасности NTFS"))
If Len(strAccount) > 0 Then
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.BrowseForFolder(0, "Выбор каталога", &h10 + &h200, &h11)
If Not objFolder Is Nothing Then
strPath = objFolder.Self.Path
Set objWsNet = CreateObject("WScript.Network")
strDomain = objWsNet.UserDomain
strComputer = objWsNet.ComputerName
Set objWsNet = Nothing
Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
'--- Определение версии ОС
Set objCollection = objWMI.ExecQuery("SELECT Version FROM Win32_OperatingSystem")
For Each objItem In objCollection
intOSVersion = CInt(Replace(Left(objItem.Version, 3), ".", ""))
Next
Set objItem = Nothing
Set objCollection = Nothing
Set objWMI = Nothing
'------
strAccount = Replace(strAccount, """", "")
'--- Настройка правильного наименования "учётки" локальной ОС в зависимости от версии ОС
If intOSVersion < 61 Then
strAccount = Replace(strAccount, "Система", "System", 1, -1, vbTextCompare)
Else
strAccount = Replace(strAccount, "System", "Система", 1, -1, vbTextCompare)
End If
'------
If StrComp(strDomain, strComputer, vbTextCompare) <> 0 Then blnIsDomain = True
If StrComp(strAccount, "System", vbTextCompare) = 0 Or StrComp(strAccount, "Система", vbTextCompare) = 0 Or _
StrComp(strAccount, "Все", vbTextCompare) = 0 Then
strDomain = vbNullString
Else
If blnIsDomain Then
If MsgBox("Задана доменная учётная запись?", vbYesNo + vbQuestion, "Проверка настроек безопасности NTFS") = vbNo Then
strDomain = strComputer
End If
Else
strDomain = strComputer
End If
End If
intTemp = Trim(InputBox("Тип доступа и маска доступа в формате" & vbNewLine & _
"+ЧИСЛО (разрешить) или -ЧИСЛО (запретить)," & vbNewLine & _
"где ЧИСЛО:" & vbNewLine & _
"1 - запись;" & vbNewLine & _
"2 - только чтение;" & vbNewLine & _
"3 - чтение и выполнение;" & vbNewLine & _
"4 - чтение и запись (без выполнения);" & vbNewLine & _
"5 - чтение, запись, выполнение;" & vbNewLine & _
"6 - изменение (без удаления подпапок и файлов);" & vbNewLine & _
"7 - изменение (с удалением подпапок и файлов);" & vbNewLine & _
"8 - смена разрешений;" & vbNewLine & _
"9 - почти полный доступ (без смены владельца);" & vbNewLine & _
"10 - смена владельца;" & vbNewLine & _
"11 - смена разрешений и владельца;" & vbNewLine & _
"12 - полный доступ." & vbNewLine & vbNewLine & _
"Если знак типа доступа (+/-) отсутствует," & vbNewLine & _
"то предполагается разрешение." & vbNewLine & vbNewLine & _
"Для удаления записи из списка" & vbNewLine & _
"в качестве значения маски укажите 0", "Настройка безопасности NTFS"))
If IsNumeric(intTemp) Then
intTemp = CInt(intTemp)
If Abs(intTemp) >= 0 And Abs(intTemp) <= 12 Then
lngACEMask = arrACEMasks(Abs(intTemp))
If intTemp < 0 Then
intACEType = 1
If intOSVersion >= 52 And lngACEMask = FULL_ACCESS Then
lngACEMask = lngACEMask + FLAG_SYNCHRONIZE
'Эта проверка позволяет учесть разницу между значениями маски "Полный доступ"
'у записей разных типов в ОС версий "2000/XP"
End If
ElseIf intTemp > 0 Then
intACEType = 0
lngACEMask = lngACEMask + FLAG_SYNCHRONIZE
Else
intACEType = 0
End If
If intTemp <> 0 Then
If MsgBox("Добавлять запись в список, если она отсутствует?", vbYesNo + vbQuestion, _
"Настройка безопасности NTFS") = vbYes Then
blnAddACE = True
End If
End If
xResult = Modify_DACL(strDomain, strComputer, strAccount, strPath, intACEType, lngACEMask, blnAddACE)
Else
xResult = "Маска доступа задана неверно."
End If
Else
xResult = "Тип доступа или маска доступа не заданы или заданы неверно."
End If
Wscript.Echo xResult
Else
WScript.Echo "Каталог не выбран."
End If
Set objShell = Nothing
Set objFolder = Nothing
Else
WScript.Echo "Учётная запись не указана."
End If
WScript.Quit 0
'======
Function Modify_DACL(strDom, strWS, strSAN, strDir, intType, lngMask, blnAdd)
Dim objWMI, objSecSettings, objSD, objACE
Dim xRes, arrACE, objCollection, objItem, strSID
Dim objSID, objTrustee, objNewACE
Dim blnHasACE, i
Const SE_DACL_PROTECTED = 4096 'Флаг-признак отключенного режима наследования управляемым каталогом безопасности NTFS от родительского каталога
Const OBJECT_INHERIT_ACE = 1 'Флаг-признак области действия записи на текущий каталог и его файлы
Const CONTAINER_INHERIT_ACE = 2 'Флаг-признак области действия записи на текущий каталог и его подкаталоги
On Error Resume Next
xRes = 0: blnHasACE = False
Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strWS & "\root\cimv2")
If Err.Number = 0 Then
Set objSecSettings = objWMI.Get("Win32_LogicalFileSecuritySetting.Path='" & strDir & "'")
If Err.Number = 0 Then
If objSecSettings.GetSecurityDescriptor(objSD) = 0 Then 'Чтение содержимого дескриптора безопасности управляемого каталога
If Not IsNull(objSD.DACL) Then 'Проверка наличия хотя бы одной записи в DACL управляемого каталога
'--- Отключение наследования настроек безопасности от "родителя"
If Not CBool(objSD.ControlFlags And SE_DACL_PROTECTED) Then
objSD.ControlFlags = objSD.ControlFlags + SE_DACL_PROTECTED
xRes = objSecSettings.SetSecurityDescriptor(objSD)
End If
'------
If xRes = 0 Then
'--- Поиск заданной "учётки" на локальном компьютере или в Active Directory
If Len(strDom) > 0 Then
Set objCollection = objWMI.ExecQuery("SELECT SID FROM Win32_Account WHERE Domain='" & strDom & "' AND Name='" & strSAN & "'")
Else
Set objCollection = objWMI.ExecQuery("SELECT SID FROM Win32_Account WHERE Name='" & strSAN & "'")
End If
'------
If objCollection.Count > 0 Then
'--- Определение SID заданной "учётки"
For Each objItem In objCollection
strSID = UCase(objItem.SID)
Next
Set objItem = Nothing
'------
'--- Поиск в DACL записи с известным SID
For Each objACE In objSD.DACL
If UCase(objACE.Trustee.SIDString) = strSID Then
blnHasACE = True 'флаг-признак того, что запись с искомым SID найдена
'--- Установка заданных значений типа и маски доступа для найденной записи
objACE.AceType = intType
objACE.AccessMask = lngMask
'-----
End If
Next
'------
If blnHasACE Then
'--- Применение изменений, внесённых в DACL, в том случае,
'когда хотя бы одна запись с искомым SID там найдена
xRes = objSecSettings.SetSecurityDescriptor(objSD)
Select Case xRes
Case "0": xRes = "Успешное завершение."
Case "2": xRes = "Не удалось настроить параметры существующей записи " & UCase(strDom & "\" & strSAN) & vbNewLine & "Доступ запрещён."
Case "5", "9": xRes = "Не удалось настроить параметры существующей записи " & UCase(strDom & "\" & strSAN) & vbNewLine & "Для выполнения операции недостаточно полномочий."
Case "21": xRes = "Не удалось настроить параметры существующей записи " & UCase(strDom & "\" & strSAN) & vbNewLine & "Заданы недопустимые значения параметров."
Case Else: xRes = "Не удалось настроить параметры существующей записи " & UCase(strDom & "\" & strSAN) & vbNewLine & "Неизвестная ошибка с кодом: " & xRes
End Select
Else
If blnAdd Then
'--- Добавление в DACL записи с известным SID, если она там не найдена
arrACE = objSD.DACL
Set objSID = objWMI.Get("Win32_SID.SID='" & strSID & "'")
Set objTrustee = objWMI.Get("Win32_Trustee").Spawninstance_
objTrustee.Domain = strDom
objTrustee.Name = strSAN
objTrustee.SID = objSID.BinaryRepresentation
objTrustee.SidLength = objSID.SidLength
objTrustee.SIDString = strSID
Set objSID = Nothing
Set objNewACE = objWMI.Get("Win32_Ace").Spawninstance_
objNewACE.AceType = intType
objNewACE.AceFlags = OBJECT_INHERIT_ACE + CONTAINER_INHERIT_ACE
objNewACE.AccessMask = lngMask
objNewACE.Trustee = objTrustee
Set objTrustee = Nothing
i = UBound(arrACE) + 1
ReDim Preserve arrACE(i)
Set arrACE(i) = objNewACE
objSD.DACL = arrACE
Set objNewACE = Nothing
Erase arrACE
xRes = objSecSettings.SetSecurityDescriptor(objSD)
Select Case xRes
Case "0": xRes = "Успешное завершение."
Case "2": xRes = "Не удалось добавить запись " & UCase(strDom & "\" & strSAN) & vbNewLine & "Доступ запрещён."
Case "5", "9": xRes = "Не удалось добавить запись " & UCase(strDom & "\" & strSAN) & vbNewLine & "Для выполнения операции недостаточно полномочий."
Case "21": xRes = "Не удалось добавить запись " & UCase(strDom & "\" & strSAN) & vbNewLine & "Заданы недопустимые значения параметров."
Case Else: xRes = "Не удалось добавить запись " & UCase(strDom & "\" & strSAN) & vbNewLine & "Неизвестная ошибка с кодом: " & xRes
End Select
'------
Else
xRes = "Запись " & UCase(strDom & "\" & strSAN) & " в DACL объекта " & UCase(strDir) & " отсутствует."
End If
End If
Else
xRes = "Не найдена учётная запись объекта " & UCase(strDom & "\" & strSAN)
End If
Set objCollection = Nothing
Else
xRes = "Не удалось отключить наследование безопасности для каталога " & UCase(strDir)
End If
Else
xRes = "Список управления доступом к каталогу " & UCase(strDir) & " пуст."
End If
Else
xRes = "Не удалось прочитать дескриптор безопасности каталога " & UCase(strDir)
End If
Set objSD = Nothing
Set objSecSettings = Nothing
Else
xRes = "Ошибка " & CStr(Err.Number) & vbNewLine & Err.Description
Err.Clear
End If
Else
xRes = "Ошибка " & CStr(Err.Number) & vbNewLine & Err.Description
Err.Clear
End If
Set objWMI = Nothing
On Error GoTo 0
Modify_DACL = xRes
End Function[/code]
Сценарий 4.
Изменение списка управления доступом NTFS (DACL) указанного каталога текущего компьютера с сохранением настроек, унаследованных от "родителя".
Варианты изменения DACL (все варианты возможны только для не унаследованных записей):
- изменение маски доступа существующей записи с учётом области её действия;
- добавление отсутствующей записи с заданными типом, областью действия и маской;
- удаление существующей записи с учётом её типа и области действия.
С помощью сценария можно изменять DACL и того каталога, у которого включено наследование от "родителя", и того - у которого отключено.
Для работы сценария необходимо задать NetBIOS-имя учётной записи, для которой необходимо изменить соответствующую запись DACL.
Можно указать имя объекта либо доменного, либо локального (для текущего компьютера) уровня. Допустимо указание имён ряда встроенных локальных объектов: "System" (или "Система"), "Все", "Администратор(ы)", "Гост(ь)(и)" и т.п. Имена объектов можно задавать как в кавычках, так и без них.
Сценарий требует привилегий локального администратора.
Каталог выбирается с помощью метода BrowseForFolder объекта Shell.Application.
Сценарий ориентирован на работу в графическом режиме.
Внимание!
1. Ни рациональность, ни, тем более, осмысленность заданного действия сценарием не проверяется.
2. В Win 2000 Pro с SP ниже 4 возможно ограничение функциональности при попытке удаления записи: запись в DACL может остаться, но не иметь ни одного установленного флага маски доступа.
[code]Option Explicit
Dim objWsNet, strDomain, strComputer, strAccount, blnIsDomain
Dim objShell, objFolder, strPath, xResult, intTemp, strTemp
Dim objWMI, objCollection, objItem, intOSVersion
Dim arrACEMasks, arrACEScopes, intACEType, intACEScope, lngACEMask
Const ACCESS_ALLOWED_ACE_TYPE = 0 'Флаг-признак записи типа "РАЗРЕШЕНИЕ"
Const ACCESS_DENIED_ACE_TYPE = 1 'Флаг-признак записи типа "ЗАПРЕТ"
Const OBJECT_INHERIT_ACE = 1 'Флаг-признак области действия записи на текущий каталог и его файлы
Const CONTAINER_INHERIT_ACE = 2 'Флаг-признак области действия записи на текущий каталог и его подкаталоги
Const REMOVE_ACE = 0 'Значение маски для удаления записи из DACL
'--- Допустимые значения для указания областей действия записи
Const ANY_SCOPE = -1 'Любая область действия записи
Const FOLDER_ONLY = 0 'Только текущая папка
Const FOLDER_AND_FILES = 1 'Текущая папка и её файлы
Const FOLDER_AND_SUBFOLDERS = 2 'Текущая папка и её подпапки
Const FOLDER_SUBFOLDERS_FILES = 3 'Текущая папка её подпапки и файлы
Const FILES_ONLY = 9 'Только файлы текущей папки
Const SUBFOLDERS_ONLY = 10 'Только подпапки текущей папки
Const SUBFOLDERS_AND_FILES = 11 'Подпапки и файлы текущей папки
'--- Набор типичных значений масок доступа
Const WRITE_ONLY = 278
Const READ_ONLY = 131209
Const READ_AND_EXECUTE = 131241
Const READ_WRITE = 131487
Const READ_WRITE_EXECUTE = 131519
Const MODIFY = 197055
Const MODIFY_AND_REMOVE_CHILDREN = 197119
Const CHANGE_DACL = 262144
Const ACCESS_WITHOUT_CHANGE_OWNER = 459263
Const CHANGE_OWNER = 524288
Const CHANGE_DACL_AND_OWNER = 786432
Const FULL_ACCESS = 983551
'---
Const FLAG_SYNCHRONIZE = 1048576 'Значение флага синхронизации доступа к объекту файловой системы
'(применим только для записей типа "РАЗРЕШЕНИЕ")
arrACEMasks = Array(REMOVE_ACE, WRITE_ONLY, READ_ONLY, READ_AND_EXECUTE, READ_WRITE, READ_WRITE_EXECUTE, MODIFY, _
MODIFY_AND_REMOVE_CHILDREN, CHANGE_DACL, ACCESS_WITHOUT_CHANGE_OWNER, CHANGE_OWNER, _
CHANGE_DACL_AND_OWNER, FULL_ACCESS)
arrACEScopes = Array(ANY_SCOPE, FOLDER_ONLY, FOLDER_AND_FILES, FOLDER_AND_SUBFOLDERS, FOLDER_SUBFOLDERS_FILES, _
FILES_ONLY, SUBFOLDERS_ONLY, SUBFOLDERS_AND_FILES)
strAccount = InputBox("Имя учётной записи:", "Настройка безопасности NTFS")
If Len(strAccount) > 0 Then
If StrComp(strAccount, "Система", vbTextCompare) = 0 Then strAccount = "System"
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.BrowseForFolder(0, "Выбор каталога", &H10 + &H200, &H11)
If Not objFolder Is Nothing Then
strPath = objFolder.Self.Path
Set objWsNet = CreateObject("WScript.Network")
strDomain = objWsNet.UserDomain
strComputer = objWsNet.ComputerName
Set objWsNet = Nothing
Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
'--- Определение версии ОС
Set objCollection = objWMI.ExecQuery("SELECT Version FROM Win32_OperatingSystem")
For Each objItem In objCollection
intOSVersion = CInt(Replace(Left(objItem.Version, 3), ".", ""))
Next
Set objItem = Nothing
Set objCollection = Nothing
Set objWMI = Nothing
'------
strAccount = Replace(strAccount, """", "")
'--- Настройка правильного наименования "учётки" локальной ОС в зависимости от версии ОС
If intOSVersion < 61 Then
strAccount = Replace(strAccount, "Система", "System", 1, -1, vbTextCompare)
Else
strAccount = Replace(strAccount, "System", "Система", 1, -1, vbTextCompare)
End If
'------
If StrComp(strDomain, strComputer, vbTextCompare) <> 0 Then blnIsDomain = True
If StrComp(strAccount, "System", vbTextCompare) = 0 Or StrComp(strAccount, "Система", vbTextCompare) = 0 Or _
StrComp(strAccount, "Все", vbTextCompare) = 0 Then
strDomain = vbNullString
Else
If blnIsDomain Then
If MsgBox("Задана доменная учётная запись?", vbYesNo + vbQuestion, "Настройка безопасности NTFS") = vbNo Then
strDomain = strComputer
End If
Else
strDomain = strComputer
End If
End If
intTemp = Trim(InputBox("Тип доступа и маска доступа в формате" & vbNewLine & _
"+ЧИСЛО (разрешить) или -ЧИСЛО (запретить)," & vbNewLine & _
"где ЧИСЛО:" & vbNewLine & _
"1 - запись;" & vbNewLine & _
"2 - только чтение;" & vbNewLine & _
"3 - чтение и выполнение;" & vbNewLine & _
"4 - чтение и запись (без выполнения);" & vbNewLine & _
"5 - чтение, запись, выполнение;" & vbNewLine & _
"6 - изменение (без удаления подпапок и файлов);" & vbNewLine & _
"7 - изменение (с удалением подпапок и файлов);" & vbNewLine & _
"8 - смена разрешений;" & vbNewLine & _
"9 - почти полный доступ (без смены владельца);" & vbNewLine & _
"10 - смена владельца;" & vbNewLine & _
"11 - смена разрешений и владельца;" & vbNewLine & _
"12 - полный доступ." & vbNewLine & vbNewLine & _
"Если знак типа доступа (+/-) отсутствует," & vbNewLine & _
"то предполагается разрешение." & vbNewLine & vbNewLine & _
"Для удаления записи из списка" & vbNewLine & _
"в качестве значения маски укажите:" & vbNewLine & _
"+0 - для записи типа ""РАЗРЕШЕНИЕ"";" & vbNewLine & _
"-0 - для записи типа ""ЗАПРЕТ"";" & vbNewLine & _
"0 - для записи любого типа.", "Настройка безопасности NTFS"))
If IsNumeric(intTemp) Then
strTemp = Left(intTemp, 1)
intTemp = CInt(intTemp)
If Abs(intTemp) >= 0 And Abs(intTemp) <= 12 Then
lngACEMask = arrACEMasks(Abs(intTemp))
If intTemp < 0 Then
intACEType = 1
If intOSVersion >= 52 And lngACEMask = FULL_ACCESS Then
lngACEMask = lngACEMask + FLAG_SYNCHRONIZE
'Эта проверка позволяет учесть разницу между значениями маски "Полный доступ"
'у записей разных типов в ОС версий "2000/XP"
End If
ElseIf intTemp > 0 Then
intACEType = 0
lngACEMask = lngACEMask + FLAG_SYNCHRONIZE
Else
Select Case strTemp
Case "-": intACEType = 1
Case "+": intACEType = 0
Case Else: intACEType = -1
End Select
End If
intTemp = Trim(InputBox("Область действия записи:" & vbNewLine & _
"1 - только текущая папка;" & vbNewLine & _
"2 - текущая папка и её файлы;" & vbNewLine & _
"3 - текущая папка и её подпапки;" & vbNewLine & _
"4 - текущая папка, её подпапки и файлы;" & vbNewLine & _
"5 - только файлы текущей папки;" & vbNewLine & _
"6 - только подпапки текущей папки;" & vbNewLine & _
"7 - подпапки и файлы текущей папки." & vbNewLine & vbNewLine & _
"Для обработки записи с любой" & vbNewLine & _
"областью действия задайте значение 0", "Настройка безопасности NTFS"))
If IsNumeric(intTemp) Then
intTemp = CInt(intTemp)
If intTemp < 0 Or intTemp > 7 Then
intTemp = 4
MsgBox "Область действия задана неверно." & vbNewLine & _
"Будет использована стандартная область:" & vbNewLine & _
"ТЕКУЩАЯ ПАПКА, ЕЁ ПОДПАПКИ И ФАЙЛЫ.", _
vbExclamation, "Настройка безопасности NTFS"
End If
Else
intTemp = 4
MsgBox "Область действия не задана или задана неверно." & vbNewLine & _
"Будет использована стандартная область:" & vbNewLine & _
"ТЕКУЩАЯ ПАПКА, ЕЁ ПОДПАПКИ И ФАЙЛЫ.", _
vbExclamation, "Настройка безопасности NTFS"
End If
intACEScope = arrACEScopes(intTemp)
xResult = ModifyEx2_DACL(strDomain, strComputer, strAccount, strPath, intACEType, intACEScope, lngACEMask)
Else
xResult = "Маска доступа задана неверно."
End If
Else
xResult = "Тип доступа или маска доступа не заданы или заданы неверно."
End If
Wscript.Echo xResult
Else
WScript.Echo "Каталог не выбран."
End If
Set objShell = Nothing
Set objFolder = Nothing
Else
WScript.Echo "Учётная запись не указана."
End If
WScript.Quit 0
'======
Function ModifyEx2_DACL(strDom, strWS, strSAN, strDir, intType, intScope, lngMask)
Dim objWMI, objSecSettings, objSD, blnHasInherited, blnHasACE, i
Dim xRes, arrACE, objCollection, objItem, strSID
Dim objSID, objTrustee, objACE
Const SE_DACL_PROTECTED = 4096 'Флаг-признак отключенного режима наследования управляемым каталогом безопасности NTFS от "родителя"
Const INHERITED_ACE = 16 'Флаг-признак того, что текущая запись DACL унаследована от "родителя"
On Error Resume Next
xRes = 0
Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strWS & "\root\cimv2")
If Err.Number = 0 Then
Set objSecSettings = objWMI.Get("Win32_LogicalFileSecuritySetting.Path='" & strDir & "'")
If Err.Number = 0 Then
If objSecSettings.GetSecurityDescriptor(objSD) = 0 Then
If Not IsNull(objSD.DACL) Then
'--- Поиск заданной "учётки" на локальном компьютере или в Active Directory
If Len(strDom) > 0 Then
Set objCollection = objWMI.ExecQuery("SELECT SID FROM Win32_Account WHERE Domain='" & strDom & "' AND Name='" & strSAN & "'")
Else
Set objCollection = objWMI.ExecQuery("SELECT SID FROM Win32_Account WHERE Name='" & strSAN & "'")
End If
'------
If objCollection.Count > 0 Then
If Not CBool(objSD.ControlFlags And SE_DACL_PROTECTED) Then blnHasInherited = True
If blnHasInherited Then
arrACE = Array()
'--- Выборка из исходного DACL записей, не унаследованных от "родителя"
i = -1
For Each objItem In objSD.DACL
If Not CBool(objItem.AceFlags And INHERITED_ACE) Then
i = i + 1
ReDim Preserve arrACE(i)
Set arrACE(i) = objItem
End If
Next
Set objItem = Nothing
'------
'--- Отключение наследования настроек безопасности от "родителя"
objSD.ControlFlags = objSD.ControlFlags + SE_DACL_PROTECTED
xRes = objSecSettings.SetSecurityDescriptor(objSD)
'------
Else
arrACE = objSD.DACL
End If
If xRes = 0 Then
'--- Определение SID "учётки", назначенной для обработки
For Each objItem In objCollection
strSID = UCase(objItem.SID)
Next
Set objItem = Nothing
'------
If lngMask > 0 Then
'--- Подготовка к добавлению в DACL новой записи
Set objSID = objWMI.Get("Win32_SID.SID='" & strSID & "'")
Set objTrustee = objWMI.Get("Win32_Trustee").Spawninstance_()
objTrustee.Domain = strDom
objTrustee.Name = strSAN
objTrustee.SID = objSID.BinaryRepresentation
objTrustee.SidLength = objSID.SidLength
objTrustee.SIDString = strSID
Set objSID = Nothing
Set objACE = objWMI.Get("Win32_Ace").Spawninstance_()
objACE.AceType = intType
objACE.AceFlags = intScope
objACE.AccessMask = lngMask
objACE.Trustee = objTrustee
Set objTrustee = Nothing
i = UBound(arrACE) + 1
ReDim Preserve arrACE(i)
Set arrACE(i) = objACE
objSD.DACL = arrACE
'------
Else
'--- Подготовка к удалению из DACL указанной записи
For Each objACE In arrACE
blnHasACE = False
'--- Поиск указанной записи по SID, области действия и типу
If UCase(objACE.Trustee.SIDString) = strSID Then
If intScope >= 0 Then
If objACE.AceFlags = intScope Then
If intType < 0 Or objACE.AceType = intType Then
blnHasACE = True 'запись заданного типа с искомыми SID и областью действия найдена
End If
End If
Else
blnHasACE = True 'запись с искомым SID найдена (область действия - любая)
End If
If blnHasACE Then
objACE.AccessMask = 0
End If
End If
'------
Next
'------
End If
objSD.DACL = arrACE 'Собственно изменение DACL
Set objACE = Nothing
Erase arrACE
If blnHasInherited Then
'--- Включение наследования настроек безопасности от "родителя",
'если первоначально оно было включено
objSD.ControlFlags = objSD.ControlFlags - SE_DACL_PROTECTED
'------
End If
'--- Итоговое сохраненение изменений, внесённых в дескриптор безопасности
xRes = objSecSettings.SetSecurityDescriptor(objSD)
Select Case xRes
Case 0: xRes = "Успешное завершение."
Case 2: xRes = "Не удалось сохранить изменения DACL." & vbNewLine & "Доступ запрещён."
Case 5, 9: xRes = "Не удалось сохранить изменения DACL." & vbNewLine & "Для выполнения операции недостаточно полномочий."
Case 21: xRes = "Не удалось сохранить изменения DACL." & vbNewLine & "Заданы недопустимые значения параметров."
Case Else: xRes = "Не удалось сохранить изменения DACL." & vbNewLine & "Неизвестная ошибка."
End Select
'------
Else
xRes = "Не удалось отключить наследование безопасности для папки " & UCase(strDir)
End If
Else
xRes = "Не найдена учётная запись объекта " & UCase(strDom & "\" & strSAN)
End If
Set objCollection = Nothing
Else
xRes = "Список управления доступом (ACL) к заданному объекту пуст."
End If
Else
xRes = "Не удалось прочитать дескриптор безопасности объекта."
End If
Set objSD = Nothing
Set objSecSettings = Nothing
Else
xRes = "Ошибка " & CStr(Err.Number) & vbNewLine & Err.Description
Err.Clear
End If
Else
xRes = "Ошибка " & CStr(Err.Number) & vbNewLine & Err.Description
Err.Clear
End If
Set objWMI = Nothing
On Error GoTo 0
ModifyEx2_DACL = xRes
End Function[/code]
Сценарий 5.
Очистка DACL указанного дерева папок от записей с не олицетворёнными SID.
Сценарий способен работать и в графическом, и в консольном режимах.
Подробное описание функциональности сценария и особенностей его работы - во встроенной справке (см. функцию View_Help()).
[code]Option Explicit
Dim objFS, objShell, objFolder, objFile, objWShell, objWMI
Dim strTranslator, strLogFile, strComputer, strTargetPath
Dim objDict, objRegExp, arrTemp, intNumArgs, strKey, strTemp, i
Dim blnIsConsole, blnRecursive, blnCreateLog, blnSilent, blnAvailable, blnHasError
strComputer = "."
blnCreateLog = True: blnSilent = True: blnAvailable = True
Set objFS = CreateObject("Scripting.FileSystemObject")
strTranslator = objFS.GetBaseName(WScript.FullName)
If StrComp(strTranslator, "cscript", vbTextCompare) = 0 Then blnIsConsole = True
If blnIsConsole Then
arrTemp = Array("tc", "tlp", "r", "nl", "s")
Set objDict = CreateObject("Scripting.Dictionary")
objDict.CompareMode = 1
For i = 0 To UBound(arrTemp)
objDict.Add arrTemp(i), vbNullString
Next
'--- Проверка корректности набора заданных ключей, определение значений ключей
Set objRegExp = CreateObject("VBScript.RegExp")
objRegExp.Global = True
objRegExp.IgnoreCase = True
objRegExp.Pattern = "^[-/]"
intNumArgs = WScript.Arguments.Count
Select Case intNumArgs
Case 0: Call View_Help: WScript.Quit 0
Case 1
strTemp = objRegExp.Replace(WScript.Arguments.Item(0), "")
If strTemp = "?" Then
Call View_Help: WScript.Quit 0
Else
If Len(strTemp) > 1 Then
If LCase(Left(strTemp, 4)) <> "tlp:" Then
Call Err_Message(1, strTemp)
WScript.Quit 0
Else
If Len(strTemp) > 4 Then