Inside
sendmail
is the often overlooked
checkcompat
() routine. It has existed since Version 3 and
is intended to allow the site administrator to accept, reject,
and log mail delivery attempts.
Among its uses, and those we will illustrate, are the following:
-
Refuse to act as a mail gateway. Reject any mail that is both
from and to any outside address.
-
Limit the size of guest messages. Screen messages based on
user
uid
, and reject those for the class of users
who are guests when the message is over a specified limit
in bytes.
-
Verify
identd
(8) information. Compare the host information
in
$s
to that in
$_
and log a warning if they
differ.
-
Prune
Received:
headers at a firewall. Make all outgoing
mail appear fresh as it exits the internal network via a firewall.
-
Reject mail from spamming or mail-bombing sites. Look up the
sender in an external database and bounce the message if the
sender is listed as "bad."
The
checkcompat
() routine is located in the file
src/conf.c
.
That file contains comments describing one way to code
checkcompat
().
In this chapter we show you other ways to code it.
The
checkcompat
() routine is inherently "internal,"
meaning that it must understand internal data structures that may
change.
[1]
Since you are modifying source
code, you have to
be prepared to read source code.
In this chapter we offer examples of ways to use
checkcompat
().
Be aware that they are examples only, and you will need C programming
skill to extend them to real-world situations.
The
checkcompat
() routine is called for every delivery attempt
to every recipient. When designing a
checkcompat
() routine
of your own, be aware that a cascade of errors may propagate if
you are not careful with your design. Logging a warning based on the
sender, for example, may result in multiple warnings when there are
multiple recipients.
When
sendmail
prepares to deliver mail, it first checks the
size of the mail message and rejects (bounces) it if it is
larger than the limit imposed by the
M=
delivery agent equate (see
Section 30.4.7, M=
).
V8.8
sendmail
then calls the
check_compat
rule set
(see
Section 29.10.4
).
Next, all versions of
sendmail
call the
checkcompat
()
routine.
The
checkcompat
() routine lies in a unique position within
the
sendmail
code. It is the one place where both the sender and
recipient addresses are available at the same time. Since it precedes
actual delivery, all the information needed for delivery is available
to you for checking.
If
checkcompat
() returns EX_OK,
as defined in
<sysexits.h>
, the mail message is considered
okay and delivered.
Otherwise, the message is bounced.
If you wish the message to be requeued instead of bounced, you
can return EX_TEMPFAIL.
Again note that the
checkcompat
() routine
is called once for each recipient.
The
checkcompat
() is found in the C language source
file
src/conf.c
.
Inside that file you will find it declared like this:
checkcompat(to, e)
register ADDRESS *to;
register ENVELOPE *e;
Here,
to
is a pointer to a structure of
typedef
ADDRESS that contains information about the recipient.
And
e
is a pointer to a structure
(actually a linked list of structures) of
typedef
ENVELOPE that contains information about the current envelope.
The members of the
ADDRESS *to
structure are shown in
Table 20.1
.
Note that these members are correct for V8.8
sendmail
only.
Also note that the table shows only those members that may be
useful in a
checkcompat
() routine (see
sendmail.h
for the other members of
*to
).
Table 20.1: ADDRESS *to Members
Type |
Member |
Description |
char *
|
q_paddr
|
The address in a form suitable for printing |
char *
|
q_user
|
The user part (
$:
) from rule set 0 (see
Section 29.6, "Rule Set 0"
) |
char *
|
q_ruser
|
The login name for this user, if known |
char *
|
q_host
|
The host part (
$@
) from rule set 0 (see
Section 29.6
) |
struct mailer *
|
q_mailer
|
The delivery agent (
$#
) from rule set 0 (see
Section 29.6
) |
u_long
|
q_flags
|
Status flags (see
Section 37.3.1, "The Output Produced by printaddr()"
in
Section 37.3.1
) |
uid_t
|
q_uid
|
The
uid
of the
q_ruser
, if known |
gid_t
|
q_gid
|
The
gid
of the
q_ruser
, if known |
char *
|
q_home
|
The home directory (path), if delivery is local |
char *
|
q_fullname
|
The (gecos) full name of
q_ruser
, if known |
struct address *
|
q_next
|
Link to the next ADDRESS in the chain |
struct address *
|
q_alias
|
The alias that yielded this address |
char *
|
q_owner
|
The owner of
q_alias
|
The members of the
ENVELOPE *e
structure are shown in
Table 20.2
.
Note that these members are correct for V8.8
sendmail
only.
Also note that the table shows only those members that may be
useful in a
checkcompat
() routine (see
sendmail.h
for other members of
*e
).
Table 20.2: ENVELOPE *e Members
Type |
Member |
Description |
HDR *
|
e_header
|
Linked list of headers |
time_t
|
e_ctime
|
Time message first placed into the queue |
ADDRESS
|
e_from
|
The sender |
ADDRESS *
|
e_sendqueue
|
Linked list of recipients |
long
|
e_msgsize
|
Size of the message in bytes |
long
|
e_flags
|
Envelope flags (see
Table 37.3
in
Section 37.5.12, -d2.1
) |
int
|
e_nrcpts
|
Number of recipients |
short
|
e_hopcount
|
The hop count for the message |
The
checkcompat
() routine is a powerful internal hook inside
sendmail
. It is so internal and powerful, in fact, that if
you are truly clever, you can even use
checkcompat
() to
modify rewrite rules at runtime (scary but possible).
Over 100 global variables are used by V8.8
sendmail
. They are all
listed in
sendmail.h
and
conf.c
with "lite" comments.
Global variables store information such as
sendmail
's option values,
file descriptor values, macro values, class lists,
and database access information.
Any can be modified inside
checkcompat
(), but before
attempting to do so, study the
sendmail
C source code
to anticipate any unexpected side effects.
In general, you can use almost any of the global variables
when designing your own
checkcompat
() routine.
The four most interesting are the following:
-
RealHostAddr
-
The IP address of the sending host.
This is a union of several
sockaddr_
types depending on your selection of protocol type.
This can be zero for locally submitted mail.
-
RealHostName
-
A string containing the definitive canonical name of the sending host.
If it can't be resolved to a name, it will contain
the host's IP number in text form, surrounded by square brackets.
-
LogLevel
-
This variable determines the amount of logging that
sendmail
does.
It is initially set with the
LogLevel
(
L
) option (see
Section 34.8.33, LogLevel (L)
).
You might want to use
checkcompat
() to detect questionable
connections and, if any are detected, to increase the value in
LogLevel
to 12. This will cause
both sides of every subsequent SMTP connection to be logged.
-
MatchGecos
-
Whether or not unmatched local looking names are looked up in the
passwd
(5)
file is under the control of the
MatchGECOS
(
G
) option
(see
Section 34.8.34, MatchGECOS (G)
). Because this kind of lookup is expensive, you
might wish to enable it only during nonbusiness hours. One way to do this
would be by modifying the
MatchGecos
variable inside
checkcompat
().
|