7 /* Postfix SASL interface for SMTP client
9 /* #include smtp_sasl.h
11 /* void smtp_sasl_helo_auth(state, words)
15 /* int smtp_sasl_helo_login(state)
18 /* This module contains random chunks of code that implement
19 /* the SMTP protocol interface for SASL negotiation. The goal
20 /* is to reduce clutter in the main SMTP client source code.
22 /* smtp_sasl_helo_auth() processes the AUTH option in the
23 /* SMTP server's EHLO response.
25 /* smtp_sasl_helo_login() authenticates the SMTP client to the
26 /* SMTP server, using the authentication mechanism information
27 /* given by the server. The result is a Postfix delivery status
28 /* code in case of trouble.
34 /* List of SASL authentication mechanisms (separated by blanks)
36 /* All errors are fatal.
40 /* The Secure Mailer license must be distributed with this software.
45 /* 65760 Eschborn, Germany
49 /* IBM T.J. Watson Research
51 /* Yorktown Heights, NY 10598, USA
58 #ifdef STRCASECMP_IN_STRINGS_H
62 /* Utility library. */
66 #include <stringops.h>
70 #include <mail_params.h>
72 /* Application-specific. */
75 #include "smtp_sasl.h"
79 /* smtp_sasl_compat_mechs - Trim server's mechanism list */
81 static const char *smtp_sasl_compat_mechs(const char *words
)
89 * Use server's mechanisms if no filter specified
91 if (smtp_sasl_mechs
== 0 || *words
== 0)
95 buf
= vstring_alloc(10);
98 VSTRING_TERMINATE(buf
);
100 save_mech
= mech_list
= mystrdup(words
);
102 while ((mech
= mystrtok(&mech_list
, " \t")) != 0) {
103 if (string_list_match(smtp_sasl_mechs
, mech
)) {
104 if (VSTRING_LEN(buf
) > 0)
105 VSTRING_ADDCH(buf
, ' ');
106 vstring_strcat(buf
, mech
);
111 return (vstring_str(buf
));
114 /* smtp_sasl_helo_auth - handle AUTH option in EHLO reply */
116 void smtp_sasl_helo_auth(SMTP_SESSION
*session
, const char *words
)
118 const char *mech_list
= smtp_sasl_compat_mechs(words
);
122 * XXX If the server offers no compatible authentication mechanisms, then
123 * pretend that the server doesn't support SASL authentication.
125 * XXX If the server offers multiple different lists, concatenate them. Let
126 * the SASL library worry about duplicates.
128 if (session
->sasl_mechanism_list
) {
129 if (strcasecmp(session
->sasl_mechanism_list
, mech_list
) != 0
130 && strlen(mech_list
) > 0
131 && strlen(session
->sasl_mechanism_list
) < var_line_limit
) {
132 junk
= concatenate(session
->sasl_mechanism_list
, " ", mech_list
,
134 myfree(session
->sasl_mechanism_list
);
135 session
->sasl_mechanism_list
= junk
;
139 if (strlen(mech_list
) > 0) {
140 session
->sasl_mechanism_list
= mystrdup(mech_list
);
142 msg_warn(*words
? "%s offered no supported AUTH mechanisms: '%s'" :
143 "%s offered null AUTH mechanism list",
144 session
->namaddrport
, words
);
146 session
->features
|= SMTP_FEATURE_AUTH
;
149 /* smtp_sasl_helo_login - perform SASL login */
151 int smtp_sasl_helo_login(SMTP_STATE
*state
)
153 SMTP_SESSION
*session
= state
->session
;
154 DSN_BUF
*why
= state
->why
;
158 * Skip authentication when no authentication info exists for this
159 * server, so that we talk to each other like strangers.
161 if (smtp_sasl_passwd_lookup(session
) == 0) {
162 session
->features
&= ~SMTP_FEATURE_AUTH
;
167 * Otherwise, if authentication information exists, assume that
168 * authentication is required, and assume that an authentication error is
169 * recoverable from the message delivery point of view. An authentication
170 * error is unrecoverable from a session point of view - the session will
174 if (session
->sasl_mechanism_list
== 0) {
175 dsb_simple(why
, "4.7.0", "SASL authentication failed: "
176 "server %s offered no compatible authentication mechanisms for this type of connection security",
178 ret
= smtp_sess_fail(state
);
179 /* Session reuse is disabled. */
182 smtp_sasl_start(session
, VAR_SMTP_SASL_OPTS
,
185 if (session
->tls_context
== 0)
186 smtp_sasl_start(session
, VAR_SMTP_SASL_OPTS
,
188 else if (TLS_CERT_IS_MATCHED(session
->tls_context
))
189 smtp_sasl_start(session
, VAR_SMTP_SASL_TLSV_OPTS
,
190 var_smtp_sasl_tlsv_opts
);
192 smtp_sasl_start(session
, VAR_SMTP_SASL_TLS_OPTS
,
193 var_smtp_sasl_tls_opts
);
195 if (smtp_sasl_authenticate(session
, why
) <= 0) {
196 ret
= smtp_sess_fail(state
);
197 /* Session reuse is disabled. */