025 Системный Администратор 12 2004

Page 1

№12(25) декабрь 2004 подписной индекс 81655 www.samag.ru

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

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

Обработка переадресованных http-запросов Автоматизация FTP с помощью Python



оглавление 2 БЕЗОПАСНОСТЬ Защита сетевых сервисов с помощью stunnel

РЕПОРТАЖ АДМИНИСТРИРОВАНИЕ Linspire одним глазком

Андрей Бешков Валентин Синицын

4

val@linuxcenter.ru

Идеальный карманный компьютер для системного администратора Часть 2

42

tigrisha@sysadmins.ru

Железный login: ломаем зубы грубой силе Александр Похабов

48

chiko@agk.ru

Андрей Маркелов

8 Тени исчезают в полдень

andrew@markelov.net

Дистрибутив для всех

Сергей Яремчук

54

grinder@ua.fm

Сергей Яремчук grinder@ua.fm

Копирование файлов в автоматическом режиме с множества компьютеров через SSH

10 WEB PHP-GTK Андрей Уваров

60

dashin@ua.fm

Рашид Ачилов shelton@granch.ru

Единая учетная запись для Windows и UNIX в Active Directory Игорь Полянский ipoliansky@mail.ru

12 Обработка переадресованных http-запросов Алексей Мичурин

18

FreeBSD tips: настройка VLAN Сергей Супрунов amsand@rambler.ru

24

info@samag.ru

Пакетный фильтр OpenBSD Часть 2

HARDWARE Запись дисков CD-R/RW в Linux Часть 2 Владимир Мешков

68

ubob@mail.ru

Биллинг для АТС на базе PostgreSQL Георгий Толоконников

62

alexey@office-a.mtu-net.ru

ОБРАЗОВАНИЕ 26 Файловая система NTFS извне и изнутри Часть 2 Крис Касперски

76

kk@sendmail.ru

Денис Назаров pheonix@sysattack.com

Настоящий UNIX в наши дни Александр Байрак x01mer@pisem.net

30 Разработка сценария регистрации пользователей в сети Часть 2 34

Автоматизируем FTP с помощью Python Сергей Супрунов amsand@rambler.ru

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

Иван Коробко

82

ikorobko@prosv.ru

Содержание журнала за 2004 год

36 BUGTRAQ

92

33, 53, 91, 94 1


репортаж

AGNITUM OUTPOST OFFICE FIREWALL НОВЫЙ АСПЕКТ КОРПОРАТИВНОЙ ЗАЩИТЫ 3 декабря 2004 года компания Agnitum (www.agnitum.com) – разработчик популярного персонального брандмауэра Outpost Firewall Pro анонсировала выход новой версии своего продукта – Outpost Office Firewall, нацеленного на использование в корпоративных локальных сетях в качестве средства персональной защиты клиентских компьютеров. Новая разработка явилась продолжением работы над очередной версией брандмауэра – Outpost Firewall Pro 2.5. Стоит отметить, что речь идет не о серверном варианте Outpost Firewall, а именно об офисной версии, то есть специализированном ПО, предназначенном для массового развертывания в корпоративной сети, на компьютерах пользователей. Презентация проходила в Санкт-Петербурге, на борту легендарного крейсера «Аврора», что само по себе явилось удивительным сюрпризом. Главный менеджер по продажам Николай Васильев и координатор российского проекта, организатор презентации Ольга Величко (на фото) рассказали, что они давно хотели провести презентацию на этом историческом крейсере под лозунгом «Революция в мире информационных технологий». В назначенное время у трапа крейсера собрались журналисты практически всех популярных IT-изданий России. На борту представителей прессы встречали В.И. Ленин и военные матросы, вручая каждому морскую бескозырку с ленточкой, на которой было написано «Outpost Firewall Pro». Расскажем о впечатлениях от анонса и о заявленных возможностях нового продукта. В качестве клиентской части Outpost Office Firewall будет содержать некоторое подобие Outpost Firewall Pro 2.5. Дистрибутив брандмауэра поставляется в формате MSI, что позволяет для развертывания его в домене Active Directory использовать групповые политики. К сожалению, в пилотной версии другие возможности удаленной установки поддерживаться пока не будут. Таким образом, автоматическое развертывание Outpost Firewall будет возможно только в доменах Active Directory и только на компьютерах с Windows 2000 и старше. В остальных случаях установку придется произвести вручную. Возможность удаленной установки при помощи RPC, а не через групповые политики планируется реализовать в следующих версиях.

Клиентская часть после установки взаимодействует с сервером и нацелена на работу в корпоративной сети. В частности, контроль компонентов приложений (Component Control) и контроль скрытых процессов (Hidden Process Control) будут выключены по умолчанию, а брандмауэр будет загружаться в фоновом режиме. Это обеспечит минимальное вовлечение пользователя в процесс защиты компьютера – многочисленные запросы сетевого доступа приложениями могли бы ввести неопытного пользователя в замешательство. К сожалению, клиентская часть Outpost Office Firewall несовместима с предыдущими версиями программы. Если на некоторых компьютерах уже установлена одна из предыдущих версий, включая Outpost Firewall 2.5, ее необходимо полностью удалить перед установкой офисного варианта. Новых серьезных изменений по сравнению с версией 2.5 в клиентской части практически не будет. Функциональность нового продукта будет постоянно улучшаться, а переговоры с создателями антивирусных продуктов о реализации совместных решений помогут привести к созданию надежной комплексной защиты. Например, реализовать защиту от программ типа Ad-Aware, количество которых в последнее время угрожающе растет. Средством управления и мониторинга будет служить Outpost Command Center, выполненный в виде оснастки «Консоли управления» (MMC snap-in), через который осуществляется управление службами, запуск редактора настроек и публикация конфигураций для клиентских машин. Одновременно с ним устанавливается редактор настроек, предназначенный для конфигурирования брандмауэра на клиентских машинах, а также «Служба обновлений» и «Служба публикации». Конфигурации клиентам передает «Служба публикации». Она запускается на том же сервере, где и «Командный центр» Outpost, и также управляется с его помощью. При каждой загрузке компьютер пользователя запрашивает у сервера конфигурацию. Если были созданы и опубликованы новые настройки, то «Служба публикации» передает клиенту файл по внутреннему протоколу. После получения настроек брандмауэр на компьютере пользователя применяет их. Период запроса клиентами обновлений конфигурации – изменяемый параметр. Однако форсировать немедленное обновление на клиентах пока нельзя. Возможно, это появится в следующих версиях. В первой версии Outpost Office Firewall не предвидится возможности назначения разных конфигураций различным группам клиентов, а также не планируется разрешать редактирование отдельных записей в конфигурации без затрагивания остальных параметров. По словам представителей компании выпуск коммерческой версии продукта ожидается примерно в феврале 2005 года.

Роман Марков Фото автора

2



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

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

ВАЛЕНТИН СИНИЦИН Фирма Linspire (www.linspire.com) – ветеран движения за популяризацию Linux, хотя самой торговой марке едва насчитывается пять месяцев. Между тем компания была основана в далеком 2001 году. С тех пор и по сей день ее бессменным управляющим является всемирно известный авантюрист-инноватор Майкл Робертсон (Michael Robertson), создатель портала MP3.com. Первоначально компания называлась Lindows, а ее основное детище и герой сегодняшней статьи, настольный дистрибутив Linux, – LindowsOS. Такое явное созвучие с «Окнами» не могло понравиться корпорации Microsoft и очень быстро стало предметом многочисленных судебных разбирательств как на территории США, так и за их пределами. Тяжба не утихала в течение нескольких лет, причем фортуна практически равным образом благоволила как той, так и другой стороне. Вконец погрязнув в пучине судебных баталий, Lindows, Inc. и Microsoft в июле этого года пришли к мировому соглашению, по которому все права на торговую марку «Lindows» и соответствующие доменные имена отошли в «Редмонд», правда, не безвозмездно. Размер контрибуции составил около 20 млн. долларов. Вполне удовлетворенная исходом дела, Lindows сменила имя на Linspire и с большой выгодой продала свою прежнюю вывеску на аукционе eBay. На сегодняшний день компания представляет широкий модельный ряд, включающий базовую редакцию Linspire 4.5, профессиональную Linspire 4.5 Developers Edition, загружаемый диск LinspireLive! и специальную версию LinspireEspaсol для испаноязычных пользователей. Помимо этого имеются различные дополнения, например, LinspireOffice. Ранее существовала еще одна разновидность – Laptop Edition, предназначенная для ноутбуков, но сейчас она, по-видимому, слилась с базовой версией. Как и многие настольные дистрибутивы, Linspire является коммерческим программным продуктом. Цена базовой редакции – 49,95 доллара. Версия для разработчиков стоит чуть дороже – $59,95. LinspireLive! можно приобрести за $19,95 или (официально!) загрузить через файлообменную сеть BitTorrent. Выбрав столь оригинальный (для по-

4

ставщиков закрытого ПО) канал доставки, компания вызвала сильное удивление у коллег по цеху, а г-н Робертсон в очередной раз подтвердил звание большого затейника. Подробности доступны по адресу: http://info.linspire.com/p2p/ p2p-pr.html. Иногда (правда, в последнее время все реже и реже) Linspire проводит промо-акции, в ходе которых требуется угадать текст купона (как правило, это нечто очевидное для тех, кто внимательно следит за заголовками новостных лент), ввести его и получить стопроцентную скидку в интернет-магазине компании. После этого ISO-образ дистрибутива можно загрузить бесплатно через HTTP или все тот же BitTorrent. В данном обзоре мы рассмотрим основные возможности Linspire 4.5.189 Developers Edition, датированной январем 2004 года. С тех пор было выпущено несколько исправлений (об их роли в этой истории мы поговорим чуть позже), однако базовая функциональность системы не претерпела существенных изменений.

Делай раз: установка Итак, вставляем компакт-диск с Linspire в оптический привод и перезапускаем компьютер. Нашему взору представляется графический splash-экран с логотипом компании и меню с двумя загрузочными опциями: Install и Diagnostic. Последний вариант может использоваться для тонкой (экспертной) настройки параметров или восстановления системы. Выбрав его и подождав достаточное время, можно попасть в текстовую консоль и, например, переразбить жесткий диск, пользуясь командой fdisk или же реанимировать файловую систему с помощью fsck. Из важных утилит в этом режиме не доступен, пожалуй, один hdparam (читатели, у которых хотя бы раз «взрывался» хорошо раскрученный CD-ROM, меня поймут). Впрочем, развитие промышленности идет семимильными шагами и несбалансированные/некачественные диски сейчас встречаются все реже и реже. Сделав все необходимое, можно начать установку Linspire командой startx или же выйти из диагностического режима, набрав exit.


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

Ðèñóíîê 1. Êëèåíò Click-N-Run

Программа-инсталлятор, напротив, является воплощением простоты. Достаточно упомянуть, что она состоит максимум из четырех экранов. Вначале пользователю предлагается выбрать один из двух режимов: Take Over An Entire Hard Disk («Занять жесткий диск целиком» – режим по умолчанию, хорошо подходит для установки на чистый неразмеченный диск и не требует вмешательства пользователя) или Advanced Install. «Продвинутость» в данном случае означает возможность указать существующий раздел для инсталляции корневой файловой системы. Изменить их структуру программа не позволяет, вероятно, для того, чтобы неопытный пользователь нечаянно не уничтожил данные на соседнем Windows-разделе. После осуществления выбора мы переходим на третий экран, где предлагается ввести имя для нашего компьютера и пароль. Последняя настройка является необязательной, что очень понравится пользователям Windows 9x и приведет в ужас бывалых администраторов. Программа не проверяет введенные пароли на прочность: хотите «123456» – пожалуйста. После заполнения данных полей ваше участие в процессе заканчивается и система приступает к копированию файлов. Вполне оправдывающий себя подход, по крайней мере до тех пор, пока не возникнет внештатная ситуация. Сообщения инсталлятора об ошибках малоинформативны и обычно состоят из числового кода, краткого описания (например: «200: rsync failed» или «255 Unspecified Error») и предложения обратиться в службу технической поддержки, которая, как следует из периодически появляющейся в ходе установки рекламной картинки, доступна через Web и по телефону, правда, не круглосуточно. Опыт показывает, что специалисты откликаются достаточно быстро, однако на вопрос о причинах неудачи разводят руками: мол ошибка, знаем, работаем. Возможно, build 189 был в этом отношении не слишком успешным (как уже упоминалось ранее, с тех пор вышло несколько исправлений, и текущий релиз имеет номер 444), но мне с трудом удалось найти компьютер, на который Linspire поставился без сучка и задоринки. Особенно обидно, что в число «неприкасаемых» попал и мой ноутбук, с помощью которого предполагалось проверить на практике, насколько хорошо система поддерживает работу с беспроводными сетями. Эта возможность широко рекламируется в руководстве пользователя, что внушает некоторое уважение: прочие дистрибутивы Linux, ори-

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

ентированные на ту же целевую аудиторию, стали продвигать совместимость с WiFi лишь к концу 2004 года (моя версия Linspire, напомню, была выпущена в январе). Возможно, эти ошибки уже исправлены, однако достоверных сведений на сей счет у меня нет. В процессе установки программа сама отформатирует предназначенный системе раздел. В качестве файловой системы по умолчанию (впрочем, этот термин здесь не вполне уместен, ведь ничего другого выбрать не предложили) используется ReiserFS, что неудивительно – Linspire спонсирует ее разработчиков, о чем красноречиво свидетельствует лейбл на сайте Namesys (www.namesys.com). Эта компания вообще поддерживает или принимает участие в достаточно большом числе открытых проектов, в том числе KDE (www.kde.org) и Mozilla (www.mozilla.org), и даже с некоторых пор имеет собственную Open Source инициативу – Nvu (www.nvu.com), задача которой ни много ни мало – создать свободный аналог Macromedia DreamWeaver и Microsoft Frontpage. В качестве основы используется редактор Mozilla Composer. Проект делает определенные успехи: по крайней мере все новые страницы на сайте Linspire разработаны с помощью Nvu. Завершив (ура!) копирование файлов, инсталлятор выдаст соответствующее сообщение и предложит перезагрузить систему. Добро пожаловать в мир настольного Linux!

Делай два: первый запуск и постинсталляционная настройка После неизбежного перезапуска мы видим уже знакомую заставку и меню, на этот раз содержащее три опции. Две из них нам хорошо известны и предназначены для нормального старта системы и перехода в экспертный режим. Средняя, «Redetect», используется для обнаружения нового оборудования. Дождавшись загрузки системы (наберитесь терпения – как и многие настольные дистрибутивы, Linspire не слишком легок на подъем. Это неизбежная плата за отсутствие тонкой настройки) и введя пароль (если таковой имеется), мы окажемся в окне мастера первого запуска, который предложит нам ознакомиться с лицензией и установить ряд параметров. Беглый взгляд на соглашение конечного пользователя (EULA) обнаруживает занятную вещь – лицензия Linspire является Family Friendly. Говоря русским языком, одну копию системы можно легально установить на неограниченное число компьютеров, владельцы которых составляют одну семью. Не вдаваясь в юридические тонкости, отметим явное преимущество такого договора как для нас с вами, так и для производителя: если отечественный пользователь худо-бедно свыкся с мыслью о том, что программы имеют лицензию, которую надо соблюдать, то платить за себя, за маму и за папу он точно не станет. Нажав на расположенную в окне кнопку «Advanced», можно добавить новые учетные записи (по умолчанию вы заходите в систему как root) или настроить экранное разрешение, глубину цвета и частоту развертки (в состав Linspire входят фирменные драйверы ATI и Nvidia, поэтому приготовьтесь к высокому refresh rate). Программа также предложит вам настроить системное время. Выполнив все необходимые операции, можете спокойно выходить из мастера. Вас ждет сюрприз: одно из фирменных аудиоруководств Linspire! В

5


администрирование ходе интерактивных уроков, выполненных с использованием технологии Macromedia Flash (конечно, проигрыватель Flash-роликов также включен в комплект поставки), пользователь может получить представление о возможностях системы и приобрести базовые навыки работы с нею. Значительная часть первого руководства посвящена технологии CNR («Click-N-Run»), речь о которой пойдет чуть ниже. К сожалению, эта красота требует жертв: после нескольких уроков, прослушанных на моем компьютере, диктор стал «заикаться», а потом и вовсе умолк. Пришлось лечить систему с помощью Quick Restart, по-простому – перезагрузки X-сервера.

Ðèñóíîê 2. Linspire 4.5: ðàáî÷èé ñòîë ïî óìîë÷àíèþ

Как и многие современные дистрибутивы, Linspire немыслим без Интернета. По утверждению разработчиков, кабельное подключение система распознает и конфигурирует в полуавтоматическом режиме (пользователю может потребоваться ввести IP-адрес и т. п.). Для «счастливых» владельцев модемов на рабочий стол вынесена специальная пиктограмма – Internet Connection Tools. Создатели Linspire позаботились о клиентах крупнейших интернет-провайдеров США (AOL, Juno, Earthlink и т. д.) – им достаточно просто щелкнуть по иконке с нужным именем. Остальным предлагается настроить KPPP (а именно эта утилита используется для доступа в Интернет) вручную – подробное руководство прилагается. Сверх указанных авторами мер мне пришлось лишь указать устройство, к которому подсоединен мой модем, в настройках этой замечательной утилиты. Теперь, когда вы подключены к Всемирной паутине, настало время познакомиться с «жемчужиной» Linspire – CNR Warehouse.

Делай три: Кладовая «Раз – и готово» Не пугайтесь непривычных слов: примерно так переводится на русский язык словосочетание «Click-N-Run Warehouse», обозначающее технологию, разработанную в Linspire с целью упрощения установки нового ПО и обновления системы. Зависимости всегда были бичом Linux, и любой создатель дистрибутива, претендующий на место в сердцах среднестатистических пользователей, должен позаботиться о скруглении «острых углов». В настоящий момент с помощью CNR Warehouse можно установить более 1900 про-

6

грамм, как открытых, так и коммерческих. Для этого потребуется доступ в Интернет и несколько щелчков мышью. Клиент Click-N-Run (рис. 1) автоматически скачает и установит выбранные вами программы, а также позволит добавить иконку на рабочий стол или в меню Autostart. Вы можете инсталлировать как отдельные приложения, так и целые наборы – «Aisles», созданные разработчиками Linspire или другими пользователями. Членство в CNR платное (4,95 доллара в месяц или 49,95 год), однако «прикоснуться к прекрасному» можно и даром. Достаточно ввести номер кредитной карточки, и в течение 15 дней вы можете прекратить подписку, не заплатив ни цента за загруженный софт. Переведя эти деньги в отечественную валюту, получим 120-150 рублей в месяц, то есть намного меньше, чем большая часть жителей нашей страны тратит на сотовый телефон. Важным ограничивающим фактором является ширина канала: скачать большую часть интересных приложений по модему практически нереально, а оплата трафика при использовании выделенной линии может влететь в копеечку. Таким образом, целевая аудитория CNR Warehouse у нас в России, по сути, ограничена пользователями unlimitedтарифов. Большая часть репозитария CNR бесплатна для подписчиков, исключения составляют коммерческие приложения, на которые предоставляются ощутимые скидки. Единожды загрузив как ую-либо программу из CNR Warehouse, вы становитесь ее собственником навеки и сможете вновь получить к ней доступ, когда потребуется. Существование этого банка программ создает определенную специфику Linspire. В состав системы включен самый минимум приложений (нет ни офисного пакета, ни графического редактора, ни проигрывателя видеофильмов). Все остальное предлагается загружать из CNR. Каждый пункт меню «Launch» (аналог кнопки «Пуск» Windows) включает обязательную ссылку на Warehouse, поэтому логотип данной технологии – бегущий человек в зеленом круге – вы будете видеть довольно часто. Постоянное желание «выклянчить пару баксов» является несомненным минусом Linspire. Впрочем, выход, как всегда, есть. Дистрибутив основан на Debian и содержит необходимый для опытного пользователя инструментарий: dpkg и apt-get, с помощью которого можно устанавливать пакеты в формате deb. Редакция Developers Edition, помимо этого, включает в себя полный комплект средств разработки (в том числе среду KDevelop), что позволяет собирать пакеты из исходных текстов. Может быть, это и неэстетично, но по крайней мере дешево. Таким образом я скомпилировал «программу в правом нижнем углу» – системный монитор gkrellm (http://web.wt.net/~billw/gkrellm/gkrellm.html). В меню утилита не появилась, но зато работала как часы. Другое дело, захочет ли Пользователь с большой буквы связываться с инструментами командной строки? Можно сказать, что CNR Warehouse отражает идеологию Open Source: брать деньги не за ПО, а за услуги, то есть за желание клиента не делать чего-то самостоятельно. Однако, несмотря на все многообразие приложений для Linux, пользователь может захотеть запустить и какую-то программу для Win32, например, игру. Что же предоставляет Linspire для этой категории граждан? Исходной целью


администрирование разработчиков Lindows была практически стопроцентная совместимость с Windows-приложениями (отчасти поэтому ей и было присвоено столь «неудачное» имя). Стремясь достичь ее, компания не жалела денег на инвестиции, в первую очередь, в проект Wine (http://www.winehq.com). Однако, спустя некоторое время г-н Робертсон изменил курс. Сославшись на дороговизну продуктов для Windows, он предложил сконцентрировать все усилия на написании их полноценных аналогов (чем компания сейчас и занимается, достаточно вспомнить тот же Nvu). Было ли это реальной причиной или же стопроцентная эмуляция Win32 API оказалась чересчур трудоемкой задачей, науке доподлинно неизвестно, но факт остается фактом: в смысле двоичной совместимости с Windows у пользователей Linspire нет особых преимуществ перед «простыми смертными». Через CNR Warehouse доступны все те же Wine, NeTraverse Win4Lin (около 70 долларов с учетом «клубной скидки») и WineX (приблизительно 15 долларов). Весьма популярный пакет CrossOver Office, базирующийся на Wine, и входящий в комплект поставки конкурентов Linspire (Lycoris Desktop/ LX и Xandros), в CNR Warehouse отсутствует. Как вы уже, наверное, обратили внимание, названия интерфейсных элементов в данной статье приводятся на английском языке. Это происходит вовсе не из-за прозападной ориентации автора – английский является языком Linspire по умолчанию, а помимо него, система официально поддерживает лишь испанский. В отличие от Linare (см. статью «Заметки о Linare», журнал «Системный администратор», №11, ноябрь 2004 г.), где поддержка кириллицы выдрана с корнем, научить Linspire хоть как-то говорить порусски возможно. Для этого потребуется установить стандартный пакет локализации KDE и шрифты все из того же CNR Warehouse. Среди заслуживающих внимания приложений, входящих в состав «Кладовой», следует назвать авторские разработки Linspire: аудиоплейер в стиле «все в одном2 Lsongs (http:/ /info.linspire.com/lsongs), аналогичный iTunes и фотоальбом Lphoto (http://info.linspire.com/lphoto), заменяющий iPhoto. Обе программы бесплатны для подписчиков CNR и стоят около 20 долларов для остальных.

Делай четыре: приступаем к работе Итак, все подготовительные операции завершены, дополнительное ПО установлено, и мы можем наконец-то приступить к тому, ради чего все и затевалось, – работе. Внешний вид Linspire 4.5 представлен на рис. 2. В качестве рабочего стола используется KDE. Содержимое меню «Launch» (зеленая буква «L» в левом нижнем углу) старательно повторяет привычное пользователям Windows (кроме тех, кто успел основательно обжиться в XP): те же Programs, Settings, Search и Run Command. В устоявшийся порядок вещей добавлен всего один штрих – опция «Terminate Program» («Снять программу»). При ее выборе (равно как и при нажатии магической комбинации <Ctrl-AltDel>) на экране появляется дерево запущенных процессов. Во время своего старта система автоматически загружает апплет, извещающий пользователя о наличии новых сообщений в почтовом ящике (конверт в правом нижнем углу) – мелочь, а удобно. Для чтения писем, а также просмотра Web

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

и создания HTML-документов используется интернет-пакет Mozilla.org. Не так давно компания MozDev Group (http:// www.mozdevgroup.com) по заказу создателей дистрибутива расширила его возможности интегрированным поиском (по любому слову на странице, в теле письма и т. д.) и проверкой правописания. Функция имеет название Hot Words (http://info.linspire.com/suite.html) и доступна, как и все в мире Linspire, через CNR Warehouse. В состав Linspire 4.5 включены также интернет-пейджер GAIM (gaim.sourceforge.net) и IP-телефон SIPphone (www.sipphone.com). Поинтересуйтесь у начинающего линуксоида, что ему кажется самым непонятным в этой системе. Уверен, в «горячую десятку» непременно попадет процедура подключения (mount) разделов, особенно остро встающая для съемных носителей: дискет, компакт-дисков, USB Flash и т. д. Здесь Linspire оказался на высоте. Вставленный в USBразъем «брелок» система опознала сразу, о чем уведомила меня, разместив пиктограмму «Flash Disk» на рабочем столе. Вставленный в привод DVD-ROM оптический диск был также легко опознан и смонтирован, а вот с его отключением возникли небольшие проблемы. В случае, если он оказывался занят (в понимании Linux – например, было открыто окно с деревом расположенных на нем каталогов), система игнорировала нажатие на кнопку Eject на передней панели. Такое поведение родного компьютера может смутить и испугать новичка. Было бы лучше, если бы Linspire выдавала диалог с сообщением о невозможности извлечения диска и списком потенциальных причин (или даже названием приложения, использующего CD/DVD-ROM в данный момент). Вот и подошел к концу этот небольшой обзор. Что можно сказать в заключение? По-моему, Linspire – это неплохой дистрибутив, страдающий излишним интересом к деньгам своего владельца и отсутствием полноценной русификации, но, несмотря на это, предоставляющий достаточный комфорт для домашнего и офисного применения. Если у вас есть широкий канал в Интернет – загрузите LinspireLive. Возможно, он вам понравится. Если что-то не получилось, не расстраивайтесь – Linspire не единственный в своем роде. В январском номере журнала мы рассмотрим Lycoris Desktop/LX, загадочный дистрибутив от компании, ранее известной как Redmond Linux.

Ðèñóíîê 3. Ïîíàäîáèëñÿ îôèñ? Äîáðî ïîæàëîâàòü â CNR Warehouse!

7


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

ИДЕАЛЬНЫЙ КАРМАННЫЙ КОМПЬЮТЕР ДЛЯ СИСТЕМНОГО АДМИНИСТРАТОРА ЧАСТЬ 2

АНДРЕЙ МАРКЕЛОВ Обновляем системное программное обеспечение КПК За время, прошедшее с выхода первой части статьи1, компания Sharp успела выпустить преемника рассматриваемой модели карманного компьютера, в основном отличающегося наличием четырехгигабайтного жесткого диска. Однако пока еще эта модель под названием SL-C3000 заговорит хотя бы по-английски, а не по-японски, и доберется до нашего рынка, пройдет очень много времени. А пока идеальным КПК для системного администратора как был, так и остается Sharp Zaurus SL-C860. Кстати, с появлением трехтысячной модели, цена на восемьсот шестидесятую должна упасть, что сделает Zaurus более доступными. Продолжим же наш разговор об этом карманном компьютере, работающем под управлением ОС Linux. В первой части статьи я уже рассказывал о существующем многообразии «прошивок» ROM для Zaurus. Две основных из них – это pdaXrom (http://www.pdaxrom.org) и Cacko ROM (http://cacko.biz/cacko). Первая в качестве графической среды использует X11, а вторая, как и родная шарповская – Qtopia. Доставшийся мне «карманник» шел с довольно устаревшей русифицированной для «МакЦентра» версией Cacko ROM. Поэтому я хочу начать вторую часть с описания процесса перепрошивки ROM, который весьма не тривиален. После окончания операции по сравнению с макцентровской версией, помимо исправлений ошибок, мы должны дополнительно получить огромное число бонусов: Наиболее заметные изменения: ! переделаны все значки и обои; ! значительно обновлена программа kino2 – оболочка для mplayer; ! включена поддержка NLS для всех языков в ядре; ! модернизирована программа переключения клавиатурных раскладок; 1

8

! ! ! !

! ! ! ! ! ! ! !

включены версии баузеров Opera 7.25 и NetFront 3.1; улучшена поддержка USB-устройств через CF USB Host; добавлена поддержка эмуляторов SNES и Scumvm. поддержка файловых систем ext3 (позволяет создавать отказоустойчивые ext3 разделы на больших внешних картах памяти) и squashfs (предоставляет очень хорошую степень сжатия данных при невысоком использовании системных ресурсов), fuse (FileSystem in User Space); обновлены драйвера bluetooth и WiFi (используются драйвера HostAp, поддерживаются Wireless Extentions версии 15, WPA); добавлен модуль брандмауэра iptables; bash «дорос» до версии 3.0; в прошивку включен Midnight Commander; включены в прошивку unrar, diff, smbmount и другие консольные утилиты, которые иначе пришлось бы доустанавливать вручную; созданы новые версии многих консольных утилит (wget, fdisk, OpenSSL/OpenSSH); обновлена программа эмулятора терминала; добавлена поддержка целого ряда новых bluetooth и WiFi CF-карт.

Как видите, список изменений весьма внушителен, для того чтобы приступить к обновлению прошивки. Нужно сказать, что к этому процессу стоит отнестись со всей ответственностью, так как можно легко привести КПК в неработоспособное состояние. Снимки с экрана Zaurus во время выполнения этого увлекательного процесса вы можете найти по адресу www.markelov.net/z860upd.html, а далее я постараюсь подробно описать само действо. Начнем с того, что на всякий случай сохраним копию текущей прошивки. Для этого нам необходимо попасть в так называемое «диагностическое меню» карманного компьютера – аналог BIOS настольных ПК. Для того чтобы зайти в

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


администрирование него, необходимо на некоторое время вынуть батарею, либо просто отодвинуть на некоторое время защелку батареи. После чего возвращаем все в исходное состояние, и при включении «завра» держим нажатыми клавиши <D+M>. Перед вами меню на английском языке. Я настоятельно рекомендую не экспериментировать с его пунктами, так как можно легко «убить» ваш КПК. Теперь перемещаемся на третью страницу меню. Там выбираем пункт «NAND Flash Back Up». Перед этим необходимо убедиться, что в КПК вставлена отформатированная в файловой системе FAT карточка. Места же должно хватить для 135 Мб файла с полной копией вашего текущего содержимого NAND ROM. По окончании процесса на флэшке будет лежать файл systc860.dbk. Обратно в диагностическое меню можно будет вернуться по клавише «Cancel», а из самого диагностического меню выход осуществляется выбором подпункта «Reset» пункта «Extra menu». При необходимости вернуться к сохраненной прошивке можно выполнить обратную операцию по восстановлению через пункт «NAND Flash Restore». Теперь приступим непосредственно к замене нашей устаревшей версии на новую прошивку. Это делается из специального меню на японском языке. Не забудьте, что Sharp официально не продает Zaurus за пределами Японии! Получить доступ в это меню можно, если после «горячего» рестарта включать КПК кнопкой «Power» с одновременно нажатой клавишей «Ок». В меню выбираем четвертый, нижний пункт. После КПК спросит, с какого носителя мы будем обновлять прошивку. Три файла из архива – initrd.bin, tools.tar и updater.sh должны лежать в корне либо CF – либо SD-карты. Кроме того, убедитесь, что подключили блок питания, иначе процесс не начнется. До этого момента он не должен был быть подключенным. Итак, выбираем второй или третий пункт, и спустя некоторое время попадаем в загрузочное меню установщика. Далее, для корректной работы новой прошивки нам необходимо переразбить внутреннюю flash-память КПК, выделив под root-раздел 28 Мб. Выбираем пятый пункт «Flash repartition», и в ответ на вопрос вводим 28. По окончании переразбивки КПК предложит перезагрузиться. Заново входим в японское меню, и повторяем все действия вплоть до попадания в загрузочное меню установщика прошивки. Наконец, выбираем «Install new ROM» и ожидаем окончания процесса. После обновления ROM, вам, возможно, захочется попробовать собрать какую-нибудь программу на Zaurus из исходников. К сожалению, из-за относительно небольшого объема запоминающего устройства на КПК по умолчанию не стоят средства разработки. Тем более что все в основном собирается кросс-компилятором на «большом» линуксе. Однако все-таки возможность разработки непосредственно на КПК есть. Для этого необходимо скачать и установить «Developer image» – образ сжатой файловой системы, который занимает порядка 35 Мб. В нем содержится компилятор gcc, заголовочные файлы, утилиты и библиотеки для сборки утилит командной строки и Qtopia. Скачать его можно с http://www.zaurususergroup.com. Там же находятся и RPM-пакеты для кросс-компилятора. Надеюсь, статьи, посвященные замечательному карманному компьютеру от фирмы Sharp, не только помогли со-

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

ставить о нем представление тем, кто только собрался обзавестись карманной Linux-системой, но окажутся полезными и обладателям Zaurus. На возникшие вопросы автор с удовольствием ответит по электронной почте, либо на форуме журнала. Хочу поблагодарить Антона Масловского, предоставившего мне предварительную версию Cacko ROM 1.22, которая к моменту публикации статьи наверняка уже выйдет в свет.

Ðèñóíîê 1. Çàãðóæàåòñÿ îáíîâëåííàÿ âåðñèÿ Cacko ROM

Ðèñóíîê 2. Îáíîâëåííûé èíòåðôåéñ

Ðèñóíîê 3. Ñèñòåìíàÿ èíôîðìàöèÿ

9


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

ДИСТРИБУТИВ ДЛЯ ВСЕХ СЕРГЕЙ ЯРЕМЧУК Какие бы доводы ни приводились в вечных спорах Windows vs Linux, но изучать компьютерные технологии, мне кажется, лучше все-таки на UNIX-системах. Открытость, возможность разобраться во внутреннем строении, наличие огромного числа удобных и свободных инструментов – все это позволяет при желании в совершенстве освоить любую профессию, связанную с компьютерами. Но не всегда имеется возможность установить еще одну операционную систему. Сегодня пойдет речь об интересном дистрибутиве, который позволяет изучить возможности GNU/Linux и, думаю, придется по вкусу некоторым администраторам и пользователям. Цель австралийского LiveCD дистрибутива ADIOS – Automated Download and Installation of Operating Systems (http:// dc.qut.edu.au/adios) – дать возможность быстро и легко загрузить и использовать операционную систему для лабораторных исследований. Первоначально образ ADIOS через веб-сервер использовался для установки операционной системы на жесткие диски компьютеров, дополнительно возможно было сохранять копии образов OС на запасные дисковые разделы, и только относительно недавно появилась возможность запускать с CD-ROM. Базируется дистрибутив на Fedora 1.0. Поэтому ADIOS присущи поддержка большого количества оборудования и его автоматическое определение, реализуемое при помощи kudzu, а также все те понятные и удобные инструменты для настройки системы. Система включает популярные графические среды – KDE, GNOME и IceWM, так что первое знакомство с Linux пройдет в благоприятной обстановке. Ядро 2.4.24 собрано с поддержкой loopback squashfs (http://squashfs.sourceforge.net), файловой системы, использующей zlib для уменьшения размера, в результате в дистрибутив поместилось больше чем 2 Гб приложений. В составе имеются ядра, поддерживаются защищенные режимы – LIDS (Linux Intrusion Detection System), SELinux (NSA Security Enhanced Linux), в будущем планируется добавить Grsecurity или RSBAC. И кроме того поддерживается UML (User Mode Linux), при помощи которого возможно разбить одиночную систему на несколько независимых виртуальных машин, общающихся между собой через виртуальные Ethernet-интерфейсы. Поэтому пользователи, желающие изучить на досуге эти технологии, получают готовый и уже настроенный инструмент. Системные требования невысоки, поддерживаются все процессоры от 486 до Pentium 4 и минимально рекомендуемый объем ОЗУ – 64 Мб.

Работа с дистрибутивом ADIOS в первую очередь LiveCD, и для удобства пользователей в дистрибутиве заложены широкие возможности по сохранению части данных на разделах жесткого диска (DOS FAT или Linux EXT2/3), флоппи-диске или USB-устройствах. При каждом запуске система сканирует разделы жесткого диска и, если находит готовый swap-раздел, предлагает под-

10

ключить его. При появлении приглашения boot: возможно выбрать несколько вариантов загрузки. При нажатии на Enter (или ввести linux) загружается обычное ядро, если набрать lids, загрузится ядро с поддержкой этого режима, возможны еще варианты: 11 (переход сразу к 11 пункту см. ниже), 4 (к 4 пункту), s4 (4 пункт с поддержкой LIDS), lock (пункт lock). Далее перед пользователем появляется меню: 1) Run Linux from CD-ROM with /var in RAM only 2) Run Linux from CD-ROM with /var on FAT/EXT2 disk 3) Run Linux from FAT/EXT2 disk (incorporates Option 2) 4) Run Linux from CD-ROM with /var on USB storage 5) Install ADIOS repartition disk and create EXT3 filesystem 9) Create Swap file on FAT/EXT2 disk x) Remove hardware and X windows configuration information r) Change run-level (default 5 for X windows) i) Display Copyright, License and System Information h) Display Help g) Display the 'guru' menu options

Как видите, выбор большой. Возможно запустить ADIOS только с CD-ROM, примонтировать раздел /var с других источников либо установить его на жесткий диск и запускать в дальнейшем оттуда, изменить уровень запуска системы (по умолчанию 5). Но это еще не все пункты, если выбрать «g» – guru, то их количество удвоится (появятся и опции 11 и lock). Отсюда при необходимости можно прямо из меню создать/удалить swap-раздел или swap-файл (только на FAT или ext2/3). Установку на жесткий диск система может выполнить автоматически, в том числе и переразбить разделы (как FAT, так и NTFS). Эта несколько рискованная операция может быть выполнена и вручную при помощи утилиты ntfsresize. За подробностями работы которой обращайтесь к документации дистрибутива или к моей статье «Linux и NTFS» (журнал «Системный администратор», №8, август 2004 г.). В системе заведены четыре пользователя: root, super (Alternate Administrator), cso (Chief Security Officer) и adios. Первые два представляют собой администраторов, причем в графическом режиме root система не позволит зарегистрироваться, только super, cso необходим для работы с SELinux и adios предназначен для повседневной работы. Пароль у всех этих пользователей один – 12qwaszx (легко запомнить по две клавиши слева в каждом ряду), поэтому рекомендуется сразу же его сменить. Все найденные разделы система монтирует в режиме «только чтение», при необходимости записи перемонтируйте их с опцией –o remount,rw. Дистрибутивы, основанные на RedHat, всегда отличались большим списком поддерживаемого оборудования, поэтому в большинстве для выхода в сеть остается выставить только нужные параметры. Те, кто не знаком с работой консольных утилит вроде /sbin/ifconfig, найдут большое количество графических front-end для настройки сети, например internet-druid (рис. 1). Программное обеспечение на диске содержит коллекцию утилит управления и сетевого администрирования. Здесь все: веб-сервер Apache; прокси-сервер Squid; FreeS/WAN IPSec для создания VPN; маршрутизатор zebra; пакет Samba,


администрирование который позволит работать в сетях Windows; сервер аутентификации openldap; сетевая система обнаружения атак Snort c ACID; сканеры Nessus и Nmap; снифферы tcpdump и ethereal позволят проанализировать сетевые пакеты; файрвол iptables с графическим интерфейсом firestarter; traceroute и графический xtraceroute позволят выяснить путь к интересующему узлу, и еще много сетевых утилит, традиционно входящих в состав любой UNIX-системы. Имеются утилиты для работы в беспроводных сетях.

analysis tools (http://www.sleuthkit.org/sleuthkit). О возможностях утилит, входящих в его комплект, уже писалось на страницах журнала. Для наглядности работы этих утилит разработчиками также установлен Autopsy Forensic Browser (http://www.sleuthkit.org/autopsy), позволяющий использовать для вывода результатов веб-интерфейс. Для этого достаточно набрать в консоли autopsy & и вставить появившуюся строку в браузер. Далее Squirrelmail Webmail также дает возможность использовать браузер для работы, в данном случае это почта. Для его использования достаточно разрешить запуск сервиса IMAP в /etc/xinetd.d/imap (disable = no) и запустить xinetd, который по умолчанию не работает. # /sbin/service xinetd start

И затем sendmail. # /sbin/service sendmail start

Ðèñóíîê 1

Если набрать в строке веб-браузера IP-адрес своего компьютера, то обнаружится еще одна положительная сторона ADIOS – ARK (Administrators Resource Kit) (рис .2), содержащий большое количество различной документации и коллекцию ссылок по Linux/UNIX вообще, настройке отдельных сервисов, защите, языкам программирования, которые придутся по душе новичкам. Отсюда же можно получить доступ к man-страницам дистрибутива.

Проверяем, работает ли веб-сервер /sbin/service httpd status (для проверки всех запущеных /sbin/service --status-all). Если все работает, набираем http://localhost/webmail. В комплект программ также включен Swish-e (http:// swish-e.org), позволяющий легко создать небольшой, но эффективный поиск по сайту. При этом поиск по документам, имеющимся на ADIOS CD, уже настроен. В любом другом случае это просто организовать самому. Настраиваем параметры поиска в /etc/swish.conf, затем индексируем файлы. #cd /var/www/swish #swish-e -c /etc/swish.conf

-f index.swish

И в html-код страницы вставляем что-то вроде: <form action=”/cgi-bin/search.cgi” target=”main”>

Ðèñóíîê 2

Для удобства администрирования системы в комплект входит webmin, для его запуска достаточно ввести /sbin/ service webmin start и затем набрать в строке браузера http:// localhost:10000, после чего использовать для входа пользователя root. Этот сервис может оказаться полезным еще и потому, что дистрибутив практически не содержит данных, необходимых для локализаций, отличных от английской, и только webmin можно заставить общаться на русском. Для работы с данными, содержащимися на жестких дисках, в том числе для их восстановления и исследований последствий взлома в комплекте имеется Sleuthkit file system

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

для возможности поиска документов из браузера. Также в дистрибутиве имеются сервер переадресации rinetd и утилита контроля Nagios. Плюс принятые в большинстве UNIX утилиты для программирования в bash, nasm, C, C++, Perl, Python, PHP и Ruby со средствами отладки. А еще офисные программы, утилиты для работы с мультимедиа, графикой, игры. Так что комплект на все случаи жизни. Работа с поддержкой SELinux возможна только после установки ADIOS на жесткий диск. Для тех, кто хочет создать свой собственный LiveCD, проект представляет набор скриптов ADIOS development kit (ADK), работа с которыми хорошо описана в документации. Изучение UNIX-систем никогда не было легким, требуется затратить некоторые усилия и проявить терпение, прежде чем появится первый результат. ADIOS представляет собой хороший инструмент, который поможет сделать эти первые шаги. Кроме того, это неплохой инструмент для демонстрации возможностей GNU/Linux, при организации всевозможных курсов, особенно когда используется оборудование, задействованное в других задачах. И, конечно же, его можно использовать при решении задач администрирования, когда нет под рукой других инструментов, позволяющих решить вдруг возникшие проблемы.

11


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

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

РАШИД АЧИЛОВ Постановка задачи

Настройка SSH

Предположим, имеется некоторое количество компьютеров под управлением операционной системы UNIX (Windows) с запущенным SSH-сервером, на которых автоматически по расписанию в некоторое время стартует программа, создающая резервные копии некоторых каталогов (например, /etc, /usr/local/etc) и складывающая их в определенное место. Пример такого скрипта, адаптированного под систему periodic во FreeBSD, можно скачать с http://www.granch.ru/ ~shelton/fileZ/130.backup-dirs. Все используемые параметры описаны в начале скрипта. Для обеспечения сохранности данных архивов было бы неплохо копировать их все в одну точку, откуда их можно было бы перенести на съемный носитель, например. Копирование должно проводиться в автоматическим режиме, все имена каталогов – быть уникальными, требовать минимум настроек и обеспечивать максимум безопасности при передаче данных по сети (если, например, архив /etc попадет в чужие руки, можно получить столько проблем, что мало не покажется). С этой целью был разработан скрипт копирования файлов через SCP2 (программу безопасного копирования, входящую в комплект SSH2) без ввода паролей, используя авторизацию с помощью публичных ключей. Скрипт выполняет копирование файлов, размещенных в некотором, заранее обусловленном каталоге, отмечает каждое действие в собственном файле журнала. В статье скрипт будет приводиться по частям (которые, будучи объединены вместе, тем не менее дадут полноценный скрипт), полный текст скрипта можно загрузить с http://www.granch.ru/~shelton/fileZ/safecopy. Для разработки скрипта, отладки и применения использовался компьютер с операционной системой FreeBSD 4.10STABLE и SSH2 от SSH Communications Inc., установленный из портов (/usr/ports/security/ssh2). Скрипт имеет некоторые адаптационные возможности для работы с OpenSSH, но работоспособность этих возможностей не проверялась и может содержать ошибки. Для работы скрипта использовалось имя пользователя rmbackup.

SSH – это протокол связи двух компьютеров через TCP/IP c шифрованием передаваемых данных. Этот протокол обеспечивает надежный и безопасный доступ к удаленному компьютеру, расположенному... да неважно где, лишь бы у него был выход в Интернет. С точки зрения рядового системного администратора SSH обычно рассматривается как безопасное средство удаленного управления сервером, для чего ранее использовалась программа telnet. Конечно, есть и другие средства шифровки трафика, но их мы рассматривать не будем. Разумеется, шифрование сессии во время работы по SSH выполняется, но возможности SSH не исчерпываются только этим. Я не буду приводить здесь описание всех возможностей SSH, это тема для отдельной статьи, всех интересующихся отсылаю к документации на SSH2 (http:// www.ssh.fi/support/documentation/online/ssh/adminguide/32). Одной из возможностей SSH является то, что он может выполнять авторизацию пользователей и организовывать удаленное выполнение команд в SSH-сессии без ввода пароля, с помощью так называемого публичного ключа. Эта возможность основана на стандартном методе авторизации с помощью асимметричных ключей – приватного и публичного. Приватный ключ доступен только пользователю и тщательно им оберегается от хищения, публичный же ключ, наоборот, размещается во всех местах, где только можно его разместить. На мой взгляд, наиболее удачное описание того, как работает SSH и как его использовать (не считая, конечно, man ssh2, man ssh.conf и прочих манов) – это книга «SSH, the Secure Shell: Definitive Guide» [1]. После того как принято решение о включении данного компьютера в автоматическое копирование файлов, но перед тем как начинать собственно копирование, необходимо выполнить следующие шаги по настройке SSH: 1. Создаем пользователя, от имени которого будет выполняться копирование файлов. Пользователь может не

12


администрирование иметь пароля («*» в поле пароля в /etc/master.passwd), но должен иметь действительный shell, поскольку он (shell) будет выполнять некоторые команды. Пользователь должен быть создан на всех компьютерах, с которых будут копироваться файлы, и на всех компьютерах иметь одинаковые настройки и имя. Это не обязательно с точки зрения SSH, но необходимо для скрипта, поскольку тот использует одно фиксированное имя пользователя. Интерактивной работы на компьютерах, с которых будут копироваться данные, никогда не будет, поэтому /bin/sh будет вполне достаточно. На компьютере, на котором будет выполняться скрипт (назовем его «мастер») установите любой привычный shell. 2. Создаем ключевую пару для данного пользователя на данном компьютере. Для этого используется программа ssh-keygen2. Порядок создания ключей не важен, следует только помнить, что мастер-компьютер обращается ко всем компьютерам, с которых копируются данные, а к самому мастер-компьютеру не обращается никто. Поскольку предполагается автоматическая работа, то создается ключевая пара, не защищенная паролем. Пример создания ключевой пары приведен ниже:

тивном режиме. Это необходимо для создания хост-ключей в подкаталоге hostkeys каталога .ssh2. Хост-ключи идентифицируют SSH-сервер в целом. При отсутствии хост-ключа в подкаталоге hostkeys перед началом сессии мастер и удаленный компьютер обмениваются хост-ключами, и хостключ удаленного компьютера помещается в подкаталог hostkeys для пользователя rmbackup. При этом на консоли появляется следующий запрос: >ssh mybox Host key not found from database. Key fingerprint: xocob-bicub-vatun-mofos-nutym-parok-sahet-hefer-papuh-kepyz-rexox You can get a public key's fingerprint by running % ssh-keygen -F publickey.pub on the keyfile. Are you sure you want to continue connecting (yes/no)? yes Host key saved to /usr/home/rmbackup/.ssh2/hostkeys/key_22_mybox.pub host key for mybox, accepted by rmbackup Wed Nov 03 2004 23:44:10 +0600

Проверка того, что авторизация настроена правильно, очень проста – набираете команду ssh remote на мастеркомпьютере, где remote – имя или адрес удаленного компьютера. Удаленная SSH-сессия должна начаться сразу же, без дополнительных запросов пароля. Если появится запрос пароля на разблокировку ключа:

>ssh-keygen2 -P

Опускать -P здесь нельзя – опция указывает на необходимость создания ключа, не защищенного паролем. После создания ключевой пары появляются файлы id_dsa_2048_a (приватный ключ) и id_dsa_2048_a.pub (публичный ключ). Подробную информацию о создании ключевой пары см. man ssh-keygen2. Публичный ключ мастер-компьютера, переименованный, например, в rmbackup_master.pub, нужно поместить в подкаталог .ssh2 домашнего каталога пользователя rmbackup на всех компьютерах, с которых будут копироваться файлы. 3. Настраиваем конфигурационные файлы идентификации и авторизации. Эти файлы определяют имя файла (файлов – в SSH2 их может быть несколько) приватного ключа (ключей) и имена файлов, задающие ключи, авторизация с которыми разрешена на данном компьютере для данного пользователя. По умолчанию имена этих файлов identification и authorization. На мастер-компьютере файл authorization можно не создавать – на него никто не будет заходить данным пользователем. На компьютерах, с которых будут копироваться данные, файл authorization обязательно должен содержать имя файла ключа мастер-компьютера. Примеры файлов: identification: IdKey id_dsa_2048_a authorization: Key rmbackup_master.pub

Следует иметь в виду, что если планируется заходить с нескольких компьютеров, ключ каждого компьютера должен быть помещен в подкаталог .ssh2 данного компьютера и описан в файле authorization. Более подробная информация о настройке авторизации по публичному ключу приведена в man ssh.conf и man sshd.conf. 4. В первый раз заходим с мастер-компьютера на компьютер, с которого будут копироваться файлы в интерак-

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

>ssh mybox Passphrase for key "/usr/home/rmbackup/.ssh2/id_dsa_2048_a" with comment "2048-bit dsa, rmbackup@mybox.com, Fri Jul 23 2004 12:50:25 +0700":

значит ключ был сгенерирован с паролем. Такой ключ следует удалить и создать заново, но без пароля (см. пример выше). Если же появляется стандартный запрос пароля: >ssh mybox rmbackup's password:

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

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

13


администрирование нем каталоге пользователя rmbackup на удаленном компьютере следует создать каталоги /bin и /etc. В каталог /bin поместить файлы (переписать из стандартного /bin) ls, sh и (ВНИМАНИЕ!) исполняемый файл sftp-server, собранный таким образом, что у него отсутствуют динамические ссылки на библиотеки. Такой режим обычно применяется для программ, используемых в процессе восстановления системы. Исполняемый файл sftp-сервера должен быть обязательно собран с отключением динамических библиотек, иначе придется дублировать всю структуру динамической загрузки – /usr/libexec/ld-elf.so, /var/run/ld-so.hints и все остальное. Исполняемый файл такого типа можно получить, дописав в каталоге, где лежат исходные тексты ssh, в подкаталоге apps/ssh в файл Makefile в строчку 273 (или около того) LDADD=<флаги> флаг -static и пересобрать SSH. Как проверить, является ли полученный исполняемый файл статически или динамически собранным? > ldd sftp-server2 Ldd: sftp-server2: not a dynamic executable

Приведенный выше ответ является правильным, если вместо него появляется что-то типа: > ldd sftp-server2: libm.so.2 => /usr/lib/libm.so.2 (0x280bb000) libcrypt.so.2 => /usr/lib/libcrypt.so.2 (0x280d7000) libutil.so.3 => /usr/lib/libutil.so.3 (0x280f0000) libncurses.so.5 => /usr/lib/libncurses.so.5 (0x280f9000) libc.so.4 => /usr/lib/libc.so.4 (0x2813b000)

значит, это динамически собранный исполняемый файл, и он не годится. На самом деле его тоже можно использовать. Но для этого придется создать /usr/libexec в домашнем каталоге пользователя rmbackup, перенести туда lself.so, создать /usr/lib и поместить туда все библиотеки, перечисленные в выводе ldd, создать /var/run/ld-so.hints командой ldconfig. С моей точки зрения, пересобрать программу значительно проще. В каталог /etc помещаются файлы group и master.passwd. Из файла group удаляются все реальные пользовательские группы, важно, чтобы там присутствовала группа, прописанная как ChrootGroup в конфигурационном файле SSHсервера. Из файла master.passwd удаляются все пользователи с паролями, пароль root заменяется на «*». После чего создаются файлы passwd, pwd.db и spwd.db командой: >pwd_mkdb -p -d . master.passwd

Теперь файл master.passwd можно стереть. Кроме того, в конфигурационном файле SSH-сервера указывается группа, к членам которой будет применяться chroot (по умолчанию это группа sftp): ChRootGroups

sftp,guest

Кроме того, проследите, чтобы параметр AllowedAuthentications содержал publickey, а RequiredAuthentications не содержал password. Еще лучше, чтобы он был удален или закомментирован. Как убедиться в том, что сессия идет в chroot? В файле регистрационного журнала SSH-сервера об этом делается специальная отметка:

14

connection from "192.168.1.1" Public key /usr/local/share/rmbackup/.ssh2/rmbackup_mybox.pub used. Public key authentication for user rmbackup accepted. User rmbackup, coming from mybox, authenticated. User 'rmbackup' will be chrooted to directory '/usr/local/share/rmbackup'. Now running on rmbackup's privileges.

Предварительная подготовка завершена. Мы настроили компьютеры, с которых (и на которые) будут копироваться данные таким образом, что можно выполнять команду на удаленном компьютере через SSH2 без ввода паролей с помощью авторизации по публичному ключу.

Настройка скрипта Настройка скрипта выполняется через задание переменных в конфигурационном файле /etc/periodic.conf. Эти переменные используются скриптом резервного копирования, упомянутым в начале статьи, и скриптом, описываемым в данной статье. Скрипт использует следующие переменные: daily_backup_owner="rmbackup" # Owner of backup files daily_backup_group=”wheel” # Group of backup files daily_backup_mode="0600" # Mode of backup files daily_backup_dirmode="0700" # Mode of intermediate dirs

Это соответственно переменные, задающие пользователя, группу, режим доступа к файлам и каталогам, создаваемым скриптами. Скрипт не устанавливает значения переменных по умолчанию, поэтому все переменные должны быть заданы в /etc/periodic.conf или /etc/defaults/periodic.conf.

Заголовок и вспомогательные функции #!/bin/sh # Safe updating, so – copying current daily backup directory # from remote server to local. Used SSH2 publickey auth # method, so you need a working installation before starting. # This is an open-source software, licenced by BSD license. # Written by CityCat 23.07.2004 # $Id: safecopy,v 1.5 2004/08/10 04:26:40 shelton Exp $ PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin: ↵ /usr/local/sbin

В приведенном выше заголовке нет ничего необычного. Переустановка переменной PATH нужна для того, чтобы находить программу SSH2, даже если пользователь ее изменил. # Logging function # Logged string in variable logline! safe_logger() { logdate=`date +"%d/%m/%Y %T"` echo "$logdate [$$] safering: $logline" >> $logfile }

Функция записи информации в регистрационный журнал, который ведется программой, имитирует работу программы logger и формирует в журнале записи такого формата: 07/08/2004 05:00:02 [70241] safering: File _etc.tar.bz2 from host mybox was succesfully transferred

при этом выводимая в журнал строка передается в переменной logline.


администрирование # Go down function # Set variable godown to downing directory name go_down() { if [ ! -e $godown ]; then mkdir $godown chown $daily_backup_owner:$daily_backup_group $godown chmod $daily_backup_dirmode $godown fi }

! Переменные hostlist и logfile задают соответственно име! !

cd $godown

Функция перехода в подкаталог, задаваемый переменной godown. Если каталог отсутствует, он будет создан, и ему будут установлены права доступа, заданные в конфигурационном файле.

! ! !

# If there is a global system configuration file, suck it in. # if [ -r /etc/defaults/periodic.conf ]; then . /etc/defaults/periodic.conf source_periodic_confs fi

Загрузка значению по умолчанию для скрипта, если они заданы (обычно вписываются в /etc/defaults/periodic.conf).

Переменные Единственная переменная, которую имеет смысл настраивать в скрипте, вынесена перед строкой предупреждения. Разумеется, все остальные переменные тоже можно менять – это же скрипт. Но все же делать это не рекомендуется без понимания механизма его работы. # Variables # There is only maintained variables! # This is a root folder for all subordinated folders sysdir="/usr/local/share/rmbackup" # NO CHANGES BEHIND THIS LINE!! YOU HAVE BEEN WARNED!! backupdir="backup" ringdir="$sysdir/backup" maintdir="$ringdir/maint" hostlist="$maintdir/cphosts" logfile="$maintdir/saferlog" wsyear=`date +"%Y"` wsmon=`date +"%m"` wsday=`date +"%d"` # We assumed SSH2 by SSH Com. presence and locating config # in /usr/local/etc/ssh2 openssh=0 sshconf="/usr/local/etc/ssh2/ssh2_config" sshome="$HOME/.ssh2" scpname=scp2

Итак:

! Переменная sysdir указывает корневой каталог системы кольцевого копирования. Обычно это домашний каталог пользователя rmbackup, хотя можно указать любой другой. В этом каталоге будут располагаться все остальные каталоги. ! Переменная backupdir указывает на каталог с резервными копиями на удаленном компьютере. ! Переменная ringdir указывает на каталог с резервными копиями на мастер-компьютере. ! Переменная maintdir указывает на каталог с регистрационным журналом, списком компьютеров, с которых будут копироваться данные, и собственно скриптом.

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

на файлов списка компьютеров и регистрационного журнала. Переменные wsyear, wsmon и wsday хранят текущие год, месяц, день. Переменная openssh указывает на то, что SSH, обнаруженный скриптом, является OpenSSH (используется для адаптации путей и работы с конфигурационными файлами). Переменная sshconf указывает на расположение конфигурационного файла SSH по умолчанию. Переменная sshome указывает на пользовательский каталог с настройками, ключами и т. д. для SSH (имена каталогов отличаются в SSH2 и OpenSSH). Переменная scpname задает имя программы безопасного копирования SCP (в SSH2 и OpenSSH они отличаются).

Проверка командной строки и обнаружение SSH # Check commandline if [ $# -ne 0 ]; then if [ $1 = "-h" ]; then echo "Safering updater. Copying current daily ↵ backup dir from remote server." echo " Usage: safecopy [hostlist-location-and-name]." exit else hostlist=$1 fi fi # Check on presence SSH in system and detect their version wssh=`which ssh2'` if [ -z $wssh ]; then wssh=`which ssh'` if [ -z $wssh ]; then logline="No any SSH program was detected, ↵ install it first"; safe_logger exit else wsver=`$wssh | awk '{printf "%s %s %s",$1,$2,$3}'` sshome="$HOME/.ssh" scpname=scp wsx=`$wssh | awk '{print $3}'` if [ $wsx = "SSH" ]; then openssh=1 sshconf="/etc/ssh/ssh_config" else logline="Broken SSH1 from SSH ↵ Communicationc Inc. probably detected" safe_logger exit fi

fi else wsver=`$wssh -V 2>&1 | awk '{printf "%s %s ↵ %s %s",$2,$3,$4,$5}'` fi

# Log detected version logline="Detected version: $wsver"; safe_logger

Допустимыми параметрами командной строки являются -h или имя файла со списком компьютеров, с которых производится копирование. Если имя файла не задано, будет использоваться файл cphosts в каталоге $maintdir. Первым делом ищется программа ssh2 (which ssh2). Если она найдена, то выбирается информация о версии (пе-

15


администрирование ременная wsver будет содержать «SSH Secure Shell x.x.x.x», где x.x.x.x – номер версии SSH), и полученная информация выводится в регистрационный журнал. Если же она не найдена, производится попытка обнаружить программу ssh (which ssh), и если она найдена, проверяется, что за программа обнаружена. Если это OpenSSH (определяется по характерному признаку – третье слово при запуске без параметров содержит «SSH»), то переменные sshome, scpname, sshconf и openssh устанавливаются в соответствующие значения. Иначе скрипт завершает работу, поскольку работа с SSH1 от SSH Communications не поддерживается (по причине его небезопасности).

Проверка наличия файла идентификации и разбор списка компьютеров Как уже говорилось выше, файл идентификации обязательно должен быть создан, если предполагается использовать авторизацию по публичному ключу. Поэтому отсутствие данного файла обозначает ситуацию, когда авторизация по публичному ключу еще не была настроена. # Taking identity file name, drop down comment field identity=`grep IdentityFile $sshconf` idfirst=`echo $identity | awk '{print $1}'` if [ $idfirst = "#" ]; then idfile=`echo $identity | awk '{print $3}'` else idfile=`echo $identity | awk '{print $2}'` fi # For OpenSSH drop down path from pathname if [ $openssh -eq 1 ]; then idname=${idfile##*/} else idname=$idfile fi # Check on existance identification file. When doesn't – # SSH dodn't setup to work with publickey auth method if [ ! -e $sshome/$idname ]; then logline="Publickey auth method did not configured ↵ yet"; safe_logger exit fi

Скрипт проверяет наличие параметра IdentityFile в конфигурационном файле сервера (даже если он отмечен знаком комментария). Для OpenSSH дополнительно отбрасывается путь к IdentityFile, если он там указан. Потом проверяется существование файла, описанного как IdentityFile. Если он не существует, скрипт прекращает работу. Разбор списка компьютеров осуществляется установкой переменной IFS в значение «\n». Для этого не нужно писать «IFS=”\n”» – shell не интерпретирует метасимволы. Следует написать «IFS=”», нажать «перевод строки» и закрыть кавычку – внутри кавычек окажется символ перевода строки. После считывания файла организовывается стандартный цикл по списку переменных-строк: # Taking hosts list IFS=" " hosts=`cat $hostlist` cd $ringdir # Doing safering update for host in $hosts do

16

Разбор строки и получение списка файлов для копирования # Parse host line hostname=`echo $host | awk '{print $1}'` hostadr=`echo $host | awk '{print $2}'` fullpath=$backupdir/$wsyear/$wsmon-$wsyear/ ↵ $wsday-$wsmon-$wsyear # Take list of files to backup wls=`$wssh -o "BatchMode yes" -q $hostadr ↵ "cd $fullpath 2> null && /bin/ls -1"`

Один из двух наиболее важных моментов. Скрипт копирования файлов создает каталоги вида YYYY/MM-YYYY/DDMM-YYYY, где YYYY – текущий год, MM – текущий месяц, DD – текущий день. Можно было бы, конечно, создавать папки типа YYYY/MM/DD, но мне удобнее просматривать список в mc, когда видна полная дата. В переменной wls после выполнения команды будет результат команды «перейти в заданный каталог и получить список файлов в нем». Если предполагается копировать нечто другое, следует задать соответствующий путь в переменной fullpath. Если команда завершилась аварийно, то список будет пуст, и скрипт перейдет к другому узлу из списка или завершит работу, если этот список уже кончился. Результат выполнения последней команды хранится в переменной status. Если команда выполнена успешно, то выполняется последовательный переход в каталоги: имя удаленного компьютера, YYYY, MM-YYYY, DD-MM-YYYY, например: cd myhost; cd 2004; cd 12-2004; cd 15-12-2004. Если такой каталог отсутствует, он создается с правами, заданными параметрами. Мы говорили об этом в разделе «Настройка скрипта». # When list is empty, do nothing # (and don't create directories) status=$? if [ $status -ne 0 ]; then continue else # Go down the ladder godown=$hostname; go_down godown=$wsyear; go_down godown=$wsmon-$wsyear; go_down godown=$wsday-$wsmon-$wsyear; go_down fi

Пофайловое копирование for file in $wls do $scpname -q -Q $hostadr:$fullpath/$file . 2> null status=$? # Check on operation return code if [ $status -ne 0 ]; then logline="Transfer of file $file unsuccesful, ↵ return code is $status"; safe_logger else logline="File $file from host $hostname ↵ was succesfully transferred"; safe_logger chown $daily_backup_owner:$daily_backup_group $file chmod $daily_backup_mode $file fi done # Return to top cd $ringdir done


администрирование Последнее и самое важное действие скрипта – поочередное копирование файлов из списка, полученного на предыдущем шаге. Выполняется команда scp, и результат ее работы заносится в переменную status. В зависимости от значения переменной status выдается сообщение либо об успешном завершении копирования (при этом устанавливаются права и режим доступа, соответствующие параметрам, перечисленным в пункте «Настройка скрипта»), либо об аварийном завершении (и тогда в журнал заносится код ошибки, расшифровку которого можно посмотреть в man ssh2).

Возможные ошибки и изменения скрипта Если скрипт работает не так, как ожидается, то, скорее всего, имеет место ошибка в настройке SSH (по крайней мере, почти все ошибки, с которыми я сталкивался после завершения его разработки, были такого плана). Это очень просто проверить – достаточно с консоли мастер-компьютера набрать ssh remotebox, где remotebox – имя любого компьютера, с которого должны копироваться данные. Если сразу же открывается терминал удаленного компьютера – все нормально (при этом motd показываться не должно). Если же появляется запрос пароля на разблокирование ключа, запрос пароля на регистрацию на удаленном компьютере или какие-либо сообщения об ошибках – следует устранить ошибки и повторить. Единственной ошибкой, которую можно совершить при генерации ключа, является запуск ssh-keygen2 без ключа -P. При этом при генерации ключа будет запрошен пароль. Если при генерации ключа появился запрос пароля, лучше генерацию прервать и запустить ssh-keygen2 заново с ключом -P. Самой распространенной ошибкой авторизации является то, что ключ мастер-компьютера не помещен в каталог .ssh2 пользователя rmbackup удаленного компьютера, не описан в файле authorization, или в имени ключа допущена банальная опечатка. Если ключ для пользователя rmbackup создавался через su rmbackup от пользователя root, возможно, установлены неверные права на файлы identification и authorization (при создании файлов владельцем становится создатель). Второй распространенной ошибкой является задание параметра RequiredAuthentication password в конфигурационном файле sshd.conf на удаленном компьютере, требующего обязательной аутентификации по паролю. Если терминальная сессия на удаленном компьютере открывается нормально, то следует попробовать вручную ввести команду (вместо 192.168.1.1 подставить IP или имя компьютера, с которого должны быть получены файлы): >su rmbackup >ssh2 -o "BatchMode yes" -q 192.168.1.1 "cd /etc && ↵ /bin/ls -1"

Если в результате выполнения этой команды получается оглавление каталога /etc (в chroot это файлы group, passwd, pwd.db и spwd.db) – значит, следует проверить работу scp. Иначе следует проверить файл журнала, в который выводятся сообщения от SSH-сервера на удаленном

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

компьютере на предмет сообщений об ошибках и устранить их. Если предыдущая команда завершена успешно, следует проверить работу команды scp следующим образом (заменить 192.168.1.1 на IP-адрес или имя компьютера, с которого должны быть получены файлы. Файл .profile должен существовать на удаленном компьютере): scp2 192.168.1.1:.profile

./profile-tmp

(Внимание! Точка – элемент команды!) Если в текущем каталоге появился файл .profile-tmp, следует уточнить код ошибки по руководству к ssh2 (man ssh2) и устранить ошибки. Если же нет – проверить файл журнала, в который выводятся сообщения от SSH-сервера на удаленном компьютере на предмет сообщений об ошибках, и устранить их. Здесь наиболее частой ошибкой может быть неверный sftp-server2, который не собран в соответствии с рекомендациями раздела «Дополнительные вопросы безопасности», а просто переписан и для работы требует наличия динамического загрузчика, libc и пр. Как можно изменить место, откуда берутся копируемые файлы на удаленном компьютере? Для этого достаточно изменить формирование переменной fullpath, описанной в разделе «Разбор строки и получение файлов для копирования». Как можно изменить место и организацию каталогов, в которые раскладываются файлы на мастер-компьютере? Для этого в функцию go_down передается значение переменной godown – каталог будет создан по ее содержимому. Можно вообще все складывать в один каталог – для этого нужно закомментировать строки с «godown=...; go_down».

Заключение Данный скрипт – инструмент системного администратора из разряда «настроил и забыл». После его настройки он не требует какого-либо сопровождения, кроме, пожалуй, регулярного резервного копирования каталога с файлами, скопированными с удаленных компьютеров. Ну и, конечно, обеспечения необходимых мер безопасности по отношению к каталогу, в котором хранятся резервные копии. Разумеется, он разрабатывался для решения определенной частной задачи, но его нетрудно адаптировать для копирования чего угодно откуда угодно. Ошибки в самом скрипте исключены ввиду его достаточной простоты, как правило, все ошибки связаны с ошибками самого SSH.

Дополнительная информация: 1. Daniel J. Barrett, Richard Silverman. SSH, the Secure Shell: Definitive Guide. O’Reilly & Associates, 2001, 558 pages. ISBN: 0-596-00011-1. 2. http://www.ssh.fi/support/documentation/online/ssh/ adminguide/32 – SSH Secure Shell for Servers Version 3.2 Administrator’s Guide. 3. http://www.opennet.ru/docs/RUS/ssh_faq – Faq по SSH в русской редакции. Русская редакция: Андрей Лаврентьев (lavr@unix1.jinr.ru). 4. man ssh2, man sshd2, man ssh.conf, man sshd.conf, man ssh-keygen2.

17


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

ЕДИНАЯ УЧЕТНАЯ ЗАПИСЬ ДЛЯ WINDOWS И UNIX В ACTIVE DIRECTORY

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

18

А за тем, что очень многие организации изначально ориентированы на платформу Windows и в качестве каталога применяют Active Directory, а когда в сети начинает появляться UNIX, то встает вопрос об интеграции, и не всегда хорошие коммерческие решения подходят, либо из-за стоимости, либо в силу других причин. Я изначально рассматривал вариант с ведением второго каталога для UNIX-клиентов на базе OpenLdap, но хотелось все-таки управлять учетными записями из единой точки, а именно из Active Directory, потому что этот каталог широко используется у нас в сети.


администрирование Вариант Samba + winbind меня не устраивал, поскольку по роду задач samba вообще не нужна, к тому же это лишние службы на каждой машине, использование которых всетаки не решает проблем с централизованным управлением пользовательскими данными, поэтому это решение мне показалось неразумным и неизящным. Более всего привлекал вариант с использованием сервера NIS, который входит в продукт, известный как Services For Unix от компании Microsoft и синхронизация записей Active Directory to NIS. Зайдя на microsoft.com в надежде скачать SFU3.5, которая в отличие от предыдущей версии SFU3.0 бесплатна, я набрел на ряд интересных статей, прочитав которые, пошел по другому пути. Как уже говорилось в начале, не все UNIX-подобные системы могут проходить аутентификацию и запрашивать данные о пользователе в Active Directory описанным здесь способом, а только те, которые умеют работать с PAM и pam-модулями. Как вы, наверное, догадались, я буду описывать способ взаимодействия с ldap-сервером, входящим в Active Directory через модули pam_ldap и nss_ldap. Итак, начнем. В качестве подопытных будут выступать MS Windows 2000 Server Standart с установленной Active Directory (в дальнейшем AD), Linux Manrdake 10.0, Solaris 9 x86, FreeBSD 4.10. Над Windows 2000/XP опыты ставить бессмысленно – все и так работает. Как минимум понадобится DNS-сервер, который может быть установлен на том же Windows 2000 Server. Свежеустановленная AD не имеет традиционной ldap-схемы для UNIX: userid, grouid, login shell, home directory. Нам нужно её расширить, и для этого я воспользуюсь SFU3.5. Вообще-то существует несколько способов это сделать: вручную создав ldif-файл с нужной схемой и импортировав его при помощи каких-либо программ сторонних разработчиков, например такой, как AD4Unix (www.padl.com/download/MKSADPlugins.msi), или с помощью SFU от Microsoft. Первый способ я оставляю гуру, вышеозначенную программу MKSADPlugins.msi вам установить вряд ли удастся, если Windows 2000 Server работает с альтернативной локалью, отличной от US, что для России уместно. В пользу же SFU, на мой взгляд, говорит то, что она сделана в том же КБ, где Windows и AD, плюс в своем составе имеет много утилит от UNIX. Пройдя добровольно-принудительную процедуру получения .NET Passport, вы сможете бесплатно скачать и использовать SFU3.5 (www.microsoft.com/windows/sfu). Размер программы примерно 230 Мб. Прежде чем устанавливать SFU, нужно инсталлировать Active Directory Schema MMC snap-in следующей командой: regsvr32 ñ:\WINNT\system32\schmmgmt.dll

Для расширения схемы AD достаточно установить только NIS-сервер из состава SFU. Для успешного завершения установки необходимо быть либо членом групп Domain Admins и Schema Admins, либо работать с правами Администратора. После установки будет предложено перегрузить машину. NIS-сервер как таковой не понадобится и его можно остановить и благополучно забыть о нём. В свойствах пользователя, группы, компьютера в Active Directory Users and Computers добавится вкладка UNIX Attributes.

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

Как видите, теперь у каждого пользователя есть атрибуты, применяемые в UNIX-системах. Первое поле «NIS Domain» будет содержать краткую форму имени нашего домена. Этот параметр нужен для службы NIS, и хотя в нашем случае она не применяется, без нее не активируются другие поля. С остальными полями, я думаю, затруднений не возникнет, может быть, за исключением GID. Прежде чем выбрать из этого поля группу, её надо создать или в свойствах уже имеющейся задать UNIX-атрибуты. Проблема с группами заключается в том, что нельзя задать одно и то же имя для пользователя и группы, а в мире UNIX такой подход весьма распространен. В таком случае можно использовать только численное представление, правда, я сомневаюсь, что это хороший выход из создавшейся ситуации. Ещё потребуется создать учетную запись, которая будет применяться для взаимодействия UNIX-машин с ldap-сервером. Это своего рода дыра в безопасности, поэтому сей аккаунт не должен принадлежать кому-либо и доступ к важным ресурсам ему должен быть запрещен. Тем не менее он должен иметь право на поиск объектов в каталоге. На этом этапе вы готовы управлять единой учетной записью при помощи Active Directory. Переходим к настройке клиентских машин. Я использовал Linux Mandrake 10.0 Official и всё необходимое ПО устанавливал из rpm-пакетов, входивших в состав дистрибутива. Понадобится установить pam_ldap и nss_ldap. После установки этих пакетов нужно отредактировать несколько конфигурационных файлов. Pam_ldap и nss_ldap для настроек используют один и тот же файл ldap.conf. Также нужно будет отредактировать nsswitch.conf и как минимум один файл, находящийся в /etc/pam.d, а именно system-auth. Не забудьте сделать копии оригинальных файлов. Итак, файл ldap.conf должен содержать следующее: # Áàçîâûå íàñòðîéêè, íåîáõîäèìûå äëÿ ïîäêëþ÷åíèÿ ê AD. # domain, loc è server.domain.loc âû äîëæíû èçìåíèòü # â ñîîòâåòñòâèè ñî ñâîèìè íàñòðîéêàìè base dc=domain,dc=loc

19


администрирование scope sub uri ldap://server.domain.loc port 389 ldap_version 3 # Òîò ñàìûé àêêàóíò, êàê âèäèòå, îí áûë ñîçäàí â êîíòåéíåðå # Users ñ èìåíåì ldap è ïàðîëåì qwerty binddn cn=ldap,cn=Users,dc=domain,dc=loc bindpw qwerty # Êîãäà âû áóäåòå ââîäèòü èìÿ ïîëüçîâàòåëÿ è ïàðîëü, áóäóò # ïðèìåíÿòüñÿ ñëåäóþùèå îáúåêòû è àòðèáóòû èç AD: pam_filter objectclass=User pam_login_attribute sAMAccountName pam_password ad # Ýòè çàïèñè íóæíû äëÿ óñêîðåíèÿ ïîèñêà. Ìîæåòå èõ âîîáùå # íå âñòàâëÿòü. Îáðàòèòå âíèìàíèå, âñå ïîëüçîâàòåëè â ýòîì # ïðèìåðå õðàíÿòñÿ â «Organization Unit → firma» nss_base_passwd ou=firma,dc=domain,dc=loc?sub nss_base_shadow ou=firma,dc=domain,dc=loc?sub nss_base_group ou=firma,dc=domain,dc=loc?sub # Ýòè çàïèñè îòíîñÿòñÿ ê ìîäóëþ nss_ldap, ïðåîáðàæàþò # îáúåêòû è àòðèáóòû AD ê âèäó, ïðèíÿòîìó â LDAP nss_map_objectclass posixAccount User nss_map_objectclass shadowAccount User nss_map_attribute uid sAMAccountName nss_map_attribute uidNumber msSFU30UidNumber nss_map_attribute gidNumber msSFU30GidNumber nss_map_attribute cn sAMAccountName nss_map_attribute uniqueMember member nss_map_attribute homeDirectory msSFU30HomeDirectory nss_map_attribute loginShell msSFU30LoginShell nss_map_attribute gecos name nss_map_objectclass posixGroup Group

Далее на очереди файл nsswitch.conf, тут всё просто – находите строчки: passwd: shadow: group:

files nisplus nis files nisplus nis files nisplus nis

и меняете их на: passwd: shadow: group:

files ldap files ldap files ldap

Редактируем файл /etc/pam.d/system-auth: #%PAM-1.0 auth required auth sufficient auth sufficient use_first_pass auth required

pam_env.so pam_unix.so likeauth nullok /lib/security/pam_ldap.so ↵ pam_deny.so

account required pam_unix.so account [default=bad success=ok user_unknown=ignore ↵ service_err=ignore system_err=ignore] ↵ lib/security/pam_ldap.so password required pam_cracklib.so retry=3 ↵ minlen=2 dcredit=0 ucredit=0 ucredit=0 password sufficient pam_unix.so nullok ↵ use_authtok md5 shadow password sufficient /lib/security/pam_ldap.so ↵ use_authtok password required pam_deny.so session required pam_limits.so session required pam_unix.so session required /lib/security/pam_mkhomedir.so ↵ skel=/etc/skel umask=0022 session optional /lib/security/pam_ldap.so

правила для локального пользователя, если такой учетной записи нет, то информация берется из AD. Но есть одна маленькая проблема, которая может стать большой. Дело в том, что домашний каталог автоматически не создается и по умолчанию таковым считается /. Вам придется создавать домашние каталоги руками на каждой машине, что не очень удобно. Для этого можно использовать модуль pam_mkhomedir. При регистрации в данной системе модуль смотрит, есть ли домашний каталог, если нет, то он его создает и копирует туда файлы из /etc/skel. Вы можете в соответствии со своими требованиями менять и порядок модулей, и их опции для разных служб. В таких перестановках надо быть осторожным, потому как можно прийти к неожиданным результатам вплоть до невозможности регистрироваться в системе даже под учетной записью root. Для начала логично почитать чтонибудь о PAM. После этих манипуляций можно попробовать зарегистрироваться на Linux-машине пользователем, который не упоминается в файлах passwd, shadow, group, но его UNIX-атрибуты присутствуют в AD. Если всё прошло отлично, то при первом входе среди прочих надписей увидим следующее: Creating directory '/home/test'. Creating directory '/home/test/tmp'.

Посмотрим, кем нас считает система: [test@linux-pc test]$ id uid=10000(test) gid=10000(testgroup) groups=10000(testgroup)

Настраиваем Solaris 9 x86. В Solaris есть свои модули pam_ldap и nss_ldap, только вот незадача – они не совсем совместимы с Active Directory, поэтому Microsoft рекомендует использовать модули от PADL (www.padl.com), те же, что применяются в Linux. Чтобы скомпилировать эти модули, потребуется установить ряд GNU-утилит, получить их можно на www.sunfreeware.com. Оглашаю весь список: ! autoconf-2.57-sol9-intel-local.gz ! automake-1.7.2-sol9-intel-local.gz ! gcc-3.2.1-sol9-intel-local.gz ! m4-1.4-sol9-intel-local.gz ! make-3.80-sol9-intel-local.gz Плюс к этому берем с сайта www.blastwave.org пакет berkeleydb3-3.11-i386-CSW.pkg.gz. Перед тем как собирать pam_ldap и nss_ldap, создадим символическую ссылку в /usr/local/bin на perl: ln -s /usr/bin/perl /usr/local/bin/perl

На файлы из каталогов /opt/csw/bin, /opt/csw/lib, /opt/csw/ include, созданные в процессе инсталляции berkeleydb33.11-i386-CSW.pkg.gz, сделаем символические ссылки в аналогичные каталоги, расположенные в /usr. Сделаем резервную копию оригинальных модулей pam_ldap и nss_ldap: cp /usr/lib/security/pam_ldap.so.1 ↵ /usr/lib/security/pam_ldap.so.1.bak; cp /usr/lib/nss_ldap.so.1 /usr/lib/nss_ldap.so.1.bak

Объявим переменные среды: В этом примере строчки, содержащие модуль pam_ ldap.so, были добавлены в соответствии с рекомендациями Microsoft. Суть их такова, что сначала система применяет

20

PATH=/usr/local/bin:$PATH LD_LIBRARY_PATH=/usr/local/lib export LD_LIBRARY_PATH


администрирование Это сработает для оболочек, совместимых по синтаксису с sh, например, bash, ksh. Если вы пользуетесь другим интерпретатором, посмотрите документацию к нему. Соберем модули от PADL, перейдя в соответствующие директории, созданные в процессе разархивации файлов, полученных с www.padl.com/download: cd pam_ldap-176 ./configure make make install cd nss_ldap-226 ./configure --enable-schema-mapping make make install

Если все прошло удачно, редактируем ldap.conf и nsswitch.conf аналогично Linux, за исключением строчки: uri ldap://server.domain.loc

которую заменим на: host server.domain.loc

Linux воспринимает оба формата, Solaris почему-то только host. Настройки PAM в Solaris хранятся в файле /etc/ pam.conf. На этом этапе, следуя советам Microsoft, я получил неработоспособную систему, поэтому кое-что поменял и добавил (представлены фрагменты с внесенными изменениями): # login service (explicit because of pam_dial_auth) login auth requisite pam_authtok_get.so.1 login auth required pam_dhkeys.so.1 login auth sufficient pam_unix_auth.so.1 login auth required pam_dial_auth.so.1 login auth sufficient pam_ldap.so.1 use_first_pass # Default definitions for Authentication management # Used when service name is not explicitly mentioned # for authenctication other auth requisite pam_authtok_get.so.1 other auth required pam_dhkeys.so.1 other auth sufficient pam_unix_auth.so.1 other auth sufficien pam_ldap.so.1 use_first_pass # Default definition for Session management # Used when service name is not explicitly mentioned # for session management other session required pam_unix_session.so.1 other session sufficient ↵ pam_mkhomedir.so skel=/etc/skel/ umask=0022 # Default definition for Password management # Used when service name is not explicitly mentioned # for password management other password required pam_dhkeys.so.1 other password requisite pam_authtok_get.so.1 other password requisite pam_authtok_check.so.1 other password required pam_authtok_store.so.1 other password sufficient pam_ldap.so.1 use_authtok

Здесь смысл примерно такой же, как и в случае с Linux. Pam_mkhomedir для Solaris не существует, но его можно собрать самостоятельно. Я следовал инструкциям на http:/ /keutel.de/pam_mkhomedir и получил работоспособный модуль, проделав следующие шаги на машине с Solaris: ! Скачал и распаковал исходный код Linux-PAM: http:// www.kernel.org/pub/linux/libs/pam/pre/library/Linux-PAM0.77.tar.gz, допустим, в /tmp.

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

! Скачал исходный код: http://keutel.de/pam_mkhomedir/ pam_mkhomedir.c тоже в /tmp и скомпилировал следующей командой (в одну строчку), находясь в /tmp: /usr/local/bin/gcc -D_REENTRANT -g -O2 -Wall -fPIC ↵ -c -ILinux-PAM-0.77/libpam/include ↵ -ILinux-PAM-0.77/libpamc/include ↵ -ILinux-PAM-0.77/modules/pammodutil/include ↵ -DPAM_DYNAMIC pam_mkhomedir.c -o pam_mkhomedir.o

! Получил готовый модуль следующей командой: /usr/ccs/bin/ld -o pam_mkhomedir.so -B dynamic -G ↵ -lc pam_mkhomedir.o

К сожалению, FreeBSD 4.x не умеет работать с nss_ldap и значит запрашивать данные о пользователе в AD, плюс не может менять пароль стандартными средствами с помощью pam_ldap. Но всё же доступ к машине, как с консоли, так и к службам ssh, ftp и т. д. можно получить, пройдя аутентификацию в Active Directory. Для этого установите pam_ ldap, отредактируйте два файла – ldap.conf и pam.conf. В ldap.conf достаточно внести следующий фрагмент: base dc=domain,dc=loc scope sub uri ldap://server.domain.loc port 389 ldap_version 3 binddn cn=ldap,cn=Users,dc=domain,dc=loc bindpw qwerty pam_filter objectclass=User pam_login_attribute sAMAccountName pam_password ad

В этом случае пароль из AD будет запрашиваться при входе с консоли, ftp и ssh, если пароль отвергнут, поиск будет продолжен в локальных файлах. login login login #login login #login #login login login login login

auth sufficient auth sufficient auth sufficient auth requisite auth requisite auth sufficient auth sufficient auth required account required password required session required

/usr/local/lib/pam_ldap.so pam_skey.so pam_opie.so no_fake_prompts pam_opieaccess.so pam_cleartext_pass_ok.so pam_kerberosIV.so try_first_pass pam_krb5.so try_first_pass pam_unix.so try_first_pass pam_unix.so pam_permit.so pam_permit.so

# Same requirement for ftpd as login ftpd auth sufficient /usr/local/lib/pam_ldap.so ftpd auth sufficient pam_skey.so ftpd auth sufficient pam_opie.so no_fake_prompts #ftpd auth requisite pam_opieaccess.so ftpd auth requisite pam_cleartext_pass_ok.so #ftpd auth sufficient pam_kerberosIV.so try_first_pass #ftpd auth sufficient pam_krb5.so try_first_pass ftpd auth required pam_unix.so try_first_pass # OpenSSH with PAM support requires similar modules. # The session one is a bit strange, though... sshd auth sufficient /usr/local/lib/pam_ldap.so sshd auth sufficient pam_skey.so sshd auth sufficient pam_opie.so no_fake_prompts #sshd auth requisite pam_opieaccess.so #sshd auth sufficient pam_kerberosIV.so try_first_pass #sshd auth sufficient pam_krb5.so try_first_pass sshd auth required pam_unix.so try_first_pass sshd account required pam_unix.so sshd password required pam_permit.so sshd session required pam_permit.so

Локально пароль можно вообще не хранить. Для этого при помощи команды vipw отредактируйте файл паролей.

21


администрирование Сотрите зашифрованный пароль во втором поле и поставьте там * (звёздочка). По сведениям, взятым на http://www.padl.com/OSS/nss_ ldap.html, FreeBSD 5.1 и выше уже работает с nss_ldap, но проверить это лично не удалось по причине отсутствия дистрибутива. Осталось прикрутить SSL. Хотя это вовсе не обязательно, наверняка вы захотите использовать шифрование по двум причинам. Первая – безопасность, ведь запросы к ldap, в том числе пароли, передаются в открытом виде, вторая – возможность пользователю самому менять пароль в AD посредством стандартной команды passwd. Необходимо проделать некоторые операции, как на Windows-сервере, так и на клиентских машинах. На сервере: ! Убедиться, что поддерживается шифрование 128 bit, иначе вы не сможете удаленно поменять пароль. Windows 2000 sp2 и выше это умеет, в противном случае установите Encryption pack. ! Установить сервис сертификатов, входящий в дистрибутив. Без этого сервер не будет принимать соединения по протоколу ldaps. В процессе инсталляции сервиса сертификатов будет предложено создать корневой сертификат. Заполнив поля (можно не все), вы получите файл сертификата, лежащий в директории с:\. Делать с ним ничего не придется. В журнале событий (event viewer) должна появиться запись о возможности принятия соединений LDAPS (прим.: у меня это сообщение появилось на следующий день, может, потому, что я не перегружал машину, а до этого все попытки коннекта на ldaps:636 терпели неудачу). Проверить, что сервер работает корректно, можно простым способом. С любой Windows-машины в домене или на самом сервере выполните «Start → Search → For People».

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

22

setgid = stunnel # Some debugging stuff debug = 7 output = /var/log/stunnel.log # Use it for client mode client = yes # Service-level configuration [ldap] accept = 127.0.0.1:389 connect = server.domain.loc:636

Из данного примера мы видим – stunnel работает в клиентском режиме, слушает запросы на 127.0.0.1 порт 389 и пересылает их на Windows-сервер порт 636 уже в зашифрованном виде. В зависимости от операционной системы вам придется вручную создать пользователя stunnel и каталог /var/tmp/stunnel с возможностью записи для этого пользователя. В файле ldap.conf просто поменяем строчку: ri ldap://server.domain.loc

на host 127.0.0.1

Перегружаем машину, регистрируемся, пробуем менять пароль. Параллельно tcpdump на другом терминале можно наблюдать наши SSL-соединения. В результате мы имеем централизованную систему управления пользователями средствами Active Directory, что значительно облегчает работу администратора. Интеграция таким способом позволяет внедрить UNIX-системы в существующую структуру Windows-сетей и при этом отказаться от ведения дополнительных каталогов или хранения пользовательских данных на каждой машине.



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

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

СЕРГЕЙ СУПРУНОВ Представьте себе ситуацию: узел СПД в составе маршрутизатора CISCO и коммутатора Catalyst находится на первом этаже, а ваш FreeBSD-сервер – на четвертом. И при этом требуется вывести во внешний мир несколько подсетей, которые проходят через сервер FreeBSD на Catalyst. Можно, конечно, подключить к серверу несколько сетевых адаптеров, занять для внутреннего использования несколько портов на Catalyst и пробросить между этажами километр кабеля 5-й категории. На кабеле можно даже сэкономить, пропустив по одному кабелю сразу два соединения и задействовав тем самым все имеющиеся пары. Однако все равно и затрат, и дополнительных работ по прокладке кабелей получается слишком много. А раз возникает сложность, то наверняка кто-то уже нашел способ ее устранить. И в нашем случае панацеей будет технология VLAN – виртуальные локальные сети. Данная технология позволяет логически разделять несколько подсетей на одном устройстве (например, коммутаторе) таким образом, что машины, объединенные в одну VLAN, ничего не знают о существовании компьютеров, входящих в другую. И с точки зрения топологии сети мы получаем отдельные коммутаторы для каждой подсети. На уровне протоколов это достигается добавлением нескольких полей в заголовок пакета сетевого уровня. Одно из добавленных полей содержит идентификатор (номер) сети VLAN, на основе которого и происходит разделение Ethernet-кадров по виртуальным сетям. Кадры, имеющие одинаковый номер VLAN, рассматриваются как принадлежащие одной подсети. Регламентируется это стандартом IEEE 802.1Q. Развитие технологии VLAN привело к тому, что стало возможным не только назначать отдельные подсети отдельным портам, но и через один порт пропускать несколько VLAN (так называемый multiVLAN). То же относится и к сетевым адаптерам, чем мы и воспользуемся. Рассмотрим настройку VLAN для FreeBSD на следующем примере: пусть имеется один отрезок кабеля между Catalyst и FreeBSD. На Catalyst свободен один порт, на FreeBSD – одна сетевая карта, обслуживающая внешние соединения. Нужно через это соединение организовать передачу следующих подсетей:

24

! подсеть реальных адресов для работы в Интернете (111.222.0.0/28);

! корпоративная частная подсеть для доступа к вышестоящим узлам компании (10.0.123.0/24);

! и еще одна сеть для управления оборудованием СПД (10.254.0.0/24). Прежде всего нужно проверить, поддерживает ли ваша сетевая карта работу по VLAN. Некоторые карты обеспечивают поддержку данной технологии на аппаратном уровне, однако драйвер также должен поддерживать VLAN. Страница справочного руководства (см. man vlan) для FreeBSD 5.2 сообщает, что аппаратное мультиплексирование поддерживается для драйверов bge, em, gx, nge, ti и txp. (Во FreeBSD 5.3 к этому списку добавился еще и драйвер re, обеспечивающий работу сетевых адаптеров на чипсетах RealTek 8139C+/8169/8169S/8110S). Узнать подробную информацию по каждому из драйверов, в том числе список поддерживаемых драйвером моделей сетевых карт, можно на страницах man (например, man 4 em сообщает, что драйвером em поддерживается Intel PRO/1000 Gigabit Ethernet adapter). Если ваш адаптер не входит в этот список, то наверняка он сможет работать с использованием программной эмуляции мультиплексирования. По крайней мере, для большинства современных карт это утверждение справедливо. Нужно заметить, что тот же man vlan гласит, что сетевой адаптер для полноценной эмуляции должен поддерживать «длинные» кадры (oversized frames). В противном случае из-за необходимости размещения дополнительных полей заголовка, содержащих информацию о VLAN, которой принадлежит пакет, приходится снижать максимальный размер передаваемого пакета (MTU) на соответствующем интерфейсе. Драйвера сетевых адаптеров, поддерживающих длинные кадры, перечислены в man vlan, однако данный список нельзя считать исчерпывающим, поскольку с 2002 года (когда писались страницы руководства) ситуация изменилась в лучшую сторону и перечень совместимых сетевых карт значительно расширился. По крайней мере, D-Link DFE538TX, работающий на драйвере rl, отсутствующем в списке, никаких нареканий с моей стороны не вызвал. (Замеча-


администрирование ние: во FreeBSD 5.3 поддержка vlan значительно расширена, и теперь поддержка длинных кадров драйвером rl оформлена официально.) Пожалуй, хватит теории. Перейдем к практике. Для работы VLAN в системе должны быть соответствующие псевдоустройства. В случае с FreeBSD 5.2 (думаю, это справедливо и для всей 5-й ветки) устройства vlan создаются динамически. За это отвечает модуль ядра if_vlan.ko. Если вы предпочитаете иметь монолитное ядро, то потребуется пересобрать его со следующей опцией: device

vlan

Для 3-й и 4-й веток FreeBSD может потребоваться пересобрать ядро с такой строчкой: pseudo-device

vlan

N

Вместо N нужно подставить количество устройств, которое вам понадобится. После сборки и установки нового ядра в системе должны появиться соответствующие интерфейсы vlan0, vlan1 и т. д., просмотреть которые можно командой: ifconfig -a

Для FreeBSD 5.2 (в недавно вышедшей 5.3 все настраивается точно так же) для создания vlan-интерфейсов используется «клонирование» (cloning) на этапе загрузки (об этом – чуть ниже) либо программа ifconfig с опцией create. Второй вариант выглядит следующим образом: # ifconfig vlan0 ifconfig: interface vlan0 does not exist

# ifconfig vlan0 create 111.222.0.5 ↵ netmask 255.255.255.240 vlan 111 vlandev rl0 # ifconfig vlan0 vlan0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 inet 111.222.0.5 netmask 0xfffffff0 broadcast 111.222.0.15 inet6 fe70::204:5cff:fedf:f81f%vlan0 prefixlen 64 scopeid 0xd ether 00:05:5d:cf:f9:1e media: Ethernet autoselect (100baseTX <full-duplex>) status: active vlan: 111 parent interface: rl0

Опция vlan задает номер VLAN, присвоенный этой сети. Параметр vlandev указывает физический интерфейс, используемый для организации VLAN. Заметьте, что этот интерфейс (в нашем случае rl0) должен иметь собственный IP-адрес, даже если реально он нигде использоваться не будет: # ifconfig rl0 rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 options=8<VLAN_MTU> inet 10.10.10.10 netmask 0xffffff00 broadcast 10.10.10.255 inet6 fe70::204:5cff:fedf:f81f%rl0 prefixlen 64 scopeid 0x1 ether 00:05:5d:cf:f9:1e media: Ethernet autoselect (100baseTX <full-duplex>) status: active

Обратите внимание, что интерфейсы vlan наследуют MAC-адрес «родительского» интерфейса, но поскольку сети у нас разные, то ни к каким конфликтам это не приведет.

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

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

Аналогично описываются остальные интерфейсы. Идентификатор VLAN задается в параметре encapsulation dot1Q, в данном случае он равен 111. На Catalyst соответствующий порт нужно перевести в trunk-режим и при желании можно указать список разрешенных номеров VLAN: interface FastEthernet0/24 switchport trunk allowed vlan 100,111,999 switchport mode trunk no ip address

С точки зрения остальных служб операционной системы, например ipfw или natd, полученный интерфейс ничем не отличается от физических и может использоваться как обычно. Например, можно подсчитать трафик, проходящий через vlan0: # ipfw add 1234 count ip from any to any via vlan0

Остался последний штрих – настройка конфигурации для автоматического создания нужного интерфейса при перезагрузке. Для этого в файл /etc/rc.conf добавим следующие строчки: # Ñîçäàåì íóæíûå èíòåðôåéñû, èñïîëüçóÿ ìåõàíèçì # êëîíèðîâàíèÿ: cloned_interfaces="vlan0 vlan1 vlan2" # È îïèñûâàåì ñîîòâåòñòâóþùèå èíòåðôåéñû VLAN: ifconfig_vlan0="inet 111.222.0.5 ↵ netmask 255.255.255.240 vlan 111 vlandev rl0" ifconfig_vlan1="inet 10.254.0.5 ↵ netmask 255.255.255.0 vlan 100 vlandev rl0" ifconfig_vlan2="inet 10.0.0.3 ↵ netmask 255.255.255.0 vlan 999 vlandev rl0"

Если «пропадание» сервера на пару минут не критично, то рекомендуется его перезагрузить, чтобы лишний раз убедиться в правильности всех настроек. Бежать среди ночи к неудачно загрузившемуся из-за пропущенного пробела серверу – не самое приятное занятие. Нужно заметить, что технология VLAN позволяет шифровать трафик (например, ряд сетевых карт поддерживают аппаратное шифрование), однако во FreeBSD это не реализовано и поддерживается только разделение пакетов на основе идентификаторов VLAN. Хотя можно ожидать, что поддержка карт с аппаратным шифрованием появится в будущем. Тем не менее имеющихся в данный момент возможностей вполне достаточно, чтобы без особых усилий повысить эффективность использования имеющегося оборудования.

25


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

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

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

26

ся в базу данных телефонных переговоров, поддерживаемую СУБД PostgreSQL. На основе базы данных ведется подсчет трафика, расчет оплаты и выполняются практически любые запросы, интересующие пользователей. Обычный веб-интерфейс позволяет выводить на экраны (удаленных) компьютеров результаты запросов в режиме реального времени.


администрирование Введение Биллинговая система – это комплекс программ, работающий на компьютере, сопряженном с АТС и позволяющий тарифицировать телефонный трафик, выставлять счета абонентам, получать практически любую информацию по звонкам. Такие системы обычно дороги. Многие пользуются Win Tarif (как правило, взломанной версией…). Можно также посмотреть сайт www.billonline.ru со всеобъемлющим сертифицированным Министерством связи решением проблем (за деньги) учета телефонных переговоров. Наш подход, однако, – демонстрация философии UNIX в действии – позволяет обеспечить простое, бесплатное, открытое решение. Состоит оно из нескольких десятков строк кода и опирается на типовые утилиты UNIX. Сложность кода минимальная, достаточно, например, владения азами SQL и Perl. Обычно оператор связи, предоставивший телефоны, выставляет счет раз в месяц, а тарификацию по внутренним номерам офисной АТС либо вообще отказывается делать, либо требует дополнительной оплаты. Платное программное обеспечение имеет закрытый код и не ясно, что и как оно считает, заменить в нем что-нибудь на более подходящий вариант невозможно. Таким образом, наличие подобного предлагаемого в статье простого решения полезно для работы организации. В настоящее время в небольших фирмах – операторах связи или в офисах крупных (и не очень) компаний наряду в ЛВС имеется АТС, часто попадающая на обслуживание системному администратору. Так что затронутые в статье вопросы многим окажутся интересны. План действий по автоматизации тарификации АТС следующий: ! смотрим, что и в каком формате выводит АТС на порт, сопрягаемый с компьютером (часто это com-порт); ! пишем скрипт, разбирающий должным образом получаемый поток байтов с АТС; ! заводим в СУБД (PostgreSQL) необходимые таблицы; ! добавляем к скрипту блоки захвата вывода с АТС и загрузки обработанных скриптом записей в СУБД; ! формируем скрипт сопряжения базы данных с веб-сервером для возможности просмотра данных и запросов абонентами и руководством. Собственно и все. За пару дней это можно сделать и запустить в эксплуатацию. Например, на следующем комплексе: Pentium-200 MMX, 256 Мб ОЗУ, FreeBSD версии 4.5 и выше с Perl5, PostgreSQL 7 довольно быстро обрабатывается до 100 тыс. записей звонков. Это около 100-150 номеров абонентов, звонящих с интенсивностью выше средней в течение месяца. На Pentium 4 можно легко обрабатывать уже миллионы записей. Все вышеприведенное будет легко работать и под любым другим UNIX.

Тестирование формата вывода АТС и алгоритм программы Сначала надо изучить выходные сигналы АТС. Мы рассматриваем NEAX2000 IPS с настройками, практически не отличающимися от стандартных. В нашем случае отличие сво-

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

дится к тому, что обозначение внутренних номеров начинается со знака *, например, *029. Такая нумерация обычно используется, чтобы можно было звонить «в город» без набора «9». Соединим кабелем COM-порт компьютера с RS232 разъемом АТС, находящимся на процессорной плате. Для определенности используем нулевой порт – как правило, в компьютере два COM-порта: нулевой и первый. Обычно тарификация проводится для исходящих вызовов, поэтому здесь мы не будем рассматривать другие звонки. Введем следующую команду для прослушивания порта, на который поступает информация от АТС (для Linux порт будет называться не dev/cuaa0, а, cкорее всего, /dev/ ttyS0): # cat /dev/cuaa0 >> file

получим при каждом исходящем вызове добавку к содержимому файла file: ^B0!KA050077001*029 08110737260811073756 000050050100 0000 04040

(с учетом пробелов для каждой записи получаем 128 байтов, по байту на каждый символ). Приведенный пример содержит информацию о том, что с номера *029, 11 августа с 7 час. 37 мин. 26 сек до 37 мин. 56 сек. абонент звонил на номер 100 (служба «время» в МГТС). При разборке файла с помощью Perl в качестве признака конца записи для отдельных вызовов можно принять восклицательный знак «!». Воспользовавшись вызовом sysread(fd, $v, length), где fd – дескриптор файла $v – переменная, в которую пишется информация, length – количество считывающихся байтов за один вызов, можно установить, что АТС выдает всю запись по вызову отдельными порциями наборов символов, указанных в примере, разделенными пробелами. В АТС имеется буфер (довольно приличный по размеру), в котором хранятся данные по вызовам, так что при соединении с компьютером все предыдущие вызовы «скачиваются» в компьютер. Код будущей программы состоит из двух блоков: ! блок считывания и обработки (считывает из порта информацию, поступающую из АТС); ! блок загрузки записей в базу данных. Перед рассмотрением приведенного ниже кода скрипта подчеркнем следующее. Наша цель – показать, что создать собственную систему биллинга совсем несложно. У каждого системного администратора есть свои излюбленные приемы в Perl, которые он при необходимости использует, приспособив подходящим образом приведенный скрипт или написав свой собственный. Поэтому мы для краткости оставили лишь типовую обработку ошибок, не стремимся усложнять код для обеспечения его безопасности, оптимальности или краткости. Отметим только, что приведенный код неплохо работал у нас на стареньком отдельно стоящем компьютере:

27


администрирование процессы внутри АТС относительно медленные и Perl успевает делать все вовремя и без ухищрений. Отлаженный вариант биллинговой системы с учетом кода для вывода данных с помощью PHP на Apache-сервер достаточно длинный для размещения в тексте, поэтому предоставлен автором всем желающим (www.samag.ru/source).

Реализация программы Для реализации программы с помощью системы портов FreeBSD помимо PostgreSQL необходимо для работы интерфейса Perl к PostgreSQL установить модули Perl – DBI, DBD-Pg. Запустив PostgreSQL, создадим таблицу atstarif базы данных ats: # create table atstarif (nums varchar(15), mydate date, ↵ mytime time, min int, numd bigint);

! ! ! !

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

Программа биллинга на Perl может иметь следующий вид (некоторые комментарии даны в самом коде). #!/usr/bin/perl use POSIX qw(:errno_h); use DBI; use strict; my $user="pgsql"; my $dbname="ats"; my $dsh; my $dbh; my $p; my $pid; $SIG{ALRM}= 'proga'; sub proga { kill 9 => $pid; kill 9 => $p; } # ïðîãðàììà ðàáîòàåò â áåñêîíå÷íîì öèêëå, ïåðèîäè÷åñêè # (ðàç â äâå ìèíóòû) ïîäêëþ÷àÿñü ê ïîðòó, íà êîòîðûé # ÀÒÑ ïîñûëàåò äàííûå î çâîíêàõ while(1) { $dsh="dbi:Pg:dbname=$dbname;port=5432"; $dbh=DBI->connect("$dsh", "$user") or die ↵ "can't connect: $!\n"; $pid=open (ATS, "cu -l/dev/cuaa1 -s9600|"); $p=($pid)+1; # ïðîãðàììà ïîäêëþ÷èëàñü ê áàçå äàííûõ è íà÷àëà ñ÷èòûâàòü # äàííûå îò ÀÒÑ eval { alarm(60); }; my @str = <ATS>; my $sstr; my $ccc; my $ss; my $g; # â ýòîì öèêëå íà÷èíàåòñÿ îáðàáîòêà ïîñòóïàþùèõ ñòðîê îò ÀÒÑ foreach $sstr (@str) { if ($sstr=~ /!/) { my @s= split /!/, $sstr; # ïîäñ÷åò âðåìåíè çâîíêà óäîáíî âûäåëèòü â îòäåëüíóþ # ïîäïðîãðàììó

28

sub duration { my $a=substr($ccc, 6, 10); my $b=substr($ccc, 16, 10); my @aa=split //, $a; my @bb=split //, $b; my $aaa=(($aa[2]*10)+$aa[3])*24*60*60+($aa[4]*10+ ↵ $aa[5])*60*60+($aa[6]*10+$aa[7])*60+$aa[8]*10+$aa[9]; my $bbb=(($bb[2]*10)+$bb[3])*24*60*60+($bb[4]*10+ ↵ $bb[5])*60*60+($bb[6]*10+$bb[7])*60+$bb[8]*10+$bb[9]; my $r=$bbb-$aaa; my $cc1=$r%60; my $cc11=($r-$cc1)/60; my $cc2=$cc11%60; my $cc21=($cc11-$cc2)/60; my $cc3=$cc21%24; my $z=" h$cc3 m$cc2 s$cc1 "; } foreach $ss (@s) { $ss =~ s/.*\*/\*/g; $ss =~ s/\b0000 .*//g; $ss =~ s/\b0000600606//g; $ss =~ s/\b000050050//g; $ccc=$ss; my $z=substr($ss, 16, 10); # òåïåðü ïðèìåíèì ïîäïðîãðàììó ïîäñ÷åòà âðåìåíè # ê ïåðåìåííîé $ccc; my $res=&duration; $ss=~ s/$z/$res/g; $ss=~ s/h//g; $ss=~ s/m//g; $ss=~ s/s//g; my @f= split (/\s+/, $ss); if ($f[4]) { $f[4] = 1; } my $z = $f[2]*60 + $f[3] + $f[4]; my @g = split (//, $f[1]); if ($g[4]==0) { $g[4]=""; } my @gg = ($g[2].$g[3], '.', $g[0].$g[1], '.', ↵ '04', " ", $g[4].$g[5], ':', $g[6].$g[7]); $f[1]= join ("", @gg); my @ff = ($f[0], $f[1], $z, $f[5]); $ss = join (" ", @ff); if ($ss=~ /\*\d\d\d \d\d\.\d\d\.\d\d \d+:\d+ \d+ \d+/) { # ñòðîêà ñôîðìèðîâàíà äëÿ çàïèñè â áàçó äàííûõ $g= $ss; # òåïåðü ñòðîêó $g ïðèâåäåì ê íåîáõîäèìîìó ôîðìàòó # è çàãðóçèì â áàçó äàííûõ chomp($g); my @gg=split / /, $g; my @ggg=split /\./, $gg[1]; $gg[1]=join "-", "20$ggg[2]", $ggg[1], $ggg[0]; my @dt; $dt[0]=$dbh->quote("$gg[0]"); $dt[1]=$dbh->quote("$gg[1]"); $dt[2]=$dbh->quote("$gg[2]"); $dt[3]=$dbh->quote("$gg[3]"); $dt[4]=$dbh->quote("$gg[4]"); my $tbl="atstarif "; $dbh->do("insert into $tbl (nums, mydate, mytime, min, numd) values ($dt[0], $dt[1], $dt[2], $dt[3], $dt[4])"); } } } } $dbh->disconnect(); close ATS; sleep(60); }

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



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

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

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

30

ные транзакции. Пограничным хостом (firewall) была давненько установленная нами, в то время еще OpenBSD 3.1stable, с PF в качестве пакетного фильтра. При осмотре Linux-сервера сразу стало понятно, что его атаковали, и не раз, я нашел огромное количество различных exploits на сервере и несколько скриптов, которые в тот момент держали открытыми порты с shell, запущенными от прав wwwсервера. После проверки сервера различными методами я пришел к выводу, что злоумышленникам так и не удалось ни похитить данные, ни проникнуть на сервер. Мне стало интересно, как же данные со взломанного сервера (сервер действительно считался взломанным по нашим критериям) так и не ушли в чужие руки.

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


администрирование Так как сервер останавливать было нельзя, пришлось вживую искать все ниточки. Все свелось к одному – на сервере с OpenBSD, посмотрев лог-файлы пакетного фильтра, сразу стало ясно, что любые попытки добраться к тем shell на Linux-сервере оканчивались провалом, ибо фильтрация была настолько четкой, что помимо входящих соединений контролировались и все исходящие. Дальнейшее исследование показало все места, откуда были произведены атаки, и подтвердило их безуспешность. Сейчас в той организации стоит новый мощный сервер под управлением Sun Solaris 10 и теперь уже OpenBSD 3.6-stable. К чему вся эта история? Показать на конкретном примере, как важно использование пакетных фильтров и как они могут защитить заведомо опасные приложения. Итак, приступим к продолжению нашей статьи, я расскажу вам о следующих вещах: ! Распределение по очередям (Queuing). ! Роутинг (маршрутизация).

Распределение по очередям (Queuing) Любые пакеты могут быть разделены по очередям для контроля полосы пропускания. Зачем это надо? Распределять нагрузку на канал равномерно для всей сети, например, или же, наоборот, урезать трафик для определенного сервиса или IP-адреса. Для определения «очереди» (queue) нужны всего лишь две декларации, и в дальнейшем все пакеты можно будет распределять по очередям, используя «имя очереди». Согласно компоненту фильтрации пакетного фильтра (PF), для правила pass данный пакет будет помещен в очередь, на которую ссылалось последнее(!) правило. Немножко запутанно? Поясню на примере: pass in any pass in any

on $ext_if inet proto tcp from any to ↵ port 80 keep state queue www-1 on $ext_if inet proto tcp from any to ↵ port 80 keep state queue www-2

Здесь будет применено последнее правило, т.е пакет будет присвоен очереди с именем «www-2». Очередями управляют «планировщики». На данный момент PF поддерживает 3 типа «планировщиков»: ! CBQ (Class Based Queueing) – очереди, прикрепленные к интерфейсу, создают «дерево», в котором каждая из этих очередей может иметь своих «потомков». Очереди имеют приоритет и полосу пропускания. Приоритет определяет, через какую очередь пакет пройдет первым, а полоса пропускания уже непосредственно влияет на скорость прохождения. CBQ выполняет двухсторонее разделение полосы пропускания вашего канала, используя иерархически-структурированные классы. Каждый класс имеет свою собственную «очередь» и присвоенную ей способность пропускания. Класс-потомок может заимствовать у родительского класса только(!) ту пропускную способность, которая в данный момент доступна для него. ! PRIQ (Priority Queueing) – очереди просто присоединены к интерфейсу и не могут иметь очередей-потомков. Каждая такая очередь имеет свой уникальный «приоритет», который может принимать значения от 0 до 15.

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

Пакеты в очереди с наибольшим приоритетом будут обработаны первыми. ! HFSC (Hierarchical Fair Service Curve) – описание очень схоже с CBQ за исключением некоторых дополнений. HFSC есть не что иное как «исправленный» механизм, базирующийся на модели QoS. Его уникальность состоит в возможности разъединять связь между задержкой пакета и очередью. То есть HFSC обрабатывает очереди и пакеты отдельно друг от друга, однако после процесса обработки пакет и очередь опять логически связываются. В некоторых ситуациях это позволяет добиться максимальной производительности от трафик-шейпера. Очень часто это используется для сервисов, работающих в режиме реального времени. Активизировать возможность распределения по очередям нужно в конфигурационном файле вашего фильтра (по умолчанию /etc/pf.conf) при помощи директивы «altq on», которая имеет свои дополнительные параметры: ! <interface> – имя интерфейса, для которого мы включаем данную возможность, если не определено, то очереди будут активированы для всех интерфейсов. ! <scheduler> – планировщик, в данный момент PF поддерживает cbq, priq, hfsc. ! bandwidth <value> – максимальный битрейт для всех очередей на данном интерфейсе. Значение может быть определено как процент от общей пропускной способности интерфейса, так и числовой величиной. Для этого могут использоваться слова b, Kb, Mb, Gb. Что соответственно – биты, килобиты, мегабиты, гигабиты. Если значение bandwidth не задано, то будет использована максимальная скорость. ! qlimit <value> – количество пакетов, которое может обслуживать очередь, по умолчанию 50, это значение отлично подходит для 100-мегабтиных сетей. ! queue <list> – определяет список очередей, которые будут созданы для данного интерфейса. В этом примере интерфейс dc0 будет распределять в очереди 5Mbit/s, используя CBQ. altq on dc0 cbq bandwidth 5Mb queue { std, http, mail, ssh }

После включения altq мы можем создавать очереди-потомки. Для них используются те же дополнительные параметры, что и для директивы altq, за исключением <scheduler> и queue, т.к они уже определены. Имя родительской очереди должно совпадать с определением в altq. Например: queue std bandwidth 10% cbq(default)

Для <scheduler> есть список параметров, которые помогают контролировать работу очереди. ! default – попадая в эту очередь, пакет не проверяется дальше, а тут же обрабатывается. ! red – Random Early Detection – RED отбрасывает пакеты, которые, предположительно могут перегрузить очередь.

31


администрирование ! ecn – Explicit Congestion Notification – практически то же самое, что и RED. Отличается лишь алгоритмом обработки очередей, в итоге результат тот же, что и при использовании RED. RED использует более оптимизированный алгоритм, и за его счет обработка очередей происходит гораздо быстрее. Для CBQ предусмотрены дополнительные параметры.

! borrow – очередь-потомок может «заимствовать» свободную пропускную способность у родительской очереди в случае необходимости. Теперь параметры для HFSC.

! realtime <sc> – минимальная доступная пропускная способность для очереди.

! upperlimit <sc> – максимальная доступная очереди пропускная способность.

! <sc> – список так называемых service curve (для realtime задач), которые имеют формат (m1, d, m2), работают они по принципу «для первых d мили-секунд выдавать пропускную способность m1, после этого m2». Синтаксис определения очередей CBQ и HFSC одинаков, разница лишь в дополнительных параметрах (см. выше). Однако стоит помнить, что скорость пропускания для очередей-потомков не может быть больше той, что определена для родительской очереди. Дополнительный параметр для определения очередей – priority <level> – указывает приоритет очереди. Для CBQ и HFSC значения могут быть от 0 до 7, для PRIQ – от 0 до 15. Значение по умолчанию для всех очередей 1. Присвоение пакетов очередям происходит при помощи ключевого слова queue в правилах фильтрации(!). В нормальном режиме указать можно только одну очередь, однако, если же указана вторая, то пакеты будут обрабатываться на основе TOS (Type Of Service). Что ж, теперь давайте посмотрим, как все это выглядит на практике, ибо в теории мало что понятно. Включаем очереди:

Итак, очередь std будет забирать 10% от нашего 5Mbit/s канала. Очередь http будет забирать 60% и иметь двух потомков employees и developers с механизмом определения преждевременной нагрузки RED и возможностью «заимствования» полосы пропускания у родителя. У очереди http приоритет равен 2, что в данной конфигурации является наивысшим приоритетом (т.к значения больше, чем «2» не определены). Значит, данная очередь будет обрабатывать пакеты первой. Для очередей-потомков установлены скорости в процентном отношении соответственно 75% и 15%. Важно понимать, что вычисляться эти проценты будут из того куска общей пропускной способности канала, который отдан родительской очереди. Очередь mail определена как 10% от общей полосы пропускания и имеет низший приоритет (0), чем другие. Очередь ssh делится на ssh_interactive и ssh_bulk, имеющие приоритеты 7 и 0. Как только появляется пакет с портом назначения 22 и его помещают в очередь ssh_bulk. После того как соединение считается установленным, пакет переходит в очередь ssh_interactive и имеет наивысший приоритет для родительской очереди. А зачем так сложно? Стоит помнить, что «контроль состояний» (stateful inspection) применяется не только для фильтрации, но и для контроля полосы пропускания, а это означает, что даже при огромных правилах фильтров и различных ограничений скорости ваш сервер не будет иметь проблем с загрузкой процессора.

Роутинг (маршрутизация)

И назначаем правила:

Тут все просто и мощно. Управлять пакетом нам позволяют те же правила фильтрации, однако с добавлением одной из нижеперечисленных опций. Помните – когда создается «состояние» (state), все пакеты для данного правила фильтрации и роутинга попадают под него. ! fastroute – обычный режим, система обрабатывает пакет обычным образом. ! route-to – система направляет пакет на нужный интерфейс с возможностью указания IP для «следующего хоста». Надо помнить, что помимо route-to нужно создать правила, позволяющие направлять пакет с одного интерфейса на другой в правилах фильтрации, иначе все ваши пакеты будут зарезаны фильтром. ! reply-to – на сей раз система отвечает пакетом с указанным IP-адресом и интерфейсом. ! dup-to – создает дубликат пакета и отправляет его с помощью route-to. Настоящий пакет обрабатывается обычным способом. Dup-to полезно использовать для обнаружения конфликтов в сети, когда рабочий сервер трогать нельзя, а трафик, проходящий через него, нужно анализировать.

block return out on dc0 inet all queue std pass out on dc0 inet proto tcp from $developerhosts to ↵ any port 80 keep state queue developers pass out on dc0 inet proto tcp from $employeehosts to ↵ any port 80 keep state queue employees pass out on dc0 inet proto tcp from any to ↵

Комбинируя правила фильтрации и опции роутинга, можно добиться очень сложных схем маршрутизации, но для таких целей придумали Cisco routers. А это уже совсем другая история.

altq on dc0 cbq bandwidth 5Mb queue { std, http, mail, ssh }

Определяем родительские очереди и очереди-потомки. queue queue { queue queue queue queue { queue queue

32

any port 22 keep state queue(ssh_bulk, ssh_interactive) pass out on dc0 inet proto tcp from any to ↵ any port 25 keep state queue mail

std bandwidth 10% cbq(default) http bandwidth 60% priority 2 cbq(borrow red) ↵ employees, developers } developers bandwidth 75% cbq(borrow) employees bandwidth 15% mail bandwidth 10% priority 0 cbq(borrow ecn) ssh bandwidth 20% cbq(borrow) ↵ ssh_interactive, ssh_bulk } ssh_interactive priority 7 ssh_bulk priority 0


bugtraq Повышение привилегий в Symantec Windows LiveUpdate

Переполнение буфера в Microsoft Windows NT DHCP

Программа: Norton AntiVirus 2001, Norton AntiVirus 2002, Norton Internet Security 2001, Norton Internet Security 2002, Norton Internet Security 2003, Norton Internet Security 2003 Professional, Norton Internet Security 2004, Norton Internet Security 2004 Professional, Norton SystemWorks 2001, Norton SystemWorks 2002, Norton SystemWorks 2003, Norton SystemWorks 2004, Symantec AntiVirus for Handhelds 3.x, Symantec Norton AntiVirus 2003, Symantec Norton AntiVirus 2004, Symantec Windows LiveUpdate 1.x, Symantec Windows LiveUpdate 2.x. Опасность: Средняя. Описание: Обнаружена уязвимость в Symantec Windows LiveUpdate. Локальный атакующий может повысить свои привилегии на системе. Уязвимость существует из-за того, что Symantec Automatic LiveUpdate позволяет управлять некоторыми интернет-опциями с системными привилегиями. Локальный атакующий может использовать эту уязвимость во время сессии LiveUpdate посредством графического интерфейса при запущенной задаче «NetDetect». URL производителя: www.symantec.com. Решение: Установите обновления с сайта производителя.

Программа: Microsoft Windows NT. Опасность: Средняя. Описание: Обнаружено несколько уязвимостей в DHCPслужбе в Microsoft Windows NT. Удаленный атакующий может вызвать отказ в обслуживании и скомпрометировать уязвимую систему. 1. Уязвимость существует из-за некорректной проверки длины буфера при логировании некоторых значений определенных пакетов. Удаленный атакующий может специальным образом сформировать DHCP-пакет и вызвать отказ в обслуживании. 2. Уязвимость существует из-за некорректной проверки буфера при обработке DHCP-сообщений. Удаленный атакующий может послать специально сформированное DHCP-сообщение, вызвать переполнение буфера и выполнить произвольный код на уязвимой системе. URL производителя: www.microsoft.com. Решение: Установите обновления: 1. Microsoft Windows NT Server 4.0 (requires Service Pack 6a): http://www.microsoft.com/downloa...F82D-F2A2-49AABF33-897498898EAD. 2. Microsoft Windows NT Server 4.0 Terminal Server Edition (requires Service Pack 6): http://www.microsoft.com/ downloa...259F-3004-462C-B2A8-37F65EB78A2D.

Переполнение буфера в WINS Программа: Microsoft Windows 2000 Advanced Server, Microsoft Windows 2000 Datacenter Server, Microsoft Windows 2000 Server, Microsoft Windows NT 4.0 Server, Microsoft Windows NT 4.0 Server, Terminal Server Edition, Microsoft Windows Server 2003 Datacenter Edition, Microsoft Windows Server 2003 Enterprise Edition, Microsoft Windows Server 2003 Standard Edition, Microsoft Windows Server 2003 Web Edition. Опасность: Высокая. Описание: Обнаружено переполнение буфера в службе WINS. Удаленный атакующий может выполнить произвольный код на уязвимой системе. Уязвимость существует из-за некорректной проверки длины буфера при обработке параметра Name в определенных пакетах. Удаленный атакующий может с помощью специально сформированного пакета вызвать переполнение буфера и выполнить произвольный код на уязвимой системе. URL производителя: www.microsoft.com. Решение: Установите обновления с сайта производителя.

Выполнение произвольного кода в Cyrus IMAP Server Программа: Cyrus IMAP Server 2.2.9 и более ранние версии. Опасность: Средняя. Описание: Обнаружена уязвимость в Cyrus IMAP Server. Удаленный атакующий может выполнить произвольный код на уязвимой системе. Уязвимость обнаружена в функции mysasl_canon_user(). Удаленный атакующий может вызвать переполнение буфера и выполнит произвольный код на системе с привилегиями IMAP-процесса. URL производителя: asg.web.cmu.edu/cyrus. Решение: Установите обновление: ftp://ftp.andrew.cmu.edu/ pub/cyrus-mail.

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

Выполнение произвольных FTP-команд в Microsoft Internet Explorer Программа: Microsoft Internet Explorer 6. Опасность: Низкая. Описание: Обнаружена уязвимость в Microsoft Internet Explorer при обработке FTP-ссылок. Удаленный атакующий может выполнить произвольную FTP-команду на уязвимой системе. Удаленный атакующий может создать специально сформированный FTP URL, который выполнит произвольную FTP-команду на определенном FTP-сервере. Команда вставляется в URL и разделяется символами «%0a». Пример: ftp://ftpuser:ftppass@server/directory%0asomecommand%0a

URL производителя: www.microsoft.com. Решение: Решения не существует на данный момент.

Повышение привилегий в ядре Linux Программа: Linux kernel версии до 2.4.23. Опасность: Низкая. Описание: Уязвимость обнаружена в ядре Linux на платформах AMD64 и Intel EM64T. Локальный атакующий может повысить свои привилегии на системе. Уязвимость существует при установке TSS-лимитов. Локальный атакующий может вызвать отказ в обслуживании или выполнить произвольный код на уязвимой системе. URL производителя: www.kernel.org. Решение: Установите обновление от производителя.

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

33


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

НАСТОЯЩИЙ UNIX В НАШИ ДНИ

АЛЕКСАНДР БАЙРАК

В этой статье я рассмотрю один из вариантов запуска настоящего UNIX на современных компьютерах. Я думаю, любой юниксоид хотя бы один раз читал историю возникновения UNIX, как он развивался и какие метаморфозы пережил, чтобы дойти до нас в виде множества своих «детей». Глядя на генеалогическое древо UNIX, диву даешься, какое большое количество ответвлений и версий системы было выпущено в прошлом. Некоторые уже давно умерли, иные просто в спячке, но большинство из них выросли и дожили до наших дней. Ну как тут не загореться желанием посмотреть на тот самый настоящий, легендарный AT&T UNIX, с которого все и началось? Конечно, в наши дни достаточно затруднительно найти PDP11 и родной дистрибутив. Так что единственной возможностью погрузиться во времена использования настоящего UNIX на PDP11 нам помогут эмуляторы. Точнее, один из них – simh (Simulator History). Начало данному проекту было положено в 1993 году. Главный разработчик проекта – Robert M Supnik. В настоящее время simh можно запустить почти на всех современных ОС, а именно: ! OpenVMS/VAX ! Tru64 ! OpenVMS/Alpha ! Solaris ! Windows 9x/2k/XP ! HP-UX ! MacOS X ! *BSD ! Linux ! OS/2

Если процесс компиляции прошел гладко, приступаем непосредственно к запуску:

Классический pdp 11/45 был выпущен в 1970 году. Из pdp-серии это был единственный 16-битный компьютер. Хотя были и 24- и 18-битные машины. При рекордно низкой цене (~ 10800$) pdp 11 получил широчайшее распространение. Всего было продано около 600000 (!) экземпляров. Некоторые из них работают и по сей день. Все свои эксперименты я проводил на P3-550 МГц/ 320 Мб RAM под управлением FreeBSD 5.3. Для начала нашего путешествия во времени нам нужен дистрибутив, который можно взять с http://simh.trailingedge.com/sources/simhv33-0.zip. Также понадобится дамп диска с установленным UNIX. Его мы берем с http://simh.trailing-edge.com/kits/uv7swve.zip. Распакуем и установим программу:

Более подробно обо всех опциях, использованных выше, можно прочитать в документации, поставляемой вместе с программой. Далее нам показывают объем доступной памяти, он равен целым 177 856 байтам! После чего мы попадаем в shell. В принципе можно начинать работу с настоящим UNIX 7-ой версии. По умолчанию мы попадаем в систему с правами root. В документации к эмулятору в качестве примера работы были приведены следующие действия:

# # # # # #

mkdir unixemul cd unixemul unzip ../simhv33-0.zip unzip ../uv7swve.zip mkdir BIN gmake

Симулятор помещает все свои исполняемые файлы в каталог BIN. Но так как по умолчанию он не существует, создаем его: # mkdir BIN # gmake

34

# BIN/pdp11

На экране появится приглашение программы. // Óêàçûâàåì, êàêîé òèï ïðîöåññîðà ìû áóäåì ýìóëèðîâàòü: sim> set cpu 18 // u18 ñîîòâåòñòâóåò ïðîöåññîðó, óñòàíîâëåííîìó // íà êëàññè÷åñêîé pdp 11/45. // Óêàçûâàåì, ÷òî áóäåì èñïîëüçîâàòü êîíñîëüíûé òåðìèíàë // DL11. Âûâîä èíôîðìàöèè áóäåò ïðîèçâîäèòüñÿ â ðåæèìå // 7 áèò íà ñèìâîë. sim> set tto 7b // Óêàçûâàåì, ÷òî ââîä áóäåò òàêæå èñêëþ÷èòåëüíî 7-áèòíûé. sim> set tti 7b // Ïðèñîåäèíÿåì äàìï äèñêà ñ UNIX ê rl.  êà÷åñòâå rl // âûñòóïàåò êîíòðîëëåð äèñêà RLV12/RL01. sim> attach rl unix_v7_rl.dsk // Óêàçûâàåì, îòêóäà ïðîèçâîäèòü çàãðóçêó: sim> boot rl

Начинается загрузка: @boot New Boot, known devices are hp ht rk rl rp tm vt

Указываем, что именно запускать: : rl(0,0)rl2unix

// Ñîçäàäèì êàòàëîã dmr # mkdir /usr/dmr // Ñäåëàåì âëàäåëüöåì êàòàëîãà dmr ïîëüçîâàòåëÿ dmr # chown dmr /usr/dmr // Èçìåíèì ãðóïïó âëàäåíèÿ êàòàëîãà íà òðåòüþ # chgrp 3 /usr/dmr // Ñîçäàäèì êàòàëîã äëÿ âðåìåííûõ ôàéëîâ # mkdir /tmp // Ïîñòàâèì äëÿ íåãî ïîëíûé äîñòóï äëÿ âñåõ # chmod 777 /tmp // Íàæèìàåì <Ctrl+D> # ^D

После чего на экране появляется приглашение к вводу логина. Restricted rights: Use, duplication, or disclosure is subject to restrictions stated in your contract with Western Electric Company, Inc. Thu Sep 22 05:51:05 EDT 1988

Идем дальше.


администрирование // Ââîäèì ëîãèí dmr: login: dmr // Ñ ïîìîùüþ ðåäàêòîðà ed íà÷èíàåì ðåäàêòèðîâàòü ôàéë hello.c: $ ed hello.c ?hello.c a main() { printf(«Hello World!\n»); } . w 40 q // Ñêîìïèëèðóåì íàïèñàííûé íàìè ôàéë: $ cc hello.c // Çàïóñòèì: $ a.out

Видим результат: Hello World!

Кстати, вы еще не догадались, кому принадлежит имя пользователя dmr? Человеку – живой легенде современности – Деннису Ритчи, отцу и основоположнику Юникса! Согласитесь, что очень неудобно при каждом запуске ОС каждый раз вводить все команды инициализации. Тут нам на помощь приходят команды save и restore. Для «сохранения» ввода команд, необходимых для запуска ОС, нам нужно набрать команду: sim> save filename

В качестве filename введите имя файла, в который вы хотите сохранить текущий образ эмулятора. Для «восстановления» состояния набираем: sim> restore filename

После чего будут актуальны ранее введенные и сохраненные настройки. Также следует отметить одну очень досадную недоработку по части удобства использования. В оболочке эмулятора нет возможности редактировать вводимые команды. Про возможность автодополнения команд я вообще молчу. Хотя должен заметить, можно использовать заранее определенные алиасы. Например, для команды attach синонимом будет команда at. Более подробно про алиасы можно прочитать в документации. Simh поддерживает работу через сеть. Например, у вас нет возможности работать с ОС, запущенной через эмулятор, находясь непосредственно перед монитором компьютера, на котором включен simh. Или вы хотите дать возможность своим знакомым или друзьям поэкспериментировать на запущенной через эмулятор ОС. Воспользуемся опцией, определяющей консоль: sim> set console telnet=12345

Назначаем доступ к консоли через порт 12345. На что эмулятор ответит: Listening on port 12345.

Проверить, действительно ли нас ожидает соединение

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

на указанном порту, мы можем с помощью команд netstat na или sockstat -4. Работать по сети мы сможем после ввода на локальной машине параметров, указывающих, откуда нам запускать ОС. В нашем случае это boot rl. После вывода которой мы видим на экране: Waiting for console Telnet connection.

После чего мы можем получить доступ к эмулятору через telnet. Пример сессии: [01mer@darkthrone]:~> telnet marduk 12345 Trying 192.168.1.22 Connected to marduk Escape charset is ‘^]’ Connected to PDP11 simulator @

Я не буду описывать здесь все свои эксперименты которые проводил в UNIX, чтобы не лишать читателя удовольствия самому заняться исследованием этой ОС. А море различных открытий и удивительных находок я вам обещаю. Для корректного завершения работы с UNIX надо два раза произвести синхронизацию диска с помощью команды sync. После чего нажать <Ctrl+E>, и вы снова попадете в оболочку эмулятора. Выход из которой осуществляется с помощью команд exit, quit, bye, на выбор. В конце хотел бы добавить, что рассмотренный эмулятор кроме PDP11 поддерживает еще достаточно большое количество различных компьютеров: ! Data General Nova, Eclipse ! Digital Equipment Corporation PDP-1, PDP-4, PDP-7, PDP-8, PDP-9, PDP-10, PDP-11, PDP-15, VAX ! GRI Corporation GRI-909 ! IBM 1401, 1620, 1130, System 3 ! Interdata (Perkin-Elmer) 16b and 32b systems ! Hewlett-Packard 2116, 2100, 21MX ! Honeywell H316/H516 ! MITS Altair 8800, with both 8080 and Z80 ! Royal-Mcbee LGP-30, LGP-21 ! Scientific Data Systems SDS 940 Соответственно, если мы найдем ОС для данных компьютеров и приложим немного смекалки и настойчивости, получим в собственное распоряжение целый полигон для изучения истории компьютеров и ОС. Особый интерес (по крайней мере для меня) представляет эмуляция VAX. Особенно при учете того, что на VAX можно запустить OpenBSD, NetBSD, и другие менее известные в настоящее время ОС. Но этому вопросу я намерен посвятить отдельную статью. Я был бы очень рад всем вашим отзывам c описанием экспериментов, поставленных с помощью этого эмулятора.

Ссылки: 1. http://simh.trailing-edge.com/software.html – небольшая коллекция программ и ОС, подходящих для использования под эмулятором simh. 2. http://simh.trailing-edge.com/photos.html – фотогалерея различных старых компьютеров. 3. http://www.cs.bell-labs.com/who/dmr – домашняя страничка Денниса Ритчи.

35


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

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

СЕРГЕЙ СУПРУНОВ Любой системный администратор, если он в меру ленив, рано или поздно берется за автоматизацию своей работы. Сначала вместо длинных команд со множеством ключей появляются псевдонимы (aliases), потом группы команд объединяются в пакетные файлы командной оболочки, затем на арену выходят сценарии на более функциональных языках типа Perl… И все для того, чтобы сократить количество «кликов» и по возможности переложить часть работы на пользователей, которые эти операции и должны бы делать «по идее», но «по факту» научить их находить нужный файл в дереве каталогов, упаковывать его и отправлять по назначению оказывается на порядок сложнее, чем делать это самому. Об использовании Python для выполнения тех или иных операций на UNIX-серверах написано достаточно много. В данной же статье я хочу показать применение этого языка для решения «бытовых» задач в среде Windows. В качестве примера (которым возможности Python никоим образом не ограничиваются) разработаем приложение, автоматизирующее отправку данных и получение обновлений по FTP, используя заранее настроенные пути и имена файлов. Попытаемся сделать наше приложение максимально универсальным, однако будем иметь в виду конкретную цель – нужно организовать обмен данными с удаленной кассой (ежедневно сбрасывать на сервер файлы реестров и время от времени получать с сервера обновленную базу

36

абонентов). Все задачи условно разделим на пользовательские (например, инициирование отправки) и администраторские (например, первичная настройка). Первые из них требуется разработать максимально удобно, предоставив простейший интерфейс и лишив пользователя возможности ошибаться. Задачи второй категории по традиции решим достаточно упрощенно – главное, чтобы все работало при минимуме телодвижений. Первым делом скачаем с http://python.org дистрибутив Python для Windows. Его инсталляция никаких вопросов вызвать не должна. На момент написания статьи у меня была установлена версия Python 2.3.4. Входящая в состав пакета среда разработки IDLE (рис. 1) предоставляет некоторые удобства, но для меня как-то уже устоялся стиль разработки, когда код вбивается в обычный текстовый файл, и затем исполняется командой типа: C:\myworks\python\test>python test.py

Можно, конечно, в командной строке набрать просто test.py – в процессе инсталляции в Windows расширение «.py» ассоциируется с интерпретатором python.exe, и подобная команда тоже выполнит код. Однако на стадии отладки это не совсем удобно – для потоков stdout и stderr в этом случае создается новое консольное окно, которое закрывается сразу же после завершения (в том числе и ава-


администрирование рийного) работы сценария, не позволяя ознакомиться с сообщениями об ошибке.

Ðèñóíîê 1

Знакомство с Python Подробно останавливаться на основах языка я не буду. Данный раздел имеет целью коротко пояснить, что и как, для тех, кто ранее с Python не сталкивался, но статью прочитать непременно хочет. И сразу, как говорится, – с места в карьер: (0) (1) (2) (3) (4) (5) (6) (7) (8) (9) (a) (b)

# -*- coding: cp866 -*#----------------------------- first.py import os def hello(message): print message print 'Âû íàõîäèòåñü â %s.' % os.getcwd() if __name__ == '__main__': hello('Hello from Python.') raw_input('Íàæìèòå Enter...') else: pass #----------------------------end of first.py

Результат работы этого сценария будет следующим: C:\myworks\python\test>python test.py Hello from Python. Вы находитесь в C:\myworks\python\test. Нажмите Enter...

(0) – первая строка указывает интерпретатору, в какой кодировке следует рассматривать приведенный ниже текст. Для ASCII-текста она не требуется, но поскольку мы используем кириллицу, то без нее интерпретатор будет каждый раз выдавать предупреждение «DeprecationWarining: NonASCII character…». (1, b) – комментарии, как и принято в UNIX, предваряются символом «#». Для многострочных комментариев часто используют обрамление текста с помощью утроенных кавычек: «’’’ multiline comment ’’’». Этот же прием можно использовать для временного исключения участков кода на стадии отладки. (2) – третья строка импортирует модуль, в данном случае «os», который является стандартным для Python и содержит функции для работы с конкретной операционной системой. В нашем примере из этого модуля мы используем функцию getcwd(), возвращающую текущий каталог. (3) – с этой строки начинается определение функции «hello». В скобках указывается список параметров, причем даже если параметров нет, скобки обязательно должны быть. Двоеточие начинает блок кода, содержащий тело функции. В отличие от таких языков, как C или Perl, в Python блок операторов (определения функций, циклы, ветвления) не обрамляется операторными скобками, а выделяется от-

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

ступом. Отступ может быть выполнен любым количеством символов «пробел», но все операторы блока должны иметь одинаковый отступ. Первая же строка, выполненная без отступа, рассматривается как окончание блока операторов. Здесь хочется сделать отступление и немного пофилософствовать о стиле программирования. Тот же Perl позволяет кодировать как угодно – хоть в одну строку. С одной стороны, каждый программист со временем вырабатывает тот стиль, который ему более удобен. При переходе на Perl с других языков можно перенести и устоявшийся стиль написания кода. Но с другой стороны тут есть и вероятность, что кто-то другой будет очень долго воспроизводить «неASCII»-звуки, пытаясь разобраться в исходниках программы, написанной как-нибудь экзотически. Язык Python в этом смысле более требователен к разработчику, унифицируя тем самым стиль кодирования и упрощая работу тем, кому придется работать с этим кодом в будущем. Однако продолжим… (4, 5) – оператор «print» выводит на экран значение строковой переменной или непосредственно строку, заключенную в кавычки или апострофы. Вставка в строку переменных выполняется в стиле оператора printf языка Си, за тем исключением, что список интегрируемых переменных задается после символа «%» как кортеж (то есть через запятую и в круглых скобках). Если переменная одна, как в нашем случае, скобки можно опустить. (6) – пустые строки, естественно, допускаются. (7, a) – оператор ветвления пояснять, думаю, не нужно. Как и обычно, задаются условие и блок операторов (выделяется отступом), которые будут выполнены, если условие истинно. В противном случае, если задан далее оператор «else», будет выполнен его блок операторов. Если команда в блоке одна, допускается указывать ее непосредственно после двоеточия в этой же строке (хотя это и противоречит официальному стилю программирования). Оператор «pass» ничего не делает, и строго говоря, строка «a» в нашем случае совершенно не нужна. Чуть подробнее следует остановиться на самом условии, указанном в строке (7): __name__ == ‘__main__’. Встроенная переменная __name__ возвращает имя программы, если вызывается как модуль из другого сценария (об этом – чуть ниже) либо строку «__main__», если файл запускается непосредственно. То есть код строк «8-9» будет выполнен только тогда, когда файл first.py запускается из командной строки. Зачем это сделано, будет объяснено далее. (8) – здесь мы просто вызываем описанную ранее функцию «hello», передав ей текстовую строку в качестве аргумента. (9) – функция raw_input считывает со стандартного потока ввода stdin строку, завершающуюся символом перевода строки. В данном случае этот оператор используется исключительно для задержки вывода, чтобы консольное окно не закрывалось сразу. Теперь рассмотрим еще одну концепцию Python – повторное использование кода. Конечно, это позволяет делать любой язык программирования, но в Python повторное использование положено в основу синтаксиса, и все получается очень легко и естественно.

37


администрирование Для примера напишем еще один сценарий: (0) import first (1) first.hello('Hi')

Запустив его, мы получим такой вывод: C:\myworks\python\test>python test.py Hi. Вы находитесь в C:\myworks\python\test.

То есть мы подключили нашу первую программу как модуль и получили возможность использовать определенные в ней функции. Код вне функций (в нашем случае это строки «0, 1, 6-b») выполняется в момент импорта. Именно для того, чтобы избежать какой-либо активности нашего первого сценария во время его импортирования, мы и ввели проверку имени __name__, чтобы определить, подключается наш сценарий к другому или запускается автономно. Говоря об импорте, следует указать еще на один синтаксис подключения: «from first import hello». Эта команда импортирует из first.py только функцию hello. Через запятую можно перечислить и несколько импортируемых функций. Команда «from first import * » импортирует в текущий сценарий все функции, найденные в first.py. Отличие этого синтаксиса от использованного в second.py заключается в том, что имена функций включаются в пространство имен импортирующего сценария, и поэтому подгруженные функции должны вызываться без указания модуля: (0) from first import hello (1) hello('Hi')

Ну и для полноты картины – несколько слов о библиотеке графических объектов Tkinter. Основанная на Tk/Tcl, она позволяет достаточно просто наделять сценарии графическим интерфейсом: (0) (1) (2) (3) (4) (5) (6) (7) (8) (a) (b)

# -*- coding: cp866 -*from Tkinter import * window = Tk() window.title(u'Ïðîñòîå ãðàôè÷åñêîå îêíî') label = Label(window, text = u' ↵ Ïðîñòàÿ òåêñòîâàÿ ìåòêà') label.config(fg = 'blue', ↵ font = ('Georgia', 14, 'italic')) label.pack() button = Button(window, text = u'Çàêðûòü', ↵ command = window.quit) button.pack(expand=YES, fill=X) window.mainloop()

В строке «1» импортируем все из модуля Tkinter. Далее последовательность действий такова: объявляем окно window верхнего уровня (3); задаем ему текст заголовка (4); описываем и упаковываем текстовую метку (5-7); аналогично поступаем с кнопкой (8-a) и, наконец, в строке «b» запускаем на выполнение цикл окна. Синтаксис описания различных элементов во многом одинаков – первым параметром задается родительский элемент (в данном случае окно верхнего уровня), к которому прикрепляется данный элемент. Далее перечисляются другие параметры: «text» для задания отображаемого текста, «command» определяет обработчик обратного вызова, который будет исполнен при выборе данного элемента (в данном примере при нажатии на кнопку главное окно будет закрыто). Параметры можно задавать и с помо-

38

щью метода «config» графического объекта, как показано в строке «6». Любой объект должен быть размещен одним из менеджеров размещения (в данном примере используем наиболее простой из них – pack). То есть для каждого объекта требуется вызвать метод pack(), который поместит его в конкретном месте окна. С помощью дополнительных параметров можно управлять упаковкой, например, указывать, к какой стороне окна требуется прикрепить элемент (параметр side), следует ли растягивать элемент при изменении размеров окна (expand), должен ли элемент заполнять все отведенное ему пространство в указанном направлении (fill). Самый лучший способ познакомиться с особенностями упаковки – на практике попробовать различные варианты. Метод mainloop() запускает цикл обработки событий графического окна. При его вызове окно с упакованными на нем элементами отображается на экране, и дальнейшее управление поведением сценария возможно только с помощью обработчиков обратных вызовов, которым передается управление при наступлении того или иного события. Метод quit, строго говоря, осуществляет выход из цикла mainloop и передачу управления на следующий оператор сценария. Обратите внимание на символ «u» перед текстовыми строками. Этот хитрый оператор заставляет Python преобразовывать следующую далее текстовую строку в кодировку Unicode. Базовая кодировка должна быть задана так, как показано в строке «0». В версиях Python до 2.3 этот синтаксис не действует, и там требуется явно задавать функцию преобразования unicode(). Еще одно замечание – внутри скобок допускается перенос строки и произвольный отступ перенесенной части, как это продемонстрировано в строках «8-9». В результате с помощью этих нескольких строк мы получим полнофункциональное окно, изображенное на рис. 2. Для первого знакомства, думаю, этого достаточно. Еще некоторые нюансы мы рассмотрим в дальнейшем.

Ðèñóíîê 2

Модуль для архивирования myzip Поскольку передавать по сети файлы в запакованном виде намного приятнее, особенно когда речь идет о коммутируемой линии, то заготовим несколько функций для работы с zip-файлами. Чтобы иметь возможность использовать эти функции и в других приложениях, поместим их в отдельный файл: # -*- coding: cp866 -*#-------------------------------------------------------# # myzip.py: ìîäóëü ðàáîòû ñ zip-àðõèâàìè # #-------------------------------------------------------# Ìîäóëü äëÿ ðàáîòû ñ zip-àðõèâàìè from zipfile import * # Èìïîðòèðóåòñÿ ôóíêöèÿ glob äëÿ îáõîäà êàòàëîãîâ from glob import glob # Åñëè íå íîëü – âûâîäèòü ñîîáùåíèÿ íà ýêðàí


администрирование VERBOSE = 1 # Î÷èñòêà àðõèâà îò èìåþùèõñÿ â íåì ôàéëîâ: # àðõèâ îòêðûâàåòñÿ íà çàïèñü è ñðàçó çàêðûâàåòñÿ def clearzip(zipname): if VERBOSE: print 'myzip: Î÷èñòêà àðõèâà %s.' % zipname zip = ZipFile(zipname, 'w', ZIP_DEFLATED) zip.close # Ôóíêöèÿ çàïèñè ôàéëà â àðõèâ: # óêàçàííûé ôàéë äîáàâëÿåòñÿ ê ñóùåñòâóþùèì def writezip(zipname, filename): if VERBOSE: print 'myzip: Óïàêîâûâàåòñÿ %s â %s.' ↵ % (filename, zipname) zip = ZipFile(zipname, 'a', ZIP_DEFLATED) zip.write(filename) zip.close # Çàïèñü â àðõèâ âñåõ ôàéëîâ èç êàòàëîãà, óäîâëåòâîðÿþùèõ # øàáëîíó def writepattzip(zipname, patterns): if VERBOSE: print 'myzip: Ñîçäàåòñÿ àðõèâ %s...' % zipname clearzip(zipname) for pattern in patterns: filelist = glob(pattern) for filename in filelist: writezip(zipname, filename) if VERBOSE: print 'myzip: Àðõèâ ñîçäàí.' # Èçâëå÷åíèå ôàéëà èç àðõèâà def readzip(zipname, filename): if VERBOSE: print 'myzip: Èçâëåêàåòñÿ %s èç %s.' ↵ % (filename, zipname) zip = ZipFile(zipname, 'r', ZIP_DEFLATED) open(filename, 'wb').write(zip.read(filename)) zip.close # Èçâëå÷åíèå âñåõ ôàéëîâ èç àðõèâà def readallzip(zipname): if VERBOSE: print 'myzip: ×èòàåòñÿ àðõèâ %s...' % zipname zip = ZipFile(zipname, 'r', ZIP_DEFLATED) for filename in zip.namelist(): readzip(zipname, filename) zip.close if VERBOSE: print 'myzip: Àðõèâ ïðî÷òåí.' # Åñëè çàïóñêàåòñÿ èç êîìàíäíîé ñòðîêè, òî ìîæíî # ÷òî-òî ñäåëàòü if __name__ == '__main__': print 'Òîëüêî êàê ìîäóëü.'

В основе данного сценария лежит стандартный модуль zipfile. Он предоставляет довольно развитые средства для работы с архивами, но его непосредственное использование потребует каждый раз писать один и тот же код обвязки. Поэтому мы и создаем собственный модуль, в котором опишем нужные нам функции на более высоком уровне. Класс ZipFile модуля zipfile позволяет работать с архивом, почти как с обычным файлом – читать из него, записывать и т. д. Фигурирующий здесь параметр ZIP_DEFLATED определяет метод компрессии. В дальнейшем нам понадобятся отсюда: функция readallzip, которая будет извлекать в текущую папку все файлы из скачанного архива, и writepattzip, которая будет упаковывать в архив все файлы из текущего каталога. Функции соответствуют шаблону. Из интересного отметим здесь, что шаблоны передаются в виде кортежа, то есть этот параметр должен выглядеть примерно так: «(‘*.db’, ‘*.px’)». Также обратите внимание на синтаксис цикла «for»: он перебирает все значения из списка, заданного после ключевого слова «in».

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

Модуль работы с FTP myftp Аналогично в отдельный файл вынесем и функции работы по протоколу FTP. Здесь нам требуется две функции – отправка одного файла по заданному пути и чтение одного файла. Возможность загрузки или отправки сразу нескольких файлов реализовывать не будем: поскольку в основе нашего приложения будет лежать работа с архивами, то целесообразно упаковывать все передаваемое или принимаемое в один файл. Код модуля представлен ниже: # -*- coding: cp866 -*#-------------------------------------------------------# # myftp.py: ìîäóëü ðàáîòû ñ FTP # #-------------------------------------------------------# Èìïîðò íóæíûõ ôóíêöèé import os from ftplib import FTP from myzip import * VERBOSE = 1 # Ñêà÷èâàíèå ôàéëà ïî FTP: # ïåðåäàþòñÿ ñëåäóþùèå ïàðàìåòðû: # fromdir – ïàïêà-èñòî÷íèê íà FTP-ñåðâåðå # file – èìÿ ñêà÷èâàåìîãî ôàéëà # (fromsite, ftpuser, ftppassword) – FTP-ñåðâåð # è ëîãèí/ïàðîëü äëÿ âõîäà # todir - ëîêàëüíàÿ ïàïêà äëÿ ñîõðàíåíèÿ ñêà÷àííîãî ôàéëà # def getftp(fromdir, file, (fromsite, ftpuser, ↵ ftppassword), todir): olddir = os.getcwd() # çàïîìèíàåòñÿ òåêóùèé êàòàëîã os.chdir(todir) # ïåðåõîä â ïàïêó íàçíà÷åíèÿ if VERBOSE: print 'myftp: Óñòàíàâëèâàåòñÿ ñîåäèíåíèå ñ ↵ %s...' % fromsite try: localfile = open(file, 'wb') connection = FTP(fromsite) connection.login(ftpuser, ftppassword) connection.cwd(fromdir) except: print 'myftp: ÎØÈÁÊÀ ÑÎÅÄÈÍÅÍÈß Ñ %s!' % fromsite return(-1) if VERBOSE: print 'myftp: Ñîåäèíåíèå ñ %s óñòàíîâëåíî.' ↵ % fromsite if VERBOSE: print 'myftp: Âûïîëíÿåòñÿ çàãðóçêà %s...' % file try: connection.retrbinary('RETR ' + ↵ file, localfile.write, 1024) connection.quit() localfile.close() except: print 'myftp: ÎØÈÁÊÀ ÏÎËÓ×ÅÍÈß ÔÀÉËÀ %s' % file return(-2) if VERBOSE: print 'myftp: Çàãðóçêà ôàéëà %s çàâåðøåíà.' % file # èñïîëüçóåì try, ïîñêîëüêó ñêà÷àííûé ôàéë ìîæåò # îêàçàòüñÿ íå zip-àðõèâîì. Õîòÿ ýòî ìîæíî áûëî # áû ïðîâåðèòü è ÿâíî: try: readallzip(file) except: print 'myftp: %s íå ÿâëÿåòñÿ àðõèâîì, ïîìåùåí ↵ êàê åñòü.' % file os.chdir(olddir) # # # # # # # #

# âîçâðàùàåìñÿ â ïðåæíèé êàòàëîã

Çàãðóçêà ôàéëà ïî FTP íà ñåðâåð: ïåðåäàþòñÿ ñëåäóþùèå ïàðàìåòðû: fromdir – ëîêàëüíàÿ ïàïêà-èñòî÷íèê file – èìÿ îòïðàâëÿåìîãî zip-ôàéëà pattern – ñïèñîê øàáëîíîâ äëÿ îòïðàâêè (fromsite, ftpuser, ftppassword) – FTP-ñåðâåð è ëîãèí/ïàðîëü äëÿ âõîäà todir – ïàïêà íà FTP-ñåðâåðå äëÿ çàãðóçêè ôàéëà

39


администрирование # def putftp(fromdir, zipfile, pattern, (tosite, ↵ ftpuser, ftppassword), todir): olddir = os.getcwd() os.chdir(fromdir) if VERBOSE: print 'myftp: Ïîäãîòîâêà ôàéëîâ ê îòïðàâêå...' writepattzip(zipfile, pattern) if VERBOSE: print 'myftp: Ôàéëû óïàêîâàíû â %s.' % zipfile print 'myftp: Óñòàíàâëèâàåòñÿ ñîåäèíåíèå ↵ ñ %s...' % tosite try: localfile = open(zipfile, 'rb') connection = FTP(tosite) connection.login(ftpuser, ftppassword) connection.cwd(todir) except: print 'myftp: ÎØÈÁÊÀ ÑÎÅÄÈÍÅÍÈß Ñ %s' % tosite return(-2) if VERBOSE: print 'myftp: Ñîåäèíåíèå ñ %s óñòàíîâëåíî' % tosite print 'myftp: Âûïîëíÿåòñÿ îòïðàâêà ôàéëà ↵ %s...' % zipfile try: connection.storbinary('STOR ' + zipfile, ↵ localfile, 1024) connection.quit() localfile.close() except: print 'myftp: ÎØÈÁÊÀ ÎÒÏÐÀÂÊÈ ÔÀÉËÀ %s!' % zipfile return(-2) if VERBOSE: print 'myftp: Ôàéë %s îòïðàâëåí.' % zipfile os.chdir(olddir)

Здесь следует обратить внимание на то, что файлы следует открывать в бинарном режиме (используем параметры «rb» и «wb»), чтобы они не пострадали в результате интерпретации Python символов конца строки. Всю черную работу в этом сценарии выполняет стандартный модуль ftplib, а конкретно – его класс FTP, который отвечает за методы установления соединения, обеспечивает работу протокола FTP и т. д. Потенциально опасные операции, которые могут вызвать ошибку (например, FTP-сервер может быть недоступен), заключены в оператор «try – except». Он в свою очередь перехватывает ошибку и не позволяет нашему приложению «обрушиться» со страшными для пользователя ругательствами.

Файл конфигурации config.py Конечно, нужные нам переменные, такие как URL FTP-сервера, имя и пароль пользователя, и прочее, можно задать непосредственно в главном модуле нашего приложения, но несколько удобнее представляется вынос этих описаний в отдельный файл. Чтобы не связываться с разбором конфигурационного файла и не изобретать ему какой-то формат, будем использовать в его качестве обычный сценарий Python, в котором определяются соответствующие переменные. Затем, будучи импортирован в главный сценарий, он предоставит свои переменные другим функциям. В конце концов это уже относится к «административным» функциям, а мы условились не тратить много усилий на красоту в данном случае. # -*- coding: cp866 -*#-----------------------------------------------------# ïðåäâû÷èñëÿåìûé êîä: import os

40

from glob import glob olddir = os.getcwd() root = 'data/' os.chdir(root) list = glob('Pay_*') list.sort() srcdir = root + list[-1] # ïîñëåäíèé ýëåìåíò ñïèñêà os.chdir(olddir) # print 'config: Òåêóùèé êàòàëîã îòïðàâêè – %s' % srcdir #----------------------------------------------------# Ñïèñîê FTP-ñåðâåðîâ. Ôîðìàò çàïèñè: # (FTP-ñåðâåð, ëîãèí, ïàðîëü) ftpservers = [ ('ftp.my.server.ru', 'user', 'password'), ('ftp.freebsd.org', 'ftp', 'my@mail.ru'), ] #----------------------------------------------------# Ñïèñîê îïåðàöèé. ôîðìàò çàïèñè: # (íîìåð, òèï îïåðàöèè, íàçâàíèå îïåðàöèè, íîìåð FTP-ñåðâåðà, # ïàïêà-èñòî÷íèê, èìÿ àðõèâà, øàáëîí, ïàïêà íàçíà÷åíèÿ) operations = [ (0, 'get', u'Îáíîâèòü äàííûå', 0, 'downdata', ↵ 'basa.zip', ('*',), 'data'), (1, 'put', u'Îòïðàâèòü ðååñòðû', 0, srcdir, ↵ 'reestr.zip', ('*.db', '*.px',), 'updata'), (2, 'get', u'Îáíîâèòü ïðîãðàììó', 0, 'ftpman', ↵ 'ftpman.zip', ('*',), 'bin'), (3, 'get', u'Ïîëó÷èòü README.TXT', 1, ↵ 'pub/FreeBSD', 'README.TXT', ('*',), '.'), ]

Наиболее важными здесь являются список FTP-серверов и список операций. Код в начале сценария, помеченный как «предвычисляемый», нужен для динамического определения значения некоторых переменных, подставляемых в списки. В нашем примере в нем вычисляется значение переменной srcdir, которая задает папку-источник данных, используемую в операции 1 («Отправить реестры»). В качестве источника должна использоваться папка с именем вида Pay_NN, где NN – двузначное число, с наибольшим значением NN. Для того чтобы определить эту папку на данный момент, и нужен этот «предвычисляемый» код. Список FTP-серверов задается как список кортежей, каждый из которых содержит адрес сервера, имя и пароль пользователя для доступа на этот сервер. В дальнейшем обращение к данным по тому или иному серверу выполняется по порядковому номеру записи (начиная с нуля). Например, имя пользователя, которое должно использоваться для доступа на ftp.freebsd.org, можно будет получить так: «ftpservers[1][1]». Аналогично задается список операций. Назначения полей приведены в комментарии. Номер операции здесь указываем явно – так будет удобнее в дальнейшем. Второе поле задает саму операцию – получение данных (get) или отправка (put). Конечно, формат нашего конфигурационного файла способен напугать кого угодно, однако пользователям не придется с ним работать, а администратор как-нибудь разберется.

Главный сценарий manager.py Теперь попытаемся объединить все это в законченное приложение: # -*- coding: cp866 -*from Tkinter import * from myftp import getftp, putftp


администрирование VERBOSE = 1 if VERBOSE: print '================> manager.py çàïóùåí.' # Ñëóæåáíî-äåêîðàòèâíàÿ ôóíêöèÿ. Íóæíà, ÷òîáû ìåíÿòü òåêñò # ìåòêè â çàâèñèìîñòè îò ñîñòîÿíèÿ def chStat(messvar, color, btn, btnrelief): # èçìåíÿåì ãðàíèöó êíîïêè òàê, ÷òîáû â ìîìåíò # âûïîëíåíèÿ îïåðàöèè îíà âûãëÿäåëà âäàâëåííîé – # èñêëþ÷èòåëüíî «äåêîðàòèâíûé» ýôôåêò btn.config(relief = btnrelief) # ìåíÿåì òåêñò ìåòêè status.config(text = messvar) # ìåíÿåì öâåò ìåòêè status.config(fg = color) # ïåðåðèñîâûâàåì ìåòêó status.update() # Ôóíêöèÿ ïîëó÷åíèÿ äàííûõ. Íàçíà÷àåòñÿ êàê îáðàáîò÷èê # êíîïêàì îïåðàöèé òèïà 'get' def get(nr): if VERBOSE: print '================> âûïîëíÿåòñÿ ↵ çàãðóçêà...' # âûáèðàåì íóæíûé êîðòåæ op = config.operations[nr] # âû÷èñëÿåì èìÿ êíîïêè ïî íîìåðó exec 'obj = btn%d' % op[0] # âûáèðàåì äàííûå ïî FTP-ñåðâåðó ftpsite = config.ftpservers[op[3]] msg = u'Ïîäîæäèòå: âûïîëíÿåòñÿ çàãðóçêà...' chStat(msg, '#AA0000', obj, 'sunken') err = getftp(op[4], op[5], ftpsite, op[7]) if err: msg = u'ÎØÈÁÊÀ ÏÎËÓ×ÅÍÈß ÄÀÍÍÛÕ!.' chStat(msg, '#FF0000', obj, 'raised') else: msg = u'Äàííûå ïîëó÷åíû.' chStat(msg, '#007700', obj, 'raised') if VERBOSE: print '================> çàãðóçêà çàâåðøåíà.' # Ôóíêöèÿ îòïðàâêè äàííûõ. Íàçíà÷àåòñÿ êàê îáðàáîò÷èê # êíîïêàì îïåðàöèé òèïà 'put' def put(nr): if VERBOSE: print '================> âûïîëíÿåòñÿ ↵ îòïðàâêà...' op = config.operations[nr] exec 'obj = btn%d' % op[0] ftpsite = config.ftpservers[op[3]] msg = u'Ïîäîæäèòå: âûïîëíÿåòñÿ îòïðàâêà...' chStat(msg, '#AA0000', obj, 'sunken') err = putftp(op[4], op[5], op[6], ftpsite, op[7]) if err: msg = u'ÎØÈÁÊÀ ÎÒÏÐÀÂÊÈ ÄÀÍÍÛÕ!' chStat(msg, '#FF0000', obj, 'raised') else: msg = u'Äàííûå îòïðàâëåíû.' chStat(msg, '#007700', obj, 'raised') if VERBOSE: print '================> îòïðàâêà âûïîëíåíà.'

# Èìåííî â ýòîò ìîìåíò áóäóò âûïîëíåíû «ïðåäâû÷èñëåíèÿ» import config # Ïåðåáèðàÿ âñå êîðòåæè â ñïèñêå îïåðàöèé, äèíàìè÷åñêè # ñîçäàåì äëÿ êàæäîé èç íèõ êíîïêó for op in config.operations: cmd = "btn%d = Button(comf, text = '%s', " % (op[0], op[2]) cmd = cmd + "command = (lambda: %s(%d))) " % (op[1], op[0]) exec cmd exec 'btn%d.pack(fill=X)' % op[0] # Êíîïêà «Çàêðûòü» è åùå íåìíîãî äåêîðàöèé closeBtn = Button(comf, text = u'Çàêðûòü', command = tk.quit) closeBtn.pack(side=RIGHT) copyLbl = Label(comf, text = u'Coded by Amsand, 2004') copyLbl.config(font = ('Georgia', 8, 'italic')) copyLbl.pack(side=LEFT) # Âûâîäèì íà ýêðàí ïîëó÷åííîå îêíî è ïåðåäàåì åìó óïðàâëåíèå mainloop() # Êîãäà îêíî áóäåò çàêðûòî, óïðàâëåíèå âíîâü âåðíåòñÿ # ñöåíàðèþ if VERBOSE: print '================> manager.py îñòàíîâëåí.'

В результате исполнения этого сценария на экране отобразится графическое окно наподобие изображенного на рис. 3. Одновременно с этим будет открыто консольное окно, куда будет направляться вывод операторов print (рис. 4). Отдавая сценарий на выполнение интерпретатору pythonw, а не python, можно избежать появления консольного окна. Но в данном случае оно нам нужно для получения дополнительной информации.

Ðèñóíîê 3

# Ñîçäàåì ãëàâíîå îêíî tk = Tk() tk.title(u'Öåíòð óïðàâëåíèÿ îáìåíîì') # Íåêîòîðûå äåêîðàòèâíûå ýëåìåíòû... topf = Frame(tk) topf.pack(expand=NO, fill=X) lbl = Label(topf, text = u' – Àâòîìàòèçàöèÿ îáìåíà ↵ äàííûìè ïî FTP ') lbl.config(font = ('Georgia', 9, 'italic bold')) lbl.config(bg = '#AAAAFF') lbl.pack(side=TOP, expand=YES, fill=X) # Ñîçäàåì ñòàòóñ-ìåòêó, â êîòîðóþ áóäåò âûâîäèòüñÿ # èíôîðìàöèÿ î ñîñòîÿíèè midf = Frame(tk) midf.pack(expand=YES, fill=BOTH) status = Label(midf, text = u'Ïîäðîáíûé âûâîä ñì. ↵ â îêíå êîíñîëè') status.config(bg='#FFFFFF', bd=2, relief=SUNKEN, height=3) status.pack(expand=YES, fill=BOTH) # Ôðåéì äëÿ ðàçìåùåíèÿ êíîïîê îïåðàöèé. Íóæåí äëÿ óïðàâëåíèÿ # ðàñòÿãèâàíèåì ïðè èçìåíåíèè ðàçìåðîâ îêíà – âåñü ôðåéì # áóäåò «ïðèâÿçàí» ê íèæíåé êðîìêå îêíà comf = Frame(tk) comf.pack(fill=X) # Èìïîðòèðóåì êîíôèãóðàöèîííûé ôàéë.

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

Ðèñóíîê 4

Таким образом, потратив немного усилий, нам удалось существенно упростить для пользователя работу с FTP. Описав в файле config.py все операции, которые должны будут выполняться пользователями, мы получим удобное графическое окно. Каждая операция будет запускаться по одному щелчку мышки. В случае необходимости можно внести коррективы в список операций, на это уйдут считанные минуты. Безусловно, полученное приложение не является идеальным. Зато его можно назвать оптимальным в плане соотношения затрат на разработку, полученной функциональности и удобства использования. К тому же исходный код в несколько строчек всегда рядом, и внести любое изменение не составит особого труда.

41


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

ЗАЩИТА СЕТЕВЫХ СЕРВИСОВ С ПОМОЩЬЮ STUNNEL

АНДРЕЙ БЕШКОВ Инциденты с безопасностью были и, видимо, будут всегда. Не последнюю роль в этом играет изначально ошибочный дизайн многих сетевых протоколов. Большинство из них передают и принимают данные либо в открытом виде, либо с минимальным шифрованием. Криптография не стоит на месте, и постепенно некоторые протоколы обзаводятся функциями, реализующими стойкое шифрование, но, к сожалению, процесс этот идет не слишком быстро. Для подавляющего большинства разработчиков программного обеспечения вопросы безопасности создаваемого продукта стоят далеко не на первом месте. Обычно все делается по принципу «лишь бы приложение хоть как-то заработало», а потом мы уже исправим все недочеты. Обычно это «потом» растягивается на годы. И чаще всего для внедрения в уже работающий программный комплекс механизмов безопасности необходимо достаточно сильно менять не только код, но и многие идеи, лежащие в основе всего дизайна. Не каждый производитель программного обеспечения с радостью пойдет на дополнительные трудозатраты. Благодаря инициативе компании Netscape стандартом де факто для задач шифрования веб-коммуникаций стал SSL (Security Socket Layer). Первоначально он применялся для защиты данных, передаваемых с помощью HTTP. Годы активного использования в сфере веб-коммерции доказали стабильность и надежность этого решения. Таким образом, возникла защищенная версия протокола HTTP, в дальнейшем получившая название HTTPS. Вслед за этим появились протоколы IMAPS, POP3S, SMTPS, NNTPS, LDAPS. Они призваны со временем заменить своих небезопасных предков. По идее, использование SSL вместо стандартного API для работы с сетевыми сокетами должно быть довольно простым и прозрачным для приложения. На первый взгляд, нужно всего лишь заменить в исходном коде защищаемого приложения вызовы стандартных функций на их SSL-аналоги и произвести перекомпиляцию. Но не тут то было, при работе в многопоточной и многопользовательской среде приходится добавлять в свое приложение довольно много кода поддержки SSL. На данный момент в сети существует несколько библиотек, реализующих функции SSL. Самой популярной из них является OpenSSL, распространяемая по открытой лицензии.

42

Как я говорил ранее, переделка обычной программы в SSL-версию – уже нетривиальный процесс, но на этом трудности не заканчиваются. К сожалению, настройка и установка на сервере программного обеспечения, реализующего защищенные версии протоколов, упомянутых выше, часто тоже довольно непроста. Кроме этого, иногда встречаются ситуации, когда производитель того или иного серверного или клиентского обеспечения, работающего с небезопасными протоколами, канул в Лету, не успев создать защищенных версий своих программ и оборудования. За право пользования этими разработками когда-то были заплачены лицензионные отчисления и, соответственно, отказаться от работы с ними экономически невыгодно. Иногда это сделать вообще невозможно по причине того, что ни одно из решений, предлагаемых сторонними поставщиками, не реализует нужные функции. Но чаще всего складывается ситуация, когда безопасные приложения от нового поставщика не удается встроить в устаревшее оборудование и программные среды, до сих пор используемые во многих производственных процессах и служащие нам верой и правдой. Таким образом, мы незаметно подошли к предмету нашей сегодняшней беседы. Говорить мы будем о программе Stunnel, которая позволяет защитить небезопасные сервисы. Механика действия довольно проста. Stunnel позволяет шифровать любое TCP-соединение с помощью SSL. При этом ни отправитель, ни получатель не подозревают о том, что трафик в процессе передачи по сети шифруется с помощью внешней программы. Программа работает на следующих операционных системах: ! FreeBSD ! HP NonStop™ Kernel ! NetBSD ! HP-UX ! OpenBSD ! Plan 9 ! GNU/Linux ! QNX ! AmigaOS ! SCO OpenServer ! BeOS ! SGI IRIX ! IBM AIX ! Solaris ! Mac OS X ! Tru64, он же Digital Unix, он же DEC OSF/1 ! OpenVMS ! Windows 95/98/ME/NT/2000/XP Итак, рассмотрим пример превращения небезопасных


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

Таким образом, картина, показываемая командой: # netstat -na | grep LISTEN

выглядит следующим образом: tcp4 tcp4 tcp4

0 0 0

0 *.25 0 *.143 0 *.110

*.* *.* *.*

LISTEN LISTEN LISTEN

Демоны ждут входящих соединений на портах 25, 110, 143. Что означают эти номера, можно узнать, пролистав файл /etc/services. Кстати, стоит убедиться, что в этом же файле есть записи, описывающие наши будущие защищенные сервисы: imaps imaps pop3s pop3s smtps smtps

993/tcp # imap4 protocol over TLS/SSL 993/udp 95/tcp spop3 # pop3 protocol over TLS/SSL 995/udp spop3 465/tcp # smtp protocol over TLS/SSL (was ssmtp) 465/udp

Объяснить, как все происходит, довольно просто. На схеме изображена типичная картина сетевого взаимодействия клиента и почтового сервера (см. рис. 1). При отправке сообщений почтовый клиент, умеющий работать с SSL, шифрует пакеты и передает их демону stunnel. Тот в свою очередь расшифровывает их и отдает демонам imap, pop3, smtp. А почтовые демоны в ответ на запросы отдают данные в открытом виде stunnel, который шифрует их и передает клиенту. При этом ни клиент, ни демоны не догадываются о том, что общаются друг с другом через посредника. Итак, приступаем к установке stunnel на сервер. Предварительно в систему должен быть проинсталлирован OpenSSL, так как для правильного функционирования stunnel требуются криптоалгоритмы, реализуемые именно этой библиотекой. Для FreeBSD проводить инсталляцию удобнее всего из портов. # cd /usr/ports/security/stunnel # make all install

По окончании сборки будет автоматически создан пользователь stunnel, входящий в одноименную группу. Затем произойдет установка, и нам будет доступен stunnel версии 4.04. Сразу же после этого система начнет создавать секретный ключ и сертификат. Вы можете воспользоваться этим способом и начать отвечать на задаваемые вопросы или просто нажимать Enter и впоследствии самостоятельно создать нужные файлы. Я предпочитаю второй способ. Создаем директорию, где у нас будут храниться сертификаты и ключи. # mkdir /usr/local/etc/stunnel/certs # cd /usr/local/etc/stunnel/certs

Самостоятельно создаем ключи и сертификаты со сроком действия 1 год. В связи с тем, что stunnel не умеет работать с ключами, защищенными паролями, используем опцию -nodes.

Ðèñóíîê 1

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

43


безопасность # openssl req -new -x509 -days 365 -nodes ↵ -out mailserver.cert -keyout mailserver.key Generating a 1024 bit RSA private key ................++++++ ......................++++++ writing new private key to 'mailserver.key' ----You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----Country Name (2 letter code) [AU]:RU State or Province Name (full name) [Some-State]:Rostov region Locality Name (eg, city) []:Rostov-on-Don Organization Name (eg, company) [Internet Widgits Pty Ltd]:Tigrisha home Organizational Unit Name (eg, section) []:Test Lab Common Name (eg, YOUR name) []:freebsd410.unreal.net Email Address []:tigrisha@freebsd410.unreal.net

Обратите внимание, что для заполнения поля Common Name или CN было использовано DNS-имя сервера. Это обязательно нужно делать, иначе почтовый клиент будет постоянно возмущаться несовпадением фактического имени сервера и того, что записано в недрах сертификата. Также необходимо убедиться, что на клиентском компьютере правильно работает разрешение имени freebsd410. unreal.net. Покончив с предыдущим пунктом, устанавливаем правильные права доступа к файлам. # chmod 600 ./mailserver.cert ./mailserver.key

Создаем директорию, куда демон перейдет в chroot: # mkdir /var/tmp/stunnel # chown stunnel:stunnel /var/tmp/stunnel # chmod 700 /var/tmp/stunnel

При запуске без параметров stunnel будет использовать файл конфигурации /usr/local/etc/stunnel/stunnel.conf. Записываем в него следующие строки: # Êëþ÷è è ñåðòèôèêàòû cert = /usr/local/etc/stunnel/certs/mailserver.cert key = /usr/local/etc/stunnel/certs/mailserver.key # Äèðåêòîðèÿ, âíóòðè êîòîðîé áóäåò ðàáîòàòü äåìîí chroot = /var/tmp/stunnel # Ôàéë pid. pid = /stunnel.pid # Èìÿ ïîëüçîâàòåëÿ è ãðóïïà, ñ ÷üèìè ïðàâàìè áóäåò # ðàáîòàòü äåìîí setuid = stunnel setgid = stunnel # Óðîâåíü ïîäðîáíîñòè îòëàäî÷íûõ ñîîáùåíèé debug = 7 # Èìÿ ôàéëà ïðîòîêîëèðîâàíèÿ output = /var/log/stunnel.log # Îïèñàíèå íàøèõ ñåðâèñîâ [pop3s] accept = 10.10.21.134:995 connect = 110 [imaps] accept connect [ssmtp] accept connect

44

= 993 = 143 = 465 = 127.0.0.1:25

В описании сервисов стоит обратить особое внимание на ключевые слова accept и connect. Первое описывает адрес и порт, через который к нам и от нас будут идти зашифрованные данные, а второе, соответственно, адрес и порт для обмена расшифрованными данными с демонами. Описание обоих переменных может быть в нескольких форматах. Адрес:порт – данные принимаются и отправляются только на интерфейсе и порте с указанным адресом. В случае если адрес не указан, по необходимости будут задействованы соответствующие порты на всех доступных интерфейсах. В моем конфигурационном файле для наглядности продемонстрированы оба вида настроек. Запускаем stunnel и смотрим, что демон пишет в /var/ log/stunnel.log. Должны увидеть что-то подобное: 2004.12.04 19:09:15 LOG5[2405:134598656]: stunnel 4.04 on i386-portbld-freebsd4.10 PTHREAD+LIBWRAP with OpenSSL 0.9.7d 17 Mar 2004 2004.12.04 19:09:15 LOG7[2405:134598656]: Snagged 64 random bytes from /root/.rnd 2004.12.04 19:09:15 LOG7[2405:134598656]: Wrote 1024 new random bytes to /root/.rnd 2004.12.04 19:09:15 LOG7[2405:134598656]: RAND_status claims sufficient entropy for the PRNG 2004.12.04 19:09:15 LOG6[2405:134598656]: PRNG seeded successfully 2004.12.04 19:09:15 LOG7[2405:134598656]: Certificate: /usr/local/etc/stunnel/certs/mailserver.cert 2004.12.04 19:09:15 LOG7[2405:134598656]: Key file: /usr/local/etc/stunnel/certs/mailserver.key 2004.12.04 19:09:15 LOG5[2405:134598656]: FD_SETSIZE=1024, file ulimit=957 -> 467 clients allowed 2004.12.04 19:09:15 LOG7[2405:134598656]: FD 6 in non-blocking mode 2004.12.04 19:09:15 LOG7[2405:134598656]: SO_REUSEADDR option set on accept socket 2004.12.04 19:09:15 LOG7[2405:134598656]: pop3s bound to 10.10.21.134:995 2004.12.04 19:09:15 LOG7[2405:134598656]: FD 7 in non-blocking mode 2004.12.04 19:09:15 LOG7[2405:134598656]: SO_REUSEADDR option set on accept socket 2004.12.04 19:09:15 LOG7[2405:134598656]: imaps bound to 0.0.0.0:993 2004.12.04 19:09:15 LOG7[2405:134598656]: FD 8 in non-blocking mode 2004.12.04 19:09:15 LOG7[2405:134598656]: SO_REUSEADDR option set on accept socket 2004.12.04 19:09:15 LOG7[2405:134598656]: ssmtp bound to 0.0.0.0:465 2004.12.04 19:09:15 LOG7[2405:134598656]: FD 9 in non-blocking mode 2004.12.04 19:09:15 LOG7[2405:134598656]: FD 10 in non-blocking mode 2004.12.04 19:09:15 LOG7[2406:134598656]: Created pid file /stunnel.pid

Теперь нужно снова посмотреть, что нам скажет команда: netstat -na | grep LISTEN tcp4 tcp4 tcp4 tcp4 tcp4 tcp4

0 0 0 0 0 0

0 0 0 0 0 0

*.465 *.993 *.995 *.25 *.143 *.110

*.* *.* *.* *.* *.* *.*

LISTEN LISTEN LISTEN LISTEN LISTEN LISTEN

Как видите, список портов, ожидающих входящие соединения, существенно увеличился. Самое время настроить почтовый клиент. В качестве подопытного кролика будет использоваться Microsoft Outlook Express 6. Первым делом будут не самолеты, о которых подумали поклонники советской эстрады, а копирование сертификата с почтового сервера и импортирование его в почтовый клиент. С первым заданием, я думаю, вы и сами справитесь. Подойдет любой способ, лишь бы файл mailserver.cert оказался на Windows-машине. В Outlook Express задействуем меню «Сервис → Параметры», затем выбираем вкладку


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

Ðèñóíîê 2

Ðèñóíîê 6

Ðèñóíîê 3

Ðèñóíîê 7

Ðèñóíîê 4

После этого в списке доверенных центров сертификации должно появиться имя нашего сервера.

Ðèñóíîê 8

Ðèñóíîê 5

На этом возню с сертификатом можно считать законченной. Переходим к настройке учетной записи. Тут тоже нет ничего сложного: нужно всего лишь сделать все так, как изображено на следующих снимках.

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

Ðèñóíîê 9

45


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

Ðèñóíîê 10

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

Для того чтобы забирать письма с сервера, в данном примере использовался POP3S, но смею вас уверить, что IMAPS будет также надежно выполнять эту задачу. Вдоволь наигравшись с Outlook Express, я принялся тестировать все

46

почтовые клиенты, что были под рукой. Поэтому могу смело заявить: как и ожидалось, Mozilla Thunderbird 0.6 и Ximian Evolution 2.0.2 работают с SSL вполне стабильно и быстро. Единственное нарекание стоит адресовать Kmail 1.7.1, который при использовании защищенных протоколов стал шевелиться в несколько раз медленнее, чем обычно. В частности, на получение тестового письма из 500 байт у него в среднем уходило примерно 45 секунд. The Bat, любимый многими на постсоветских просторах, тоже отлично работает в наших условиях. Тесты, описанные ниже, проводились на версии 3.0.1.33. Впрочем, думаю, что с большинством версий The Bat это тоже будет работать. Итак, для того чтобы включить ночного вампира в нашу связку, нужно установить все так же, как изображено на следующем снимке. Удивляться тому, что вместо SSL приходится выбирать TLS, не стоит. Главное, что такой подход работает.

Ðèñóíîê 11

При первой попытке соединения с сервером получаем следующее предупреждение. За исключением опечаток все в нем выглядит неплохо.

Ðèñóíîê 12

Первым делом жмем «Просмотреть сертификат». И убеждаемся в том, что он действительно принадлежит нам.

Ðèñóíîê 13


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

Ðèñóíîê 14

tcp wrapper. О первом способе написано достаточно много статей, поэтому давайте посмотрим, как работать с tcp wrapper. При обнаружении нового входящего соединения inetd вызывает демона tcpd. Тот в свою очередь просматривает файл /etc/host.allow и в зависимости от адреса вызывающей стороны принимает решение о том, что делать с соединением. Если соединение проходит через этот контроль, то его передают демону, который будет в дальнейшем его обслуживать. В отличие от межсетевого экрана, который для принятия решений оперирует адресами и номерами портов, tcpd работает с адресами клиентов и именами вызываемых демонов. По умолчанию в /etc/hosts.allow описано разрешение принимать данные от любых хостов. Это нам не подходит, а значит, надо удалить или закомментировать строку ALL : ALL : allow и добавить в файл вот это: cucipop : localhost 127.0.0.1 : allow dkimap : localhost 127.0.0.1 : allow

После внесения изменений все должно работать как часы. Впрочем, для достижения наилучшего эффекта никто не мешает комбинировать настройки tcpd и запреты пакетов на межсетевом экране. После всех действий данные, выдаваемые netstat, должны выглядеть так:

Ðèñóíîê 15

С помощью кнопки «Добавить к доверенным» завершаем процедуру. Отныне все операции с почтой будут шифроваться с помощью этого SSL-сертификата. Ради интереса загляните в список доверенных сертификатов. На экране должно появиться что-то вроде следующего снимка.

tcp4 tcp4 tcp4 tcp4 tcp4 tcp4

0 0 0 0 0 0

0 0 0 0 0 0

*.465 *.* *.993 *.* 10.10.21.134.995 *.* 127.0.0.1.25 *.* *.143 *.* *.110 *.*

LISTEN LISTEN LISTEN LISTEN LISTEN LISTEN

После некоторого количества тестов можно понижать уровень подробности отладочных сообщений, описываемый переменной debug в файле /usr/local/etc/stunnel/stunnel.conf. Приемлемым значением будет цифра 3. Кстати, если нужно, чтобы stunnel автоматически запускался после перезагрузки машины, не забудьте переименовать /usr/local/etc/rc.d/stunnel.sh.sample в /usr/local/etc/rc.d/ stunnel.sh. В случае, когда у нас есть клиент, способный самостоятельно работать с SSL, все выглядит довольно просто. А вот что делать, если такового нет? Этот и многие другие вопросы мы обсудим в следующей статье.

Уважаемые читатели! Продолжается подписка на журнал на I-полугодие 2005 года. Ðèñóíîê 16

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

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

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

Доставка почтой в любую точку России.

47


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

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

АЛЕКСАНДР ПОХАБОВ 48


безопасность В этой статье будут рассмотрены решения проблем аутентификации и хранения сертификатов и ключей с помощью hardware-ключей. В своей работе я использовал ОС GNU/ Linux, рассматриваемый дистрибутив – Gentoo Linux. Тем, кто работает с другими дистрибутивами, использующих Pluggable Authentication Modules, не стоит расстраиваться, разница будет заметна лишь при установке необходимого ПО. Предполагается, что мы имеем два хоста – рабочая станция и удаленный сервер под управлением ОС Linux. С сервером (назовем его «remote») работаем, используя sshd, на обоих хостах имеем привилегии суперпользователя. Взглянем на проблемы, рассматриваемые в статье.

Проблема первая Часто приходится сталкиваться с проблемой запоминания паролей, запрашиваемых /bin/login. Все знают, что пароли должны иметь минимальную длину в восемь символов и включать в себя символы верхнего и нижнего регистров, а также спецсимволы. Когда количество подконтрольных нам серверов и пользовательских учетных записей на них возрастает, удержать в памяти все пароли зачастую почти непосильная задача. Все принятые нормативные акты по использованию данных учетной записи запрещают записывать пароли на бумаге, сохранять их в файлах и так далее. Как же быть администратору, у которого десятки, а то и сотни серверов и на каждом время от времени приходится регистрироваться с разными учетными данными?

Проблема вторая Например, мы используем GnuPG, публичный ключ доступен многим, secret key защищен паролем (pass phrase), но он является не более чем файлом на диске. Если этот файл похищен злоумышленником, он попытается подобрать верный pass phrase (brute force). Нет гарантии, что правильный пароль не будет найден в ближайшее время. Электронные USB-ключи, такие как Aladdin eToken или Rainbow iKey, а также смарткарты решают эти проблемы. USB-ключ или смарткарту удобно держать при себе, нельзя просто получить доступ к хранящимся в них ключам и сертификатам, как в случае их хранения на жестком диске. Подбор PIN по словарю также обречен на провал, так как после трех (в моем примере) неудачных попыток PIN будет заблокирован. Проект OpenSC основал Olaf Kirch. Он хотел написать библиотеку, предоставляющую структуру для написания драйверов устройств чтения смарткарт по принципу «все в одном», как для работы с устройствами, подключаемыми к последовательному порту, так и для USB-ключей. К моменту написания данной статьи поддерживаются следующие устройства: ! KOBIL KAAN Professional ! Schlumberger e-gate ! Aladdin eToken PRO ! Eutron CryptoIdentity IT-SEC ! Rainbow iKey 3000 Список поддерживаемого оборудования всегда можно посмотреть на веб-сайте проекта OpenSC – http://opensc.org.

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

Установка Так как в моем примере рассматривается USB-token от Aladdin (Aladdin eToken PRO 32K), ядро должно быть собрано с поддержкой USB device filesystem. # USE='usb pam' emerge opensc

Убедимся, что установлено все необходимое для последующей работы: # qpkg -I -v | grep open net-misc/openssh-3.8.1_p1-r1 * dev-libs/openssl-0.9.7d-r1 * dev-libs/opensc-0.8.1-r1 * dev-libs/openct-0.5.0 *

# qpkg -I -v | grep hotplug sys-apps/hotplug-base-20040401 * sys-apps/hotplug-20040401 *

Копируем пример конфигурационного файла opensc.conf: # cp /usr/share/opensc/opensc.conf.example /etc/opensc.conf

Сделаем openct и hotplug демонами, запускаемыми по умолчанию: # rc-update add hotplug default # rc-update add openct default

Запускаем их: # rc * Starting input hotplugging... * Starting pci hotplugging... * Starting usb hotplugging... * Starting OpenCT...

[ ok ] [ ok ] [ ok ] [ ok ]

Чтобы не работать постоянно с учетной записью root, добавим непривилегированного пользователя chiko в группу openct и wheel (для возможности использования $ su): # usermod -G openct,wheel chiko

Далее работаем уже под непривилегированной учетной записью. Вставим USB-ключ и убедимся, что он распознан: # openct-tool list 0 Aladdin eToken PRO

Наш ключ имеет идентификатор 0 – запомним его. Идентификаторы ключа всегда присваиваются по возрастанию начиная с 0. Если ключ не распознан, проверьте исправность USB-порта и наличие в ядре поддержки USB: # cat /ïóòü/ê/èñõîäíèêàì_ÿäðà/.config | grep CONFIG_USB_DEVICEFS CONFIG_USB_DEVICEFS=y

а также вывод mount: # mount | grep usbfs usbfs on /proc/bus/usb type usbfs (rw)

49


безопасность Все готово для создания RSA-ключей и X509-сертификата, приступим: # /etc/ssl/misc/CA.pl –newca CA 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 Nameor 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]:KRAST Locality Name (eg, city) []:Achinsk Organization Name (eg, company) [Internet Widgits Pty Ltd]:AGK Organizational Unit Name (eg, section) []:SB Common Name (eg, YOUR name) []:Pokhabov Aleksandr Email Address []:chiko@example.com

Примечание: все будет временно храниться в директории ~/demoCA. Создаем пароль:

Certificate Details: Serial Number: 1 (0x1) Validity Not Before: Nov 4 09:48:50 2004 GMT Not After : Nov 4 09:48:50 2005 GMT Subject: countryName = RU stateOrProvinceName = KRAST localityName = Achinsk organizationName = AGK organizationalUnitName = SB commonName = Pokhabov Aleksandr emailAddress = chiko@example.com X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: D9:F9:DB:F8:59:4C:72:86:15:13:B0:C0:FE:76:5C:93:C0:FD:38:B9 X509v3 Authority Key Identifier: keyid:6B:2E:C8:03:71:2E:67:62:71:BF:A7:93:56:52:C2:FF:62:30BA:F0 DirName:/C=RU/ST=KRAST/L=Achinsk/O=AGK/OU=SB/ ` CN=Pokhabov Aleksandr/emailAddress=chiko@example.com serial:00 Certificate is to be certified until Nov 4 09:48:50 2005 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

Экспортируем наш закрытый ключ: # openssl rsa -in newreq.pem -out newkey.pem

# openssl x509 -in demoCA/cacert.pem -days 3650 ↵ -out demoCA/cacert.pem -signkey demoCA/private/cakey.pem Getting Private key Enter pass phrase for demoCA/private/cakey.pem:

# /etc/ssl/misc/CA.pl –newreq Generating 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]:KRAST Locality Name (eg, city) []:Achinsk Organization Name (eg, company) [Internet Widgits Pty Ltd]:AGK Organizational Unit Name (eg, section) []:SB Common Name (eg, YOUR name) []:Pokhabov Aleksandr Email Address []:chiko@example.com Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []:OurChallengePass An optional company name []:AGK Request (and private key) is in newreq.pem

Подписываем: # /etc/ssl/misc/CA.pl –sign Using configuration from /etc/ssl/openssl.cnf 2745:error:0E06D06C:configuration file routines:NCONF_get_string:no value: conf_lib.c:329:group=CA_default name=unique_subject Enter pass phrase for ./demoCA/private/cakey.pem: Check that the request matches the signature Signature ok

50

Enter pass phrase for newreq.pem: writing RSA key

# /etc/ssl/misc/CA.pl -pkcs12 Enter pass phrase for newreq.pem: Enter Export Password: Verifying - Enter Export Password:

Сертификат и ключи готовы, поместим их на наш USBtoken. Смарткарты, как и USB-ключи используют для хранения сертификатов и ключей файловую систему. Многие производители в своих устройствах используют собственные проприетарные механизмы хранения ключей и сертификатов, например различные имена директорий. OpenSC реализует PKCS #15 стандарт и имеет модуль эмуляции для несовместимых механизмов хранения. Необходимо отформатировать аппаратный ключ (параметры «-EC» – сокращенные от «--erase-card» и «--create-pkcs15») перед его первым использованием (внимание! вся информация на ключе будет уничтожена!): # pkcs15-init -EC --label 'Chiko Test Card' --no-so-pin Connecting to card in reader Aladdin eToken PRO... Using card driver: Siemens CardOS About to erase card. About to create PKCS #15 meta structure.

Параметр --no-so-pin указывает, что не будет использоваться Security Officer PIN. Это избавит вас от лишних запросов Security Officer PIN, но так вы понижаете планку безопасности (владельцу ключа будут доступны возможности создания новых профилей). Также, в случае утери PIN и PUK-кодов пользовательского профиля вы не сможете разблокировать пользовательский PIN. Выбор за вами. На следующем шаге создается пользовательский профиль, выбираются PIN- и PUK-коды:


безопасность # pkcs15-init -P --auth-id 01 --label 'CHIKOPIN'

# grep -ir pam_opensc /var/log/messages

Connecting to card in reader Aladdin eToken PRO... Using card driver: Siemens CardOS Found Chiko Test Card About to store PIN. New user PIN required. Please enter PIN: Please type again to verify: Unlock code for new user PIN required (press return for no PIN). Please enter PIN: Please type again to verify:

Nov 11 16:43:00 workstation su(pam_opensc)[3374]: Authentication successful for chiko at pts/0.

Помещаем в аппаратный ключ только что созданный секретный ключ. На ошибку в пятой строке не обращаем внимания: # pkcs15-init -S newcert.p12 --format pkcs12 -a 01 --split-key Connecting to card in reader Aladdin eToken PRO... Using card driver: Siemens CardOS Found Chiko Test Card About to store private key. error:23076071:PKCS12 routines:PKCS12_parse:mac verify failure Please enter passphrase to unlock secret key: Importing 2 certificates: 0: /C=RU/ST=KRAST/L=Achinsk/O=AGK/OU=SB/ CN=Pokhabov Aleksandr/emailAddress=chiko@example.com 1: /C=RU/ST=KRAST/L=Achinsk/O=AGK/OU=SB/ CN=Pokhabov Aleksandr/emailAddress=chiko@example.com User PIN required. Please enter PIN:

Всё! Ключ прошит. Распорядитесь ключами и сертификатом, находящимися в ~/demoCA, подобающим образом. Не стоит забывать, что одна из преследуемых нами целей – исключить наличие сертификатов и закрытых ключей на жестком диске. Теперь мы готовы настроить PAM-аутентификацию, используя pam_opensc.so. # mkdir ~/.eid # pkcs15-tool -r 45 -o ~/.eid/authorized_certificates Connecting to card in reader Aladdin eToken PRO... Using card driver: Siemens CardOS Trying to find a PKCS#15 compatible card... Found Chiko Test Card! Reading certificate with ID '45'

Регистрируемся как root и вносим необходимые изменения в настройку PAM. Для использования # su без запроса пароля членами группы wheel, имеющими аппаратный ключ, привожу пример конфигурационного файла: # more /etc/pam.d/su auth sufficient /lib/security/pam_opensc.so auth required /lib/security/pam_wheel.so use_uid account required ↵ /lib/security/pam_stack.so service=system-auth session required ↵ /lib/security/pam_stack.so service=system-auth

Так как мы работали с учетной записью chiko (в вашем случае может быть другой), проверяем корректную работу следующим образом: # su chiko Using card reader Aladdin eToken PRO Enter PIN1 [CHIKOPIN]: $

Работает! Вывод # ps auxf докажет, что нет никакого обмана. Проверим логи:

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

Извлечем ключ из USB: # su chiko No smart card present su: Permission denied Sorry.

Теперь не только длина, но и само наличие пароля не обязательны. Можно удалить хэш пароля для пользователя chiko (и не только для него) из /etc/shadow, заменив его на восклицательный знак. При желании сделать аутентификацию только по hardware-ключу, /etc/pam.d/login должен быть соответствующе изменен. У меня он имеет вид: # more /etc/pam.d/login auth required /lib/security/pam_opensc.so account required ↵ /lib/security/pam_stack.so service=system-auth session required ↵ /lib/security/pam_stack.so service=system-auth

При попытке зарегистрироваться без наличия аппаратного ключа в USB получим: workstation login: chiko No smart card present Login incorrect

Если предполагается регистрация в системе под root по # su, файл /root/.eid/authorized_certificates должен быть доступен для чтения, иначе получим ошибку: # su Using card reader Aladdin eToken PRO Enter PIN1 [CHIKOPIN]: No such user, user has no .eid directory or .eid unreadable.

Будьте осторожны при изменении файлов конфигурации PAM, если допустить ошибки конфигурирования, то есть риск появления неприятного события – мы не сможем зарегистрироваться как root, и придется загружаться с LiveCD, монтировать раздел с /etc и править конфигурационные файлы PAM. Если в ваши планы ни в коем случае не входит перезагрузка, предпочтительно сделать резервные копии файлов конфигурации PAM, и используя crontab, по расписанию в определеное время вернуть их на место. Это применимо в случае ограничения количества pid и tty для root, если же таких ограничений нет, предпочтительнее использовать заранее открытую сессию. Подробнее о работе с PAM можно узнать в страницах руководства по PAM. Внимание! Во всех домашних каталогах пользователей, с учетными данными которых мы будем регистрироваться в системе, должен присутствовать корректный ~/.eid/ authorized_certificates. В моем примере до блокирования PIN дается три попытки его ввода. Как быть, если после третьей неудачной попытки ввести PIN мы получили предупреждение о его блокировке? # su

51


безопасность Using card reader Aladdin eToken PRO Enter PIN1 [CHIKOPIN]: sc_pkcs15_verify_pin: Authentication method blocked

Ведь даже после ввода корректного PIN мы не увидим ничего, кроме предупреждения о том, что он заблокирован. При создании пользовательского профиля на аппаратном ключе, кроме PIN мы также указывали PUK-код, его необходимо помнить именно для такого случая. Разблокирование:

Итак, у нас имеется готовый ключ и корректно собранный, настроенный и активный sshd на сервере remote. На нем есть учетная запись пользователя ajwol и в его домашнем каталоге имеется директория ~/.ssh . Чтобы зарегистрироваться с его учетной записью, используя наш ключ, в домашней директории ajwol, должен присутствовать и быть доступным для чтения файл ~/.ssh/authorized_keys, содержащий в себе публичный ключ. Создадим его на машине, с которой будем регистрироваться:

# pkcs15-tool -u

# ssh-keygen -D 0 > ~/authorized_keys

Connecting to card in reader Aladdin eToken PRO... Using card driver: Siemens CardOS Trying to find a PKCS#15 compatible card... Found Chiko Test Card! Enter PUK [CHIKOPIN]: Enter new PIN [CHIKOPIN]: Enter new PIN again [CHIKOPIN]: PIN successfully unblocked.

Если и PUK забыт и (в нашем примере) не использовался Security Officer PIN, не остается ничего кроме форматирования ключа, поэтому будьте максимально осторожны. Первоочередная цель достигнута – dual factor authentication (наличие hardware-ключа и знание PIN) работает на нашей системе. Невооруженным глазом заметно, что такой способ аутентификации намного безопасней пары login/ password. С регистрацией в локальной системе разобрались, рассмотрим регистрацию с помощью нашего аппаратного ключа на удаленных серверах. Первое, что следует отметить, – openssh должен быть собран с поддержкой смарткарт. В Gentoo это делается очень просто: # USE='X509 pam smartcard' emerge openssh

Пользователи других дистрибутивов применяют следующее: ./configure --with-opensc=/ïóòü/opensc

Как настроить и запустить sshd, думаю, объяснять нет необходимости. Никаких особенных настроек не требуется, за исключением вставки на рабочей станции в /etc/pam.d/ sshd строки auth required /lib/security/pam_opensc.so. Вот как он выглядит у меня: # more /etc/pam.d/sshd auth required accoun required session required

52

/lib/security/pam_opensc.so pam_stack.so service=system-auth pam_stack.so service=system-auth

где «0» – идентификатор ключа. Скопируем этот файл в /home/ajwol/.ssh/authorized_keys на сервер remote: # scp ~/authorized_keys ajwol@remote:.ssh

Регистрируемся на удаленном сервере, используя параметр -I 0 (id ключа): # ssh -I 0 -l ajwol remote Enter PIN for Private Key: Last login: Fri Nov 12 08:20:15 2004 from grayhat ajwol@remote ajwol $

Задача выполнена. Вы можете регистрироваться старым проверенным способом без ключа (не указывая параметр -I), используя login/password, но, по желанию, можете также поиграть с настройками модулей PAM на сервере remote. Примечание: ~/.ssh/authorized_keys должен быть доступен во всех домашних каталогах пользователей, с логинами которых будем регистрироваться удаленно. Теперь не имеет значения длина пароля для логина ajwol на хосте remote, пользователь даже не обязан знать его, хватит и PIN. Эти шаги можно проделать со многими удаленными хостами, освободив себя от необходимости запоминания массы длинных паролей к множеству пользовательских аккаунтов. Задачи, поставленные в начале статьи, решены. В следующих статьях об использовании аппаратных ключей будут рассмотрены примеры их работы с Mozilla и Apache 2, шифрование домашних каталогов.

Ссылки: ! ! ! !

http://opensc.org http://www.openssl.org/docs http://www.kernel.org/pub/linux/libs/pam man opensc


bugtraq Повышение привилегий в Microsoft Windows Программа: Microsoft Windows 2000 Advanced Server, Microsoft Windows 2000 Datacenter Server, Microsoft Windows 2000 Professional, Microsoft Windows 2000 Server Microsoft Windows NT 4.0 Server Microsoft Windows NT 4.0 Server, Terminal Server Edition, Microsoft Windows Server 2003 Datacenter Edition, Microsoft Windows Server 2003 Enterprise Edition, Microsoft Windows Server 2003 Standard Edition, Microsoft Windows Server 2003 Web Edition, Microsoft Windows XP Home Edition, Microsoft Windows XP Professional. Опасность: Высокая. Описание: Обнаружено несколько уязвимостей в ОС Microsoft Windows. Локальный атакующий может повысить свои привилегии на системе. 1. Уязвимость существует из-за некорректной проверки буфера при обработке данных, посланных через порт LPC (Local Procedure Call). Локальный атакующий может с помощью специально сформированного запроса вызвать переполнение буфера и повысить свои привилегии на системе. 2. Уязвимость существует при обработке identity токенов в службе LSASS. Локальный атакующий может повысить свои привилегии на системе. Удачная эксплуатация этих уязвимостей дает атакующему полный контроль над уязвимой системой. URL производителя: www.microsoft.com. Решение: Установите обновления: 1. Microsoft Windows NT Server 4.0 (requires Service Pack 6a): http://www.microsoft.com/downloa...AA8F-AF09-4839B9E8-BB218C7A8564. 2. Microsoft Windows NT Server 4.0 Terminal Server Edition (requires Service Pack 6): http://www.microsoft.com/ downloa...A61F-C69F-403A-BD6A-EF3984BFA2B8. 3. Microsoft Windows 2000 (requires Service Pack 3 or Service Pack 4): http://www.microsoft.com/downloa...A122-DDA440B8-A7AF-9DDCC3870C38. 4. Microsoft Windows XP (requires Service Pack 1 or Service Pack 2): http://www.microsoft.com/downloa...5D5C-3E4A4F41-B81E-376AA1CD204F. 5. Microsoft Windows XP 64-Bit Edition (requires Service Pack 1): http://www.microsoft.com/downloa...AE1E-0ABF4D31-BE12-3982C5146AE8/ 6. Microsoft Windows XP 64-Bit Edition Version 2003: http:// www.microsoft.com/downloa...9AB9-36BF-4A90-BC373B4FB6DCDF9A. 7. Microsoft Windows Server 2003: http://www.microsoft.com/ downloa...97CB-E8F0-461F-B2D2-F1065229B64E. 8. Microsoft Windows Server 2003 64-Bit Edition: http:// www.microsoft.com/downloa...9AB9-36BF-4A90-BC373B4FB6DCDF9A.

Множественные уязвимости в Linux-ядре Программа: Linux kernel 2.4 – 2.4.28, 2.6 – 2.6.9. Опасность: Высокая. Описание: Обнаружено несколько уязвимостей в реализации IGMP-протокола в ядре Linux. Удаленный атакующий может вызвать отказ в обслуживании. Локальный атакующий может повысить свои привилегии на системе. 1. Уязвимость существует в функции ip_mc_source(), которая может быть вызвана с помощью пользовательского API (IP_(UN)BLOCK_SOURCE, IP_ADD/DROP_SOURCE_ MEMBERSHIP, равно как и MCAST_(UN)BLOCK_SOURCE и MCAST_JOIN/LEAVE_SOURCE_GROUP уровня сокета SOL_IP). Существует возможность уменьшить значение «sl_count» счетчика структуры «ip_sf_socklist» до 0xffffffff (т.е. -1 для целочисленных), что приведет к зацикливанию вызова функции и вызовет зависание системы на несколько минут (в зависимости от скорости обработки данных на системе). Эти действия приведут к тому, что вся память ядра, которая следует за kmallocбуфером, будет смещена на 4 байта, что должно привести к немедленной перезагрузке системы в обычных условиях и позволить локальному атакующему повысить свои привилегии на системе. 2. Из-за уязвимости, описанной выше, возможно прочитать большое количество памяти ядра с помощью функций ip_mc_msfget() и ip_mc_gsfget(). 3. Уязвимость функции igmp_marksources() из модуля network (которая вызывается в контексте группы запросов IGMP, полученных из сети) существует из-за недостаточной проверки длины полученных параметров IGMP-сообщений. Эта уязвимость реализуема только на мультикаст-системах, где приложение создает многоадресный сокет. Удаленный атакующий может вызвать отказ в обслуживании системы. URL производителя: kernel.org. Решение: Установите обновление c сайта производителя.

Выполнение произвольного кода в WINS Программа: Семейство ОС Microsoft Windows. Опасность: Высокая. Описание: Обнаружено переполнение буфера в службе wins.exe. Удаленный атакующий может выполнить произвольный код на уязвимой системе. Удаленный атакующий может послать специально сформированный WINS-пакет на 42 TCP-порт, для того чтобы изменить указатель и записать произвольный код в любую ячейку памяти. Удаленный атакующий может выполнить произвольный код на уязвимой системе. URL производителя: www.microsoft.com. Решение: Решения на данный момент не существует.

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

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

53


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

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

СЕРГЕЙ ЯРЕМЧУК Известно, что появлению Интернета мы обязаны американскому министерству обороны. Поэтому интересными являются и разрабатываемые в этом ведомстве технологии, направленные на защиту информации. На страницах журнала уже рассказывалось о проекте Security Enhanced Linux1 (http://www.nsa.gov/selinux) от U.S. National Security Agency (NSA), основной задачей которого является создание высокозащищенных систем. Сегодняшняя статья о не менее интересной системе, помогающей выявить проблемы в сети. Разработанная в 1994 году, система обнаружения атак SHADOW или Secondary Heuristic Analysis for Defensive 1

54

Online Warfare (http://www.nswc.navy.mil/ISSEC/CID) является результатом деятельности другого проекта Cooperative Intrusion Detection Evaluation and Response (CIDER). CIDER в свою очередь был попыткой совместной разработки инструментов для автоматического сбора и анализа потоков информации в целях обнаружения атак. Основные работы ведутся Naval Surface Warfare Center, но свои усилия приложили и другие не менее известные организации вроде NSWC Dahlgren, NFR, NSA и SANS. Некоторое время система была закрыта, затем SHADOW так же стал свободно доступен, так как основой являются программы с откры-

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


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

Архитектура SHADOW Основу проекта составляют tcpdump и libpcap, применяющиеся для сбора сетевых пакетов. Как уже говорилось, анализируются только заголовки без анализа информации. Первоначально это может показаться не совсем разумно, так как некоторые атаки могут быть выявлены только при анализе содержимого, но для организаций, в которых повышенное внимание к конфиденциальности информации, – это, наверное, единственно разумный выход. Ведь если злоумышленник либо лицо, на это не уполномоченное, сможет получить доступ к данным базы собранных пакетов, то грош цена такой IDS. К тому же подобный подход требует меньшего количества ресурсов. Сама же система состоит из датчиков, анализаторов и базы собранных пакетов (рис. 1). При этом не имеет значения количество и место расположения датчиков, он просто собирает пакеты и по запросу переправляет их дальше анализатору. Их можно установить в зависимости от задач на внешнем интерфейсе, в DMZ или внутри сети. Установка вне firewall – большой риск, поэтому разработчики старались максимально его уменьшить и подстраховаться от возможной компрометации датчика. Анализатор всегда должен находиться за firewall. Его задача загрузить и оценить данные, собранные различными датчиками. Датчики и анализаторы для выборки данных и обслуживания соединяются посредством SSH. Для отбора событий, представляющих интерес, используются фильтры и скрипты. Последние позволяют обнаруживать и некоторые медленные, т.е. растянутые по времени атаки, а также распределенные атаки. Вся собранная информация в дальнейшем будет выводиться администратору в виде веб-страницы. Веб-интерфейс позволяет исследовать информацию, полученную от различных датчиков, за различные периоды времени, с подробной информацией относительно отдельного узла или образца, а также создавать готовые отчеты отправки для посылки в CIRT.

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

Ðèñóíîê 1

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

55


безопасность другая, которую желательно поместить за firewall, будет передавать информацию анализаторам. Для включения режима невидимости в дистрибутиве Red Hat и базирующихся на нем, файл /etc/sysconfig/networkscripts/ifcfg-eth0 (где eth0 – первая сетевая карта), должен содержать такие строки.

Построение датчика Скачиваем архив размером чуть меньше 7 Мб. И создаем каталоги для размещения. В документации предлагается /usr/local/, можно выбрать и другой, но при этом придется указать новый путь во многих конфигурационных файлах. # mkdir -p /usr/local/SHADOW

DEVICE=eth0 ONBOOT= no

В других дистрибутивах это будет скорее выглядеть несколько иначе, например, в SuSE за загрузку отвечает переменная STARTMODE. Системные требования невысоки. Единственное, в больших и активных сетях может понадобиться применение SCSI-диска и больший объем жесткого диска (в основном для анализаторов) для хранения захваченной информации. В моем случае система на детекторы захватывала около 2-3 Гб в день. Дополнительно рекомендуется выкинуть все ненужное из ядра и отказаться от использования модулей (ответ «N» в «Enable loadable module support.»). В документации приведен пример .config-файла для перекомпиляции ядра, желательно также обновить систему. В целях безопасности все процессы и каталоги на датчиках и анализаторах работают от имени отдельного непривилегированного пользователя. Поэтому его необходимо будет завести перед установкой: # useradd -c "SHADOW" -u 666 -d /home/SHADOW shadow

Для защиты рекомендуется выключить все лишние сервисы на используемых компьютерах (получить их список можно, введя chkconfig --list). Для отключения запускаемых через xinetd можно удалить все файлы в каталоге /etc/xinetd.d или проверить наличие строки «disable = yes» в каждом из них. Вторым шагом сетевой защиты является использование tcp_wrappers. Для чего в файле /etc/hosts.allow должны быть описаны адреса компьютеров, которым разрешен доступ к тем или иным сервисам. Формат файла прост: ñïèñîê_ñåðâèñîâ: ñïèñîê_ìàøèí [: êîìàíäà]

Например: sshd: ALL: ALL:

192.168.2. 192.168.1.100,127.0.0.1 ALL

: : :

allow allow deny

В приложении «С», в инструкции по установке, вы найдете рекомендуемые опции для настройки iptables. Документ описывает установку на Red Hat Linux (конкретно версии 8.0), именно под него разрабатывается SHADOW. Я использовал White Box Linux 3.0 и SuSE Linux 9.1. Если с первым проблем практически не было, что и неудивительно, ведь его основой служат исходные коды Red Hat Enterprise Linux. То при установке в SuSE пришлось немного повозиться, в основном это касается путей к конфигурационным файлам, которые пришлось изменять практически во всех скриптах. Это общие вопросы, теперь отдельно рассмотрим особенности настройки датчика и анализатора.

56

И распаковываем в него архив (tar xvfz /tmp/SHADOW1.8.tar.gz). Все основные файлы подписаны при помощи GPG, и при сомнении подпись можно проверить. # gpg --verify some_file_name.sig

Теперь в каталоге появится большое количество скриптов и подкаталогов, о назначении некоторых станет ясно по ходу изложения. В подкаталоге Doc вы найдете инструкцию по установке, в accessories – необходимые для работы утилиты libcap, tcpdump и openssh в rpm-пакетах и исходных кодах. Здесь последние версии этих утилит на момент выпуска SHADOW (апрель 2003), поэтому можно оставить имеющиеся в используемом дистрибутиве или взять более новые версии с официальных сайтов. Еще один момент, связанный с tcpdump. В RedHat, начиная с версии 6.2, применяют патчи, расширяющие возможности, но изменяющие выходной формат данных, с которыми анализатор работать не может. Поэтому если вы не уверены, tcpdump лучше всетаки взять и установить с http://www.tcpdump.org. О настройке и работе этих утилит уже рассказывалось на страницах журнала, поэтому этот вопрос в статье затрагиваться будет в объеме, необходимом для понимания процесса конфигурирования SHADOW. Теперь три скрипта в /usr/local/SHADOW/sensor требуют настройки. Это sensor_init.sh, std.ph и std.filter. Скрипт sensor_init.sh используется для запуска датчика. В нем переменная SENSOR_PATH должна указывать на каталог, куда установлен сенсор, SENSOR_PARAMETER указывает на файл, содержащий настройки датчика (без расширения .ph). Для примера настроек, в каталоге имеется файл std.ph. При необходимости можно использовать сразу несколько сенсоров с индивидуальными конфигурационными файлами. Далее необходимо проверить наличие файлов, прописанных в следующих переменных. # . # .

Source function library. /etc/rc.d/init.d/functions Source networking configuration. /etc/sysconfig/network

В SuSE первую строку пришлось закомментировать. Теперь копируем скрипт в положенное место. # cd /usr/local/SHADOW/sensor # cp sensor_init.sh /etc/rc.d/init.d/sensor

Это для RedHat, в других дистрибутивах путь, возможно, будет другим. Например, в SuSE команда будет такой: # cp sensor_init.sh /etc/rc.d/sensor

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


безопасность # chkconfig --add sensor

В файле std.ph (или как вы его назвали) также проверьте наличие файлов и каталогов, указанных в переменных. В std.filter указываются параметры фильтра для захватываемых tcpdump-пакетов. По умолчанию в файле одна строка ip, можно использовать и собственные конструкции вроде: icmp and icmp[0] != 8 and icmp[0] != 0

для icmp-пакетов или для NetBIOS: ip and (port 137 or port 138 or port 139)

Сценарий sensor_driver.pl управляет сенсорами. Для того чтобы собирать данные, каждый час во время работы системы используется crontab-сценарий – sensor_crontab. Для реализации последней возможности копируем его в каталог /etc/cron.hourly. Этот сценарий содержит три строки. Первые две предназначены для синхронизации времени посредством Network Time Protocol (NTP), последняя, которую нужно раскомментировать, управляет запуском sensor_ driver.pl. Параметры внутри, конечно же, можно подправить (список серверов времени на http://www.ntp.org, плюс статья Михаила Платова «NTP – атомные часы на каждом столе», журнал «Системный администратор», № 4, апрель 2004 г.). 17 23 * * * /usr/sbin/ntpdate time-a.nist.gov 18 23 * * * /sbin/hwclock --systohc 0 * * * * /usr/local/SHADOW/sensor/sensor_driver.pl std > ↵ /dev/null 2>&1

Все, датчик готов, можно приступать к настройке анализатора.

Настройка анализатора Все первичные действия для анализаторов ничем не отличаются от проводимых на датчиках. Но после распаковки архива на свое место внимания требуют совсем другие файлы. Также для работы потребуется установленный веб-сервер Apache любой версии (в целях безопасности обновление рекомендуемо всегда), желательно с модулями mod_ssl и mod_perl. Практически во всех дистрибутивах он есть. Можно использовать веб-сервер параллельно основной работе, но лучше только для работы с SHADOW. В каталоге /usr/local/SHADOW/httpd/apache-conf найдете примеры конфигурационных файлов для версий 1.3 и 2.0, в том числе и оригинальный httpd.conf. Общим для всех файлов веб-сервера, включая и .htaccess, является наличие для всех упоминаемых в них каталогов, конструкций вида. Order deny,allow Deny from all Allow from 172.21.122 Allow from localhost Allow from 127.0.0.1

Не забудьте заменить адреса своими, иначе в доступе будет отказано. В файле httpd-2.0.40.basic содержатся минимальные настройки веб-сервера, с которыми система уже может быть

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

запущена (в RedHat). Для этого достаточно его скопировать на свое место. # cp /etc/apache2/httpd.conf /etc/apache2/httpd.conf.orig # cp /usr/local/SHADOW/httpd/apache-conf ↵ /httpd-2.0.40.basic /etc/apache2/httpd.conf

В SuSE необходимо заменить пользователя и группу. User wwwrun Group www

И дописать в файл строку: Include /etc/apache2/sysconfig.d/loadmodule.conf

Можно как вариант использовать более подробный httpd-2.0.40.conf. Теперь готовим каталоги, в которых будут размещаться результаты, выводимые пользователю. # # # #

mkdir -p /home/shadow/html/tcpdump_results cd /usr/local/SHADOW/httpd/home cp * /home/shadow/html cp .htaccess /home/shadow/html

Не забудьте изменить адреса в .htaccess. # chown -R shadow:shadow /home/shadow

Все, можно перезапускать веб-сервер. # /etc/init.d/httpd restart

И теперь самое интересное и хлопотное – настройка ключей ssh. Для правильной работы OpenSSH, необходимо, чтобы файл /home/shadow/.ssh/authorized_keys на детекторах содержал копии открытых ключей пользователя shadow, которые были сгенерированы на анализаторе. Но поначалу необходимо, естественно, установить OpenSSH на датчике и анализаторе. Если команда ls /etc/ssh не покажет наличия файлов вида ssh_host_key.pub, то ключи можно сгенерировать автоматически, просто запустив сервер. # /etc/init.d/sshd start

И не забудьте добавить запуск OpenSSH при загрузке системы. # chkconfig --add sshd

Теперь необходимо, чтобы участвующие в работе узлы узнали о публичных ключах друг друга. Есть много способов, самый простой – соединиться с нужным узлом, и эта операция будет проделана автоматически. Разработчики считают более безопасным другой вариант. Монтируем дискету на датчике и копируем в нее все необходимые файлы. # mount -t vfat /dev/fd0 /mnt/floppy # cd /etc/ssh # cat ssh_host_key.pub ssh_host_dsa_key.pub ↵ ssh_host_rsa_key.pub > /mnt/floppy/ssh_known_hosts # umount /mnt/floppy

57


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

mount -t vfat /dev/fd0 /mnt/floppy cd /etc/ssh cp /mnt/floppy/ssh_known_hosts . umount /mnt/floppy

Теперь на анализаторе необходимо сгенерировать от имени пользователя shadow ключи и скопировать их затем на датчики. # su – shadow

В некоторых дистрибутивах при создании пользователя создается и каталог .ssh, если такого нет, создаем его. # mkdir .ssh # chmod 700 .ssh # cd .ssh

Генерируем ключи: # /usr/bin/ssh-keygen -b 1024 -t dsa -f .id_dsa Generating public/private dsa key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in .id_dsa. Your public key has been saved in .id_dsa.pub. The key fingerprint is: 89:e5:73:fa:37:78:9d:4b:7f:a7:10:49:eb:21:27:21 shadow@notebook

то можно продолжать дальше. Иначе проверьте имена файлов и права доступа к ним (700 для каталогов и 600 для файлов). Тему безопасности соединений ssh можно продолжать и далее. Например, используя инструкции ListenAddress и AllowUsers файла /etc/ssh/sshd_config можно еще более сузить диапазон возможных действий пользователя. Еще для полноценной работы необходимо установить nmap и сконфигурировать sudo, для того чтобы Apache мог его запустить. Для этого редактируем файл /etc/sudoers, примерно так. # Host alias specification Host_Alias SHADOW = analyzer1.com, analyzer2.com # Cmnd alias specification Cmnd_Alias NMAP = /usr/bin/nmap # User privilege specification root ALL=(ALL) apache SHADOW=NOPASSWD:

NMAP

ALL

Кроме того, такой инструмент, как nmap, не рекомендуется раздавать кому попало, тем более что он запускается от имени root. Поэтому некоторые скрипты, находящиеся в /home/shadow/httpd/cgi-bin/privileged (в документации здесь тоже ошибка), защищены дополнительно файлом .htaccess с использованием директивы Satisfy (надо отметить, что в большинстве советов по построению защищенного веб-сервера, о Satisfy почему-то забывают). Теперь при запросе из незащищенной сети от пользователя потребуют дополнительной авторизации.

# /usr/bin/ssh-keygen -b 1024 -t rsa -f .id_rsa2 Generating public/private rsa key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in .id_rsa2. Your public key has been saved in .id_rsa2.pub. The key fingerprint is: b6:63:24:af:1e:c1:c2:3a:f5:cc:6b:cd:e0:b2:19:89 shadow@notebook

В этом моменте в документации допущена ошибка. По умолчанию ключ rsa генерирует вторую версию, а в инструкции указано rsa2, что приводит к ошибке. Номер показывать необходимо как раз для первой версии. # /usr/bin/ssh-keygen -b 1024 -t rsa1 -f .id_rsa1 Generatingpublic/private rsa1 key pair. Enterpassphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in .id_rsa1. Your public key has been saved in .id_rsa1.pub. The key fingerprint is: bf:9e:2e:44:3b:65:f1:2f:77:6b:23:bc:e6:a9:66:3f shadow@notebook

# cat .id_dsa.pub .id_rsa2.pub .id_rsa1.pub > authorized_keys # mount -t vfat /dev/fd0 /mnt/floppy/ # cp authorized_keys /mnt/floppy/ # umount /mnt/floppy

И на датчиках: # # # #

mount -t vfat /dev/fd0 /mnt/floppy cd /home/shadow/.ssh cp /mnt/floppy/authorized_keys . umount /mnt/floppy

Теперь можно попробовать зайти с анализатора по ssh на датчик от имени пользователя shadow. Если получилось,

58

AuthType Basic AuthName "Privileged SHADOW Users" AuthUserFile /usr/local/SHADOW/httpd/cgi-bin ↵ /privileged/nmap_pwd Satisfy any require valid-user order deny,allow deny from all allow from 172.16.47

Как видите, только пользователи сети 172.16.47 могут запускать nmap без ввода пароля. Пароль можно создать при помощи htpasswd, формат вызова которой: htpasswd -c /path/to/store/password username

Например: # htpasswd -c /usr/local/SHADOW/httpd/cgi-bin ↵ /privileged/nmap_pwd grinder

Опция -с создает файл заново, что нам сейчас и нужно, но при добавлении нового пользователя в уже используемый файл вызывайте htpasswd без нее. В каталоге /usr/local/SHADOW/filters имеются шесть фильтров, отдельно для каждого протокола, с подробными комментариями внутри: filter.getall.doc, goodhost.filter.doc, icmp.filter.doc, ip.filter.doc, tcp.filter.doc, и udp.filter.doc. Скрипт find_scan.pl использует файл filter.getall.doc для определения внутренних сетей, fetchem.pl при помощи good host.filter.doc определяет свои mail, web servers и DNS-серверы. После проверки адресов и внесения своих параметров убираем комментарии при помощи скрипта comment_ strip.


безопасность # /usr/local/SHADOW/comment_strip ip.filter.doc > ↵ /usr/local/SHADOW/filters/Site1/ip.filter # /usr/local/SHADOW/comment_strip icmp.filter.doc > ↵ /usr/local/SHADOW/filters/Site1/icmp.filter # /usr/local/SHADOW/comment_strip tcp.filter.doc > ↵ /usr/local/SHADOW/filters/Site1/tcp.filter # /usr/local/SHADOW/comment_strip udp.filter.doc > ↵ /usr/local/SHADOW/filters/Site1/udp.filter # /usr/local/SHADOW/comment_strip goodhost.filter.doc > ↵ /usr/local/SHADOW/filters/Site1/goodhost.filter #/usr/local/SHADOW/comment_strip filter.getall.doc > ↵ /usr/local/SHADOW/filters/Site1/filter.getall

После чего рекомендуется проверить работу фильтров. # tcpdump -i eth0 -n -F /usr/local/SHADOW/filters ↵ /Site1/tcp.filter

Если не получена ошибка «parse error», то фильтр можно использовать в работе. Теперь осталось заглянуть в файл /usr/local/SHADOW/ etc/shadow.conf, который содержит настройки для конкретной системы. Надо отметить, что появление этого файла в последних версиях SHADOW заметно упростило настройку, теперь многие скрипты берут параметры отсюда. Ранее все параметры приходилось вбивать в каждый файл, что приводило к ошибкам и затрудняло конфигурацию. Проверьте, чтобы совпадали пути к утилитам и измените IP-адреса и e-mail на реальные. После этого его можно скопировать в /etc или просто создать символическую ссылку. # ln –s /usr/local/SHADOW/etc/shadow.conf /etc/shadow.conf

На сенсорах файл /etc/shadow.conf не используется, вместо него применяется файл Site.ph, лежащий в /usr/local/ SHADOW/sites/. Файл примера, который найдете в этом каталоге, содержит настройки для первого детектора «Outside Network Perimeter» с именем Site1.ph. Для других детекторов параметры $SITE и $SITE_LABEL и имя необходимо изменить, сверившись с /etc/shadow.conf. Кроме того, в переменных $SENSOR, $WEB_SERVER и @LOCAL_IP проставьте нужные параметры. Переменная $SENSOR_DIR=»/LOG», указывает на каталог, куда детекторы будут сохранять собранные данные. Мне показалось, что-то вроде /var/shadow с вынесеным в отдельный дисковый раздел /var будет более правильно. Теперь осталось проверить наличие всех каталогов, указанных в переменных файлов /etc/shadow.conf на анализаторе и Site1.ph на всех детекторах и изменить пользователя/группу chown –R shadow:shadow, где это потребуется. Все детекторы собирают информацию (не менее часа), теперь можно попробовать ее получить и проанализировать. Для начала лучше это проделать вручную. Для получения информации с определенного детектора используется скрипт fetchem.pl. Основная задача которого получить с указанного детектора нужный файл, содержащий собранные данные, создать для него подкаталог на анализаторе и выходной html-файл, сортировать данные, заменить IP-адреса именами и еще много чего. Например, данные за 21 час 31 октября 2004 года, с выводом логов в /tmp/fetchem.log можно получить так. # /usr/local/SHADOW/fetchem.pl -l Site1 -d 2004103121 -debug

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

В результате с указанного детектора будет скачан файл с указанными данными и положен в /usr/local/SHADOW/data/ Site1/Oct31/tcp.2004103120.gz. После первичного анализа в домашнем каталоге веб-сервера будет создан каталог /home/ shadow/html/tcpdump_results/Site1/Oct31 с несколькими файлами, пользователю будет выводиться 2004103121.html. Для автоматизации этого процесса в работе используется cron-файл analyzer_crontab.shadow # Run fetchem to get SHADOW data files: # SHADOW_PATH=/usr/local/SHADOW # 1 * * * * $SHADOW_PATH/fetchem.pl -l Site1 3 * * * * $SHADOW_PATH/fetchem.pl -l Site2 -debug # # Cleanup once per day. # 15 1 * * * $SHADOW_PATH/cleanup.pl -l Site1 24 1 * * * $SHADOW_PATH/cleanup.pl -l Site2 # # Collect statistics each night. # 1 0 * * * $SHADOW_PATH/stats/do_daily_stats.pl -l Site1 1 3 * * * $SHADOW_PATH/stats/do_daily_stats.pl -l Site2

Скрипт do_daily_scripts.pl из собранных за день данных собирает статистику, эти данные будут затем выводиться по нажатию кнопки «STATISTICS» в веб-браузере, cleanup.pl во избежание исчерпания свободного дискового места, полностью удаляет собранные на датчиках данные. Теперь можно запускать браузер и пробовать соединиться с веб-сервером, запустится два окна (рис. 2). В результате экспериментов выяснилось, что левая панель инструментов, запускаемая из /cgi-bin/tools.cgi не может быть нормально отображаться всеми браузерами. Разработчики указали на совместимость практически со всеми браузерами старых версий, но из всего имеющегося набора в SuSE 9.1 комфортно работать можно было только в konqueror. Вероятно, функции, прописанные в openwin.js, требуется переписать.

Ðèñóíîê 2

Если подойти к процессу настройки внимательно и творчески, то сейчас все должно работать. И только при желании для удобства использования можно потихоньку подправить скрипты под себя. В дальнейшем необходимо изучение захваченной информации и подстройка фильтров, для того чтобы система получала только необходимое. Успехов.

59


web

PHP-GTK

АНДРЕЙ УВАРОВ Наверное, не стоит говорить о том, какое большое распространение получил язык PHP в настоящее время. Преимущественно он используется в веб-программировании (собственно, как и задумывалось его создателем). Надёжно укрепившись на серверах, теперь не спеша переходит и на десктопы. Об этом свидетельствуют как минимум две вещи: появление поддержки ncurses и проект PHP-GTK, о чём и поговорим сегодня. Данная статья ориентирована на достаточно широкий круг читателей, так как в ней не рассматриваются какиелибо сложные аспекты. И может оказаться полезной как для людей, желающих использовать PHP для написания приложений с графическим интерфейсом пользователя, выполняющихся на клиентской стороне, так и для тех, кто просто желает начать изучение GTK. PHP-GTK представляет собой расширение (модуль), позволяющее создавать приложения с оконным графическим интерфейсом. Стоит заметить, что данное расширение является кроссплатформенным, речь идёт не только о *nix-подобных системах, но и Win. Всю документацию, исходные коды или же откомпилированное расширение вы найдёте на сайте проекта – gtk.php.net.

Что такое GTK? Итак, что же такое GTK? На самом деле в данном случае правильней было бы говорить о GTK+. GTK представляет собой набор библиотек, используемых для создания оконного графического интерфейса пользователя. Основным отличием GTK+ от GTK является объектная ориентированность и наличие механизма сигналов. Аббревиатура GTK означает – GIMP Toolkit, так как изначально разрабатывалась для GIMP (в рамках одноименного проекта). GTK+ основывается на двух основных понятиях: виджет и сигнал. Виджетом называется любой компонент графического

60

интерфейса, будь то кнопка, поле ввода или окно. Все виджеты наследуются от абстрактного класса GtkWidget. Виджеты, которые могут содержать другие виджеты, называются контейнерами. Предком контейнеров является Gtk Container (сам же GtkContainer наследуется от GtkWidget). Сигналами называются сообщения, создаваемые виджетами. Сигналы используются для того, чтобы реагировать на действия пользователя. Например, при появлении курсора над кнопкой – экземпляром класса GtkButton, генерируется сигнал «enter», а при нажатии – сигнал «clicked». Сигналы наследуются. Для обработки сигналов используются callback-фукции. Не стоит путать сигналы с событиями. Сигналы существуют в рамках GTK. А события являются отражением механизма событий в оконной системе. Итак, несколько «оглядевшись», можно приступить и к примерам. Напишем простейшее приложение. <?php if( !extension_loaded('gtk')) { dl( 'php_gtk.' . PHP_SHLIB_SUFFIX); }

?>

$window = &new GtkWindow(); $window->show(); gtk::main();


web Разберём нашу программу «по косточкам». Осуществляем проверку, загружено ли уже расширение, если нет, то загружаем его. if( !extension_loaded('gtk')) { dl( 'php_gtk.' . PHP_SHLIB_SUFFIX); }

Создаём экземпляр класса GtkWindow – окно. И осуществляем его отображение вызовом метода show(). Если размер окна не устанавливается в программе, как в нашем случае, то используется размер по умолчанию – 200х200. То же касается и заголовка окна, по умолчанию это имя скрипта. $window = &new GtkWindow(); $window->show();

Вызовом gtk::main() мы «включаем» основной цикл программы, то есть программа начинает слушать события. Без этой строки наше приложение просто отобразило бы окно и завершило на этом свою работу. Если вы попробуете закрыть приложение, то оно всё равно не завершит работу, так как сигнал о завершении выполнения игнорируется Для нормального завершения мы должны были обрабатывать сигнал «destroy» объекта window. Итак, овладев основами, можно приступить к рассмотрению чуть более сложного примера. <?php if( !extension_loaded('gtk')) { dl( 'php_gtk.' . PHP_SHLIB_SUFFIX); } function button_click(&$text){ $window = &new GtkWindow(); // óñòàíàâëèâàåì çàãîëîâîê îêíà $window->set_title('Message'); // óñòàíàâëèâàåì ðàçìåð îêíà $window->set_usize(200, 30);

}

$label = &new GtkLabel($text->get_text()); // äîáàâëÿåì îáúåêò â êîíòåéíåð $window->add($label); $window->show_all();

$mainwindow = &new GtkWindow(); // óñòàíàâëèâàåì çàãîëîâîê îêíà $mainwindow->set_title('Hello world'); $mainwindow->connect_object('destroy', Array('gtk', ↵ 'main_quit'));

$mainwindow->connect_object('destroy', Array('gtk', ↵ 'main_quit'));

Можно было бы заменить вызовом метода connect(), но при этом нам было бы необходимо определять функцию для обработки сигнала «destroy». ... function mainDestroy(){ gtk::main_quit(); }: ... $mainwindow->connect('destroy', 'mainDestroy'); ...

Первым параметром connect() является имя сигнала, вторым – имя callback-функции. Напишем похожую программу, только уже на языке Python. sample.py: import gtk def button_click(text): window = gtk.Window() window.set_title("Message") window.set_usize(200, 30) label = gtk.Label(text.get_text()) window.add(label) window.show_all() def main_quit(object): gtk.main_quit() mainwindow = gtk.Window() mainwindow.set_title("Hello world") mainwindow.connect("destroy", main_quit) box = gtk.HBox() button = gtk.Button("press me") entry = gtk.Entry()

// Ýòîò êëàññ ÿâëÿåòñÿ ñïåöèàëüíûì êîíòåéíåðîì, // êîòîðûé ïîçâîëÿåò ðàçìåùàòü ïî ãîðèçîíòàëè // äîáàâëåííûå â íåãî îáúåêòû. $box = &new GtkHBox();

button.connect_object("clicked", button_click, entry)

$button = &new GtkButton('press me');

mainwindow.add(box)

$entry = &new GtkEntry();

mainwindow.show_all() gtk.main()

$button->connect_object('clicked', 'button_click', ↵ $entry); $box->pack_start($entry); $box->pack_end($button); $mainwindow->add($box); $mainwindow->show_all(); ?>

Особый интерес для нас в данном случае представляет метод connect_object(). Данный метод осуществляет присоединение callback-функции к нужному сигналу. По своему назначению метод connect_object() сходен с connect() (оба метода наследуются от GtkObject). Строку:

gtk::main();

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

box.pack_start(entry) box.pack_end(button)

Как видите, все различия заключаются в синтаксисе. Таким образом, освоив GTK, вам не составит труда писать приложения практически на любом языке (разумеется, имеющем поддержку GTK). На данный момент PHP-GTK существует только для PHP4, но сейчас ведётся разработка следующей версии, в которой будет реализована поддержка GTK2 и PHP5, что выглядит весьма перспективно.

61


web

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

АЛЕКСЕЙ МИЧУРИН Согласитесь, что адрес http://site.ru/news/page2.html намного удобнее, чем http://site.ru/cgi-bin/news/view.cgi?page=2. Первый из них гораздо легче запомнить, записать, продиктовать по телефону. В этой статье я хотел бы рассмотреть наиболее доступные приёмы перенаправления http-запросов, делая упор на способы их обработки.

Знакомство с проблемой Когда обсуждается некая обработка запроса, конечно, подразумевается, что на сервере есть какие-то активные элементы (программы, сценарии...), способные обработать запрос и обеспечить определённую «реакцию». Программы обычно получают необходимую информацию либо со стандартного потока ввода (при запросе POST), либо из строки запроса, содержащейся в адресе справа от вопросительного знака (при запросе GET). Эти механизмы передачи данных прекрасно известны, документированы, поддержаны в неисчислимом множестве модулей и библиотек, и я не буду касаться их в настоящей статье. Я как раз хотел бы обсудить другие возможности, позволяющие передать информацию на сервер. То есть мы будем запускать сценарии, формировать веб-страницы динамически, но не будем включать в адрес ни знака вопроса, ни строку запроса. Метод POST мы тоже использовать не будем.

62

Как же в таком случае передать скрипту информацию? Ответ прост: через адрес. То есть мы рассмотрим приёмы, позволяющие вызвать один и тот же скрипт, используя разные адреса; а также обсудим, как скрипт может получить информацию о том, по какому адресу он был вызван на этот раз. Обсудим, какие дополнительные возможности обеспечивает такой способ управления скриптами. Я буду ориентироваться не на администраторов серверов, полномочия которых практически безграничны, а на гораздо более многочисленную армию веб-мастеров, которые обычно пользуются готовым хостингом и имеют ограниченный доступ к настройкам сервера. В этой статье мы рассмотрим только те возможности, которые могут быть настроены в файле .htaccess. Конечно, все описываемые приёмы доступны и администраторам. Материал расположен в порядке от простого и широко известного к более сложному. Читатели, частично знакомые с вопросом, могут пропустить первые разделы, практически ничего не теряя.

Несколько слов о файле .htaccess Файл .htaccess – это просто текстовый файл, который размещается в одной директории с веб-документами или сценариями. То есть для его редактирования вполне достаточ-


web но полномочий, позволяющих управлять содержимым сервера, коими обладают все владельцы виртуальных серверов. В нём хранятся конфигурационные директивы для сервера. Действие этих директив распространяется на все файлы, принадлежащие директории, в которой расположен .htaccess. Оно распространяется и на файлы всех вложенных директорий, хотя вложенные директории могут, в свою очередь, тоже содержать файлы .htaccess, которые переопределят настройки, данные в родительских директориях. Вообще говоря, использование имени .htaccess совсем не обязательно. Ваш сервер может быть настроен на использование другого имени вместо .htaccess. Настройка производится инструкцией: AccessFileName èìÿ_ôàéëà

Но я никогда не видел, чтобы администраторы серверов злоупотребляли этой возможностью и отступали от традиций. Какие настройки можно производить в .htaccess? Ответ зависит от нравов администратора. Все конфигурационные инструкции Apache, допустимые в .htaccess, поделены на категории. Администратор обычно даёт пользователю только часть полномочий, разрешая ему изменять настройки, принадлежащие только к определённым категориям. Настройка этих ограничений производится инструкцией: AllowOverride ñïèñîê_êàòåãîðèé_èëè_All_èëè_None

Поэтому прежде чем писать свой .htaccess, осведомитесь у администратора сервера, какие категории настроек вам доступны. Существует всего пять категорий: ! AuthConfig – директивы, отвечающие за организацию авторизованного доступа; ! FileInfo – директивы, управляющие обработкой ошибок и отвечающие за информацию о языках и кодировках и прочее; ! Indexes – команды, отвечающие за доступ к директориям, то есть за те случаи, когда файл в адресе не указан; ! Limit – команды, позволяющие ограничить доступ к ресурсу, например, закрыть или открыть доступ для клиентов, имеющих определённые IP-адреса; ! Options – всего две инструкции Options и XBitHack; первая регламентирует работу механизмов CGI, SSI и автоматического составления листинга директорий; вторая управляет реакцией SSI-процессора на атрибут файла «исполняемый» и используется весьма редко. Перейдём теперь к приёмам обработки адреса. Естественно, чтобы передать скрипту информацию через адрес, мы должны иметь возможность вызвать один и тот же скрипт, используя разные адреса. Когда это происходит?

Директива DirectoryIndex Начнём наш экскурс с самой простой возможности, о которой знают практически все. Директива DirectoryIndex при-

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

надлежит к категории Indexes и служит для определения файлов, выступающих в роли традиционного index.html. Если .htaccess, расположенный в некоторой директории, содержит инструкцию: DirectoryIndex index.html /cgi-bin/index.cgi

то при обращении к этой директории (без указания файла) сервер действует по следующему алгоритму: сперва он будет искать файл index.html, если таковой существует, то будет выдан клиенту, в противном случае, сервер выдаст результат выполнения сценария /cgi-bin/index.cgi. Если и последний не существует, то клиент получит сообщение об ошибке 404. Если разместить такой .htaccess сразу в двух директориях /one/ и /two/, то и по адресу /one/, и по адресу /two/ клиент получит результат работы /cgi-bin/index.cgi (естественно, если соответствующий index.html не найден). Мы вызываем один и тот же скрипт по разным адресам. Для получения такого эффекта может быть достаточно и одного подобного .htaccess. В нашем случае и для директории /one/first/, и /one/second/ в отсутствии index.html будет вызван /cgi-bin/index.cgi. Для нас существенно то, что сценарий /cgi-bin/index.cgi, кроме обычных переменных окружения, получит две дополнительные: REDIRECT_URL и REDIRECT_STATUS. Первая будет содержать запрошенный адрес без имени сервера. Вторая – статус (обычно 200). То есть сценарий может «определить», для какой директории он вызван, и совершить адекватные действия. Например, для одних директорий (скажем, с html-документами) он может составлять индекс, придавая ему должный вид и включая в него только определённые файлы, а для других директорий (допустим, с графикой) он будет перенаправлять пользователя на первую страницу или выдавать сообщение об ошибке. Для полноты картины осталось только сказать о переменной REDIRECT_QUERY_STRING: она практически эквивалентна QUERY_STRING (о которой мы договорились не упоминать в этой статье). Если в директории /paper сервера paper.ru в файле .htaccess находится инструкция: DirectoryIndex /cgi-bin/index.cgi

то при запросе адреса http://paper.ru/paper?string=data или http://paper.ru/paper/?string=data, как вы уже догадались, будет вызван сценарий /cgi-bin/index.cgi, но наряду с переменной QUERY_STRING ему будет передана ещё и REDIRECT_ QUERY_STRING. Обе они будут равны строке запроса, в нашем примере string=data. Разница между этими переменными состоит только в том, что когда строка запроса отсутствует, переменная QUERY_STRING существует, но равна пустой строке, а REDIRECT_QUERY_STRING не существует вовсе.

Обработка ошибок. Директива ErrorDocument Директива ErrorDocument принадлежит к категории FileInfo и предназначена для определения файлов, выдаваемых клиенту, если обработка запроса вызвала ошибку.

63


web Если добавить в .htaccess инструкцию: ErrorDocument 404 /cgi-bin/error.cgi

то при возникновении ошибки 404 будет выполнен сценарий /cgi-bin/error.cgi. Ему будут переданы четыре дополнительные переменные: ! REDIRECT_REQUEST_METHOD – метод, которым был выполнен ошибочный запрос; ! REDIRECT_STATUS – статус, его удобно использовать в обработчиках, предназначенных для ошибок разного типа, очевидно, в нашем случае статус может равняться только 404; ! REDIRECT_URL – адрес несуществующего ресурса без имени сервера, этот адрес, например, можно использовать для регистрации в журнале; ! REDIRECT_ERROR_NOTES – сообщение об ошибке.

Авторизованный доступ Прежде всего, скажу несколько слов о том, как активизировать механизм авторизации. Чтобы ограничить доступ к некоторой директории (и ко всем вложенным директориям), следует написать в .htaccess приблизительно такие инструкции: AuthType Basic AuthName "By Invitation Only" AuthUserFile /home/www/paper/secret/passwd Require valid-user

Все они, как вы, наверное, догадались, принадлежат к категории AuthConfig. Первая из них задаёт тип процедуры авторизации, на практике используется только Basic. Вторая инструкция задаёт текст, который отобразит браузер в окне диалога.

Кроме того, при наличии строки запроса создаётся переменная REDIRECT_QUERY_STRING, описанная выше. Эти переменные удобно использовать не только в CGIсценариях, но в SSI-документах. Так, если создать .htaccess с директивой: ErrorDocument 404 /error/404.shtml

а в файле /error/404.shtml разместить следующий SSI-код: <html> <head><title>404</title></head> <body> <h1>Ôàéë íå íàéäåí!</h1> Ôàéë <b><!--#echo var="REDIRECT_URL" --></b> áûë çàïðîøåí ìåòîäîì <b><!--#echo var="REDIRECT_REQUEST_METHOD" --></b>. Çàïðîñ áûë ïåðåíàïðàâëåí íà ýòîò äîêóìåíò ñî ñòàòóñîì <b><!--#echo var="REDIRECT_STATUS" --></b>. Ïîëíàÿ äèàãíîñòèêà òàêîâà: <b><!--#echo var="REDIRECT_ERROR_NOTES" --></b>. (âñå èñïîëüçîâàííûå ïåðåìåííûå äîñòóïíû è â CGI) </body> </html>

то при обращении к несуществующему файлу /is_it_is.html клиент получит следующее сообщение:

Ещё один пример обработчика ошибок мы увидим уже в следующем разделе. А здесь осталось добавить, что директива ErrorDocument допускает и другой синтаксис:

Директива AuthUserFile определяет файл с паролями пользователей, который легко создать с помощью утилиты htpasswd, входящей в поставку Apache. Обратите внимание, файл паролей в целях безопасности можно (и желательно!) размещать вне дерева директорий, доступных через Web. Директива Require регламентирует, какие пользователи или группы пользователей имеют доступ к данному ресурсу. В приведённом примере я позволил всем пользователям (конечно, только если они пройдут процедуру авторизации) обращаться к файлам и подкаталогам директории, где размещён наш .htaccess. Техника ограничения доступа описана многократно, и я не хотел бы повторять здесь других авторов. Для нас будет важно то, что когда клиент работает в директории авторизованно, сервер создаёт ещё две дополнительные переменные: REMOTE_USER и AUTH_TYPE. Первая, как вы понимаете, содержит имя пользователя, вторая – тип авторизации (Basic). Если несколько пользователей имеют доступ к одному ресурсу, то переменную REMOTE_USER удобно использовать в системах хранения персональных настроек или для ведения журналов. Эти переменные доступны и CGI-сценариям, и SSI-документам. Например, страница enter.shtml:

ErrorDocument 404 "Sorry. File not found

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

64

<html> <head><title>Enter</title></head> <body> <h1>Hi, <!--#echo var="REMOTE_USER" -->!</h1> <p>(AUTH_TYPE=<!--#echo var="AUTH_TYPE" -->)</p> </body> </html>

Будет выглядеть так:


web очень удобно. Для сценария, выполняемого на сервере, виртуальный путь принципиально ничем не отличается от строки запроса. Браузер же рассматривает его просто как путь, нисколько не ощущая его виртуальности. Следуя по относительным ссылкам, браузер сохраняет путь (или его часть). Пример такого сценария я и хочу привести: После успешной авторизации переменные REMOTE_ USER и AUTH_TYPE передаются и обработчикам ошибок в дополнение ко всем перечисленным выше, содержащим информацию об ошибке. Эта передача происходит даже в том случае, если обработчик находится за пределами засекреченной области (ошибка, конечно, должна произойти в засекреченной области). При неудачной авторизации возникает ошибка 401, для которой тоже может быть назначен обработчик: ErrorDocument 401 /error/401.shtml

или ErrorDocument 401 /cgi-bin/error.cgi

Мне осталось только заметить, что пользователи могут быть объединены в группы. Для этого существует директива AuthGroupFile. Так вот, информация о том, к какой группе принадлежит пользователь, не передаётся сценарию.

Применение PATH_INFO Сервер Apache (и не только он) предоставляет интересную возможность: если существует сценарий /cgi-bin/script.cgi, то любой адрес вида /cgi-bin/script.cgi/location/doc.ext считается вполне допустимым. При его обработке выполняется сценарий /cgi-bin/script.cgi, а строка /location/doc.ext передаётся ему в переменной PATH_INFO. Кроме неё, создаётся переменная PATH_TRANSLATED, содержащая как бы путь к запрашиваемому файлу относительно корня файловой системы сервера. Если в нашем примере предположить, что документы сервера расположены в директории /www/docs, то PATH_TRANSLATED будет содержать путь /www/docs/ location/doc.ext. Путь, который был на самом деле запрошен клиентом, как обычно, доступен через переменную REQUEST_URI. Эта возможность находит самые разные применения. Например, вы можете хранить все документы в кодировке КОИ-8, и их CP-1251-модификации создавать «на лету», используя виртуальные пути вида /cgi-bin/koi2win.cgi/... Единственное, что может доставить вам хлопоты – для реализации такого подхода потребуется все перекрёстные ссылки в документах делать относительными, а все адреса графических и мультимедийных объектов, CSS-, JS-компонент делать абсолютными. В противном случае вам придётся сделать сценарий koi2win.cgi чуть умнее, чем просто перекодировщик: он должен будет правильно (без искажений) передавать файлы, не являющиеся HTML-документами и не требующие перекодировки, что, впрочем, не так уж сложно реализовать. Другое применение – хранение в виртуальном пути некой информации (например, идентификатора сессии). Это

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

#!/usr/bin/perl use strict; my ($path, $script) = @ENV{qw/PATH_INFO SCRIPT_NAME/}; my ($color, $file) = $path=~m|/([^/]+)/([^/]+)$|; my $html_list=''; foreach (1..5) { $html_list .= <<"TEXT"; <li><a href="$_.html">$_.html</a></li> TEXT } print <<"TEXT"; Content-Type: text/html <html> <head><title>$script</title></head> <body text="$color" bgcolor="white" link="$color" vlink="$color"> <h1>$file</h1> <ul>$html_list</ul> </body> </html> TEXT

Как видите, сценарий выделяет из строки PATH_INFO (сохранённой в переменной $path) два последние элемента пути. Первая из этих частей интерпретируется как цвет (сохраняется в переменой $color), вторая – как имя файла (переменная $file), её можно было бы использовать для подключения определённого содержания. В цикле foreach мы создаём небольшое навигационное меню с относительными ссылками. Разместим наш сценарий по адресу: /cgi-bin/pi.cgi. Теперь по адресу /cgi-bin/pi.cgi/gray/3.html мы увидим:

Код страницы таков: <html> <head><title>/cgi-bin/pi.cgi</title></head> <body text="gray" bgcolor="white" link="gray" vlink="gray"> <h1>3.html</h1> <ul><li><a href="1.html">1.html</a></li> <li><a href="2.html">2.html</a></li> <li><a href="3.html">3.html</a></li> <li><a href="4.html">4.html</a></li> <li><a href="5.html">5.html</a></li> </ul> </body> </html>

Как видите, все ссылки «указывают» тоже на серые

65


web документы, вернее, они оставляют информацию о цвете (путь) неизменной. По адресу /cgi-bin/pi.cgi/red/1.html мы обнаружим аналогичную структуру «красных документов». Мысль, намеченную в этом сценарии, легко развить в необходимом русле. Единственное, о чем следует позаботиться – это безопасность. Отсутствие хотя бы каких-нибудь проверок в сценарии pi.cgi чревато только комичными ситуациями. Например, такой: /cgi-bin/pi.cgi/white/1.html. Но если ваш сценарий работает с файлами, то всегда надо быть готовым к тому, что кто-то запросит документ /cgi-bin/ koi2win.cgi/../../../etc/passwd. Конечно, конкретно эта атака наивна и, скорее всего, не представляет серьёзной опасности, хотя всё зависит от того, как устроен koi2win.cgi. Замечу ещё, что всё сказанное справедливо не только для CGI-сценариев, но и для SSI-документов. При обращении к ресурсу /dir/doc.shtml/data (конечно, предполагается, что doc.shtml не директория, а SSI-документ) будут также созданы две дополнительные переменные PATH_INFO и PATH_TRANSLATED. Кроме того, SSI-процессором всегда создаётся переменная DOCUMENT_PATH_INFO, которая пуста, если PATH_INFO и PATH_TRANSLATED отсутствуют. Я думаю, что у внимательного читателя уже возник вопрос, можно ли усовершенствовать наше решение так, чтобы избежать таких «неповоротливых» адресов, превратив, например, /cgi-bin/pi.cgi/gray/3.html в /color/gray/3.html. Ответ на этот вопрос – да, возможно. Как раз это обсуждается в следующем разделе.

Магия Action Наверное, самые большие возможности предоставляет директива Action. С её помощью вы можете назначить скриптобработчик для определённых типов файлов. Приведу пример. Напишем в .htaccess следующие директивы:

не к двум расширениям (.html и .htm), а к одному-единственному MIME-типу (text/html). С содержимым .htaccess разобрались, давайте теперь рассмотрим /cgi-bin/para.cgi. Если разместить наш .htaccess в директории /action, то при обработке адреса /action/1.para будет выполнен сценарий /cgi-bin/para.cgi, которому будет передан целый ряд дополнительных переменных: ! PATH_INFO – содержит адрес запрошенной «страницы», в нашем случае это /action/1.para; ! PATH_TRANSLATED – полное имя запрошенного файла, например, /www/docs/action/1.para; ! REDIRECT_STATUS – если всё в порядке, то 200. Обратите внимание: если файл 1.para не существует, то код всё равно будет 200. То есть сервер успешно запустил скрипт /cgi-bin/para.cgi, а существует ли файл 1.para – проблема скрипта. ! REDIRECT_URL – равно PATH_INFO. Если в адресе содержалась ещё и строка запроса (например, /action/1.para?subsection=3), то она не включается в PATH_INFO и REDIRECT_URL, а попадает в переменные QUERY_STRING и REDIRECT_QUERY_STRING, о которых уже говорилось в начале статьи. Если вам понадобится полный адрес (вместе со строкой запроса), то ищите его, как обычно, в переменной REQUEST_URI. Давайте разберём простенький пример. Пусть в файлах *.para будет храниться просто ASCII-текст, а скрипт /cgi-bin/ para.cgi будет формировать html-документы из ASCII-текста, производя с ним нехитрые преобразования: квотирование небезопасных символов (&, «, >, <), добавление тега <br> в конце каждой строки, добавление тегов, открывающих и закрывающих html-документ. Имя файла, который следует обработать, сценарий будет брать из переменной PATH_TRANSLATED. Код сценария таков: #!/usr/bin/perl

AddHandler my-handler .para Action my-handler /cgi-bin/para.cgi

Обе директивы, содержащиеся в этом файле, принадлежат к категории FileInfo. Первая – добавляет новый дескриптор файла, ассоциированный с расширением .para. Теперь все файлы *.para будут ассоциироваться с манипулятором my-handler. Особенностью директивы AddHandler является то, что она не чувствительна к регистру, то есть распространяется в равной мере и на файлы *.Para, *.PARA, *.PaRa и так далее. Кроме того, символ «точка» необязателен. Вторая директива – Action – назначает действие, которое необходимо выполнять для файлов, ассоциированных с манипулятором my-handler. Теперь любое обращение к файлу *.para должно приводить к запуску сценария /cgi-bin/ para.cgi. Для полноты картины добавлю, что вместо дескриптора можно использовать MIME-тип. В принципе, нетрудно представить случаи, когда это будет удобно. Например, вы поддерживаете публичный хостинг и хотите, чтобы ко всем страницам ваших клиентов автоматически добавлялся баннер. Тогда проще привязать обработчик html-документов

66

use strict; my ($file, $url)=@ENV{qw/PATH_TRANSLATED REDIRECT_URL/}; open FH, "<$file" or die; my $f=join('', <FH>); close FH; $f=~s/\&/&/g; $f=~s/\</</g; $f=~s/\>/>/g; $f=~s/\"/"/g; $f=~s/\n/<br>\n/g; print <<"TEXT"; Content-Type: text/html <html> <head> <title>$url</title> </head> <body><h1>$url</h1> $f </body> </html> TEXT

Теперь, если в файле /action/1.para находится следующие три строки: "AAA" <BBB> CCC


web то по адресу /action/1.para браузер обнаружит результат работы нашего скрипта: <html> <head> <title>/action/1.para</title> </head> <body><h1>/action/1.para</h1> "AAA"<br> <BBB><br> CCC </body> </html>

Выглядеть он будет так:

Как видите, текст корректно преобразован в HTML-документ. Вы, наверное, уже обратили внимание на то, что описанный подход очень похож на подход предыдущего раздела. Действительно, по адресу /cgi-bin/para.cgi/action/1.para мы увидим почти то же самое. «Почти» потому, что в этом случае переменной REDIRECT_URL уже не будет. Если бы мы использовали вместо неё PATH_INFO, то скрипт вообще «не почувствовал» бы разницы, будь он вызван как /cgi-bin/ para.cgi/action/1.para или как /action/1.para. Но самое интересное – сходства этих двух подходов на этом не заканчиваются. Оказывается, что и при Action-подходе сервер не проверяет, существует ли файл на самом деле! При обращении к любому файлу с расширением .para (в директории /action), независимо от того, существует ли файл, вызывается скрипт /cgi-bin/para.cgi. Даже REDIRECT_ STATUS сохраняет значение 200. То есть все замечания относительно безопасности остаются в силе. А теперь вопрос «на засыпку»: как отреагирует сервер на запросы /action/dir/1.para, /action/dir.para/1.para, /action/ dir.para/1.text? Естественно, ни директории /action/dir, ни директории /action/dir.para не существует. Правильный ответ таков: в первом случае возникнет ошибка 404. Её бы не возникло, если бы /action/dir существовала, даже в том случае, если сам файл /action/dir/1.para отсутствовал. Во втором и третьем случаях будет как ни в чем не бывало вызван скрипт /cgi-bin/para.cgi. Теперь, я думаю, читатель догадывается, как можно решить задачу, обозначенную в последнем абзаце предыдущего раздела. Например, мы можем создать директорию /color и разместить в ней .htaccess со следующей директивой: Action text/html /cgi-bin/pi.cgi

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

Кстати, обратите внимание, в этом примере мы обошлись без директивы AddHandler, так как обработчик привязан к определённому MIME-типу. Теперь мы можем запустить pi.cgi двумя способами. Первый – создать в директории /color директории, соответствующие необходимым цветам, скажем gray и green. Теперь по адресу /color/green/1.html мы обнаружим систему «зелёных» документов. Обратите внимание: если директория /color/cyan не существует, то запрос документа /color/cyan/1.html вызовет ошибку 404. Второй способ (внимание! это может быть потенциальная дыра в системе безопасности) – обратиться по адресу /color/hole.html/cyan/1.html. При этом директория hole.html не должна существовать. Теперь наличие расширения .html у директории hole.html приведёт к запуску pi.cgi, а он будет рассматривать только последние две компоненты пути – cyan и 1.html. Таким образом всё сработает «как часы». Так можно получить документ любого цвета, если на сервере не выполняется никаких проверок (как это сделано в нашем беспечном pi.cgi). И снова обращаю ваше внимание на то, что если директория /color/hole.html существует, а /color/hole.html/cyan не существует, то по адресу /color/hole.html/cyan/1.html мы получим ошибку 404.

Ограничения Вы видите, что сценарий или скрипт можно запустить не только «напрямую» (как /cgi-bin/forum.cgi), но и многими другими вполне доступными способами. И кроме традиционно используемой переменной QUERY_STRING сервер создаёт множество полезных переменных, но не забывайте, что использовать их надо не менее осторожно, чем QUERY_STRING. Даже мои небольшие примеры не лишены изъянов. Так, я довольно опрометчиво встраиваю в HTML-код, создаваемый SSI-процессором, такие переменные, как PATH_INFO. Подобные переменные задаются удалённым пользователем. Не исключено, что он сформирует такой адрес, по которому будет выдаваться HTML-документ, оснащённый вредоносным JavaScript-кодом или иным аппаратом (иногда для осуществления атаки оказывается достаточно считаных байт). Таким образом злоумышленник может скомбинировать адрес, наделяющий ваш ресурс вредоносными свойствами. Никогда нельзя использовать напрямую переменные, значение которых определяется удалённо. Следует отметить, что описанный подход, будучи реализован в чистом виде, практически полностью исключает возможность обработки форм. Это большой минус, но ни один из перечисленных приёмов не лишает вас возможности использовать переменную QUERY_STRING или REDIRECT_QUERY_STRING и обрабатывать формы, отправленные методом GET. Также к любому сценарию можно обратиться методом POST. Но самое главное, существует широкий круг задач, ограничивающихся организацией навигации и не предполагающих работу с формами (от лент новостей и фото-галерей до веб-каталогов). Именно в этих случаях наиболее оправданно применение подходов, описанных в настоящей статье.

67


hardware

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

ВЛАДИМИР МЕШКОВ Во второй части статьи рассмотрены примеры программ, выполняющих запись различной информации – музыкальных треков и данных – на компакт-диск CD-R/RW.

Запись информации на компакт-диск

Для определения текущих параметров устройства применяется команда MODE SENSE, а для установки параметров – команда MODE SELECT. Формат команды MODE SENSE приведен на рисунке:

Запись данных на компакт-диск Рассмотрим пример программы, выполняющей запись данных на компакт-диск. Под термином «данные» понимается файл в формате ISO (файл-образ), полученный при помощи утилиты mkisofs или каким-либо другим способом. Исходные тексты всех программ доступны на сайте журнала (www.samag.ru/source). Алгоритм выполнения операции записи данных на компакт-диск следующий: ! Определяются текущие параметры режима записи устройства путем считывания страницы параметров режима записи, код 0x05. ! Устанавливаются требуемые значения полей страницы параметров режима записи – режим записи, тип блока данных, режим трека (аудио/данные) и др. ! Из файла образа считываются блоки данных, и команда WRITE_10 выполняет запись этих блоков в соответствующие сектора компакт-диска. Стартовый номер сектора, с которого начинается запись, равен 0. Размер блока определяет значение поля «Data Block Type» страницы параметров режима записи (см. рис. 15 первой части статьи). ! По окончании записи данных (достигнут конец файлаобраза) последовательно выполняются команды SYNCHRONIZE CACHE, CLOSE TRACK, CLOSE SESSION. По команде SYNCHRONIZE CACHE все данные, подлежащие записи, переносятся на носитель, кэш устройства освобождается. Команда CLOSE TRACK завершает трек, а CLOSE SESSION завершает сессию – формирует Lead-In и Lead-Out-области сессии (диска).

68

Ðèñóíîê

1. Ôîðìàò êîìàíäû MODE SENSE

Поле Page Code содержит код запрашиваемой страницы режимов, поле Allocation Length – размер считываемых данных. Формат команды MODE SELECT приведен на рисунке:

Ðèñóíîê 2. Ôîðìàò êîìàíäû MODE SELECT

Поле Parameter List Length содержит размер передаваемого списка параметров в байтах. Бит PF (Page Format) установлен в единицу. Это означает, что формат страницы соответствует стандарту SCSI. Запись данных на диск выполняет команда WRITE_10. Формат этой команды представлен на рис. 3.


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

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

Ðèñóíîê 3. Ôîðìàò êîìàíäû WRITE_10

Назначение полей:

! Logical Block Address – адрес блока, в который будет записана информация.

! Transfer Length – число блоков для записи на диск. В команде SYNCHRONIZE CACHE используется только нулевой байт – он содержит код операции 0x35. Формат команды CLOSE TRACK/SESSION представлен на рисунке:

// äåñêðèïòîð ôàéëà sg-óñòðîéñòâà int sg_fd; // óêàçàòåëü íà äàííûå ñòðàíèöû ïàðàìåòðîâ ðåæèìà çàïèñè wpm_t *wpm; // çíà÷åíèå ïîëÿ Mode Data Length çàãîëîâêà Mode Parameter // Header __u16 mode_page_len = 0; // ðàçìåð ñïèñêà ñòðàíèö ðåæèìà Mode Parameter List – 8 áàéò // çàãîëîâêà ñïèñêà Mode Parameter Header + 52 áàéòà ñàìîé // ñòðàíèöû (ñì. ðèñ. 13-15, ïåðâîé ÷àñòè ñòàòüè) __u16 data_len = 60; // áëîê ïàìÿòè äëÿ ÷òåíèÿ ñïèñêà Mode Parameter List __u8 data_buff[60];

Функция mode_sense() считывает страницу параметров режима записи устройства: int mode_sense() { __u8 mode_sense_cmd[10]; /* Óñòðîéñòâà ãîòîâî? */ if(test_unit_ready() < 0) exit(-1); memset(data_buff, 0, 60); // wpm óêàçûâàåò íà íà÷àëî ñòðàíèöû ïàðàìåòðîâ ðåæèìà // çàïèñè wpm = (void *)(data_buff + 8);

Ðèñóíîê 4. Ôîðìàò êîìàíäû CLOSE TRACK/SESSION

Поле Close Function может принимать следующие значения: ! 001b – закрыть трек, номер которого указан в поле Track Number. ! 010b – закрыть последнюю незавершенную сессию, значение поля Track Number игнорируется. Следующая структура описывает формат страницы параметров режима записи (см. рис. 15 в первой части статьи): typedef struct { __u8 page_code :6; __u8 rez __u8 ps __u8 page_length; __u8 write_type __u8 test_write __u8 ls_v __u8 BUFE __u8 rez1 __u8 track_mode __u8 copy __u8 FP __u8 multises __u8 dbt __u8 rez2 __u8 link_size; __u8 rez3; __u8 hac __u8 rez4 __u8 s_format; __u8 rez5; __u32 packet_size; __u16 apl; __u8 mcn[16];

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

:1; :1; :4; :1; :1; :1; :1; :4; :1; :1; :2; :4; :4; :6; :2;

/* Ôîðìèðóåì êîìàíäûé ïàêåò */ memset(mode_sense_cmd, 0, 10); // êîä êîìàíäû MODE SENSE mode_sense_cmd[0] = MODE_SENSE_10; // êîä ñòðàíèöû ïàðàìåòðîâ ðåæèìà çàïèñè mode_sense_cmd[2] = 5; // ðàçìåð äàííûõ - 60 áàéò mode_sense_cmd[8] = data_len; /* Ïîñûëàåì êîìàíäó óñòðîéñòâó */ if(send_cmd(mode_sense_cmd, 10, SG_DXFER_FROM_DEV, ↵ data_buff, data_len, 20000) < 0) return -1; /* Ðàçìåð ñ÷èòàííûõ äàííûõ – çíà÷åíèå ïîëÿ Mode Data Length * çàãîëîâêà ñïèñêà ñòðàíèö */ memcpy((void *)&mode_page_len, data_buff, 2); mode_page_len = __swab16(mode_page_len); printf("Mode data length - %d\n", mode_page_len); /* Îòîáðàçèì òåêóùèå ïàðàìåòðû ðåæèìà çàïèñè */ // êîä ñòðàíèöû printf("Page code - %d\n", wpm->page_code); // ðàçìåð ñòðàíèöû printf("Page length - %d\n", wpm->page_length); // ðåæèì çàïèñè printf("Write type - %d\n", wpm->write_type); // òèï áëîêà äàííûõ printf("Data block type - %d\n", wpm->dbt); // ôîðìàò ñåññèè printf("Session format - %d\n", wpm->s_format); // ðåæèì òðåêà (ïîëå Control Field) printf("Track mode - %d\n", wpm->track_mode); }

return 0;

Установку требуемых параметров режима записи выполняет функция mode_select(). Этой функции мы передаем два параметра – тип блока данных (поле dbt структуры wpm_t) и тип информации, находящейся в треке (поле track_mode структуры wpm_t): int mode_select(__u8 dbt, __u8 track_mode) { __u8 mode_select_cmd[10];

69


hardware /* Îïðåäåëÿåì òåêóùèå ïàðàìåòðû ðåæèìà çàïèñè */ if(mode_sense() < 0) exit(-1); /* Óñòàíàâëèâàåì ïàðàìåòðû äëÿ çàïèñè äàííûõ */ wpm->write_type = 1; // ðåæèì çàïèñè – TAO wpm->dbt = dbt; // òèï áëîêà äàííûõ wpm->s_format = 0; // îòêðûòèå íîâîé ñåññèè çàïðåùåíî wpm->track_mode = track_mode; // ðåæèì òðåêà

NIZE CACHE, CLOSE TRACK, CLOSE SESSION. Команду SYNCHRONIZE CACHE формирует и посылает устройству функция sync_cache(): int sync_cache() { __u8 flush_cache[10];

/* Óñòðîéñòâî ãîòîâî? */ if(test_unit_ready() < 0) exit(-1); /* Ôîðìèðóåì êîìàíäíûé ïàêåò */ memset(mode_select_cmd, 0, 10); // êîä êîìàíäû MODE SELECT mode_select_cmd[0] = MODE_SELECT_10; // óñòàíàâëèâàåì â 1 áèò PF (Page Format) mode_select_cmd[1] = 1 << 4; /* Â ïîëå Parameter List Header çàïèñûâàåì ðàçìåð áëîêà * äàííûõ */ data_len = 60; mode_page_len = __swab16(data_len); memcpy((void *)(mode_select_cmd + 7), ↵ (void *)&mode_page_len, 2); /* Ïîñûëàåì óñòðîéñòâó êîìàíäó */ if(send_cmd(mode_select_cmd, 10, SG_DXFER_TO_DEV, ↵ data_buff, data_len, 20000) < 0) return -1; /* Äëÿ êîíòðîëÿ îòîáðàçèì óñòàíîâëåííûå ïàðàìåòðû ðåæèìà * çàïèñè */ if(mode_sense() < 0) exit(-1); return 0; }

Запись данных на компакт-диск выполняет функция write_iso(). Входные параметры функции – указатель на строку, содержащую имя файла-образа: int write_iso(__u8 *file_name) { int in_f; __u8 write_cmd[10]; __u8 write_buff[CD_FRAMESIZE]; __u32 lba = 0, lba1 = 0; if(test_unit_ready() < 0) exit(-1); /* Îòêðûâàåì ôàéë-îáðàç */ in_f = open(file_name, O_RDONLY, 0600); memset(write_buff, 0, CD_FRAMESIZE);

if(test_unit_ready() < 0) exit(-1); /* Ôîðìèðóåì è ïîñûëàåì êîìàíäó */ memset(flush_cache, 0, 10); flush_cache[0] = SYNCHRONIZE_CACHE; // êîä êîìàíäû if(send_cmd(flush_cache, 10, SG_DXFER_NONE, ↵ NULL, 0, 20000) < 0) return -1; }

Закрывает трек функция close_track(): int close_track() { __u8 close_trk_cmd[10]; if(sync_cache() < 0) { printf("Cannot synchronize cache\n"); return -1; } if(test_unit_ready() < 0) exit(-1); /* Ôîðìèðóåì êîìàíäó çàêðûòèÿ òðåêà è ïîñûëàåì * åå óñòðîéñòâó */ memset(close_trk_cmd, 0, 10); close_trk_cmd[0] = 0x5B; // êîä êîìàíäû CLOSE TRACK close_trk_cmd[2] = 1; // ôëàã çàêðûòèÿ òðåêà close_trk_cmd[5] = 1; // íîìåð òðåêà, îí ó íàñ îäèí if(send_cmd(close_trk_cmd, 10, SG_DXFER_NONE, ↵ NULL, 0, 20000) < 0) return -1; }

int close_session() { __u8 close_sess_cmd[10]; if(test_unit_ready() < 0) exit(-1); memset(close_sess_cmd, 0, 10); close_sess_cmd[0] = 0x5B; // êîä êîìàíäû CLOSE SESSION close_sess_cmd[2] = 2; // ôëàã çàêðûòèÿ òåêóùåé ñåññèè

/* Ôîðìèðóåì êîìàíäíûé ïàêåò */ memset(write_cmd, 0, 10); write_cmd[0] = WRITE_10; // êîä êîìàíäû write_cmd[8] = 1; // êîëè÷åñòâî ñåêòîðîâ äëÿ çàïèñè

/* Àäðåñ áëîêà äëÿ çàïèñè */ lba = __swab32(lba1); memcpy((write_cmd + 2), (void *)&lba, 4); lba1 += 1; /* Ïîñûëàåì óñòðîéñòâó êîìàíäó */ if(send_cmd(write_cmd, 10, SG_DXFER_TO_DEV, write_buff, ↵ CD_FRAMESIZE, 20000) < 0) return -1; }

}

return 0;

Функция close_session() закрывает текущую сессию:

/* Öèêë ÷òåíèÿ áëîêîâ äàííûõ èç ôàéëà. * Ðàçìåð áëîêà – 2048 áàéò */ while(read(in_f, write_buff, CD_FRAMESIZE) > 0) {

printf("%c", 0x0D); printf("lba - %6d", lba1);

return 0;

if(send_cmd(close_sess_cmd, 10, SG_DXFER_NONE, ↵ NULL, 0, 60000) < 0) return -1; }

return 0;

После того как данные записаны, извлекаем компактдиск из привода, послав устройству команду START/STOP UNIT (см. [5]): void eject_cd() { __u8 start_stop_cmd[6]; memset(start_stop_cmd, 0, 6); start_stop_cmd[0] = 0x1B; // êîä êîìàíäû START/STOP UNIT start_stop_cmd[4] = 2; // èçâëå÷ü êîìïàêò-äèñê

printf("\n"); return 0;

send_cmd(start_stop_cmd, 6, SG_DXFER_NONE, NULL, 0, 20000);

По окончании записи данных необходимо, как было уже сказано выше, послать устройству три команды: SYNCHRO-

70

}

return;


hardware Имя файла-образа передается главной функции программы в виде параметра. Функция main() выглядит следующим образом:

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

int main(int argc, char **argv) { /* Ïðîâåðÿåì íàëè÷èå âõîäíûõ ïàðàìåòðîâ */ if(argc != 2) { printf("\n\tUsage: write_iso [ISO-image]\n\n"); return 0; } /* Îòêðûâàåì ôàéë sg-óñòðîéñòâà */ if((sg_fd = open(SG_DEV, O_RDWR)) < 0) { perror("open"); return -1; } /* Óñòàíàâëèâàåì ïàðàìåòðû ðåæèìà çàïèñè äàííûõ: * òèï áëîêà äàííûõ dbt = 8 – ôîðìàò áëîêà Mode 1, ðàçìåð * áëîêà 2048 áàéò; * òèï èíôîðìàöèè, íàõîäÿùåéñÿ â òðåêå track_mode = 4 – * òðåê ñîäåðæèò äàííûå. */ mode_select(8, 4); /* Âûïîëíÿåì çàïèñü äàííûõ íà êîìïàêò-äèñê */ if(write_iso(argv[1]) < 0) { printf("Cannot write image %s\n", argv[1]); return -1; } /* Çàêðûâàåì òðåê, ñåññèþ è èçâëåêàåì êîìïàêò-äèñê èç ïðèâîäà*/ close_track(); close_session(); eject_cd();

}

close(sg_fd); return 0;

Ðèñóíîê 6. Ôîðìàò êîìàíäû READ TRACK INFORMATION

Значение поля Address/Number Type определяет содержание поля Logical Block Address/Track/Session Number. Если Address/Number Type = 01b, то устройство вернет блок информации о треке, номер которого находится в поле Logical Block Address/Track/Session Number. Формат блока информации о треке представлен на рис. 7. Из всего многообразия данных, находящихся в блоке, нас интересует только поле Track Start Address. Это поле содержит стартовый адрес трека, с этого адреса выполняется запись трека. Назначение остальных полей приведено в спецификации SCSI MMC-4 ([1]). Функция reserv_track() выполняет резервирование на компакт-диске пространства для трека. Входной параметр функции – размер трека в блоках.

Полный текст программы записи ISO-образа на компактдиск находится в файле SG/iso_write.c.

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

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

В поле Reservation size указывается размер трека в блоках. Каждый вызов команды RESERVE TRACK модифицирует PMA-область, добавляя в нее запись о координатах

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

Ðèñóíîê 7. Ôîðìàò áëîêà èíôîðìàöèè î òðåêå

71


hardware int reserv_track(__u32 track_size) { __u8 reserv_track_cmd[10]; __u32 size = 0; if(test_unit_ready() < 0) exit(-1); /* Ôîðìèðóåì êîìàíäíûé ïàêåò */ memset(reserv_track_cmd, 0, 10); reserv_track_cmd[0] = 0x53; // êîä êîìàíäû RESERVE TRACK /* Çàïîëíÿåì ïîëå Reservation size */ size = __swab32(track_size); memcpy((void *)(reserv_track_cmd + 5), (void *)&size, 4); if(send_cmd(reserv_track_cmd, 10, SG_DXFER_NONE, ↵ NULL, 0, 20000) < 0) return -1; /* C÷èòûâàåì PMA */ read_pma(); return 0; }

Чтение информации о треке выполняет функция read_track_info(). Параметр функции – номер трека. Возвращаемое значение – стартовый адрес трека. __u32 read_track_info(int trk_num) { __u8 read_track_info_cmd[10]; __u8 data_buff[40]; // áëîê èíôîðìàöèè î òðåêå __u16 len = 40; // ðàçìåð áëîêà __u32 lba = 0; if(test_unit_ready() < 0) exit(-1); /* Ôîðìèðóåì êîìàíäíûé ïàêåò */ memset(data_buff, 0, 40); memset(read_track_info_cmd, 0, 10); read_track_info_cmd[0] = 0x52; // ïîëå Address/Number Type = 01b read_track_info_cmd[1] = 1; read_track_info_cmd[5] = trk_num; // íîìåð òðåêà len = __swab16(len); memcpy((void *)(read_track_info_cmd + 7), (void *)&len, 2); if(send_cmd(read_track_info_cmd, 10, SG_DXFER_FROM_DEV, ↵ data_buff, 40, 20000) < 0) { printf("Cannot read track #%d info!\n", trk_num); exit(-1); } /* Èç áëîêà èíôîðìàöèè î òðåêå ñ÷èòûâàåì äàííûå î ðàçìåðå * òðåêà (ïîëå Track Size ) */ memcpy((void *)&lba, (void *)(data_buff + 24), 4); printf("Track #%d size - %u sectors\n", ↵ trk_num, __swab32(lba)); /* Ñòàðòîâûé àäðåñ òðåêà */ memcpy((void *)&lba, (void *)(data_buff + 8), 4); return __swab32(lba); }

Рассмотрим главную функцию программы записи аудиоданных. Входные параметры – список файлов в формате Ogg Vorbis. int main(int argc, char **argv) { int i = 1; struct stat s; __u32 start_lba = 0, total_sectors = 0; __u32 track_size = 0; /* Ïðîâåðÿåì íàëè÷èå âõîäíûõ ïàðàìåòðîâ */ if(argc == 1) { printf("\n\tUsage: write_audio [OGG-files]\n\n"); return 0; }

/* Îòêðûâàåì ôàéë óñòðîéñòâà */ sg_fd = open(SG_DEV, O_RDWR); /* Óñòàíàâëèâàåì ïàðàìåòðû ðåæèìà çàïèñè: * òèï áëîêà äàííûõ dbt = 0 – «ñûðûå» äàííûå, ðàçìåð áëîêà * 2352 áàéòà; * track_mode = 0 – òðåê ñîäåðæèò àóäèîäàííûå. */ mode_select(0, 0); /* Ñ÷èòûâàåì èíôîðìàöèþ èç PMA */ printf("Display PMA:\n"); read_pma(); /* Öèêë çàïèñè òðåêîâ íà äèñê */ for(i = 1; i < argc; i++) { /* Ïðåîáðàçóåì ôàéë èç ôîðìàòà Ogg Vorbis â WAV * (áåç çàãîëîâêà). Èìÿ âûõîäíîãî ôàéëà – track.cdr */ ogg_decoder(argv[i]); /* Îïðåäåëÿåì ðàçìåð ôàéëà track.cdr â áàéòàõ*/ memset((void *)&s, 0, sizeof(struct stat)); stat("./track.cdr", &s); /* Ðàçìåð ôàéëà â áëîêàõ */ track_size = s.st_size / CD_FRAMESIZE_RAW; printf("File size - %u\n", s.st_size); printf("Sectors in file - %u\n", track_size); printf("Reserve track #%d\n", i); /* Ðåçåðâèðóåì ïðîñòðàíñòâî äëÿ òðåêà */ reserv_track(track_size); /* Îïðåäåëÿåì ñòàðòîâûé àäðåñ òðåêà */ start_lba = read_track_info(i); printf("Start LBA for track #%d - %u\n", i, start_lba); /* Çàïèñûâàåì â òðåê àóäèîäàííûå. Íîìåð ñòàðòîâîãî áëîêà * ðàâåí start_lba */ total_sectors = write_audio("./track.cdr", start_lba); if(total_sectors == 0) return -1; /* Çàêðûâàåì òðåê */ close_track(i); } /* Öèêë çàïèñè òðåêîâ çàâåðøåí. Çàêðûâàåì ñåññèþ */ close_session(); /* Óäàëÿåì ôàéë track.cdr è èçâëåêàåì äèñê èç ïðèâîäà */ unlink("./track.cdr"); eject_cd();

}

close(sg_fd); return 0;

Преобразование файла из формата Ogg Vorbis в WAV выполняет функция ogg_decoder(). Входной параметр функции – имя файла в формате Ogg Vorbis. Для конвертирования используются библиотека libvorbis (http://www.vorbis.org). На выходе получается файл track.cdr в формате WAV, но без RIFF-заголовка. void ogg_decoder(__u8 *file_name) { __u8 pcmout[8192]; FILE *f; int out; OggVorbis_File vf; int current_section; printf("\nDecoding file %s..", file_name); f = fopen(file_name,"r"); out = open("./track.cdr", O_CREAT|O_RDWR|O_TRUNC, 0600); if(ov_open(f, &vf, NULL, 0) < 0) { printf("Input does not appear to be an Ogg bitstream.\n"); exit(-1); } for(;;) {

72


hardware memset(pcmout, 0, 8192); long ret = ov_read(&vf, pcmout, sizeof(pcmout), ↵ 0, 2, 1, &current_section); if (ret == 0) break; if(ret < 0) { printf("Error OGG bitsream"); exit(-1); }

}

if(write(out, pcmout, ret) < 0) { printf("write"); exit(-1); }

fclose(f); close(out);

}

printf("OK\n"); return;

Функция write_audio() выполняет запись аудиотрека на диск. Входные параметры – имя файла WAV-формата (без заголовка), содержащего аудиоданные, и стартовый адрес, с которого начинается запись. Возвращаемое значение – общее число записанных на диск блоков: __u32 write_audio(__u8 *file_name, __u32 start_lba) { int in_f; __u8 write_cmd[10]; // áëîê äëÿ àóäèîäàííûõ, 2352 áàéò __u8 write_buff[CD_FRAMESIZE_RAW]; __u32 lba = 0, lba1 = 0;

# ./ogg2cdda trk1.ogg trk2.ogg trk3.ogg

Результаты работы программы: Decoding file trk1.ogg..OK File size – 41505744 bytes Sectors in file - 17647 Reserve track #1 PMA data length - 24 PMA entries - 2 Entry ADR CTRL Point 0 2 0 0 1 1 0 1 Track #1 size - 17647 sectors Start LBA for track #1 - 0 Decoding file trk2.ogg..OK File size – 36604176 bytes Sectors in file - 15563 Reserve track #2 PMA data length - 35 PMA entries - 3 Entry ADR CTRL Point 0 2 0 0 1 1 0 1 2 1 0 2 Track #2 size - 15563 sectors Start LBA for track #2 - 17799 Decoding file trk3.ogg..OK File size – 47684448 bytes Sectors in file - 20274 Reserve track #3 PMA data length - 46 PMA entries - 4 Entry ADR CTRL Point 0 2 0 0 1 1 0 1 2 1 0 2 3 1 0 3 Track #3 size - 20274 sectors Start LBA for track #3 - 33514

Min 80 3

Sec 71 57

Frame PMin 82 0 24 0

Psec 0 2

Pframe 0 0

LBA --0

Min 80 3 7

Sec 71 57 26

Frame 82 24 64

PMin 0 0 3

Psec 0 2 59

Pframe 0 0 24

LBA --0 17799

Min 80 3 7 11

Sec 71 57 26 59

Frame 82 24 64 15

PMin 0 0 3 7

Psec 0 2 59 28

PFrame 0 0 24 64

LBA --0 17799 33514

Close session..OK

if(test_unit_ready() < 0) exit(-1); lba1 = start_lba; /* Îòêðûâàåì ôàéë ñ àóäèîäàííûìè */ in_f = open(file_name, O_RDONLY, 0600); memset(write_buff, 0, CD_FRAMESIZE_RAW); /* Öèêë ÷òåíèÿ äàííûõ èç ôàéëà è çàïèñè */ while(read(in_f, write_buff, CD_FRAMESIZE_RAW) > 0) { /* Ôîðìèðóåì êîìàíäíûé ïàêåò */ memset(write_cmd, 0, 10); write_cmd[0] = WRITE_10; write_cmd[8] = 1; // ÷èñëî áëîêîâ äëÿ çàïèñè printf("%c", 0x0D); printf("lba - %6d", lba1); // àäðåñ áëîêà, â êîòîðûé âûïîëíÿåòñÿ çàïèñü äàííûõ lba = __swab32(lba1); memcpy((write_cmd + 2), (void *)&lba, 4); lba1 += 1; if(send_cmd(write_cmd, 10, SG_DXFER_TO_DEV, write_buff, ↵ CD_FRAMESIZE_RAW, 20000) < 0) return 0; memset(write_buff, 0, CD_FRAMESIZE_RAW); }

}

close(in_f); printf("\n"); return lba1; // ÷èñëî áëîêîâ, çàïèñàííûõ íà äèñê

Полный текст программы создания аудиодиска из файлов формата Ogg Vorbis находится с файле SG/ogg2cdda.c. Получаем исполняемый файл при помощи команды: # gcc -o ogg2cdda ogg2cdda.c -lvorbis -lvorbisfile

Рассмотрим пример работы программы ogg2cdda. Устанавливаем в привод диск CD-RW и запускаем программу на выполнение, указав в командной строке имена трех файлов в формате Ogg Vorbis:

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

Хорошо видно, что после каждого вызова функции reserv_track в PMA добавляется запись о новом треке. Расстояние между треками – 2 секунды. Теперь рассмотрим пример записи аудиоданных без предварительного резервирования треков. Для определения стартового адреса трека при помощи команды READ TRACK INFORMATION считывается адрес невидимого, незавершенного (invisible) трека. В этом случае поле Address/ Number Type команды READ TRACK INFORMATION содержит 01b, поле Logical Block Address/Track/Session Number – значение 0xFF (см. табл. 452, стр. 374 спецификации [1]). Функция определения стартового адреса невидимого трека: __u32 read_track_info() { __u8 read_track_info_cmd[10]; __u8 data_buff[40]; // áëîê èíôîðìàöèè î òðåêå __u16 len = 40; // ðàçìåð áëîêà èíôîðìàöèè î òðåêå __u32 lba = 0; if(test_unit_ready() < 0) exit(-1); /* Ôîðìèðóåì êîìàíäíûé ïàêåò */ memset(data_buff, 0, 40); memset(read_track_info_cmd, 0, 10); read_track_info_cmd[0] = 0x52; read_track_info_cmd[1] = 1; read_track_info_cmd[5] = 0xFF; // invisible track len = __swab16(len); memcpy((void *)(read_track_info_cmd + 7), (void *)&len, 2); if(send_cmd(read_track_info_cmd, 10, SG_DXFER_FROM_DEV, ↵ data_buff, 40, 20000) < 0) { printf("Cannot read track info!\n"); exit(-1); } /* Ñòàðòîâûé àäðåñ íåâèäèìîãî òðåêà. Ñ ýòîãî àäðåñà áóäåò * âûïîëíÿòüñÿ çàïèñü

73


hardware */ }

memcpy((void *)&lba, (void *)(data_buff + 8), 4); return __swab32(lba);

Рассмотрим главную функцию программы записи аудиоданных. Входные параметры – список файлов в формате MP3. int main(int argc, char **argv) { int i = 1; __u32 start_lba = 0, total_sectors = 0; /* Ïðîâåðÿåì âõîäíûå ïàðàìåòðû */ if(argc == 1) { printf("\n\tUsage: write_audio [MP3-files]\n\n"); return 0; } /* Îòêðûâàåì ôàéë óñòðîéñòâà */ if((sg_fd = open(SG_DEV, O_RDWR)) < 0) { perror("open"); return -1; } /* Óñòàíàâëèâàåì ïàðàìåòðû ðåæèìà çàïèñè * (ñì. ïðåäûäóùèé ïðèìåð) */ mode_select(0, 0); /* Öèêë çàïèñè òðåêîâ íà äèñê */ for(i = 1; i < argc; i++) { /* Äåêîäèðóåì ôàéë èç MP3-ôîðìàòà â WAV */ printf("\nDecoding file %s..\n", argv[i]); mp3_decoder(argv[i]); /* Îïðåäåëÿåì ñòàðòîâûé àäðåñ òðåêà */ start_lba = read_track_info(); printf("Start LBA for track #%d - %u\n", i, start_lba); /* Çàïèñûâàåì òðåê íà äèñê è çàêðûâàåì òðåê */ total_sectors = write_audio("./track.wav", start_lba); if(total_sectors == 0) return -1; close_track(i); } /* Öèêë çàïèñè òðåêîâ çàâåðøèëñÿ, çàêðûâàåì ñåññèþ */ close_session(); /* Óäàëÿåì ôàéë track.wav è èçâëåêàåì äèñê èç ïðèâîäà */ unlink("./track.wav"); eject_cd();

}

close(sg_fd); return 0;

Преобразование файлов из формата MP3 в WAV выполняет функция mp3_decoder(). Входные параметры функции – имя файла формата MP3. На выходе получаем файл track.wav в формате WAV. Для конвертирования используется программа mpg321: void mp3_decoder(__u8 *file_name) { static pid_t pid; int status; switch(pid = fork()) { case -1: perror("fork"); exit(-1); case 0:

}

74

execl("/usr/bin/mpg321", "mpg321", "-q", ↵ "-w", "track.wav", file_name, 0); exit(-1);

}

if((pid = waitpid(pid, &status, 0)) && ↵ WIFEXITED(status)) return;

При записи WAV-файла необходимо отбросить его заголовок. В функции записи файла write_audio() после открытия файла необходимо сместиться к началу аудиоданных при помощи вызова: lseek(in_f, WAV_HEADER_SIZE, 0)

где WAV_HEADER_SIZE = 44 – размер заголовка WAV-файла. Полный текст программы создания аудиодиска из файлов формата MP3 находится в файле SG/mp2cd_inv_track.c. Следующий фрагмент программы выполняет запись треков, и стартовый адрес мы вычисляем самостоятельно: total_sectors = 0; /* Öèêë çàïèñè òðåêîâ */ for(i = 1; i < argc; i++) { printf("\nWriting track #%d:\n", i); /* Îïðåäåëÿåì ñòàðòîâûé àäðåñ òðåêà è çàïèñûâàåì òðåê * íà äèñê. Ïîñëå ýòîãî çàêðûâàåì òðåê */ // ñòàðòîâûé àäðåñ òðåêà if(i > 1) start_lba = total_sectors + apl + 2; printf("Start sector - %u\n", start_lba); total_sectors = write_audio(argv[i], start_lba); if(total_sectors == 0) return -1; }

close_track(i);

Стартовый адрес первого трека нам известен – он равен нулю. Адрес нового трека вычисляется по формуле: start_lba = total_sectors + apl + 2

где total_sector – общее число секторов, записанных на диск, apl – длина аудиопаузы, значение поля Audio Pause Length (APL) страницы параметров режима записи (рис. 15 первой части статьи). Значение APL хранится в поле apl структуры wpm, и определяется следующим образом: mode_sense(); apl = __swab16(wpm->apl);

В файле SG/write_audio.c находится полный текст программы, выполняющей запись WAV-файлов на аудиокомпакт. Стартовый адрес трека вычисляется вышеприведенным способом. А теперь давайте сотрем с диска все, что мы на него записали. Для стирания информации с диска используется команда BLANK. Формат этой команды приведен на рис. 8. Поле Blanking type устанавливает режим очистки диска. Может принимать следующие значения: ! 000b – стирается вся информация, находящаяся на диске. Значение поля Start Address игнорируется. ! 001b – минимальная очистка диска. Стирается PMA, Lead-In-область диска и pre-gap-область первого трека. Параметр Start Address игнорируется.


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

Ðèñóíîê 8. Ôîðìàò êîìàíäû BLANK

Остальные значения поля Blanking type и их описание приведены в спецификации [1], табл. 219 «Blanking Types CD-RW and DDCD-RW». Функция blank() выполняет очистку CD-RW-диска. Параметр функции blank_type устанавливает режим очистки диска. Допустимые значения этого параметра – 0 или 1: int blank(__u8 blank_type) { __u8 blank_cmd[12]; if(test_unit_ready() < 0) exit(-1); memset(blank_cmd, 0, 12); blank_cmd[0] = 0xA1; // êîä êîìàíäû BLANK // ðåæèì î÷èñòêè: 0 – ïîëíàÿ, 1 – ìèíèìàëüíàÿ blank_cmd[1] = blank_type;

}

if(send_cmd(blank_cmd, 12, SG_DXFER_NONE, ↵ NULL, 0, 9600*1000) < 0) return -1; return 0;

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

и завершает работу. Здесь Sense Key = 0x06, ASC = 0x28, ASCQ = 0x00 (см. [3, 5]), что означает «UNIT ATTENTION. Indicates that the removable medium may have been changed or the ATAPI CD-ROM Drive has been reset. NOT READY TO READY TRANSITION, MEDIUM MAY HAVE CHANGED» (Носитель был заменен или выполнен сброс ATAPI-контроллера). При повторном запуске программа выполняется без ошибок.

Литература и ссылки: 1. Спецификация SCSI Multimedia Commands-4 (SCSI MMC-4), http://www.t10.org/ftp/t10/drafts/mmc4/mmc4r03d.pdf. 2. Спецификация SCSI-3 Multimedia Commands, http:// www.t10.org/ftp/t10/drafts/mmc/mmc-r10a.pdf. 3. Specification for ATAPI DVD Devices, ftp.seagate.com/sff/ INF-8090.pdf. 4. SCSI-Generic-HOWTO, http://www.linux.org/docs/ldp/ howto/SCSI-Generic-HOWTO/index.html. 5. Мешков В. «Пакетные команды интерфейса ATAPI» – Журнал «Системный администратор», № 9, сентябрь 2004 г. – 70-84 с.

75


образование

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

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

КРИС КАСПЕРСКИ Атрибуты Структурно всякий атрибут состоит из заголовка (attribute header) и тела (attribute body). Заголовок атрибута всегда хранится в файловой записи, расположенной внутри MFT

76

(см. первую часть статьи, «Файловые записи»). Тела резидентных атрибутов хранятся там же. Нерезидентные атрибуты хранят свое тело вне MFT, в одном или нескольких кластерах, перечисленных в заголовке данного атрибута в


образование специальном списке (см. «Списки отрезков»). Если 8-разрядное поле, расположенное по смещению 08h байт от начала атрибутного заголовка, равно нулю, атрибут считается резидентным, а если единице – то нет. Любые другие значения недопустимы. Первые четыре байта атрибутного заголовка определяют его тип. Тип атрибута в свою очередь определяет формат представления тела атрибута. В частности, тело атрибута данных (тип: 80h – $DATA) представляет собой «сырую» последовательность байт. Тело атрибута стандартной информации (тип: 10h – $STANDARD_INFORMATION) описывает время его создания, права доступа и т. д. Подробнее см. «Типы атрибутов». Следующие четыре байта заголовка содержат длину атрибута, выражаемую в байтах. Длина нерезидентного атрибута равна сумме длин его тела и заголовка, а длина резидентного атрибута равна длине его заголовка. Короче говоря, если к смещению атрибута добавить его длину, мы получим указатель на следующий атрибут (или маркер конца, если текущий атрибут – последний в цепочке). Длина тела резидентных атрибутов, выраженная в байтах, хранится в 32-разрядном поле, расположенном по смещению 10h байт от начала атрибутного заголовка. 16-разрядное поле, следующее за его концом, хранит смещение резидентного тела, отсчитываемое от начала атрибутного заголовка. С нерезидентными атрибутами в этом плане все намного сложнее и для хранения длины их тела используется множество полей. Реальный размер тела атрибута (real size of attribute), выраженный в байтах, хранится в 64-разрядном (!) поле, находящемся по смещению 30h байт от начала атрибутного заголовка. Следующее за ним 64-разрядное поле хранит инициализированный размер потока (initialized data size of the stream), выраженный в байтах и, судя по всему, всегда равный реальному размеру тела атрибута. 64-разрядное поле, расположенное по смещению 28h байт от начала атрибутного заголовка, хранит выделенный размер (allocated size of attribute), выраженный в байтах и равный реальному размеру тела атрибута, округленному до размера кластера (в большую сторону). Два 64-разрядных поля, расположенные по смещению 10h и 18h байт от начала атрибутного заголовка, задают первый (starting VCN) и последний (last VCN) номер виртуального кластера, принадлежащего телу нерезидентного атрибута. Виртуальные кластеры представляют собой логические номера кластеров, не зависящие от своего физического расположения на диске. В подавляющем большинстве случав номер первого кластера тела нерезидентного атрибута равен нулю, а последний – количеству кластеров, занятых телом атрибута, уменьшенном на единицу. 16-разрядное поле, расположенное по смещению 20h от начала атрибутного заголовка, содержит указатель на массив Data Runs, расположенный внутри этого заголовка и описывающий логический порядок размещения нерезидентного тела атрибута на диске (подробнее см. «Списки отрезков»). Каждый атрибут имеет свой собственный идентификатор (attribute ID), уникальный для данной файловой записи и хранящийся в 16-разрядном поле, расположенном по смещению 0Eh от начала атрибутного заголовка.

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

Если атрибут имеет имя (attribute Name), то 16-разрядное поле, расположенное по смещению 0Ah байт от атрибутного заголовка, содержит указатель на него. Для безымянных атрибутов оно равно нулю (а большинство атрибутов безымянны!). Имя атрибута хранится в атрибутном заголовке в формате UNICODE, а его длина определяется 8разрядным полем, расположенным по смещению 09h байт от начала атрибутного заголовка. Если тело атрибута сжато, зашифровано или разряжено, 16-разрядное поле флагов, расположенное по смещению 0Ch байт от начала атрибутного заголовка, не равно нулю. Остальные поля не играют сколь-нибудь существенной роли и потому здесь не рассматриваются. Òàáëèöà 1. Ñòðóêòóðà ðåçèäåíòíîãî àòðèáóòà

Òàáëèöà 2. Ñòðóêòóðà íåðåçèäåíòíîãî àòðèáóòà

Типы атрибутов NTFS поддерживает большее количество предопределенных типов атрибутов, перечисленных в таблице 3. Как уже говорилось выше, тип атрибута определяет его назначение и формат представления тела. Полное описание всех атрибутов заняло бы очень много места и поэтому здесь приводятся лишь наиболее «ходовые» из них, а за информацией об остальных обращайтесь к Linux-NTFS Project.

77


образование Òàáëèöà 3. Îñíîâíûå òèïû àòðèáóòîâ

! файл содержит много альтернативных имен или жестких ссылок;

! файл очень сильно фрагментирован; ! файл содержит очень сложный дескриптор безопасности;

! файл имеет очень много потоков данных (т.е. атрибутов типа $DATA). Структура атрибута списка атрибутов приведена ниже: Òàáëèöà 5. Ñòðóêòóðà àòðèáóòà $ATTRIBUTE_LIST

Атрибут стандартной информации $STANDARD_INFORMATION Атрибут стандартной информации описывает время создания/изменения/последнего доступа к файлу и права доступа, а также некоторую другую вспомогательную информацию (например, квоты): Òàáëèöà 4. Ñòðóêòóðà àòðèáóòà $STANDARD_INFORMATION

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

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

Атрибут списка атрибутов $ATTRIBUTE_LIST Атрибут списка атрибутов (получился каламбур) используется в тех случаях, когда все атрибуты файла не умещаются в базовой файловой записи и файловая система вынуждена располагать их в расширенных. Индексы расширенных файловых записей содержатся в атрибуте списка атрибутов, помещаемом в базовую файловую запись. При каких обстоятельствах атрибуты не умещаются в одной файловой записи? Это может произойти, когда:

78

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


образование дить байты в нибблы и наоборот. Младший ниббл равен (X & 15), а старший – (X / 16). Легко видеть, что младший ниббл соответствует младшему шестнадцатеричному разряду байта, а старший – старшему. Например, 69h состоит из двух нибблов – младший равен 9h, а старший – 6h. Список отрезков представляет собой массив структур, каждая из которых описывает характеристики «своего» отрезка, а в конце списка находится завершающий нуль. Первый байт структуры состоит из двух полубайт: младший задает длину поля начального кластера отрезка (условно обозначаемого буквой F), старший – количество кластеров в отрезке (L). Поле длины отрезка идет следом. В зависимости от значения L оно может занимать от одного до восьми байт (более длинные поля недопустимы). Первый байт поля стартового кластера файла расположен по смещению 1 + L байт от начала структуры (что соответствует 2+2∗L нибблам). Кстати говоря, в документации Linux-NTFS Project (версия 0.4) поля размеров начального кластера и количества кластеров в отрезке перепутаны местами. Òàáëèöà 7. Ñòðóêòóðà îäíîãî ýëåìåíòà ñïèñêà îòðåçêîâ

Покажем, как с этим работать на практике. Допустим, мы имеем следующий run-list, соответствующий нормальному нефрагментированному файлу (что может быть проще!): «21 18 34 56 00». Попробуем его декодировать. Начнем с первого байта – 21h. Младший полубайт (01h) описывает размер поля длины отрезка, старший (02h) – размер поля начального кластера. Следующие несколько байт представляют поле длины отрезка, размер которого в данном случае равен одному байту – 18h. Два других байта (34h 56h) задают номер начального кластера отрезка. Нулевой байт на конце сигнализирует о том, что это последний отрезок в файле. Итак, наш файл состоит из одногоединственного отрезка, начинающегося с кластера 5634h и заканчивающегося кластером 5634h+ 18h == 564Ch. Рассмотрим более сложный пример фрагментированного файла со следующим списком отрезков: «31 38 73 25 34 32 14 01 E5 11 02 31 42 AA 00 03 00». Извлекаем первый байт – 31h. Один байт приходится на поле длины и три байта на поле начального кластера. Таким образом, первый отрезок (run 1) начинается с кластера 342573h и продолжается вплоть до кластера 342573h + 38 == 3425ABh. Чтобы найти смещение следующего отрезка в списке, мы складываем размер обоих полей с их начальным смещением: 3 + 1 == 4. Отсчитываем четыре байта от начала run-list и переходим к декодированию следующего отрезка: 32h – два байта на поле длины отрезка (равное в данном случае 0114h) и три байта на поле номера начального кластера (0211E5h). Следовательно, второй отрезок (run 2) начинается с кластера 0211E5h и продолжается вплоть до кластера 0211E5h + 114h == 212F9h. Третий отрезок (run 3): 31h – один байт на поле длины и три байта на поле начального кластера, равные 42h и 0300AAh соответственно. Поэтому третий отрезок (run 3) начинается с кластера 0300AAh и продолжается вплоть до кластера 0300AAh + 42h == 300ECh.

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

Завершающий нуль на конце run-list сигнализирует о том, что это последний отрезок в файле. Таким образом, подопытный файл состоит из трех отрезков, разбросанных по диску в следующем живописном порядке: 342573h – 3425ABh; 0211E5h – 212F9h; 0300AAh – 300ECh. Остается только прочитать его с диска! Начиная с версии 3.0, NTFS поддерживает разряженные (sparse) атрибуты, т.е. такие, которые не записывают на диск кластеры, содержащие одни нули. При этом поле номера начального кластера отрезка может быть равным нулю, что означает, что данному отрезку не выделен никакой кластер. Поле длины содержит количество кластеров, заполненных нулями. Их не нужно считывать с диска. Вы должны самостоятельно изготовить их в памяти. Кстати говоря, далеко не все дисковые доктора знают о существовании разряженных атрибутов (если атрибут разряжен его флаг равен 8000h), и интерпретируют нулевую длину поля номера начального кластера весьма странным образом. Последствия такого «лечения» обычно оказываются очень печальны.

Пространства имен (name spaces) NTFS изначально проектировалась как системно-независимая файловая система, способная работать со множеством различных подсистем, как то: Win32, MS-DOS, POSIX и т. д. Поскольку, каждая из них налагает свои собственные ограничения на набор символов, допустимых для использования в имени файла, NTFS вынуждена поддерживать несколько независимых пространств имен (name space).

POSIX Допустимы все UNICODE-символы (с учетом регистра), за исключением символа нуля (NULL), обратного слеша («/») и знака двоеточия («:»). Последнее, кстати говоря, не ограничение POSIX, а ограничение NTFS, использующей этот символ для доступа к именованным атрибутам. Максимально допустимая длина имени составляет 255 символов.

Win32 Доступны все UNICODE-символы (без учета регистра), за исключением следующего набора: «“» (кавычки), «*» (звездочка), «/» (прямой слеш), «:» (двоеточие), «<» (знак меньше), «>» (знак больше), «?» (вопросительный знак), «\» (обратный слеш), «|» (символ конвейера). К тому же, имя файла не может заканчиваться на точку или пробел. Максимально допустимая длина имени составляет 255 символов.

MS-DOS Доступны все символы пространства имен win32 (без учета регистра), за исключением: «+» (знак плюс), «,» (знак запятая), «.» (знак точка), «;» (точка с запятой), «=» (знак равно). Имя файла не должно превышать восьми символов за которыми следует необязательное расширение с длиной от одного до трех символов.

Назначение некоторых служебных файлов NTFS содержит большое количество служебных файлов (метафайлов) строго определенного формата, важнейший из которых – $MFT – мы только что рассмотрели. Осталь-

79


образование ные метафайлы играют вспомогательную роль и для восстановления данных знать их структуру, в общем-то, и необязательно. Тем не менее если они окажутся искажены, штатный драйвер файловой системы не сможет работать с таким томом, поэтому иметь некоторые представления о назначении каждого из них все же необходимо. У нас нет возможности рассказать о структуре всех метафайлов (да и незачем дублировать Linux-NTFS Project), поэтому эта информация здесь не приводится. Òàáëèöà 8. Íàçíà÷åíèå îñíîâíûõ ñòàíäàðòíûõ ôàéëîâ

Путешествие по NTFS Рассказ о NTFS был бы неполным без практической иллюстрации техники разбора файловой записи «руками». До сих пор мы витали в облаках теоретической абстракции. Пора спускаться на грешную землю. Воспользовавшись любым дисковым редактором, например, Disk Probe, попробуем декодировать одну файловую запись вручную. Найдем сектор, содержащий сигнатуру «FILE» в его начале (не обязательно брать первый встретившийся сектор). Он может выглядеть, например, так: Ëèñòèíã 1. Ðó÷íîå äåêîäèðîâàíèå ôàéëîâîé çàïèñè (ðàçíûå àòðèáóòû âûäåëåíû ðàçíûì öâåòîì)

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

80

содержимое последовательности обновления. По смещению 04h от начала сектора лежит 16-разрядный указатель на нее, равный в данном случае 2Ah (значит, это NTFS 3.0 или младше). А что у нас лежит по смещению 2Ah? Пара байт 03 00. Это номер последовательности обновления. Сверяем его с содержимым двух последних байт этого и следующего секторов (смещения 1FEh и 3FEh соответственно). Они равны! Значит, данная файловая запись цела (по крайней мере внешне) и можно переходить к операции спасения. По смещению 2Ch расположен массив, содержащий оригинальные значения последовательности обновления. Количество элементов в нем равно содержимому 16-разрядного поля, расположенному по смещению 06h от начала сектора и уменьшенного на единицу (т.е. в данном случае 03h – 01h == 02h). Извлекаем два слова начиная со смещения 2Ch (в данном случае они равны 00 00 и 00 00) и записываем их в конец первого и последнего секторов. Теперь нам необходимо выяснить – используется ли данная файловая запись или ассоциированный с ней файл/каталог был удален. 16-разрядное поле, расположенное по смещению 16h, содержит значение 01h. Следовательно, перед нами файл, а не каталог, и этот файл еще не удален. Но является ли данная файловая запись базовой для данного файла или мы имеем дело с ее продолжением? 64разрядное поле, расположенное по смещению 20h, равно нулю, следовательно, данная файловая запись – базовая. Переходим к исследованию атрибутов. 16-разрядное поле, находящееся по смещению 14h равно 30h, следовательно, заголовок первого атрибута начинается со смещения 30h от начала сектора. Первое двойное слово атрибута равно 10h, значит, перед нами атрибут типа $STANDARD_INFORMATION. 32-разрядное поле длины атрибута, находящееся по смещению 04h и равное в данном случае 60h байт, позволяет нам вычислить смещение следующего атрибута в списке – 30h (смещение нашего атрибута) + 60h (его длина) == 90h (смещение следующего атрибута). Первое двойное слово следующего атрибута равно 30h, значит, это атрибут типа $NAME и следующее 32-разрядное поле хранит его длину, равную в данном случае 70h. Сложив длину атрибута с его смещением, мы получим смещение следующего атрибута – 90h + 70h == 100h. Первое двойное слово третьего атрибута равно 80h, следовательно, это атрибут типа $DATA, хранящий основные данные файла. Складываем его смешение с длиной – 100h + 32h == 132h. Мы наткнулись на частокол FFFFFFh, сигнализирующий о том, что атрибут $DATA последний в списке. Теперь, разбив файловую запись на атрибуты, приступить к исследованию каждого из атрибутов в отдельности. Начнем с имени. 8-разрядное поле, находящееся по смещению 08h от начала атрибутного заголовка (и по смещению 98h от начала сектора), содержит флаг нерезидентности, который в данном случае равен нулю (т.е. атрибут резидентный и его тело хранится непосредственно в самой файловой записи). 16-разрядное поле, расположенное по смещению 0Ch от начала атрибутного заголовка (и по смещению 9Ch от начала сектора) равно нулю, следовательно тело атрибута не сжато и не зашифровано. 32-разрядное поле, расположенное по смещению 10h от начала атрибут-


образование ного заголовка и по смещению A0h от начала сектора, содержит длину атрибутного тела, равную в данном случае 54h байт, а 16-разрядное поле, расположенное по смещению 14h от начала атрибутного заголовка и по смещению A4h от начала сектора, хранит смещение атрибутного тела, равное в данном случае 18h, следовательно, тело атрибута $NAME располагается по смещению A8h от начала сектора. Формат атрибута типа $NAME описан в таблице XX. Первые восемь байт содержат ссылку на материнский каталог данного файла, равную в данном случае 11ADBh:01 (индекс – 11ADBh, номер последовательности – 01h). Следующие 32-байта содержат штаммы времени создания, изменения и времени последнего доступа к файлу. По смещению 28h от начала тела атрибута и D0h от начала сектора лежит 64-разрядное поле выделенного размера, а за ним – 64-разрядное поле реального размера. Оба равны нулю, что означает, что за размером файла следует обращаться к атрибутам типа $DATA. Длина имени файла содержится в 8-разрядном поле, находящемся по смещению 40h байт от начала тела атрибута и по смещению E8h от начала сектора. В данном случае оно равно 09h. Само же имя начинается со смещения 42h от начала тела атрибута и со смещения EAh от начала сектора. И здесь находится Ilfak.dbx. Переходим к атрибуту основных данных файла, пропустив атрибут стандартной информации, который не содержит решительно ничего интересного. 8-разрядный флаг нерезидентности, расположенный по смещению 08h от начала атрибутного заголовка и по смещению 108h от начала сектора, равен 01h, следовательно атрибут нерезидентный. 16-разрядный флаг, расположенный по смещению 0Ch от начала атрибутного заголовка и по смещению 10Сh от начала сектора, равен нулю, значит, атрибут не сжат и не зашифрован. 8-разрядное поле, расположенное по смещению

09h от начала атрибутного заголовка и по смещению 109h от начала сектора, равно нулю – атрибут безымянный. Реальная длина тела атрибута (в байтах) содержится в 64разрядном поле, расположенном по смещению 30h от начала атрибутного заголовка и по смещению 130h от начала сектора. В данном случае она равна 4ED1F0h (5.165.552). Два 64-разрядных поля, расположенных по смещениям 10h/ 110h и 18h/118h байт от начала атрибутного заголовка/сектора соответственно, содержат начальный и конечный номер виртуального кластера неризидентного тела. В данном случае они равны: 0000h/4EDh. Остается лишь декодировать список отрезков, адрес которого хранится в 16-разрядном поле, находящемся по смещению 20h от начала атрибутного заголовка и 120h от начала сектора. В данном случае оно равно 40h, что соответствует смещению от начала сектора в 140h. Сам же список отрезков выглядит так: 32 EE 04 D9 91 00 00. Два байта занимает поле длины (равное в данном случае 04EEh кластерам) и три – поле начального кластера (0091h). Завершающий ноль на конце говорит о том, что этот отрезок последний в списке отрезков. Подытожим полученную информацию. Файл называется Ilfak.dbx, он начинается с кластера 0091h и продолжается вплоть до кластера 57Fh, при реальной длине файла в 5 165 552 байт. За сим все! Теперь уже ничего не стоит скопировать файл на резервный носитель (например, ZIP или стример).

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

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

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

81


образование

РАЗРАБОТКА СЦЕНАРИЯ РЕГИСТРАЦИИ ПОЛЬЗОВАТЕЛЕЙ В СЕТИ ЧАСТЬ ЧАСТЬ 2

ИВАН КОРОБКО В первой части статьи1 я начал рассказывать о создании скрипта, который позволит упростить и автоматизировать различные процессы. В ней шел разговор о структуре скрипта и были описаны основополагающие моменты, как осуществляется сбор различной информации о рабочей станции и пользователях. Итак, продолжим.

Автоматическое подключение сетевых ресурсов К сетевым ресурсам относятся сетевые принтеры и диски. Рассмотрим подробнее каждый из них.

Подключение сетевых принтеров. Теория Соглашение об именах Имя должно содержать как можно больше информации о принтере, при этом быть удобным для использования. На рабочих станциях под управлением операционной системы Windows пользователь имеет дело с двумя именами – непосредственное и сетевое имена принтера. Чаще всего имя, назначаемое принтеру, представляет собой реальное имя принтера с порядковым номером, если есть несколько принтеров одинаковой модели, например, HP LaserJet 1200 (1), HP LaserJet 2300 (2). Такой способ именования рекомендуется использовать в небольших организациях. В крупных корпорациях принцип именования принтеров может быть другим. Сетевое имя, как отмечено ранее, должно быть более коротким, но при этом не должно терять смысловой нагрузки. Оно чаще всего представляет собой общую характеристику принтера, например, HP1200_1, HP2300_2.

Предварительная настройка принтера и AD Работа сценария строится на анализе и обработке данных, содержащихся в Active Directory и пользовательском реестре. На основе полученных данных осуществляется подключение и отключение принтера в зависимости от членства пользователя в соответствующих группах безопасности. Для обеспечения работоспособности сценария необходимо выполнение нескольких условий: Первое условие – названия принтеров, групп безопасности должны удовлетворять соглашению об именах. 1

82

Второе – сетевые принтеры, подключением и отключением которых должен управлять скрипт, должны быть опубликованы в Active Directory. Третье – названия групп безопасности должны строиться в соответствии со следующим шаблоном: название одной из групп, члены которой могут только выводить задания на печать, образуется добавлением к сетевому имени принтера через дефис слова Print, например, «HP2300_1 – Print». Название другой группы строится аналогично, с той разницей, что слово «Print» заменяют на словосочетание «Print Managers». Члены этой группы могут управлять очередью печати и принтером. Таким образом, принтеру с сетевым именем «HP1200_1», соответствуют следующие названия групп: имя первой группы «HP1200_1 – Print», второй «HP1200_1 – Print Managers».

Ðèñóíîê 1

Четвертое – должны быть определены параметры безопасности принтера. В свойствах принтера (см. рис. 2) на сервере печати во вкладке «Security» (безопасность) должна быть удалена группа «Everyone» (в противном случае скрипт будет подключать этот принтер всем пользователям сети) и добавлены две группы безопасности, соответствующие данному принтеру: «HP1200_1 – Print» и «HP1200_1 – Print Managers». Для группы «HP1200_1 – Print» должен быть установлен в разделе «Permissions» (разрешения) флажок напротив свойства «Print» (см. рис. 2), а для группы «HP1200_1 – Print Managers» – флажки напротив «Print»

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


образование (печать) и «Manage Documents» (управление документами). Ставить флажок напротив «Manage Printers» не рекомендуется, поскольку управление принтерами подразумевает возможность изменять настройки принтера, удалять его. По мнению автора, такими привилегиями может обладать только системный администратор.

Ðèñóíîê 2

SELECT ïîëå_1, ïîëå_2, …, ïîëå_n FROM ↵ “LDAP://dc=äîìåí_1,dc=äîìåí_2…,domen_n” ↵ WHERE objectClass=’òèï_îáúåêòà’

В SELECT указываются поля, по которым идет выборка. Поля перечисляются через запятую, «пробелы» после запятой обязательны. Полный список полей объектов AD можно получить с помощью утилиты ADSI Edit, которая размещается в дистрибутиве Microsoft Windows 2000 в директории /Support/Tools (см. статью «Программное управление ADSI: LDAP», журнал «Системный администратор», №3, март 2004г.). В FROM указывается путь к объекту. В данном случае известен только домен. При описании данного раздела пробелы не допускаются. В WHERE указывается тип объекта, к которому адресован запрос. Данное поле является фильтром. Провайдер LDAP поддерживает несколько типов объектов, которые в запросе SQL определяются переменной objectClass: Print Queue – массив принтеров, опубликованных в AD; Group – группы, созданные в AD; User – пользователи, созданные в AD; Computer – массив компьютеров, зарегистрированных в AD. Пример использования запроса SQL см. в следующем разделе.

Подключение сетевых принтеров. Практика Итак, работа сценария строится на анализе данных, содержащихся в Active Directory и пользовательском реестре. Его работу можно разбить на три этапа. На первом этапе формируется список принтеров, которые должны быть подключены к пользователю. На втором этапе – список сетевых принтеров, уже установленных на рабочей станции пользователя. Наконец, на третьем – осуществляется приведение этих списков в соответствие.

Формирование списка принтеров, которые необходимо подключить пользователю Определение имени текущего домена С помощью функции GetObject() осуществляется чтение корня пространства имен, в данном случае определяется имя текущего домена. Пример определения текущего домена: $rootDSE_ = GetObject("LDAP://RootDSE") $domain_ = "LDAP://" + $rootDSE_.Get("defaultNamingContext")

Переменная domain_ имеет вид «dc=microsoft,dc=com», если домен «microsoft.com». Имя текущего домена, полученного провайдером WinNT, нельзя использовать, поскольку с его помощью можно получить только сокращенное имя домена (в данном случае «microsoft»). Если все же указано сокращенное имя домена в строке с SQL-запросом, то при выполнении скрипта произойдет ошибка. В сообщении о ней будет сказано, что по указанному пути база не обнаружена, поэтому установить соединение невозможно.

Построение запроса SQL Запрос SQL используется для осуществления процедуры поиска объектов, при заданном типе объекта. В общем случае он выглядит следующим образом:

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

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

83


образование $shares_enum & chr(13) & "Îïèñàíèå: " & $description_enum. MessageBox($temp,"Õàðàêòåðèñòèêè ïðèíòåðà",0,0) $temp="" Until $st.EOF

В Active Directory объектом класса printQueue является принтер. Этот объект имеет свойства, значение которых может быть двух типов: строкой и массивом. В приведенном примере поле, содержащее название принтера, является строковой переменной, а сетевое имя принтера – массивом. Ниже приведена таблица, содержащая названия и описания часто используемых полей, соответствующий им тип и формат данных: Òàáëèöà 1

Формирование массива Идея, лежащая в основе механизма подключения принтеров, следующая: осуществляется попытка подключить принтер, затем сценарий загрузки «смотрит», что из этого получилось, и в зависимости от результата предпринимает действия. При объяснении работы этого механизма (для облегчения восприятия материала) я намеренно поменял местами причину и следствие. После того как в Active Directory найден очередной опубликованный принтер и прочитаны его свойства, для него формируется UNC-путь (\\server\sharename). Затем осуществляется попытка подключить пользователю принтер и считывать код функции, производящей подключение. Если функция подключения возвращает код ошибки 0 (подключение к принтеру прошло успешно), то пользователь является членом одной из двух групп безопасности, перечисленных в свойствах принтера на сервере печати. Для тех принтеров, на которые пользователь имеет право печатать (как минимум), формируется массив, например, $access_array[$i]. Формат элементов массива следующий: «,,server,printername», где server – короткое имя сервера, printername – локальное имя принтера.

Ðèñóíîê 3

84

$path_enum_connect = "\\" + $server_enum + "\" + $shares_enum $connect_flag = addprinterconnection( $path_enum_connect ) if $connect_flag=0 $path_full =",," + $server_enum + "," + $name_enum $print_sysinfo=$print_sysinfo+$shares_enum+": ↵ "+$description_enum+chr(13) $access_array[$i] = lcase($path_full) $i=$i+1 Endif

Формирование списка сетевых принтеров, подключенных пользователю Процесс определения подключенных пользователю сетевых принтеров основан на анализе ветви HKCU локального реестра (см. рис. 3). С помощью функции ENUM осуществляется чтение названий папок, содержащих в себе короткое имя сервера и полное имя принтера. На основе полученной информации формируется массив, элементами которого являются строки, имеющие следующий формат: «,,server,printername», где server – короткое имя сервера, printername – локальное имя принтера. Для удобства сравнения обоих массивов (подключенных принтеров и принтеров, на которые пользователь имеет права) необходимо, чтобы форматы элементов массивов совпадали. Формат элементов продиктован особенностью построения реестра Windows 2000. $Index=0 DO $connected_array[$index]= lcase(ENUMKEY("HKEY_CURRENT_USER\ ↵ Printers\Connections\", $Index)) $Index = $Index + 1 UNTIL Len($Group) =0

Необходимо отметить, что после формирования второго массива между ними соблюдаются следующее неравен≥М1, где М2 – массив, элементами которого являство: М2≥ ются названия подключенных принтеров, M1 – принтеров, на которые пользователь имеет права. На третьем, заключительном этапе добиваются выполнения следующего условия: М1=М2.

Приведение созданных списков принтеров в соответствие Сопоставление массивов М1 и М2 осуществляется с помощью функции ASCAN. В том случае, если функция возвращает значение -1, то элемент, найденный в одном массиве,


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

Удаление принтера осуществляется с помощью соответствующей функции, параметром которой является UNC-путь принтера. Для того чтобы сформировать этот путь, осуществляется анализ ветви HKLM (см. рис. 4): if $flag_p=-1 $group=$connected_array[$i] $name_=right($group, len($group)-instrrev($group,",")) $server_=right(left($group,len($group)-len($name_)-1), ↵ len(left($group,len($group)-len($name_)-1))-2) $share_=readvalue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ ↵ Windows NT\CurrentVersion\Print\Providers\ ↵ LanMan Print Services\Servers\"+$server_+"\Printers\ ↵ "+$name_,"Share Name") $disconnect_ ="\\"+$server_+"\"+$share_ $r=DelPrinterConnection( $disconnect_ ) endif

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

дет монтироваться ресурс и его порядковый номер. Он присваивается для обеспечения возможности подключать на одну и ту же букву разные ресурсы. Каждый раздел содержит пять параметров: название сервера (SERVER), путь к сетевой папке (SHARE), группы безопасности, членам которых будет подключаться ресурс (ACCESSGROUP1 и ACCESSGROUP2), описание ресурса (DESCRIPTION). Пример файла приведен ниже: [L1] SERVER=Main SHARE=Consultant ACCESSGROUP1=everyone ACCESSGROUP2=Âñå DESCRIPTION="Êîíñóëüòàíò+" [W1] SERVER=Second SHARE=work\department1 ACCESSGROUP1=department1 ACCESSGROUP2=department3 DESCRIPTION="Ðåñóðñû îòäåëà 1" [W2] SERVER=Second SHARE=work\department2 ACCESSGROUP1=department2 ACCESSGROUP2= DESCRIPTION="Ðåñóðñû îòäåëà 2"

Таким образом, на основе данных, прочитанных сценарием из примера, всем пользователям будет подключен «Консультант+» на букву «L», находящийся по пути \\main\ consultant. Пользователям, являющимся членами групп departament1, departament2, departament3, будет подключен диск W. Для членов групп departament1, departament3 подключается ресурс по адресу \\second\work\departament1, для departament2 – \\second\work\departament2. Сценарий, обеспечивающий автоматическое управление подключением сетевых дисков, работает по схеме: ! Чистка локального кэша на рабочей станции, содержащего список групп, в которые входит пользователь. Удаление ветви реестра HKEY_CURRENT_USER\Software\ KiXtart.

Ðèñóíîê 4

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

85


образование ! Чтение параметрического файла. Данные рекомендуется помещать в соответствующие массивы. ! Отключение всех доступных сетевых дисков. ! Подключение сетевых дисков, на которые данный пользователь имеет права. ! Вывод на экран статистики о подключенных сетевых дисках.

ку группы, содержащие это сочетание символов, предназначены для управления принтерами и не принимают участия в процессе подключения сетевых дисков. dim $usergroup_name[] $k=0 DO $Group = ENUMGROUP($i) if instr("$Group","- Print")=0 $ug1_len=len($group)-instrrev($group,"\") ReDim Preserve $usergroup_name[$k] $usergroup_name[$k]=right($group,"$ug1_len") $u_val=$usergroup_name[$k] $k=$k+1 endif $i=$i+1 UNTIL Len($Group) = 0

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

Подключение сетевых дисков. Практика В теоретической части был описан алгоритм, обеспечивающий автоматическое управление подключением сетевых дисков. Поскольку все этапы взаимосвязаны, то их необходимо рассматривать как единое целое. Итак, сначала осуществляется чистка локального кэша на рабочей станции, содержащего список групп, в которые входит пользователь. Эту процедуру рекомендуется вынести в самое начало сценария загрузки, чтобы его работа начиналась именно с очистки кэша. Процедура удаления осуществляется с помощью функции DelTree(): DelTree("HKEY_CURRENT_USER\Software\KiXtart")

Затем рекомендуется создать и наполнить данными динамический массив. Элементами этого массива являются названия групп, в которые входит пользователь. В синтаксисе языка KIXTart существует специально созданная функция – EnumGroup(): DO

$Group = ENUMGROUP($i) ? $Group $i = $i + 1 UNTIL Len($Group) = 0

Переменная $Group содержит полное название группы. Формат названия группы следующий: \\domain\group_name. Для подключения различных ресурсов необходимо вычленить имя группы без префикса в виде имени домена или рабочей станции. Попутно необходимо исключить группы, в названиях которых присутствует слово «- print», посколь-

86

$i=1 dim $gr[] open(2,"@LDRIVE/shared.ini",2) ; ôàéë shared.ini ↵ ðàñïîëàãàåòñÿ â îäíîì êàòàëîãå ñî ñêðèïòîì –\\Server\Netlogon WHILE @ERROR = 0 $x=ReadLine(2) $skoba=instrrev("$x","[") if $skoba<>0 ReDim Preserve $gr[$i] $gr[$i]=right(left($x,len("$x")-1), ↵ len(left($x,len("$x")-1))-1) $i = $i + 1 endif LOOP

После того как сформирован массив, осуществляется повторное чтение INI-файла. На этот раз он рассматривается как параметрический файл. Осуществляется чтение параметров. По ходу чтения параметрического диска сначала осуществляется попытка отключить сетевой диск, затем подключить его, если пользователь входит в соответствующую группу безопасности. Таким образом, соблюдается актуальность подключенных сетевых дисков. $k=ubound($gr) for $i=1 to $k $letter=$gr[$i] $serv=readprofilestring("$ini_file1", "$letter","server") $share=readprofilestring("$ini_file1", "$letter","share") $accessgroup1=readprofilestring("$ini_file1", ↵ "$letter","accessgroup1") $accessgroup2=readprofilestring("$ini_file1", ↵ "$letter","accessgroup2") $description=readprofilestring("$ini_file1", ↵ "$letter","description") $share_name="\\"+$serv+"\"+$share+"" $let=$letter+":" $letter_S=left($letter,1) use $letter_S /delete if ingroup("$accessgroup1","$accessgroup2") use $letter_S+":" $share_name


образование endif next

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

Автоматическое конфигурирование рабочей станции Поскольку скрипт выполняется от имени пользователя, который не обладает правами системного администратора, то изменения могут быть внесены только в ветвь HKCU. В этом разделе хранятся сведения о текущем зарегистрированном пользователе, и он имеет название, соответствующее значению идентификатора безопасности (SID) текущего пользователя. Каждый раз при перезагрузке компьютера раздел создается заново на основе данных, считанных из HKU. Автоматическое конфигурирование ветви HKU выполняется с помощью групповых политик (будет рассмотрено позже), а ветви HKCU – с помощью скрипта. В качестве примера приведем таблицу, в которой описаны некоторые ключи и соответствующие им параметры, которые можно изменять на всех рабочих станциях домена каждый раз во время регистрации пользователей в сети с помощью скрипта. Приведенный список краток. В печати и в Интернете читатель сможет найти множество советов по настройке реестра. Òàáëèöà 2

лючив сбойный блок. Согласитесь, это гораздо лучше, чем иметь только 2 варианта, характеризующих работоспособность – 0% и 100%. Реализация идеи следующая: из конфигурационного файла (см. пример файла kix.ini) считываются параметры, которые имеют значение 0 (выключено) и 1 (включено): Пример файла kix.ini: [part] print=1 share=1 sysinfo=1

В таком случае структура скрипта будет выглядеть следующим образом: $config_ini ="@LDRIVE/kix.ini"; ôàéë kix.ini ðàñïîëàãàåòñÿ ↵ â îäíîì êàòàëîãå ñî ñêðèïòîì - \\Server\Netlogon open(1, $config_ini, 2) ………………………………; îïèñûâàþòñÿ ðàçëè÷íûå ãëîáàëüíûå ↵ ïåðåìåííûå, îñóùåñòâëÿåòñÿ ñîåäèíåíèå ñ AD è äð. if readprofilestring("$config_ini","part","sysinfo")=1 ……………………………… Endif if readprofilestring("$config_ini","part"," share ")=1 ……………………………… Endif if readprofilestring("$config_ini","part"," print ")=1 ……………………………… Endif

Таким образом, если необходимо протестировать какуюлибо новую функцию сценария, можно создать еще один раздел, например, «test», и размещать в нем тестируемый код.

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

Блочность скрипта

Выбор варианта

Согласитесь, что скрипт – это программа, которая должна отличаться стабильностью в своей работе. А разве это не обязательно для всех без исключения программ? С другой стороны, используя его на практике, могу сказать, что в нем постоянно что-то изменяется и никто не застрахован от ошибки. Тестирование на локальной машине и в сети, как говорят, две большие разницы. В данной статье рассмотрены только основные задачи, реально их гораздо больше, например, в крупных организациях может быть актуально автоматизированное подключение баз 1с в бухгалтерии и т. д. Поэтому правильным шагом будет создать конфигурационный файл для этого скрипта, который бы позволил оперативно управлять включением и выключением различных блоков. В случае внештатной ситуации вы сможете сохранить работоспособность скрипта на 70-90%, вык-

Рассмотрим все три способа:

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

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

Визуализация скрипта с помощью сторонней надстройки KIXTart в виде DLL-библиотеки Визуализация и интерактивность работы скрипта реализуется с помощью специально созданной для этих целей надстройки – KIXForms 3.2 или KIXGui 1.1. Обе программы можно загрузить с сайта http://www.kixtart.org.

87


образование У этих программ есть только один недостаток: для корректной работы визуализационной части необходимо на рабочей станции зарегистрировать соответствующую DLLбиблиотеку. Для регистрации этой библиотеки необходимо обладать правами администратора. Конечно, можно создать MSI-архив, который будет централизованно распространяться по сети с помощью групповых политик, но это неудобно. Использовать надстройки такого рода выгодно только в небольших сетях с маленьким количеством рабочих станций.

DHTML возвращает в KIX код ошибки в виде целого числа, макросу @ERROR. В случае успешного завершения операции @ERROR=0. Передача данных с помощью утилиты KIXWIN осуществляется сценарием загрузки следующим образом:

Визуализация работы скрипта c помощью сторонней утилиты, передающей параметры из KIXTart в HTML-файл

DHTML-файл

Этот способ мне кажется наиболее оптимальным для реализации визуализации и интерактивности работы скрипта в крупных сетях, поскольку утилита самодостаточна и представляет собой файл с расширением EXE, который рекомендуется располагать в каталоге Netlogon, вместе со скриптом. KixWin 1.1 (http://www.kixtart.org) вызывается из скрипта с набором параметров. Затем она передает эти параметры в DHTML-файл. Для корректной работы визуализационной части необходимо дать ему право на запись в папке, в которой находится DHTML-файл. Раздробление скрипта на две части является основным недостатком данного варианта. DHTML-файл вместе с сопутствующими ему файлами (GIF, JPEG, CSS) рекомендуется располагать в скрытой сетевой папке. DHTML-файл содержит в себе сценарии, созданные с помощью VBScript или JScript.

Как отмечалось ранее, параметры передаются DHTML-странице, содержащей вставки на VBScript. При загрузке страницы в теге body указывается функция, например, onload=”startrun()”, с помощью которой запускается таймер. В том случае, если таймер не прерван, то по окончанию отсчета автоматическое закрывание окна и продолжения процесса загрузки компьютера:

Синтаксис KIXWin Приведем синтаксис утилиты и фрагмент DHTML-файла: kixwin "dialog" ["arguments"] ["options"]

Описание параметров:

! «dialog» – строка, содержащая строку в формате URL к HTML-документу.

! «arguments» – строка, содержащая параметры, передаваемые из KIX в HTML. Для разделения параметров в HTML-файле используют строку window.dialogArguments. split(«;»). В данном примере разделителем параметров является «;». ! «style» – строка, которая определяет оформление диалогового окна. Используются один или несколько из следующих параметров стиля: dialogHeight:sHeight dialogLeft:sXPos dialogTop:sYPos dialogWidth:sWidth center:{ yes | no | 1 | 0 | on | off } dialogHide:{ yes | no | 1 | 0 | on | off } edge:{ sunken | raised } help:{ yes | no | 1 | 0 | on | off } resizable:{ yes | no | 1 | 0 | on | off } scroll:{ yes | no | 1 | 0 | on | off } status:{ yes | no | 1 | 0 | on | off } unadorned:{ yes | no | 1 | 0 | on | off }

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

88

shell '%0/../kixwin.exe $html "$system_info ^ ↵ $hardware_info ^ Óñòàíîâëåííûå ïðîãðàììû: $en $prog ^ ↵ Ïîäêëþ÷åííûå ñåòåâûå äèñêè:$en $n1 ^ Ïîäêëþ÷åííûå ↵ ñåòåâûå ïðèíòåðû:$en $n2" "scroll:off;resizable:on"'

Основы формирования файла

<BODY onload="startrun()" TEXT="BLACK" …> ……………………………………………………… <Script Language="JavaScript"> function startrun() { window.form1.textarea1.value="Ïðîöåññ íàñòðîéêè êîìïüþòåðà ↵ çàâåðøåí.\nÄëÿ ïðîäîëæåíèÿ íàæìèòå êíîïêó ÏÐÎÄÎËÆÈÒÜ ↵ èëè ïîäîæäèòå 7ñåê. – îêíî çàêðîåòñÿ ñàìî." timer1=setTimeout('exit()', 20000); } … </Script> </BODY>

Как видно из примера, в текстовой области выводится сообщение о том, что настройка рабочей станции завершена и запускается таймер. Если ни одна кнопка на клавиатуре не нажималась в течение 20 000 мсек, то осуществляется вызов функции exit(), которая закрывает окно браузера (листинг DHTML-файла на www.samag.ru/source). Кнопки, при нажатии на которые отображается информация различного рода, представляют собой картинку с надписями на ней, которая разделена на различные области. При нажатии на описанные области осуществляется запуск соответствующей функции, которая, в свою очередь, отображает информацию, переданную из скрипта в текстовую область window.form1.textarea1: …… <img src="bar2.jpg" name="imgAdvert" usemap="#Prosv" border=0> <map name="Prosv"> <area onclick=system() alt="Ñâåäåíèÿ îá îïåðàöèîííîé ↵ ñèñòåìå" shape=circle coords="69,40,50"> <area onclick=hardware() alt="Ñâåäåíèÿ î êîìïüþòåðå" ↵ shape=circle coords="166,40,50"> …… </map> <Script Language="JavaScript"> …… function system() { clearTimeout(timer1); var argv; argv = window.dialogArguments.split("^"); document.all.parametr0 = argv[0];


образование window.form1.textarea1.value='' window.form1.textarea1.value=document.all.parametr0 } function hardware() { clearTimeout(timer1); var argv; argv = window.dialogArguments.split("^"); document.all.parametr1 = argv[1]; window.form1.textarea1.value='' window.form1.textarea1.value=document.all.parametr1 } …

Обратите внимание, что при вызове любой функции осуществляется прерывание таймера функцией clearTime out(timer1), затем чтение соответствующего аргумента.

Обеспечение удобства Для обеспечения удобства работы со сценарием необходимо изменить представление окна браузера: сделать его неизменяемым, убрать различные панели инструментов и т. д. (см. рис. 6). Для того чтобы информация выводилась корректно, необходимо в теге META указать кодировку, в которой должны быть отражены символы, а именно Windows-1251: <META http-equiv=Content-Type content="text/html; ↵ charset=windows-1251">

набора файлов, необходимых KIX для работы на данной платформе. А затем запускает скрипт. @ECHO OFF if c:\%os%==c:\ goto win9x if not c:\%os%==c:\ goto winnt :winnt start /wait Kix32.exe Script.kix goto kix :win9x copy %0\..\win9x\*.dll c:\windows\system /y %0\..\Kix32.exe %0\..\Script.kix goto kix :kix @echo End Of Batch File

Пояснения к синтаксису файла START.BAT:

! Принцип определения операционной системы основан на том, что в Win9x отсутствует переменная окружения %os%. В Windows 2k переменная %os%=WindowsNT. ! С помощью строки «start /wait Kix32.exe Script.kix» добиваются последовательной загрузки – сначала скрипт, затем рабочий стол и т. д., а не одновременной. То есть на время выполнения скрипта многозадачность «отключается». Это делается для того, чтобы до окончания действия скрипта дальнейшая загрузка операционной системы не производилась. ! Для корректной работы win9x, в качестве пути к файлу необходимо указывать «%0\..\filename.ext». Windows XP не воспринимает относительного пути «%0/./», поэтому для Windows семейства 2k необходимо указать только имя файла, который находится в папке Netlogon.

Ðèñóíîê 6

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

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

Ðèñóíîê 7

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

89


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

! Перейти во вкладку вкладку «Group Policy» и загрузить «Default Dоmain Policy» (см. рис. 9).

Ðèñóíîê 9

! В загруженной групповой политике (Default Domain Ðèñóíîê 8

В разделе групповой политики «User Configuration» необходимо соответственно включить «Run legacy logon script synhronously» (запускать сценарий загрузки синхронно) и «Run legasy script hidden» (запускать сценарий скрыто). Для этого необходимо проделать следующее: ! Зарегистрироваться на сервере с помощью учетной записи, имеющей административные права. ! Загрузить в Active Directory Users and Computers (Start → Programs → Administrative Tools) и войти в свойства контроллера домена (см. рис. 8).

Ðèñóíîê 10

90

Policy) необходимо в «User Configuration» (настройках пользователя) войти в «Administrative Templates» (административные шаблоны). Там выбрать раздел «System» (система), вкладку «logon/logoff» (войти/выйти) и включить раннее оговоренные политики (см. рис. 10). На этом создание полноценного сценария загрузки завершено. Необходимо отметить, что с введением такого продукта в эксплуатацию, затраты на поддержку значительно сокращаются. Надеюсь, что создание такого рода сценария принесет вам значительное облегчение в работе. Листинг скрипта и всех вспомогательных подпрограмм приведен на сайте журнала http://www.samag.ru/source.


bugtraq Раскрытие SMB-паролей в KDE Программа: KDE 3.2.x, 3.3.0, 3.3.1, and 3.3.2. Опасность: Средняя. Описание: Обнаружена уязвимость в KDE. Атакующий может получить пароль пользователя на доступ к удаленному ресурсу. Когда пользователь создает ссылку на удаленный файл, используя любое KDE-приложение, эта ссылка может содержать пароль на доступ к удаленному файлу. Пароль для SMB-ссылок всегда добавляется к URL в виде обычного текста и сохраняется в ярлыке («*.desktop»-файл). URL производителя: www.kde.org. Решение: Установите обновления. 1. Патчи для KDE 3.3.1 ftp://ftp.kde.org/pub/kde/security_patches: 501852d12f82aebe7eb73ec5d96c9e6d post-3.3.1-kdebasesmb.diff 5b9c1738f2de3f00533e376eb64c7137 post-3.3.1-kdelibskhtml.diff f287c900c637af2452c7a554f2df166f post-3.3.1-kdelibskio.diff 2. Патч для KDE 3.3.2 ftp://ftp.kde.org/pub/kde/security_patches: d3658e90acec6ff140463ed2fd0e7736 post-3.3.2-kdelibskio.diff 3. Патчи для KDE 3.2.3 ftp://ftp.kde.org/pub/kde/security_patches: d080d9acf4d2abc5f91ccec8fc463568 post-3.2.3-kdebasesmb.diff d79d1717b4bc0b3891bacaaf37deade0 post-3.2.3-kdelibskhtml.diff 94e76ec98cd58ce27cad8f886d241986 post-3.2.3-kdelibskio.diff

Переполнение буфера в Microsoft HyperTerminal Программа: Microsoft Windows 2000 Advanced Server, Microsoft Windows 2000 Datacenter Server, Microsoft Windows 2000 Server, Microsoft Windows NT 4.0 Server, Microsoft Windows NT 4.0 Server, Terminal Server Edition, Microsoft Windows Server 2003 Datacenter Edition, Microsoft Windows Server 2003 Enterprise Edition, Microsoft Windows Server 2003 Standard Edition, Microsoft Windows Server 2003 Web Edition, Microsoft Windows XP Home Edition, Microsoft Windows XP Professional. Опасность: Средняя. Описание: Обнаружена уязвимость в Microsoft HyperTerminal. Удаленный атакующий может выполнить произвольный код на уязвимой системе. Уязвимость обнаружена при обработке файлов сессий и telnet-ссылок. Удаленный атакующий может специальным образом создать файл сессии (.ht) для HyperTerminal или URL для telnet и выполнить произвольный код на системе целевого пользователя. URL производителя: www.microsoft.com. Решение: Установите обновления с сайта производителя.

Выполнение произвольного кода в Microsoft Windows Resource Kit Программа: Microsoft Windows 2000/XP Resource Kit. Опасность: Средняя. Описание: Обнаружено несколько уязвимостей в Microsoft Windows 2000/XP Resource Kit. Удаленный атакующий может выполнить произвольный код на уязвимой системе. Удаленный атакующий может предпринять XSS-нападение. Уязвимость существует в w3who.dll в расширении ISAPI для Windows 2000/XP Resource Kit из-за некорректной обработки входных данных пользователей перед отображением их в HTTP-заголовках или в сообщениях об ошибках. Удаленный атакующий может создать специальным образом URL и выполнить произвольный HTML-код в браузере целевого пользователя. Примеры: Connection: keep-alive<script>alert(«Hello»)</script> /scripts/w3who.dll?bogus=<script>alert(«Hello»)</script>

Переполнение буфера существует при обработке входных параметров URL. Удаленный атакующий может с помощью специально сформированного URL вызвать переполнение буфера и потенциально выполнить произвольный код на системе. Пример: /scripts/w3who.dll?AAAAAAAAA...[519 to 12571]....AAAAAAAAAAAAA

URL производителя: www. microsoft.com. Решение: Решения не существует на данный момент.

Раскрытие информации в Squid Программа: Squid 2.5. Опасность: Низкая. Описание: Обнаружена уязвимость в Squid. Удаленный атакующий может получить внутреннюю информацию от целевого сервера. Удаленный атакующий может послать серверу ряд специально сформированных запросов к несуществующим хостам, и заставить Squid возвращать в качестве сообщения об ошибке случайные данные, которые могут содержать информацию о запросах других пользователей. Пример: http://./.gz/

URL производителя: www.squid-cache.org. Решение: Установите обновление: http://www.squid-cache.org/ Versions/v2/2.5/bugs/squid-2.5.STABLE7-dothost.patch.

Обход защиты персональных брандмауэров Программа: большинство персональных брандмауэров. Опасность: Низкая. Описание: Вредоносное программное обеспечение может реализовать атаку типа shatter на разрешенное брандмауэром GUI-приложение и выполнить произвольный код в его контексте. После этого вредоносное программное обеспечение получает возможность взаимодействовать с внешними сетями в обход политик безопасности брандмауэра. Решение: Решения не существует на данный момент.

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

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

91


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.