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