Вы находитесь на странице: 1из 93

№12(25) декабрь 2004

подписной индекс 81655


www.samag.ru

Единая учетная запись для Windows


и UNIX в Active Directory
Копирование файлов
в автоматическом режиме
с множества компьютеров через SSH
Защита сетевых сервисов
с помощью stunnel
Использование аппаратных ключей
в целях аутентификации в Linux
Система обнаружения атак SHADOW
Биллинг для АТС на базе PostgreSQL
Обработка переадресованных
http-запросов
№12(25) декабрь 2004

Автоматизация FTP с помощью Python


оглавление

РЕПОРТАЖ 2 БЕЗОПАСНОСТЬ
АДМИНИСТРИРОВАНИЕ Защита сетевых сервисов
с помощью stunnel
Linspire одним глазком
Андрей Бешков
Валентин Синицын tigrisha@sysadmins.ru 42
val@linuxcenter.ru 4
Железный login:
Идеальный карманный компьютер ломаем зубы грубой силе
для системного администратора
Часть 2 Александр Похабов
chiko@agk.ru 48
Андрей Маркелов
andrew@markelov.net 8 Тени исчезают в полдень
Дистрибутив для всех Сергей Яремчук
grinder@ua.fm 54
Сергей Яремчук
grinder@ua.fm 10 WEB
Копирование файлов PHP-GTK
в автоматическом режиме
с множества компьютеров через SSH Андрей Уваров
dashin@ua.fm 60
Рашид Ачилов
shelton@granch.ru 12 Обработка переадресованных
http-запросов
Единая учетная запись
для Windows и UNIX Алексей Мичурин
в Active Directory alexey@office-a.mtu-net.ru 62
Игорь Полянский HARDWARE
ipoliansky@mail.ru 18
Запись дисков CD-R/RW в Linux
FreeBSD tips: настройка VLAN Часть 2
Сергей Супрунов
amsand@rambler.ru 24 Владимир Мешков
ubob@mail.ru 68
Биллинг для АТС на базе PostgreSQL
ОБРАЗОВАНИЕ
Георгий Толоконников
info@samag.ru 26 Файловая система NTFS извне и изнутри
Часть 2
Пакетный фильтр OpenBSD
Часть 2 Крис Касперски
kk@sendmail.ru 76
Денис Назаров
pheonix@sysattack.com 30 Разработка сценария регистрации
пользователей в сети
Настоящий UNIX в наши дни Часть 2
Александр Байрак Иван Коробко
x01mer@pisem.net 34 ikorobko@prosv.ru 82
Автоматизируем FTP с помощью Python Содержание журнала за 2004 год 92
Сергей Супрунов
amsand@rambler.ru 36 BUGTRAQ 33, 53, 91, 94

№12(25), декабрь 2004 1


репортаж

AGNITUM OUTPOST OFFICE FIREWALL


НОВЫЙ АСПЕКТ КОРПОРАТИВНОЙ ЗАЩИТЫ
3 декабря 2004 года компания Agnitum (www.agnitum.com) – Клиентская часть после установки взаимодействует с
разработчик популярного персонального брандмауэра сервером и нацелена на работу в корпоративной сети. В
Outpost Firewall Pro анонсировала выход новой версии свое- частности, контроль компонентов приложений (Component
го продукта – Outpost Office Firewall, нацеленного на исполь- Control) и контроль скрытых процессов (Hidden Process
зование в корпоративных локальных сетях в качестве сред- Control) будут выключены по умолчанию, а брандмауэр бу-
ства персональной защиты клиентских компьютеров. Новая дет загружаться в фоновом режиме. Это обеспечит мини-
разработка явилась продолжением работы над очередной мальное вовлечение пользователя в процесс защиты ком-
версией брандмауэра – Outpost Firewall Pro 2.5. Стоит отме- пьютера – многочисленные запросы сетевого доступа при-
тить, что речь идет не о серверном варианте Outpost Firewall, ложениями могли бы ввести неопытного пользователя в
а именно об офисной версии, то есть специализированном замешательство. К сожалению, клиентская часть Outpost
ПО, предназначенном для массового развертывания в кор- Office Firewall несовместима с предыдущими версиями про-
поративной сети, на компьютерах пользователей. граммы. Если на некоторых компьютерах уже установлена
Презентация проходила в Санкт-Петербурге, на борту одна из предыдущих версий, включая Outpost Firewall 2.5,
легендарного крейсера «Аврора», что само по себе явилось ее необходимо полностью удалить перед установкой офис-
удивительным сюрпризом. Главный менеджер по продажам ного варианта. Новых серьезных изменений по сравнению
Николай Васильев и координатор российского проекта, с версией 2.5 в клиентской части практически не будет. Фун-
организатор презентации Ольга Величко (на фото) расска- кциональность нового продукта будет постоянно улучшать-
зали, что они давно хотели провести презентацию на этом ся, а переговоры с создателями антивирусных продуктов о
историческом крейсере под лозунгом «Революция в мире реализации совместных решений помогут привести к со-
информационных технологий». зданию надежной комплексной защиты. Например, реали-
В назначенное время у трапа крейсера собрались жур- зовать защиту от программ типа Ad-Aware, количество ко-
налисты практически всех популярных IT-изданий России. торых в последнее время угрожающе растет.
На борту представителей прессы встречали В.И. Ленин и Средством управления и мониторинга будет служить
военные матросы, вручая каждому морскую бескозырку с Outpost Command Center, выполненный в виде оснастки «Кон-
ленточкой, на которой было написано «Outpost Firewall Pro». соли управления» (MMC snap-in), через который осуществ-
Расскажем о впечатлениях от анонса и о заявленных ляется управление службами, запуск редактора настроек и
возможностях нового продукта. публикация конфигураций для клиентских машин. Одновре-
В качестве клиентской части Outpost Office Firewall бу- менно с ним устанавливается редактор настроек, предназ-
дет содержать некоторое подобие Outpost Firewall Pro 2.5. наченный для конфигурирования брандмауэра на клиентс-
Дистрибутив брандмауэра поставляется в формате MSI, что ких машинах, а также «Служба обновлений» и «Служба пуб-
позволяет для развертывания его в домене Active Directory ликации».
использовать групповые политики. К сожалению, в пилот- Конфигурации клиентам передает «Служба публика-
ной версии другие возможности удаленной установки под- ции». Она запускается на том же сервере, где и «Команд-
держиваться пока не будут. Таким образом, автоматичес- ный центр» Outpost, и также управляется с его помощью.
кое развертывание Outpost Firewall будет возможно только При каждой загрузке компьютер пользователя запрашива-
в доменах Active Directory и только на компьютерах с ет у сервера конфигурацию. Если были созданы и опубли-
Windows 2000 и старше. В остальных случаях установку кованы новые настройки, то «Служба публикации» пере-
придется произвести вручную. Возможность удаленной ус- дает клиенту файл по внутреннему протоколу. После полу-
тановки при помощи RPC, а не через групповые политики чения настроек брандмауэр на компьютере пользователя
планируется реализовать в следующих версиях. применяет их. Период запроса клиентами обновлений кон-
фигурации – изменяемый параметр. Однако форсировать
немедленное обновление на клиентах пока нельзя. Возмож-
но, это появится в следующих версиях.
В первой версии Outpost Office Firewall не предвидится
возможности назначения разных конфигураций различным
группам клиентов, а также не планируется разрешать ре-
дактирование отдельных записей в конфигурации без зат-
рагивания остальных параметров.
По словам представителей компании выпуск коммер-
ческой версии продукта ожидается примерно в феврале
2005 года.
Роман Марков
Фото автора

2
администрирование

LINSPIRE ОДНИМ ГЛАЗКОМ

ВАЛЕНТИН СИНИЦИН
Фирма Linspire (www.linspire.com) – ветеран движения за по- ставщиков закрытого ПО) канал доставки, компания выз-
пуляризацию Linux, хотя самой торговой марке едва насчи- вала сильное удивление у коллег по цеху, а г-н Робертсон в
тывается пять месяцев. Между тем компания была основа- очередной раз подтвердил звание большого затейника.
на в далеком 2001 году. С тех пор и по сей день ее бес- Подробности доступны по адресу: http://info.linspire.com/p2p/
сменным управляющим является всемирно известный аван- p2p-pr.html. Иногда (правда, в последнее время все реже и
тюрист-инноватор Майкл Робертсон (Michael Robertson), со- реже) Linspire проводит промо-акции, в ходе которых тре-
здатель портала MP3.com. Первоначально компания назы- буется угадать текст купона (как правило, это нечто оче-
валась Lindows, а ее основное детище и герой сегодняш- видное для тех, кто внимательно следит за заголовками
ней статьи, настольный дистрибутив Linux, – LindowsOS. новостных лент), ввести его и получить стопроцентную скид-
Такое явное созвучие с «Окнами» не могло понравиться ку в интернет-магазине компании. После этого ISO-образ
корпорации Microsoft и очень быстро стало предметом мно- дистрибутива можно загрузить бесплатно через HTTP или
гочисленных судебных разбирательств как на территории все тот же BitTorrent.
США, так и за их пределами. Тяжба не утихала в течение В данном обзоре мы рассмотрим основные возможнос-
нескольких лет, причем фортуна практически равным об- ти Linspire 4.5.189 Developers Edition, датированной янва-
разом благоволила как той, так и другой стороне. Вконец рем 2004 года. С тех пор было выпущено несколько исправ-
погрязнув в пучине судебных баталий, Lindows, Inc. и лений (об их роли в этой истории мы поговорим чуть поз-
Microsoft в июле этого года пришли к мировому соглаше- же), однако базовая функциональность системы не претер-
нию, по которому все права на торговую марку «Lindows» и пела существенных изменений.
соответствующие доменные имена отошли в «Редмонд»,
правда, не безвозмездно. Размер контрибуции составил Делай раз: установка
около 20 млн. долларов. Вполне удовлетворенная исходом Итак, вставляем компакт-диск с Linspire в оптический при-
дела, Lindows сменила имя на Linspire и с большой выго- вод и перезапускаем компьютер. Нашему взору представ-
дой продала свою прежнюю вывеску на аукционе eBay. ляется графический splash-экран с логотипом компании и
На сегодняшний день компания представляет широкий меню с двумя загрузочными опциями: Install и Diagnostic. Пос-
модельный ряд, включающий базовую редакцию Linspire ледний вариант может использоваться для тонкой (эксперт-
4.5, профессиональную Linspire 4.5 Developers Edition, заг- ной) настройки параметров или восстановления системы.
ружаемый диск LinspireLive! и специальную версию Выбрав его и подождав достаточное время, можно попасть
LinspireEspaсol для испаноязычных пользователей. Поми- в текстовую консоль и, например, переразбить жесткий диск,
мо этого имеются различные дополнения, например, пользуясь командой fdisk или же реанимировать файловую
LinspireOffice. Ранее существовала еще одна разновид- систему с помощью fsck. Из важных утилит в этом режиме
ность – Laptop Edition, предназначенная для ноутбуков, но не доступен, пожалуй, один hdparam (читатели, у которых
сейчас она, по-видимому, слилась с базовой версией. хотя бы раз «взрывался» хорошо раскрученный CD-ROM,
Как и многие настольные дистрибутивы, Linspire явля- меня поймут). Впрочем, развитие промышленности идет се-
ется коммерческим программным продуктом. Цена базо- мимильными шагами и несбалансированные/некачествен-
вой редакции – 49,95 доллара. Версия для разработчиков ные диски сейчас встречаются все реже и реже.
стоит чуть дороже – $59,95. LinspireLive! можно приобрести Сделав все необходимое, можно начать установку
за $19,95 или (официально!) загрузить через файлообмен- Linspire командой startx или же выйти из диагностического
ную сеть BitTorrent. Выбрав столь оригинальный (для по- режима, набрав exit.

4
администрирование
ентированные на ту же целевую аудиторию, стали продви-
гать совместимость с WiFi лишь к концу 2004 года (моя вер-
сия Linspire, напомню, была выпущена в январе). Возмож-
но, эти ошибки уже исправлены, однако достоверных све-
дений на сей счет у меня нет.
В процессе установки программа сама отформатирует
предназначенный системе раздел. В качестве файловой си-
стемы по умолчанию (впрочем, этот термин здесь не впол-
не уместен, ведь ничего другого выбрать не предложили)
используется ReiserFS, что неудивительно – Linspire спон-
сирует ее разработчиков, о чем красноречиво свидетель-
ствует лейбл на сайте Namesys (www.namesys.com). Эта
компания вообще поддерживает или принимает участие в
достаточно большом числе открытых проектов, в том чис-
ле KDE (www.kde.org) и Mozilla (www.mozilla.org), и даже с
Ðèñóíîê 1. Êëèåíò Click-N-Run некоторых пор имеет собственную Open Source инициати-
Программа-инсталлятор, напротив, является воплоще- ву – Nvu (www.nvu.com), задача которой ни много ни мало –
нием простоты. Достаточно упомянуть, что она состоит мак- создать свободный аналог Macromedia DreamWeaver и
симум из четырех экранов. Вначале пользователю предла- Microsoft Frontpage. В качестве основы используется редак-
гается выбрать один из двух режимов: Take Over An Entire тор Mozilla Composer. Проект делает определенные успе-
Hard Disk («Занять жесткий диск целиком» – режим по умол- хи: по крайней мере все новые страницы на сайте Linspire
чанию, хорошо подходит для установки на чистый нераз- разработаны с помощью Nvu.
меченный диск и не требует вмешательства пользователя) Завершив (ура!) копирование файлов, инсталлятор вы-
или Advanced Install. «Продвинутость» в данном случае оз- даст соответствующее сообщение и предложит перезагру-
начает возможность указать существующий раздел для ин- зить систему. Добро пожаловать в мир настольного Linux!
сталляции корневой файловой системы. Изменить их струк-
туру программа не позволяет, вероятно, для того, чтобы нео- Делай два: первый запуск
пытный пользователь нечаянно не уничтожил данные на со- и постинсталляционная настройка
седнем Windows-разделе. После осуществления выбора мы После неизбежного перезапуска мы видим уже знакомую
переходим на третий экран, где предлагается ввести имя заставку и меню, на этот раз содержащее три опции. Две
для нашего компьютера и пароль. Последняя настройка яв- из них нам хорошо известны и предназначены для нормаль-
ляется необязательной, что очень понравится пользовате- ного старта системы и перехода в экспертный режим. Сред-
лям Windows 9x и приведет в ужас бывалых администрато- няя, «Redetect», используется для обнаружения нового обо-
ров. Программа не проверяет введенные пароли на проч- рудования. Дождавшись загрузки системы (наберитесь тер-
ность: хотите «123456» – пожалуйста. После заполнения пения – как и многие настольные дистрибутивы, Linspire не
данных полей ваше участие в процессе заканчивается и слишком легок на подъем. Это неизбежная плата за отсут-
система приступает к копированию файлов. Вполне оправ- ствие тонкой настройки) и введя пароль (если таковой име-
дывающий себя подход, по крайней мере до тех пор, пока ется), мы окажемся в окне мастера первого запуска, кото-
не возникнет внештатная ситуация. рый предложит нам ознакомиться с лицензией и установить
Сообщения инсталлятора об ошибках малоинформатив- ряд параметров. Беглый взгляд на соглашение конечного
ны и обычно состоят из числового кода, краткого описания пользователя (EULA) обнаруживает занятную вещь – лицен-
(например: «200: rsync failed» или «255 Unspecified Error») и зия Linspire является Family Friendly. Говоря русским язы-
предложения обратиться в службу технической поддерж- ком, одну копию системы можно легально установить на
ки, которая, как следует из периодически появляющейся в неограниченное число компьютеров, владельцы которых со-
ходе установки рекламной картинки, доступна через Web и ставляют одну семью. Не вдаваясь в юридические тонко-
по телефону, правда, не круглосуточно. Опыт показывает, сти, отметим явное преимущество такого договора как для
что специалисты откликаются достаточно быстро, однако нас с вами, так и для производителя: если отечественный
на вопрос о причинах неудачи разводят руками: мол ошиб- пользователь худо-бедно свыкся с мыслью о том, что про-
ка, знаем, работаем. Возможно, build 189 был в этом отно- граммы имеют лицензию, которую надо соблюдать, то пла-
шении не слишком успешным (как уже упоминалось ранее, тить за себя, за маму и за папу он точно не станет. Нажав
с тех пор вышло несколько исправлений, и текущий релиз на расположенную в окне кнопку «Advanced», можно доба-
имеет номер 444), но мне с трудом удалось найти компью- вить новые учетные записи (по умолчанию вы заходите в
тер, на который Linspire поставился без сучка и задоринки. систему как root) или настроить экранное разрешение, глу-
Особенно обидно, что в число «неприкасаемых» попал и бину цвета и частоту развертки (в состав Linspire входят
мой ноутбук, с помощью которого предполагалось прове- фирменные драйверы ATI и Nvidia, поэтому приготовьтесь
рить на практике, насколько хорошо система поддержива- к высокому refresh rate). Программа также предложит вам
ет работу с беспроводными сетями. Эта возможность ши- настроить системное время. Выполнив все необходимые
роко рекламируется в руководстве пользователя, что вну- операции, можете спокойно выходить из мастера. Вас ждет
шает некоторое уважение: прочие дистрибутивы Linux, ори- сюрприз: одно из фирменных аудиоруководств Linspire! В

№12(25), декабрь 2004 5


администрирование
ходе интерактивных уроков, выполненных с использовани- грамм, как открытых, так и коммерческих. Для этого потре-
ем технологии Macromedia Flash (конечно, проигрыватель буется доступ в Интернет и несколько щелчков мышью. Кли-
Flash-роликов также включен в комплект поставки), пользо- ент Click-N-Run (рис. 1) автоматически скачает и установит
ватель может получить представление о возможностях си- выбранные вами программы, а также позволит добавить
стемы и приобрести базовые навыки работы с нею. Значи- иконку на рабочий стол или в меню Autostart. Вы можете
тельная часть первого руководства посвящена технологии инсталлировать как отдельные приложения, так и целые на-
CNR («Click-N-Run»), речь о которой пойдет чуть ниже. К боры – «Aisles», созданные разработчиками Linspire или
сожалению, эта красота требует жертв: после нескольких другими пользователями. Членство в CNR платное (4,95
уроков, прослушанных на моем компьютере, диктор стал доллара в месяц или 49,95 год), однако «прикоснуться к
«заикаться», а потом и вовсе умолк. Пришлось лечить сис- прекрасному» можно и даром. Достаточно ввести номер
тему с помощью Quick Restart, по-простому – перезагрузки кредитной карточки, и в течение 15 дней вы можете пре-
X-сервера. кратить подписку, не заплатив ни цента за загруженный
софт. Переведя эти деньги в отечественную валюту, полу-
чим 120-150 рублей в месяц, то есть намного меньше, чем
большая часть жителей нашей страны тратит на сотовый
телефон. Важным ограничивающим фактором является ши-
рина канала: скачать большую часть интересных приложе-
ний по модему практически нереально, а оплата трафика
при использовании выделенной линии может влететь в ко-
пеечку.
Таким образом, целевая аудитория CNR Warehouse у
нас в России, по сути, ограничена пользователями unlimited-
тарифов. Большая часть репозитария CNR бесплатна для
подписчиков, исключения составляют коммерческие при-
ложения, на которые предоставляются ощутимые скидки.
Единожды загрузив как ую-либо программу из CNR
Warehouse, вы становитесь ее собственником навеки и смо-
жете вновь получить к ней доступ, когда потребуется. Су-
Ðèñóíîê 2. Linspire 4.5: ðàáî÷èé ñòîë ïî óìîë÷àíèþ ществование этого банка программ создает определенную
Как и многие современные дистрибутивы, Linspire не- специфику Linspire. В состав системы включен самый ми-
мыслим без Интернета. По утверждению разработчиков, нимум приложений (нет ни офисного пакета, ни графичес-
кабельное подключение система распознает и конфигу- кого редактора, ни проигрывателя видеофильмов). Все ос-
рирует в полуавтоматическом режиме (пользователю мо- тальное предлагается загружать из CNR. Каждый пункт
жет потребоваться ввести IP-адрес и т. п.). Для «счастли- меню «Launch» (аналог кнопки «Пуск» Windows) включает
вых» владельцев модемов на рабочий стол вынесена спе- обязательную ссылку на Warehouse, поэтому логотип дан-
циальная пиктограмма – Internet Connection Tools. Созда- ной технологии – бегущий человек в зеленом круге – вы
тели Linspire позаботились о клиентах крупнейших интер- будете видеть довольно часто.
нет-провайдеров США (AOL, Juno, Earthlink и т. д.) – им Постоянное желание «выклянчить пару баксов» являет-
достаточно просто щелкнуть по иконке с нужным именем. ся несомненным минусом Linspire. Впрочем, выход, как все-
Остальным предлагается настроить KPPP (а именно эта гда, есть. Дистрибутив основан на Debian и содержит необ-
утилита используется для доступа в Интернет) вручную – ходимый для опытного пользователя инструментарий: dpkg
подробное руководство прилагается. Сверх указанных ав- и apt-get, с помощью которого можно устанавливать пакеты
торами мер мне пришлось лишь указать устройство, к ко- в формате deb. Редакция Developers Edition, помимо этого,
торому подсоединен мой модем, в настройках этой заме- включает в себя полный комплект средств разработки (в
чательной утилиты. том числе среду KDevelop), что позволяет собирать пакеты
Теперь, когда вы подключены к Всемирной паутине, на- из исходных текстов. Может быть, это и неэстетично, но по
стало время познакомиться с «жемчужиной» Linspire – CNR крайней мере дешево. Таким образом я скомпилировал «про-
Warehouse. грамму в правом нижнем углу» – системный монитор gkrellm
(http://web.wt.net/~billw/gkrellm/gkrellm.html).
Делай три: Кладовая «Раз – и готово» В меню утилита не появилась, но зато работала как
Не пугайтесь непривычных слов: примерно так переводится часы. Другое дело, захочет ли Пользователь с большой
на русский язык словосочетание «Click-N-Run Warehouse», буквы связываться с инструментами командной строки?
обозначающее технологию, разработанную в Linspire с це- Можно сказать, что CNR Warehouse отражает идеологию
лью упрощения установки нового ПО и обновления систе- Open Source: брать деньги не за ПО, а за услуги, то есть за
мы. Зависимости всегда были бичом Linux, и любой созда- желание клиента не делать чего-то самостоятельно.
тель дистрибутива, претендующий на место в сердцах сред- Однако, несмотря на все многообразие приложений для
нестатистических пользователей, должен позаботиться о Linux, пользователь может захотеть запустить и какую-то
скруглении «острых углов». В настоящий момент с помо- программу для Win32, например, игру. Что же предостав-
щью CNR Warehouse можно установить более 1900 про- ляет Linspire для этой категории граждан? Исходной целью

6
администрирование
разработчиков Lindows была практически стопроцентная и создания HTML-документов используется интернет-пакет
совместимость с Windows-приложениями (отчасти поэтому Mozilla.org. Не так давно компания MozDev Group (http://
ей и было присвоено столь «неудачное» имя). Стремясь до- www.mozdevgroup.com) по заказу создателей дистрибути-
стичь ее, компания не жалела денег на инвестиции, в пер- ва расширила его возможности интегрированным поиском
вую очередь, в проект Wine (http://www.winehq.com). Одна- (по любому слову на странице, в теле письма и т. д.) и про-
ко, спустя некоторое время г-н Робертсон изменил курс. веркой правописания. Функция имеет название Hot Words
Сославшись на дороговизну продуктов для Windows, он (http://info.linspire.com/suite.html) и доступна, как и все в мире
предложил сконцентрировать все усилия на написании их Linspire, через CNR Warehouse. В состав Linspire 4.5 вклю-
полноценных аналогов (чем компания сейчас и занимает- чены также интернет-пейджер GAIM (gaim.sourceforge.net)
ся, достаточно вспомнить тот же Nvu). Было ли это реаль- и IP-телефон SIPphone (www.sipphone.com).
ной причиной или же стопроцентная эмуляция Win32 API Поинтересуйтесь у начинающего линуксоида, что ему
оказалась чересчур трудоемкой задачей, науке доподлин- кажется самым непонятным в этой системе. Уверен, в «го-
но неизвестно, но факт остается фактом: в смысле двоич- рячую десятку» непременно попадет процедура подключе-
ной совместимости с Windows у пользователей Linspire нет ния (mount) разделов, особенно остро встающая для съем-
особых преимуществ перед «простыми смертными». Через ных носителей: дискет, компакт-дисков, USB Flash и т. д.
CNR Warehouse доступны все те же Wine, NeTraverse Здесь Linspire оказался на высоте. Вставленный в USB-
Win4Lin (около 70 долларов с учетом «клубной скидки») и разъем «брелок» система опознала сразу, о чем уведоми-
WineX (приблизительно 15 долларов). Весьма популярный ла меня, разместив пиктограмму «Flash Disk» на рабочем
пакет CrossOver Office, базирующийся на Wine, и входящий столе. Вставленный в привод DVD-ROM оптический диск
в комплект поставки конкурентов Linspire (Lycoris Desktop/ был также легко опознан и смонтирован, а вот с его отклю-
LX и Xandros), в CNR Warehouse отсутствует. чением возникли небольшие проблемы. В случае, если он
Как вы уже, наверное, обратили внимание, названия ин- оказывался занят (в понимании Linux – например, было от-
терфейсных элементов в данной статье приводятся на анг- крыто окно с деревом расположенных на нем каталогов),
лийском языке. Это происходит вовсе не из-за прозапад- система игнорировала нажатие на кнопку Eject на передней
ной ориентации автора – английский является языком панели. Такое поведение родного компьютера может сму-
Linspire по умолчанию, а помимо него, система официаль- тить и испугать новичка. Было бы лучше, если бы Linspire
но поддерживает лишь испанский. В отличие от Linare (см. выдавала диалог с сообщением о невозможности извлече-
статью «Заметки о Linare», журнал «Системный админист- ния диска и списком потенциальных причин (или даже на-
ратор», №11, ноябрь 2004 г.), где поддержка кириллицы званием приложения, использующего CD/DVD-ROM в дан-
выдрана с корнем, научить Linspire хоть как-то говорить по- ный момент).
русски возможно. Для этого потребуется установить стан- Вот и подошел к концу этот небольшой обзор. Что мож-
дартный пакет локализации KDE и шрифты все из того же но сказать в заключение? По-моему, Linspire – это непло-
CNR Warehouse. хой дистрибутив, страдающий излишним интересом к день-
Среди заслуживающих внимания приложений, входящих гам своего владельца и отсутствием полноценной русифи-
в состав «Кладовой», следует назвать авторские разработ- кации, но, несмотря на это, предоставляющий достаточный
ки Linspire: аудиоплейер в стиле «все в одном2 Lsongs (http:/ комфорт для домашнего и офисного применения. Если у
/info.linspire.com/lsongs), аналогичный iTunes и фотоальбом вас есть широкий канал в Интернет – загрузите LinspireLive.
Lphoto (http://info.linspire.com/lphoto), заменяющий iPhoto. Возможно, он вам понравится. Если что-то не получилось,
Обе программы бесплатны для подписчиков CNR и стоят не расстраивайтесь – Linspire не единственный в своем
около 20 долларов для остальных. роде. В январском номере журнала мы рассмотрим Lycoris
Desktop/LX, загадочный дистрибутив от компании, ранее
Делай четыре: приступаем к работе известной как Redmond Linux.
Итак, все подготовительные операции завершены, допол-
нительное ПО установлено, и мы можем наконец-то при-
ступить к тому, ради чего все и затевалось, – работе. Вне-
шний вид Linspire 4.5 представлен на рис. 2. В качестве ра-
бочего стола используется KDE. Содержимое меню
«Launch» (зеленая буква «L» в левом нижнем углу) стара-
тельно повторяет привычное пользователям Windows (кро-
ме тех, кто успел основательно обжиться в XP): те же
Programs, Settings, Search и Run Command. В устоявшийся
порядок вещей добавлен всего один штрих – опция
«Terminate Program» («Снять программу»). При ее выборе
(равно как и при нажатии магической комбинации <Ctrl-Alt-
Del>) на экране появляется дерево запущенных процессов.
Во время своего старта система автоматически загружает
апплет, извещающий пользователя о наличии новых сооб-
щений в почтовом ящике (конверт в правом нижнем углу) –
мелочь, а удобно. Для чтения писем, а также просмотра Web Ðèñóíîê 3. Ïîíàäîáèëñÿ îôèñ? Äîáðî ïîæàëîâàòü â CNR Warehouse!

№12(25), декабрь 2004 7


администрирование

ИДЕАЛЬНЫЙ КАРМАННЫЙ КОМПЬЮТЕР


ДЛЯ СИСТЕМНОГО АДМИНИСТРАТОРА
ЧАСТЬ 2

АНДРЕЙ МАРКЕЛОВ
Обновляем системное программное ! включены версии баузеров Opera 7.25 и NetFront 3.1;
обеспечение КПК ! улучшена поддержка USB-устройств через CF USB Host;
За время, прошедшее с выхода первой части статьи1, ком- ! добавлена поддержка эмуляторов SNES и Scumvm.
пания Sharp успела выпустить преемника рассматриваемой ! поддержка файловых систем ext3 (позволяет создавать
модели карманного компьютера, в основном отличающе- отказоустойчивые ext3 разделы на больших внешних кар-
гося наличием четырехгигабайтного жесткого диска. Однако тах памяти) и squashfs (предоставляет очень хорошую
пока еще эта модель под названием SL-C3000 заговорит степень сжатия данных при невысоком использовании
хотя бы по-английски, а не по-японски, и доберется до на- системных ресурсов), fuse (FileSystem in User Space);
шего рынка, пройдет очень много времени. А пока идеаль- ! обновлены драйвера bluetooth и WiFi (используются
ным КПК для системного администратора как был, так и драйвера HostAp, поддерживаются Wireless Extentions
остается Sharp Zaurus SL-C860. Кстати, с появлением трех- версии 15, WPA);
тысячной модели, цена на восемьсот шестидесятую долж- ! добавлен модуль брандмауэра iptables;
на упасть, что сделает Zaurus более доступными. Продол- ! bash «дорос» до версии 3.0;
жим же наш разговор об этом карманном компьютере, ра- ! в прошивку включен Midnight Commander;
ботающем под управлением ОС Linux. ! включены в прошивку unrar, diff, smbmount и другие кон-
В первой части статьи я уже рассказывал о существую- сольные утилиты, которые иначе пришлось бы доуста-
щем многообразии «прошивок» ROM для Zaurus. Две ос- навливать вручную;
новных из них – это pdaXrom (http://www.pdaxrom.org) и ! созданы новые версии многих консольных утилит (wget,
Cacko ROM (http://cacko.biz/cacko). Первая в качестве гра- fdisk, OpenSSL/OpenSSH);
фической среды использует X11, а вторая, как и родная ! обновлена программа эмулятора терминала;
шарповская – Qtopia. Доставшийся мне «карманник» шел ! добавлена поддержка целого ряда новых bluetooth и WiFi
с довольно устаревшей русифицированной для «МакЦент- CF-карт.
ра» версией Cacko ROM. Поэтому я хочу начать вторую
часть с описания процесса перепрошивки ROM, который Как видите, список изменений весьма внушителен, для
весьма не тривиален. После окончания операции по срав- того чтобы приступить к обновлению прошивки. Нужно ска-
нению с макцентровской версией, помимо исправлений зать, что к этому процессу стоит отнестись со всей ответ-
ошибок, мы должны дополнительно получить огромное чис- ственностью, так как можно легко привести КПК в нерабо-
ло бонусов: тоспособное состояние. Снимки с экрана Zaurus во время
Наиболее заметные изменения: выполнения этого увлекательного процесса вы можете най-
! переделаны все значки и обои; ти по адресу www.markelov.net/z860upd.html, а далее я по-
! значительно обновлена программа kino2 – оболочка для стараюсь подробно описать само действо.
mplayer; Начнем с того, что на всякий случай сохраним копию те-
! включена поддержка NLS для всех языков в ядре; кущей прошивки. Для этого нам необходимо попасть в так
! модернизирована программа переключения клавиатур- называемое «диагностическое меню» карманного компью-
ных раскладок; тера – аналог BIOS настольных ПК. Для того чтобы зайти в

1
Маркелов А. Идеальный карманный компьютер для системного администратора. Часть 1. – Журнал «Системный администратор», №10,
октябрь, 2004 г.

8
администрирование
него, необходимо на некоторое время вынуть батарею, либо ставить о нем представление тем, кто только собрался об-
просто отодвинуть на некоторое время защелку батареи. завестись карманной Linux-системой, но окажутся полез-
После чего возвращаем все в исходное состояние, и при ными и обладателям Zaurus. На возникшие вопросы автор
включении «завра» держим нажатыми клавиши <D+M>. Пе- с удовольствием ответит по электронной почте, либо на фо-
ред вами меню на английском языке. Я настоятельно реко- руме журнала.
мендую не экспериментировать с его пунктами, так как мож- Хочу поблагодарить Антона Масловского, предоставив-
но легко «убить» ваш КПК. Теперь перемещаемся на третью шего мне предварительную версию Cacko ROM 1.22, кото-
страницу меню. Там выбираем пункт «NAND Flash Back Up». рая к моменту публикации статьи наверняка уже выйдет в
Перед этим необходимо убедиться, что в КПК вставлена от- свет.
форматированная в файловой системе FAT карточка. Места
же должно хватить для 135 Мб файла с полной копией ваше-
го текущего содержимого NAND ROM. По окончании про-
цесса на флэшке будет лежать файл systc860.dbk. Обратно
в диагностическое меню можно будет вернуться по клавише
«Cancel», а из самого диагностического меню выход осуще-
ствляется выбором подпункта «Reset» пункта «Extra menu».
При необходимости вернуться к сохраненной прошивке мож-
но выполнить обратную операцию по восстановлению через
пункт «NAND Flash Restore».
Теперь приступим непосредственно к замене нашей ус-
таревшей версии на новую прошивку. Это делается из спе-
циального меню на японском языке. Не забудьте, что Sharp
официально не продает Zaurus за пределами Японии! По-
лучить доступ в это меню можно, если после «горячего»
рестарта включать КПК кнопкой «Power» с одновременно
нажатой клавишей «Ок». В меню выбираем четвертый, ниж- Ðèñóíîê 1. Çàãðóæàåòñÿ îáíîâëåííàÿ âåðñèÿ Cacko ROM
ний пункт. После КПК спросит, с какого носителя мы будем
обновлять прошивку. Три файла из архива – initrd.bin,
tools.tar и updater.sh должны лежать в корне либо CF – либо
SD-карты. Кроме того, убедитесь, что подключили блок
питания, иначе процесс не начнется. До этого момента он
не должен был быть подключенным. Итак, выбираем вто-
рой или третий пункт, и спустя некоторое время попадаем
в загрузочное меню установщика.
Далее, для корректной работы новой прошивки нам не-
обходимо переразбить внутреннюю flash-память КПК, вы-
делив под root-раздел 28 Мб. Выбираем пятый пункт «Flash
repartition», и в ответ на вопрос вводим 28. По окончании
переразбивки КПК предложит перезагрузиться. Заново вхо-
дим в японское меню, и повторяем все действия вплоть до
попадания в загрузочное меню установщика прошивки. На-
конец, выбираем «Install new ROM» и ожидаем окончания
Ðèñóíîê 2. Îáíîâëåííûé èíòåðôåéñ
процесса.
После обновления ROM, вам, возможно, захочется по-
пробовать собрать какую-нибудь программу на Zaurus из
исходников. К сожалению, из-за относительно небольшого
объема запоминающего устройства на КПК по умолчанию
не стоят средства разработки. Тем более что все в основ-
ном собирается кросс-компилятором на «большом» линук-
се. Однако все-таки возможность разработки непосред-
ственно на КПК есть. Для этого необходимо скачать и уста-
новить «Developer image» – образ сжатой файловой систе-
мы, который занимает порядка 35 Мб. В нем содержится
компилятор gcc, заголовочные файлы, утилиты и библио-
теки для сборки утилит командной строки и Qtopia. Ска-
чать его можно с http://www.zaurususergroup.com. Там же
находятся и RPM-пакеты для кросс-компилятора.
Надеюсь, статьи, посвященные замечательному карман-
ному компьютеру от фирмы Sharp, не только помогли со- Ðèñóíîê 3. Ñèñòåìíàÿ èíôîðìàöèÿ

№12(25), декабрь 2004 9


администрирование

ДИСТРИБУТИВ ДЛЯ ВСЕХ


СЕРГЕЙ ЯРЕМЧУК
Какие бы доводы ни приводились в вечных спорах Windows ключить его. При появлении приглашения boot: возможно
vs Linux, но изучать компьютерные технологии, мне кажет- выбрать несколько вариантов загрузки. При нажатии на Enter
ся, лучше все-таки на UNIX-системах. Открытость, возмож- (или ввести linux) загружается обычное ядро, если набрать
ность разобраться во внутреннем строении, наличие огром- lids, загрузится ядро с поддержкой этого режима, возможны
ного числа удобных и свободных инструментов – все это еще варианты: 11 (переход сразу к 11 пункту см. ниже), 4 (к
позволяет при желании в совершенстве освоить любую про- 4 пункту), s4 (4 пункт с поддержкой LIDS), lock (пункт lock).
фессию, связанную с компьютерами. Но не всегда имеется Далее перед пользователем появляется меню:
возможность установить еще одну операционную систему.
1) Run Linux from CD-ROM with /var in RAM only
Сегодня пойдет речь об интересном дистрибутиве, который 2) Run Linux from CD-ROM with /var on FAT/EXT2 disk
позволяет изучить возможности GNU/Linux и, думаю, при- 3) Run Linux from FAT/EXT2 disk (incorporates Option 2)
4) Run Linux from CD-ROM with /var on USB storage
дется по вкусу некоторым администраторам и пользовате- 5) Install ADIOS repartition disk and create EXT3 filesystem
лям. 9) Create Swap file on FAT/EXT2 disk
Цель австралийского LiveCD дистрибутива ADIOS – Auto- x) Remove hardware and X windows configuration information
r) Change run-level (default 5 for X windows)
mated Download and Installation of Operating Systems (http:// i) Display Copyright, License and System Information
dc.qut.edu.au/adios) – дать возможность быстро и легко заг- h) Display Help
g) Display the 'guru' menu options
рузить и использовать операционную систему для лабора-
торных исследований. Первоначально образ ADIOS через Как видите, выбор большой. Возможно запустить ADIOS
веб-сервер использовался для установки операционной си- только с CD-ROM, примонтировать раздел /var с других ис-
стемы на жесткие диски компьютеров, дополнительно воз- точников либо установить его на жесткий диск и запускать
можно было сохранять копии образов OС на запасные дис- в дальнейшем оттуда, изменить уровень запуска системы
ковые разделы, и только относительно недавно появилась (по умолчанию 5). Но это еще не все пункты, если выбрать
возможность запускать с CD-ROM. Базируется дистрибу- «g» – guru, то их количество удвоится (появятся и опции 11
тив на Fedora 1.0. Поэтому ADIOS присущи поддержка боль- и lock). Отсюда при необходимости можно прямо из меню
шого количества оборудования и его автоматическое оп- создать/удалить swap-раздел или swap-файл (только на FAT
ределение, реализуемое при помощи kudzu, а также все те или ext2/3). Установку на жесткий диск система может вы-
понятные и удобные инструменты для настройки системы. полнить автоматически, в том числе и переразбить разде-
Система включает популярные графические среды – KDE, лы (как FAT, так и NTFS). Эта несколько рискованная опе-
GNOME и IceWM, так что первое знакомство с Linux прой- рация может быть выполнена и вручную при помощи ути-
дет в благоприятной обстановке. Ядро 2.4.24 собрано с под- литы ntfsresize. За подробностями работы которой обращай-
держкой loopback squashfs (http://squashfs.sourceforge.net), тесь к документации дистрибутива или к моей статье «Linux
файловой системы, использующей zlib для уменьшения раз- и NTFS» (журнал «Системный администратор», №8, август
мера, в результате в дистрибутив поместилось больше чем 2004 г.). В системе заведены четыре пользователя: root,
2 Гб приложений. В составе имеются ядра, поддерживают- super (Alternate Administrator), cso (Chief Security Officer) и
ся защищенные режимы – LIDS (Linux Intrusion Detection adios. Первые два представляют собой администраторов,
System), SELinux (NSA Security Enhanced Linux), в будущем причем в графическом режиме root система не позволит
планируется добавить Grsecurity или RSBAC. И кроме того зарегистрироваться, только super, cso необходим для ра-
поддерживается UML (User Mode Linux), при помощи кото- боты с SELinux и adios предназначен для повседневной ра-
рого возможно разбить одиночную систему на несколько боты. Пароль у всех этих пользователей один – 12qwaszx
независимых виртуальных машин, общающихся между со- (легко запомнить по две клавиши слева в каждом ряду),
бой через виртуальные Ethernet-интерфейсы. Поэтому поль- поэтому рекомендуется сразу же его сменить. Все найден-
зователи, желающие изучить на досуге эти технологии, ные разделы система монтирует в режиме «только чтение»,
получают готовый и уже настроенный инструмент. Систем- при необходимости записи перемонтируйте их с опцией –o
ные требования невысоки, поддерживаются все процессо- remount,rw. Дистрибутивы, основанные на RedHat, всегда
ры от 486 до Pentium 4 и минимально рекомендуемый объем отличались большим списком поддерживаемого оборудо-
ОЗУ – 64 Мб. вания, поэтому в большинстве для выхода в сеть остается
выставить только нужные параметры. Те, кто не знаком с
Работа с дистрибутивом работой консольных утилит вроде /sbin/ifconfig, найдут боль-
ADIOS в первую очередь LiveCD, и для удобства пользова- шое количество графических front-end для настройки сети,
телей в дистрибутиве заложены широкие возможности по например internet-druid (рис. 1).
сохранению части данных на разделах жесткого диска (DOS Программное обеспечение на диске содержит коллекцию
FAT или Linux EXT2/3), флоппи-диске или USB-устройствах. утилит управления и сетевого администрирования. Здесь
При каждом запуске система сканирует разделы жесткого все: веб-сервер Apache; прокси-сервер Squid; FreeS/WAN
диска и, если находит готовый swap-раздел, предлагает под- IPSec для создания VPN; маршрутизатор zebra; пакет Samba,

10
администрирование
который позволит работать в сетях Windows; сервер аутен- analysis tools (http://www.sleuthkit.org/sleuthkit). О возможно-
тификации openldap; сетевая система обнаружения атак стях утилит, входящих в его комплект, уже писалось на стра-
Snort c ACID; сканеры Nessus и Nmap; снифферы tcpdump ницах журнала. Для наглядности работы этих утилит раз-
и ethereal позволят проанализировать сетевые пакеты; фай- работчиками также установлен Autopsy Forensic Browser
рвол iptables с графическим интерфейсом firestarter; (http://www.sleuthkit.org/autopsy), позволяющий использовать
traceroute и графический xtraceroute позволят выяснить путь для вывода результатов веб-интерфейс. Для этого доста-
к интересующему узлу, и еще много сетевых утилит, тра- точно набрать в консоли autopsy & и вставить появившую-
диционно входящих в состав любой UNIX-системы. Имеют- ся строку в браузер.
ся утилиты для работы в беспроводных сетях. Далее Squirrelmail Webmail также дает возможность ис-
пользовать браузер для работы, в данном случае это по-
чта. Для его использования достаточно разрешить запуск
сервиса IMAP в /etc/xinetd.d/imap (disable = no) и запустить
xinetd, который по умолчанию не работает.

# /sbin/service xinetd start

И затем sendmail.

# /sbin/service sendmail start

Проверяем, работает ли веб-сервер /sbin/service httpd


status (для проверки всех запущеных /sbin/service --status-all).
Если все работает, набираем http://localhost/webmail.
Ðèñóíîê 1 В комплект программ также включен Swish-e (http://
Если набрать в строке веб-браузера IP-адрес своего ком- swish-e.org), позволяющий легко создать небольшой, но эф-
пьютера, то обнаружится еще одна положительная сторо- фективный поиск по сайту. При этом поиск по документам,
на ADIOS – ARK (Administrators Resource Kit) (рис .2), со- имеющимся на ADIOS CD, уже настроен. В любом другом
держащий большое количество различной документации случае это просто организовать самому. Настраиваем пара-
и коллекцию ссылок по Linux/UNIX вообще, настройке от- метры поиска в /etc/swish.conf, затем индексируем файлы.
дельных сервисов, защите, языкам программирования, ко-
торые придутся по душе новичкам. Отсюда же можно полу- #cd /var/www/swish
#swish-e -c /etc/swish.conf -f index.swish
чить доступ к man-страницам дистрибутива.
И в html-код страницы вставляем что-то вроде:

<form action=”/cgi-bin/search.cgi” target=”main”>

для возможности поиска документов из браузера.


Также в дистрибутиве имеются сервер переадресации
rinetd и утилита контроля Nagios. Плюс принятые в боль-
шинстве UNIX утилиты для программирования в bash, nasm,
C, C++, Perl, Python, PHP и Ruby со средствами отладки. А
еще офисные программы, утилиты для работы с мультиме-
диа, графикой, игры. Так что комплект на все случаи жиз-
ни. Работа с поддержкой SELinux возможна только после
установки ADIOS на жесткий диск.
Для тех, кто хочет создать свой собственный LiveCD,
проект представляет набор скриптов ADIOS development kit
Ðèñóíîê 2 (ADK), работа с которыми хорошо описана в документации.
Для удобства администрирования системы в комплект Изучение UNIX-систем никогда не было легким, требу-
входит webmin, для его запуска достаточно ввести /sbin/ ется затратить некоторые усилия и проявить терпение,
service webmin start и затем набрать в строке браузера http:// прежде чем появится первый результат. ADIOS представ-
localhost:10000, после чего использовать для входа пользо- ляет собой хороший инструмент, который поможет сделать
вателя root. Этот сервис может оказаться полезным еще и эти первые шаги. Кроме того, это неплохой инструмент для
потому, что дистрибутив практически не содержит данных, демонстрации возможностей GNU/Linux, при организации
необходимых для локализаций, отличных от английской, и всевозможных курсов, особенно когда используется обо-
только webmin можно заставить общаться на русском. рудование, задействованное в других задачах. И, конечно
Для работы с данными, содержащимися на жестких дис- же, его можно использовать при решении задач админист-
ках, в том числе для их восстановления и исследований по- рирования, когда нет под рукой других инструментов, по-
следствий взлома в комплекте имеется Sleuthkit file system зволяющих решить вдруг возникшие проблемы.

№12(25), декабрь 2004 11


администрирование

КОПИРОВАНИЕ ФАЙЛОВ
В АВТОМАТИЧЕСКОМ РЕЖИМЕ
С МНОЖЕСТВА КОМПЬЮТЕРОВ
ЧЕРЕЗ SSH

РАШИД АЧИЛОВ
Постановка задачи Настройка SSH
Предположим, имеется некоторое количество компьютеров SSH – это протокол связи двух компьютеров через TCP/IP
под управлением операционной системы UNIX (Windows) с c шифрованием передаваемых данных. Этот протокол обес-
запущенным SSH-сервером, на которых автоматически по печивает надежный и безопасный доступ к удаленному ком-
расписанию в некоторое время стартует программа, созда- пьютеру, расположенному... да неважно где, лишь бы у него
ющая резервные копии некоторых каталогов (например, был выход в Интернет. С точки зрения рядового системно-
/etc, /usr/local/etc) и складывающая их в определенное мес- го администратора SSH обычно рассматривается как бе-
то. Пример такого скрипта, адаптированного под систему зопасное средство удаленного управления сервером, для
periodic во FreeBSD, можно скачать с http://www.granch.ru/ чего ранее использовалась программа telnet. Конечно, есть
~shelton/fileZ/130.backup-dirs. Все используемые парамет- и другие средства шифровки трафика, но их мы рассмат-
ры описаны в начале скрипта. Для обеспечения сохраннос- ривать не будем.
ти данных архивов было бы неплохо копировать их все в Разумеется, шифрование сессии во время работы по
одну точку, откуда их можно было бы перенести на съем- SSH выполняется, но возможности SSH не исчерпываются
ный носитель, например. Копирование должно проводить- только этим. Я не буду приводить здесь описание всех воз-
ся в автоматическим режиме, все имена каталогов – быть можностей SSH, это тема для отдельной статьи, всех инте-
уникальными, требовать минимум настроек и обеспечивать ресующихся отсылаю к документации на SSH2 (http://
максимум безопасности при передаче данных по сети (если, www.ssh.fi/support/documentation/online/ssh/adminguide/32).
например, архив /etc попадет в чужие руки, можно полу- Одной из возможностей SSH является то, что он может
чить столько проблем, что мало не покажется). С этой це- выполнять авторизацию пользователей и организовывать
лью был разработан скрипт копирования файлов через удаленное выполнение команд в SSH-сессии без ввода па-
SCP2 (программу безопасного копирования, входящую в роля, с помощью так называемого публичного ключа. Эта
комплект SSH2) без ввода паролей, используя авториза- возможность основана на стандартном методе авториза-
цию с помощью публичных ключей. Скрипт выполняет ко- ции с помощью асимметричных ключей – приватного и пуб-
пирование файлов, размещенных в некотором, заранее личного.
обусловленном каталоге, отмечает каждое действие в соб- Приватный ключ доступен только пользователю и тща-
ственном файле журнала. В статье скрипт будет приводить- тельно им оберегается от хищения, публичный же ключ, на-
ся по частям (которые, будучи объединены вместе, тем не оборот, размещается во всех местах, где только можно его
менее дадут полноценный скрипт), полный текст скрипта разместить. На мой взгляд, наиболее удачное описание
можно загрузить с http://www.granch.ru/~shelton/fileZ/safecopy. того, как работает SSH и как его использовать (не считая,
Для разработки скрипта, отладки и применения исполь- конечно, man ssh2, man ssh.conf и прочих манов) – это кни-
зовался компьютер с операционной системой FreeBSD 4.10- га «SSH, the Secure Shell: Definitive Guide» [1].
STABLE и SSH2 от SSH Communications Inc., установлен- После того как принято решение о включении данного
ный из портов (/usr/ports/security/ssh2). Скрипт имеет неко- компьютера в автоматическое копирование файлов, но пе-
торые адаптационные возможности для работы с OpenSSH, ред тем как начинать собственно копирование, необходи-
но работоспособность этих возможностей не проверялась мо выполнить следующие шаги по настройке SSH:
и может содержать ошибки. Для работы скрипта использо- 1. Создаем пользователя, от имени которого будет вы-
валось имя пользователя rmbackup. полняться копирование файлов. Пользователь может не

12
администрирование
иметь пароля («*» в поле пароля в /etc/master.passwd), но тивном режиме. Это необходимо для создания хост-клю-
должен иметь действительный shell, поскольку он (shell) чей в подкаталоге hostkeys каталога .ssh2. Хост-ключи иден-
будет выполнять некоторые команды. Пользователь должен тифицируют SSH-сервер в целом. При отсутствии хост-клю-
быть создан на всех компьютерах, с которых будут копиро- ча в подкаталоге hostkeys перед началом сессии мастер и
ваться файлы, и на всех компьютерах иметь одинаковые удаленный компьютер обмениваются хост-ключами, и хост-
настройки и имя. Это не обязательно с точки зрения SSH, ключ удаленного компьютера помещается в подкаталог
но необходимо для скрипта, поскольку тот использует одно hostkeys для пользователя rmbackup. При этом на консоли
фиксированное имя пользователя. Интерактивной работы появляется следующий запрос:
на компьютерах, с которых будут копироваться данные,
>ssh mybox
никогда не будет, поэтому /bin/sh будет вполне достаточно. Host key not found from database.
На компьютере, на котором будет выполняться скрипт (на- Key fingerprint:
xocob-bicub-vatun-mofos-nutym-parok-sahet-hefer-papuh-kepyz-rexox
зовем его «мастер») установите любой привычный shell. You can get a public key's fingerprint by running
2. Создаем ключевую пару для данного пользователя % ssh-keygen -F publickey.pub
on the keyfile.
на данном компьютере. Для этого используется программа Are you sure you want to continue connecting (yes/no)? yes
ssh-keygen2. Порядок создания ключей не важен, следует Host key saved to /usr/home/rmbackup/.ssh2/hostkeys/key_22_mybox.pub
host key for mybox, accepted by rmbackup Wed Nov 03 2004 23:44:10 +0600
только помнить, что мастер-компьютер обращается ко всем
компьютерам, с которых копируются данные, а к самому Проверка того, что авторизация настроена правильно,
мастер-компьютеру не обращается никто. Поскольку пред- очень проста – набираете команду ssh remote на мастер-
полагается автоматическая работа, то создается ключевая компьютере, где remote – имя или адрес удаленного компь-
пара, не защищенная паролем. Пример создания ключе- ютера. Удаленная SSH-сессия должна начаться сразу же,
вой пары приведен ниже: без дополнительных запросов пароля. Если появится зап-
рос пароля на разблокировку ключа:
>ssh-keygen2 -P
>ssh mybox
Passphrase for key "/usr/home/rmbackup/.ssh2/id_dsa_2048_a"
Опускать -P здесь нельзя – опция указывает на необхо- with comment "2048-bit dsa, rmbackup@mybox.com,
Fri Jul 23 2004 12:50:25 +0700":
димость создания ключа, не защищенного паролем. После
создания ключевой пары появляются файлы id_dsa_2048_a значит ключ был сгенерирован с паролем. Такой ключ сле-
(приватный ключ) и id_dsa_2048_a.pub (публичный ключ). дует удалить и создать заново, но без пароля (см. пример
Подробную информацию о создании ключевой пары см. man выше).
ssh-keygen2. Публичный ключ мастер-компьютера, пере- Если же появляется стандартный запрос пароля:
именованный, например, в rmbackup_master.pub, нужно по-
местить в подкаталог .ssh2 домашнего каталога пользова- >ssh mybox
rmbackup's password:
теля rmbackup на всех компьютерах, с которых будут копи-
роваться файлы. значит, существуют проблемы в настройке авторизации. В
3. Настраиваем конфигурационные файлы идентифи- разделе «Возможные ошибки и изменения скрипта» при-
кации и авторизации. Эти файлы определяют имя файла ведены примеры того, что может пойти не так во время на-
(файлов – в SSH2 их может быть несколько) приватного стройки, и некоторые советы по исправлению создавшего-
ключа (ключей) и имена файлов, задающие ключи, автори- ся положения.
зация с которыми разрешена на данном компьютере для
данного пользователя. По умолчанию имена этих файлов Дополнительные вопросы безопасности
identification и authorization. На мастер-компьютере файл Поскольку созданный нами публичный ключ не имеет па-
authorization можно не создавать – на него никто не будет рольной защиты, то всегда существует ненулевая вероят-
заходить данным пользователем. На компьютерах, с кото- ность, что данный ключ может быть похищен и использо-
рых будут копироваться данные, файл authorization обяза- ваться не по назначению. Для того чтобы сделать такую
тельно должен содержать имя файла ключа мастер-компь- возможность как можно менее привлекательной, пользо-
ютера. Примеры файлов: вателя, от имени которого выполняется копирование, по-
местим в chroot-окружение.
identification: Что это такое? Это отдельная настройка SSH-сервера,
IdKey id_dsa_2048_a
authorization: при которой он передает клиенту информацию о том, что
Key rmbackup_master.pub домашний каталог пользователя – это корень файловой
системы. Естественно, выше корня двигаться невозможно.
Следует иметь в виду, что если планируется заходить с Технология изоляции критичных системных сервисов в «пе-
нескольких компьютеров, ключ каждого компьютера дол- сочницы» (sandboxes) применяется уже достаточно давно
жен быть помещен в подкаталог .ssh2 данного компьютера и успешно. Правда тут есть одно «но» – нам понадобится
и описан в файле authorization. Более подробная информа- обеспечить работоспособность сервера в данном окруже-
ция о настройке авторизации по публичному ключу приве- нии. Поскольку абсолютно все, что находилось выше до-
дена в man ssh.conf и man sshd.conf. машнего каталога в режиме chroot, недоступно, следует со-
4. В первый раз заходим с мастер-компьютера на ком- здать собственную иерархию каталогов со всем необходи-
пьютер, с которого будут копироваться файлы в интерак- мым. Правда, этого необходимого крайне мало. В домаш-

№12(25), декабрь 2004 13


администрирование
нем каталоге пользователя rmbackup на удаленном компь- connection from "192.168.1.1"
ютере следует создать каталоги /bin и /etc. В каталог /bin Public key /usr/local/share/rmbackup/.ssh2/rmbackup_mybox.pub used.
Public key authentication for user rmbackup accepted.
поместить файлы (переписать из стандартного /bin) ls, sh и User rmbackup, coming from mybox, authenticated.
(ВНИМАНИЕ!) исполняемый файл sftp-server, собранный User 'rmbackup' will be chrooted to directory '/usr/local/share/rmbackup'.
таким образом, что у него отсутствуют динамические ссыл- Now running on rmbackup's privileges.

ки на библиотеки. Такой режим обычно применяется для Предварительная подготовка завершена. Мы настрои-
программ, используемых в процессе восстановления сис- ли компьютеры, с которых (и на которые) будут копировать-
темы. Исполняемый файл sftp-сервера должен быть обяза- ся данные таким образом, что можно выполнять команду
тельно собран с отключением динамических библиотек, на удаленном компьютере через SSH2 без ввода паролей с
иначе придется дублировать всю структуру динамической помощью авторизации по публичному ключу.
загрузки – /usr/libexec/ld-elf.so, /var/run/ld-so.hints и все ос-
тальное. Исполняемый файл такого типа можно получить, Настройка скрипта
дописав в каталоге, где лежат исходные тексты ssh, в под- Настройка скрипта выполняется через задание перемен-
каталоге apps/ssh в файл Makefile в строчку 273 (или около ных в конфигурационном файле /etc/periodic.conf. Эти пе-
того) LDADD=<флаги> флаг -static и пересобрать SSH. Как ременные используются скриптом резервного копирования,
проверить, является ли полученный исполняемый файл ста- упомянутым в начале статьи, и скриптом, описываемым в
тически или динамически собранным? данной статье.
Скрипт использует следующие переменные:
> ldd sftp-server2
Ldd: sftp-server2: not a dynamic executable
daily_backup_owner="rmbackup" # Owner of backup files
daily_backup_group=”wheel” # Group of backup files
Приведенный выше ответ является правильным, если daily_backup_mode="0600" # Mode of backup files
вместо него появляется что-то типа: daily_backup_dirmode="0700" # Mode of intermediate dirs

> ldd sftp-server2: Это соответственно переменные, задающие пользова-


libm.so.2 => /usr/lib/libm.so.2 (0x280bb000)
libcrypt.so.2 => /usr/lib/libcrypt.so.2 (0x280d7000) теля, группу, режим доступа к файлам и каталогам, созда-
libutil.so.3 => /usr/lib/libutil.so.3 (0x280f0000) ваемым скриптами. Скрипт не устанавливает значения пе-
libncurses.so.5 => /usr/lib/libncurses.so.5 (0x280f9000)
libc.so.4 => /usr/lib/libc.so.4 (0x2813b000)
ременных по умолчанию, поэтому все переменные должны
быть заданы в /etc/periodic.conf или /etc/defaults/periodic.conf.
значит, это динамически собранный исполняемый файл, и
он не годится. На самом деле его тоже можно использо- Заголовок и вспомогательные функции
вать. Но для этого придется создать /usr/libexec в домаш-
нем каталоге пользователя rmbackup, перенести туда ls- #!/bin/sh
# Safe updating, so – copying current daily backup directory
elf.so, создать /usr/lib и поместить туда все библиотеки, пе- # from remote server to local. Used SSH2 publickey auth
речисленные в выводе ldd, создать /var/run/ld-so.hints ко- # method, so you need a working installation before starting.
# This is an open-source software, licenced by BSD license.
мандой ldconfig. С моей точки зрения, пересобрать програм- # Written by CityCat 23.07.2004
му значительно проще. # $Id: safecopy,v 1.5 2004/08/10 04:26:40 shelton Exp $
В каталог /etc помещаются файлы group и master.passwd. PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin: ↵
Из файла group удаляются все реальные пользовательс- /usr/local/sbin
кие группы, важно, чтобы там присутствовала группа, про-
писанная как ChrootGroup в конфигурационном файле SSH- В приведенном выше заголовке нет ничего необычно-
сервера. Из файла master.passwd удаляются все пользова- го. Переустановка переменной PATH нужна для того, что-
тели с паролями, пароль root заменяется на «*». После чего бы находить программу SSH2, даже если пользователь ее
создаются файлы passwd, pwd.db и spwd.db командой: изменил.

>pwd_mkdb -p -d . master.passwd # Logging function


# Logged string in variable logline!
safe_logger()
Теперь файл master.passwd можно стереть. Кроме того, {
logdate=`date +"%d/%m/%Y %T"`
в конфигурационном файле SSH-сервера указывается груп- echo "$logdate [$$] safering: $logline" >> $logfile
па, к членам которой будет применяться chroot (по умолча- }
нию это группа sftp):
Функция записи информации в регистрационный жур-
ChRootGroups sftp,guest нал, который ведется программой, имитирует работу про-
граммы logger и формирует в журнале записи такого фор-
Кроме того, проследите, чтобы параметр AllowedAuthen- мата:
tications содержал publickey, а RequiredAuthentications не
содержал password. Еще лучше, чтобы он был удален или 07/08/2004 05:00:02 [70241] safering: File _etc.tar.bz2 from host mybox
was succesfully transferred
закомментирован. Как убедиться в том, что сессия идет в
chroot? В файле регистрационного журнала SSH-сервера при этом выводимая в журнал строка передается в пере-
об этом делается специальная отметка: менной logline.

14
администрирование
# Go down function ! Переменные hostlist и logfile задают соответственно име-
# Set variable godown to downing directory name на файлов списка компьютеров и регистрационного
go_down() журнала.
{ ! Переменные wsyear, wsmon и wsday хранят текущие год,
if [ ! -e $godown ]; then
mkdir $godown месяц, день.
chown $daily_backup_owner:$daily_backup_group $godown ! Переменная openssh указывает на то, что SSH, обнару-
chmod $daily_backup_dirmode $godown
fi женный скриптом, является OpenSSH (используется для
cd $godown
адаптации путей и работы с конфигурационными фай-
} лами).
! Переменная sshconf указывает на расположение конфи-
Функция перехода в подкаталог, задаваемый перемен- гурационного файла SSH по умолчанию.
ной godown. Если каталог отсутствует, он будет создан, и ! Переменная sshome указывает на пользовательский ка-
ему будут установлены права доступа, заданные в конфи- талог с настройками, ключами и т. д. для SSH (имена
гурационном файле. каталогов отличаются в SSH2 и OpenSSH).
! Переменная scpname задает имя программы безопас-
# If there is a global system configuration file, suck it in. ного копирования SCP (в SSH2 и OpenSSH они отлича-
#
if [ -r /etc/defaults/periodic.conf ]; then ются).
. /etc/defaults/periodic.conf
source_periodic_confs
fi Проверка командной строки
и обнаружение SSH
Загрузка значению по умолчанию для скрипта, если они
заданы (обычно вписываются в /etc/defaults/periodic.conf). # Check commandline
if [ $# -ne 0 ]; then
if [ $1 = "-h" ]; then
Переменные echo "Safering updater. Copying current daily ↵
backup dir from remote server."
Единственная переменная, которую имеет смысл настра- echo " Usage: safecopy [hostlist-location-and-name]."
ивать в скрипте, вынесена перед строкой предупрежде- exit
else
ния. Разумеется, все остальные переменные тоже можно hostlist=$1
менять – это же скрипт. Но все же делать это не рекомен- fi
fi
дуется без понимания механизма его работы.
# Check on presence SSH in system and detect their version
# Variables wssh=`which ssh2'`
# There is only maintained variables! if [ -z $wssh ]; then
# This is a root folder for all subordinated folders wssh=`which ssh'`
sysdir="/usr/local/share/rmbackup"
if [ -z $wssh ]; then
# NO CHANGES BEHIND THIS LINE!! YOU HAVE BEEN WARNED!! logline="No any SSH program was detected, ↵
backupdir="backup"
ringdir="$sysdir/backup" install it first"; safe_logger
exit
maintdir="$ringdir/maint" else
hostlist="$maintdir/cphosts"
logfile="$maintdir/saferlog" wsver=`$wssh | awk '{printf "%s %s %s",$1,$2,$3}'`
sshome="$HOME/.ssh"
wsyear=`date +"%Y"` scpname=scp
wsmon=`date +"%m"` wsx=`$wssh | awk '{print $3}'`
wsday=`date +"%d"`
# We assumed SSH2 by SSH Com. presence and locating config if [ $wsx = "SSH" ]; then
openssh=1
# in /usr/local/etc/ssh2 sshconf="/etc/ssh/ssh_config"
openssh=0
sshconf="/usr/local/etc/ssh2/ssh2_config" else
logline="Broken SSH1 from SSH ↵
sshome="$HOME/.ssh2" Communicationc Inc. probably detected"
scpname=scp2
safe_logger
exit
fi
Итак: fi
! Переменная sysdir указывает корневой каталог систе- else
wsver=`$wssh -V 2>&1 | awk '{printf "%s %s ↵
мы кольцевого копирования. Обычно это домашний ка- %s %s",$2,$3,$4,$5}'`
талог пользователя rmbackup, хотя можно указать лю- fi
бой другой. В этом каталоге будут располагаться все # Log detected version
остальные каталоги. logline="Detected version: $wsver"; safe_logger
! Переменная backupdir указывает на каталог с резерв-
ными копиями на удаленном компьютере. Допустимыми параметрами командной строки являют-
! Переменная ringdir указывает на каталог с резервными ся -h или имя файла со списком компьютеров, с которых
копиями на мастер-компьютере. производится копирование. Если имя файла не задано,
! Переменная maintdir указывает на каталог с регистра- будет использоваться файл cphosts в каталоге $maintdir.
ционным журналом, списком компьютеров, с которых Первым делом ищется программа ssh2 (which ssh2).
будут копироваться данные, и собственно скриптом. Если она найдена, то выбирается информация о версии (пе-

№12(25), декабрь 2004 15


администрирование
ременная wsver будет содержать «SSH Secure Shell x.x.x.x», Разбор строки и получение списка
где x.x.x.x – номер версии SSH), и полученная информация файлов для копирования
выводится в регистрационный журнал. Если же она не най-
дена, производится попытка обнаружить программу ssh # Parse host line
hostname=`echo $host | awk '{print $1}'`
(which ssh), и если она найдена, проверяется, что за про- hostadr=`echo $host | awk '{print $2}'`
грамма обнаружена. Если это OpenSSH (определяется по
fullpath=$backupdir/$wsyear/$wsmon-$wsyear/ ↵
характерному признаку – третье слово при запуске без па- $wsday-$wsmon-$wsyear
раметров содержит «SSH»), то переменные sshome, scpname,
# Take list of files to backup
sshconf и openssh устанавливаются в соответствующие зна- wls=`$wssh -o "BatchMode yes" -q $hostadr ↵
чения. Иначе скрипт завершает работу, поскольку работа с "cd $fullpath 2> null && /bin/ls -1"`
SSH1 от SSH Communications не поддерживается (по при-
чине его небезопасности). Один из двух наиболее важных моментов. Скрипт копи-
рования файлов создает каталоги вида YYYY/MM-YYYY/DD-
Проверка наличия MM-YYYY, где YYYY – текущий год, MM – текущий месяц,
файла идентификации DD – текущий день. Можно было бы, конечно, создавать
и разбор списка компьютеров папки типа YYYY/MM/DD, но мне удобнее просматривать
Как уже говорилось выше, файл идентификации обязатель- список в mc, когда видна полная дата. В переменной wls
но должен быть создан, если предполагается использовать после выполнения команды будет результат команды «пе-
авторизацию по публичному ключу. Поэтому отсутствие рейти в заданный каталог и получить список файлов в нем».
данного файла обозначает ситуацию, когда авторизация по Если предполагается копировать нечто другое, следует за-
публичному ключу еще не была настроена. дать соответствующий путь в переменной fullpath.
Если команда завершилась аварийно, то список будет
# Taking identity file name, drop down comment field пуст, и скрипт перейдет к другому узлу из списка или завер-
identity=`grep IdentityFile $sshconf`
idfirst=`echo $identity | awk '{print $1}'` шит работу, если этот список уже кончился. Результат вы-
полнения последней команды хранится в переменной status.
if [ $idfirst = "#" ]; then
idfile=`echo $identity | awk '{print $3}'` Если команда выполнена успешно, то выполняется после-
else довательный переход в каталоги: имя удаленного компью-
idfile=`echo $identity | awk '{print $2}'`
fi тера, YYYY, MM-YYYY, DD-MM-YYYY, например: cd myhost;
cd 2004; cd 12-2004; cd 15-12-2004. Если такой каталог от-
# For OpenSSH drop down path from pathname
if [ $openssh -eq 1 ]; then сутствует, он создается с правами, заданными параметра-
idname=${idfile##*/} ми. Мы говорили об этом в разделе «Настройка скрипта».
else
idname=$idfile
fi # When list is empty, do nothing
# (and don't create directories)
# Check on existance identification file. When doesn't – status=$?
# SSH dodn't setup to work with publickey auth method
if [ ! -e $sshome/$idname ]; then if [ $status -ne 0 ]; then
logline="Publickey auth method did not configured ↵ continue
yet"; safe_logger else
exit # Go down the ladder
fi godown=$hostname; go_down
godown=$wsyear; go_down
godown=$wsmon-$wsyear; go_down
Скрипт проверяет наличие параметра IdentityFile в кон- godown=$wsday-$wsmon-$wsyear; go_down
фигурационном файле сервера (даже если он отмечен зна- fi
ком комментария). Для OpenSSH дополнительно отбрасы-
вается путь к IdentityFile, если он там указан. Потом прове-
ряется существование файла, описанного как IdentityFile. Пофайловое копирование
Если он не существует, скрипт прекращает работу.
Разбор списка компьютеров осуществляется установ- for file in $wls
do
кой переменной IFS в значение «\n». Для этого не нужно $scpname -q -Q $hostadr:$fullpath/$file . 2> null
писать «IFS=”\n”» – shell не интерпретирует метасимволы. status=$?
Следует написать «IFS=”», нажать «перевод строки» и зак- # Check on operation return code
рыть кавычку – внутри кавычек окажется символ перевода if [ $status -ne 0 ]; then
logline="Transfer of file $file unsuccesful, ↵
строки. После считывания файла организовывается стан- return code is $status"; safe_logger
дартный цикл по списку переменных-строк: else
logline="File $file from host $hostname ↵
was succesfully transferred"; safe_logger
# Taking hosts list chown $daily_backup_owner:$daily_backup_group $file
IFS=" chmod $daily_backup_mode $file
" fi
hosts=`cat $hostlist`
cd $ringdir done
# Doing safering update # Return to top
for host in $hosts cd $ringdir
do done

16
администрирование
Последнее и самое важное действие скрипта – пооче- компьютере на предмет сообщений об ошибках и устра-
редное копирование файлов из списка, полученного на пре- нить их.
дыдущем шаге. Выполняется команда scp, и результат ее Если предыдущая команда завершена успешно, следу-
работы заносится в переменную status. В зависимости от ет проверить работу команды scp следующим образом (за-
значения переменной status выдается сообщение либо об менить 192.168.1.1 на IP-адрес или имя компьютера, с ко-
успешном завершении копирования (при этом устанавли- торого должны быть получены файлы. Файл .profile должен
ваются права и режим доступа, соответствующие парамет- существовать на удаленном компьютере):
рам, перечисленным в пункте «Настройка скрипта»), либо
об аварийном завершении (и тогда в журнал заносится код scp2 192.168.1.1:.profile ./profile-tmp
ошибки, расшифровку которого можно посмотреть в man
ssh2). (Внимание! Точка – элемент команды!)
Если в текущем каталоге появился файл .profile-tmp,
Возможные ошибки следует уточнить код ошибки по руководству к ssh2 (man
и изменения скрипта ssh2) и устранить ошибки. Если же нет – проверить файл
Если скрипт работает не так, как ожидается, то, скорее все- журнала, в который выводятся сообщения от SSH-сервера
го, имеет место ошибка в настройке SSH (по крайней мере, на удаленном компьютере на предмет сообщений об ошиб-
почти все ошибки, с которыми я сталкивался после завер- ках, и устранить их. Здесь наиболее частой ошибкой мо-
шения его разработки, были такого плана). Это очень про- жет быть неверный sftp-server2, который не собран в соот-
сто проверить – достаточно с консоли мастер-компьютера ветствии с рекомендациями раздела «Дополнительные воп-
набрать ssh remotebox, где remotebox – имя любого компь- росы безопасности», а просто переписан и для работы тре-
ютера, с которого должны копироваться данные. Если сра- бует наличия динамического загрузчика, libc и пр.
зу же открывается терминал удаленного компьютера – все Как можно изменить место, откуда берутся копируемые
нормально (при этом motd показываться не должно). Если файлы на удаленном компьютере? Для этого достаточно
же появляется запрос пароля на разблокирование ключа, изменить формирование переменной fullpath, описанной в
запрос пароля на регистрацию на удаленном компьютере разделе «Разбор строки и получение файлов для копиро-
или какие-либо сообщения об ошибках – следует устранить вания».
ошибки и повторить. Как можно изменить место и организацию каталогов, в
Единственной ошибкой, которую можно совершить при которые раскладываются файлы на мастер-компьютере? Для
генерации ключа, является запуск ssh-keygen2 без ключа этого в функцию go_down передается значение переменной
-P. При этом при генерации ключа будет запрошен пароль. godown – каталог будет создан по ее содержимому. Можно
Если при генерации ключа появился запрос пароля, лучше вообще все складывать в один каталог – для этого нужно
генерацию прервать и запустить ssh-keygen2 заново с клю- закомментировать строки с «godown=...; go_down».
чом -P.
Самой распространенной ошибкой авторизации явля- Заключение
ется то, что ключ мастер-компьютера не помещен в ката- Данный скрипт – инструмент системного администратора
лог .ssh2 пользователя rmbackup удаленного компьютера, из разряда «настроил и забыл». После его настройки он не
не описан в файле authorization, или в имени ключа допу- требует какого-либо сопровождения, кроме, пожалуй, ре-
щена банальная опечатка. Если ключ для пользователя гулярного резервного копирования каталога с файлами,
rmbackup создавался через su rmbackup от пользователя скопированными с удаленных компьютеров. Ну и, конечно,
root, возможно, установлены неверные права на файлы обеспечения необходимых мер безопасности по отношению
identification и authorization (при создании файлов владель- к каталогу, в котором хранятся резервные копии. Разуме-
цем становится создатель). Второй распространенной ется, он разрабатывался для решения определенной част-
ошибкой является задание параметра RequiredAuthentication ной задачи, но его нетрудно адаптировать для копирова-
password в конфигурационном файле sshd.conf на удален- ния чего угодно откуда угодно. Ошибки в самом скрипте
ном компьютере, требующего обязательной аутентифика- исключены ввиду его достаточной простоты, как правило,
ции по паролю. все ошибки связаны с ошибками самого SSH.
Если терминальная сессия на удаленном компьютере
открывается нормально, то следует попробовать вручную Дополнительная информация:
ввести команду (вместо 192.168.1.1 подставить IP или имя 1. Daniel J. Barrett, Richard Silverman. SSH, the Secure Shell:
компьютера, с которого должны быть получены файлы): Definitive Guide. O’Reilly & Associates, 2001, 558 pages.
ISBN: 0-596-00011-1.
>su rmbackup 2. http://www.ssh.fi/support/documentation/online/ssh/
>ssh2 -o "BatchMode yes" -q 192.168.1.1 "cd /etc && ↵
/bin/ls -1" adminguide/32 – SSH Secure Shell for Servers Version 3.2
Administrator’s Guide.
Если в результате выполнения этой команды получа- 3. http://www.opennet.ru/docs/RUS/ssh_faq – Faq по SSH в
ется оглавление каталога /etc (в chroot это файлы group, русской редакции. Русская редакция: Андрей Лаврен-
passwd, pwd.db и spwd.db) – значит, следует проверить ра- тьев (lavr@unix1.jinr.ru).
боту scp. Иначе следует проверить файл журнала, в кото- 4. man ssh2, man sshd2, man ssh.conf, man sshd.conf, man
рый выводятся сообщения от SSH-сервера на удаленном ssh-keygen2.

№12(25), декабрь 2004 17


администрирование

ЕДИНАЯ УЧЕТНАЯ ЗАПИСЬ


ДЛЯ WINDOWS И UNIX
В ACTIVE DIRECTORY

ИГОРЬ ПОЛЯНСКИЙ
В данной статье речь пойдет о том, как управлять единой А за тем, что очень многие организации изначально ориен-
учетной записью пользователя посредством MS Active тированы на платформу Windows и в качестве каталога при-
Directory вне зависимости от того, на какой платформе он меняют Active Directory, а когда в сети начинает появляться
работает, будь то Windows или UNIX-подобные системы. За- UNIX, то встает вопрос об интеграции, и не всегда хорошие
бегая вперед, скажу, что если с Windows-клиентами все ясно, коммерческие решения подходят, либо из-за стоимости, либо
то интеграция с каталогом от Microsoft тем способом, кото- в силу других причин. Я изначально рассматривал вариант с
рый будет здесь описан, подходит не для всех UNIX-подоб- ведением второго каталога для UNIX-клиентов на базе
ных операционных систем. Так уж сложилось – все они раз- OpenLdap, но хотелось все-таки управлять учетными запи-
ные, да и Active Directory вовсе не идеальная среда для ин- сями из единой точки, а именно из Active Directory, потому
теграции разнородных систем. Тогда зачем я все это пишу? что этот каталог широко используется у нас в сети.

18
администрирование
Вариант Samba + winbind меня не устраивал, поскольку
по роду задач samba вообще не нужна, к тому же это лиш-
ние службы на каждой машине, использование которых все-
таки не решает проблем с централизованным управлени-
ем пользовательскими данными, поэтому это решение мне
показалось неразумным и неизящным.
Более всего привлекал вариант с использованием сер-
вера NIS, который входит в продукт, известный как Services
For Unix от компании Microsoft и синхронизация записей
Active Directory to NIS. Зайдя на microsoft.com в надежде
скачать SFU3.5, которая в отличие от предыдущей версии
SFU3.0 бесплатна, я набрел на ряд интересных статей, про-
читав которые, пошел по другому пути.
Как уже говорилось в начале, не все UNIX-подобные си-
стемы могут проходить аутентификацию и запрашивать
данные о пользователе в Active Directory описанным здесь
способом, а только те, которые умеют работать с PAM и
pam-модулями. Как вы, наверное, догадались, я буду опи-
сывать способ взаимодействия с ldap-сервером, входящим
в Active Directory через модули pam_ldap и nss_ldap.
Итак, начнем. В качестве подопытных будут выступать
MS Windows 2000 Server Standart с установленной Active
Directory (в дальнейшем AD), Linux Manrdake 10.0, Solaris 9
x86, FreeBSD 4.10. Над Windows 2000/XP опыты ставить бес- Как видите, теперь у каждого пользователя есть атрибу-
смысленно – все и так работает. Как минимум понадобит- ты, применяемые в UNIX-системах. Первое поле «NIS
ся DNS-сервер, который может быть установлен на том же Domain» будет содержать краткую форму имени нашего до-
Windows 2000 Server. Свежеустановленная AD не имеет тра- мена. Этот параметр нужен для службы NIS, и хотя в нашем
диционной ldap-схемы для UNIX: userid, grouid, login shell, случае она не применяется, без нее не активируются другие
home directory. Нам нужно её расширить, и для этого я вос- поля. С остальными полями, я думаю, затруднений не воз-
пользуюсь SFU3.5. Вообще-то существует несколько спо- никнет, может быть, за исключением GID. Прежде чем выб-
собов это сделать: вручную создав ldif-файл с нужной схе- рать из этого поля группу, её надо создать или в свойствах
мой и импортировав его при помощи каких-либо программ уже имеющейся задать UNIX-атрибуты. Проблема с группа-
сторонних разработчиков, например такой, как AD4Unix ми заключается в том, что нельзя задать одно и то же имя
(www.padl.com/download/MKSADPlugins.msi), или с помощью для пользователя и группы, а в мире UNIX такой подход весь-
SFU от Microsoft. Первый способ я оставляю гуру, вышеоз- ма распространен. В таком случае можно использовать толь-
наченную программу MKSADPlugins.msi вам установить ко численное представление, правда, я сомневаюсь, что это
вряд ли удастся, если Windows 2000 Server работает с аль- хороший выход из создавшейся ситуации. Ещё потребуется
тернативной локалью, отличной от US, что для России уме- создать учетную запись, которая будет применяться для вза-
стно. В пользу же SFU, на мой взгляд, говорит то, что она имодействия UNIX-машин с ldap-сервером. Это своего рода
сделана в том же КБ, где Windows и AD, плюс в своем со- дыра в безопасности, поэтому сей аккаунт не должен при-
ставе имеет много утилит от UNIX. надлежать кому-либо и доступ к важным ресурсам ему дол-
Пройдя добровольно-принудительную процедуру полу- жен быть запрещен. Тем не менее он должен иметь право на
чения .NET Passport, вы сможете бесплатно скачать и ис- поиск объектов в каталоге. На этом этапе вы готовы управ-
пользовать SFU3.5 (www.microsoft.com/windows/sfu). Размер лять единой учетной записью при помощи Active Directory.
программы примерно 230 Мб. Прежде чем устанавливать Переходим к настройке клиентских машин. Я использо-
SFU, нужно инсталлировать Active Directory Schema MMC вал Linux Mandrake 10.0 Official и всё необходимое ПО ус-
snap-in следующей командой: танавливал из rpm-пакетов, входивших в состав дистрибу-
тива. Понадобится установить pam_ldap и nss_ldap. После
regsvr32 ñ:\WINNT\system32\schmmgmt.dll установки этих пакетов нужно отредактировать несколько
конфигурационных файлов. Pam_ldap и nss_ldap для на-
Для расширения схемы AD достаточно установить толь- строек используют один и тот же файл ldap.conf. Также нуж-
ко NIS-сервер из состава SFU. Для успешного завершения но будет отредактировать nsswitch.conf и как минимум один
установки необходимо быть либо членом групп Domain файл, находящийся в /etc/pam.d, а именно system-auth. Не
Admins и Schema Admins, либо работать с правами Адми- забудьте сделать копии оригинальных файлов. Итак, файл
нистратора. После установки будет предложено перегру- ldap.conf должен содержать следующее:
зить машину. NIS-сервер как таковой не понадобится и его
можно остановить и благополучно забыть о нём. В свой- # Áàçîâûå íàñòðîéêè, íåîáõîäèìûå äëÿ ïîäêëþ÷åíèÿ ê AD.
# domain, loc è server.domain.loc âû äîëæíû èçìåíèòü
ствах пользователя, группы, компьютера в Active Directory # â ñîîòâåòñòâèè ñî ñâîèìè íàñòðîéêàìè
Users and Computers добавится вкладка UNIX Attributes. base dc=domain,dc=loc

№12(25), декабрь 2004 19


администрирование
scope sub правила для локального пользователя, если такой учетной
uri ldap://server.domain.loc записи нет, то информация берется из AD. Но есть одна ма-
port 389
ldap_version 3 ленькая проблема, которая может стать большой. Дело в том,
# Òîò ñàìûé àêêàóíò, êàê âèäèòå, îí áûë ñîçäàí â êîíòåéíåðå
что домашний каталог автоматически не создается и по умол-
# Users ñ èìåíåì ldap è ïàðîëåì qwerty чанию таковым считается /. Вам придется создавать домаш-
binddn cn=ldap,cn=Users,dc=domain,dc=loc ние каталоги руками на каждой машине, что не очень удоб-
bindpw qwerty
но. Для этого можно использовать модуль pam_mkhomedir.
# Êîãäà âû áóäåòå ââîäèòü èìÿ ïîëüçîâàòåëÿ è ïàðîëü, áóäóò При регистрации в данной системе модуль смотрит, есть ли
# ïðèìåíÿòüñÿ ñëåäóþùèå îáúåêòû è àòðèáóòû èç AD:
pam_filter objectclass=User домашний каталог, если нет, то он его создает и копирует
pam_login_attribute sAMAccountName туда файлы из /etc/skel. Вы можете в соответствии со свои-
pam_password ad
ми требованиями менять и порядок модулей, и их опции для
# Ýòè çàïèñè íóæíû äëÿ óñêîðåíèÿ ïîèñêà. Ìîæåòå èõ âîîáùå разных служб. В таких перестановках надо быть осторож-
# íå âñòàâëÿòü. Îáðàòèòå âíèìàíèå, âñå ïîëüçîâàòåëè â ýòîì
# ïðèìåðå õðàíÿòñÿ â «Organization Unit → firma» ным, потому как можно прийти к неожиданным результатам
nss_base_passwd ou=firma,dc=domain,dc=loc?sub вплоть до невозможности регистрироваться в системе даже
nss_base_shadow ou=firma,dc=domain,dc=loc?sub
nss_base_group ou=firma,dc=domain,dc=loc?sub под учетной записью root. Для начала логично почитать что-
# Ýòè çàïèñè îòíîñÿòñÿ ê ìîäóëþ nss_ldap, ïðåîáðàæàþò
нибудь о PAM. После этих манипуляций можно попробовать
# îáúåêòû è àòðèáóòû AD ê âèäó, ïðèíÿòîìó â LDAP зарегистрироваться на Linux-машине пользователем, кото-
nss_map_objectclass posixAccount User рый не упоминается в файлах passwd, shadow, group, но его
nss_map_objectclass shadowAccount User
nss_map_attribute uid sAMAccountName UNIX-атрибуты присутствуют в AD.
nss_map_attribute uidNumber msSFU30UidNumber Если всё прошло отлично, то при первом входе среди
nss_map_attribute gidNumber msSFU30GidNumber
nss_map_attribute cn sAMAccountName прочих надписей увидим следующее:
nss_map_attribute uniqueMember member
nss_map_attribute homeDirectory msSFU30HomeDirectory Creating directory '/home/test'.
nss_map_attribute loginShell msSFU30LoginShell Creating directory '/home/test/tmp'.
nss_map_attribute gecos name Посмотрим, кем нас считает система:
nss_map_objectclass posixGroup Group
[test@linux-pc test]$ id
Далее на очереди файл nsswitch.conf, тут всё просто – uid=10000(test) gid=10000(testgroup) groups=10000(testgroup)
находите строчки: Настраиваем Solaris 9 x86. В Solaris есть свои модули
pam_ldap и nss_ldap, только вот незадача – они не совсем
passwd: files nisplus nis совместимы с Active Directory, поэтому Microsoft рекомен-
shadow: files nisplus nis
group: files nisplus nis дует использовать модули от PADL (www.padl.com), те же,
что применяются в Linux. Чтобы скомпилировать эти моду-
и меняете их на: ли, потребуется установить ряд GNU-утилит, получить их
можно на www.sunfreeware.com. Оглашаю весь список:
passwd:
shadow:
files ldap
files ldap
! autoconf-2.57-sol9-intel-local.gz
group: files ldap ! automake-1.7.2-sol9-intel-local.gz
! gcc-3.2.1-sol9-intel-local.gz
Редактируем файл /etc/pam.d/system-auth: ! m4-1.4-sol9-intel-local.gz
! make-3.80-sol9-intel-local.gz
#%PAM-1.0
auth required pam_env.so
auth sufficient pam_unix.so likeauth nullok Плюс к этому берем с сайта www.blastwave.org пакет
auth sufficient /lib/security/pam_ldap.so ↵ berkeleydb3-3.11-i386-CSW.pkg.gz.
use_first_pass
auth required pam_deny.so Перед тем как собирать pam_ldap и nss_ldap, создадим
символическую ссылку в /usr/local/bin на perl:
account required pam_unix.so
account [default=bad success=ok user_unknown=ignore ↵
service_err=ignore system_err=ignore] ↵ ln -s /usr/bin/perl /usr/local/bin/perl
lib/security/pam_ldap.so
password required pam_cracklib.so retry=3 ↵ На файлы из каталогов /opt/csw/bin, /opt/csw/lib, /opt/csw/
minlen=2 dcredit=0 ucredit=0 ucredit=0
password sufficient pam_unix.so nullok ↵ include, созданные в процессе инсталляции berkeleydb3-
use_authtok md5 shadow 3.11-i386-CSW.pkg.gz, сделаем символические ссылки в
password sufficient /lib/security/pam_ldap.so ↵
use_authtok аналогичные каталоги, расположенные в /usr. Сделаем ре-
password required pam_deny.so зервную копию оригинальных модулей pam_ldap и nss_ldap:
session required pam_limits.so
session required pam_unix.so cp /usr/lib/security/pam_ldap.so.1 ↵
session required /lib/security/pam_mkhomedir.so ↵ /usr/lib/security/pam_ldap.so.1.bak;
skel=/etc/skel umask=0022 cp /usr/lib/nss_ldap.so.1 /usr/lib/nss_ldap.so.1.bak
session optional /lib/security/pam_ldap.so
Объявим переменные среды:
В этом примере строчки, содержащие модуль pam_
ldap.so, были добавлены в соответствии с рекомендациями PATH=/usr/local/bin:$PATH
LD_LIBRARY_PATH=/usr/local/lib
Microsoft. Суть их такова, что сначала система применяет export LD_LIBRARY_PATH

20
администрирование
Это сработает для оболочек, совместимых по синтак- ! Скачал исходный код: http://keutel.de/pam_mkhomedir/
сису с sh, например, bash, ksh. Если вы пользуетесь другим pam_mkhomedir.c тоже в /tmp и скомпилировал следую-
интерпретатором, посмотрите документацию к нему. щей командой (в одну строчку), находясь в /tmp:
Соберем модули от PADL, перейдя в соответствующие
директории, созданные в процессе разархивации файлов, /usr/local/bin/gcc -D_REENTRANT -g -O2 -Wall -fPIC ↵
-c -ILinux-PAM-0.77/libpam/include ↵
полученных с www.padl.com/download: -ILinux-PAM-0.77/libpamc/include ↵
-ILinux-PAM-0.77/modules/pammodutil/include ↵
cd pam_ldap-176 -DPAM_DYNAMIC pam_mkhomedir.c -o pam_mkhomedir.o
./configure
make ! Получил готовый модуль следующей командой:
make install
/usr/ccs/bin/ld -o pam_mkhomedir.so -B dynamic -G ↵
cd nss_ldap-226 -lc pam_mkhomedir.o
./configure --enable-schema-mapping
make
make install К сожалению, FreeBSD 4.x не умеет работать с nss_ldap
и значит запрашивать данные о пользователе в AD, плюс
Если все прошло удачно, редактируем ldap.conf и не может менять пароль стандартными средствами с помо-
nsswitch.conf аналогично Linux, за исключением строчки: щью pam_ldap. Но всё же доступ к машине, как с консоли,
так и к службам ssh, ftp и т. д. можно получить, пройдя аутен-
uri ldap://server.domain.loc тификацию в Active Directory. Для этого установите pam_
ldap, отредактируйте два файла – ldap.conf и pam.conf. В
которую заменим на: ldap.conf достаточно внести следующий фрагмент:

host server.domain.loc base dc=domain,dc=loc


scope sub
uri ldap://server.domain.loc
Linux воспринимает оба формата, Solaris почему-то толь- port 389
ldap_version 3
ко host. Настройки PAM в Solaris хранятся в файле /etc/ binddn cn=ldap,cn=Users,dc=domain,dc=loc
pam.conf. На этом этапе, следуя советам Microsoft, я полу- bindpw qwerty
pam_filter objectclass=User
чил неработоспособную систему, поэтому кое-что поменял pam_login_attribute sAMAccountName
и добавил (представлены фрагменты с внесенными изме- pam_password ad
нениями):
В этом случае пароль из AD будет запрашиваться при
# login service (explicit because of pam_dial_auth) входе с консоли, ftp и ssh, если пароль отвергнут, поиск
login auth requisite pam_authtok_get.so.1
login auth required pam_dhkeys.so.1 будет продолжен в локальных файлах.
login auth sufficient pam_unix_auth.so.1
login auth required pam_dial_auth.so.1 login auth sufficient /usr/local/lib/pam_ldap.so
login auth sufficient pam_ldap.so.1 use_first_pass login auth sufficient pam_skey.so
# Default definitions for Authentication management login auth sufficient pam_opie.so no_fake_prompts
#login auth requisite pam_opieaccess.so
# Used when service name is not explicitly mentioned login auth requisite pam_cleartext_pass_ok.so
# for authenctication
other auth requisite pam_authtok_get.so.1 #login auth sufficient pam_kerberosIV.so try_first_pass
#login auth sufficient pam_krb5.so try_first_pass
other auth required pam_dhkeys.so.1 login auth required pam_unix.so try_first_pass
other auth sufficient pam_unix_auth.so.1
other auth sufficien pam_ldap.so.1 use_first_pass login account required pam_unix.so
login password required pam_permit.so
# Default definition for Session management login session required pam_permit.so
# Used when service name is not explicitly mentioned # Same requirement for ftpd as login
# for session management ftpd auth sufficient /usr/local/lib/pam_ldap.so
other session required pam_unix_session.so.1
other session sufficient ↵ ftpd auth sufficient pam_skey.so
ftpd auth sufficient pam_opie.so no_fake_prompts
pam_mkhomedir.so skel=/etc/skel/ umask=0022 #ftpd auth requisite pam_opieaccess.so
# Default definition for Password management ftpd auth requisite pam_cleartext_pass_ok.so
#ftpd auth sufficient pam_kerberosIV.so try_first_pass
# Used when service name is not explicitly mentioned #ftpd auth sufficient pam_krb5.so try_first_pass
# for password management
other password required pam_dhkeys.so.1 ftpd auth required pam_unix.so try_first_pass
other password requisite pam_authtok_get.so.1 # OpenSSH with PAM support requires similar modules.
other password requisite pam_authtok_check.so.1
other password required pam_authtok_store.so.1 # The session one is a bit strange, though...
sshd auth sufficient /usr/local/lib/pam_ldap.so
other password sufficient pam_ldap.so.1 use_authtok sshd auth sufficient pam_skey.so
sshd auth sufficient pam_opie.so no_fake_prompts
Здесь смысл примерно такой же, как и в случае с Linux. #sshd auth requisite pam_opieaccess.so
#sshd auth sufficient pam_kerberosIV.so try_first_pass
Pam_mkhomedir для Solaris не существует, но его можно #sshd auth sufficient pam_krb5.so try_first_pass
собрать самостоятельно. Я следовал инструкциям на http:/ sshd auth required pam_unix.so try_first_pass
sshd account required pam_unix.so
/keutel.de/pam_mkhomedir и получил работоспособный мо- sshd password required pam_permit.so
дуль, проделав следующие шаги на машине с Solaris: sshd session required pam_permit.so
! Скачал и распаковал исходный код Linux-PAM: http://
www.kernel.org/pub/linux/libs/pam/pre/library/Linux-PAM- Локально пароль можно вообще не хранить. Для этого
0.77.tar.gz, допустим, в /tmp. при помощи команды vipw отредактируйте файл паролей.

№12(25), декабрь 2004 21


администрирование
Сотрите зашифрованный пароль во втором поле и поставь- setgid = stunnel
те там * (звёздочка). # Some debugging stuff
По сведениям, взятым на http://www.padl.com/OSS/nss_ debug = 7
ldap.html, FreeBSD 5.1 и выше уже работает с nss_ldap, но output = /var/log/stunnel.log
проверить это лично не удалось по причине отсутствия ди- # Use it for client mode
стрибутива. client = yes
Осталось прикрутить SSL. Хотя это вовсе не обязатель- # Service-level configuration
но, наверняка вы захотите использовать шифрование по [ldap]
accept = 127.0.0.1:389
двум причинам. Первая – безопасность, ведь запросы к ldap, connect = server.domain.loc:636
в том числе пароли, передаются в открытом виде, вторая –
возможность пользователю самому менять пароль в AD Из данного примера мы видим – stunnel работает в кли-
посредством стандартной команды passwd. Необходимо ентском режиме, слушает запросы на 127.0.0.1 порт 389 и
проделать некоторые операции, как на Windows-сервере, пересылает их на Windows-сервер порт 636 уже в зашиф-
так и на клиентских машинах. рованном виде. В зависимости от операционной системы
На сервере: вам придется вручную создать пользователя stunnel и ка-
! Убедиться, что поддерживается шифрование 128 bit, ина- талог /var/tmp/stunnel с возможностью записи для этого
че вы не сможете удаленно поменять пароль. Windows пользователя. В файле ldap.conf просто поменяем строчку:
2000 sp2 и выше это умеет, в противном случае устано-
вите Encryption pack. ri ldap://server.domain.loc
! Установить сервис сертификатов, входящий в дистри-
бутив. Без этого сервер не будет принимать соедине- на
ния по протоколу ldaps. В процессе инсталляции серви-
са сертификатов будет предложено создать корневой host 127.0.0.1
сертификат. Заполнив поля (можно не все), вы получи-
те файл сертификата, лежащий в директории с:\. Де- Перегружаем машину, регистрируемся, пробуем менять
лать с ним ничего не придется. В журнале событий (event пароль. Параллельно tcpdump на другом терминале можно
viewer) должна появиться запись о возможности приня- наблюдать наши SSL-соединения.
тия соединений LDAPS (прим.: у меня это сообщение В результате мы имеем централизованную систему уп-
появилось на следующий день, может, потому, что я не равления пользователями средствами Active Directory, что
перегружал машину, а до этого все попытки коннекта значительно облегчает работу администратора. Интегра-
на ldaps:636 терпели неудачу). Проверить, что сервер ция таким способом позволяет внедрить UNIX-системы в
работает корректно, можно простым способом. С лю- существующую структуру Windows-сетей и при этом отка-
бой Windows-машины в домене или на самом сервере заться от ведения дополнительных каталогов или хране-
выполните «Start → Search → For People». ния пользовательских данных на каждой машине.

В свойствах укажите адрес сервера, порт 636, контей-


нер для поиска.
В данном примере мы ищем объекты в контейнере Users.
Если поиск завершился успехом, значит ваш сервер настро-
ен на прием запросов по протоколу LDAPS порт 636.
На клиенте:
Самым простым решением для меня оказалось исполь-
зование программы stunnel. После установки stunnel нуж-
но поправить два файла stunnel.conf и ldap.conf. Stunnel.conf
может выглядеть так:

chroot = /var/tmp/stunnel
pid = /stunnel.pid
setuid = stunnel

22
администрирование

FreeBSD TIPS:
НАСТРОЙКА VLAN

СЕРГЕЙ СУПРУНОВ
Представьте себе ситуацию: узел СПД в составе маршру- ! подсеть реальных адресов для работы в Интернете
тизатора CISCO и коммутатора Catalyst находится на пер- (111.222.0.0/28);
вом этаже, а ваш FreeBSD-сервер – на четвертом. И при ! корпоративная частная подсеть для доступа к вышесто-
этом требуется вывести во внешний мир несколько подсе- ящим узлам компании (10.0.123.0/24);
тей, которые проходят через сервер FreeBSD на Catalyst. ! и еще одна сеть для управления оборудованием СПД
Можно, конечно, подключить к серверу несколько сетевых (10.254.0.0/24).
адаптеров, занять для внутреннего использования несколь-
ко портов на Catalyst и пробросить между этажами кило- Прежде всего нужно проверить, поддерживает ли ваша
метр кабеля 5-й категории. На кабеле можно даже сэконо- сетевая карта работу по VLAN. Некоторые карты обеспе-
мить, пропустив по одному кабелю сразу два соединения и чивают поддержку данной технологии на аппаратном уров-
задействовав тем самым все имеющиеся пары. Однако все не, однако драйвер также должен поддерживать VLAN.
равно и затрат, и дополнительных работ по прокладке ка- Страница справочного руководства (см. man vlan) для
белей получается слишком много. А раз возникает слож- FreeBSD 5.2 сообщает, что аппаратное мультиплексирова-
ность, то наверняка кто-то уже нашел способ ее устранить. ние поддерживается для драйверов bge, em, gx, nge, ti и
И в нашем случае панацеей будет технология VLAN – вир- txp. (Во FreeBSD 5.3 к этому списку добавился еще и драй-
туальные локальные сети. вер re, обеспечивающий работу сетевых адаптеров на чип-
Данная технология позволяет логически разделять не- сетах RealTek 8139C+/8169/8169S/8110S). Узнать подроб-
сколько подсетей на одном устройстве (например, комму- ную информацию по каждому из драйверов, в том числе
таторе) таким образом, что машины, объединенные в одну список поддерживаемых драйвером моделей сетевых карт,
VLAN, ничего не знают о существовании компьютеров, вхо- можно на страницах man (например, man 4 em сообщает,
дящих в другую. И с точки зрения топологии сети мы полу- что драйвером em поддерживается Intel PRO/1000 Gigabit
чаем отдельные коммутаторы для каждой подсети. Ethernet adapter). Если ваш адаптер не входит в этот спи-
На уровне протоколов это достигается добавлением не- сок, то наверняка он сможет работать с использованием
скольких полей в заголовок пакета сетевого уровня. Одно программной эмуляции мультиплексирования. По крайней
из добавленных полей содержит идентификатор (номер) мере, для большинства современных карт это утвержде-
сети VLAN, на основе которого и происходит разделение ние справедливо. Нужно заметить, что тот же man vlan гла-
Ethernet-кадров по виртуальным сетям. Кадры, имеющие сит, что сетевой адаптер для полноценной эмуляции дол-
одинаковый номер VLAN, рассматриваются как принадле- жен поддерживать «длинные» кадры (oversized frames). В
жащие одной подсети. Регламентируется это стандартом противном случае из-за необходимости размещения допол-
IEEE 802.1Q. нительных полей заголовка, содержащих информацию о
Развитие технологии VLAN привело к тому, что стало VLAN, которой принадлежит пакет, приходится снижать мак-
возможным не только назначать отдельные подсети отдель- симальный размер передаваемого пакета (MTU) на соот-
ным портам, но и через один порт пропускать несколько ветствующем интерфейсе.
VLAN (так называемый multiVLAN). То же относится и к се- Драйвера сетевых адаптеров, поддерживающих длин-
тевым адаптерам, чем мы и воспользуемся. ные кадры, перечислены в man vlan, однако данный список
Рассмотрим настройку VLAN для FreeBSD на следую- нельзя считать исчерпывающим, поскольку с 2002 года (ког-
щем примере: пусть имеется один отрезок кабеля между да писались страницы руководства) ситуация изменилась
Catalyst и FreeBSD. На Catalyst свободен один порт, на в лучшую сторону и перечень совместимых сетевых карт
FreeBSD – одна сетевая карта, обслуживающая внешние значительно расширился. По крайней мере, D-Link DFE-
соединения. Нужно через это соединение организовать 538TX, работающий на драйвере rl, отсутствующем в спис-
передачу следующих подсетей: ке, никаких нареканий с моей стороны не вызвал. (Замеча-

24
администрирование
ние: во FreeBSD 5.3 поддержка vlan значительно расшире- Если со стороны CISCO все настроено должным обра-
на, и теперь поддержка длинных кадров драйвером rl офор- зом (собственно говоря, основное требование – номер VLAN
млена официально.) должен совпадать с тем, который назначен интерфейсу со
Пожалуй, хватит теории. Перейдем к практике. стороны FreeBSD), то после этой команды все должно ра-
Для работы VLAN в системе должны быть соответствую- ботать. Например, конфигурация интерфейса для подсети
щие псевдоустройства. В случае с FreeBSD 5.2 (думаю, это реальных адресов на CISCO у меня выглядит следующим
справедливо и для всей 5-й ветки) устройства vlan создают- образом:
ся динамически. За это отвечает модуль ядра if_vlan.ko. Если
вы предпочитаете иметь монолитное ядро, то потребуется interface FastEthernet0/0.111
encapsulation dot1Q 111
пересобрать его со следующей опцией: ip vrf forwarding Inet
ip address 111.222.0.1 255.255.255.240
device vlan no ip route-cache

Аналогично описываются остальные интерфейсы. Иден-


Для 3-й и 4-й веток FreeBSD может потребоваться пе- тификатор VLAN задается в параметре encapsulation dot1Q,
ресобрать ядро с такой строчкой: в данном случае он равен 111.
На Catalyst соответствующий порт нужно перевести в
pseudo-device vlan N trunk-режим и при желании можно указать список разре-
шенных номеров VLAN:
Вместо N нужно подставить количество устройств, ко-
торое вам понадобится. После сборки и установки нового interface FastEthernet0/24
switchport trunk allowed vlan 100,111,999
ядра в системе должны появиться соответствующие интер- switchport mode trunk
фейсы vlan0, vlan1 и т. д., просмотреть которые можно ко- no ip address
мандой:
С точки зрения остальных служб операционной систе-
ifconfig -a мы, например ipfw или natd, полученный интерфейс ничем
не отличается от физических и может использоваться как
Для FreeBSD 5.2 (в недавно вышедшей 5.3 все настра- обычно. Например, можно подсчитать трафик, проходящий
ивается точно так же) для создания vlan-интерфейсов ис- через vlan0:
пользуется «клонирование» (cloning) на этапе загрузки (об
этом – чуть ниже) либо программа ifconfig с опцией create. # ipfw add 1234 count ip from any to any via vlan0
Второй вариант выглядит следующим образом:
Остался последний штрих – настройка конфигурации
# ifconfig vlan0 для автоматического создания нужного интерфейса при пе-
ifconfig: interface vlan0 does not exist резагрузке. Для этого в файл /etc/rc.conf добавим следую-
щие строчки:
# ifconfig vlan0 create 111.222.0.5 ↵
netmask 255.255.255.240 vlan 111 vlandev rl0
# ifconfig vlan0 # Ñîçäàåì íóæíûå èíòåðôåéñû, èñïîëüçóÿ ìåõàíèçì
# êëîíèðîâàíèÿ:
vlan0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 cloned_interfaces="vlan0 vlan1 vlan2"
inet 111.222.0.5 netmask 0xfffffff0 broadcast 111.222.0.15
inet6 fe70::204:5cff:fedf:f81f%vlan0 prefixlen 64 scopeid 0xd # È îïèñûâàåì ñîîòâåòñòâóþùèå èíòåðôåéñû VLAN:
ether 00:05:5d:cf:f9:1e ifconfig_vlan0="inet 111.222.0.5 ↵
media: Ethernet autoselect (100baseTX <full-duplex>) netmask 255.255.255.240 vlan 111 vlandev rl0"
status: active ifconfig_vlan1="inet 10.254.0.5 ↵
vlan: 111 parent interface: rl0 netmask 255.255.255.0 vlan 100 vlandev rl0"
ifconfig_vlan2="inet 10.0.0.3 ↵
netmask 255.255.255.0 vlan 999 vlandev rl0"
Опция vlan задает номер VLAN, присвоенный этой сети.
Параметр vlandev указывает физический интерфейс, исполь- Если «пропадание» сервера на пару минут не критич-
зуемый для организации VLAN. Заметьте, что этот интерфейс но, то рекомендуется его перезагрузить, чтобы лишний раз
(в нашем случае rl0) должен иметь собственный IP-адрес, убедиться в правильности всех настроек. Бежать среди ночи
даже если реально он нигде использоваться не будет: к неудачно загрузившемуся из-за пропущенного пробела
серверу – не самое приятное занятие.
# ifconfig rl0 Нужно заметить, что технология VLAN позволяет шиф-
rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 ровать трафик (например, ряд сетевых карт поддерживают
options=8<VLAN_MTU> аппаратное шифрование), однако во FreeBSD это не реа-
inet 10.10.10.10 netmask 0xffffff00 broadcast 10.10.10.255
inet6 fe70::204:5cff:fedf:f81f%rl0 prefixlen 64 scopeid 0x1 лизовано и поддерживается только разделение пакетов на
ether 00:05:5d:cf:f9:1e основе идентификаторов VLAN. Хотя можно ожидать, что
media: Ethernet autoselect (100baseTX <full-duplex>)
status: active
поддержка карт с аппаратным шифрованием появится в бу-
дущем. Тем не менее имеющихся в данный момент возмож-
Обратите внимание, что интерфейсы vlan наследуют ностей вполне достаточно, чтобы без особых усилий повы-
MAC-адрес «родительского» интерфейса, но поскольку сети сить эффективность использования имеющегося оборудо-
у нас разные, то ни к каким конфликтам это не приведет. вания.

№12(25), декабрь 2004 25


администрирование

БИЛЛИНГ ДЛЯ АТС НА БАЗЕ PostgreSQL

ГЕОРГИЙ ТОЛОКОННИКОВ
В статье рассматривается содержащая около 90 строк кода ся в базу данных телефонных переговоров, поддерживае-
биллинговая система для небольших АТС, которая легко мую СУБД PostgreSQL. На основе базы данных ведется под-
может быть расширена на АТС большой номерной емкос- счет трафика, расчет оплаты и выполняются практически
ти. В качестве примера рассматривается NEAX2000 IPS. любые запросы, интересующие пользователей.
Стандартный выход АТС соединяется с портом компью- Обычный веб-интерфейс позволяет выводить на экра-
тера, приходящая от АТС информация захватывается скрип- ны (удаленных) компьютеров результаты запросов в режи-
том биллинговой системы, обрабатывается, и направляет- ме реального времени.

26
администрирование
Введение дится к тому, что обозначение внутренних номеров начина-
Биллинговая система – это комплекс программ, работаю- ется со знака *, например, *029. Такая нумерация обычно
щий на компьютере, сопряженном с АТС и позволяющий используется, чтобы можно было звонить «в город» без на-
тарифицировать телефонный трафик, выставлять счета бора «9».
абонентам, получать практически любую информацию по Соединим кабелем COM-порт компьютера с RS232
звонкам. разъемом АТС, находящимся на процессорной плате. Для
Такие системы обычно дороги. Многие пользуются Win определенности используем нулевой порт – как правило, в
Tarif (как правило, взломанной версией…). Можно также по- компьютере два COM-порта: нулевой и первый.
смотреть сайт www.billonline.ru со всеобъемлющим серти- Обычно тарификация проводится для исходящих вызо-
фицированным Министерством связи решением проблем вов, поэтому здесь мы не будем рассматривать другие звон-
(за деньги) учета телефонных переговоров. ки.
Наш подход, однако, – демонстрация философии UNIX Введем следующую команду для прослушивания пор-
в действии – позволяет обеспечить простое, бесплатное, та, на который поступает информация от АТС (для Linux
открытое решение. Состоит оно из нескольких десятков порт будет называться не dev/cuaa0, а, cкорее всего, /dev/
строк кода и опирается на типовые утилиты UNIX. Слож- ttyS0):
ность кода минимальная, достаточно, например, владения
азами SQL и Perl. Обычно оператор связи, предоставив- # cat /dev/cuaa0 >> file
ший телефоны, выставляет счет раз в месяц, а тарифика-
цию по внутренним номерам офисной АТС либо вообще от- получим при каждом исходящем вызове добавку к содер-
казывается делать, либо требует дополнительной оплаты. жимому файла file:
Платное программное обеспечение имеет закрытый код и
^B0!KA050077001*029 08110737260811073756
не ясно, что и как оно считает, заменить в нем что-нибудь
000050050100 0000 04040
на более подходящий вариант невозможно. Таким образом,
наличие подобного предлагаемого в статье простого реше- (с учетом пробелов для каждой записи получаем 128 бай-
ния полезно для работы организации. тов, по байту на каждый символ).
В настоящее время в небольших фирмах – операторах Приведенный пример содержит информацию о том, что
связи или в офисах крупных (и не очень) компаний наряду с номера *029, 11 августа с 7 час. 37 мин. 26 сек до 37 мин.
в ЛВС имеется АТС, часто попадающая на обслуживание 56 сек. абонент звонил на номер 100 (служба «время» в
системному администратору. Так что затронутые в статье МГТС).
вопросы многим окажутся интересны. При разборке файла с помощью Perl в качестве при-
План действий по автоматизации тарификации АТС сле- знака конца записи для отдельных вызовов можно принять
дующий: восклицательный знак «!».
! смотрим, что и в каком формате выводит АТС на порт, Воспользовавшись вызовом sysread(fd, $v, length), где
сопрягаемый с компьютером (часто это com-порт); fd – дескриптор файла $v – переменная, в которую пишет-
! пишем скрипт, разбирающий должным образом полу- ся информация, length – количество считывающихся бай-
чаемый поток байтов с АТС; тов за один вызов, можно установить, что АТС выдает всю
! заводим в СУБД (PostgreSQL) необходимые таблицы; запись по вызову отдельными порциями наборов символов,
! добавляем к скрипту блоки захвата вывода с АТС и заг- указанных в примере, разделенными пробелами. В АТС
рузки обработанных скриптом записей в СУБД; имеется буфер (довольно приличный по размеру), в кото-
! формируем скрипт сопряжения базы данных с веб-сер- ром хранятся данные по вызовам, так что при соединении
вером для возможности просмотра данных и запросов с компьютером все предыдущие вызовы «скачиваются» в
абонентами и руководством. компьютер.
Код будущей программы состоит из двух блоков:
Собственно и все. За пару дней это можно сделать и ! блок считывания и обработки (считывает из порта ин-
запустить в эксплуатацию. Например, на следующем комп- формацию, поступающую из АТС);
лексе: Pentium-200 MMX, 256 Мб ОЗУ, FreeBSD версии 4.5 ! блок загрузки записей в базу данных.
и выше с Perl5, PostgreSQL 7 довольно быстро обрабаты-
вается до 100 тыс. записей звонков. Это около 100-150 но- Перед рассмотрением приведенного ниже кода скрип-
меров абонентов, звонящих с интенсивностью выше сред- та подчеркнем следующее.
ней в течение месяца. На Pentium 4 можно легко обрабаты- Наша цель – показать, что создать собственную систе-
вать уже миллионы записей. му биллинга совсем несложно. У каждого системного ад-
Все вышеприведенное будет легко работать и под лю- министратора есть свои излюбленные приемы в Perl, кото-
бым другим UNIX. рые он при необходимости использует, приспособив под-
ходящим образом приведенный скрипт или написав свой
Тестирование формата вывода АТС собственный. Поэтому мы для краткости оставили лишь ти-
и алгоритм программы повую обработку ошибок, не стремимся усложнять код для
Сначала надо изучить выходные сигналы АТС. Мы рассмат- обеспечения его безопасности, оптимальности или кратко-
риваем NEAX2000 IPS с настройками, практически не от- сти. Отметим только, что приведенный код неплохо рабо-
личающимися от стандартных. В нашем случае отличие сво- тал у нас на стареньком отдельно стоящем компьютере:

№12(25), декабрь 2004 27


администрирование
процессы внутри АТС относительно медленные и Perl успе- sub duration {
вает делать все вовремя и без ухищрений. my $a=substr($ccc, 6, 10);
my $b=substr($ccc, 16, 10);
Отлаженный вариант биллинговой системы с учетом my @aa=split //, $a;
кода для вывода данных с помощью PHP на Apache-сервер my @bb=split //, $b;
достаточно длинный для размещения в тексте, поэтому пре- my $aaa=(($aa[2]*10)+$aa[3])*24*60*60+($aa[4]*10+ ↵
доставлен автором всем желающим (www.samag.ru/source). $aa[5])*60*60+($aa[6]*10+$aa[7])*60+$aa[8]*10+$aa[9];
my $bbb=(($bb[2]*10)+$bb[3])*24*60*60+($bb[4]*10+ ↵
$bb[5])*60*60+($bb[6]*10+$bb[7])*60+$bb[8]*10+$bb[9];
Реализация программы my $r=$bbb-$aaa;
my $cc1=$r%60;
Для реализации программы с помощью системы портов my $cc11=($r-$cc1)/60;
FreeBSD помимо PostgreSQL необходимо для работы ин- my $cc2=$cc11%60;
my $cc21=($cc11-$cc2)/60;
терфейса Perl к PostgreSQL установить модули Perl – DBI, my $cc3=$cc21%24;
DBD-Pg. my $z=" h$cc3 m$cc2 s$cc1 ";
}
Запустив PostgreSQL, создадим таблицу atstarif базы
данных ats: foreach $ss (@s)
{
$ss =~ s/.*\*/\*/g;
# create table atstarif (nums varchar(15), mydate date, ↵ $ss =~ s/\b0000 .*//g;
mytime time, min int, numd bigint); $ss =~ s/\b0000600606//g;
$ss =~ s/\b000050050//g;
Таким образом, строки в ней будут содержать поля: $ccc=$ss;
my $z=substr($ss, 16, 10);
! Номер, инициировавший соединение.
! Дата и время начала разговора. # òåïåðü ïðèìåíèì ïîäïðîãðàììó ïîäñ÷åòà âðåìåíè
# ê ïåðåìåííîé $ccc;
! Длительность звонка в минутах разговора.
! Номер, на который шел вызов. my $res=&duration;
$ss=~ s/$z/$res/g;
$ss=~ s/h//g;
Программа биллинга на Perl может иметь следующий $ss=~ s/m//g;
$ss=~ s/s//g;
вид (некоторые комментарии даны в самом коде).
my @f= split (/\s+/, $ss);
if ($f[4]) {
#!/usr/bin/perl $f[4] = 1;
use POSIX qw(:errno_h); }
use DBI; my $z = $f[2]*60 + $f[3] + $f[4];
use strict; my @g = split (//, $f[1]);
my $user="pgsql"; if ($g[4]==0) {
my $dbname="ats"; $g[4]="";
my $dsh; }
my $dbh; my @gg = ($g[2].$g[3], '.', $g[0].$g[1], '.', ↵
my $p; '04', " ", $g[4].$g[5], ':', $g[6].$g[7]);
my $pid; $f[1]= join ("", @gg);
$SIG{ALRM}= 'proga'; my @ff = ($f[0], $f[1], $z, $f[5]);
$ss = join (" ", @ff);
sub proga { if ($ss=~ /\*\d\d\d \d\d\.\d\d\.\d\d \d+:\d+ \d+ \d+/) {
kill 9 => $pid;
kill 9 => $p; # ñòðîêà ñôîðìèðîâàíà äëÿ çàïèñè â áàçó äàííûõ
}
$g= $ss;
# ïðîãðàììà ðàáîòàåò â áåñêîíå÷íîì öèêëå, ïåðèîäè÷åñêè
# (ðàç â äâå ìèíóòû) ïîäêëþ÷àÿñü ê ïîðòó, íà êîòîðûé # òåïåðü ñòðîêó $g ïðèâåäåì ê íåîáõîäèìîìó ôîðìàòó
# ÀÒÑ ïîñûëàåò äàííûå î çâîíêàõ # è çàãðóçèì â áàçó äàííûõ
while(1) chomp($g);
{ my @gg=split / /, $g;
$dsh="dbi:Pg:dbname=$dbname;port=5432"; my @ggg=split /\./, $gg[1];
$dbh=DBI->connect("$dsh", "$user") or die ↵ $gg[1]=join "-", "20$ggg[2]", $ggg[1], $ggg[0];
"can't connect: $!\n"; my @dt;
$pid=open (ATS, "cu -l/dev/cuaa1 -s9600|"); $dt[0]=$dbh->quote("$gg[0]");
$p=($pid)+1; $dt[1]=$dbh->quote("$gg[1]");
$dt[2]=$dbh->quote("$gg[2]");
# ïðîãðàììà ïîäêëþ÷èëàñü ê áàçå äàííûõ è íà÷àëà ñ÷èòûâàòü $dt[3]=$dbh->quote("$gg[3]");
# äàííûå îò ÀÒÑ $dt[4]=$dbh->quote("$gg[4]");
my $tbl="atstarif ";
eval { alarm(60); }; $dbh->do("insert into $tbl (nums, mydate, mytime, min, numd)
my @str = <ATS>; values ($dt[0], $dt[1], $dt[2], $dt[3], $dt[4])");
my $sstr; }
my $ccc; }
my $ss; }
my $g; }
$dbh->disconnect();
# â ýòîì öèêëå íà÷èíàåòñÿ îáðàáîòêà ïîñòóïàþùèõ ñòðîê îò ÀÒÑ close ATS;
sleep(60);
foreach $sstr (@str) { }
if ($sstr=~ /!/)
{
my @s= split /!/, $sstr; Программу можно запустить в фоновом режиме, обыч-
ным образом обеспечить ее запуск при перезагрузке ком-
# ïîäñ÷åò âðåìåíè çâîíêà óäîáíî âûäåëèòü â îòäåëüíóþ
# ïîäïðîãðàììó пьютера, организовать ее использование по усмотрению
системного администратора.

28
администрирование

ПАКЕТНЫЙ ФИЛЬТР OpenBSD


ЧАСТЬ 2

ДЕНИС НАЗАРОВ
Вот и вышел очередной новогодний выпуск этого замеча- ные транзакции. Пограничным хостом (firewall) была дав-
тельного журнала из печати, на улице холодно, а мы будем ненько установленная нами, в то время еще OpenBSD 3.1-
сидеть в тепле, пить горячий кофе и с удовольствием по- stable, с PF в качестве пакетного фильтра. При осмотре
знавать то, что несет нам этот номер. Linux-сервера сразу стало понятно, что его атаковали, и не
В прошлой статье1 я рассказал об основных возможно- раз, я нашел огромное количество различных exploits на
стях пакетного фильтра операционной системы OpenBSD сервере и несколько скриптов, которые в тот момент дер-
и почему так важно использование фильтров. Недавно нам жали открытыми порты с shell, запущенными от прав www-
поступило тревожное сообщение от одной из организаций сервера. После проверки сервера различными методами я
о том, что их сервер «барахлит», мне пришлось ехать и про- пришел к выводу, что злоумышленникам так и не удалось
верять, но я и не подозревал, насколько всё серьёзно! Сеть ни похитить данные, ни проникнуть на сервер. Мне стало
организации была спроектирована довольно хорошо, од- интересно, как же данные со взломанного сервера (сервер
нако единственным слабым местом был Linux-сервер, на действительно считался взломанным по нашим критериям)
котором крутились Java-сервлеты и обслуживали денеж- так и не ушли в чужие руки.

1
Назаров Д. Пакетный фильтр OpenBSD. – Журнал «Системный администратор», №11, ноябрь 2004 г.

30
администрирование
Так как сервер останавливать было нельзя, пришлось Пакеты в очереди с наибольшим приоритетом будут об-
вживую искать все ниточки. Все свелось к одному – на сер- работаны первыми.
вере с OpenBSD, посмотрев лог-файлы пакетного фильт- ! HFSC (Hierarchical Fair Service Curve) – описание очень
ра, сразу стало ясно, что любые попытки добраться к тем схоже с CBQ за исключением некоторых дополнений.
shell на Linux-сервере оканчивались провалом, ибо фильт- HFSC есть не что иное как «исправленный» механизм,
рация была настолько четкой, что помимо входящих соеди- базирующийся на модели QoS. Его уникальность состо-
нений контролировались и все исходящие. Дальнейшее ис- ит в возможности разъединять связь между задержкой
следование показало все места, откуда были произведены пакета и очередью. То есть HFSC обрабатывает очере-
атаки, и подтвердило их безуспешность. Сейчас в той орга- ди и пакеты отдельно друг от друга, однако после про-
низации стоит новый мощный сервер под управлением Sun цесса обработки пакет и очередь опять логически свя-
Solaris 10 и теперь уже OpenBSD 3.6-stable. К чему вся эта зываются. В некоторых ситуациях это позволяет добить-
история? Показать на конкретном примере, как важно ис- ся максимальной производительности от трафик-шей-
пользование пакетных фильтров и как они могут защитить пера. Очень часто это используется для сервисов, ра-
заведомо опасные приложения. ботающих в режиме реального времени.
Итак, приступим к продолжению нашей статьи, я рас-
скажу вам о следующих вещах: Активизировать возможность распределения по очере-
! Распределение по очередям (Queuing). дям нужно в конфигурационном файле вашего фильтра (по
! Роутинг (маршрутизация). умолчанию /etc/pf.conf) при помощи директивы «altq on»,
которая имеет свои дополнительные параметры:
Распределение по очередям (Queuing) ! <interface> – имя интерфейса, для которого мы включа-
Любые пакеты могут быть разделены по очередям для кон- ем данную возможность, если не определено, то очере-
троля полосы пропускания. Зачем это надо? Распределять ди будут активированы для всех интерфейсов.
нагрузку на канал равномерно для всей сети, например, или ! <scheduler> – планировщик, в данный момент PF под-
же, наоборот, урезать трафик для определенного сервиса держивает cbq, priq, hfsc.
или IP-адреса. Для определения «очереди» (queue) нужны ! bandwidth <value> – максимальный битрейт для всех оче-
всего лишь две декларации, и в дальнейшем все пакеты редей на данном интерфейсе. Значение может быть оп-
можно будет распределять по очередям, используя «имя ределено как процент от общей пропускной способнос-
очереди». Согласно компоненту фильтрации пакетного ти интерфейса, так и числовой величиной. Для этого
фильтра (PF), для правила pass данный пакет будет поме- могут использоваться слова b, Kb, Mb, Gb. Что соответ-
щен в очередь, на которую ссылалось последнее(!) прави- ственно – биты, килобиты, мегабиты, гигабиты. Если
ло. Немножко запутанно? значение bandwidth не задано, то будет использована
Поясню на примере: максимальная скорость.
! qlimit <value> – количество пакетов, которое может об-
pass in on $ext_if inet proto tcp from any to ↵ служивать очередь, по умолчанию 50, это значение от-
any port 80 keep state queue www-1
pass in on $ext_if inet proto tcp from any to ↵ лично подходит для 100-мегабтиных сетей.
any port 80 keep state queue www-2 ! queue <list> – определяет список очередей, которые бу-
дут созданы для данного интерфейса.
Здесь будет применено последнее правило, т.е пакет бу-
дет присвоен очереди с именем «www-2». В этом примере интерфейс dc0 будет распределять в
Очередями управляют «планировщики». На данный мо- очереди 5Mbit/s, используя CBQ.
мент PF поддерживает 3 типа «планировщиков»:
! CBQ (Class Based Queueing) – очереди, прикрепленные altq on dc0 cbq bandwidth 5Mb queue { std, http, mail, ssh }
к интерфейсу, создают «дерево», в котором каждая из
этих очередей может иметь своих «потомков». Очере- После включения altq мы можем создавать очереди-по-
ди имеют приоритет и полосу пропускания. Приоритет томки. Для них используются те же дополнительные пара-
определяет, через какую очередь пакет пройдет первым, метры, что и для директивы altq, за исключением <scheduler>
а полоса пропускания уже непосредственно влияет на и queue, т.к они уже определены. Имя родительской очере-
скорость прохождения. CBQ выполняет двухсторонее ди должно совпадать с определением в altq.
разделение полосы пропускания вашего канала, исполь- Например:
зуя иерархически-структурированные классы. Каждый
класс имеет свою собственную «очередь» и присвоен- queue std bandwidth 10% cbq(default)
ную ей способность пропускания. Класс-потомок может
заимствовать у родительского класса только(!) ту про- Для <scheduler> есть список параметров, которые по-
пускную способность, которая в данный момент доступ- могают контролировать работу очереди.
на для него. ! default – попадая в эту очередь, пакет не проверяется
! PRIQ (Priority Queueing) – очереди просто присоедине- дальше, а тут же обрабатывается.
ны к интерфейсу и не могут иметь очередей-потомков. ! red – Random Early Detection – RED отбрасывает паке-
Каждая такая очередь имеет свой уникальный «приори- ты, которые, предположительно могут перегрузить оче-
тет», который может принимать значения от 0 до 15. редь.

№12(25), декабрь 2004 31


администрирование
! ecn – Explicit Congestion Notification – практически то же any port 22 keep state queue(ssh_bulk, ssh_interactive)
самое, что и RED. Отличается лишь алгоритмом обра- pass out on dc0 inet proto tcp from any to ↵
any port 25 keep state queue mail
ботки очередей, в итоге результат тот же, что и при ис-
пользовании RED. RED использует более оптимизиро- Итак, очередь std будет забирать 10% от нашего 5Mbit/s
ванный алгоритм, и за его счет обработка очередей про- канала.
исходит гораздо быстрее. Очередь http будет забирать 60% и иметь двух потом-
ков employees и developers с механизмом определения
Для CBQ предусмотрены дополнительные параметры. преждевременной нагрузки RED и возможностью «заим-
! borrow – очередь-потомок может «заимствовать» сво- ствования» полосы пропускания у родителя. У очереди http
бодную пропускную способность у родительской очере- приоритет равен 2, что в данной конфигурации является
ди в случае необходимости. наивысшим приоритетом (т.к значения больше, чем «2» не
определены). Значит, данная очередь будет обрабатывать
Теперь параметры для HFSC. пакеты первой. Для очередей-потомков установлены ско-
! realtime <sc> – минимальная доступная пропускная спо- рости в процентном отношении соответственно 75% и 15%.
собность для очереди. Важно понимать, что вычисляться эти проценты будут из
! upperlimit <sc> – максимальная доступная очереди про- того куска общей пропускной способности канала, который
пускная способность. отдан родительской очереди.
! <sc> – список так называемых service curve (для realtime Очередь mail определена как 10% от общей полосы про-
задач), которые имеют формат (m1, d, m2), работают пускания и имеет низший приоритет (0), чем другие.
они по принципу «для первых d мили-секунд выдавать Очередь ssh делится на ssh_interactive и ssh_bulk, име-
пропускную способность m1, после этого m2». ющие приоритеты 7 и 0. Как только появляется пакет с пор-
том назначения 22 и его помещают в очередь ssh_bulk. Пос-
Синтаксис определения очередей CBQ и HFSC одина- ле того как соединение считается установленным, пакет пе-
ков, разница лишь в дополнительных параметрах (см. вы- реходит в очередь ssh_interactive и имеет наивысший
ше). Однако стоит помнить, что скорость пропускания для приоритет для родительской очереди. А зачем так сложно?
очередей-потомков не может быть больше той, что опреде- Стоит помнить, что «контроль состояний» (stateful in-
лена для родительской очереди. spection) применяется не только для фильтрации, но и для
Дополнительный параметр для определения очередей – контроля полосы пропускания, а это означает, что даже при
priority <level> – указывает приоритет очереди. Для CBQ и огромных правилах фильтров и различных ограничений ско-
HFSC значения могут быть от 0 до 7, для PRIQ – от 0 до 15. рости ваш сервер не будет иметь проблем с загрузкой про-
Значение по умолчанию для всех очередей 1. цессора.
Присвоение пакетов очередям происходит при помощи
ключевого слова queue в правилах фильтрации(!). В нор- Роутинг (маршрутизация)
мальном режиме указать можно только одну очередь, од- Тут все просто и мощно. Управлять пакетом нам позволяют
нако, если же указана вторая, то пакеты будут обрабаты- те же правила фильтрации, однако с добавлением одной
ваться на основе TOS (Type Of Service). из нижеперечисленных опций. Помните – когда создается
Что ж, теперь давайте посмотрим, как все это выглядит «состояние» (state), все пакеты для данного правила филь-
на практике, ибо в теории мало что понятно. трации и роутинга попадают под него.
Включаем очереди: ! fastroute – обычный режим, система обрабатывает па-
кет обычным образом.
altq on dc0 cbq bandwidth 5Mb queue { std, http, mail, ssh } ! route-to – система направляет пакет на нужный интер-
фейс с возможностью указания IP для «следующего
Определяем родительские очереди и очереди-потом- хоста». Надо помнить, что помимо route-to нужно создать
ки. правила, позволяющие направлять пакет с одного ин-
терфейса на другой в правилах фильтрации, иначе все
queue std bandwidth 10% cbq(default) ваши пакеты будут зарезаны фильтром.
queue http bandwidth 60% priority 2 cbq(borrow red) ↵
{ employees, developers } ! reply-to – на сей раз система отвечает пакетом с ука-
queue developers bandwidth 75% cbq(borrow) занным IP-адресом и интерфейсом.
queue employees bandwidth 15%
queue mail bandwidth 10% priority 0 cbq(borrow ecn) ! dup-to – создает дубликат пакета и отправляет его с по-
queue ssh bandwidth 20% cbq(borrow) ↵ мощью route-to. Настоящий пакет обрабатывается обыч-
{ ssh_interactive, ssh_bulk }
queue ssh_interactive priority 7 ным способом. Dup-to полезно использовать для обна-
queue ssh_bulk priority 0 ружения конфликтов в сети, когда рабочий сервер тро-
гать нельзя, а трафик, проходящий через него, нужно
И назначаем правила: анализировать.

block return out on dc0 inet all queue std Комбинируя правила фильтрации и опции роутинга,
pass out on dc0 inet proto tcp from $developerhosts to ↵
any port 80 keep state queue developers можно добиться очень сложных схем маршрутизации, но
pass out on dc0 inet proto tcp from $employeehosts to ↵ для таких целей придумали Cisco routers. А это уже совсем
any port 80 keep state queue employees
pass out on dc0 inet proto tcp from any to ↵ другая история.

32
bugtraq

Повышение привилегий Переполнение буфера


в Symantec Windows LiveUpdate в Microsoft Windows NT DHCP
Программа: Norton AntiVirus 2001, Norton AntiVirus 2002, Программа: Microsoft Windows NT.
Norton Internet Security 2001, Norton Internet Security 2002, Опасность: Средняя.
Norton Internet Security 2003, Norton Internet Security 2003 Описание: Обнаружено несколько уязвимостей в DHCP-
Professional, Norton Internet Security 2004, Norton Internet службе в Microsoft Windows NT. Удаленный атакующий мо-
Security 2004 Professional, Norton SystemWorks 2001, Norton жет вызвать отказ в обслуживании и скомпрометировать
SystemWorks 2002, Norton SystemWorks 2003, Norton уязвимую систему.
SystemWorks 2004, Symantec AntiVirus for Handhelds 3.x, 1. Уязвимость существует из-за некорректной проверки
Symantec Norton AntiVirus 2003, Symantec Norton AntiVirus длины буфера при логировании некоторых значений оп-
2004, Symantec Windows LiveUpdate 1.x, Symantec Windows ределенных пакетов. Удаленный атакующий может спе-
LiveUpdate 2.x. циальным образом сформировать DHCP-пакет и выз-
Опасность: Средняя. вать отказ в обслуживании.
Описание: Обнаружена уязвимость в Symantec Windows 2. Уязвимость существует из-за некорректной проверки бу-
LiveUpdate. Локальный атакующий может повысить свои фера при обработке DHCP-сообщений. Удаленный ата-
привилегии на системе. кующий может послать специально сформированное
Уязвимость существует из-за того, что Symantec Automatic DHCP-сообщение, вызвать переполнение буфера и вы-
LiveUpdate позволяет управлять некоторыми интернет-оп- полнить произвольный код на уязвимой системе.
циями с системными привилегиями. Локальный атакующий URL производителя: www.microsoft.com.
может использовать эту уязвимость во время сессии Решение: Установите обновления:
LiveUpdate посредством графического интерфейса при за- 1. Microsoft Windows NT Server 4.0 (requires Service Pack
пущенной задаче «NetDetect». 6a): http://www.microsoft.com/downloa...F82D-F2A2-49AA-
URL производителя: www.symantec.com. BF33-897498898EAD.
Решение: Установите обновления с сайта производителя. 2. Microsoft Windows NT Server 4.0 Terminal Server Edition
(requires Service Pack 6): http://www.microsoft.com/
Переполнение буфера в WINS downloa...259F-3004-462C-B2A8-37F65EB78A2D.
Программа: Microsoft Windows 2000 Advanced Server,
Microsoft Windows 2000 Datacenter Server, Microsoft Windows Выполнение произвольных FTP-команд
2000 Server, Microsoft Windows NT 4.0 Server, Microsoft в Microsoft Internet Explorer
Windows NT 4.0 Server, Terminal Server Edition, Microsoft Программа: Microsoft Internet Explorer 6.
Windows Server 2003 Datacenter Edition, Microsoft Windows Опасность: Низкая.
Server 2003 Enterprise Edition, Microsoft Windows Server 2003 Описание: Обнаружена уязвимость в Microsoft Internet
Standard Edition, Microsoft Windows Server 2003 Web Edition. Explorer при обработке FTP-ссылок. Удаленный атакующий
Опасность: Высокая. может выполнить произвольную FTP-команду на уязвимой
Описание: Обнаружено переполнение буфера в службе системе.
WINS. Удаленный атакующий может выполнить произволь- Удаленный атакующий может создать специально сфор-
ный код на уязвимой системе. мированный FTP URL, который выполнит произвольную
Уязвимость существует из-за некорректной проверки дли- FTP-команду на определенном FTP-сервере. Команда
ны буфера при обработке параметра Name в определенных вставляется в URL и разделяется символами «%0a». При-
пакетах. Удаленный атакующий может с помощью специ- мер:
ально сформированного пакета вызвать переполнение бу-
фера и выполнить произвольный код на уязвимой системе. ftp://ftpuser:ftppass@server/directory%0asomecommand%0a
URL производителя: www.microsoft.com. URL производителя: www.microsoft.com.
Решение: Установите обновления с сайта производителя. Решение: Решения не существует на данный момент.

Выполнение произвольного кода Повышение привилегий в ядре Linux


в Cyrus IMAP Server Программа: Linux kernel версии до 2.4.23.
Программа: Cyrus IMAP Server 2.2.9 и более ранние версии. Опасность: Низкая.
Опасность: Средняя. Описание: Уязвимость обнаружена в ядре Linux на плат-
Описание: Обнаружена уязвимость в Cyrus IMAP Server. формах AMD64 и Intel EM64T. Локальный атакующий мо-
Удаленный атакующий может выполнить произвольный код жет повысить свои привилегии на системе.
на уязвимой системе. Уязвимость обнаружена в функции Уязвимость существует при установке TSS-лимитов. Ло-
mysasl_canon_user(). Удаленный атакующий может вызвать кальный атакующий может вызвать отказ в обслуживании
переполнение буфера и выполнит произвольный код на или выполнить произвольный код на уязвимой системе.
системе с привилегиями IMAP-процесса. URL производителя: www.kernel.org.
URL производителя: asg.web.cmu.edu/cyrus. Решение: Установите обновление от производителя.
Решение: Установите обновление: ftp://ftp.andrew.cmu.edu/
pub/cyrus-mail. Составил Александр Антипов

№12(25), декабрь 2004 33


администрирование

НАСТОЯЩИЙ UNIX
В НАШИ ДНИ
АЛЕКСАНДР БАЙРАК
В этой статье я рассмотрю один из вариантов запуска на- Если процесс компиляции прошел гладко, приступаем
стоящего UNIX на современных компьютерах. непосредственно к запуску:
Я думаю, любой юниксоид хотя бы один раз читал исто-
рию возникновения UNIX, как он развивался и какие мета- # BIN/pdp11
морфозы пережил, чтобы дойти до нас в виде множества
своих «детей». Глядя на генеалогическое древо UNIX, диву На экране появится приглашение программы.
даешься, какое большое количество ответвлений и версий
системы было выпущено в прошлом. Некоторые уже давно // Óêàçûâàåì, êàêîé òèï ïðîöåññîðà ìû áóäåì ýìóëèðîâàòü:
sim> set cpu 18
умерли, иные просто в спячке, но большинство из них вы- // u18 ñîîòâåòñòâóåò ïðîöåññîðó, óñòàíîâëåííîìó
росли и дожили до наших дней. Ну как тут не загореться // íà êëàññè÷åñêîé pdp 11/45.
// Óêàçûâàåì, ÷òî áóäåì èñïîëüçîâàòü êîíñîëüíûé òåðìèíàë
желанием посмотреть на тот самый настоящий, легендар- // DL11. Âûâîä èíôîðìàöèè áóäåò ïðîèçâîäèòüñÿ â ðåæèìå
ный AT&T UNIX, с которого все и началось? Конечно, в наши // 7 áèò íà ñèìâîë.
sim> set tto 7b
дни достаточно затруднительно найти PDP11 и родной ди- // Óêàçûâàåì, ÷òî ââîä áóäåò òàêæå èñêëþ÷èòåëüíî 7-áèòíûé.
стрибутив. Так что единственной возможностью погрузиться sim> set tti 7b
// Ïðèñîåäèíÿåì äàìï äèñêà ñ UNIX ê rl.  êà÷åñòâå rl
во времена использования настоящего UNIX на PDP11 нам // âûñòóïàåò êîíòðîëëåð äèñêà RLV12/RL01.
помогут эмуляторы. Точнее, один из них – simh (Simulator sim> attach rl unix_v7_rl.dsk
// Óêàçûâàåì, îòêóäà ïðîèçâîäèòü çàãðóçêó:
History). Начало данному проекту было положено в 1993 sim> boot rl
году. Главный разработчик проекта – Robert M Supnik. В
настоящее время simh можно запустить почти на всех со- Начинается загрузка:
временных ОС, а именно:
! OpenVMS/VAX ! Tru64 @boot
New Boot, known devices are hp ht rk rl rp tm vt
! OpenVMS/Alpha ! Solaris
! Windows 9x/2k/XP ! HP-UX Указываем, что именно запускать:
! MacOS X ! *BSD
! Linux ! OS/2 : rl(0,0)rl2unix

Классический pdp 11/45 был выпущен в 1970 году. Из Более подробно обо всех опциях, использованных выше,
pdp-серии это был единственный 16-битный компьютер. можно прочитать в документации, поставляемой вместе с
Хотя были и 24- и 18-битные машины. При рекордно низкой программой.
цене (~ 10800$) pdp 11 получил широчайшее распростра- Далее нам показывают объем доступной памяти, он
нение. Всего было продано около 600000 (!) экземпляров. равен целым 177 856 байтам! После чего мы попадаем в
Некоторые из них работают и по сей день. shell. В принципе можно начинать работу с настоящим UNIX
Все свои эксперименты я проводил на P3-550 МГц/ 7-ой версии. По умолчанию мы попадаем в систему с пра-
320 Мб RAM под управлением FreeBSD 5.3. вами root. В документации к эмулятору в качестве примера
Для начала нашего путешествия во времени нам нужен работы были приведены следующие действия:
дистрибутив, который можно взять с http://simh.trailing-
edge.com/sources/simhv33-0.zip. // Ñîçäàäèì êàòàëîã dmr
# mkdir /usr/dmr
Также понадобится дамп диска с установленным UNIX. // Ñäåëàåì âëàäåëüöåì êàòàëîãà dmr ïîëüçîâàòåëÿ dmr
Его мы берем с http://simh.trailing-edge.com/kits/uv7swve.zip. # chown dmr /usr/dmr
// Èçìåíèì ãðóïïó âëàäåíèÿ êàòàëîãà íà òðåòüþ
Распакуем и установим программу: # chgrp 3 /usr/dmr
// Ñîçäàäèì êàòàëîã äëÿ âðåìåííûõ ôàéëîâ
# mkdir unixemul # mkdir /tmp
# cd unixemul // Ïîñòàâèì äëÿ íåãî ïîëíûé äîñòóï äëÿ âñåõ
# chmod 777 /tmp
# unzip ../simhv33-0.zip // Íàæèìàåì <Ctrl+D>
# unzip ../uv7swve.zip
# mkdir BIN # ^D
# gmake
После чего на экране появляется приглашение к вводу
Симулятор помещает все свои исполняемые файлы в логина.
каталог BIN. Но так как по умолчанию он не существует,
создаем его: Restricted rights: Use, duplication, or disclosure is subject to restrictions
stated in your contract with Western Electric Company, Inc.
Thu Sep 22 05:51:05 EDT 1988
# mkdir BIN
# gmake
Идем дальше.

34
администрирование
// Ââîäèì ëîãèí dmr: на указанном порту, мы можем с помощью команд netstat -
login: dmr na или sockstat -4.
// Ñ ïîìîùüþ ðåäàêòîðà ed íà÷èíàåì ðåäàêòèðîâàòü ôàéë hello.c:
$ ed hello.c Работать по сети мы сможем после ввода на локальной
?hello.c
машине параметров, указывающих, откуда нам запускать
a ОС. В нашем случае это boot rl. После вывода которой мы
main() видим на экране:
{
printf(«Hello World!\n»);
} Waiting for console Telnet connection.
.
w После чего мы можем получить доступ к эмулятору че-
40 рез telnet. Пример сессии:
q
// Ñêîìïèëèðóåì íàïèñàííûé íàìè ôàéë: [01mer@darkthrone]:~> telnet marduk 12345
$ cc hello.c Trying 192.168.1.22
// Çàïóñòèì: Connected to marduk
$ a.out Escape charset is ‘^]’
Connected to PDP11 simulator
Видим результат: @

Hello World!
Я не буду описывать здесь все свои эксперименты ко-
Кстати, вы еще не догадались, кому принадлежит имя торые проводил в UNIX, чтобы не лишать читателя удоволь-
пользователя dmr? Человеку – живой легенде современ- ствия самому заняться исследованием этой ОС. А море
ности – Деннису Ритчи, отцу и основоположнику Юникса! различных открытий и удивительных находок я вам обещаю.
Согласитесь, что очень неудобно при каждом запуске Для корректного завершения работы с UNIX надо два
ОС каждый раз вводить все команды инициализации. Тут раза произвести синхронизацию диска с помощью коман-
нам на помощь приходят команды save и restore. Для «со- ды sync. После чего нажать <Ctrl+E>, и вы снова попадете
хранения» ввода команд, необходимых для запуска ОС, нам в оболочку эмулятора. Выход из которой осуществляется с
нужно набрать команду: помощью команд exit, quit, bye, на выбор.
В конце хотел бы добавить, что рассмотренный эмуля-
sim> save filename тор кроме PDP11 поддерживает еще достаточно большое
количество различных компьютеров:
В качестве filename введите имя файла, в который вы ! Data General Nova, Eclipse
хотите сохранить текущий образ эмулятора. ! Digital Equipment Corporation PDP-1, PDP-4, PDP-7, PDP-8,
Для «восстановления» состояния набираем: PDP-9, PDP-10, PDP-11, PDP-15, VAX
! GRI Corporation GRI-909
sim> restore filename ! IBM 1401, 1620, 1130, System 3
! Interdata (Perkin-Elmer) 16b and 32b systems
После чего будут актуальны ранее введенные и сохра- ! Hewlett-Packard 2116, 2100, 21MX
ненные настройки. ! Honeywell H316/H516
Также следует отметить одну очень досадную недора- ! MITS Altair 8800, with both 8080 and Z80
ботку по части удобства использования. В оболочке эмуля- ! Royal-Mcbee LGP-30, LGP-21
тора нет возможности редактировать вводимые команды. ! Scientific Data Systems SDS 940
Про возможность автодополнения команд я вообще
молчу. Хотя должен заметить, можно использовать зара- Соответственно, если мы найдем ОС для данных компь-
нее определенные алиасы. Например, для команды attach ютеров и приложим немного смекалки и настойчивости, по-
синонимом будет команда at. Более подробно про алиасы лучим в собственное распоряжение целый полигон для изу-
можно прочитать в документации. чения истории компьютеров и ОС. Особый интерес (по край-
Simh поддерживает работу через сеть. Например, у вас ней мере для меня) представляет эмуляция VAX. Особенно
нет возможности работать с ОС, запущенной через эмуля- при учете того, что на VAX можно запустить OpenBSD,
тор, находясь непосредственно перед монитором компью- NetBSD, и другие менее известные в настоящее время ОС.
тера, на котором включен simh. Или вы хотите дать воз- Но этому вопросу я намерен посвятить отдельную статью.
можность своим знакомым или друзьям поэксперименти- Я был бы очень рад всем вашим отзывам c описанием
ровать на запущенной через эмулятор ОС. экспериментов, поставленных с помощью этого эмулятора.
Воспользуемся опцией, определяющей консоль:
Ссылки:
sim> set console telnet=12345 1. http://simh.trailing-edge.com/software.html – небольшая
коллекция программ и ОС, подходящих для использо-
Назначаем доступ к консоли через порт 12345. вания под эмулятором simh.
На что эмулятор ответит: 2. http://simh.trailing-edge.com/photos.html – фотогалерея
различных старых компьютеров.
Listening on port 12345.
3. http://www.cs.bell-labs.com/who/dmr – домашняя странич-
Проверить, действительно ли нас ожидает соединение ка Денниса Ритчи.

№12(25), декабрь 2004 35


администрирование

АВТОМАТИЗИРУЕМ FTP С ПОМОЩЬЮ PYTHON

СЕРГЕЙ СУПРУНОВ
Любой системный администратор, если он в меру ленив, абонентов). Все задачи условно разделим на пользователь-
рано или поздно берется за автоматизацию своей работы. ские (например, инициирование отправки) и администра-
Сначала вместо длинных команд со множеством ключей по- торские (например, первичная настройка). Первые из них
являются псевдонимы (aliases), потом группы команд объе- требуется разработать максимально удобно, предоставив
диняются в пакетные файлы командной оболочки, затем простейший интерфейс и лишив пользователя возможнос-
на арену выходят сценарии на более функциональных язы- ти ошибаться. Задачи второй категории по традиции ре-
ках типа Perl… И все для того, чтобы сократить количество шим достаточно упрощенно – главное, чтобы все работало
«кликов» и по возможности переложить часть работы на при минимуме телодвижений.
пользователей, которые эти операции и должны бы делать Первым делом скачаем с http://python.org дистрибутив
«по идее», но «по факту» научить их находить нужный файл Python для Windows. Его инсталляция никаких вопросов
в дереве каталогов, упаковывать его и отправлять по на- вызвать не должна. На момент написания статьи у меня
значению оказывается на порядок сложнее, чем делать это была установлена версия Python 2.3.4. Входящая в состав
самому. пакета среда разработки IDLE (рис. 1) предоставляет неко-
Об использовании Python для выполнения тех или иных торые удобства, но для меня как-то уже устоялся стиль раз-
операций на UNIX-серверах написано достаточно много. В работки, когда код вбивается в обычный текстовый файл,
данной же статье я хочу показать применение этого языка и затем исполняется командой типа:
для решения «бытовых» задач в среде Windows. В качестве
примера (которым возможности Python никоим образом не C:\myworks\python\test>python test.py
ограничиваются) разработаем приложение, автоматизирую-
щее отправку данных и получение обновлений по FTP, ис- Можно, конечно, в командной строке набрать просто
пользуя заранее настроенные пути и имена файлов. test.py – в процессе инсталляции в Windows расширение
Попытаемся сделать наше приложение максимально «.py» ассоциируется с интерпретатором python.exe, и по-
универсальным, однако будем иметь в виду конкретную добная команда тоже выполнит код. Однако на стадии от-
цель – нужно организовать обмен данными с удаленной кас- ладки это не совсем удобно – для потоков stdout и stderr в
сой (ежедневно сбрасывать на сервер файлы реестров и этом случае создается новое консольное окно, которое зак-
время от времени получать с сервера обновленную базу рывается сразу же после завершения (в том числе и ава-

36
администрирование
рийного) работы сценария, не позволяя ознакомиться с со- ступом. Отступ может быть выполнен любым количеством
общениями об ошибке. символов «пробел», но все операторы блока должны иметь
одинаковый отступ. Первая же строка, выполненная без
отступа, рассматривается как окончание блока операторов.
Здесь хочется сделать отступление и немного пофило-
софствовать о стиле программирования. Тот же Perl позво-
ляет кодировать как угодно – хоть в одну строку. С одной
стороны, каждый программист со временем вырабатывает
тот стиль, который ему более удобен. При переходе на Perl
с других языков можно перенести и устоявшийся стиль на-
писания кода. Но с другой стороны тут есть и вероятность,
что кто-то другой будет очень долго воспроизводить «не-
Ðèñóíîê 1 ASCII»-звуки, пытаясь разобраться в исходниках програм-
мы, написанной как-нибудь экзотически. Язык Python в этом
Знакомство с Python смысле более требователен к разработчику, унифицируя
Подробно останавливаться на основах языка я не буду. Дан- тем самым стиль кодирования и упрощая работу тем, кому
ный раздел имеет целью коротко пояснить, что и как, для придется работать с этим кодом в будущем. Однако про-
тех, кто ранее с Python не сталкивался, но статью прочи- должим…
тать непременно хочет. И сразу, как говорится, – с места в (4, 5) – оператор «print» выводит на экран значение стро-
карьер: ковой переменной или непосредственно строку, заключен-
ную в кавычки или апострофы. Вставка в строку перемен-
(0) # -*- coding: cp866 -*- ных выполняется в стиле оператора printf языка Си, за тем
(1) #----------------------------- first.py
(2) import os исключением, что список интегрируемых переменных за-
(3) def hello(message): дается после символа «%» как кортеж (то есть через запя-
(4) print message
(5) print 'Âû íàõîäèòåñü â %s.' % os.getcwd() тую и в круглых скобках). Если переменная одна, как в на-
(6) шем случае, скобки можно опустить.
(7) if __name__ == '__main__':
(8) hello('Hello from Python.') (6) – пустые строки, естественно, допускаются.
(9) raw_input('Íàæìèòå Enter...') (7, a) – оператор ветвления пояснять, думаю, не нужно.
(a) else: pass
(b) #----------------------------end of first.py Как и обычно, задаются условие и блок операторов (выде-
ляется отступом), которые будут выполнены, если условие
Результат работы этого сценария будет следующим: истинно. В противном случае, если задан далее оператор
«else», будет выполнен его блок операторов. Если команда
C:\myworks\python\test>python test.py
Hello from Python. в блоке одна, допускается указывать ее непосредственно
Вы находитесь в C:\myworks\python\test. после двоеточия в этой же строке (хотя это и противоречит
Нажмите Enter...
официальному стилю программирования). Оператор «pass»
(0) – первая строка указывает интерпретатору, в какой ничего не делает, и строго говоря, строка «a» в нашем слу-
кодировке следует рассматривать приведенный ниже текст. чае совершенно не нужна.
Для ASCII-текста она не требуется, но поскольку мы исполь- Чуть подробнее следует остановиться на самом усло-
зуем кириллицу, то без нее интерпретатор будет каждый вии, указанном в строке (7): __name__ == ‘__main__’. Встро-
раз выдавать предупреждение «DeprecationWarining: Non- енная переменная __name__ возвращает имя программы,
ASCII character…». если вызывается как модуль из другого сценария (об этом
(1, b) – комментарии, как и принято в UNIX, предваря- – чуть ниже) либо строку «__main__», если файл запуска-
ются символом «#». Для многострочных комментариев ча- ется непосредственно. То есть код строк «8-9» будет вы-
сто используют обрамление текста с помощью утроенных полнен только тогда, когда файл first.py запускается из ко-
кавычек: «’’’ multiline comment ’’’». Этот же прием можно ис- мандной строки. Зачем это сделано, будет объяснено да-
пользовать для временного исключения участков кода на лее.
стадии отладки. (8) – здесь мы просто вызываем описанную ранее фун-
(2) – третья строка импортирует модуль, в данном слу- кцию «hello», передав ей текстовую строку в качестве аргу-
чае «os», который является стандартным для Python и со- мента.
держит функции для работы с конкретной операционной (9) – функция raw_input считывает со стандартного по-
системой. В нашем примере из этого модуля мы использу- тока ввода stdin строку, завершающуюся символом пере-
ем функцию getcwd(), возвращающую текущий каталог. вода строки. В данном случае этот оператор используется
(3) – с этой строки начинается определение функции исключительно для задержки вывода, чтобы консольное
«hello». В скобках указывается список параметров, причем окно не закрывалось сразу.
даже если параметров нет, скобки обязательно должны Теперь рассмотрим еще одну концепцию Python – по-
быть. Двоеточие начинает блок кода, содержащий тело вторное использование кода. Конечно, это позволяет де-
функции. В отличие от таких языков, как C или Perl, в Python лать любой язык программирования, но в Python повтор-
блок операторов (определения функций, циклы, ветвления) ное использование положено в основу синтаксиса, и все
не обрамляется операторными скобками, а выделяется от- получается очень легко и естественно.

№12(25), декабрь 2004 37


администрирование
Для примера напишем еще один сценарий: щью метода «config» графического объекта, как показа-
но в строке «6».
(0) import first Любой объект должен быть размещен одним из менед-
(1) first.hello('Hi')
жеров размещения (в данном примере используем наибо-
Запустив его, мы получим такой вывод: лее простой из них – pack). То есть для каждого объекта
C:\myworks\python\test>python test.py
требуется вызвать метод pack(), который поместит его в
Hi. конкретном месте окна. С помощью дополнительных пара-
Вы находитесь в C:\myworks\python\test. метров можно управлять упаковкой, например, указывать,
То есть мы подключили нашу первую программу как мо- к какой стороне окна требуется прикрепить элемент (пара-
дуль и получили возможность использовать определенные метр side), следует ли растягивать элемент при изменении
в ней функции. Код вне функций (в нашем случае это стро- размеров окна (expand), должен ли элемент заполнять все
ки «0, 1, 6-b») выполняется в момент импорта. Именно для отведенное ему пространство в указанном направлении (fill).
того, чтобы избежать какой-либо активности нашего пер- Самый лучший способ познакомиться с особенностями упа-
вого сценария во время его импортирования, мы и ввели ковки – на практике попробовать различные варианты.
проверку имени __name__, чтобы определить, подключа- Метод mainloop() запускает цикл обработки событий гра-
ется наш сценарий к другому или запускается автономно. фического окна. При его вызове окно с упакованными на
Говоря об импорте, следует указать еще на один син- нем элементами отображается на экране, и дальнейшее
таксис подключения: «from first import hello». Эта команда управление поведением сценария возможно только с по-
импортирует из first.py только функцию hello. Через запя- мощью обработчиков обратных вызовов, которым переда-
тую можно перечислить и несколько импортируемых функ- ется управление при наступлении того или иного события.
ций. Команда «from first import * » импортирует в текущий Метод quit, строго говоря, осуществляет выход из цикла
сценарий все функции, найденные в first.py. Отличие этого mainloop и передачу управления на следующий оператор
синтаксиса от использованного в second.py заключается в сценария.
том, что имена функций включаются в пространство имен Обратите внимание на символ «u» перед текстовыми
импортирующего сценария, и поэтому подгруженные фун- строками. Этот хитрый оператор заставляет Python преоб-
кции должны вызываться без указания модуля: разовывать следующую далее текстовую строку в кодиров-
ку Unicode. Базовая кодировка должна быть задана так, как
(0) from first import hello показано в строке «0». В версиях Python до 2.3 этот синтак-
(1) hello('Hi')
сис не действует, и там требуется явно задавать функцию
Ну и для полноты картины – несколько слов о библиоте- преобразования unicode().
ке графических объектов Tkinter. Основанная на Tk/Tcl, она Еще одно замечание – внутри скобок допускается пе-
позволяет достаточно просто наделять сценарии графичес- ренос строки и произвольный отступ перенесенной части,
ким интерфейсом: как это продемонстрировано в строках «8-9».
В результате с помощью этих нескольких строк мы по-
(0) # -*- coding: cp866 -*- лучим полнофункциональное окно, изображенное на рис. 2.
(1) from Tkinter import *
(2) Для первого знакомства, думаю, этого достаточно. Еще не-
(3) window = Tk() которые нюансы мы рассмотрим в дальнейшем.
(4) window.title(u'Ïðîñòîå ãðàôè÷åñêîå îêíî')
(5) label = Label(window, text = u' ↵
Ïðîñòàÿ òåêñòîâàÿ ìåòêà')
(6) label.config(fg = 'blue', ↵
font = ('Georgia', 14, 'italic'))
(7) label.pack() Ðèñóíîê 2
(8) button = Button(window, text = u'Çàêðûòü', ↵
command = window.quit)
(a)
(b)
button.pack(expand=YES, fill=X)
window.mainloop()
Модуль для архивирования myzip
Поскольку передавать по сети файлы в запакованном виде
В строке «1» импортируем все из модуля Tkinter. Далее намного приятнее, особенно когда речь идет о коммутиру-
последовательность действий такова: объявляем окно емой линии, то заготовим несколько функций для работы с
window верхнего уровня (3); задаем ему текст заголовка (4); zip-файлами. Чтобы иметь возможность использовать эти
описываем и упаковываем текстовую метку (5-7); анало- функции и в других приложениях, поместим их в отдель-
гично поступаем с кнопкой (8-a) и, наконец, в строке «b» ный файл:
запускаем на выполнение цикл окна.
Синтаксис описания различных элементов во многом # -*- coding: cp866 -*-
#--------------------------------------------------------
одинаков – первым параметром задается родительский #
элемент (в данном случае окно верхнего уровня), к кото- # myzip.py: ìîäóëü ðàáîòû ñ zip-àðõèâàìè
#
рому прикрепляется данный элемент. Далее перечисля- #--------------------------------------------------------
ются другие параметры: «text» для задания отображаемо-
# Ìîäóëü äëÿ ðàáîòû ñ zip-àðõèâàìè
го текста, «command» определяет обработчик обратного from zipfile import *
вызова, который будет исполнен при выборе данного эле- # Èìïîðòèðóåòñÿ ôóíêöèÿ glob äëÿ îáõîäà êàòàëîãîâ
from glob import glob
мента (в данном примере при нажатии на кнопку главное
окно будет закрыто). Параметры можно задавать и с помо- # Åñëè íå íîëü – âûâîäèòü ñîîáùåíèÿ íà ýêðàí

38
администрирование
VERBOSE = 1 Модуль работы с FTP myftp
# Î÷èñòêà àðõèâà îò èìåþùèõñÿ â íåì ôàéëîâ:
Аналогично в отдельный файл вынесем и функции работы
# àðõèâ îòêðûâàåòñÿ íà çàïèñü è ñðàçó çàêðûâàåòñÿ по протоколу FTP. Здесь нам требуется две функции – от-
def clearzip(zipname): правка одного файла по заданному пути и чтение одного
if VERBOSE:
print 'myzip: Î÷èñòêà àðõèâà %s.' % zipname файла. Возможность загрузки или отправки сразу несколь-
zip = ZipFile(zipname, 'w', ZIP_DEFLATED) ких файлов реализовывать не будем: поскольку в основе
zip.close
нашего приложения будет лежать работа с архивами, то
# Ôóíêöèÿ çàïèñè ôàéëà â àðõèâ: целесообразно упаковывать все передаваемое или прини-
# óêàçàííûé ôàéë äîáàâëÿåòñÿ ê ñóùåñòâóþùèì
def writezip(zipname, filename): маемое в один файл. Код модуля представлен ниже:
if VERBOSE:
print 'myzip: Óïàêîâûâàåòñÿ %s â %s.' ↵
% (filename, zipname) # -*- coding: cp866 -*-
zip = ZipFile(zipname, 'a', ZIP_DEFLATED) #--------------------------------------------------------
zip.write(filename) #
zip.close # myftp.py: ìîäóëü ðàáîòû ñ FTP
#
# Çàïèñü â àðõèâ âñåõ ôàéëîâ èç êàòàëîãà, óäîâëåòâîðÿþùèõ #--------------------------------------------------------
# øàáëîíó
def writepattzip(zipname, patterns): # Èìïîðò íóæíûõ ôóíêöèé
if VERBOSE: import os
print 'myzip: Ñîçäàåòñÿ àðõèâ %s...' % zipname from ftplib import FTP
clearzip(zipname) from myzip import *
for pattern in patterns:
filelist = glob(pattern) VERBOSE = 1
for filename in filelist:
writezip(zipname, filename) # Ñêà÷èâàíèå ôàéëà ïî FTP:
if VERBOSE: # ïåðåäàþòñÿ ñëåäóþùèå ïàðàìåòðû:
print 'myzip: Àðõèâ ñîçäàí.' # fromdir – ïàïêà-èñòî÷íèê íà FTP-ñåðâåðå
# file – èìÿ ñêà÷èâàåìîãî ôàéëà
# Èçâëå÷åíèå ôàéëà èç àðõèâà # (fromsite, ftpuser, ftppassword) – FTP-ñåðâåð
def readzip(zipname, filename): # è ëîãèí/ïàðîëü äëÿ âõîäà
if VERBOSE: # todir - ëîêàëüíàÿ ïàïêà äëÿ ñîõðàíåíèÿ ñêà÷àííîãî ôàéëà
print 'myzip: Èçâëåêàåòñÿ %s èç %s.' ↵ #
% (filename, zipname) def getftp(fromdir, file, (fromsite, ftpuser, ↵
zip = ZipFile(zipname, 'r', ZIP_DEFLATED) ftppassword), todir):
open(filename, 'wb').write(zip.read(filename)) olddir = os.getcwd() # çàïîìèíàåòñÿ òåêóùèé êàòàëîã
zip.close os.chdir(todir) # ïåðåõîä â ïàïêó íàçíà÷åíèÿ
if VERBOSE:
# Èçâëå÷åíèå âñåõ ôàéëîâ èç àðõèâà print 'myftp: Óñòàíàâëèâàåòñÿ ñîåäèíåíèå ñ ↵
def readallzip(zipname): %s...' % fromsite
if VERBOSE: try:
print 'myzip: ×èòàåòñÿ àðõèâ %s...' % zipname localfile = open(file, 'wb')
zip = ZipFile(zipname, 'r', ZIP_DEFLATED) connection = FTP(fromsite)
for filename in zip.namelist(): connection.login(ftpuser, ftppassword)
readzip(zipname, filename) connection.cwd(fromdir)
zip.close except:
if VERBOSE: print 'myftp: ÎØÈÁÊÀ ÑÎÅÄÈÍÅÍÈß Ñ %s!' % fromsite
print 'myzip: Àðõèâ ïðî÷òåí.' return(-1)
if VERBOSE:
print 'myftp: Ñîåäèíåíèå ñ %s óñòàíîâëåíî.' ↵
# Åñëè çàïóñêàåòñÿ èç êîìàíäíîé ñòðîêè, òî ìîæíî % fromsite
# ÷òî-òî ñäåëàòü
if __name__ == '__main__': print 'Òîëüêî êàê ìîäóëü.' if VERBOSE:
print 'myftp: Âûïîëíÿåòñÿ çàãðóçêà %s...' % file
try:
В основе данного сценария лежит стандартный модуль connection.retrbinary('RETR ' + ↵
zipfile. Он предоставляет довольно развитые средства для file, localfile.write, 1024)
connection.quit()
работы с архивами, но его непосредственное использова- localfile.close()
ние потребует каждый раз писать один и тот же код обвяз- except:
print 'myftp: ÎØÈÁÊÀ ÏÎËÓ×ÅÍÈß ÔÀÉËÀ %s' % file
ки. Поэтому мы и создаем собственный модуль, в котором return(-2)
опишем нужные нам функции на более высоком уровне. if VERBOSE:
print 'myftp: Çàãðóçêà ôàéëà %s çàâåðøåíà.' % file
Класс ZipFile модуля zipfile позволяет работать с архи-
вом, почти как с обычным файлом – читать из него, записы- # èñïîëüçóåì try, ïîñêîëüêó ñêà÷àííûé ôàéë ìîæåò
# îêàçàòüñÿ íå zip-àðõèâîì. Õîòÿ ýòî ìîæíî áûëî
вать и т. д. Фигурирующий здесь параметр ZIP_DEFLATED # áû ïðîâåðèòü è ÿâíî:
определяет метод компрессии. try:
readallzip(file)
В дальнейшем нам понадобятся отсюда: функция read- except:
allzip, которая будет извлекать в текущую папку все файлы print 'myftp: %s íå ÿâëÿåòñÿ àðõèâîì, ïîìåùåí ↵
êàê åñòü.' % file
из скачанного архива, и writepattzip, которая будет упако-
вывать в архив все файлы из текущего каталога. Функции os.chdir(olddir) # âîçâðàùàåìñÿ â ïðåæíèé êàòàëîã
соответствуют шаблону. # Çàãðóçêà ôàéëà ïî FTP íà ñåðâåð:
Из интересного отметим здесь, что шаблоны передают- # ïåðåäàþòñÿ ñëåäóþùèå ïàðàìåòðû:
# fromdir – ëîêàëüíàÿ ïàïêà-èñòî÷íèê
ся в виде кортежа, то есть этот параметр должен выгля- # file – èìÿ îòïðàâëÿåìîãî zip-ôàéëà
деть примерно так: «(‘*.db’, ‘*.px’)». Также обратите внима- # pattern – ñïèñîê øàáëîíîâ äëÿ îòïðàâêè
# (fromsite, ftpuser, ftppassword) – FTP-ñåðâåð
ние на синтаксис цикла «for»: он перебирает все значения # è ëîãèí/ïàðîëü äëÿ âõîäà
из списка, заданного после ключевого слова «in». # todir – ïàïêà íà FTP-ñåðâåðå äëÿ çàãðóçêè ôàéëà

№12(25), декабрь 2004 39


администрирование
# from glob import glob
def putftp(fromdir, zipfile, pattern, (tosite, ↵ olddir = os.getcwd()
ftpuser, ftppassword), todir): root = 'data/'
olddir = os.getcwd() os.chdir(root)
os.chdir(fromdir) list = glob('Pay_*')
list.sort()
if VERBOSE: srcdir = root + list[-1] # ïîñëåäíèé ýëåìåíò ñïèñêà
print 'myftp: Ïîäãîòîâêà ôàéëîâ ê îòïðàâêå...' os.chdir(olddir)
writepattzip(zipfile, pattern) # print 'config: Òåêóùèé êàòàëîã îòïðàâêè – %s' % srcdir
if VERBOSE:
print 'myftp: Ôàéëû óïàêîâàíû â %s.' % zipfile #-----------------------------------------------------
print 'myftp: Óñòàíàâëèâàåòñÿ ñîåäèíåíèå ↵ # Ñïèñîê FTP-ñåðâåðîâ. Ôîðìàò çàïèñè:
ñ %s...' % tosite # (FTP-ñåðâåð, ëîãèí, ïàðîëü)
try:
localfile = open(zipfile, 'rb') ftpservers = [
connection = FTP(tosite) ('ftp.my.server.ru', 'user', 'password'),
connection.login(ftpuser, ftppassword) ('ftp.freebsd.org', 'ftp', 'my@mail.ru'),
connection.cwd(todir) ]
except:
print 'myftp: ÎØÈÁÊÀ ÑÎÅÄÈÍÅÍÈß Ñ %s' % tosite #-----------------------------------------------------
return(-2) # Ñïèñîê îïåðàöèé. ôîðìàò çàïèñè:
if VERBOSE: # (íîìåð, òèï îïåðàöèè, íàçâàíèå îïåðàöèè, íîìåð FTP-ñåðâåðà,
print 'myftp: Ñîåäèíåíèå ñ %s óñòàíîâëåíî' % tosite # ïàïêà-èñòî÷íèê, èìÿ àðõèâà, øàáëîí, ïàïêà íàçíà÷åíèÿ)
print 'myftp: Âûïîëíÿåòñÿ îòïðàâêà ôàéëà ↵
%s...' % zipfile operations = [
try: (0, 'get', u'Îáíîâèòü äàííûå', 0, 'downdata', ↵
connection.storbinary('STOR ' + zipfile, ↵ 'basa.zip', ('*',), 'data'),
localfile, 1024) (1, 'put', u'Îòïðàâèòü ðååñòðû', 0, srcdir, ↵
connection.quit() 'reestr.zip', ('*.db', '*.px',), 'updata'),
localfile.close() (2, 'get', u'Îáíîâèòü ïðîãðàììó', 0, 'ftpman', ↵
except: 'ftpman.zip', ('*',), 'bin'),
print 'myftp: ÎØÈÁÊÀ ÎÒÏÐÀÂÊÈ ÔÀÉËÀ %s!' % zipfile (3, 'get', u'Ïîëó÷èòü README.TXT', 1, ↵
return(-2) 'pub/FreeBSD', 'README.TXT', ('*',), '.'),
if VERBOSE: ]
print 'myftp: Ôàéë %s îòïðàâëåí.' % zipfile

os.chdir(olddir) Наиболее важными здесь являются список FTP-серве-


ров и список операций. Код в начале сценария, помечен-
Здесь следует обратить внимание на то, что файлы сле- ный как «предвычисляемый», нужен для динамического
дует открывать в бинарном режиме (используем парамет- определения значения некоторых переменных, подставля-
ры «rb» и «wb»), чтобы они не пострадали в результате ин- емых в списки. В нашем примере в нем вычисляется значе-
терпретации Python символов конца строки. ние переменной srcdir, которая задает папку-источник дан-
Всю черную работу в этом сценарии выполняет стан- ных, используемую в операции 1 («Отправить реестры»). В
дартный модуль ftplib, а конкретно – его класс FTP, кото- качестве источника должна использоваться папка с име-
рый отвечает за методы установления соединения, обес- нем вида Pay_NN, где NN – двузначное число, с наиболь-
печивает работу протокола FTP и т. д. шим значением NN. Для того чтобы определить эту папку
Потенциально опасные операции, которые могут выз- на данный момент, и нужен этот «предвычисляемый» код.
вать ошибку (например, FTP-сервер может быть недосту- Список FTP-серверов задается как список кортежей,
пен), заключены в оператор «try – except». Он в свою оче- каждый из которых содержит адрес сервера, имя и пароль
редь перехватывает ошибку и не позволяет нашему прило- пользователя для доступа на этот сервер. В дальнейшем
жению «обрушиться» со страшными для пользователя ру- обращение к данным по тому или иному серверу выполня-
гательствами. ется по порядковому номеру записи (начиная с нуля). На-
пример, имя пользователя, которое должно использовать-
Файл конфигурации config.py ся для доступа на ftp.freebsd.org, можно будет получить так:
Конечно, нужные нам переменные, такие как URL FTP-сер- «ftpservers[1][1]».
вера, имя и пароль пользователя, и прочее, можно задать Аналогично задается список операций. Назначения по-
непосредственно в главном модуле нашего приложения, но лей приведены в комментарии. Номер операции здесь ука-
несколько удобнее представляется вынос этих описаний в зываем явно – так будет удобнее в дальнейшем. Второе
отдельный файл. Чтобы не связываться с разбором кон- поле задает саму операцию – получение данных (get) или
фигурационного файла и не изобретать ему какой-то фор- отправка (put).
мат, будем использовать в его качестве обычный сценарий Конечно, формат нашего конфигурационного файла
Python, в котором определяются соответствующие перемен- способен напугать кого угодно, однако пользователям не
ные. Затем, будучи импортирован в главный сценарий, он придется с ним работать, а администратор как-нибудь раз-
предоставит свои переменные другим функциям. В конце берется.
концов это уже относится к «административным» функци-
ям, а мы условились не тратить много усилий на красоту в Главный сценарий manager.py
данном случае. Теперь попытаемся объединить все это в законченное при-
ложение:
# -*- coding: cp866 -*-
#------------------------------------------------------
# ïðåäâû÷èñëÿåìûé êîä: # -*- coding: cp866 -*-
from Tkinter import *
import os from myftp import getftp, putftp

40
администрирование
VERBOSE = 1 # Èìåííî â ýòîò ìîìåíò áóäóò âûïîëíåíû «ïðåäâû÷èñëåíèÿ»
import config
if VERBOSE: print '================> manager.py çàïóùåí.'
# Ïåðåáèðàÿ âñå êîðòåæè â ñïèñêå îïåðàöèé, äèíàìè÷åñêè
# Ñëóæåáíî-äåêîðàòèâíàÿ ôóíêöèÿ. Íóæíà, ÷òîáû ìåíÿòü òåêñò # ñîçäàåì äëÿ êàæäîé èç íèõ êíîïêó
# ìåòêè â çàâèñèìîñòè îò ñîñòîÿíèÿ for op in config.operations:
def chStat(messvar, color, btn, btnrelief): cmd = "btn%d = Button(comf, text = '%s', " % (op[0], op[2])
# èçìåíÿåì ãðàíèöó êíîïêè òàê, ÷òîáû â ìîìåíò cmd = cmd + "command = (lambda: %s(%d))) " % (op[1], op[0])
# âûïîëíåíèÿ îïåðàöèè îíà âûãëÿäåëà âäàâëåííîé – exec cmd
# èñêëþ÷èòåëüíî «äåêîðàòèâíûé» ýôôåêò exec 'btn%d.pack(fill=X)' % op[0]
btn.config(relief = btnrelief)
# ìåíÿåì òåêñò ìåòêè # Êíîïêà «Çàêðûòü» è åùå íåìíîãî äåêîðàöèé
status.config(text = messvar) closeBtn = Button(comf, text = u'Çàêðûòü', command = tk.quit)
# ìåíÿåì öâåò ìåòêè closeBtn.pack(side=RIGHT)
status.config(fg = color) copyLbl = Label(comf, text = u'Coded by Amsand, 2004')
# ïåðåðèñîâûâàåì ìåòêó copyLbl.config(font = ('Georgia', 8, 'italic'))
status.update() copyLbl.pack(side=LEFT)

# Ôóíêöèÿ ïîëó÷åíèÿ äàííûõ. Íàçíà÷àåòñÿ êàê îáðàáîò÷èê # Âûâîäèì íà ýêðàí ïîëó÷åííîå îêíî è ïåðåäàåì åìó óïðàâëåíèå
# êíîïêàì îïåðàöèé òèïà 'get' mainloop()
def get(nr):
if VERBOSE: print '================> âûïîëíÿåòñÿ ↵ # Êîãäà îêíî áóäåò çàêðûòî, óïðàâëåíèå âíîâü âåðíåòñÿ
çàãðóçêà...' # ñöåíàðèþ
# âûáèðàåì íóæíûé êîðòåæ if VERBOSE: print '================> manager.py îñòàíîâëåí.'
op = config.operations[nr]
# âû÷èñëÿåì èìÿ êíîïêè ïî íîìåðó В результате исполнения этого сценария на экране ото-
exec 'obj = btn%d' % op[0]
# âûáèðàåì äàííûå ïî FTP-ñåðâåðó бразится графическое окно наподобие изображенного на
ftpsite = config.ftpservers[op[3]] рис. 3. Одновременно с этим будет открыто консольное окно,
msg = u'Ïîäîæäèòå: âûïîëíÿåòñÿ çàãðóçêà...'
chStat(msg, '#AA0000', obj, 'sunken') куда будет направляться вывод операторов print (рис. 4).
err = getftp(op[4], op[5], ftpsite, op[7]) Отдавая сценарий на выполнение интерпретатору pythonw,
if err:
msg = u'ÎØÈÁÊÀ ÏÎËÓ×ÅÍÈß ÄÀÍÍÛÕ!.' а не python, можно избежать появления консольного окна.
chStat(msg, '#FF0000', obj, 'raised') Но в данном случае оно нам нужно для получения дополни-
else:
msg = u'Äàííûå ïîëó÷åíû.' тельной информации.
chStat(msg, '#007700', obj, 'raised')
if VERBOSE: print '================> çàãðóçêà çàâåðøåíà.'
# Ôóíêöèÿ îòïðàâêè äàííûõ. Íàçíà÷àåòñÿ êàê îáðàáîò÷èê
# êíîïêàì îïåðàöèé òèïà 'put'
def put(nr):
if VERBOSE: print '================> âûïîëíÿåòñÿ ↵
îòïðàâêà...'
op = config.operations[nr]
exec 'obj = btn%d' % op[0]
ftpsite = config.ftpservers[op[3]]
msg = u'Ïîäîæäèòå: âûïîëíÿåòñÿ îòïðàâêà...'
chStat(msg, '#AA0000', obj, 'sunken') Ðèñóíîê 3
err = putftp(op[4], op[5], op[6], ftpsite, op[7])
if err:
msg = u'ÎØÈÁÊÀ ÎÒÏÐÀÂÊÈ ÄÀÍÍÛÕ!'
chStat(msg, '#FF0000', obj, 'raised')
else:
msg = u'Äàííûå îòïðàâëåíû.'
chStat(msg, '#007700', obj, 'raised')
if VERBOSE: print '================> îòïðàâêà âûïîëíåíà.'

# Ñîçäàåì ãëàâíîå îêíî


tk = Tk()
tk.title(u'Öåíòð óïðàâëåíèÿ îáìåíîì')

# Íåêîòîðûå äåêîðàòèâíûå ýëåìåíòû...


topf = Frame(tk)
topf.pack(expand=NO, fill=X)
lbl = Label(topf, text = u' – Àâòîìàòèçàöèÿ îáìåíà ↵
äàííûìè ïî FTP - ') Ðèñóíîê 4
lbl.config(font = ('Georgia', 9, 'italic bold'))
lbl.config(bg = '#AAAAFF') Таким образом, потратив немного усилий, нам удалось
lbl.pack(side=TOP, expand=YES, fill=X) существенно упростить для пользователя работу с FTP. Опи-
# Ñîçäàåì ñòàòóñ-ìåòêó, â êîòîðóþ áóäåò âûâîäèòüñÿ сав в файле config.py все операции, которые должны будут
# èíôîðìàöèÿ î ñîñòîÿíèè выполняться пользователями, мы получим удобное графи-
midf = Frame(tk)
midf.pack(expand=YES, fill=BOTH) ческое окно. Каждая операция будет запускаться по одному
status = Label(midf, text = u'Ïîäðîáíûé âûâîä ñì. ↵ щелчку мышки. В случае необходимости можно внести кор-
â îêíå êîíñîëè')
status.config(bg='#FFFFFF', bd=2, relief=SUNKEN, height=3) рективы в список операций, на это уйдут считанные минуты.
status.pack(expand=YES, fill=BOTH) Безусловно, полученное приложение не является иде-
# Ôðåéì äëÿ ðàçìåùåíèÿ êíîïîê îïåðàöèé. Íóæåí äëÿ óïðàâëåíèÿ альным. Зато его можно назвать оптимальным в плане со-
# ðàñòÿãèâàíèåì ïðè èçìåíåíèè ðàçìåðîâ îêíà – âåñü ôðåéì отношения затрат на разработку, полученной функциональ-
# áóäåò «ïðèâÿçàí» ê íèæíåé êðîìêå îêíà
comf = Frame(tk) ности и удобства использования. К тому же исходный код в
comf.pack(fill=X) несколько строчек всегда рядом, и внести любое измене-
# Èìïîðòèðóåì êîíôèãóðàöèîííûé ôàéë. ние не составит особого труда.

№12(25), декабрь 2004 41


безопасность

ЗАЩИТА СЕТЕВЫХ СЕРВИСОВ


С ПОМОЩЬЮ STUNNEL

АНДРЕЙ БЕШКОВ
Инциденты с безопасностью были и, видимо, будут всегда. Как я говорил ранее, переделка обычной программы в
Не последнюю роль в этом играет изначально ошибочный SSL-версию – уже нетривиальный процесс, но на этом труд-
дизайн многих сетевых протоколов. Большинство из них пе- ности не заканчиваются. К сожалению, настройка и уста-
редают и принимают данные либо в открытом виде, либо с новка на сервере программного обеспечения, реализующе-
минимальным шифрованием. Криптография не стоит на ме- го защищенные версии протоколов, упомянутых выше, ча-
сте, и постепенно некоторые протоколы обзаводятся функ- сто тоже довольно непроста. Кроме этого, иногда встреча-
циями, реализующими стойкое шифрование, но, к сожале- ются ситуации, когда производитель того или иного сер-
нию, процесс этот идет не слишком быстро. Для подавляю- верного или клиентского обеспечения, работающего с не-
щего большинства разработчиков программного обеспече- безопасными протоколами, канул в Лету, не успев создать
ния вопросы безопасности создаваемого продукта стоят защищенных версий своих программ и оборудования. За
далеко не на первом месте. Обычно все делается по прин- право пользования этими разработками когда-то были зап-
ципу «лишь бы приложение хоть как-то заработало», а по- лачены лицензионные отчисления и, соответственно, отка-
том мы уже исправим все недочеты. Обычно это «потом» заться от работы с ними экономически невыгодно. Иногда
растягивается на годы. И чаще всего для внедрения в уже это сделать вообще невозможно по причине того, что ни
работающий программный комплекс механизмов безопас- одно из решений, предлагаемых сторонними поставщика-
ности необходимо достаточно сильно менять не только код, ми, не реализует нужные функции. Но чаще всего склады-
но и многие идеи, лежащие в основе всего дизайна. Не каж- вается ситуация, когда безопасные приложения от нового
дый производитель программного обеспечения с радостью поставщика не удается встроить в устаревшее оборудова-
пойдет на дополнительные трудозатраты. ние и программные среды, до сих пор используемые во
Благодаря инициативе компании Netscape стандартом многих производственных процессах и служащие нам ве-
де факто для задач шифрования веб-коммуникаций стал рой и правдой.
SSL (Security Socket Layer). Первоначально он применялся Таким образом, мы незаметно подошли к предмету на-
для защиты данных, передаваемых с помощью HTTP. Годы шей сегодняшней беседы. Говорить мы будем о программе
активного использования в сфере веб-коммерции доказа- Stunnel, которая позволяет защитить небезопасные серви-
ли стабильность и надежность этого решения. Таким обра- сы. Механика действия довольно проста. Stunnel позволя-
зом, возникла защищенная версия протокола HTTP, в даль- ет шифровать любое TCP-соединение с помощью SSL. При
нейшем получившая название HTTPS. Вслед за этим по- этом ни отправитель, ни получатель не подозревают о том,
явились протоколы IMAPS, POP3S, SMTPS, NNTPS, LDAPS. что трафик в процессе передачи по сети шифруется с по-
Они призваны со временем заменить своих небезопасных мощью внешней программы.
предков. Программа работает на следующих операционных сис-
По идее, использование SSL вместо стандартного API темах:
для работы с сетевыми сокетами должно быть довольно про- ! FreeBSD ! HP NonStop™ Kernel
стым и прозрачным для приложения. На первый взгляд, нуж- ! NetBSD ! HP-UX
но всего лишь заменить в исходном коде защищаемого при- ! OpenBSD ! Plan 9
ложения вызовы стандартных функций на их SSL-аналоги ! GNU/Linux ! QNX
и произвести перекомпиляцию. Но не тут то было, при ра- ! AmigaOS ! SCO OpenServer
боте в многопоточной и многопользовательской среде при- ! BeOS ! SGI IRIX
ходится добавлять в свое приложение довольно много кода ! IBM AIX ! Solaris
поддержки SSL. На данный момент в сети существует не- ! Mac OS X ! Tru64, он же Digital Unix, он же DEC OSF/1
сколько библиотек, реализующих функции SSL. Самой по- ! OpenVMS ! Windows 95/98/ME/NT/2000/XP
пулярной из них является OpenSSL, распространяемая по
открытой лицензии. Итак, рассмотрим пример превращения небезопасных

42
безопасность
сервисов pop3, imap, smtp в их безопасные аналоги IMAPS, Объяснить, как все происходит, довольно просто. На схе-
POP3S, SMTPS. Представим, что у нас есть сервер, функ- ме изображена типичная картина сетевого взаимодействия
ционирующий под управлением FreeBSD 4.10. Он назы- клиента и почтового сервера (см. рис. 1).
вается freebsd410.unreal.net и доступен нашему клиенту При отправке сообщений почтовый клиент, умеющий ра-
по адресу 10.10.21.134. Кроме всего прочего, на нем ра- ботать с SSL, шифрует пакеты и передает их демону stunnel.
ботают программы dkimap, postfix, cucipop, которые и ре- Тот в свою очередь расшифровывает их и отдает демонам
ализуют ту самую «святую троицу» протоколов. Все они imap, pop3, smtp. А почтовые демоны в ответ на запросы
принимают входящие соединения на любом сетевом ин- отдают данные в открытом виде stunnel, который шифрует
терфейсе. Postfix работает как резидентный демон, а ос- их и передает клиенту. При этом ни клиент, ни демоны не
тальные демоны запускаются с помощью inetd, как толь- догадываются о том, что общаются друг с другом через
ко кто-нибудь попытается присоединиться к нужным пор- посредника.
там. Соответственно, в /etc/inetdd.conf присутствуют сле- Итак, приступаем к установке stunnel на сервер.
дующие строки: Предварительно в систему должен быть проинсталли-
рован OpenSSL, так как для правильного функционирова-
pop3 stream tcp nowait root ↵ ния stunnel требуются криптоалгоритмы, реализуемые имен-
/usr/local/libexec/cucipop cucipop -Y
imap stream tcp nowait root ↵ но этой библиотекой. Для FreeBSD проводить инсталляцию
/usr/local/libexec/dkimap4 dkimap удобнее всего из портов.

Таким образом, картина, показываемая командой: # cd /usr/ports/security/stunnel


# make all install

# netstat -na | grep LISTEN По окончании сборки будет автоматически создан поль-
зователь stunnel, входящий в одноименную группу. Затем
выглядит следующим образом: произойдет установка, и нам будет доступен stunnel версии
4.04. Сразу же после этого система начнет создавать сек-
tcp4 0 0 *.25 *.* LISTEN
tcp4 0 0 *.143 *.* LISTEN ретный ключ и сертификат. Вы можете воспользоваться этим
tcp4 0 0 *.110 *.* LISTEN способом и начать отвечать на задаваемые вопросы или про-
Демоны ждут входящих соединений на портах 25, 110, сто нажимать Enter и впоследствии самостоятельно создать
143. Что означают эти номера, можно узнать, пролистав нужные файлы. Я предпочитаю второй способ. Создаем ди-
файл /etc/services. Кстати, стоит убедиться, что в этом же ректорию, где у нас будут храниться сертификаты и ключи.
файле есть записи, описывающие наши будущие защищен-
ные сервисы: # mkdir /usr/local/etc/stunnel/certs
# cd /usr/local/etc/stunnel/certs

imaps 993/tcp # imap4 protocol over TLS/SSL Самостоятельно создаем ключи и сертификаты со сро-
imaps 993/udp
pop3s 95/tcp spop3 # pop3 protocol over TLS/SSL ком действия 1 год. В связи с тем, что stunnel не умеет ра-
pop3s 995/udp spop3 ботать с ключами, защищенными паролями, используем оп-
smtps 465/tcp # smtp protocol over TLS/SSL (was ssmtp)
smtps 465/udp цию -nodes.

Ðèñóíîê 1

№12(25), декабрь 2004 43


безопасность
# openssl req -new -x509 -days 365 -nodes ↵ В описании сервисов стоит обратить особое внимание
-out mailserver.cert -keyout mailserver.key на ключевые слова accept и connect. Первое описывает ад-
Generating a 1024 bit RSA private key рес и порт, через который к нам и от нас будут идти зашиф-
................++++++
......................++++++ рованные данные, а второе, соответственно, адрес и порт
writing new private key to 'mailserver.key' для обмена расшифрованными данными с демонами. Опи-
-----
сание обоих переменных может быть в нескольких форма-
You are about to be asked to enter information that will be incorporated
into your certificate request. тах.
What you are about to enter is what is called a Distinguished Name or a DN. Адрес:порт – данные принимаются и отправляются толь-
There are quite a few fields but you can leave some blank
For some fields there will be a default value, ко на интерфейсе и порте с указанным адресом. В случае
If you enter '.', the field will be left blank. если адрес не указан, по необходимости будут задейство-
-----
Country Name (2 letter code) [AU]:RU
ваны соответствующие порты на всех доступных интерфей-
State or Province Name (full name) [Some-State]:Rostov region сах. В моем конфигурационном файле для наглядности
Locality Name (eg, city) []:Rostov-on-Don продемонстрированы оба вида настроек.
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Tigrisha home
Organizational Unit Name (eg, section) []:Test Lab Запускаем stunnel и смотрим, что демон пишет в /var/
Common Name (eg, YOUR name) []:freebsd410.unreal.net log/stunnel.log. Должны увидеть что-то подобное:
Email Address []:tigrisha@freebsd410.unreal.net

Обратите внимание, что для заполнения поля Common 2004.12.04 19:09:15 LOG5[2405:134598656]: stunnel 4.04
on i386-portbld-freebsd4.10 PTHREAD+LIBWRAP
Name или CN было использовано DNS-имя сервера. Это with OpenSSL 0.9.7d 17 Mar 2004
обязательно нужно делать, иначе почтовый клиент будет 2004.12.04 19:09:15 LOG7[2405:134598656]: Snagged 64 random bytes
from /root/.rnd
постоянно возмущаться несовпадением фактического 2004.12.04 19:09:15 LOG7[2405:134598656]: Wrote 1024 new random
имени сервера и того, что записано в недрах сертифика- bytes to /root/.rnd
2004.12.04 19:09:15 LOG7[2405:134598656]: RAND_status claims
та. Также необходимо убедиться, что на клиентском компь-
sufficient entropy for the PRNG
ютере правильно работает разрешение имени freebsd410. 2004.12.04 19:09:15 LOG6[2405:134598656]: PRNG seeded successfully
unreal.net. 2004.12.04 19:09:15 LOG7[2405:134598656]: Certificate:
/usr/local/etc/stunnel/certs/mailserver.cert
Покончив с предыдущим пунктом, устанавливаем пра- 2004.12.04 19:09:15 LOG7[2405:134598656]: Key file:
вильные права доступа к файлам. /usr/local/etc/stunnel/certs/mailserver.key
2004.12.04 19:09:15 LOG5[2405:134598656]: FD_SETSIZE=1024,
file ulimit=957 -> 467 clients allowed
# chmod 600 ./mailserver.cert ./mailserver.key 2004.12.04 19:09:15 LOG7[2405:134598656]: FD 6 in non-blocking mode
2004.12.04 19:09:15 LOG7[2405:134598656]: SO_REUSEADDR option
set on accept socket
Создаем директорию, куда демон перейдет в chroot: 2004.12.04 19:09:15 LOG7[2405:134598656]: pop3s bound
to 10.10.21.134:995
2004.12.04 19:09:15 LOG7[2405:134598656]: FD 7 in non-blocking mode
# mkdir /var/tmp/stunnel
# chown stunnel:stunnel /var/tmp/stunnel 2004.12.04 19:09:15 LOG7[2405:134598656]: SO_REUSEADDR option
# chmod 700 /var/tmp/stunnel set on accept socket
2004.12.04 19:09:15 LOG7[2405:134598656]: imaps bound to 0.0.0.0:993
2004.12.04 19:09:15 LOG7[2405:134598656]: FD 8 in non-blocking mode
При запуске без параметров stunnel будет использовать 2004.12.04 19:09:15 LOG7[2405:134598656]: SO_REUSEADDR option
set on accept socket
файл конфигурации /usr/local/etc/stunnel/stunnel.conf. Запи- 2004.12.04 19:09:15 LOG7[2405:134598656]: ssmtp bound to 0.0.0.0:465
сываем в него следующие строки: 2004.12.04 19:09:15 LOG7[2405:134598656]: FD 9 in non-blocking mode
2004.12.04 19:09:15 LOG7[2405:134598656]: FD 10 in non-blocking mode
2004.12.04 19:09:15 LOG7[2406:134598656]: Created pid file /stunnel.pid
# Êëþ÷è è ñåðòèôèêàòû
cert = /usr/local/etc/stunnel/certs/mailserver.cert
key = /usr/local/etc/stunnel/certs/mailserver.key Теперь нужно снова посмотреть, что нам скажет коман-
да:
# Äèðåêòîðèÿ, âíóòðè êîòîðîé áóäåò ðàáîòàòü äåìîí
chroot = /var/tmp/stunnel
netstat -na | grep LISTEN
# Ôàéë pid. pid = /stunnel.pid
tcp4 0 0 *.465 *.* LISTEN
# Èìÿ ïîëüçîâàòåëÿ è ãðóïïà, ñ ÷üèìè ïðàâàìè áóäåò tcp4 0 0 *.993 *.* LISTEN
# ðàáîòàòü äåìîí tcp4 0 0 *.995 *.* LISTEN
setuid = stunnel tcp4 0 0 *.25 *.* LISTEN
setgid = stunnel tcp4 0 0 *.143 *.* LISTEN
tcp4 0 0 *.110 *.* LISTEN
# Óðîâåíü ïîäðîáíîñòè îòëàäî÷íûõ ñîîáùåíèé
debug = 7 Как видите, список портов, ожидающих входящие со-
# Èìÿ ôàéëà ïðîòîêîëèðîâàíèÿ единения, существенно увеличился.
output = /var/log/stunnel.log Самое время настроить почтовый клиент. В качестве по-
# Îïèñàíèå íàøèõ ñåðâèñîâ допытного кролика будет использоваться Microsoft Outlook
[pop3s] Express 6. Первым делом будут не самолеты, о которых по-
accept = 10.10.21.134:995
connect = 110 думали поклонники советской эстрады, а копирование сер-
тификата с почтового сервера и импортирование его в по-
[imaps]
accept = 993 чтовый клиент. С первым заданием, я думаю, вы и сами спра-
connect = 143 витесь. Подойдет любой способ, лишь бы файл mailserver.cert
[ssmtp]
accept = 465 оказался на Windows-машине. В Outlook Express задейству-
connect = 127.0.0.1:25 ем меню «Сервис → Параметры», затем выбираем вкладку

44
безопасность
«Безопасность», незамедлительно жмем на кнопки «Серти-
фикаты» и «Импортировать» и делаем все, как на следую-
щих снимках.

Ðèñóíîê 6
Ðèñóíîê 2

Ðèñóíîê 3

Ðèñóíîê 7

Ðèñóíîê 4
После этого в списке доверенных центров сертифика-
ции должно появиться имя нашего сервера.

Ðèñóíîê 8

Ðèñóíîê 5
На этом возню с сертификатом можно считать закон-
ченной. Переходим к настройке учетной записи. Тут тоже
нет ничего сложного: нужно всего лишь сделать все так,
как изображено на следующих снимках. Ðèñóíîê 9

№12(25), декабрь 2004 45


безопасность
почтовые клиенты, что были под рукой. Поэтому могу сме-
ло заявить: как и ожидалось, Mozilla Thunderbird 0.6 и Ximian
Evolution 2.0.2 работают с SSL вполне стабильно и быстро.
Единственное нарекание стоит адресовать Kmail 1.7.1, ко-
торый при использовании защищенных протоколов стал ше-
велиться в несколько раз медленнее, чем обычно. В част-
ности, на получение тестового письма из 500 байт у него в
среднем уходило примерно 45 секунд.
The Bat, любимый многими на постсоветских просторах,
тоже отлично работает в наших условиях. Тесты, описан-
ные ниже, проводились на версии 3.0.1.33. Впрочем, думаю,
что с большинством версий The Bat это тоже будет рабо-
тать. Итак, для того чтобы включить ночного вампира в нашу
связку, нужно установить все так же, как изображено на
Ðèñóíîê 10 следующем снимке. Удивляться тому, что вместо SSL при-
После этого вся принимаемая и отправляемая почта ходится выбирать TLS, не стоит. Главное, что такой подход
будет шифроваться с помощью SSL, а в файле /var/log/ работает.
stunnel.log будут появляться подобные надписи:
2004.12.04 22:40:01 LOG7[2406:134598656]: pop3s accepted FD=11 from
10.10.21.162:32872
2004.12.04 22:40:01 LOG7[2406:134598656]: FD 11 in non-blockingmode
2004.12.04 22:40:01 LOG7[2406:134600704]: pop3s started
2004.12.04 22:40:01 LOG5[2406:134600704]: pop3s connected from
10.10.21.162:32872
2004.12.04 22:40:02 LOG7[2406:134600704]: Relying on OpenSSL RSA Blinding.
2004.12.04 22:40:02 LOG7[2406:134600704]: SSL state (accept):
before/accept initialization
2004.12.04 22:40:02 LOG7[2406:134600704]: SSL state (accept):
SSLv3 read client hello A
2004.12.04 22:40:02 LOG7[2406:134600704]: SSL state (accept):
SSLv3 write server hello A
2004.12.04 22:40:02 LOG7[2406:134600704]: SSL state (accept):
SSLv3 write certificate A
2004.12.04 22:40:02 LOG7[2406:134600704]: SSL state (accept):
SSLv3 write server done A
2004.12.04 22:40:02 LOG7[2406:134600704]: SSL state (accept):
SSLv3 flush data
2004.12.04 22:40:02 LOG7[2406:134600704]: waitforsocket: FD=11, DIR=read
Ðèñóíîê 11
2004.12.04 22:40:02 LOG7[2406:134600704]: waitforsocket: ok
2004.12.04 22:40:02 LOG7[2406:134600704]: SSL state (accept):
При первой попытке соединения с сервером получаем
SSLv3 read client key exchange A следующее предупреждение. За исключением опечаток все
2004.12.04 22:40:02 LOG7[2406:134600704]: SSL state (accept):
SSLv3 read finished A в нем выглядит неплохо.
2004.12.04 22:40:02 LOG7[2406:134600704]: SSL state (accept):
SSLv3 write change cipher spec A
2004.12.04 22:40:02 LOG7[2406:134600704]: SSL state (accept):
SSLv3 write finished A
2004.12.04 22:40:02 LOG7[2406:134600704]: SSL state (accept):
SSLv3 flush data
2004.12.04 22:40:02 LOG7[2406:134600704]: 3 items in the session cache
2004.12.04 22:40:02 LOG7[2406:134600704]: 0 client connects (SSL_connect())
2004.12.04 22:40:02 LOG7[2406:134600704]: 0 client connects that finished
2004.12.04 22:40:02 LOG7[2406:134600704]: 0 client renegotiatations requested
2004.12.04 22:40:02 LOG7[2406:134600704]: 9 server connects (SSL_accept())
2004.12.04 22:40:02 LOG7[2406:134600704]: 9 server connects that finished
2004.12.04 22:40:02 LOG7[2406:134600704]: 0 server renegotiatiations requested
2004.12.04 22:40:02 LOG7[2406:134600704]: 1 session cache hits
2004.12.04 22:40:02 LOG7[2406:134600704]: 1 session cache misses Ðèñóíîê 12
2004.12.04 22:40:02 LOG7[2406:134600704]: 5 session cache timeouts
2004.12.04 22:40:02 LOG6[2406:134600704]: Negotiated ciphers: AES256-SHA Первым делом жмем «Просмотреть сертификат». И
SSLv3 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA1
2004.12.04 22:40:02 LOG7[2406:134600704]: FD 12 in non-blocking mode убеждаемся в том, что он действительно принадлежит нам.
2004.12.04 22:40:02 LOG7[2406:134600704]: pop3s connecting 127.0.0.1:110
2004.12.04 22:40:02 LOG7[2406:134600704]: Remote FD=12 initialized
2004.12.04 22:40:02 LOG7[2406:134600704]: Socket closed on read
2004.12.04 22:40:02 LOG7[2406:134600704]: SSL alert (write): warning:
close notify
2004.12.04 22:40:02 LOG7[2406:134600704]: SSL write shutdown
(output buffer empty)
2004.12.04 22:40:02 LOG7[2406:134600704]: SSL alert (read): warning: close notify
2004.12.04 22:40:02 LOG7[2406:134600704]: SSL closed on SSL_read
2004.12.04 22:40:02 LOG7[2406:134600704]: Socket write shutdown
(output buffer empty)
2004.12.04 22:40:02 LOG5[2406:134600704]: Connection closed:
12678 bytes sent to SSL, 10178 bytes sent to socket
2004.12.04 22:40:02 LOG7[2406:134600704]: pop3s finished (0 left)

Для того чтобы забирать письма с сервера, в данном


примере использовался POP3S, но смею вас уверить, что
IMAPS будет также надежно выполнять эту задачу. Вдоволь
наигравшись с Outlook Express, я принялся тестировать все Ðèñóíîê 13

46
безопасность
tcp wrapper. О первом способе написано достаточно много
статей, поэтому давайте посмотрим, как работать с tcp
wrapper. При обнаружении нового входящего соединения
inetd вызывает демона tcpd. Тот в свою очередь просматри-
вает файл /etc/host.allow и в зависимости от адреса вызыва-
ющей стороны принимает решение о том, что делать с со-
единением. Если соединение проходит через этот контроль,
то его передают демону, который будет в дальнейшем его
обслуживать. В отличие от межсетевого экрана, который для
принятия решений оперирует адресами и номерами портов,
tcpd работает с адресами клиентов и именами вызываемых
демонов. По умолчанию в /etc/hosts.allow описано разреше-
ние принимать данные от любых хостов. Это нам не подхо-
Ðèñóíîê 14 дит, а значит, надо удалить или закомментировать строку
ALL : ALL : allow и добавить в файл вот это:

cucipop : localhost 127.0.0.1 : allow


dkimap : localhost 127.0.0.1 : allow

После внесения изменений все должно работать как


часы. Впрочем, для достижения наилучшего эффекта ник-
то не мешает комбинировать настройки tcpd и запреты па-
кетов на межсетевом экране. После всех действий данные,
выдаваемые netstat, должны выглядеть так:
tcp4 0 0 *.465 *.* LISTEN
tcp4 0 0 *.993 *.* LISTEN
tcp4 0 0 10.10.21.134.995 *.* LISTEN
tcp4 0 0 127.0.0.1.25 *.* LISTEN
Ðèñóíîê 15
tcp4 0 0 *.143 *.* LISTEN
С помощью кнопки «Добавить к доверенным» заверша- tcp4 0 0 *.110 *.* LISTEN
ем процедуру. После некоторого количества тестов можно понижать
Отныне все операции с почтой будут шифроваться с уровень подробности отладочных сообщений, описываемый
помощью этого SSL-сертификата. Ради интереса загляни- переменной debug в файле /usr/local/etc/stunnel/stunnel.conf.
те в список доверенных сертификатов. На экране должно Приемлемым значением будет цифра 3.
появиться что-то вроде следующего снимка. Кстати, если нужно, чтобы stunnel автоматически запус-
кался после перезагрузки машины, не забудьте переиме-
новать /usr/local/etc/rc.d/stunnel.sh.sample в /usr/local/etc/rc.d/
stunnel.sh. В случае, когда у нас есть клиент, способный
самостоятельно работать с SSL, все выглядит довольно про-
сто. А вот что делать, если такового нет? Этот и многие
другие вопросы мы обсудим в следующей статье.

Уважаемые читатели!
Продолжается подписка на журнал
на I-полугодие 2005 года.

Ðèñóíîê 16 Если вы не успели подписаться


Итак, мы добились того, что данные нормально переда- на все шесть выпусков следующего полугодия,
ются по сети в защищенном виде. Теперь осталось сделать вы сможете приобрести недостающие номера
так, чтобы никто, кроме stunnel, не смог воспользоваться через интернет-магазины
старыми версиями наших сервисов. Для этого нужно, чтобы
стандартные демоны SMTP, POP3, IMAP принимали соеди-
нения только от 127.0.0.1. Соответственно, клиенты смогут
работать с сервером только через stunnel. В случае c postfix
все довольно просто: необходимо всего лишь установить пе-
ременную inet_interfaces = localhost в файле main.cf и пере-
запустить его. А вот с cucipop и dkimap4 есть два варианта
решения проблемы. Первый – запретить входящие соедине- Доставка почтой в любую точку России.
ния с помощью межсетевого экрана. Второй – использовать

№12(25), декабрь 2004 47


безопасность

ЖЕЛЕЗНЫЙ LOGIN:
ЛОМАЕМ ЗУБЫ ГРУБОЙ СИЛЕ

АЛЕКСАНДР ПОХАБОВ
48
безопасность
В этой статье будут рассмотрены решения проблем аутен- Установка
тификации и хранения сертификатов и ключей с помощью Так как в моем примере рассматривается USB-token от
hardware-ключей. В своей работе я использовал ОС GNU/ Aladdin (Aladdin eToken PRO 32K), ядро должно быть собра-
Linux, рассматриваемый дистрибутив – Gentoo Linux. Тем, но с поддержкой USB device filesystem.
кто работает с другими дистрибутивами, использующих
Pluggable Authentication Modules, не стоит расстраиваться, # USE='usb pam' emerge opensc
разница будет заметна лишь при установке необходимого
ПО. Убедимся, что установлено все необходимое для пос-
Предполагается, что мы имеем два хоста – рабочая стан- ледующей работы:
ция и удаленный сервер под управлением ОС Linux. С сер-
вером (назовем его «remote») работаем, используя sshd, # qpkg -I -v | grep open
на обоих хостах имеем привилегии суперпользователя. net-misc/openssh-3.8.1_p1-r1 *
Взглянем на проблемы, рассматриваемые в статье. dev-libs/openssl-0.9.7d-r1 *
dev-libs/opensc-0.8.1-r1 *
dev-libs/openct-0.5.0 *
Проблема первая
# qpkg -I -v | grep hotplug
Часто приходится сталкиваться с проблемой запоминания
паролей, запрашиваемых /bin/login. Все знают, что пароли sys-apps/hotplug-base-20040401 *
sys-apps/hotplug-20040401 *
должны иметь минимальную длину в восемь символов и
включать в себя символы верхнего и нижнего регистров, а Копируем пример конфигурационного файла opensc.conf:
также спецсимволы. Когда количество подконтрольных нам
серверов и пользовательских учетных записей на них воз- # cp /usr/share/opensc/opensc.conf.example /etc/opensc.conf
растает, удержать в памяти все пароли зачастую почти не-
посильная задача. Все принятые нормативные акты по ис- Сделаем openct и hotplug демонами, запускаемыми по
пользованию данных учетной записи запрещают записы- умолчанию:
вать пароли на бумаге, сохранять их в файлах и так далее.
Как же быть администратору, у которого десятки, а то и # rc-update add hotplug default
# rc-update add openct default
сотни серверов и на каждом время от времени приходится
регистрироваться с разными учетными данными? Запускаем их:

Проблема вторая # rc
Например, мы используем GnuPG, публичный ключ досту- * Starting input hotplugging... [ ok ]
пен многим, secret key защищен паролем (pass phrase), но * Starting pci hotplugging... [ ok ]
* Starting usb hotplugging... [ ok ]
он является не более чем файлом на диске. Если этот файл * Starting OpenCT... [ ok ]
похищен злоумышленником, он попытается подобрать вер-
ный pass phrase (brute force). Нет гарантии, что правиль- Чтобы не работать постоянно с учетной записью root,
ный пароль не будет найден в ближайшее время. добавим непривилегированного пользователя chiko в груп-
Электронные USB-ключи, такие как Aladdin eToken или пу openct и wheel (для возможности использования $ su):
Rainbow iKey, а также смарткарты решают эти проблемы.
USB-ключ или смарткарту удобно держать при себе, нельзя # usermod -G openct,wheel chiko
просто получить доступ к хранящимся в них ключам и сер-
тификатам, как в случае их хранения на жестком диске. Под- Далее работаем уже под непривилегированной учетной
бор PIN по словарю также обречен на провал, так как пос- записью.
ле трех (в моем примере) неудачных попыток PIN будет заб- Вставим USB-ключ и убедимся, что он распознан:
локирован.
Проект OpenSC основал Olaf Kirch. Он хотел написать # openct-tool list
библиотеку, предоставляющую структуру для написания 0 Aladdin eToken PRO
драйверов устройств чтения смарткарт по принципу «все в
одном», как для работы с устройствами, подключаемыми к Наш ключ имеет идентификатор 0 – запомним его. Иден-
последовательному порту, так и для USB-ключей. тификаторы ключа всегда присваиваются по возрастанию
К моменту написания данной статьи поддерживаются начиная с 0. Если ключ не распознан, проверьте исправ-
следующие устройства: ность USB-порта и наличие в ядре поддержки USB:
! KOBIL KAAN Professional
! Schlumberger e-gate # cat /ïóòü/ê/èñõîäíèêàì_ÿäðà/.config | grep CONFIG_USB_DEVICEFS
! Aladdin eToken PRO CONFIG_USB_DEVICEFS=y
! Eutron CryptoIdentity IT-SEC
! Rainbow iKey 3000 а также вывод mount:

Список поддерживаемого оборудования всегда можно # mount | grep usbfs


посмотреть на веб-сайте проекта OpenSC – http://opensc.org. usbfs on /proc/bus/usb type usbfs (rw)

№12(25), декабрь 2004 49


безопасность
Все готово для создания RSA-ключей и X509-сертифи- Certificate Details:
ката, приступим: Serial Number: 1 (0x1)
Validity
Not Before: Nov 4 09:48:50 2004 GMT
# /etc/ssl/misc/CA.pl –newca Not After : Nov 4 09:48:50 2005 GMT
Subject:
CA certificate filename (or enter to create) countryName = RU
stateOrProvinceName = KRAST
Making CA certificate ... localityName = Achinsk
Generating a 1024 bit RSA private key organizationName = AGK
........++++++ organizationalUnitName = SB
.................................++++++ commonName = Pokhabov Aleksandr
writing new private key to './demoCA/private/cakey.pem' emailAddress = chiko@example.com
X509v3 extensions:
Enter PEM pass phrase:
X509v3 Basic Constraints:
Verifying - Enter PEM pass phrase:
CA:FALSE
-----
Netscape Comment:
You are about to be asked to enter information that will be incorporated OpenSSL Generated Certificate
into your certificate request. X509v3 Subject Key Identifier:
What you are about to enter is what is called a Distinguished Nameor a DN. D9:F9:DB:F8:59:4C:72:86:15:13:B0:C0:FE:76:5C:93:C0:FD:38:B9
There are quite a few fields but you can leave some blank. X509v3 Authority Key Identifier:
For some fields there will be a default value, keyid:6B:2E:C8:03:71:2E:67:62:71:BF:A7:93:56:52:C2:FF:62:30BA:F0
If you enter '.', the field will be left blank. DirName:/C=RU/ST=KRAST/L=Achinsk/O=AGK/OU=SB/
----- ` CN=Pokhabov Aleksandr/emailAddress=chiko@example.com
Country Name (2 letter code) [AU]:RU serial:00
State or Province Name (full name) [Some-State]:KRAST
Locality Name (eg, city) []:Achinsk Certificate is to be certified until Nov 4 09:48:50 2005 GMT (365 days)
Organization Name (eg, company) [Internet Widgits Pty Ltd]:AGK Sign the certificate? [y/n]:y
Organizational Unit Name (eg, section) []:SB
Common Name (eg, YOUR name) []:Pokhabov Aleksandr 1 out of 1 certificate requests certified, commit? [y/n]y
Email Address []:chiko@example.com Write out database with 1 new entries
Data Base Updated
Signed certificate is in newcert.pem
Примечание: все будет временно храниться в директо-
рии ~/demoCA. Экспортируем наш закрытый ключ:
Создаем пароль:
# openssl rsa -in newreq.pem -out newkey.pem
# openssl x509 -in demoCA/cacert.pem -days 3650 ↵ Enter pass phrase for newreq.pem:
-out demoCA/cacert.pem -signkey demoCA/private/cakey.pem
writing RSA key
Getting Private key # /etc/ssl/misc/CA.pl -pkcs12
Enter pass phrase for demoCA/private/cakey.pem:
Enter pass phrase for newreq.pem:
# /etc/ssl/misc/CA.pl –newreq Enter Export Password:
Verifying - Enter Export Password:
Generating a 1024 bit RSA private key
......................++++++ Сертификат и ключи готовы, поместим их на наш USB-
............................................................................................................++++++
writing new private key to 'newreq.pem'
token. Смарткарты, как и USB-ключи используют для хра-
Enter PEM pass phrase: нения сертификатов и ключей файловую систему. Многие
Verifying - Enter PEM pass phrase:
производители в своих устройствах используют собствен-
-----
You are about to be asked to enter information that will be incorporated ные проприетарные механизмы хранения ключей и серти-
into your certificate request. фикатов, например различные имена директорий. OpenSC
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank. реализует PKCS #15 стандарт и имеет модуль эмуляции для
For some fields there will be a default value, несовместимых механизмов хранения. Необходимо отфор-
If you enter '.', the field will be left blank.
-----
матировать аппаратный ключ (параметры «-EC» – сокра-
Country Name (2 letter code) [AU]:RU щенные от «--erase-card» и «--create-pkcs15») перед его пер-
State or Province Name (full name) [Some-State]:KRAST вым использованием (внимание! вся информация на клю-
Locality Name (eg, city) []:Achinsk
Organization Name (eg, company) [Internet Widgits Pty Ltd]:AGK че будет уничтожена!):
Organizational Unit Name (eg, section) []:SB
Common Name (eg, YOUR name) []:Pokhabov Aleksandr # pkcs15-init -EC --label 'Chiko Test Card' --no-so-pin
Email Address []:chiko@example.com
Connecting to card in reader Aladdin eToken PRO...
Please enter the following 'extra' attributes Using card driver: Siemens CardOS
to be sent with your certificate request About to erase card.
A challenge password []:OurChallengePass
About to create PKCS #15 meta structure.
An optional company name []:AGK
Request (and private key) is in newreq.pem
Параметр --no-so-pin указывает, что не будет использо-
Подписываем: ваться Security Officer PIN. Это избавит вас от лишних зап-
росов Security Officer PIN, но так вы понижаете планку бе-
# /etc/ssl/misc/CA.pl –sign зопасности (владельцу ключа будут доступны возможнос-
ти создания новых профилей). Также, в случае утери PIN и
Using configuration from /etc/ssl/openssl.cnf
2745:error:0E06D06C:configuration file routines:NCONF_get_string:no value: PUK-кодов пользовательского профиля вы не сможете раз-
conf_lib.c:329:group=CA_default name=unique_subject блокировать пользовательский PIN. Выбор за вами.
Enter pass phrase for ./demoCA/private/cakey.pem:
Check that the request matches the signature
На следующем шаге создается пользовательский про-
Signature ok филь, выбираются PIN- и PUK-коды:

50
безопасность
# pkcs15-init -P --auth-id 01 --label 'CHIKOPIN' # grep -ir pam_opensc /var/log/messages
Connecting to card in reader Aladdin eToken PRO... Nov 11 16:43:00 workstation su(pam_opensc)[3374]:
Using card driver: Siemens CardOS Authentication successful for chiko at pts/0.
Found Chiko Test Card Извлечем ключ из USB:
About to store PIN.
New user PIN required.
Please enter PIN: # su chiko
Please type again to verify:
Unlock code for new user PIN required (press return for no PIN). No smart card present
Please enter PIN: su: Permission denied
Please type again to verify: Sorry.

Помещаем в аппаратный ключ только что созданный Теперь не только длина, но и само наличие пароля не
секретный ключ. На ошибку в пятой строке не обращаем обязательны. Можно удалить хэш пароля для пользовате-
внимания: ля chiko (и не только для него) из /etc/shadow, заменив его
на восклицательный знак.
# pkcs15-init -S newcert.p12 --format pkcs12 -a 01 --split-key При желании сделать аутентификацию только по hard-
Connecting to card in reader Aladdin eToken PRO... ware-ключу, /etc/pam.d/login должен быть соответствующе
Using card driver: Siemens CardOS изменен.
Found Chiko Test Card
About to store private key.
У меня он имеет вид:
error:23076071:PKCS12 routines:PKCS12_parse:mac verify failure
Please enter passphrase to unlock secret key: # more /etc/pam.d/login
Importing 2 certificates: auth required /lib/security/pam_opensc.so
0: /C=RU/ST=KRAST/L=Achinsk/O=AGK/OU=SB/ account required ↵
CN=Pokhabov Aleksandr/emailAddress=chiko@example.com /lib/security/pam_stack.so service=system-auth
1: /C=RU/ST=KRAST/L=Achinsk/O=AGK/OU=SB/ session required ↵
CN=Pokhabov Aleksandr/emailAddress=chiko@example.com /lib/security/pam_stack.so service=system-auth
User PIN required.
Please enter PIN: При попытке зарегистрироваться без наличия аппарат-
Всё! Ключ прошит. Распорядитесь ключами и сертифи- ного ключа в USB получим:
катом, находящимися в ~/demoCA, подобающим образом. workstation login: chiko
Не стоит забывать, что одна из преследуемых нами целей – No smart card present
исключить наличие сертификатов и закрытых ключей на Login incorrect
жестком диске. Если предполагается регистрация в системе под root по
Теперь мы готовы настроить PAM-аутентификацию, ис- # su, файл /root/.eid/authorized_certificates должен быть дос-
пользуя pam_opensc.so. тупен для чтения, иначе получим ошибку:

# mkdir ~/.eid # su
# pkcs15-tool -r 45 -o ~/.eid/authorized_certificates
Using card reader Aladdin eToken PRO
Connecting to card in reader Aladdin eToken PRO... Enter PIN1 [CHIKOPIN]:
Using card driver: Siemens CardOS No such user, user has no .eid directory or .eid unreadable.
Trying to find a PKCS#15 compatible card...
Found Chiko Test Card! Будьте осторожны при изменении файлов конфигура-
Reading certificate with ID '45'
ции PAM, если допустить ошибки конфигурирования, то есть
Регистрируемся как root и вносим необходимые изме- риск появления неприятного события – мы не сможем за-
нения в настройку PAM. Для использования # su без запро- регистрироваться как root, и придется загружаться с LiveCD,
са пароля членами группы wheel, имеющими аппаратный монтировать раздел с /etc и править конфигурационные
ключ, привожу пример конфигурационного файла: файлы PAM. Если в ваши планы ни в коем случае не вхо-
дит перезагрузка, предпочтительно сделать резервные ко-
# more /etc/pam.d/su пии файлов конфигурации PAM, и используя crontab, по рас-
auth sufficient /lib/security/pam_opensc.so
auth required /lib/security/pam_wheel.so use_uid писанию в определеное время вернуть их на место. Это
account required ↵ применимо в случае ограничения количества pid и tty для
/lib/security/pam_stack.so service=system-auth
session required ↵ root, если же таких ограничений нет, предпочтительнее ис-
/lib/security/pam_stack.so service=system-auth пользовать заранее открытую сессию. Подробнее о работе
с PAM можно узнать в страницах руководства по PAM.
Так как мы работали с учетной записью chiko (в вашем Внимание! Во всех домашних каталогах пользователей,
случае может быть другой), проверяем корректную работу с учетными данными которых мы будем регистрироваться
следующим образом: в системе, должен присутствовать корректный ~/.eid/
authorized_certificates.
# su chiko В моем примере до блокирования PIN дается три по-
Using card reader Aladdin eToken PRO пытки его ввода. Как быть, если после третьей неудачной
Enter PIN1 [CHIKOPIN]: попытки ввести PIN мы получили предупреждение о его бло-
$
кировке?
Работает! Вывод # ps auxf докажет, что нет никакого
обмана. Проверим логи: # su

№12(25), декабрь 2004 51


безопасность
Using card reader Aladdin eToken PRO Итак, у нас имеется готовый ключ и корректно собран-
Enter PIN1 [CHIKOPIN]: ный, настроенный и активный sshd на сервере remote. На
sc_pkcs15_verify_pin: Authentication method blocked
нем есть учетная запись пользователя ajwol и в его домаш-
Ведь даже после ввода корректного PIN мы не увидим нем каталоге имеется директория ~/.ssh . Чтобы зарегист-
ничего, кроме предупреждения о том, что он заблокирован. рироваться с его учетной записью, используя наш ключ, в
При создании пользовательского профиля на аппаратном домашней директории ajwol, должен присутствовать и быть
ключе, кроме PIN мы также указывали PUK-код, его необ- доступным для чтения файл ~/.ssh/authorized_keys, содер-
ходимо помнить именно для такого случая. Разблокирова- жащий в себе публичный ключ. Создадим его на машине, с
ние: которой будем регистрироваться:

# pkcs15-tool -u # ssh-keygen -D 0 > ~/authorized_keys

Connecting to card in reader Aladdin eToken PRO...


Using card driver: Siemens CardOS где «0» – идентификатор ключа.
Trying to find a PKCS#15 compatible card...
Found Chiko Test Card!
Скопируем этот файл в /home/ajwol/.ssh/authorized_keys
Enter PUK [CHIKOPIN]: на сервер remote:
Enter new PIN [CHIKOPIN]:
Enter new PIN again [CHIKOPIN]: # scp ~/authorized_keys ajwol@remote:.ssh
PIN successfully unblocked.

Если и PUK забыт и (в нашем примере) не использовал- Регистрируемся на удаленном сервере, используя па-
ся Security Officer PIN, не остается ничего кроме формати- раметр -I 0 (id ключа):
рования ключа, поэтому будьте максимально осторожны.
Первоочередная цель достигнута – dual factor authen- # ssh -I 0 -l ajwol remote
tication (наличие hardware-ключа и знание PIN) работает на Enter PIN for Private Key:
нашей системе. Невооруженным глазом заметно, что та- Last login: Fri Nov 12 08:20:15 2004 from grayhat
ajwol@remote ajwol $
кой способ аутентификации намного безопасней пары login/
password. Задача выполнена. Вы можете регистрироваться ста-
С регистрацией в локальной системе разобрались, рас- рым проверенным способом без ключа (не указывая пара-
смотрим регистрацию с помощью нашего аппаратного клю- метр -I), используя login/password, но, по желанию, можете
ча на удаленных серверах. также поиграть с настройками модулей PAM на сервере
Первое, что следует отметить, – openssh должен быть remote.
собран с поддержкой смарткарт. В Gentoo это делается Примечание: ~/.ssh/authorized_keys должен быть досту-
очень просто: пен во всех домашних каталогах пользователей, с логина-
ми которых будем регистрироваться удаленно.
# USE='X509 pam smartcard' emerge openssh Теперь не имеет значения длина пароля для логина ajwol
на хосте remote, пользователь даже не обязан знать его,
Пользователи других дистрибутивов применяют следу- хватит и PIN. Эти шаги можно проделать со многими уда-
ющее: ленными хостами, освободив себя от необходимости запо-
минания массы длинных паролей к множеству пользова-
./configure --with-opensc=/ïóòü/opensc тельских аккаунтов.
Задачи, поставленные в начале статьи, решены. В сле-
Как настроить и запустить sshd, думаю, объяснять нет дующих статьях об использовании аппаратных ключей бу-
необходимости. Никаких особенных настроек не требует- дут рассмотрены примеры их работы с Mozilla и Apache 2,
ся, за исключением вставки на рабочей станции в /etc/pam.d/ шифрование домашних каталогов.
sshd строки auth required /lib/security/pam_opensc.so. Вот как
он выглядит у меня: Ссылки:
! http://opensc.org
# more /etc/pam.d/sshd
auth required /lib/security/pam_opensc.so
! http://www.openssl.org/docs
accoun required pam_stack.so service=system-auth ! http://www.kernel.org/pub/linux/libs/pam
session required pam_stack.so service=system-auth ! man opensc

52
bugtraq

Повышение привилегий Множественные уязвимости в Linux-ядре


в Microsoft Windows Программа: Linux kernel 2.4 – 2.4.28, 2.6 – 2.6.9.
Программа: Microsoft Windows 2000 Advanced Server, Опасность: Высокая.
Microsoft Windows 2000 Datacenter Server, Microsoft Windows Описание: Обнаружено несколько уязвимостей в реализа-
2000 Professional, Microsoft Windows 2000 Server Microsoft ции IGMP-протокола в ядре Linux. Удаленный атакующий
Windows NT 4.0 Server Microsoft Windows NT 4.0 Server, может вызвать отказ в обслуживании. Локальный атакую-
Terminal Server Edition, Microsoft Windows Server 2003 щий может повысить свои привилегии на системе.
Datacenter Edition, Microsoft Windows Server 2003 Enterprise 1. Уязвимость существует в функции ip_mc_source(), кото-
Edition, Microsoft Windows Server 2003 Standard Edition, рая может быть вызвана с помощью пользовательского
Microsoft Windows Server 2003 Web Edition, Microsoft Windows API (IP_(UN)BLOCK_SOURCE, IP_ADD/DROP_SOURCE_
XP Home Edition, Microsoft Windows XP Professional. MEMBERSHIP, равно как и MCAST_(UN)BLOCK_SOURCE
Опасность: Высокая. и MCAST_JOIN/LEAVE_SOURCE_GROUP уровня соке-
Описание: Обнаружено несколько уязвимостей в ОС та SOL_IP). Существует возможность уменьшить зна-
Microsoft Windows. Локальный атакующий может повысить чение «sl_count» счетчика структуры «ip_sf_socklist» до
свои привилегии на системе. 0xffffffff (т.е. -1 для целочисленных), что приведет к за-
1. Уязвимость существует из-за некорректной проверки цикливанию вызова функции и вызовет зависание сис-
буфера при обработке данных, посланных через порт темы на несколько минут (в зависимости от скорости
LPC (Local Procedure Call). Локальный атакующий мо- обработки данных на системе). Эти действия приведут
жет с помощью специально сформированного запроса к тому, что вся память ядра, которая следует за kmalloc-
вызвать переполнение буфера и повысить свои приви- буфером, будет смещена на 4 байта, что должно приве-
легии на системе. сти к немедленной перезагрузке системы в обычных
2. Уязвимость существует при обработке identity токенов условиях и позволить локальному атакующему повысить
в службе LSASS. Локальный атакующий может повы- свои привилегии на системе.
сить свои привилегии на системе. 2. Из-за уязвимости, описанной выше, возможно прочитать
большое количество памяти ядра с помощью функций
Удачная эксплуатация этих уязвимостей дает атакую- ip_mc_msfget() и ip_mc_gsfget().
щему полный контроль над уязвимой системой. 3. Уязвимость функции igmp_marksources() из модуля
URL производителя: www.microsoft.com. network (которая вызывается в контексте группы запро-
Решение: Установите обновления: сов IGMP, полученных из сети) существует из-за недо-
1. Microsoft Windows NT Server 4.0 (requires Service Pack статочной проверки длины полученных параметров
6a): http://www.microsoft.com/downloa...AA8F-AF09-4839- IGMP-сообщений. Эта уязвимость реализуема только на
B9E8-BB218C7A8564. мультикаст-системах, где приложение создает многоад-
2. Microsoft Windows NT Server 4.0 Terminal Server Edition ресный сокет.
(requires Service Pack 6): http://www.microsoft.com/
downloa...A61F-C69F-403A-BD6A-EF3984BFA2B8. Удаленный атакующий может вызвать отказ в обслужи-
3. Microsoft Windows 2000 (requires Service Pack 3 or Service вании системы.
Pack 4): http://www.microsoft.com/downloa...A122-DDA4- URL производителя: kernel.org.
40B8-A7AF-9DDCC3870C38. Решение: Установите обновление c сайта производителя.
4. Microsoft Windows XP (requires Service Pack 1 or Service
Pack 2): http://www.microsoft.com/downloa...5D5C-3E4A- Выполнение произвольного кода в WINS
4F41-B81E-376AA1CD204F. Программа: Семейство ОС Microsoft Windows.
5. Microsoft Windows XP 64-Bit Edition (requires Service Опасность: Высокая.
Pack 1): http://www.microsoft.com/downloa...AE1E-0ABF- Описание: Обнаружено переполнение буфера в службе
4D31-BE12-3982C5146AE8/ wins.exe. Удаленный атакующий может выполнить произ-
6. Microsoft Windows XP 64-Bit Edition Version 2003: http:// вольный код на уязвимой системе.
www.microsoft.com/downloa...9AB9-36BF-4A90-BC37- Удаленный атакующий может послать специально сфор-
3B4FB6DCDF9A. мированный WINS-пакет на 42 TCP-порт, для того чтобы
7. Microsoft Windows Server 2003: http://www.microsoft.com/ изменить указатель и записать произвольный код в любую
downloa...97CB-E8F0-461F-B2D2-F1065229B64E. ячейку памяти. Удаленный атакующий может выполнить
8. Microsoft Windows Server 2003 64-Bit Edition: http:// произвольный код на уязвимой системе.
www.microsoft.com/downloa...9AB9-36BF-4A90-BC37- URL производителя: www.microsoft.com.
3B4FB6DCDF9A. Решение: Решения на данный момент не существует.

Составил Александр Антипов

№12(25), декабрь 2004 53


безопасность

ТЕНИ ИСЧЕЗАЮТ В ПОЛДЕНЬ

СЕРГЕЙ ЯРЕМЧУК
Известно, что появлению Интернета мы обязаны американ- Online Warfare (http://www.nswc.navy.mil/ISSEC/CID) является
скому министерству обороны. Поэтому интересными явля- результатом деятельности другого проекта Cooperative
ются и разрабатываемые в этом ведомстве технологии, Intrusion Detection Evaluation and Response (CIDER). CIDER
направленные на защиту информации. На страницах жур- в свою очередь был попыткой совместной разработки ин-
нала уже рассказывалось о проекте Security Enhanced Linux1 струментов для автоматического сбора и анализа потоков
(http://www.nsa.gov/selinux) от U.S. National Security Agency информации в целях обнаружения атак. Основные работы
(NSA), основной задачей которого является создание вы- ведутся Naval Surface Warfare Center, но свои усилия при-
сокозащищенных систем. Сегодняшняя статья о не менее ложили и другие не менее известные организации вроде
интересной системе, помогающей выявить проблемы в сети. NSWC Dahlgren, NFR, NSA и SANS. Некоторое время сис-
Разработанная в 1994 году, система обнаружения атак тема была закрыта, затем SHADOW так же стал свободно
SHADOW или Secondary Heuristic Analysis for Defensive доступен, так как основой являются программы с откры-

1
Яремчук С. SELinux. – Журнал «Системный администратор», №5, май 2003 г.

54
безопасность
тым исходным кодом. Одним из требований при разработ-
ке системы было обнаружение максимального количества
атак (насколько это возможно), с максимальной эффектив-
ностью и контролем большого количества сетей.
Это уникальная в своем роде разработка, она базиру-
ется на идее статистического анализа потоков информа-
ции. Проверяются только размеры пакетов, откуда они при-
ходят и куда направлены, без проверки внутреннего содер-
жания. Это означает, что SHADOW пытается отыскать в
первую очередь исследования, предшествующие атаке, а
не саму атаку. Поэтому такая система в принципе способ-
на выдать раннее предупреждение, что отличает ее от сиг-
натурных реализаций или определяющих аномалии в ре-
альном времени. Такой анализ потоков информации дела-
ет возможным работу системы при использовании различ-
ных форм шифрования трафика. Также эта система может
помочь отследить статистику работы компьютеров в сети, Ðèñóíîê 1
если же обнаружится неизвестный, то администратор по-
лучит предупреждение. Также администратор получает в Установка SHADOW
свои руки полезный инструмент, позволяющий визуально К сожалению, проект практически лишен нормальной до-
определить происходящее в сети. Собранная информация кументации. Имеется инструкция по установке да пара ссы-
поможет определиться со стратегией безопасности и бу- лок на устаревшие статьи с других сайтов. Инструкция по-
дет полезна при задании правил firewall. казывает процесс установки в пошаговом режиме, но при
этом в некоторых ключевых местах допущены мелкие, но
Архитектура SHADOW сбивающие и запутывающие ошибки, а о некоторых важ-
Основу проекта составляют tcpdump и libpcap, применяю- ных деталях там совсем ничего не сказано. Вся же конфи-
щиеся для сбора сетевых пакетов. Как уже говорилось, гурация производится исключительно вручную и требует
анализируются только заголовки без анализа информа- знаний архитектуры сетей, строения UNIX и особенностей
ции. Первоначально это может показаться не совсем ра- настройки некоторых Open Source-разработок. Поэтому это
зумно, так как некоторые атаки могут быть выявлены толь- занятие не тривиальное, требующее внимательности и зна-
ко при анализе содержимого, но для организаций, в кото- ний, и у новичков, скорее всего, возникнут трудности. Но
рых повышенное внимание к конфиденциальности инфор- вот что мне нравится, так это подход. Фактически пользо-
мации, – это, наверное, единственно разумный выход. Ведь ватель (или злоумышленник) в правильно настроенной си-
если злоумышленник либо лицо, на это не уполномочен- стеме обставлен флажками, за которые он выскочить не
ное, сможет получить доступ к данным базы собранных па- сможет при всем своем желании. Поэтому использование
кетов, то грош цена такой IDS. К тому же подобный подход SHADOW, даже при многочисленных сенсорах, вряд ли
требует меньшего количества ресурсов. может снизить общую защищенность сети и служить ис-
Сама же система состоит из датчиков, анализаторов и точником утечки информации или дать информацию о стро-
базы собранных пакетов (рис. 1). При этом не имеет значе- ении сети. С другой стороны, тем, кто хочет разобраться с
ния количество и место расположения датчиков, он просто безопасной настройкой и использованием всех упоминае-
собирает пакеты и по запросу переправляет их дальше ана- мых ниже сервисов, стоит для ознакомления почитать эту
лизатору. Их можно установить в зависимости от задач на инструкцию. Также одной из целей этой статьи является
внешнем интерфейсе, в DMZ или внутри сети. Установка вне показ варианта безопасного конфигурирования разных сер-
firewall – большой риск, поэтому разработчики старались мак- висов. В различной литературе не всегда можно найти от-
симально его уменьшить и подстраховаться от возможной веты на все вопросы.
компрометации датчика. Анализатор всегда должен нахо- Для датчиков и анализаторов подойдет любая UNIX-по-
диться за firewall. Его задача загрузить и оценить данные, добная система, под которую можно скомпилировать
собранные различными датчиками. Датчики и анализаторы libpcap, tcpdump, Perl, gzip, Apache и OpenSSH. Датчики и
для выборки данных и обслуживания соединяются посред- анализатор в целях безопасности должны находиться на
ством SSH. Для отбора событий, представляющих интерес, разных машинах. Хотя в принципе и возможно их разме-
используются фильтры и скрипты. Последние позволяют щение на одном компьютере, но подразумевается, что дат-
обнаруживать и некоторые медленные, т.е. растянутые по чик будет находиться в агрессивной среде, и поэтому в це-
времени атаки, а также распределенные атаки. Вся собран- лях безопасности рекомендуется раздельное размещение.
ная информация в дальнейшем будет выводиться админис- Девиз такой – никакого доверия датчикам. Датчик сконфи-
тратору в виде веб-страницы. Веб-интерфейс позволяет ис- гурирован так, чтобы работать только по SSH и только с
следовать информацию, полученную от различных датчиков, анализаторами. Датчики должны быть защищены в макси-
за различные периоды времени, с подробной информацией мально возможной степени. Чтобы сделать датчик невиди-
относительно отдельного узла или образца, а также созда- мым, рекомендуется использование двух сетевых плат.
вать готовые отчеты отправки для посылки в CIRT. Одна «невидимая» без IP-адреса будет собирать данные, а

№12(25), декабрь 2004 55


безопасность
другая, которую желательно поместить за firewall, будет пе- Построение датчика
редавать информацию анализаторам. Скачиваем архив размером чуть меньше 7 Мб. И создаем
Для включения режима невидимости в дистрибутиве каталоги для размещения. В документации предлагается
Red Hat и базирующихся на нем, файл /etc/sysconfig/network- /usr/local/, можно выбрать и другой, но при этом придется
scripts/ifcfg-eth0 (где eth0 – первая сетевая карта), должен указать новый путь во многих конфигурационных файлах.
содержать такие строки.
# mkdir -p /usr/local/SHADOW
DEVICE=eth0
ONBOOT= no
И распаковываем в него архив (tar xvfz /tmp/SHADOW-
В других дистрибутивах это будет скорее выглядеть не- 1.8.tar.gz). Все основные файлы подписаны при помощи
сколько иначе, например, в SuSE за загрузку отвечает пе- GPG, и при сомнении подпись можно проверить.
ременная STARTMODE.
Системные требования невысоки. Единственное, в боль- # gpg --verify some_file_name.sig
ших и активных сетях может понадобиться применение
SCSI-диска и больший объем жесткого диска (в основном Теперь в каталоге появится большое количество скрип-
для анализаторов) для хранения захваченной информации. тов и подкаталогов, о назначении некоторых станет ясно
В моем случае система на детекторы захватывала около по ходу изложения. В подкаталоге Doc вы найдете инструк-
2-3 Гб в день. Дополнительно рекомендуется выкинуть все цию по установке, в accessories – необходимые для работы
ненужное из ядра и отказаться от использования модулей утилиты libcap, tcpdump и openssh в rpm-пакетах и исход-
(ответ «N» в «Enable loadable module support.»). В докумен- ных кодах. Здесь последние версии этих утилит на момент
тации приведен пример .config-файла для перекомпиляции выпуска SHADOW (апрель 2003), поэтому можно оставить
ядра, желательно также обновить систему. имеющиеся в используемом дистрибутиве или взять более
В целях безопасности все процессы и каталоги на дат- новые версии с официальных сайтов. Еще один момент,
чиках и анализаторах работают от имени отдельного не- связанный с tcpdump. В RedHat, начиная с версии 6.2, при-
привилегированного пользователя. Поэтому его необходи- меняют патчи, расширяющие возможности, но изменяющие
мо будет завести перед установкой: выходной формат данных, с которыми анализатор работать
не может. Поэтому если вы не уверены, tcpdump лучше все-
# useradd -c "SHADOW" -u 666 -d /home/SHADOW shadow таки взять и установить с http://www.tcpdump.org. О настрой-
ке и работе этих утилит уже рассказывалось на страницах
Для защиты рекомендуется выключить все лишние сер- журнала, поэтому этот вопрос в статье затрагиваться бу-
висы на используемых компьютерах (получить их список мож- дет в объеме, необходимом для понимания процесса кон-
но, введя chkconfig --list). Для отключения запускаемых че- фигурирования SHADOW.
рез xinetd можно удалить все файлы в каталоге /etc/xinetd.d Теперь три скрипта в /usr/local/SHADOW/sensor требу-
или проверить наличие строки «disable = yes» в каждом из ют настройки. Это sensor_init.sh, std.ph и std.filter.
них. Вторым шагом сетевой защиты является использова- Скрипт sensor_init.sh используется для запуска датчика.
ние tcp_wrappers. Для чего в файле /etc/hosts.allow должны В нем переменная SENSOR_PATH должна указывать на
быть описаны адреса компьютеров, которым разрешен до- каталог, куда установлен сенсор, SENSOR_PARAMETER
ступ к тем или иным сервисам. Формат файла прост: указывает на файл, содержащий настройки датчика (без
расширения .ph). Для примера настроек, в каталоге имеет-
ñïèñîê_ñåðâèñîâ: ñïèñîê_ìàøèí [: êîìàíäà] ся файл std.ph. При необходимости можно использовать
сразу несколько сенсоров с индивидуальными конфигура-
Например: ционными файлами. Далее необходимо проверить наличие
файлов, прописанных в следующих переменных.
sshd: 192.168.2. : allow
ALL: 192.168.1.100,127.0.0.1 : allow # Source function library.
ALL: ALL : deny . /etc/rc.d/init.d/functions
# Source networking configuration.
В приложении «С», в инструкции по установке, вы най- . /etc/sysconfig/network
дете рекомендуемые опции для настройки iptables.
Документ описывает установку на Red Hat Linux (конк- В SuSE первую строку пришлось закомментировать.
ретно версии 8.0), именно под него разрабатывается Теперь копируем скрипт в положенное место.
SHADOW. Я использовал White Box Linux 3.0 и SuSE Linux
9.1. Если с первым проблем практически не было, что и не- # cd /usr/local/SHADOW/sensor
# cp sensor_init.sh /etc/rc.d/init.d/sensor
удивительно, ведь его основой служат исходные коды Red
Hat Enterprise Linux. То при установке в SuSE пришлось не- Это для RedHat, в других дистрибутивах путь, возмож-
много повозиться, в основном это касается путей к конфи- но, будет другим. Например, в SuSE команда будет такой:
гурационным файлам, которые пришлось изменять прак-
тически во всех скриптах. Это общие вопросы, теперь от- # cp sensor_init.sh /etc/rc.d/sensor
дельно рассмотрим особенности настройки датчика и ана-
лизатора. И добавляем скрипт в автозапуск.

56
безопасность
# chkconfig --add sensor запущена (в RedHat). Для этого достаточно его скопиро-
вать на свое место.
В файле std.ph (или как вы его назвали) также проверь-
те наличие файлов и каталогов, указанных в переменных. # cp /etc/apache2/httpd.conf /etc/apache2/httpd.conf.orig
# cp /usr/local/SHADOW/httpd/apache-conf ↵
В std.filter указываются параметры фильтра для захватывае- /httpd-2.0.40.basic /etc/apache2/httpd.conf
мых tcpdump-пакетов. По умолчанию в файле одна строка
ip, можно использовать и собственные конструкции вроде: В SuSE необходимо заменить пользователя и группу.

icmp and icmp[0] != 8 and icmp[0] != 0 User wwwrun


Group www

для icmp-пакетов или для NetBIOS: И дописать в файл строку:

ip and (port 137 or port 138 or port 139) Include /etc/apache2/sysconfig.d/loadmodule.conf

Сценарий sensor_driver.pl управляет сенсорами. Для того Можно как вариант использовать более подробный
чтобы собирать данные, каждый час во время работы сис- httpd-2.0.40.conf.
темы используется crontab-сценарий – sensor_crontab. Для Теперь готовим каталоги, в которых будут размещать-
реализации последней возможности копируем его в ката- ся результаты, выводимые пользователю.
лог /etc/cron.hourly. Этот сценарий содержит три строки.
Первые две предназначены для синхронизации времени по- # mkdir -p /home/shadow/html/tcpdump_results
# cd /usr/local/SHADOW/httpd/home
средством Network Time Protocol (NTP), последняя, которую # cp * /home/shadow/html
нужно раскомментировать, управляет запуском sensor_ # cp .htaccess /home/shadow/html
driver.pl. Параметры внутри, конечно же, можно подправить
(список серверов времени на http://www.ntp.org, плюс статья Не забудьте изменить адреса в .htaccess.
Михаила Платова «NTP – атомные часы на каждом столе»,
журнал «Системный администратор», № 4, апрель 2004 г.). # chown -R shadow:shadow /home/shadow

17 23 * * * /usr/sbin/ntpdate time-a.nist.gov Все, можно перезапускать веб-сервер.


18 23 * * * /sbin/hwclock --systohc
0 * * * * /usr/local/SHADOW/sensor/sensor_driver.pl std > ↵
/dev/null 2>&1 # /etc/init.d/httpd restart

Все, датчик готов, можно приступать к настройке ана- И теперь самое интересное и хлопотное – настройка
лизатора. ключей ssh. Для правильной работы OpenSSH, необходи-
мо, чтобы файл /home/shadow/.ssh/authorized_keys на де-
Настройка анализатора текторах содержал копии открытых ключей пользователя
Все первичные действия для анализаторов ничем не отли- shadow, которые были сгенерированы на анализаторе. Но
чаются от проводимых на датчиках. Но после распаковки поначалу необходимо, естественно, установить OpenSSH
архива на свое место внимания требуют совсем другие фай- на датчике и анализаторе. Если команда ls /etc/ssh не по-
лы. кажет наличия файлов вида ssh_host_key.pub, то ключи мож-
Также для работы потребуется установленный веб-сер- но сгенерировать автоматически, просто запустив сервер.
вер Apache любой версии (в целях безопасности обновле-
ние рекомендуемо всегда), желательно с модулями mod_ssl # /etc/init.d/sshd start
и mod_perl. Практически во всех дистрибутивах он есть.
Можно использовать веб-сервер параллельно основной ра- И не забудьте добавить запуск OpenSSH при загрузке
боте, но лучше только для работы с SHADOW. В каталоге системы.
/usr/local/SHADOW/httpd/apache-conf найдете примеры кон-
фигурационных файлов для версий 1.3 и 2.0, в том числе и # chkconfig --add sshd
оригинальный httpd.conf. Общим для всех файлов веб-сер-
вера, включая и .htaccess, является наличие для всех упо- Теперь необходимо, чтобы участвующие в работе узлы
минаемых в них каталогов, конструкций вида. узнали о публичных ключах друг друга. Есть много спосо-
бов, самый простой – соединиться с нужным узлом, и эта
Order deny,allow операция будет проделана автоматически. Разработчики
Deny from all
Allow from 172.21.122 считают более безопасным другой вариант. Монтируем дис-
Allow from localhost кету на датчике и копируем в нее все необходимые файлы.
Allow from 127.0.0.1

Не забудьте заменить адреса своими, иначе в доступе # mount -t vfat /dev/fd0 /mnt/floppy
# cd /etc/ssh
будет отказано. # cat ssh_host_key.pub ssh_host_dsa_key.pub ↵
В файле httpd-2.0.40.basic содержатся минимальные ssh_host_rsa_key.pub > /mnt/floppy/ssh_known_hosts
# umount /mnt/floppy
настройки веб-сервера, с которыми система уже может быть

№12(25), декабрь 2004 57


безопасность
Теперь вставляем дискету в дисковод анализатора и то можно продолжать дальше. Иначе проверьте имена фай-
копируем полученный файл на свое место. лов и права доступа к ним (700 для каталогов и 600 для фай-
лов). Тему безопасности соединений ssh можно продолжать
# mount -t vfat /dev/fd0 /mnt/floppy и далее. Например, используя инструкции ListenAddress и
# cd /etc/ssh
# cp /mnt/floppy/ssh_known_hosts . AllowUsers файла /etc/ssh/sshd_config можно еще более су-
# umount /mnt/floppy зить диапазон возможных действий пользователя.
Еще для полноценной работы необходимо установить
Теперь на анализаторе необходимо сгенерировать от nmap и сконфигурировать sudo, для того чтобы Apache мог
имени пользователя shadow ключи и скопировать их затем его запустить. Для этого редактируем файл /etc/sudoers,
на датчики. примерно так.

# su – shadow # Host alias specification


Host_Alias SHADOW = analyzer1.com, analyzer2.com

В некоторых дистрибутивах при создании пользовате- # Cmnd alias specification


Cmnd_Alias NMAP = /usr/bin/nmap
ля создается и каталог .ssh, если такого нет, создаем его.
# User privilege specification
# mkdir .ssh root ALL=(ALL) ALL
# chmod 700 .ssh apache SHADOW=NOPASSWD: NMAP
# cd .ssh
Кроме того, такой инструмент, как nmap, не рекоменду-
Генерируем ключи: ется раздавать кому попало, тем более что он запускается
от имени root. Поэтому некоторые скрипты, находящиеся
# /usr/bin/ssh-keygen -b 1024 -t dsa -f .id_dsa в /home/shadow/httpd/cgi-bin/privileged (в документации здесь
Generating public/private dsa key pair. тоже ошибка), защищены дополнительно файлом .htaccess
Enter passphrase (empty for no passphrase): с использованием директивы Satisfy (надо отметить, что в
Enter same passphrase again:
Your identification has been saved in .id_dsa.
большинстве советов по построению защищенного веб-сер-
Your public key has been saved in .id_dsa.pub. вера, о Satisfy почему-то забывают). Теперь при запросе из
The key fingerprint is: незащищенной сети от пользователя потребуют дополни-
89:e5:73:fa:37:78:9d:4b:7f:a7:10:49:eb:21:27:21 shadow@notebook
тельной авторизации.
# /usr/bin/ssh-keygen -b 1024 -t rsa -f .id_rsa2
AuthType Basic
Generating public/private rsa key pair. AuthName "Privileged SHADOW Users"
Enter passphrase (empty for no passphrase): AuthUserFile /usr/local/SHADOW/httpd/cgi-bin ↵
Enter same passphrase again: /privileged/nmap_pwd
Your identification has been saved in .id_rsa2. Satisfy any
Your public key has been saved in .id_rsa2.pub. require valid-user
The key fingerprint is: order deny,allow
b6:63:24:af:1e:c1:c2:3a:f5:cc:6b:cd:e0:b2:19:89 shadow@notebook deny from all
allow from 172.16.47
В этом моменте в документации допущена ошибка. По
умолчанию ключ rsa генерирует вторую версию, а в инст- Как видите, только пользователи сети 172.16.47 могут
рукции указано rsa2, что приводит к ошибке. Номер пока- запускать nmap без ввода пароля. Пароль можно создать
зывать необходимо как раз для первой версии. при помощи htpasswd, формат вызова которой:

# /usr/bin/ssh-keygen -b 1024 -t rsa1 -f .id_rsa1 htpasswd -c /path/to/store/password username

Generatingpublic/private rsa1 key pair.


Enterpassphrase (empty for no passphrase): Например:
Enter same passphrase again:
Your identification has been saved in .id_rsa1.
Your public key has been saved in .id_rsa1.pub. # htpasswd -c /usr/local/SHADOW/httpd/cgi-bin ↵
The key fingerprint is:
/privileged/nmap_pwd grinder
bf:9e:2e:44:3b:65:f1:2f:77:6b:23:bc:e6:a9:66:3f shadow@notebook
Опция -с создает файл заново, что нам сейчас и нужно,
# cat .id_dsa.pub .id_rsa2.pub .id_rsa1.pub > authorized_keys но при добавлении нового пользователя в уже используе-
# mount -t vfat /dev/fd0 /mnt/floppy/ мый файл вызывайте htpasswd без нее.
# cp authorized_keys /mnt/floppy/ В каталоге /usr/local/SHADOW/filters имеются шесть
# umount /mnt/floppy
фильтров, отдельно для каждого протокола, с подробными
И на датчиках: комментариями внутри: filter.getall.doc, goodhost.filter.doc,
icmp.filter.doc, ip.filter.doc, tcp.filter.doc, и udp.filter.doc.
# mount -t vfat /dev/fd0 /mnt/floppy Скрипт find_scan.pl использует файл filter.getall.doc для
# cd /home/shadow/.ssh
# cp /mnt/floppy/authorized_keys . определения внутренних сетей, fetchem.pl при помощи good
# umount /mnt/floppy host.filter.doc определяет свои mail, web servers и DNS-сер-
веры. После проверки адресов и внесения своих парамет-
Теперь можно попробовать зайти с анализатора по ssh ров убираем комментарии при помощи скрипта comment_
на датчик от имени пользователя shadow. Если получилось, strip.

58
безопасность
# /usr/local/SHADOW/comment_strip ip.filter.doc > ↵ В результате с указанного детектора будет скачан файл
/usr/local/SHADOW/filters/Site1/ip.filter с указанными данными и положен в /usr/local/SHADOW/data/
# /usr/local/SHADOW/comment_strip icmp.filter.doc > ↵
/usr/local/SHADOW/filters/Site1/icmp.filter Site1/Oct31/tcp.2004103120.gz. После первичного анализа в
# /usr/local/SHADOW/comment_strip tcp.filter.doc > ↵ домашнем каталоге веб-сервера будет создан каталог /home/
/usr/local/SHADOW/filters/Site1/tcp.filter
# /usr/local/SHADOW/comment_strip udp.filter.doc > ↵ shadow/html/tcpdump_results/Site1/Oct31 с несколькими фай-
/usr/local/SHADOW/filters/Site1/udp.filter лами, пользователю будет выводиться 2004103121.html.
# /usr/local/SHADOW/comment_strip goodhost.filter.doc > ↵
/usr/local/SHADOW/filters/Site1/goodhost.filter Для автоматизации этого процесса в работе использу-
#/usr/local/SHADOW/comment_strip filter.getall.doc > ↵ ется cron-файл analyzer_crontab.shadow
/usr/local/SHADOW/filters/Site1/filter.getall

После чего рекомендуется проверить работу фильтров. # Run fetchem to get SHADOW data files:
#
SHADOW_PATH=/usr/local/SHADOW
# tcpdump -i eth0 -n -F /usr/local/SHADOW/filters ↵ #
/Site1/tcp.filter 1 * * * * $SHADOW_PATH/fetchem.pl -l Site1
3 * * * * $SHADOW_PATH/fetchem.pl -l Site2 -debug
Если не получена ошибка «parse error», то фильтр мож- #
# Cleanup once per day.
но использовать в работе. #
Теперь осталось заглянуть в файл /usr/local/SHADOW/ 15 1 * * * $SHADOW_PATH/cleanup.pl -l Site1
24 1 * * * $SHADOW_PATH/cleanup.pl -l Site2
etc/shadow.conf, который содержит настройки для конкрет- #
ной системы. Надо отметить, что появление этого файла в # Collect statistics each night.
#
последних версиях SHADOW заметно упростило настрой- 1 0 * * * $SHADOW_PATH/stats/do_daily_stats.pl -l Site1
ку, теперь многие скрипты берут параметры отсюда. Ранее 1 3 * * * $SHADOW_PATH/stats/do_daily_stats.pl -l Site2
все параметры приходилось вбивать в каждый файл, что
приводило к ошибкам и затрудняло конфигурацию. Скрипт do_daily_scripts.pl из собранных за день данных
Проверьте, чтобы совпадали пути к утилитам и изме- собирает статистику, эти данные будут затем выводиться по
ните IP-адреса и e-mail на реальные. После этого его мож- нажатию кнопки «STATISTICS» в веб-браузере, cleanup.pl во
но скопировать в /etc или просто создать символическую избежание исчерпания свободного дискового места, полно-
ссылку. стью удаляет собранные на датчиках данные.
Теперь можно запускать браузер и пробовать соединить-
# ln –s /usr/local/SHADOW/etc/shadow.conf /etc/shadow.conf ся с веб-сервером, запустится два окна (рис. 2). В резуль-
тате экспериментов выяснилось, что левая панель инстру-
На сенсорах файл /etc/shadow.conf не используется, вме- ментов, запускаемая из /cgi-bin/tools.cgi не может быть нор-
сто него применяется файл Site.ph, лежащий в /usr/local/ мально отображаться всеми браузерами. Разработчики ука-
SHADOW/sites/. Файл примера, который найдете в этом ка- зали на совместимость практически со всеми браузерами
талоге, содержит настройки для первого детектора «Outside старых версий, но из всего имеющегося набора в SuSE 9.1
Network Perimeter» с именем Site1.ph. Для других детекто- комфортно работать можно было только в konqueror. Веро-
ров параметры $SITE и $SITE_LABEL и имя необходимо из- ятно, функции, прописанные в openwin.js, требуется пере-
менить, сверившись с /etc/shadow.conf. Кроме того, в пере- писать.
менных $SENSOR, $WEB_SERVER и @LOCAL_IP проставь-
те нужные параметры. Переменная $SENSOR_DIR=»/LOG»,
указывает на каталог, куда детекторы будут сохранять со-
бранные данные. Мне показалось, что-то вроде /var/shadow
с вынесеным в отдельный дисковый раздел /var будет бо-
лее правильно.
Теперь осталось проверить наличие всех каталогов, ука-
занных в переменных файлов /etc/shadow.conf на анализа-
торе и Site1.ph на всех детекторах и изменить пользовате-
ля/группу chown –R shadow:shadow, где это потребуется.
Все детекторы собирают информацию (не менее часа),
теперь можно попробовать ее получить и проанализировать.
Для начала лучше это проделать вручную.
Для получения информации с определенного детекто-
ра используется скрипт fetchem.pl. Основная задача кото-
рого получить с указанного детектора нужный файл, содер-
жащий собранные данные, создать для него подкаталог на Ðèñóíîê 2
анализаторе и выходной html-файл, сортировать данные, Если подойти к процессу настройки внимательно и твор-
заменить IP-адреса именами и еще много чего. Например, чески, то сейчас все должно работать. И только при жела-
данные за 21 час 31 октября 2004 года, с выводом логов в нии для удобства использования можно потихоньку подпра-
/tmp/fetchem.log можно получить так. вить скрипты под себя. В дальнейшем необходимо изучение
захваченной информации и подстройка фильтров, для того
# /usr/local/SHADOW/fetchem.pl -l Site1 -d 2004103121 -debug чтобы система получала только необходимое. Успехов.

№12(25), декабрь 2004 59


web

PHP-GTK

АНДРЕЙ УВАРОВ
Наверное, не стоит говорить о том, какое большое распро- интерфейса, будь то кнопка, поле ввода или окно. Все вид-
странение получил язык PHP в настоящее время. Преиму- жеты наследуются от абстрактного класса GtkWidget. Вид-
щественно он используется в веб-программировании (соб- жеты, которые могут содержать другие виджеты, называ-
ственно, как и задумывалось его создателем). Надёжно ются контейнерами. Предком контейнеров является Gtk
укрепившись на серверах, теперь не спеша переходит и на Container (сам же GtkContainer наследуется от GtkWidget).
десктопы. Об этом свидетельствуют как минимум две вещи: Сигналами называются сообщения, создаваемые вид-
появление поддержки ncurses и проект PHP-GTK, о чём и жетами. Сигналы используются для того, чтобы реагиро-
поговорим сегодня. вать на действия пользователя. Например, при появлении
Данная статья ориентирована на достаточно широкий курсора над кнопкой – экземпляром класса GtkButton, ге-
круг читателей, так как в ней не рассматриваются какие- нерируется сигнал «enter», а при нажатии – сигнал «clicked».
либо сложные аспекты. И может оказаться полезной как Сигналы наследуются. Для обработки сигналов использу-
для людей, желающих использовать PHP для написания ются callback-фукции. Не стоит путать сигналы с события-
приложений с графическим интерфейсом пользователя, вы- ми. Сигналы существуют в рамках GTK. А события являют-
полняющихся на клиентской стороне, так и для тех, кто про- ся отражением механизма событий в оконной системе.
сто желает начать изучение GTK. Итак, несколько «оглядевшись», можно приступить и к
PHP-GTK представляет собой расширение (модуль), по- примерам.
зволяющее создавать приложения с оконным графическим Напишем простейшее приложение.
интерфейсом. Стоит заметить, что данное расширение явля-
ется кроссплатформенным, речь идёт не только о *nix-подоб- <?php
if( !extension_loaded('gtk')) {
ных системах, но и Win. Всю документацию, исходные коды dl( 'php_gtk.' . PHP_SHLIB_SUFFIX);
или же откомпилированное расширение вы найдёте на сай- }
те проекта – gtk.php.net. $window = &new GtkWindow();
$window->show();
gtk::main();
Что такое GTK? ?>
Итак, что же такое GTK? На самом деле в данном случае
правильней было бы говорить о GTK+. GTK представляет
собой набор библиотек, используемых для создания окон-
ного графического интерфейса пользователя. Основным
отличием GTK+ от GTK является объектная ориентирован-
ность и наличие механизма сигналов. Аббревиатура GTK
означает – GIMP Toolkit, так как изначально разрабатыва-
лась для GIMP (в рамках одноименного проекта).
GTK+ основывается на двух основных понятиях: виджет
и сигнал.
Виджетом называется любой компонент графического

60
web
Разберём нашу программу «по косточкам».
Осуществляем проверку, загружено ли уже расшире-
ние, если нет, то загружаем его.

if( !extension_loaded('gtk')) {
dl( 'php_gtk.' . PHP_SHLIB_SUFFIX);
}
Особый интерес для нас в данном случае представляет
Создаём экземпляр класса GtkWindow – окно. И осуще- метод connect_object(). Данный метод осуществляет при-
ствляем его отображение вызовом метода show(). Если раз- соединение callback-функции к нужному сигналу. По свое-
мер окна не устанавливается в программе, как в нашем му назначению метод connect_object() сходен с connect()
случае, то используется размер по умолчанию – 200х200. (оба метода наследуются от GtkObject). Строку:
То же касается и заголовка окна, по умолчанию это имя
скрипта. $mainwindow->connect_object('destroy', Array('gtk', ↵
'main_quit'));
$window = &new GtkWindow(); Можно было бы заменить вызовом метода connect(), но
$window->show();
при этом нам было бы необходимо определять функцию
Вызовом gtk::main() мы «включаем» основной цикл про- для обработки сигнала «destroy».
граммы, то есть программа начинает слушать события. Без
этой строки наше приложение просто отобразило бы окно ...
function mainDestroy(){
и завершило на этом свою работу. gtk::main_quit();
Если вы попробуете закрыть приложение, то оно всё рав- }:
...
но не завершит работу, так как сигнал о завершении вы- $mainwindow->connect('destroy', 'mainDestroy');
полнения игнорируется ...
Для нормального завершения мы должны были обра-
батывать сигнал «destroy» объекта window. Первым параметром connect() является имя сигнала,
Итак, овладев основами, можно приступить к рассмот- вторым – имя callback-функции.
рению чуть более сложного примера. Напишем похожую программу, только уже на языке
Python.
<?php
if( !extension_loaded('gtk')) { sample.py:
dl( 'php_gtk.' . PHP_SHLIB_SUFFIX);
} import gtk
def button_click(text):
function button_click(&$text){ window = gtk.Window()
$window = &new GtkWindow(); window.set_title("Message")
// óñòàíàâëèâàåì çàãîëîâîê îêíà window.set_usize(200, 30)
$window->set_title('Message'); label = gtk.Label(text.get_text())
// óñòàíàâëèâàåì ðàçìåð îêíà window.add(label)
$window->set_usize(200, 30); window.show_all()
$label = &new GtkLabel($text->get_text()); def main_quit(object):
// äîáàâëÿåì îáúåêò â êîíòåéíåð gtk.main_quit()
$window->add($label);
$window->show_all(); mainwindow = gtk.Window()
} mainwindow.set_title("Hello world")
$mainwindow = &new GtkWindow(); mainwindow.connect("destroy", main_quit)
box = gtk.HBox()
// óñòàíàâëèâàåì çàãîëîâîê îêíà
$mainwindow->set_title('Hello world'); button = gtk.Button("press me")
$mainwindow->connect_object('destroy', Array('gtk', ↵
'main_quit')); entry = gtk.Entry()
// Ýòîò êëàññ ÿâëÿåòñÿ ñïåöèàëüíûì êîíòåéíåðîì, button.connect_object("clicked", button_click, entry)
// êîòîðûé ïîçâîëÿåò ðàçìåùàòü ïî ãîðèçîíòàëè
// äîáàâëåííûå â íåãî îáúåêòû. box.pack_start(entry)
$box = &new GtkHBox(); box.pack_end(button)
$button = &new GtkButton('press me'); mainwindow.add(box)
$entry = &new GtkEntry(); mainwindow.show_all()
$button->connect_object('clicked', 'button_click', ↵ gtk.main()
$entry);
Как видите, все различия заключаются в синтаксисе.
$box->pack_start($entry); Таким образом, освоив GTK, вам не составит труда писать
$box->pack_end($button); приложения практически на любом языке (разумеется, име-
ющем поддержку GTK).
$mainwindow->add($box);
На данный момент PHP-GTK существует только для
$mainwindow->show_all(); PHP4, но сейчас ведётся разработка следующей версии, в
gtk::main(); которой будет реализована поддержка GTK2 и PHP5, что
?> выглядит весьма перспективно.

№12(25), декабрь 2004 61


web

ОБРАБОТКА ПЕРЕАДРЕСОВАННЫХ
HTTP-ЗАПРОСОВ

АЛЕКСЕЙ МИЧУРИН
Согласитесь, что адрес http://site.ru/news/page2.html намного Как же в таком случае передать скрипту информацию?
удобнее, чем http://site.ru/cgi-bin/news/view.cgi?page=2. Пер- Ответ прост: через адрес. То есть мы рассмотрим приёмы,
вый из них гораздо легче запомнить, записать, продикто- позволяющие вызвать один и тот же скрипт, используя раз-
вать по телефону. В этой статье я хотел бы рассмотреть ные адреса; а также обсудим, как скрипт может получить
наиболее доступные приёмы перенаправления http-запро- информацию о том, по какому адресу он был вызван на
сов, делая упор на способы их обработки. этот раз. Обсудим, какие дополнительные возможности
обеспечивает такой способ управления скриптами.
Знакомство с проблемой Я буду ориентироваться не на администраторов серве-
Когда обсуждается некая обработка запроса, конечно, под- ров, полномочия которых практически безграничны, а на
разумевается, что на сервере есть какие-то активные эле- гораздо более многочисленную армию веб-мастеров, кото-
менты (программы, сценарии...), способные обработать зап- рые обычно пользуются готовым хостингом и имеют огра-
рос и обеспечить определённую «реакцию». Программы ниченный доступ к настройкам сервера. В этой статье мы
обычно получают необходимую информацию либо со стан- рассмотрим только те возможности, которые могут быть на-
дартного потока ввода (при запросе POST), либо из строки строены в файле .htaccess. Конечно, все описываемые при-
запроса, содержащейся в адресе справа от вопроситель- ёмы доступны и администраторам.
ного знака (при запросе GET). Эти механизмы передачи дан- Материал расположен в порядке от простого и широко
ных прекрасно известны, документированы, поддержаны в известного к более сложному. Читатели, частично знако-
неисчислимом множестве модулей и библиотек, и я не буду мые с вопросом, могут пропустить первые разделы, прак-
касаться их в настоящей статье. Я как раз хотел бы обсу- тически ничего не теряя.
дить другие возможности, позволяющие передать инфор-
мацию на сервер. То есть мы будем запускать сценарии, Несколько слов о файле .htaccess
формировать веб-страницы динамически, но не будем вклю- Файл .htaccess – это просто текстовый файл, который раз-
чать в адрес ни знака вопроса, ни строку запроса. Метод мещается в одной директории с веб-документами или сце-
POST мы тоже использовать не будем. нариями. То есть для его редактирования вполне достаточ-

62
web
но полномочий, позволяющих управлять содержимым сер- надлежит к категории Indexes и служит для определения
вера, коими обладают все владельцы виртуальных серве- файлов, выступающих в роли традиционного index.html.
ров. В нём хранятся конфигурационные директивы для сер- Если .htaccess, расположенный в некоторой директории,
вера. Действие этих директив распространяется на все фай- содержит инструкцию:
лы, принадлежащие директории, в которой расположен
.htaccess. Оно распространяется и на файлы всех вложен- DirectoryIndex index.html /cgi-bin/index.cgi
ных директорий, хотя вложенные директории могут, в свою
очередь, тоже содержать файлы .htaccess, которые пере- то при обращении к этой директории (без указания файла)
определят настройки, данные в родительских директори- сервер действует по следующему алгоритму: сперва он
ях. будет искать файл index.html, если таковой существует, то
Вообще говоря, использование имени .htaccess совсем будет выдан клиенту, в противном случае, сервер выдаст
не обязательно. Ваш сервер может быть настроен на ис- результат выполнения сценария /cgi-bin/index.cgi. Если и пос-
пользование другого имени вместо .htaccess. Настройка ледний не существует, то клиент получит сообщение об
производится инструкцией: ошибке 404.
Если разместить такой .htaccess сразу в двух директо-
AccessFileName èìÿ_ôàéëà риях /one/ и /two/, то и по адресу /one/, и по адресу /two/
клиент получит результат работы /cgi-bin/index.cgi (есте-
Но я никогда не видел, чтобы администраторы серве- ственно, если соответствующий index.html не найден). Мы
ров злоупотребляли этой возможностью и отступали от тра- вызываем один и тот же скрипт по разным адресам. Для
диций. получения такого эффекта может быть достаточно и од-
Какие настройки можно производить в .htaccess? От- ного подобного .htaccess. В нашем случае и для директо-
вет зависит от нравов администратора. Все конфигураци- рии /one/first/, и /one/second/ в отсутствии index.html будет
онные инструкции Apache, допустимые в .htaccess, поде- вызван /cgi-bin/index.cgi.
лены на категории. Администратор обычно даёт пользова- Для нас существенно то, что сценарий /cgi-bin/index.cgi,
телю только часть полномочий, разрешая ему изменять на- кроме обычных переменных окружения, получит две допол-
стройки, принадлежащие только к определённым катего- нительные: REDIRECT_URL и REDIRECT_STATUS. Первая
риям. Настройка этих ограничений производится инструк- будет содержать запрошенный адрес без имени сервера.
цией: Вторая – статус (обычно 200). То есть сценарий может «оп-
ределить», для какой директории он вызван, и совершить
AllowOverride ñïèñîê_êàòåãîðèé_èëè_All_èëè_None адекватные действия. Например, для одних директорий
(скажем, с html-документами) он может составлять индекс,
Поэтому прежде чем писать свой .htaccess, осведоми- придавая ему должный вид и включая в него только опре-
тесь у администратора сервера, какие категории настроек делённые файлы, а для других директорий (допустим, с гра-
вам доступны. фикой) он будет перенаправлять пользователя на первую
Существует всего пять категорий: страницу или выдавать сообщение об ошибке.
! AuthConfig – директивы, отвечающие за организацию Для полноты картины осталось только сказать о пере-
авторизованного доступа; менной REDIRECT_QUERY_STRING: она практически эк-
! FileInfo – директивы, управляющие обработкой ошибок вивалентна QUERY_STRING (о которой мы договорились
и отвечающие за информацию о языках и кодировках и не упоминать в этой статье). Если в директории /paper сер-
прочее; вера paper.ru в файле .htaccess находится инструкция:
! Indexes – команды, отвечающие за доступ к директори-
ям, то есть за те случаи, когда файл в адресе не указан; DirectoryIndex /cgi-bin/index.cgi
! Limit – команды, позволяющие ограничить доступ к ре-
сурсу, например, закрыть или открыть доступ для кли- то при запросе адреса http://paper.ru/paper?string=data или
ентов, имеющих определённые IP-адреса; http://paper.ru/paper/?string=data, как вы уже догадались, бу-
! Options – всего две инструкции Options и XBitHack; пер- дет вызван сценарий /cgi-bin/index.cgi, но наряду с перемен-
вая регламентирует работу механизмов CGI, SSI и ав- ной QUERY_STRING ему будет передана ещё и REDIRECT_
томатического составления листинга директорий; вто- QUERY_STRING. Обе они будут равны строке запроса, в
рая управляет реакцией SSI-процессора на атрибут нашем примере string=data. Разница между этими перемен-
файла «исполняемый» и используется весьма редко. ными состоит только в том, что когда строка запроса отсут-
ствует, переменная QUERY_STRING существует, но равна
Перейдём теперь к приёмам обработки адреса. Есте- пустой строке, а REDIRECT_QUERY_STRING не существу-
ственно, чтобы передать скрипту информацию через ад- ет вовсе.
рес, мы должны иметь возможность вызвать один и тот же
скрипт, используя разные адреса. Когда это происходит? Обработка ошибок.
Директива ErrorDocument
Директива DirectoryIndex Директива ErrorDocument принадлежит к категории FileInfo
Начнём наш экскурс с самой простой возможности, о кото- и предназначена для определения файлов, выдаваемых
рой знают практически все. Директива DirectoryIndex при- клиенту, если обработка запроса вызвала ошибку.

№12(25), декабрь 2004 63


web
Если добавить в .htaccess инструкцию: Авторизованный доступ
Прежде всего, скажу несколько слов о том, как активизи-
ErrorDocument 404 /cgi-bin/error.cgi ровать механизм авторизации. Чтобы ограничить доступ к
некоторой директории (и ко всем вложенным директори-
то при возникновении ошибки 404 будет выполнен сцена- ям), следует написать в .htaccess приблизительно такие ин-
рий /cgi-bin/error.cgi. Ему будут переданы четыре дополни- струкции:
тельные переменные:
! REDIRECT_REQUEST_METHOD – метод, которым был AuthType Basic
AuthName "By Invitation Only"
выполнен ошибочный запрос; AuthUserFile /home/www/paper/secret/passwd
! REDIRECT_STATUS – статус, его удобно использовать Require valid-user
в обработчиках, предназначенных для ошибок разного
типа, очевидно, в нашем случае статус может равнять- Все они, как вы, наверное, догадались, принадлежат к
ся только 404; категории AuthConfig.
! REDIRECT_URL – адрес несуществующего ресурса без Первая из них задаёт тип процедуры авторизации, на
имени сервера, этот адрес, например, можно использо- практике используется только Basic.
вать для регистрации в журнале; Вторая инструкция задаёт текст, который отобразит бра-
! REDIRECT_ERROR_NOTES – сообщение об ошибке. узер в окне диалога.

Кроме того, при наличии строки запроса создаётся пе-


ременная REDIRECT_QUERY_STRING, описанная выше.
Эти переменные удобно использовать не только в CGI-
сценариях, но в SSI-документах. Так, если создать .htaccess
с директивой:

ErrorDocument 404 /error/404.shtml

а в файле /error/404.shtml разместить следующий SSI-код: Директива AuthUserFile определяет файл с паролями
пользователей, который легко создать с помощью утилиты
<html> htpasswd, входящей в поставку Apache. Обратите внима-
<head><title>404</title></head>
<body> ние, файл паролей в целях безопасности можно (и жела-
<h1>Ôàéë íå íàéäåí!</h1> тельно!) размещать вне дерева директорий, доступных че-
Ôàéë <b><!--#echo var="REDIRECT_URL" --></b> áûë çàïðîøåí
ìåòîäîì <b><!--#echo var="REDIRECT_REQUEST_METHOD" --></b>. рез Web.
Çàïðîñ áûë ïåðåíàïðàâëåí íà ýòîò äîêóìåíò ñî ñòàòóñîì Директива Require регламентирует, какие пользовате-
<b><!--#echo var="REDIRECT_STATUS" --></b>. Ïîëíàÿ äèàãíîñòèêà
òàêîâà: <b><!--#echo var="REDIRECT_ERROR_NOTES" --></b>. ли или группы пользователей имеют доступ к данному ре-
(âñå èñïîëüçîâàííûå ïåðåìåííûå äîñòóïíû è â CGI) сурсу. В приведённом примере я позволил всем пользова-
</body>
</html> телям (конечно, только если они пройдут процедуру авто-
ризации) обращаться к файлам и подкаталогам директо-
то при обращении к несуществующему файлу /is_it_is.html рии, где размещён наш .htaccess.
клиент получит следующее сообщение: Техника ограничения доступа описана многократно, и я
не хотел бы повторять здесь других авторов. Для нас будет
важно то, что когда клиент работает в директории автори-
зованно, сервер создаёт ещё две дополнительные перемен-
ные: REMOTE_USER и AUTH_TYPE. Первая, как вы пони-
маете, содержит имя пользователя, вторая – тип авториза-
ции (Basic).
Если несколько пользователей имеют доступ к одному
ресурсу, то переменную REMOTE_USER удобно использо-
Ещё один пример обработчика ошибок мы увидим уже вать в системах хранения персональных настроек или для
в следующем разделе. А здесь осталось добавить, что ди- ведения журналов.
ректива ErrorDocument допускает и другой синтаксис: Эти переменные доступны и CGI-сценариям, и SSI-до-
кументам. Например, страница enter.shtml:
ErrorDocument 404 "Sorry. File not found
<html>
<head><title>Enter</title></head>
При возникновении ошибки пользователю будет выда- <body>
но указанное сообщение. Никакого перенаправления при <h1>Hi, <!--#echo var="REMOTE_USER" -->!</h1>
<p>(AUTH_TYPE=<!--#echo var="AUTH_TYPE" -->)</p>
этом не происходит, сервер сам генерирует соответствую- </body>
щий документ. </html>
Обратите внимание, закрывающей кавычки в указан-
ной директиве нет. Будет выглядеть так:

64
web
очень удобно. Для сценария, выполняемого на сервере, вир-
туальный путь принципиально ничем не отличается от стро-
ки запроса. Браузер же рассматривает его просто как путь,
нисколько не ощущая его виртуальности. Следуя по отно-
сительным ссылкам, браузер сохраняет путь (или его часть).
Пример такого сценария я и хочу привести:

После успешной авторизации переменные REMOTE_ #!/usr/bin/perl


USER и AUTH_TYPE передаются и обработчикам ошибок в use strict;
дополнение ко всем перечисленным выше, содержащим
my ($path, $script) = @ENV{qw/PATH_INFO SCRIPT_NAME/};
информацию об ошибке. Эта передача происходит даже в my ($color, $file) = $path=~m|/([^/]+)/([^/]+)$|;
том случае, если обработчик находится за пределами за- my $html_list='';
foreach (1..5) {
секреченной области (ошибка, конечно, должна произойти $html_list .= <<"TEXT";
в засекреченной области). <li><a href="$_.html">$_.html</a></li>
TEXT
При неудачной авторизации возникает ошибка 401, для }
которой тоже может быть назначен обработчик: print <<"TEXT";
Content-Type: text/html
ErrorDocument 401 /error/401.shtml <html>
<head><title>$script</title></head>
<body text="$color" bgcolor="white"
или link="$color" vlink="$color">
<h1>$file</h1>
<ul>$html_list</ul>
ErrorDocument 401 /cgi-bin/error.cgi </body>
</html>
TEXT
Мне осталось только заметить, что пользователи могут
быть объединены в группы. Для этого существует директи- Как видите, сценарий выделяет из строки PATH_INFO
ва AuthGroupFile. Так вот, информация о том, к какой груп- (сохранённой в переменной $path) два последние элемен-
пе принадлежит пользователь, не передаётся сценарию. та пути. Первая из этих частей интерпретируется как цвет
(сохраняется в переменой $color), вторая – как имя файла
Применение PATH_INFO (переменная $file), её можно было бы использовать для
Сервер Apache (и не только он) предоставляет интересную подключения определённого содержания.
возможность: если существует сценарий /cgi-bin/script.cgi, В цикле foreach мы создаём небольшое навигационное
то любой адрес вида /cgi-bin/script.cgi/location/doc.ext счита- меню с относительными ссылками.
ется вполне допустимым. При его обработке выполняется Разместим наш сценарий по адресу: /cgi-bin/pi.cgi.
сценарий /cgi-bin/script.cgi, а строка /location/doc.ext переда- Теперь по адресу /cgi-bin/pi.cgi/gray/3.html мы увидим:
ётся ему в переменной PATH_INFO. Кроме неё, создаётся
переменная PATH_TRANSLATED, содержащая как бы путь
к запрашиваемому файлу относительно корня файловой
системы сервера. Если в нашем примере предположить, что
документы сервера расположены в директории /www/docs,
то PATH_TRANSLATED будет содержать путь /www/docs/
location/doc.ext.
Путь, который был на самом деле запрошен клиентом,
как обычно, доступен через переменную REQUEST_URI.
Эта возможность находит самые разные применения.
Например, вы можете хранить все документы в кодировке
КОИ-8, и их CP-1251-модификации создавать «на лету»,
используя виртуальные пути вида /cgi-bin/koi2win.cgi/... Код страницы таков:
Единственное, что может доставить вам хлопоты – для ре-
ализации такого подхода потребуется все перекрёстные <html>
<head><title>/cgi-bin/pi.cgi</title></head>
ссылки в документах делать относительными, а все адреса <body text="gray" bgcolor="white"
графических и мультимедийных объектов, CSS-, JS-компо- link="gray" vlink="gray">
<h1>3.html</h1>
нент делать абсолютными. В противном случае вам при- <ul><li><a href="1.html">1.html</a></li>
дётся сделать сценарий koi2win.cgi чуть умнее, чем просто <li><a href="2.html">2.html</a></li>
<li><a href="3.html">3.html</a></li>
перекодировщик: он должен будет правильно (без искаже- <li><a href="4.html">4.html</a></li>
ний) передавать файлы, не являющиеся HTML-документа- <li><a href="5.html">5.html</a></li>
</ul>
ми и не требующие перекодировки, что, впрочем, не так уж </body>
сложно реализовать. </html>
Другое применение – хранение в виртуальном пути не-
кой информации (например, идентификатора сессии). Это Как видите, все ссылки «указывают» тоже на серые

№12(25), декабрь 2004 65


web
документы, вернее, они оставляют информацию о цвете не к двум расширениям (.html и .htm), а к одному-единствен-
(путь) неизменной. ному MIME-типу (text/html).
По адресу /cgi-bin/pi.cgi/red/1.html мы обнаружим анало- С содержимым .htaccess разобрались, давайте теперь
гичную структуру «красных документов». рассмотрим /cgi-bin/para.cgi.
Мысль, намеченную в этом сценарии, легко развить в Если разместить наш .htaccess в директории /action, то
необходимом русле. Единственное, о чем следует позабо- при обработке адреса /action/1.para будет выполнен сцена-
титься – это безопасность. Отсутствие хотя бы каких-ни- рий /cgi-bin/para.cgi, которому будет передан целый ряд
будь проверок в сценарии pi.cgi чревато только комичными дополнительных переменных:
ситуациями. Например, такой: /cgi-bin/pi.cgi/white/1.html. Но ! PATH_INFO – содержит адрес запрошенной «страницы»,
если ваш сценарий работает с файлами, то всегда надо в нашем случае это /action/1.para;
быть готовым к тому, что кто-то запросит документ /cgi-bin/ ! PATH_TRANSLATED – полное имя запрошенного фай-
koi2win.cgi/../../../etc/passwd. Конечно, конкретно эта атака ла, например, /www/docs/action/1.para;
наивна и, скорее всего, не представляет серьёзной опас- ! REDIRECT_STATUS – если всё в порядке, то 200. Обра-
ности, хотя всё зависит от того, как устроен koi2win.cgi. тите внимание: если файл 1.para не существует, то код
Замечу ещё, что всё сказанное справедливо не только всё равно будет 200. То есть сервер успешно запустил
для CGI-сценариев, но и для SSI-документов. При обраще- скрипт /cgi-bin/para.cgi, а существует ли файл 1.para –
нии к ресурсу /dir/doc.shtml/data (конечно, предполагается, проблема скрипта.
что doc.shtml не директория, а SSI-документ) будут также ! REDIRECT_URL – равно PATH_INFO.
созданы две дополнительные переменные PATH_INFO и
PATH_TRANSLATED. Если в адресе содержалась ещё и строка запроса (на-
Кроме того, SSI-процессором всегда создаётся перемен- пример, /action/1.para?subsection=3), то она не включается
ная DOCUMENT_PATH_INFO, которая пуста, если PATH_INFO в PATH_INFO и REDIRECT_URL, а попадает в переменные
и PATH_TRANSLATED отсутствуют. QUERY_STRING и REDIRECT_QUERY_STRING, о которых
Я думаю, что у внимательного читателя уже возник воп- уже говорилось в начале статьи. Если вам понадобится
рос, можно ли усовершенствовать наше решение так, что- полный адрес (вместе со строкой запроса), то ищите его,
бы избежать таких «неповоротливых» адресов, превратив, как обычно, в переменной REQUEST_URI.
например, /cgi-bin/pi.cgi/gray/3.html в /color/gray/3.html. От- Давайте разберём простенький пример. Пусть в файлах
вет на этот вопрос – да, возможно. Как раз это обсуждает- *.para будет храниться просто ASCII-текст, а скрипт /cgi-bin/
ся в следующем разделе. para.cgi будет формировать html-документы из ASCII-тек-
ста, производя с ним нехитрые преобразования: квотиро-
Магия Action вание небезопасных символов (&, «, >, <), добавление тега
Наверное, самые большие возможности предоставляет ди- <br> в конце каждой строки, добавление тегов, открываю-
ректива Action. С её помощью вы можете назначить скрипт- щих и закрывающих html-документ. Имя файла, который
обработчик для определённых типов файлов. следует обработать, сценарий будет брать из переменной
Приведу пример. Напишем в .htaccess следующие ди- PATH_TRANSLATED. Код сценария таков:
рективы:
#!/usr/bin/perl
AddHandler my-handler .para
Action my-handler /cgi-bin/para.cgi use strict;
my ($file, $url)=@ENV{qw/PATH_TRANSLATED REDIRECT_URL/};
Обе директивы, содержащиеся в этом файле, принад- open FH, "<$file" or die;
лежат к категории FileInfo. my $f=join('', <FH>);
close FH;
Первая – добавляет новый дескриптор файла, ассоции- $f=~s/\&/&amp;/g;
рованный с расширением .para. Теперь все файлы *.para $f=~s/\</&lt;/g;
$f=~s/\>/&gt;/g;
будут ассоциироваться с манипулятором my-handler. Осо- $f=~s/\"/&quot;/g;
бенностью директивы AddHandler является то, что она не $f=~s/\n/<br>\n/g;
чувствительна к регистру, то есть распространяется в рав- print <<"TEXT";
ной мере и на файлы *.Para, *.PARA, *.PaRa и так далее. Content-Type: text/html
Кроме того, символ «точка» необязателен. <html>
Вторая директива – Action – назначает действие, кото- <head>
<title>$url</title>
рое необходимо выполнять для файлов, ассоциированных </head>
с манипулятором my-handler. Теперь любое обращение к <body><h1>$url</h1>
$f
файлу *.para должно приводить к запуску сценария /cgi-bin/ </body>
para.cgi. </html>
TEXT
Для полноты картины добавлю, что вместо дескрипто-
ра можно использовать MIME-тип. В принципе, нетрудно Теперь, если в файле /action/1.para находится следую-
представить случаи, когда это будет удобно. Например, вы щие три строки:
поддерживаете публичный хостинг и хотите, чтобы ко всем
страницам ваших клиентов автоматически добавлялся бан- "AAA"
<BBB>
нер. Тогда проще привязать обработчик html-документов CCC

66
web
то по адресу /action/1.para браузер обнаружит результат Кстати, обратите внимание, в этом примере мы обо-
работы нашего скрипта: шлись без директивы AddHandler, так как обработчик при-
вязан к определённому MIME-типу.
<html> Теперь мы можем запустить pi.cgi двумя способами.
<head>
<title>/action/1.para</title> Первый – создать в директории /color директории, соот-
</head> ветствующие необходимым цветам, скажем gray и green.
<body><h1>/action/1.para</h1>
&quot;AAA&quot;<br> Теперь по адресу /color/green/1.html мы обнаружим систе-
&lt;BBB&gt;<br> му «зелёных» документов.
CCC
</body> Обратите внимание: если директория /color/cyan не су-
</html> ществует, то запрос документа /color/cyan/1.html вызовет
ошибку 404.
Выглядеть он будет так: Второй способ (внимание! это может быть потенциаль-
ная дыра в системе безопасности) – обратиться по адре-
су /color/hole.html/cyan/1.html. При этом директория hole.html
не должна существовать. Теперь наличие расширения .html
у директории hole.html приведёт к запуску pi.cgi, а он будет
рассматривать только последние две компоненты пути –
cyan и 1.html. Таким образом всё сработает «как часы». Так
можно получить документ любого цвета, если на сервере
не выполняется никаких проверок (как это сделано в на-
шем беспечном pi.cgi).
И снова обращаю ваше внимание на то, что если ди-
ректория /color/hole.html существует, а /color/hole.html/cyan
не существует, то по адресу /color/hole.html/cyan/1.html мы
Как видите, текст корректно преобразован в HTML-до- получим ошибку 404.
кумент.
Вы, наверное, уже обратили внимание на то, что опи- Ограничения
санный подход очень похож на подход предыдущего разде- Вы видите, что сценарий или скрипт можно запустить не
ла. Действительно, по адресу /cgi-bin/para.cgi/action/1.para мы только «напрямую» (как /cgi-bin/forum.cgi), но и многими
увидим почти то же самое. «Почти» потому, что в этом слу- другими вполне доступными способами. И кроме традици-
чае переменной REDIRECT_URL уже не будет. Если бы мы онно используемой переменной QUERY_STRING сервер
использовали вместо неё PATH_INFO, то скрипт вообще «не создаёт множество полезных переменных, но не забывай-
почувствовал» бы разницы, будь он вызван как /cgi-bin/ те, что использовать их надо не менее осторожно, чем
para.cgi/action/1.para или как /action/1.para. QUERY_STRING.
Но самое интересное – сходства этих двух подходов на Даже мои небольшие примеры не лишены изъянов. Так,
этом не заканчиваются. Оказывается, что и при Action-под- я довольно опрометчиво встраиваю в HTML-код, создавае-
ходе сервер не проверяет, существует ли файл на самом мый SSI-процессором, такие переменные, как PATH_INFO.
деле! При обращении к любому файлу с расширением .para Подобные переменные задаются удалённым пользовате-
(в директории /action), независимо от того, существует ли лем. Не исключено, что он сформирует такой адрес, по ко-
файл, вызывается скрипт /cgi-bin/para.cgi. Даже REDIRECT_ торому будет выдаваться HTML-документ, оснащённый вре-
STATUS сохраняет значение 200. То есть все замечания доносным JavaScript-кодом или иным аппаратом (иногда для
относительно безопасности остаются в силе. осуществления атаки оказывается достаточно считаных
А теперь вопрос «на засыпку»: как отреагирует сервер байт). Таким образом злоумышленник может скомбиниро-
на запросы /action/dir/1.para, /action/dir.para/1.para, /action/ вать адрес, наделяющий ваш ресурс вредоносными свой-
dir.para/1.text? ствами. Никогда нельзя использовать напрямую перемен-
Естественно, ни директории /action/dir, ни директории ные, значение которых определяется удалённо.
/action/dir.para не существует. Следует отметить, что описанный подход, будучи реа-
Правильный ответ таков: в первом случае возникнет лизован в чистом виде, практически полностью исключает
ошибка 404. Её бы не возникло, если бы /action/dir суще- возможность обработки форм. Это большой минус, но ни
ствовала, даже в том случае, если сам файл /action/dir/1.para один из перечисленных приёмов не лишает вас возможно-
отсутствовал. Во втором и третьем случаях будет как ни в сти использовать переменную QUERY_STRING или
чем не бывало вызван скрипт /cgi-bin/para.cgi. REDIRECT_QUERY_STRING и обрабатывать формы, от-
Теперь, я думаю, читатель догадывается, как можно правленные методом GET. Также к любому сценарию мож-
решить задачу, обозначенную в последнем абзаце преды- но обратиться методом POST. Но самое главное, существу-
дущего раздела. ет широкий круг задач, ограничивающихся организацией
Например, мы можем создать директорию /color и раз- навигации и не предполагающих работу с формами (от лент
местить в ней .htaccess со следующей директивой: новостей и фото-галерей до веб-каталогов). Именно в этих
случаях наиболее оправданно применение подходов, опи-
Action text/html /cgi-bin/pi.cgi санных в настоящей статье.

№12(25), декабрь 2004 67


hardware

ЗАПИСЬ ДИСКОВ CD-R/RW В LINUX


ЧАСТЬ 2

ВЛАДИМИР МЕШКОВ
Во второй части статьи рассмотрены примеры программ, Для определения текущих параметров устройства при-
выполняющих запись различной информации – музыкаль- меняется команда MODE SENSE, а для установки парамет-
ных треков и данных – на компакт-диск CD-R/RW. ров – команда MODE SELECT. Формат команды MODE
SENSE приведен на рисунке:
Запись информации на компакт-диск
Запись данных на компакт-диск
Рассмотрим пример программы, выполняющей запись дан-
ных на компакт-диск. Под термином «данные» понимается
файл в формате ISO (файл-образ), полученный при помо-
щи утилиты mkisofs или каким-либо другим способом.
Исходные тексты всех программ доступны на сайте жур-
нала (www.samag.ru/source).
Алгоритм выполнения операции записи данных на ком-
пакт-диск следующий: Ðèñóíîê 1. Ôîðìàò êîìàíäû MODE SENSE
! Определяются текущие параметры режима записи уст- Поле Page Code содержит код запрашиваемой страни-
ройства путем считывания страницы параметров режи- цы режимов, поле Allocation Length – размер считываемых
ма записи, код 0x05. данных.
! Устанавливаются требуемые значения полей страницы Формат команды MODE SELECT приведен на рисунке:
параметров режима записи – режим записи, тип блока
данных, режим трека (аудио/данные) и др.
! Из файла образа считываются блоки данных, и коман-
да WRITE_10 выполняет запись этих блоков в соответ-
ствующие сектора компакт-диска. Стартовый номер сек-
тора, с которого начинается запись, равен 0. Размер бло-
ка определяет значение поля «Data Block Type» страни-
цы параметров режима записи (см. рис. 15 первой час-
ти статьи).
! По окончании записи данных (достигнут конец файла-
образа) последовательно выполняются команды SYNC- Ðèñóíîê 2. Ôîðìàò êîìàíäû MODE SELECT
HRONIZE CACHE, CLOSE TRACK, CLOSE SESSION. По Поле Parameter List Length содержит размер передава-
команде SYNCHRONIZE CACHE все данные, подлежа- емого списка параметров в байтах. Бит PF (Page Format)
щие записи, переносятся на носитель, кэш устройства установлен в единицу. Это означает, что формат страницы
освобождается. Команда CLOSE TRACK завершает соответствует стандарту SCSI.
трек, а CLOSE SESSION завершает сессию – формиру- Запись данных на диск выполняет команда WRITE_10.
ет Lead-In и Lead-Out-области сессии (диска). Формат этой команды представлен на рис. 3.

68
hardware
__u8 isrc[16];
__u32 sh;
} __attribute__ ((packed)) wpm_t;

Определим глобальные переменные:

// äåñêðèïòîð ôàéëà sg-óñòðîéñòâà


int sg_fd;
// óêàçàòåëü íà äàííûå ñòðàíèöû ïàðàìåòðîâ ðåæèìà çàïèñè
wpm_t *wpm;
// çíà÷åíèå ïîëÿ Mode Data Length çàãîëîâêà Mode Parameter
// Header
__u16 mode_page_len = 0;
// ðàçìåð ñïèñêà ñòðàíèö ðåæèìà Mode Parameter List – 8
Ðèñóíîê 3. Ôîðìàò êîìàíäû WRITE_10
áàéò
Назначение полей: // çàãîëîâêà ñïèñêà Mode Parameter Header + 52 áàéòà ñàìîé
// ñòðàíèöû (ñì. ðèñ. 13-15, ïåðâîé ÷àñòè ñòàòüè)
! Logical Block Address – адрес блока, в который будет __u16 data_len = 60;
записана информация. // áëîê ïàìÿòè äëÿ ÷òåíèÿ ñïèñêà Mode Parameter List
__u8 data_buff[60];
! Transfer Length – число блоков для записи на диск.
Функция mode_sense() считывает страницу параметров
В команде SYNCHRONIZE CACHE используется только режима записи устройства:
нулевой байт – он содержит код операции 0x35.
Формат команды CLOSE TRACK/SESSION представлен int mode_sense()
{
на рисунке: __u8 mode_sense_cmd[10];
/* Óñòðîéñòâà ãîòîâî? */
if(test_unit_ready() < 0) exit(-1);
memset(data_buff, 0, 60);
// wpm óêàçûâàåò íà íà÷àëî ñòðàíèöû ïàðàìåòðîâ ðåæèìà
// çàïèñè
wpm = (void *)(data_buff + 8);
/* Ôîðìèðóåì êîìàíäûé ïàêåò */
memset(mode_sense_cmd, 0, 10);
// êîä êîìàíäû MODE SENSE
mode_sense_cmd[0] = MODE_SENSE_10;
// êîä ñòðàíèöû ïàðàìåòðîâ ðåæèìà çàïèñè
mode_sense_cmd[2] = 5;
Ðèñóíîê 4. Ôîðìàò êîìàíäû CLOSE TRACK/SESSION // ðàçìåð äàííûõ - 60 áàéò
mode_sense_cmd[8] = data_len;
Поле Close Function может принимать следующие зна-
чения: /* Ïîñûëàåì êîìàíäó óñòðîéñòâó */
if(send_cmd(mode_sense_cmd, 10, SG_DXFER_FROM_DEV, ↵
! 001b – закрыть трек, номер которого указан в поле Track data_buff, data_len, 20000) < 0) return -1;
Number.
/* Ðàçìåð ñ÷èòàííûõ äàííûõ – çíà÷åíèå ïîëÿ Mode Data Length
! 010b – закрыть последнюю незавершенную сессию, зна- * çàãîëîâêà ñïèñêà ñòðàíèö
чение поля Track Number игнорируется. */
memcpy((void *)&mode_page_len, data_buff, 2);
mode_page_len = __swab16(mode_page_len);
Следующая структура описывает формат страницы па- printf("Mode data length - %d\n", mode_page_len);
раметров режима записи (см. рис. 15 в первой части ста- /* Îòîáðàçèì òåêóùèå ïàðàìåòðû ðåæèìà çàïèñè */
тьи): // êîä ñòðàíèöû
printf("Page code - %d\n", wpm->page_code);
// ðàçìåð ñòðàíèöû
typedef struct { printf("Page length - %d\n", wpm->page_length);
__u8 page_code :6; // ðåæèì çàïèñè
__u8 rez :1; printf("Write type - %d\n", wpm->write_type);
__u8 ps :1; // òèï áëîêà äàííûõ
__u8 page_length; printf("Data block type - %d\n", wpm->dbt);
__u8 write_type :4; // ôîðìàò ñåññèè
__u8 test_write :1; printf("Session format - %d\n", wpm->s_format);
__u8 ls_v :1; // ðåæèì òðåêà (ïîëå Control Field)
__u8 BUFE :1; printf("Track mode - %d\n", wpm->track_mode);
__u8 rez1 :1;
__u8 track_mode :4; return 0;
__u8 copy :1; }
__u8 FP :1;
__u8 multises :2;
__u8 dbt :4; Установку требуемых параметров режима записи вы-
__u8 rez2 :4; полняет функция mode_select(). Этой функции мы переда-
__u8 link_size;
__u8 rez3; ем два параметра – тип блока данных (поле dbt структуры
__u8 hac :6; wpm_t) и тип информации, находящейся в треке (поле
__u8 rez4 :2;
__u8 s_format; track_mode структуры wpm_t):
__u8 rez5;
__u32 packet_size; int mode_select(__u8 dbt, __u8 track_mode)
__u16 apl; {
__u8 mcn[16];
__u8 mode_select_cmd[10];

№12(25), декабрь 2004 69


hardware
/* Îïðåäåëÿåì òåêóùèå ïàðàìåòðû ðåæèìà çàïèñè */ NIZE CACHE, CLOSE TRACK, CLOSE SESSION. Команду
if(mode_sense() < 0) exit(-1); SYNCHRONIZE CACHE формирует и посылает устройству
/* Óñòàíàâëèâàåì ïàðàìåòðû äëÿ çàïèñè äàííûõ */ функция sync_cache():
wpm->write_type = 1; // ðåæèì çàïèñè – TAO
wpm->dbt = dbt; // òèï áëîêà äàííûõ
wpm->s_format = 0; // îòêðûòèå íîâîé ñåññèè çàïðåùåíî int sync_cache()
wpm->track_mode = track_mode; // ðåæèì òðåêà {
__u8 flush_cache[10];
/* Óñòðîéñòâî ãîòîâî? */
if(test_unit_ready() < 0) exit(-1); if(test_unit_ready() < 0) exit(-1);

/* Ôîðìèðóåì êîìàíäíûé ïàêåò */ /* Ôîðìèðóåì è ïîñûëàåì êîìàíäó */


memset(mode_select_cmd, 0, 10); memset(flush_cache, 0, 10);
// êîä êîìàíäû MODE SELECT flush_cache[0] = SYNCHRONIZE_CACHE; // êîä êîìàíäû
mode_select_cmd[0] = MODE_SELECT_10;
// óñòàíàâëèâàåì â 1 áèò PF (Page Format) if(send_cmd(flush_cache, 10, SG_DXFER_NONE, ↵
mode_select_cmd[1] = 1 << 4; NULL, 0, 20000) < 0) return -1;

/* Â ïîëå Parameter List Header çàïèñûâàåì ðàçìåð áëîêà return 0;


* äàííûõ }
*/
data_len = 60; Закрывает трек функция close_track():
mode_page_len = __swab16(data_len);
memcpy((void *)(mode_select_cmd + 7), ↵
(void *)&mode_page_len, 2); int close_track()
{
/* Ïîñûëàåì óñòðîéñòâó êîìàíäó */ __u8 close_trk_cmd[10];
if(send_cmd(mode_select_cmd, 10, SG_DXFER_TO_DEV, ↵
data_buff, data_len, 20000) < 0) return -1; if(sync_cache() < 0) {
printf("Cannot synchronize cache\n");
/* Äëÿ êîíòðîëÿ îòîáðàçèì óñòàíîâëåííûå ïàðàìåòðû ðåæèìà return -1;
* çàïèñè }
*/
if(mode_sense() < 0) exit(-1); if(test_unit_ready() < 0) exit(-1);
return 0;
} /* Ôîðìèðóåì êîìàíäó çàêðûòèÿ òðåêà è ïîñûëàåì
* åå óñòðîéñòâó
*/
Запись данных на компакт-диск выполняет функция memset(close_trk_cmd, 0, 10);
write_iso(). Входные параметры функции – указатель на close_trk_cmd[0] = 0x5B; // êîä êîìàíäû CLOSE TRACK
close_trk_cmd[2] = 1; // ôëàã çàêðûòèÿ òðåêà
строку, содержащую имя файла-образа: close_trk_cmd[5] = 1; // íîìåð òðåêà, îí ó íàñ îäèí

int write_iso(__u8 *file_name) if(send_cmd(close_trk_cmd, 10, SG_DXFER_NONE, ↵


{ NULL, 0, 20000) < 0) return -1;
int in_f; return 0;
__u8 write_cmd[10];
__u8 write_buff[CD_FRAMESIZE]; }
__u32 lba = 0, lba1 = 0;
Функция close_session() закрывает текущую сессию:
if(test_unit_ready() < 0) exit(-1);
/* Îòêðûâàåì ôàéë-îáðàç */ int close_session()
in_f = open(file_name, O_RDONLY, 0600); {
memset(write_buff, 0, CD_FRAMESIZE); __u8 close_sess_cmd[10];
/* Öèêë ÷òåíèÿ áëîêîâ äàííûõ èç ôàéëà. if(test_unit_ready() < 0) exit(-1);
* Ðàçìåð áëîêà – 2048 áàéò
*/ memset(close_sess_cmd, 0, 10);
while(read(in_f, write_buff, CD_FRAMESIZE) > 0) { close_sess_cmd[0] = 0x5B; // êîä êîìàíäû CLOSE SESSION
close_sess_cmd[2] = 2; // ôëàã çàêðûòèÿ òåêóùåé ñåññèè
/* Ôîðìèðóåì êîìàíäíûé ïàêåò */
memset(write_cmd, 0, 10); if(send_cmd(close_sess_cmd, 10, SG_DXFER_NONE, ↵
write_cmd[0] = WRITE_10; // êîä êîìàíäû NULL, 0, 60000) < 0) return -1;
write_cmd[8] = 1; // êîëè÷åñòâî ñåêòîðîâ äëÿ çàïèñè
return 0;
printf("%c", 0x0D); }
printf("lba - %6d", lba1);

/* Àäðåñ áëîêà äëÿ çàïèñè */ После того как данные записаны, извлекаем компакт-
lba = __swab32(lba1); диск из привода, послав устройству команду START/STOP
memcpy((write_cmd + 2), (void *)&lba, 4);
lba1 += 1; UNIT (см. [5]):
/* Ïîñûëàåì óñòðîéñòâó êîìàíäó */ void eject_cd()
if(send_cmd(write_cmd, 10, SG_DXFER_TO_DEV, write_buff, ↵ {
CD_FRAMESIZE, 20000) < 0) return -1;
} __u8 start_stop_cmd[6];

printf("\n"); memset(start_stop_cmd, 0, 6);


return 0; start_stop_cmd[0] = 0x1B; // êîä êîìàíäû START/STOP UNIT
start_stop_cmd[4] = 2; // èçâëå÷ü êîìïàêò-äèñê
}
send_cmd(start_stop_cmd, 6, SG_DXFER_NONE, NULL, 0, 20000);
По окончании записи данных необходимо, как было уже
return;
сказано выше, послать устройству три команды: SYNCHRO- }

70
hardware
Имя файла-образа передается главной функции про- нового трека (таблица 4 первой части статьи). Считать ин-
граммы в виде параметра. Функция main() выглядит следу- формацию о координатах трека можно при помощи коман-
ющим образом: ды READ TRACK INFORMATION. Формат команды:

int main(int argc, char **argv)


{
/* Ïðîâåðÿåì íàëè÷èå âõîäíûõ ïàðàìåòðîâ */
if(argc != 2) {
printf("\n\tUsage: write_iso [ISO-image]\n\n");
return 0;
}

/* Îòêðûâàåì ôàéë sg-óñòðîéñòâà */


if((sg_fd = open(SG_DEV, O_RDWR)) < 0) {
perror("open");
return -1;
}
Ðèñóíîê 6. Ôîðìàò êîìàíäû READ TRACK INFORMATION
/* Óñòàíàâëèâàåì ïàðàìåòðû ðåæèìà çàïèñè äàííûõ:
* òèï áëîêà äàííûõ dbt = 8 – ôîðìàò áëîêà Mode 1, ðàçìåð Значение поля Address/Number Type определяет содер-
* áëîêà 2048 áàéò;
* òèï èíôîðìàöèè, íàõîäÿùåéñÿ â òðåêå track_mode = 4 – жание поля Logical Block Address/Track/Session Number. Если
* òðåê ñîäåðæèò äàííûå. Address/Number Type = 01b, то устройство вернет блок ин-
*/
mode_select(8, 4); формации о треке, номер которого находится в поле Logical
Block Address/Track/Session Number. Формат блока инфор-
/* Âûïîëíÿåì çàïèñü äàííûõ íà êîìïàêò-äèñê */
if(write_iso(argv[1]) < 0) { мации о треке представлен на рис. 7.
printf("Cannot write image %s\n", argv[1]); Из всего многообразия данных, находящихся в блоке,
return -1;
} нас интересует только поле Track Start Address. Это поле
содержит стартовый адрес трека, с этого адреса выполня-
/* Çàêðûâàåì òðåê, ñåññèþ è èçâëåêàåì êîìïàêò-äèñê èç ïðèâîäà*/
close_track(); ется запись трека. Назначение остальных полей приведе-
close_session(); но в спецификации SCSI MMC-4 ([1]).
eject_cd();
Функция reserv_track() выполняет резервирование на
close(sg_fd); компакт-диске пространства для трека. Входной параметр
return 0;
} функции – размер трека в блоках.

Полный текст программы записи ISO-образа на компакт-


диск находится в файле SG/iso_write.c.

Запись аудиоданных
Алгоритм записи аудиоданных практически не отличается
от приведенного ранее алгоритма записи данных. Но так
как в одной сессии теперь будет находиться несколько тре-
ков, то при записи аудиотрека на компакт-диск необходи-
мо будет знать стартовый адрес трека. Этот адрес можно
вычислить самостоятельно, можно определить его как ад-
рес невидимого, незавершенного трека (invisible, incomplete
track) либо предварительно зарезервировать на компакт-
диске пространство для каждого трека.
Резервирование пространства для трека выполняет ко-
манда RESERVE TRACK. Формат этой команды представ-
лен на рисунке:

Ðèñóíîê 5. Ôîðìàò êîìàíäû RESERVE TRACK


В поле Reservation size указывается размер трека в бло-
ках. Каждый вызов команды RESERVE TRACK модифици-
рует PMA-область, добавляя в нее запись о координатах Ðèñóíîê 7. Ôîðìàò áëîêà èíôîðìàöèè î òðåêå

№12(25), декабрь 2004 71


hardware
int reserv_track(__u32 track_size) /* Îòêðûâàåì ôàéë óñòðîéñòâà */
{ sg_fd = open(SG_DEV, O_RDWR);
__u8 reserv_track_cmd[10];
__u32 size = 0; /* Óñòàíàâëèâàåì ïàðàìåòðû ðåæèìà çàïèñè:
* òèï áëîêà äàííûõ dbt = 0 – «ñûðûå» äàííûå, ðàçìåð áëîêà
if(test_unit_ready() < 0) exit(-1); * 2352 áàéòà;
* track_mode = 0 – òðåê ñîäåðæèò àóäèîäàííûå.
/* Ôîðìèðóåì êîìàíäíûé ïàêåò */ */
memset(reserv_track_cmd, 0, 10); mode_select(0, 0);
reserv_track_cmd[0] = 0x53; // êîä êîìàíäû RESERVE TRACK
/* Ñ÷èòûâàåì èíôîðìàöèþ èç PMA */
/* Çàïîëíÿåì ïîëå Reservation size */ printf("Display PMA:\n");
size = __swab32(track_size); read_pma();
memcpy((void *)(reserv_track_cmd + 5), (void *)&size, 4);
/* Öèêë çàïèñè òðåêîâ íà äèñê */
if(send_cmd(reserv_track_cmd, 10, SG_DXFER_NONE, ↵ for(i = 1; i < argc; i++) {
NULL, 0, 20000) < 0) return -1;
/* Ïðåîáðàçóåì ôàéë èç ôîðìàòà Ogg Vorbis â WAV
/* C÷èòûâàåì PMA */ * (áåç çàãîëîâêà). Èìÿ âûõîäíîãî ôàéëà – track.cdr
read_pma(); */
return 0; ogg_decoder(argv[i]);
}
/* Îïðåäåëÿåì ðàçìåð ôàéëà track.cdr â áàéòàõ*/
memset((void *)&s, 0, sizeof(struct stat));
Чтение информации о треке выполняет функция stat("./track.cdr", &s);
read_track_info(). Параметр функции – номер трека. Возвра- /* Ðàçìåð ôàéëà â áëîêàõ */
щаемое значение – стартовый адрес трека. track_size = s.st_size / CD_FRAMESIZE_RAW;
printf("File size - %u\n", s.st_size);
printf("Sectors in file - %u\n", track_size);
__u32 read_track_info(int trk_num) printf("Reserve track #%d\n", i);
{
__u8 read_track_info_cmd[10]; /* Ðåçåðâèðóåì ïðîñòðàíñòâî äëÿ òðåêà */
__u8 data_buff[40]; // áëîê èíôîðìàöèè î òðåêå reserv_track(track_size);
__u16 len = 40; // ðàçìåð áëîêà
__u32 lba = 0; /* Îïðåäåëÿåì ñòàðòîâûé àäðåñ òðåêà */
start_lba = read_track_info(i);
if(test_unit_ready() < 0) exit(-1); printf("Start LBA for track #%d - %u\n", i, start_lba);
/* Ôîðìèðóåì êîìàíäíûé ïàêåò */ /* Çàïèñûâàåì â òðåê àóäèîäàííûå. Íîìåð ñòàðòîâîãî áëîêà
memset(data_buff, 0, 40); * ðàâåí start_lba
memset(read_track_info_cmd, 0, 10); */
read_track_info_cmd[0] = 0x52; total_sectors = write_audio("./track.cdr", start_lba);
// ïîëå Address/Number Type = 01b if(total_sectors == 0) return -1;
read_track_info_cmd[1] = 1;
/* Çàêðûâàåì òðåê */
read_track_info_cmd[5] = trk_num; // íîìåð òðåêà close_track(i);
}
len = __swab16(len);
memcpy((void *)(read_track_info_cmd + 7), (void *)&len, 2); /* Öèêë çàïèñè òðåêîâ çàâåðøåí. Çàêðûâàåì ñåññèþ */
close_session();
if(send_cmd(read_track_info_cmd, 10, SG_DXFER_FROM_DEV, ↵
data_buff, 40, 20000) < 0) { /* Óäàëÿåì ôàéë track.cdr è èçâëåêàåì äèñê èç ïðèâîäà */
printf("Cannot read track #%d info!\n", trk_num); unlink("./track.cdr");
exit(-1); eject_cd();
}
close(sg_fd);
/* Èç áëîêà èíôîðìàöèè î òðåêå ñ÷èòûâàåì äàííûå î ðàçìåðå return 0;
* òðåêà (ïîëå Track Size ) }
*/
memcpy((void *)&lba, (void *)(data_buff + 24), 4); Преобразование файла из формата Ogg Vorbis в WAV
printf("Track #%d size - %u sectors\n", ↵
trk_num, __swab32(lba)); выполняет функция ogg_decoder(). Входной параметр функ-
ции – имя файла в формате Ogg Vorbis. Для конвертирова-
/* Ñòàðòîâûé àäðåñ òðåêà */
memcpy((void *)&lba, (void *)(data_buff + 8), 4); ния используются библиотека libvorbis (http://www.vorbis.org).
return __swab32(lba); На выходе получается файл track.cdr в формате WAV, но
}
без RIFF-заголовка.
Рассмотрим главную функцию программы записи аудио-
данных. Входные параметры – список файлов в формате void ogg_decoder(__u8 *file_name)
{
Ogg Vorbis. __u8 pcmout[8192];
FILE *f;
int main(int argc, char **argv) int out;
{ OggVorbis_File vf;
int current_section;
int i = 1;
struct stat s;
__u32 start_lba = 0, total_sectors = 0; printf("\nDecoding file %s..", file_name);
f = fopen(file_name,"r");
__u32 track_size = 0; out = open("./track.cdr", O_CREAT|O_RDWR|O_TRUNC, 0600);
/* Ïðîâåðÿåì íàëè÷èå âõîäíûõ ïàðàìåòðîâ */ if(ov_open(f, &vf, NULL, 0) < 0) {
if(argc == 1) { printf("Input does not appear to be an Ogg bitstream.\n");
printf("\n\tUsage: write_audio [OGG-files]\n\n");
return 0; exit(-1);
}
}
for(;;) {

72
hardware
memset(pcmout, 0, 8192); # ./ogg2cdda trk1.ogg trk2.ogg trk3.ogg
long ret = ov_read(&vf, pcmout, sizeof(pcmout), ↵
0, 2, 1, &current_section);
if (ret == 0) break; Результаты работы программы:
if(ret < 0) {
printf("Error OGG bitsream"); Decoding file trk1.ogg..OK
exit(-1); File size – 41505744 bytes
} Sectors in file - 17647
Reserve track #1
if(write(out, pcmout, ret) < 0) { PMA data length - 24
printf("write"); PMA entries - 2
Entry ADR CTRL Point Min Sec Frame PMin Psec Pframe LBA
exit(-1); 0 2 0 0 80 71 82 0 0 0 ---
} 1 1 0 1 3 57 24 0 2 0 0
} Track #1 size - 17647 sectors
Start LBA for track #1 - 0
fclose(f);
Decoding file trk2.ogg..OK
close(out); File size – 36604176 bytes
Sectors in file - 15563
printf("OK\n"); Reserve track #2
return; PMA data length - 35
} PMA entries - 3
Entry ADR CTRL Point Min Sec Frame PMin Psec Pframe LBA
0 2 0 0 80 71 82 0 0 0 ---
Функция write_audio() выполняет запись аудиотрека на 1
2
1
1
0
0
1
2
3
7
57
26
24
64
0
3
2
59
0
24
0
17799
диск. Входные параметры – имя файла WAV-формата (без Track #2 size - 15563 sectors
Start LBA for track #2 - 17799
заголовка), содержащего аудиоданные, и стартовый адрес,
Decoding file trk3.ogg..OK
с которого начинается запись. Возвращаемое значение – File size – 47684448 bytes
Sectors in file - 20274
общее число записанных на диск блоков: Reserve track #3
PMA data length - 46
PMA entries - 4
__u32 write_audio(__u8 *file_name, __u32 start_lba) Entry ADR CTRL Point Min Sec Frame PMin Psec PFrame LBA
{ 0 2 0 0 80 71 82 0 0 0 ---
int in_f; 1 1 0 1 3 57 24 0 2 0 0
__u8 write_cmd[10]; 2 1 0 2 7 26 64 3 59 24 17799
3 1 0 3 11 59 15 7 28 64 33514
// áëîê äëÿ àóäèîäàííûõ, 2352 áàéò
Track #3 size - 20274 sectors
__u8 write_buff[CD_FRAMESIZE_RAW]; Start LBA for track #3 - 33514
__u32 lba = 0, lba1 = 0;
Close session..OK
if(test_unit_ready() < 0) exit(-1);
Хорошо видно, что после каждого вызова функции
lba1 = start_lba;
reserv_track в PMA добавляется запись о новом треке. Рас-
/* Îòêðûâàåì ôàéë ñ àóäèîäàííûìè */ стояние между треками – 2 секунды.
in_f = open(file_name, O_RDONLY, 0600);
memset(write_buff, 0, CD_FRAMESIZE_RAW); Теперь рассмотрим пример записи аудиоданных без
предварительного резервирования треков. Для определе-
/* Öèêë ÷òåíèÿ äàííûõ èç ôàéëà è çàïèñè */
while(read(in_f, write_buff, CD_FRAMESIZE_RAW) > 0) { ния стартового адреса трека при помощи команды READ
TRACK INFORMATION считывается адрес невидимого, не-
/* Ôîðìèðóåì êîìàíäíûé ïàêåò */
memset(write_cmd, 0, 10); завершенного (invisible) трека. В этом случае поле Address/
write_cmd[0] = WRITE_10; Number Type команды READ TRACK INFORMATION содер-
write_cmd[8] = 1; // ÷èñëî áëîêîâ äëÿ çàïèñè
жит 01b, поле Logical Block Address/Track/Session Number –
printf("%c", 0x0D); значение 0xFF (см. табл. 452, стр. 374 спецификации [1]).
printf("lba - %6d", lba1);
// àäðåñ áëîêà, â êîòîðûé âûïîëíÿåòñÿ çàïèñü äàííûõ Функция определения стартового адреса невидимого
lba = __swab32(lba1); трека:
memcpy((write_cmd + 2), (void *)&lba, 4);
lba1 += 1;
__u32 read_track_info()
if(send_cmd(write_cmd, 10, SG_DXFER_TO_DEV, write_buff, ↵ {
CD_FRAMESIZE_RAW, 20000) < 0) return 0; __u8 read_track_info_cmd[10];
__u8 data_buff[40]; // áëîê èíôîðìàöèè î òðåêå
memset(write_buff, 0, CD_FRAMESIZE_RAW); __u16 len = 40; // ðàçìåð áëîêà èíôîðìàöèè î òðåêå
} __u32 lba = 0;
close(in_f); if(test_unit_ready() < 0) exit(-1);
printf("\n");
return lba1; // ÷èñëî áëîêîâ, çàïèñàííûõ íà äèñê /* Ôîðìèðóåì êîìàíäíûé ïàêåò */
} memset(data_buff, 0, 40);
memset(read_track_info_cmd, 0, 10);
Полный текст программы создания аудиодиска из фай- read_track_info_cmd[0] = 0x52;
read_track_info_cmd[1] = 1;
лов формата Ogg Vorbis находится с файле SG/ogg2cdda.c. read_track_info_cmd[5] = 0xFF; // invisible track
Получаем исполняемый файл при помощи команды:
len = __swab16(len);
memcpy((void *)(read_track_info_cmd + 7), (void *)&len, 2);
# gcc -o ogg2cdda ogg2cdda.c -lvorbis -lvorbisfile
if(send_cmd(read_track_info_cmd, 10, SG_DXFER_FROM_DEV, ↵
data_buff, 40, 20000) < 0) {
Рассмотрим пример работы программы ogg2cdda. Ус- printf("Cannot read track info!\n");
exit(-1);
танавливаем в привод диск CD-RW и запускаем програм- }
му на выполнение, указав в командной строке имена трех
/* Ñòàðòîâûé àäðåñ íåâèäèìîãî òðåêà. Ñ ýòîãî àäðåñà áóäåò
файлов в формате Ogg Vorbis: * âûïîëíÿòüñÿ çàïèñü

№12(25), декабрь 2004 73


hardware
*/ if((pid = waitpid(pid, &status, 0)) && ↵
memcpy((void *)&lba, (void *)(data_buff + 8), 4); WIFEXITED(status)) return;
return __swab32(lba); }
}
При записи WAV-файла необходимо отбросить его за-
Рассмотрим главную функцию программы записи аудио- головок. В функции записи файла write_audio() после от-
данных. Входные параметры – список файлов в формате крытия файла необходимо сместиться к началу аудиодан-
MP3. ных при помощи вызова:

int main(int argc, char **argv) lseek(in_f, WAV_HEADER_SIZE, 0)


{
int i = 1;
__u32 start_lba = 0, total_sectors = 0; где WAV_HEADER_SIZE = 44 – размер заголовка WAV-фай-
/* Ïðîâåðÿåì âõîäíûå ïàðàìåòðû */ ла.
if(argc == 1) { Полный текст программы создания аудиодиска из фай-
printf("\n\tUsage: write_audio [MP3-files]\n\n");
return 0; лов формата MP3 находится в файле SG/mp2cd_inv_track.c.
} Следующий фрагмент программы выполняет запись
/* Îòêðûâàåì ôàéë óñòðîéñòâà */ треков, и стартовый адрес мы вычисляем самостоятельно:
if((sg_fd = open(SG_DEV, O_RDWR)) < 0) {
perror("open"); total_sectors = 0;
return -1;
} /* Öèêë çàïèñè òðåêîâ */
for(i = 1; i < argc; i++) {
/* Óñòàíàâëèâàåì ïàðàìåòðû ðåæèìà çàïèñè
* (ñì. ïðåäûäóùèé ïðèìåð) printf("\nWriting track #%d:\n", i);
*/
mode_select(0, 0); /* Îïðåäåëÿåì ñòàðòîâûé àäðåñ òðåêà è çàïèñûâàåì òðåê
* íà äèñê. Ïîñëå ýòîãî çàêðûâàåì òðåê
/* Öèêë çàïèñè òðåêîâ íà äèñê */ */
for(i = 1; i < argc; i++) { // ñòàðòîâûé àäðåñ òðåêà
if(i > 1) start_lba = total_sectors + apl + 2;
/* Äåêîäèðóåì ôàéë èç MP3-ôîðìàòà â WAV */
printf("\nDecoding file %s..\n", argv[i]); printf("Start sector - %u\n", start_lba);
mp3_decoder(argv[i]); total_sectors = write_audio(argv[i], start_lba);
if(total_sectors == 0) return -1;
/* Îïðåäåëÿåì ñòàðòîâûé àäðåñ òðåêà */
start_lba = read_track_info(); close_track(i);
printf("Start LBA for track #%d - %u\n", i, start_lba); }
/* Çàïèñûâàåì òðåê íà äèñê è çàêðûâàåì òðåê */
total_sectors = write_audio("./track.wav", start_lba);
if(total_sectors == 0) return -1; Стартовый адрес первого трека нам известен – он ра-
close_track(i); вен нулю. Адрес нового трека вычисляется по формуле:
}

/* Öèêë çàïèñè òðåêîâ çàâåðøèëñÿ, çàêðûâàåì ñåññèþ */ start_lba = total_sectors + apl + 2


close_session();

/* Óäàëÿåì ôàéë track.wav è èçâëåêàåì äèñê èç ïðèâîäà */ где total_sector – общее число секторов, записанных на диск,
unlink("./track.wav");
eject_cd(); apl – длина аудиопаузы, значение поля Audio Pause Length
(APL) страницы параметров режима записи (рис. 15 пер-
close(sg_fd);
return 0; вой части статьи).
} Значение APL хранится в поле apl структуры wpm, и оп-
ределяется следующим образом:
Преобразование файлов из формата MP3 в WAV вы-
полняет функция mp3_decoder(). Входные параметры фун- mode_sense();
apl = __swab16(wpm->apl);
кции – имя файла формата MP3. На выходе получаем файл
track.wav в формате WAV. Для конвертирования использу- В файле SG/write_audio.c находится полный текст про-
ется программа mpg321: граммы, выполняющей запись WAV-файлов на аудиоком-
пакт. Стартовый адрес трека вычисляется вышеприведен-
void mp3_decoder(__u8 *file_name) ным способом.
{
static pid_t pid; А теперь давайте сотрем с диска все, что мы на него
int status; записали. Для стирания информации с диска используется
switch(pid = fork()) { команда BLANK. Формат этой команды приведен на рис. 8.
Поле Blanking type устанавливает режим очистки дис-
case -1:
perror("fork"); ка. Может принимать следующие значения:
exit(-1); ! 000b – стирается вся информация, находящаяся на дис-
case 0: ке. Значение поля Start Address игнорируется.
execl("/usr/bin/mpg321", "mpg321", "-q", ↵ ! 001b – минимальная очистка диска. Стирается PMA,
"-w", "track.wav", file_name, 0);
exit(-1); Lead-In-область диска и pre-gap-область первого трека.
} Параметр Start Address игнорируется.

74
hardware
Полный текст программы очистки CD-RW-диска приве-
ден в файле SG/blank.c.
Общее замечание по работе всех программ. Иногда
программа после запуска выдает сообщение об ошибке:
Sense data: 0x70 0x00 0x06 0x00 0x00 0x00 0x00 0x0a 0x00 0x00
0x00 0x00 0x28 0x00 0x00 0x00 0x00 0x00
Driver_status=0x28
Unit not ready

и завершает работу. Здесь Sense Key = 0x06, ASC = 0x28,


ASCQ = 0x00 (см. [3, 5]), что означает «UNIT ATTENTION.
Indicates that the removable medium may have been changed or
Ðèñóíîê 8. Ôîðìàò êîìàíäû BLANK the ATAPI CD-ROM Drive has been reset. NOT READY TO
Остальные значения поля Blanking type и их описание READY TRANSITION, MEDIUM MAY HAVE CHANGED» (Носи-
приведены в спецификации [1], табл. 219 «Blanking Types тель был заменен или выполнен сброс ATAPI-контроллера).
CD-RW and DDCD-RW». При повторном запуске программа выполняется без
Функция blank() выполняет очистку CD-RW-диска. Па- ошибок.
раметр функции blank_type устанавливает режим очистки
диска. Допустимые значения этого параметра – 0 или 1: Литература и ссылки:
1. Спецификация SCSI Multimedia Commands-4 (SCSI MMC-4),
int blank(__u8 blank_type) http://www.t10.org/ftp/t10/drafts/mmc4/mmc4r03d.pdf.
{
__u8 blank_cmd[12]; 2. Спецификация SCSI-3 Multimedia Commands, http://
www.t10.org/ftp/t10/drafts/mmc/mmc-r10a.pdf.
if(test_unit_ready() < 0) exit(-1);
3. Specification for ATAPI DVD Devices, ftp.seagate.com/sff/
memset(blank_cmd, 0, 12); INF-8090.pdf.
blank_cmd[0] = 0xA1; // êîä êîìàíäû BLANK
// ðåæèì î÷èñòêè: 0 – ïîëíàÿ, 1 – ìèíèìàëüíàÿ 4. SCSI-Generic-HOWTO, http://www.linux.org/docs/ldp/
blank_cmd[1] = blank_type; howto/SCSI-Generic-HOWTO/index.html.
if(send_cmd(blank_cmd, 12, SG_DXFER_NONE, ↵ 5. Мешков В. «Пакетные команды интерфейса ATAPI» –
NULL, 0, 9600*1000) < 0) return -1; Журнал «Системный администратор», № 9, сентябрь
return 0;
} 2004 г. – 70-84 с.

№12(25), декабрь 2004 75


образование

ФАЙЛОВАЯ СИСТЕМА NTFS ИЗВНЕ И ИЗНУТРИ


ЧАСТЬ 2

В продолжение знакомства с файловой системой


NTFS сегодня мы сосредоточимся на строении
атрибутов, исследовав их заголовок и механизмы
хранения нерезидентного тела на диске, а также
покажем, как рассмотренные нами структуры
данных выглядят вживую в дисковом редакторе
типа Disk Probe или Sector Inspector.

КРИС КАСПЕРСКИ
Атрибуты (см. первую часть статьи, «Файловые записи»). Тела рези-
Структурно всякий атрибут состоит из заголовка (attribute дентных атрибутов хранятся там же. Нерезидентные атри-
header) и тела (attribute body). Заголовок атрибута всегда буты хранят свое тело вне MFT, в одном или нескольких
хранится в файловой записи, расположенной внутри MFT кластерах, перечисленных в заголовке данного атрибута в

76
образование
специальном списке (см. «Списки отрезков»). Если 8-раз- Если атрибут имеет имя (attribute Name), то 16-разряд-
рядное поле, расположенное по смещению 08h байт от на- ное поле, расположенное по смещению 0Ah байт от атри-
чала атрибутного заголовка, равно нулю, атрибут считает- бутного заголовка, содержит указатель на него. Для безы-
ся резидентным, а если единице – то нет. Любые другие мянных атрибутов оно равно нулю (а большинство атрибу-
значения недопустимы. тов безымянны!). Имя атрибута хранится в атрибутном за-
Первые четыре байта атрибутного заголовка определя- головке в формате UNICODE, а его длина определяется 8-
ют его тип. Тип атрибута в свою очередь определяет фор- разрядным полем, расположенным по смещению 09h байт
мат представления тела атрибута. В частности, тело атри- от начала атрибутного заголовка.
бута данных (тип: 80h – $DATA) представляет собой «сы- Если тело атрибута сжато, зашифровано или разряже-
рую» последовательность байт. Тело атрибута стандартной но, 16-разрядное поле флагов, расположенное по смещению
информации (тип: 10h – $STANDARD_INFORMATION) опи- 0Ch байт от начала атрибутного заголовка, не равно нулю.
сывает время его создания, права доступа и т. д. Подроб- Остальные поля не играют сколь-нибудь существенной
нее см. «Типы атрибутов». роли и потому здесь не рассматриваются.
Следующие четыре байта заголовка содержат длину ат- Òàáëèöà 1. Ñòðóêòóðà ðåçèäåíòíîãî àòðèáóòà
рибута, выражаемую в байтах. Длина нерезидентного ат-
рибута равна сумме длин его тела и заголовка, а длина ре-
зидентного атрибута равна длине его заголовка. Короче го-
воря, если к смещению атрибута добавить его длину, мы
получим указатель на следующий атрибут (или маркер кон-
ца, если текущий атрибут – последний в цепочке).
Длина тела резидентных атрибутов, выраженная в бай-
тах, хранится в 32-разрядном поле, расположенном по сме-
щению 10h байт от начала атрибутного заголовка. 16-раз-
рядное поле, следующее за его концом, хранит смещение
резидентного тела, отсчитываемое от начала атрибутного
заголовка.
С нерезидентными атрибутами в этом плане все намного
сложнее и для хранения длины их тела используется мно-
жество полей. Реальный размер тела атрибута (real size of
attribute), выраженный в байтах, хранится в 64-разрядном (!)
поле, находящемся по смещению 30h байт от начала атри- Òàáëèöà 2. Ñòðóêòóðà íåðåçèäåíòíîãî àòðèáóòà
бутного заголовка. Следующее за ним 64-разрядное поле
хранит инициализированный размер потока (initialized data
size of the stream), выраженный в байтах и, судя по всему,
всегда равный реальному размеру тела атрибута. 64-раз-
рядное поле, расположенное по смещению 28h байт от на-
чала атрибутного заголовка, хранит выделенный размер
(allocated size of attribute), выраженный в байтах и равный
реальному размеру тела атрибута, округленному до раз-
мера кластера (в большую сторону).
Два 64-разрядных поля, расположенные по смещению
10h и 18h байт от начала атрибутного заголовка, задают
первый (starting VCN) и последний (last VCN) номер вирту-
ального кластера, принадлежащего телу нерезидентного
атрибута. Виртуальные кластеры представляют собой ло-
гические номера кластеров, не зависящие от своего физи-
ческого расположения на диске. В подавляющем большин-
стве случав номер первого кластера тела нерезидентного
атрибута равен нулю, а последний – количеству кластеров,
занятых телом атрибута, уменьшенном на единицу. 16-раз-
рядное поле, расположенное по смещению 20h от начала
атрибутного заголовка, содержит указатель на массив Data Типы атрибутов
Runs, расположенный внутри этого заголовка и описываю- NTFS поддерживает большее количество предопределен-
щий логический порядок размещения нерезидентного тела ных типов атрибутов, перечисленных в таблице 3. Как уже
атрибута на диске (подробнее см. «Списки отрезков»). говорилось выше, тип атрибута определяет его назначение
Каждый атрибут имеет свой собственный идентифика- и формат представления тела. Полное описание всех атри-
тор (attribute ID), уникальный для данной файловой записи бутов заняло бы очень много места и поэтому здесь приво-
и хранящийся в 16-разрядном поле, расположенном по сме- дятся лишь наиболее «ходовые» из них, а за информацией
щению 0Eh от начала атрибутного заголовка. об остальных обращайтесь к Linux-NTFS Project.

№12(25), декабрь 2004 77


образование
Òàáëèöà 3. Îñíîâíûå òèïû àòðèáóòîâ ! файл содержит много альтернативных имен или жест-
ких ссылок;
! файл очень сильно фрагментирован;
! файл содержит очень сложный дескриптор безопасно-
сти;
! файл имеет очень много потоков данных (т.е. атрибу-
тов типа $DATA).

Структура атрибута списка атрибутов приведена ниже:


Òàáëèöà 5. Ñòðóêòóðà àòðèáóòà $ATTRIBUTE_LIST

Атрибут стандартной информации Атрибут полного имени $FILE_NAME


$STANDARD_INFORMATION Атрибут полного имени файла хранит имя файла в соот-
Атрибут стандартной информации описывает время созда- ветствующем пространстве имен. Таких атрибутов у фай-
ния/изменения/последнего доступа к файлу и права досту- ла может быть и несколько (например, win32-имя и MS-DOS
па, а также некоторую другую вспомогательную информа- имя). Здесь же хранятся и жесткие ссылки (hard link), если
цию (например, квоты): они есть.
Òàáëèöà 4. Ñòðóêòóðà àòðèáóòà $STANDARD_INFORMATION Структура атрибута полного имени приведена ниже:
Òàáëèöà 6. Ñòðóêòóðà àòðèáóòà $FILE_NAME

Списки отрезков (data runs)


Тела нерезидентных атрибутов хранятся на диске в одной
или нескольких кластерных цепочках, называемых отрез-
ками (runs). Отрезком называется последовательность
смежных кластеров, характеризующаяся номером началь-
ного кластера и длиной. Совокупность отрезков называет-
ся списком, run-list или data run.
Внутренний формат представления списков не то, что-
бы сложен, но явно не прост, за что получил прозвище brain
damage format (формата, срывающего крышу). Для эконо-
Атрибут списка атрибутов $ATTRIBUTE_LIST мии места длина отрезка и номер начального кластера хра-
Атрибут списка атрибутов (получился каламбур) использу- нятся в полях переменной длины. То есть, если размер от-
ется в тех случаях, когда все атрибуты файла не умещают- резка умещается в байт (т.е. его значение не прерывыша-
ся в базовой файловой записи и файловая система вынуж- ет 255), он и хранится в байте. Соответственно, если раз-
дена располагать их в расширенных. Индексы расширен- мер отрезка требует для своего представления двойного
ных файловых записей содержатся в атрибуте списка ат- слова, он и хранится в двойном слове.
рибутов, помещаемом в базовую файловую запись. Сами же поля размеров хранятся в 4-байтовых ячейках,
При каких обстоятельствах атрибуты не умещаются в называемых нибблами (nibble) или полубайтами. Шестнад-
одной файловой записи? Это может произойти, когда: цатеричная система исчисления позволяет легко перево-

78
образование
дить байты в нибблы и наоборот. Младший ниббл равен Завершающий нуль на конце run-list сигнализирует о том,
(X & 15), а старший – (X / 16). Легко видеть, что младший что это последний отрезок в файле.
ниббл соответствует младшему шестнадцатеричному раз- Таким образом, подопытный файл состоит из трех от-
ряду байта, а старший – старшему. Например, 69h состоит резков, разбросанных по диску в следующем живописном
из двух нибблов – младший равен 9h, а старший – 6h. порядке: 342573h – 3425ABh; 0211E5h – 212F9h; 0300AAh –
Список отрезков представляет собой массив структур, 300ECh. Остается только прочитать его с диска!
каждая из которых описывает характеристики «своего» от- Начиная с версии 3.0, NTFS поддерживает разряженные
резка, а в конце списка находится завершающий нуль. Пер- (sparse) атрибуты, т.е. такие, которые не записывают на диск
вый байт структуры состоит из двух полубайт: младший за- кластеры, содержащие одни нули. При этом поле номера на-
дает длину поля начального кластера отрезка (условно обо- чального кластера отрезка может быть равным нулю, что оз-
значаемого буквой F), старший – количество кластеров в начает, что данному отрезку не выделен никакой кластер.
отрезке (L). Поле длины отрезка идет следом. В зависимо- Поле длины содержит количество кластеров, заполненных
сти от значения L оно может занимать от одного до восьми нулями. Их не нужно считывать с диска. Вы должны само-
байт (более длинные поля недопустимы). Первый байт поля стоятельно изготовить их в памяти. Кстати говоря, далеко
стартового кластера файла расположен по смещению 1 + L не все дисковые доктора знают о существовании разряжен-
байт от начала структуры (что соответствует 2+2∗L ниб- ных атрибутов (если атрибут разряжен его флаг равен 8000h),
блам). Кстати говоря, в документации Linux-NTFS Project и интерпретируют нулевую длину поля номера начального
(версия 0.4) поля размеров начального кластера и количе- кластера весьма странным образом. Последствия такого
ства кластеров в отрезке перепутаны местами. «лечения» обычно оказываются очень печальны.
Òàáëèöà 7. Ñòðóêòóðà îäíîãî ýëåìåíòà ñïèñêà îòðåçêîâ
Пространства имен (name spaces)
NTFS изначально проектировалась как системно-незави-
симая файловая система, способная работать со множе-
ством различных подсистем, как то: Win32, MS-DOS, POSIX
и т. д. Поскольку, каждая из них налагает свои собствен-
Покажем, как с этим работать на практике. Допустим, ные ограничения на набор символов, допустимых для ис-
мы имеем следующий run-list, соответствующий нормаль- пользования в имени файла, NTFS вынуждена поддерживать
ному нефрагментированному файлу (что может быть про- несколько независимых пространств имен (name space).
ще!): «21 18 34 56 00». Попробуем его декодировать.
Начнем с первого байта – 21h. Младший полубайт (01h) POSIX
описывает размер поля длины отрезка, старший (02h) – Допустимы все UNICODE-символы (с учетом регистра), за
размер поля начального кластера. Следующие несколько исключением символа нуля (NULL), обратного слеша («/»)
байт представляют поле длины отрезка, размер которого в и знака двоеточия («:»). Последнее, кстати говоря, не огра-
данном случае равен одному байту – 18h. Два других бай- ничение POSIX, а ограничение NTFS, использующей этот
та (34h 56h) задают номер начального кластера отрезка. символ для доступа к именованным атрибутам. Максималь-
Нулевой байт на конце сигнализирует о том, что это после- но допустимая длина имени составляет 255 символов.
дний отрезок в файле. Итак, наш файл состоит из одного-
единственного отрезка, начинающегося с кластера 5634h Win32
и заканчивающегося кластером 5634h+ 18h == 564Ch. Доступны все UNICODE-символы (без учета регистра), за
Рассмотрим более сложный пример фрагментирован- исключением следующего набора: «“» (кавычки), «*» (звез-
ного файла со следующим списком отрезков: «31 38 73 25 дочка), «/» (прямой слеш), «:» (двоеточие), «<» (знак мень-
34 32 14 01 E5 11 02 31 42 AA 00 03 00». Извлекаем первый ше), «>» (знак больше), «?» (вопросительный знак), «\» (об-
байт – 31h. Один байт приходится на поле длины и три бай- ратный слеш), «|» (символ конвейера). К тому же, имя фай-
та на поле начального кластера. Таким образом, первый ла не может заканчиваться на точку или пробел. Макси-
отрезок (run 1) начинается с кластера 342573h и продол- мально допустимая длина имени составляет 255 символов.
жается вплоть до кластера 342573h + 38 == 3425ABh. Что-
бы найти смещение следующего отрезка в списке, мы скла- MS-DOS
дываем размер обоих полей с их начальным смещением: Доступны все символы пространства имен win32 (без уче-
3 + 1 == 4. Отсчитываем четыре байта от начала run-list и та регистра), за исключением: «+» (знак плюс), «,» (знак
переходим к декодированию следующего отрезка: 32h – два запятая), «.» (знак точка), «;» (точка с запятой), «=» (знак
байта на поле длины отрезка (равное в данном случае равно). Имя файла не должно превышать восьми симво-
0114h) и три байта на поле номера начального кластера лов за которыми следует необязательное расширение с
(0211E5h). Следовательно, второй отрезок (run 2) начина- длиной от одного до трех символов.
ется с кластера 0211E5h и продолжается вплоть до класте-
ра 0211E5h + 114h == 212F9h. Третий отрезок (run 3): 31h – Назначение некоторых
один байт на поле длины и три байта на поле начального служебных файлов
кластера, равные 42h и 0300AAh соответственно. Поэтому NTFS содержит большое количество служебных файлов
третий отрезок (run 3) начинается с кластера 0300AAh и (метафайлов) строго определенного формата, важнейший
продолжается вплоть до кластера 0300AAh + 42h == 300ECh. из которых – $MFT – мы только что рассмотрели. Осталь-

№12(25), декабрь 2004 79


образование
ные метафайлы играют вспомогательную роль и для вос- содержимое последовательности обновления. По смеще-
становления данных знать их структуру, в общем-то, и нео- нию 04h от начала сектора лежит 16-разрядный указатель
бязательно. Тем не менее если они окажутся искажены, на нее, равный в данном случае 2Ah (значит, это NTFS 3.0
штатный драйвер файловой системы не сможет работать с или младше). А что у нас лежит по смещению 2Ah? Пара
таким томом, поэтому иметь некоторые представления о байт 03 00. Это номер последовательности обновления.
назначении каждого из них все же необходимо. Сверяем его с содержимым двух последних байт этого и
У нас нет возможности рассказать о структуре всех следующего секторов (смещения 1FEh и 3FEh соответствен-
метафайлов (да и незачем дублировать Linux-NTFS Project), но). Они равны! Значит, данная файловая запись цела (по
поэтому эта информация здесь не приводится. крайней мере внешне) и можно переходить к операции спа-
Òàáëèöà 8. Íàçíà÷åíèå îñíîâíûõ ñòàíäàðòíûõ ôàéëîâ сения. По смещению 2Ch расположен массив, содержащий
оригинальные значения последовательности обновления.
Количество элементов в нем равно содержимому 16-разряд-
ного поля, расположенному по смещению 06h от начала сек-
тора и уменьшенного на единицу (т.е. в данном случае 03h –
01h == 02h). Извлекаем два слова начиная со смещения 2Ch
(в данном случае они равны 00 00 и 00 00) и записываем их
в конец первого и последнего секторов.
Теперь нам необходимо выяснить – используется ли дан-
ная файловая запись или ассоциированный с ней файл/ка-
талог был удален. 16-разрядное поле, расположенное по
смещению 16h, содержит значение 01h. Следовательно,
перед нами файл, а не каталог, и этот файл еще не удален.
Но является ли данная файловая запись базовой для дан-
ного файла или мы имеем дело с ее продолжением? 64-
разрядное поле, расположенное по смещению 20h, равно
нулю, следовательно, данная файловая запись – базовая.
Переходим к исследованию атрибутов. 16-разрядное
поле, находящееся по смещению 14h равно 30h, следова-
тельно, заголовок первого атрибута начинается со смеще-
ния 30h от начала сектора.
Первое двойное слово атрибута равно 10h, значит, пе-
ред нами атрибут типа $STANDARD_INFORMATION. 32-раз-
рядное поле длины атрибута, находящееся по смещению
Путешествие по NTFS 04h и равное в данном случае 60h байт, позволяет нам вы-
Рассказ о NTFS был бы неполным без практической иллю- числить смещение следующего атрибута в списке – 30h
страции техники разбора файловой записи «руками». До (смещение нашего атрибута) + 60h (его длина) == 90h (сме-
сих пор мы витали в облаках теоретической абстракции. щение следующего атрибута). Первое двойное слово сле-
Пора спускаться на грешную землю. дующего атрибута равно 30h, значит, это атрибут типа
Воспользовавшись любым дисковым редактором, на- $NAME и следующее 32-разрядное поле хранит его длину,
пример, Disk Probe, попробуем декодировать одну файло- равную в данном случае 70h. Сложив длину атрибута с его
вую запись вручную. Найдем сектор, содержащий сигнату- смещением, мы получим смещение следующего атрибута –
ру «FILE» в его начале (не обязательно брать первый встре- 90h + 70h == 100h. Первое двойное слово третьего атрибу-
тившийся сектор). Он может выглядеть, например, так: та равно 80h, следовательно, это атрибут типа $DATA, хра-
нящий основные данные файла. Складываем его смеше-
Ëèñòèíã 1. Ðó÷íîå äåêîäèðîâàíèå ôàéëîâîé çàïèñè (ðàçíûå ние с длиной – 100h + 32h == 132h. Мы наткнулись на час-
àòðèáóòû âûäåëåíû ðàçíûì öâåòîì)
токол FFFFFFh, сигнализирующий о том, что атрибут $DATA
последний в списке.
Теперь, разбив файловую запись на атрибуты, присту-
пить к исследованию каждого из атрибутов в отдельности.
Начнем с имени. 8-разрядное поле, находящееся по сме-
щению 08h от начала атрибутного заголовка (и по смеще-
нию 98h от начала сектора), содержит флаг нерезидентно-
сти, который в данном случае равен нулю (т.е. атрибут ре-
зидентный и его тело хранится непосредственно в самой
файловой записи). 16-разрядное поле, расположенное по
смещению 0Ch от начала атрибутного заголовка (и по сме-
щению 9Ch от начала сектора) равно нулю, следовательно
тело атрибута не сжато и не зашифровано. 32-разрядное
Первым делом необходимо восстановить оригинальное поле, расположенное по смещению 10h от начала атрибут-

80
образование
ного заголовка и по смещению A0h от начала сектора, со- 09h от начала атрибутного заголовка и по смещению 109h
держит длину атрибутного тела, равную в данном случае от начала сектора, равно нулю – атрибут безымянный. Ре-
54h байт, а 16-разрядное поле, расположенное по смеще- альная длина тела атрибута (в байтах) содержится в 64-
нию 14h от начала атрибутного заголовка и по смещению разрядном поле, расположенном по смещению 30h от на-
A4h от начала сектора, хранит смещение атрибутного тела, чала атрибутного заголовка и по смещению 130h от нача-
равное в данном случае 18h, следовательно, тело атрибу- ла сектора. В данном случае она равна 4ED1F0h (5.165.552).
та $NAME располагается по смещению A8h от начала сек- Два 64-разрядных поля, расположенных по смещениям 10h/
тора. 110h и 18h/118h байт от начала атрибутного заголовка/сек-
Формат атрибута типа $NAME описан в таблице XX. тора соответственно, содержат начальный и конечный но-
Первые восемь байт содержат ссылку на материнский ка- мер виртуального кластера неризидентного тела. В данном
талог данного файла, равную в данном случае 11ADBh:01 случае они равны: 0000h/4EDh.
(индекс – 11ADBh, номер последовательности – 01h). Сле- Остается лишь декодировать список отрезков, адрес ко-
дующие 32-байта содержат штаммы времени создания, торого хранится в 16-разрядном поле, находящемся по сме-
изменения и времени последнего доступа к файлу. По сме- щению 20h от начала атрибутного заголовка и 120h от на-
щению 28h от начала тела атрибута и D0h от начала секто- чала сектора. В данном случае оно равно 40h, что соответ-
ра лежит 64-разрядное поле выделенного размера, а за ствует смещению от начала сектора в 140h. Сам же список
ним – 64-разрядное поле реального размера. Оба равны отрезков выглядит так: 32 EE 04 D9 91 00 00. Два байта
нулю, что означает, что за размером файла следует обра- занимает поле длины (равное в данном случае 04EEh кла-
щаться к атрибутам типа $DATA. стерам) и три – поле начального кластера (0091h). Завер-
Длина имени файла содержится в 8-разрядном поле, шающий ноль на конце говорит о том, что этот отрезок пос-
находящемся по смещению 40h байт от начала тела атри- ледний в списке отрезков.
бута и по смещению E8h от начала сектора. В данном слу- Подытожим полученную информацию. Файл называет-
чае оно равно 09h. Само же имя начинается со смещения ся Ilfak.dbx, он начинается с кластера 0091h и продолжает-
42h от начала тела атрибута и со смещения EAh от начала ся вплоть до кластера 57Fh, при реальной длине файла в
сектора. И здесь находится Ilfak.dbx. 5 165 552 байт. За сим все! Теперь уже ничего не стоит ско-
Переходим к атрибуту основных данных файла, пропу- пировать файл на резервный носитель (например, ZIP или
стив атрибут стандартной информации, который не содер- стример).
жит решительно ничего интересного. 8-разрядный флаг не-
резидентности, расположенный по смещению 08h от нача- Заключение
ла атрибутного заголовка и по смещению 108h от начала Вооруженные джентльменским набором знаний (а также
сектора, равен 01h, следовательно атрибут нерезидентный. дисковым редактором в придачу), мы готовы дать реши-
16-разрядный флаг, расположенный по смещению 0Ch от тельный отпор энтропии, потеснив ее по всем фронтам.
начала атрибутного заголовка и по смещению 10Сh от на- Следующая статья этого цикла расскажет о том как вос-
чала сектора, равен нулю, значит, атрибут не сжат и не за- станавливать удаленные файлы, отформатированные раз-
шифрован. 8-разрядное поле, расположенное по смещению делы и разрушенные служебные структуры данных.

Что читать
Основными источниками данных по NTFS служат:
! Книга Хелен Кастер (Helen Custer, часто сокращаемая до просто «Helen») «Inside the Windows NT file system» (в рус-
ском издании она входит в состав «Основы Windows NT и NTFS»), подробно описывающая концепции файловой
системы и дающая о ней общее представление. К сожалению, все объяснения ведутся на абстрактном уровне без
указания конкретных числовых значений, смещений и структур. К тому же в операционных системах Windows 2000 и
Windows XP с файловой системой произошли значительные изменения, никак не отраженные в книге. Если не найде-
те эту книгу в магазинах – ищите ее в файлообменных сетях. (Например, www.eMule.ru).
! Хакерская документация от коллектива «Linux-NTFS Project» (http://linux-ntfs.sourceforge.net), чьим хобби долгое вре-
мя была разработка независимого NTFS-драйвера для OS Linux. Однако сейчас энтузиазм команды начал стреми-
тельно угасать. Это выдающееся творение, подробно описывающее все ключевые структуры файловой системы
(естественно, на английском языке), отнюдь не заменяет книгу Хелен, а лишь расширяет ее! Разобраться в NTFS-
project без знаний NTFS очень и очень непросто!
! Документация от Active Data Recovery Software на утилиту Active Uneraser, бесплатную копию которой можно найти на
сайте www.NTFS.com. Это своеобразный синтез книги Хелен и Linux-NTFS Project, описывающий важнейшие струк-
туры данных и обходящий стороной все вопросы, которые только можно обойти. Здесь же можно найти до предела
выхолощенное изложение методики восстановления данных. Если не найдете Хелен, скачайте демонстрационную
версию Active Uneraser и воспользуйтесь прилагаемой к нею документацией (Active Uneraser поставляется в двух
вариантах – образе FDD и образе CD, документация присутствует только на последнем из них).
! Контекстная помощь на Runtime Software Disk Explorer также содержит достаточно подробное описание файловой
системы, однако, на редкость бестолково организованное. Для упрощения навигации по тексту рекомендуется де-
компилировать chm-файл в обычный текст, вручную перегнав его в MS Word, pdf или любой другой удобный для вас
формат.

№12(25), декабрь 2004 81


образование

РАЗРАБОТКА СЦЕНАРИЯ РЕГИСТРАЦИИ


ПОЛЬЗОВАТЕЛЕЙ В СЕТИ
ЧАСТЬ
ЧАСТЬ 2

ИВАН КОРОБКО
В первой части статьи1 я начал рассказывать о создании Второе – сетевые принтеры, подключением и отключе-
скрипта, который позволит упростить и автоматизировать нием которых должен управлять скрипт, должны быть опуб-
различные процессы. В ней шел разговор о структуре скрип- ликованы в Active Directory.
та и были описаны основополагающие моменты, как осу- Третье – названия групп безопасности должны строить-
ществляется сбор различной информации о рабочей стан- ся в соответствии со следующим шаблоном: название од-
ции и пользователях. Итак, продолжим. ной из групп, члены которой могут только выводить зада-
ния на печать, образуется добавлением к сетевому имени
Автоматическое подключение принтера через дефис слова Print, например, «HP2300_1 –
сетевых ресурсов Print». Название другой группы строится аналогично, с той
К сетевым ресурсам относятся сетевые принтеры и диски. разницей, что слово «Print» заменяют на словосочетание
Рассмотрим подробнее каждый из них. «Print Managers». Члены этой группы могут управлять оче-
редью печати и принтером. Таким образом, принтеру с се-
Подключение сетевых принтеров. Теория тевым именем «HP1200_1», соответствуют следующие на-
звания групп: имя первой группы «HP1200_1 – Print», вто-
Соглашение об именах рой «HP1200_1 – Print Managers».
Имя должно содержать как можно больше информации о
принтере, при этом быть удобным для использования. На
рабочих станциях под управлением операционной систе-
мы Windows пользователь имеет дело с двумя именами –
непосредственное и сетевое имена принтера.
Чаще всего имя, назначаемое принтеру, представляет
собой реальное имя принтера с порядковым номером, если
есть несколько принтеров одинаковой модели, например,
HP LaserJet 1200 (1), HP LaserJet 2300 (2). Такой способ
именования рекомендуется использовать в небольших орга-
низациях. В крупных корпорациях принцип именования
принтеров может быть другим.
Сетевое имя, как отмечено ранее, должно быть более
коротким, но при этом не должно терять смысловой нагруз-
ки. Оно чаще всего представляет собой общую характери-
стику принтера, например, HP1200_1, HP2300_2. Ðèñóíîê 1
Четвертое – должны быть определены параметры бе-
Предварительная настройка принтера и AD зопасности принтера. В свойствах принтера (см. рис. 2) на
Работа сценария строится на анализе и обработке данных, сервере печати во вкладке «Security» (безопасность) дол-
содержащихся в Active Directory и пользовательском реес- жна быть удалена группа «Everyone» (в противном случае
тре. На основе полученных данных осуществляется подклю- скрипт будет подключать этот принтер всем пользователям
чение и отключение принтера в зависимости от членства сети) и добавлены две группы безопасности, соответству-
пользователя в соответствующих группах безопасности. ющие данному принтеру: «HP1200_1 – Print» и «HP1200_1 –
Для обеспечения работоспособности сценария необходи- Print Managers». Для группы «HP1200_1 – Print» должен
мо выполнение нескольких условий: быть установлен в разделе «Permissions» (разрешения)
Первое условие – названия принтеров, групп безопас- флажок напротив свойства «Print» (см. рис. 2), а для груп-
ности должны удовлетворять соглашению об именах. пы «HP1200_1 – Print Managers» – флажки напротив «Print»

1
Коробко И. Разработка сценария регистрации пользователей в сети. Часть 1. – Журнал «Системный администратор», №11, ноябрь, 2004 г.

82
образование
(печать) и «Manage Documents» (управление документами). SELECT ïîëå_1, ïîëå_2, …, ïîëå_n FROM ↵
Ставить флажок напротив «Manage Printers» не рекомен- “LDAP://dc=äîìåí_1,dc=äîìåí_2…,domen_n” ↵
WHERE objectClass=’òèï_îáúåêòà’
дуется, поскольку управление принтерами подразумевает
возможность изменять настройки принтера, удалять его. По В SELECT указываются поля, по которым идет выбор-
мнению автора, такими привилегиями может обладать толь- ка. Поля перечисляются через запятую, «пробелы» после
ко системный администратор. запятой обязательны. Полный список полей объектов AD
можно получить с помощью утилиты ADSI Edit, которая раз-
мещается в дистрибутиве Microsoft Windows 2000 в дирек-
тории /Support/Tools (см. статью «Программное управление
ADSI: LDAP», журнал «Системный администратор», №3,
март 2004г.).
В FROM указывается путь к объекту. В данном случае
известен только домен. При описании данного раздела про-
белы не допускаются.
В WHERE указывается тип объекта, к которому адресо-
ван запрос. Данное поле является фильтром. Провайдер
LDAP поддерживает несколько типов объектов, которые в
запросе SQL определяются переменной objectClass: Print
Queue – массив принтеров, опубликованных в AD; Group –
группы, созданные в AD; User – пользователи, созданные в
AD; Computer – массив компьютеров, зарегистрированных
Ðèñóíîê 2 в AD. Пример использования запроса SQL см. в следую-
щем разделе.
Подключение сетевых принтеров. Практика
Итак, работа сценария строится на анализе данных, содер- Поиск опубликованных принтеров в AD
жащихся в Active Directory и пользовательском реестре. Его Поиск объектов в Active Directory с помощью провайдера
работу можно разбить на три этапа. LDAP реализуется через ADODB-соединение. После созда-
На первом этапе формируется список принтеров, кото- ния соединения формируется SQL-запрос и осуществляет-
рые должны быть подключены к пользователю. На втором ся поиск по заданным критериям. Результатом поиска бу-
этапе – список сетевых принтеров, уже установленных на дет массив, элементами которого являются значения по-
рабочей станции пользователя. Наконец, на третьем – осу- лей, которые указаны в параметре SELECT SQL-запроса.
ществляется приведение этих списков в соответствие. Затем происходит вывод данных на экран. В приведенном
примере осуществляется поиск всех опубликованных прин-
Формирование списка принтеров, которые теров в текущем домене и вывод на экран названия прин-
необходимо подключить пользователю тера, его сетевого имени (ShareName):

Определение имени текущего домена $strADSQuery = "SELECT shortservername, portname, ↵


servername, printername, printsharename, location, ↵
С помощью функции GetObject() осуществляется чтение description FROM '" +$domain_+"' ↵
корня пространства имен, в данном случае определяется WHERE objectClass='printQueue'"
$objConnection = CreateObject("ADODB.Connection")
имя текущего домена. $objCommand = CreateObject("ADODB.Command")
Пример определения текущего домена: $objConnection.CommandTimeout = 120
$objConnection.Provider = "ADsDSOObject"
$rootDSE_ = GetObject("LDAP://RootDSE") $objConnection.Open ("Active Directory Provider")
$domain_ = "LDAP://" + $rootDSE_.Get("defaultNamingContext") $objCommand.ActiveConnection = $objConnection
$objCommand.CommandText = $strADSQuery
Переменная domain_ имеет вид «dc=microsoft,dc=com», $st = $objCommand.Execute
$st.Movefirst
если домен «microsoft.com». $i=0
Имя текущего домена, полученного провайдером WinNT,
Do
нельзя использовать, поскольку с его помощью можно по- $server_enum=""
лучить только сокращенное имя домена (в данном случае $name_enum=""
$shares_enum=""
«microsoft»). Если все же указано сокращенное имя доме- $description_enum=""
на в строке с SQL-запросом, то при выполнении скрипта $server_enum = $St.Fields("shortservername").Value
$name_enum = $St.Fields("printername").Value
произойдет ошибка. В сообщении о ней будет сказано, что $shares=$St.Fields("printsharename").Value
по указанному пути база не обнаружена, поэтому устано- for each $share in $shares
$shares_enum = $shares_enum + $share
вить соединение невозможно. next
$descrs=$St.Fields("description").Value
for each $desc in $descrs
Построение запроса SQL $description_enum = $description_enum + $desc
Запрос SQL используется для осуществления процедуры Next
$st.MoveNext
поиска объектов, при заданном типе объекта. В общем слу- $temp="Íàçâàíèå ïðèíòåðà: " & $name_enum & chr(13) & ↵
чае он выглядит следующим образом: "Ïóòü ê ïðèíòåðó: " & "\\" & $server_enum & "\" & ↵

№12(25), декабрь 2004 83


образование
$shares_enum & chr(13) & "Îïèñàíèå: " & $description_enum. $path_enum_connect = "\\" + $server_enum + "\" + $shares_enum
MessageBox($temp,"Õàðàêòåðèñòèêè ïðèíòåðà",0,0) $connect_flag = addprinterconnection( $path_enum_connect )
$temp="" if $connect_flag=0
Until $st.EOF $path_full =",," + $server_enum + "," + $name_enum
$print_sysinfo=$print_sysinfo+$shares_enum+": ↵
"+$description_enum+chr(13)
В Active Directory объектом класса printQueue является $access_array[$i] = lcase($path_full)
принтер. Этот объект имеет свойства, значение которых мо- $i=$i+1
Endif
жет быть двух типов: строкой и массивом. В приведенном
примере поле, содержащее название принтера, является
строковой переменной, а сетевое имя принтера – массивом. Формирование списка сетевых принтеров,
Ниже приведена таблица, содержащая названия и опи- подключенных пользователю
сания часто используемых полей, соответствующий им тип Процесс определения подключенных пользователю сете-
и формат данных: вых принтеров основан на анализе ветви HKCU локально-
Òàáëèöà 1 го реестра (см. рис. 3).
С помощью функции ENUM осуществляется чтение на-
званий папок, содержащих в себе короткое имя сервера и
полное имя принтера. На основе полученной информации
формируется массив, элементами которого являются стро-
ки, имеющие следующий формат: «,,server,printername», где
server – короткое имя сервера, printername – локальное имя
принтера.
Для удобства сравнения обоих массивов (подключен-
ных принтеров и принтеров, на которые пользователь име-
Формирование массива ет права) необходимо, чтобы форматы элементов масси-
Идея, лежащая в основе механизма подключения принте- вов совпадали. Формат элементов продиктован особенно-
ров, следующая: осуществляется попытка подключить прин- стью построения реестра Windows 2000.
тер, затем сценарий загрузки «смотрит», что из этого по-
лучилось, и в зависимости от результата предпринимает $Index=0
DO
действия. При объяснении работы этого механизма (для $connected_array[$index]= lcase(ENUMKEY("HKEY_CURRENT_USER\ ↵
облегчения восприятия материала) я намеренно поменял Printers\Connections\", $Index))
$Index = $Index + 1
местами причину и следствие. UNTIL Len($Group) =0
После того как в Active Directory найден очередной опуб-
ликованный принтер и прочитаны его свойства, для него Необходимо отметить, что после формирования второ-
формируется UNC-путь (\\server\sharename). Затем осуще- го массива между ними соблюдаются следующее неравен-
ствляется попытка подключить пользователю принтер и ≥М1, где М2 – массив, элементами которого явля-
ство: М2≥
считывать код функции, производящей подключение. ются названия подключенных принтеров, M1 – принтеров,
Если функция подключения возвращает код ошибки 0 на которые пользователь имеет права. На третьем, заклю-
(подключение к принтеру прошло успешно), то пользова- чительном этапе добиваются выполнения следующего ус-
тель является членом одной из двух групп безопасности, ловия: М1=М2.
перечисленных в свойствах принтера на сервере печати.
Для тех принтеров, на которые пользователь имеет пра- Приведение созданных списков принтеров
во печатать (как минимум), формируется массив, напри- в соответствие
мер, $access_array[$i]. Формат элементов массива следую- Сопоставление массивов М1 и М2 осуществляется с помо-
щий: «,,server,printername», где server – короткое имя сер- щью функции ASCAN. В том случае, если функция возвра-
вера, printername – локальное имя принтера. щает значение -1, то элемент, найденный в одном массиве,

Ðèñóíîê 3

84
образование
не является элементом другого. Поэтому принтер, соответ- дет монтироваться ресурс и его порядковый номер. Он при-
ствующий этому элементу, должен быть отключен. сваивается для обеспечения возможности подключать на
одну и ту же букву разные ресурсы. Каждый раздел содер-
for $i=0 to ubound($connected_array) жит пять параметров: название сервера (SERVER), путь к
$flag_p=0
$flag_p=Ascan($access_array,$connected_array[$i]) сетевой папке (SHARE), группы безопасности, членам ко-
if $flag_p=-1 торых будет подключаться ресурс (ACCESSGROUP1 и
………
endif ACCESSGROUP2), описание ресурса (DESCRIPTION). При-
next мер файла приведен ниже:

Удаление принтера осуществляется с помощью соответ- [L1]


ствующей функции, параметром которой является UNC-путь SERVER=Main
принтера. Для того чтобы сформировать этот путь, осуще- SHARE=Consultant
ACCESSGROUP1=everyone
ствляется анализ ветви HKLM (см. рис. 4): ACCESSGROUP2=Âñå
DESCRIPTION="Êîíñóëüòàíò+"
if $flag_p=-1
$group=$connected_array[$i] [W1]
$name_=right($group, len($group)-instrrev($group,",")) SERVER=Second
$server_=right(left($group,len($group)-len($name_)-1), ↵
len(left($group,len($group)-len($name_)-1))-2) SHARE=work\department1
ACCESSGROUP1=department1
$share_=readvalue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ ↵ ACCESSGROUP2=department3
Windows NT\CurrentVersion\Print\Providers\ ↵
LanMan Print Services\Servers\"+$server_+"\Printers\ ↵ DESCRIPTION="Ðåñóðñû îòäåëà 1"
"+$name_,"Share Name") [W2]
$disconnect_ ="\\"+$server_+"\"+$share_
$r=DelPrinterConnection( $disconnect_ ) SERVER=Second
endif SHARE=work\department2
ACCESSGROUP1=department2
ACCESSGROUP2=
DESCRIPTION="Ðåñóðñû îòäåëà 2"
Подключение сетевых дисков. Теория
Сценарий загрузки осуществляет подключение сетевых Таким образом, на основе данных, прочитанных сцена-
дисков пользователям в зависимости от их членства в груп- рием из примера, всем пользователям будет подключен
пах, аналогично подключению сетевых принтеров. Главная «Консультант+» на букву «L», находящийся по пути \\main\
особенность данного сценария заключается в том, что в нем consultant. Пользователям, являющимся членами групп
реализован механизм подключения различных ресурсов на departament1, departament2, departament3, будет подключен
одну и ту же букву. Реализовано для пользователей, вхо- диск W. Для членов групп departament1, departament3 под-
дящих в непересекающиеся группы безопасности. Необхо- ключается ресурс по адресу \\second\work\departament1, для
димо строго следить, чтобы членства пользователей в груп- departament2 – \\second\work\departament2.
пах, подключающихся на одну букву, не пересекались. Сценарий, обеспечивающий автоматическое управле-
Рассмотрим содержимое конфигурационного файла, ние подключением сетевых дисков, работает по схеме:
который представляет собой текстовый файл с произволь- ! Чистка локального кэша на рабочей станции, содержа-
ным расширением, например INI. щего список групп, в которые входит пользователь. Уда-
В файле в квадратных скобках перечислены названия ление ветви реестра HKEY_CURRENT_USER\Software\
разделов, которые включают в себя букву, на которую бу- KiXtart.

Ðèñóíîê 4

№12(25), декабрь 2004 85


образование
! Чтение параметрического файла. Данные рекомендует- ку группы, содержащие это сочетание символов, предназ-
ся помещать в соответствующие массивы. начены для управления принтерами и не принимают учас-
! Отключение всех доступных сетевых дисков. тия в процессе подключения сетевых дисков.
! Подключение сетевых дисков, на которые данный поль-
зователь имеет права. dim $usergroup_name[]
$k=0
! Вывод на экран статистики о подключенных сетевых DO
дисках. $Group = ENUMGROUP($i)

if instr("$Group","- Print")=0
$ug1_len=len($group)-instrrev($group,"\")
ReDim Preserve $usergroup_name[$k]
$usergroup_name[$k]=right($group,"$ug1_len")
$u_val=$usergroup_name[$k]
$k=$k+1
endif
$i=$i+1
UNTIL Len($Group) = 0

На следующем этапе осуществляется чтение конфигу-


рационного файла с расширением INI. Чтение параметри-
ческого файла осуществляется в соответствии с алгорит-
мом, приведенным на рис. 5. Итак, поскольку названия под-
разделов (значения, заключенные в INI-файлах в «квадрат-
ные» скобки) неизвестны, то сначала файл рассматрива-
ется как обычный текстовый файл, который читается пост-
рочно. Каждая строка анализируется, и если она включает
в себе символ «[», то содержимое, находящееся между
квадратными скобками, помещается в динамический мас-
сив $gr[]:

Ðèñóíîê 5 $i=1
dim $gr[]
open(2,"@LDRIVE/shared.ini",2) ; ôàéë shared.ini ↵
Подключение сетевых дисков. Практика ðàñïîëàãàåòñÿ â îäíîì êàòàëîãå ñî ñêðèïòîì –\\Server\Netlogon
В теоретической части был описан алгоритм, обеспечива- WHILE @ERROR = 0
ющий автоматическое управление подключением сетевых
$x=ReadLine(2)
дисков. Поскольку все этапы взаимосвязаны, то их необхо- $skoba=instrrev("$x","[")
димо рассматривать как единое целое. if $skoba<>0
ReDim Preserve $gr[$i]
Итак, сначала осуществляется чистка локального кэша $gr[$i]=right(left($x,len("$x")-1), ↵
на рабочей станции, содержащего список групп, в которые len(left($x,len("$x")-1))-1)
$i = $i + 1
входит пользователь. Эту процедуру рекомендуется выне- endif
сти в самое начало сценария загрузки, чтобы его работа LOOP
начиналась именно с очистки кэша.
Процедура удаления осуществляется с помощью функ- После того как сформирован массив, осуществляется
ции DelTree(): повторное чтение INI-файла. На этот раз он рассматрива-
ется как параметрический файл. Осуществляется чтение
DelTree("HKEY_CURRENT_USER\Software\KiXtart") параметров. По ходу чтения параметрического диска сна-
чала осуществляется попытка отключить сетевой диск, за-
Затем рекомендуется создать и наполнить данными ди- тем подключить его, если пользователь входит в соответ-
намический массив. Элементами этого массива являются ствующую группу безопасности. Таким образом, соблюда-
названия групп, в которые входит пользователь. В синтак- ется актуальность подключенных сетевых дисков.
сисе языка KIXTart существует специально созданная фун-
кция – EnumGroup(): $k=ubound($gr)
for $i=1 to $k
$letter=$gr[$i]
DO $serv=readprofilestring("$ini_file1", "$letter","server")
$Group = ENUMGROUP($i) $share=readprofilestring("$ini_file1", "$letter","share")
? $Group $accessgroup1=readprofilestring("$ini_file1", ↵
$i = $i + 1 "$letter","accessgroup1")
UNTIL Len($Group) = 0 $accessgroup2=readprofilestring("$ini_file1", ↵
"$letter","accessgroup2")
Переменная $Group содержит полное название группы. $description=readprofilestring("$ini_file1", ↵
"$letter","description")
Формат названия группы следующий: \\domain\group_name. $share_name="\\"+$serv+"\"+$share+""
Для подключения различных ресурсов необходимо вычле- $let=$letter+":"
$letter_S=left($letter,1)
нить имя группы без префикса в виде имени домена или use $letter_S /delete
рабочей станции. Попутно необходимо исключить группы,
if ingroup("$accessgroup1","$accessgroup2")
в названиях которых присутствует слово «- print», посколь- use $letter_S+":" $share_name

86
образование
endif лючив сбойный блок. Согласитесь, это гораздо лучше, чем
next иметь только 2 варианта, характеризующих работоспособ-
Замечание. Данные, содержащие в себе имя монтируе- ность – 0% и 100%.
мого диска в конфигурационном файле, имеют структуру – Реализация идеи следующая: из конфигурационного
название диска + номер. Нумерация сквозная. При под- файла (см. пример файла kix.ini) считываются параметры,
ключении ресурса нумерация отбрасывается. Таким спо- которые имеют значение 0 (выключено) и 1 (включено):
собом на одну и ту же букву монтируются различные ре- Пример файла kix.ini:
сурсы для разных пользователей. Соответственно необ-
ходимо помнить, что членства в группах не должны пере- [part]
print=1
секаться. share=1
sysinfo=1
Автоматическое конфигурирование
рабочей станции В таком случае структура скрипта будет выглядеть сле-
Поскольку скрипт выполняется от имени пользователя, ко- дующим образом:
торый не обладает правами системного администратора,
то изменения могут быть внесены только в ветвь HKCU. В $config_ini ="@LDRIVE/kix.ini"; ôàéë kix.ini ðàñïîëàãàåòñÿ ↵
â îäíîì êàòàëîãå ñî ñêðèïòîì - \\Server\Netlogon
этом разделе хранятся сведения о текущем зарегистриро-
ванном пользователе, и он имеет название, соответствую- open(1, $config_ini, 2)
………………………………; îïèñûâàþòñÿ ðàçëè÷íûå ãëîáàëüíûå ↵
щее значению идентификатора безопасности (SID) текуще- ïåðåìåííûå, îñóùåñòâëÿåòñÿ ñîåäèíåíèå ñ AD è äð.
го пользователя. Каждый раз при перезагрузке компьюте-
if readprofilestring("$config_ini","part","sysinfo")=1
ра раздел создается заново на основе данных, считанных ………………………………
из HKU. Автоматическое конфигурирование ветви HKU Endif
выполняется с помощью групповых политик (будет рассмот- if readprofilestring("$config_ini","part"," share ")=1
рено позже), а ветви HKCU – с помощью скрипта. ………………………………
Endif
В качестве примера приведем таблицу, в которой опи-
саны некоторые ключи и соответствующие им параметры, if readprofilestring("$config_ini","part"," print ")=1
………………………………
которые можно изменять на всех рабочих станциях домена Endif
каждый раз во время регистрации пользователей в сети с
помощью скрипта. Приведенный список краток. В печати и Таким образом, если необходимо протестировать какую-
в Интернете читатель сможет найти множество советов по либо новую функцию сценария, можно создать еще один
настройке реестра. раздел, например, «test», и размещать в нем тестируемый
Òàáëèöà 2 код.

Обеспечение интерактивности
работы скрипта
Сценарии на языке KIXTart можно визуализировать, по край-
ней мере, тремя способами:
! с помощью стандартных диалоговых окон;
! с помощью сторонней надстройки KIXTart в виде DLL-
библиотеки;
! c помощью сторонней утилиты, передающей парамет-
ры из KIXTart в HTML-файл.

Блочность скрипта Выбор варианта


Согласитесь, что скрипт – это программа, которая должна Рассмотрим все три способа:
отличаться стабильностью в своей работе. А разве это не
обязательно для всех без исключения программ? С другой Визуализация работы скрипта
стороны, используя его на практике, могу сказать, что в с помощью стандартных диалоговых окон
нем постоянно что-то изменяется и никто не застрахован В начале работы скрипта пользователю выводится инфор-
от ошибки. Тестирование на локальной машине и в сети, мация о том, что он начал функционировать. Основным не-
как говорят, две большие разницы. В данной статье рас- достатком этого метода визуализации является полное от-
смотрены только основные задачи, реально их гораздо боль- сутствие интерактивности работы сценария.
ше, например, в крупных организациях может быть акту-
ально автоматизированное подключение баз 1с в бухгал- Визуализация скрипта с помощью сторонней
терии и т. д. Поэтому правильным шагом будет создать кон- надстройки KIXTart в виде DLL-библиотеки
фигурационный файл для этого скрипта, который бы по- Визуализация и интерактивность работы скрипта реализу-
зволил оперативно управлять включением и выключением ется с помощью специально созданной для этих целей над-
различных блоков. В случае внештатной ситуации вы смо- стройки – KIXForms 3.2 или KIXGui 1.1. Обе программы мож-
жете сохранить работоспособность скрипта на 70-90%, вык- но загрузить с сайта http://www.kixtart.org.

№12(25), декабрь 2004 87


образование
У этих программ есть только один недостаток: для кор- DHTML возвращает в KIX код ошибки в виде целого числа,
ректной работы визуализационной части необходимо на ра- макросу @ERROR. В случае успешного завершения опе-
бочей станции зарегистрировать соответствующую DLL- рации @ERROR=0.
библиотеку. Для регистрации этой библиотеки необходи- Передача данных с помощью утилиты KIXWIN осуще-
мо обладать правами администратора. Конечно, можно со- ствляется сценарием загрузки следующим образом:
здать MSI-архив, который будет централизованно распрос-
траняться по сети с помощью групповых политик, но это shell '%0/../kixwin.exe $html "$system_info ^ ↵
$hardware_info ^ Óñòàíîâëåííûå ïðîãðàììû: $en $prog ^ ↵
неудобно. Использовать надстройки такого рода выгодно Ïîäêëþ÷åííûå ñåòåâûå äèñêè:$en $n1 ^ Ïîäêëþ÷åííûå ↵
только в небольших сетях с маленьким количеством рабо- ñåòåâûå ïðèíòåðû:$en $n2" "scroll:off;resizable:on"'
чих станций.

Визуализация работы скрипта c помощью DHTML-файл


сторонней утилиты, передающей параметры
из KIXTart в HTML-файл Основы формирования файла
Этот способ мне кажется наиболее оптимальным для реа- Как отмечалось ранее, параметры передаются DHTML-стра-
лизации визуализации и интерактивности работы скрипта нице, содержащей вставки на VBScript. При загрузке стра-
в крупных сетях, поскольку утилита самодостаточна и пред- ницы в теге body указывается функция, например,
ставляет собой файл с расширением EXE, который реко- onload=”startrun()”, с помощью которой запускается таймер.
мендуется располагать в каталоге Netlogon, вместе со В том случае, если таймер не прерван, то по окончанию
скриптом. KixWin 1.1 (http://www.kixtart.org) вызывается из отсчета автоматическое закрывание окна и продолжения
скрипта с набором параметров. Затем она передает эти процесса загрузки компьютера:
параметры в DHTML-файл. Для корректной работы визуа-
лизационной части необходимо дать ему право на запись в <BODY onload="startrun()" TEXT="BLACK" …>
………………………………………………………
папке, в которой находится DHTML-файл.
Раздробление скрипта на две части является основным <Script Language="JavaScript">
function startrun()
недостатком данного варианта. DHTML-файл вместе с со- {
путствующими ему файлами (GIF, JPEG, CSS) рекоменду- window.form1.textarea1.value="Ïðîöåññ íàñòðîéêè êîìïüþòåðà ↵
çàâåðøåí.\nÄëÿ ïðîäîëæåíèÿ íàæìèòå êíîïêó ÏÐÎÄÎËÆÈÒÜ ↵
ется располагать в скрытой сетевой папке. DHTML-файл èëè ïîäîæäèòå 7ñåê. – îêíî çàêðîåòñÿ ñàìî."
содержит в себе сценарии, созданные с помощью VBScript timer1=setTimeout('exit()', 20000);
}
или JScript. …
</Script>
</BODY>
Синтаксис KIXWin
Приведем синтаксис утилиты и фрагмент DHTML-файла: Как видно из примера, в текстовой области выводится
сообщение о том, что настройка рабочей станции завер-
kixwin "dialog" ["arguments"] ["options"] шена и запускается таймер. Если ни одна кнопка на клави-
атуре не нажималась в течение 20 000 мсек, то осуществ-
Описание параметров: ляется вызов функции exit(), которая закрывает окно брау-
! «dialog» – строка, содержащая строку в формате URL к зера (листинг DHTML-файла на www.samag.ru/source).
HTML-документу. Кнопки, при нажатии на которые отображается инфор-
! «arguments» – строка, содержащая параметры, переда- мация различного рода, представляют собой картинку с
ваемые из KIX в HTML. Для разделения параметров в надписями на ней, которая разделена на различные облас-
HTML-файле используют строку window.dialogArguments. ти. При нажатии на описанные области осуществляется
split(«;»). В данном примере разделителем параметров запуск соответствующей функции, которая, в свою очередь,
является «;». отображает информацию, переданную из скрипта в тексто-
! «style» – строка, которая определяет оформление диа- вую область window.form1.textarea1:
логового окна. Используются один или несколько из сле-
дующих параметров стиля: ……

<img src="bar2.jpg" name="imgAdvert" usemap="#Prosv" border=0>


dialogHeight:sHeight <map name="Prosv">
dialogLeft:sXPos <area onclick=system() alt="Ñâåäåíèÿ îá îïåðàöèîííîé ↵
dialogTop:sYPos ñèñòåìå" shape=circle coords="69,40,50">
dialogWidth:sWidth <area onclick=hardware() alt="Ñâåäåíèÿ î êîìïüþòåðå" ↵
center:{ yes | no | 1 | 0 | on | off } shape=circle coords="166,40,50">
dialogHide:{ yes | no | 1 | 0 | on | off } ……
edge:{ sunken | raised } </map>
help:{ yes | no | 1 | 0 | on | off }
resizable:{ yes | no | 1 | 0 | on | off } <Script Language="JavaScript">
scroll:{ yes | no | 1 | 0 | on | off } ……
status:{ yes | no | 1 | 0 | on | off } function system()
unadorned:{ yes | no | 1 | 0 | on | off } {
clearTimeout(timer1);
var argv;
Логическое разделение передаваемых параметров осу- argv = window.dialogArguments.split("^");
ществляется с помощью заранее оговоренного символа. document.all.parametr0 = argv[0];

88
образование
window.form1.textarea1.value='' набора файлов, необходимых KIX для работы на данной
window.form1.textarea1.value=document.all.parametr0 платформе. А затем запускает скрипт.
}
function hardware() @ECHO OFF
{
clearTimeout(timer1); if c:\%os%==c:\ goto win9x
var argv; if not c:\%os%==c:\ goto winnt
argv = window.dialogArguments.split("^");
document.all.parametr1 = argv[1]; :winnt
window.form1.textarea1.value='' start /wait Kix32.exe Script.kix
window.form1.textarea1.value=document.all.parametr1 goto kix
}
… :win9x
copy %0\..\win9x\*.dll c:\windows\system /y
%0\..\Kix32.exe %0\..\Script.kix
Обратите внимание, что при вызове любой функции осу- goto kix
ществляется прерывание таймера функцией clearTime :kix
out(timer1), затем чтение соответствующего аргумента. @echo End Of Batch File

Обеспечение удобства Пояснения к синтаксису файла START.BAT:


Для обеспечения удобства работы со сценарием необхо- ! Принцип определения операционной системы основан
димо изменить представление окна браузера: сделать его на том, что в Win9x отсутствует переменная окружения
неизменяемым, убрать различные панели инструментов %os%. В Windows 2k переменная %os%=WindowsNT.
и т. д. (см. рис. 6). Для того чтобы информация выводилась ! С помощью строки «start /wait Kix32.exe Script.kix» до-
корректно, необходимо в теге META указать кодировку, в биваются последовательной загрузки – сначала скрипт,
которой должны быть отражены символы, а именно затем рабочий стол и т. д., а не одновременной. То есть
Windows-1251: на время выполнения скрипта многозадачность «отклю-
чается». Это делается для того, чтобы до окончания дей-
<META http-equiv=Content-Type content="text/html; ↵ ствия скрипта дальнейшая загрузка операционной сис-
charset=windows-1251">
темы не производилась.
! Для корректной работы win9x, в качестве пути к файлу
необходимо указывать «%0\..\filename.ext». Windows XP
не воспринимает относительного пути «%0/./», поэтому
для Windows семейства 2k необходимо указать только
имя файла, который находится в папке Netlogon.

Ðèñóíîê 6

Внедрение скрипта в эксплуатацию


Скрипт выполняется каждый раз при регистрации пользо-
вателя в сети, если он указан в разделе Profile свойствах
пользователя (см. рис. 7) службы Active Directory: Users and
Computers.
Для автоматизации установки KIXtart на рабочих стан-
циях домена предлагается следующее: в папку Netlogon по-
местить файлы:
! KIX32.EXE ! KIXWIN.EXE
! SCRIPT.KIX ! KIX.INI
! START.BAT ! SHARED.INI
! подкаталог Win9x, содержит файлы KX16.DLL и KX32.DLL

В скрытую сетевую папку скопировать DHTML-файл и


все сопутствующие ему файлы.
В ходе выполнения файла START.BAT определяется тип Ðèñóíîê 7
операционной системы, установленной на рабочей станции, На время выполнения скрипта необходимо скрыть CMD-
и в зависимости от результатов происходит копирование панель, в которой выполняется скрипт, и приостановить заг-

№12(25), декабрь 2004 89


образование
рузку рабочего стола до окончания всего скрипта. Этого ! Перейти во вкладку вкладку «Group Policy» и загрузить
результата добиваются с помощью групповой политики, рас- «Default Dоmain Policy» (см. рис. 9).
пространяющейся на домен («Default Domain Controllers
Policy»).

Ðèñóíîê 9
! В загруженной групповой политике (Default Domain
Policy) необходимо в «User Configuration» (настройках
пользователя) войти в «Administrative Templates» (адми-
Ðèñóíîê 8 нистративные шаблоны). Там выбрать раздел «System»
В разделе групповой политики «User Configuration» не- (система), вкладку «logon/logoff» (войти/выйти) и вклю-
обходимо соответственно включить «Run legacy logon script чить раннее оговоренные политики (см. рис. 10).
synhronously» (запускать сценарий загрузки синхронно) и
«Run legasy script hidden» (запускать сценарий скрыто). Для На этом создание полноценного сценария загрузки за-
этого необходимо проделать следующее: вершено. Необходимо отметить, что с введением такого
! Зарегистрироваться на сервере с помощью учетной за- продукта в эксплуатацию, затраты на поддержку значитель-
писи, имеющей административные права. но сокращаются. Надеюсь, что создание такого рода сце-
! Загрузить в Active Directory Users and Computers (Start → нария принесет вам значительное облегчение в работе.
Programs → Administrative Tools) и войти в свойства кон- Листинг скрипта и всех вспомогательных подпрограмм
троллера домена (см. рис. 8). приведен на сайте журнала http://www.samag.ru/source.

Ðèñóíîê 10

90
bugtraq

Раскрытие SMB-паролей в KDE Выполнение произвольного кода


Программа: KDE 3.2.x, 3.3.0, 3.3.1, and 3.3.2. в Microsoft Windows Resource Kit
Опасность: Средняя. Программа: Microsoft Windows 2000/XP Resource Kit.
Описание: Обнаружена уязвимость в KDE. Атакующий мо- Опасность: Средняя.
жет получить пароль пользователя на доступ к удаленному Описание: Обнаружено несколько уязвимостей в Microsoft
ресурсу. Windows 2000/XP Resource Kit. Удаленный атакующий мо-
Когда пользователь создает ссылку на удаленный файл, жет выполнить произвольный код на уязвимой системе. Уда-
используя любое KDE-приложение, эта ссылка может со- ленный атакующий может предпринять XSS-нападение.
держать пароль на доступ к удаленному файлу. Пароль для Уязвимость существует в w3who.dll в расширении ISAPI
SMB-ссылок всегда добавляется к URL в виде обычного тек- для Windows 2000/XP Resource Kit из-за некорректной об-
ста и сохраняется в ярлыке («*.desktop»-файл). работки входных данных пользователей перед отображе-
URL производителя: www.kde.org. нием их в HTTP-заголовках или в сообщениях об ошибках.
Решение: Установите обновления. Удаленный атакующий может создать специальным обра-
1. Патчи для KDE 3.3.1 зом URL и выполнить произвольный HTML-код в браузере
ftp://ftp.kde.org/pub/kde/security_patches: целевого пользователя. Примеры:
501852d12f82aebe7eb73ec5d96c9e6d post-3.3.1-kdebase-
smb.diff Connection: keep-alive<script>alert(«Hello»)</script>
/scripts/w3who.dll?bogus=<script>alert(«Hello»)</script>
5b9c1738f2de3f00533e376eb64c7137 post-3.3.1-kdelibs-
khtml.diff Переполнение буфера существует при обработке вход-
f287c900c637af2452c7a554f2df166f post-3.3.1-kdelibs- ных параметров URL. Удаленный атакующий может с по-
kio.diff мощью специально сформированного URL вызвать пере-
2. Патч для KDE 3.3.2 полнение буфера и потенциально выполнить произвольный
ftp://ftp.kde.org/pub/kde/security_patches: код на системе. Пример:
d3658e90acec6ff140463ed2fd0e7736 post-3.3.2-kdelibs-
kio.diff /scripts/w3who.dll?AAAAAAAAA...[519 to 12571]....AAAAAAAAAAAAA
3. Патчи для KDE 3.2.3 URL производителя: www. microsoft.com.
ftp://ftp.kde.org/pub/kde/security_patches: Решение: Решения не существует на данный момент.
d080d9acf4d2abc5f91ccec8fc463568 post-3.2.3-kdebase-
smb.diff Раскрытие информации в Squid
d79d1717b4bc0b3891bacaaf37deade0 post-3.2.3-kdelibs- Программа: Squid 2.5.
khtml.diff Опасность: Низкая.
94e76ec98cd58ce27cad8f886d241986 post-3.2.3-kdelibs- Описание: Обнаружена уязвимость в Squid. Удаленный ата-
kio.diff кующий может получить внутреннюю информацию от це-
левого сервера.
Переполнение буфера Удаленный атакующий может послать серверу ряд спе-
в Microsoft HyperTerminal циально сформированных запросов к несуществующим хо-
Программа: Microsoft Windows 2000 Advanced Server, стам, и заставить Squid возвращать в качестве сообщения
Microsoft Windows 2000 Datacenter Server, Microsoft Windows об ошибке случайные данные, которые могут содержать ин-
2000 Server, Microsoft Windows NT 4.0 Server, Microsoft формацию о запросах других пользователей. Пример:
Windows NT 4.0 Server, Terminal Server Edition, Microsoft
Windows Server 2003 Datacenter Edition, Microsoft Windows http://./.gz/
Server 2003 Enterprise Edition, Microsoft Windows Server 2003 URL производителя: www.squid-cache.org.
Standard Edition, Microsoft Windows Server 2003 Web Edition, Решение: Установите обновление: http://www.squid-cache.org/
Microsoft Windows XP Home Edition, Microsoft Windows XP Versions/v2/2.5/bugs/squid-2.5.STABLE7-dothost.patch.
Professional.
Опасность: Средняя. Обход защиты
Описание: Обнаружена уязвимость в Microsoft HyperTerminal. персональных брандмауэров
Удаленный атакующий может выполнить произвольный код Программа: большинство персональных брандмауэров.
на уязвимой системе. Опасность: Низкая.
Уязвимость обнаружена при обработке файлов сессий Описание: Вредоносное программное обеспечение может
и telnet-ссылок. Удаленный атакующий может специальным реализовать атаку типа shatter на разрешенное брандмау-
образом создать файл сессии (.ht) для HyperTerminal или эром GUI-приложение и выполнить произвольный код в его
URL для telnet и выполнить произвольный код на системе контексте. После этого вредоносное программное обеспе-
целевого пользователя. чение получает возможность взаимодействовать с внешни-
URL производителя: www.microsoft.com. ми сетями в обход политик безопасности брандмауэра.
Решение: Установите обновления с сайта производителя. Решение: Решения не существует на данный момент.

Составил Александр Антипов

№12(25), декабрь 2004 91