Current File : //usr/libexec/postfix/postfix-tls-script
#!/bin/sh

#++
# NAME
#	postfix-tls 1
# SUMMARY
#	Postfix TLS management
# SYNOPSIS
#	\fBpostfix tls\fR \fIsubcommand\fR
# DESCRIPTION
#	The "\fBpostfix tls \fIsubcommand\fR" feature enables
#	opportunistic TLS in the Postfix SMTP client or server, and
#	manages Postfix SMTP server private keys and certificates.
#
#	The following subcommands are available:
# .IP "\fBenable-client\fR [\fB-r \fIrandsource\fR]"
#	Enable opportunistic TLS in the Postfix SMTP client, if all
#	SMTP client TLS settings are at their default values.
#	Otherwise, suggest parameter settings without making any
#	changes.
# .sp
#	Specify \fIrandsource\fR to update the value of the
#	\fBtls_random_source\fR configuration parameter (typically,
#	/dev/urandom).  Prepend \fBdev:\fR to device paths or
#	\fBegd:\fR to EGD socket paths.
# .sp
#	See also the \fBall-default-client\fR subcommand.
# .IP "\fBenable-server\fR [\fB-r \fIrandsource\fR] [\fB-a \fIalgorithm\fR] [\fB-b \fIbits\fR] [\fIhostname\fB...\fR]"
#	Create a new private key and self-signed server certificate
#	and enable opportunistic TLS in the Postfix SMTP server,
#	if all SMTP server TLS settings are at their default values.
#	Otherwise, suggest parameter settings without making any
#	changes.
# .sp
#	The \fIrandsource\fR parameter is as with \fBenable-client\fR
#	above, and the remaining options are as with \fBnew-server-key\fR
#	below.
# .sp
#	See also the \fBall-default-server\fR subcommand.
# .IP "\fBnew-server-key\fR [\fB-a \fIalgorithm\fR] [\fB-b \fIbits\fR] [\fIhostname\fB...\fR]"
#	Create a new private key and self-signed server certificate,
#	but do not deploy them. Log and display commands to deploy
#	the new key and corresponding certificate.  Also log and
#	display commands to output a corresponding CSR or TLSA
#	records which may be needed to obtain a CA certificate or
#	to update DNS before the new key can be deployed.
# .sp
#	The \fIalgorithm\fR defaults to \fBrsa\fR, and \fIbits\fR
#	defaults to 2048.  If you choose the \fBecdsa\fR  \fIalgorithm\fR
#	then \fIbits\fR will be an EC curve name (by default
#	\fBsecp256r1\fR, also known as prime256v1).  Curves other
#	than \fBsecp256r1\fR, \fBsecp384r1\fR or \fBsecp521r1\fR
#	are unlikely to be widely interoperable.  When generating
#	EC keys, use one of these three.  DSA keys are obsolete and
#	are not supported.
# .sp
#	Note: ECDSA support requires OpenSSL 1.0.0 or later and may
#	not be available on your system.  Not all client systems
#	will support ECDSA, so you'll generally want to deploy both
#	RSA and ECDSA certificates to make use of ECDSA with
#	compatible clients and RSA with the rest. If you want to
#	deploy certificate chains with intermediate CAs for both
#	RSA and ECDSA, you'll want at least OpenSSL 1.0.2, as earlier
#	versions may not handle multiple chain files correctly.
# .sp
#	The first \fIhostname\fR argument will be the \fBCommonName\fR
#	of both the subject and issuer of the self-signed certificate.
#	It, and any additional \fIhostname\fR arguments, will also
#	be listed as DNS alternative names in the certificate.  If
#	no \fIhostname\fR is provided the value of the \fBmyhostname\fR
#	main.cf parameter will be used.
# .sp
#	For RSA, the generated private key and certificate files
#	are named \fBkey-\fIyyyymmdd-hhmmss\fB.pem\fR and
#	\fBcert-\fIyyyymmdd-hhmmss\fB.pem\fR, where \fIyyyymmdd\fR
#	is the calendar date and \fIhhmmss\fR is the time of day
#	in UTC.  For ECDSA, the file names start with \fBeckey-\fR
#	and \fBeccert-\fR instead of \fBkey-\fR and \fBcert-\fR
#	respectively.
# .sp
#	Before deploying the new key and certificate with DANE,
#	update the DNS with new DANE TLSA records, then wait for
#	secondary nameservers to update and then for stale records
#	in remote DNS caches to expire.
# .sp
#	Before deploying a new CA certificate make sure to include
#	all the required intermediate issuing CA certificates in
#	the certificate chain file.  The server certificate must
#	be the first certificate in the chain file.  Overwrite and
#	deploy the file with the original self-signed certificate
#	that was generated together with the key.
# .IP "\fBnew-server-cert\fR [\fB-a \fIalgorithm\fR] [\fB-b \fIbits\fR] [\fIhostname\fB...\fR]"
#	This is just like \fBnew-server-key\fR except that, rather
#	than generating a new private key, any currently deployed
#	private key is copied to the new key file.  Thus if you're
#	publishing DANE TLSA "3 1 1" or "3 1 2" records, there is
#	no need to update DNS records.  The \fIalgorithm\fR and
#	\fIbits\fR arguments are used only if no key of the same
#	algorithm is already configured.
# .sp
#	This command is rarely needed, because the self-signed
#	certificates generated have a 100-year nominal expiration
#	time.  The underlying public key algorithms may well be
#	obsoleted by quantum computers long before then.
# .sp
#	The most plausible reason for using this command is when
#	the system hostname changes, and you'd like the name in the
#	certificate to match the new hostname (not required for
#	DANE "3 1 1", but some needlessly picky non-DANE opportunistic
#	TLS clients may log warnings or even refuse to communicate).
# .IP "\fBdeploy-server-cert \fIcertfile\fB \fIkeyfile\fR"
#	This subcommand deploys the certificates in \fIcertfile\fR
#	and private key in \fIkeyfile\fR (which are typically
#	generated by the commands above, which will also log and
#	display the full command needed to deploy the generated key
#	and certificate).  After the new certificate and key are
#	deployed any obsolete keys and certificates may be removed
#	by hand.   The \fIkeyfile\fR and \fIcertfile\fR filenames
#	may be relative to the Postfix configuration directory.
# .IP "\fBoutput-server-csr\fR [\fB-k \fIkeyfile\fR] [\fIhostname\fB...\fR]"
#	Write to stdout a certificate signing request (CSR) for the
#	specified \fIkeyfile\fR.
# .sp
#	Instead of an absolute pathname or a pathname relative to
#	$config_directory, \fIkeyfile\fR may specify one of the
#	supported key algorithm names (see "\fBpostconf -T
#	public-key-algorithms\fR"). In that case, the corresponding
#	setting from main.cf is used to locate the \fIkeyfile\fR.
#	The default \fIkeyfile\fR value is \fBrsa\fR.
# .sp
#	Zero or more \fIhostname\fR values can be specified.  The
#	default \fIhostname\fR is the value of \fBmyhostname\fR
#	main.cf parameter.
# .IP "\fBoutput-server-tlsa\fR [\fB-h \fIhostname\fR] [\fIkeyfile\fB...\fR]"
#	Write to stdout a DANE TLSA RRset suitable for a port 25
#	SMTP server on host \fIhostname\fR with keys from any of
#	the specified \fIkeyfile\fR values.  The default \fIhostname\fR
#	is the value of the \fBmyhostname\fR main.cf parameter.
# .sp
#	Instead of absolute pathnames or pathnames relative to
#	$config_directory, the \fIkeyfile\fR list may specify
#	names of supported public key algorithms (see "\fBpostconf
#	-T public-key-algorithms\fR").  In that case, the actual
#	\fIkeyfile\fR list uses the values of the corresponding
#	Postfix server TLS key file parameters.  If a parameter
#	value is empty or equal to \fBnone\fR, then no TLSA record
#	is output for that algorithm.
# .sp
#	The default \fIkeyfile\fR list consists of the two supported
#	algorithms \fBrsa\fR and \fBecdsa\fR.
# AUXILIARY COMMANDS
# .IP "\fBall-default-client\fR"
#	Exit with status 0 (success) if all SMTP client TLS settings are
#	at their default values.  Otherwise, exit with a non-zero status.
#	This is typically used as follows:
# .sp
#	\fBpostfix tls all-default-client &&
#		postfix tls enable-client\fR
# .IP "\fBall-default-server\fR"
#	Exit with status 0 (success) if all SMTP server TLS settings are
#	at their default values.  Otherwise, exit with a non-zero status.
#	This is typically used as follows:
# .sp
#	\fBpostfix tls all-default-server &&
#		postfix tls enable-server\fR
# CONFIGURATION PARAMETERS
# .ad 
# .fi
#	The "\fBpostfix tls \fIsubcommand\fR" feature reads
#	or updates the following configuration parameters.
# .IP "\fBcommand_directory (see 'postconf -d' output)\fR"
#	The location of all postfix administrative commands.
# .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
#	The default location of the Postfix main.cf and master.cf
#	configuration files.
# .IP "\fBopenssl_path (openssl)\fR"
#	The location of the OpenSSL command line program \fBopenssl\fR(1).
# .IP "\fBsmtp_tls_loglevel (0)\fR"
#	Enable additional Postfix SMTP client logging of TLS activity.
# .IP "\fBsmtp_tls_security_level (empty)\fR"
#	The default SMTP TLS security level for the Postfix SMTP client;
#	when a non-empty value is specified, this overrides the obsolete
#	parameters smtp_use_tls, smtp_enforce_tls, and smtp_tls_enforce_peername.
# .IP "\fBsmtp_tls_session_cache_database (empty)\fR"
#	Name of the file containing the optional Postfix SMTP client
#	TLS session cache.
# .IP "\fBsmtpd_tls_cert_file (empty)\fR"
#	File with the Postfix SMTP server RSA certificate in PEM format.
# .IP "\fBsmtpd_tls_eccert_file (empty)\fR"
#	File with the Postfix SMTP server ECDSA certificate in PEM format.
# .IP "\fBsmtpd_tls_eckey_file ($smtpd_tls_eccert_file)\fR"
#	File with the Postfix SMTP server ECDSA private key in PEM format.
# .IP "\fBsmtpd_tls_key_file ($smtpd_tls_cert_file)\fR"
#	File with the Postfix SMTP server RSA private key in PEM format.
# .IP "\fBsmtpd_tls_loglevel (0)\fR"
#	Enable additional Postfix SMTP server logging of TLS activity.
# .IP "\fBsmtpd_tls_received_header (no)\fR"
#	Request that the Postfix SMTP server produces Received:  message
#	headers that include information about the protocol and cipher used,
#	as well as the remote SMTP client CommonName and client certificate issuer
#	CommonName.
# .IP "\fBsmtpd_tls_security_level (empty)\fR"
#	The SMTP TLS security level for the Postfix SMTP server; when
#	a non-empty value is specified, this overrides the obsolete parameters
#	smtpd_use_tls and smtpd_enforce_tls.
# .IP "\fBtls_random_source (see 'postconf -d' output)\fR"
#	The external entropy source for the in-memory \fBtlsmgr\fR(8) pseudo
#	random number generator (PRNG) pool.
# SEE ALSO
#	master(8) Postfix master program
#	postfix(1) Postfix administrative interface
# README FILES
# .ad
# .fi
#	Use "\fBpostconf readme_directory\fR" or
#	"\fBpostconf html_directory\fR" to locate this information.
# .na
# .nf
#	TLS_README, Postfix TLS configuration and operation
# LICENSE
# .ad
# .fi
#	The Secure Mailer license must be distributed with this software.
# HISTORY
#	The "\fBpostfix tls\fR" command was introduced with Postfix
#	version 3.1.
# AUTHOR(S)
#	Viktor Dukhovni
#--

