Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<title>Postfix Per-Client/User/etc. Access Control</title>

<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">

</head>

<body>

<h1><img src="postfix-logo.jpg" width="203" height="98" ALT="">Postfix
Per-Client/User/etc. Access Control</h1>

<hr>

<h2>Postfix restriction classes</h2>

<p> The Postfix SMTP server supports access restrictions such as
<a href="postconf.5.html#reject_rbl_client">reject_rbl_client</a> or <a href="postconf.5.html#reject_unknown_client_hostname">reject_unknown_client_hostname</a> on the right-hand side
of SMTP server <a href="access.5.html">access(5)</a> tables. This allows you to implement
different junk mail restrictions for different clients or users.
</p>

<p> Having to specify lists of access restrictions for every
recipient becomes tedious quickly. Postfix restriction classes
allow you to give easy-to-remember names to groups of UCE restrictions
(such as "permissive", "restrictive", and so on). </p>

<p> The real reason for the existence of Postfix restriction classes
is more mundane:  you can't specify a lookup table on the right-hand
side of a Postfix access table. This is because Postfix needs to
open lookup tables ahead of time, but the reader probably does not
care about these low-level details. </p>

<p> Example: </p>

<blockquote>
<pre>
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
    <a href="postconf.5.html#smtpd_restriction_classes">smtpd_restriction_classes</a> = restrictive, permissive
    # With Postfix &lt; 2.3 specify <a href="postconf.5.html#reject_unknown_client_hostname">reject_unknown_client</a>.
    restrictive = <a href="postconf.5.html#reject_unknown_sender_domain">reject_unknown_sender_domain</a> <a href="postconf.5.html#reject_unknown_client_hostname">reject_unknown_client_hostname</a> ...
    permissive = permit

    <a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a> = 
        <a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a>
        # <a href="postconf.5.html#reject_unauth_destination">reject_unauth_destination</a> is not needed here if the mail
        # relay policy is specified with <a href="postconf.5.html#smtpd_relay_restrictions">smtpd_relay_restrictions</a>
        # (available with Postfix 2.10 and later).
        <a href="postconf.5.html#reject_unauth_destination">reject_unauth_destination</a>
        <a href="postconf.5.html#check_recipient_access">check_recipient_access</a> <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/recipient_access
        ...

/etc/postfix/recipient_access:
    joe@my.domain       permissive
    jane@my.domain      restrictive
</pre>
</blockquote>

<p> With this in place, you can use "restrictive" or "permissive"
on the right-hand side of your per-client, helo, sender, or recipient
SMTPD access tables. </p>

<p> The remainder of this document gives examples of how Postfix
access restriction classes can be used to: </p>

<ul>

<li> <a href="#internal"> Shield an internal mailing list from
outside posters</a>,

<li> <a href="#external"> Prevent external access by internal
senders</a>.

</ul>

<p> These questions come up frequently, and the examples hopefully
make clear that Postfix restriction classes aren't really the right
solution. They should be used for what they were designed to do,
different junk mail restrictions for different clients or users.
</p>

<h2><a name="internal">Protecting internal email distribution
lists</a></h2>

<blockquote>

<p> We want to implement an internal email distribution list.
Something like all@our.domain.com, which aliases to all employees.
My first thought was to use the aliases map, but that would lead
to "all" being accessible from the "outside", and this is not
desired...  :-) </p>

</blockquote>

<p> Postfix can implement per-address access controls.  What follows
is based on the SMTP client IP address, and therefore is subject
to IP spoofing. </p>

<blockquote>
<pre>
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
    <a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a> =
        ...
        <a href="postconf.5.html#check_recipient_access">check_recipient_access</a> <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/access
        <i>...the usual stuff...</i>

/etc/postfix/access:
    all@my.domain   <a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a>,reject
    all@my.hostname <a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a>,reject
</pre>
</blockquote>

