Подпрограммы для создания и удаления учетных записей в Unix
Подпрограммы для создания и удаления учетных записей в Unix
Начнем с примеров кода для создания учетных записи в Unix. Большая часть этого кода будет элементарной, поскольку мы избрали легкий путь. Наши подпрограммы для создания и удаления учетных записей вызывают команды с необходимыми аргументами, входящие в состав операционной системы, для «добавления пользователей», «удаления пользователей» и «смены пароля».
Зачем нужна эта очевидная попытка отвертеться? Этот метод приемлем, поскольку известно, что программы, входящие в состав операционной системы, хорошо «уживаются» с другими компонентами. В частности, этот метод:
- Не забывает о блокировке (т. е. позволяет избежать проблем с поврежденными данными, которые могут возникнуть, если две программы пытаются одновременно записать данные в файл паролей).
- Справляется с вариациями в файле паролей (включая шифрование пароля), о чем упоминалось раньше.
- Наверняка справится со схемами авторизации и механизмами распространения паролей, существующими в этой операционной системе. Например, в Digital Unix добавляющая пользователей внешняя программа может напрямую работать и с NIS-картами на основном сервере.
Применение внешних программ для создания и удаления учетных записей обладает такими недостатками:
Различия операционных систем
В каждую операционную систему входит свой собственный набор программ, расположенных в разных местах и принимающих несколько различные аргументы. Это редкий пример совместимости, однако практически во всех распространенных вариантах Unix (включая Linux, но исключая BSD) используются максимально совместимые программы для удаления и создания пользователей: useradd и user-del. В вариантах BSD применяются adduser и rmuser, две программы со сходным назначением, но совершенно разными аргументами. Подобные различия могут значительно усложнить наш код.
Соображения безопасности
Вызываемые программы с переданными им аргументами будут видны всем, кто употребляет команду ps. Если создавать учетные записи только на защищенной машине (например, на основном сервере), риск утечки данных значительно снизится.
Зависимость от программы.
Если внешняя программа почему-либо изменится или будет удалена, то нашей системе учетных записей настанет «полный капут».
Потеря контроля
Нам приходится считать часть процесса создания учетной записи неделимым. Другими словами, когда запущена внешняя программа, мы не можем вмешаться в этот процесс и добавить какие-либо свои собственные операции. Выявление ошибок и процесс восстановления становятся более сложными.
Эти программы редко делают все
Вероятнее всего, что данные программы не выполняют все действия, необходимые для формирования учетной записи на вашей машине. Возможно, вам понадобится добавить некоторых пользователей в некоторые вспомогательные группы, включить их в список рассылки на вашей системе или же добавить пользователей к файлу лицензии коммерческого продукта. Для обработки подобных действий вам придется написать дополнительные программы. Это, конечно, не проблема, наверняка любая система учетных записей, которую вы придумаете, потребует от вас большего, чем просто вызвать пару внешних программ. Более того, это не удивит большинство системных администраторов, потому что их работа меньше всего похожа на беззаботную прогулку по парку.
В случае с нашей демонстрационной системой учетных записей преимущества перевешивают недостатки, поэтому посмотрим на примеры кодов, в которых используется вызов внешних программ. Чтобы ничего не усложнять, мы покажем пример программы, работающей только на локальной машине с Linux и Solaris, и проигнорируем все трудности, вроде NIS и вариаций BSD. Если вам хочется посмотреть на более сложный пример этого метода в действии, поищите семейство модулей Cf gTie Рэнди Мааса (Randy Maas).
Вот основная программа, необходимая для создания учетной записи:
# На самом деле эти переменные надо определить в центральном
# конфигурационном файле
сluseraddex = "/usr/sbin/useradd"; ft путь к useradd $passwdex = "/bin/passwd";
# путь к passwd $homel)nixdirs = "/home"; ft корневой каталог
# домашних каталогов Sskeldir = "/home/skel"; ft прототип домашнего
# каталога $defshell = "/bin/zsh"; ft интерпретатор no
# умолчанию
sub CreateUnixAccount{
my ($account,$record) = @_;
# конструируем командную строку, используя:
ft -с = поле комментария
ft -d = домашний каталог
и -д = группа (считаем равной типу пользователя)
ft -m = создать домашний каталог
ft -k = и скопировать файлы из каталога-прототипа
» -s = интерпретатор по умолчанию
# (можно также использовать -G group, group, group для
# добавления пользователя к нескольким группам)
my @cmd = (Suseraddex,
"-с", $record->{"fullname"},
"-d", "$homeUnixdirs/$account",
"-g", $record->{"type"},
"-m",
"-k", $skeldir,
"-s", Sdefshell,
laccount);
print STOERR "Creating account..."; ^
my $result = Oxff & system @cmd;
# код возврата 0 в случае успеха и не 0 при неудаче,
и поэтому необходимо инвертирование
if (!$result){
print STDERR "failed.\n";
return "Suseraddex failed"; } else {
print STDERR "succeeded.\n"; }
print STDERR "Changing passwd...";
unless ($result = &InitUnixPasswd($account,$record->{"password"»){
print STDERR "succeeded.\n";
return ""; > else {
print STDERR "failed.\n";
return $result; } >
В результате необходимая запись будет добавлена в файл паролей, будет создан домашний каталог для учетной записи и скопированы некоторые файлы окружения (.profile, .tcshrc, .zshrc, и т.д.) из каталога-прототипа.
Обратите внимание, что мы используем отдельный вызов для установки пароля. Команда useradd на некоторых операционных системах (например, Solaris) оставляет учетную запись заблокированной до тех пор, пока для этой учетной записи не будет вызвана программа pass-wd. Подобный процесс требует известной ловкости рук, поэтому мы оформим данный шаг как отдельную подпрограмму, чтобы оставить в стороне подробности. Об этой подпрограмме мы еще поговорим, а пока рассмотрим «симметричный» код, удаляющий учетные записи:
# На самом деле эти переменные надо устанавливать в центральном
# конфигурационном файле
$userdelex = "/usr/sbin/userdel";
# путь к userdel
sub DeleteUnixAccount{
my ($account,Srecord) = @_;
# конструируем командную строку, используя:
# -г - удалить домашний каталог
my @cmd = (Suserdelex, "-r", $account);
print STDERR "Deleting account.,.";
my $result - Oxffff & system tJcmd;
tt код возврата 0 соответствует успеху, не 0 - неудаче,
№ поэтому необходимо инвертирование
if ('$result){
print STDERR "succeeded.\n";
return ""; } else {
print STDERR "failed.\n":
return "Suserdelex failed";
}
}
Перед тем как перейти к операциям с учетными записями в NT, разберемся с подпрограммой InitUmxPasswdO, о которой упоминалось раньше. Чтобы завершить создание учетной записи (по крайней мере, в Solaris), необходимо изменить ее пароль при помощи стандартной команды passwd. Обращениеpasswd <accountname> изменит пароль для этой учетной записи.
Звучит просто, но тут затаилась проблема. Команда passwd запрашивает пароль у пользователя. Она принимает меры предосторожности, чтобы убедиться, что общается с настоящим пользователем, взаимодействуя напрямую с его терминалом. В результате следующий код работать не будет:
и такой код РАБОТАТЬ НЕ БУДЕТ open(PW,"|passwd Saccount")
print PW $olcipasswd, "\n"; print PW Snewpasswd,"\n";
На этот раз мы должны быть искуснее, чем обычно; нам нужно как-то заставить команду passed думать, что она имеет дело с человеком, а не программой на Perl. Этого можно достичь, если использовать модуль Expect.pm, написанный Остином Шутцом (Austin Schutz), - ведь он устанавливает псевдотерминал (pty), внутри которого выполняется другая программа. Expect.pm основан на известной Tel-программе Expect Дона Либеса (Don Libes). Этот модуль входит в семейство модулей, взаимодействующих с программами. В главе 6 мы рассмотрим его близкого «родственника», модуль Net: :Telnet Джея Роджерса (Jay Rogers).
Эти модули действуют в соответствии со следующей моделью: они ждут вывода программы, посылают ей на ввод данные, ждут ответа, посылают некоторые данные и т. д. Приведенная ниже программа запускает команду passed в псевдотерминале и ждет до тех пор, пока та запросит пароль. Поддержание «разговора» с passwd не должно требовать усилий:
use Expect;
sub InitUnixPasswd {
my (Saccount,Spasswd) = @_;
ft вернуть объект
my $pobj - Expect->spawn($passwdex, Saccount);
die "Unable to spawn $passwdex:$!\n" unless (defined SpoDj):
it не выводить данные на стандартный вывод (т. е.
# работать молча)
$pobj->log_stdout(0);
# Подождать запроса на ввод пароля и запроса на повторение
# пароля, ответить. $pobj->expect(10,"New password: ");
и Linux иногда выводит подсказки раньше, чем он готов к вводу,
print $pob] "$passwd\r"
$pobi->expect(10, "Re-enter new password: "); print $pob] "$passwd\r";
it работает"
Sresul: = (defined ($pobj-~ expectdO.
"successfully changeo")) ? "" : "password crarac.
failed"): в закрываем обьект, ждем 15 секунд, пока процесс завершится
$pobj-'suft_close();
return $resuJ t.:
}
Модуль Expect.pm очень хорошо подходит для этой подпрограммы, но стоит отметить, что он годится для куда более сложных операций. Подробную информацию можно найти в документации и руководстве по модулю Expect.pm.