RSA_BITS=2048		# default
EC_CURVE=secp256r1	# default

case $daemon_directory in
"") echo This script must be run by the postfix command. 1>&2
    echo Do not run directly. 1>&2
    exit 1;;
esac

umask 022
SHELL=/bin/sh

postconf=$command_directory/postconf
LOGGER="$command_directory/postlog -t $MAIL_LOGTAG/postfix-tls-script"
INFO="$LOGGER -p info"
WARN="$LOGGER -p warn"
ERROR="$LOGGER -p error"
FATAL="$LOGGER -p fatal"

# Overwrite SMTP client and server settings only when these are at defaults.
client_settings="
    smtp_use_tls 
    smtp_enforce_tls 
    smtp_tls_enforce_peername 
    smtp_tls_security_level 
    smtp_tls_cert_file
    smtp_tls_dcert_file
    smtp_tls_eccert_file
"

server_settings="
    smtpd_use_tls 
    smtpd_enforce_tls 
    smtpd_tls_security_level 
    smtpd_tls_cert_file
    smtpd_tls_dcert_file
    smtpd_tls_eccert_file
"

#
# Can't do much without these in place.
#
cd $command_directory || {
    # Let's hope there's a "postlog" somewhere else on the PATH
    FATAL="postlog -p fatal -t $MAIL_LOGTAG/postfix-tls-script"
    msg="no Postfix command directory '${command_directory}'"
    $FATAL "$msg" || { echo "$msg" >&2; sleep 1; }
    exit 1
}

