70.1.13. pepsi-stage-dot-forward¶
process per-user ~/.forward files
- Manual section:
1
70.1.13.1.1. Name¶
pepsi-stage-dot-forward - the ~/.forward processing stage of the Pepsi pipeline.
70.1.13.1.2. Synopsis¶
pepsi-stage-dot-forward [GLOBAL-OPTIONS] worker
70.1.13.1.3. Description¶
pepsi-stage-dot-forward is a stage program run by pepsi-dispatch(1).
For each envelope recipient that resolves to a local account it runs that
user’s ~/.forward file — the classic sendmail/Postfix mechanism by which an
account owner redirects their own mail. Locality is decided exactly as in
pepsi-stage-relay-to-maildir(1): the recipient’s domain must be in
LOCAL_DOMAINS, its mailbox name (local-part, sub-address after
RECIPIENT_DELIMITER removed, lower-cased) must resolve to a passwd entry, and
that uid must be permitted by TARGETS. A recipient that is not local is left
untouched and advances to NEXT_STAGE.
The ~/.forward itself is read and executed by the privileged helper
pepsi-helper-dot-forward(1), which drops to the target user first. The
helper’s exit status tells the stage what became of that recipient:
no ~/.forward — the recipient is a passthrough: it stays on the message, which advances to NEXT_STAGE (typically local delivery, then a smarthost).
forwarded — the recipient is replaced by the addresses the
~/.forwardnamed. Those restart the pipeline at RESTART_STAGE (defaultinit) on a newpendingsibling row, so the rewritten recipients are re-authenticated and re-routed like fresh mail. An empty address list (the message was consumed entirely by|pipe//filedirectives) simply drops the recipient.failed — running the
~/.forwardfailed (a pipe command exited non-zero, a file could not be written, or a disabled directive was requested); the recipient is routed to BOUNCE_STAGE so a failure DSN is generated (honouring the sender’sNOTIFY). A message that is itself a bounce (null sender) is never re-bounced.
A single message may have a mix of these outcomes across its recipients; the forwarded addresses, the per-recipient bounces and the kept (passthrough) recipients are reconciled atomically in one database round-trip.
70.1.13.1.4. Forwarding loops¶
Because a forwarded message restarts the whole pipeline, two users forwarding to
each other (~bob → alice, ~alice → bob) would loop. To prevent
this the stage records every login whose ~/.forward it has run in the
message’s state["dot-forwarders"] array (see pepsi.state(7)). A
recipient whose user is already listed there is dropped without calling the
helper (a warning is logged), so the chain terminates: the offending copy is
discarded, and a message left with no recipients is deleted.
70.1.13.1.5. Arguments and sub-commands¶
- worker
Run as a persistent pepsi-dispatch(1) worker, reading message ids on standard input and writing one status line each. This is how the dispatcher runs the stage in production.
70.1.13.1.6. Configuration¶
Read from the message’s [stage-<stage>] section:
- PROGRAM
Must be
pepsi-stage-dot-forward.- RESTART_STAGE
The stage a successfully forwarded message restarts at. Defaults to
init(re-running the full inbound pipeline, including authentication). Set it to a later stage (e.g.srs) to skip re-authenticating an internally forwarded message. Must name an existing stage.- ALLOW_PIPE
Whether
|commanddirectives in a~/.forwardare honoured (the message is piped to the command, run as the user). Defaults toyes.- ALLOW_FILE
Whether
/pathdirectives (append the message to a file) are honoured. Defaults toyes. When both ALLOW_PIPE and ALLOW_FILE arenothe stage does not pipe the message body to the helper at all (the helper only needs to read forwarding addresses).- TARGETS, LOCAL_DOMAINS, RECIPIENT_DELIMITER
The local-account selection, identical in meaning to pepsi-stage-relay-to-maildir(1). TARGETS defaults to the regular (non-system) uid range from
/etc/login.defs; LOCAL_DOMAINS defaults to[pepsi-ingress] ACCEPTED_DOMAINS; RECIPIENT_DELIMITER defaults to+(nonedisables sub-address stripping).- HELPER
The privileged
~/.forwardhelper to run. Defaults topepsi-helper-dot-forward(resolved on$PATH); set an absolute path to override.- NEXT_STAGE
Where passthrough recipients (no
~/.forward) advance. Required, since most recipients have no~/.forward. The stage is normally placed just before local delivery, so NEXT_STAGE is the local-delivery stage.- BOUNCE_STAGE
The DSN-generation stage a recipient is routed to when its
~/.forwardexecution fails.
70.1.13.1.7. A ~/.forward file¶
The helper interprets each non-empty, non-comment (#) line of the user’s
~/.forward as one of:
an e-mail address — collected and used as a new recipient (a leading
\is stripped);|command— when ALLOW_PIPE is on, the message is piped to/bin/sh -c commandrun as the user;/absolute/path— when ALLOW_FILE is on, the message is appended to that file (mbox style) as the user.
Forwarding addresses should be fully qualified (user@domain); a bare local
name is returned verbatim and may not re-resolve as local.
70.1.13.1.8. Installation and privileges¶
To reach the setuid-root helper, pepsi-stage-dot-forward must itself be
installed set-group-id to the pepsi-forward group (mode 2755, owner
root:pepsi-forward). pepsi-dispatch(1) runs the stage as the
unprivileged pepsi service user; the setgid bit gives the worker an effective
gid of pepsi-forward, which is exactly what lets it execute the
group-restricted pepsi-helper-dot-forward(1) — and nothing else on the host
gains that ability. make install sets this up (its install-forward-stage
step), provided it is run as root and the pepsi-forward group exists;
otherwise it prints the exact commands to run by hand.
70.1.13.1.9. See Also¶
pepsi-helper-dot-forward(1), pepsi-stage-relay-to-maildir(1), pepsi-stage-aliases(1), pepsi-stage-bounce(1), pepsi-dispatch(1), pepsi.conf(5), pepsi.state(7)
70.1.13.1.10. Bugs¶
Report bugs to the Pepsi issue tracker.