Транспорт "pipe"


    Транспорт pipe использует доставку через трубу (pipe) к команде, выполняющейся в ином процессе. Один пример - использование pipe как псевдоудалённого транспорта для передачи сообщений какому-то иному механизму доставки (типа UUCP). Другой - использование отдельными пользователями для автоматической обработки их входящих сообщений. Транспорт pipe может использоваться одним из следующих способов:

  • Маршрутизатор направляет один адрес на транспорт обычным способом, и транспорт сконфигурен как транспорт pipe . В этом случае, $local_part содержит локальную часть адреса (как обычно), и запускаемая команда задана в транспорте, опцией command .
  • Если опция batch_max установлена более чем в 1 (значение по умолчанию - 1), транспорт может обработать более одного адреса за один запуск. В этом случае, когда к транспорту роутится более одного адреса, $local_part не установлена (поскольку она не уникальна). Однако, псевдопеременная $pipe_addresses (описанная в разделе 29.3) содержит все адреса которые роутятся к транспорту.
  • Роутер переадресует адрес напрямую к команде pipe (например, из файла альясов или форвардов). В этом случае, $address_pipe содержит текст команды pipe, и опция command в роутере - игнорируется. Если транспортируется лишь один адрес ( batch_max более одного, или лишь один адрес был передаресован к команде трубы), $local_part содержит переадресованную локальную часть.
       Транспорт
    pipe - неинтерактивный метод доставки. Также, exim может доставлять сообщения через трубы, используя интерактивный протокол LMTP. Это осуществляется транспортом lmtp .
       В случае, когда
    pipe работает как следствие совпадения в локальном пользовательском файле .forward , команда запускается под uid и gid этого пользователя. В других случаях, uid и gid должны быть заданы явно, или в транспорте, или в маршрутизаторе обрабатывающем адрес. Текущая и домашняя директории также управляемы. Для получения дополнительных деталей о окружении долальной доставки, смотрите раздел 23, и раздел 25 для обсуждения пакетной локальной доставки.

    29.1 Конкурирующие доставки

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

    29.2 Возвращаемый статус и данные

       Если команда выходит со статусом отличным от нуля, доставка считается неудачной, если не установлена опция ignore_status (в этом случае код возврата обрабатывается как ноль), или возвращаемый код - один из перечисленных в опции temp_errors , которые интерпретируются со смыслом попробуйте позднее (try again later). В этом случае, доставка задерживается. Детали постоянной ошибки логгируются, но не включаются в рикошет, просто содержащий local delivery failed.
       Если код возврата более чем 128, и выполняемая команда - shell-скрипт, это, обычно, означает, что скрипт был уничтожен сигналом, чьё значение равно - код возврата минус 128ю
       Если exim не может запустить команду (т.е. - если
    execve() неудачна), код возврата устанавливается равным 127. Это - значение, возвращаемое shell`ом, если запрашивают о запуске невыполняемой команды. Формулировка для логов наводит на мысль, что проблемой может быть несуществующая команда.
       Опция
    return_output может затрагивать результат доставки. Если она установлена, и команда производит какой-либо вывод на своём стандартном выводе, или в стандартном потоке ошибок, предполагается, что произошла ошибка команды, даже если она вернула нулевой код возврата, или установлена опция ignore_status . Вывод команды включается как часть сообщения рикошета. Опция return_fail_output подобна вышеописанной, за исключением что вывод возвращается лишь когда команда выходит с ошибочным кодом возврата, т.е. значениями кроме нуля или совпадающим с temp_errors .

    29.3 Как выполняется команда

       Командная строка (по умолчанию) разбирается в имя команды и аргументы непосредственно транспортом pipe . Опции allow_commands и restrict_to_path могут использоваться для ограничения команд, которые могут быть запущены.
       Элементы не помещённые в кавычки разделяются по пробелам. Если аргумент помещён в двойные кавычки, обратный слэш интерпретируется как обычно, - как специальный символ. Если аргумент фигурирует в одинарных кавычках, интерпретации специальных символов не производится (имеются ввиду символы начинающиеся с обратного слэша - прим. lissyara).
       К командной строке применяется раскрытие строки, кроме случаев когда она приходит из традиционного файла
    .forward (команды из файла фильтра раскрываются). Раскрытие применяется по очереди, к каждому аргументу, а не ко всей строке. Поэтому, любой любой элемент раскрытия, содержащий пробелы, должен быть помещён в кавычки таким образом, чтобы он был внутри одного аргумента. Установка типа

    
    command = /some/path ${if eq{$local_part}{postmaster}{xx}{yy}}
    
    
    

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

    
    command = /some/path "${if eq{$local_part}{postmaster}{xx}{yy}}"
    
    
    

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

    
    command = /bin/sh -c ${lookup{
    $local_part}lsearch{/some/file}}
    
    
    

       Имеет место специальная обработка, когда аргумент состоит в точности из текста $pipe_addresses . Это - не общая переменая раскрытия; единственное место, где распознаётся эта строка, - когда она появляется как парметр для трубы, или команды транспортного фильтра. Она вызывает каждый обрабатываемый адрес для вставки в список аргументов, в этой точке, как отдельный параметр. Это позволяет избежать любых проблем с пробелами или метасимволами shell, и используется когда транспорт pipe обрабатывает группу адресов в пакете.
       После разделения на параметры и раскрытие, результирующая команда запускается в субпроцессе напрямую от транспорта, не под shell`ом. Доставляемое сообщение предоставялется на стандартном вводе, и оба - стандартный вывод, и стандартный вывод для ошибок, связаны с одной трубой, читаемое exim`ом. Опция
    max_output - контролирует,как много вывода может произвести команда, и опции return_output и return_fail_output - управляют, что с ним делается.
       Невыполнение команды под shell`ом (по умолчанию), уменьшает риск безопасности в случаях, когда команда из пользовательского фильтра строится из данных взятых из входящего сообщения. Если shell требуется, он, разумеется, может быть явно определён как оамнда, которая выполнится. Однако, существуют обстоятельства, когда существующие команды (например, в файлах
    .forward ) ожидают своего выполнения под shell`ом,и не могут быть легко модифицированы. Для разрешениия этих случаев, есть опция, называемая use_shell , которая изменяет способ работы транспорта pipe . Вместо описанной разбивки командной строки, она раскрывает её как одну строку, и передаёт результат /bin/sh . Опция restrict_to_path и средство $pipe_addresses не могут использоваться с use_shell , и весь механизм - менее безопасен.

    29.4 Переменные окружения

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

    имя
    значение
    DOMAIN домен адреса
    HOME домашняя директория; если задана
    HOST имя хоста при вызове из роутера (смотрите ниже)
    LOCAL_PART смотрите ниже
    LOCAL_PART_PREFIX смотрите ниже
    LOCAL_PART_SUFFIX смотрите ниже
    LOGNAME смотрите ниже
    MESSAGE_ID локальный идентификатор сообщения exim`a
    PATH как задано путём опции “path
    QUALIFY_DOMAIN квалификационный домен отправителя
    RECIPIENT полный адрес получателя
    SENDER отправитель сообщения (пустой - если рикошет)
    SHELL /bin/sh
    TZ значение опции “timezone; если установлена
    USER смотрите ниже

       Когда транспорт pipe вызывается непосредственно из (например) роутера accept , LOCAL_PART устанавливается в локальную часть адреса. Когда он вызывается как результат раскрытия форварда или альяса, LOCAL_PART устанавливается в локальную часть адреса, который был раскрыт. В обоих случаях, любые аффиксы удаляются из локальной части, и становятся доступны в LOCAL_PART_PREFIX и LOCAL_PART_SUFFIX, соответственно. LOGNAME и USER устанавливаются в тоже значение, что и LOCAL_PART, для совместимости с другими MTA.
       HOST - устанавливается лишь когда транспорт
    pipe вызывается из роутера, который ассоциирует хосты с адресами, типично используя pipe как псевдоудалённый транспорт. HOST устанавливается в первое имя хоста заданное роутером.
       Если установлена общая транспортная опция
    home_directory , её значенеи используется для переменной окружения HOME.  Иначе, домашняя директория может быть установлена роутером, путём опции transport_home_directory , иеющей дефолтовое значение на домашнюю директорию пользователя, если установлена check_local_user .

    29.5 Частные опции для pipe

    Имя
    Использование
    Тип
    Дефолтовое значение
    allow_commands pipe string list† незадана

       Строка раскрывается, и, затем, интерпретируется как раздёлённый двоеточиями список допустимых команд. Если restrict_to_path не установлена, разрешены лишь команды перечисленные в списке allow_commands . Они не должны быть абсолютными путями; опция path продолжает использоваться для относительных путей. Если restrict_to_path установлена с allow_commands , команда должна быть в списке allow_commands , или именем без каких-либо слэшей наёденным в путях. Другими словами, если не установлена ни allow_commands , ни restrict_to_path - нет никаких ограничений на команды, но иначе, разрешены лишь команды допускаемые той или другой опциеями. Например, если

    allow_commands = /usr/bin/vacation
    
    
    

    и restrict_to_path не установлена, разрешена лишь команда /usr/bin/vacation . Опция allow_commands не может быть установлена, если установлена use_shell .

    Имя
    Использование
    Тип
    Дефолтовое значение
    batch_id pipe string† незадана

       Смотрите описание пакетной локальной доставки в разделе 25.

    Имя
    Использование
    Тип
    Дефолтовое значение
    batch_max pipe integer 1

       Эта опция ограничивает число адресов, которые могут быть обработаны в одной доставке. Смотрите описание пакетной локальной доставки в разделе 25.

    Имя
    Использование
    Тип
    Дефолтовое значение
    check_string pipe string незадана

       Когда pipe пишет сообщение, начало каждой строки проверяется на совпадение с check_string , и если оно происходит, начальные совпавшие символы заменяются содержимым escape_string , если обе установлены. Значение check_string - литеральная строка, а не регулярное выражение, и регистр букв имеет значение. Когда установлена use_bsmtp , содержимое check_string и escape_string приводится к значениям, которые оформлены протоколом экранирования SMTP (? - невкурил... - прим. lissyara). Любые настройки сделанные в конфигурационном файле - игнорируются.

    Имя
    Использование
    Тип
    Дефолтовое значение
    command pipe string† незадана

       Эта опция не должна быть установлена, когда pipe используется для доставки в трубы, полученные непосредственно от переназначения адресов. В других случаях, опция должна быть установлена, для предоставления команды, которая будет выполнена. Она не нуждается в абсолютном пути (смотрите ниже, опцию path ). Команда разделяется exim`ом на отдельные параметры, и каждый аргумент отдельно раскрывается, как описано выше, в разделе 29.3.

    Имя
    Использование
    Тип
    Дефолтовое значение
    environment pipe string† незадана

       Эта опция используется для добавления дополнительный переменных к среде окружения, в которой выполняется команда (смотрите раздел 29.4, для получения списка дефолтовых значений). Ее значение - строка, которая вначале раскрывается, и затем интерпретируется, как список, разделённый двоеточиями, установок среды окружения в форме <name>=<value> .

    Имя
    Использование
    Тип
    Дефолтовое значение
    escape_string pipe string незадана

       Смотрите выше, опцию check_string .

    Имя
    Использование
    Тип
    Дефолтовое значение
    freeze_exec_fail pipe boolean ложь

       Ошибка выполнения команды в транспорте pipe , по умолчанию, обрабатывается как любая другая ошибка при запуске команды. Однако, если установлена опция freeze_exec_fail , ошибка выполнения обрабатывается особым образом, и вызывает заморозку сообщения вне зависисмости от установки ignore_status .

    Имя
    Использование
    Тип
    Дефолтовое значение
    ignore_status pipe boolean ложь

       Если эта опция истинна, статус возвращаемый субпроцессом запустившим команду - игнорируется, и exim ведёт себя так, как будто был возвращён ноль. Иначе, ненулевой статус или завершение по сигналу вызывают ошибку из транспорта, если статус - не одно из значений перечисленных в temp_errors ; они вызывают задержку доставки и дальнейшие, более поздние попытки доставки.
       Отметтьте: Эта опция не касается таймаутов, которые не возвращают статус. Смотрите опцию
    timeout_defer , для информации о обработке таймаутов.

    Имя
    Использование
    Тип
    Дефолтовое значение
    log_defer_output pipe boolean ложь

       Если эта опция установлена, и статус возвращаемый командой - один из кодов перечисленных в temp_errors (т.е. доставка была задержана), и её был сгенерён какой-либо вывод, его первая строка записывается в главный лог.

    Имя
    Использование
    Тип
    Дефолтовое значение
    log_fail_output pipe boolean ложь

       Если эта опция установлена, и команда возвращает какой-либо вывод, и, также, завершается с кодом возврата не равным ни нулю, ни кодам перечисленным в temp_errors (т.е. - доставка неудачна), первая строка вывода записывается в главный лог. Эта опция, и log_output - взаимоисключаемы. Лишь одна из них может быть установлена.

    Имя
    Использование
    Тип
    Дефолтовое значение
    log_output pipe boolean ложь

       Если эта опция установлена, и команда возвращает какой-либо вывод, первая строка вывода записывается в главный лог вне зависимости от возвращённого кода. Эта опция, и log_fail_output - взаимоисключаемы. Лишь одна из них может быть установлена.

    Имя
    Использование
    Тип
    Дефолтовое значение
    max_output pipe integer 20K

       Эта опция определяет максимальное количество вывода, который команда может сгенерить на своём стандартном выводе и объединённом стандартном файле ошибок. Если лимит исчерпан, процесс, выполняющий команду, уничтожается. Это - мера безопасности, для поимки неудержиморастущих процессов. Ограничение применяется независимо от настроек опций контролирующих что происходит с этим выводом (например, return_output ). Из-за эффекта буферизации, объём вывода может немного превысить ограничение, до того, как exim это заметит.

    Имя
    Использование
    Тип
    Дефолтовое значение
    message_prefix pipe string† смотрите ниже

       Заданная строка раскрывается, и выводится в начале каждого сообщения. По умолчанию, она незадана, если установлена опция use_bsmtp . Иначе, она

    message_prefix = \
      From ${if def:return_path{$return_path}{MAILER-DAEMON}}\
      ${tod_bsdinbox}\n
    
    
    

       Обычно, это требуется для программы /usr/bin/vacation . Однако, она не должна присутствовать, если производится доставка на Cyrus IMAP server, или локальному агенту доставки tmail . Преффикс может быть запрещён путём установки

    message_prefix =
    
    
    

    Имя
    Использование
    Тип
    Дефолтовое значение
    message_suffix pipe string† смотрите ниже

       Заданная строка раскрывается, и выводится в начале каждого сообщения. По умолчанию, она незадана, если установлена опция use_bsmtp . Иначе, она - одна новая строка. Суффикс может быть запрещён путём установки

    message_suffix =
    
    
    

    Имя
    Использование
    Тип
    Дефолтовое значение
    path pipe string /bin:/usr/bin

       Эта опция определяет строку, которая устанавливается в переменную окружения PATH, субпроцесса. Если опция command не приводит к абсолютному пути к имени, команда разыскивается в директориях PATH обычным способом. Предупреждение: Это не применяется к команде, заданной как транспортный фильтр.

    Имя
    Использование
    Тип
    Дефолтовое значение
    pipe_as_creator pipe boolean ложь

       Если незадана общая опция user , и эта опция истинна, процесс доставки запускается под uid, который был у exim при при изначальном вызове для приёма сообщения. Если не установлен идентификатор группы (через общую опцию group ), в силе gid, который был у exim при при изначальном вызове для приёма сообщения.

    Имя
    Использование
    Тип
    Дефолтовое значение
    restrict_to_path pipe boolean ложь

       Когда эта опция установлена, любое имя команды не перечисленное в allow_commands не должно содержать какихбы-то ни было слэшей. Команда ищется лишь в директориях перечисленных в опции path . Эта опция предназначена для случая, когда команда трубы была сгенерена из пользовательского файла .forward . Обычно, это обрабатывается транспортом pipe , называемым address_pipe .

    Имя
    Использование
    Тип
    Дефолтовое значение
    return_fail_output pipe boolean ложь

       Если эта опция установлена в истину, и команда производит какой-либо вывод, и завершается с кодом возврата не равным нулю или несодержащимся в кодах перечисленных в temp_errors (т.е. ошибка доставки), вывод возвращается в рикошете. Однако, если сообщение имеет пустого отправителя (т.е. оно само по себе рикошет), вывод команды отбрасывается. Эта опция и return_output - взаимоисключаемы. Лишь одна из них может быть установлена.

    Имя
    Использование
    Тип
    Дефолтовое значение
    return_output pipe boolean ложь

       Если эта опция установлена в истину, и команда производит какой-либо вывод, доставка считается неудачной вне зависмости от кода возврата, и вывод возвращается в рикошете. Иначе, вывод просто игнорируется. Однако, если сообщение имеет пустого отправителя (т.е. оно само по себе рикошет), вывод всегда команды отбрасывается, вне зависимости от установки этой опции. Эта опция и return_fail_output - взаимоисключаемы. Лишь одна из них может быть установлена.

    Имя
    Использование
    Тип
    Дефолтовое значение
    temp_errors pipe boolean незадана

       Эта опция содержит или список, разделённый двоеточиями, или единственную звёздочку. Если опция ignore_status - ложна, и return_output - незадана, и команда выходит с ненулевым кодом, ошибка обрабатывается как временная, и доставка задерживается - если код возврата совпадает с одним из чисел, или если стоит звёздочка. Иначе, ненулевые коды возврата обрабтываются как постоянные ошибки. Значение по умолчанию сожержит коды заданные EX_TEMPFAIL и EX_CANTCREAT в sysexits.h . Если exim скомпилен на системе не задающей эти макросы, они принимают значения 75 и 73, соответственно.

    Имя
    Использование
    Тип
    Дефолтовое значение
    timeout pipe time 1h

       Если команда не смогла завершится в течение этого времени, она уничтожена. Обычно, это вызывает ошибку доставки (но, посмотрите опцию timeout_defer ). Нулевой интервал времени задаёт, что нет таймаута. Для гарантии, что любые созданные командой субпроцессы также уничтожены, exim делает начальный процесс лидером группы процессов, и по таймауту всю группу процессов. Однако, это может быть обойдено, если один из процессов начинает новую группу процессов.

    Имя
    Использование
    Тип
    Дефолтовое значение
    timeout_defer pipe boolean ложь

       Таймаут в транспорте pipe , или в команде, запускаемой транспортом, или в ассоциированном с ним транспортном фильтре, по дефолту обрабтывается как жёсткая ошибка, и доставка неудачна. Однако, если timeout_defer установлена в истину, оба вида таймаута становятся временными, вызывая задержку доставки.

    Имя
    Использование
    Тип
    Дефолтовое значение
    umask pipe octal integer 022

       Эта опция определяет установку umask для субпроцесса выполняющего команду.

    Имя
    Использование
    Тип
    Дефолтовое значение
    use_bsmtp pipe boolean ложь

       Если эта опция установлена в истину, транспорт pipe пишет сообщения в формате пакетного SMTP, с отправителем конверта и получателем (получателями) включенными как SMTP-команды. Если вы хотите включить начальную команду HELO с каждым сообщением, вы можете сделать это, путём установки опции message_prefix . Для получения дополнительных деталей о пакетном SMTP, смотрите раздел 44.10.

    Имя
    Использование
    Тип
    Дефолтовое значение
    use_classresources pipe boolean ложь

       Эта опция доступна лишь в случае, если exim работает на FreeBSD, NetBSD, или BSD/OS (FreeBSD - форева; - извините, прим. lissyara :)). Если она установлена в истину, функция setclassresources() используется для установки ограничений ресурсов, когда транспорт pipe производит доставку. Лимиты для uid, под которым работает труба, лолучаются из БД классов логинов (/etc/login.conf - прим. lissyara).

    Имя
    Использование
    Тип
    Дефолтовое значение
    use_crlf pipe boolean ложь

       Эта опция заставляет завершаться строки двухсимвольной CRLF последовательностью (возврат каретки, новя строка), вместо одного символа перевода строки. В случае пакетного SMTP, записанная в трубу последовательность байтов - точное подобие того, что было бы послано в реальном SMTP-подключении.
       Содержимое опций
    message_prefix и message_suffix пишется дословно, таким образом, они должны содержать свои символы возврата каретки, если они им необходимы. Так как сдефолтовое значение для обоих - message_prefix и message_suffix содержит один перевод строки, их значения должны быть изменены, чтобы они завершались \r\n, если задана опция use_crlf .

    29.6 Использование внешнего (стороннего) агента локальной доставки

       Транспорт pipe может использоваться для передачи всех сообщений, которым требуется локальная доставка, отдельному локальному агенту доставки, типа procmail . Когда это делается, нужно быть осторожным, чтобы гагантировать, что труба выполняется под соответствующими uid и gid. В некоторых конфигурациях, требуется, чтобы это был uid, которому доверяет агент доставки, для предоставления корректного отправителя сообщения. Может потребоваться повторно пересобрать или переконфигурировать агента доставки таким образом, чтобы он доверял соответтсвующему пользователю. Далее - пример конфигурации транспорта и роутра, для procmail :

    
    # transport
    procmail_pipe:
      driver = pipe
      command = /usr/local/bin/procmail -d $local_part
      return_path_add
      delivery_date_add
      envelope_to_add
      check_string = "From "
      escape_string = ">From "
      user = $local_part
      group = mail
    
    # router
    procmail:
      driver = accept
      check_local_user
      transport = procmail_pipe
    
    
    

       В этом примере, труба запускается как локальный пользователь, но с установленнной группой mail . Как альтернатива - запускать трубу под определённым пользователем, типа mail или exim , но в этом случае вы должны принять меры, чтобы procmail доверял этому пользователю для предоставления корректного адреса отправителя. Если вы не задаёте или опцию group или опцию user , команда трубы запускается под локальным пользователем. Домашняя директория - дефолтовая домашняя директория пользователя.
       Отметтьте: Команда, которая запускает транспорт
    pipe , не начинается с

    IFS=" "
    
    
    

    как показано в некоторой документации на procmail , поскольку exim, по умолчанию, не использует shell для запуска команд канала.
    Следующий пример показывает транспорт и роутер для систем, где локальные доставки обрабатываются Cyrus IMAP server.

    
    # transport
    local_delivery_cyrus:
      driver = pipe
      command = /usr/cyrus/bin/deliver \
                -m ${substr_1:$local_part_suffix} -- $local_part
      user = cyrus
      group = mail
      return_output
      log_output
      message_prefix =
      message_suffix =
    
    # router
    local_user_cyrus:
      driver = accept
      check_local_user
      local_part_suffix = .*
      transport = local_delivery_cyrus
    
    
    

       Отметтьте, что незаданы message_prefix и message_suffix , и использование return_output , для того, чтобы любой текст, записанный Cyrus`ом, был возвращён отправителю.




    =============
    Автор перевода: lissyara, оригинал: http://www.lissyara.su/?id=1200