check_getopt() {
    OPTIND=1
    a=
    b=
    c=
    set -- -a 1 -b 2 -c -- -pos
    while getopts :a:b:c o
    do
	case $o in
	a) a="${OPTARG}";;
	b) b="${OPTARG}";;
	c) c=3;;
	*) return 1;;
	esac
    done
    shift `expr ${OPTIND} - 1`
    if [ "${a}" != "1" -o "${b}" != 2 -o "${c}" != 3 \
	 -o "${OPTIND}" -ne 7 -o "$1" != "-pos" ]; then
	return 1
    fi
}

check_getopt || {
    $FATAL "/bin/sh does not implement a compatible 'getopts' built-in"
    exit 1
}

# ----- BEGIN OpenSSL-specific -----

# No need to set the location of the OpenSSL command in each Postfix instance,
# the value from the default instance is used for all instances.
#
default_config_directory=`$postconf -dh config_directory`
openssl=`$postconf -c $default_config_directory -xh openssl_path`
"$openssl" version >/dev/null 2>&1 || {
    $FATAL "No working openssl(1) command found with 'openssl_path = $openssl'"
    exit 1
}

# ----- END OpenSSL-specific -----

test -n "$config_directory" -a -d "$config_directory" || {
    $FATAL no Postfix configuration directory $config_directory!
    exit 1
}

# Do we support TLS and if so which algorithms?
#
$postconf -T compile-version | grep . >/dev/null || {
    mail_version=`$postconf -dh mail_version`
    $FATAL "Postfix $mail_version is not compiled with TLS support"
    exit 1
}
rsa=
ecdsa=
for _algo in `$postconf -T public-key-algorithms | egrep '^(rsa|ecdsa)$'`
do
    eval $_algo=$_algo
done

# ----- BEGIN OpenSSL-specific -----

if [ -n "${ecdsa}" ]; then
    $openssl ecparam -name secp256r1 >/dev/null 2>&1 || {
	cat <<-EOM | $WARN
	Postfix supports ECDSA, but the $openssl command does not. Consider
	setting the openssl_path parameter to a more capable version of the
	command-line utility than $openssl (with PATH=$PATH).
	EOM
	ecdsa=
    }
fi
if [ -n "${rsa}" ]; then
   DEFALG=rsa
elif [ -n "${ecdsa}" ]; then
   DEFALG=ecdsa
else
    mail_version=`$postconf -dh mail_version`
    $FATAL "Postfix $mail_version does not support either RSA or ECDSA"
    exit 1
fi

# Make sure stdin is open when testing
if [ -r /dev/stdin ] < /dev/null; then
    stdin=/dev/stdin
elif [ -r /dev/fd/0 ] </dev/null; then
    stdin=/dev/fd/0
else
    $FATAL No /dev/fd/0 or /dev/stdin found
    exit 1
fi

hex_sha256() {
    $openssl dgst -binary -sha256 | od -An -vtx1 | tr -d ' \012'
}

# We require SHA2-256 support from openssl(1)
#
null256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
tmp=`hex_sha256 </dev/null 2>/dev/null`
if [ "${tmp}" != "${null256}" ]; then
    cat <<EOF >&2
Your $openssl does not support the SHA2-256 digest algorithm. To enable
'postfix tls', install an OpenSSL that does. Install its openssl(1) command
at /usr/local/bin/openssl or other suitable location, and set the
'openssl_path' parameter in $default_config_directory/main.cf accordingly.
EOF
    $FATAL "No 'postfix tls' support when openssl(1) is obsolete"
    exit 1
