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