когда мы выяснили, как образована
Теперь, когда мы выяснили, как образована информация о пользователях в Unix-системах, мы можем посмотреть, как это делается в NT/2000. Большая часть этой информации сходна с уже рассмотренной, поэтому следует обратить внимание на различия между двумя операционными системами.
Хранение и доступ к информации о пользователях в Windows NT/2000
NT/2000 хранит постоянную информацию о пользователях в базе данных SAM
(Security Accounts Manager, диспетчер учетных записей в системе защиты). База данных SAM - это часть реестра NT/2000, находящаяся в
%SYSTEMROOT%/system32/config. Файлы, входящие в состав реестра, хранятся в двоичном формате, следовательно, обычные функции для работы с текстом в Perl нельзя применять для чтения или внесения изменений в эту базу данных. Теоретически, если NT/2000 не запущена, можно использовать операторы над двоичными данными (раск() и unpack()) для работы с SAM, но такой способ безумен и мучителен.
К счастью, существуют более удачные методы доступа к этой информации и работы с ней в Perl.
Один из способов - вызвать внешнюю программу, которая обесепечит ваше взаимодействие с операционной системой. На каждой машине с NT/2000 есть команда net, она позволяет добавлять, удалять и просматривать данные о пользователях, net довольно странная и ограниченная команда и, вероятно, к ее использованию стоит прибегать в крайнем случае.
Вот так, например, команда net выполняется на машине с двумя учетными записями:
C:\>net users
User accounts for
\\HOTDIGGITYDOG
------------------------------------------------------
Administrator Guest
The command completed successfully.
При необходимости, вывод этой команды было бы просто разобрать из Perl. Помимо net существуют и другие коммерческие пакеты, в состав которых входят программы, запускаемые из командной строки и выполняющие те же действия.
Другой подход - использовать модуль Wi п32: : Net Admin (входящий в состав дистрибутива ActiveState Perl) или один из модулей, созданных для расширения функциональности Win32:: NetArMn. В их число входят модули Win32: :AdminMisc Дэвида Рота (David Roth, модуль находится на http://www.roth.net) и Win32: :UserAdmiri (описанный Эшли Мэггитом (Ashley Meggitt) и Тимоти Ритчи (Timothy Ritchey) в книге «Windows NT User Administration» (Windows NT: Администрирование пользователей), модуль можно найти на ftp://ftp.oreilly.com/pub/ examples/windows/winuser/).
Для выполнения большинства операций с пользователями я предпочитаю модуль Win32: .-AdrcinMisc, поскольку он предлагает множество инструментов системного администрирования, кроме того, Рот активно поддерживает его в нескольких форумах. И хотя доступная в Сети документация по этому модулю очень хороша, лучшая документация -это книга самого автора «Win32 Perl Programming: The Standard Extensions» (Программирование на Perl для Win32: стандартные расширения) (Macmillan Technical Publishing). Такую книгу всегда полезно иметь под рукой, если вы собираетесь писать на Perl программы для Win32.
Приведу пример, перечисляющий пользователей на локальной машине, а также некоторые сведения об этих пользователях. Выводимые в примере строки похожи на строки из файла
/etc/passwd в Unix:
use Win32::AdminMisc;
и получаем список всех локальных пользователей
Win32::AdminMisc::GetUsers('','',\@users) or
die "Невозможно получить список пользователей: $!\п";
П получаем их атрибуты и выводим их foreach $user (@users){
Win32::AdminMisc::UserGetMiscAttributes('',$user,\%att ribs)
or warn " Невозможно получить атрибуты: $!\п"; print join(":",$user,
' * '
$attribs{USER_USER_ID},
$attribs{USER_PRIMARY_GROUP_ID},
$attribs{USER_COMMENT},
$attribs{USER_FULL_NAME},
$attribs{USER_HOME_DIR_DRIVE}.
$attribs{USER_HOME DIR}, "),"\n";
}
Наконец, вы можете использовать модуль Win32: : OLE для доступа к интерфейсам активных служб каталогов (ADSI, Active Directory Service Interfaces). Данная служба встроена в Windows 2000 и ее можно установить на Windows NT 4.0. Эта тема и соответствующие примеры будут подробно рассмотрены в главе 6 «Службы каталогов».
Другие примеры программ на Perl для работы с пользователями в NT/2000 встретятся позже, а пока вернемся к обсуждению различий между пользователями в Unix и Windows NT/2000.
Идентификаторы пользователей в NT/2000
Идентификаторы пользователей в NT/2000 создаются не простыми смертными и их нельзя использовать повторно. В отличие от Unix, где мы просто берем следующий свободный идентификатор пользователя, в Windows NT/2000 операционная система уникальным образом генерирует эквивалентный идентификатор каждый раз при создании пользователя. Уникальный идентификатор пользователя (который в NT/2000 называется относительным идентификатором или RID, Relative ID) объединяется с идентификатором машины и домена, и вместе они образуют длинный идентификационный номер - идентификатор безопасности (SID, Security ID), который используется в качестве1 идентификатора пользователя (UID). Например, RID равный FOG, является частью длинного идентификатора SID, который выглядит так:
S-1-5-21-2046255566-1111630368-2110791508-500
RID - это то число, которое мы получаем в результате вызова функции UserGetMiscAttributes() в последнем примере. Вот так должен выглядеть код для получения идентификатора RID конкретного пользователя:
use Win32::AdminMisc;
Win32: :AdrninMisc: : UserGetMiscAttriuutest ' '.
$user \%attribs): print $attnbs{USEFLUSER_ID}, "\n";
Вы не сможете (каким бы то ни было нормальным способом) заново создать пользователя после того, как он был удален. И даже если вы создадите пользователя с тем же самым именем, его идентификатор безопасности (SID) все равно будет отличаться. У нового пользователя не будет доступа к файлам и ресурсам его предшественника.
По этой причине в некоторых книгах по NT рекомендуется переименовывать учетные записи, которые наследуются от других людей. Если к новому работнику должны перейти все файлы и привилегии уходящего работника, следует скорее переименовать существующую учетную запись, чтобы сохранить SID, чем создавать новую учетную запись, переписывать все файлы и затем удалять старую. Лично я нахожу такой способ передачи учетных записей несколько грубоватым, поскольку в этом случае новый работник наследует все поврежденные и бесполезные настройки реестра от своего предшественника. Но это самый удобный способ, а иногда это важно.
Частично эта рекомендация связана с мучениями при передаче права собственности на файлы. В Unix привилегированный пользователь может сказать: «Изменить права владения для всех этих файлов так, чтобы они перешли к новому пользователю». В NT, однако, право на владение нельзя дать, его можно только получить. К счастью, существует два способа обойти это ограничение и считать, что мы используем семантику Unix. В Perl мы можем:
- Программу chown либо из пакета Microsoft NT Resource (коммерческий продукт, упомянутый далее), либо из дистрибутива Cygwin с
http://www.cygnus.com (бесплатный). - Программу setowner, входящую в число утилит NTSEC, продаваемых Pedestal Software на http://www.pedestalsoftware.com. Я предпочитаю ее, т. к. программа отличается гибкостью и при этом требует наименьших затрат.
- Использовать модуль Win32: : Perms, написанный Дэвидом Ротом (David Roth), который можно найти на http://www.oth.net/perl/perms. Вот простой пример, изменяющий владельца каталога и его содержимое, включая подкаталоги:
- Учетные записи пользователей всего домена должны обслуживаться централизованно. Администраторы должны иметь возможность определить произвольное подмножество прав и привилегий пользователей, которые можно присвоить всей группе одновременно.
- При желании, все машины домена должны иметь возможность использовать преимущества такого централизованного управления. Администратор отдельной машины по-прежнему должен иметь возможность создавать пользователей, «живущих» только на этой машине.
- Администратор каждой машины должен иметь возможность решать, каким пользователям разрешать доступ к этой машине. Администратор должен иметь возможность делать это, используя группы, существующие в домене, а не задавать имена пользователей вручную.
- Члены этих групп и локальные пользователи должны иметь возможность считаться равными с точки зрения администратора (речь идет о правах и прочем).
- Создает на каждой машине локальную группу Local-Autnorized Omphies.
- Добавляет в эту локальную группу локальные гостевые учетные записи.
- Добавляет глобальную группу Global-Onph People в указанную локальную группу.
- Добавляет право (права пользователей мы обсудим в следующем разделе) Log on Locally (регистрироваться локально) локальной группе Local-Authorized Omphies.
- Удаляет право Log on Locally для всех остальных неавторизованных групп.
- В Windows 2000 используются активные каталоги (Active Directory, более подробную информацию о них можно найти в главе 6) для хранения информации о пользователях. Это означает, что информация о глобальных группах теперь хранится в активном каталоге на контроллере домена, а не в его SAM.
- Локальные группы теперь называются локальными группами домена.
- Была добавлена третья,
пространственная (scope) группа. Помимо глобальных и локальных групп домена в Windows 2000 добавились
универсальные группы. Универсальные группы, по существу, разрывают границы домена. В них могут входить учетные записи, глобальные группы и универсальные группы из любого места каталога. В локальные группы домена могут входить как глобальные группы, так и универсальные группы.
$acl = new Win3?: Pernis();
$acl->0wner($NewAccountName):
Sresult = $aci->SetReci;rse($dir);
$acl->Close():
Пароли в NT/2000
Алгоритмы, применяемые для шифрования паролей, ограничивающих доступ к владениям пользователей в NT/2000 и Unix, криптографически несовместимы. Вы не можете передавать зашифрованные пароли из одной операционной системы в другую, что бывает необходимо для смены пароля или создания учетных записей. В результате, два набора паролей приходится использовать и/или хранить синхронно. Это различие - просто проклятье всех системных администраторов, вынужденных управлять смешанным окружением Unix-NT/2000. Некоторые администраторы обходят эти проблемы, используя специальные модули авторизации - как коммерческие, так и прочие.
Если вы не применяете специальные механизмы авторизации, то единственное, что вы можете сделать как программист на Perl, - создать систему, благодаря которой пользователи смогут представлять свои пароли в виде обычного текста. Такие пароли позволяют выполнять связанные с ними операции (изменение пароля и пр.), различные в каждой операционной системе.
Группы в NT
До сих пор при обсуждении идентификации пользователя я не упоминал о различиях между хранением этой информации на локальной машине и средствами какой-либо сетевой службы, например NIS. Для той информации, о которой шла речь, не было существенно, используется ли она на одной системе, на всех системах в сети или в рабочей группе. Чтобы обоснованно говорить о группах пользователей в NT/2000 и их связи с Perl, мы должны, к сожалению, отойти от этого соглашения. Мы остановимся на группах в Windows NT 4.0. В Windows 2000 был добавлен еще один уровень сложности, поэтому информацию о группах в Windows 2000 я вынес во врезку «Изменения групп в Windows 2000», которую вы найдете в этой главе.
В NT информация о пользователях может храниться в одном из двух мест: в SAM на конкретной машине или в SAM на контроллере домена. Именно здесь проявляется различие между локальным пользователем, который может входить в систему и работать только на одной машине, и пользователем домена, который может регистрироваться на любой из машин в домене.
Группы в NT также бывают двух типов: глобальные и локальные. Разница между ними заключается не совсем в том, чего можно было бы ожидать из названия. Неверно, что первая состоит из пользователей домена, а вторая из локальных пользователей. Так же неверно и то, что один тип пользователей имеет доступ только на одну машину, в то время как другой пользуется всей сетью, как могли ожидать лица, знакомые с Unix. Частично верно и одно определение, и другое, но давайте рассмотрим все подробно.
Если начать с рассмотрения целей, лежащих за названием, и механизмом их реализации, станет немного яснее. Вот чего мы пытаемся достичь:
Глобальные и локальные группы позволяют нам добиться всего вышеперечисленного. В двух предложениях это можно объяснить так: в глобальные группы входят только пользователи домена. В локальные группы входят локальные пользователи, а также в них входят/импортируются пользователи глобальных групп.
Вот простой пример для объяснения, как все это работает. Скажем, у вас есть домен NT для кафедры в университете, в котором уже созданы пользователи домена - студенты, преподаватели и служащие. Когда появляется новый исследовательский проект под названием Omphalos-kepsis, системные администраторы создают новую глобальную группу Global-Omph People. В данную глобальную группу входят все пользователи домена, занятые в этом проекте. Когда студенты и персонал присоединяются к проекту или выходят из него, они, соответственно, добавляются или удаляются из этой группы.
Для этого проекта используется отдельный компьютерный класс. На машинах такого класса созданы гостевые учетные записи для нескольких представителей факультета с других кафедр (они не являются пользователями домена). Системный администратор этого класса делает следующее (разумеется, на Perl), чтобы запретить использовать компьютеры тем, кто не занят в этом проекте:
В результате только авторизованные локальные пользователи и пользователи из авторизованных глобальных групп могут регистрироваться на машинах этого класса. Как только в группу Global-Omph People добавляется новый пользователь, он автоматически получает право регистрироваться на этих машинах без каких-либо изменений учета. Как только вы освоитесь с понятием локальных/глобальных групп, такая схема покажется вам удобной.
Подобная схема была бы совсем удобной, если бы не усложняла программирование на Perl. Во всех упомянутых модулях существуют отдельные функции для локальных и глобальных групп. Например, в Win32: :NetAdmin имеем:
GroupCreate() GroupDelete() GroupGetAttributes() GroupSetAttributes() GroupAddUsers() GroupDeleteUsers( ) GroupIsMember( ) GroupGetMembers() |
LocalGroupCreate() LocalGroupDelete( ) LocalGroupGetAttributes( ) LocalGroupSetAttributes( ) LocalGroupAddlisers( ) LocalGroupDeleteUsers( ) LocalGrouoIsMember( ) LocalG-uijpGetMeTibers() |
Отличия групп в Windows 2000
Практически все, что мы говорили о локальных и глобальных группах в NT, также относится и к Windows 2000, но существует несколько характерных особенностей, о которых необходимо упомянуть:
На момент написания этой книги стандартные модули Perl для администрирования
учетных записей еще не учитывали таких изменений. Эти модули можно по-прежнему использовать, поскольку интерфейсы NT4 SAM пока еще действуют, но они не смогут применять новые возможности. Поэтому данная врезка единственное место, .где мы упоминаем об этих различиях в Windows 2000. Подробную информацию вам придется искать в описании интерфейсов служб активных каталогов (Active Directory Service Interfaces, ADSI), о которых речь пойдет в главе 6.
Таким образом, не исключено, что в программах для выполнения одной и той же операции понадобится употребить две функции. Например, если нужно получить список всех групп, в которые может входить пользователь, придется вызвать две функции - одну для локальных, а другую для глобальных групп. Приведенные функции характеризуются своими названиями. Детальное описание можно найти в документации и книге Рота.
Вот короткий совет из книги Рота: чтобы получить список локальных групп, ваша программа должна выполняться с привилегиями администратора, но имена глобальных групп должны быть доступны всем пользователям.
Права пользователей в NT/2000
Последнее различие между информацией о пользователях в Unix и NT/2000, о котором мы поговорим, - это понятие «пользовательских прав». В Unix действия, предпринимаемые пользователем, ограничиваются как правами доступа к файлам, так и различиями между суперпользователем и остальными пользователями. В NT/2000 права реализованы гораздо сложнее. Пользователи (и группы) могут быть наделены особой силой, которая становится частью информации о пользователях. Например, если предоставить обычному пользователю право Change the System Time (Изменение системного времени), то он сможет изменять настройки системных часов.
Некоторые считают, что такая концепция прав пользователей сбивает с толку, поскольку они предпринимали попытки прибегнуть к помощи отвратительного диалогового окна User Rights Policy (Политика прав пользователей) из NT 4.0 в приложениях User Manager (Диспетчер пользователей) или User Manager for Domains (Диспетчер пользователей для доменов). В этом диалоговом окне информация представлена виде, прямо противоположном тому, в котором большинство пользователей ожидают ее там увидеть. Она содержит перечень возможных прав пользователей и предлагает добавить группы или пользователей к списку тех, у кого такие права уже есть. Вот как выглядит это диалоговое окно (рис. 3.1) пользовательских прав в действии.
Было бы лучше, если бы права пользователей разрешалось добавлять и удалять, а не наоборот. В действительности, именно так мы и будем поступать, используя Perl.
Один из возможных подходов - вызвать программу ntrights.exe из Microsoft NT Resource Kit. Если вы об этом никогда не слышали, обязательно прочитайте следующую врезку.
Работать с ntrights.exe очень легко; достаточно вызывать эту программу из Perl, как любую другую (т. е., применяя обратные кавычки или функцию system()). В этом случае мы обратимся к ntrights.exe при помощи такой командной строки:
чтобы предоставить право пользователю или группе (на машине rnachi-пепате,
имя которой указывать не обязательно). Чтобы отнять право, необходимо применить такой синтаксис:
С:\>ntrights.exe -г <ngtit name> +u <user or group narr,e> [-m \\vachintnaive]
Пользователи Unix знакомы с употреблением символов + и - (как в chmod), в данном случае для ключа -г, чтобы предоставить или лишить привилегий. Список допустимых имен (например, SetSys::emti-mePrivilege для разрешения устанавливать системное время) можно найти в документации Microsoft NT Resource Kit no команде ntrights
Второй подход, с использованием только Perl, связан с применением модуля Win32: : Lanman, написанного Йенсом Хелбергом (Jens Helberg), который можно найти либо на ftp://ftp.roth.net/pub/ntperl/Others/ Lanman/, либо на
http://jenda.krynicky.cz. Начнем с того, что рассмотрим процесс получения прав для учетной записи. Этот процесс состоит из нескольких шагов, поэтому рассмотрим его подробно, шаг за шагом.
Сначала необходимо загрузить модуль:
use Win32::Lanman;
Затем следует получить идентификатор (SID) для учетной записи, с которой надо работать. В следующем примере мы получим SID для учетной записи Guest:
unless(Win32: : Lanman: : LsaLookupNames($server, [ 'Guest' ]. \@info)
{ die "Невозможно найти SID':
".Win32::Lanman::Get LastError()."\n";
}
@info - это массив ссылок на анонимные хэши, каждый элемент которого соответствует отдельной учетной записи (в нашем случае это один-единственный элемент для учетной записи Guest). В каждом хэ-ше есть такие ключи: domain, do;nainsid, relativeid, sid и use. На следующем шаге нас будет интересовать только ключ sid. Теперь мы можем узнать о правах этой учетной записи:
unless (Win32: : Lanman :: LsaEnurierateAccountRights($server.
${$info[0]}{sid}, \@rights)){ die "Невозможно узнать права:
"32: :Lanmai .GetL.asrError() "\r"\
Microsoft Windows NT/ Windows 2000 Resource Kits
«У вас должен быть установлен NT 4.0 Server и/или Workstation Resource Kit» - в этом, обычно, единодушны и серьезные администраторы NT, и средства информации. Microsoft Press опубликовал два больших тома, каждый из которых полон жизненно необходимой информации об одной из версий операционной системы NT/2000. Ценность этих книг заключается не столько в сведениях, сколько в компакт-дисках, распространяемых вместе с книгами. На компакт-дисках есть множество важных утилит для администрирования NT/2000. Утилиты, поставляемые с книгой по NT/2000 Server, содержат и утилиты, входящие в компакт-диск для версии NT Workstation/Windows 2000 Professional. Если вам придется выбирать одну из книг, предпочтите издание, посвященное NT/2000 Server.
Многие из этих утилит распространяются группой разработчиков NT/2000, написавших собственные программы, поскольку они нигде не смогли найти нужные им инструменты. Например, в состав этих утилит входят программы для добавления пользователей, изменения информации о безопасности файловой системы, отображения установленных драйверов принтеров, работы с профилями, помощи с отладкой служб доменов и обозревателя сети и т. д.
Инструменты из пакета дополнительных программ поставляются «как есть» (as is), иными словами, они практически не поддерживаются. Такая политика «неподдержки» может показаться грубой, но она преследует важную цель - дать возможность Microsoft предоставить администраторам множество полезных программ и не заставлять их платить непомерно много за поддержку. В программах из этого пакета есть некоторые мелкие ошибки, но, в целом, они работают замечательно. Обновления, исправляющие ошибки в некоторых утилитах, публикуются на веб-сайте Microsoft.
Массив ©rights теперь содержит набор строк, описывающих все права учетной записи Guest.
Узнать, чему соответствует API-имя ( Application Program Interface, интерфейс прикладного программирования) того или иного права пользователя, может оказаться непростой задачей. Самый легкий способ выяснить, каким правам какие имена соответствуют, - ознакомиться с документацией SDK (Software Developement Kit, набор инструментальных средств разработки программного обеспечения), которая находится на http://msdn.microsoft.com. Нужную документацию отыскать легко, потому что Хелберг сохранил имена стандартных
функций SDK для функций в Perl. Чтобы найти имена доступных прав, достаточно поискать в MSDN (Microsoft's Developer Network) «LsaEnumerateAccountRights», и мы быстро их отыщем.
Подобная информация полезна и для изменения прав пользователей. Например, если мы хотим разрешить пользователю Guest выключать (останавливать) систему, мы можем применить следующее:
use Win32::Lanman;
unless (Win32::Lanman::LsaLookupNames($server ['Guest'],
\@info)) {
die " Невозможно найти SID; ".Win32::Lanman::GetLastError()."\n"
}
unless (Win32::Lanman::LsaAddAccountRights($server,
${$info[0]}{sid}, [&SE^SHUTDOWN_NAME])) {
die " Невозможно изменить права: ". Win32::Lanman::GetLastError()."\n"
}
На этот раз мы нашли право SE_SHUTDOWN_NAME в документации по SDK и применили подпрограмму &SE__SHUTDOWN_NAME (определенную в Win32: : Lanman), возвращающую значение этой константы SDK.
Win32: : Lanman: : LsaRemoveAccountRights() - это функция. Она используется для лишения прав и принимает аргументы, схожие с теми, которые применяет функция для добавления прав.
Перед тем как перейти к другим темам, необходимо упомянуть, что в Win32:: Lanman входит также и функция, действующая аналогично неудачному интерфейсу диспетчера пользователей, о котором мы говорили раньше. Вместо того чтобы сопоставлять пользователей с правами, мы можем сопоставлять права с пользователями. Применяя функцию Win32: : Lanman: : LsaEnumerateAccountsWithUserRight(), мы можем получить список идентификаторов (SID), у которых есть определенные поля. Иногда такое знание может сослужить добрую службу.