20.6 How a Delivery Agent Is Executed
For safety and efficiency, sendmail undertakes a
complicated series of steps to run (execute) a delivery
agent.
Some (such as setting the environment) are intended to improve
security. Others (such as forking) are required so that
sendmail can launch delivery agents.
Here, we discuss those steps in the order in which they
are taken by sendmail.
20.6.1 The Fork
When
sendmail performs delivery, it cannot simply
replace itself with the delivery agent program. Instead, it must
fork(2), and the child will replace itself.
If sendmail is running in verbose mode (Verbose), it shows that it is about to start this
process:
Connecting to delivery agent
If a traffic-logging file was specified with the
-X command-line switch (Section 14.2), sendmail appends the
following line to that file:
pid = == EXEC the expanded A= here
Here, the A= delivery agent equate (A=) from the delivery agent's
declaration is printed with all its sendmail
macros expanded and with the recipients listed.
Next sendmail creates a
pipe so that it will be able to print the email
message to the delivery agent and so that it can read errors emitted
by the delivery agent. See the -d11 debugging
switch (-d11.1) for a description of what can
go wrong.
If all has gone well, sendmail
fork(2)s a copy of itself. The parent then pipes
the email message to the child.
When the entire message has been sent, the parent then
wait(3)s for the child to complete its work and
exit(2)s. The parent collects the
exit(2) value from the child and determines
delivery success based on that exit value.
20.6.2 The Child
The
child is the copy of sendmail that will
transform into the delivery agent. Before the child can transform, it
must perform a few more necessary steps.
If sendmail was compiled with HASSETUSERCONTEXT
defined (HAS...), it calls
setusercontext(3) like this:
setusercontext(NULL, pwd, user-id, LOGIN_SETRESOURCES|LOGIN_SETPRIORITY);
Here, pwd is a pointer to a structure of
type passwd for the user whose
user-id is user-id.
The user-id is that of the controlling
user (Section 12.2.2) or the recipient (F=o).
The sendmail program next sets its
group-id as appropriate. If the
DontInitGroups option (DontInitGroups) is false, sendmail calls
initgroups(3). The group identity used is that
described under the DefaultUser option (DefaultUser).
If the /= delivery agent equate (/= (forward slash)) has a non-NULL value,
sendmail calls chroot(8) to
change its topmost directory into a private directory tree.
If the N= delivery agent equate (N=) has a nonzero value,
sendmail calls nice(3) to
"re-nice" the delivery agent to
that value.
The sendmail program then sets its
user-id. The user identity used is chosen by the
mailer F=S and U= equates and
the DefaultUser option as detailed in DefaultUser.
The sendmail program then attempts to
chdir(2) into one of the directories listed in
the D= delivery agent equate (D=).
Next, sendmail dup(2)s the
pipes created in the previous section.
Finally, sendmail calls
setsid(2) to become a process-group leader and
execve(2) to become the delivery agent. That
latter call looks like this:
execve(agent, argv, envp);
Here, agent is the full path of the
delivery agent as specified in the P= delivery
agent equate (P=). The argument vector
(contents of the A= delivery agent equate with all
the sendmail macros expanded and all the
recipients added) is passed as argv. The
environment is that originally given to
sendmail, massaged for security and augmented by
the E configuration command (Section 10.2.1).
If the execve(2) fails, the child exits with an
appropriate error code.
|