For safety and efficiency, sendmail undertakes a complicated series of steps to run (execute) a delivery agent. [14] Some (such as setting the environment) are intended to improve security. Others (such as forking) are intended to improve efficiency by creating parallel actions. Here, we discuss those steps in the order in which they are taken by sendmail .
[14] For the purpose of this discussion we will exclude the internal agents (such as IPC) and focus on actual programs (such as /bin/mail ).
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 (see Section 34.8.76, Verbose ), it shows that it is about to start this process:
Connecting to delivery agent
If a traffic-logging file was specified with
-X
command-line switch (see
Section 26.4, "Log Transactions with -X"
),
sendmail
appends the following line to that file:
pid === EXEC the expanded A= here
Here, the
A=
equate (see
Section 30.4.1
) from the delivery agent's declaration is printed with all its 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 (see
Section 37.5.44, -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.
The child is the copy of sendmail that will transform into the delivery agent. But before the child can transform, it must perform a few more necessary steps.
If sendmail was compiled with HASSETUSERCONTEXT defined (see Section 18.8.9, HAS... ), it calls setusercontext (3) like this:
setusercontext(NULL,pwd
,uid
, LOGIN_SETRESOURCES|LOGIN_SETPRIORITY);
Here,
pwd
is a pointer to a structure of type
passwd
for the user whose
uid
is
uid
. The
uid
is that of the controlling user (see
Section 24.2.2, "Delivery to Files"
) or the recipient (see
Section 30.8.33, F=o
).
If the
N=
equate (see
Section 30.4.8
) has a nonzero value,
sendmail
calls
nice
(3) to "re-nice" the delivery agent to that value.
The
sendmail
program next sets its
uid
and
gid
as appropriate. If the
DontInitGroups
option (see
Section 34.8.19, DontInitGroups
) is false,
sendmail
calls
initgroups
(3). The identity used is that described under the
DefaultUser
option (see
Section 34.8.15
).
Next
sendmail
attempts to
chdir
(2) into one of the directories listed in the
D=
equate (see
Section 30.4.3
). This process can be watched with the
-d11.20
debugging switch (see
Section 37.5.46
).
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=
equate (see
Section 30.4.9
). The argument vector (contents of the
A=
equate with all the 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 (see
Section 22.2.1
).