Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postfix/src/smtp/   (Postfix Mailserver Version 3.11©)  Datei vom 13.10.2025 mit Größe 12 kB image not shown  

Quelle  smtp_tlsrpt.c

  Sprache: C
 

/*++
/* NAME
/* smtp_tlsrpt 3
/* SUMMARY
/* TLSRPT support for the SMTP protocol engine
/* SYNOPSIS
/* #include <smtp_tlsrpt.h>
/*
/* int smtp_tlsrpt_post_jail(
/* const char *sockname_pname,
/* const char *sockname_pval)
/*
/* void smtp_tlsrpt_create_wrapper(
/* SMTP_STATE *state,
/* const char *domain)
/*
/* void smtp_tlsrpt_set_tls_policy(
/* SMTP_STATE *state)
/*
/* void smtp_tlsrpt_set_tcp_connection(
/* SMTP_STATE *state)
/*
/* void smtp_tlsrpt_set_ehlo_resp(
/* SMTP_STATE *state,
/* const char *ehlo_resp)
/* DESCRIPTION
/* This module populates a TLSRPT_WRAPPER object with  a)
/* remote TLSRPT policy information, b) remote TLSA or STS policy
/* information, and c) selected SMTP connection information. This
/* object is passed to a TLS protocol engine, which may run in a
/* different process than the SMTP protocol engine. The TLS protocol
/* engine uses the TLSRPT_WRAPPER object to report a TLS handshake
/* error to a TLSRPT library. The SMTP protocol engine uses the
/* object to report a TLS handshake error or success.
/*
/* smtp_tls_post_jail() does configuration sanity checks and returns
/* 0 if successful, i.e. TLSRPT support is properly
/* configured. Otherwise it returns -1 and logs a warning. Arguments:
/* .IP sockname_pname
/* The name of a configuration parameter for the endpoint that
/* is managed by TLSRPT infrastructure. This name is used in a
/* diagnostic message.
/* .IP sockname_pval
/* The value of said parameter.
/* .PP
/* smtp_tlsrpt_create_wrapper() destroys a TLSRPT_WRAPPER referenced
/* by state->tlsrpt, and looks for a TLSRPT policy for the specified
/* domain. If one policy exists, smtp_tlsrpt_create_wrapper()
/* attaches a TLSRPT_WRAPPER instance to state->tlsrpt. Otherwise,
/* state->tlsrpt will be null, and other smtp_tlsrpt_* calls must not
/* be made. The TLSRPT_WRAPPER instance may be reused for different
/* SMTP connections for the same TLSRPT policy domain. Arguments:
/* .IP domain
/* The name of a domain that may publish a TLSRPT policy. An
/* internationalized domain name may be in U-label or A-label form
/* (the U-label form will be converted to A-label internally).
/* .PP
/* smtp_tlsrpt_set_tls_policy() updates the TLSRPT_WRAPPER
/* object with DANE or STS TLS policy information, and clears
/* information that was added with smtp_tlsrpt_set_tcp_connection()
/* or smtp_tlsrpt_set_ehlo_resp().
/* .PP
/* smtp_tlsrpt_set_tcp_connection() updates the TLSRPT_WRAPPER
/* object with TCP connection properties.
/* .PP
/* smtp_tlsrpt_set_ehlo_resp() updates the TLSRPT_WRAPPER object
/* with the SMTP server's EHLO response.
/* BUGS
/* This module inherits all limitations from tlsrpt_wrapper(3).
/* SEE ALSO
/* tlsrpt_wrapper(3) TLSRPT support for the TLS protocol engine.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* porcupine.org
/*--*/


 /*
  * System library.
  */

#include <sys_defs.h>
#include <sys/socket.h>

 /*
  * Utility library.
  */

#include <hex_code.h>
#include <midna_domain.h>
#include <msg.h>
#include <myaddrinfo.h>
#include <name_code.h>
#include <stringops.h>

 /*
  * Global library.
  */

#include <mail_params.h>

 /*
  * TLS library.
  */

#include <tls.h>
#include <tlsrpt_wrapper.h>

 /*
  * Application-specific.
  */

#include <smtp.h>

#if defined(USE_TLS) && defined(USE_TLSRPT)

