1 /* $NetBSD: smtpd_sasl_proto.c,v 1.1.1.1 2009/06/23 10:08:56 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 (state->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 /* 190 * All authentication failures shall be logged. The 5xx reply code from 191 * the SASL authentication routine triggers tar-pit delays, which help to 192 * slow down password guessing attacks. 193 */ 194 auth_mechanism = argv[1].strval; 195 initial_response = (argc == 3 ? argv[2].strval : 0); 196 return (smtpd_sasl_authenticate(state, auth_mechanism, initial_response)); 197 } 198 199 /* smtpd_sasl_auth_reset - clean up after AUTH command */ 200 201 void smtpd_sasl_auth_reset(SMTPD_STATE *state) 202 { 203 smtpd_sasl_logout(state); 204 } 205 206 /* smtpd_sasl_mail_opt - SASL-specific MAIL FROM option */ 207 208 char *smtpd_sasl_mail_opt(SMTPD_STATE *state, const char *addr) 209 { 210 211 /* 212 * Do not store raw RFC2554 protocol data. 213 */ 214 if (!smtpd_sasl_is_active(state)) { 215 state->error_mask |= MAIL_ERROR_PROTOCOL; 216 return ("503 5.5.4 Error: authentication disabled"); 217 } 218 #if 0 219 if (state->sasl_username == 0) { 220 state->error_mask |= MAIL_ERROR_PROTOCOL; 221 return ("503 5.5.4 Error: send AUTH command first"); 222 } 223 #endif 224 if (state->sasl_sender != 0) { 225 state->error_mask |= MAIL_ERROR_PROTOCOL; 226 return ("503 5.5.4 Error: multiple AUTH= options"); 227 } 228 if (strcmp(addr, "<>") != 0) { 229 state->sasl_sender = mystrdup(addr); 230 printable(state->sasl_sender, '?'); 231 } 232 return (0); 233 } 234 235 /* smtpd_sasl_mail_log - SASL-specific MAIL FROM logging */ 236 237 void smtpd_sasl_mail_log(SMTPD_STATE *state) 238 { 239 #define IFELSE(e1,e2,e3) ((e1) ? (e2) : (e3)) 240 241 msg_info("%s: client=%s%s%s%s%s%s%s", 242 state->queue_id ? state->queue_id : "NOQUEUE", FORWARD_NAMADDR(state), 243 IFELSE(state->sasl_method, ", sasl_method=", ""), 244 IFELSE(state->sasl_method, state->sasl_method, ""), 245 IFELSE(state->sasl_username, ", sasl_username=", ""), 246 IFELSE(state->sasl_username, state->sasl_username, ""), 247 IFELSE(state->sasl_sender, ", sasl_sender=", ""), 248 IFELSE(state->sasl_sender, state->sasl_sender, "")); 249 } 250 251 /* smtpd_sasl_mail_reset - SASL-specific MAIL FROM cleanup */ 252 253 void smtpd_sasl_mail_reset(SMTPD_STATE *state) 254 { 255 if (state->sasl_sender) { 256 myfree(state->sasl_sender); 257 state->sasl_sender = 0; 258 } 259 } 260 261 /* permit_sasl_auth - OK for authenticated connection */ 262 263 int permit_sasl_auth(SMTPD_STATE *state, int ifyes, int ifnot) 264 { 265 if (state->sasl_method && strcasecmp(state->sasl_method, "anonymous")) 266 return (ifyes); 267 return (ifnot); 268 } 269 270 #endif 271