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