<p> Specify <b>dbm</b> instead of <b>hash</b> if your system uses
<b>dbm</b> files instead of <b>db</b> files. To find out what map
types Postfix supports, use the command <b>postconf -m</b>. </p>

<p> Now, that would be sufficient when your machine receives all
Internet mail directly from the Internet.  That's unlikely if your
network is a bit larger than an office. For example, your backup
MX hosts would "launder" the client IP address of mail from the
outside so it would appear to come from a trusted machine. </p>

<p> In the general case you need two lookup tables: one table that
lists destinations that need to be protected, and one table that
lists domains that are allowed to send to the protected destinations.
</p>

<p> What follows is based on the sender SMTP envelope address, and
therefore is subject to SMTP sender spoofing. </p>

<blockquote>
<pre>
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
    <a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a> =
        ...
        <a href="postconf.5.html#check_recipient_access">check_recipient_access</a> <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/protected_destinations
        <i>...the usual stuff...</i>

    <a href="postconf.5.html#smtpd_restriction_classes">smtpd_restriction_classes</a> = insiders_only
    insiders_only = <a href="postconf.5.html#check_sender_access">check_sender_access</a> <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/insiders, reject

/etc/postfix/protected_destinations:
    all@my.domain   insiders_only
    all@my.hostname insiders_only

/etc/postfix/insiders:
    my.domain       OK  <i>matches my.domain and subdomains</i>
    another.domain  OK  <i>matches another.domain and subdomains</i>
</pre>
</blockquote>

<p> Getting past this scheme is relatively easy, because all one
has to do is to spoof the SMTP sender address. </p>

<p> If the internal list is a low-volume one, perhaps it makes more
sense to make it moderated. </p>

<h2><a name="external">Restricting what users can send mail to
off-site destinations</a></h2>

<blockquote>

<p> How can I configure Postfix in a way that some users can send
mail to the internet and other users not. The users with no access
should receive a generic bounce message. Please don't discuss
whether such access restrictions are necessary, it was not my
decision. </p>

</blockquote>

<p> Postfix has support for per-user restrictions.  The restrictions
are implemented by the SMTP server. Thus, users that violate the
policy have their mail rejected by the SMTP server.  Like this:
</p>

<blockquote>
<pre>
554 &lt;user@remote&gt;: Access denied
</pre>
</blockquote>

<p> The implementation uses two lookup tables. One table defines
what users are restricted in where they can send mail, and the
other table defines what destinations are local. It is left as an
exercise for the reader to change this into a scheme where only
some users have permission to send mail to off-site destinations,
and where most users are restricted. </p>

<p> The example assumes DB/DBM files, but this could also be done
with LDAP or SQL. </p>

<blockquote>
<pre>
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
    <a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a> =
        ...
        <a href="postconf.5.html#check_sender_access">check_sender_access</a> <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/restricted_senders
        <i>...other stuff...</i>

    <a href="postconf.5.html#smtpd_restriction_classes">smtpd_restriction_classes</a> = local_only
    local_only = 
        <a href="postconf.5.html#check_recipient_access">check_recipient_access</a> <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/local_domains, reject

/etc/postfix/restricted_senders:
    foo@domain      local_only
    bar@domain      local_only

/etc/postfix/local_domains:
    this.domain     OK      <i>matches this.domain and subdomains</i>
    that.domain     OK      <i>matches that.domain and subdomains</i>
</pre>
</blockquote>

<p> Specify <b>dbm</b> instead of <b>hash</b> if your system uses
<b>dbm</b> files instead of <b>db</b> files. To find out what map
types Postfix supports, use the command <b>postconf -m</b>. </p>

<p> Note: this scheme does not authenticate the user, and therefore it can be
bypassed in several ways: </p>

<ul>

<li> <p> By sending mail via a less restrictive mail
<a href="postconf.5.html#relayhost">relay host</a>. </p>

<li> <p> By sending mail as someone else who does have permission
to send mail to off-site destinations. </p>

</ul>

</body>

</html>