/*++
/* NAME
/* tlsrpt_wrapper 3
/* SUMMARY
/* TLSRPT support for the SMTP and TLS protocol engines
/* SYNOPSIS
/* #include <tlsrpt_wrapper.h>
/*
/* #ifdef USE_TLS
/* #ifdef USE_TLSRPT
/* TLS_RPT *trw_create(
/* const char *rpt_socket_name,
/* const char *rpt_policy_domain,
/* const char *rpt_policy_string,
/* int skip_reused_hs)
/*
/* void trw_free(
/* TLSRPT_WRAPPER *trw)
/*
/* void trw_set_tls_policy(
/* TLSRPT_WRAPPER *trw,
/* tlsrpt_policy_type_t tls_policy_type,
/* const char *const *tls_policy_strings,
/* const char *tls_policy_domain
/* const char *const *mx_host_patterns)
/*
/* void trw_set_tcp_connection(
/* TLSRPT_WRAPPER *trw,
/* const char *snd_mta_addr,
/* const char *rcv_mta_name,
/* const char *rcv_mta_addr)
/*
/* void trw_set_ehlo_resp(
/* TLSRPT_WRAPPER *trw,
/* const char *rcv_mta_ehlo)
/*
/* void trw_report_failure(
/* TLSRPT_WRAPPER *trw,
/* tlsrpt_failure_t failure_type,
/* const char *additional_info,
/* const char *failure_reason)
/*
/* void trw_report_success(
/* TLSRPT_WRAPPER *trw)
/*
/* int trw_is_reported(
/* TLSRPT_WRAPPER *trw)
/*
/* int trw_is_skip_reused_hs(
/* TLSRPT_WRAPPER *trw)
/*
/* tlsrpt_policy_type_t convert_tlsrpt_policy_type(
/* const char *policy_type)
/*
/* tlsrpt_failure_t convert_tlsrpt_policy_failure(
/* const char *policy_failure)
/* #endif /* USE_TLS_RPT */
/*
/* int valid_tlsrpt_policy_type(
/* const char *type_name)
/*
/* int valid_tlsrpt_policy_failure(
/* const char *failure_name)
/* #endif /* USE_TLS */
/* POSTFIX ARCHITECTURE, BOTTOM-UP VIEW
/* .ad
/* .fi
/* This module encapsulates TLSRPT support for Postfix's
/* multi-process and multi-layer architecture. The text that follows
/* explains the purpose of this software layer.
/*
/* First, Postfix TLSRPT support uses the TLSRPT client library
/* from sys4.de. That library makes the reasonable assumption that
/* all calls concerning one SMTP session will be made from within
/* one process.
/*
/* Second, some TLS errors are detected in the SMTP protocol
/* engine (example: a remote SMTP server does not announce STARTTLS
/* support), while other TLS errors are detected in the TLS protocol
/* engine (example: certificate verification error).
/*
/* Third, the Postfix TLS protocol engine may be located in a
/* different process than the SMTP protocol engine. And even if the
/* two are located in the same process, the TLS protocol engine knows
/* nothing about SMTP. Hence, there needs to be an abstraction that
/* isolates the TLS protocol engine from the SMTP-specific details
/* of TLSRPT.
/*
/* Fourth, Postfix has a pipelined and layered architecture where
/* each process (or architectural layer) handles a problem as it
/* runs into it, instead of reporting problem details back to its
/* pipeline predecessor (or back to a higher architectural layer).
/* TLSRPT_WRAPPER IMPLEMENTATION
/* .ad
/* .fi
/* At a high level, the SMTP protocol engine encapsulates SMTP
/* session and TLS policy information in an opaque TLSRPT_WRAPPER
/* object, and passes that object to the TLS protocol engine. The
/* TLS protocol engine can invoke TLSRPT_WRAPPER methods to report a
/* TLS error through the sys4.de TLSRPT client library. In a similar
/* manner, the SMTP protocol engine can invoke TLSRPT_WRAPPER object
/* methods to report a TLS error or success.
/*
/* At a low level, The Postfix SMTP protocol engine (smtp_proto.c)
/* reports TLS errors when TLS support is required but unavailable,
/* or requests the Postfix TLS protocol engine to perform a TLS
/* protocol handshake over an open SMTP connection. The SMTP
/* protocol engine either calls the TLS protocol engine directly,
/* or calls it over local IPC in a tlsproxy(8) process.
/*
/* The TLS protocol engine may report a TLS error by invoking
/* TLSRPT_WRAPPER methods, and either returns no TLS session object,
/* or a TLS session object for a completed handshake. The TLS session
/* object will indicate if the TLS protocol engine reported any
/* TLS error through TLSRPT (for example an error that resulted in
/* a successful TLS handshake with a downgraded TLS security level).
/*
/* The Postfix SMTP protocol engine reports success or failure
/* by invoking TLSRPT_WRAPPER methods, depending on whether all
/* matching requirements were satisfied. The SMTP protocol engine
/* does not report success or failure by invoking TLSRPT_WRAPPER
/* methods if the TLS protocol engine already reported a failure.
/* TLSRPT_WRAPPER API
/* .ad
/* .fi
/* The functions below must be called in a specific order. All
/* string inputs are copied. If a required call is missing then
/* the request will be ignored, and a warning will be logged,
/* but this not affect email deliveries.
/* .PP
/* trw_create() must be called before other trw_xxx() requests can
/* be made. Arguments:
/* .IP rpt_socket_name
/* The name of a socket that will be managed by local TLSRPT
/* infrastructure.
/* .IP rpt_policy_domain
/* The TLSRPT policy domain name, i.e. the domain that wishes to
/* receive TLSRPT summary reports. An internationalized domain name
/* must be in A-label form (i.e. punycode).
/* .IP rpt_policy_string
/* The TLSRPT policy record content, i.e. how to submit TLSRPT
/* summary reports.
/* .IP skip_reused_hs
/* If non-zero, do not report the TLSRPT status for TLS handshakes
/* that reuse a previously-negotiated TLS session; such sessions
/* were already reported when they were used for the first time.
/* .PP
/* trw_free() destroys storage allocated with other trw_xxx()
/* requests.
/* .PP
/* trw_set_tls_policy() must be called by the SMTP protocol engine
/* after it found a DANE, STS, or no policy, and before it tries to
/* establish a new SMTP connection. This function clears information
/* that was specified earlier with trw_set_tls_policy() or
/* trw_set_tcp_connection(), and resets whether trw_report_failure()
/* or trw_report_success() were called. Mapping from arguments to
/* TLSRPT report fields:
/* .IP tls_policy_type
/* policies[].policy.policy-type.
/* .IP tls_policy_strings (may be null)
/* policies[].policy.policy-string[]. Ignored if the tls_policy_type
/* value is TLSRPT_NO_POLICY_FOUND.
/* .IP tls_policy_domain (may be null)
/* policies[].policy.policy-domain. If null, this defaults to the
/* TLSRPT policy domain.
/* .IP mx_host_patterns (may be null)
/* policies[].policy.mx-host[]. Ignored if the tls_policy_type
/* value is TLSRPT_NO_POLICY_FOUND.
/* .PP
/* trw_set_tcp_connection() and trw_set_ehlo_resp() are optionally
/* called by the SMTP protcol engine, after it has established
/* a new SMTP connection, before it requests a TLS protocol
/* handshake. Mapping from arguments to TLSRPT report fields:
/* .IP snd_mta_addr (may be null)
/* policies[].failure-details[].sending-mta-ip.
/* .IP rcv_mta_name (may be null)
/* policies[].failure-details[].receiving-mx-hostname.
/* .IP rcv_mta_addr (may be null)
/* policies[].failure-details[].receiving-ip.
/* .PP
/* trw_set_ehlo_resp() is optionally called by the SMTP protcol
/* engine to pass on the EHLO response. Presumably this is the EHLO
/* response before STARTTLS (TLSRPT is primarily interested in
/* pre-handshake and handshake errors).
/* .IP rcv_mta_ehlo (may be null)
/* policies[].failure-details[].receiving-mx-helo.
/* .PP
/* trw_report_failure() is called by the TLS protocol engine or
/* SMTP protocol engine to report a TLS error. The result value
/* is 0 for success, -1 for failure as indicated with the errno
/* value. The call is successfully skipped if information is missing
/* or if failure or success were already reported for the
/* connection. Mapping from arguments to TLSRPT report fields:
/* .IP failure_type
/* policies[].failure-details[].result-type.
/* .IP additional_info (may be null)
/* policies[].failure-details[].additional-information.
/* .IP failure_reason (may be null)
/* policies[].failure-details[].failure-reason-code
/* .PP
/* trw_report_success() is called by the SMTP protocol engine
/* to report a successful TLS handshake. The result value is
/* 0 for success, -1 for failure with errno indicating the
/* error type. The call is successfully skipped if information if
/* missing or if failure or success were already reported for
/* the connection.
/* .PP
/* trw_is_reported() returns non-zero when the contents of the
/* specified TLSRPT_WRAPPER have been reported.
/* .PP
/* trw_is_skip_reused_hs() returns non-zero if the skip_reused_hs
/* argument of trw_create() was non-zero.
/* .PP
/* convert_tlsrpt_policy_type() and convert_tlsrpt_policy_failure()
/* convert a valid policy type or failure name to the corresponding
/* enum value. The result is < 0 if the name is not valid.
/* .PP
/* valid_tlsrpt_policy_type() and valid_tlsrpt_policy_failure()
/* return non-zero if the specified policy type or failure name
/* is valid in TLSRPT. These functions do not require that the
/* module is built with TLSRPT support. This allows the names to
/* be used even if TLSRPT is disabled.
/* DIAGNOSTICS
/* Some functions will log a warning when information is missing.
/* Such warnings will not affect the operation of the SMTP or TLS
/* protocol engine.
/* BUGS
/* This implementation is suitable to report successful TLS policy
/* compliance, and to report a failure that prevents TLS policy
/* compliance (example: all TLSA records are unusable). Do not use
/* this implementation to report other errors (example: some TLSA
/* record is non-parsable).
/* SEE ALSO
/* https://github.com/sys4/tlsrpt, TLSRPT client library
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* porcupine.org
/*--*/
#if defined(USE_TLS)
/*
* System library.
*/
#include <sys_defs.h>
#include <errno.h>
#include <string.h>
#if defined(USE_TLSRPT)
#include <tlsrpt.h>
#endif
#if !
defined(TLSRPT_PREREQ)
#define TLSRPT_PREREQ(maj, min) \
(
defined(TLSRPT_VERSION_MAJOR) && \
((TLSRPT_VERSION_MAJOR <<
16) + TLSRPT_VERSION_MINOR >= \
((maj) <<
16) + (min)))
#endif
/*
* Utility library.
*/
#include <argv.h>
#include <msg.h>
#include <mymalloc.h>
#include <name_code.h>
#include <stringops.h>
/*
* Some functions are not #ifdef USE_TLSRPT.
*/
#define TLSRPT_WRAPPER_INTERNAL
#include <tlsrpt_wrapper.h>
#if defined(USE_TLSRPT)
/*
* Macros to make repetitive code more readable.
*/
#define MYFREE_IF_SET(member)
do { \
if (member) \
myfree(member); \
}
while (
0)
#define MYFREE_IF_SET_AND_CLEAR(member, value)
do { \
if (member) { \
myfree(member); \
(member) =
0; \
} \
}
while (
0)
#define MYFREE_IF_SET_AND_COPY(member, value)
do { \
MYFREE_IF_SET(member); \
(member) = (value) ? mystrdup(value) :
0; \
}
while (
0)
#define ARGV_FREE_IF_SET(member)
do { \
if (member) \
argv_free(member); \
}
while (
0)
#define ARGV_FREE_IF_SET_AND_CLEAR(member)
do { \
if (member) { \
argv_free(member); \
(member) =
0; \
} \
}
while (
0)
#define ARGV_FREE_IF_SET_AND_COPY(member, value)
do { \
ARGV_FREE_IF_SET(member); \
(member) = (value) ? argv_addv((ARGV *)
0, value) :
0; \
}
while (
0)
/* trw_create - create initial TLSRPT_WRAPPER instance */
TLSRPT_WRAPPER *trw_create(
const char *rpt_socket_name,
const char *rpt_policy_domain,
const char *rpt_policy_string,
int skip_reused_hs)
{
const char myname[] =
"trw_create";
TLSRPT_WRAPPER *trw;
if (msg_verbose >
1)
msg_info(
"%s(rpt_socket_name=%s, rpt_policy_domain=%s, "
"rpt_policy_string=%s, skip_reused_hs=%d)",
myname, rpt_socket_name, rpt_policy_domain,
rpt_policy_string, skip_reused_hs);
#if TLSRPT_PREREQ(
0,
6)
if (tlsrpt_version_check(TLSRPT_VERSION_MAJOR, TLSRPT_VERSION_MINOR,
TLSRPT_VERSION_PATCH) ==
0)
msg_warn(
"run-time library vs. compile-time header version mismatch: "
"libtlsrpt API version '%s' is not compatible with "
"libtlsrpt API version '%s' ", tlsrpt_version(),
TLSRPT_VERSION_STRING);
#endif
/*
* memset() is not portable for pointer etc. types.
*/
trw = (TLSRPT_WRAPPER *) mymalloc(
sizeof(*trw));
trw->rpt_socket_name = mystrdup(rpt_socket_name);
trw->rpt_policy_domain = mystrdup(rpt_policy_domain);
trw->rpt_policy_string = mystrdup(rpt_policy_string);;
trw->tls_policy_type =
0;
trw->tls_policy_strings =
0;
trw->tls_policy_domain =
0;
trw->mx_host_patterns =
0;
trw->snd_mta_addr =
0;
trw->rcv_mta_name =
0;
trw->rcv_mta_addr =
0;
trw->rcv_mta_ehlo =
0;
trw->skip_reused_hs = skip_reused_hs;
trw->flags =
0;
return (trw);
}
/* trw_free - destroy TLSRPT_WRAPPER instance. */
void trw_free(TLSRPT_WRAPPER *trw)
{
if (msg_verbose >
1)
msg_info(
"trw_free: rpt_socket_name=%s, rpt_policy_domain=%s, ...",
trw->rpt_socket_name, trw->rpt_policy_domain);
/* Destroy fields set with trw_create(). */
myfree(trw->rpt_socket_name);
myfree(trw->rpt_policy_domain);
myfree(trw->rpt_policy_string);
/* Destroy fields set with trw_set_tls_policy(). */
ARGV_FREE_IF_SET(trw->tls_policy_strings);
MYFREE_IF_SET(trw->tls_policy_domain);
ARGV_FREE_IF_SET(trw->mx_host_patterns);
/* Destroy fields set with trw_set_tcp_connection(). */
trw_set_tcp_connection(trw, (
char *)
0, (
char *)
0, (
char *)
0);
/* Destroy fields set with trw_set_ehlo_resp(). */
trw_set_ehlo_resp(trw, (
char *)
0);
/* That's all. */
myfree((
void *) trw);
}
/* trw_set_tls_policy - set TLS policy info, clear SMTP info */
void trw_set_tls_policy(TLSRPT_WRAPPER *trw,
tlsrpt_policy_type_t tls_policy_type,
const char *
const * tls_policy_strings,
const char *tls_policy_domain,
const char *
const * mx_host_patterns)
{
const char myname[] =
"trw_set_tls_policy";
#define STR_OR_NULL(s) ((s) ? (s) :
"(Null)")
#define PSTR_OR_NULL(p) ((p) ? STR_OR_NULL(*p) :
"(Null)")
if (msg_verbose >
1)
msg_info(
"%s(tlsrpt_policy_type_t=%d, tls_policy_strings=%s..., "
"tls_policy_domain=%s, mx_host_patterns=%s...)",
myname, tls_policy_type,
PSTR_OR_NULL(tls_policy_strings),
STR_OR_NULL(tls_policy_domain),
PSTR_OR_NULL(mx_host_patterns));
trw->tls_policy_type = tls_policy_type;
if (tls_policy_domain ==
0)
tls_policy_domain = trw->rpt_policy_domain;
MYFREE_IF_SET_AND_COPY(trw->tls_policy_domain, tls_policy_domain);
if (tls_policy_type == TLSRPT_NO_POLICY_FOUND) {
ARGV_FREE_IF_SET_AND_CLEAR(trw->tls_policy_strings);
ARGV_FREE_IF_SET_AND_CLEAR(trw->mx_host_patterns);
}
else {
ARGV_FREE_IF_SET_AND_COPY(trw->tls_policy_strings, tls_policy_strings);
ARGV_FREE_IF_SET_AND_COPY(trw->mx_host_patterns, mx_host_patterns);
}
trw->flags = TRW_FLAG_HAVE_TLS_POLICY;
trw_set_tcp_connection(trw, (
char *)
0, (
char *)
0, (
char *)
0);
trw_set_ehlo_resp(trw, (
char *)
0);
}
/* trw_set_tcp_connection - set SMTP endpoint info */
void trw_set_tcp_connection(TLSRPT_WRAPPER *trw,
const char *snd_mta_addr,
const char *rcv_mta_name,
const char *rcv_mta_addr)
{
const char myname[] =
"trw_set_tcp_connection";
if (msg_verbose >
1 && (snd_mta_addr || rcv_mta_name || rcv_mta_addr))
msg_info(
"%s(snd_mta_addr=%s, rcv_mta_name=%s, rcv_mta_addr=%s)",
myname, STR_OR_NULL(snd_mta_addr),
STR_OR_NULL(rcv_mta_name), STR_OR_NULL(rcv_mta_addr));
/*
* Sanity check: usage errors are not a show stopper.
*/
if ((snd_mta_addr || rcv_mta_name || rcv_mta_addr)
&& ((trw->flags & TRW_FLAG_HAVE_TLS_POLICY) ==
0
|| (trw->flags & TRW_FLAG_REPORTED))) {
msg_warn(
"%s: missing trw_set_tls_policy call", myname);
return;
}
MYFREE_IF_SET_AND_COPY(trw->snd_mta_addr, snd_mta_addr);
MYFREE_IF_SET_AND_COPY(trw->rcv_mta_name, rcv_mta_name);
MYFREE_IF_SET_AND_COPY(trw->rcv_mta_addr, rcv_mta_addr);
}
/* trw_set_ehlo_resp - set EHLO response */
void trw_set_ehlo_resp(TLSRPT_WRAPPER *trw,
const char *rcv_mta_ehlo)
{
const char myname[] =
"trw_set_ehlo_resp";
if (msg_verbose >
1 && rcv_mta_ehlo)
msg_info(
"%s(rcv_mta_ehlo=%s)", myname, rcv_mta_ehlo);
/*
* Sanity check: usage errors are not a show stopper.
*/
if (rcv_mta_ehlo && ((trw->flags & TRW_FLAG_HAVE_TLS_POLICY) ==
0
|| (trw->flags & TRW_FLAG_REPORTED))) {
msg_warn(
"%s: missing trw_set_tls_policy call", myname);
return;
}
MYFREE_IF_SET_AND_COPY(trw->rcv_mta_ehlo, rcv_mta_ehlo);
}
/* trw_munge_report_result - helper to map and log libtlsrpt result value */
static int trw_munge_report_result(
int libtlsrpt_errorcode)
{
int err;
/*
* First, deal with the non-error cases.
*/
if (libtlsrpt_errorcode ==
0) {
return (
0);
}
/*
* Report a tlsrpt library internal error.
*/
else if (tlsrpt_error_code_is_internal(libtlsrpt_errorcode)) {
msg_warn(
"Could not report TLS handshake result to tlsrpt library:"
" %s (error %d)", tlsrpt_strerror(libtlsrpt_errorcode),
libtlsrpt_errorcode);
return (-
1);
}
/*
* Report a libc error. Do not report success if errno was zero. When
* debug logging is enabled, also log some library-internal info.
*/
else {
err = tlsrpt_errno_from_error_code(libtlsrpt_errorcode);
msg_warn(
"Could not report TLS handshake result to tlsrpt library:"
" %s (errno %d)", mystrerror(err), err);
if (msg_verbose)
msg_warn(
"Error location in tlsrpt library: %s (error %d)",
tlsrpt_strerror(libtlsrpt_errorcode),
libtlsrpt_errorcode);
errno = err;
return (-
1);
}
}
/* trw_tlsrpt_failure_to_string - make debug logging readable */
static const char *trw_failure_type_to_string(tlsrpt_failure_t failure_type)
{
static const NAME_CODE failure_types[] = {
"starttls_not_supported", TLSRPT_STARTTLS_NOT_SUPPORTED,
"certificate_host_mismatch", TLSRPT_CERTIFICATE_HOST_MISMATCH,
"certificate_not_trusted", TLSRPT_CERTIFICATE_NOT_TRUSTED,
"certificate_expired", TLSRPT_CERTIFICATE_EXPIRED,
"validation_failure", TLSRPT_VALIDATION_FAILURE,
"sts_policy_fetch_error", TLSRPT_STS_POLICY_FETCH_ERROR,
"sts_policy_invalid", TLSRPT_STS_POLICY_INVALID,
"sts_webpki_invalid", TLSRPT_STS_WEBPKI_INVALID,
"tlsa_invalid", TLSRPT_TLSA_INVALID,
"dnssec_invalid", TLSRPT_DNSSEC_INVALID,
"dane_required", TLSRPT_DANE_REQUIRED,
"unfinished_policY", TLSRPT_UNFINISHED_POLICY,
0, -
1
};
const char *cp;
static VSTRING *buf;
if ((cp = str_name_code(failure_types, failure_type)) ==
0) {
if (buf ==
0)
buf = vstring_alloc(
20);
msg_warn(
"unknown tlsrpt_failure_t value %d", failure_type);
vstring_sprintf(buf,
"failure_type_%d", failure_type);
cp = vstring_str(buf);
}
return (cp);
}
/* trw_report_failure - one-shot failure reporter */
int trw_report_failure(TLSRPT_WRAPPER *trw,
tlsrpt_failure_t failure_type,
const char *additional_info,
const char *failure_reason)
{
const char myname[] =
"trw_report_failure";
struct tlsrpt_connection_t *con;
int res;
if (msg_verbose >
1)
msg_info(
"%s(failure_type=%d, additional_info=%s, failure_reason=%s)",
myname, failure_type, STR_OR_NULL(additional_info),
STR_OR_NULL(failure_reason));
/*
* Sanity check: usage errors are not a show stopper.
*/
if ((trw->flags & TRW_FLAG_HAVE_TLS_POLICY) ==
0) {
msg_warn(
"%s: missing trw_set_tls_policy call", myname);
return (
0);
}
/*
* Report a failure only when it is seen first. If a failure was already
* reported by a lower-level function close to the root cause, then skip
* the less detailed failure report from a later caller who is further
* away from the point where trouble was found.
*
* TODO(wietse) Is it worthwhile to distinguish between failure versus
* success already reported?
*/
if (trw->flags & TRW_FLAG_REPORTED) {
if (msg_verbose)
msg_info(
"%s: success or failure already reported", myname);
return (
0);
}
trw->flags |= TRW_FLAG_REPORTED;
/* Give the local admin a clue. */
msg_info(
"TLSRPT: status=failure, domain=%s, receiving_mx=%s[%s],"
" failure_type=%s%s%s",
trw->rpt_policy_domain, trw->rcv_mta_name, trw->rcv_mta_addr,
trw_failure_type_to_string(failure_type),
failure_reason ?
", failure_reason=" :
"",
failure_reason ? failure_reason :
"");
if ((res = tlsrpt_open(&con, trw->rpt_socket_name)) ==
0) {
struct tlsrpt_dr_t *dr;
char **cpp;
if ((res = tlsrpt_init_delivery_request(&dr, con,
trw->rpt_policy_domain,
trw->rpt_policy_string)) ==
0) {
if ((res = tlsrpt_init_policy(dr, trw->tls_policy_type,
trw->tls_policy_domain)) ==
0) {
if (trw->tls_policy_strings)
for (cpp = trw->tls_policy_strings->argv;
res ==
0 && *cpp; cpp++)
res = tlsrpt_add_policy_string(dr, *cpp);
if (trw->mx_host_patterns)
for (cpp = trw->mx_host_patterns->argv;
res ==
0 && *cpp; cpp++)
res = tlsrpt_add_mx_host_pattern(dr, *cpp);
if (res ==
0)
res = tlsrpt_add_delivery_request_failure(dr,
/* failure_code= */ failure_type,
/* sending_mta_ip= */ trw->snd_mta_addr,
/* receiving_mx_hostname= */ trw->rcv_mta_name,
/* receiving_mx_helo= */ trw->rcv_mta_ehlo,
/* receiving_ip= */ trw->rcv_mta_addr,
/* additional_information= */ additional_info,
/* failure_reason_code= */ failure_reason);
if (res ==
0)
res = tlsrpt_finish_policy(dr, TLSRPT_FINAL_FAILURE);
}
if (res ==
0) {
res = tlsrpt_finish_delivery_request(&dr);
}
else {
(
void) tlsrpt_cancel_delivery_request(&dr);
}
}
(
void) tlsrpt_close(&con);
}
return (trw_munge_report_result(res));
}
/* trw_report_success - one-shot success reporter */
int trw_report_success(TLSRPT_WRAPPER *trw)
{
const char myname[] =
"trw_report_success";
struct tlsrpt_connection_t *con;
int res;
if (msg_verbose >
1)
msg_info(
"trw_report_success");
/*
* Sanity check: usage errors are not a show stopper.
*/
if ((trw->flags & TRW_FLAG_HAVE_TLS_POLICY) ==
0) {
msg_warn(
"%s: missing trw_set_tls_policy call", myname);
return (
0);
}
/* This should not happen. Log a warning. */
if (trw->flags & TRW_FLAG_REPORTED) {
msg_warn(
"%s: success or failure was already reported", myname);
return (
0);
}
trw->flags |= TRW_FLAG_REPORTED;
/* Give the local admin a clue. */
msg_info(
"TLSRPT: status=success, domain=%s, receiving_mx=%s[%s]",
trw->rpt_policy_domain, trw->rcv_mta_name, trw->rcv_mta_addr);
if ((res = tlsrpt_open(&con, trw->rpt_socket_name)) ==
0) {
struct tlsrpt_dr_t *dr;
if ((res = tlsrpt_init_delivery_request(&dr, con,
trw->rpt_policy_domain,
trw->rpt_policy_string)) ==
0) {
if ((res = tlsrpt_init_policy(dr, trw->tls_policy_type,
trw->tls_policy_domain)) ==
0) {
char **cpp;
if (trw->tls_policy_strings)
for (cpp = trw->tls_policy_strings->argv;
res ==
0 && *cpp; cpp++)
res = tlsrpt_add_policy_string(dr, *cpp);
if (trw->mx_host_patterns)
for (cpp = trw->mx_host_patterns->argv;
res ==
0 && *cpp; cpp++)
res = tlsrpt_add_mx_host_pattern(dr, *cpp);
if (res ==
0)
res = tlsrpt_finish_policy(dr, TLSRPT_FINAL_SUCCESS);
}
if (res ==
0) {
res = tlsrpt_finish_delivery_request(&dr);
}
else {
(
void) tlsrpt_cancel_delivery_request(&dr);
}
}
(
void) tlsrpt_close(&con);
}
return (trw_munge_report_result(res));
}
/* trw_is_reported - trw_report_success() or trw_report_failure() called */
int trw_is_reported(
const TLSRPT_WRAPPER *trw)
{
return (trw->flags & TRW_FLAG_REPORTED);
}
/* trw_is_skip_reused_hs - don't report TLS handshakes that reuse a session */
int trw_is_skip_reused_hs(
const TLSRPT_WRAPPER *trw)
{
return (trw->skip_reused_hs);
}
#endif /* USE_TLS_RPT */
/*
* Dummy definitions for builds without the TLSRPT library, so that we can
* still validate names.
*/
#if !
defined(USE_TLSRPT)
#define TLSRPT_POLICY_DANE
0
#define TLSRPT_POLICY_STS
0
#define TLSRPT_NO_POLICY_FOUND
0
#define TLSRPT_VALIDATION_FAILURE
0
#define TLSRPT_STS_POLICY_FETCH_ERROR
0
#define TLSRPT_STS_POLICY_INVALID
0
#define TLSRPT_STS_WEBPKI_INVALID
0
#endif
/*
* Mapping from RFC 8460 string to libtlsrpt enum for policy types and
* policy failures. The mapping assumes that all enum values are
* non-negative.
*/
const NAME_CODE tlsrpt_policy_type_mapping[] = {
"sts", TLSRPT_POLICY_STS,
"no-policy-found", TLSRPT_NO_POLICY_FOUND,
0, -
1,
};
const NAME_CODE tlsrpt_policy_failure_mapping[] = {
"sts-policy-fetch-error", TLSRPT_STS_POLICY_FETCH_ERROR,
"sts-policy-invalid", TLSRPT_STS_POLICY_INVALID,
"sts-webpki-invalid", TLSRPT_STS_WEBPKI_INVALID,
"validation-failure", TLSRPT_VALIDATION_FAILURE,
0, -
1,
};
/* valid_tlsrpt_policy_type - validate policy_type attribute value */
int valid_tlsrpt_policy_type(
const char *policy_type)
{
return (name_code(tlsrpt_policy_type_mapping, NAME_CODE_FLAG_NONE,
policy_type) >=
0);
}
/* valid_tlsrpt_policy_failure - validate policy_failure attribute value */
int valid_tlsrpt_policy_failure(
const char *policy_failure)
{
return (name_code(tlsrpt_policy_failure_mapping, NAME_CODE_FLAG_NONE,
policy_failure) >=
0);
}
#if defined(USE_TLSRPT)
/* convert_tlsrpt_policy_type - convert string to enum */
tlsrpt_policy_type_t convert_tlsrpt_policy_type(
const char *policy_type)
{
return (name_code(tlsrpt_policy_type_mapping, NAME_CODE_FLAG_NONE,
policy_type));
}
/* convert_tlsrpt_policy_failure - convert string to enum */
tlsrpt_failure_t convert_tlsrpt_policy_failure(
const char *policy_failure)
{
return (name_code(tlsrpt_policy_failure_mapping, NAME_CODE_FLAG_NONE,
policy_failure));
}
#endif /* USE_TLSRPT */
#endif /* USE_TLS */