No empty .Rs/.Re
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / smtpd / smtpd_sasl_glue.c
blob230a069d4a27a9d013a7ef2edfcded3437c03c9b
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* smtpd_sasl_glue 3
6 /* SUMMARY
7 /* Postfix SMTP server, SASL support interface
8 /* SYNOPSIS
9 /* #include "smtpd_sasl_glue.h"
11 /* void smtpd_sasl_initialize()
13 /* void smtpd_sasl_activate(state, sasl_opts_name, sasl_opts_val)
14 /* SMTPD_STATE *state;
15 /* const char *sasl_opts_name;
16 /* const char *sasl_opts_val;
18 /* char *smtpd_sasl_authenticate(state, sasl_method, init_response)
19 /* SMTPD_STATE *state;
20 /* const char *sasl_method;
21 /* const char *init_response;
23 /* void smtpd_sasl_logout(state)
24 /* SMTPD_STATE *state;
26 /* void smtpd_sasl_deactivate(state)
27 /* SMTPD_STATE *state;
29 /* int smtpd_sasl_is_active(state)
30 /* SMTPD_STATE *state;
32 /* int smtpd_sasl_set_inactive(state)
33 /* SMTPD_STATE *state;
34 /* DESCRIPTION
35 /* This module encapsulates most of the detail specific to SASL
36 /* authentication.
38 /* smtpd_sasl_initialize() initializes the SASL library. This
39 /* routine should be called once at process start-up. It may
40 /* need access to the file system for run-time loading of
41 /* plug-in modules. There is no corresponding cleanup routine.
43 /* smtpd_sasl_activate() performs per-connection initialization.
44 /* This routine should be called once at the start of every
45 /* connection. The sasl_opts_name and sasl_opts_val parameters
46 /* are the postfix configuration parameters setting the security
47 /* policy of the SASL authentication.
49 /* smtpd_sasl_authenticate() implements the authentication
50 /* dialog. The result is zero in case of success, -1 in case
51 /* of failure. smtpd_sasl_authenticate() updates the following
52 /* state structure members:
53 /* .IP sasl_method
54 /* The authentication method that was successfully applied.
55 /* This member is a null pointer in the absence of successful
56 /* authentication.
57 /* .IP sasl_username
58 /* The username that was successfully authenticated.
59 /* This member is a null pointer in the absence of successful
60 /* authentication.
61 /* .PP
62 /* smtpd_sasl_logout() cleans up after smtpd_sasl_authenticate().
63 /* This routine exists for the sake of symmetry.
65 /* smtpd_sasl_deactivate() performs per-connection cleanup.
66 /* This routine should be called at the end of every connection.
68 /* smtpd_sasl_is_active() is a predicate that returns true
69 /* if the SMTP server session state is between smtpd_sasl_activate()
70 /* and smtpd_sasl_deactivate().
72 /* smtpd_sasl_set_inactive() initializes the SMTP session
73 /* state before the first smtpd_sasl_activate() call.
75 /* Arguments:
76 /* .IP state
77 /* SMTP session context.
78 /* .IP sasl_opts_name
79 /* Security options parameter name.
80 /* .IP sasl_opts_val
81 /* Security options parameter value.
82 /* .IP sasl_method
83 /* A SASL mechanism name
84 /* .IP init_reply
85 /* An optional initial client response.
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
98 /* Adopted by:
99 /* Wietse Venema
100 /* IBM T.J. Watson Research
101 /* P.O. Box 704
102 /* Yorktown Heights, NY 10598, USA
103 /*--*/
105 /* System library. */
107 #include <sys_defs.h>
108 #include <stdlib.h>
109 #include <string.h>
111 /* Utility library. */
113 #include <msg.h>
114 #include <mymalloc.h>
115 #include <stringops.h>
117 /* Global library. */
119 #include <mail_params.h>
121 /* XSASL library. */
123 #include <xsasl.h>
125 /* Application-specific. */
127 #include "smtpd.h"
128 #include "smtpd_sasl_glue.h"
129 #include "smtpd_chat.h"
131 #ifdef USE_SASL_AUTH
134 * Silly little macros.
136 #define STR(s) vstring_str(s)
139 * SASL server implementation handle.
141 static XSASL_SERVER_IMPL *smtpd_sasl_impl;
143 /* smtpd_sasl_initialize - per-process initialization */
145 void smtpd_sasl_initialize(void)
149 * Sanity check.
151 if (smtpd_sasl_impl)
152 msg_panic("smtpd_sasl_initialize: repeated call");
155 * Initialize the SASL library.
157 if ((smtpd_sasl_impl = xsasl_server_init(var_smtpd_sasl_type,
158 var_smtpd_sasl_path)) == 0)
159 msg_fatal("SASL per-process initialization failed");
163 /* smtpd_sasl_activate - per-connection initialization */
165 void smtpd_sasl_activate(SMTPD_STATE *state, const char *sasl_opts_name,
166 const char *sasl_opts_val)
168 const char *mechanism_list;
169 XSASL_SERVER_CREATE_ARGS create_args;
170 int tls_flag;
173 * Sanity check.
175 if (smtpd_sasl_is_active(state))
176 msg_panic("smtpd_sasl_activate: already active");
179 * Initialize SASL-specific state variables. Use long-lived storage for
180 * base 64 conversion results, rather than local variables, to avoid
181 * memory leaks when a read or write routine returns abnormally after
182 * timeout or I/O error.
184 state->sasl_reply = vstring_alloc(20);
185 state->sasl_mechanism_list = 0;
186 state->sasl_username = 0;
187 state->sasl_method = 0;
188 state->sasl_sender = 0;
191 * Set up a new server context for this connection.
193 #define SMTPD_SASL_SERVICE "smtp"
194 #ifdef USE_TLS
195 tls_flag = state->tls_context != 0;
196 #else
197 tls_flag = 0;
198 #endif
199 #define ADDR_OR_EMPTY(addr, unknown) (strcmp(addr, unknown) ? addr : "")
200 #define REALM_OR_NULL(realm) (*(realm) ? (realm) : (char *) 0)
202 if ((state->sasl_server =
203 XSASL_SERVER_CREATE(smtpd_sasl_impl, &create_args,
204 stream = state->client,
205 server_addr = "", /* need smtpd_peer.c update */
206 client_addr = ADDR_OR_EMPTY(state->addr,
207 CLIENT_ADDR_UNKNOWN),
208 service = SMTPD_SASL_SERVICE,
209 user_realm = REALM_OR_NULL(var_smtpd_sasl_realm),
210 security_options = sasl_opts_val,
211 tls_flag = tls_flag)) == 0)
212 msg_fatal("SASL per-connection initialization failed");
215 * Get the list of authentication mechanisms.
217 if ((mechanism_list =
218 xsasl_server_get_mechanism_list(state->sasl_server)) == 0)
219 msg_fatal("no SASL authentication mechanisms");
220 state->sasl_mechanism_list = mystrdup(mechanism_list);
223 /* smtpd_sasl_deactivate - per-connection cleanup */
225 void smtpd_sasl_deactivate(SMTPD_STATE *state)
227 if (state->sasl_reply) {
228 vstring_free(state->sasl_reply);
229 state->sasl_reply = 0;
231 if (state->sasl_mechanism_list) {
232 myfree(state->sasl_mechanism_list);
233 state->sasl_mechanism_list = 0;
235 if (state->sasl_username) {
236 myfree(state->sasl_username);
237 state->sasl_username = 0;
239 if (state->sasl_method) {
240 myfree(state->sasl_method);
241 state->sasl_method = 0;
243 if (state->sasl_sender) {
244 myfree(state->sasl_sender);
245 state->sasl_sender = 0;
247 if (state->sasl_server) {
248 xsasl_server_free(state->sasl_server);
249 state->sasl_server = 0;
253 /* smtpd_sasl_authenticate - per-session authentication */
255 int smtpd_sasl_authenticate(SMTPD_STATE *state,
256 const char *sasl_method,
257 const char *init_response)
259 int status;
260 const char *sasl_username;
263 * SASL authentication protocol start-up. Process any initial client
264 * response that was sent along in the AUTH command.
266 for (status = xsasl_server_first(state->sasl_server, sasl_method,
267 init_response, state->sasl_reply);
268 status == XSASL_AUTH_MORE;
269 status = xsasl_server_next(state->sasl_server, STR(state->buffer),
270 state->sasl_reply)) {
273 * Send a server challenge.
275 smtpd_chat_reply(state, "334 %s", STR(state->sasl_reply));
278 * Receive the client response. "*" means that the client gives up.
279 * XXX For now we ignore the fact that an excessively long response
280 * will be chopped into multiple reponses. To handle such responses,
281 * we need to change smtpd_chat_query() so that it returns an error
282 * indication.
284 smtpd_chat_query(state);
285 if (strcmp(STR(state->buffer), "*") == 0) {
286 msg_warn("%s: SASL %s authentication aborted",
287 state->namaddr, sasl_method);
288 smtpd_chat_reply(state, "501 5.7.0 Authentication aborted");
289 return (-1);
292 if (status != XSASL_AUTH_DONE) {
293 msg_warn("%s: SASL %s authentication failed: %s",
294 state->namaddr, sasl_method,
295 STR(state->sasl_reply));
296 /* RFC 4954 Section 6. */
297 smtpd_chat_reply(state, "535 5.7.8 Error: authentication failed: %s",
298 STR(state->sasl_reply));
299 return (-1);
301 /* RFC 4954 Section 6. */
302 smtpd_chat_reply(state, "235 2.7.0 Authentication successful");
303 if ((sasl_username = xsasl_server_get_username(state->sasl_server)) == 0)
304 msg_panic("cannot look up the authenticated SASL username");
305 state->sasl_username = mystrdup(sasl_username);
306 printable(state->sasl_username, '?');
307 state->sasl_method = mystrdup(sasl_method);
308 printable(state->sasl_method, '?');
310 return (0);
313 /* smtpd_sasl_logout - clean up after smtpd_sasl_authenticate */
315 void smtpd_sasl_logout(SMTPD_STATE *state)
317 if (state->sasl_username) {
318 myfree(state->sasl_username);
319 state->sasl_username = 0;
321 if (state->sasl_method) {
322 myfree(state->sasl_method);
323 state->sasl_method = 0;
327 #endif