1 /* $NetBSD: smtpd_sasl_proto.c,v 1.3 2020/03/18 19:05:20 christos Exp $ */
2
3 /*++
4 /* NAME
5 /* smtpd_sasl_proto 3
6 /* SUMMARY
7 /* Postfix SMTP protocol support for SASL authentication
8 /* SYNOPSIS
9 /* #include "smtpd.h"
10 /* #include "smtpd_sasl_proto.h"
11 /*
12 /* int smtpd_sasl_auth_cmd(state, argc, argv)
13 /* SMTPD_STATE *state;
14 /* int argc;
15 /* SMTPD_TOKEN *argv;
16 /*
17 /* void smtpd_sasl_auth_extern(state, username, method)
18 /* SMTPD_STATE *state;
19 /* const char *username;
20 /* const char *method;
21 /*
22 /* void smtpd_sasl_auth_reset(state)
23 /* SMTPD_STATE *state;
24 /*
25 /* char *smtpd_sasl_mail_opt(state, sender)
26 /* SMTPD_STATE *state;
27 /* const char *sender;
28 /*
29 /* void smtpd_sasl_mail_reset(state)
30 /* SMTPD_STATE *state;
31 /*
32 /* static int permit_sasl_auth(state, authenticated, unauthenticated)
33 /* SMTPD_STATE *state;
34 /* int authenticated;
35 /* int unauthenticated;
36 /* DESCRIPTION
37 /* This module contains random chunks of code that implement
38 /* the SMTP protocol interface for SASL negotiation. The goal
39 /* is to reduce clutter of the main SMTP server source code.
40 /*
41 /* smtpd_sasl_auth_cmd() implements the AUTH command and updates
42 /* the following state structure members:
43 /* .IP sasl_method
44 /* The authentication method that was successfully applied.
45 /* This member is a null pointer in the absence of successful
46 /* authentication.
47 /* .IP sasl_username
48 /* The username that was successfully authenticated.
49 /* This member is a null pointer in the absence of successful
50 /* authentication.
51 /* .PP
52 /* smtpd_sasl_auth_reset() cleans up after the AUTH command.
53 /* This is required before smtpd_sasl_auth_cmd() can be used again.
54 /* This may be called even if SASL authentication is turned off
55 /* in main.cf.
56 /*
57 /* smtpd_sasl_auth_extern() records authentication information
58 /* that is received from an external source.
59 /* This may be called even if SASL authentication is turned off
60 /* in main.cf.
61 /*
62 /* smtpd_sasl_mail_opt() implements the SASL-specific AUTH=sender
63 /* option to the MAIL FROM command. The result is an error response
64 /* in case of problems.
65 /*
66 /* smtpd_sasl_mail_reset() performs cleanup for the SASL-specific
67 /* AUTH=sender option to the MAIL FROM command.
68 /*
69 /* permit_sasl_auth() permits access from an authenticated client.
70 /* This test fails for clients that use anonymous authentication.
71 /*
72 /* Arguments:
73 /* .IP state
74 /* SMTP session context.
75 /* .IP argc
76 /* Number of command line tokens.
77 /* .IP argv
78 /* The command line parsed into tokens.
79 /* .IP sender
80 /* Sender address from the AUTH=sender option in the MAIL FROM
81 /* command.
82 /* .IP authenticated
83 /* Result for authenticated client.
84 /* .IP unauthenticated
85 /* Result for unauthenticated client.
86 /* DIAGNOSTICS
87 /* All errors are fatal.
88 /* LICENSE
89 /* .ad
90 /* .fi
91 /* The Secure Mailer license must be distributed with this software.
92 /* AUTHOR(S)
93 /* Initial implementation by:
94 /* Till Franke
95 /* SuSE Rhein/Main AG
96 /* 65760 Eschborn, Germany
97 /*
98 /* Adopted by:
99 /* Wietse Venema
100 /* IBM T.J. Watson Research
101 /* P.O. Box 704
102 /* Yorktown Heights, NY 10598, USA
103 /*
104 /* Wietse Venema
105 /* Google, Inc.
106 /* 111 8th Avenue
107 /* New York, NY 10011, USA
108 /*
109 /* TLS support originally by:
110 /* Lutz Jaenicke
111 /* BTU Cottbus
112 /* Allgemeine Elektrotechnik
113 /* Universitaetsplatz 3-4
114 /* D-03044 Cottbus, Germany
115 /*--*/
116
117 /* System library. */
118
119 #include <sys_defs.h>
120 #include <string.h>
121
122 #ifdef STRCASECMP_IN_STRINGS_H
123 #include <strings.h>
124 #endif
125
126 /* Utility library. */
127
128 #include <msg.h>
129 #include <mymalloc.h>
130 #include <stringops.h>
131
132 /* Global library. */
133
134 #include <mail_params.h>
135 #include <mail_proto.h>
136 #include <mail_error.h>
137 #include <ehlo_mask.h>
138
139 /* Application-specific. */
140
141 #include "smtpd.h"
142 #include "smtpd_token.h"
143 #include "smtpd_chat.h"
144 #include "smtpd_sasl_proto.h"
145 #include "smtpd_sasl_glue.h"
146
147 #ifdef USE_SASL_AUTH
148
149 /* smtpd_sasl_auth_cmd - process AUTH command */
150
smtpd_sasl_auth_cmd(SMTPD_STATE * state,int argc,SMTPD_TOKEN * argv)151 int smtpd_sasl_auth_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
152 {
153 char *auth_mechanism;
154 char *initial_response;
155 const char *err;
156
157 if (var_helo_required && state->helo_name == 0) {
158 state->error_mask |= MAIL_ERROR_POLICY;
159 smtpd_chat_reply(state, "503 5.5.1 Error: send HELO/EHLO first");
160 return (-1);
161 }
162 if (SMTPD_STAND_ALONE(state) || !smtpd_sasl_is_active(state)
163 || (state->ehlo_discard_mask & EHLO_MASK_AUTH)) {
164 state->error_mask |= MAIL_ERROR_PROTOCOL;
165 smtpd_chat_reply(state, "503 5.5.1 Error: authentication not enabled");
166 return (-1);
167 }
168 if (SMTPD_IN_MAIL_TRANSACTION(state)) {
169 state->error_mask |= MAIL_ERROR_PROTOCOL;
170 smtpd_chat_reply(state, "503 5.5.1 Error: MAIL transaction in progress");
171 return (-1);
172 }
173 if (state->milters != 0 && (err = milter_other_event(state->milters)) != 0) {
174 if (err[0] == '5') {
175 state->error_mask |= MAIL_ERROR_POLICY;
176 smtpd_chat_reply(state, "%s", err);
177 return (-1);
178 }
179 /* Sendmail compatibility: map 4xx into 454. */
180 else if (err[0] == '4') {
181 state->error_mask |= MAIL_ERROR_POLICY;
182 smtpd_chat_reply(state, "454 4.3.0 Try again later");
183 return (-1);
184 }
185 }
186 #ifdef USE_TLS
187 if (var_smtpd_tls_auth_only && !state->tls_context) {
188 state->error_mask |= MAIL_ERROR_PROTOCOL;
189 /* RFC 4954, Section 4. */
190 smtpd_chat_reply(state, "504 5.5.4 Encryption required for requested authentication mechanism");
191 return (-1);
192 }
193 #endif
194 if (state->sasl_username) {
195 state->error_mask |= MAIL_ERROR_PROTOCOL;
196 smtpd_chat_reply(state, "503 5.5.1 Error: already authenticated");
197 return (-1);
198 }
199 if (argc < 2 || argc > 3) {
200 state->error_mask |= MAIL_ERROR_PROTOCOL;
201 smtpd_chat_reply(state, "501 5.5.4 Syntax: AUTH mechanism");
202 return (-1);
203 }
204 /* Don't reuse the SASL handle after authentication failure. */
205 #ifndef XSASL_TYPE_CYRUS
206 #define XSASL_TYPE_CYRUS "cyrus"
207 #endif
208 if (state->flags & SMTPD_FLAG_AUTH_USED) {
209 smtpd_sasl_deactivate(state);
210 #ifdef USE_TLS
211 if (state->tls_context != 0)
212 smtpd_sasl_activate(state, VAR_SMTPD_SASL_TLS_OPTS,
213 var_smtpd_sasl_tls_opts);
214 else
215 #endif
216 smtpd_sasl_activate(state, VAR_SMTPD_SASL_OPTS,
217 var_smtpd_sasl_opts);
218 } else if (strcmp(var_smtpd_sasl_type, XSASL_TYPE_CYRUS) == 0) {
219 state->flags |= SMTPD_FLAG_AUTH_USED;
220 }
221
222 /*
223 * All authentication failures shall be logged. The 5xx reply code from
224 * the SASL authentication routine triggers tar-pit delays, which help to
225 * slow down password guessing attacks.
226 */
227 auth_mechanism = argv[1].strval;
228 initial_response = (argc == 3 ? argv[2].strval : 0);
229 return (smtpd_sasl_authenticate(state, auth_mechanism, initial_response));
230 }
231
232 /* smtpd_sasl_mail_opt - SASL-specific MAIL FROM option */
233
smtpd_sasl_mail_opt(SMTPD_STATE * state,const char * addr)234 char *smtpd_sasl_mail_opt(SMTPD_STATE *state, const char *addr)
235 {
236
237 /*
238 * Do not store raw RFC2554 protocol data.
239 */
240 #if 0
241 if (state->sasl_username == 0) {
242 state->error_mask |= MAIL_ERROR_PROTOCOL;
243 return ("503 5.5.4 Error: send AUTH command first");
244 }
245 #endif
246 if (state->sasl_sender != 0) {
247 state->error_mask |= MAIL_ERROR_PROTOCOL;
248 return ("503 5.5.4 Error: multiple AUTH= options");
249 }
250 if (strcmp(addr, "<>") != 0) {
251 state->sasl_sender = mystrdup(addr);
252 printable(state->sasl_sender, '?');
253 }
254 return (0);
255 }
256
257 /* smtpd_sasl_mail_reset - SASL-specific MAIL FROM cleanup */
258
smtpd_sasl_mail_reset(SMTPD_STATE * state)259 void smtpd_sasl_mail_reset(SMTPD_STATE *state)
260 {
261 if (state->sasl_sender) {
262 myfree(state->sasl_sender);
263 state->sasl_sender = 0;
264 }
265 }
266
267 /* permit_sasl_auth - OK for authenticated connection */
268
permit_sasl_auth(SMTPD_STATE * state,int ifyes,int ifnot)269 int permit_sasl_auth(SMTPD_STATE *state, int ifyes, int ifnot)
270 {
271 if (state->sasl_method && strcasecmp(state->sasl_method, "anonymous"))
272 return (ifyes);
273 return (ifnot);
274 }
275
276 #endif
277