1 /* $NetBSD: smtpd_sasl_proto.c,v 1.1.1.3 2011/05/11 09:11:19 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 (var_smtpd_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 /* Don't reuse the SASL handle after authentication failure. */ 190 #ifndef SMTPD_FLAG_AUTH_USED 191 #define SMTPD_FLAG_AUTH_USED (1<<15) 192 #endif 193 #ifndef XSASL_TYPE_CYRUS 194 #define XSASL_TYPE_CYRUS "cyrus" 195 #endif 196 if (state->flags & SMTPD_FLAG_AUTH_USED) { 197 smtpd_sasl_deactivate(state); 198 #ifdef USE_TLS 199 if (state->tls_context != 0) 200 smtpd_sasl_activate(state, VAR_SMTPD_SASL_TLS_OPTS, 201 var_smtpd_sasl_tls_opts); 202 else 203 #endif 204 smtpd_sasl_activate(state, VAR_SMTPD_SASL_OPTS, 205 var_smtpd_sasl_opts); 206 } else if (strcmp(var_smtpd_sasl_type, XSASL_TYPE_CYRUS) == 0) { 207 state->flags |= SMTPD_FLAG_AUTH_USED; 208 } 209 210 /* 211 * All authentication failures shall be logged. The 5xx reply code from 212 * the SASL authentication routine triggers tar-pit delays, which help to 213 * slow down password guessing attacks. 214 */ 215 auth_mechanism = argv[1].strval; 216 initial_response = (argc == 3 ? argv[2].strval : 0); 217 return (smtpd_sasl_authenticate(state, auth_mechanism, initial_response)); 218 } 219 220 /* smtpd_sasl_auth_reset - clean up after AUTH command */ 221 222 void smtpd_sasl_auth_reset(SMTPD_STATE *state) 223 { 224 smtpd_sasl_logout(state); 225 } 226 227 /* smtpd_sasl_mail_opt - SASL-specific MAIL FROM option */ 228 229 char *smtpd_sasl_mail_opt(SMTPD_STATE *state, const char *addr) 230 { 231 232 /* 233 * Do not store raw RFC2554 protocol data. 234 */ 235 if (!smtpd_sasl_is_active(state)) { 236 state->error_mask |= MAIL_ERROR_PROTOCOL; 237 return ("503 5.5.4 Error: authentication disabled"); 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 258 void 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 286 void 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 296 int 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