Enabling SASL without any authentication back-end for use with XCLIENT only

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Enabling SASL without any authentication back-end for use with XCLIENT only

Melvin Vermeeren
Hi all,

Recent version of dovecot come with a submission server (MSA), which allows
for simpler configuration and adds BURL support, avoiding the need for the
client to upload the mail twice: once to IMAP, once to the MSA.
See also: https://doc.dovecot.org/admin_manual/submission_server/

This means the postfix configuration can be rather simple as the SASL binding
to dovecot is no longer needed. Postfix only runs on the usual port 25 and
just relays the mail coming from localhost via dovecot's MSA.

Now what I want to do is limit each user to mailing from his own mail address.
Dovecot's MSA is still very primitive, so this is to be handled in postfix.
This at first sight seems simple. Use XCLIENT so postfix gets full client
details, including SASL username. Then use the standard sender restrictions
and sender login maps. I add to main.cf:
> smtpd_authorized_xclient_hosts = $mynetworks
> smtpd_sender_restrictions = reject_sender_login_mismatch
> smtpd_sender_login_maps = regexp:/etc/postfix/senders

In the dovecot MSA I need to enable XCLIENT, so there I set:
> submission_relay_trusted = yes

Straightforward so far, but this configuration will not work:
> connect from localhost[127.0.0.1]
> warning: restriction `reject_authenticated_sender_login_mismatch' ignored:
> no SASL support
> warning: restriction `reject_unauthenticated_sender_login_mismatch' ignored:
> no SASL support
> MSG_ID: client=localhost[REAL_IPv6_HERE], sasl_method=XCLIENT,
> sasl_username=[hidden email]

Of course, SASL needs to be enabled. But here comes the problem: How does one
enable SASL **without** configuring any form of authentication back-end? In
other words: How to enable SASL for XCLIENT and only XCLIENT?

I checked all of the available options but it appears that an authentication
back-end is required, even though this is not needed when using XCLIENT as
dovecot MSA is responsible for authentication here. In the end setting:
> smtpd_sasl_auth_enable = yes

Means you also have to set "smtpd_sasl_type" to one of the available values,
which is either "cyrus" or "dovecot". This then implies having to actually
properly configure the back-end, or you will get errors such as:
> warning: xsasl_cyrus_server_get_mechanism_list: no applicable SASL
> mechanisms
> fatal: no SASL authentication mechanisms

Am I misunderstanding how XCLIENT is supposed to work or is this specific
configuration currently not possible? I would have expected something such as
"smtpd_sasl_type = xclient" would exist, but it seems like it doesn't.

Thanks,

Melvin.

signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Enabling SASL without any authentication back-end for use with XCLIENT only

Wietse Venema
Melvin Vermeeren:
> > connect from localhost[127.0.0.1]
> > warning: restriction `reject_authenticated_sender_login_mismatch' ignored:
> > no SASL support

This means that Postfix is built without any SASL support,
or that you have "smtpd_sasl_enable=no".

        Wietse

Code sample:

#ifdef USE_SASL_AUTH
        } else if (is_map_command(state, name, CHECK_SASL_ACL, &cpp)) {
            if (var_smtpd_sasl_enable) {
                if (state->sasl_username && state->sasl_username[0])
                    status = check_sasl_access(state, *cpp, def_acl);
            } else
#endif
                msg_warn("restriction `%s' ignored: no SASL support", name);
        } else ...
Reply | Threaded
Open this post in threaded view
|

Re: Enabling SASL without any authentication back-end for use with XCLIENT only

Melvin Vermeeren
On Saturday, 21 March 2020 15:59:45 CET Wietse Venema wrote:

> Melvin Vermeeren:
> > > connect from localhost[127.0.0.1]
> > > warning: restriction `reject_authenticated_sender_login_mismatch'
> > > ignored:
> > > no SASL support
>
> This means that Postfix is built without any SASL support,
> or that you have "smtpd_sasl_enable=no".
>
> Wietse
>
> Code sample:
>
> #ifdef USE_SASL_AUTH
>         } else if (is_map_command(state, name, CHECK_SASL_ACL, &cpp)) {
>             if (var_smtpd_sasl_enable) {
>                 if (state->sasl_username && state->sasl_username[0])
>                     status = check_sasl_access(state, *cpp, def_acl);
>             } else
> #endif
>                 msg_warn("restriction `%s' ignored: no SASL support", name);
> } else ...
Assuming "smtpd_sasl_enable" is the same as "smtpd_sasl_auth_enable" (current
docs only have the latter) I came to the same conclusion initially, I also
grepped the source code and indeed saw the logic in the code sample given.

