One very common use of wrapper scripts is as security
wrappers. A security script may call a gatekeeper program
to check some sort of credential, then conditionally execute another
based on the status value returned by the gatekeeper.
Bernstein chaining is a specialized security-wrapper technique
first invented by Daniel J. Bernstein, who has employed it in a number
of his packages. (A similar pattern appears in commands like
nohup(1)
and
su(1),
but the conditionality is absent.) Conceptually, a Bernstein chain is
like a pipeline, but
each successive stage replaces the previous one rather than running
concurrently with it.
The usual application is to confine security-privileged
applications to some sort of gatekeeper program, which can then hand
state to a less privileged one. The technique pastes several programs
together using execs, or possibly a combination of forks and
execs. The programs are all named on one command line. Each program
performs some function and (if successful) runs
exec(2)
on the rest of its command line.
Bernstein's rblsmtpd package is a
prototypical example. It serves to look up a host in the anti-spam DNS
zone of the Mail Abuse Prevention System. It does this by doing a DNS
query on the IP address passed into it in the
TCPREMOTEIP environment variable. If the query is
successful, then rblsmtpd runs its own SMTP
that discards the mail. Otherwise the remaining command-line arguments
are presumed to constitute a mail transport agent that knows the SMTP
protocol, and are handed to
exec(2)
to be run.
Another example may be found in Bernstein's
qmail package. It contains a program called
condredirect. The first parameter is an
email address, and the remainder a gatekeeper program and
arguments. Condredirect forks and execs the
gatekeeper with its arguments. If the gatekkeper exits successfully,
condredirect forwards the email
pending on stdin to the specified email address. In this case,
opposite to that of rblsmtpd, the security
decision is made by the child; this case is a bit more like a
classical shellout.
A more elaborate example is the qmail
POP3 server. It consists of three programs,
qmail-popup,
checkpassword and
qmail-pop3d.
Checkpassword comes from a separate package
cleverly called checkpassword, and
unsurprisingly it checks the password. The POP3 protocol has an
authentication phase and mailbox phase; once you enter the mailbox
phase you cannot go back to the authentication phase. This is a
perfect application for Bernstein chaining.
The first parameter of qmail-popup is
the hostname to use in the POP3 prompts. The rest of its parameters
are forked and execed, after the POP3 username and password have been
fetched. If the program returns failure, the password must be wrong,
so qmail-popup reports that and waits for a
different password. Otherwise, the program is presumed to have
finished the POP3 conversation, so qmail-popup exits.
The program named on qmail-popup's
command line is expected to read three null-terminated strings from
file descriptor 3
[53]. These are the username, password, and response to
a cryptographic challenge, if any. This time it's
checkpassword which accepts as parameters
the name of qmail-pop3d and its
parameters. The checkpassword program exits
with failure if the password does not match; otherwise it changes to
the user's uid, gid, and home directory, and executes the rest of its
command line on behalf of that user.
Bernstein chaining is useful for situations in which the
application needs setuid or setgid privileges to initialize a
connection, or acquire some credential, and then drop those privileges
so that following code does not have to be trusted. Following the
exec, the child program cannot setreuid back to root. It's also more
flexible than a single process, because you can modify the behavior of
the system by inserting another program into the chain.
For example, rblsmtpd (mentioned
above) can be inserted into a Bernstein chain, in between tcpserver
(from the ucspi-tcp package) and the real
SMTP server, typically
qmail-smtpd. However, it works with
inetd(8)
and sendmail -bs as well.