fi

read_key() {
    [ -n "$1" -a -f "$1" ] || return 1

    # Old OpenSSL versions return success even for unsupported sub-commands!
    # So we inspect the output instead.	 Don't prompt if the key is password
    # protected.
    #
    while read cmd key_algo key_param cert_param; do
	$openssl $cmd -passin "pass:umask 077" -in "$1" |
	    grep . && return 0
    done 2>/dev/null <<-EOF
	rsa rsa smtpd_tls_key_file smtpd_tls_cert_file
	ec ecdsa smtpd_tls_eckey_file smtpd_tls_eccert_file
	EOF
    return 1
}

pubkey_dgst() {
    [ -n "$1" -a -f "$1" ] || return 1

    # Old OpenSSL versions return success even for unsupported sub-commands!
    # So we inspect the output instead.
    #
    for cmd in ec rsa; do
	$openssl $cmd -passin "pass:umask 077" -in "$1" -pubout |
	$openssl $cmd -pubin -outform DER |
	hex_sha256 | egrep -v "${null256}" && return 0
    done 2>/dev/null
    return 1
}

cert_pubkey_dgst() {
    [ -n "$1" -a -f "$1" ] || return 1

    # Old OpenSSL versions return success even for unsupported sub-commands!
    # So we inspect the output instead.
    #
    for cmd in ec rsa; do
	$openssl x509 -pubkey -noout -in "$1" |
	$openssl $cmd -pubin -outform DER |
	hex_sha256 | egrep -v "${null256}" && return 0
    done 2>/dev/null
    return 1
}

copy_key() {
    _algo=$1; shift
    _bits=$1; shift
    _fold=$1; shift
    _fnew=$1; shift
    _umask=`umask`

    umask 077
    read_key "${_fold}" > "${_fnew}"	# sets key_algo of current key
    _ret=$?
    umask "${_umask}"

    if [ "${_ret}" -ne 0 ]; then
	$FATAL "Error copying private key from '${_fold}' to '${_fnew}'"
	return 1
    fi
    if [ "${key_algo}" != "${_algo}" ]; then
	$FATAL "Key algorithm '$key_algo' of '${_fold}' is not '${_algo}'"
	return 1
    fi
    # XXX: We'd need C-code in postconf to portably check for compatible "bits"
}

create_key() {
    _algo=$1
    _bits=$2
    _fnew=$3
    _umask=`umask`

    case $_algo in
        "") $FATAL "Internal error: empty algorithm"; return 1;;
      $rsa) set -- "${openssl}" genrsa -out "${_fnew}" "${_bits}";;
    $ecdsa) set -- "${openssl}" ecparam -param_enc named_curve -genkey \
		-out "${_fnew}" -name "${_bits}";;
	 *) $FATAL "Internal error: bad algorithm '${_algo}'"
	    return 1;;
    esac

    umask 077
    _err=`"$@" 2>&1`
    _ret=$?
    umask "${_umask}"

    if [ "${_ret}" -ne 0 ]; then
	echo "${_err}" | $WARN
	$FATAL "error generating new ${_algo} ${_bits} private key"
	return 1
    fi
}

