1 /* $NetBSD: smtpd_sasl_proto.c,v 1.1.1.4 2012/08/10 12:35:55 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 #define IN_MAIL_TRANSACTION(state) ((state)->sender != 0) 158 if (IN_MAIL_TRANSACTION(state)) { 159 state->error_mask |= MAIL_ERROR_PROTOCOL; 160 smtpd_chat_reply(state, "503 5.5.1 Error: MAIL transaction in progress"); 161 return (-1); 162 } 163 if (smtpd_milters != 0 && (err = milter_other_event(smtpd_milters)) != 0) { 164 if (err[0] == '5') { 165 state->error_mask |= MAIL_ERROR_POLICY; 166 smtpd_chat_reply(state, "%s", err); 167 return (-1); 168 } 169 /* Sendmail compatibility: map 4xx into 454. */ 170 else if (err[0] == '4') { 171 state->error_mask |= MAIL_ERROR_POLICY; 172 smtpd_chat_reply(state, "454 4.3.0 Try again later"); 173 return (-1); 174 } 175 } 176 #ifdef USE_TLS 177 if (var_smtpd_tls_auth_only && !state->tls_context) { 178 state->error_mask |= MAIL_ERROR_PROTOCOL; 179 /* RFC 4954, Section 4. */ 180 smtpd_chat_reply(state, "504 5.5.4 Encryption required for requested authentication mechanism"); 181 return (-1); 182 } 183 #endif 184 if (state->sasl_username) { 185 state->error_mask |= MAIL_ERROR_PROTOCOL; 186 smtpd_chat_reply(state, "503 5.5.1 Error: already authenticated"); 187 return (-1); 188 } 189 if (argc < 2 || argc > 3) { 190 state->error_mask |= MAIL_ERROR_PROTOCOL; 191 smtpd_chat_reply(state, "501 5.5.4 Syntax: AUTH mechanism"); 192 return (-1); 193 } 194 195 /* Don't reuse the SASL handle after authentication failure. */ 196 #ifndef SMTPD_FLAG_AUTH_USED 197 #define SMTPD_FLAG_AUTH_USED (1<<15) 198 #endif 199 #ifndef XSASL_TYPE_CYRUS 200 #define XSASL_TYPE_CYRUS "cyrus" 201 #endif 202 if (state->flags & SMTPD_FLAG_AUTH_USED) { 203 smtpd_sasl_deactivate(state); 204 #ifdef USE_TLS 205 if (state->tls_context != 0) 206 smtpd_sasl_activate(state, VAR_SMTPD_SASL_TLS_OPTS, 207 var_smtpd_sasl_tls_opts); 208 else 209 #endif 210 smtpd_sasl_activate(state, VAR_SMTPD_SASL_OPTS, 211 var_smtpd_sasl_opts); 212 } else if (strcmp(var_smtpd_sasl_type, XSASL_TYPE_CYRUS) == 0) { 213 state->flags |= SMTPD_FLAG_AUTH_USED; 214 } 215 216 /* 217 * All authentication failures shall be logged. The 5xx reply code from 218 * the SASL authentication routine triggers tar-pit delays, which help to 219 * slow down password guessing attacks. 220 */ 221 auth_mechanism = argv[1].strval; 222 initial_response = (argc == 3 ? argv[2].strval : 0); 223 return (smtpd_sasl_authenticate(state, auth_mechanism, initial_response)); 224 } 225 226 /* smtpd_sasl_auth_reset - clean up after AUTH command */ 227 228 void smtpd_sasl_auth_reset(SMTPD_STATE *state) 229 { 230 smtpd_sasl_logout(state); 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 (!smtpd_sasl_is_active(state)) { 242 state->error_mask |= MAIL_ERROR_PROTOCOL; 243 return ("503 5.5.4 Error: authentication disabled"); 244 } 245 #if 0 246 if (state->sasl_username == 0) { 247 state->error_mask |= MAIL_ERROR_PROTOCOL; 248 return ("503 5.5.4 Error: send AUTH command first"); 249 } 250 #endif 251 if (state->sasl_sender != 0) { 252 state->error_mask |= MAIL_ERROR_PROTOCOL; 253 return ("503 5.5.4 Error: multiple AUTH= options"); 254 } 255 if (strcmp(addr, "<>") != 0) { 256 state->sasl_sender = mystrdup(addr); 257 printable(state->sasl_sender, '?'); 258 } 259 return (0); 260 } 261 262 /* smtpd_sasl_mail_log - SASL-specific MAIL FROM logging */ 263 264 void smtpd_sasl_mail_log(SMTPD_STATE *state) 265 { 266 267 /* 268 * See also: smtpd.c, for a shorter client= logfile record. 269 */ 270 #define PRINT_OR_NULL(cond, str) \ 271 ((cond) ? (str) : "") 272 #define PRINT2_OR_NULL(cond, name, value) \ 273 PRINT_OR_NULL((cond), (name)), PRINT_OR_NULL((cond), (value)) 274 275 msg_info("%s: client=%s%s%s%s%s%s%s%s%s%s%s", 276 (state->queue_id ? state->queue_id : "NOQUEUE"), 277 state->namaddr, 278 PRINT2_OR_NULL(state->sasl_method, 279 ", sasl_method=", state->sasl_method), 280 PRINT2_OR_NULL(state->sasl_username, 281 ", sasl_username=", state->sasl_username), 282 PRINT2_OR_NULL(state->sasl_sender, 283 ", sasl_sender=", state->sasl_sender), 284 PRINT2_OR_NULL(HAVE_FORWARDED_IDENT(state), 285 ", orig_queue_id=", FORWARD_IDENT(state)), 286 PRINT2_OR_NULL(HAVE_FORWARDED_CLIENT_ATTR(state), 287 ", orig_client=", FORWARD_NAMADDR(state))); 288 } 289 290 /* smtpd_sasl_mail_reset - SASL-specific MAIL FROM cleanup */ 291 292 void smtpd_sasl_mail_reset(SMTPD_STATE *state) 293 { 294 if (state->sasl_sender) { 295 myfree(state->sasl_sender); 296 state->sasl_sender = 0; 297 } 298 } 299 300 /* permit_sasl_auth - OK for authenticated connection */ 301 302 int permit_sasl_auth(SMTPD_STATE *state, int ifyes, int ifnot) 303 { 304 if (state->sasl_method && strcasecmp(state->sasl_method, "anonymous")) 305 return (ifyes); 306 return (ifnot); 307 } 308 309 #endif 310