Note that the initial mail continues after this observation and
"smtpd_sasl_auth_enable" is set to "yes". Only after that change does the real
problem come to light, which is what the initial mail really is about.

To be specific the problem is that it appears impossible to enable SASL
without configuring a real, working, authentication back-end, which is not
needed if only XCLIENT-style SASL is used I believe.

Thanks,

Melvin.

signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Enabling SASL without any authentication back-end for use with XCLIENT only

Wietse Venema
Melvin Vermeeren:
> To be specific the problem is that it appears impossible to enable SASL
> without configuring a real, working, authentication back-end, which is not
> needed if only XCLIENT-style SASL is used I believe.

By default, Postfix has

    smtpd_sasl_type = cyrus

Why don't you set

    smtpd_sasl_type = dovecot

and follow SASL_README instructions to configure Postfix as if it
will use Dovecot?

The only interaction betweeen Postfix and Dovecot is to get a list
of authentication mechanisms, which Postfix wlll never use. I think
that is a small sacrifice to make if you want to use Postfix in a
manner that has never been tried before.

        Wietse
Reply | Threaded
Open this post in threaded view
|

Re: Enabling SASL without any authentication back-end for use with XCLIENT only

Wietse Venema
Wietse Venema:

> Melvin Vermeeren:
> > To be specific the problem is that it appears impossible to enable SASL
> > without configuring a real, working, authentication back-end, which is not
> > needed if only XCLIENT-style SASL is used I believe.
>
> By default, Postfix has
>
>     smtpd_sasl_type = cyrus
>
> Why don't you set
>
>     smtpd_sasl_type = dovecot
>
> and follow SASL_README instructions to configure Postfix as if it
> will use Dovecot?
>
> The only interaction betweeen Postfix and Dovecot is to get a list
> of authentication mechanisms, which Postfix wlll never use. I think
> that is a small sacrifice to make if you want to use Postfix in a
> manner that has never been tried before.

If you have the resources to build Postfix from source code, then
we can consider experiments with careful changes to the source to
relax the requirement that smtpd_sasl_auth_enable=yes.

We cannot simply remove the "if (var_smtpd_sasl_emable != 0)" check
from all Postfix code, as that would likely result in segmentation
faults in randomi places.

        Wietse
Reply | Threaded
Open this post in threaded view
|

Re: Enabling SASL without any authentication back-end for use with XCLIENT only

Melvin Vermeeren
Wietse Venema:

> Wietse Venema:
> > Melvin Vermeeren:
> > > To be specific the problem is that it appears impossible to enable SASL
> > > without configuring a real, working, authentication back-end, which is
> > > not
> > > needed if only XCLIENT-style SASL is used I believe.
> >
> > By default, Postfix has
> >
> >     smtpd_sasl_type = cyrus
> >
> > Why don't you set
> >
> >     smtpd_sasl_type = dovecot
> >
> > and follow SASL_README instructions to configure Postfix as if it
> > will use Dovecot?
> >
> > The only interaction betweeen Postfix and Dovecot is to get a list
> > of authentication mechanisms, which Postfix wlll never use. I think
> > that is a small sacrifice to make if you want to use Postfix in a
> > manner that has never been tried before.
Yeah, this was what I would have done if I could not find another way to do
things. I was just thinking that technically speaking such configuration
should not be necessary with XCLIENT, which is why I mailed initially.

> If you have the resources to build Postfix from source code, then
> we can consider experiments with careful changes to the source to
> relax the requirement that smtpd_sasl_auth_enable=yes.
>
> We cannot simply remove the "if (var_smtpd_sasl_emable != 0)" check
> from all Postfix code, as that would likely result in segmentation
> faults in randomi places.

Sure, I can build it from source and/or patch the version I currently use,
which is 3.4.8 on Debian. Patches would be preferred to minimise the changes.
Not very familiar with Postfix sources, though they are easy to read.

In src/smtpd/smtpd_state.c I found the following which interested me:

    /*
     * Minimal initialization to support external authentication (e.g.,
     * XCLIENT) without having to enable SASL in main.cf.
     */
#ifdef USE_SASL_AUTH
    if (SMTPD_STAND_ALONE(state))
        var_smtpd_sasl_enable = 0;
    smtpd_sasl_set_inactive(state);
    smtpd_sasl_state_init(state);
