в Unix, поскольку стандартные вызовы
Подпрограммы для создания и удаления учетных записей в Windows NT/2000
Процесс создания и удаления учетных записей в Windows NT/2000 несколько проще, чем в Unix, поскольку стандартные вызовы API для этой операции существуют в NT. Как и в Unix, мы могли бы вызвать внешнюю программу, чтобы выполнить подобную работу (например, вездесущую команду net с ключом USERS/ADD), но проще использовать API-вызовы из многочисленных модулей, о некоторых из которых мы уже говорили. Функции для создания учетных записей есть, например, в Win32::NetAdmin, Win32: :UserAdmin, Win32API::Net и Win32::Lanman. Пользователям Windows 2000 лучше ознакомиться с материалом по ADSI в главе 6.
Выбор одного из этих модулей, в основном, дело вкуса. Чтобы разобраться в отличиях между ними, рассмотрим существующие вызовы для создания пользователей. Эти вызовы описаны в документации Network Management SDK на http://msdn.microsoft. com (если вы ничего не можете найти, поищите «NetUserAdd»). NetllserAdd() и другие вызовы принимают в качестве параметра информационный уровень данных. Например, если информационный уровень равен 1, структура данных на С, передаваемая вызову для создания пользователя, выглядит так:
typedef struct JJSER_INFO_1 {
LPWSTR usri1_name;
LPWSTR usri1_oassworc';
DWORD usril_passwora_age:
DWORD usril_oriv:
LPWSTR usril_home_dir;
LPWSTR usri1_comment;
DWORD usri1_flags:
LPWSTR usri1_script_pat!i:
}
Если используется информационный уровень, равный 2, структура значительно расширится:
typedef struct _UbER_INrG;
LPWSTR | usn2_name; |
LPWSTP | lisri? password: |
DWORD | usri2_password_age: |
DWORD | usn2_priv: |
LPWSTR | Lisri2_home_dir; |
LPWSTR | usri2_conwient : |
DWORD | usri2_flags; |
LPWSTR | usri2_scnpt_path; |
DWORD | usri2_auth_f lags; |
LPWSTR | usri2_fiJll_name: |
LPWSTR | usri2_usr_comment; |
LPWSTR | usri2_parms: |
LPWSTR | usri2_workstations: |
DWORD | usri2_last_logon; |
DWORD | usn2_last_logoff ; |
DWORD | usri2_acct_expires; |
DWORD | usri2_max_storage; |
DWORD | usri2_units_per_week; |
PBYTE | usri2_logon_hours; |
DWORD | usri2_bad_pw^count; |
DWORD | usri2_num_logons; |
LPWSTR | usri2_logon_server; |
DWORD | usri2_country_code; |
DWORD | usri2_code_page; |
Какое это имеет отношение к Perl? Каждый упомянутый модуль требует принять два решения:
- Нужно ли объяснять программистам на Perl, что такое «информационный уровень»?
- Какой информационный уровень (т. е. сколько параметров) может использовать программист?
Теперь читателю должно быть понятно, почему выбор модуля - это де ло личных предпочтений. Хорошей стратегией было бы сначала решить, какие параметры важны для вас, а затем найти модуль, который их поддерживает. Для наших демонстрационных подпрограмм мы выбираем модуль Win32: : Lanman. Вот какой код можно применить для создания и удаления пользователей в нашей системе учетных записей:
use Win32: :Lanman; tt для создания учетной записи
use Win32::Perms; # для установки прав на домашний каталог
$homeNTdirs = "\\\\homeserver\\home"; # корневой каталог
# домашних каталогов
sub CreateNTAccount{
my ($account,$record) = @_;
П создаем учетную запись на локальной машине
# (т. е., первый параметр пустой)
$result = Win32::Lanman::NetUserAdd("",
{'name' => Saccount,
'password' => $record->{password},
'home_dir' => "$homeNTdirs\\$account",
'full_name' => $record->{fullname}});
return Win32::Lanman::6etLastError() unless ($result);
добавляем в нужную ЛОКАЛЬНУЮ группу
(предварительно мы Я получаем SID учетной записи)
# Мы считаем, что имя группы совпадает с типом учетной
die "SID lookup error: ".Win32::Lanman::6etLastError()."\n"
unless (Win32: :Lanman: :LsalookupNames("", [$account],
\@info)); $result = Win32::Lanman::NetLocalGroupAddMember("",
$record->{type), ${$info[0]){sid»;
return Win32::Lanman::GetLastError() unless (Sresult);
# создаем домашний каталог
mkdir "$homeNTdirs\\$account",0777 or
return "Unable to make honedir:$!";
№ устанавливаем ACL и владельца каталога
$acl = new Win32::Perms("$homeNTdirs\\$account");
$acl->0wner($account);
# мы предоставляем пользователю полный контроль за
# каталогом и всеми файлами, которые будут в нем созданы
# (потому и два различных вызова)
DIRECTORY | СОНТШЕВ_ШЕИТ_АСЕ);
$acl->Allow($account, FULL, -
FILE|OBJECT_INHERIT_ACE|IMHERIT_ONLY_ACE);
$result = $acl->Set(); $acl->Close();
return($result ? "" : Sresult); }
Программа для удаления пользователей выглядит так:
use Win32: iLanman;
для удаления учетной записи
use File::Path;
для рекурсивного удаления каталогов
sub DeleteNTAccount{
my($account,$record) = @_;
# удаляем пользователя только из ЛОКАЛЬНЫХ групп.
Если мы № хотим удалить их и из глобальных групп, мы можем убрать
слово "Local" из двух вызовов Win32::Lanman::NetUser
(например, NetUserGetGroups)
die "SID lookup error: ".Win32::Lanman::GetLastError()."\n"
unless (Win32::Lanman::LsaLookupNames("",
[Saccount], \@info));
Win32::Lanman::NetUserGetLocalGroups($server, Saccount, ",
\@groups); foreach $group (@groups){
print "Removing user from local group ".
$group->{name}."...";
print(Win32::Lanman::NetLocalGroupDelMember("",
$group->{name}, ${$info[0]}{sid})?
"succeeded\n" : "FAILED\n"); }
tt удалить эту учетную запись с локальной машины
(т. е., перый параметр пустой) Sresult = Win32::Lanman::NetUserDel("", Saccount);
return Win32::Lanman::GetLastError() if ($result);
удалить домашний каталог и его содержимое
Sresult = rmtree("$homeNTdirs\\$account",0,1);
rmtree возвращает число удаленных файлов, так что если мы
удалили более нуля элементов, то скорее всего все прошло 8 успешно return Sresult;
}
Заметьте, для удаления домашнего каталога здесь используется переносимый модуль File: :Path. Если бы мы хотели сделать что-то специфичное для Win32, например, переместить домашний каталог в корзину, то могли бы сделать это при помощи модуля Win32: :File Op Йенды Крыники (Jenda Krynicky), который можно найти на http://jen da.krynicky.cz/. В таком случае мы применили бы Wi n32: ; F: 1еОр и изменили бы строку, включающую rmtrc-e(), на:
# удалим каталог в корзину, потенциально подтверждая
# действие пользователем, если для этой учетной записи
# необходимо подтверждать такие операции
$result = Recycle("$homeNTdirs\\$account");
В данном модуле есть функция Delete(), которая выполняет то же, что и rmtree() менее переносимым (правда, более быстрым) способом.