1 /*        $NetBSD: smtp_sasl_proto.c,v 1.3 2022/10/08 16:12:49 christos Exp $   */
2 
3 /*++
4 /* NAME
5 /*        smtp_sasl_proto 3
6 /* SUMMARY
7 /*        Postfix SASL interface for SMTP client
8 /* SYNOPSIS
9 /*        #include smtp_sasl.h
10 /*
11 /*        void      smtp_sasl_helo_auth(state, words)
12 /*        SMTP_STATE *state;
13 /*        const char *words;
14 /*
15 /*        int       smtp_sasl_helo_login(state)
16 /*        SMTP_STATE *state;
17 /* DESCRIPTION
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.
21 /*
22 /*        smtp_sasl_helo_auth() processes the AUTH option in the
23 /*        SMTP server's EHLO response.
24 /*
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.
29 /*
30 /*        Arguments:
31 /* .IP state
32 /*        Session context.
33 /* .IP words
34 /*        List of SASL authentication mechanisms (separated by blanks)
35 /* DIAGNOSTICS
36 /*        All errors are fatal.
37 /* LICENSE
38 /* .ad
39 /* .fi
40 /*        The Secure Mailer license must be distributed with this software.
41 /* AUTHOR(S)
42 /*        Original author:
43 /*        Till Franke
44 /*        SuSE Rhein/Main AG
45 /*        65760 Eschborn, Germany
46 /*
47 /*        Adopted by:
48 /*        Wietse Venema
49 /*        IBM T.J. Watson Research
50 /*        P.O. Box 704
51 /*        Yorktown Heights, NY 10598, USA
52 /*
53 /*        Wietse Venema
54 /*        Google, Inc.
55 /*        111 8th Avenue
56 /*        New York, NY 10011, USA
57 /*--*/
58 
59 /* System library. */
60 
61 #include <sys_defs.h>
62 #include <string.h>
63 #ifdef STRCASECMP_IN_STRINGS_H
64 #include <strings.h>
65 #endif
66 
67 /* Utility library. */
68 
69 #include <msg.h>
70 #include <mymalloc.h>
71 #include <stringops.h>
72 
73 /* Global library. */
74 
75 #include <mail_params.h>
76 #include <sasl_mech_filter.h>
77 
78 /* Application-specific. */
79 
80 #include "smtp.h"
81 #include "smtp_sasl.h"
82 
83 #ifdef USE_SASL_AUTH
84 
85 /* smtp_sasl_helo_auth - handle AUTH option in EHLO reply */
86 
smtp_sasl_helo_auth(SMTP_SESSION * session,const char * words)87 void    smtp_sasl_helo_auth(SMTP_SESSION *session, const char *words)
88 {
89     const char *mech_list = sasl_mech_filter(smtp_sasl_mechs, words);
90     char   *junk;
91 
92     /*
93      * XXX If the server offers no compatible authentication mechanisms, then
94      * pretend that the server doesn't support SASL authentication.
95      *
96      * XXX If the server offers multiple different lists, concatenate them. Let
97      * the SASL library worry about duplicates.
98      */
99     if (session->sasl_mechanism_list) {
100           if (strcasecmp(session->sasl_mechanism_list, mech_list) != 0
101               && strlen(mech_list) > 0
102               && strlen(session->sasl_mechanism_list) < var_line_limit) {
103               junk = concatenate(session->sasl_mechanism_list, " ", mech_list,
104                                      (char *) 0);
105               myfree(session->sasl_mechanism_list);
106               session->sasl_mechanism_list = junk;
107           }
108           return;
109     }
110     if (strlen(mech_list) > 0) {
111           session->sasl_mechanism_list = mystrdup(mech_list);
112     } else {
113           msg_warn(*words ? "%s offered no supported AUTH mechanisms: '%s'" :
114                      "%s offered null AUTH mechanism list%s",
115                      session->namaddrport, words);
116     }
117     session->features |= SMTP_FEATURE_AUTH;
118 }
119 
120 /* smtp_sasl_helo_login - perform SASL login */
121 
smtp_sasl_helo_login(SMTP_STATE * state)122 int     smtp_sasl_helo_login(SMTP_STATE *state)
123 {
124     SMTP_SESSION *session = state->session;
125     DSN_BUF *why = state->why;
126     int     ret;
127 
128     /*
129      * Skip authentication when no authentication info exists for this
130      * server, so that we talk to each other like strangers.
131      */
132     if (smtp_sasl_passwd_lookup(session) == 0) {
133           session->features &= ~SMTP_FEATURE_AUTH;
134           return 0;
135     }
136 
137     /*
138      * Otherwise, if authentication information exists, assume that
139      * authentication is required, and assume that an authentication error is
140      * recoverable from the message delivery point of view. An authentication
141      * error is unrecoverable from a session point of view - the session will
142      * not be reused.
143      */
144     ret = 0;
145     if (session->sasl_mechanism_list == 0) {
146           dsb_simple(why, "4.7.0", "SASL authentication failed: "
147                        "server %s offered no compatible authentication mechanisms for this type of connection security",
148                        session->namaddr);
149           ret = smtp_sess_fail(state);
150           /* Session reuse is disabled. */
151     } else {
152 #ifndef USE_TLS
153           smtp_sasl_start(session, VAR_LMTP_SMTP(SASL_OPTS), var_smtp_sasl_opts);
154 #else
155           if (session->tls_context == 0)
156               smtp_sasl_start(session, VAR_LMTP_SMTP(SASL_OPTS),
157                                   var_smtp_sasl_opts);
158           else if (TLS_CERT_IS_MATCHED(session->tls_context))
159               smtp_sasl_start(session, VAR_LMTP_SMTP(SASL_TLSV_OPTS),
160                                   var_smtp_sasl_tlsv_opts);
161           else
162               smtp_sasl_start(session, VAR_LMTP_SMTP(SASL_TLS_OPTS),
163                                   var_smtp_sasl_tls_opts);
164 #endif
165           if (smtp_sasl_authenticate(session, why) <= 0) {
166               ret = smtp_sess_fail(state);
167               /* Session reuse is disabled. */
168           }
169     }
170     return (ret);
171 }
172 
173 #endif
174