static const char smtp_tlsrpt_support[] = "TLSRPT support";

/* smtp_tlsrpt_post_jail - post-jail configuration sanity check */

int     smtp_tlsrpt_post_jail(const char *sockname_pname,
                 const char *sockname_pval)
{
    if (smtp_dns_support == SMTP_DNS_DISABLED) {
 msg_warn("Cannot enable %s: DNS is disabled", smtp_tlsrpt_support);
 return (-1);
    }
    if (*sockname_pval == 0) {
 msg_warn("%s: parameter %s has empty value -- %s will be disabled",
   smtp_tlsrpt_support, sockname_pname, smtp_tlsrpt_support);
 return (-1);
    }
    return (0);
}

/* smtp_tlsrpt_find_policy - look up TLSRPT policy and verify version ID */

static DNS_RR *smtp_tlsrpt_find_policy(const char *adomain)
{
    VSTRING *why = vstring_alloc(100);
    VSTRING *qname = vstring_alloc(100);
    DNS_RR *rr_list = 0;
    DNS_RR *rr_result = 0;
    DNS_RR *rr;
    DNS_RR *next;
    int     res_opt = 0;
    int     dns_status;

    /*
     * Preliminaries.
     */

    if (smtp_dns_support == SMTP_DNS_DNSSEC)
 res_opt |= RES_USE_DNSSEC;

    /*
     * Lexical features: As specified in RFC 8460, a TLSRPT policy record
     * must start with a version field ("v=TLSRPTv1") followed by *WSP;*WSP
     * and at least one other field (we must not assume that the second field
     * will be "rua"). We leave further validation to the code that actually
     * needs it.
     */

#define TLSRPTv1_MAGIC  "v=TLSRPTv1"
#define TLSRPTv1_MAGIC_LEN (sizeof(TLSRPTv1_MAGIC) - 1)
#define RFC5234_WSP  " \t"

    /*
     * Look up TXT records. Ignore records that don't start with the expected
     * version ID, and require that there is exactly one such DNS record.
     */

    vstring_sprintf(qname, "_smtp._tls.%s", adomain);
    dns_status = dns_lookup(STR(qname), T_TXT, res_opt, &rr_list,
       (VSTRING *) 0, why);
    vstring_free(qname);
    if (dns_status != DNS_OK) {
 switch (dns_status) {
 case DNS_NOTFOUND:
 case DNS_POLICY:
     /* Expected results. */
     break;
 default:
     /* Unexpected results. */
     msg_warn("%s: policy lookup failed for %s: %s",
       smtp_tlsrpt_support, adomain, STR(why));
 }
    } else {
 for (rr = rr_list; rr; rr = next) {
     char   *cp;

     next = rr->next;
     if (strncmp(rr->data, TLSRPTv1_MAGIC, TLSRPTv1_MAGIC_LEN) != 0)
  /* Ignore non-TLSRPTv1 info. */
  continue;
     cp = rr->data + TLSRPTv1_MAGIC_LEN;

     /*
      * Should the TLSRPT library validate the entire policy for us?
     */

     if (cp[strspn(cp, RFC5234_WSP)] != ';') {
  msg_warn("%s: ignoring malformed policy for %s:, \"%s\"",
    smtp_tlsrpt_support, adomain, rr->data);
  continue;
     }
     if (rr_result) {
  msg_warn("%s: Too many TLSRPT policies for %s",
    smtp_tlsrpt_support, adomain);
  dns_rr_free(rr_result);
  rr_result = 0;
  break;
     }
     rr_result = rr;
     rr_list = dns_rr_detach(rr_list, rr);
 }
    }
    vstring_free(why);
    if (rr_list)
 dns_rr_free(rr_list);
    return (rr_result);
}

/* smtp_tlsrpt_create_wrapper - look up policy and attach TLSRPT_WRAPPER */

