1/*++ 2/* NAME 3/* smtp_sasl_proto 3 4/* SUMMARY 5/* Postfix SASL interface for SMTP client 6/* SYNOPSIS 7/* #include smtp_sasl.h 8/* 9/* void smtp_sasl_helo_auth(state, words) 10/* SMTP_STATE *state; 11/* const char *words; 12/* 13/* int smtp_sasl_helo_login(state) 14/* SMTP_STATE *state; 15/* DESCRIPTION 16/* This module contains random chunks of code that implement 17/* the SMTP protocol interface for SASL negotiation. The goal 18/* is to reduce clutter in the main SMTP client source code. 19/* 20/* smtp_sasl_helo_auth() processes the AUTH option in the 21/* SMTP server's EHLO response. 22/* 23/* smtp_sasl_helo_login() authenticates the SMTP client to the 24/* SMTP server, using the authentication mechanism information 25/* given by the server. The result is a Postfix delivery status 26/* code in case of trouble. 27/* 28/* Arguments: 29/* .IP state 30/* Session context. 31/* .IP words 32/* List of SASL authentication mechanisms (separated by blanks) 33/* DIAGNOSTICS 34/* All errors are fatal. 35/* LICENSE 36/* .ad 37/* .fi 38/* The Secure Mailer license must be distributed with this software. 39/* AUTHOR(S) 40/* Original author: 41/* Till Franke 42/* SuSE Rhein/Main AG 43/* 65760 Eschborn, Germany 44/* 45/* Adopted by: 46/* Wietse Venema 47/* IBM T.J. Watson Research 48/* P.O. Box 704 49/* Yorktown Heights, NY 10598, USA 50/*--*/ 51 52/* System library. */ 53 54#include <sys_defs.h> 55#include <string.h> 56#ifdef STRCASECMP_IN_STRINGS_H 57#include <strings.h> 58#endif 59 60/* Utility library. */ 61 62#include <msg.h> 63#include <mymalloc.h> 64#include <stringops.h> 65 66/* Global library. */ 67 68#include <mail_params.h> 69 70/* Application-specific. */ 71 72#include "smtp.h" 73#include "smtp_sasl.h" 74 75#ifdef USE_SASL_AUTH 76 77/* smtp_sasl_compat_mechs - Trim server's mechanism list */ 78 79static const char *smtp_sasl_compat_mechs(const char *words) 80{ 81 static VSTRING *buf; 82 char *mech_list; 83 char *save_mech; 84 char *mech; 85 86 /* 87 * Use server's mechanisms if no filter specified 88 */ 89 if (smtp_sasl_mechs == 0 || *words == 0) 90 return (words); 91 92 if (buf == 0) 93 buf = vstring_alloc(10); 94 95 VSTRING_RESET(buf); 96 VSTRING_TERMINATE(buf); 97 98 save_mech = mech_list = mystrdup(words); 99 100 while ((mech = mystrtok(&mech_list, " \t")) != 0) { 101 if (string_list_match(smtp_sasl_mechs, mech)) { 102 if (VSTRING_LEN(buf) > 0) 103 VSTRING_ADDCH(buf, ' '); 104 vstring_strcat(buf, mech); 105 } 106 } 107 myfree(save_mech); 108 109 return (vstring_str(buf)); 110} 111 112/* smtp_sasl_helo_auth - handle AUTH option in EHLO reply */ 113 114void smtp_sasl_helo_auth(SMTP_SESSION *session, const char *words) 115{ 116 const char *mech_list = smtp_sasl_compat_mechs(words); 117 char *junk; 118 119 /* 120 * XXX If the server offers no compatible authentication mechanisms, then 121 * pretend that the server doesn't support SASL authentication. 122 * 123 * XXX If the server offers multiple different lists, concatenate them. Let 124 * the SASL library worry about duplicates. 125 */ 126 if (session->sasl_mechanism_list) { 127 if (strcasecmp(session->sasl_mechanism_list, mech_list) != 0 128 && strlen(mech_list) > 0 129 && strlen(session->sasl_mechanism_list) < var_line_limit) { 130 junk = concatenate(session->sasl_mechanism_list, " ", mech_list, 131 (char *) 0); 132 myfree(session->sasl_mechanism_list); 133 session->sasl_mechanism_list = junk; 134 } 135 return; 136 } 137 if (strlen(mech_list) > 0) { 138 session->sasl_mechanism_list = mystrdup(mech_list); 139 } else { 140 msg_warn(*words ? "%s offered no supported AUTH mechanisms: '%s'" : 141 "%s offered null AUTH mechanism list", 142 session->namaddrport, words); 143 } 144 session->features |= SMTP_FEATURE_AUTH; 145} 146 147/* smtp_sasl_helo_login - perform SASL login */ 148 149int smtp_sasl_helo_login(SMTP_STATE *state) 150{ 151 SMTP_SESSION *session = state->session; 152 DSN_BUF *why = state->why; 153 int ret; 154 155 /* 156 * Skip authentication when no authentication info exists for this 157 * server, so that we talk to each other like strangers. 158 */ 159 if (smtp_sasl_passwd_lookup(session) == 0) { 160 session->features &= ~SMTP_FEATURE_AUTH; 161 return 0; 162 } 163 164 /* 165 * Otherwise, if authentication information exists, assume that 166 * authentication is required, and assume that an authentication error is 167 * recoverable from the message delivery point of view. An authentication 168 * error is unrecoverable from a session point of view - the session will 169 * not be reused. 170 */ 171 ret = 0; 172 if (session->sasl_mechanism_list == 0) { 173 dsb_simple(why, "4.7.0", "SASL authentication failed: " 174 "server %s offered no compatible authentication mechanisms for this type of connection security", 175 session->namaddr); 176 ret = smtp_sess_fail(state); 177 /* Session reuse is disabled. */ 178 } else { 179#ifndef USE_TLS 180 smtp_sasl_start(session, VAR_SMTP_SASL_OPTS, 181 var_smtp_sasl_opts); 182#else 183 if (session->tls_context == 0) 184 smtp_sasl_start(session, VAR_SMTP_SASL_OPTS, 185 var_smtp_sasl_opts); 186 else if (TLS_CERT_IS_MATCHED(session->tls_context)) 187 smtp_sasl_start(session, VAR_SMTP_SASL_TLSV_OPTS, 188 var_smtp_sasl_tlsv_opts); 189 else 190 smtp_sasl_start(session, VAR_SMTP_SASL_TLS_OPTS, 191 var_smtp_sasl_tls_opts); 192#endif 193 if (smtp_sasl_authenticate(session, why) <= 0) { 194 ret = smtp_sess_fail(state); 195 /* Session reuse is disabled. */ 196 } 197 } 198 return (ret); 199} 200 201#endif 202