diff options
Diffstat (limited to '')
-rw-r--r-- | src/smtpd/smtpd_sasl_proto.c | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/src/smtpd/smtpd_sasl_proto.c b/src/smtpd/smtpd_sasl_proto.c new file mode 100644 index 0000000..476752d --- /dev/null +++ b/src/smtpd/smtpd_sasl_proto.c @@ -0,0 +1,274 @@ +/*++ +/* NAME +/* smtpd_sasl_proto 3 +/* SUMMARY +/* Postfix SMTP protocol support for SASL authentication +/* SYNOPSIS +/* #include "smtpd.h" +/* #include "smtpd_sasl_proto.h" +/* +/* int smtpd_sasl_auth_cmd(state, argc, argv) +/* SMTPD_STATE *state; +/* int argc; +/* SMTPD_TOKEN *argv; +/* +/* void smtpd_sasl_auth_extern(state, username, method) +/* SMTPD_STATE *state; +/* const char *username; +/* const char *method; +/* +/* void smtpd_sasl_auth_reset(state) +/* SMTPD_STATE *state; +/* +/* char *smtpd_sasl_mail_opt(state, sender) +/* SMTPD_STATE *state; +/* const char *sender; +/* +/* void smtpd_sasl_mail_reset(state) +/* SMTPD_STATE *state; +/* +/* static int permit_sasl_auth(state, authenticated, unauthenticated) +/* SMTPD_STATE *state; +/* int authenticated; +/* int unauthenticated; +/* DESCRIPTION +/* This module contains random chunks of code that implement +/* the SMTP protocol interface for SASL negotiation. The goal +/* is to reduce clutter of the main SMTP server source code. +/* +/* smtpd_sasl_auth_cmd() implements the AUTH command and updates +/* the following state structure members: +/* .IP sasl_method +/* The authentication method that was successfully applied. +/* This member is a null pointer in the absence of successful +/* authentication. +/* .IP sasl_username +/* The username that was successfully authenticated. +/* This member is a null pointer in the absence of successful +/* authentication. +/* .PP +/* smtpd_sasl_auth_reset() cleans up after the AUTH command. +/* This is required before smtpd_sasl_auth_cmd() can be used again. +/* This may be called even if SASL authentication is turned off +/* in main.cf. +/* +/* smtpd_sasl_auth_extern() records authentication information +/* that is received from an external source. +/* This may be called even if SASL authentication is turned off +/* in main.cf. +/* +/* smtpd_sasl_mail_opt() implements the SASL-specific AUTH=sender +/* option to the MAIL FROM command. The result is an error response +/* in case of problems. +/* +/* smtpd_sasl_mail_reset() performs cleanup for the SASL-specific +/* AUTH=sender option to the MAIL FROM command. +/* +/* permit_sasl_auth() permits access from an authenticated client. +/* This test fails for clients that use anonymous authentication. +/* +/* Arguments: +/* .IP state +/* SMTP session context. +/* .IP argc +/* Number of command line tokens. +/* .IP argv +/* The command line parsed into tokens. +/* .IP sender +/* Sender address from the AUTH=sender option in the MAIL FROM +/* command. +/* .IP authenticated +/* Result for authenticated client. +/* .IP unauthenticated +/* Result for unauthenticated client. +/* DIAGNOSTICS +/* All errors are fatal. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Initial implementation by: +/* Till Franke +/* SuSE Rhein/Main AG +/* 65760 Eschborn, Germany +/* +/* Adopted by: +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/* +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/* +/* TLS support originally by: +/* Lutz Jaenicke +/* BTU Cottbus +/* Allgemeine Elektrotechnik +/* Universitaetsplatz 3-4 +/* D-03044 Cottbus, Germany +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <string.h> + +#ifdef STRCASECMP_IN_STRINGS_H +#include <strings.h> +#endif + +/* Utility library. */ + +#include <msg.h> +#include <mymalloc.h> +#include <stringops.h> + +/* Global library. */ + +#include <mail_params.h> +#include <mail_proto.h> +#include <mail_error.h> +#include <ehlo_mask.h> + +/* Application-specific. */ + +#include "smtpd.h" +#include "smtpd_token.h" +#include "smtpd_chat.h" +#include "smtpd_sasl_proto.h" +#include "smtpd_sasl_glue.h" + +#ifdef USE_SASL_AUTH + +/* smtpd_sasl_auth_cmd - process AUTH command */ + +int smtpd_sasl_auth_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) +{ + char *auth_mechanism; + char *initial_response; + const char *err; + + if (var_helo_required && state->helo_name == 0) { + state->error_mask |= MAIL_ERROR_POLICY; + smtpd_chat_reply(state, "503 5.5.1 Error: send HELO/EHLO first"); + return (-1); + } + if (SMTPD_STAND_ALONE(state) || !smtpd_sasl_is_active(state) + || (state->ehlo_discard_mask & EHLO_MASK_AUTH)) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "503 5.5.1 Error: authentication not enabled"); + return (-1); + } + if (SMTPD_IN_MAIL_TRANSACTION(state)) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "503 5.5.1 Error: MAIL transaction in progress"); + return (-1); + } + if (state->milters != 0 && (err = milter_other_event(state->milters)) != 0) { + if (err[0] == '5') { + state->error_mask |= MAIL_ERROR_POLICY; + smtpd_chat_reply(state, "%s", err); + return (-1); + } + /* Sendmail compatibility: map 4xx into 454. */ + else if (err[0] == '4') { + state->error_mask |= MAIL_ERROR_POLICY; + smtpd_chat_reply(state, "454 4.3.0 Try again later"); + return (-1); + } + } +#ifdef USE_TLS + if (var_smtpd_tls_auth_only && !state->tls_context) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + /* RFC 4954, Section 4. */ + smtpd_chat_reply(state, "504 5.5.4 Encryption required for requested authentication mechanism"); + return (-1); + } +#endif + if (state->sasl_username) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "503 5.5.1 Error: already authenticated"); + return (-1); + } + if (argc < 2 || argc > 3) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "501 5.5.4 Syntax: AUTH mechanism"); + return (-1); + } + /* Don't reuse the SASL handle after authentication failure. */ +#ifndef XSASL_TYPE_CYRUS +#define XSASL_TYPE_CYRUS "cyrus" +#endif + if (state->flags & SMTPD_FLAG_AUTH_USED) { + smtpd_sasl_deactivate(state); +#ifdef USE_TLS + if (state->tls_context != 0) + smtpd_sasl_activate(state, VAR_SMTPD_SASL_TLS_OPTS, + var_smtpd_sasl_tls_opts); + else +#endif + smtpd_sasl_activate(state, VAR_SMTPD_SASL_OPTS, + var_smtpd_sasl_opts); + } else if (strcmp(var_smtpd_sasl_type, XSASL_TYPE_CYRUS) == 0) { + state->flags |= SMTPD_FLAG_AUTH_USED; + } + + /* + * All authentication failures shall be logged. The 5xx reply code from + * the SASL authentication routine triggers tar-pit delays, which help to + * slow down password guessing attacks. + */ + auth_mechanism = argv[1].strval; + initial_response = (argc == 3 ? argv[2].strval : 0); + return (smtpd_sasl_authenticate(state, auth_mechanism, initial_response)); +} + +/* smtpd_sasl_mail_opt - SASL-specific MAIL FROM option */ + +char *smtpd_sasl_mail_opt(SMTPD_STATE *state, const char *addr) +{ + + /* + * Do not store raw RFC2554 protocol data. + */ +#if 0 + if (state->sasl_username == 0) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + return ("503 5.5.4 Error: send AUTH command first"); + } +#endif + if (state->sasl_sender != 0) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + return ("503 5.5.4 Error: multiple AUTH= options"); + } + if (strcmp(addr, "<>") != 0) { + state->sasl_sender = mystrdup(addr); + printable(state->sasl_sender, '?'); + } + return (0); +} + +/* smtpd_sasl_mail_reset - SASL-specific MAIL FROM cleanup */ + +void smtpd_sasl_mail_reset(SMTPD_STATE *state) +{ + if (state->sasl_sender) { + myfree(state->sasl_sender); + state->sasl_sender = 0; + } +} + +/* permit_sasl_auth - OK for authenticated connection */ + +int permit_sasl_auth(SMTPD_STATE *state, int ifyes, int ifnot) +{ + if (state->sasl_method && strcasecmp(state->sasl_method, "anonymous")) + return (ifyes); + return (ifnot); +} + +#endif |