void    smtp_tlsrpt_create_wrapper(SMTP_STATE *state, const char *domain)
{
    const char *adomain;
    DNS_RR *rr;

    /*
     * TODO(wietse): document in a suitable place that state->tlsrpt exists
     * only if the next-hop domain announces a TLSRPT policy.
     */

    if (state->tlsrpt) {
 trw_free(state->tlsrpt);
 state->tlsrpt = 0;
    }

    /*
     * IDNA support. An internationalized domain name must be in A-label form
     * 1) for TLSRPT summaries and 2) for DNS lookups. The A-label lookup
     * result comes from a limited-size in-process cache, so it does not
     * matter that the SMTP client requests the same mapping later.
     */

#ifndef NO_EAI
    if (!allascii(domain) && (adomain = midna_domain_to_ascii(domain)) != 0) {
 if (msg_verbose)
     msg_info("%s: internationalized domain %s asciified to %s",
       smtp_tlsrpt_support, domain, adomain);
    } else
#endif
 adomain = domain;

    if ((rr = smtp_tlsrpt_find_policy(adomain)) != 0) {
 if (msg_verbose)
     msg_info("%s: domain %s has policy %.100s",
       smtp_tlsrpt_support, domain, rr->data);
 if (warn_compat_break_smtp_tlsrpt_skip_reused_hs) {
     msg_info("using using backwards-compatible default setting "
       VAR_SMTP_TLSRPT_SKIP_REUSED_HS "=yes");
     var_smtp_tlsrpt_skip_reused_hs = 1;
     warn_compat_break_smtp_tlsrpt_skip_reused_hs = 0;
 }
 state->tlsrpt = trw_create(
       /* rpt_socket_name= */ var_smtp_tlsrpt_sockname,
        /* rpt_policy_domain= */ adomain,
        /* rpt_policy_string= */ rr->data,
       /* skip_reused_hs = */ var_smtp_tlsrpt_skip_reused_hs);
 dns_rr_free(rr);
    } else {
 if (msg_verbose)
     msg_info("%s: no policy for domain %s",
       smtp_tlsrpt_support, domain);
    }
}

/* smtp_tlsrpt_set_no_policy - no policy found */

static void smtp_tlsrpt_set_no_policy(SMTP_STATE *state)
{
    trw_set_tls_policy(state->tlsrpt, TLSRPT_NO_POLICY_FOUND,
          /* tls_policy_strings= */ (const char *const *) 0,
          /* tls_policy_domain= */ (char *) 0,
          /* mx_host_patterns= */ (const char *const *) 0);
}

/* smtp_tlsrpt_set_dane_policy - add DANE policy properties */

static void smtp_tlsrpt_set_dane_policy(SMTP_STATE *state)
{
    VSTRING *buf = vstring_alloc(200);
    ARGV   *argv = argv_alloc(10);
    TLS_DANE *dane = state->tls->dane;
    TLS_TLSA *tlsa;

    for (tlsa = dane->tlsa; tlsa != 0; tlsa = tlsa->next) {
 vstring_sprintf(buf, "%d %d %d ", tlsa->usage,
   tlsa->selector, tlsa->mtype);
 hex_encode_opt(buf, (char *) tlsa->data, tlsa->length,
         HEX_ENCODE_FLAG_APPEND);
 argv_add(argv, STR(buf), (char *) 0);
    }
    trw_set_tls_policy(state->tlsrpt, TLSRPT_POLICY_TLSA,
         (const char *const *) argv->argv, dane->base_domain,
          /* mx_host_patterns= */ (const char *const *) 0);
    argv_free(argv);
    vstring_free(buf);
}

/* smtp_tlsrpt_set_ext_policy - add external policy from smtp_tls_policy_maps */

static void smtp_tlsrpt_set_ext_policy(SMTP_STATE *state)
{
    SMTP_TLS_POLICY *tls = state->tls;
    tlsrpt_policy_type_t policy_type_val;

    if (tls->ext_policy_type == 0)
 msg_panic("smtp_tlsrpt_set_ext_policy: no policy type");

#define ARGV_OR_NULL(ap) ((ap) ? (ap)->argv : 0)

    switch (policy_type_val =
     convert_tlsrpt_policy_type(tls->ext_policy_type)) {
    case TLSRPT_POLICY_STS:
 trw_set_tls_policy(state->tlsrpt, policy_type_val,
  (const char *const *) ARGV_OR_NULL(tls->ext_policy_strings),
      tls->ext_policy_domain,
      (const char *const *) ARGV_OR_NULL(tls->ext_mx_host_patterns));
 break;
    case TLSRPT_NO_POLICY_FOUND:
 smtp_tlsrpt_set_no_policy(state);
 break;
    default:
 /* Policy type must be validated in smtp_tls_policy_maps parser. */
 msg_panic("unexpected policy type: \"%s\"",
    tls->ext_policy_type);
    }

    /*
     * TODO(wietse) propagate tls->policy_failure to force policy enforcement
     * to fail with the indicated error, and prevent a false positive match
     * when a certificate would satisfy conventional PKI constraints.
     */

}

