1 /*	$NetBSD: smtpd_sasl_proto.c,v 1.1.1.1 2009/06/23 10:08:56 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     if (smtpd_milters != 0 && (err = milter_other_event(smtpd_milters)) != 0) {
158 	if (err[0] == '5') {
159 	    state->error_mask |= MAIL_ERROR_POLICY;
160 	    smtpd_chat_reply(state, "%s", err);
161 	    return (-1);
162 	}
163 	/* Sendmail compatibility: map 4xx into 454. */
164 	else if (err[0] == '4') {
165 	    state->error_mask |= MAIL_ERROR_POLICY;
166 	    smtpd_chat_reply(state, "454 4.3.0 Try again later");
167 	    return (-1);
168 	}
169     }
170 #ifdef USE_TLS
171     if (state->tls_auth_only && !state->tls_context) {
172 	state->error_mask |= MAIL_ERROR_PROTOCOL;
173 	/* RFC 4954, Section 4. */
174 	smtpd_chat_reply(state, "504 5.5.4 Encryption required for requested authentication mechanism");
175 	return (-1);
176     }
177 #endif
178     if (state->sasl_username) {
179 	state->error_mask |= MAIL_ERROR_PROTOCOL;
180 	smtpd_chat_reply(state, "503 5.5.1 Error: already authenticated");
181 	return (-1);
182     }
183     if (argc < 2 || argc > 3) {
184 	state->error_mask |= MAIL_ERROR_PROTOCOL;
185 	smtpd_chat_reply(state, "501 5.5.4 Syntax: AUTH mechanism");
186 	return (-1);
187     }
188 
189     /*
190      * All authentication failures shall be logged. The 5xx reply code from
191      * the SASL authentication routine triggers tar-pit delays, which help to
192      * slow down password guessing attacks.
193      */
194     auth_mechanism = argv[1].strval;
195     initial_response = (argc == 3 ? argv[2].strval : 0);
196     return (smtpd_sasl_authenticate(state, auth_mechanism, initial_response));
197 }
198 
199 /* smtpd_sasl_auth_reset - clean up after AUTH command */
200 
201 void    smtpd_sasl_auth_reset(SMTPD_STATE *state)
202 {
203     smtpd_sasl_logout(state);
204 }
205 
206 /* smtpd_sasl_mail_opt - SASL-specific MAIL FROM option */
207 
208 char   *smtpd_sasl_mail_opt(SMTPD_STATE *state, const char *addr)
209 {
210 
211     /*
212      * Do not store raw RFC2554 protocol data.
213      */
214     if (!smtpd_sasl_is_active(state)) {
215 	state->error_mask |= MAIL_ERROR_PROTOCOL;
216 	return ("503 5.5.4 Error: authentication disabled");
217     }
218 #if 0
219     if (state->sasl_username == 0) {
220 	state->error_mask |= MAIL_ERROR_PROTOCOL;
221 	return ("503 5.5.4 Error: send AUTH command first");
222     }
223 #endif
224     if (state->sasl_sender != 0) {
225 	state->error_mask |= MAIL_ERROR_PROTOCOL;
226 	return ("503 5.5.4 Error: multiple AUTH= options");
227     }
228     if (strcmp(addr, "<>") != 0) {
229 	state->sasl_sender = mystrdup(addr);
230 	printable(state->sasl_sender, '?');
231     }
232     return (0);
233 }
234 
235 /* smtpd_sasl_mail_log - SASL-specific MAIL FROM logging */
236 
237 void    smtpd_sasl_mail_log(SMTPD_STATE *state)
238 {
239 #define IFELSE(e1,e2,e3) ((e1) ? (e2) : (e3))
240 
241     msg_info("%s: client=%s%s%s%s%s%s%s",
242       state->queue_id ? state->queue_id : "NOQUEUE", FORWARD_NAMADDR(state),
243 	     IFELSE(state->sasl_method, ", sasl_method=", ""),
244 	     IFELSE(state->sasl_method, state->sasl_method, ""),
245 	     IFELSE(state->sasl_username, ", sasl_username=", ""),
246 	     IFELSE(state->sasl_username, state->sasl_username, ""),
247 	     IFELSE(state->sasl_sender, ", sasl_sender=", ""),
248 	     IFELSE(state->sasl_sender, state->sasl_sender, ""));
249 }
250 
251 /* smtpd_sasl_mail_reset - SASL-specific MAIL FROM cleanup */
252 
253 void    smtpd_sasl_mail_reset(SMTPD_STATE *state)
254 {
255     if (state->sasl_sender) {
256 	myfree(state->sasl_sender);
257 	state->sasl_sender = 0;
258     }
259 }
260 
261 /* permit_sasl_auth - OK for authenticated connection */
262 
263 int     permit_sasl_auth(SMTPD_STATE *state, int ifyes, int ifnot)
264 {
265     if (state->sasl_method && strcasecmp(state->sasl_method, "anonymous"))
266 	return (ifyes);
267     return (ifnot);
268 }
269 
270 #endif
271