В первой и второй части я рассказал про основные моменты управления принтерами в PowerShell и теперь хочу поговорить о правах на принтеры. Т.к. принтеры управляются с помощью классов WMI, то управление правами доступа к ним будет превращаться в очередную эпохальную эпопею, которую я исследовал при изучении безопасности Share Permissions (вот ссылка на эти статьи в моём прежнем блоге: http://vpodans.spaces.live.com/lists/cns!BB1419A2CFC1E008!178). Однако, с принтерами оказалось всё печальней :'( Мне так и не удалось заставить работать метод SetSecurityDescriptor. Итак, я расскажу о своих кратких исследованиях и в чём же мы имеем проблему.

Для чтения прав доступа принтера потребуется метод GetSecurityDescriptor:

[System32] $a=(gwmi win32_printer -filter "name='cutepdf writer'").getsecuritydescriptor() [System32] $a __GENUS : 2 __CLASS : __PARAMETERS __SUPERCLASS : __DYNASTY : __PARAMETERS __RELPATH : __PROPERTY_COUNT : 2 __DERIVATION : {} __SERVER : __NAMESPACE : __PATH : Descriptor : System.Management.ManagementBaseObject ReturnValue : 0 [System32] $a.Descriptor | fl [a-z]* ControlFlags : 32780 DACL : {System.Management.ManagementBaseObject, System.Management.ManagementBaseObject,System.Mana gement.ManagementBaseObject, System.Management.ManagementBaseObject...} Group : System.Management.ManagementBaseObject Owner : System.Management.ManagementBaseObject SACL : TIME_CREATED : [System32] $a.descriptor.dacl[0] | fl [a-z]* AccessMask : 983052 AceFlags : 0 AceType : 0 GuidInheritedObjectType : GuidObjectType : TIME_CREATED : Trustee : System.Management.ManagementBaseObject [System32] $a.descriptor.dacl[0].trustee | fl [a-z]* Domain : Thor Name : Admin SID : {1, 5, 0, 0...} SidLength : 28 SIDString : S-1-5-21-3020384060-3247076327-363933757-1000 TIME_CREATED : [System32]

Как видите, метод GetSecurityDescriptor вернул нам единственный параметр - Descriptor. Заглянув в Descriptor, нам нужно было найти параметр DACL, который уже содержит все пермишены. Подробнее материал изложен тут: WMI Security Descriptor Objects.

Примечание: методы GetSecurityDescriptor и SetSecurityDescriptor доступны только в ОС начиная от Windows Vista/Windows Server 2008 и выше.

Структура DACL содержит в себе как права доступа (AccessMask), так и сведения о пользователе, который имеет указаную AccessMask маску доступа (Trustee). Я попробовал создать идентичную структуру SecurityDescriptor (как описано в ссылке: WMI Security Descriptor Objects) и получил вот такой скрипт:

# задаём пользователя, которому хотим предоставить доступ
$user = "everyone"
# объявляем необходимые классы, которые описывают дескриптор безопасности
$SD = ([WMIClass] "Win32_SecurityDescriptor").CreateInstance()
$ace = ([WMIClass] "Win32_Ace").CreateInstance()
$Trustee = ([WMIClass] "Win32_Trustee").CreateInstance()
# преобразовываем имя пользователя в строковый SID и массив байтов для Win32_Trustee
$SID = (new-object security.principal.ntaccount $user).translate([security.principal.securityidentifier])
[byte[]] $SIDArray = ,0 * $SID.BinaryLength
$SID.GetBinaryForm($SIDArray,0)
# заполняем необходимыми данными класс Win32_Trustee
$Trustee.Name = $user
$Trustee.SID = $SIDArray
# заполняем поля класса Win32_Ace, которые описывают права доступа и заворачиваем
# пользователя в лице класса Win32_Trustee
# AccessMask в контексте принтера может принимать значения:
# 524288 - Take ownership
# 131072 - read permissions
# 262144 - change permissions
# 983088 - manage documents
# 983052 - manage printers
# 131080 - print + read permissions

$ace.AccessMask = 983052
$ace.AceType = 0
$ace.AceFlags = 0
$ace.Trustee = $Trustee
# заворачиваем полученный объект Win32_Ace в параметр DACL класса Win32_SecurityDescriptor
$SD.DACL = $ace
# получаем объект принтера, с которым собираемся работать
$Printer = gwmi win32_printer -filter "name='CutePDF Writer'"
# получаем свойства метода SetSecurityDescriptor, чтобы в соответствии с ними
# завернуть туда SecurityDescriptor
$inParams = $Printer.psbase.GetMethodParameters("SetSecurityDescriptor")
# заворачиваем SecurityDescriptor в параметр Descriptor метода SetSecurityDescriptor
$inParams.Descriptor = $SD
# применяем метод SetSecurityDescriptor
$Printer.SetSecurityDescriptor($inParams)

И попробуем его запустить:

[System32] $user = "everyone"
[System32] $SD = ([WMIClass] "Win32_SecurityDescriptor").CreateInstance()
[System32] $ace = ([WMIClass] "Win32_Ace").CreateInstance()
[System32] $Trustee = ([WMIClass] "Win32_Trustee").CreateInstance()
[System32] $SID = (new-object security.principal.ntaccount $user).translate([security.principal.securityidentifier])
[System32] [byte[]] $SIDArray = ,0 * $SID.BinaryLength[System32] $SID.GetBinaryForm($SIDArray,0)
[System32] $Trustee.Name = $user
[System32] $Trustee.SID = $SIDArray
[System32] $ace.AccessMask = 983052
[System32] $ace.AceType = 0
[System32] $ace.AceFlags = 0
[System32] $ace.Trustee = $Trustee
[System32] $SD.DACL = $ace
[System32] $Printer = gwmi win32_printer -filter "name='CutePDF Writer'"
[System32] $inParams = $Printer.psbase.GetMethodParameters("SetSecurityDescriptor")
[System32] $inParams.Descriptor = $SD
[System32] $Printer.SetSecurityDescriptor($inParams)   

__GENUS          : 2
__CLASS          : __PARAMETERS
__SUPERCLASS     :
__DYNASTY        : __PARAMETERS
__RELPATH        :
__PROPERTY_COUNT :
__DERIVATION     : {}
__SERVER         :
__NAMESPACE      :
__PATH           :
ReturnValue      : 2147749896


[System32]

Как видно, ни одна строка не вернула ошибок, а последняя строка вернула значение 2147749896. Прогулявшись по MSDN нашёл описание этой ошибки: Win32SDToSDDL Method of the Win32_SecurityDescriptorHelper Class (практически везде данное значение в контексте SecurityDescriptor интерпретируются так):

  • One of the parameters to the call is not correct.

один из параметров вызова указан неверно. Давайте попробуем проанализировать, что мы сформировали и сравним с данными, которые получили методом GetSecurityDescriptor:

[System32] $inparams 

__GENUS          : 2
__CLASS          : __PARAMETERS
__SUPERCLASS     :
__DYNASTY        : __PARAMETERS
__RELPATH        :
__PROPERTY_COUNT : 1
__DERIVATION     : {}
__SERVER         :
__NAMESPACE      :
__PATH           :
Descriptor       : System.Management.ManagementBaseObject


[System32] $inparams.Descriptor | fl [a-z]* ControlFlags :

DACL         : {System.Management.ManagementBaseObject}
Group        :
Owner        :
SACL         :
TIME_CREATED : 


[System32] $inparams.Descriptor.dacl[0] | fl [a-z]* 

AccessMask              : 983052
AceFlags                : 0
AceType                 : 0
GuidInheritedObjectType :
GuidObjectType          :
TIME_CREATED            :
Trustee                 : System.Management.ManagementBaseObject 


[System32] $inparams.Descriptor.dacl[0].trustee | fl [a-z]* 

Domain       :
Name         : everyone
SID          : {1, 1, 0, 0...}
SidLength    :
SIDString    :
TIME_CREATED : 
[System32]

Если сравнивать с первым листингом, где мы получали текущий SecurityDescriptor, то мы сохранили структуру SecurityDescriptor и в соответствующие поля записали нужные данные. При этом я также пытался для Trustee записать строковый SIDString и SIDLength:

$Trustee.SIDString = $SID.Value
$Trustee.SIDLength = $SID.BinaryLength

и получил уже такой Trustee:

[System32] $inparams.Descriptor.dacl[0].trustee | fl [a-z]* 

Domain       :
Name         : everyone
SID          : {1, 1, 0, 0...}
SidLength    : 12
SIDString    : S-1-1-0
TIME_CREATED : 


[System32]

От этого результат не изменился. Попробовал вызвать несколько иначе метод SetSecurityDescriptor:

$Printer.psbase.invokemethod("SetSecurityDescriptor", $inParams, $null)


и всё по старому. Я попытался нагуглить этот вопрос поисковой фразой "setsecuritydescriptor win32_printer powershell" (да-да, каюсь, я пользуюсь гуглем, как это ни прискорбно). И он мне выдал меньше одной страницы и 2 вменяемые ссылки, одна из которых ведёт на MSDN, а вторая на какой-то французский сайт (в котором я без переводчика плохо понимаю, а жаль) - http://powershell-scripting.com/index.php?option=com_joomlaboard&Itemid=76&func=view&id=2292&catid=6, но человек там творил что-то страшное и я понял, что там помощи не ждать.

Вобщем, этот вопрос пока остаётся открытым. Что ему не нравится, я пока не могу понять. Управление SecurityDescriptor в WMI - это не самая удачная модель управления безопасностью в WMI, но пока это почти единственный способ добиться результата - приходится с этим работать. Хотя, на первый взгляд может показаться, что там всё страшно и ужасно, но на самом деле, если разобрать предметно вопрос и поупражняться, всё оказывается вполне понятным, хоть и не совсем логичным и не всегда это хочет работать как положено :)

PowerShell |  ACL |  WMI
Friday, November 14, 2008 9:21:45 PM (FLE Standard Time, UTC+02:00)   Comments [0]    

 

 · 
All content © 2008 - 2010, Vadims Podāns
"Spaces" Theme provided by: Vadims Podāns
About


E-mail - Send mail to the author(s)
Live Messenger -
My former blog -
For english language visitors
Библиотека
Календарик
<September 2010>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

Карта расположения посетителей
Favorites





Disclaimer
Вся информация на сайте предоставляется на условиях «как есть», без предоставления каких-либо гарантий и прав.

При использовании материалов c данного сайта ссылка на оригинальный источник обязательна.