РО ТИ РАС РА КУ Ж ПИ
НИ НО К У ВО ЛЫ ГО ЗА ДНИ ТЯ Е НУ ЛИ С
ЛИ
Ь
Так видит журнал читатель, который забыл оформить подписку:
Так видит журнал читатель, оформивший подписку:
№12(61) декабрь 2007
КО НЕО НЧ ЖИ ИЛ ДА ИС НН ЬД О ЕН ЬГ И ЗА
П АВ ОС РА ЛЕ Л ОТ НА П У РА СК БО А ТЕ
УЕ ХА Л
ВО
ТП
УС К
КА
БЫ СТ
№12(61) декабрь 2007 подписной индекс 20780 www.samag.ru
MS Exchange 2003 + SpamAssassin Asterisk: организуем автоматическое распределение поступающих вызовов Citadel – Open Source-решение для коллективной работы DTrace – рентген для операционной системы Программное управление MS Exchange Используем скрипты WSH в «1С:Предприятие»
ПОДПИШИТЕСЬ И ЧИТАЙТЕ! Роспечать – 20780, 81655 Пресса России – 88099, 87836 Интер-почта – тел. (495) 500-00-60
GNU Autotools: ошибки свои и чужие Работаем с OpenDocument из Perl Новое в синтаксисе Perl 5.10
в номере РЕПОРТАЖ
IP-ТЕЛЕФОНИЯ
2 «Платформа 2008». Новое лицо Microsoft
Ежегодная конференция Microsoft «Платформа 2008» совпала с 15-летием компании ООО «Майкрософт Рус», что придало событию отчасти знаковый характер. Алексей Барабанов
5 ТЕНДЕНЦИИ
48 Игра в IT, или Зарисовки к портрету Дмитрия Гудзенко
6 Дао DTrace
Базовая архитектура DTrace и основные принципы её работы. Евгений Ильин
12 Frugalware 0.7 - Linux для бережливых?
Девиз этого дистрибутива звучит так: «Let's make things frugal!» или, в вольном переводе, «Давайте будем бережливее!». Посмотрим, насколько хорошо это удается команде разработчиков. Валентин Синицын
16 Citadel – Open Source-решение для коллективной работы Обзор возможностей системы.
Сергей Яремчук
22 GNU Autotools: ошибки свои и чужие
GNU autotools, комплект скриптов для облегчения процесса построения сложных программных проектов, – удобная, мощная, но плохо документированная система. Прочитав статью, вы узнаете, как программы autotools связаны между собой, и как можно исправить чужие ошибки, не наделав своих. Рашид Ачилов
28 Программное управление MS Exchange
Рассматриваются процедуры создания и удаления почтовых ящиков. Иван Коробко
34 MS Exchange 2003 + SpamAssassin
Перепробовав множество коммерческих продуктов, направленных на борьбу со спамом, таких как SerfControl E-mail Filter, SpamFighter Exchange Module (SEM) и другие, я пришел к выводу, что соотношение цена/качество оставляет желать лучшего. Но как всегда, есть альтернативы в виде Open Source-продуктов. Артем Деянов
БЕЗОПАСНОСТЬ 36 Синхронизация ACL и структуры организации
Описывается создание надстройки для Windows Server 2003, позволяющей эффективно совместно использовать два ее основных механизма разграничения доступа: на основе структуры организации и ACL. Вадим Андросов
АДМИНИСТРИРОВАНИЕ «1С» Сервер сценариев Windows (WSH) позволяет без предварительной компиляции запускать программы, написанные на любых языках, поддерживающих технологию Component Object Model. Андрей Луконькин
№12, декабрь 2007
Как использование Asterisk поможет решить непростую проблему обслуживания клиентов. Сергей Яремчук
ЧЕЛОВЕК НОМЕРА
АДМИНИСТРИРОВАНИЕ
43 Используем скрипты WSH в «1С:Предприятие»
44 Asterisk: организуем автоматическое распределение поступающих вызовов
История о директоре, который любит учиться и учить. Оксана Родионова
WEB 52 Создаём собственный хостинг, или Сам себе ISP. Часть вторая
Рассматривается создание системы домашних каталогов пользователей, отделение пользователей друг от друга и от системы, а также настройка производительности системы. Андрей Шетухин
ПРОГРАММИРОВАНИЕ 56 Новое в синтаксисе Perl 5.10
Основные нововведения, которые появились в Perl 5.10. Андрей Шитов
64 Работаем с OpenDocument из Perl
Открытые форматы документов приобретают все большую популярность – и вы тоже можете извлечь из них пользу, даже не запуская OpenOffice.org. Все, что вам потребуется – это интерпретатор Perl и задача, которую необходимо решить. Валентин Синицын
70 Основные процедуры для работы с деревьями
Систем, построенных на основе бескомпромиссного иерархического подхода, немного, так как такой подход выглядит труднореализуемым. Однако его применение повысит вероятность того, что ваша система в конце концов не окажется в тупике. Александр Ямпольский
74 Пространства имен в PHP
Способы применения пространств имен и их особенности в языке PHP. Александр Майоров
РЕТРОСПЕКТИВА 82 Окно в электронный мир: история развития графического пользовательского интерфейса. Часть 2
Графический пользовательский интерфейс в 1980-ые стал движущей силой для быстрого распространения персональных компьютеров по всему миру. Отныне десятки крупных компаний развивали идеи первых GUI в собственных проектах. Дмитрий Мороз
90 КНИЖНАЯ ПОЛКА 92 СОДЕРЖАНИЕ ЖУРНАЛА ЗА 2007 ГОД 42, 55, 73
BUGTRAQ
репортаж
«Платформа 2008». Новое лицо Microsoft
В здании Российской академии наук 27-28 ноября прошла ежегодная конференция Microsoft «Платформа 2008». Это мероприятие было 9-м по счету в России, и его проведение совпало с пятнадцатилетием компании ООО «Майкрософт Рус», что придало событию отчасти знаковый характер.
О
хватить в короткой заметке все аспекты этого собрания невозможно, да и незачем, так как пресса и Сеть наполнены обзорами и репортажами. Самый детальный и красочный, на мой взгляд, можно прочесть в http://www.windowsfaq.ru/ content/view/657/94. Но есть что-то, что отличает именно эту конференцию от всех ранее прошедших и не позволяет свести рассказ к тривиальному перечислению увиденного. Попытаемся самое примечательное рассортировать по трем категориям и таким образом получить картинку целого в иной поляризации. Итак, ...
Взгляд первый, технологический Безусловно, «Платформа 2008» знаменует очередное технологическое продвижение компании Microsoft и ставит своей целью поведать техническому сообществу о них. Основные направления, заданные в пленарном докладе, – это Windows Server 2008, SQL Server 2008, Visual Studio 2008 и многое другое, даже не всегда с индексом 2008. Невооруженным глазом видно, что перечисленные продукты, анонсированные на конференции, не входят в категорию, если можно так сказать, общеупотребительных. Но они составляют платформенную среду и тем самым определяют стратегические направления развития.
Одним из таких направлений, которо- консолидации, а SoftGrid представляму было отведено значительное мес- ется как средство решения противото как в пленарном докладе, так и да- речий в системном реестре за счет лее, в докладах тематических, явля- создания изолированной среды исется виртуализация, представленная полнения для отдельных приложений, в виде комплексного подхода в реше- но нельзя не заметить стремления нии многих проблем. Виртуализация сделать виртуализацию неотъемлене была сведена к простой инкапсу- мой частью ОС. ляции среды исполнения ОС за счет Из остальных тем, затронутых аппаратных возможностей. В докла- на конференции, отмечу очень интеде Эрика Раддера (на фото), старшего ресную новацию от Intel – технологии вице-президента по технической стра- класса «Pro». В двух словах, это средстегии, было рассмотрено применение тва, дополняющие аппаратные возвиртуализации на всех уровнях рабо- можности компьютеров так, что в них ты вычислительной системы от аппа- появляется функциональность, эквиратной виртуализации до виртуали- валентная HP iLO. Реализована эта зации отдельных приложений с помо- возможность за счет расширения щью Microsoft SoftGrid. Наиболее ин- чипсета и позволяет работать по затересной мне показалась идея о вир- щищенным каналам через сеть даже туализации презентационных услуг. с выключенным устройством. ДемонсЭто фактически выводит виртуали- трация выгляделавпечатляюще. В цензацию за рамки аппаратно-програм- тре зала были установлены настольмных комплексов и позволяет ощу- ный ПК и ноутбук. Десктоп имел протить преимущества такого подхода водную связь, а ноутбук только wireless. не только системным администрато- По запросу оператора эти компьютерам, но и рядовым пользователям, на- ры были дистанционно проинспектипример, в процессе работы через VPN. рованы без включения питания, затем Общее впечатление от пленарного до- включены и далее снова выключены. клада свелось к тому, что идея вирту- Представители Intel уверяли, что исализации – это «Номер 1» в ближай- пользование этой технологии безошей перспективе. Хотя для обоснова- пасно, так как применяются средства ния использования в составе Windows шифрования. Server 2008 собственного гипервайзеДальше пересказывать нет смысра приводятся все те же очевидные ар- ла, так как практически все тематичесгументы, вроде неполной загрузки вы- кие доклады, прозвучавшие на кончислительных мощностей и стремле- ференции, доступны в записи. Приния экономить электроэнергию за счет чем это не только «сервис-постфак-
репортаж тум». Например, если участник конференции тривиально проспал важный для него доклад Андрея Бешкова «Реализация требуемой политики безопасности рабочих мест», прозвучавший рано утром, не беда – можно прослушать запись, загрузив с сайта www.platforma2008.ru после регистрации. Могу в шутку выразить сожаление, что тем самым авторы обзорных статей лишаются возможности сообщить чтото новое и содержательное и вынуждены довольствоваться общими впечатлениями. Потому перейдем к численным оценкам.
Взгляд второй, метрический В течение 10 дней после открытия Эрик Раддер регистрации на форум были проданы все места. Участвовало 1700 че- мантической фазы в истории Microsoft ник Microsoft, и «пингвины» вообще-то ловек, что значительно меньше, чем в России и обозначили начало фазы не приглашались. И окончательно карты раскрыл догод назад, когда было отмечено 3500 прагматической. Тут не о чем сожапосетителей конференции. Компании леть. Конкиста, предпочитаемая ро- клад Дмитрия Халина, директора ДеООО «Майкрософт Рус» исполнилось мантиками, закончилась бесславным партамента стратегических техноло15 лет! Продукция её занимает 70% делом учителя Поносова. С прагма- гий (назначен осенью этого года) на зарынка ПО в России – настоящий «бло- тиками иметь дело не в пример при- крытой пресс-конференции. Конспект кирующий пакет». Следующее мероп- ятнее. Начну с перечисления выгод, доклада доступен в архивах на сайте риятие запланировано в Крокус-Сити, как в известной сказке Киплинга о хо- www.platforma2008.ru. Отмечу самое главное. По мнению Дмитрия Халии регистрация предполагается за пол- боте слона. Выгода первая. Программа опре- на, ранее «мероприятия Microsoft быгода до даты проведения, что воспринимается как намек на увеличение делилась голосованием. Состав и по- ли ориентированы только на IT-аудичисла участников. Получается какой- рядок тематических докладов был не- торию», что понятно, так как ставито юбилейный регресс в числе при- известен почти до самого начала кон- лась цель увеличения присутствия глашенных. Как это объяснить? Толь- ференции. Это значит, что каждый на рынке любым путем. Настоящую ко лишь платформенной спецификой участник мог повлиять на выбор ин- «Платформу 2008» Дмитрий называпредставленных продуктов? Быть мо- тересных тем и заранее сообщить ор- ет «возвращением к истокам» и считажет, ограниченными ресурсами на пи- ганизаторам о предпочтениях, что- ет не случайным введение таких новтание участников? Представлю свою бы те смогли более точно запланиро- шеств, как интерактивный выбор довать ресурсы. кладов. Это, по его словам, признание версию. Выгода вторая. Все доклады, про- интеллектуального потенциала россиНапомню два события уходящего 2007 года. Весной завершилось «Де- звучавшие на конференции, доступ- ян. В подтверждении своих слов госло Поносова», которое во многом из- ны в записи через Интернет после ре- подин Халин указал, что в России суменило взгляды на допустимые пре- гистрации. Для проверки я зарегист- ществует нехватка 30 тысяч IT‑специделы вмешательства транснациональ- рировался на сайте platforma2008.ru алистов (в оригинале на конференных корпораций в жизнь россиян и за- из openSUSE используя Firefox, полу- ции было «программистов»), и это ставило высказаться по этим вопросам чил Windows Live ID и скачал наибо- значит, что для многих молодых люочень многих влиятельных политиков. лее интересные доклады в виде зази- дей есть шанс сделать выбор професА летом президент Microsoft в России пованных файлов формата wmv, ко- сии в пользу информационных технои СНГ Ольга Дергунова объявила о на- торые затем прослушал с помощью логий. Во всем этом я вижу смену памерении перейти в ВТБ. Ольга Дергу- MPlayer. Третья приятная неожиданность, радигмы общения Microsoft в Роснова работала в компании с 1994 года, а с 1995-го занимала пост главы пред- удивившая меня, это тройное упоми- сии. Такое впечатление, что компаставительства Microsoft, то есть разви- нание GNU/Linux в ходе только лишь ния решительно пересматривает мнотие бизнеса Microsoft в России проис- пленарного доклада. Хотя, пока все гие ранее сложившиеся стереотипы ходило в значительной степени под её более в качестве шуток – «ой, кто это и в чем-то начинает «с нуля». Напримне поставил в виртуальный бокс мер, на «Платформе 2008» впервые руководством. Эти два события некоторым обра- Linux», – но сам факт достоин упоми- представлена локализованная верзом ознаменовали завершение ро- нания. Не стоит забывать, это празд- сия Microsoft Visual Studio, и вообще
№12, декабрь 2007
репортаж
Пресс-конференция
значительное внимание уделено про- для «RH‑линукс» (оригинальная тердуктам для разработчиков. Было отме- минология сохранена). Все сказанное чено, что из числа участников 60% со- позволяет дать очень высокую оценку ставляют системные администраторы «Платформы 2008» и ожидать от слеи CIO, а оставшиеся 40% в основном дующей конференции развития этих разработчики. положительных тенденций. Почему вдруг была проявлена необыкновенная толерантность по отно- Взгляд третий, шению к GNU/Linux? И этому есть то- оптимистический же объяснение. Внедрение виртуали- Напоследок расскажу о формате конзации с одновременным соблюдени- ференции. С точки зрения удобства ем условия сохранения мобильнос- для посетителя мероприятие было орти и бесперебойности подачи серви- ганизовано превосходно, чему отчассов приводит к идеям о неизбежной ти способствовало относительно негетерогенности вычислительной сре- большое число участников. Хотя запуды. К примеру, даже в вышеприве- танная архитектура здания Академии денном докладе Андрея Бешкова бы- наук несколько осложняла навигацию ло упомянуто о наличии в NAP-плагина по залам. Нельзя не отметить порази-
Шоу, сопровождавшее открытие
тельное сосредоточие сервисов – фуршетные столы, коктейль-бары и шоколадные фонтаны, – все атрибуты корпоративной вечеринки. Но доступные и настроенные через Wi-Fi в онлайн ноутбуки в интернет-кафе не давали забыть о специфичности данного собрания. Биргер Стен, директор ООО «Майкрософт Рус», неоднократно называл «Платформу 2008» клубом. И надо согласиться, что это подходящее название именно в силу степени гостеприимства, а не в обозначение закрытости. Как всегда, были предусмотрены подарки каждому участнику и специальные презенты, названные «Боекомплект IT-профессионала и разработчика», представляющие подборку книг по профессиональным темам. Особого упоминания заслуживает розыгрыш коммуникаторов от HTC. Открытие сопровождалось цветомузыкальным шоу, в завершение которого прозвучал своего рода корпоративный гимн. В припеве можно было различить фразу «поддержим мы тебя во всем». Показательно, да? Хочется воспринимать это обещание в контексте заявления Биргера Стена о том, что на каждый 1 доллар дохода Microsoft партнеры получают 17 долларов. Которое можно понимать и так, что каждые 100 у.е., потраченные на продукцию этой компании, оборачиваются 1700 у.е., вложенными в адаптацию решения, а можно и так – «зарабатывайте вместе с Microsoft»! Лишним будет говорить, что этому мероприятию нет аналогов по масштабности и информативности. Могу лишь выразить надежду, что и бренды категории Open Source когда-нибудь смогут представляться подобным образом. Как уже упоминалось, следующая «Платформа» пройдет предположительно с еще большим масштабом, а те, кто не успеет зарегистрироваться или не может стать участником по иным причинам, уверен, получат достойную виртуальную замену. Предполагаю, в следующей заметке придется все более описывать обеденное меню, условия парковки и то, что не попадет в сетевую трансляцию из-за малой значимости...
Текст Алексей Барабанов, фото предоставлены компанией Microsoft
тенденции Началась новая волна нарушений GPL В середине ноября группа разработчиков свободного программного обеспечения при содействии Харальда Вельте (Harald Welte), основателя организации GPL-Violations.org, обвинила французскую телекоммуникационную компанию Iliad в нарушении лицензии GNU GPL. Инициатива стала следствием игнорирования компанией Iliad требований опубликовать исходный код свободных компонентов, включенных в ее продукт Freebox. Freebox – программно-аппаратный комплекс, предоставляющий доступ к сети Интернет, телефонной линии (VoIP) и телевидению. На счету GPL‑Violations.org – целый ряд успешных результатов в подобных разбирательствах. Среди оппонентов организации выступали такие компании, как Skype, Fortinet и Sitecom. Уже к концу месяца в СМИ начала появляться информация о другом случае нарушения свободной лицензии – на сей раз в злодеянии обвинялась ASUSTeK Computer. Как позже подтвердила тайваньская компания, она действительно нарушила GNU GPLv2 в своем Linux-лаптопе Eee PC. В системе использовалась модифицированная версия модуля Linux-ядра asus_acpi, однако в изначально обнародованном ASUS архиве с исходниками его не было. Представители компании оперативно отреагировали на недовольные возгласы сообщества и опубликовали недостающий код на своем FTP-сервере. А в декабре вновь о себе напомнил Юридический центр свободы программного обеспечения (Software Freedom Law Center, SFLC), оказавший посильную помощь проекту BusyBox ранее в этом году в споре с Monsoon Multimedia. На сей раз иск был подан на компанию Verizon Communications, нарушавшую авторские права все тех же разработчиков BusyBox. Истцы заявили, что Verizon не выполняет условия GNU GPLv2, включая наработки BusyBox в продукт, распространяемый с интернет- и ТВ-сервисом FiOS. Оказалось, что Verizon поставляет клиентам, пользующимся услугам FiOS, беспроводные роутеры Actiontec MI424WR, в которых присутствует BusyBox, и не публикует исходный код программного содержимого своего продукта.
До конца 2007 года будет сформирован пробный пакет свободного ПО, который апробируют в школах Татарстана, Пермского края и Томской области.
В государственных учреждениях Нидерландов готовятся к использованию Open Source Министерство экономики Нидерландов объявило, что в апреле 2008 года государственные ведомства должны приступить к работе с программным обеспечением с открытым кодом. Как стало известно от агентства Associated Press со ссылкой на представителя министерства Эдвин ван Шерренбург (Edwin van Scherrenburg), государственные организации смогут также продолжать работать с проприетарным программным обеспечением и закрытыми форматами, но теперь в таком случае они будут вынуждены обосновывать свой выбор. Представитель нидерландского подразделения Microsoft Ганс Бос (Hans Bos) заметил, что документы в формате Word по-прежнему разрешены в Нидерландах как равнозначная альтернатива, и высказал надежду на распространение в этой стране нового формата Microsoft OOXML. Одновременно с тем он огласил озабоченность по поводу продвигаемой политики правительства, которая ясно гласит, что государственные ведомства должны предпочитать Open Source.
Подготовил Дмитрий Шурупов по материалам www.nixp.ru
Стал известен поставщик свободного ПО в российские школы 30 ноября был официально выбран разработчик и поставщик пакета свободного программного обеспечения для российских школ – им стала группа компаний «Армада». «Армада» объединяет такие компании, как «РБК СОФТ», «Гелиос Компьютер», «ПМ Эксперт», «СоюзИнформ» и ЕТС. Заявка на открытый конкурс «Разработка и апробация в пилотных субъектах Российской Федерации пакета свободного программного обеспечения для использования в общеобразовательных учреждениях Российской Федерации в 2007‑2008 гг.» была подана от имени «РБК-Центра» с указанной суммой контракта в 59,5 миллионов рублей. Также сообщается, что в число субподрядчиков этого проекта вошли отечественные Linux-компании ALT Linux, «ЛИНУКС‑ОНЛАЙН» и Linux Ink, создатель операционной системы МСВС ВНИИНС, системные интеграторы «РАМЭК» и НЦИТ.
№12, декабрь 2007
администрирование
Дао DTrace Познай себя и познай своего врага. Тогда в сотне битв ты не будешь знать поражения. Сан дзу. Искусство войны
Евгений Ильин Снять гипс с «клиента» без «шума и пыли», можно, как известно, несколькими способами. Если говорить о трассировке, DTrace предлагает свой, элегантный метод добраться до бриллиантов, где бы они ни были спрятаны в системе.
Н
едавно я делал презентацию об открытых технологиях Sun Microsystems. Технологий было много и получалось, что обзор каждой должен занимать не более пяти минут, в том числе и рассказ о таком мощном средстве наблюдения за системой, каким является DTrace. Чтобы дать аудитории краткое и понятное представление об этом инструменте, я придумал, как мне кажется, удачную аналогию: «DTrace – рентген для операционной системы». Ведь как рентген может «заглянуть» внутрь живого организма, так и DTrace позволяет увидеть процессы, происходящие внутри операционной системы и пользовательских приложений. С помощью этой технологии можно получить исчерпывающую информацию о внутреннем состоянии приложения, причём сам процесс исследования для «пациента» абсолютно безопасен, так как он не оказывает никакого влияния на «жизнедеятельность» объекта исследования. Правда, это не совсем полная аналогия, поскольку принципы работы DTrace и рентгеновского аппарата от-
личаются. DTrace получает информа- приведённые примеры были понятцию от многочисленных датчиков, что ны, представлено краткое описание находятся в ядре, библиотеках и при- языка программирования D, который ложениях, которые срабатывают толь- предоставляет универсальный доступ ко в том случае, когда кто-то включил ко всем возможностям DTrace. их в явном виде. Выключенные датчики не оказывают никакого влияния на Обзор архитектуры DTrace производительность, и система в це- Основные архитектурные компоненлом работает так, как будто их вооб- ты DTrace – это потребители, корневой ще нет. Весь секрет в том, что DTrace модуль DTrace, датчики и провайдеры. умеет динамически модифицировать Процессы становятся потребителями объект исследования. (consumers) DTrace, инициируя общеПожалуй, можно провести еще од- ние с корневым модулем DTrace. Корну параллель между DTrace и рент- невой модуль находится в ядре опегеном. Для успешного рентгеновско- рационной системы и обеспечивает го исследования необходимо знание доступ к средствам модификации кофизиологии, анатомии и устройства да, буферизацию и обработку собырентгеновского оборудования. Анало- тий от датчиков (probes). У потребигично и для эффективного использо- теля две основные задачи: передать вания DTrace необходимо понимание спецификации трассировки модулю принципов работы операционной сис- DTrace (далее по тексту термины кортемы и устройства инструмента, кото- невой модуль и модуль DTrace суть сирый позволяет заглянуть внутрь рабо- нонимы) и обрабатывать данные, полутающей системы. ченные в процессе трассировки. ПотВ этой статье пойдёт рассказ об ребители обращаются к корневому моархитектуре DTrace, её составляю- дулю через интерфейс, предоставляещих элементах и методологиях мо- мый библиотекой libdtrace(3LIB). Дандификации системы. Для того чтобы ные между потребителем и ядром пе-
администрирование редаются посредством вызовов ioctl(2) для псевдо-устройства dtrace, реализованного драйвером dtrace(7d). Потребителем DTrace может быть любая программа. В состав Solaris 10 включены утилиты lockstat(1M), plockstat(1M) и intrstat(1M), являющиеся оными (это не полный список утилит Solaris 10, что являются потребителями DTrace). Однако каноническим потребителем является утилита dtrace(1M), которая предоставляет универсальный доступ ко всем средствам DTrace, так как является драйвером для компилятора языка программирования D (сам компилятор находится в библиотеке libdtrace(3LIB)). Также можно использовать dtrace(1M) в качестве самостоятельной утилиты трассировки. Примечание: в компиляторостроении под драйвером понимается утилита, которая позволяет управлять процессом трансляции и вызывает все остальные компоненты, как то собственно компилятор, оптимизатор, кодогенератор, и т. д. Например команда сс – это драйвер компилятора С.
Провайдеры и датчики Модуль DTrace не оснащает код инструментальными средствами, делегируя эту задачу провайдерам, которые в свою очередь также являются модулями ядра. Когда модуль DTrace даёт соответствующую команду, провайдеры определяют точки в системе, куда они потенциально могут вставить инструментальные средства. Для каждой найденной точки провайдер делает обратный вызов модуля DTrace, чтобы создать датчик (probe). То есть, по сути, провайдер – это модуль ядра, который создаёт множество датчиков, сгруппированных по тому или иному принципу (например, функции ядра, системные вызовы или функции какогото пользовательского приложения). При помощи команды modinfo(1M) можно посмотреть на некоторые модули ядра некоторых стандартных провайдеров в Solaris: jedi# modinfo | grep Tracing 4 f93dc000 16438 155 207 f930631c d98 156 208 f9200ab8 554 157 209 feb56c04 c5c 158 211 f93894f8 1304 159 212 f927b000 3fcc 167 225 f91358bc 68c 241
1 1 1 1 1 1 1
dtrace (Dynamic Tracing) profile (Profile Interrupt Tracing) systrace (System Call Tracing) fbt (Function Boundary Tracing) sdt (Statically Defined Tracing) fasttrap (Fasttrap Tracing) lx_systrace (Linux Brand System Call Tracing)
Рисунок 1. Архитектура DTrace
имя функции, в которой находится датчик, как, например, ufs_read() в ядре или же printf() из libc для пользовательского приложения, а семантическое имя – по сути осмысленное название, как, например, on-cpu и off-cpu для датчиков планировщика или же start для датчиков ввода-вывода. Таким образом, каждый датчик полностью идентифицируется следующей четвёркой: <провайдер, модуль, функция, имя>
Создание датчиков ещё не модифицирует систему, это только лишь определение возможных точек модификации системы. Это по сути создание необходимых структур данных, после чего DTrace только возвращает идентификатор датчика провайдеру. В какой же момент происходит модификация? Созданные провайдером датчики становятся видимыми для потребителей, которые могут включить группу датчиков, задав комбинацию элементов из вышеупомянутой четвёрки. После включения DTrace создаёт и привязывает к датчику блок управления (ECB – enabling control block), где определены действия (actions) и предикат (predicate), то есть что и при каком условии будет выполнено в случае срабатывания датчика. Если во время создания данного ECB других связанных с текущим датчиком ECB нет, DTrace обращается к провайдеру с указанием включить данный датчик (кстати, если ECB уже есть, то новый блок становится в хвост цепочки ECB-блоков для этого датчика). И в этот момент провайдер динамически модифицирует систему таким образом, что при срабатывании датчика управление переходит к модулю DTrace, причём первым аргументом в обращении к нему следует идентификатор датчика. Итак, DTrace получил управление. Как только это произошло, на текущем процессоре запрещаются прерывания, и DTrace отрабатывает действия, определённые в каждом ECB-блоке из цепочки ECB-блоков сработавшего датчика. Затем прерывания разрешаются вновь, и управление возвращается провайдеру.
В примере вы видите модули ядра самого DTrace и провайдеры, которые присутствуют при установке Solaris 10 в базовой конфигурации. О некоторых из них я расскажу подробнее, сейчас же хочу обратить ваше внимание на модуль lx_systrace, который реализует провайдер lxsyscall для типизированных зон Linux (BrandZ) и содержит множество датчиков для трассировки системных вызовов Linux. На данный момент, насколько мне известно, это единственно возможный способ воспользоваться DTrace для трассировки Linux-приложений. Для того чтобы создать датчик, провайдер специфицирует имена модуля и функции для точки инструментальной модификации кода и собственно его семантическое имя. Причем под модулем в данном контексте надо понимать программную принадлежность датчика. Для ядра это будет название модуля ядра (например, zfs), для приложений Пример модификации кода провайдером это будет или библиотека (libjvm.so, libc.so), или даже неко- Теперь давайте посмотрим, как же реально модифицируется торая пользовательская подсистема (Xorg). Функция – это код на платформе x86 в Solaris . Для этого нам понадобится
№12, декабрь 2007
администрирование Solaris 10 или Solaris Express Developer Edition, рутовый доступ, штатный отладчик модулей ядра mdb и 2 терминальных окошка. В одном из окошек запускаем mdb и дизассемблируем функцию ufs_lookup(), ограничив вывод тремя первыми командами, чтобы его не загромождать: jedi# mdb -k Loading modules: [ unix genunix specfs dtrace uppc pcplusmp scsi_vhci ufs ip hook neti sctp arp usba uhci fctl nca lofs zfs random audiosup sppp ptm md cpc crypto fcip fcp logindmux nsctl sdbc sv ii rdc ipc ]
> ufs_lookup::dis -n 3 ufs_lookup: ufs_lookup+1: ufs_lookup+3:
pushl %ebp movl %esp,%ebp subl $0x10,%esp
Выходим из mdb при помощи <Ctrl+D>, а затем включим датчики на модуле ufs, запустив DTrace в другом терминальном окне: jedi# dtrace -m 'ufs { trace(execname);}' dtrace: description 'ufs ' matched 836 probes CPU ID FUNCTION:NAME 6 20874 ufs_getpage:entry 6 21348 ufs_lockfs_begin_getpage:entry 6 20930 ufs_lockfs_is_under_rawlockfs:entry 6 20931 ufs_lockfs_is_under_rawlockfs:return 6 21349 ufs_lockfs_begin_getpage:return 6 21512 bmap_has_holes:entry ...
dtrace dtrace dtrace dtrace dtrace dtrace
Вывод показывает, какие исполняемые файлы в системе вызывают функции модуля ufs. В нашем случае это команда dtrace, которую мы же сами и запустили. Оставим dtrace работать дальше, а сами снова вернёмся к первому окошку и снова запустим mdb: jedi# mdb -k Loading modules: [ unix genunix specfs dtrace uppc pcplusmp scsi_vhci ufs ip hook neti sctp arp usba uhci fctl nca lofs zfs random audiosup sppp ptm md cpc crypto fcip fcp logindmux nsctl sdbc sv ii rdc ipc ]
> ufs_lookup::dis -n 3 ufs_lookup: ufs_lookup+3: ufs_lookup+6:
lock movl %esp,%ebp subl $0x10,%esp andl $0xfffffff0,%esp
Как нетрудно увидеть, в начале первой инструкции появился префикс lock. Это не совсем корректный код с точки зрения ассемблера x86, потому что по спецификации #lock нельзя использовать в комбинации с инструкцией movl. Поэтому эта комбинация генерирует программное прерывание (illegal opcode), управление перехватывается ловушкой (trap), где в итоге передаётся DTrace. Если вы попробуете воспроизвести эти действия, то возможно, что вместо #lock увидите нечто другое. Полученный после модификации ассемблерный код для x86, amd64 и, разумеется, для SPARC будет различен. Подробнее об этом позже, а теперь снова вернёмся к обзору архитектуры.
Предикаты и действия. Буферы и DIF У каждого ЕCB-блока может быть ассоциированый с ним предикат. Если таковой имеется, но его условие не выполняется, то DTrace по цепочке переходит к следующему ECBблоку. Помимо предиката у каждого блока ECB есть список
действий и, если условие предиката удовлетворено, то обработка ECB-блока продолжится последовательным исполнением всех действий данного блока. Если действие предполагает запись каких-то данных, то они будут сохранены в специальном буфере, который выделяется для каждого CPU и однозначно привязывается к потребителю, создавшему ECB-блок. Это делается потому, что для обеспечения безопасности использования действия не могут содержать явную запись в память ядра, изменение регистров, равно как и выполнение каких-то других явных операций, изменяющих состояние системы. Они могут делать это косвенно, но строго определённым способом, например остановить текущий процесс или сгенерировать точку останова в ядре. Такие действия можно делать только пользователям с определёнными полномочиями и явно разрешив деструктивные действия. Еще одна линия защиты системы от нанесения непреднамеренного вреда – это виртуальная машина DTrace с собственным набором машинно-независимых команд RISC, который называется DIF (D Intermediate Format) и является целевым языком компиляции для libdtrace. D-скрипты транслируются в DIF и эмулируются в ядре при срабатывании датчика, подобно тому, как виртуальная машина Java (JVM) интерпретирует байткод Java. Использование эмуляции в момент исполнения гарантирует, что возможные ошибки, способные дестабилизировать систему, будут выловлены и обработаны безопасным способом. При помощи ключа -S команды dtrace можно посмотреть на генерируемые DIF-объекты (DIFO): jedi# cat difo.d && dtrace -S -s difo.d syscall::ioctl:entry { self->follow = 1; } DIFO 0x6f8cc0 refcnt=1 returns D type (integer) (size 4) OFF OPCODE INSTRUCTION 00: 25000001 setx DT_INTEGER[0], %r1 ! 0x1 01: 2d050001 stts %r1, DT_VAR(1280) ! DT_VAR(1280) = "follow" 02: 23000001 ret %r1 NAME ID KND SCP FLAG TYPE follow 500 scl tls w D type (integer) (size 4) dtrace: script 'difo.d' matched 1 probe ^C
На этом я заканчиваю обзор архитектуры и предлагаю перейти к краткому знакомству со скриптовым языком программирования D.
Шпрехен зи D? Как уже говорилось ранее, каноническим потребителем, предоставляющим универсальный доступ ко всем средствам, является dtrace(1M). Универсальность достигается благодаря языку D, на котором программируются предикаты и действия. Программа на языке D выглядит как последовательность компонентов (clauses) вида: дескриптор-датчика, [дескриптор-датчика...] [ /предикат/ ] { действие; [действие; ...] }
Как можно догадаться, дескриптор-датчика, он же ин-
администрирование дентификатор датчика, – это та самая четвёрка <провай- printf() в языке C), так и использование встроенных передер, модуль, функция, имя>. В синтаксисе языка D она в об- менных execname и uid, определённых в языке D, которые щем виде выглядит следующим образом: часто встречаются в предикатах и действиях D-скриптов. Также часто используются и следующие встроенные пеprobeprov:probemod:probefunc:probename ременные: n probeprov, probemod, probefunc, probename – имена Не обязательно определять все элементы этой четверпровайдера, модуля, функции и датчика для текущего ки, несколько из них можно опустить, также предусмотредатчика; но использование шаблонов (конструкция «::» равносиль- n execname – имя текущего исполняемого модуля; на «:*:»). Вот примеры допустимых дескрипторов: n pid, ppid – идентификаторы текущего процесса и родиn tick-1s теля текущего процесса; n syscall::read:entry n curpsinfo – структура psinfo для текущего процесса; n ::exec*:entry n timestamp – время с момента загрузки в наносекундах; Предикат – это условное выражение. Если он отсутс- n args[] – массив аргументов, нумерующийся от 0 до <котвует в компоненте, то в этом случае считается, что предиличество_аргументов – 1>. кат есть и его условие всегда удовлетворено. Действия – это, собственно, то, что будет выполняться, когда датчик Про последний массив надо сказать, что его элеменсработал и удовлетворено условие предиката. Кстати, по- ты определяются провайдером по своему усмотрению. нимая, как порождаются ЕCB-блоки, и учитывая, что каж- Так, для провайдера syscall на датчике entry в массиве дый новый ECB-блок становится в хвост списка ECB-бло- arg[0..n] будут представлены аргументы системного выков датчика, мы видим, что последовательность выполня- зова, а на датчике return в массиве arg[0..1] коды возврата. емых компонентами действий определяется порядком их А вот для провайдера io в arg[0] будет указатель на струкпоявления в D-скрипте и временем, когда происходит мо- туру bufinfo. Значения аргументов для всех провайдеров дификация кода инструментальными средствами. приведены в спецификации «Dynamic Tracing Guide»(http:// Поскольку язык D создавался с оглядкой на С, в нем docs.sun.com/app/docs/doc/817-6223). поддерживаются все встроенные типы языка С, typedef, Последнее, что следует сказать про переменные,– это их а также возможность определять типы struct, union и enum. области видимости. Глобальные переменные декларируютИмеются также собственные встроенные скалярные ти- ся с использованием синтаксиса языка С либо могут быть пы (string), ассоциативные массивы и агрегации. Послед- объявлены неявно при присваивании. В последнем случае ний тип представляет собой именованную структуру, хра- такой переменной назначается тип выражения в правой часнящую результат некоторой агрегирующей функции, ко- ти присваивания. Помимо глобальных переменных, кототорая индексируется кортежами (n-ками). К примеру, та- рые видны всем компонентам (clauses) скрипта на D, можкой скрипт: но создавать thread-local и clause-local переменные любого типа. Доступ к таким переменным осуществляется при поsyscall::write:entry мощи префиксов self-> и this-> соответственно. Префиксы { служат как для того, чтобы разделить пространство имён @count[execname]=count(); } для переменных, так и для того, чтобы без необходимости предварительной декларации использовать их в выражепокажет, какое количество системных вызовов произвел каждый исполняемый файл, выполнявшийся за время работы скрипта. А если изменить агрегацию так, чтобы индексировать данные по двум параметрам, скажем execname и uid, то получим таблицу, где увидим, что общее количество будет еще и разбито по конкретным идентификаторам пользователей: bash-3.00# cat aggr.d && dtrace -qs aggr.d syscall::write:entry { @count[execname,uid]=count(); printf( "." ); } ...............................^C dtrace dtrace init dtgreet
1234 0 0 0
5 7 8 13
Запустив команду, нужно подождать некоторое время, после чего нажать <Ctrl+C>. Приведенный выше пример также демонстрирует как использование действия printf() (оно, кстати, полностью повторяет реализацию функции
№12, декабрь 2007
Рисунок 2. ECB, предикаты и действия
администрирование ниях присваивания. Clause-local пере- чае, когда при исполнении скрипта менные содержатся в области памяти, произошла ошибка времени исполнекоторая используется повторно при ис- ния, скажем, попытка разыменовываполнении данной компоненты и сродни ния указателя NULL. автоматическим переменным в языке C. Thread-local переменные привязы- Провайдер profile вают каждый индентификатор пере- Большая часть провайдеров привязыменной к отдельным областям памя- вается к определённой точке в коде ти для каждого потока команд в опе- пользовательского приложения, прорационной системе. граммы или ядра. На этом фоне провайдер profile стоит особняком, посПровайдеры кольку вместо изменения кода испольВы уже знаете, что модификацию сис- зует источник асинхронных событий. темы инструментальным кодом осу- Источником таких событий для profile ществляют провайдеры, и поскольку являются прерывания по времени с заони формально отделены от ядра под- данным интервалом. И его датчики системы трассировки, то это значит, могут использоваться для того, чточто в DTrace возможно использовать бы производить снятие данных, котонеоднородные методологии внедрения рые отображают определённые аспеккода инструментальных средств. Бо- ты состояния системы, или выполнять лее того, количество методов со вре- действия через строго определённые менем увеличивается, поскольку но- промежутки времени. В качестве провые методы очень легко встроить стого, но часто встречающегося шабв существующую реализацию DTrace. лона использования этого провайдера Но хотя провайдеры и используют раз- модифицируем пример с агрегациями ные методы внедрения инструменталь- следующим образом: ного кода, их объединяет тот факт, что syscall::write:entry все они не влияют на работу системы, { если датчики находятся в выключен@count[execname]=count(); } ном состоянии. Далее мы рассмотрим методолоtick-7s { гии, которые применяются в некоторых популярных провайдерах. Но сперва упомяну про три датчика, которые преВ результате, для того чтобы посдоставляются провайдером DTrace – мотреть итоговые данные, нам больBEGIN, END и ERROR. ше не надо специально жать <Ctrl+C>, Датчик BEGIN всегда срабатыва- скрипт автоматически закончит работу ет только один раз в момент запуска через 7 секунд, когда сработает датчик скрипта, прежде чем сработает любой tick-7s и сработает действие exit() с цедругой датчик. Причём до тех пор, пока лочисленным аргументом, что вызовет не отработают все действия компонен- срабатывание датчика END и приведёт ты c идентификатором датчика BEGIN, к нормальному завершению работы. никакой другой датчик сработать В качестве более серьёзного прине может. Благодаря такому свойству мера использования этого провайдеBEGIN обеспечивает предварительную ра стоит посмотреть на D-Light. Этот инициализацию переменных, которые инструмент входит в пакет Sun Studio могут понадобиться другим компонен- Express (см. меню Tools) – экпресс-ретам программы на D. лизе интегрированной среды разработДатчик END тоже срабатывает ки Sun Studio (чтобы посмотреть на нетолько в единственный момент жиз- го зайдите на страницу http://developers. ненного цикла программы, соответс- sun.com/sunstudio/downloads/express/ твенно в самом конце и только тогда, index.jsp). Там этот провайдер исполькогда отработали все другие датчики. зуется для сбора различной сэмплинЕго удобно использовать для того что- говой информации на всём жизненном бы обработать собранные в момент ра- цикле приложения. боты программы данные, отформатировать вывод и красиво показать ито- Провайдер syscall говые результаты. Этот провайдер создаёт датчики на Датчик ERROR срабатывает в слу- входе и возврате из каждого систем-
10
ного вызова в Solaris. Поскольку системные вызовы являются основным интерфейсом между пользовательскими приложениями и ядром операционной системы, провайдер syscall позволяет получить массу полезной информации о поведении приложения с точки зрения системы. Метод, по которому работает провайдер syscall – динамическая подмена соответствующей записи в таблице системных вызовов при включении датчика. Примером для данного провайдера будет почти детективная история, которую можно найти на блогах Sun. Дело было так: в один прекрасный день, на одном сервере, который предоставлял терминальный доступ, пользователи после ввода пары логин-пароль вместо привычного приглашения оболочки к вводу команды имели неудовольствие лицезреть, как по терминальному окну бежала последовательность строк, состоящих из «непечатных» символов. Довольно быстро выяснилось, что это безобразие происходит из-за того, что некий шутник сделал /etc/motd символической ссылкой на один из служебных файлов. После удаления симлинка система некоторое время работала нормально, однако с упорством, достойным лучшего применения, через какое-то время /etc/motd вновь ссылался на тот же самый файл. В системе явно работал некий злоумышленник (пусть это будет daemon), которого нужно было обезвредить. Вооружившись DTrace, детектив принялся за работу. Во-первых, было очевидно, что ключ к разгадке даст трассировка системного вызова symlink(), который создаёт ссылки. Следовательно, при помощи провайдера syscall можно отловить момент вызова, а предикатом ограничить область срабатывания датчика таким образом, чтобы запуск действий происходил только при манипуляции с файлом /etc/motd. Далее остаётся вывести pid, и дело сделано. Сие было реализовано таким образом: #!/usr/sbin/dtrace -qs syscall::symlink:entry /basename(copyinstr(arg1))=="motd" / { printf("Execname: %s, ↵ pid=%d\n", execname, pid); }
администрирование Детектив оставил скрипт сидеть в засаде и стал ждать результатов наблюдений. Через некоторое время датчик сработал, но запуск из консоли команды ptree с выловленным pid в качестве аргумента ничего не дал – такого идентификатора процесса в системе уже не было. Злодей успел сделать своё грязное дело и смылся. Поэтому следующая версия ловушки выглядела более хитроумно: !#/usr/sbin/dtrace -wqs syscall::symlink:entry /basename(copyinstr(arg1))=="motd" / { printf("Execname: %s, pid=%d\n", execname, pid); copyoutstr("/tmp/motd",arg1,9); stop(); system("ptree %d",pid); system("prun %d",pid); system("rm /tmp/motd"); }
Что поменялось? Во-первых, исполнение процесса, на котором сработал датчик, приостанавливалось действием stop(). Во-вторых, аргумент вызова symlink подменялся на /tmp/motd вместо /etc/motd (это, кстати, примеры деструктивных действий, для того чтобы разрешить их, необходимо было снабдить вызов dtrace(1M) ключиком ‑w). Ну и, наконец, действием system() запускалась команда ptree на полученом pid, затем prun возобновлял прежде приостановленное выполнение процесса, и напоследок удалялась ссылка /tmp/motd. Можно было бы обойтись чуть меньшим количеством действий, но несложно догадаться, почему не лишенный чувства юмора детектив не уничтожил процесс, а позволил ему выполняться дальше, не причиняя вреда системе.
Провайдер fbt (function boundary tracing) Провайдер трассировки границ функции (fbt) создаёт датчики для момента входа-в и выхода-из всех функций ядра Solaris. Хотя механизм реализации fbt сильно привязан к конкретной архитектуре набора команд, fbt присутствует и на SPARC, и на x86, и на amd64. Фактически мы уже успели посмотреть и понять, каким образом fbt модифицирует код на архитектуре x86 в примере, где использовался mdb для дизассемблирования функции ufs_lookup(). Приведённый в том примере трюк с #lock используется по историческим соображениям, на платформе amd64 реализован более элегантный способ – при помощи вызова программного прерывания. На SPARC это реализовано ещё элегантней, при помощи команды перехода «ba,a +offset» и, если вы обладаете знанием ассемблера SPARC, то можете проделать абсолютно аналогичное упражнение при помощи mdb и даже продвинуться немного дальше. Если дизассемблировать в mdb код по адресу ufs_lookup+offset, где offset – операнд команды перехода, то увидим, как именно происходит передача управления к DTrace. Провайдер fbt позволяет заглянуть глубже и наблюдать за тем, что происходит непосредственно в ядре. Скрипт, приведённый в качестве примера использования провайдера, показывает, какую последовательность вызовов функций ядра генерирует системный вызов ioctl:
№12, декабрь 2007
#!/usr/bin/dtrace -s #pragma D option flowindent syscall::ioctl:entry { self->follow = 1; } fbt::: /self->follow/ { } syscall::ioctl:return /self->follow/ { self->follow = 0; exit(0); }
Этот пример также иллюстрирует использование threadlocal переменной. Здесь она используется для того чтобы ограничить вывод только теми вызовами, которые происходят в том же потоке команд, что и сам системный вызов. Прагма flowindent служит более наглядному представлению результата. Некоторые вышеизложенные детали позволяют понять, почему срабатывание датчика не заставит себя долго ждать и на каком исполняемом файле это произойдёт с очень большой вероятностью.
Заключение Мы рассмотрели базовую архитектуру DTrace и основные принципы её работы. Многое осталось за пределами первой части статьи, как, например, возможности, предоставляемые провайдером sdt (statically-defined tracing) для создания произвольных датчиков при разработке приложений. Используя такие датчики, можно реализовать динамический аналог вызова assert() для получения отладочной информации на работающем приложении или динамически включать дополнительные детальные логи при необычном поведении серверных приложений. Не было упомянуто о том, что провайдер pid умеет создавать динамические датчики для точек входа и выхода любого приложения, не требуя модификации его исходного кода. Более того, с его помощью можно даже трассировать отдельные инструкции любой функции. Рассказ об этих провайдерах и средствах визуализации будет в продолжении. Пока же приведу несколько ссылок, которые помогут вам продолжить изучение самостоятельно. В руководстве «Dynamic Tracing Guide» (последняя ревизия: http://docs.sun.com/app/docs/doc/819-3620) приводится подробное описание всех базовых провайдеров. Этот документ вкупе с «DTrace User Guide» (описывает основы DTrace: http://docs.sun.com/app/docs/doc/819-5488) содержит полную документацию по Dtrace. К качестве исходной точки для поиска дальнейших материалов в Интернет рекомендую посмотреть страницу сообщества DTrace на портале opensolaris.org (http://www.opensolaris.org/os/community/ dtrace). Там вы найдёте ссылки на литературу, статьи и публикации других сайтов. Из русскоязычных материалов в Интернете можно перечислить недавно запущеный в пилотном режиме – http://developers.sun.ru, жж-сообщество – http://community. livejournal.com/ru_opensolaris и сайт российской группы пользователей OpenSolaris – http://osug.ru.
11
администрирование
Frugalware 0.7 – Linux для бережливых?
Валентин Синицын Девиз этого дистрибутива звучит так: «Let's make things frugal!» или, в вольном переводе, «Давайте будем бережливее!». Посмотрим, насколько хорошо это удается команде разработчиков...
F
rugalware – сравнительно моло- ше придерживаться крупных решедой проект (версия 0.1 увиде- ний известных производителей вроде ла свет всего три года назад, Ubuntu, Red Hat, OpenSUSE, Mandriva 2 ноября 2004 года), разрабатываемый и т. д.? На этот вопрос мы и постара«группой молодых программистов» емся дать ответ. под чутким руководством венгра ВайFrugalware Linux – ответвление ны Миклоса (Vajna Miklos). Frugalware – Slackware, впрочем, изменившее своедистрибутив общего назначения, стре- го родителя практически до полной немящийся придерживаться принципа: узнаваемости. Любопытно, что на офи«простота, мультимедиа, дизайн». циальном сайте Frugalware о происFrugalware – динамично развивающий- хождении дистрибутива не говорится дистрибутив: текущая на момент на- ся – данную информацию можно пописания статьи версия имеет номер 0.7, черпнуть из Wikipedia [1] со ссылкой при этом 0.8pre1 уже доступна для ска- на интервью с Миклосом, которая чивания. Разработчики стремятся при- в настоящий момент уже не действудерживаться де-факто стандартного ет. Его целевая аудитория – продвив мире Linux полугодового релиз-цик- нутые пользователи, не боящиеся рала, при этом стабильная версия полу- боты в командной строке и не ждущие чает только исправления безопаснос- от системы обилия графических масти, в то время как ветвь -current обнов- теров настройки. В этом смысле он ляется ежедневно. Имеет ли смысл похож на Slackware или, скорее, Arch обратить на него внимание или луч- Linux. С последним его роднит еще
12
одно обстоятельство – менеджер пакетов. И Arch, и Frugalware используют для этих целей pacman Джуда Винетта (Judd Vinet), правда, здесь он основательно переписан и называется pacman-g2 [2]. Дерево ABS (Arch Build Tree) во Frugalware трансформируется в FST (Frugalware Source Tree) и является опцией для разработчиков, так что любителей пересобирать любимое ПО из исходников ждет легкое разочарование (если это про вас, установите pacman-tools и воспользуйтесь утилитой repoman сотоварищи). Пакеты Frugalware представляют собой обычные архивы tar.bz2 (информация о зависимостях в них присутствует) и, как правило, имеют расширение fpm. Дистрибутив официально поддерживает архитектуры x86 (i686 и выше) и x86_64. Оригинальность Frugalware прояв-
администрирование
Скучный процесс инсталляции можно скрасить игрой в тетрис
ляется уже на странице загрузки: вместо традиционных MD5-сумм для проверки целостности образа здесь используются более стойкие SHA1. Любовь разработчиков к этому хэш-алгоритму чувствуется и дальше: именно он фигурирует в PKGBUILD (скриптах для сборки двоичных пакетов) и других подобных местах. Кстати, пока вы еще находитесь на сайте, обратите внимание на русскоязычные меню (а если повезет – и на текст страницы). Несмотря на свои славянские корни, Frugalware не поддерживает русский язык на официальном уровне, и это, по сути, единственное место, где кириллицей можно наслаждаться без дополнительных телодвижений. Политика разработчиков в области локализации проста – Frugalware поддерживает все языки, для которых существуют официальные пакеты, но инсталлятор и специализированные инструменты переведены помимо английского лишь на датский, немецкий, французский, венгерский и словацкий. К счастью, заставить дистрибутив «говорить» по-русски не так уж сложно – Linux Cyrillic HOWTO вам в помощь. Frugalware Linux 0.7 (Sayshell), о котором пойдет речь в данной статье, доступен для загрузки на CD (13 штук) или на DVD (2 штуки); по утверждению разработчиков, обычно бывает достаточно скачать только первые два CD или один DVD. Кроме этого, существуют мини-образы (около 45 Мб) для инсталляции через Интернет.
Установка В качестве тестового набора был выбран набор из двух CD для архитекту-
№12, декабрь 2007
Больше приложений? Нет, спасибо — сначала уберите половину!
ры x86. Первые несколько попыток за- тор нигде не сообщает о размещении вершились провалом: как оказалось, выбранных пакетов по компакт-дисFrugalware не слишком дружит с вирту- кам, а просто предлагает «Вставить альными машинами. В VirtualBox 1.5.2 очередной диск, если он у вас есть, инсталлятор «падал» из-за двойно- или же нажать кнопку No». Что прого освобождения памяти, в Parallels изойдет в случае, если выбранные ваWorkstation 2.2 – периодически за- ми пакеты оказались на отсутствуювисал, и только VMware Server отра- щем CD, не сообщается, но итоговая ботал от начала и до конца (просьба система получается вполне работосне рассматривать данное предложе- пособной. ние как рекламу продуктов VMware, В целом, если отвлечься от этой неInc). Инсталлятор Frugalware – тексто- дружелюбности, инсталлятор Frugalware вый и весьма напоминает таковой все нормально справляется со своей задав том же Arch Linux. В принципе ниче- чей. В первую очередь вам предложат го другого от дистрибутива «для про- выделить и отформатировать раздедвинутых пользователей» мы и не жда- лы (рекомендуем не менее 6 Гб, следуя ли: человека, способного выжить в ко- современным тенденциям, Frugalware мандной строке, Ncurses не испуга- использует libata, так что не удивляйешь. Тем не менее удобству использо- тесь устройствам /dev/sda в системе вания можно было бы уделить поболь- с IDE-дисками) и сформировать RAIDше внимания: программа «не проща- массивы, если в этом есть необходиет ошибок» и часто не дает вернуться мость. Затем происходит копирование назад, чтобы их исправить. Справед- файлов (скоротать время до его заверливости ради следует отметить, что шения можно, играя в тетрис – он люинсталляторы Arch и Slackware ведут безно запущен на vt5), после которосебя аналогичным образом, но тот же го производится первичная настройка Arch настоятельно рекомендует уста- системы: установка загрузчика (GRUB), новить на первом этапе лишь базо- типа мыши, сетевых параметров (влавую систему, а все остальное добавить дельцам ADSL-модемов будет приятуже из оболочки. В случае же двух CD но узнать, что Frugalware поддержива(а тем более – DVD) с пакетами веро- ет PPPoE, но, увы, не PPTP), часового ятность пометить что-то не то возрас- пояса и конфигурирование X Window тает многократно. К счастью, поми- System. Все указанные инструменты мо «экспертного» режима с выбором можно вызвать и в уже установленной отдельных пакетов существует так- системе командой setup. же «простой», где необходимо лишь Утилита xconfig показала себя указать категории. Нам показалось не с лучшей стороны: после выбора интересным изучить подборку паке- разрешения и глубины цвета экран тов по умолчанию, поэтому здесь мы на секунду погас, а затем появился все не стали вносить никаких изменений. тот же диалог – ни сообщения об ошибДругое недоразумение связано с ус- ке, ни уведомления об успешном затановочными носителями: инсталля- вершении. Отладочный терминал (vt4)
13
администрирование А вот в том, что касается подборки ПО, Frugalware находится на высоте. В репозиториях дистрибутива содержится около 3500 пакетов. Frugalware 0.7 базируется на ядре 2.6.22 и включает glibc 2.6.1, gcc 4.2.1, Perl 5.8.8, Python 2.5.1, Ruby 1.8.6, Mono 1.2.5.1 (исполняемый файл mono даже назначается в качестве обработчика .exe-сборок в момент старта системы), Apache 2.2.6, Postfix 2.4.5, MySQL 5.0.45, PostgreSQL 8.2.5, Samba 3.0.26, OpenOffice.org 2.3.0, Mozilla Firefox 2.0.0.8 и Thunderbird 2.0.0.6. Огорчает только отсутствие NetworkManager и каких-либо других распространенных средств управления соединением (в том числе беспроводным), кроме wpa_supplicant с его родным GUI. Возможно, дело в том, что разработчики Frugalware уже позаботились об этом самостоятельно. Входящая в состав дистрибутива утилита Gnetconfig хотя и недотягивает до NM, но легко справляется с проводными сетями и PPPoE, а также Даже продвинутым пользователям иногда хочется расслабиться. поддерживает профили («дом», «офисная сеть» и т. п.). ПоGnetconf поможет настроить сеть способом «выбери и щелкни» мимо нее, во Frugalware 0.7 доступены собственный графитоже «молчал». Как оказалось впоследствии, ошибка все ческий менеджер пакетов Gfpm и редактор служб Frugalware же происходила – вместо драйвера vesa утилита почему-то Runlevel Editor. Дистрибутив разрабатывается за пределапыталась задействовать vga, который, естественно, не мог ми США, а значит, с проигрыванием MP3, двоичными драйсправиться ни с предложенными 1024x768x32, ни с более верами Nvidia/ATI и тому подобным тоже нет никаких пробскромными 800x600x16. Простое редактирование файла лем. Установить необходимые пакеты, будь то кодеки или /etc/X11/xorg.conf после установки системы мгновенно ре- поддержка записи на разделы NTFS (средствами ntfs-3g), шило эту проблему. в большинстве случаев можно одной командой:
Первый запуск
pacman-g2 -S имя_пакета
Ну вот наконец система установлена – можно извлекать компакт-диск и перезагружаться. Как и все современные Добавив всего две буквы (pacman-g2 -Suy), можно полдистрибутивы, Frugalware 0.7 скрывает вывод rc-скрип- ностью синхронизировать систему с репозиториями разтов за spalsh-заставкой, которую, впрочем, можно отклю- работчиков – это особенно полезно, если вы хотите «обночить, добавив параметр nosplashy к командной строке яд- виться до -current». Рекомендуемые и опциональные завира в меню GRUB. симости, как в Ubuntu/Debian, не поддерживаются, но автоПо субъективным ощущениям, старт дистрибутива про- матическое разрешение обычных «жестких» у Pacman заисходит весьма быстро. В настройке по умолчанию загрузка труднений не вызывает. происходит на 4 уровень (runlevel), при этом запускаются такие службы, как D-BUS, HAL, Avahi, SSH, Postfix... Несколь- Разбор полетов ко странный набор как для настольного ПК, так и для серве- После прочтения данной статьи может сложиться впечатра. В качестве менеджера дисплея (кстати, X-экран созда- ление об общей негативной оценке дистрибутива – это ется не на привычном 6-7, а на 12 терминале) используется не вполне верно. Frugalware, конечно, испытывает «болезни KDM, в качестве рабочего стола по умолчанию – соответс- роста» и прочие трудности, связанные с развитием, силами твенно KDE (3.5.7). Помимо этого, доступны GNOME 2.20, группы энтузиастов, в которой каждый делает то, что ему IceWM и несколько легковесных оконных менеджеров, в об- нравится. Но тем не менее это достаточно интересный щем, есть из чего выбрать. Жаль только, что разработчи- и вполне работоспособный дистрибутив. Едва ли его можки не учли маленькой детали и меню получилось черес- но рекомендовать тем, кому надо «дело делать, а не глучур перегруженным нерелевантными приложениями: к че- постями заниматься» (автор вообще не склонен предламу, например, иметь в KDE редактор Gconf? Простая стро- гать решения в стиле Frugalware или Arch для использовака «OnlyShowIn=KDE/GNOME» в файлах .desktop могла бы ния на предприятии), но желающим разобраться во внутисправить ситуацию, но, увы, этого сделано не было. ренней механике современной Linux-системы он может соВообще создается впечатление, что команда еще служить очень хорошую службу. Да, вы также можете попне пришла к единому мнению относительно того, как дол- робовать себя в роли разработчика – во Frugalware есть жен выглядеть рабочий стол Frugalware. Предлагая по умол- что улучшить для русскоязычного пользователя. чанию среду KDE, они снабжают дистрибутив собственными графическими конфигураторами на GTK+, в качестве те- 1. Страница Frugalware на Wikipedia – http://en.wikipedia.org/wiki/ мы визуального оформления выбрана QtCurve, унифицируFrugalware. ющая внешний вид приложений KDE и GNOME, но – толь- 2. Pacman-g2 на Frugalware Wiki – http://wiki.frugalware.org/ ко для рабочего стола KDE. На работоспособность это, коPacman‑G2. нечно, не влияет, но ощущение целостности системы не- 3. Официальный сайт Frugalware Linux – frugalware.org. сколько смазывается. 4. Сайт проекта Arch Linux – www.archlinux.org.
14
администрирование
Citadel – Open Source-решение для коллективной работы
Сергей Яремчук В 1980-90-х годах одной из популярных платформ для организации BBS был Citadel, в 1998 году разработчики начали расширять его функциональность, и постепенно Citadel превратился в удобную систему для организации коллективной работы. 16
администрирование
В
ообще-то правильнее называть Citadel/UX (то есть UNIX), так как клонов оригинальной Citadel было создано много. Изначально проект ориентирован исключительно на UNIXсистемы – Linux и *BSD, это и хотели подчеркнуть в имени проекта. Хотя сами разработчики для краткости используют также имя Citadel, аргументируя это еще и тем, что это пока единственный активный проект с таким именем. Некоторое время проект развивался без лишнего шума, готовое решение было представлено общественности приблизительно в 2002 году. Первое время в Citadel часто находили уязвимости разной степени серьезности, но теперь по прошествии стольких лет разработки ситуация изменилась в лучшую сторону. Распространяется Citadel по лицензии GNU GPL. Кроме указанных систем, точно будет работать в Solaris и Mac OS X.
Возможности Citadel В журнале уже шел разговор об одной из систем для групповой работы eGroupware [1], там же дано краткое описание некоторых имеющихся решений. Citadel построен по клиент-серверной архитектуре и обеспечивает работу как пользователям, подключающимся по коммутируемым соединениям (вроде Fidonet), так и через Интернет. В его состав включено большое количество приложений, обеспечивающих самые разнообразные функции. Системный администратор, установивший Citadel, обнаружит целый ряд сервисов: n BBS (Bulletin Board System) со всеми типичными функциями; n почтовый сервис, обеспечивающий работу по протоколам IMAP, POP3, ESMTP со встроенной поддержкой аутентификации пользователя, сортировки и фильтрации сообщений при помощи Realtime Blackhole Lists (RBL) и SpamAssassin, а также языка фильтрации Sieve и списков рассылки; n чат, форум, открытые и приватные комнаты общения (room); n календарь с поддержкой протоколов Webcal/GroupDAV, список задач.
№12, декабрь 2007
Изменение внешнего вида WebCit Несмотря на то, что WebCit также написан на С, разработчики предусмотрели ряд механизмов, позволяющих изменить как внешний вид, так и выводимые сообщения. Так, за то, как будет выглядеть выводимая страница, отвечает CSS-файл static/ webcit.css. Трогать его не нужно. Достаточно создать в другом каталоге static.local файл с таким же именем, он будет считываться после основного и аннулирует все его настройки. С его помощью можно изменить как вид окна входа в систему, так и рабочее пространство, появляющееся после регистрации.
Сообщения и помощь, выводимые при регистрации пользователей как в консоли, так и WebCit, записаны в нескольких файлах, находящихся в подкаталогах messages и help, каталога, в который установлен сервер Citadel. Их содержимое можно изменить, записав свои сообщения на выбранном языке, только не забывайте использовать редактор, поддерживающий UTF-8. Для локализации интерфейса в Citadel используется GNU Gettext, в архиве WebCit находится файл шаблона для переводчиков webcit/po/webcit.pot (см. рис. 1).
А еще адресная книга с поддержПрактически все функции Citadel кой vCard и LDAP, заметки, агрега- реализованы в контейнерах, также тор RSS, простой консольный клиент называемых room, поэтому при необдля подключения к серверу, публич- ходимости добавить любую функционые каталоги и другие. Некоторые не- нальность очень просто. нужные сервисы после установки можПротокол GroupDAV в настоящее но отключить. время поддерживается KDE Kontact, Для всех протоколов реализована Evolution и частично Mozilla Sunbird. поддержка SSL/TLS для безопасной В качестве почтового клиента можаутентификации и передачи данных. но использовать любой из доступСписки рассылки могут быть двух ных: Microsoft Outlook, The Bat!, Mozilla видов: list и digest. Thunderbird и так далее. По умолчанию для обмена сообВ первом случае сообщения получателям доставляются индивидуально, щениями используется UTF-8, поэтов поле «От» будет стоять адрес авто- му проблем с кодировками нет. ра сообщения. Citadel различает типы MIME, поВо втором случае в поле «От» бу- этому, например, при добавлении нодет стоять адрес «room», что позво- вого контакта с использованием vCard лит пользователю ответить на адрес он может быть добавлен в глобальную комнаты. базу сервера.
Рисунок 1. Окно регистрации пользователя
17
администрирование Уровни доступа пользователей Citadel Пользователь в Citadel может иметь один из 7 уровней доступа, администратор в настройках может указать, к какому уровню будет принадлежать новый пользователь. 0 – Deleted – учетная запись, у которой уровень установлен в 0, будет удалена; 1 – New User – новый не подтвержденный пользователь, получает доступ только на чтение сообщений, отправлять сообщение из комнаты «Mail>» может только администратору; 2 – Problem user – ограниченная учетная запись, используется например, для условного тестового доступа;
3 – Local User – может отправлять сообщения только внутри Citadel, без выхода наружу; 4 – Network User – может вводить сообщения в каждой доступной комнате; 5 – Preferred user – имеет доступ к привилегированным комнатам и к администрированию некоторых функций; 6 – Aide – администратор системы, отдельные пользователи могут получать права этого уровня в отдельных комнатах, также есть возможность автоматического задания таких прав для пользователей, создавших приватные комнаты.
Для быстрого поиска возможно и без проблем обеспечивает одновреиндексирование информации на фо- менную работу большого числа польрумах, BBS, адресной книге и других зователей, без ограничений на колиоткрытых ресурсах. чество и размер сообщений. Данные и сообщения хранятся Отдельно предлагается WebCit – простой, интуитивный и интерактив- в Berkeley DB, если письмо адресованый веб-интерфейс, реализованный но нескольким пользователям, на жестс использованием AJAX. С его помо- ком диске все равно хранится только щью пользователь может получить одна его копия. Один сервер может доступ ко всем функциям, предостав- обслуживать несколько виртуальных ляемым Citadel, а в распоряжении ад- доменов. министратора и удобная система упТакже возможна совместная раборавления настройками сервера. Под- та нескольких серверов Citadel, обслудерживается любой браузер, умеющий живающих в том числе и разные домеработать с cookies и фреймами, для по- ны с репликацией данных между ними. лучения мгновенных сообщений нужно Учетные записи любого домена при неразрешить всплывающие окна. обходимости могут быть сохранены К сожалению, в списке поддержи- на любом из серверов Citadel. ваемых языков отсутствует русский Ознакомиться с работой Citadel (см. врезку «Изменение внешнего ви- и, в частности, WebCit как обычный да WebCit»). пользователь, можно свободно, зареКомпоненты citadel написаны на С, гистрировавшись по ссылке [3]. Это расервер поддерживает многопоточность бочая система, в которой разработчи-
ки обмениваются информацией с пользователями. В Live CD дистрибутиве Myrinix [4] доступен модуль Citadel, который можно добавить при самостоятельной сборке. Кроме того, на сайте проекта доступен образ для виртуальной машины VMware с полностью настроенной операционной системой и Citadel.
Установка Citadel Перед установкой необходимо удалить все сервисы (groupware, почтовые и прочие), которые могут конфликтовать с Citadel по портам и файлам. Хотя не исключается возможность совместной работы Exim, Postfix и некоторыми другими серверами. WebCit может использовать встроенный или внешний веб‑сервер, вроде Apache. Для тех, кто не хочет самостоятельно компилировать приложение, разработчики предлагают свой репозитарий и скрипт «easy install». Второй вариант очень прост, чтобы он работал, требуется только наличие find, wget (или curl). Все остальное, включая зависимости, будет автоматически скачано и установлено. Сначала устанавливаем компилятор и некоторые библиотеки в Debian/ Ubuntu, команда проста: $ sudo apt-get update $ sudo apt-get install ↵ build-essential curl libssl-dev
Список пакетов для openSUSE, SUSE и RedHat/Fedora и клонов приведен на сайте проекта. Для работы скрипта необходимо использовать права root: $ sudo curl http:// ↵ easyinstall.citadel.org/ ↵ install | sh
или $ sudo wget -q -O - http:// ↵ easyinstall.citadel.org/ ↵ install | sh
Рисунок 2. Консоль Citadel
18
Скрипт создаст подкаталоги citadel и webcit в /usr/local, в которые и установит компоненты Citadel, сопутствующие библиотеки будут установлены в ctdlsupport. В процессе установки будет задано несколько вопросов по настройкам будущей системы.
администрирование
Рисунок 3. Окно настройки сетевых сервисов
Таким же образом можно очень просто обновлять уста- но для работы, регулируется запуском скрипта /etc/init.d/ новленную Citadel. apache2 или webcit. Кроме этого, разработчики предоставляют репозитарий Дальше запрашиваются адреса интерфейсов, на котодля Debian/Ubuntu, в котором пакеты собраны для архитек- рых Citadel будет принимать входящие соединения, по умолтур i386 и amd64. Чтобы установить Citadel с его помощью, чанию установлено на всех, то есть 0.0.0.0. Оставляем или изменяем название учетной записи аддостаточно добавить в /etc/apt/sources.list: министратора и указываем метод аутентификации польdeb http://[debian|ubuntu].citadel.org/[debian|ubuntu]/ ↵ зователей. [sid|sarge|sarge_bdb44|etch|breezy|gutsy|feisty] ↵ По умолчанию предлагается встроенная база данных main пользователей, которые при этом могут не иметь учетные Для установки в Ubuntu 7.10 Gutsy Gibbon я использо- записи в системе, но можно использовать /etc/passwd, NIS вал команду: или LDAP. deb http://ubuntu.citadel.org/ubuntu/gutsy main
и чтобы установить исходные тексты: deb-src http://debian.citadel.org/source stable source
После этого стандартные: $ sudo apt-get update $ sudo apt-get install citadel-suite
В результате было скачано и установлено 10 пакетов. В процессе установки пакета citadel-webcit был выдан запрос об интеграции с Apache. Возможен выбор из: Apache, Apache-SSL, Apache2, All и Internal. Последний вариант предполагает использование внутреннего веб-сервера. Если у вас есть сомнения, можно выбрать самый простой вариант – «All». В этом случае будут созданы все необходимые настройки, а что конкретно будет использова-
№12, декабрь 2007
Установка при помощи исходных текстов Самостоятельная сборка не трудна, при наличии всего необходимого для удовлетворения зависимостей проблем обычно не возникает. Кроме компилятора, понадобится Berkeley DB от 4.1, libical от 0.26 и libSieve от 2.2.3 и библиотеки SSL. Если будете их устанавливать из репозитария дистрибутива, не забудьте и devel-пакеты с исходными кодами. Перед началом установки сервера необходимо создать учетную запись citadel, от имени которой будет работать сервер и пользователи Citadel. В документации рекомендованная строка в /etc/passwd для этого пользователя выглядит как: citadel::100:1:Citadel ↵ Login:/usr/local/citadel:/usr/local/citadel/citadel
По умолчанию Citadel устанавливается в раздел /usr/ local, если при конфигурировании указано его другое раз-
19
администрирование мещение (./configure --prefix=), этот путь также следует изменить. Последняя запись /usr/local/citadel/citadel показывает на оболочку, которая будет доступна пользователям при их регистрации при помощи telnet (см. рис. 2). По поводу группы, в которую должен входить пользователь Citadel, ничего не сказано. Но группа с GID 1 это обычно root. После установки пакета в Ubuntu эта запись выглядит по-иному: citadel:x:110:1001:Citadel ↵ system user,,,:/var/lib/citadel:/bin/false
Пользователь входит в группу citadel (GID – 1001), использование shell будет недоступно данной учетной записи. Сама же оболочка для входа расположена в /usr/bin/citadel. Это необходимо помнить, и изменить запись в /etc/passwd, если такая функциональность понадобится. То есть команды для добавления пользователя в общем случае могут выглядеть так: $ sudo addgroup citadel $ sudo adduser --system --no-create-home ↵ --home /usr/local/citadel --shell
Но это еще не все. Чтобы пользователь, входя в систему через telnet, попадал не в командную строку, что требует наличия учетной записи в системе, а сразу в оболочку Citadel, дополнительно следует создать файл /etc/xinetd.d/ telnet, такого содержания: service telnet { flags = REUSE socket_type = stream wait = no user = root server = /usr/sbin/in.telnetd server_args = -L /usr/local/citadel/citadel # или в Ubuntu # server_args = -L /usr/bin/citadel log_on_failure += USERID disable = no }
Не забыв установить собственно xinetd (в Ubuntu: «sudo apt-get install xinetd»). При конфигурировании следует обратить внимание на вывод скрипта. Например WebCit.
Пример опять для WebCit. $ cd /usr/local/webcit/ $ sudo ./setup
Скрипт задаст несколько вопросов по настройкам, основной из которых – необходимость в автоматическом запуске приложения при загрузке системы. После окончания работы приложение можно запускать. Если не планируется использовать Apache, вводим: $ sudo /usr/local/webcit/webserver … Text domain Charset: UTF8 Changing directory to /usr/local/webcit/ Attempting to bind to port 2000... …
Шаблона для запуска через Apache в поставке WebCit нет. В Ubuntu для этих целей используется файл /etc/citadel/ webcit.conf, символическая ссылка на который расположена в /etc/apache2/sites-available: <location /webcit> Allow from all </location> <location /listsub> Allow from all </location> <location /groupdav> Allow from all </location> ProxyPass /webcit/ http://127.0.0.1:8504/webcit/ ProxyPassReverse /webcit/ http://127.0.0.1:8504/webcit/ ProxyPass /listsub/ http://127.0.0.1:8504/listsub/ ProxyPassReverse /listsub/ http://127.0.0.1:8504/listsub/ ProxyPass /groupdav/ http://127.0.0.1:8504/groupdav/ ProxyPassReverse /groupdav/ ↵ http://127.0.0.1:8504/groupdav/ ProxyPass /who_inner_html ↵ http://127.0.0.1:8504/who_inner_html ProxyPassReverse /who_inner_html ↵ http://127.0.0.1:8504/who_inner_html alias /static /usr/share/citadel-webcit/static alias /tiny_mce /usr/share/tinymce/www
Обратите внимание на используемый порт. При использовании встроенного веб-сервера подключаться следует к 2000 порту, в варианте, предложенном сборщиком пакета для Ubuntu – 8504. После установки сервера Citadel команwebcit-7.24 $ ./configure да netstat покажет несколько открытых портов: 25 (SMTP), 110/995 (POP3/S), 143 (IMAP), 504 (Citadel), 587 (SMTP-MSA) … zlib compression: yes и 2020 (Sieve). Calendar support: yes В поставку WebCit входит встраиваемый редактор Character set conversion support: yes National language support: yes TinyMCE, но в пакетах Ubuntu его нет. При установке создаются ключи и сертификаты для TLS, Если хоть в одной из позиций не будет стоять yes, ко- которые хранятся в подкаталоге keys в файлах citadel.key, манда make закончит свое выполнение с ошибкой. Если citadel.cer и citadel.csr. все нормально: Вот и вся установка. Кроме исходных текстов сервера Citadel и WebCit, на сайте проекта можно найти ссыл$ make ки на три программы. Это утилита RSS2CTDL, предна$ sudo make install значенная для трансляции RSS потоков в комнаты Citadel, Затем как в случае установки сервера Citadel, так и в новой версии в ее использовании уже нет необходимосWebCit следует перейти в каталог, в который он установ- ти. И два модуля, предназначенных для подключения программ на Perl и PHP к Citadel. лен, и запустить скрипт setup.
20
администрирование Администрирование Citadel Для администрирования Citadel можно использовать командную строку или WebCit. Список команд, вводимых в консоли, можно узнать из документа «CITADEL Admininistration Manual». Например, чтобы создать новую четную запись, вводим: Lobby> . Aide edit User
После чего отвечаем на ряд вполне стандартных вопросов. Настройки сервера можно произвести, введя: Lobby> . Aide System configuration ↵ General
Рисунок 4. Создание учетной записи
По умолчанию разрешена регистрация всем пользователям. Первый зарегистрировавшийся пользователь получает доступ администратора уровня Aide (более подробно см. врезку «Уровни доступа пользователей Citadel»). Внешний вид окна WebCit у пользователя разных уровней не отличается, только у администратора появляется дополнительная вкладка «Administrator», в которой и производятся все настройки системы. Настройки понятны любому опытному пользователю. Выбирая подпункты во вкладке «Administrator», можно отключить ненужные сервисы (например, оставив только защищенные аналоги), глобально запретить отсылать/ получать почту из Интернета, настроить пересылку почты на другие сервеРисунок 5. Календарь Citadel ры, фильтрацию, запретить самостоятельную регистрацию пользователей, подключиться к се- ций вроде BBS. Простота в установке и удобство настройке позоляют начинающему администратору использовать ти Citadel и многое другое. В комплект входит и несколько вспомогательных ути- его просто как почтовый сервер. Для небольшой и средней лит: aidepost, whobbs, msgform, userlist и sendcommand. На- организации его будет вполне достаточно. Следует отметить и весьма неплохую документацию пример, userlist позволяет получить список пользоватепроекта, которая хотя и на английском, но при базовом зналей системы. нии языка вполне достаточно, чтобы разобраться с особен$ sudo userlist ностями работы этого сервера. User Name Num L LastCall Calls Posts ------------------------- ----- - ---------- ----- ----grinder 1 6 11/23/2007 2 9 sergej 2 4 11/24/2007 3 3 vasja 3 4 11/23/2007 1 3
Заключение Итак Citadel, весьма интересная система для организации групповой работы, имеющая ряд дополнительных функ-
№12, декабрь 2007
1. Яремчук С. Устанавливаем eGroupware. //«Системный администратор», № 3, 2007 г. – С. 36-41. 2. Сайт проекта Citadel – http://www.citadel.org. 3. Рабочая версия Citadel – https://uncensored.citadel.org. 4. Сайт проекта Myrinix liveCD – http://www.myrinix.com. 5. Сайт проекта Berkeley DB – http://www.sleepycat.com. 6. Сайт проекта libical – http://www.aurore.net/projects/libical. 7. Сайт проекта libSieve – http://libsieve.sourceforge.net.
21
администрирование
GNU Autotools: ошибки свои и чужие
Рашид Ачилов GNU Autotools, комплект скриптов, предназначенный для облегчения процесса построения сложных программных проектов, является чрезвычайно удобной и мощной системой. Есть тут только одно «но» – эта система очень плохо документирована. Поэтому если при сборке чужого проекта неожиданно возникает ошибка, то чувство растерянности – и что тут делать дальше? – вполне уместно. Прочитав эту статью, вы узнаете о том, как программы Autotools связаны между собой и как можно исправить чужие ошибки, не наделав своих.
Анатомия Каждый программист знает, что соСейчас уже трудно себе представить, провождение программных проектов, что когда-то для сборки любого про- в которые входят хотя бы два файла граммного проекта сначала необхо- и одна внешняя библиотека, – это додимо было тщательно читать различ- статочно сложное и муторное дело – ные README, INSTALL и другую доку- необходимо позаботиться о том, чтоментацию – большую часть работы по бы в системе оказались все нужные выполнению нужных проверок и со- функции и вспомогательные програмзданию файла Makefile берет на себя мы, чтобы были установлены подхоскрипт configure. Но ведь и сам скрипт дящие библиотеки требуемых версий. configure должен создаваться каким-то Также надо найти места, где дополниобразом? В этом и состоит роль GNU тельные программы установлены, заAutotools – в упрощении работы по со- нести в Makefile перечень всех файлов провождению программных проектов. с исходным текстом и предусмотреть 22
обработку специальных файлов, если они есть. При этом, конечно же, не забыть создать все каталоги и перечислить нужные библиотеки при компиляции и сборке. Приходится делать множество вещей, которые повторяются раз от раза для каждого из разрабатываемых программных проектов. Все это хорошо знал и Дэвид МакКензи (David MacKenzie), разработавший в 1992 году первый компонент GNU Autotools – программу Autoconf. В 1994 году им же была написана первая версия программы Automake,
администрирование позже полностью переписанная Томом Троми (Tom Tromey). В 1996 году в состав GNU Autotools вошел третий важный компонент – Libtool, написанный Гордоном Матцигкейтом (Gordon Matzigkeit). В 1998 году GNU Autotools были портированы под Windows Яном Лэнсом Тейлором (Ian Lance Taylor). Почему же эти скрипты так важны, чем они так облегчают жизнь программисту? Autoconf предназначен для создания скрипта configure, который выполняет первую важную задачу – проверяет наличие в системе тех или иных функций (в библиотеках) и наличие тех или иных библиотек необходимых версий, проверяет наличие вспомогательных программ, запоминает все сделанные настройки и формирует файл Makefile (а также другие файлы, формирование которых задано) на основе Makefile.in (и других файлов с расширением .in). В качестве дополнительного источника макросов, используемых при проверке, испольузется файл acinclude.m4, если он есть в текущем каталоге. К числу обычно формируемых дополнительных файлов, как правило, относится файл config.h, который содержит определения типа #undef HAVE_LIBJPEG #define HAVE_LIBICONV
1
Исходным файлом д ля создания скрипта configure является файл configure.in (еще он может называться configure.ac). Сразу же возникает вопрос – а откуда берутся исходные версии файлов, то есть Makefile.in, configure.in, config.h.in? Можно создавать их вручную, в текстовом редакторе, а можно использовать Automake. Automake – это второй скрипт из пакета GNU Autotools. В цепочке преобразований вспомогательных файлов он стоит впереди. Automake создает файлы, которые затем используются как входные файлы для Аutoconf. Для более полного понимания механизма работы GNU Autotools вся цепочка преобразований основных файлов изображена на схеме. Основной задачей Automake является создание файла Makefile.in, то есть генерация некоторого набора стандартных мишеней, с учетом списка исходных файлов и некоторых спе-
№12, декабрь 2007
Диаграмма зависимостей для GNU Autotools
циальных действий. Ну в самом деле, в каждом программном проекте есть мишени all, install, clean, distclean и т. д. Почему бы не написать некий скрипт, который из предъявленного списка файлов исходных текстов будет формировать Makefile.in? Этим и занимается automake. Он обрабатывает специальный входной файл под названием Makefile.am. Он содержит так называемые «примитивы» (Primaries), которые используются для формирования мишеней, а также правила и переменные, которые просто копируются в Makefile.in, при этом заменяя собой подобное стандартное правило или переменную, если таковые имеются. Кроме того, в зависимости от режимов работы, Automake может создать набор вспомогательных файлов, которые требуются во всех проектах, соответствующих файловой структуре GNU, – COPYING, INSTALL, NEWS, TODO, README. Ну хорошо, Makefile создан. Но мало прописать нужные мишени – нужно еще проследить, чтобы в переменных, задающих флаги компиляции, были прописаны нужные заголовочные файлы, а в переменных, задающих флаги сборки, – нужные библиотеки, чтобы эти заголовочные файлы и библиотеки существовали и были доступны. Этим занимается последний основной скрипт из GNU Autotools – Libtool. В отличие от первых двух, Libtool не имеет исходного конфигурационного файла. Поддержка Libtool может быть встроена в исходные файлы configure.in и Makefile.am:
n в configure.in вписывается одна строка – макрос AC_PROG_LIBTOOL;
n в Makefile.am используются другие примитивы (например, LTLIBRARIES вместо LIBRARIES). После того как configure отработает и создаст все необходимые файлы в текущем каталоге, появится скрипт, который и будет называться Libtool. Этот скрипт будет использоваться в процессе работы для компиляции и сборки программ. Кроме того, в GNU Autotools входят некоторые вспомогательные программы: n Autoscan – предназначена для первоначального создания файла configure.in. Сканирует все файлы проекта и создает файл configure.ac, в который заносит макросы по поиску использованных в файлах функций и некоторых программ. n Autoheader – предназначена для создания файла config.h.in. Точно так же сканирует все файлы проекта и создает файл config.h.in на основе использованных заголовочных файлов. Может использовать файл aclocal.m4, если он существует в текущем каталоге. n Aclocal – предназначена для создания файла aclocal.m4, который содержит локальные макросы для Automake. Эти макросы могут быть заданы в командной строке или присутствовать в файле configure.ac. Более полное опис ание GNU Autotools, правда, на английском язы-
23
администрирование ке, можно получить, установив порт devel/autobook, а также из info autoconf‑2.61, info automake-1.9.
Физиология
Пока все стандартно, без ошибок, без особенностей. Запускаем gmake... и удивляемся: # /bin/sh ../libtool --silent --tag=CXX --mode=link ↵ g++ -g -O2 -L/usr/local/lib -L/usr/X11R6/lib ↵ -o kdialogd3 kdialogd.o -lkio -lkdecore -lqt-mt
Ну хорошо, нам известны компоненты пакета GNU Autotools и примерная взаимосвязь между ними: сначала запускает/usr/bin/ld: cannot find -lkio ся aclocal, потом Automake, потом Autoconf. Как все это возgmake[2]: *** [kdialogd3] Error 1 можно применить для сборки чужой программы, загруженной, допустим с Sourceforge.net? А удивляемся мы от того, что здесь совершенно отсутсПрежде всего отмечу, что autotools hell (буквально твуют указания на то, где искать библиотеки KDE. А это зна«ад autotools», ситуация, когда из-за установки большого чит, что configure не выполняет своих функций. Посмотрев количества разных версий autotools, использующих оди- файл config.log, который создается после каждого выполнаковые имена файлов, возникала очень большая путани- нения configure и содержит вывод всех тестов и диагностица), связанный с необходимостью иметь на машине разра- ческие сообщения, убеждаемся – да, в configure просто-наботчика Autoconf всех версий от 2.13 до 2.61 включитель- просто отсутствует блок тестирования наличия KDE, вот тано, кончился относительно недавно, с появлением в пор- кие могут быть неаккуратно написанные скрипты. А может тах autoconf-wrapper и automake-wrapper. Нет, иметь на ком- быть, у автора KDE стоял в /usr/local, а о том, что он может пьютере все эти версии по-прежнему необходимо. Но те- находиться в другом месте, он и не подумал. перь для их поиска можно пользоваться врапперами, коДобавляем в configure.in одну строчку – макрос поиска торые поддерживают стандарт наименования, принятый KDE AC_PATH_KDE. На самом деле мы этим добавляем цев Linux, например, autoconf‑1.7, вместо принятого в FreeBSD лую огромную цепочку макросов (которая уже присутствует наименования autoconf17. Кроме того, нужные версии про- в acinclude.m4), которая выполнит поиск QT, KDE, набор неграмм можно задать через переменные окружения – мож- обходимых тестов и установит соответствующие переменно в стартовом скрипте: ные. Грамотный разработчик, конечно же, спросит, не читая дальше: «А почему именно AC_PATH_KDE? А где полsetenv AUTOTOOLS_DEBUG "yes" ный список макросов?». Честно скажу, что не знаю. Файл setenv AUTOCONF_VERSION "261" acinclude.m4 со списком макросов, относящихся к KDE, setenv AUTOMAKE_VERSION "19" при создании через Kdevelop нового проекта, относящегоТаким образом мы устанавливаем в любом случае исполь- ся к KDE, появляется в каталоге admin. Или же его можно зование Autoconf 2.61 и Automake 1.9. А можно через ко- взять из любого другого проекта. Выбираем AC_PATH_KDE манду env: потому, что этот макрос служит для поиска пути, куда установлен KDE, и по мере выполнения будет вызывать другие # env AUTOCONF_VERSION="259" autoconf необходимые макросы. Но это будет потом. Сейчас же нужно пересоздать сам Таким образом мы используем Autoconf 2.59, но только configure: для этой команды! # env AUTOCONF_VERSION=259 autoconf Итак, в общих чертах цепочка выстраивается следующая: aclocal → autoheader → automake → autoconf (см. схему). Если попытаться запустить Autoconf, не указывая верТеперь от теории переходим к практике и пробуем соб- сии, то можно получить нечто невразумительное типа: рать программу, которая отсутствует в портах. Вручную, configure.in:6: error: Autoconf version 2.58 or higher is required с использованием GNU autotools. В качестве примера возьaclocal.m4:538: AM_INIT_AUTOMAKE is expanded from... мем программу kgtk версии 0.9. (Я намеренно указываю ноconfigure.in:6: the top level мер версии, потому что последняя версия kgtk – 0.9.2, и она уже собирается с помощью Cmake.) Скачать ее можно по адНо вот Autoconf завершен успешно, запускаем снова ресу [1]. Что мы обнаруживаем в дистрибутиве? configure, убеждаемся, что да, в новом Makefile появились Обнаруживаем уже готовые файлы config.h.in, Makefile.in, нужные пути, запускаем gmake... и снова удивляемся, потоconfigure.in, и если первые два были созданы Automake 1.9, му что сталкиваемся с той особенностью проектов, которые то последний явно писался вручную, потому что не похож собираются с помощью GNU Autotools – при изменении люни на что. Кроме того, здесь мы обнаруживаем исходник бого из исходных файлов выполняется полный комплекс задля Automake – Makefile.am и несколько служебных файлов дач по перестройке всех вспомогательных файлов, то есть Automake – depcomp, install-sh, missing, config.guess, ltmain.sh aclocal, затем autoheader, затем automake, затем autoconf. и config.sub. Иногда эти файлы помещаются в подкаталог Причем, если запустить gmake без явного указания версий admin или cfgaux. autotools, можем опять получить то же самое: Запускаем configure: # ./configure --prefix=/usr/local/kde3 ↵ --with-qt-dir=/usr/X11R6/qt33 ↵ --with-extra-includes=/usr/local/include ↵ --with-extra-libs=/usr/local/lib --disable-debug
24
# gmake
cd . && /bin/sh /usr/home/shelton/program/kgtk-0.9/missing --run aclocal-1.9 autom4te253: unknown language: Autoconf-without-aclocal-m4 aclocal-1.9: autom4te failed with exit status: 1 gmake: *** [aclocal.m4] Error 1
администрирование Теперь запускаем, как упоминалось выше, с указанием версий: # env AUTOCONF_VERSION=261 AUTOMAKE_VERSION=19 gmake
Теперь Autotools благополучно перестраивает свои файлы, но configure все равно отработать не в состоянии. Мы забыли про одну вещь, которая изначально не входила в autotools, но в последнее время играет все большую роль в процессе сборки программ. Эта вещь называется pkg‑config. Pkg-config – это своего рода информационная база по установленным программам. Она содержит информацию, отличную от той, что содержит /var/db/ pkg. Это информация о том, в какие каталоги была установлена программа, с какими флагами она компилировалась, с какими библиотеками собиралась, какой номер версии сейчас установлен, с какими пакетами может конфликтовать... Хранится все это в текстовых файлах с расширением .pc, которые как правило располагаются в /usr/ local/libdata/pkgconfig, хотя могут располагаться и в других каталогах – это просто текстовые файлы, в них нет ничего мистического. Но если pkg-config не указать эти дополнительные каталоги, то он и искать информацию будет только в /usr/local/libdata/pkgconfig. Каталоги задаются в переменной окружения PKG_CONFIG_PATH через двоеточие. Так вот, в процессе работы configure пытается обнаружить некоторые программы через pkg-config, ничего не находит и аварийно завершается. Запускаем вот таким образом: # env AUTOCONF_VERSION=261 AUTOMAKE_VERSION=19 ↵ PKG_CONFIG_PATH=/usr/X11R6/libdata/pkgconfig: ↵ /usr/X11R6/qt33/libdata/pkgconfig:/usr/local/kde3 ↵ /libdata/pkgconfig gmake
Ну вот, кое с чем справились – Autotools перестроили свои файлы, configure завершился успешно. Зато получили чрезвычайно странную ошибку: # /bin/sh ../libtool --silent --tag=CXX --mode=link ↵ g++ -g -O2 -L/usr/local/lib -L/usr/X11R6/lib ↵ -o kdialogd3 -L/usr/X11R6/lib ↵ -L/usr/X11R6/qt33/ lib -L/usr/local/kde3/lib ↵ -L/usr/local/lib kdialogd.o -lkio -lkdecore -lqt-mt libtool: link: cannot find the library `' gmake[2]: *** [kdialogd3] Error 1
На первый взгляд в командной строке все нормально – все перечисленные библиотеки могут быть найдены в одном из перечисленных путей, других ключей нет... Какой же библиотеки не хватает для завершения сборки и библиотеки ли? Путей решения этой проблемы есть два – лобовой и нормальный. В лобовом методе решения исключается Libtool. В Makefile.am добавляется собственная переменная CXXLINK: CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) ↵ $(AM_LDFLAGS) $(LDFLAGS) -o $@
Почему именно CXXLINK и что вообще мы такое натворили? Опять же где можно получить полный список переменных?
№12, декабрь 2007
На этот вопрос ответить проще. Полный список переменных, которые можно задавать в Makefile.am, приведен в документации по automake, например в info automake-1.9. Там сказано, что CXXLINK – это переменная, содержащая команду, которая используется для сборки программы на языке C++. Там же описаны и прочие переменные, использованные здесь. Кратко на «человеческий» язык это можно перевести так – «используя программу, заданную в переменной CXXLD, флаги компилятора, заданные переменными AM_CXXFLAGS и CXXFLAGS, и флаги компоновщика, заданные переменными AM_LDFLAGS и LDFLAGS, скомпоновать программу и поместить ее файл с именем, заданным в ключе -o компоновщика» При этом, поскольку собственные переменные замещают переменные по умолчанию, вызова Libtool вообще не произойдет. Но при этом всю его работу нам придется выполнить самим, то есть проверить, что переменные AM_LDFLAGS и LDFLAGS содержат имена всех нужных библиотек и пути к ним. При выборе нормального метода нужно-таки доискаться до корней причины возникновения такой непонятной ошибки. Для этого необходимо знать, как работает Libtool. Libtool был написан для того, чтобы решать за программиста вопрос «не забыл ли программист указать какую-нибудь нужную библиотеку в строке команды для компилятора или сборщика». Делается это просто – Libtool получает в качестве параметра строку вызова компилятора или сборщика и последовательно проверяет все ключи этой строки. Допустим, при вызове Libtool в режиме сборщика (mode=link) если ключ является указанием пути к библиотекам (-L, -R) или именем статической библиотеки (filename.la), то он переписывается в командную строку, с которой Libtool потом запустит сборщик. Если это известная ему опция командной строки, она игнорируется, возможно, при этом выставляются некоторые флаги работы Libtool. Если же это ссылка на библиотеку (-l), то libtool пытается найти файл с именем, соответствующим имени библиотеки, и расширением .la и извлечь из него информацию о том, как собиралась данная библиотека. Если файл найден, то информация извлекается и присоединяется к исходной строке запуска сборщика. Эта операция выполняется для всех библиотек, которые были найдены в строке параметров Libtool. Но что будет, если Libtool обнаружит незнакомую опцию командной строки? esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else $echo "$modename: cannot find the library \`$lib'" 1>&2 exit 1 fi
Ответ мы видим непосредственно в коде самого Libtool. Если это из вышеперечисленных (а также многих других предусмотренных) вариантов – предполагается, что это файл, и он должен существовать. Но, судя по тексту сообщения об ошибке, переменная $lib не установлена, оттого и сообщение об ошибке выглядит так странно. Что же это за загадочный ключ командной строки? Пристальней вглядевшись в перечисленные в Libtool
25
администрирование ключи, можно обнаружить, что среди них отсутствует ‑pthread. Так? Делаем небольшой патч:
точно вставить проверку на операционную систему и, если это FreeBSD, игнорировать тестирование на libdl:
--- admin/ltmain.sh.bak 2007-10-11 23:07:36.000000000 +0700 +++ admin/ltmain.sh 2007-10-11 23:07:36.000000000 +0700 @@ -1923,6 +1923,10 @@ continue ;; *.la) lib="$deplib" ;; + -pthread) + deplibs="$deplib $deplibs" + continue + ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs"
@@ -156,19 +158,25 @@ fi AC_CHECK_FUNCS(getpeereid) +# FreeBSD has not dlvsym, so we check this occassion +HOST=`uname` -# Check if we have dlvsym... -AC_CHECK_LIB(dl, dlvsym, +if test "$HOST" != "FreeBSD"; then + # Check if we have dlvsym... + AC_CHECK_LIB(dl, dlvsym, AC_DEFINE(HAVE_DLVSYM, 1, [dlvsym in libdl]), AC_MSG_WARN([You're libdl does not contain ↵ dlvsym - SWT apps will not be supported])) -# Determine version of dlsym... -for d in `libtool --config | ↵ grep sys_lib_search_path_spec | ↵ awk -F= '{print $2}' | sed s:\"::g ` ; do + # Determine version of dlsym... + for d in `libtool --config | ↵ grep sys_lib_search_path_spec | ↵ awk -F= '{print $2}' | sed s:\"::g ` ; do if test -z $KGTK_DLSYM_VERSION ↵ && test -f $d/libdl.so ; then KGTK_DLSYM_VERSION=`objdump ↵ --dynamic-syms $d/libdl.so | ↵ grep dlsym | awk '{print $6}'` AC_DEFINE_UNQUOTED(KGTK_DLSYM_VERSION, ↵ "$KGTK_DLSYM_VERSION", [Version of dlsym]) fi -done + done +fi
Не забываем добавить в Makefile.am, в строку kdialog3_ LDFLAGS упоминание библиотеки libpthread, коль уж она заявлена при сборке библиотек KDE: kdialogd3_LDFLAGS = $(all_libraries) $(LIBPTHREAD)
и запускаем сборку заново. Все в порядке – Libtool отрабатывает нормально. Но это пока еще не «корень зла», а всего лишь то, что называется quick hack (так обычно называют правку на скорую руку, сделанную только для того, чтобы проверить истинность или ложность некоторых посылок. Буквальный перевод этого выражения – «быстрый взлом»). Чтобы доискаться-таки до причины, нужно вспомнить, что сам скрипт Libtool создается из файла ltmain.sh, который, как правило, распространяется вместе с дистрибутивом или в корневом каталоге, или в каталоге для вспомогательных файлов. ltmain.sh – это тот же Libtool, только в нем не выполнены некоторые макроподстановки. Если наложить на него патч, приведенный выше, на всякий случай удалить Libtool и заново запустить configure (через env с указанием всех необходимых переменных), то должен быть создан работоспособный Libtool. Но как же так получилось? Автор программы распространяет со своим дистрибутивом ltmain.sh, содержащий ошибки? Нет. Просто ltmain.sh, который поставляется в дистрибутиве, – очень старый. Достаточно заглянуть внутрь, чтобы убедиться, что это так и есть: PROGRAM=ltmain.sh PACKAGE=libtool VERSION=1.4e TIMESTAMP=" (1.1090 2002/02/07 19:54:36)"
В 2002 году не было ключа командной строки -pthread. Для решения этой проблемы без применения упомянутого выше патча достаточно переписать в каталог сборки (или каталог вспомогательных файлов – в зависимости от того, где находился ltmain.sh) новую версию, которую можно взять из каталога libtool, установленного в системе – /usr/ local/share/libtool. Сборка снова завершается аварийно, но уже в другом каталоге и по другой причине – сборщик не смог найти библиотеку libdl. Неудивительно – во FreeBSD вообще нет такой библиотеки (вы не забыли, что программа изначально написана под Linux?). Вот тут нам и пригодится возможность редактирования configure.in и пересоздания configure. Доста-
26
Сборка завершена. Ура. Вот мы и побывали в роли человека, портирующего приложения Linux на FreeBSD, осталось только порт создать.
Гигиена Вообще использование обычных команд оболочки внутри файла configure.in имеет некоторые особенности. Во-первых, нельзя использовать перенаправление ввода-вывода. Встраиваемые в configure.in команды будут частью скрипта, который использует сложное собственное перенаправление ввода-вывода в различные потоки. Во-вторых, нельзя использовать оператор set по тем же причинам, что и перенаправление, – скрипт уже задействовал эту возможность. Можно только использовать независимые команды, причем такие, которые не могут отсутствовать в системе либо наличие которых уже проверено. Например, вот как можно проверить, что команда mkdir поддерживает ключ -p: mkkey=`mkdir 2>&1 | tail -c +15 | head -c 2`
А вот так можно проверить версию программы kavdaemon – демон антивирусной защиты старого образца (версии 4.х): KAVD=`whereis -b -B $kavbin -f kavdaemon | awk '{print $2}'` KAVER=`$KAVD -v | awk '{print $6}' | head -c 7`
Если используется некоторый набор одних и тех же тестов, то лучше всего их поместить в отдельный каталог и подключать его в самом начале при вызове aclocal: # aclocal -I m4
если собственные макросы размещены в подкаталоге m4 текущего каталога.
администрирование в особенности в тех программах, которые писались «только Какие же ошибки допускают разработчики программ: Первая и, пожалуй, наиболее частая ошибка – это под Linux». Авторы этих программ могут и не подозревать жестко прописаные пути (hadrcoded path). Многие разра- и о том, что их программа может работать в другой системе, ботчики, особенно начинающие, всерьез полагают, что если и о том, что для сборки в другой системе вовсе не нужны неу него программа А и библиотека В установлены в /usr/local, которые библиотеки, поэтому в configure могут встречатьто точно так же поступают и все остальные и, нимало не сом- ся проверки на наличие библиотек, изначально отсутствуневаясь, прописывают вызов программы без указания пути ющих в данной операционной системе (как, например, libdl или библиотеки без указания каталога поиска. В этом слу- в патче, приведенном выше). Если убрать имя такой библичае нужно внести изменения в файл Makefile.am, если он отеки из строки параметров сборки программы, то ничего есть. Если файла Makefile.am не существует, тогда можно не произойдет – все равно Linux-специфичные библиотевносить изменения в файл Makefile.in, но если существует, – ки во FreeBSD не используются. в Makefile.in вносить изменения бессмысленно, он все равно Последние две известные мне (но далеко не посбудет перестроен из Makefile.am. Для добавления пути по- ледние вообще) ошибки – это использование Autotools иска для файлов заголовков или библиотек следует пере- не той версии, чем у автора, и отсутствие в configure.in нести в Makefile.am следующие определения переменных: нужного макроса, самостоятельная разработка макроCXXFLAGS – если необходимо добавить путь поиска заго- са (при наличии уже готовых точно таких же). Первая ловков (-I/some/path/to), LDFLAGS – если необходимо доба- проявляется обычно тем, что при запуске make появляется вить путь поиска библиотек (-L/some/path/to) и дополнить их множество замечаний от Automake, от Autoconf. Как прависвоими значениями. Как уже упоминалось выше, automake, ло, в таком случае autotools не отрабатывает успешно, хообнаружив в Makefile.am задание стандартной переменной, тя бывают и исключения. Второй случай наиболее распропереносит ее в Makefile.in в неизменном виде. странен с KDE, и проявляется он, как правило, отсутствиВторая наиболее частая ошибка – это то самое со- ем правила для преобразования файлов .ui в файлы .moc общение «Cannot find the library», причину появления ко- или другой такой же ошибкой, которая в нормальных услоторого мы уже разобрали. Возникает она оттого, что разра- виях возникнуть не может. ботчики используют неведомо где добытые файлы ltmain.sh Ну и самой очевидной, поэтому и до сих пор не упоот давным-давно устаревших версий Libtool, которые уже минавшейся, ошибкой является использование исклюне понимают всего набора ключей, что может ими исполь- чительно Linux-ориентированных библиотек, заголозоваться. Я много раз натыкался на это сообщение, но толь- вочных файлов, других компонентов (например /proc, ко сейчас у меня хватило терпения разобраться, откуда же хотя его до известной степени можно сэмулировать чеоно берется. Решается этот вопрос либо заменой ltmain.sh рез linprocfs). Так что чтение описания программы до того, на файл из последней версии Libtool, либо (если замена как начать сборку, никто не отменял. невозможна, например в порту) созданием патча, который будет обрабатывать нужный ключ нужным образом. Хотя, Заключение конечно, можно и порт заставить скопировать новую вер- Все это не так сложно, как кажется с первого раза. Люсию файла ltmain.sh. ди совершают одинаковые ошибки, которые после втоТретья распространенная ошибка – это предположе- рого-третьего раза распознаются и исправляются практиние, что какая-то версия программы или библиотеки не- чески мгновенно, хоть поначалу и ощущаешь полное бесзависимо ни от чего присутствует в системе. Во FreeBSD силие. Надеюсь, что вооружившись этой статьей, вы смонет и никогда не было некоторых библиотек, но если следо- жете собирать программы, которые не могли собрать равать логике configure, если они не обнаруживаются, значит, нее из-за того, что непонятно было, откуда берутся ошибесть, но старые. Варианта «таких библиотек нет», как пра- ки и что же с ними делать. вило, в таких случаях не предусматривается. Здесь вполне уместно заметить следующую вещь: configure – не догма, 1. http://home.freeuk.com/cpdrummond/kgtk-0.9.tar.bz2.
№12, декабрь 2007
27
администрирование
Программное управление MS Exchange
Иван Коробко Управление ящиками Microsoft Exchange является очень важным разделом в автоматизации процесса управления учетными записями пользователей. Рассмотрим подробнее процедуры создания и удаления почтовых ящиков.
В
крупных организациях каждому пользователю даются индивидуальные привилегии. Подключение сетевых дисков, необходимых для работы баз данных, сетевых принтеров, создание почтового ящика. Все это требует значительных усилий, затраченных на администрирование. Регулярное использование мастеров, сценариев регистрации пользователей и другие меры позволят автоматизировать процессы в сети. Рассмотрим подробнее процесс автоматизированного управления почтовыми ящиками. Для удаленного управления Microsoft Exchange на рабочей станции должно быть предустановленно соответствующее программное обеспечение.
Необходимые компоненты Для удаленного управления почтовым ящиком необходимо зарегистрировать COM-объект Microsoft CDO for Exchange Management Library (CDOEX) на рабочей станции, с которой осуществляется запуск сценария. Для этого на компьютере необходимо установить следующие компоненты:
28
n Microsoft Admin Pack д ля
ходит без каких-либо трудностей, поэWindows Server. Для Microsoft тому подробно его описывать не буду. Exchange 2000 и 2003 клиентом может быть одна из следующих опера- Установка Microsoft Exchange: ционных систем: Windows 2000, XP, Management Tools 2003. Microsoft Admin Pack для Чтобы запустить процесс установWindows 2003 Server можно загру- ки Microsoft Exchange 2003 в каталозить с сайта Microsoft [3]. Этот ком- ге %CD-ROM%/setup/i386 необходимо понент необходим для установки дважды кликнуть на файл setup.exe. В появившемся диалоговом окне Microsoft Exchange. n M i c r o s o f t E xc h a n g e S ys t e m (см. рис. 1) нужно выбрать напротив Management Tools. Этот пакет – Microsoft Exchange метод установки составная часть Microsoft Exchange Custom, а напротив Microsoft Exchange 2000/2003, которая в разверну- System Management Tools – Install. Затом виде занимает около 100 Мб. тем нажмите кнопку «Далее» для проНесмотря на то что библиотека должения установки. Interop.CDOEXM.dll присутствует Замечание: если на компьютере отв «развернутом виде», необходи- сутствует Microsoft Admin Pack, то промо установить System Management цесс установки Microsoft Exchange буTools, так как в процессе установ- дет прерван. На экране будет отобраки осуществляется ее регистрация жено соответствующее информационкак псевдо COM-объекта. Без этой ное сообщение. процедуры ее невозможно использовать в VBScript-сценариях. MailBox в Active Directory Точкой входа в любой домен служит Установка Microsoft Admin виртуальный объект RootDSE, опреPack для Windows Server 2003 деленный в RFC 2251 как часть специПосле того как Microsoft Admin Pack за- фикации LDAP версии 3. Каждый конгружен с сайта Microsoft [3], необходимо троллер домена самостоятельно подего установить. Процесс установки про- держивает этот искусственный объект,
администрирование являющийся вершиной логического пространства имен, по которому осуществляется поиск с помощью провайдера LDAP. Для подключения к RootDSE используется бессерверное анонимное подключение: определение доступного пространства имен осуществляется локатором контроллеров домена. Объект включает в себя около двух десятков свойств. Для создания и управления ящиками необходимо использовать некоторые из них: n rootDomainNamingContext. Значение этого параметра – имя домена. Пример: DC=msk, DC=ru. n defaultNamingContext. По умолчанию совпадает со значением rootDomainNamingContext. n configurationNamingContext. С помощью этого пространства имен осуществляется дост уп к тек ущей конфигурации домена Active Directory. Пример: CN=Configuration,DC=msk,DC=ru. Один из первых двух параметров (rootDomainNaming Context или defaultNamingContext) необходим для определения местоположения учетной записи пользователя в Active Directory, с почтовым ящиком которого будут производиться манипуляции. Второй – configurationNamingContext – используется для непосредственного управления почтовым ящиком пользователя. Идентификатор почтового ящика – текстовый параметр homeMDBBL, находящийся в контейнере: CN=Mailbox Store (ServerName),CN=First Storage Group,CN=Information Store,CN= ServerName,CN=Servers,CN=ShortDomain-Mail, CN=Administrative Groups,CN=FirmName,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=***,DC=***, DC=***. Значение параметра – путь к учетной записи пользователя в домене в LDAP-формате. При создании сценария путь к контейнеру можно задать двумя способами: жестко в теле сценария или определить местоположение CN=Mailbox Store (ServerName) в контейнере Configuration. Настоятельно рекомендуется использовать второй способ.
Операции с почтовым ящиком С почтовым ящиком могут быть осуществлены следующие операции (см рис. 2): n Создание почтового ящика пользователя (Create MailBox); n Создание почтового адреса (Establish E-mail Address); n Удаление атрибу тов Exchange (Remove Exchange Attributes); n Перемещение почтового ящика (Move MailBox); n Удаление почтового ящика (Delete MailBox); n Изменение параметров (Configure Exchange Features). Остановимся подробнее на выполнении основных операций с почтовым ящиком: создание, удаление и изменение свойств его почтового ящика. Рассмотрим каждую из операций последо-
№12, декабрь 2007
Рисунок 1. Установка Microsoft Exchange System Management Tools
вательно на двух языках программирования: компилируемом (VB.NET) и интерпретируемом (VBscript). Для наглядности используем языки из одного семейства – Visual Basic. Замечание: сценарий должен быть запущен с административными правами на рабочей станции или сервере, где установлен компонент Microsoft CDO for Exchange Management Library.
Создание учетной записи пользователя Рассмотрим алгоритм работы сценария, который создает почтовый ящик заданному пользователю на VBScript и VB.NET. Его работу условно можно разделить на несколько этапов: n создание соединения с Active Directory и определение местоположения учетной записи пользователя (поле distinguishedName) в контейнере домена; n с о з д а н и е с о е д и н е н и я с п о м о щ ью ко н те й н е р а Configuration, определение местоположение хранилища Exchange (поле distinguishedName); n установка связи (link) между учетной записью пользователя и хранилищем Exchange в контейнере Configuration, создание почтового ящика (mailbox).
Рисунок 2. Операции с почтовым ящиком
29
администрирование После создания соединения можно перейти непосредственно к определению местоположения учетной записи пользователя в домене, используя метод Execute, предварительно составив SQL-запрос (см. листинг 3). Для составления эффективных SQL-запросов необходимо знать названия считываемых свойств, соответствующие им типы данных и примерные их значения. Названия параметров, их значения и типы данных объектов Active Directory (см. рис. 3) можно узнать с помощью программы Softerra LDAP Browser 2.6 [4]. Листинг 3. Поиск объектов в SQL (VBScript)
Рисунок 3. Внешний вид LDAP Browser 2.6.
Предлагаю перейти к реализации алгоритма на практике.
Создание соединения с Active Directory и определение местоположения учетной записи пользователя На первом этапе работы сценария, созданного на языке VBScript, определяют имя текущего домена (см. листинг 1). Для этого используется виртуальный объект RootDSE, который был рассмотрен ранее. Листинг 1. Определение имени текущего домена (VBScript) Set obj1=GetObject("LDAP://RootDSE") domain="LDAP://" +obj1.Get("defaultNamingContext")
Затем используют провайдер ADsDSOObject, получают доступ к пространству имен Active Directory c помощью ADODB-соединения (см. листинг 2). COM-объект ADODB является стандартным и зарегистрирован на любой рабочей станции. Создавая соединение желательно отключить кэширование результатов поиска в Active Directory (последняя строка листинга 2). Эта мера позволит увеличить достоверность получаемых результатов, однако немного снизит скорость работы сценария. При выключенном режиме кэширования скорость работы сценария будет уменьшаться на 2‑3 минуты. За это время будет обработано около 1000‑1500 почтовых ящиков. Необходимо отметить, что приведенные цифры ориентировочны. Скорость выполнения сценария зависит от производительности сети, загрузки серверов и других факторов. Листинг 2. Создание ADODB-соединения с Active Directory (VBScript) Set objConnection = CreateObject("ADODB.Connection") Set objCommand = CreateObject("ADODB.Command") objConnection.CommandTimeout = 120 objConnection.Provider = "ADsDSOObject" objConnection.Open "Active Directory Provider" Set objCommand.ActiveConnection = objConnection objCommand.properties("Cache Results")=False
30
Set sql=objconnection.execute( ↵ "SQL_QUERY" ) UserDN = Sql.Fields( ↵ "distinguishedName").Value
где SQL_QUERY – запрос SQL. Для создания почтового ящика необходимо «привязать» учетную запись пользователя к создаваемому ящику. Для этого необходимо знать расположение учетной записи пользователя (свойство distinguishedName) в Active Directory. Для составления соответствующего SQL-запроса необходимо использовать следующие параметры: n distinguishedName – описывает местоположение учетной записи пользователя в LDAP-формате; n samaccountname='Login' – имя пользователя в сети (login). Это ключевое значение, по которому ведется поиск. Имя в сети уникально; n objectClass='user' and NOT objectClass='computer' – учетная запись пользователя относится к классу «user» и не входит в класс «computer». Этот фильтр используется для ускорения процедуры поиска. SQL-запрос после подстановки значений: Листинг 4. SQL-запрос поиска distinguishedName по указному сетевому имени пользователя (VBScript) Select * from ("SELECT distinguishedName FROM '" & ↵ Domain & " ' WHERE samaccountname='"+LoginName+"' ↵ and objectClass='user' and NOT objectClass='computer'"
где domain – имя домена в формате LDAP://DC=…,DC=… После того как запрос выполнен с помощью метода Execute, необходимо считать найденный параметр (см. листинг 3, строка 2). В VB.NET процедура поиска объекта может быть также реализована с помощью ADODBсоединения, однако рекомендуется использовать метод с большей производительностью на основе библиотеки System.DirectoryServices NET.Framework. На первом этапе необходимо создать точку входа, обращаясь к виртуальному объекту RootDSE. Определив значение свойства defaultnamingcontext, получают имя текущего домена: Листинг 5. Определение имени текущего домена (VB.NET) Dim a As New DirectoryEntry("LDAP://rootdse")
администрирование
№12, декабрь 2007
31
администрирование Dim domain As String = "LDAP://" + ↵ a.Properties("defaultNamingContext").Value
На следующем этапе осуществляется вызов метода DirectorySearcher() и задание параметров листинга. Среди них можно выделить как обязательные, определение точки входа и фильтр (см. листинг 6, строка 2 и 4), так и необязательные. Все необязательные параметры имеют значения по умолчанию. Листинг 6. Поиск объектов в SQL (VB.NET) Dim sobj As New DirectorySearcher() sobj.SearchRoot = New DirectoryEntry(domain) sobj.SearchScope = SearchScope.Subtree sobj.Filter = "(&(samaccountname=" + findemail + "))" Dim ss As SearchResult ss = sobj.FindOne() Dim DNUser As String = "LDAP://" + ↵ ss.Properties("distinguishedName")(0)
Листинг 7б. Определение местоположения контейнера Configuration (VB.NET) Dim a As New DirectoryEntry("LDAP://rootdse") Dim domain As String = "LDAP://" + ↵ a.Properties("configurationNamingContext").Value
Как отмечалось ранее, критерий поиска также изменяется. В сценарии на VBScript изменяется SQL-запрос (см. листинг 8а), в листинге на VB.NET – фильтр поиска (см. листинг 8б, строка 1, 2 и 8). Листинг 8а. SQL-запрос определения местоположения Exchange-хранилища (VBScript) Set exchange=objconnection.execute("SELECT ↵ distinguishedName FROM '" & configuration & "' ↵ WHERE cn='"+FindConfPath+"'") StoreDN = exchange.Fields("distinguishedName").Value
где FindConfPath= "CN=Mailbox Store (" + ServerName + ") ". Затем, после определения критериев поиска, осуществляется поиск с помощью одного из двух методов. Если осуществляется поиск одного объекта, то используется метод FindOne(), если нескольких – FindAll(). Синтаксис вызова методов незначительно отличается. Поскольку учетная запись пользователя в домене уникальна, то разумнее использовать метод FindOne() (см. листинг 6, строка 5-6). После того как процедура поиска завершена с помощью свойства .Properties("distinguishedName")(0), считывают значение параметра.
Создание соединения с хранилищем Exchange, определение его местоположения в контейнере Configuration
Листинг 8б. Поиск объектов в SQL (VB.NET) Public ExchangeServer = "MAIL_SERVER_NAME" Dim findconfpath As String = ↵ "Mailbox Store (" + ExchangeServer + ")" Dim m As New DirectoryEntry("LDAP://rootdse") Dim conf As String = "LDAP://" + ↵ m.Properties("configurationnamingcontext").Value Dim mobj As New DirectorySearcher() mobj.SearchRoot = New DirectoryEntry(conf) mobj.SearchScope = SearchScope.Subtree mobj.Filter = "(&(cn=" + findconfpath + "))" mobj.PropertiesToLoad.Add("distinguishedName") Dim ms As SearchResult ms = mobj.FindOne()
Установка взаимосвязи между объектами
Хранилище почтовых ящиков Exchange в Active Directory и создание почтового ящика располагается в контейнере Configuration: CN=Mailbox Для установки взаимосвязи между учетной записью польStore (ServerName),CN=First Storage Group,CN=Information зователя и хранилищем почтовых ящиков используется Store,CN=Ser verName,CN=Ser vers,CN=ShortDomain- LDAP-путь (distinguishedName) учетной записи пользоваMail,CN=Administrative Groups,CN=FirmName,CN=Microsoft теля. При создании почтового ящика соответствующая заExchange,CN=Services,CN=Configuration,DC=***,DC=***, пись появляется в Active Directory в контейнере Configuration. В результате действия сценария (см. листинги 9а, 9б) в нем DC=***… Поиск параметра CN=Mailbox Store (ServerName) осу- создается учетная запись почтового ящика, в которой фиществляется по описанному в предыдущем разделе ал- гурирует имя учетной записи пользователя, к которой пригоритму. Изменяется лишь контейнер, в котором осущест- вязан ящик. вляется поиск (см. листинги 7а, 7б) Список некоторых параметров почтового ящика и SQL-запрос (см. листинги 8а, 8б). Параметр Тип данных Описание Путь к контейнеру определяется с помощью одного из свойств объектов submissionContLength Строка Максимальный размер письма (Кб), которое может быть отправлено пользователем RootDSE: rootDomainNamingContext delivContLength Строка Максимальный размер письма (Кб), которое может быть принято или в defaultNamingContext. На практипользователем ке используют параметр defaultNaming mDBStorageQuota Строка В случае превышения указанного размера ящика в (Кб) пользователю Context. Для определения местоповысылается письмо, содержащее информацию о свободном месте ложения контейнера Configuration испочтового ящика пользуется параметр configuration mDBOverQuotaLimit Строка При достижении размера почтового ящика, указанного в (Кб) , пользователь не сможет отправлять письма NamingContext. Листинг 7а. Определение местоположения контейнера Configuration (VBScript) Set obj1=GetObject( ↵ "LDAP://RootDSE") domain="LDAP://" +obj1.Get( ↵ "configurationNamingContext ")
32
mDBOverHardQuotaLimit
Строка
При достижении размера почтового ящика, указанного в (Кб), пользователь не сможет отправлять и принимать письма
proxyAddresses
Массив
Элементы массива – алиасы почтового ящика пользователя
mailNickname
Строка
Короткое имя, которое с помощью программы-клиента может быть расшифровано в полноценный адрес
Строка
Оригинальный почтовый адрес
proxyAddresses
Строка
Адрес прокси-сервера
администрирование Замечание: в листинге 9а объект CDOEX не используется явным образом, однако соответствующая библиотека должна быть зарегистрирована на рабочей станции, с которой выполняется сценарий. Листинг 9а. Создание почтового ящика (VBScript) Set User = GetObject("LDAP://" & UserDN) Set Mailbox = User Mailbox.CreateMailbox StoreDN User.SetInfo Листинг 9б. Создание почтового ящика (VB.NET) Dim deMail As New DirectoryEntry(DNUser) If Not deMail Is Nothing Then Dim mailboxStore As IMailboxStore mailboxStore = CType(deMail.NativeObject, IMailboxStore) mailboxStore.CreateMailbox(ms.Path) deMail.CommitChanges() Else MsgBox("MailBox Exists") End If
Полную версию сценария, осуществляющего создание почтового ящика, на VBScript и на VB.NET, смотрите на сайте журнала www.samag.ru в разделе «Исходный код».
Удаление почтового ящика Процедура удаления почтового ящика пользователя сводится к вызову метода – .DeleteMailBox. Алгоритм работы сценария следующий (см. листинги 10а, 10б): подключившись к Active Directory с помощью провайдера ADsDSOObject, осуществляют поиск учетной записи пользователя (distinguishedName) по заданному значению, например, логину (samaccountname). Затем с помощью GetObject() получают доступ к свойствам и методам объекта. Для удаления почтового ящика вызывают последовательно методы DeleteMailBox и SetInfo. Полный листинг сценария смотрите на сайте журнала www.samag.ru в разделе «Исходный код». Листинг 10а. Создание почтового ящика (VBScript) Set User = GetObject("LDAP://" & UserDN) User.DeleteMailBox User.SetInfo
ss.Properties("distinguishedName")(0) Dim deMail As New DirectoryEntry(DNUser) If Not deMail Is Nothing Then Dim mailboxStore As IMailboxStore mailboxStore = CType(deMail.NativeObject, IMailboxStore) mailboxStore.DeleteMailbox() deMail.CommitChanges() Else MsgBox("User Not Found") End If
Изменение свойств почтового ящика Свойства почтового ящика можно изменить с помощью библиотеки CDOEX и классическим способом, используя GetObject(). Предпочтительным вариантом является использование GetObject() из-за своей простоты. Приведу в листинге 11 общий шаблон сценария изменения свойств почтового ящика учетной записи пользователя. Под буквой «а» – листинг на VBScript, под буквой «б» – на VB.NET. Листинг 11a. Изменение свойств почтового ящика (VBScript) … UserDN = Sql1.Fields("distinguishedName").Value Set User = GetObject("LDAP://" & UserDN) User.put "mDBOverQuotaLimit", "600" User.SetInfo
где mDBOverQuotaLimit – изменяемое свойство (список полей см. в Softerra LDAPBrawser 2.6), а 600 —присваиваемое значение. Листинг 11б. Изменение свойств почтового ящика (VB.NET) … Dim DNUser As String = "LDAP://" + ↵ ss.Properties("distinguishedName")(0) Dim User = GetObject("LDAP://" & DNUser) User.put("mDBOverQuotaLimit", "600") User.SetInfo()
Приведу в таблице список некоторых параметров почтового ящика. Полный листинг изменения свойств почтового ящика пользователя смотрите на сайте журнала www. samag.ru в разделе «Исходный код».
Заключение
Замечание: метод .SetInfo всегда вызывается после вы- Прочитав эту статью, вы сможете не только усовершенсзова какого-либо метода для записи данных в базу Active твовать сценарий регистрации пользователей в сети, котоDirectory. рый будет «следить» за состоянием почтового ящика польПо сравнению с функцией создания учетной записи зователя, регистрирующегося в сети, но и написать мастер пользователя в Active Directory на языке VB.NET листинг создания учетной записи пользователя в сети. функции, в которой осуществлено удаление почтового ящика, претерпевает следующие изменения. Во-первых, 1. KB 304718. «How to use the Administration Tools Pack to remotely нет необходимости определять местоположение хранилиadminister computers that are running Windows Server 2003, ща почтовых ящиков Exchange в Active Directory. Этот фрагWindows XP, or Windows 2000» – http://support.microsoft.com/ мент листинга можно удалить. Во-вторых, вместо метода ?kbid=304718. mailboxStore.CreateMailbox(ms.Path) осуществляется вы- 2. KB 327079. «How to programmatically create a mailbox for an зов другого метода: mailboxStore.DeleteMailbox() (см. лисexisting user in the Active Directory by using CDOEXM» – http:// тинг 10б). Все остальные строки остаются без изменений. support.microsoft.com/kb/327079. Полный текст листинга функции удаления почтового ящи- 3. Windows Server 2003 SP1 Administration Tools Pack – http:// ка пользователя на языке VB.NET смотрите на сайте журdownload.microsof t.com/download /6/8/1/681c9ba7-380fнала www.samag.ru в разделе «Исходный код». 4756-ac85-a3323437e6c3/WindowsServer2003-KB304718Листинг 10б. Создание почтового ящика (VB.NET) Dim DNUser As String = "LDAP://" + ↵
№12, декабрь 2007
AdministrationToolsPack.exe. 4. Softerra LDAP Browser 2.6 – http://download.softerra.com/files/ ldapbrowser26.msi.
33
администрирование
MS Exchange 2003 + SpamAssassin
Артем Деянов Перепробовав множество коммерческих продуктов, направленных на борьбу со спамом, таких как SerfControl E-mail Filter, SpamFighter Exchange Module (SEM) и другие, я пришел к выводу, что соотношение цена/качество у них оставляет желать лучшего. За что платить? Но как всегда и всюду, у людей есть альтернативы в виде Open Source-продуктов.
П
ервое, что пришло в голову – отказаться от удобства и практичности продукта Microsoft Internet Security and Acceleration Server, поставить на шлюзовом сервере один из клонов UNIX и настроить не раз описанную связку Postfix + Exchange с фильтрацией спама средствами одного из лучших фильтров – SpamAssassin, но человек тем и жив, что в стремлении к большему комфорту и удобству рождает подчас гениальные идеи, и я задумался. Если с вопросом об установке SpamAssassin на платформе Windows особых вопросов нет, SA как модуль Perl изначально кросплатформенен, то с вопросом его непосредственного взаимодействия с Exchange 2003 пришлось перекопать кучу материалов в Интернете. Парадигма «кто ищет, тот найдет»
34
сработала и здесь. Был найден интересный проект ESA Sink [1], который по сути своей является тем самым связующим звеном, обеспечивающим взаимодействие сервера Exchange 2003 и модуля SpamAssassin. Таким образом, на первый взгляд нетривиальная задача сводится к нескольким стандартным действиям: n установка Perl; n компиляция и установка SpamAssassin и связанных модулей; n установка ESA Sink; n обучение фильтра. Приступим.
Установка Perl Первое, что необходимо сделать, – это скачать дистрибутив Perl для Windows,
пройдя по ссылке [2]. С установкой проблем возникнуть не должно. После установки необходимо добавить переменную окружения Perl с путем к установленному дистрибутиву (у меня это C:\perl\bin) и перезагрузить сервер. Затем устанавливаем нужные модули: ppm install Win32-Registry-File ppm install Net-DNS ppm install DB_File ppm install IP-Country ppm install Mail-SPF ppm install Error ppm install Digest-SHA
Компиляция и установка SpamAssassin и связанных модулей Далее скачиваем исходные коды самого SpamAssassin, например, с проекта Apache Software Foundation [3], также
администрирование для его компиляции понадобится nmake [4]. Качаем, распаковываем архив в папку с установленным Perl (C:\perl\bin) и начинаем процесс сборки исходного кода: cd \..\Mail-SpamAssassin-3.2.3 perl Makefile.pl nmake nmake install
Процесс сборки должен пройти без проблем, но если что, их всегда можно решить, ибо сборщик в достаточной степени информативен. После установки копируем файл spamassassin.bat из директории C:\perl\site\bin в директорию C:\perl\bin. Снимаем с него атрибут «только для чтения» и в редакторе сразу после строк, отключающих echo, добавляем следующее: SET RES_NAMESERVERS=xxx.xxx.xxx.xxx SET LANG=ru
Можно так же отредактировать конфигурационный файл фильтра (C:\perl\site\etc\mail\spamassassin\local.cf) на предмет включения баесов, установки порогового значения баллов и т. д.
Установка ESA Sink Следующим пунктом и номером нашей программы является установка самого ESASink, который перехватывает поток поступающих на Exchange сообщений, перенаправляет его
SpamAssassin на анализ и с выставленными баллами и модифицированным заголовком (при условии, что балловый порог, по умолчанию равный 5, превышен и включена соответствующая настройка) возвращает серверу, который перенаправляет сообщение в mailbox получателя. С этим проблем возникнуть не должно, т.к. дистрибутив имеет интерактивный и интуитивно понятный установщик. После этого правим файл C:\ESA\ExchangeSpamAssassin.ini, добавляя в него полный путь к нашему SpamAssassin: SpamAssassin_Batch_File=C:\Perl\bin\spamassassin.bat
Пробуем со всем этим делом «взлететь»: С:\ESA\Install_ESA_Sink.bat
Для проверки связки можно прислать себе тестовое письмо и посмотреть на его заголовок, если там присутствуют строки примерно следующего содержания: X-Spam-Checker-Version: * X-Spam-Status: No, score=1.6 required=5.0
то все работает, если таких строк нет, ищем ошибки и «грызем гранит науки».
Обучение фильтра Связка установлена и настроена, осталось только провести ручное обучение нашего фильтра. Для этого удобно импортировать спам-писма и белую почту в ящики формата mbox. Cделать это проще всего с помощью программы The Bat!, которая имеет в своем инструментарии богатый набор средств по конвертированию различных форматов почтовых ящиков. Итак, имея на руках два файла формата UNIX mbox – у меня они называются spam и ham соответственно, приступаем к обучению фильтра. Общий формат команды обучения смотрите на рисунке. И в частности: Sa-learn – -spam – -mbox ..\spam Sa-learn – -ham - -mbox ..\ham
При большем объеме соответствующих ящиков процедура занимает довольно длительное время. Все, остается только включить автоматическое обучение и радоваться жизни. Удачи!
Общий формат команды обучения
№12, декабрь 2007
1. http://www.christopherlewis.com/ESA / ExchangeSpamAssassin.htm. 2. http://www.activestate.com/Products/ activeperl. 3. http://spamassassin.apache.org. 4. h t t p : / / d o w n l o a d . m i c r o s o f t . c o m / download/vc15/Patch/1.52/W95/EN‑US/ Nmake15.exe.
35
безопасность
Синхронизация ACL и структуры организации Часть 1
Вадим Андросов В статье описывается создание надстройки для операционной системы Windows Server 2003, позволяющей эффективно совместно использовать два ее основных механизма разграничения доступа: на основе структуры организации и списков контроля доступа (ACL). В итоге основная работа по управлению доступом к защищаемым ресурсам сводится к поддержанию адекватной структурной модели организации.
Постановка задачи ной структурой. Цель статьи – обес- пользуя оснастку Active Directory Users Операционная сис тема Windows печить возможность совместного ис- and Computers, можно задать структуServer 2003 позволяет создавать мо- пользования структуры предприятия ру организации, а также принадлеждели структуры организации, одна- и списков контроля доступа. Защита ность пользователей и рабочих станко содержит довольно ограниченные основных элементов информацион- ций определенным подразделенисредства использования подобных мо- ной системы должна осуществляться ям. Требуется лишь незначительная делей для защиты корпоративных ин- преимущественно на основе организа- доработка стандартной схемы Active формационных систем. Главная причи- ционной структуры предприятия. Из- Directory для реализации прикреплена этому – сложность и уникальность начально строится модель структуры, ния групп безопасности к организациправил защиты на различных пред- и распределяются права (случаи, ког- онным единицам. Сначала сформулиприятиях. Все разнообразие подходов да доступ к объектам имеют все со- руем основные идеи совместного исоперационная система поддерживать трудники определенного отдела, очень пользования модели организационной не может. Однако она содержит мощ- распространены). Затем главной за- структуры предприятия и списков конные средства расширения своей фун- дачей администратора должна стать троля доступа. кциональности. Их использование бы- поддержка адекватной модели струкВ статье будут описаны два уровня ло рассмотрено в октябрьском номере туры организации. Другими словами взаимосвязи списков контроля достужурнала [1]. при переходе пользователя из одно- па и структуры организации. Основная Windows Server 2003 предостав- го отдела в другой системный адми- идея заключается в существовании ляет стандартную для операционных нистратор не должен вручную пере- специальной группы пользователей, систем своего класса возможность назначать ему все необходимые пра- прикрепленной к организационной разграничения прав доступа на ос- ва – достаточно переместить объект единице. При добавлении нового польнове списков доступа. Обычно учет- пользователя в нужную организаци- зователя в отдел он будет автоматиные записи пользователей для повы- онную единицу. Еще одно требование чески регистрироваться и в этой групшения удобства и гибкости админис- к разрабатываемым механизмам: они пе. Аналогично удаление пользователя трирования объединяются в группы, не должны препятствовать использо- из организационной единицы должно и права на доступ к различным объек- ванию стандартных процедур назна- приводить к его автоматическому удатам предоставляются именно группам. чения прав при реализации прав до- лению также из группы. В результате Это нужный и часто используемый ме- ступа, не соответствующих структуре в рамках домена будет существовать ханизм, однако он лежит в плоскос- предприятия. набор групп, состав которых соответти, ортогональной организационной Под моделью будем понимать объ- ствует персоналу отдела. Поддержка структуре предприятия. Объединение ект, в достаточной степени повторя- вручную подобной функциональноспользователей в группы никак не свя- ющий свойства моделируемого объ- ти возможна (более того, в подавлязано с их принадлежностью опреде- екта. В статье рассматривается орга- ющем числе случаев она именно так ленной организационной единице. низационная подсистема предприя- и осуществляется), но связана с больТак что в результате мы получаем тия, которая может быть в достаточ- шим количеством рутинных действий, два мощных механизма, которые, од- ной для решаемой задачи степени что чревато ошибками, особенно при нако, нелегко использовать согласо- смоделирована с помощью штатных условии высокого уровня динамики ванно, особенно для обеспечения бе- средств Windows 2003 Server, а имен- структуры предприятия. Другая прозопасности в организациях со слож- но средствами Active Directory. Так, ис- блема – масштабные изменения орга36
безопасность низации, когда меняется позиция отдела или целого поддерева. Важно обеспечить единое место редактирования структуры организации. Первый уровень синхронизации – это создание группы, которая будет автоматически включать всех пользователей, принадлежащих своей организационной единице. Это самый примитивный уровень соответствия, который, однако, позволит существенно повысить удобство разграничения доступа к ресурсам на уровне отдельных отделов. Следующий уровень – группа, содержащая пользователей текущего отдела и всех его дочерних подразделений. То есть группа, представляющая поддерево. С ее помощью можно реализовать более сложные правила разграничения доступа к ресурсам. Отмечу, что добавленная функциональность никак не затронет стандартных способов использования пользовательских групп. Администратор и далее будет иметь возможность создавать любое количество групп для реализации правил разграничения доступа, не соответствующих структуре организации.
Особенности функционирования Первым делом определим механизм прикрепления групп организационным единицам. Первый вариант – на основе имени. В каждом отделе будут существовать по две группы с названиями вида «Название_отдела_Group_Single» и «Название_отдела_Group_Subtree». Таким образом, можно получить удобный механизм связывания, как с точки зрения программирования, так и использования. Однако такое решение является недостаточно гибким. Администратор может предпочесть другую схему именования. Поэтому нужно предоставить альтернативный способ привязки групп к организационным единицам, оставив, однако, приведенный способ именования в качестве решения по умолчанию. Добавим в класс «Организационная единица» атрибуты для идентификации привязанных групп. Их понадобится два: n groupSingle – для группы с пользователями одной организационной единицы;
№12, декабрь 2007
Рисунок 1. Атрибуты класса Win32_Group
n groupTree – для группы, включа- ния пользователями. Поэтому для свяющей пользователей поддерева структуры организации, начиная с указанной единицы. Теперь нужно определить, какой атрибут группы можно использовать в качестве указателя. Воспользуемся утилитой WMI CIM Studio, которую можно бесплатно загрузить с сайта Microsoft [2]. Для указателя нам потребуется атрибут, уникальным образом идентифицирующий пользовательскую группу. Из рис. 1 видно, что для групп в операционной системе используется составной ключ, состоящий из двух полей: имени домена и группы. Если предположить, что мы работаем в пределах одного домена, имя группы будет ее уникальным идентификатором. Для случая использования нескольких доменов можно воспользоваться ссылкой вида <Имя группы>@<Имя домена>, например «management@dynamic.ua». Итак, ссылка может быть строкового типа и содержать имя группы. Однако такое решение сильно затруднит переименование объектов (придется отслеживать операции переименования и обновлять связи). Существует другое поле, уникальным образом идентифицирующее объект – GUID [7]. Тип этого свойства: Octet String. Оно является системным и не предназначено для непосредственного редактирова-
зи с группами более удачным решением является использование ссылки на GUID группы. Привязанные группы можно будет при необходимости удалить – в этом случае значением ссылки будет пустое значение. Ссылку будем хранить в формате юникодной строки, так как присваивание объектов типа Octet String должным образом не реализовано. Кроме того, для поиска объектов с помощью LDAP-запросов все равно требуется строковое представление GUID. Иногда нужно не включать сотрудников некоторых отделов поддерева к общим ресурсам. Например, в финансовое подразделение предприятия входят бухгалтерия, плановый отдел, отдел сбыта и вспомогательный персонал. С одной стороны было бы удобно назначить права доступа к общим ресурсам (финансовой документации) сразу всему финансовому подразделению. Но с другой, отдел «Вспомогательный персонал» не нуждается в подобном доступе. Поэтому должна быть возможность исключения из поддерева некоторых отделов. Сначала рассмотрим общий механизм регистрации пользователей в специальных группах. Как уже говорилось, таких групп должно быть два вида: содержащих пользователей текущего подразделения (Single group) и пользователей поддерева отделов
37
безопасность
Рисунок 2. Структура классов модели
с корнем в текущем (Tree group). Предлагаю следующий способ формирования групп типа Tree. В них автоматически включается группа типа Single текущего подразделения и группы типа Tree непосредственных дочерних организационных единиц. Таким образом, нужно будет заботиться только о поддержании связей с ближайшими дочерними подразделениями, делегируя им управление своими потомками. Такой подход организации древовидных структур для представления иерархий часть-целое соответствует распространенному паттерну «Компоновщик» (Composite) [3]. Он позволяет легко отключить определенный отдел от получения прав поддерева – достаточно удалить из его специальной группы типа Tree группу типа Single. При этом мы не потеряем возможность манипулировать разрешениями пользователей этого отдела с помощью одной группы. На рис. 2 показана диаграмма классов, отражающая логическую организацию надстройки. Физически существуют только объекты класса «User group», классы «Single group» и «Tree group» наследуют его только в смысле другого поведения (другой реакции на события над объектами). Новые классы операционной системы было решено не создавать во избежание излишней сложности. Остановимся на вопросе удаления специальных групп. Было решено не блокировать эту возможность, но в этом случае нужно определиться с поведением надстройки.
При удалении группы типа Tree все решается просто – ее обязанности берет на себя такая группа родительского подразделения (иначе будет потеряно поддерево, начиная с организационной единицы с удаленной группой). С группой типа Single дела обстоят несколько сложнее. Очевидной реакции здесь назначить нельзя. Остановимся на следующем решении: пользователи отдела с удаленной специальной группой типа Single вообще не будут участвовать в распределении прав на основе структуры организации. Это жесткий подход, однако остальные варианты (когда пользователи этого отдела включались бы в состав группы типа Single или Tree родительского подразделения) могут оказаться неочевидными для администратора, а поэтому чреваты ошибками. Одной из самых опасных ошибок администратора будем считать предоставление доступа к ресурсам организации пользователям, которые в них не нуждаются. От них и страхует полное исключение пользователей отдела с удаленной группой типа Single из предлагаемого механизма распределения прав доступа. С его помощью доступ к ресурсам разрешается неявно (посредством помещения пользователя в нужную организационную единицу), поэтому важно свести к минимуму вероятность «случайного» предоставления прав. Отдельно остановимся на вопросе работы со структурами, которые нельзя отнести к строго иерархическим. Поддержку в таких случаях достаточно легко организовать. Например (см. рис. 3), сотрудникам бухгалтерии и производственного отдела может понадобиться общий доступ к специальному виду документации. Для его обеспечения достаточно создать группу, в которую включить группы типа Single или Tree (в зависимости от того, требуется ли предоставить доступ конкретным отделам или целым подструктурам). Предоставив необходимые права данной группе, администратор в дальнейшем будет лишен необходимости работы с нею – достаточно будет поддерживать корректность структурной модели. Рассмотрим наиболее важные вопросы реализации предложенных методов. Сначала нужно расширить схему Active Directory, добавив к объекту «Организационная единица» необходимые атрибуты (groupSingle и groupSubtree). Механизм расширения схемы был рассмотрен в статье [1], поэтому подробно останавливаться на нем не будем. Расширение схемы делается с помощью специальной оснастки «Active Directory Schema» [1, 4].
Программная реализация
Рисунок 3. Пример структуры организации
38
В этом разделе рассмотрим сценарии, обеспечивающие конфигурирование надстройки с использованием оснастки Active Directory Users and Computers через новые контекстные меню подобно тому, как это было сделано в статье [1]. Сценарии, вызываемые в ответ на выбор определенного раздела меню, получают отличительное
безопасность имя выбранного в оснастке объекта в качестве первого параметра с помощью вызова oArgs.item(0). Мы будем использовать расширенную функцию регистрации новых контекстных меню, так как в отличие от [1] нам потребуются команды не только для организационных единиц, но и для групп. function operateMenu(operation, className, id, name, criptPath) Set root= GetObject("LDAP://rootDSE") sConfig = root.Get("configurationNamingContext") sPath = "LDAP://cn=" & className & "-Display,cn=409, ↵ cn=DisplaySpecifiers," & sConfig Set obj= GetObject(sPath) sValue = id & "," & name & "," & scriptPath vValue = Array(sValue) obj.PutEx operation, "adminContextMenu", vValue obj.SetInfo end function
Для начала создадим промежу точную функцию operateMenu. Она будет использоваться как для добавления новых пунктов меню в оснастку Active Directory Users And Computers, так и для их последующего удаления. Конкретная операция будет определяться первым параметром функции. Для установки нового пункта меню нужно будет воспользоваться следующей функцией: const ADS_PROPERTY_APPEND = 3 function installMenu(className, id, name, scriptPath) operateMenu(ADS_PROPERTY_APPEND, className, id, name, ↵ scriptPath) end function
Функция устанавливает контекстное меню для заданного объекта. В качестве первого параметра ей передается имя класса объекта, остальные – аналогичны подобной функции из [1]: идентификатор для определения позиции меню, название и путь к сценарию, выполняемому при вызове команды. Для удобства были определены отдельные функции для подключения меню к соответственно организационным единицам и группам: function installOUMenu(id, name, scriptPath) installMenu "organizationalUnit", id, name, scriptPath end function function installGroupMenu(id, name, scriptPath) installMenu "group", id, name, scriptPath end function
Сначала должны быть разработаны сценарии создания специальных групп. Их вызов будет осуществляться из специальных контекстных меню класса «Организационная единица». Приведу пример сценария добавления группы типа Single, поскольку процесс создания второго типа групп очень похож: Const ADS_GROUP_TYPE_LOCAL_GROUP = &h4 Const ADS_GROUP_TYPE_SECURITY_ENABLED = &h80000000 set ouObj = getObject(oArgs.item(0)) newGroupName = inputBox("Enter single attached group name", ↵ "New attached group", ouObj.ou & "_Group_Single") if isEmpty(newGroupName) then WScript.Quit set groupObj = ouObj.create("Group", "cn=" & newGroupName) groupObj.sAMAccountName = ouObj.ou & "Single" groupObj.groupType = ADS_GROUP_TYPE_LOCAL_GROUP Or ↵ ADS_GROUP_TYPE_SECURITY_ENABLED groupObj.description = "All users from " & ouObj.ou & " OU" groupObj.SetInfo ouObj.groupSingle = groupObj.guid ouObj.setInfo
№12, декабрь 2007
При вызове контекстного меню выполняется этот сценарий, первым параметром которому передается отличительное имя (Distinguished Name) текущей организационной единицы [1]. Пользователь получает приглашение ввести название прикрепленной единицы. По умолчанию предлагается название «Имя организационной единицы_Group_Single». В этом месте пользователь еще может отменить операцию, нажав соответствующую кнопку. Создается группа с заданным именем в текущей организационной единице. Комментарием к новой группе назначается строка «Все пользователи из организационной единицы». И в конце сценария имя новой группы привязывается к организационной единице. Подробнее остановимся на вопросе об области действия прикрепленных групп [4]. В данном примере используются локальные в домене группы (константа ADS_GROUP_ TYPE_LOCAL_GROUP). Они могут включать в себя группы или учетные записи как из своего домена, так и из других. Доступ же с их помощью можно назначить только к объектам своего домена. Есть еще два типа групп. Во-первых, глобальные. С их помощью можно предоставлять доступ к ресурсам в любом домене, однако включать в них можно только группы глобального типа, что может затруднить реализацию надстройки (требование использовать только группы одного типа является слишком ограничивающим). Существует еще один тип групп, который появился в ОС Windows 2000 Server – универсальные. С одной стороны они являются наиболее удобными для описываемой надстройки: позволяют включать группы и назначать доступ к ресурсам в любом домене. Однако широкое использование универсальных групп может негативно сказаться на общей производительности сети, кроме того, их применение возможно только в доменах, работающих в собственном режиме (native mode). В любом случае приведенный пример показывает лишь создание прикрепленной группы с типом по умолчанию – при необходимости администратор сможет самостоятельно присоединить к организационной единице группу необходимого типа (возможность этого будет реализована в дальнейшем). Обратите внимание, что добавлять группы любого типа в локальные становится возможным только после поднятия функционального уровня домена (Raise Domain Functional Level) до уровня Windows Server 2003 с помощью оснастки Active Directory Domains and Trusts. Создадим контекстное меню для вывода дополнительных свойств организационной единицы, как это было сделано в [1]. Теперь администратор сможет узнать, какие группы прикреплены (см. рис. 4). Далее рассмотрим вывод информации об организационной единице на экран. Сценарий вызывается из контекстного меню организационной единицы: set ouObj = getObject(oArgs.item(0)) singleStr = getGroupName(ouObj.groupSingle) treeStr = getGroupName(ouObj.groupTree) msgbox "Single: " & singleStr & chr(10) & _ "Subtree: " & treeStr, vbInformation, "OU attached groups"
В основе работы сценария лежит функция, определяю-
39
безопасность щая название группы по ее идентификатору. Ниже приведен ее текст. Принцип работы функции прост. Если идентификатор группы – пустое значение, возвращается текст, обозначающий отсутствие прикрепленной группы (none). В противном случае осуществляется поиск объекта на основе GUID: function isGroupExist(guid) isGroupExist = Not isEmpty(guid) end function function getGroupName(guid) if isGroupExist(guid) then set singleGroup = getObject("LDAP://<GUID=" & guid & ">") getGroupName = singleGroup.cn else getGroupName = "none" end if end function
Далее рассмотрим вспомогательные сценарии контекстного меню, позволяющие прикрепить произвольную ранее существующую группу к организационной единице, а также отключить группу. Начнем с подключения группы (делается с помощью дополнительного контекстного меню для объектов типа группа): set groupObj = getObject(oArgs.item(0)) set ouObj = getObject("LDAP://" & getOU(oArgs.item(0))) if isSomeAttached(ouObj) then if msgbox("Current organizational unit(" & ouObj.ou & _ ") already has attached group(" & _ getGroupName(ouObj.groupSingle) & _ "). Do you wish to unattach this group and " & _ "attach yours(" & groupObj.cn & ") as Single?", _ vbYesNo, "Group already attached") = vbNo _ then WScript.quit end if ouObj.groupSingle = groupObj.guid ouObj.setInfo msgbox "Group attached as single" function getOU(dn) getOU = right(dn, len(dn) - instr(1, dn, ",", ↵ vbTextCompare)) end function function isSomeAttached(ou) isSomeAttached = isGroupExist(ou.groupSingle) end function
else msgbox "This ou has no attached single groups", ↵ vbInformation, "Nothing to unattach" end if
В ходе выполнения сценария мы просто получаем объект организационной единицы и очищаем ей свойство groupSingle. Делается это с помощью метода putEx, которому передается константа, обозначающая очистку, и название поля. Теперь отдельно остановимся на операции подключения групп типа Tree. Здесь логика несколько сложнее. Такая группа должна при необходимости «склеить» дерево. Рассмотрим это на примере из рис. 3. Допустим, мы устанавливаем группу типа Tree для подразделения «Учет». Корректное подключение должно сопровождаться следующими действиями. Пусть новая группа называется «Учет_поддерево». n В подключаемую группу нужно добавить группу типа Single этого подразделения. n «Учет_поддерево» должна быть добавлена в группу типа Tree родительского подразделения («Производство»). n В «Учет_поддерево» нужно добавить группы этого типа дочерних подразделений. Реализуем этот алгоритм в функции подключения группы. Для последующей поддержки перемещения поддеревьев выделим регистрацию дочернего подразделения в родительском в отдельную функцию: Function registerInParent (childOU, parentOU) parentTreeGUID = parentOU.groupTree if not isGroupExist(parentTreeGUID) then Exit Function set parentTreeGroup = Getobject("LDAP://<GUID=" & _ parentTreeGUID & ">") if not isGroupExist(childOU.groupTree) then childOU.groupTree = parentTreeGUID childOU.setInfo attach parentTreeGroup, childOU end If on Error Resume Next parentTreeGroup.Add("LDAP://<GUID= ↵ " & childOU.groupTree & ">") parentTreeGroup.setInfo on Error Goto 0 End Function
Работа функций достаточно проста. Вызывается сценарий из контекстного меню группы. В поле организациСценарий прослушивания событий операций над групонной единицы groupSingle записывается идентификатор пами должен также поддерживать функциональность групп группы. Подключение группы в качестве поддерева будет типа Tree. Рассмотрим подробнее его обязанности на привыглядеть аналогично, только поле для записи GUID будет мере из [1] (см. рис. 3). называться groupTree. Если к организационной единице уже Допустим, группы типа Single содержатся в каждой орприкреплена группа, сценарий выводит ее название и за- ганизационной единице. Будем использовать соглашения прашивает подтверждение на замену. именования групп, принятые в начале статьи. Так группа Также для настройки нам понадобится возможность типа Singe для подразделения «Управление» будет назыотключения групп от организационных единиц, когда нам ваться «Управление_Group_Single», а группа типа Tree тонужно приостановить наблюдение за определенным отде- го же отдела – «Управление_Group_Subtree». Тогда группа лом. Следующий сценарий будет вызываться из контекст- «Организация_Group_Subtree» будет включать группу «Орного меню организационной единицы: ганизация_Group_Single», а также группы «Производство_ Group_Subtree» и «Управление_Group_Subtree». Группы тиconst ADS_PROPERTY_CLEAR = 1 па Tree листовых узлов будут включать только их группы set ouObj = getObject(oArgs.item(0)) первого типа. В случае если администратор решит удалить if isSomeAttached(ouObj) then if msgbox("Attached single group is " & _ группу «Учет_Group_Subtree», на ее место должна быть авgetGroupName(ouObj.groupSingle) & _ томатически установлена ссылка на группу родительского chr(10) & "Unattach?", vbYesNo, "Unattach...") = vbNo _ then WScript.Quit подразделения («Производство_Group_Subtree»). То есть ouObj.puEx ADS_PROPERTY_CLEAR, "groupSingle", "" группы поддержки поддеревьев родительских подраздеouObj.setInfo
40
безопасность лений могут при необходимости выполнять функции дочерних. Ссылки на прикрепленные группы родительских подразделений позволят значительно упростить функции обработки событий с пользователями, поскольку в этих случаях не потребуется обрабатывать особым образом ситуации, когда организационная единица не имеет собственной группы. Сначала мы получаем группу типа Tree родительского подразделения. Если у текущей организационной единицы нет прикрепленной группы этого типа – устанавливаем в ее качестве Рисунок 4. Информация о прикрепленных группах группу родителя. Таким образом, одна Отмечу, что прикрепление и отключение специальных группа может включать учетные записи сотрудников сразу из нескольких подразделений. Это полезно, когда ряд отде- групп не сопровождается в текущей реализации никакилов имеет доступ к одним и тем же ресурсам. С помощью ми побочными действиями. При подключении группы тифункции attach выполняется добавление во вновь прикреп- па Single можно добавлять в нее всех пользователей текуленную группу типа Tree таких групп из дочерних подраз- щего отдела. Подключая же группу типа Tree – добавлять делений. Далее мы рассмотрим ее подробнее. Ну и в кон- в нее группы этого вида дочерних подразделений. Но в каце мы добавляем группу, отвечающую за поддерево теку- честве решения по умолчанию такой подход опасен, так как представляет собой большое количество неявных действий, щего подразделения, в родительское. Итак, рассмотрим функцию attach. В процессе добав- которых администратор может не ожидать. Такую функциления групп дочерних подразделений они могут уже при- ональность логично сделать опциональной, причем изнанадлежать целевой группе. Чтобы не делать специальных чально отключенной. Итак, в первой части статьи были сформулированы оспроверок, будем игнорировать возникающие в этом случае ошибки с помощью директивы «on Error Resume Next». новные принципы функционирования надстройки. Также Дело в том, что метод isMember класса «группа» в отли- были разработаны функции для реализации базовой функчие от add не работает с LDAP-запросами поиска по иден- циональности. Но данная работа по сложности существенно тификатору, требуя передачи только отличительного име- превосходит надстройку из [1]. Поэтому использовать тольни (DN). Поэтому здесь проще игнорировать ошибки, чем ко базовые и наиболее распространенные приемы работы предварительно проверять принадлежность добавляемо- со сценариями WSH стало нецелесообразным. В следующий раз рассмотрим более сложные методы оформления го объекта группе. сценариев, которые, однако, позволяют более эффективfunction attach(treeGroup, ou) но управляться с громоздкими решениями. Также будет заon error resume next вершена разработка подпрограмм, обеспечивающих полsingleGUID = ou.groupSingle if isGroupExist(singleGUID) Then ную функциональность надстройки. treeGroup.Add ("LDAP://<GUID=" & singleGUID & ">") treeGroup.setInfo end If for each childOU in ou if childOU.class = "organizationalUnit" then if isTreeAttached(childOU) then if childOU.groupTree <> treeGroup.GUID Then treeGroup.add ("LDAP://<GUID=" ↵ & childOU.groupTree & ">") treeGroup.setInfo Else attach treeGroup, childOU end If end if end if next on error goto 0 end function
Сначала в группу типа Tree добавляется группа типа Single текущего подразделения. Затем перебираются все дочерние организационные единицы и их группы типа Tree добавляются в родительскую. Если же у подчиненных отделов нет своих Tree-групп, на их место устанавливается эта группа текущего отдела с помощью рекурсивного вызова этой же функции attach.
№12, декабрь 2007
1. Андросов В. Реализуем нестандартные правила управления доступом на основе архитектуры организации в Windows Server 2003. //Системный администратор, №10, 2007 г. – С. 48‑58. 2. Сайт Microsoft – www.microsoft.com. 3. Гамма Э., Хелм Р., Джонсон Р., Влиссидес Д. «Приемы объектно-ориентированного проектирования. Паттерны проектирования». – СПб.: Питер, 2007. – 366 с. 4. Чарли Рассел, Шарон Кроуфорд, Джейсон Джеренд. «Windows server 2003 +SP1 и R2. Справочник администратора». – М.: Издательство «ЭКОМ», 2006. – 1424 с. 5. Alain Lissoir. «Understanding WMI Scripting». – Digital Press, 2003. 6. Microsoft Development Network – msdn.microsoft.com. 7. Чекмарев А.Н. «Windows 2000 Active Directory». – СПб.: БХВПетербург, 2001. – 400 с. 8. Don Jones, Jefferey Hicks «Advanced VBScript for Microsoft Windows Administrators». – Washington: Microsoft Press, 2006. 9. Microsoft® Windows® 2000 Scripting Guide «Enhanced WMI Monitoring Scripts».
41
bugtraq Выполнение произвольного кода в ClamAV
Переполнение буфера в JustSystems Ichitaro
Программа: ClamAV 0.91.1, возможно, более ранние версии. Опасность: Критическая. Описание: Уязвимость позволяет злоумышленнику с помощью специально сформированного e-mail-сообщения выполнить произвольный код на целевой системе. Подробности уязвимости не сообщаются. URL производителя: www.clamav.net. Решение: В настоящее время способов устранения уязвимости не существует.
Программа: JustSystems Ichitaro 2005, 2006, 2007. Опасность: Критическая. Описание: Уязвимость существует из-за ошибки проверки границ данных в jsgci.dll при обработке .jtd-документов. Удаленный пользователь может с помощью специально сформированного .jtd-файла вызвать переполнение стека и выполнить произвольный код на целевой системе. Примечание: уязвимость активно эксплуатируется в настоящее время. URL производителя: www.justsystems.com. Решение: В настоящее время способов устранения уязвимости не существует.
Использование небезопасных методов в HP Info Center HPInfo Class ActiveX‑компоненте Программа: HP Info Center 1.0.1.1, возможно, более ранние версии. Опасность: Высокая. Описание: 1. Уязвимость существует из-за того, что HPInfoDLL.HPInfo.1 ActiveX-компонент (HPInfoDLL.dll) использует небезопасный метод LaunchApp(). Удаленный пользователь может с помощью специально сформированного веб-сайта выполнить произвольные команды на системе. 2. Уязвимость существует из-за того, что HPInfoDLL. HPInfo.1 ActiveX-компонент (HPInfoDLL.dll) использует небезопасные методы GetRegValue() и SetRegValue(). Удаленный пользователь может с помощью специально сформированного веб-сайта получить и записать данные в системный реестр. URL производителя: www.hp.com. Решение: В настоящее время способов устранения уязвимости не существует.
Множественные уязвимости в PHP Программа: PHP версии до 5.2.5. Опасность: Средняя. Описание: 1. Уязвимость существует из-за ошибок в функциях htmlentities и htmlspecialchars, когда частичные многобайтовые последовательности символов не принимаются. 2. Уязвимость существует из-за ошибок проверки границ данных в функциях fnmatch(), setlocale() и glob(). Удаленный пользователь может вызвать переполнение буфера. 3. Уязвимость существует из-за ошибки при обработке .htaccess-файлов. Злоумышленник может изменить директиву mail.force_extra_parameters в .htaccess-файле и обойти ограничения директивы disable_functions. 4. Уязвимость существует из-за ошибки при обработке переменных, которая позволяет злоумышленнику с помощью функции ini_set() переопределить значения переменных в httpd.conf-файле. URL производителя: www.php.net. Решение: Установите последнюю версию 5.2.5 с сайта производителя.
42
Множественные уязвимости в IBM DB2 Программа: IBM DB2 for Linux UNIX and Windows 9.x. Опасность: Средняя. Описание: 1. Уязвимость существует из-за ошибок в DB2WATCH, DB2FREEZE и некоторых setuid-приложениях. Подробности уязвимости не раскрываются. 2. Инструмент DB2DARTвыполняет команду TPUT и позволяет злоумышленнику выполнить команды от имени владельца экземпляра DB2. 3. Уязвимость существует из-за ошибок в OPERATING SYSTEM SERVICES-компоненте (например, некорректные привилегии на доступ к DB2NODES.CFG). Подробности уязвимости не раскрываются. URL производителя: www.ibm.com. Решение: Установите исправление с сайта производителя.
Переполнение буфера в Samba Программа: Samba 3.0.26a, возможно, более ранние версии. Опасность: Средняя. Описание: 1. Уязвимость существует из-за ошибки проверки границ данных в функции reply_netbios_packet() в файле nmbd/nmbd_packets.c при отправке NetBIOS-ответов. Удаленный пользователь может отправить специально сформированные WINS Name Registration-запросы, за которыми следуют WINS Name Query-запросы, вызвать переполнение стека и выполнить произвольный код на целевой системе. Для успешной эксплуатации уязвимости Samba должна быть запущена в качестве WINS-сервера (опция wins support). 2. Уязвимость существует из-за ошибки проверки границ данных при обработке GETDC-запросов. Удаленный пользователь может с помощью специально сформированного GETDC-запроса вызвать переполнение буфера и выполнить произвольный код на целевой системе. Для успешной эксплуатации уязвимости Samba должна быть сконфигурирована в качестве основного или резервного контроллера домена. URL производителя: www.samba.org. Решение: Установите последнюю версию 3.0.27 с сайта производителя.
Составил Александр Антипов
администрирование «1С»
Используем скрипты WSH в «1С:Предприятие» Андрей Луконькин Сервер сценариев Windows (WSH) позволяет без предварительной компиляции запускать программы, написанные на любых языках, поддерживающих технологию Component Object Model (COM).
О
бращаться к методам COM-объектов возможно в том числе и на встроенном языке системы «1С:Предприятие». Создание СОМ-объекта в версии 7.7 происходит с помощью конструкции СоздатьОбъект, а в версии 8 – Новый СОМОбъект. Для версии 7.7: СОМ = СоздатьОбъект("InternetExplorer.Application");
Для версии 8.х:
SendKeys(String) – имитируется нажатие клавиши или последовательности клавиш, указанных в параметре String. В качестве параметра можно указывать как алфавитноцифровые символы, так и символы специальных клавиш, например <Enter>, <Tab>, <F1>, <Alt>, <Shift>, <Ctrl> и т. д. Для указания клавиш <Alt>, <Shift>, <Ctrl> существуют специальные коды: n <Shift> – + n <Ctrl> – ^ n <Alt> – %
СОМ = Новый СОМОбъект("InternetExplorer.Application");
Если возникнет необходимость передать специальные символы именно как символы, а не команды, нужно заклюС помощью WSH можно непосредственно из «1С:Пред- чать их в фигурные скобки, например {+}. приятие» работать с файловой системой, дисками, файлами и папками, системным реестром Windows, сетевы- Пример 2. Подключение сетевого ми ресурсами. принтера Рассмотрим несколько примеров, демонстрирующих Для работы с сетевыми ресурсами в WSH предназначен объработу скриптов в «1С:Предприятие». ект WshNetwork. Из «1С:Предприятие» можно напрямую управлять сетевыми ресурсами, в том числе и принтерами:
Пример 1. Имитация нажатия клавиш
В системе «1С:Предприятие» часто возникает ситуация, когда нужно закрыть окно сообщений, появляющееся при вызове метода Сообщить. Стандартно это окно закрывается при нажатии комбинации клавиш <Ctrl> + <Shift> + <Z>, но можно сделать это и программно: //В ходе выполнения некоторого кода открывается //окно сообщений Сообщить("Сегодня: " +ТекущаяДата()); //Выполнение другой части кода //Теперь нам необходимо закрыть окно сообщений Wsh = Новый СОМОбъект("Wscript.shell"); //Wsh – переменная. Можно было дать любое другое имя, //например, Окно Wsh.SendKeys("^+z"); //имитируем нажатие ++ Wsh.SendKeys("^+я"); //для случая, если текущей является //русская раскладка клавиатуры
В результате выполнения данного кода окно сообщений будет закрыто. Теперь поясню работу этого небольшого фрагмента программы.
№12, декабрь 2007
//Создаём новый СОМ-объект Сеть = Новый СОМОбъект("Wscript.Network"); Попытка //Устанавливаем принтер Сеть.AddWindowsPrinterConnection( ↵ "\\ИмяСервера\ИмяПринтера"); //Делаем этот принтер принтером по умолчанию Сеть.SetDefaultPrinter("\\ИмяСервера\ИмяПринтера"); Исключение //В случае неудачного подключения принтера Сообщить("Невозможно произвести подключение"); КонецПопытки;
Объект WshNetwork позволяет определить список подключенных сетевых принтеров. Для этого используется метод EnumPrinterConnections, который возвращает коллекцию принтеров. Данную коллекцию в системе «1С:Предприятие» версии 8 можно перебрать с помощью конструкции: Для каждого... из... Цикл... КонецЦикла
Таким образом, можно использовать систему «1С:Предприятие» не только как систему учета в организации, но и в целом для администрирования сетевых ресурсов.
43
IP-телефония
Asterisk: организуем автоматическое распределение поступающих вызовов
Сергей Яремчук От оперативности персонала, работающего с клиентами, зависит мнение о самой организации в целом. Если клиент подолгу будет звонить в службу поддержки, это вряд ли положительно скажется на имидже компании. Использование популярного VoIP-сервера IP-PBX Asterisk поможет решить эту проблему. 44
IP-телефония
В
журнале уже подробно рассказы‑ валось о настройке Asterisk [1‑3]. Конечно, много воды с тех пор утекло. Уже доступна новая ветка про‑ дукта 1.4.x с новыми возможностями и параметрами, а некоторые старые убраны, но общий принцип настроек остался таким же. Asterisk может работать как систе‑ ма, автоматически распределяющая поступающие вызовы (ACD – Automatic Call Distribution). В службах поддержки это очень полезная возможность, поль‑ зователь звонит на один из номеров, а на звонок отвечает свободный в дан‑ ное время сотрудник. Реализуется такая функциональ‑ ность при помощи агентов. Агент ак‑ тивируясь в системе, используя спе‑ Настройки agents.conf в AsteriskNOW циальную процедуру, объявляет себя доступным для приема вызовов. Ко‑ личество агентов ничем в общем‑то не ограничено. Каждый агент при нас‑ тройке получает идентификацион‑ ный номер. Здесь следует учитывать, что номера телефонов и ID агента – это не одно и то же. Asterisk-агенты не привязаны к од‑ ному номеру и могут подключаться с любых номеров. Для этого пользо‑ ватель должен позвонить по опреде‑ ленному внутреннему номеру и ввести последовательно по подсказкам систе‑ мы свой ID, пароль и номер телефона (в конце каждого действия необходимо нажимать <#>), к которому его нужно привязать. То есть агент – это как бы еще один виртуальный номер телефо‑ на, но позвонить по нему может только Настройки queues.conf в AsteriskNOW сервер. Кстати, поэтому агентов мож‑ Остальные пользователи добавляются аналогично. Если но использовать и в том случае, когда сотрудники не имеют постоянного рабочего места, назначив каждому ID агента, база пользователей ведется в файле users.conf, то в описа‑ можно всегда его «поймать» вне зависимости от того, ка‑ ние номера следует добавить параметр «hasagent = yes». Теперь можно перейти непосредственно к настройке кой телефон он сейчас использует. По умолчанию все конфигурационные файлы сервера работы агентов. Asterisk находятся в каталоге /etc/asterisk. Применение аген‑ тов не снимает необходимости в создании записи для ре‑ Настройка агентов гистрации телефона в sip.conf или users.conf и экстеншна Агенты определяются в файле agents.conf, в самом простом в extensions.conf. Поэтому в sip.conf заносим информацию случае достаточно добавить в конце файла параметр agent с необходимыми значениями. о номере телефона, например 600: [600] type=friend host=dynamic username=600 secret=600_password nat=no canreinvite=no context=callcenter callerid="User" <600> allow=gsm allow=ulaw allow=alaw
№12, декабрь 2007
$ sudo mcedit /etc/asterisk/agents.conf [general] ; Сохранение статуса агентов в локальной базе не требует ; повторной его регистрации в случае перезагрузки сервера persistentagents=yes ; Разрешение/запрет привязывать к одному экстеншну ; несколько агентов. По умолчанию разрешено ;multiplelogin=yes
45
IP-телефония [agents]
Файл queues.conf:
; Количество неудачных регистраций агента перед отказом ; (по умолчанию – 3) maxlogintries=5
; Создаем новую очередь MyQueue [MyQueue]
; Отключение агента, если трубка в течение ; указанного времени (в секундах) не снята autologoff=15
; Персональный MOH, используется, если нет musiconhold ; в agents.conf ; musicclass = default
; Отключаем обязательное подтверждение регистрации кнопкой ; <#> при регистрации агента через agentcallpark, ; по умолчанию включено, но иногда это вызывает проблемы ackcall=no
; Если агент участвует в нескольких очередях, ; ему проигрывается сообщение, помогающее сориентироваться ; и правильно принять клиента announce = queue-markq
; Время (в мс) между окончанием разговора и повторным вызовом ; агента из очереди. Нужно, например, чтобы пользователь ; успел заполнить отчет (0 – задержка отсутствует) wrapuptime=5000
; Поиск свободного агента strategy=ringall
; Класс фоновой музыки ожидания для агентов musiconhold = default ; Звуковой сигнал, проигрываемый при подключении агентов custom_beep=beep ; Звуковой файл, проигрываемый при отключении агента ;agentgoodbye => vm-goodbye ; Членство в группах для агентов, используется в queues.conf ;group=1,2 ; Далее описывается запись разговоров агентов с клиентами. ; Эта секция является глобальной для канала агентов ; chan_agent ; Включение записи (по умолчанию выключено) ;recordagentcalls=yes ; Формат файла: wav (по умолчанию), gsm, wav49 recordformat=gsm ; Включать в записи CDR поле с именем файла, содержащего ; запись этого вызова. По умолчанию - отключено ;createlink=yes ; Строка, добавляемая к имени при записи, позволяет ; формировать URL ;urlprefix=http://localhost/calls/ ; По умолчанию записи сохраняются ; в /var/spool/asterisk/monitor, каталог можно изменить ;savecallsin=/var/calls ; Описание агентов, в виде ; agent => agentID,agentPassword,имя agent => 3001,1234,Vasja Pupkin agent => 3002,2345, Serg Jaremchuk
Параметром autologoff следует пользоваться очень ос‑ торожно. Если абонент на некоторое время отошел от ра‑ бочего места, а Asterisk его отключил, это может обнару‑ житься не сразу. В некоторых случаях лучше приучить поль‑ зователей снимать и затем восстанавливать регистрацию агента, если он временно не сможет отвечать на звонки. Ес‑ ли параметр timeout в файле queues.conf меньше значения autologoff, то агент в любом случае не будет отключаться.
Очереди обработки вызовов Очереди для обработки вызовов определены в файле queues. conf. Причем одновременно поддерживается несколько оче‑ редей вызовов. Имена очередей используются затем в ка‑ честве аргумента Queue в extensions.conf. В queues.conf все можно оставить по умолчанию, достаточно добавить в конце файла описание новой очереди. Некоторые параметры фай‑ лов agents.conf и queues.conf совпадают, объяснение этому простое, агентов также можно записать в этом файле в ка‑ честве участников, обрабатывающих указанную очередь.
46
; Сколько должен звонить телефон у агента прежде, ; чем переключиться на следующего timeout=15 ; Ожидание перед повторной попыткой обзвона retry=5 ; Вес очереди, то есть приоритет вызова, очереди ; с большим приоритетом будет отдаваться предпочтение weight=0 wrapuptime=15 ; Максимальное количество абонентов в очереди ; (0 - без ограничений) maxlen = 0 ; Через сколько объявлять о приблизительном времени ; ожидания или позиции абонента в очереди (0 - выкл) announce-frequency = 60 ; yes|no|once – включение в анонсы времени ожидания ; абонента announce-holdtime = no ; Периодическое сообщение, вроде «Спасибо, что позвонили, ; ожидайте, вам скоро ответят», чтобы абонет не думал, ; что о нем все забыли periodic-announce = thank-you-message ; Проигрывать thank-you-message каждые 60 секунд ожидания periodic-announce-frequency = 60 ; Величина для округления значения времени announce-round-seconds = 10 ; При подключении агенту указывается, сколько времени ; прождал клиент reportholdtime = yes ; При установке в yes, значение тайм-аута для агента будет ; сбрасываться, если от него будут получены сигналы BUSY ; или CONGESTION, например агент отметил вызов timeoutrestart = no ; Описание агентов, обслуживающих очередь member => Agent/3001 member => Agent/3002 ; member => Agent/@1 ; Это группа агентов
При описании агента, через запятую, после ID (member => Agent/3002,1) может указываться параметр penalty. Сер‑ вер будет последовательно обзванивать агентов, начиная с penalty с меньшим номером, если они все заняты, то перей‑ дет на агентов с более высоким значением penalty. Это мож‑ но использовать для обслуживания очереди в критические моменты. Например, у персонала с номером penalty = 0 от‑ вечать на звонки – это основная обязанность, они и будут обслуживать очередь. Если количество звонков увеличит‑ ся, будет привлечен дополнительный персонал с penalty = 1 и так далее. Параметр strategy отвечает за распределение вызовов между агентами. По умолчанию используется значение ringall, при котором звонок производится по всем свобод‑
IP-телефония ным номерам, пока один из них не ответит. Такой режим не всегда удобен, и можно рекомендовать только при кри‑ тических нагрузках, поэтому в зависимости от ситуации его нужно изменить на другой. Например, в небольшом офисе подойдет вариант более справедливый rrmemory. В этом случае запоминается последний агент, которому был пере‑ дан звонок, при поступлении следующего запроса поиск на‑ чнется со следующего по списку агента. Режим roundrobin несколько похож на rrmemory, только запоминается агент, с которого начинался поиск, и в следующий раз поиск на‑ чнется со следующего по списку. Возможны другие вари‑ анты: random (произвольный агент), leastrecent (отвечав‑ ший ранее других) и fewestcalls (получивший меньшее ко‑ личество звонков в этой очереди). Также в файле в параметрах, начинающихся на queue-*, описано несколько звуковых файлов, используемых для ука‑ зания абоненту его позиции в очереди или приблизительно‑ го времени ожидания обработки его вызова. Сами сообще‑ ния на английском, нужно на их место подставить свои. Чтобы агенты могли регистрироваться, необходимо в extensions.conf добавить специальные расширения и за‑ нести сам экстеншн:
рые входят внутренний номер и агент. После регистрации агент будет поставлен в очередь на обработку поступаю‑ щих звонков на номер 911. Если после соединения с 911 вы‑ дается сообщение: Unable to join queue 'MyQueue'
то скорее всего на данный момент ни один из агентов не за‑ регистрирован. Позвонив повторно на номер 7001, можно сменить телефон, к которому будет привязан агент, или, на‑ жав <#>, отменить регистрацию агента. При поступлении входящего звонка Asterisk поднимает трубку, переводя со‑ единение в состояние ответа, и вызывает свободного в дан‑ ное время агента. Если все номера заняты, звонившему мо‑ жет выдаваться информация о времени ожидания и прибли‑ зительном времени, когда ему ответят, и музыка.
Настройка музыки при ожидании
Слушать гудки, пока абонент не снял трубку, скучно, что‑ бы немного снять напряжение, можно установить мелодию, которая будет проиграна вместо гудков. В Asterisk в качес‑ тве источника звука можно использовать файлы в форма‑ тах WAV, MP3, UL, RAW и других, а также потоковое аудио. Формат WAV в версии 1.4.x используется по умолчанию и яв‑ ; номер для регистрации агента ляется предпочтительным, так как отнимает меньше сис‑ exten=> 7001,1,AgentCallbackLogin(||${CALLERIDNUM}@callcenter) темных ресурсов на конвертирование. Учитывая нагрузку [callcenter] на канал и качество связи, 8 бит часто вполне достаточно, exten=> 911,1,Answer использовать файлы с лучшим качеством не стоит. В ран‑ exten=> 911,2,Ringing exten=> 911,3,Wait(2) них версиях для воспроизведения MP3-файлов необходи‑ exten=> 911,4,Queue(MyQueue) мо было установить утилиту mpg123 или другую, использу‑ exten=> 911,5,Hangup ; и номера телефонов емую для преобразования mpeg в PCM. Сейчас разработ‑ exten => 600,1,Dial(SIP/600) чики Asterisk отказались от его использования, и для под‑ ; и так далее держки MP3 необходимо использовать пакет asterisk-addons. После изменений в конфигурации не забываем пере‑ В поставке Asterisk уже есть несколько мелодий, которые загружать Asterisk: находятся в каталоге /var/lib/asterisk/moh. В самом простом случае достаточно в musiconhold.conf указать новый класс, $ sudo asterisk -r состоящий всего из нескольких директив: CLI> reload
Сервер должен показать, что модуль app_queue.so го‑ тов к работе (True Call Queueing). Теперь, чтобы зарегистрировать агента, набираем но‑ мер 7001 и по подсказкам системы вводим сначала ID = 3001 и #, затем пароль 1234 и #. При работе с некоторыми софт‑ фонами (X-Lite и ZoIPer njxyj) Asterisk почему-то не опреде‑ ляет автоматически номер телефона, поэтому на третьем шаге может последовать запрос о номере, к которому сле‑ дует привязать агента – 600 и #. Если все сделано правильно, то будет проиграно сооб‑ щение «agent-loginok», сервер положит трубку, а в консоли появится сообщение: Callback Agent '3001' logged in on 600@callcenter Setting global variable 'AGENTBYCALLERID_600' to '3001'
Если в регистрации отказано и в консоли выдано со‑ общение: Extension '600@callcenter' is not valid for automatic login of agent '3001'
проверьте еще раз все позиции номерного плана, в кото‑
№12, декабрь 2007
[default] mode => files directory => /var/lib/asterisk/moh random=yes
Класс default описывает ресурс для MON. В нем мы ука‑ зали режим воспроизведения файлов, каталог, в котором находится музыка, и установили их случайное воспроизве‑ дение. Если файлы имеют специфический формат, который не может воспроизвести Asterisk, дополнительно следует использовать директиву «application». В качестве аргумен‑ та в «application» можно использовать и скрипты, умеющие воспроизводить музыку в определенном формате. Вот собственно и все настройки. Как видите, исполь‑ зование Asterisk может помочь решить весьма непростую проблему обслуживания клиентов. Успехов. 1. Платов М. Asterisk и Linux: миссия IP-телефония. Действие 1 //«Системный администратор», № 6, 2005 г. – C. 12-19. 2. Платов М. Asterisk и Linux: миссия IP-телефония. Действие 2 //«Системный администратор», № 7, 2005 г. – C. 32-38. 3. Платов М. Asterisk и Linux: миссия IP-телефония. Действие 3 //«Системный администратор», № 8, 2005 г. – C. 10-19.
47
человек номера
Игра в IT, или Зарисовки к портрету Дмитрия Гудзенко
История о директоре, который любит учиться и учить.
Фея для Золушки
бывают чудеса. И приятно понимать, ложить еще немного усилий... Такое Мне очень понравилась история од- что чудо это – рукотворное. И еще мне настроение у меня всегда было, когда ной современной Золушки, вернее, очень приятно разговаривать с руко- я в детстве смотрела старые советские «Золушка», потому как мужского по- водителем центра, который «кует» та- фильмы про героев труда – они работала… Юноша, весьма молоденький, кие чудесные биографии аж с 1991 го- ли не покладая рук, и обязательно дос чистым послужным листом и нуле- да. Он имеет право сказать даже та- бивались потрясающих успехов – возвым опытом, явился в учебный центр кие слова: «Мы на сегодня обучили бо- водили завод, корабль, домну. Мне да«Специалист» и закончил несколько лее 300 тысяч человек, и я очень рад, же это выражение всегда нравилось: популярных курсов по различным на- что у большинства из них жизнь стала «не покладая рук». В нем такой аппеправлениям в области информацион- лучше, чем была до курсов». Согла- тит к своему делу! И я никогда не пониных технологий. А затем со всеми ко- ситесь, одна возможность заявить та- мала, как это народ получает удовольствие от философского «far niente» рочками о полученной достаточно вы- кое окрыляет. сокой квалификации «Золушок»… усВообще, когда беседуешь с Дмит- (ничегонеделания). троился на высокооплачиваемую ра- рием Гудзенко, куда-то исчезают лень боту в престижную фирму. Без всякого и апатия. Начинаешь думать, что не Простая система блата. Почему мне нравится эта исто- все потеряно, а все задуманное обя- Директор учебного центра «Специрия? Честно говоря, приятно знать, что зательно сбудется, стоит только при- алист» Дмитрий Юрьевич Гудзенко
48
человек номера свою неиссякаемую энергию, деловой ресно преподавать и которые это деВ соответствии с общей стратегинастрой по каким-то неведомым кана- лают с удовольствием. И наша задача – ей решаются и два других генеральных лам передает выпускникам своего уни- создать им хорошие условия». вопроса – кого учить и чему? Невозкального учебного заведения. УдивиЭто сейчас Дмитрий Гудзенко спо- можно научить всех. Однако Дмитрий тельно, как? Он ведь сам не учитель- койно говорит о кадровой проблеме. Гудзенко постарался сделать четкий ствует. На то есть двести квалифици- А в свое время, когда зарплаты в IT- выбор. В итоге выстроилась полная секторе стали расти чуть ли не по 40% педагогическая «линейка». «Мы учим рованных преподавателей. Но существует такой сорт руко- в год и преподаватели центра нача- пользователей; продвинутых пользоводителей – у них есть дар «прони- ли уходить консультантами в веду- вателей; продвинутых специалистов; кать» во все дела, быть живым, од- щие инофирмы, было ощущение шока. технических специалистов, но не иннако незримым «духом» своей ком- Способ остановить текучку кадров был женеров; инженеров; специалистов по пании. Голос Дмитрия Гудзенко, когда найден, а заодно были решены многие управлению проектами. Наша задача – он в офисе, слышится сразу во всех другие проблемы. Как? организовать не фрагментарное обууголках центра, к нему можно обрачение, а комплексные программы». титься по любому, самому пустяково- Совет для сисадминов Чему учить, подсказывает рынок му поводу, и он даст подробное разъ- А вот так. Главная управленческая за- труда. Если спрос велик, значит, эта яснение, хотя вовсе не обязан быть дача Дмитрия Гудзенко всегда была та- тема появляется в учебной програмв курсе всех деталей. А когда дирек- кая: «Чтобы к нам приходили клиенты. ме центра. тор, не дай бог, заболевает, по элект- У нас не было никакого государственронной почте от него приходят сотни ного финансирования, у нас нет до сих «Неинтересная» писем в день. Нет, он доверяет своим пор никаких других интересов, кроме биография сотрудникам, просто такая привычка – интересов наших слушателей. Мы жи- Дмитрий Гудзенко шутит: «Биография нести ответственность за свое детище. вем только за деньги, которые нам пла- у меня «неинтересная», однако вполне Коллеги Дмитрия Юрьевича волей-не- тят наши слушатели, у нас нет никаких логичная». Да, биография словно наволей должны быть под стать своему других источников доходов». рочно придумана для наградного лисруководителю. Количественный рост – сознатель- та. Началось все со школы, с увлече«Каков ваш стиль руководства? – ная позиция. Но это не потому что ру- ния математикой, компьютерами, веринтересуюсь я. – Как справляетесь ководителю «Специалиста» хочет- нее, тогда, в конце 80-х, программирус таким количеством преподавате- ся объять необъятное, прославиться емыми калькуляторами. «Уже в 8 класлей?». – «Это несложно. Преподава- и попасть в книгу рекордов Гиннесса… се у меня был программируемый кальтели вообще не нуждаются в руко- Большое количество слушателей да- кулятор, – вспоминает Дмитрий Юрьводстве. Преподаватель – это наша ет множество преимуществ. «Мы са- евич. – Наверное, мне очень повезло, основная движущая сила. Как прави- мый большой учебный центр – а зна- что не пришлось себя искать, менять ло, он хорошо знает курс, который чи- чит, у нас есть стабильное расписа- сферы деятельности. Компьютер – лютает. Все, что ему нужно, – правильно ние на три с половиной тысячи групп бовь жизни с детства». А дальше все организовать учебный процесс, этим на год вперед. В отличие от маленьких еще проще. «В 1981 году я поступил вопросом у нас занимаются специ- учебных центров мы можем гаранти- в МВТУ имени Баумана на кафедру альные люди. Моя задача – стимули- ровать, что, например, ваше обучение «Электронно-вычислительные машировать энтузиастов и не пускать в ком- по курсу «Расширенные возможности ны и системы», в 1987 году закончил, панию ремесленников и халтурщиков. Excel» начнется и закончится в опре- поступил в аспирантуру. С 1991 года Ничего сложного нет. Преподаватели деленные сроки, даже если вы захо- организую компьютерные курсы по инне нуждаются в ежедневной провер- тите учиться весной следующего года. формационным технологиям». ке. Оценку им выставляют слушатели. Для клиента это предсказуеЕсли преподаватель хорошо работает мость, возможность выбора, «Наверное, мне очень повезло, что не пришлось и слушатели в восторге, никаких проб- как в большом магазине. Дасебя искать, менять сферы деятельности. лем нет. Простая система». лее мы эффективно испольКомпьютер – любовь жизни с детства». «А найти хорошего преподавателя зуем ресурсы. Наши классы тоже просто?» – «Это самая большая всегда заполнены. У тех ценпроблема. Было время, когда препо- тров, которые учат частных лиц, в осИдея курсов, конечно, возникдавателей было больше, чем рабочих новном битком забиты вечерние клас- ла не случайно. Уже на старших курмест. В конце 1990-х – начале 2000-х сы, у тех, кто учит компании, – наобо- сах Дмитрий начал преподавать. Коггодов многие технические специалис- рот, дневные, а вечером пусто. А мы да поступил в аспирантуру, стал проты, оказавшись не у дел, с удовольс- учим и тех, и других, поэтому наши водить занятия уже не только для стутвием шли преподавать. Сейчас ситу- классы не простаивают. В результа- дентов, но и для взрослых по линии поация изменилась. Зарплаты техничес- те наш заказчик получает высочай- вышения квалификации. Так возник ких специалистов выросли. Да и конку- шее качество по приемлемой цене. опыт преподавания информационных рировать на рынке достаточно сложно. Преподавателям мы платим больше, технологий взрослым. «Поскольку я в Тем не менее всегда, в любом поколе- чем другие учебные центры, а с кли- институте занимался разработкой пронии, есть энтузиасты, которым инте- ента берем столько же». граммных систем, причем наша груп-
№12, декабрь 2007
49
человек номера Дмитрий Юрьевич гордится: «В Бауманке есть такая традиция – выпускники очень хорошо друг к другу относятся, независимо от того, где и как они учились, поэтому слово «выпускник МВТУ» – это своего рода пароль, который открывает многие двери». И, конечно, ему приятно на ежегодных встречах слышать об успехах своих клиентов: «Приятно, что делаем чтото полезное для других людей. Замечательно, что наши выпускники пользуются дополнительным авторитетом, по сравнению со слушателями других центров. Это увеличивает их шансы найти лучшую работу».
па одна из первых стала использовать персональные компьютеры, то выбор, чем заниматься, по-моему, был предопределен. С 1991 года по сегодняшний Сам себе ученик день я руковожу центром компьютер- Компьютерные курсы для кого-то – ного обучения, который вырос из очень просто волшебная коробочка. Стоит ее маленькой организации с одним чело- «открыть», получить сертификат – и бовеком в штате в крупнейший учебный гатство, успех, карьерный рост обеспецентр России по информационным тех- чены. Тут есть доля истины, но, естеснологиям». твенно, очень многое зависит от челоНайдя свою и только свою нишу, века. Дмитрий Гудзенко рассказывает: Дмитрий Гудзенко сознательно остал- «Когда к нам на курсы приходят слушася в вузовских родных стенах. Учеб- тели и спрашивают, в какой области ный центр расположен на базе «аль- им специализироваться, мы рекоменма-матер» Дмитрия Юрьевича, и это дуем им попытаться продолжать рабопозволяет директору «Специалиста» тать в той области, где они уже трудятся в полном смысле слова быть «на пе- и где добились успеха. Лучше испольрекрестке» между вузом, работодате- зовать весь свой жизненный и пролями и однокашниками. фессиональный опыт, все знания, которые у вас есть. К тому же из«Учиться я люблю, хотя, конечно, мое обуче- вестно, что работодатели с поние идет в более интенсивной форме, часто дозрением относятся к человеку, который часто меняет месповышаю свою квалификацию на семинарах, то работы». конференциях». Впрочем, у «Специалиста» немало клиентов, которые совДмитрий Гудзенко не теряет связи сем не желают переходить на другую с преподавателями, которые учили его работу, а просто хотят повысить свою самого и его однокурсников, – это раз. квалификацию. Сфера IT развивается Он в обязательном порядке встре- очень быстро. «Даже оставаясь в рамчается со своей студенческой группой, ках одной специальности, одной прораз в год бывшие мальчики и девочки, фессии, нужно постоянно что-то новое а ныне солидные дяди и тети выбира- изучать, новые технологии осваивать ются за город, – это два. и помнить, что, если ты сегодня что-то Зачастую выпускники центра «Спе- выучил, через три года это будет никоциалист» устраиваются на работу му не нужно. Попытайтесь сейчас найв фирмы, которыми руководят бауман- ти работу со знанием Windows NT или цы, и берут «птенцов гнезда Гудзенко» первой версии Novell! Знания сильно всегда с радостью, – это три. устаревают».
50
«А вы сами любите учиться?» – «Даже больше, чем нужно! Человек не может занимается профессионально обучением, если сам не любит учиться. В прошлом году летом я прошел в нашем же центре курс по PhotoShop, хотелось посмотреть, что это такое. Было очень интересно. А в этом году я учился на заочных курсах по управлению учебными центрами, в ноябре ездил в Штаты сдавать экзамен, первый в России получил статус Certified Program Planner (на русский переводится примерно как «Cертифицированный руководитель учебных программ»). Кстати, таких сертифицированных специалистов в мире всего три тысячи. Учиться я люблю, хотя, конечно, мое обучение идет в более интенсивной форме, часто повышаю свою квалификацию на семинарах, конференциях». Выпускницей центра уже успела стать старшая дочь Дмитрия Гудзенко. Вкус к учебе, естественно, передается детям. Пока одному Богу известно, какую профессию выберут юные леди Гудзенко, но уже сегодня информационные технологии для них такая же привычная вещь, как телевизор и телефон. Так что, возможно, состоится когда-нибудь рождение новой династии, на сей раз в области обучения IT. Дочки Гудзенко твердо знают – настоящий директор работает 24 в сутки. И не потому, что заставляют, а потому, что по-другому он не может. «У меня хобби и работа совпадают, – признается Дмитрий. – Мне интересно то, чем я занимаюсь. Компания «Специалист» в постоянном развитии. Ставятся новые курсы, приходят новые преподаватели, используются новые технические средства, новые приемы, новые методы организации труда. Это все настолько интересно, поверьте мне, театр отдыхает». «Вы все это изучаете вместо того, чтобы смотреть по телевизору сериалы?» – «Я в это играю. Человек должен заниматься тем, что ему очень нравится. Тогда он достигает высоких результатов, при этом гораздо меньше напрягается. А заниматься нелюбимым делом только ради денег в сфере интеллектуального труда невозможно».
Оксана Родионова На правах рекламы
web
Создаём собственный хостинг, или Сам себе ISP Часть вторая
Андрей Шетухин В предыдущей части была описана общая схема веб-хостинга, первоначальная подготовка сервера к настройке, установка необходимого программного обеспечения и его минимальная настройка. Сегодня мы рассмотрим создание системы домашних каталогов пользователей, отделение пользователей друг от друга и от системы, а также настройку производительности системы.
Общие концепции Как уже упоминалось в первой части (см. №4 за 2007 год), мы разделяем типы пользователей. То есть у нас есть отдельный пользователь c отдельным паролем для доступа к СУБД, FTP и для работы в шелле по SSH. Чтобы не возникало неразберихи, следует как-то систематизировать все создаваемые сущности. Хорошим и проверенным методом является следующий: все пользователи данной техплощадки имеют один и тот же префикс в виде имени площадки. Пример: u00000, где u – сокращение от «user»,
52
а 00000 – порядковый номер площадки по базе данных. Для площадки с номером 12345 у нас будут следующие реквизиты: n /home/www/u12345 – каталог с сайтами, например /home/www/u12345/ somesite.ru; n u12345 – имя пользователя для работы по SSH и FTP; n u12345.ftp.ourhosting.ru – название хоста для доступа на техплощадку по FTP; n u12345.ssh.ourhosting.ru – название хоста для доступа на техплощадку по SSH;
n u12345 – имя пользователя для работы c базой данных;
n u12345 – собственно база данных; n u12345.mysql.ourhosting.ru – имя хоста, на котором расположена БД. В случае, если пользователю понадобятся дополнительные базы данных, их имена будут u12345_2, u12345_3, u12345_4 и т. д. Разумеется, у хостинга должны быть настроены зоны DNS так, чтобы при запросе имен хостов отдавались правильные IP-адреса.
web Небольшое отступление. Очень плохая практика называть пользователей значимыми именами, например «alex» или «somesite_ru», это очень неудобно с точки зрения организации биллинга, системы резервного копирования и миграции данных между машинами, заставляет каждый раз придумывать новые имена, а самое главное – при наличии достаточного количества клиентов приводит к повторениям и дальнейшей путанице.
Профиль пользователя На сегодняшний день реалии таковы, что большая часть сайтов имеют кодировку Windows-1251. Применительно к вопросу веб-хостинга это означает, что вся локализация консоли, веб-сервера и сервера базы данных должна быть ru_RU.CP1251. Для локализации консоли необходимо создать дополнительный класс russianwww в файле /etc/login.conf: # # Russian Web Users Accounts. # Setup proper environment variables. # russianwww|Russian Users Accounts:\ :charset=CP1251:\ :lang=ru_RU.CP1251:\ :umask=0007:\ :tc=default:
После необходимых правок /etc/login.conf, пересоздаем базу данных: cap_mkdb /etc/login.conf
Для локализации Apache придется изменить файл /usr/local/sbin/apachectl, внеся в него следующие строки: #!/bin/sh # Localization umask 0002 LC_ALL=ru_RU.CP1251; export LC_ALL LANG=ru_RU.CP1251; export LANG MM_CHARSET=CP1251; export MM_CHARSET
Для сервера MySQL достаточно будет создавать пользовательские базы данных с кодировкой cp1251 и cp1251_general_ci collation: CREATE DATABASE `u00001` DEFAULT CHARACTER SET cp1251 ↵ COLLATE cp1251_general_ci;
Система каталогов пользователей Как уже было описано в первой части статьи (см. №4 за 2007 год), пользователи виртуального хостинга размещаются на отдельном разделе /home в каталоге www. Если с течением времени свободное место в /home/www закончится, мы сможем установить в сервер дополнительный физический диск и смонтировать его в /home/www1. При этом общая схема работы хостинга не изменится, и дополнительная настройка не понадобится. Для того чтобы пользователи не имели доступа к «чужим» данным, необходимо правильно выставить права и владельцев каталогов. Такая настройка каталогов пользователей – очень важный момент, поэтому остановимся на ней подробнее.
№12, декабрь 2007
Итак, пользователи не должны иметь доступ к каталогам друг друга, но при этом надо позаботиться о доступности этих данных веб-серверу. К счастью, механизм UNIX permissions позволяет решить эту проблему: мы создадим специальную группу, в которую будут входить пользователи веб-хостинга и пользователь, от которого запущен вебсервер Apache: pw groupadd virtwww -M www
Создаем каталоги: mkdir -p /home/www chown root:wheel /home/www
Права на каталог /home/www должны быть 0711, чтобы нельзя было получить список файлов/каталогов внутри. Пользователи могут войти в каталог, но не могут получить листинг. Создаем пользователя нашего веб-хостинга: pw useradd u00001 -g virtwww -d /home/www/u00001 ↵ -s /usr/local/bin/bash -L russianwww -m pw groupadd u00001 -M u00001
Таким образом, каждый пользователь имеет две группы: первичную – virtwww и дополнительную, совпадающую по имени с именем пользователя. Устанавливаем права на домашний каталог пользователя: chmod 04710 /home/www/u00001 chown u00001:www /home/www/u00001
При таких правах на каталог никто, кроме пользователя u00001 и веб-сервера, не будет иметь доступа к данным пользователя, а созданные внутри файлы и каталоги будут наследовать ID и GID владельца. Для хранения лог-файлов мы выберем каталог /var/log/ apache. Именно здесь нам потребуется введенная дополнительно группа у пользователя хостинга: при её помощи мы выдадим права на просмотр лог-файлов. Создаем каталог, в котором будут храниться лог-файлы: mkdir -p /var/log/apache chmod 0711 /var/log/apache chown root:wheel /var/log/apache mkdir /var/log/apache/u00001 chmod 0750 /var/log/apache/u00001 chown root:u00001 /var/log/apache/u00001
Теперь осталось расписать процедуру заведения виртуального хоста для пользователя. Сделаем это на примере сайта example.ru: 1. Создаем каталоги: mkdir -p /home/www/u00001/example.ru/www mkdir -p /home/www/u00001/example.ru/cgi mkdir -p /home/www/u00001/example.ru/tmp chown -R u00001:virtwww /home/www/u00001/example.ru chmod -R 04770 /home/www/u00001/example.ru mkdir /var/log/apache/u00001/example.ru chmod 0750 /var/log/apache/u00001/example.ru
53
web 2. Прописываем конфигурацию для Apache:
Для автоматизации создания учетных записей пользователей можно воспользоваться скриптом, доступным по адресу http://www.reki.ru/products/webhosting/addftpuser.
<VirtualHost 127.0.0.1:80> ServerName example.ru ServerAlias www.example.ru DocumentRoot /home/www/u00001/example.ru/www ScriptAlias /cgi /home/www/u00001/example.ru/cgi ErrorLog /var/log/apache/u00001/example.ru/ ↵ error_log TransferLog /var/log/apache/u00001/example.ru/ ↵ access_log
php_admin_value upload_tmp_dir ↵ /home/www/u00001/example.ru/tmp php_admin_value doc_root ↵ /home/www/u00001/example.ru php_admin_value user_dir www php_admin_value open_basedir /home/www/ ↵ u00001:/usr/local/share/smarty:/usr/ ↵ local/share/pear php_admin_value session.save_path ↵ /home/www/u00001/example.ru/tmp
Настройка параметров системы Настройка параметров системы преследует две цели. Первая цель: повысить уровень безопасности путем изоляции пользователей друг от друга и от системы и вторая – достичь оптимальной производительности хостинга. Для изоляции клиентов хостинга на уровне файловой системы мы воспользовались системой UNIX permissions. Теперь необходимо изолировать клиентов на уровне доступа к списку процессов, используемых ресурсов и т. п. Для этого в файл /etc/sysctl.conf вносим строчку: security.bsd.see_other_uids=0
и перечитываем конфигурацию:
User u00001 Group virtwww </VirtualHost>
/etc/rc.d/sysctl restart
3. Проверяем конфигурацию Apache: Для того чтобы при падении программ система писала core-файлы в один каталог, а не во всю файловую систему, также добавляем строчки:
/usr/local/sbin/apachectl configtest Syntax OK
4. Перезапускаем веб-сервер Apache и проверяем работу системы:
Для оптимизации работы системы пропишем следующие параметры:
/usr/local/sbin/apachectl restart echo "<? phpinfo(); ?>" > /home/www/u00001/example.ru/www/test.php fetch http://example.ru/test.html test.php
34 kB
13 MBps
rm /home/www/u00001/example.ru/www/test.php
5. Заводим FTP-доступ для пользвателя. Поскольку всех FTP-пользователей мы храним в БД, вся процедура создания доступа по FTP сводится к созданию ровно одной записи: INSERT INTO ftp.ftpusers VALUES('u00001', 'topsecret', ↵ '1001', '1000', '/home/www/u00001', 0, 1, '');
где 1001 – UID пользователя, а 1000 – GID группы virtwww. Проверяем доступ по FTP: ftp localhost Trying ::1... Connected to localhost. 220---------- Welcome to Pure-FTPd [privsep] [TLS] ---------220-You are user number 1 of 50 allowed. 220-Local time is now 01:58. Server port: 21. 220-This is a private system - No anonymous login 220 You will be disconnected after 15 minutes of inactivity. Name (localhost:stellar): u00001 331 User u00001 OK. Password required Password: 230-User u00001 has group access to: u00001 virtwww 230 OK. Current restricted directory is / Remote system type is UNIX. Using binary mode to transfer files. ftp> quit 221-Goodbye. You uploaded 0 and downloaded 0 kbytes. 221 Logout.
54
kern.sugid_coredump=0 kern.corefile=/var/tmp/%N.core
kern.ipc.maxsockbuf=16777216 net.inet.tcp.rfc1323=1 net.inet.tcp.sendspace=1048576 net.inet.tcp.recvspace=1048576 net.inet.tcp.sack.enable=1 kern.maxfiles=204800 kern.maxfilesperproc=200000 net.inet.ip.portrange.first=1024 net.inet.ip.portrange.last=65535 net.inet.ip.portrange.randomized=0 net.inet.tcp.nolocaltimewait=1
Детальное их описание довольно сложно и выходит за рамки данного руководства; интересующимся следует обратиться к текстам докладов Первой конференции российских веб-разработчиков: http://www.rit2007.ru/org.html.
Выводы Разумеется, это всего лишь прототип реального хостинга и при количестве клиентов до нескольких сотен будет работать в предлагаемой конфигурации. Для развертывания системы в эксплуатацию с несколькими тысячами пользователей необходимо, как минимум, разнести веб-сервер и сервер БД, а для биллинга выделить отдельную машину. Также следует рассмотреть вопросы организации резервных копий (backup), систему миграции пользователей между серверами хостинговой площадки, а также – систему миниторинга пользовательской активности. Возможно, об этом – в следующих статьях. Удачи!
bugtraq Несколько уязвимостей в ядре Linux Программа: Linux kernel версии до 2.6.23.8. Опасность: Средняя. Описание: 1. Уязвимость существует из-за ошибки разыменования нулевого указателя в функции tcp_sacktag_ write_queue() в файле tcp_input.c при обработке ACK-ответов. Удаленный пользователь может с помощью специально сформированного ACK-пакета аварийно завершить работу ядра системы. 2. Уязвимость существует из-за некорректной обработки состояния завершения процесса в функции wait_task_ stopped(). Локальный пользователь может аварийно завершить работу ядра системы. URL производителя: www.kernel.org. Решение: Установите последнюю версию ядра 2.6.23.8 с сайта производителя.
Переполнение буфера в Cisco Security Agent Программа: Cisco Conference Connection (CCC) 1.x, Cisco Emergency Responder (CER) 1.x, Cisco IP Call Center Express (IPCC Express), Cisco IP Interactive Voice Response (IP IVR), Cisco Personal Assistant Version 1.3x, Cisco Personal Assistant Version 1.4x, Cisco Security Agent (CSA) 4.x, Cisco Security Agent (CSA) 5.x, Cisco Unified Communications Manager 4.x, Cisco Unified Communications Manager 5.x, Cisco Unified Communications Manager 6.x, Cisco Unified MeetingPlace 4.x. Опасность: Средняя. Описание: Уязвимость существует из-за ошибки проверки границ данных в определенном системном драйвере. Удаленный пользователь может с помощью специально сформированного пакета на порт 139/TCP или 445/TCP вызвать переполнение буфера и скомпрометировать целевую систему. URL производителя: www.cisco.com. Решение: Установите исправление с сайта производителя.
Переполнение буфера в продуктах Trend Micro Программа: Trend Micro AntiVirus plus AntiSpyware 2008, Trend Micro Internet Security 2008, Trend Micro Internet Security Pro 2008. Опасность: Средняя. Описание: Уязвимость существует из-за ошибки проверки границ данных в PccScan.dll при обработке UUE-файлов. Удаленный пользователь может с помощью специально сформированного UUE-файла вызвать отказ в обслуживании приложения. Примечание: Согласно уведомлению производителя исправлена уязвимость форматной строки при обработке UUE-файлов. В данный момент не ясно, о какой уязвимости идет речь. URL производителя: www.trendmicro.com. Решение: Установите исправление с сайта производителя.
№12, декабрь 2007
Множественные уязвимости в Ingate Firewall и SIParator Программа: Ingate Firewall версии до 4.6.0, Ingate SIParator версии до 4.6.0. Опасность: Средняя. Описание: 1. Уязвимость существует из-за ошибки проверки границ данных в libsrtp. Удаленный пользователь может вызвать переполнение буфера и скомпрометировать целевую систему. 2. Уязвимость существует из-за ошибки в SRTP-компоненте при обработке слишком длинных RTCP-индексов. Злоумышленник может с помощью специально сформированного RTCP-индекса аварийно завершить работу ядра. 3. Уязвимость существует из-за ошибки при обработке второй фазы IPsec, не содержащей PFS. Злоумышленник может аварийно завершить работу IPSec-модуля. 4. Уязвимость существует из-за ошибки в SIP-компоненте во время использования Remote NAT Traversal. Ошибка может привести к конфликту регистраций и отправке сообщений другому пользователю. 5. Пароли обычных администраторов хранятся в открытом виде. URL производителя: www.ingate.com. Решение: Установите последнюю версию 4.6.0 с сайта производителя.
Отказ в обслуживании в Wireshark Программа: Wireshark 0.99.6 и более ранние версии. Опасность: Средняя. Описание: Уязвимости существуют из-за различных ошибок (большие циклы с потреблением большого количества памяти, зацикливание, аварийное завершение работы, переполнение буфера) в различных диссекторах (SSL, ANSI MAP, Firebird/Interbase, NCP, HTTP, MEGACO, DCP ETSI, PPP и Bluetooth SDP), при обработке MP3 или iSeries (OS/400) Communication-файлов, при обработке DNP- или RPC Portmap-пакетов. Удаленный пользователь может аварийно завершить работу приложения. URL производителя: www.wireshark.org. Решение: Установите последнюю версию 0.99.7 с сайта производителя.
Переполнение буфера в Squid Программа: Squid версии до 2.6.STABLE17. Опасность: Средняя. Описание: Уязвимость существует из-за ошибки проверки границ данных при обработке ответов для обработки кэша. Удаленный пользователь может с помощью специально сформированного ответа аварийно завершить работу прокси-сервера. URL производителя: www.squid-cache.org. Решение: Установите последнюю версию 2.6.STABLE17 или исправление с сайта производителя.
Составил Александр Антипов
55
программирование
Новое в синтаксисе Perl 5.10
Андрей Шитов 18 декабря исполнилось 20 лет с момента выхода первой версии Perl. Наиболее распространенная на сегодня версия – 5.8.8 – вышла в свет в начале 2006 года, при том что сама ветка 5.8 была начата еще почти четырьмя годами раньше, летом 2002-го. В этот же день 18 декабря в 2007 году произошло два важных события: выпущена новая стабильная версия Perl 5.10 [1], которая, по-видимому, станет стандартом на переходный период до создания полноценного компилятора Perl 6, и новая версия виртуальной машины Parrot [2], в составе которой содержится заново переписанный экспериментальный компилятор Perl 6.
В
этой статье описаны основ- и появились при разработке дизайные нововведения, которые по- на Perl 6. явились в Perl 5.10. Читателя не должно смущать, что вместо шес- Установка той версии продолжает развиваться Н о в о й в е р с и и п р е д ш е с т в о в а л и пятая. В версии Perl 5.10 включены не- две предварительные: RC1 и RC2. которые операторы, которые как раз Тем не менее для экспериментов с но-
56
вым языком предпочтительнее установить дистрибутив в отдельный каталог /perl5.10 на UNIX-системах. Пользователям Windows проще воспользоваться готовым инсталлятором ActivePerl 5.10, выпущенным компанией ActiveState.
программирование Процесс установки из исходных кодов стандартен; для упомянутого каталога установки необходимо выполнить следующие команды: ./Configure -Dprefix=/perl5.10 make make install
Конфигурационный скрипт традиционно задает множество вопросов. Чтобы их избежать, можно при запуске Configure указать опции -des, чтобы выбрать все значения по умолчанию. Для удобства экспериментов полезно включить путь к исполнимому файлу perl5.10 в переменную окружения PATH. После успешной установки команда perl5.10 -v должна напечатать информацию о версии; в моем случае вывелось следующее: This is perl, v5.10.0 built for darwin-2level Copyright 1987-2007, Larry Wall
use feature Для некоторых новых возможностей потребовалось ввести в язык новые ключевые слова. Поэтому, для того чтобы обеспечить максимально возможную обратную совместимость, необходимо сообщить компилятору о том, что необходимо включить поддержку этих слов. Для их активации предусмотрена инструкция use feature, которая может принимать список идентификаторов. В Perl 5.10 существует три случая, когда это необходимо делать:
переданных аргументов. Допустимо также передать файловый дескриптор. Например: say 2007; say 'London LHR'; say $air_carrier; say $weekday_name[($departure_day + 1) % 7]; say $printer "flight coupon No. $current of $total";
Функция say в Perl 5.10 частично повторяет поведение одноименной функции из Perl 6, однако есть несоответствия, вызванные тем, что в Perl 5.10 приходится соблюдать соглашения, принятые в более младших версиях. Различие проявляется в двух случаях. Во-первых, невозможно использовать вызов say как метод некоторого объекта, как это допустимо в Perl 6: $day.say();. Кроме того, в Perl 5.10 функция, вызванная без аргументов, продолжает принимать переменную по умолчанию $_. Поэтому один и тот же код: say for 1..3;
даст разные результаты. В Perl 5.10 будут напечатаны три строки с числами от одного до трех, а в Perl 6 всего лишь три перевода строк (чтобы использовать переменную по умолчанию, нужно записать либо $_.say, либо .say).
use feature 'state'
Ключевое слово state, которое становится доступным после инструкции use featuer 'state', позволяет создавать переменные с лексической областью видимости, котоuse feature say; рые, однако, сохраняют свое значение даже после выuse feature state; хода программы из области видимости этой переменuse feature switch; ной. Как только выполнение программы вновь окажетКроме того, возможно объединять несколько инструк- ся в той же области, переменная будет снова доступна с прежним значением. ций в одну строку, например: Например, переменные, объявленные как state, могут use feature qw(say state switch); быть использованы для подсчета числа вызовов функции, для генерации последовательных номеров, для подКаждая из этих возможностей детально описана далее. счета числа созданных объектов или для накопления стаЧтобы подключить сразу все новые ключевые слова, тистики. можно воспользоваться одной из нескольких инструкций, Два примера. В первом из них функция next_serial() при каждом вызове возвращает последовательно увелиуказывающих версию языка: чивающиеся номера. use 5.10.0; use v5.10; use feature ":5.10";
sub next_serial { state $serial = 0; return ++$serial; }
И, наконец, при выполнении кода из командной строки можно использовать ключ -E вместо традиционного -e. say next_serial(); say next_serial(); Важно иметь в виду, что инструкция use feature имеет say next_serial(); лексическую область видимости и поэтому ее можно использовать, чтобы включить новые ключевые слова лишь Во втором примере вычисляется среднее значение слув пределах текущего блока кода. Кроме того, существует чайной последовательности чисел: для каждого нового знаинструкция с противоположным действием no feature, ко- чения вызывается функция register_value(), которая накапторая отменяет соответствующие расширения. ливает сумму всех полученных величин и их число.
use feature 'say' Инструкция use feature 'say' подключает одну-единственную функцию say, которая выполняет те же действия, что и print, но делает перевод строки после вывода списка
№12, декабрь 2007
sub register_value { state $sum = 0; state $num = 0; my $value = shift;
57
программирование $sum += $value; $num++; }
return $num ? $sum / $num : 0;
for (1..1000) { say register_value (rand 10); }
При большом числе повторов программа в итоге начинает печатать среднее значение, близкое к пяти, как и ожидалось. Обратите внимание, что инициализация статических переменных происходит в момент объявления и выполняется однократно.
use feature 'switch' С одной стороны, название switch говорит само за себя, с другой, не совпадает ни с одним новым ключевым словом. Инструкция use feature 'switch' вводит в обращение ключевые слова given, when и default, которые предназначены для реализации блоков выбора. Синтаксис почти совпадает с принятым в Perl 6, за тем исключением, что в Perl 5.10 по-прежнему необходимы круглые скобки вокруг условия. Работа блока выбора given/when напоминает традиционный блок switch в других языках программирования, однако имеет больше возможностей при анализе аргумента. Блок выбора открывается ключевым словом given, отдельные ветви словом when, а действие по умолчанию – default. Например: given ($day) { when (6) {say 'Saturday'} when (7) {say 'Sunday'} default {say 'Weekday'} }
В отличие от С и C++, после найденного совпадения выполняется только один блок кода, и «проваливания» в следующие блоки when не происходит. Первый успешный when выполняет соответствующий блок кода и прекращает выполнение блока given, не допуская, таким образом, остальные попытки проверить условия в блоках when, записанных ниже. Если поведение требуется изменить, следует указать это инструкцией continue в конце соответствующего блока. given ($day) { when ($today) {say 'Today'; continue} when (6) {say 'Saturday'} when (7) {say 'Sunday'} default {say 'Weekday'} }
for ('a'..'z') { when (/[aeiou]/) {say "$_ is vowel"} }
Обратите внимание на два момента (помимо того, что when используется внутри for). Во-первых, в блоке кода использована переменная $_. Во-вторых, в условии when записано регулярное выражение, которое сопоставляется с переменной $_. Показанный цикл печатает сообщение для каждой гласной буквы. В некоторых случаях необходимо явно указывать переменную по умолчанию, например: when ($_ > 0) или when (test_me ($_)). В последнем примере возможно также передать ссылку на функцию: when (\&test_me). Действия, выполняемые в каждой ветви when, зависят от типов переменных, участвующих в сравнении. Подробнее об этом рассказано в следующем разделе. В частности, условие when (5) внутри блока given ($day) эквивалентно проверке if ($day == 5), а when (2 + $period) – if ($day == 2 + $period). Но если в условии when записан вызов функции или передана ссылка на нее, то сравнения исходного значения с результатом функции не происходит: указанная в заголовке блока given переменная передается этой функции как аргумент, а решение об успешности текущей ветви when принимается на основании значения, возвращаемого функцией. Это значение интерпретируется как булево, то есть если функция вернула ненулевое значение, блок when считается успешным. В следующих двух блоках given происходит вызов функции func(), и поскольку она возвращает ненулевое значение 2 или 1, первая же проверка when оказывается успешной: sub func { my $arg = shift; return $arg; } given (2) { when (\&func) {say "func"} when (2) {say "2"} } given (2) { when (func(1)) {say "func"} when (2) {say "2"} }
Чтобы сравнить переменную с возвращаемым функцией значением, необходимо записать это явно: given (2) { when ($_ == func(0)) {say "func"} when (2) {say "2"} }
Обратите также внимание, что значение, возвращаеАргументом в ветвях when может быть не только конс- мое функцией, преобразуется в булево по традиционным танта или переменная. Там, где в программе встречается правилам: например, строка «0» считается ложью, а «0.0», вызов when, происходит сопоставление переменной $_ с вы- «00» или «0E0» истиной. ражением, которое является аргументом when(). Явно указывать эту переменную обычно не требуется, поскольку она ~~ (smart matching) автоматически устанавливается при входе в блок given. Сопоставление, о котором было сказано в предыдущем Сам по себе блок given не обязателен, чтобы вызвать разделе, на самом деле является не традиционным сопосwhen. Например, допустимо воспользоваться циклом for, тавлением с регулярным выражением, а так называемым которые тоже устанавливает переменную по умолчанию smart matching, которое имеет собственный символ в грам$_: матике языка: ~~.
58
программирование Предыдущие примеры можно было бы переписать, явно используя переменную по умолчанию, и оператор ~~, которые неявно подразумеваются при обращении к when: given ($day) { when ($_ ~~ $today) {say 'Today'; continue} when ($_ ~~ 6) {say 'Saturday'} when ($_ ~~ a7) {say 'Sunday'} default {say 'Weekday'} }
sub subD {say shift; return 1} my $subA1_ref = \&subA; my $subA2_ref = \&subA; my $subD_ref = \&subD; my @test = ( ' $b ~~ undef ' $c ~~ "abc" ' $c ~~ /b/
my @a = (1..3); my @b = (1..3); my @c = (3..5); my @d = (123, 'abc'); my @e = (qr/\d/, qr/\w/); my @f = ('a'..'f'); my @g = (1..10); my %h = (a => 'alpha', b => 'beta'); my $h_ref = \%h; my %hh = (b => 1, a => 2); sub subA {say "subA"; return 2} sub subB {say "subB"; return 2} sub subC {say "subC"; return 3}
№12, декабрь 2007
', ',
', ' ', '
1 == 1 && 2 == 2 && 3 == 3 1 == 3 && 2 == 4 && 3 == 5
'
@d ~~ @e
', '
123 ~~ /\d/ && "abc" ~~ /\w/ ',
'
@f ~~ "d"
', '
grep {$_ eq "d"} @f
',
' '
@g ~~ 7 @g ~~ /^\d$/
', ' ', '
grep {$_ == 7} @g grep {$_ =~ /^\d\d$/} @g
', ',
'
3.14 ~~ "3.14"
', '
3.14 == "3.14"
',
' ' '
$subA1_ref ~~ $subA2_ref ', ' $subA1_ref == $subA2_ref subA() ~~ subB() ', ' subA() == subB() subA() ~~ subC() ', ' subA() == subC()
', ', ',
' ' '
$a ~~ $subA_ref ', ' -1 ~~ $subA_ref ', ' $c ~~ $subD_ref ', '
$subA_ref->() $subA_ref->() $subD_ref->($c)
', ', ',
' ' ' '
%h ~~ "a" $h_ref ~~ "a" %h ~~ /[A-F]/i %h ~~ %hh
exists $h{"a"} ', exists $h_ref->{"a"} ', grep {/[A-F]/i} keys %h ', [sort keys %h] ~~ [sort keys %hh] ',
if ($x ~~ 100) {say "constant"} if ($x ~~ /\d+/) {say "regexp"} if ($x ~~ $y) {say "variable"} if ($x ~~ [50..150]) {say "array ref"} if ($x ~~ @a) {say "array"} unless ($x ~~ undef) {say "undef"}
my $a = 1; my $b; my $c = 'abc';
', ', ',
@a ~~ @b @a ~~ @c
Оператор ~~ всегда коммутативен, то есть выражения $a ~~ $b и $b ~~ $a дают одинаковый результат. Кроме того, оператор ~~ допускает в качестве аргументов не только переменные, константы или регулярные выражения. Например:
use v5.10;
!defined $b $c eq "abc" $c =~ /b/
' '
for ('a'..'z') { when ($_ ~~ /[aeiou]/) {say "$_ is vowel"} }
Название smart matching обусловлено тем, что оператор ~~ самостоятельно выбирает, как именно сравнивать аргументы, основываясь на их типе. Следующая программа демонстрирует примеры эквивалентных проверок, либо не использующих оператор ~~ вовсе, либо сводящихся к использованию более простого варианта. Массив @test содержит попарные инструкции, которые при выполнении дают одинаковый результат (в большинстве случаев использование smart matching позволяет написать более короткий и прозрачный код). Тесты выполняются автоматически в цикле do {...} while @test, для каждого из них выводится сообщение ok или not ok в зависимости от того, успешно было сопоставление или нет. Эквивалентные пары дают одинаковый результат, однако следует иметь в виду, что фактическая реализация не обязательно совпадает с кодом во втором столбце. В частности, компилятор делает оптимизации, чтобы не вычислять величины, которые не повлияют на результат.
', ' ', ' ', '
);
', ' ', ' ', ' ', '
do {
my $smart_match = shift @test; my $equivalent = shift @test;
say eval $smart_match ? 'ok' : 'not ok', " $smart_match"; say eval $equivalent ? 'ok' : 'not ok', " $equivalent\n"; } while @test;
Результат выполнения этого скрипта содержит пары строк, начинающихся с ok или not ok, причем в пределах каждой пары результаты должны совпадать: ok ok
$b ~~ undef !defined $b
ok ok
$c ~~ "abc" $c eq "abc"
ok ok
$c ~~ /b/ $c =~ /b/
ok ok
@a ~~ @b 1 == 1 && 2 == 2 && 3 == 3
not ok not ok
@a ~~ @c 1 == 3 && 2 == 4 && 3 == 5
ok ok
@d ~~ @e 123 ~~ /\d/ && "abc" ~~ /\w/
ok ok
@f ~~ "d" grep {$_ eq "d"} @f
ok ok
@g ~~ 7 grep {$_ == 7} @g
ok ok
@g ~~ /^\d$/ grep {$_ =~ /^\d\d$/} @g
ok ok
3.14 ~~ "3.14" 3.14 == "3.14"
ok ok
$subA1_ref ~~ $subA2_ref $subA1_ref == $subA2_ref
59
программирование subA subB ok subA() ~~ subB() subA subB ok subA() == subB() subA subC not ok subA subC not ok
subA() ~~ subC() subA() == subC()
not ok not ok
$a ~~ $subA_ref $subA_ref->()
not ok not ok
-1 ~~ $subA_ref $subA_ref->()
abc ok abc ok
$c ~~ $subD_ref $subD_ref->($c)
ok ok
%h ~~ "a" exists $h{"a"}
ok ok
$h_ref ~~ "a" exists $h_ref->{"a"}
ok ok
%h ~~ /[A-F]/i grep {/[A-F]/i} keys %h
ok ok
%h ~~ %hh [sort keys %h] ~~ [sort keys %hh]
Полезно также самостоятельно поэкспериментировать с показанным скриптом, записывая новые условия проверок [3].
// и //= Оператор //, называемый defined-or, пришел из Perl 6. Этот бинарный оператор возвращает значение левого операнда, если он определен, и правого в противоположном случае. Важно отличать оператор // от ||. Запись «$a = $b // $c» эквивалентна «$a = defined $b ? $b : $c», в то время как «$a = $b || $c $a = $b ? $b : $c». Поэтому если предположить, что переменная $a содержит нулевое значение, то выражение «$a // $b» всегда вернет 0, а «$a || $b» – значение переменной $b. Для записи «$a = $a // $b» предусмотрен сокращенный вариант «$a //= $b».
my $_ В Perl 5.10 переменную по умолчанию $_ возможно объявить локально, присвоив ей новое значение: for (1..5) { my $_ = '*'; print; }
Этот код напечатает пять символов '*'. Чтобы обратиться к одноименной переменной, которая устанавливается при входе в цикл, следует указать имя пакета main, записав $main::$_ либо просто $::_. Глобальную переменную $::_ возможно изменить с помощью объявления our $_. Следующий код тоже печатает пять звездочек:
60
for (1..5) { our $_ = '*'; print $::_; }
_ в прототипах При создании функций теперь возможно использовать символ подчеркивания для обозначения скалярного аргумента, который по умолчанию принимает значение переменной $_. Например, вызовы функции name() в показанном ниже цикле приведут к вызовам с аргументом $_. sub name(_) { say shift; } for (1..3) { name(); }
Поскольку переменная, прототип которой объявлен с помощью символа «_», по определению не является обязательной, она должна стоять либо последней в списке, либо после точки с запятой, отделяющей обязательные формальные аргументы от необязательных.
Регулярные выражения В синтаксисе регулярных выражений, доступных в Perl 5.10, появилось много дополнений, которые могут существенно облегчить выполнение многих практических задач.
Именованные сохраняющие скобки Значения, попавшие в сохраняющие круглые скобки, попрежнему хранятся в переменных типа $1, $2 и т. д. Однако теперь есть возможность в самом регулярном выражении присвоить каждой паре скобок имя, используя конструкцию (?<имя>...), например: my $date = 'Tue 1 January 2008'; $date =~ / (?<wday> \w+ ) \s+ (?<day> \d+ ) \s+ (?<month> \w+ ) \s+ (?<year> \d{4}) /x;
Сохраненные значения доступны в массиве %+: say $+{wday}; say $+{year};
Именованные значения сохраняются фактически как ссылки на соответствующие переменные $1, $2 и т. д. В программе допустимо одновременно использовать оба типа сохраняющих скобок. Элементы массива %+ доступны и при использовании оператора s/// в выражении для замены: $date =~ s/(?<year>\d{4})/$+{year} + 1/e;
Обратные ссылки Обратные ссылки (традиционно использующие для записи обратный слеш и номер сохраняющей пары) получили но-
программирование вый синтаксис. Для именованных скобок обратная ссылка %-, в котором для каждого имени хранится ссылка на масимеет вид \k<имя>. Например, следующий код использует сив значений. обратные ссылки, чтобы отыскать в полученной строке опНапример, следующий фрагмент выбирает из списка ределения переменных и заменить повторное использова- високосных лет два года, приходящихся на границу тысяние переменной ее значением: челетия: my $code = 'my $value = 100; say $value;'; $code =~ s/ my \s* (?<variable> \$[a-z]+) \s* = \s* (?<value> [^;]+ ) \s* ; \s* (?<other_code>.*?) \k<variable> /$+{other_code}$+{value}/x;
Показанное регулярное выражение вначале отыскивает подстроку my $value = 100 и сохраняет подстроки $value и 100 соответственно в переменных $+{variable} и $+{value}, а затем ищет второе вхождение $value (этого требует метапоследовательность \k<variable>). После выполненной замены в переменной $code окажется строка say 100;. Именованные сохраняющие скобки помимо удобства использования позволяют избегать неоднозначности, когда число скобок превышает 10: теперь нет необходимости использовать выражения вида \11. Для обратных ссылок предусмотрен альтернативный метасимвол \g, после которого Perl ожидает номер сохраняющих скобок, причем для исключения неоднозначности номер рекомендуется заключать в фигурные скобки, например: my $re = qr/ (?<what> \w+) board .*? \g{1} /x; 'keyboard made of keys' =~ $re; say $+{what}; 'snowboarding assumes snow' =~ $re; say $+{what};
my $leap_years = '1992 1996 2004 2008'; $leap_years =~ / (?<year> 1 \d{3}) \s* (?<year> 2 \d{3}) /x;
Здесь дважды встречается имя <year>, и элемент хеша $+{year} хранит первое совпавшее значение, в то время как в $-{year} появился массив, содержащий значения 1996 и 2004: say $_ for @{$-{year}};
При использовании имени для сохраняющих скобок более чем один раз следует быть особенно осторожным, поскольку поведение программы в этом случае может отличаться от того, что, возможно, имел в виду программист. В частности, модификатор g не добавляет новые элементы в хеш %-: my $leap_years = '1992 1996 2004 2008'; $leap_years =~ m/(?<year>\d{4})/g; say $_ for @{$-{year}};
Регулярное выражение /(?<year>\d{4})/g сохранит только первое найденное значение: 1992. Более того, поскольку для успешного совпадения достаточно найти только первый год, дальнейший поиск компилятор выполнять не обязан. В том случае, если это же выражение используется для замены, Perl должен пройтись по всей строке и найти все четыре подходящих подстроки: $leap_years =~ s/(?<year>\d{4})/*/g;
В приведенном примере метапоследовательность \g{1} Строка теперь будет содержать значение «* * * *», а в пополностью аналогична \g, \1, \k<what> и \g{what}. лях $+{year} и @$-{year} сохранится только последнее знаКроме того, \g принимает и отрицательные аргументы. чение 2008. В таком случае вся конструкция должна совпасть с сохраняНесколько иное поведение будет при наличии квантиющими скобками, нумерация которых начинается в текущем фикатора +: месте и идет к началу строки. Например, \g{-1} соответству$leap_years =~ m/(?<year>\d{4}\s*)+/g; ют предыдущим скобкам. В следующем фрагменте используется последовательность \g{-2}. Результат сопоставления со строками из предыдущего примера (обратите внимание В этом случае и $+{year}, и @$-{year} содержат по однона дополнительные скобки вокруг слова board): му последнему значению 2008. my $re = qr/ (?<what> \w+) (board) .*? \g{-2} /x;
«Завладевающие» квантификаторы
Работа квантификаторов ?, *, + и {min, max} может быть изменена вторичным квантификатором + таким образом, что их поведение будет более чем «жадным»: дополнительный + запрещает выполнять откат, если выражение уже захваПовторяющиеся имена тило какие-либо символы. В том случае, когда в регулярном выражении встречается В частности, такое поведение удобно, чтобы сделать несколько одинаково поименованных сохраняющих ско- подсказку компилятору о том, что если совпадения не набок, доступ к совпавшим подстрокам возможен через хеш шлось с первой попытки, не имеет смысла выполнять от-
№12, декабрь 2007
61
программирование каты и искать другие варианты. Например, для выделения выражения, заключенного в кавычки: my $re = qr/ ( "
(?: |
/x;
)
"
)*+
[^"\\]++ \\.
Это выражение помещают в переменную $1 строку в кавычках, правильно обрабатывая экранированные кавычки \» внутри строки. Обратите внимание на два случая применения «завладевающих» квантификаторов.
(?|...) Шаблон (?|...), называемый branch reset, принуждает регулярное выражение заново начать нумерацию сохраняющих скобок в каждой ветви альтернативных подвыражений, записанных через символ “|”. Например, регулярное выражение для чтения дат, записанных в разных форматах: my $re = qr/ (\d{4}) (\d\d) (\d\d) | (\w+) \s+ (\d+) , \s+ (\d+) /x;
сохранит подстроки в переменных $1, $2 и $3 для строки '20080101', но для строки 'January 1, 2008' подстроки окажутся в переменных с другими номерами, а именно $4, $5 и $6. Скобки (?|...), поставленные вокруг всего выражения с двумя ветками, начнут нумерацию с единицы и во втором случае: my $re = qr/ (?| (\d{4}) (\d\d) (\d\d) | (\w+) \s+ (\d+) , \s+ (\d+) ) /x;
Нужно проявлять осторожность, когда шаблон (?|...) используется совместно с именованными сохраняющими скобками. По возможности не следует повторять имена в разных ветвях регулярного выражения. Как упоминалось ранее, именованные переменные, хранимые в хешах %+ и %-, фактически являются ссылками на одни из нумерованных скобок. Поэтому, если одно и то же имя используется в скобках, номер которых не совпадает в разных подвыражениях, результат окажется не тем, какой ожидался.
\K Новый метасимвол \K сообщает, что при замене нужно отбросить часть выражения, находящуюся слева от \K, и заменить только то, что совпало справа. Например, регулярное выражение $url =~ s/\bwww\. \w+\.\Ksu\b/ru/ заменяет доменную зону su зоной ru в адре-
62
сах, начинающихся с www. Без метасимвола \K пришлось бы использовать, например, сохраняющие скобки и переменную $1, чтобы сохранить часть адреса, которую не требуется заменять.
\h, \H, \v, \V и \R Метасимволы \h и \v совпадают, соответственно, с горизонтальными и вертикальными пропусками. Пара \H и \V совпадает с тем, что не является горизонтальным или вертикальным пропуском. Еще один новый полезный метасимвол \R совпадает с переводом строки, причем независимо от формата, принятого в операционной системе. Иными словами, теперь не придется писать громоздкие конструкции вида /\n\r?/, которые к тому же всегда приходится составлять, испытывая дискомфорт из-за опасения пропустить какой-нибудь формат. Метасимвол \R не совпадет с неверной последовательностью \n\r: my @strings = ( "a\nb", "a\rb", "a\r\nb", "a\n\rb" ); for (@strings) { when (/a\Rb/) {say 'ok' } default {say 'not ok'} }
Эта программа трижды напечатает «ok» для строк с допустимым форматом перевода строки и «not ok» для последней тестовой строки. (Обратите внимание на использование ключевых слов when и default внутри цикла for.)
(?N) В регулярных выражениях возможно рекурсивно использовать части выражения, заключенные в скобки, используя метапоследовательность (?N) и указав номер соответствующих скобок. Например: 'Mon-Fri' =~ / (?<from> Mon|Tue|Wed|Thu|Fri|Sat|Sun ) (?<to> (?1) ) /x;
Сокращенные названия дней недели перечислены только один раз, а для второго совпадения используется последовательность (?1), которая делает те же проверки. В переменных $+{from} и $+{to} окажутся соответственно строки Mon и Fri. Более нетривиальное применение возможностей рекурсии в регулярных выражениях – обработка строк со вложенными скобками, число которых заранее неизвестно. Пример такого регулярного выражения показан в следующей программе. use feature ":5.10"; my $re = qr /^ (
\(
программирование (?:
)
\)
)*
[^()] | (?1)
$/x;
my @tests = ( "()", "(", "(1+2)", "1+2)", "(1-(2+3))", "(1-(2+3)", "(1+2+3*(4-5)+6/(2+3-(4*5*(6-7)))-8)", ); for (@tests) { say /$re/ ? "ok" : "not ok", " $_"; }
Регулярное выражение $re требует, чтобы строка начиналась и заканчивалась круглыми скобками: /^(\((?:[^()]|(?1))*\))$/
внутри которых либо не должно быть скобок: /^(\((?:[^()]|(?1))*\))$/
либо должно содержаться то, что описывается выражением в первых сохраняющих скобках: /^(\((?:[^()]|(?1))*\))$/
которые, в свою очередь, охватывают все регулярное выражение: /^(\((?:[^()]|(?1))*\))$/
n функция readline() читает из *ARGV при вызове ее без аргументов;
n функцию readpipe() и операторы qx// и `` разрешено переопределять;
n появился новый тип блока специа льного кода UNITCHECK, который вызывается сразу после того, как скомпилирован соответствующий фрагмент кода; n добавлена прагма mro (Method resolution order), изменяющая порядок просмотра дерева классов при множественном наследовании; n в классе UNIVERSAL появился метод DOES(), который программист может переопределять, если ему не хватает проверки, выполняемой функцией isa() (например, когда классы не наследуются); n расширен набор директив для форматированного вывода; n функции pack() и unpack() распознают модификаторы > и <, указывающие порядок байт; unpack() будучи вызванной без аргументов, работает с переменной $_; n инструкцией no N допустимо указать максимальную версию Perl, с которой разрешено выполнять программу, например no 5 в начале программы приведет к ошибке: «Perls since v5.0.0 too modern--this is v5.10.0»; n функции chdir(), chmod() и chown() работатают не только с именами, но и с дескрипторами файлов (если позволяет операционная система); mkdir() берет аргумент по умолчанию $_; n в регулярных выражениях появились экспериментальные управляющие конструкции (*THEN), (*PRUNE), (*MARK), (*SKIP), (*COMMIT), (*FAIL) и (*ACCEPT), которые, не поглощая символов, управляют ходом выполнения выражения, например позволяют поставить метку, откатить выполнение к следующей ветви, пропустить ветвление, либо вручную сообщить об ошибке [5].
Таким образом, выражение рекурсивно содержит са- Несовместимости мо себя и может совпадать с любым числом вложенных Обновление языка не обошлось без исключения некоторых (и при этом парных) скобок. устаревших возможностей и исправления прежних ошибок, Результат работы подтверждает, что невозможное что может изменить работу старого кода или вообще не позв прежних версиях языка теперь возможно: волит откомпилировать старую программу. В числе устаревших конструкций, от которых решено отказаться: ok () n псевдохеши; not ok ( n переменные $* и $#; ok (1+2) not ok 1+2) n инструкция (?p{}) в регулярных выражениях; ok (1-(2+3)) n интерпретация массивов @- и @+ внутри регулярного not ok (1-(2+3) ok (1+2+3*(4-5)+6/(2+3-(4*5*(6-7)))-8) выражения; n компилятор perlcc и сопутствующие модули.
Другие изменения
В Perl 5.10 есть еще много менее значимых изменений. Подробности о нововведениях можно найти в документации, а именно в документе perl5100delta.pod [4]. Там же упомянуто и о несовместимостях с предыдущими версиями Perl (но это в основном касается нетривиальных случаев, использующих внутренности языка, поэтому большинство пользователей различий не заметят). Вот краткий список некоторых новшеств, не описанных в статье: n возможность «нанизывать» операторы проверки состояния файла, например: if -f -w $filename;
№12, декабрь 2007
Тем, кто собирается переносить хитро написанные скрипты на Perl новой версии, необходимо ознакомиться с разделом Incompatible Changes документа perl5100delta.pod [4]. Однако большинство программ скорее всего будут работать без изменений. 1. http://search.cpan.org/~rgarcia/perl-5.10.0. 2. http://www.parrotcode.org/source.html. 3. http://talks.shitov.ru/ppt/moscow.pm/2/smart-matching.pdf. 4. http://search.cpan.org/~rgarcia/perl-5.10.0/pod/perl5100delta.pod. 5. http://www.regex-engineer.org/slides/perl510_regex.html.
63
программирование
Работаем с OpenDocument из Perl
Валентин Синицын Открытые форматы документов приобретают все большую популярность – и вы тоже можете извлечь из них пользу, даже не запуская OpenOffice.org. Все, что вам потребуется, – это интерпретатор Perl и задача, которую необходимо решить.
С
ценариями, генерирующими динамический HTMLкод, уже давно никого не удивишь. Простота языка разметки и повсеместная доступность веб-браузеров сделали этот язык «номером один» для представления структурированной информации. Однако, при своих несомненных достоинствах, HTML ориентирован в первую очередь на просмотр в электронном виде. Что же делать, если необходимо создать динамический документ для печати? Ответом может быть OpenDocument 1.0, он же ISO/IEC 26300:2006 – открытый формат офисных документов, поддерживаемый, в первую очередь, открытым офисным пакетом OpenOffice.org, а при наличии соответствующего расширения – и Microsoft Office (XP и выше). Для программирования же удобно использовать Perl – универсальный язык-клей, усиленный модулем OpenOffice::OODoc ЖанаМари Гуарна (Jean-Marie Gouarne). Помимо OpenDocument, OpenOffice::OODoc поддерживает также и более старый формат OpenOffice.org 1.x.
Установка Как и все в мире Perl, OpenOffice::OODoc доступен со CPAN [1]. Там же находятся и его основные зависимости: Archive::Zip [2] и XML::Twig [3]. Установка модуля производится стандартным образом: perl Makefile.pl make make test make install
Пользователи ActivePerl, разумеется, могут воспользоваться вместо этого утилитой PPM: ppm install OpenOffice-OODoc
64
На этапе сборки вам будет предложено ввести некоторые параметры; особое внимание следует обратить на локальную кодировку. Данные настройки сохраняются в файле config.xml в том же каталоге, где находятся файлы модуля (обычно site/lib/OpenOffice/OODoc относительно стандартного пути библиотек Perl). Для PPM-пакета конфигурирование в процессе установки не предусмотрено, поэтому config.xml необходимо отредактировать вручную.
Архитектура Модуль OpenOffice::OODoc имеет трехуровневую структуру. На самой нижней ступени иерархии находится класс OpenOffice::OODoc::File, инкапсулирующий функционал Archive::Zip и предоставляющий доступ к XML-содержимому документа для других компонентов модуля (см. врезку). Над ним располагается OpenDocument::OODoc::XPath, наследующий XML::Twig и обеспечивающий работу с XML-деревом OpenDocument посредством XPath. На этом можно было бы и остановиться: спецификация формата открыта, так что все необходимые операции можно выполнять посредством XPath-запросов, однако OODoc идет дальше и предоставляет несколько высокоуровневых «оберток», облегчающих работу с распространенными типами содержимого OpenDocument: n OpenOffice::OODoc::Text – класс для взаимодействия с текстом (абзацы, заголовки, списки, таблицы, сноски, секции и т. д.); n OpenOffice::OODoc::Image – класс, обеспечивающий работу с изображениями; n OpenOffice::OODoc::Styles – как нетрудно догадаться по названию, этот класс управляет стилями документа (шрифты, цвета и многое другое); n OpenOffice::OODoc::Meta – метаданные документа: заголовок, автор, дата создания и т. п.
программирование Обратите внимание, что деление личие от именованных стилей (Бана классы происходит по типу содер- OpenDocument изнутри зовый, Основной текст, Заголовок 1 жимого, а не документа, то есть, на- Документы OpenDocument представляют собой обычный ZIP-архив, расширеи т. д.), автоматические стили не имепример, OODoc::Text используется ют постоянного имени. как для ODT, так и для ODS. На вер- ние которого подбирается в соответствии styles.xml – место для хранения имес типом документа (.odt – для текста, .ods – шине иерархии находится к ласс нованных стилей. OpenOffice::OODoc::Document, насле- для электронных таблиц и т. п.). Внутри дующий от OpenOffice::OODoc::Text, архива находится несколько XML-фай- meta.xml – метаданные документа (имя автора, дата создания, заголовок Image и Styles. Таким образом, эк- лов и каталогов, наиболее важные из кои т. п.) земпляром OODoc::Document может торых таковы: content.xml – непосредственно событь представлен практически людержимое документа: текст, таблицы, Формат OpenDocument легко читабой документ, будь то текст, электссылки на изображения. Последние мо- ется человеком. Если вы пользуетесь ронная таблица или презентация. Негут находиться в каталоге Pictures в том OpenOffice.org, не забудьте снять галочприятным исключением из этого пеже архиве или быть полностью внешни- ку «Оптимизация по размеру для формаречня являются диаграммы – с ними ми. В файле content.xml также опреде- та XML» в «Параметры → Загрузка/сохраOpenOffice::OODoc работать не умеет ляются так называемые автоматичес- нение → Общие», чтобы XML-содержи(хочется надеяться, что пока). кие стили – то есть те, которые созда- мое сохранялось в отформатированном Из всего перечисленного выше наются офисным пакетом, когда вы на- виде (а не в одну строку, как это происхоиболее развитым интерфейсом облажимаете кнопки «жирный», «курсив», дит с оригинальной сборкой OOo по умолдает OODoc::Text. Для большинства «список» в панели инструментов. В от- чанию). текстовых элементов поддерживаются следующие действия: вставить/ добавить в конец документа (insertXXX/appendXXX), най- стого текста. Соответствующий скрипт занимает всего воти по стилю/содержимому/чему-то еще (selectByXXX), по- семь строк: лучить список всех элементов заданного типа/конкретное 1: #!/usr/bin/perl вхождение по его номеру (getXXX), удалить (removeXXX), 2: use strict; а также некоторые другие. Интересно, что в объектной 3: use OpenOffice::OODoc; 4: my $file = shift; модели OpenOffice::OODoc методы часто приписывают5: die "Usage: $0 filename.odt" unless ($file); ся не к самому элементу, а к документу в целом. Так, на6: my $doc = ooDocument(file => $file, member => 'content'); 7: $doc->outputDelimitersOn(); пример, для получения текстового содержимого элемента 8: print scalar $doc->getTextContent(); используется конструкция $document->getText($element), Программа принимает имя файла в качестве единса не $element->getText, как можно было бы ожидать. Прослойки, реализуемые указанными выше классами, твенного аргумента командной строки и выводит на конвесьма упрощают выполнение типовых операций над до- соль его текстовое содержимое. В строке 6 создается объект класса OODoc::Document кументом, но при этом являются сравнительно «тонкими», так что знание основ формата все же не помешает. Спе- (использование функций ooXXX вместо соответствующих цификацию OpenDocument (в форматах ODT и PDF) мож- конструкторов new является предпочтительным способом). но загрузить с [4], а также [5], если вас интересует неофи- Мы указываем, что нас будет интересовать файл content.xml, в котором и хранится содержимое документа. При испольциальный русскоязычный перевод. Думаю, на сегодня теории достаточно. В составе POD- зовании функции ooStyle() для получения доступа к именодокументации OpenOffice::OODoc имеется страница Intro, ванным стилям здесь будет уместно указать 'style'. Строка 7 предписывает включить «ограничители» помогающая глубже разобраться с возможностями модуля. Мы же посмотрим, как применить его к решению стандарт- (delimiters) – о них мы поговорим чуть позже. Наконец, в строке 8 мы получаем текстовое содержиных задач. Приведенные примеры были сделаны нарочито простыми, но в то же время расширяемыми, так что при не- мое документа методом getTextContent() и выводим его обходимости их можно превратить в полноценные програм- на консоль. При этом getTextContent() преобразует родмы. Полный исходный код можно скачать на сайте журна- ной для OpenDocument UTF-8 в локальную кодировку, установленную вами в файле config.xml. Обратите внимание ла www.samag.ru, в соответствующем разделе. на scalar: в списочном контексте getTextContent() возвращает массив строк, составляющих документ; мы же хотим Первый шаг OpenOffice::OODoc позволяет как создавать новые доку- получить его содержимое в виде одной строки. В этом слументы «с нуля» (точнее, на основе заранее подготовлен- чае в качестве разделителя строк используется значение ных шаблонов, хранящихся в виде несжатых XML-фай- свойства $doc->{'line_separator'}, которое вы можете усталов в каталоге, путь к которому возвращается функцией новить по своему усмотрению. А вот так решается любимая задача всех редакций пеooTemplatePath()), так и преобразовывать уже существующие. Традиционно, вторая задача считается более слож- риодических изданий – подсчет числа символов в документе без учета пробелов. Конечно, если редакция достаточно ной, поэтому мы сфокусируемся именно на ней. Пожалуй, первое, что приходит в голову в этой связи – прогрессивна и уже использует OpenDocument вместо друэто чтение файла OpenDocument и вывод его в виде про- гих проприетарных форматов...
№12, декабрь 2007
65
программирование $doc->outputDelimitersOff(); my $content = $doc->getTextContent(); $content =~ s/\s+//mg; print length $content;
(здесь и далее приводятся только части скрипта, реализующие новое поведение). Простой модификацией регулярного выражения особенно рачительная редакция может удалить из текста знаки препинания, латинские буквы, цифры и т. д. – в общем, все, за что, по мнению издателя, можно не платить. Внимательный читатель может обратить внимание, что во втором примере мы почему-то использовали метод outputDelimitersOff(), чтобы отключить вывод «ограничителей». Подобная «чехарда», конечно, не способствует пониманию процесса, поэтому попробуем объясниться: ограничитель – это всего-навсего пара строковых констант, обрамляющая текстовое представление некоторого элемента. Например, в настройке по умолчанию элементы text:span (их назначение совпадает с таковым в HTML) выделяются «елочками» (<< и >>), а сноски – фигурными скобками и префиксом 'NOTE: '. Разумеется, ограничители можно изменять по своему усмотрению; этим мы и воспользуемся в следующем примере, выводящем текст OpenDocument в раскраске «а-ля Lynx»: use Term::ANSIColor qw(:constants); ... my $doc = ooDocument(file => $file, member => 'content'); $doc->{'delimiters'}{'text:h'} = { 'begin' => RED, ↵ 'end' => RESET }; $doc->{'delimiters'}{'text:a'} = { 'begin' => BLUE, ↵ 'end' => RESET }; $doc->{'delimiters'}{'text:list-item'} = ↵ { 'begin' => YELLOW . '* ' . RESET, 'end' => '' }; $doc->{'delimiters'}{'text:span'} = { 'begin' => BOLD, ↵ 'end' => RESET }; $doc->outputDelimitersOn(); print scalar $doc->getTextContent();
Как можно видеть, разделители – это просто хэш, на который указывает свойство delimiters объекта OODoc::Text. Его ключами являются имена элементов: text:h соответствует заголовкам (они у нас выводятся красным цветом), text:a – гиперссылкам (синий цвет), text:list-item – элементам списков (желтая звездочка в качестве маркера – стандарт OpenDocument различает нумерованные и ненумерованные списки не на уровне тегов, как HTML, а на уровне стилей, и мы вернемся к этому вопросу чуть позже), а text:span – стилевому выделению (жирный, курсив и т. п.). Соответствующие константы определены в модуле Term::ANSIColor. К сожалению, в версии 2.035 (и, по-видимому, более ранних) в классе OODoc::Text присутствует ошибка, которая препятствует корректному выводу списков в методе getTextContent(). Исправление для нее можно найти на сайте журнала www.samag.ru в разделе «Исходный код». Автор модуля на предложенный патч, к сожалению, пока не отреагировал. Легкость применения ограничителей одновременно является и плюсом, и минусом, поскольку серьезно сужает их область применения. Ограничитель можно связать только с именем элемента, поэтому, например, различить заголовки различных уровней (за это отвечает атрибут
66
text:outline-level) с их помощью невозможно. Для более серьезных целей необходимо использовать другой подход – и один из возможных вариантов мы рассмотрим в следующем разделе.
HTML-конвертер Преобразование OpenDocument в HTML едва ли можно назвать трудной задачей – соответствующий экспортный фильтр включен в стандартную поставку OpenOffice.org; существуют и внешние XSLT-таблицы, например, расширение для Mozilla Firefox [6]. И в то же время каждый, кто сталкивался с необходимостью опубликовать документ OpenDocument на своем веб-сайте, думаю, согласится: с данной задачей указанные инструменты справляются далеко не на «пятерку». Проблема в том, что они (из лучших, разумеется, побуждений) стремятся максимально сохранить внешний вид документа, в результате чего он обрастает встроенными стилями и CSS-таблицами, а вамто необходимо сохранить смысловую разметку и внедрить документ в уже имеющийся дизайн! Умело используя OpenOffice::OODoc, можно экспортировать в HTML только те аспекты документа, которые действительно нужны, и игнорировать остальное. Спецификация OpenDocument 1.0 насчитывает 700 страниц, но, к счастью, далеко не все из перечисленного в ней может встретиться вам в «рядовом» документе. Приведенный ниже пример поддерживает заголовки, абзацы, списки, стилевые выделения, гиперссылки и изображения; в случае необходимости можно легко добавить и другие элементы (первая кандидатура – очевидно, таблицы). my $doc = ooDocument(file => $i_file, member => 'content'); my $meta = ooMeta(file => $i_file); $doc->outputDelimitersOff(); open(O_FILE, '>' . $o_file) || die "Unable to open $o_file"; my $title = $meta->title(); my $author = $meta->creator(); my $charset = ooLocalEncoding(); print O_FILE <<"__HEADER__"; <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>$title</title> <meta name="Author" content="$author"> <meta http-equiv="Content-Type" ↵ content="text/html; charset=$charset"> </head> <body> __HEADER__ for my $elt ($doc->selectElementsByContent('.*')) { if ($elt->isHeading) { print O_FILE heading($elt), "\n"; } elsif ($elt->isParagraph) { print O_FILE '<p>', paragraph_content($elt), "</p>\n"; } elsif ($elt->isItemList) { print O_FILE list($elt, 1), "\n"; } } print O_FILE <<'__FOOTER__'; </body> </html> __FOOTER__ close(O_FILE);
программирование Мы генерируем заголовок, основываясь на мета-информации документа; функция ooLocalEncoding() возвращает системную кодировку, установленную вами в файле config.xml. Основная работа, очевидно, сосредоточена в цикле: for my $elt ($doc->selectElementsByContent('.*')) { ... }
Метод selectElementsByContent('.*') возвращает список всех элементов второго уровня ('.*' – это регулярное выражение-фильтр; замените его на 'apples', чтобы получить только те элементы, в которых упоминаются яблоки). Наш скрипт различает три типа таких элементов: заголовки (Heading), абзацы (Paragraphs) и списки (ItemList) – все остальное может встретиться только в содержимом абзаца (элементы третьего и более высоких уровней). Обработать заголовок проще всего: sub heading { my $elt = shift; my $level = $doc->getOutlineLevel($elt); return "<h$level>" . paragraph_content($elt) . ↵ "</h$level>\n"; }
Метод getOutlineLevel() возвращает номер уровня заголовка, мы генерируем соответствующий ему тег <hi>. Функция paragraph_content обрабатывает содержимое параграфа и является в некотором смысле центральной – все, что содержит хотя бы толику текста, проходит через нее. Неудивительно, что она в несколько раз длиннее heading(). sub paragraph_content { my $para = shift; my $result; for my $child ($para->getChildNodes) { if ($child->isSpan) { $result .= span($child); } elsif ($child->isHyperlink) { $result .= hyperlink($child); } elsif ($child->isImage) { $result .= image($child); } elsif ($child->getName eq '#PCDATA') { my $text = ooDecodeText($child->text); $text =~ s/&/&amp;/g; $text =~ s/</&lt;/g; $text =~ s/>/&gt;/g; $result .= $text; } else { warn "Element '" . $child->getName . "' was ignored\n"; } } return $result; }
В рамках принятой нами упрощенной модели под «содержимым абзаца» подразумеваются: простой текст (#PCDATA, обратите внимание на декодирование из внутренней UTF-8 в локальную кодировку системы и замену символов, запрещенных в HTML), стилевые выделения (span), гиперссылки (hyperlink) и изображения (image). Все они обрабатываются одноименными функциями, поэтому при необходимости включить в данный код, например, сноски, это не составит большого труда. Для необработанных элементов генерируется предупреждение. Функция span() отвечает за выделение текста полужирным шрифтом и курсивом:
№12, декабрь 2007
sub span { my $elt = shift; my %attrs = $doc->getStyleAttributes($doc->textStyle($elt)); if ($attrs{'properties'}->{'fo:font-weight'} eq 'bold') { return "<b>" . paragraph_content($elt) . "</b>"; } elsif ($attrs{'properties'}->{'fo:font-style'} ↵ eq 'italic') { return "<i>" . paragraph_content($elt) . "</i>"; } }
Конструкция $doc->getStyleAttributes($doc->textStyle($elt)) возвращает стиль, связанный с элементом $elt. В таком виде она будет работать только для автоматических стилей; для работы с именованными стилями необходимо создать объект OODoc::Style на базе файла styles.xml (ooStyle(member => 'styles')); Помимо задействованных здесь свойств fo:font-weight и fo:font-style, назначение которых, надеюсь, понятно из кода, могут оказаться полезными fo:color (цвет текста) и fo:background-color (цвет фона). Полный список свойств стилей можно найти, конечно, в спецификации [4]. Функции image() и list() действуют аналогичным образом, и мы не будем приводить их здесь ради экономии места. Остановимся лишь на способе различить нумерованный и ненумерованный список: 1: my $is_ordered = 0; 2: my $style = $doc->getStyleElement ↵ ($doc->textStyle($elt), namespace => 'text', ↵ type => 'list-style'); 3: my $st = $doc->getNodeByXPath ↵ ("//*[\@text:level=\"$level\"]", $style); 4: if ($st && $st->getName eq ↵ 'text:list-level-style-number') { 5: $is_ordered = 1; 6: } elsif ($st && $st->getName eq ↵ 'text:list-level-style-bullet') { 7: $is_ordered = 0; 8: } else { 9: warn 'Unknown type of the list: '. $st . "\n"; 10: }
Как было отмечено выше, OpenDocument различает эти два типа списков на уровне стилей; параметры нумерованных списков задаются при помощи элемента text:list-levelstyle-number, а ненумерованных – text:list-level-style-bullet. XPath-выражение в строке 3 просто возвращает элемент стиля, соответствующий списку заданного уровня $level (а уровень, в свою очередь, определяется глубиной вложенности списков друг в друга).
По шаблону Другой распространенной задачей является генерация документов по шаблону. В простейшем случае она сводится к подстановке имен, дат, адресов, сумм, реквизитов и другой уместной информации в письма, извещения, платежные поручения и т. п. Эта задача решается средствами «чистого» OpenOffice.org благодаря механизму полей, которые могут заполняться даже из внешней базы данных, но если вы чувствуете, что для решения данной проблемы лучше создать скрипт, то его простейший вариант может выглядеть так: my $doc = ooDocument(file => $i_file, member => 'content'); $doc->userFieldValue('someField', 'someValue'); $doc->save($o_file);
67
программирование Данный код открывает документ, имя которого содержится в $i_file, присваивает полю someField значение «someValue» и сохраняет его под именем $o_file. Документ-шаблон готовится обычным образом, вставка полей происходит через меню «Вставка → Поле → Дополнительно → Переменные → Поле пользователя» (в OpenOffice.org 2.3 Pro). Несколько более интересным представляется вариант, когда на лету модифицируется не только содержимое, но и сама структура документа. Здесь опять удобно провести аналогию с динамическими веб-страницами. В простейшем случае они представляют собой HTML-код, перемежающийся с инструкциями по его созданию, обрамленными специальными тегами. Тот же подход, но на языке OpenDocument, может звучать так: шаблон представляет собой обычный документ OpenDocument со вставками кода на Perl, выделенными специальным стилем. Отметим, что похожая идея реализуется библиотекой с красивым именем pod (Pyhton Open Document), но для языка Pyhton [7]. Чтобы создать шаблон, подобный предложенному выше, откройте OpenOffice.org Writer и создайте новый стиль текста, например, на базе обычного Базового стиля. Назовите его как-нибудь вроде EmbeddedPerl (пробелы допустимы, но нежелательны – в коде нашего скрипта их придется менять на _20_). В качестве «Следующего стиля» можно указать все тот же «Базовый» – тогда при нажатии <Enter> будет автоматически начинаться обычный абзац. Для стиля EmbeddedPerl удобно установить моноширинный шрифт и цвет фона, отличный от стандартного. Однако OOo Writer – не IDE, поэтому при вводе кода следует соблюдать некоторые меры предосторожности: всегда использовать «мягкий» перевод строки (<Shift + Enter>) и отключить автозамену кавычек («Сервис → Автозамена → Параметры»). Центральная часть скрипта, обрабатывающего предложенный шаблон, может выглядеть так: my $block_no = 1; my $image_no = 1; my $anchor; for my $para ($doc->selectParagraphsByStyle('EmbeddedPerl')) { my $code = $doc->getText($para); $anchor = $para; my $result = eval $code; die "Error in template block $block_no: $@" if ($@); if (ref $result && $result->isElementNode) { $doc->replaceElement($para, $result); } else { if ($result) { my $new_para = $doc->insertParagraph($para); $doc->setText($new_para, $result); } $doc->removeElement($para); } $block_no++;
} $doc->save($o_file);
Метод selectParagraphsByStyle() возвращает список абзацев, имеющих заданный стиль (поэтому важно использовать «мягкий» перевод строки: нажав Enter, вы создадите новый абзац, и код во вставке оборвется). Если вставка, выполняемая функцией eval(), вернула объект Element, он замещает собой абзац, в котором размещалась вставка; в противном случае абзац просто удаляется. Любое другое непустое возвращаемое значение трактуется как абзац тек-
68
ста, логическая ложь означает «удалить вставку и не предпринимать ничего сверх этого». Теоретически во вставке может находиться любой Perlкод; он также имеет доступ ко всем переменным нашего скрипта. Однако вводить длинные программы в шаблон неудобно, поэтому разумно создать функции-обертки вроде heading(), paragraph(), list() и image(), вставляющие в документ заголовок, абзац, список и изображение соответственно. Для пользователя шаблона вызов этой функции будет выглядеть как простая подстановка или разворачивание макроса. Функция image(), например, может выглядеть так: sub image { my ($file, $width, $height) = @_;
}
$anchor = $doc->insertParagraph($anchor, ↵ position => 'after'); $doc->insertImageElement("Image" . $image_no++, ↵ attachment => $anchor, import => $file, ↵ size => "${width}cm, ${height}cm"); return undef;
Изображения в OpenDocument являются содержимым абзаца: мы создаем его методом insertParagraph(). Переменная $anchor содержит последний элемент, сгенерированный текущей вставкой, и используется в качестве якоря, чтобы данные элементы появлялись в итоговом документе в том же порядке, что и в шаблоне. Изображения, вставленные в документ, не обязательно будут иметь родной размер, поэтому их высота и ширина задается явным образом (в сантиметрах; использовать здесь 'px', то есть пискели, невозможно). Функция возвращает undef, так что никаких других изменений структуры документа в основном цикле не производится. По такому же принципу можно запрограммировать и все остальные функции. Следует только иметь в виду одно обстоятельство: стиль, который вы явно или неявно присваиваете созданному элементу, уже должен быть определен в документе. Этого можно добиться, создав его вручную (средствами OpenOffice::OODoc::Style) или разместив в документе элемент с нужным стилем прямо в редакторе OOo Writer. Рассмотренные здесь примеры, конечно, не претендуют на полноту, но, хочется надеяться, дают представление об использовании OpenOffice::OODoc при решении повседневных задач. Все скрипты, по возможности, проектировались максимально расширяемыми, так что вы можете использовать их в собственных целях. Если у вас получится что-то общественно-полезное, не забудьте опубликовать код где-нибудь на SourceForge.net! 1. OpenOf fice::OODOC – ht tp://search.cpan.org /~jmgdoc / OpenOffice-OODoc-2.035. 2. Archive::Zip – http://search.cpan.org/~adamk/Archive-Zip-1.23. 3. XML::Twig – http://search.cpan.org/~mirod/XML-Twig-3.32. 4. Спецификация OpenDocument – http://www.oasis-open.org/ committees/office. 5. Русскоязычный перевод спецификации OpenDocument – http://www.i-rs.ru/odf/translation. 6. ODFReader – https://addons.mozilla.org/firefox/addon/1888. 7. Библиотека pod – http://appyframework.org/pod.html.
программирование
Основные процедуры для работы с деревьями
Александр Ямпольский Иерархические структуры доминируют в мире. Систем, построенных на основе бескомпромиссного иерархического подхода, немного, так как такой подход выглядит труднореализуемым. Однако его применение повысит вероятность того, что ваша система в конце концов не окажется в тупике.
С
татья содержит реализации основных («штатных») процедур для работы с деревьями, включая реализацию алгоритма эвристического поиска. Я попытался продемонстрировать преимущества алгоритма обхода «в ширину» при работе с большими деревьями. Отличительной особенностью алгоритма является то, что он не использует инструментов, создающих неопределенность с точки зрения требований к памяти, таких как рекурсия, очереди и т. п.
Основные процедуры для работы с деревьями В системах обработки информации иерархические объекты моделируются деревьями. Схема на рис. 1 демонстрирует связи между объектами, формирующими ветвь дерева. На языке C# эта схема может быть реализована с помощью следующей структуры: public struct ObjectN // объект (узел дерева) { public string J_NAME; // имя объекта public long J_TYPE; // тип объекта(носитель знаний) public long IDF, // указатель на «отца» IDB, // указатель на «брата» ID1C; // указатель на первого потомка }
70
Дерево моделируется массивом структур ObjectN: public static ObjectN[] obj = new ObjectN[];
В качестве идентификатора объекта выступает индекс массива. В реальных системах дерево может храниться в файле, записи которого имеют структуру ObjectN. В этом случае номер записи файла будет являться идентификатором объекта. Схема, показанная на рис. 1, позволяет легко строить и модифицировать деревья произвольного размера и конфигурации. Проблемы с добавлением узлов и вставкой ветвей отсутствуют (имеется в виду отсутствие проблем с перенастройкой системы связей между объектами). Например, для добавления нового узла необходимо знать индекс свободной ячейки массива и идентификатор объекта-«отца»: FreeCell = getfreecell(); obj[FreeCell].IDF = FatherIdentifier; obj[FreeCell].IDB = obj[FatherIdentifier].ID1C; obj[FatherIdentifier].ID1C=FreeCell;
Все запросы к иерархически организованным структурам реализуются в процессе обхода узлов дерева. Основной целью обхода является выделение из сложной струк-
программирование Файл отношений между абстрактными объектами туры отдельных фрагментов – целевых объектов. Идентификатор Идентификатор Тип отношения Значение отношения абстрактного объекта абстрактного объекта Существуют два основных метода (первый объект пары) (второй объект пары) обхода древовидных структур: «depth … … … … first» обход (обход в глубину, далее Письмо Альбом фотографий Иерархическая совместимость Не совместимы DF‑обход) и «breadth first» обход (об… … … … ход в ширину, далее BF-обход). Ма р ш ру т D F- о бход а п о к а з а н файл mpwt.doc. Полный адрес файла: docs\desc\sour\var1\ на рис. 2. Общее направление обхода – поперек дерева. В про- ver1\mpwt.doc. Было бы неплохо иметь возможность вместо полноцессе обхода для обработки (например, для формирования списка целевых объектов) хаотично выдаются узлы разно- го адреса вводить отдельные узловые точки. В этом слуго уровня. С первых шагов курсор уходит вглубь и, если чае задание на поиск объекта могло бы выглядеть так: дерево большое, нескоро вновь окажется на поверхнос- desc;var1;mpwt.doc. Папки desc и var1 являются промежути. Этот метод обхода по смыслу не соответствует иерар- точными целевыми объектами. Для того чтобы выполнить задание, процедура поиска должна быстро просканирохической структуре. Преимущества метода связаны с процедурой его реа- вать близлежащие уровни и выполнить необходимые отлизации и заключаются в том, что каждый узел при DF-об- сечения. Я думаю, что полезной стратегией поиска могла бы быть ходе посещается только один раз. Проблем с исключением из маршрута неперспективных участков (отсечение ветвей такая: как можно быстрее найти хотя бы один целевой объект, получить от него дополнительную информацию, испольна основе знаний об объектах) не существует. зовать эту информацию для уточнения района дальнейшего Маршрут BF-обхода показан на рис. 3. Общее направление обхода – сверху вниз. В процессе поиска. BF-обход хорошо подходит для этой стратегии. Работа с иерархическими структурами изначально ориобхода для обработки последовательно выдаются узлы одного уровня. Курсор предпочитает держаться ближе к по- ентирована на использование знаний. В структуре ObjectN верхности, т.е. к исходному узлу дерева. Можно надеять- элементом, предназначенным для выполнения функции нося, что в этой достаточно ограниченной зоне сосредоточе- сителя знаний, является тип объекта. Тип объекта можно рассматривать как ссылку на абсны либо сами целевые объекты, либо промежуточные целевые объекты (т.е. объекты, при посещении которых мо- трактный объект, обладающий типовыми свойствами. жет быть выполнена процедура отсечения, см. далее). Этот Это эквивалентно понятию «класс» в языках программиметод обхода, по-видимому, наиболее соответствует иерар- рования. Разработчику иерархического специализированного хической структуре. Недостатки метода связаны с процедурой его реа- приложения придется выстроить собственную систему рализации. Узлы в процессе BF-обхода посещаются бо- боты со знаниями. Такие понятия, как абстрактные объеклее одного раза. Отсечение ветвей выполнить труднее, ты, типовые структуры объектов, типовые свойства и отношения объектов и т. п., должны храниться в базе значем при DF‑обходе. Работа с большими деревьями невозможна без исполь- ний системы. Например, файл отношений между абстракзования процедуры отсечения ветвей. Решение об отсече- тными объектами может выглядеть так, как представлении принимается на основе знаний об отношениях между но в таблице. Знания из этой таблицы могут быть использованы встреченными и целевыми объектами. Например, мы знаем, что бесперспективно искать письма в фотоальбоме. для принятия решений об отсечении неперспективных ветВ случае дефицита знаний принятие решения об отсече- вей. В процессе обхода дерева объектов можно отбрасынии в данном узле невозможно. В этом случае встает воп- вать все объекты (ветви), не совместимые с разыскиваерос о том, куда двигаться дальше: уходить в глубину, т.е. со- мым объектом. Нерекурсивная процедура descent реализует на языке вершать DF-обход, или оставаться на поверхности, т.е. совершать BF-обход. На мой взгляд, второй вариант более C# алгоритм BF-обхода дерева объектов. Вместе со встробезопасен по причине, которая уже упоминалась при об- енной возможностью отсечения ветвей она также реализует алгоритм эвристического поиска: суждении особенностей BF-обхода. Преимущества BF-обхода могут быть использованы public static int descent(long SourceObj,int TravDepth) в процедурах поиска объектов. Например, нужно найти // SourceObj - указатель исходного узла обхода // TravDepth - лимит глубины обхода { long[] Router = new long[TravDepth]; // маршрутизатор int Lev, // счетчик уровней дерева cur; // вспомогательный указатель уровня bool EOTree, // признак завершения дерева EOLev; // признак завершения уровня long ObjPnt, // вспомогательный указатель объекта FirstCh; // указатель на первого потомка исходного узла
Рисунок 1. Схема ветви дерева
№12, декабрь 2007
FirstCh=obj[SourceObj].ID1C; EOTree=false; Lev=0;
71
программирование
Рисунок 2. Схема DF-обхода
Рисунок 3. Схема BF-обхода while (!EOTree && Lev<TravDepth) {// цикл по уровням EOTree=true; ObjPnt=FirstCh; Lev=Lev+1; cur=1; EOLev=false; while (!EOLev) {// DF-обход фрагмента дерева глубиной Lev // спуск по левому краю ветви while (cur < Lev) { Router[cur]=ObjPnt; cur=cur+1; // Здесь может быть вставка – фрагмент кода, // реализующий отсечение ObjPnt=obj[ObjPnt].ID1C; if (ObjPnt<1) break; // узел не имеет потомков } // выпуск очередной порции узлов уровня Lev while (ObjPnt>0) { Console.WriteLine("object: {0}",obj[ObjPnt].J_NAME); // здесь может быть процедура обработки объекта EOTree=EOTree && (obj[ObjPnt].ID1C<1); ObjPnt=obj[ObjPnt].IDB; } // подняться по массиву Router до первого // ненулевого указателя на объект cur=cur-1; while (cur>0) { ObjPnt=obj[Router[cur]].IDB; if (ObjPnt>0) break; cur=cur-1; } if (cur == 0) EOLev=true; } // обход фрагмента дерева глубиной Lev } // цикл по уровням return(0); }
логия хранится в массиве Router. Как видно, BF-обход является надстройкой над DF-обходом. Эта избыточность алгоритма иногда может обернуться его преимуществом. Так как процедура постоянно откатывается назад, она имеет возможность в это время подкорректировать параметры отсечения ветвей и соответственно границы района поиска объектов. Отсечения неперспективных объектов возможны с помощью следующей процедуры: // фрагмент кода, реализующий отсечение // compatible – функция, определяющая совместимость объектов // target_j_type - тип целевого объекта if (!compatible(obj[ObjPnt].J_TYPE, target_j_type)) { ObjPnt=0; break; // как если бы узел не имел потомков }
Процедура наследования свойств реализуется с помощью посещения предков объекта и получения от них недостающей информации. while (ObjPnt != RootPnt) { // if (информация получена) break; ObjPnt=obj[ObjPnt].IDF; }
Эту процедуру можно использовать в процессе обработки выделенных объектов, т.е. после того, как процедура обхода выполнила свою задачу, сформировав список целевых объектов.
Заключение
Выпуск узлов уровня Lev осуществляется в результате В случае больших деревьев маловероятно то, что полная DF-обхода верхней части (от уровня 1 до уровня Lev) дере- информация об отношениях между объектами доступна. ва, но только узлы уровня Lev выпускаются. BF-обход с использованием (там, где это возможно) отсеВ процессе BF-обхода дерева с количеством уровней L чений – наиболее подходящая процедура для работы с такаждый узел, лежащий на уровне Lev, посещается L-Lev+1 кими деревьями. раз. В момент посещения каждого узла его полная генеаУдачи!
72
bugtraq Обход ограничений безопасности в BEA WebLogic Mobility Server
Выполнение произвольного кода в HP OpenView Network Node Manager
Программа: BEA WebLogic Mobility Server 3.3, 3.5 и 3.6 Программа: HP OpenView Network Node Manager (NNM) 6.41, 7.01 и 7.51. (включая Service Pack 1). Опасность: Средняя. Опасность: Низкая. Описание: Уязвимость существует из-за неизвестной Описание: Уязвимость существует из-за ошибки проверошибки в компоненте Image Converter. Удаленный пользо- ки границ данных в ovlogin.exe, OpenView5.exe, snmpviewer. ватель может получить неавторизованный доступ к запре- exe и webappmon.exe CGI-приложениях. Удаленный пользователь может передать слишком длинные аргументы опрещенным файлам приложений и ресурсам. URL производителя: www.bea.com. деленным CGI-переменным, вызвать переполнение стека Решение: Установите исправление с сайта производите- и выполнить произвольный код на целевой системе. ля. URL производителя: www.openview.hp.com/products/nnm. Решение: Установите исправление с сайта производителя.
Обход ограничений безопасности в Kerio WinRoute Firewall
Программа: Kerio WinRoute Firewall версии до 6.4.1. Опасность: Низкая. Описание: Уязвимость существует из-за неизвестной ошибки в прокси-сервере, который при некоторых обстоятельствах не требует аутентификацию для доступа к HTTPSстраницам. URL производителя: www.kerio.com. Решение: Установите последнюю версию 6.4.1 с сайта производителя.
Несколько уязвимостей в MySQL Программа: MySQL версии до 5.0.52 [MRU]. Опасность: Низкая. Описание: 1. Уязвимость существует из-за того, что команда ALTER VIEW сохраняет изначальное значение DEFINER, что позволяет другому пользователю получить привилегии на доступ к виду. 2. Уязвимость существует из-за ошибки в механизме FEDERATED при обработке ответов от других серверов. Злоумышленник может аварийно завершить работу приложения, если полученный ответ содержит меньше колонок, чем ожидалось. 3. Уязвимость существует из-за ошибки при переименовании таблицы. Удаленный пользователь может изменить некоторые данные. URL производителя: www.mysql.com. Решение: Установите последнюю версию 5.0.52 [MRU] с сайта производителя.
Обход ограничений безопасности в ядре Linux Программа: Linux Kernel версии до 2.6.24-rc5. Опасность: Низкая. Описание: Уязвимость существует из-за некорректной установки лимита для «mmap_min_addr». Злоумышленник может расположить страницы ниже «mmap_min_addr» путем расширения стека или с помощью вызова «do_brk()» в специально сформированном приложении. URL производителя: www.kernel.org Решение: Установите последнюю версию ядра 2.6.24-rc5 с сайта производителя.
№12, декабрь 2007
Переполнение буфера в Samba Программа: Samba 3.0.27a, возможно, более ранние версии. Опасность: Средняя. Описание: Уязвимость существует из-за ошибки проверки границ данных в функции send_mailslot(). Удаленный пользователь может с помощью специально сформированного SAMLOGON-пакета, содержащего слишком длинную строку GETDC, вызвать переполнение стека и выполнить произвольный код на целевой системе. URL производителя: www.samba.org. Решение: Установите последнюю версию 3.0.28 или исправление с сайта производителя.
Обход ограничений безопасности в Sun Solaris Программа: Sun Solaris 10. Опасность: Средняя. Описание: Уязвимость существует из-за неизвестной ошибки при установке ограничений для netgroups. Удаленный пользователь может получить root-привилегии на доступ к NFS-каталогу, сконфигурированному на доступ для netgroups. URL производителя: www.sun.com. Решение: Установите исправление с сайта производителя.
Отказ в обслуживании в Juniper Networks JUNOS Программа: Juniper Networks JUNOS версии 7.3 по 8.4. Опасность: Средняя. Описание: Уязвимость существует из-за ошибки при обработке BGP UPDATE-сообщений. Удаленный пользователь может с помощью специально сформированных BGP-сообщений вызвать нестабильную работу BGP-сессии. URL производителя: www.juniper.net. Решение: Установите последнюю версию 8.5R1 с сайта производителя.
Составил Александр Антипов
73
программирование
Пространства имен в PHP
Александр Майоров Пространства имен, появившиеся в PHP относительно недавно, предназначены для локализации имен идентификаторов и предотвращения их конфликтов. Сегодня подробно рассмотрим способы применения пространств имен и их особенности в языке PHP. 74
программирование Что такое namespace? Пространство имён (namespace) – это область определения переменных, констант и т. п., ограничивающая их область видимости. Оно предназначено для локализации имен идентификаторов и предотвращения конфликтов между ними. Элементы, объявленные в одном пространстве, отделены от элементов, принадлежащих другому пространству. Немного уйдем от PHP к С++ и посмотрим на примерах, что из себя представляют пространства имен, так как в этом языке они появились относительно давно. Среда программирования С++ наполнена большим количеством переменных, функций и классов. Раньше все их имена пребывали в одном глобальном пространстве и нередко конфликтовали между собой. Например, если в программе определена функция atoi(), она может замещать собой стандартную функцию atoi(), поскольку имена обеих функций находятся в одном глобальном пространстве имен. Чаще всего конфликты имен возникали, когда в одной программе использовались несколько сторонних библиотек одновременно, написанных разными программистами. Особенно это касается имен классов. Например, если в программе определен класс MergeInstance, а в библиотеке, которую использует эта программа, имя уже было задействовано, возникал конфликт. Было решено разделять идентификаторы по пространству имен, и ввели ключевое слово namespace. Введение namespace позволило решать эти проблемы. Поскольку пространство имен позволяет локализовать область видимости объектов, объявленных внутри него, одно и то же имя, упомянутое в разных контекстах, больше не вызывало конфликтов. Теперь стандартная библиотека определена внутри своего собственного пространства имен std, что намного уменьшает вероятность конфликтов. Программист может самостоятельно создавать свои собственные пространства имен и локализовать имена, которые могут вызывать конфликты. Это особенно важно при разработке классов и библиотек функций.
№12, декабрь 2007
Ключевое слово namespace поз- разделяют одно и то же пространство, воляет разделить глобальное про- что затрудняет коллективную разрастранство имен на декларативные ботку, так как разработчикам прихообласти. В сущности, пространство дится следить за именованием функимен – это область видимости. Общий ций, констант и переменных, чтовид объявления пространства имен вы- бы случайно не назвать их одинакоглядит так: во или не назвать именем уже имеющейся функции в языке. Отсюда namespace name и пошел стиль оформления длинных { имен, разделенных подчеркиванием. //Здесь ваш код… } Например, что-то вроде tpl_tplproc_ execute_template. Ведь как-то надо В с е , ч т о о б ъ я в л е н о в н у т р и различать функции по принадлежносnamespace, находится внутри облас- ти к той или иной библиотеке функти видимости этого пространства имен. ций. При разработке сложных приРассмотрим пример: ложений могут возникать конфликты идентификаторов, как уже описыnamespace MyNameSpace валось выше. { С приходом PHP версии 5 эта проint variable_1; int variable_2; блема решалась в какой-то степени благодаря расширенному ООП синclass MyClass { ... }; } таксису. Но это не устраняет основной проблемы. В результате было принято Здесь переменные variable_1 и решение добавить в PHP версии 6 подvariable_2, а также класс MyClass на- держку namespace. ходятся в области видимости, опредеВсе с нетерпением ждут выхоленной пространством MyNameSpace. да PHP 6, так как разработчики обеДоступ к ним можно осуществить че- щают порадовать массой нововведерез имя объявленного пространства: ний, но вот пространством имен они уже порадовали нас сейчас! НаконецMyNameSpace::variable1 = 10; то в PHP появились namespace. И уже MyNameSpace::MyClass myObject; сейчас у вас есть возможность проЛегко представить, во что пре- тестировать и попробовать в рабовратится программа, в которой часто те это нововведение. Для того чтобы встречаются ссылки на элементы про- вы смогли протестировать примеры странства имен. Текст такой програм- из статьи, вам достаточно скачать домы станет малопонятным и очень объ- ступную dev-версию PHP 5.3 с сайта емным, поскольку будет пестреть ква- http://snaps.php.net. лификаторами и операторами области разрешения видимости. Директива namespace Для того чтобы этого избежать, бы- Собственно, теперь рассмотрим, что ла введена директива using, имеющая из себя представляют namespace такой вид: в PHP. Объявление пространства имен осуществляется конструкциusing namespace name; ей namespace name. Она должна идusing name::spacemember ти всегда в самом начале файла, инаТеперь вы имеете представление че будет сгенерирована ошибка «Fatal о пространствах имен и о том, как они error...». реализованы в С++. <?php Далее мы разберем, как же реалиnamespace myspace; зовали разработчики PHP этот меха... ?> низм, рассмотрим отличия, достоинства и недостатки. Если в файле объявлен namespace, Что получили? то этот файл уже рассматривается До сегодняшнего дня PHP, как когда- как некоторый модуль, а не обычный то Cи, располагал все идентифика- include-файл. торы в одном глобальном пространсВ отличие от C++ началом протве имен. Все подключаемые файлы странства имен считается его объяв-
75
программирование ление, а окончанием – конец файла. То есть файл является неким контейнером для объявленного пространства и может рассматриваться как некий модуль, в котором все функции, классы, константы и переменные логически связаны друг с другом. В файле, в который осуществляется включение данного модуля, доступ ко всем функциям, классам и константам осуществляется через созданное пространство. <?php //ns.php namespace myspace; function test_foo ( $argv ) { printf("\n%s\n", $argv); } ?> <?php include 'ns.php'; $argv = 'test'; myspace:: test_foo( $ragv ); ?>
Вложенные namespace в отличие от С++ создавать нельзя, но можно создавать составные пространства имен: <?php namespace myspace::space1::subspace; ... ?>
Дост уп осуществляется точно так же, но через полное имя составного пространства: <?php //ns.php namespace myspace::space1::subspace; function foo_bar( $argv ) { printf("\n%s\n", $argv); } ?>
ния по поводу того, следует ли заменить слово import на слово using, к тому же оно уже зарезервировано в языке PHP. По смыслу слово import больше подходит, чем слово use, так как директива import предназначена в первую очередь для импорта пространства. И вот, скачав очередное обновление, оказалось, что ключевое слово import все-таки заменили словом use. Мне пришлось заново проводить тесты. Давайте рассмотрим, что дает нам директива use: <?php //ns.php namespace myspace; function foo_bar( $argv ) { printf("\n%s\n", $argv); } ?> <?php include 'ns.php'; use myspace as ns; $argv = 'test'; ns::foo_bar( $argv ); ?>
<?php //ns.php namespace MyNameSpace::MySpace:: ↵ Subspace;
$argv = 'test';
?>
myspace::space1::subspace:: ↵ test( $argv ); ?>
<?php include 'ns.php';
76
function foo() { ... } ?> <?php include 'ns.php'; MyNameSpace::MySpace::Subspace:: ↵ foo(); use MyNameSpace::MySpace; MySpace::Subspace:: foo(); use MyNameSpace::MySpace::Subspace; Subspace:: foo(); ?>
Это аналогично записи: <?php include 'ns.php'; MyNameSpace::MySpace::Subspace:: ↵ foo(); use MyNameSpace::MySpace as MySpace; MySpace::Subspace:: foo(); use MyNameSpace::MySpace::Subspace ↵ as Subspace; Subspace:: foo(); ?>
namespace MyNameSpace;
<?php include 'ns.php';
Так же, как и в С++, для удобства работы было добавлено ключевое слово import. Оно чем-то похоже на using из С++. Пока я писал статью и изучал новые возможности неймспейсов, разработчики вели бурные обсуж де-
namespace MyNameSpace::MySpace:: ↵ Subspace;
Мы уже успели посмотреть, что С помощью директивы use мы можно делать, используя директиимпортировали область видимости ву use (это далеко не все возможносиз пространства имен myspace в про- ти, но о них мы поговорим подробнее странство ns. Точнее, мы просто на- чуть позже). значили псевдоним (alias). Таким обНельзя делать импорт несоставноразом, мы сделали удобнее работу. го имени без определения псевдонима. Но лучше всего это можно прочувство- Если написать: вать, если вы импортируете составной <?php //ns.php namespace, например такой:
function foo_bar( $argv ) { printf("\n%s\n", $argv); }
Директива USE (IMPORT)
<?php //ns.php
use MyNameSpace::MySpace::Subspace ↵ as ns; ns::foo_bar('test');
Сами понимаете, что при программировании лишний раз писать квалификаторы области разрешения видимости будет не очень удобным. Также можно делать импорт составного имени без определения псевдонима. Например:
function foo() { ... } ?> <?php include 'ns.php'; use MyNameSpace; MySpace::Subspace:: foo(); ... ?>
то будет сгенерировано предупреждение: «Warning: The use with noncompound name has no effect in...» В отличие от С++, произвести импорт пространства имен в глобальное или текущее, используя оператор use, нельзя. Нельзя делать импорт в составной алиас:
программирование <?php include 'ns.php';
идентификатор нашим импортирован- ное имя неймспейса, включая исходным алиасом. ное имя пространства имен данноuse MyNameSpace::MySpace::Subspace ↵ Вроде бы можно было сказать, что го модуля. as test::ns; это тоже баг. Но нет! Это как раз-таки ... ?> фича. Представьте себе, как удобно пе- Зарезервированная рекрывать отдельные участки кода, ис- константа __NAMESPACE__ пользующие разные модули, но с оди- Д л я у к а з а н и я н а т е к у щ е е п р о Переопределение наковыми функциями. Налицо мы име- странство имен появилась константа и рокировка ем полиморфизм, но достигнутый не __NAMESPACE__. Есть еще одна интересная особенность средствами ООП через классы, а че<?php //ns.php в неймспейсах – это переопределение рез пространство имен. namespace MyNameSpace::MySpace:: ↵ уже существующего неймспейса и его Но это не все. Мы можем произSubspace; перекрытие. вести рокировку пространства имен. function foo_bar( $argv ) Представим, что у нас есть некото- То есть мы можем переопределить { printf("\n %s \n", ↵ рый модуль space1.php. space1 на space2, а space2 на space1. <?php namespace space1; function foo_bar() { printf("\n space1 \n"); } ?>
И модуль space2.php. <?php namespace space2; function foo_bar() { printf("\n space2 \n"); } ?>
Оба модуля подключаются к некоторому скрипту script.php. <?php include 'space1.php'; include 'space2.php'; echo space1:: foo_bar(); // Выведет space1 echo space2:: foo_bar(); // Выведет space2 ?>
Пока все работает как надо. А теперь мы берем и переопределяем space1 на space2. <?php include 'space1.php'; include 'space2.php'; use space1 as space2; echo space1:: foo_bar(); // Выведет space1 echo space2:: foo_bar(); // Выведет space1 ?>
В результате мы перекроем space2, и он станет ссылаться на space1. Просто мы «перетрем» существующий
№12, декабрь 2007
<?php include 'space1.php'; include 'space2.php'; echo space1:: foo_bar(); // Выведет space1 echo space2:: foo_bar(); // Выведет space2 printf(" \n ------------------ \n");
} ?>
Эта константа всегда указывает на текущее пространство имен. Для глобального неймспейса она не определена или имеет пустое значение.
use space1 as space2; echo space1:: foo_bar(); // Выведет space1 echo space2:: foo_bar(); // Выведет space1 printf(" \n ------------------ \n"); use space2 as space1; echo space1:: foo_bar(); // Выведет space2 echo space2:: foo_bar(); // Выведет space1 ?>
В итоге мы полностью поменяли местами названия пространства имен. Кстати, надо вас предупредить, что делать переопределение можно только один раз. Если вы попытаетесь еще раз вызвать «use space1 as space2», то будет сгенерирована ошибка «Fatal error: Cannot reuse import name ...». Но при этом вы можете переопределять пространство имен на другие имена сколь угодно много, главное, чтобы имена не повторялись.
<?php var_dump( __NAMESPACE__ ); ?>
Дамп выведет string(0), то есть пустое значение. Эту константу можно использовать для вызова функций, тем самым сделав настраиваемый квалификатор доступа. Также применение этой константы позволяет делать очень гибкие приложения с взаимозаменяемыми «сменными» модулями. Например, есть 2 библиотеки: <?php //ns1.php namespace space1; $current_space = __NAMESPACE__ ; function foo() { return "space1"; } function bar() { printf("\n %s \n", foo() ); }
<?php include 'mylib.php'; use mylib as myspace; use mylib as a; use mylib as b; use mylib as c; ... use mylib as z; ?>
При этом доступ можно осуществлять через любое переопределен-
__NAMESPACE__);
?>
и <?php //ns2.php namespace space2; $current_space = __NAMESPACE__ ; function foo() { return "space2"; }
77
программирование function bar() { printf("\n %s \n", foo() ); } ?>
Есть программа: <?php include $lib; call_user_func("$current_space:: ↵ bar"); ?>
Благодаря такой организации мы можем сменить библиотеку, изменив значение переменной $lib. Это найдет свое применение при разработке кросс-платформенных приложений. Например, можно сделать поддержку двух баз данных, MySQL и SQLite или чего-нибудь еще. Достаточно будет менять имя подключаемого модуля – и все. Хотя это не самый лучший пример, так как такой функционал можно реализовать при помощи классов. Но главное, понять суть, а применение уважаемый читатель найдет сам.
От теории к практике
Далее в нашей библиотеке мы объявляем функции. <?phpphp namespace mylib::strings::sort; function sort( $str ) { /** * Эта функция сортирует строку * в алфавитном порядке * ... */ } function rsort( $str ) { /** * Эта функция сортирует строку * в обратном алфавитном * порядке * ... */ } ?>
Также мы реализовали библиотеку для работы с массивами arrays.sort.php. Эта библиотека будет содержать точно такие же функции, как и для сортировки строк, но они для работы с массивами. <?phpphp namespace mylib::arrays::sort; function sort( $array ) { /** * Функция сортировки * ассоциативного массива * в алфавитном порядке * ... */ }
Пространство имен теперь позволяет создавать функции с именами встроенных функций в PHP. Для наглядности напишем простые тесты. Тесты будут решать некую абсfunction rsort( $array ) трактную задачу. Не будем сильно ус{ /** ложнять ее, так как моя задача пока* Функция сортировки зать принцип работы с пространством * ассоциативного массива * в обратном порядке имен, а не написать очередной Фрейм* ... ворк. Например, у нас есть библиоте*/ } ка для работы с массивами и библиотека для работы со строками. Опишем ?> каждую из них. Библиотека для работы со строкаВ PHP уже есть встроенные функми содержит функции sort() и rsort(). ции для работы с массивами, причем Вы знаете, что эти функции являют- с точно такими же именами, скажеся встроенными функциями для сор- те вы. Но я напоминаю, что мы решатировки массивов. Просто так перео- ем абстрактную задачу, поэтому сейпределить их невозможно. час потребовалось написать свои алБыло невозможно. Теперь благо- горитмы сортировок, а для удобства даря нововведению мы создаем на- мы используем имена встроенных шу библиотеку, strings.sort.php, объ- функций. являем в ней пространство имен Теперь подключаем в наш скрипт mylib::strings::sort. start.php, к примеру, наши библиотеки. Вы заметили, что имя файла похо- Вызов соответствующих функций проже на объявленное пространство имен. изводится через неймспейсы. Это сделано только для удобства, имя <?php неймспейса никак не зависит от имеinclude 'mylib/string.sort.php'; ни файла. include 'mylib/arrays.sort.php';
78
$str = 'string to sort'; $str = mylib::strings::sort:: ↵ sort( $str ); $arr = array( 'string'=>'value1', 'to'=>' value1', 'sort'=>' value1', ); $str = mylib::arrays::sort:: ↵ sort( $arr ); ?>
Как видите, мы смогли создать свои функции с зарезервированными именами. Более того, мы подключили файлы, в которых имена функций совпадают, но при этом не происходит никаких конфликтов. Вызов идет через полные пути неймспейсов, и вы можете сказать, что неудобно использовать такие длинные имена. Для этого была добавлена директива import, позволяющая делать импорт и переопределять пространства имен. Например, мы можем сделать импорт имен, тогда скрипт будет переписан следующим образом: <?php include 'mylib/string.sort.php'; include 'mylib/arrays.sort.php'; use mylib::strings::sort; $str = 'string to sort'; $str = sort::sort( $str ); $arr = array( 'string'=>'value1', 'to'=>' value2', 'sort'=>' value3', ); $str = mylib::arrays::sort ( $arr ); ?>
После этого мы получаем доступ к нашим функциям через импортированное пространство имен, что позволяет заметно сократить запись. Вы заметили, что был произведен импорт только библиотеки для работы со строками? Дело в том, что если произвести импорт неймспейса библиотеки для работы с массивами import mylib::arrays::sort, у нас произойдет конфликт имен и будет сгенерирована ошибка: «Fatal error: Cannot reuse import name...». Но тут к нам на помощь приходит директива import. Пространства имен можно не только импортировать, но так же переопределять и задавать алиасы (alias – псевдоним) для них. Если задан алиас для неймспейса, то доступ можно осуществлять одновремен-
программирование но как по полному пути неймспейса, так и по созданному псевдониму. <?php include 'mylib/string.sort.php'; include 'mylib/arrays.sort.php'; use mylib::strings::sort as str; $str = 'string to sort'; $str = str::sort( $str ); import mylib::arrays::sort as arr; $arr = array( 'string'=>'value1', 'to'=>' value2', 'sort'=>' value3', ); $str = arr::sort ( $arr ); ?>
Константы Пусть у нас есть некая общая библиотека для работы со строками. В ней есть какой-то класс, а так же константы, определяющие работу нашего приложения. Константы внутри неймспейса объявляются точно так же, как внутри класса. Если вы используете функцию define(), то такая константа будет работать точно так же, как если бы мы делали обычное включение файла без определенного пространства имен. То есть она будет находиться в глобальном пространстве, хотя и была объявлена внутри нашего namespace. Но внутри неймспейса можно определить константу, которая будет ограничена этим пространством и не будет пересекаться с такими же из других библиотек. Объявление происходит точно так же, как объявляются константы внутри классов. В нашей библиотеке strings.php хранятся некоторые классы и константы для настройки. Допустим, у нас есть разные варианты библиотек со строковыми функциями для различных кодировок: <?phpphp namespace mylib; const LOCALE = 'cp1251'; class TString { const MIXED = 0; const UPPERCASE = 1; const LOWERCASE = 2; }
public static $Encode = ''; public $case = 0;
?>
№12, декабрь 2007
Теперь мы выбираем подключаемую библиотеку в зависимости от настроек приложения. Делаем это следующим образом: <?php include 'mylib/strings.php'; switch ( mylib::LOCALE ) { case 'utf8': $path = 'utf8'; break; case 'koi8r': $path = 'koi8r'; break; default: $path = 'cp1251'; } include "mylib/$path/ ↵ strings.sort.php "; include 'mylib/arrays.sort.php'; ... ?>
При этом у нас в каждом модуле может быть своя константа LOCALE. Можно так же завести общую константу, видимую во всех файлах и не конфликтующую с внутренними константами. Внутри пространства можно определять классы. Обращение к классам, свойствам и методам класса осуществляется аналогично. <?php ... mylib::TString::$Encode = $encode; $string = new mylib::TString(); $string->case = mylib::TString:: ↵ LOWERCASE; ... ?>
Классы и интерфейсы С интерфейсами и классами дела обстоят аналогично. Можно объявить их внутри одного пространства имен, а использовать в пределах другого. Например, есть абстрактный класс и интерфейсы, объявленные внутри пространства mylib: <?php namespace mylib; interface Interface1 { public function Method_1(); } interface Interface2 { public function Method2(); }
abstract class test { public function __construct() { //... } public function __destruct() { //... } public function foo() { //.. } } ?>
Инициализация класса и наследование производятся следующим образом: <?php require_once 'abstract.php'; class test extends mylib::test implements mylib::Interface1, mylib::Interface2 { public function __construct() { //... } public function __destruct() { //... } public function Method_1() { //... } public function Method_2() { //... } public function foo() { //... } } ?>
Как видите, ничего сложного. Самое интересное, что вы можете в разных библиотеках описывать классы с одинаковыми названиями и так же их подключать и производить от них наследование. <?php require_once 'abstract1.php'; require_once 'abstract2.php'; class test implements mylib1::Interface, mylib2::Interface { ... } ?>
Единственное ограничение – это
79
программирование невозможность наследования от интерфейсов с одинаковыми методами. Но тут без комментариев, вы сами все прекрасно понимаете.
Глобальное пространство и вызов функций внутри модулей В самом файле, в который происходит подключение наших модулей, можно создавать функции и классы с именами, аналогичными именам в модулях. Правда, если не определено пространство имен, то имена пользовательских идентификаторов не должны пересекаться с зарезервированными именами встроенных функций. В самой библиотеке функций функции можно вызывать напрямую, без какихлибо обращений через пространство имен. Приведу пример:
Есть некоторый рабочий скрипт index.php. <?php include 'func.php'; include 'mylib.php'; ?>
Мы при разработке библиотеки использовали функцию foo(), доступную в файле func.php, но в самой библиотеке есть функция с аналогичным названием. Если вы вызовете функцию foo() в файле mylib.php, то будет вызвана функция mylib::foo(), а вам надо вызвать функцию foo() из файла func.php. Для этого существует глобальное пространство имен, по-другому его называют «пустой неймспейс». Вызов производится следующим образом:
<?php namespace myspace;
<?php namespace mylib;
function foo() { echo __NAMESPACE__ ; }
function foo() { /** * Тут происходит вызов функции * foo() из файла func.php */ echo __NAMESPACE__ . ::foo();
foo(); // Будет вызвана функция этого // неймспейса, описанная выше ?>
Если вы создали какую-то общую библиотеку и хотите, чтобы все функции из нее были доступны во всех объявленных вами пространствах имен, то для этого вы создаете файл без указания неймспейса. В библиотеку помещаете ваши функции. А вот обращение к ним осуществляется через пустой глобальный неймспейс. Лучше всего это пояснить на примере. Допустим, есть файл func.php. <?php function foo() { echo __FILE__ ; } ?>
Есть библиотека mylib.php. <?php namespace mylib; function foo() { echo __NAMESPACE__ ; // Здесь мы хотим вызвать функцию // foo() из файла func.php } ?>
80
} ?>
Работа с константами и классами происходит аналогичным образом. Также, если вы хотите использовать файл непосредственно в библиотеке, то можно включить его прямо в модуль: <?php namespace mylib; include 'func.php'; function foo() { /** * Тут происходит вызов функции * foo() из файла func.php */ echo __NAMESPACE__ . ::foo(); } ?>
Но не стоит думать, что включаемый файл станет частью модуля mylib.php. Он так и будет играть роль внешнего подключаемого файла, и вызовы нужно будет делать через глобальный неймспейс. Если вы попытаетесь вызвать функцию без указания глобального неймспейса из дру-
гого файла, при этом внутри модуля она не будет объявлена, то будет сгенерирована ошибка «Fatal error: Call to undefined function mylib::foo()...», так как интерпретатор будет искать функцию внутри данного модуля. Если вы включаете один модуль в другой, то это равносильно, как если бы вы подключали их по отдельности. <?php //myspace.php namespace myspace; include 'myspace.php'; function foo() { echo __NAMESPACE__ ; } ?> <?php //mylib.php namespace mylib; include 'myspace.php'; function foo() { echo __NAMESPACE__ ; } foo(); // Выведет mylib myspace:: foo() // Так делать нельзя mylib::myspace:: foo() // Так делать нельзя ?> <?php include 'mylib.php'; mylib::foo(); // Выведет mylib myspace::foo(); // Выведет myspace ?>
Мы подключили только mylib.php, но при этом нам доступны идентификаторы пространства myspace.
Переменные Что касается переменных, то они не «воспринимают никаких ограничений», и для них не существует никаких пространств имен. Если вы объявили, например, переменную $var = 1, то она будет видна во всех файлах и модулях в пределах видимости, которую допускает PHP. Пока неясно, будет ли добавлена возможность перекрывать область видимости переменных пространством имен или нет. В доступном мне снапшоте такой возможности не было. Хотя разработчики могут ограничиться тем, что переменные всегда можно упрятать в класс, сделав их статическими. По идее вызов таких переменных не будет отличаться от вызова их про-
программирование странства имен, разве что придется делать это через имя класса. <?php namespace myspace; class vars { public static $var1 = 1; public static $var2 = 'Test'; public static $var3 = ↵ array('a','b','c'); } ?>
Соответственно вызов происходит так: <?php require_once 'mylib.php'; var_dump( myspace::vars:: $var1, myspace::vars:: $var2, myspace::vars:: $var3 ); ?>
Получается, что сам класс играет роль пространства имен (хотя, по сути, так оно и есть). Глядя на код, не видно различий, где идет вызов через пространство имен, а где обращение к классу. Может быть, разработчики на это и рассчитывали. Просто сам факт того, что переменные, объявленные внутри модуля, видны вне модуля, наводит на мысль о недоработанности механизма. Например, в С++ переменные также можно «прятать» внутри пространства имен, как и все остальное. Примеры мы рассмотрели в начале статьи. Ведь объявив переменные внутри пространства имен, например для каких-то служебных целей, мы рассчитываем, что они не будут мешать переменным из других модулей. Хотя идеология построения модулей подразумевает, что модули – это некий набор функций, логически связанных между собой и используемых в проектируемом нами приложении. То есть в самом модуле ничего не должно вызываться и запускаться. Он служит всего лишь контейнером для функций и классов. Вроде бы все рассмотрели из того, что на сегодня доступно.
Итог Некоторые могут сказать, что на сегодня все, что было описано выше, можно повторить с помощью классов, ведь классы – это тоже пространства
№12, декабрь 2007
имен. Но это неверное утверждение. Если так рассуждать, то любой логический блок – это уже пространство. И так оно и есть. Когда мы объявляем классы, мы создаем пространство, внутри которого все идентификаторы логически связаны между собой и ограничены рамками класса. Но не стоит заблуждаться и путать эти понятия. Многие почему-то не осознают разницу между классами и пространством имен. Под классом подразумевается некая сущность, которая задает некоторое общее поведение для объектов. Таким образом, любой объект может принадлежать или не принадлежать определенному классу, то есть обладать или не обладать поведением, которое данный класс подразумевает. Класс определяет для объекта контракт, то есть правила, с помощью которых с объектом могут работать другие объекты (обычно это делается с помощью определения методов класса). Кроме того, классы могут находиться друг с другом в различных отношениях. В качестве контейнера для ограничения области видимости можно даже использовать функции. Следующий пример наглядно показывает это: <? function space_0( $name ) { function foo( $argv ) { var_dump( $argv ); } function bar( $a1, $a2, $a3 ) { var_dump($a1, $a2, ↵ $a3); } $argv = func_get_args(); unset($argv[0]); return call_user_func_array ↵ ( $name, $argv ); } function space_1( $name ) { function foo( $argv ) { var_dump( $argv ); } function bar( $a1, $a2, $a3 ) { var_dump($a1, $a2, ↵ $a3); } $argv = func_get_args(); unset($argv[0]); return call_user_func_array ↵ ( $name, $argv );
} var_dump( space_0('bar', 1,2,3), ↵ space_1('bar', 1,2,3) ); ?>
Как видите, мы смогли объявить два раза функции с одинаковыми названиями, но так как они спрятаны внутри функций, в свою очередь, каждая из них находится внутри пространства имен, созданного функциями space_0 и space_1 соответственно. Эти функции играют роль контейнеров, ограничивающих область видимости. При этом всем такой способ является всего лишь «костылем». С помощью классов можно повторять то же самое, но в более удобной форме. И все же, как уже было написано выше, классы не предназначены для использования их в качестве пространств имен, в том понимании, в котором подразумевает директива namespace, как и функции. Ведь библиотека может содержать несколько классов. И описывать классы внутри классов – то же самое, что описывать функции внутри функций. Поэтому введение директивы namespace – это не просто расширение языка некоторой надстройкой над уже чем-то существующим, а реальный инструмент, решающий свои конкретные задачи. Как вы уже сумели убедиться, у PHP-программистов в скором времени появится новый мощный инструмент. Сам факт появления пространств имен свидетельствует о «взрослении» языка. Для тех, кто работал хотя бы раз с С++, данное нововведение не покажется сложным для освоения. Хотя пока все это находится в стадии тестирования, но уже сейчас можно начинать планировать структуры ваших будущих фреймворков и приложений с учетом текущего синтаксиса пространств имен. Также вы заранее планируйте свои библиотеки таким образом, чтобы в них случайно не были созданы функции с зарезервированными словами namespace, import и __NAMESPACE__, иначе вам потом придется патчить ваш код, заменяя данные слова на альтернативные. Ждем релиза PHP 5.3! 1. http://ru2.php.net/manual/ru/language. namespaces.php.
81
ретроспектива
Окно в электронный мир: история развития графического пользовательского интерфейса Часть вторая Дмитрий Мороз Графический пользовательский интерфейс, вышедший из стен исследовательского центра Xerox PARC, в 80-е годы прошлого столетия стал движущей силой для быстрого распространения персональных компьютеров по всему миру. Отныне не инженеры-одиночки да исследовательские организации, а десятки крупных компаний развивали идеи первых GUI в собственных проектах.
Судьбоносная экскурсия
Стремительно увеличиваясь, ком- цию Джобс решил сразу же воплотить Впервые Джеф Раскин (Jef Raskin) поз- пания продолжала вербовать всё но- в новом компьютере. Проект «Lisa» накомился с основателями компании вых сотрудников. Бывшие инженеры стартовал. Apple Стивом Джобсом (Steve Jobs) PARC, приходившие в Apple на рабоИзначально проект должен был и Стивом Возняком (Steve Wozniak) ту, приносили с собой инновационные стать очередным компьютером с текв 1976 году, когда они в гараже кор- идеи, и Джобс, вспомнив слова Раски- стовым интерфейсом, предназначенпели над компьютером Apple I. Тогда на трёхлетней давности, наконец за- ным для офисных нужд малого и средже Раскин и рассказал друзьям об ин- интересовался разработками иссле- него бизнеса. Однако под влиянием тересных и перспективных разработ- довательского центра Xerox. В дека- PARC Джобсом было принято решение ках, творящихся в недрах PARC. Одна- бре 1979 года «яблочная» компания за- отказаться от командной строки и зако занятые своим новым изобретени- ключила с Xerox сделку, согласно ко- менить её GUI. Инженерам Apple, поем, Джобс и Возняк не обратили вни- торой за 100 тысяч акций Apple для её бывавшим вместе с ним в стенах исмания на слова Джефа. инженеров была организована экскур- следовательского центра Xerox, идея Следующая встреча Раскина с со- сия по центру PARC. По словам Возня- пришлась по душе. «Мы были в восздателями Apple состоялась в 1977 го- ка: «Стив Джобс без утайки заявил ру- торге от интерфейса Smalltalk», – всподу, когда на выставке West Coast ководству Xerox, что они обладают от- минает Брюс Дэниелс (Bruce Daniels) Computer Faire они представили ми- личными технологиями, а Apple знает, один из первых разработчиков Lisa. ру своё новое детище – компьютер как принести их в массы. «В тот момент он казался нам настояApple II. Спустя короткое время, в янВ завершение экскурсии по PARC щим прорывом. Вся наша команда бываре 1978 года, Джеф стал тридцать Ларри Тесслер (Larry Tessler) проде- ла единогласна во мнении: графичеспервым сотрудником Apple. монстрировал сотрудникам Apple кий интерфейс – как раз то, что нам неРаботая на протяжении 1970-74 го- всю мощь среды разработки Smalltalk. обходимо сделать». дов в качестве ассистента профессо- Кроме того, инженерам Джобса быСпустя шесть месяцев после эксра в Калифорнийском университете ло разрешено поработать за одним курсии PARC Apple переманила к сеСан-Диего, Раскин периодически пи- из компьютеров Alto, на котором бы- бе Ларри Тесслера, который отныне отсал статьи в различные журналы, ос- ла установлена Smalltalk. В общей вечал за разработку графического инвещавшие компьютерные технологии, сложности Джобс и компания прове- терфейса LisaOS. например, в Dr. Dobb’s Journal. Приоб- ли за Alto полтора часа, однако этоКак и компьютеры Alto и STAR, Lisa ретённый опыт позволил Джефу за- го времени Стиву было достаточно, использовала мышь для навигации нять в Apple пост менеджера публи- чтобы осознать важность графичес- по GUI. Однако вместо двух- и трёхкаций, в обязанности которого входи- кого пользовательского интерфейса кнопочных манипуляторов инженело написание инструкций к програм- для персонального компьютера и его ры Apple использовали устройство с мному обеспечению, поставлявшему- перспективы в будущем. Всю получен- одной кнопкой, что должно было обся с Apple II. ную в результате экскурсии информа- легчить пользователю жизнь при ос-
82
ретроспектива воении компьютера. Первоначально Тесслер сильно возмущался по поводу однокнопочной мыши, однако Раскин заявил, что с одной кнопкой можно проделывать все операции, что и с тремя, подтвердив свои слова собственноручно написанным документом, в котором были изложены его размышления на этот счёт. Например, впервые механизм «двойного нажатия» кнопки мыши был описан именно в нём. Впоследствии данный текст был использован для разработки графического интерфейса LisaOS. Проектирование внешнего вида GUI Lisa проводилось на компьютерах Apple II. Большинство первых «прототипов» представляли собой файловые браузеры с различным количеством колонок для отображения информации. Впоследствии, спустя девять месяцев после выхода Xerox STAR, они были заменены на интерфейс, основанный на иконках. В отличие от STAROS, позволявшей создавать иконки лишь для ограниченного количества типов файлов, LisaOS снимала это ограничение. Ещё одно новшество, появившееся в LisaOS, – возможность присваивания любому файлу программы, которая будет открывать данный документ. Новая операционная система стала первой ОС, в которой появилась «Корзина» – специальная папка, посредством которой пользователь удалял ненужные ему файлы. Среда Smalltalk, работавшая на Xerox Alto Эту операцию он мог осуществить, просто выделив один, либо несколько файлов, и, удерживая клавишу мыши, «перетащив» их на иконку Корзины. Данный метод, впервые применённый в LisaOS, получил ныне всем известное название «перетащи и брось» (Drag & Drop). Одним из главных нововведений инженеров Apple стала панель выпадающих меню, находившаяся в верхней части «Рабочего стола». Она хранила большинство команд операционной системы и ПО, причём изменяла меню и состав команд в них в зависимости от работы той или иной программы. Тогда как в STAROS количество иконок, а также их местоположение были строго заданными, в LisaOS эти ограничения были сняты. В довершение этого пользователь мог при помощи мыши перемещать иконки в любое место «РаОдин из ранних прототипов графического интерфейса LisaOS бочего стола». Для облегчения пользователю общения с компьюте- фический редактор LisaDraw и т. д. Буфер обмена LisaOS ром инженеры Apple внедрили «диалоговые окна». Ког- позволял пользователю переносить данные между всеми да LisaOS была необходима дополнительная информация приложениями, установленными в компьютере, причём это от пользователя для дальнейшего выполнения какого-либо могла быть не только текстовая информация, но и графидействия, операционная система выводила на экран окно ческие объекты: диаграммы, графики, рисунки и т. д. Эти и многие другие инновационные решения, воплос текстом вопроса и несколькими кнопками с возможными «ответами». Всё, что требовалось от человека, – нажатие щённые в Lisa, не смогли не сказаться на сроке превращетой или иной кнопки. Подобный шаг значительно облегчал ния «идеи в реальность»: на разработку компьютера Apple участь пользователя в работе с компьютером, поскольку, потратила, в общей сложности, более 200 человеко-лет, что единожды столкнувшись с диалоговым окном, в дальней- почти в три раза больше Xerox с её STAR. На момент своего выхода в мае 1983 года компьютер шем он мог быть спокоен – абсолютно все «вопросы» ОС обладал передовыми характеристиками и очень дружелюббудут формироваться в такой же форме. Кроме разработки дружелюбного интерфейса в обязан- ным графическим интерфейсом. «В отличие от ручного наности программистов Apple входило обеспечение как мож- бора команд пользователь Lisa мог выполнять множество но более стабильной работы всех программ, которые долж- функций простым указанием курсора мыши на соответствуны были стать частью пакета ПО Lisa. В него, кроме непос- ющую картинку» – так известный журнал Time отзывался редственно самой операционной системы, также входили: о новинке Apple. Однако опоздание с появлением на прилавтекстовый редактор LisaWrite, редактор электронных таб- ках (первоначально систему планировалось вывести на рылиц LisaCalc, редактор графиков и диаграмм LisaGraph, гра- нок ещё в 1981 году), а также цена в почти 10 тыс. долларов
№12, декабрь 2007
83
ретроспектива
LisaOS в 1983 году
стали непреодолимой преградой на пути коммерческого успеха Lisa.
Дружелюбное яблоко Ещё во время своей работы на посту менеджера публикаций, а затем и начальника этого отдела Джеф Раскин мечтал о разработке собственного компьютера. В свободное от работы время он писал небольшие заметки, в которых описывал характеристики системы, её возможности и преимущества над аналогами того времени. По мнению Раскина, новый компьютер, названный им Macintosh, должен был обладать большинством возможностей Lisa и при этом стоить не более 1000 долларов. В 1981 году, когда усилия инженеров Apple были сосредоточены на разработке Lisa, Джеф Раскин перешёл к более активному развитию собственного проекта. Из Калифорнийского университета он переманил в Apple своего бывшего студента, Била Аткинсона (Bill Atkinson). Позднее к Раскину присоединилась часть инженеров, работавших над Lisa. Стив Джобс, осознававший, что проект Lisa из-за постоянно отодвигающихся сроков выхода, а также увеличивающейся себестоимости, уже давно вышел за установленные рамки, решил взять в свои руки руководство проектом Macintosh. Постепенно его давление на Раскина, являвшегося идеологом команды, перешло все границы, и не выдержавший выпадов со стороны своего начальника Джеф в 1982 году покинул компанию, оставив все свои идеи и наработки Apple. По части графического интерфейса
84
MacOS 1.х
новая операционная система MacOS граммы устанавливались заранее ещё (ранее называвшаяся System) мало чем при производстве Macintosh, поэтоотличалась от своей предшественни- му сразу после включения компьютецы. Поскольку Macintosh был нацелен ра пользователь мог начать работать на неподготовленных пользователей, с ними. его ОС была максимально упрощена. Пристальное внимание к деталям Первой программой, с которой стал- проекта (от устранения малейших ошикивался человек после загрузки MacOS, бок в аппаратном и программном обесбыл Finder. Он представлял собой фай- печении до разработки корпуса, доловый менеджер, посредством которо- кументации и упаковки компьютера), го пользователь работал с документа- а также грамотно проведённая рекми, дисковыми накопителями, сетевы- ламная кампания, позволили Macintosh ми томами, а также запускал програм- стать настоящей сенсацией на рынмы. Можно сказать, что Finder был «гра- ке и гигантским толчком ко всеобщей фической командной строкой» MacOS. компьютеризации. Дабы не запутывать пользователя Apple была не единственной комсложной иерархией каталогов в фай- панией, вдохновлённой разработками ловой системе этой ОС, в первых вер- графических интерфейсов в PARC. Сесиях Finder отсутствовала возможность редина 80-х годов прошлого столетия создания новых папок внутри уже су- ознаменовалась появлением других ществующих. игроков, решивших попробовать свои Для более лёгкой настройки ком- силы в новой области. Правда, их пропьютера и операционной системы все дукция была ориентирована на другой параметры содержались в одной пане- сегмент рынка, набирающего стремили, причём их количество было макси- тельную популярность, – IBM PC-совмально сокращено. Громкость встро- местимые компьютеры. енного динамика, скорость передвижения курсора мыши, фоновое изоб- Графический интерфейс ражение, время и дата, да ещё пара покоряет ПК мелочей – вот и все настройки, доступ- В то время как пользователи компьюные пользователю. теров Apple не могли нарадоваться Специально для MacOS был разра- легкому и непринуждённому общеботан «Справочный тур по Macintosh», нию со своими электронными «товав увлекательной форме рассказы- рищами», обладателям ПК приходивавший новичку о принципах работы лось иметь дело с безликой командной с операционной системой и графичес- строкой операционной системы DOS. ким интерфейсом в частности. Первой компанией, решившей осВ качестве демонстрации возмож- частливить владельцев IBM PC, стала ностей нового компьютера для него бы- VisiCorp, разработчик редактора электли разработаны очень простые в освое- ронных таблиц VisiCalc. Её «графичеснии текстовый редактор MacWrite и гра- кая среда» VisiOn была выпущена в окфический редактор MacPaint. Эти про- тябре 1983 года.
ретроспектива По сравнению с MacOS, интерфейс Гораздо больше повезло последо- были постоянно открыты два горизонVisiOn был гораздо менее функцио- вавшей за VisiCorp компании Digital тально расположенных файловых окна. нален. Вместо отсутствовавших ико- Research, которая в 1985 году выпус- Пользователю также возбранялось пенок пользователю для работы с про- тила продукт под названием GEM ремещать их, изменять размер, а такграммами и документами необходи- (Graphical Environment Manager – Ме- же открывать другие окна. мо было нажимать на текстовые мет- неджер графической среды). GEM За всё время существования GEM ки. В нижней части экрана VisiOn рас- представлял собой графический ин- для IBM PC-совместимых компьютеполагалась строка с восемью коман- терфейс, предназначенный для ра- ров Digital Research продала нескольботы под управлением операционной ко сотен тысяч копий своего продукдами управления. Изменение размеров окна «на лету» системы DOS. та, что позволяет назвать его первым отсутствовало, пользователю приходиКорни GUI Digital Research уходят массовым графическим интерфейлось менять этот параметр при помощи опять-таки в PARC. Один из бывших сом для ПК. многократного нажатия команд «уве- разработчиков графического интерличить» и «уменьшить». Даже для того фейса STAROS, Ли Джей Лорензен (Lee Microsoft открывает чтобы закрыть окно, необходимо было Jay Lorenzen), был приглашён в Digital «Окна» нажать текстовую метку внизу экрана. Research для работы над новым GUI, Разработка Microsoft своего GUI быСами окна представляли собой безли- который он хотел назвать Crystal. Од- ла начата в сентябре 1981 года. Сама кие одноцветные квадраты (VisiOn ра- нако поскольку это имя уже было заре- того не ведая, Apple собственноручно ботала в монохромном графическом гистрировано, графический интерфейс помогла компании Билла Гейтса (Bill режиме CGA) без чётко выраженных пришлось переименовать в GEM. Gates) в разработке графического инграниц. Отсутствовавшие полосы проНесмотря на большой багаж зна- терфейса, который должен был рабокрутки заменяла правая кнопка мыши. ний, полученных в PARC, в своей рабо- тать под управлением её же операционВ отличие от Alto, STAR, Lisa те Лорензен в первую очередь ориен- ной системы MS-DOS. Ещё на раннем и Macintosh, поддерживавших различ- тировался на GUI MacOS. В результа- этапе создания Macintosh Стив Джобс ные типы и размеры шрифтов, в VisiOn те первая версия GEM была практичес- лично продемонстрировал прототип все символы были одинакового разме- ки неотличима от операционной систе- компьютера руководству Microsoft с цера. Даже ставший стандартным кур- мы Apple. Digital Research скопировала лью создания компанией программ сор в виде направленной диагонально не только внешний вид «Рабочего сто- для новой разработки Apple. вверх стрелочки был заменён на тон- ла» и иконки MacOS, но и панель выпаВпоследс твии на протяжении 1981‑1984 годов программисты Джобса кую вертикальную образца 60-х. дающих меню, а также «Корзину». За свой продукт VisiCorp просила Позднее столь полное заимство- получали доступ к конфиденциальной почти полторы тысячи долларов. Од- вание элементов интерфейса MacOS информации разработчиков компьютенако прежде чем заплатить эту сум- в собственной графической оболоч- ра (исходным текстам программ, инму, пользователь ещё должен был об- ке аукнулось Digital Research, когда терфейсам программирования прилозавестись компьютером PC-XT с жёс- в 1986 году Apple подала на компанию жений и т. д.). Apple шла на подобный тким диском, 512 Кб оперативной па- в суд, выдвинув обвинение в незакон- шаг для того, чтобы программное обесмяти и мышью, иначе VisiOn отказыва- ном копировании её интеллектуальной печение Microsoft работало под MacOS лась запускаться. Эти факторы, а так- собственности. Дабы прекратить про- как можно более стабильно, и было гоже отсутствие желания у разработчи- цесс, Digital Research пришлось значи- тово к продаже одновременно с выпусков программного обеспечения вы- тельно переработать внешний вид сво- ком компьютера. пускать ПО под новую операционную ей разработки. В результате новая верИзнача льно новый графичес систему, не позволили первому GUI сия GEM 2.0 лишилась интерактивного кий интерфейс назывался Interface для персональных компьютеров до- «Рабочего стола» с иконками, вместо Manager (Менеджер интерфейса), одстичь популярности. которых перед пользователем отныне нако на первой публичной презента-
VisiOn
№12, декабрь 2007
GEM 1.x
85
ретроспектива
Windows 1.x
Windows 2.x
Windows 3.x
ции проекта в ноябре 1983 года Microsoft сменила название на ныне привычное Windows. Первая версия Windows была очень похожа на MacOS, поэтому, чтобы избежать судебных разбирательств со стороны Apple, инженерам Microsoft пришлось лишить свой продукт некоторых преимуществ. Например, хотя изначально Windows 1.x поддерживала возможность окон перекрывать друг друга, эта опция была заблокирована. В результате работать с большим количеством одновременно работающих программ было очень сложно. И лишь диалоговые окна могли появляться поверх других. Кроме того, изменять размеры окон можно было
86
лишь в одну сторону при помощи их нижнего правого угла. Рабочий стол Windows не поддерживал иконки. С самого начала Windows была ориентирована на многозадачность (но не вытесняющую), хотя эта возможность была доступна лишь для родных программ, написанных под этот GUI. В отличие от MacOS, в Windows 1.x не было единого меню – каждая программа имела свою собственную панель меню, расположенную в верхней части окна. Выпуск Windows 1.x в 1985 году остался практически незамеченным. По своим возможностям новый графический интерфейс однозначно проигрывал продуктам от VisiCorp и Digital Research, да и рынок IBM PC-совместимых компьютеров, привыкший к командной строке DOS, ещё не был готов к обширному внедрению GUI в операционных системах. Исправить ситуацию должна была новая версия Windows, работа над которой завершилась в декабре 1987 года. В Windows 2.0 графический интерфейс значительно больше походил на MacOS. Отныне окна могли перекрывать друг друга, да и их размеры пользователь был волен изменять в любом направлении. Кроме того, в верхнем правом углу каждого окна появились две кнопки, нажатие которых «сворачивало» его, либо же «растягивало» на весь экран. Появились в новой версии и иконки, для расположения которых существовала специальная панель, находившаяся в нижней части экрана. Сходство Windows 2.0 и MacOS в марте 1988 года вылилось в судебный процесс, в котором «яблочная» компания обвиняла Microsoft в незаконном копировании элементов графического интерфейса её операционной системы. Однако из-за подписанного в ноябре 1985 года рокового соглашения между обеими фирмами, согласно которому Apple, сама того не ведая, собственноручно наделила компанию Гейтса правами на заимствование элементов GUI MacOS, Microsoft выиграла процесс, закончившийся в 1993 году. В мае 1990 года, пока шло судебное разбирательство, мир увидела Windows 3.0, наконец-то сделавшую Microsoft главным игроком на рынке GUI для персональных компьютеров. Хотя Windows 3.0 всё ещё оставалась графической надстройкой над MS‑DOS, значительно переработанный пользовательский интерфейс был призван сократить общение пользователя с командной строкой. Главным его нововведением стало появление Менеджера программ (Program Manager) и Файлового менеджера (File Manager). Менеджер программ содержал иконки для запуска приложений, которые пользователь был волен добавлять самостоятельно. В свою очередь Файловый менеджер, как следует из названия, представлял собой менеджер файлов с древовидной структурой каталогов, поддерживавший операции с файлами методом Drag & Drop. Windows 3.0 содержала полностью переработанную панель управления, как и Менеджер программ, использовавшую иконки для отображения своего содержимого. В третьей версии также появилась новая справочная система на основе гипертекстовых ссылок, внешне походившая на веббраузер. Наконец, для пущей красоты в Windows 3.0 была добавлена возможность установки «обоев», а кнопки сделаны выпуклыми.
ретроспектива Новая платформа, новая ОС, новый графический интерфейс К середине 80-х годов компания Atari вышла на финальную стадию завершения разработки нового компьютера ST. Дабы не остаться в стороне от индустрии быстро набирающих популярность графических интерфейсов, Atari начала сотрудничать с Digital Research, дабы её графическая оболочка GEM была перенесена на новую платформу. Проект под кодовым названием «Джейсон» (JASON) завершился появлением в сентябре 1985 года операционной системы Atari TOS. ОС для Atari ST состояла из двух основных компонентов – непосредственно самой операционной системы TOS, являвшейся разновидностью CP/M, а также графической оболочки GEM 1.x, практически ничем не отличавшейся от своего аналога DOS. Пожалуй, разница между ними заключалась лишь во внешнем виде иконок дисководов. Судебное разбирательство между Apple и Digital Research никак не повлияло на дальнейшую судьбу GEM в вер-
сии для Atari TOS. Следующие версии её графического интерфейса всё также содержали панель меню вверху экрана, иконки и корзину, а также способность окон перекрывать друг друга. Главный конкурент Atari, компания Commodore, не сидела, сложа руки, и также готовила новую линейку компьютеров с графическим интерфейсом. Выход первого представителя семейства, Amiga A1000, состоялся в июле 1985 года. Его операционная система AmigaOS обладала очень продвинутыми техническими характеристиками: вытесняющей многозадачностью, разделяемыми библиотеками, встроенным редактором сценариев (скриптов) на основе языка Rexx и т. д. Что же касается графической оболочки системы, получившей название Workbench, она обладала некоторыми нововведениями по сравнению с другими GUI. Например, пользователь мог работать с окном (копировать данные, прокручивать содержимое), расположенным под другим окном, без необходимости его перемещения наверх. Размер иконок не был фиксированным:
Atari TOS
AmigaOS 1.x
AmigaOS 2.x
RISC OS 2.x
№12, декабрь 2007
графический интерфейс AmigaOS позволял для каждого документа или программы задать собственную иконку произвольного размера. Несмотря на использование в интерфейсе Workbench всего четырёх цветов, пользователь был волен собственноручно настроить каждый из них, выбрав нужный из цветной палитры. Интересной особенностью GUI AmigaOS была возможность создания собственных курсоров. Операционная система и большинство программного обеспечения для неё поддерживали всплывающие меню, доступные при нажатии правой кнопки мыши. Наконец, нельзя не отметить одну из наиболее интересных возможностей компьютеров Amiga – способность одновременного отображения на экране окон с различным разрешением и глубиной цвета. В интерфейс AmigaOS 2.0 были внесены некоторые изменения. Например, окна обзавелись кнопками для мгновенной прокрутки документа от начала до конца и наоборот, а настройки операционной системы, в AmigaOS 1.x, как и в MacOS, содержавшиеся в од-
87
ретроспектива
NeXTSTEP
ной панели, в новой ОС были разделе- щую концепцию внешнего вида интерфейса самой ОС и программ для неё. ны на отдельные подкатегории. 1990 год ознаменовался выпуском Для этого Acorn распространяла среди Commodore третьей версии AmigaOS. производителей ПО специальный докуВ ней появилась возможность уста- мент под названием Style Guide, котоновки фоновых изображений (обоев), рый на своих 130 страницах описывал причём не только на Рабочий стол, но принципы работы графического интери в качестве фона для любого из окон фейса RISC OS. В результате знакомссистемы. Кроме того, пользователь мог тво с новой программой для пользовасамостоятельно изменять цвет различ- теля не составляло особого труда. Интересной особенностью графиных элементов GUI. Ну а для пущей красоты программисты Commodore ческого интерфейса RISC OS можснабдили AmigaOS 2.0 различными но назвать отсутствие общей панели псевдотрёхмерными эффектами, кото- всплывающих меню. Вместо неё как рые позже взяли на вооружение и дру- операционная система, так и приложения для неё использовали контексгие разработчики ОС. Третьим заметным игроком на рын- тно-зависимые меню, появлявшиеке домашних компьютеров того време- ся при нажатии средней кнопки трёхни была Acorn. Разработанные компа- кнопочной мыши. Следующая особеннией системы на базе только появив- ность GUI: встроенные в меню диалошегося процессора ARM потребовали говые окна. Например, чтобы изменить размер шрифта, пользователю не быновой ОС, которой и стала RISC OS. Первоначально операционная сис- ло необходимости открывать дополтема называлась Arthur. Её графичес- нительное окно, достаточно было выкий интерфейс был очень примитив- звать соответствующее подменю. Ещё ным, однако усердный труд програм- одно не менее интересное нововведемистов Acorn сделал своё дело, и уже ние – специальная панель под назваследующая версия, получившая на- нием Iconbar, размещённая в низу экзвание RISC OS, была полноценной рана. Она содержала ярлыки для бысграфической системой с некоторыми трого запуска программ, иконки свёрочень интересными особенностями, от- нутых окон, а также различных накопителей. личавшими её от себе подобных. RISC OS стала первой операционКак и большинство других компаний, Acorn хотела, чтобы её операци- ной системой, сглаживавшей экранонная система была как можно более ные шрифты (anti-aliasing) в режиме дружелюбной к пользователю. Поэто- реального времени. В результате люму фирма старалась разработать об- бой шрифт в ОС был читабельным да-
88
же на дисплеях с малым разрешением дисплея и 16-цветной палитрой. В довершение этого, специальный режим позволял сглаживать шрифты, находившиеся на цветном фоне. Наконец, ещё одна операционная система, на которой стоит заострить внимание – NeXTSTEP. Разработанная компанией NeXT, которую Стив Джобс основал после своего ухода из Apple в 1985 году, она появилась четыре года спустя. Пожа луй, главным свойством NeXTSTEP стало включение в оконный менеджер Workspace Manager интерпретатора Display PostScript, основанного на языке описания страниц PostScript. Благодаря этому пользователь всегда мог быть уверен, что информация, которую печатает принтер, будет в точности соответствовать выводимой на экран. Как и в RISC OS, в NeXTSTEP для хранения ярлыков запуска программ была использована специальная панель, названная Dock. Однако в отличие от операционной системы Acorn, пользователь NeXTSTEP мог создать несколько панелей Dock и помещать на неё любые ярлыки. Кроме того, Dock не была привязана к одному месту, и разрешала своё размещение в любом углу операционной системы. Нельзя не сказать пару слов и про навигацию в файловом менеджере NeXTSTEP. Содержимое пунктов нижней части его окна было представлено в виде колонок, количество которых, а также их размер пользователь изменял самостоятельно. Каждая колонка являла собой поддиректорию, открывавшуюся в правую сторону и сдвигавшую колонки более высокого уровня в левую. Благодаря такому подходу отпадала необходимость в пролистывании целых «деревьев», появлявшихся при желании зайти, например, в папку восьмого уровня. Верхняя же часть окна файлового менеджера представляла пользователю содержимое папок в виде иконок. Десятилетие спустя подобный механизм навигации появится в MacOS X, прародительницей которой и является NeXTSTEP. Наконец, данная операционная система стала первой ОС, графический интерфейс которой при перетаскивании окна не заменял его рамкой, а прорисовывал полностью.
ретроспектива UNIX и графический интерфейс Дабы вызвать у потенциальных покупателей интерес Операционная система UNIX и командная строка – вещи к IBM PC, а также облегчить жизнь уже существующим неразделимые. Однако и среди пользователей этой ОС на- пользователям, компания приняла решение взяться за разходились люди, желавшие работать с графическим интер- работку собственного графического интерфейса. К себе фейсом. Ими в 1984 году и была разработана оконная сис- в помощники она призвала Microsoft, с которой в августе тема X Window System, обеспечивающая стандартные ин- 1985 года был подписан договор о сотрудничестве. Новая струменты и протоколы для построения графических ин- операционная система с GUI под названием OS/2 должна терфейсов пользователя. Версия X Window под номером 11 была стать наследницей не только MS‑DOS, но и Windows. (называемая сокращённо Х11), являющаяся стандартом на Для IBM перспективы партнёрства с Microsoft были очесегодняшний день, появилась на свет в 1987 году. видны, поскольку эта компания являлась производителем В обязанности X Window входит обеспечение базовых главной ОС для её компьютеров, да к тому же уже успефункций графической среды: отрисовку и перемещение ла «нюхнуть пороху» при разработке графических интерокон на экране, взаимодействие с мышью и клавиатурой. фейсов. Однако «Голубой гигант» даже не предполагал, Однако данная оконная система не определяет деталей что собственные амбиции разработчика Windows привеинтерфейса пользователя. Эта задача возложена на окон- дут в скором времени к краху их партнёрского соглашеные менеджеры. В восьмидесятые годы прошлого века на- ния. Произойдёт это лишь в начале завершающего десяиболее распространёнными из них являлись OPEN LOOK тилетия ХХ века, ну а в 1985 году в недрах IBM ещё ничто и его конкурент – Motif. не «предвещало бури». OPEN LOOK был разработан компаниями Sun Microsystems и AT&T при поддержке Xerox PARC и появил- 1. http://www.wikipedia.org. ся в апреле 1988 года. Данный GUI примечателен исполь- 2. http://www.arstechnica.com. зованием овальных кнопок, треугольных глифов для отоб- 3. http://www.sitepoint.com. ражения всплывающих меню, а также «булавок», позволяв- 4. http://toastytech.com. ших пользователю «прикреплять» диалоговые окна, дабы 5. http://www.mprove.de. они оставались видимыми. Общая концепция OPEN LOOK 6. http://www.guidebookgallery.org. заключалась в предоставлении радующего глаз и простого в использовании GUI, благодаря которому пользователь мог сфокусировать своё внимание на программе, нежели на интерфейсе. Напоследок стоит отметить, что оригинальный дизайн этого оконного менеджера был чёрно-белым, а цвет, различные псевдотрёхмерные эффекты и тени были добавлены для удерживания конкурентоспособности на фоне Motif. Оконный менеджер Motif был разработан организацией Open Software Foundation, в результате чего его иногда называют OSF/Motif. Во внешнем виде этого оконного менеджера «правили бал» трёхмерные эффекты для различных элементов интерфейса – меню, кнопок, текстовых полей и т. д. Принцип работы с Motif был очень похож на Windows 3.x, что неудивительно, поскольку Microsoft сыграла важную роль в его разработке. Также нельзя не отметить, что Motif являлся не только оконным менеджером, но и предоставлял необходимый OPEN LOOK инструментарий для построения графических приложений, удовлетворяющих спецификациям X Window. В результате войны между двумя оконными менеджерами победу одержал Motif, ставший основой для Common Desktop Environment (CDE). Появившийся в 1993 году, этот интерфейс стал стандартом де-факто в качестве GUI различных версий UNIX вплоть до начала нового века. «Голубой гигант» вступает в игру Разработчик первого персонального компьютера, корпорация IBM, прекрасно понимала преимущества графического интерфейса. В то время как «обладавшие душой» дружелюбные компьютеры Macintosh стремительно завоёвывали всё новых и новых пользователей, персональные компьютеры с безликой командной строкой DOS оседали, в основном, на офисных столах различных компаний.
№12, декабрь 2007
Motif
89
книжная полка
Администрирование Windows Server 2003/2000 на терминальном сервере. 3‑е издание Тодд Мазерс
Автор книги не новичок как в работе с терминальными серверами, так и в написании книг о них. На русском языке уже издавалась книга Тодда Мазерса, посвященная использованию NT в качестве терминального сервера. Но Windows NT – это уже история, а терминальные серверы становятся все более и более актуальными. Книга пред-
назначена для технических специалистов, уже знакомых с серверными ОС и службой каталогов Microsoft и желающих на базе этой платформы внедрить терминальные службы. Помимо встроенных в Windows Server 2000/2003 средств в книге рассматривается и продукт компании Citrix. Автор попытался описать весь жизненный цикл проекта по внедрению терминальных служб: от планирования до эксплуатации. Первая часть книги содержит обзор MS Windows Terminal Services и Citrix MetaFrame Presentation Server 3.0. Во второй части рассмотрены вопросы управления проектом внедрения терминальных служб: сбор данных, планирование сетевой инфраструктуры, планирование аппаратных и программных средств. Третья часть посвящена практическим вопросам реа-
лизации терминальных служб. Из нее вы узнаете, как устанавливать и настраивать службы терминалов, а также MetaFrame Presentation Server. Рассматриваются вопросы настройки групповых политик, безопасность терминального сервера, управление принтерами, управление учетными записями и профилями пользователей. Отдельно освещена настройка RDP и ICA клиентов. Также автор уделил внимание установке и интеграции приложений на терминальном сервере.
n Издательство: «Вильямс» n Год издания: 2007 n Количество страниц: 1072 n ISBN: 978-5-8459-1266-4 n Цена: ≈ 744 руб. К н и г а п р е д о с т а в л е н а и з д ат е л ь с т в о м «Вильямс».
UNIX. Профессиональное программирование. 2-е издание Ричард Стивенс, Стивен Раго
Ричарда Стивенса, являющегося помимо данной книги автором еще нескольких фундаментальных монографий по UNIX и сетям (в том числе переводившихся на русский язык), наверно, не нужно представлять аудитории нашего журнала. Его книги при глубоком и квалифицированном изложении предмета в то же время от-
90
личаются простотой изложения материала. Это, впрочем, и неудивительно, учитывая богатый преподавательский опыт автора. Первое издание этой книги, вышедшее в 1992 году, стало настольной книгой для множества UNIX-программистов. Однако, когда Стивенс писал первое (и единственное вышедшее при его жизни издание), открытые реализации UNIX-систем еще не получили широкого распространения. Сейчас из наследников System V R4, которым уделялось в первом издании основное внимание, лишь Solaris сохранила более-менее заметную часть рынка. Коллега Стивенса – Стивен Раго проделал большую работу по обновлению классического труда, сохранив все достоинства первого. Был исключен устаревший материал и добавлено много нового. Большинство примеров, приводимых в книге, были проверены
на четырех платформах: FreeBSD 5.2, Linux 2.4.22 (дистрибутив Mandrake 9.1), Solaris 9 и Apple Mac OS X 10.3. Общий объем примеров составляет более десяти тысяч строк исходного кода ANSI C. Описано более 200 системных вызовов. Книга охватывает множество аспектов программирования: файловый ввод-вывод, управление файловой системой, управление процессами, сигналы, управление потоками, межпроцессное взаимодействие, терминальный ввод-вывод, печать и многое другое.
n Издательство: «Символ-Плюс» n Год издания: 2007 n Количество страниц: 1040 n ISBN: 978-5-93286-089-2 n Цена: ≈ 880 руб. Книга предоставлена интернет-магазином Books.Ru.
книжная полка
Microsoft Office SharePoint Server 2007 Билл Инглиш и группа экспертов Microsoft SharePoint
Вы любите Microsoft, коллективную работу и веб-сервисы? Тогда мы идем к вам. Оперативно переведенная книга (оригинал издательства Microsoft Press на английском также вышел в этом году) будет действительно крайне полезной всем, кто решит познакомиться с новым продуктом компании из Редмонда – Microsoft Office SharePoint
Server 2007. Хотя книга вышла в серии «Справочник администратора», издание содержит полезные сведения для самого широкого круга специалистов, работающих с SharePoint Server: веб-разработчиков, архитекторов, менеджеров проектов и просто опытных пользователей, сталкивающихся в повседневной деятельности со службами на основе SharePoint. К написанию этого справочника было привлечено почти два десятка специалистов, а издательство, в котором вышла книга, придает «официальный» статус информации, в ней изложенной. Поэтому данный том можно считать весьма полезным дополнением к другим техническим ресурсам компании Microsoft по SharePoint Server. В книге содержится информация по ряду ключевых тем, таких как установка и развертывание сервера, настройка фермы серверов и определение топологии, управление библиоте-
ками документов, репозиториями записей и рабочими процессами, управление поиском, вопросы безопасности, интеграция SharePoint Server 2007 с другими продуктами Microsoft, обновление с предыдущих версий, создание каталогов данных и управление подключениями к ним, настройка производительности системы, методы резервного копирования и восстановления данных. К книге прилагается CD. По традиции в нем записана книга в формате PDF с возможностью полнофункционального поиска (на английском языке), а также текст примеров кода, встречающегося в издании.
n Издательство: «Эком» n Год издания: 2007 n Количество страниц: 1104 n ISBN: 978-5-9790-0016-9 n Цена: ≈ 913 руб. Книга предоставлена интернет-магазином Books.Ru.
Безопасность беспроводных сетей Сергей Гордейчик, Владимир Дубровин
Достаточно неплохая книга отечественных авторов, которую можно рекомендовать как IT-специалистам, интересующимся безопасностью сетей в целом, так и безопасностью беспроводных сетей в частности. Помимо технологий, специфичных для беспроводных сетей, в издании кратко освещаются общие методы защиты се-
№12, декабрь 2007
тей. Также для не знакомых с построением и работой беспроводных сетей дается краткий обзор стандартов и технологий. В издании соблюден отличный баланс между теорией и практикой. Для практической демонстрации рассматриваемого материала авторы используют различное программное обеспечение для платформ Windows, Windows Mobile и Linux. Книга содержит шесть глав. Первая – введение в беспроводные технологии «с нуля». Во второй авторы рассказывают о базовых технологиях защиты беспроводных сетей. Третья глава посвящена защите беспроводных сетей на предприятии. Четвертая глава рассказывает о защите на сетевом уровне и содержит материал, мало привязанный именно к беспроводным сетям.
Пятая глава освещает вопросы безопасности клиентов мобильных сетей. В ней рассматриваются вопросы защиты как настольных операционных систем, так и КПК под управлением Windows Mobile. Книга содержит большое число иллюстраций, схем и снимков с экрана, облегчающих восприятие материала. Нужно отметить, что при относительно небольшом объеме книга содержит множество информации, которая будет полезна всем интересующимся безопасностью и сталкивающимся на практике с беспроводными сетями.
n Издательство: «Горячая линия-Телеком» n Год издания: 2008 n Количество страниц: 288 n ISBN: 978-5-9912-0014-1 n Цена: ≈ 293 руб. Книга предоставлена издательством «Горячая линия-Телеком».
Обзор книжных новинок подготовил Андрей Маркелов
91
содержание журнала за 2007 год АДМИНИСТРИРОВАНИЕ
№
Андрей Бирюков
03Spaces – расширение к OpenOffice.org для совместной работы Сергей Яремчук
№9
ALT Linux 4.0 Server: что день грядущий нам готовит? Дмитрий Шурупов
№8 №7 №4 №12 №1
№8
Иван Коробко
№9
Windows Messenger Иван Коробко
№10
в Solaris Алексей Коробкин
№3
компьютерной техники Алексей Бережной
№1
Как купить ПО от Microsoft? Часть 2. Разбираемся
Сергей Супрунов
№6
Frugalware 0.7 – Linux для бережливых? Валентин Синицын
№12
fsbackup: удобная и компактная утилита
в корпоративных программах лицензирования Дмитрий Бутянов №1 Как купить ПО от Microsoft? Часть 3. Приобретаем в рассрочку Дмитрий Бутянов
для резервного копирования Максим Тимофеев
№9
GNU Autotools: ошибки свои и чужие Рашид Ачилов
№12
KolibriOS: дайте ей шанс полетать на вашем компьютере
№3
Как организовать сервис телерадиовещания в интранет-сети Антон Кустов
№9
Как проводить сбор системных сообщении №3
Mandriva Corporate Server 4.0: Linux-сервер от мастеров десктопа Дмитрий Шурупов
для корпоративной почты Виктор Венявский
Как быстро и эффективно провести учет
FreeBSD: некоторые особенности сборки ядра
Сергей Кузьмин
№5
Используйте преимущества файловой системы zFS
FreeBSD в домене Windows: дополнительные возможности Рашид Ачилов
к локальной сети Ильяс Кулиев
Используем дополнительные возможности
Citadel – Open Source-решение для коллективной работы Сергей Яремчук
№11
Используем Windows Messenger в корпоративной среде
Cacti – простой и удобный инструмент для мониторинга и анализа сети Сергей Яремчук
№7
Используем Bugzilla в качестве ServiceDesk Рашид Ачилов
Используем Gmail в качестве внешнего фильтра
BusyBox: швейцарский нож для встраиваемых Linux-систем Дмитрий Шурупов
№11
Знакомимся с Windows Server 2008 Beta 3 Андрей Бирюков Используем Cisco PIX для обеспечения VPN-подключений №6
AXIGEN Mail Server – подходящий почтовый сервер для малого офиса Сергей Яремчук
Знакомимся с PowerShell – новой командной оболочкой
в гетерогенной сети Андрей Бирюков
№4
Какова в действии система резервирования AMANDA №11
MOSS 2007: быстрая настройка
Сергей Яремчук
№1
Каковы первые впечатления от работы с openSUSE 10.3
и самые интересные возможности Нелли Садретдинова
№7
Сергей Яремчук
MS Exchange 2003 + SpamAssassin Артем Деянов
№12
Каталоги бизнес-данных -интеграция легким движением руки
MySQL vs PostgreSQL Андрей Шетухин
№7
Нелли Садретдинова
NFS: из прошлого в будущее Сергей Супрунов
№4
Корпоративный MAIL RELAY-сервис. E-mail + UNIX + Exchange
OpenWRT – Linux для встраиваемых систем Дмитрий Столяров
№7
Яков Коваленко
№3
Reporting Services: составляем отчеты Павел Купцов
№1
Мониторинг сети с BixData Сергей Яремчук
№9
Sender Policy Framework как средство борьбы со спамом Сергей Яремчук
№4 №5
Unionfs в FreeBSD: разбираемся в текущей реализации
Василий Озеров
№2
Настраиваем и тестируем НРС МР1-кластер Иван Максимов
№10
Настраиваем удаленный доступ к сети с помощью MS ISA 2004 Андрей Бирюков
Сергей Супрунов
№1
Не допустите потери данных! Ленточная библиотека
UserGate – безопасный прокси-сервер Иван Максимов
№5
к вашим услугам Виталий Банковский
VirtualBox – виртуализация под GPL Валентин Синицын
№3
Нововведения в Solaris 10: на что обратить внимание админу?
Дмитрий Рощин
№4
Обзор новой версии дистрибутива Debian GNU/Linux 4.0
Vyatta – Linux-дистрибутив для роутеров Сергей Яремчук
№6
VPN на основе протокола РРТР: как повысить безопасность?
Алексей Коробкин
Администрирование учетных записей в домене Active Directory Александр Емельянов
Евгений Балдин
№1 №6 №2 №5
Обзор программ удаленного доступа: выбирайте подходящую №4
Борьба со спамом как фактор, снижающий надежность почтовой доставки Алексей Барабанов
№11
Настраиваем DNS и DHCP с хранением информации в LDAP
Split DNS: заставим BIND работать на два фронта! Яков Коваленко
№11
Рашид Ачилов
№5
Обзор серверного дистрибутива tinysofa Сергей Яремчук
№2
№8
Один из вариантов настройки спутникового Интернета
№8
Организуем кластер на платформе
Групповые политики в доменах AD Александр Емельянов
№7
FalconStor iSCSI Storage Server Геннадий Дмитриев
№8
Дао Dtrace Евгений Ильин
№12
Особенности инсталляции Solaris Владимир Василькин
№7
трафика во FreeBSD Сергей Супрунов
№2
Сергей Яремчук
Дела системные Михаил Брод
№9
Подключаем несколько локальных сетей с пересекающейся
Возможности корпоративного мобильного решения Nokia IMS Александр Иванов
в Mandriva Linux 2007 Александр Пчелинцев
Два канала – роскошь? Резервирование и балансировка
Особенности сервера коллективной работы Zimbra
Доступ к Active Directory с помощью прилинкованного
адресацией к одному компьютеру Андрей Кишкин
SQL-сервера Иван Коробко
№6
Подробное руководство по настройке тонких клиентов
еВох – новая серверная платформа Валентин Синицын
№10
на основе дистрибутива Thinstation и протокола NX. Часть 2
Есть проблема? Есть решение! Иван Коломацкий
№9
Евгений Бушков
92
№9
№10 №2
№1
содержание журнала за 2007 год Полезные советы. Утилита find Сергей Супрунов
№2
Построение отказоустойчивой системы с помощью Oracle Physical Standby Сергей Косько
№7
БЕЗОПАСНОСТЬ Auditor Collection: проверяем безопасность вашей сети Андрей Бирюков
Принципы построения доменов Active Directory
№
№3
№2
mOnOwall – дистрибутив для создания межсетевого экрана Сергей Яремчук
№5
Сергей Косько
№2
Open Source-решение: сетевой шлюз Untangle Сергей Яремчук
№10
Программное управление MS Exchange Иван Коробко
№12
Боремся с вирусами и спамом с помощью МРР Сергей Яремчук №2
Проектируем систему обмена данными Иван Коробко
№9
Защищаем локальные ресурсы сети Андрей Бирюков
Разворачиваем кластер Microsoft Exchange Андрей Бирюков
№6
Защищаем систему с помощью Outpost Security Suite
№5
Контролируем интернет-активность пользователей
Александр Емельянов Проводим мониторинг нагрузки операционной системы Solaris
Андрей Бирюков
Разворачиваем кластер на основе Windows Server 2003 Андрей Бирюков
с Kerio WinRoute Firewall Сергей Яремчук
Размещаем пользовательские бюджеты в LDAP. Часть 1 Алексей Барабанов
№1
Организуем хранение ключей OpenSSH
№2
Реализуем нестандартные правила управления доступом
в центральном сервере OpenLDAP Виталий Банковский
Размещаем пользовательские бюджеты в LDAP. Часть 2 Алексей Барабанов
№5 №6
Вадим Андросов Иван Максимов
Сергей Супрунов
№3
Артем Баранов
Система управления запросами OTRS Сергей Яремчук
№9
Синхронизация ACL и структуры организации
Создаём VPN с ViPNet Сергей Яремчук
№3
Вадим Андросов
№2
Создание и балансировка отказоустойчивых служб с помощью Cisco Content Switch Виталий Банковский
№10
Строим Jabber-сервер с OpenFire Сергей Яремчук
№5
Строим бюджетный сервер для малых №9
Строим бюджетный сервер для малых или средних компаний. Часть 2 Павел Семенец
№6
Строим сетевую инфраструктуру на основе VMware Server Алексей Бережной
№3
Технология NLB -отказоустойчивость без лишних затрат Андрей Бирюков
№7
Тонкая настройка Microsoft ISA 2004 Андрей Бирюков
№2 №9
Убить «Билла», вторая попытка, или Novell OES 2 Алексей Барабанов
№1 №12
на основе ZoneMinder Виталий Банковский
№11
Технологии защиты ядра NT Артем Баранов
№5
ИНФОРМАЦИОННАЯ БЕЗОПАСНОСТЬ № Антивирус+Антиспам Dr.Web для почтовых серверов UNIX Сергей Супрунов
№6
ПРОГРАММИРОВАНИЕ
№
Ruby: язык завтрашнего дня Владимир Овсянников
№3
Новое в синтаксисе Perl 5.10 Андрей Шитов
№12
Обзор Ruby on Rails Владимир Овсянников
№3
Организуем доступ к базам данных при разработке кроссплатформенных приложений на C++/wxWidgets Владимир Тряпичко
Три способа миграции с SPS 2003 на MOSS 2007 Нелли Садретдинова
№3
№11
Строим сетевую инфраструктуру для системы «1С:Предприятие» Сергей Алаев
№10
Строим систему видеонаблюдения и охраны
Создаём интегрированный в Active Directory файл-сервер
или средних компаний. Часть 1 Павел Семенец
№9
Руткиты режима ядра: алгоритмы работы и защита
Система контроля версий RCS на службе сисадмина
на базе Samba во FreeBSD Алексей Бережной
№11
Решаем типичные проблемы безопасности домашних сетей
Система анализа квот на базе File Server Resource Manager Иван Коробко
№10
на основе архитектуры организации в Windows Server 2003
Резервное копирование и восстановление базы данных Oracle средствами ОС Сергей Косько
№9
№11
Управляем Active Directory из командной строки
№6
Основные процедуры для работы с деревьями Александр Ямпольский
№12
Пространства имен в PHP Александр Майоров
№12
Работаем с OpenDocument из Perl Валентин Синицын
№12
Александр Емельянов
№11
Создаем СОМ-компоненты с помощью VBScript Иван Коробко
№8
Устанавливаем eGroupware Сергей Яремчук
№3
Что мы знаем о стеке? Владимир Мешков
№11
№1
WEB-ПРОГРАММИРОВАНИЕ
№
Библиотека Prototype – ваш путь в Web 2.0 Кирилл Сухов
№7
Устанавливаем и обновляем программное обеспечение в системе FreeBSD Гаспар Чилингаров Централизованная настройка UNIX-систем с помощью Puppet Сергей Яремчук
№7
Библиотека Prototype – ваш путь в Web 2.O. Часть 2: практика
АДМИНИСТРИРОВАНИЕ «1С»
№
Выгружаем данные из «1С» в Excel Андрей Луконькин
№11
Кирилл Сухов Кирилл Сухов
Используем скрипты WSH в «1С:Предприятие» Андрей Луконькин №12
Нетривиальный синтаксис в РНР, или Головоломки для кодера
Пакетный режим запуска «1С:Предприятие 7.7» Андрей Луконькин №10
Александр Майоров
Средства администрирования «1С:Предприятие 8»
Оцениваем возможности mocLpython и mod_perl
Андрей Луконькин
№12, декабрь 2007
№8
Выбираем фрэймворк-среду для веб-разработки
№9
Алексей Мичурин
№10 №10 №8
93
содержание журнала за 2007 год WEB
№
Окно в электронный мир: история развития графического пользовательского интерфейса. Часть 1 Дмитрий Мороз
xAjax – простой путь создания асинхронных веб-приложений Виктор Ермолаев
№4
пользовательского интерфейса. Часть 2 Дмитрий Мороз
Большие гонки веб-серверов Сергей Супрунов
№3
Патентные войны: оберегай своё, не посягай на чужое
Защита веб-служб. РНР-реализация Александр Календарев
№4
Дмитрий Мороз
Панель управления хостингом SysCP Сергей Яремчук
№8
Прошлое операционных систем семейства BSD
Работаем с MediaWiki Евгений Балдин
№2
Система аутентификации веб-пользователей WebAuth Сергей Яремчук
Илья Александров
№12 №5 №1
Судебные войны: оберегай своё, не посягай на чужое. №6
Создаем собственный хостинг, или Сам себе ISP Андрей Шетухин
№11
Окно в электронный мир: история развития графического
Часть вторая – программная Дмитрий Мороз
№6
Тяжкий путь первопроходца: история компьютера Foonly F1 №4
Дмитрий Мороз
№8
№12
ЧЕЛОВЕК НОМЕРА
№
Создаем собственный хостинг, или Сам себе ISP. Часть вторая Андрей Шетухин
IP-ТЕЛЕФОНИЯ
Вся правда о «Сисадмине», или Диктофон в кармане Оксана Родионова
Asterisk: организуем автоматическое распределение
№10
Игра в IT, или Зарисовки к портрету Дмитрия Гудзенко
поступающих вызовов Сергей Яремчук
№12
Оксана Родионова
Всё, что вы хотели знать о протоколе SIP Андрей Погребенник
№5
Капитан корабля Оксана Родионова
№7
Мечты сбываются Оксана Родионова
№5
Всё, что вы хотели знать о протоколе SIP. Часть 2 Андрей Погребенник
№8
Всё, что вы хотели знать о протоколе SIP. Часть 3 Андрей Погребенник
№9
Развертываем корпоративную телефонную сеть на основе технологии VoIP. Часть 1 Рашид Ачилов
№6
№12
Общение как стиль жизни Оксана Родионова
№8
Обыкновенный человек Оксана Родионова
№4
Перекресток IT-дорог, вот и я... Оксана Родионова
№11
СМИ уровня 2.0 Оксана Родионова
№6
Снаряд – броня Оксана Родионова
№1
Советы Джона Чемберса Оксана Родионова
№3
на основе технологии VoIP. Часть 2 Рашид Ачилов
№8
Солнечный мальчик Оксана Родионова
№9
СЕТИ
№
IMHO
№
№4
Программисты, программы и искусственный интеллект
Развертываем корпоративную телефонную сеть
Альтернативные беспроводные средства связи Иван Максимов
Алексей Мичурин
№4
Чего ждать от удаленной работы? Крис Касперски
№1
№2
ХОББИ
№
№
Open Source и Classic Games Иван Максимов
№2
СЕРВЕРНАЯ Как навести порядок в стойке Даниил Никифоров
ВСПОМОГАТЕЛЬНЫЕ ПРОГРАММЫ Gnuplot. Графики заказывали? Евгений Балдин
ОБРАЗОВАНИЕ
№4
№
№10
Изменения в сертификации Microsoft: новые статусы WICTS и MCITP для системных администраторов Дмитрий Павлов
РЕТРОСПЕКТИВА
№2(51) февраль 2007 подписной индекс 20780 www.samag.ru
№3(52) март 2007 подписной индекс 20780 www.samag.ru
Как навести порядок в стойке (из личного опыта)
Как построить сетевую инфраструктуру на основе VMware Server
Разбираемся в корпоративных программах лицензирования Microsoft FreeBSD в домене Windows: еще больше возможностей
FAQ: как проходит обучение и сертификация на MCSA и MCSE Дмитрий Павлов
№1(50) январь 2007 подписной индекс 20780 www.samag.ru
Как быстро и эффективно провести учет компьютерной техники
№11
Какова в действии система резервирования AMANDA №4(53) апрель 2007 подписной индекс 20780 www.samag.ru
ISA 2004: настраиваем Создаем собственный хостинг, удаленный доступ или Сам себе ISP к сети Пользовательские NFS: из прошлого в будущее бюджеты в LDAP Администрируем Противодействуем учетные записи в AD руткитам режима ядра Как проводить Чего сбор ждать системных сообщений от удаленной работы? в гетерогенной сети Cacti: вовремя находим проблемные участки сети
№
№7(56) июль 2007 подписной индекс 20780 www.samag.ru
Альтернативные беспроводные средства связи
№2
История компании Intergraph Дмитрий Мороз
№7
История компании MicroUnity: куда приводят мечты? Дмитрий Мороз
№4
Микропроцессорные войны: хроника борьбы компаний Intel и AMD Илья Александров
№9
Микропроцессорные войны: хроника борьбы компаний Intel и AMD Часть 2 Илья Александров
94
№10
Нововведения в Solaris 10: на чтомай обратить внимание админу №5(54) 2007 подписной индекс 20780
www.samag.ru Как «подружить» сети сПрограммы пересекающейся адресацией удаленного доступа: выбирайте подходящую!
Настраиваем DNS и DHCP сРазворачиваем хранением информации кластер в LDAP на основе Windows Server 2003 Создаем интегрированный в AD файл-сервер базеPIX Используем на Cisco Samba и FreeBSD VPN-подключений для обеспечения к локальной сети Open Source и Classic Games Split DNS: заставим BIND работать на два фронта! UserGate – безопасный прокси-сервер Резервное копирование и восстановление СУБД Oracle средствами ОС
MOSS 2007: оцените удобство!
Технологии защиты ядра NT
OpenWRT – Linux-дистрибутив VPNвстраиваемых на основе протокола для систем PPTP:
Всё, что вы хотели знать о протоколе SIP
Gnuplot: графики заказывали?
Глобальная сетевая энциклопедия Илья Александров
Принципы построения доменов Active Directory
Групповые политики xAjax – простой способ создавать в доменах Active Directory
асинхронные веб-приложения
Google: история лучшей поисковой системы Илья Александров №3
Два канала – роскошь? Резервирование и балансировка трафика во FreeBSD
как повысить безопасность? Централизованная настройка UNIX-систем с помощью Puppet №10(59) октябрь 2007 Как работает служба подписной индекс 20780 Network Load Balancing www.samag.ru
Особенности инсталляции Создаём отказоустойчивый ОС Solaris сервис с помощью Cisco Content Switch Библиотека Prototype – ваш путь в Web 2.0 Реализуем нестандартные правила управления доступом vs PostgreSQL вMySQL Windows Server 2003
Составит ли VirtualBox конкуренцию VMware? Система контроля версий RCS на службе сисадмина Как арендовать или купить в рассрочку ПО от Microsoft
№6(55) июнь 2007 подписной индекс 20780 www.samag.ru
Создаём VPN с ViPNet
Не допустите потери данных! Используйте преимущества Кфайловой вашим услугам системы ZFS в Solaris ленточная библиотека
Большие гонки веб-серверов
Как настроить АТС Samsung: Устанавливаем eGroupware первые шаги
Решаем типичные Разворачиваем кластер проблемы безопасности Microsoft Exchange домашних сетей
Строим сетевую инфраструктуру для системы 1С:Предприятие Антивирус+Антиспам Dr.Web для почтовых серверов UNIX Система анализа квот на базе File Server Resource Manager FreeBSD: особенности сборки ядра Тестируем дистрибутив ALT Linux 4.0 Server
№12(61) декабрь 2007 подписной индекс 20780 www.samag.ru
MS Exchange 2003 + SpamAssassin Asterisk: организуем автоматическое распределение поступающих вызовов Citadel – Open Source-решение для коллективной работы
Нужен сервер коллективной работы? Используем Zimbra
DTrace – рентген для операционной системы
Расширяем возможности Windows Messenger
Программное управление MS Exchange
Open Source-решение: сетевой шлюз Untangle
Используем скрипты WSH в «1С:Предприятие»
Защищаем систему с Outpost Security Suite
GNU Autotools: ошибки свои и чужие
Выбираем фрэймворк-среду для веб-разработки
Работаем с OpenDocument из Perl
FAQ: как проходит обучение и сертификация на MCSA и MCSE
Новое в синтаксисе Perl 5.10
подписка на 2008 год Российская Федерация
n Подписной индекс: годовой – 20780, полугодовой – 81655 Каталог агентства «Роспечать»
n Подписной индекс: годовой – 88099, полугодовой – 87836 Объединенный каталог «Пресса России» Адресный каталог «Подписка за рабочим столом» Адресный каталог «Библиотечный каталог» n Альтернативные подписные агентства: Агентство «Интер-Почта» (495) 500-00-60, курьерская доставка по Москве Агентство «Вся Пресса» (495) 787-34-47 Агентство «Курьер-Прессервис» Агентство «ООО Урал-Пресс» (343) 375-62-74 ЛинуксЦентр www.linuxcenter.ru n Подписка On-line http://www.arzi.ru http://www.gazety.ru http://www.presscafe.ru
СНГ В странах СНГ подписка принимается в почтовых отделениях по национальным каталогам или по списку номенклатуры «АРЗИ»: n Азербайджан – по объединенному каталогу российских изданий через предприятие по распространению
печати «Гасид» (370102, г. Баку, ул. Джавадхана, 21)
n Казахстан – по каталогу «Российская Пресса» через ОАО «Казпочта» и ЗАО «Евразия пресс»
n Беларусь – по каталогу изданий стран СНГ через РГО «Белпочта» (220050, г. Минск, пр-т Ф. Скорины, 10)
n Узбекистан – по каталогу «Davriy nashrlar» российские издания через агентство по распространению печати «Davriy nashrlar» (7000029, г. Ташкент, пл. Мустакиллик, 5/3, офис 33) n Армения – по списку номенклатуры «АРЗИ» через ГЗАО «Армпечать» (375005, г. Ереван, пл. Сасунци Давида, д. 2) и ЗАО «Контакт-Мамул» (375002, г. Ереван, ул. Сарьяна, 22) n Грузия – по списку номенклатуры «АРЗИ» через АО «Сакпресса» ( 380019, г. Тбилиси, ул. Хошараульская, 29) и АО «Мацне» (380060, г. Тбилиси, пр-т Гамсахурдия, 42) n Молдавия – по каталогу через ГП «Пошта Молдовей» (МД-2012, г. Кишинев, бул. Штефан чел Маре, 134) по списку через ГУП «Почта Приднестровья» (МD-3300, г. Тирасполь, ул. Ленина, 17) по прайс-листу через ООО Агентство «Editil Periodice» (МД-2012, г. Кишинев, бул. Штефан чел Маре, 134) n Подписка для Украины: Киевский главпочтамт Подписное агентство «KSS», тел./факс (044)464-0220
Подписные индексы:
20780* 81655** по каталогу агентства «Роспечать»
88099* 87836** по каталогу агентства «Пресса России» * **
№12, декабрь 2007
годовой полугодовой
95
СИСТЕМНЫЙ АДМИНИСТРАТОР №12(61), Декабрь, 2007 год УЧРЕДИТЕЛИ Владимир Положевец Александр Михалев РУКОВОДИТЕЛЬ ПРОЕКТА Петр Положевец РЕДАКЦИЯ Исполнительный директор Владимир Положевец Ответственный секретарь Наталья Хвостова sekretar@samag.ru Технический редактор Владимир Лукин Главный редактор электронного приложения «Open Source» Дмитрий Шурупов Внештатные редакторы Алексей Барабанов Валентин Синицын Иван Максимов Андрей Бирюков Олег Щербаков Дмитрий Горяинов Кирилл Сухов Алексей Мичурин Сергей Яремчук
Готовится к выходу DVD-диск с архивом номеров журнала за 2007 год Что на диске? n Архив 12-ти номеров журнала «Системный администратор» за 2007 год. n Архив всех выпусков электронного приложения «Open Source» за 2007 год. n Дистрибутивы и полезные программы от партнеров журнала.
Как получить диск в подарок? n В подарок DVD-диск получат все годовые подписчики 2008 года. Диск будет вложен в февральский номер журнала за 2008 год.
РЕКЛАМНАЯ СЛУЖБА тел./факс: (495) 628-8253 Евгения Тарабрина reсlama@samag.ru
n Клиенты компании SecurIT, заказавшие Zserver в любой комплектации
Верстка и оформление maker_up@samag.ru Дизайн обложки Дмитрий Репин Николай Петрочук
Где можно приобрести диск?
По вопросам распространения обращайтесь по телефону: (495) 628-8253 (доб. 120)
n В online-магазине Linuxcenter.ru.
107045, г. Москва, Ананьевский переулок, дом 4/2, стр. 1 тел./факс: (495) 628-8253 Сайт журнала: www.samag.ru ИЗДАТЕЛЬ ЗАО «Издательский дом «Учительская газета» Отпечатано типографией ГП «Московская Типография №13» Тираж 15000 экз. Журнал зарегистрирован в Министерстве РФ по делам печати, телерадиовещания и средств массовых коммуникаций (свидетельство ПИ № 77-12542 от 24 апреля 2002 г.). За содержание статьи ответственность несет автор. Мнение редакции может не совпадать с мнением автора. За содержание рекламных материалов ответственность несет рекламодатель. Все права на опубликованные материалы защищены.
96
или более 50 лицензий Zlock, получат диск в подарок. Акция проходит в феврале и марте 2008 года.
n В редакции журнала «Системный администратор» по адресу: г. Москва, Ананьевский переулок 4/2, стр. 1, в офисе 13 (метро «Сухаревская»).
Сколько стоит? Цена в редакции – 150 рублей.
Уважаемые читатели! Продолжается подписка на 2008 год! Приобрести новые и старые номера журнала вы можете через интернет-магазин Linuxсenter.ru.
Доставка почтой в любую точку России.