Искусство программирования для Unix
Шрифт:
Обычным применением данной методики является заключение привилегированных приложений в некоторой программе-диспетчере, которая затем может передать параметры менее привилегированной программе. В данной методике несколько программ объединяются с помощью вызовов exec или, возможно, комбинации вызовов fork и exec. Все программы указываются в одной командной строке. Каждая программа осуществляет некоторую функцию и (в случае успешного завершения) запускает ехес(2) для остальной части командной строки.
Пакет Бернштайна rblsmtpd является принципиальным примером. Он служит для поиска узла в антиспамной DNS-зоне системы предотвращения
Еще один пример можно встретить в пакете qmail Бернштайна. Пакет содержит программу, которая называется condredirect. Первым параметром является адрес электронной почты, остальные параметры — программа-диспетчер и аргументы, condredirect разветвляется и запускает программу-диспетчер со своими аргументами. В случае успешного завершения программой-диспетчером своей работы, condredirect перенаправляет почтовое сообщение, ожидающее в stdin, на указанный адрес электронной почты. В этом случае, в противоположность rblsmtpd, решение принимается дочерним процессом. Этот случай несколько больше походит на классический вызов с созданием подоболочки.
Более сложным примером является POP3-сервер qmail. Он состоит из трех программ: qmail-popup, checkpassword и qmail-pop3d. Программа Checkpassword взята из отдельного пакета, остроумно названного checkpassword, и, естественно, предназначена для проверки паролей. В протоколе POP3 предусмотрен этап аутентификации и этап работы с почтовым ящиком. Перейдя к этапу работы с почтовым ящиком, пользователь не имеет возможности вернуться к этапу аутентификации. Это идеальное применение для цепей Бернштайна.
Первым параметром программы qmail-popup является имя узла для использования в POP3-приглашениях. Остальные ее параметры, после того как имя пользователя POP3 и пароль были доставлены, разделяются и передаются ехес(2). Если данная программа возвращает отказ, то пароль, вероятнее всего, не верный, qmail-popup сообщает об этом и ожидает ввода другого пароля. В противном случае предполагается, что программа окончила POP3-диалог, поэтому qmail-popup завершает работу.
Ожидается, что программа, указанная в командной строке qmail-popup, считывает 3 строки, ограниченные символом NULL, из дескриптора файла 3 [70] : имя пользователя, пароль и ответ на криптографический запрос, если он есть. В настоящее время такой программой является checkpassword, которая принимает в качестве параметров имя qmail-pop3d и его параметры. Программа checkpassword завершается
70
Стандартный ввод и стандартный вывод программы qmail-popup представляют собой сокеты, а стандартная ошибка (дескриптор файла 2) отправляется в log-файл. Гарантируется, что дескриптор файла 3 будет следующим выделенным дескриптором. В одном печально известном комментарии к ядру было сказано: "Никто и не ждет, что вы это поймете".
Создание цепей Бернштайна полезно в ситуациях, когда приложение требует setuid- или setgid-привилегий для инициализации соединения или для получения какого-либо мандата, а затем понижает эти привилегии, чтобы можно было использовать последующий вовсе не обязательно "благонадежный" код. Поскольку дочерняя программа была запущена с помощью вызова exec, она не может установить свой действительный идентификатор пользователя равным идентификатору администратора. Такая методика является более гибкой, чем использование одного процесса, поскольку можно модифицировать поведение системы путем внедрения в цепочку другой программы.
Например, программа rblsmtpd (упомянутая выше) может быть вставлена в цепь Бернштайна между программой tcpserver (из пакета ucspi-tcp) и реальным SMTP-сервером, обычно qmail-smtpd. В то же время она также работает с inetd(8) и
7.2.5. Подчиненные процессы
Иногда дочерние программы интерактивно принимают и возвращают данные вызвавшим их программам через каналы, связанные со стандартным выводом и вводом. В отличие от простых вызовов с созданием подоболочки и конструкций, которые выше были названы "прикрепляемыми", как главный, так и подчиненный процессы нуждаются в наличии внутренних конечных автоматов для обработки протокола между ними без взаимоблокировки или конкуренции. Такая организация является значительно более сложной и более трудной в отладке, чем простые вызовы с созданием подоболочки.
Вызов popen(3) в Unix способен устанавливать либо канал ввода, либо канал вывода для подоболочки, но не оба канала для подчиненного процесса — видимо, для поощрения более простого программирования. И фактически интерактивный обмен данными между главным и подчиненным процессом является настолько сложным, что обычно используется только в ситуациях, когда (а) связанный протокол является крайне примитивным, либо (b) подчиненный процесс спроектирован для обмена данными по протоколу прикладного уровня в соответствии с принципами, которые описывались в главе 5. Данная проблема и способы ее разрешения рассматриваются в главе 8.
При написании пары "главный-подчиненный" хорошей практикой считается заставить главный процесс поддерживать ключ командной строки или переменную среды, которая позволяет вызывающим программам устанавливать собственную подчиненную команду. Кроме прочего, это полезно для отладки. Нередко обнаруживается удобство такой конструкции во время разработки для вызова реального подчиненного процесса из тестовой программы, которая осуществляет мониторинг и протоколирование транзакций между главным и подчиненным процессом.