view README.postfix @ 780:ddae562f7cf0

Document why 'nobody' is inappropriate and capitalise a few things
author Ben Schmidt
date Mon, 15 Nov 2010 10:11:28 +1100
parents fdc57c9e5f56
children 58d726e86650
line wrap: on
line source

README.postfix                                                   Dec 16th 2009

POSTFIX ISSUES

    The main issue with Postfix and Mlmmj is the Mlmmj requirement that
    the Mlmmj executables must be executed by root or the owner of the
    list directory.

    This is at odds with Postfix.  The standard local delivery mechanism
    for Postfix is local(8) that ships with Postfix.  According to
    local(8) delivery to external programs is done on behalf of the
    receiving user.  But when delivering to a program without using a
    .forward file there is no user context.  And using an alias file
    does not provide user context.

    The man page also explains that in the absence of user context the
    local(8) daemon will use the owner of the :include: file from the
    aliases file.  But this is a problem too.  By default :include:
    files are disabled as a security precaution in aliases files for
    delivering to external programs.

    So Postfix then falls back to executing with the user specified by
    the configuration option 'default_privs'.  The default setting for
    this option is the user 'nobody'.  You can make Mlmmj work by having
    your lists owned by 'nobody', but this is not recommended.  Other
    programs and daemons may use 'nobody' as a user who should not have
    access to anything; most notably, some NFS implementations use this
    user when somebody connects but fails to authenticate.  Such users
    should not be able to access your mailing lists.  Changing
    'default_privs' to an 'mlmmj' user may open other security holes,
    and may not be appropriate if Postfix is used for other external
    programs besides Mlmmj.

    This leaves us with a conundrum on how to execute the Mlmmj
    executables as an 'mlmmj' user.  One answer is to use a Postfix
    transport.

    First we'll get the 'mlmmj' user setup and then move onto the
    Postfix configuration:

MLMMJ SETUP

    Create a 'mlmmj' user that will own all the lists.  Use whatever
    user creation app/script is provided by your system.  Generally
    'useradd'.

    Create the spool directory that is owned by the 'mlmmj' user.
    This is typically /var/spool/mlmmj but can be any directory so long
    as it is owned by 'mlmmj'.  It can even be the home directory of the
    'mlmmj' user.  If the spool directory is not /var/spool/mlmmj then
    everywhere in this file replace /var/spool/mlmmj with your spool
    directory.

    Create a mailing list using mlmmj-make-ml.  Make sure to use the
    -s flag to set the spool directory if it isn't /var/spool/mlmmj

POSTFIX SETUP

    First thing is to make sure that the postfix server accepts mail for
    the mailing lists.  For a server that handles mail for multiple
    domains, this is done with a 'virtual_alias_map'.  This is how I'll
    demonstrate.

    Add a virtual_alias_map file to main.cf configuration.  We'll use a
    regular expression map since we need to be able to match all the
    various Mlmmj delimiter addresses (list-subscribe, list-unsubscribe,
    confsub-0123456789abcdef, etc.).

        main.cf:
            virtual_alias_maps = hash:/etc/postfix/virtual,
                                 regexp:/var/spool/mlmmj/virtual.regexp

        /var/spool/mlmmj/virtual.regexp:
            /^(mlmmj-test.*)@example\.com$/          ${1}
            /^(another-list.*)@sample\.com$/         ${1}

    One line needs to be in the virtual map for each list the 'mlmmj' id
    is to handle.  The regex formula is:

        /^(list-name.*)@(domain\.com)$/              ${1}

    If you want to host multiple domains in a hierarchical structure,
    you can alternatively use:

        /^(list-name.*)@(domain\.com)$/        domain--${1}

    Next we make sure that Postfix can invoke the mlmmj executables as
    the 'mlmmj' user.  This is where the transport map comes in.  So we
    add a transport map and a configuration option that instructs the
    transport to only deliver one file at a time.  See transport(5) for
    more information on transports.

        main.cf:
            transport_maps = regexp:/var/spool/mlmmj/transport
            mlmmj_destination_recipient_limit = 1

        /var/spool/mlmmj/transport:
            /^(list-test).*$/                        mlmmj:list-test
            /^(another-list).*$/                     mlmmj:another-list

    What this transport file says, is that any message destined for an
    email address that matches the regexp on the left, deliver it using
    the transport 'mlmmj' and setting 'nexthop' to the value in $1.
    Which in this case is the mailing list name.  'nexthop' is special
    variable for transports.

    For the hierarchical multi-domain solution, use this variant:

        /^(domain--list-name).*$/              mlmmj:domain/list-name

    Now we setup the 'mlmmj' transport.  The 'mlmmj' in mlmmj:$1 above
    indicates a transport listed in the Postfix master.cf file.  We are
    just going to create a transport called 'mlmmj' but it is nothing
    more than a pipe(8) to the mlmmj-receive program that is invoked as
    the 'mlmmj' user.

        master.cf:
            # mlmmj mailing lists
            mlmmj   unix  -       n       n       -       -       pipe
                flags=DORhu user=mlmmj argv=/usr/local/bin/mlmmj-receive -F -L /var/spool/mlmmj/$nexthop/

    This takes the pipe(8) Postfix delivery agent and tells it to invoke
    '/usr/local/bin/mlmmj-receive' as the 'mlmmj' user and pipe the
    email to it on stdin.  This mode of transportation is given the name
    'mlmmj'.

    The 'flags' parameter to pipe(8) is pretty critical here. In
    particular if the 'R' option is not used mlmmj-receive fails to
    receive the mail correctly. The options mean:

        D - Prepend a 'Delivered-To: recipient' header
        O - Prepend an 'X-Original-To: recipient' header
        R - Prepend a 'Return-Path:'. header
        h - fold $nexthop to lowercase
        u - fold $recipient to lowercase

    $nexthop gets set to what was on the right had side of the ':' in
    the transport file.  The way we have that configured is that
    $nexthop will get set to the name of the mailing list (or domain
    and name).  Your list directories, then, should be at
    /var/spool/mlmmj/list-name as usual, or for the hierarchical
    multi-domain version, in /var/spool/mlmmj/domain/list-name.

    Restart Postfix and enjoy your new lists.