#endif

Likewise, in src/smtpd/smtpd_sasl_glue.c:

void    smtpd_sasl_state_init(SMTPD_STATE *state)
{
    /* Initialization to support external authentication (e.g., XCLIENT). */
    state->sasl_username = 0;
    state->sasl_method = 0;
    state->sasl_sender = 0;
}

Just a wild guess: I get the feeling smtpd_check.c is relatively stand-alone
and doesn't really need SASL to be enabled, since it always performs safety
checks on the actual data such as:

if (state->sasl_username && state->sasl_username[0])

In src/smtpd/smtpd.c I notice there is "real" SASL logic going on, so it makes
sense to be wary here and not touch things unless needed.

The thing is, since we only want XCLIENT "SASL" sender checks, and not offer
actual authentication (AUTH), it would be best if smtpd_sasl_auth_enable
remained off and the checks will just automagically use the variables if set,
which is then only the case if XCLIENT is used, right?

SASL support would still need to be compiled in because #ifdef USE_SASL_AUTH
is used in many places, but I think this isn't a concern in practice.

In conclusion I believe "var_smtpd_sasl_enable" can be removed from src/smtpd/
smtpd_check.c completely, together with the "if (var_smtpd_sasl_enable)"
conditionals. Could you post your thoughts on this?

Thanks again,

Melvin.

signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Enabling SASL without any authentication back-end for use with XCLIENT only

Wietse Venema
Melvin Vermeeren:
> In conclusion I believe "var_smtpd_sasl_enable" can be removed from src/smtpd/
> smtpd_check.c completely, together with the "if (var_smtpd_sasl_enable)"
> conditionals. Could you post your thoughts on this?

You can try that. But your argument has holes because there is code
like this:

        if (state->sasl_enabled && state->sasl_enabled[0]) {
            do_something_with_state(state, *cpp, def_acl);

where do_something_with_state() may access state->sasl_mechanism
or state->sasl_sender which will not contain the expected values
that they would have gotten from a real SASL backend.

Therefore every such function will need guards like:

    if (state->sasl_mechanism && state->sasl_mechanism[0])
        do_something_with_sasl_mechanism

Some guards may already exist, but this will have to be verified
exhaustively for every function.

        Wietse
Reply | Threaded
Open this post in threaded view
|

Re: Enabling SASL without any authentication back-end for use with XCLIENT only

Melvin Vermeeren
Wietse Venema:

> Melvin Vermeeren:
> > In conclusion I believe "var_smtpd_sasl_enable" can be removed from
> > src/smtpd/ smtpd_check.c completely, together with the "if
> > (var_smtpd_sasl_enable)" conditionals. Could you post your thoughts on
> > this?
>
> You can try that. But your argument has holes because there is code
> like this:
>
> if (state->sasl_enabled && state->sasl_enabled[0]) {
>    do_something_with_state(state, *cpp, def_acl);
>
> where do_something_with_state() may access state->sasl_mechanism
> or state->sasl_sender which will not contain the expected values
> that they would have gotten from a real SASL backend.
>
> Therefore every such function will need guards like:
>
>     if (state->sasl_mechanism && state->sasl_mechanism[0])
> do_something_with_sasl_mechanism
>
> Some guards may already exist, but this will have to be verified
> exhaustively for every function.
In postfix-3.6-20200316 src/smtpd/smtpd_check.c currently four
if(var_smtpd_sasl_enable) exist. After those checks additional checks are
performed, one of:

a. if (state->sasl_username && state->sasl_username[0])
b. if (state->sender && *state->sender)

Once those pass at least one of the following three functions is invoked:

1. check_sasl_access(), after a.
2. reject_auth_sender_login_mismatch(), after b.
3. reject_unauth_sender_login_mismatch(), after b.

1. seems to map directly to a check_access() call, which appears to only
lookup things in the configured tables.
2. appears to only lookup things in the sender login maps.
3. is similar to 2, but does an even simpler lookup in the sender login maps.

Of these three, check_sasl_access() is the only one that that does not check
state->sasl_username formally, instead it is checked where it is called. I
would be surprised if any of the check/table logic did modify SASL state, so I
believe things are safe as is.

Note that only smtpd_check.c needs modification. I will try to write a simple
patch within the next few days and do some testing, will keep you up-to-date.
Thanks for the info so far.

Melvin.

signature.asc (849 bytes) Download Attachment