/* smtp_tlsrpt_set_tls_policy - set built-in or external policy */

void    smtp_tlsrpt_set_tls_policy(SMTP_STATE *state)
{
    SMTP_TLS_POLICY *tls = state->tls;

    if (TLS_DANE_BASED(tls->level)) {  /* Desired by local policy */
 if (tls->dane != 0)   /* Actual policy */
     smtp_tlsrpt_set_dane_policy(state);
 else     /* No policy */
     smtp_tlsrpt_set_no_policy(state);
    } else if (tls->ext_policy_type) {
 smtp_tlsrpt_set_ext_policy(state);
    } else {
 smtp_tlsrpt_set_no_policy(state);
    }
}

/* smtp_tlsrpt_set_tcp_connection - set TCP connection info from SMTP_STATE */

void    smtp_tlsrpt_set_tcp_connection(SMTP_STATE *state)
{
    SMTP_ITERATOR *iter = state->iterator;
    SMTP_SESSION *session = state->session;
    MAI_HOSTADDR_STR client_addr;
    struct sockaddr_storage addr_storage;
    SOCKADDR_SIZE addr_storage_len = sizeof(addr_storage);
    int     aierr;

    /*
     * Get the IP client address string. The Postfix SMTP_ITERATOR already
     * contains strings with server-side connection information.
     */

    if (getsockname(vstream_fileno(session->stream),
      (struct sockaddr *) &addr_storage,
      &addr_storage_len) < 0) {
 msg_warn("%s: getsockname() failed (%m)"
   " skipping the ignoring client-side IP address",
   smtp_tlsrpt_support);
 client_addr.buf[0] = 0;
    } else if ((aierr = sane_sockaddr_to_hostaddr(
       (struct sockaddr *) &addr_storage,
         &addr_storage_len, &client_addr,
        (MAI_SERVPORT_STR *) 0,
        SOCK_STREAM)) != 0) {
 msg_warn("%s: cannot convert IP address to string (%s)"
   " -- skipping the client-side IP address",
   smtp_tlsrpt_support, MAI_STRERROR(aierr));
 client_addr.buf[0] = 0;
    }
    trw_set_tcp_connection(state->tlsrpt, client_addr.buf, STR(iter->host),
      STR(iter->addr));
}

/* smtp_tlsrpt_set_ehlo_resp - format and set EHLO response */

void    smtp_tlsrpt_set_ehlo_resp(SMTP_STATE *state, const char *reply)
{
    ARGV   *argv;
    VSTRING *buf;
    char  **cpp;

    /*
     * Generate SMTP-style line breaks ("\r\n") for a multiline response.
     * Internally, smtp_chat_resp() returns a multiline response as text
     * separated with "\n". This is because Postfix by design removes
     * protocol-specific line endings on input, uses its own internal form to
     * represent text lines, and generates protocol-specific line endings on
     * output. The conversion to "\r\n" below is such an output conversion.
     */

    buf = vstring_alloc(100);
    argv = argv_split(reply, "\n");
    for (cpp = argv->argv; *cpp; cpp++) {
 vstring_strcat(buf, *cpp);
 if (cpp[1])
     vstring_strcat(buf, "\r\n");
    }
    argv_free(argv);
    trw_set_ehlo_resp(state->tlsrpt, STR(buf));
    vstring_free(buf);
}

#endif     /* USE_TLSRPT  && USE_TLS */

Messung V0.5 in Prozent
C=80 H=93 G=86

¤ Dauer der Verarbeitung: 0.24 Sekunden  (vorverarbeitet am  2026-08-09) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.