create_cert() {
    _k=$1; shift
    _c=$1; shift
    set_fqdn "$1"
    if [ $# -gt 0 ]; then shift; fi
    set -- "$fqdn" "$@"

    if [ -r "${_c}" ]; then
	$FATAL "New certificate file already exists: ${_c}"
	return 1
    fi

    # Generate a new self-signed (~100 year) certificate
    #
    (
	echo "default_md = sha256"
	echo "x509_extensions = v3"
	echo "prompt = yes"
	echo "distinguished_name = dn"
	echo "[dn]"
	echo "[v3]"
	echo "basicConstraints = CA:false"
	echo "subjectKeyIdentifier = hash"
	echo "extendedKeyUsage = serverAuth, clientAuth"
	echo "subjectAltName = @alts"
	echo "[alts]"
	i=1; for dns in "$@"; do
	    # XXX map empty to $myhostname
	    echo "DNS.$i = $dns"
	    i=`expr $i + 1`
	done
    ) | $openssl req -x509 -config $stdin -new -key "${_k}" \
	    -subj "/CN=$fqdn" -days 36525 -out "${_c}" || {
	rm -f "${_c}" "${_k}"
	$FATAL "error generating self-signed SSL certificate"
	return 1
    }
}

output_server_csr() {
    set_keyfile "$1" || return 1
    shift
    set_fqdn "$1" || return 1
    shift
    set -- "$fqdn" "$@"
    (
	echo "default_md = sha256"
	echo "req_extensions = v3"
	echo "prompt = yes"
	echo "distinguished_name = dn"
	echo "[dn]"
	echo "[v3]"
	echo "subjectKeyIdentifier = hash"
	echo "extendedKeyUsage = serverAuth, clientAuth"
	echo "subjectAltName = @alts"
	echo "[alts]"
	i=1; for dns in "$@"; do
	    echo "DNS.$i = $dns"
	    i=`expr $i + 1`
	done
    ) | $openssl req -config $stdin -new -key "$keyfile" -subj /
}

# ----- END OpenSSL-specific -----

info_enable_client() {
	cat <<-EOM
	*** Non-default SMTP client TLS settings detected, no changes made.
	For opportunistic TLS in the Postfix SMTP client, the below settings
	are typical:
	  smtp_tls_security_level = may
	  smtp_tls_loglevel = 1
	EOM
	if get_cache_db_type dbtype
	then
	    echo "  smtp_tls_session_cache_database = ${dbtype}:\${data_directory}/smtp_scache"
	fi
}

info_client_deployed() {
	cat <<-EOM
	Enabled opportunistic TLS in the Postfix SMTP client.
	Run the command:
	  # postfix reload
	if you want the new settings to take effect immediately.
	EOM
}

info_enable_server() {
	cat <<-EOM
	*** Non-default SMTP server TLS settings detected, no changes made.
	For opportunistic TLS in the Postfix SMTP server, the below settings
	are typical:
	  smtpd_tls_security_level = may
	  smtpd_tls_loglevel = 1
	You can use "postfix tls new-server-cert" to create a new certificate.
	Or, "postfix tls new-server-key" to also force a new private key.
	If you publish DANE TLSA records, see:
	  https://tools.ietf.org/html/rfc7671#section-8
	  https://tools.ietf.org/html/rfc7671#section-5.1
	  https://tools.ietf.org/html/rfc7671#section-5.2
	  https://community.letsencrypt.org/t/please-avoid-3-0-1-and-3-0-2-dane-tlsa-records-with-le-certificates/7022
	EOM
}

# args: certfile keyfile deploy
info_created() {
	cat <<-EOM
	New private key and self-signed certificate created. To deploy run:
	  # postfix tls deploy-server-cert $1 $2
	EOM
}

# args: certfile keyfile deploy
info_server_deployed() {
	if [ "$3" = "enable" ]; then
	    echo "Enabled opportunistic TLS in the Postfix SMTP server"
	fi
	cat <<-EOM
	New TLS private key and certificate deployed.
	Run the command:
	  # postfix reload
	if you want the new settings to take effect immediately.
	EOM
}

# args: certfile keyfile deploy
info_csr() {
	cat <<-EOM
	To generate a CSR run:
	  # postfix tls output-server-csr -k $2 [<hostname> ...]
	EOM
	if [ -z "$3" ]; then
	    echo "Save the signed certificate chain in $1, and deploy as above."
	else
	    echo "Save the signed certificate chain in $1."
	fi
}

# args: certfile keyfile deploy
info_tlsa() {
	# If already deployed, info for how to show all the deployed keys.
	# Otherwise, just the new keys, so that TLSA records can be updated
	# first.
	if [ -n "$3" ]; then shift $#; fi
	cat <<-EOM
	To generate TLSA records run:
	  # postfix tls output-server-tlsa [-h <hostname>] $2
	EOM
}

# args: certfile keyfile deploy
info_dane_dns() {
	# If already deployed, too late to wait, otherwise advise updating TLSA
	# RRs before deployment.
	if [ -n "$3" ]; then
	    cat <<-EOM
	(If you have DANE TLSA RRs, update them as soon as possible to match
	the newly deployed keys).
	EOM
	else
	    cat <<-EOM
	(deploy after updating the DNS and waiting for stale RRs to expire).
	EOM
	fi
}

set_fqdn() {
    if [ -n "$1" ]; then fqdn=$1; return 0; fi
    fqdn=`$postconf -xh myhostname` || return 1
    case $fqdn in /*) fqdn=`cat "${fqdn}"` || return 1;; esac
}

set_keyfile() {
    keyfile=$1
    case $keyfile in
       rsa) if [ -n "${rsa}" ]; then
		keyfile=`$postconf -nxh smtpd_tls_key_file`
	    else
		keyfile=
	    fi
	    ;;
     ecdsa) if [ -n "${ecdsa}" ]; then
		keyfile=`$postconf -nxh smtpd_tls_eckey_file`
	    else
		keyfile=
	    fi
	    ;;
        "") : empty ok;;
      none) : see below;;
        /*) ;;
         *) # User-specified key pathnames are relative to the configuration
	    # directory
	    keyfile="${config_directory}/${keyfile}";;
    esac
    if [ "${keyfile}" = "none" ]; then keyfile= ; fi
}

check_key() {
    read_key "$1" >/dev/null && return 0
    $FATAL "no private key found in file: $1"
    return 1
}

# Create new key or copy existing if specified.
#
ensure_key() {
    _algo=$1; shift
    _bits=$1; shift
    stamp=`TZ=UTC date +%Y%m%d-%H%M%S`

    case $_algo in
	"") $FATAL "Internal error: empty algorithm "; return 1;;
      $rsa) keyfile="${config_directory}/key-${stamp}.pem"
	    certfile="${config_directory}/cert-${stamp}.pem";;
    $ecdsa) keyfile="${config_directory}/eckey-${stamp}.pem"
	    certfile="${config_directory}/eccert-${stamp}.pem";;
	 *) $FATAL "Internal error: bad algorithm '${_algo}'"
	    return 1;;
    esac

    if [ -r "${keyfile}" ]; then
	$FATAL "New private key file already exists: ${keyfile}"
	return 1
    fi
    if [ -r "${certfile}" ]; then
	$FATAL "New certificate file already exists: ${certfile}"
	return 1
    fi

    if [ -n "$1" ]; then
	copy_key "${_algo}" "${_bits}" "$1" "${keyfile}" && return 0
    else
	create_key "${_algo}" "${_bits}" "${keyfile}" && return 0
    fi
    rm -f "${keyfile}"
    return 1
}

init_random_source() {
    tls_random_source=$1

    if [ -z "${tls_random_source}" ]; then
	tls_random_source=`$postconf -xh tls_random_source`
    fi
    if [ -n "${tls_random_source}" ]; then
	return 0
    fi
    if [ -r /dev/urandom ]
    then
	tls_random_source=dev:/dev/urandom
    else
	$FATAL no default TLS random source defined and no /dev/urandom
	return 1
    fi
}

# Don't be too clever by half.
all_default() {
    for var in "$@"
    do
	val=`$postconf -nh "${var}"`
	if [ -n "$val" ]; then return 1; fi
    done
    return 0
}

# Select read-write database type for TLS session caches.
#
get_cache_db_type() {
    var=$1; shift
    prio=0
    ret=1
    for _dbtype in `$postconf -m`
    do
	_prio=0
	case $_dbtype in
	 lmdb) _prio=2;;
	btree) _prio=1;;
	esac
	if [ "$_prio" -gt "$prio" ]
	then
	    eval "$var=\$_dbtype"
	    prio=$_prio
	    ret=0
	fi
    done
    return $ret
}

deploy_server_cert() {
    certfile=$1; shift
    keyfile=$1; shift
    deploy=$1; shift

    # Sets key_algo, key_param and cert_param
    check_key "$keyfile" || return 1

    cd=`cert_pubkey_dgst "${certfile}"` || {
	$FATAL "error computing certificate public key digest"
	return 1
    }
    kd=`pubkey_dgst "$keyfile"` || {
	$FATAL "error computing public key digest"
	return 1
    }

    if [ "$cd" != "$kd" ]; then
	$FATAL "Certificate in ${certfile} does not match key in ${keyfile}"
	return 1
    fi

    set -- \
	"${key_param} = ${keyfile}" \
	"${cert_param} = ${certfile}"

    if [ "${deploy}" = "enable" ]; then
	set -- "$@" \
	    "smtpd_tls_security_level = may" \
	    "smtpd_tls_received_header = yes" \
	    "smtpd_tls_loglevel = 1"
    fi

    if [ -n "${tls_random_source}" ]; then
	set -- "$@" "tls_random_source = ${tls_random_source}"
    fi

    # All in one shot, since postconf delays modifying "hot" main.cf files.
    $postconf -e "$@" || return 1
}

# Prepare a new cert and perhaps re-use any existing private key.
#
new_server_cert() {
    algo=$1; shift
    bits=$1; shift
    oldkey=$1; shift
    deploy=$1; shift

    # resets keyfile (copy or else new) and new certfile
    ensure_key "$algo" "$bits" "${oldkey}" || return 1
    create_cert "${keyfile}" "${certfile}" "$@" || return 1
    if [ -n "${deploy}" ]; then
	deploy_server_cert "${certfile}" "${keyfile}" "${deploy}" || return 1
    fi

    (
	if [ -z "${deploy}" ]; then
	    info_created "${certfile}" "${keyfile}" "${deploy}"
	else
	    info_server_deployed "${certfile}" "${keyfile}" "${deploy}"
	fi
	info_csr "${certfile}" "${keyfile}" "${deploy}"
	info_tlsa "${certfile}" "${keyfile}" "${deploy}"
	if [ -z "${oldkey}" ]; then
	    info_dane_dns "${certfile}" "${keyfile}" "${deploy}"
	fi
    ) | $INFO
}

enable_client() {
    if all_default ${client_settings}
    then
	set -- \
	    "smtp_tls_security_level = may" \
	    "smtp_tls_loglevel = 1"

	if get_cache_db_type dbtype
	then
	    set -- "$@" \
		"smtp_tls_session_cache_database = ${dbtype}:${data_directory}/smtp_scache"
	fi

	if [ -n "${tls_random_source}" ]; then
	    set -- "$@" "tls_random_source = ${tls_random_source}"
	fi

	# All in one shot, since postconf delays modifying "hot" main.cf files.
	$postconf -e "$@" || return 1
	info_client_deployed
    else
	info_enable_client
    fi | $INFO
}

enable_server() {
    algo=$1; shift
    bits=$1; shift

    if all_default ${server_settings}
    then
	# algo bits keyfile deploy [hostnames ...]
	new_server_cert "${algo}" "${bits}" "" "enable" "$@" || return 1
    else
	info_enable_server | $INFO
    fi
}

output_server_tlsa() {
    hostname=$1
    check_key "$2" || return 1
    data=`pubkey_dgst "$2"` || return 1
    if [ -z "$data" ]
    then
	$FATAL error computing SHA2-256 SPKI digest of "$key"
	return 1
    fi
    echo "_25._tcp.$hostname. IN TLSA 3 1 1 $data"
}

#
# Parse JCL
#
case $1 in
enable-client)
	cmd=$1; shift; OPTIND=1
	rand=
	while getopts :r: _opt
	do
	    case $_opt in
	    r) rand="${OPTARG}";;
	    *) $FATAL "usage: postfix tls $cmd [-r devrandom]"
	       exit 1;;
	    esac
	done

	# No positional arguments supported with enable-client
	if [ $# -ge "${OPTIND}" ]; then
	    $FATAL "usage: postfix tls $cmd [-r devrandom]"
	    exit 1
	fi
	# But, shift anyway
	shift `expr $OPTIND - 1`

	init_random_source "${rand}" || exit 1
	enable_client || exit 1
	;;

enable-server)
	cmd=$1; shift; OPTIND=1
	algo=$DEFALG
	bits=
	rand=
	while getopts :a:b:r: _opt
	do
	    case $_opt in
	    a) algo="${OPTARG}";;
	    b) bits="${OPTARG}";;
	    r) rand="${OPTARG}";;
	    *) $FATAL "usage: postfix tls $cmd [-a algorithm] [-b bits ] [-r devrandom] [hostname ...]"
	       exit 1;;
	    esac
	done

	# Here positional arguments are hostnames for the new certificate, as
	# many as the user wants
	shift `expr $OPTIND - 1`

	case $algo in
	    "") $FATAL "Internal error: empty algorithm "; return 1;;
	  $rsa) : ${bits:=${RSA_BITS}};;
	$ecdsa) : ${bits:=${EC_CURVE}};;
	     *) $FATAL "Unsupported private key algorithm: $algo"
		exit 1;;
	esac

	init_random_source "${rand}" || exit 1
	enable_server "${algo}" "${bits}" "$@" || exit 1
	;;

new-server-key)
	cmd=$1; shift; OPTIND=1
	algo=$DEFALG
	while getopts :a:b: _opt
	do
	    case $_opt in
	    a) algo="${OPTARG}";;
	    b) bits="${OPTARG}";;
	    *) $FATAL "usage: postfix tls $cmd [-a algorithm] [-b bits ] [hostname ...]"
	       exit 1;;
	    esac
	done

	# Here positional arguments are hostnames for the new certificate, as
	# many as the user wants
	shift `expr $OPTIND - 1`

	case $algo in
	    "") $FATAL "Internal error: empty algorithm "; return 1;;
	  $rsa) : ${bits:=${RSA_BITS}};;
	$ecdsa) : ${bits:=${EC_CURVE}};;
	     *) $FATAL "Unsupported public key algorithm: $algo"
		exit 1;;
	esac

	# Force new key
	new_server_cert "${algo}" "${bits}" "" "" "$@" || exit 1
	;;

new-server-cert)
	cmd=$1; shift; OPTIND=1
	algo=$DEFALG
	while getopts :a:b: _opt
	do
	    case $_opt in
	    a) algo="${OPTARG}";;
	    b) bits="${OPTARG}";;
	    *) $FATAL "usage: postfix tls $cmd [-a algorithm] [-b bits ] [hostname ...]"
	       exit 1;;
	    esac
	done

	# Here positional arguments are hostnames for the new certificate, as
	# many as the user wants
	shift `expr $OPTIND - 1`

	case $algo in
	    "") $FATAL "Invalid empty key algorithm"; exit 1;;
	  $rsa) : ${bits:=${RSA_BITS}};;
	$ecdsa) : ${bits:=${EC_CURVE}};;
	     *) $FATAL "Unsupported private key algorithm: $algo"
		exit 1;;
	esac

	# Existing keyfile or empty
	set_keyfile "${algo}"

	if [ -n "${keyfile}" -a ! -f "${keyfile}" ]; then
	    echo "Key file: ${keyfile} not found, creating new keys" | $WARN
	    keyfile=
	fi

	# Try to re-use (copy) existing key.
	new_server_cert "${algo}" "${bits}" "${keyfile}" "" "$@" || exit 1
	;;

deploy-server-cert)
	if [ $# -ne 3 ]; then
	    $FATAL "usage: postfix tls $1 certfile keyfile"
	    exit 1
	fi
	shift

	# User-specified key and cert pathnames are relative to the
	# configuration directory
	#
	case "${1}" in
	/*) certfile="${1}" ;;
	 *) certfile="${config_directory}/${1}" ;;
	esac
	case "${2}" in
	/*) keyfile="${2}" ;;
	 *) keyfile="${config_directory}/${2}" ;;
	esac

	deploy_server_cert "${certfile}" "${keyfile}" || exit 1
	info_server_deployed "${certfile}" "${keyfile}" "deploy" | $INFO
	;;

output-server-csr)
	cmd=$1; shift; OPTIND=1
	k=
	while getopts :k: _opt
	do
	    case $_opt in
	    k) k="${OPTARG}";;
	    *) $FATAL "usage: postfix tls $cmd [-k keyfile] [hostname ...]"
	       exit 1;;
	    esac
	done

	# Here positional arguments are hostnames for the new certificate, as
	# many as the user wants
	shift `expr $OPTIND - 1`

	if [ -n "${k}" ]; then
	    set_keyfile "${k}"
	else
	    for _algo in $rsa $ecdsa
	    do
		set_keyfile "${_algo}"
		if [ -n "${keyfile}" ]; then
		    break
		fi
	    done
	fi

	if [ -z "${keyfile}" -o ! -r "${keyfile}" ]; then
	    $FATAL "No usable keyfile specified or configured"
	    exit 1
	fi

	# Default <hostname> from $myhostname
	if [ $# -eq 0 ]; then
	    set_fqdn
	    set -- "$fqdn"
	fi

	# Output a CSR for the requested names
	output_server_csr "$keyfile" "$@" || exit 1
	;;

output-server-tlsa)
	cmd=$1; shift; OPTIND=1
	hostname=
	while getopts :h: _opt
	do
	    case $_opt in
	    h) hostname="${OPTARG}";;
	    *) $FATAL "usage: postfix tls $cmd [-h hostname] [keyfile ...]"
	       exit 1;;
	    esac
	done
	set_fqdn "${hostname}"

	# Here positional arguments are keyfiles for which we output "3 1 1"
	# TLSA RRs, as many keyfiles as the user wants.  By default the live
	# RSA and/or ECDSA keys.
	shift `expr $OPTIND - 1`

	if [ $# -eq 0 ]; then set -- $rsa $ecdsa; fi

	found=
	for _k in "$@"
	do
	    set_keyfile "${_k}"
	    if [ -z "${keyfile}" ]; then continue; fi
	    echo "; ${keyfile}"
	    output_server_tlsa "${fqdn}" "${keyfile}" || exit 1
	    found=1
	done
	if [ -z "${found}" ]; then
	    $FATAL "No usable keyfiles specified or configured"
	    exit 1
	fi
	;;

all-default-client)
	cmd=$1; shift; OPTIND=1

	# No arguments for all-default-client
	if [ $# -ge "${OPTIND}" ]; then
	    $FATAL "usage: postfix tls $cmd"
	    exit 1
	fi

	all_default ${client_settings} || exit 1
	;;

all-default-server)
	cmd=$1; shift; OPTIND=1

	# No arguments for all-default-server
	if [ $# -ge "${OPTIND}" ]; then
	    $FATAL "usage: postfix tls $cmd"
	    exit 1
	fi

	all_default ${server_settings} || exit 1
	;;

*)
	$ERROR "unknown tls command: '$1'"
	$FATAL "usage: postfix tls enable-client (or enable-server, new-server-key, new-server-cert, deploy-server-cert, output-server-csr, output-server-tlsa, all-default-client, all-default-server)"
	exit 1
	;;

esac
blog

blog

1win официальный сайт букмекера — Обзор и зеркало для входа.59

1win официальный сайт букмекера — Обзор и зеркало для входа ▶️ ИГРАТЬ Содержимое 1win Официальный Сайт Букмекера Преимущества Официального Сайта 1win Обзор и Зеркало для Входа Преимущества и Функции 1win В мире ставок и азарта 1вин является одним из самых популярных букмекеров, предлагающих широкий спектр услуг для игроков. В этой …

Read More »

Razor Shark KOSTENLOS spielen im Online-Casino – Free Demo.611

Razor Shark KOSTENLOS spielen im Online-Casino – Free Demo ▶️ SPIELEN Содержимое Das Spiel, das Sie kennen müssen Die Features des Spiels Wie funktioniert das Spiel? Das Gameplay in einigen Worten Wie können Sie Razor Shark kostenlos spielen? Das kostenlose Demo – Was Sie wissen müssen Das razor shark -Spiel …

Read More »

Casino Mostbet Azərbaycan.137

Casino Mostbet Azərbaycan ▶️ OYNA Содержимое Mostbet Casino-da Oyunlar və Slotlar Mostbet Azerbaijan-da Təqdim Olunan Oyunlar Mostbet Az-da Qazanc Əldə Etmək Mostbet-də Ödəniş və Çıxarış Üsulları Mostbet Azərbaycanın ən məşhur onlayn kazino saytlarından biridir. Mosbet Azerbaycan oyunsevərlərə geniş oyun seçimi, yüksək keyfiyyətli dizayn və əla xidmət təklif edir. Azerbaycanda kazino …

Read More »

Casino non AAMS in Italia come riconoscere quelli affidabili.565

Casino non AAMS in Italia – come riconoscere quelli affidabili ▶️ GIOCARE Содержимое La situazione attuale: i casino non AAMS in Italia Come riconoscere i casino non AAMS affidabili Il mondo dei casinò online è in costante evoluzione, e la scelta dei migliori siti non è più facile come un …

Read More »

Casino non AAMS in Italia come riconoscere quelli affidabili.928

Casino non AAMS in Italia – come riconoscere quelli affidabili ▶️ GIOCARE Содержимое La necessità di controllare la licenza Perché la licenza è importante I segni di un casino non AAMS In Italia, il settore dei giochi online è regolato dalla Agenzia delle Aziende Militari (AAMS), che emette licenze ai …

Read More »

Pocket Option Официальный сайт платформы для торговли – Бинарные Опционы.6179

Pocket Option – Официальный сайт платформы для торговли – Бинарные Опционы ▶️ ИГРАТЬ Содержимое Покет Опшн: Официальный сайт платформы для торговли – Бинарные Опционы Официальный сайт Покет Опшн: основные функции Описание платформы Pocket Option Преимущества и преобразования Pocket Option Преимущества для инвесторов В современном мире финансовых рынков, где каждый день …

Read More »

1win официальный сайт букмекера — Обзор и зеркало для входа.793

1win официальный сайт букмекера — Обзор и зеркало для входа ▶️ ИГРАТЬ Содержимое 1вин: Официальный сайт букмекера – Обзор и зеркало для входа Официальный сайт 1вин Преимущества официального сайта 1вин Зеркало для входа 1win Официальный Сайт Букмекера Обзор и Зеркало для Входа Преимущества 1вин Зеркало для входа Преимущества и Недостатки …

Read More »

1Win официальный сайт букмекера — 1Вин ставки на спорт.5124

1Win официальный сайт букмекера — 1Вин ставки на спорт ▶️ ИГРАТЬ Содержимое 1Win – Официальный Сайт Букмекера Преимущества и Функции 1Win Как сделать Ставку на Спорт Шаг 2: Выберите Матч Бонусы и Акции 1Вин Отзывы и Рейтинг Преимущества 1вин В мире ставок на спорт есть много букмекеров, но не все …

Read More »

1win — букмекерская контора 1вин.4455

1win — букмекерская контора 1вин ▶️ ИГРАТЬ Содержимое 1win – Букмекерская контора 1вин Преимущества 1win О компании 1win Преимущества для игроков Удобство и доступность Большой выбор ставок на спорт Выгодные условия для игроков Виды ставок и коэффициенты Основные виды ставок Коэффициенты в 1win Бонусы и акции 1win Отзывы и оценки …

Read More »

1win официальный сайт букмекера — Обзор и зеркало для входа.946

1win официальный сайт букмекера — Обзор и зеркало для входа ▶️ ИГРАТЬ Содержимое 1win Официальный Сайт Букмекера Обзор и Зеркало для Входа Преимущества и Функции 1win Функции 1win: Как Зарегистрироваться и Начать Играть на 1win Безопасность и Надежность В мире ставок и азарта 1win является одним из самых популярных букмекеров, …

Read More »