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