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