From a3c399cad03f9c9b775f939fdfab34c1ad20d146 Mon Sep 17 00:00:00 2001 From: Ivan Martinez-Ortiz Date: Mon, 2 Nov 2020 23:03:43 +0100 Subject: [PATCH] Add XOAuth2 support for GMail --- Dockerfile | 19 ++++++ README.md | 79 ++++++++++++++++++++-- scripts/common-run.sh | 55 +++++++++++++++ scripts/common.sh | 22 ++++++ scripts/run.sh | 3 + unit-tests/Dockerfile | 19 ++++++ unit-tests/xoauth2_support.bats | 114 ++++++++++++++++++++++++++++++++ 7 files changed, 306 insertions(+), 5 deletions(-) create mode 100644 unit-tests/xoauth2_support.bats diff --git a/Dockerfile b/Dockerfile index 8617121..235e4d4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,19 @@ ARG ALPINE_VERSION=latest +FROM alpine:${ALPINE_VERSION} as build + +ARG SASL_XOAUTH2_REPO_URL=https://github.com/tarickb/sasl-xoauth2.git +ARG SASL_XOAUTH2_GIT_REF=release-0.9 + +RUN true && \ + apk add --no-cache --upgrade git && \ + apk add --no-cache --upgrade cmake clang make gcc g++ libc-dev pkgconfig curl-dev jsoncpp-dev cyrus-sasl-dev && \ + git clone --depth 1 --branch ${SASL_XOAUTH2_GIT_REF} ${SASL_XOAUTH2_REPO_URL} /sasl-xoauth2 && \ + cd /sasl-xoauth2 && \ + mkdir build && \ + cd build && \ + cmake -DCMAKE_INSTALL_PREFIX=/ .. && \ + make + FROM alpine:${ALPINE_VERSION} LABEL maintaner="Bojan Cekrlic - https://github.com/bokysan/docker-postfix/" @@ -10,8 +25,12 @@ RUN true && \ apk add --no-cache postfix && \ apk add --no-cache opendkim && \ apk add --no-cache --upgrade ca-certificates tzdata supervisor rsyslog musl musl-utils bash opendkim-utils && \ + apk add --no-cache --upgrade libcurl jsoncpp && \ (rm "/tmp/"* 2>/dev/null || true) && (rm -rf /var/cache/apk/* 2>/dev/null || true) +# Copy SASL-XOAUTH2 plugin +COPY --from=build /sasl-xoauth2/build/src/libsasl-xoauth2.so /usr/lib/sasl2/ + # Set up configuration COPY /configs/supervisord.conf /etc/supervisord.conf COPY /configs/rsyslog*.conf /etc/ diff --git a/README.md b/README.md index ffe6958..0130a5f 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Simple postfix relay host ("postfix null client") for your Docker containers. Ba * [Postfix-specific options](#postfix-specific-options) * [RELAYHOST, RELAYHOST_USERNAME and RELAYHOST_PASSWORD](#relayhost-relayhost_username-and-relayhost_password) * [RELAYHOST_TLS_LEVEL](#relayhost_tls_level) + * [XOAUTH2_CLIENT_ID, XOAUTH2_SECRET, XOAUTH2_INITIAL_ACCESS_TOKEN and XOAUTH2_INITIAL_REFRESH_TOKEN](#xoauth2_client_id-xoauth2_secret-xoauth2_initial_access_token-and-xoauth2_initial_refresh_token) * [MASQUERADED_DOMAINS](#masqueraded_domains) * [SMTP_HEADER_CHECKS](#smtp_header_checks) * [POSTFIX_hostname](#postfix_hostname) @@ -27,6 +28,7 @@ Simple postfix relay host ("postfix null client") for your Docker containers. Ba * [Changing the DKIM selector](#changing-the-dkim-selector) * [Overriding specific OpenDKIM settings](#overriding-specific-opendkim-settings) * [Verifying your DKIM setup](#verifying-your-dkim-setup) + * [Docker Secrets](#docker-secrets) * [Helm chart](#helm-chart) * [Extending the image](#extending-the-image) * [Using custom init scripts](#using-custom-init-scripts) @@ -137,7 +139,11 @@ To change the log format, set the (unsurprisingly named) variable `LOG_FORMAT=js * `RELAYHOST` = Host that relays your messages * `RELAYHOST_USERNAME` = An (optional) username for the relay server * `RELAYHOST_PASSWORD` = An (optional) login password for the relay server -* `RELAYHOST_TLS_LEVEL` = Relay host TLS connection leve +* `RELAYHOST_TLS_LEVEL` = Relay host TLS connection level +* `XOAUTH2_CLIENT_ID` = OAuth2 client id used when configured as a relayhost. +* `XOAUTH2_SECRET` = OAuth2 secret used when configured as a relayhost. +* `XOAUTH2_INITIAL_ACCESS_TOKEN` = Initial OAuth2 access token. +* `XOAUTH2_INITIAL_REFRESH_TOKEN` = Initial OAuth2 refresh token. * `MASQUERADED_DOMAINS` = domains where you want to masquerade internal hosts * `SMTP_HEADER_CHECKS`= Set to `1` to enable header checks of to a location of the file for header checks * `POSTFIX_hostname` = Set tha name of this postfix server @@ -181,6 +187,48 @@ Define relay host TLS connection level. See [smtp_tls_security_level](http://www This level defines how the postfix will connect to your upstream server. +#### `XOAUTH2_CLIENT_ID`, `XOAUTH2_SECRET`, `XOAUTH2_INITIAL_ACCESS_TOKEN` and `XOAUTH2_INITIAL_REFRESH_TOKEN` + +> Note: These parameters are used when `RELAYHOST` and `RELAYHOST_USERNAME` are provided. + +These parameters allow you to configure a relayhost that requires (or recommends) the [XOAuth2 authentication method](https://github.com/tarickb/sasl-xoauth2) (e.g. GMail). +- `XOAUTH2_CLIENT_ID` and `XOAUTH2_SECRET` are the [OAuth2 client credentials](#oauth2-client-credentials-gmail). +- `XOAUTH2_INITIAL_ACCESS_TOKEN` and `XOAUTH2_INITIAL_REFRESH_TOKEN` are the [initial access token and refresh tokens](#obtain-initial-access-token-gmail). These values are only required to initialize the token file `/var/spool/postfix/xoauth2-tokens/$RELAYHOST_USERNAME`. + +Example: +``` +docker run --rm --name pruebas-postfix \ + -e RELAYHOST="[smtp.gmail.com]:587" \ + -e RELAYHOST_USERNAME="@gmail.com" \ + -e RELAYHOST_TLS_LEVEL="encrypt" \ + -e XOAUTH2_CLIENT_ID="" \ + -e XOAUTH2_SECRET="" \ + -e ALLOW_EMPTY_SENDER_DOMAINS="true" \ + -e XOAUTH2_INITIAL_ACCESS_TOKEN="" \ + -e XOAUTH2_INITIAL_REFRESH_TOKEN="" \ + boky/postfix +``` +Next sections describe how to obtain these values. + +##### OAuth2 Client Credentials (GMail) + +Visit the [Google API Console](https://console.developers.google.com/) to obtain OAuth 2 credentials (a client ID and client secret) for an "Installed application" application type. + +Save the client ID and secret and use them to initialize `XOAUTH2_CLIENT_ID` and `XOAUTH2_SECRET` respectively. + +We'll also need these credentials in the next step. + +##### Obtain Initial Access Token (GMail) + +Use the [Gmail OAuth2 developer tools](https://github.com/google/gmail-oauth2-tools/) to obtain an OAuth token by following the [Creating and Authorizing an OAuth Token](https://github.com/google/gmail-oauth2-tools/wiki/OAuth2DotPyRunThrough#creating-and-authorizing-an-oauth-token) instructions. + +Save the resulting tokens and use them to initialize `XOAUTH2_INITIAL_ACCESS_TOKEN` and `XOAUTH2_INITIAL_REFRESH_TOKEN`. + +##### Debug XOAuth2 issues + +If you have XOAuth2 authentication issues you can enable XOAuth2 debug message setting `XOAUTH2_SYSLOG_ON_FAILURE` to `"yes"` (default: `"no"`). If you need a more detailed log trace about XOAuth2 you can set `XOAUTH2_FULL_TRACE` to `"yes"` (default: `"no"`). + + #### `MASQUERADED_DOMAINS` If you don't want outbound mails to expose hostnames, you can use this variable to enable Postfix's @@ -333,6 +381,26 @@ variable from OpenDKIM config. I strongly suggest using a service such as [dkimvalidator](https://dkimvalidator.com/) to make sure your keys are set up properly and your DNS server is serving them with the correct records. + +### Docker Secrets + +As an alternative to passing sensitive information via environment variables, _FILE may be appended to some environment variables (see below), causing the initialization script to load the values for those variables from files present in the container. In particular, this can be used to load passwords from Docker secrets stored in /run/secrets/ files. For example: + +``` +docker run --rm --name pruebas-postfix \ + -e RELAYHOST="[smtp.gmail.com]:587" \ + -e RELAYHOST_USERNAME="@gmail.com" \ + -e RELAYHOST_TLS_LEVEL="encrypt" \ + -e XOAUTH2_CLIENT_ID_FILE="/run/secrets/xoauth2-client-id" \ + -e XOAUTH2_SECRET_FILE="/run/secrets/xoauth2-secret" \ + -e ALLOW_EMPTY_SENDER_DOMAINS="true" \ + -e XOAUTH2_INITIAL_ACCESS_TOKEN_FILE="/run/secrets/xoauth2-access-token" \ + -e XOAUTH2_INITIAL_REFRESH_TOKEN_FILE="/run/secrets/xoauth2-refresh-token" \ + boky/postfix +``` + +Currently, this is only supported for `XOAUTH2_CLIENT_ID`, `XOAUTH2_SECRET`, `XOAUTH2_INITIAL_ACCESS_TOKEN` and `XOAUTH2_INITIAL_REFRESH_TOKEN`. + ## Helm chart This image comes with its own helm chart. The chart versions are aligned with the releases of the image. Charts are hosted @@ -428,11 +496,12 @@ account which will use `UID:GID` of `100:101`. `opendkim` will run under account ### Relaying messages through your Gmail account -Please note that Gmail does not support using your password with non-OAuth2 clients, which -- technically -- postfix is. -You will need to enable [Less secure apps](https://support.google.com/accounts/answer/6010255?hl=en) in your account -and assign an "app password". You'll also need to use (only) your email as the sender address. +Please note that Gmail does not support using your password with non-OAuth2 clients. You will need to either enable +[Less secure apps](https://support.google.com/accounts/answer/6010255?hl=en) in your account and assign an "app password" +or [configure postfix support for XOAuth2 authentication](#xoauth2_client_id-xoauth2_secret-xoauth2_initial_access_token-and-xoauth2_initial_refresh_token). +You'll also need to use (only) your email as the sender address. -Your configuration would be as follows: +If you follow the *less than secure* route, your configuration would be as follows: ```shell script RELAYHOST=smtp.gmail.com:587 diff --git a/scripts/common-run.sh b/scripts/common-run.sh index d214477..05ed20f 100644 --- a/scripts/common-run.sh +++ b/scripts/common-run.sh @@ -104,6 +104,8 @@ postfix_setup_relayhost() { # smtp_tls_CApath do_postconf -e "smtp_tls_CAfile=/etc/ssl/certs/ca-certificates.crt" + file_env 'RELAYHOST_PASSWORD' + if [ -n "$RELAYHOST_USERNAME" ] && [ -n "$RELAYHOST_PASSWORD" ]; then echo -e " using username ${emphasis}$RELAYHOST_USERNAME${reset} and password ${emphasis}(redacted)${reset}." if [[ -f /etc/postfix/sasl_passwd ]]; then @@ -131,6 +133,51 @@ postfix_setup_relayhost() { fi } +postfix_setup_xoauth2_pre_setup() { + file_env 'XOAUTH2_CLIENT_ID' + file_env 'XOAUTH2_SECRET' + if [ -n "$XOAUTH2_CLIENT_ID" ] && [ -n "$XOAUTH2_SECRET" ]; then + cat < /etc/sasl-xoauth2.conf +{ + "client_id": "${XOAUTH2_CLIENT_ID}", + "client_secret": "${XOAUTH2_SECRET}", + "log_to_syslog_on_failure": "${XOAUTH2_SYSLOG_ON_FAILURE:-no}", + "log_full_trace_on_failure": "${XOAUTH2_FULL_TRACE:-no}" +} +EOF + + if [ -z "$RELAYHOST" ] || [ -z "${RELAYHOST_USERNAME}" ]; then + error "You need to specify RELAYHOST and RELAYHOST_USERNAME otherwise Postfix will not run!" + exit 1 + fi + + export RELAYHOST_PASSWORD="/var/spool/postfix/xoauth2-tokens/${RELAYHOST_USERNAME}" + + if [ ! -d "/var/spool/postfix/xoauth2-tokens" ]; then + mkdir -p "/var/spool/postfix/xoauth2-tokens" + fi + + if [ ! -f "/var/spool/postfix/xoauth2-tokens/${RELAYHOST_USERNAME}" ] && [ -n "$XOAUTH2_INITIAL_ACCESS_TOKEN" ] && [ -n "$XOAUTH2_INITIAL_REFRESH_TOKEN" ]; then + cat < "/var/spool/postfix/xoauth2-tokens/${RELAYHOST_USERNAME}" +{ + "access_token" : "${XOAUTH2_INITIAL_ACCESS_TOKEN}", + "refresh_token" : "${XOAUTH2_INITIAL_REFRESH_TOKEN}", + "expiry" : "0" +} +EOF + fi + chown -R postfix:root "/var/spool/postfix/xoauth2-tokens" + fi +} + +postfix_setup_xoauth2_post_setup() { + if [ -n "$XOAUTH2_CLIENT_ID" ] && [ -n "$XOAUTH2_SECRET" ]; then + do_postconf -e 'smtp_sasl_security_options=' + do_postconf -e 'smtp_sasl_mechanism_filter=xoauth2' + do_postconf -e 'smtp_tls_session_cache_database=btree:${data_directory}/smtp_scache' + fi +} + postfix_setup_networks() { if [ ! -z "$MYNETWORKS" ]; then deprecated "${emphasis}MYNETWORKS${reset} variable is deprecated. Please use ${emphasis}POSTFIX_mynetworks${reset} instead." @@ -388,3 +435,11 @@ execute_post_init_scripts() { done fi } + +unset_sensible_variables() { + unset RELAYHOST_PASSWORD + unset XOAUTH2_CLIENT_ID + unset XOAUTH2_SECRET + unset XOAUTH2_INITIAL_ACCESS_TOKEN + unset XOAUTH2_INITIAL_REFRESH_TOKEN +} \ No newline at end of file diff --git a/scripts/common.sh b/scripts/common.sh index 3d66d60..af0773d 100644 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -172,4 +172,26 @@ do_postconf() { } +# usage: file_env VAR [DEFAULT] +# ie: file_env 'XYZ_DB_PASSWORD' 'example' +# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of +# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) +# +file_env() { + local var="$1" + local fileVar="${var}_FILE" + local def="${2:-}" + if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then + error "Both $var and $fileVar are set (but are exclusive)" + fi + local val="$def" + if [ "${!var:-}" ]; then + val="${!var}" + elif [ "${!fileVar:-}" ]; then + val="$(< "${!fileVar}")" + fi + export "$var"="$val" + unset "$fileVar" +} + export reset green yellow orange orange_emphasis lightblue red gray emphasis underline diff --git a/scripts/run.sh b/scripts/run.sh index 559d420..7a0fac8 100644 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -17,7 +17,9 @@ postfix_restrict_message_size # Restrict the size of messages (or set them postfix_reject_invalid_helos # Reject invalid HELOs postfix_set_hostname # Set up host name postfix_set_relay_tls_level # Set TLS level security for relays +postfix_setup_xoauth2_pre_setup # (Pre) Setup XOAUTH2 authentication postfix_setup_relayhost # Setup a relay host, if defined +postfix_setup_xoauth2_post_setup # (Post) Setup XOAUTH2 autentication postfix_setup_networks # Set MYNETWORKS postfix_setup_debugging # Enable debugging, if defined postfix_setup_sender_domains # Configure allowed sender domains @@ -28,6 +30,7 @@ postfix_custom_commands # Apply custom postfix settings opendkim_custom_commands # Apply custom OpenDKIM settings postfix_open_submission_port # Enable the submission port execute_post_init_scripts # Execute any scripts found in /docker-init.db/ +unset_sensible_variables # Remove environment variables that contains sensible values (secrets) that are read from conf files notice "Starting: ${emphasis}rsyslog${reset}, ${emphasis}postfix${reset}$DKIM_ENABLED" exec supervisord -c /etc/supervisord.conf diff --git a/unit-tests/Dockerfile b/unit-tests/Dockerfile index bf8f3db..1cef79c 100644 --- a/unit-tests/Dockerfile +++ b/unit-tests/Dockerfile @@ -1,4 +1,19 @@ ARG ALPINE_VERSION=latest +FROM alpine:${ALPINE_VERSION} as build + +ARG SASL_XOAUTH2_REPO_URL=https://github.com/tarickb/sasl-xoauth2.git +ARG SASL_XOAUTH2_GIT_REF=release-0.9 + +RUN true && \ + apk add --no-cache --upgrade git && \ + apk add --no-cache --upgrade cmake clang make gcc g++ libc-dev pkgconfig curl-dev jsoncpp-dev cyrus-sasl-dev && \ + git clone --depth 1 --branch ${SASL_XOAUTH2_GIT_REF} ${SASL_XOAUTH2_REPO_URL} /sasl-xoauth2 && \ + cd /sasl-xoauth2 && \ + mkdir build && \ + cd build && \ + cmake -DCMAKE_INSTALL_PREFIX=/ .. && \ + make + FROM alpine:${ALPINE_VERSION} LABEL maintaner="Bojan Cekrlic - https://github.com/bokysan/docker-postfix/" @@ -7,10 +22,14 @@ RUN true && \ apk add --no-cache postfix && \ apk add --no-cache opendkim && \ apk add --no-cache --upgrade ca-certificates tzdata supervisor rsyslog musl musl-utils bash opendkim-utils && \ + apk add --no-cache --upgrade libcurl jsoncpp && \ (rm "/tmp/"* 2>/dev/null || true) && (rm -rf /var/cache/apk/* 2>/dev/null || true) RUN apk add --no-cache bash bats && \ (rm "/tmp/"* 2>/dev/null || true) && (rm -rf /var/cache/apk/* 2>/dev/null || true) +# Copy SASL-XOAUTH2 plugin +COPY --from=build /sasl-xoauth2/build/src/libsasl-xoauth2.so /usr/lib/sasl2/ + WORKDIR /code ENTRYPOINT ["/usr/bin/bats"] CMD ["-v"] \ No newline at end of file diff --git a/unit-tests/xoauth2_support.bats b/unit-tests/xoauth2_support.bats new file mode 100644 index 0000000..45f13cb --- /dev/null +++ b/unit-tests/xoauth2_support.bats @@ -0,0 +1,114 @@ +#!/usr/bin/env bats + +load /code/scripts/common.sh +load /code/scripts/common-run.sh + +@test "check sentive variables are unset" { + local RELAYHOST_PASSWORD="password" + local XOAUTH2_CLIENT_ID="client_id" + local XOAUTH2_SECRET="secret" + local XOAUTH2_INITIAL_ACCESS_TOKEN="access_token" + local XOAUTH2_INITIAL_REFRESH_TOKEN="refres_token" + + unset_sensible_variables + + [ -z "$RELAYHOST_PASSWORD" ] + [ -z "$XOAUTH2_CLIENT_ID" ] + [ -z "$XOAUTH2_SECRET" ] + [ -z "$XOAUTH2_INITIAL_ACCESS_TOKEN" ] + [ -z "$XOAUTH2_INITIAL_REFRESH_TOKEN" ] +} + +@test "reading sensitive values from environment or from file" { + local RELAYHOST_PASSWORD="password" + + local tmp_file=$(mktemp) + echo "password" > $tmp_file + local XOAUTH2_CLIENT_ID_FILE="$tmp_file" + + file_env 'RELAYHOST_PASSWORD' + file_env 'XOAUTH2_CLIENT_ID' + + [ -n "$RELAYHOST_PASSWORD" ] + [ -n "$XOAUTH2_CLIENT_ID" ] +} + +@test "pre-configure xoauth2 in postfix only if relayhost is configured" { + local RELAYHOST="[smtp.example.org]:597" + local RELAYHOST_USERNAME="your.acount@example.org" + local XOAUTH2_CLIENT_ID="client_id" + local XOAUTH2_SECRET="secret" + local XOAUTH2_SYSLOG_ON_FAILURE="no" + local XOAUTH2_FULL_TRACE="yes" + local XOAUTH2_INITIAL_ACCESS_TOKEN="access_token" + local XOAUTH2_INITIAL_REFRESH_TOKEN="refresh_token" + + postfix_setup_xoauth2_pre_setup + + [ -f "/etc/sasl-xoauth2.conf" ] + result=$(cat /etc/sasl-xoauth2.conf | grep -e 'client_id' | sed -r 's/\s*"[^"]+"\s*:\s*"([^,]*)"\s*,?/\1/') + [ "$result" == "$XOAUTH2_CLIENT_ID" ] + result=$(cat /etc/sasl-xoauth2.conf | grep -e 'client_secret' | sed -r 's/\s*"[^"]+"\s*:\s*"([^,]*)"\s*,?/\1/') + [ "$result" == "$XOAUTH2_SECRET" ] + result=$(cat /etc/sasl-xoauth2.conf | grep -e 'log_to_syslog_on_failure' | sed -r 's/\s*"[^"]+"\s*:\s*"([^,]*)"\s*,?/\1/') + [ "$result" == "$XOAUTH2_SYSLOG_ON_FAILURE" ] + result=$(cat /etc/sasl-xoauth2.conf | grep -e 'log_full_trace_on_failure' | sed -r 's/\s*"[^"]+"\s*:\s*"([^,]*)"\s*,?/\1/') + [ "$result" == "$XOAUTH2_FULL_TRACE" ] + [ "$RELAYHOST_PASSWORD" == "/var/spool/postfix/xoauth2-tokens/${RELAYHOST_USERNAME}" ] + result=$(cat "${RELAYHOST_PASSWORD}" | grep -e 'access_token' | sed -r 's/\s*"[^"]+"\s*:\s*"([^,]*)"\s*,?/\1/') + [ "$result" == "$XOAUTH2_INITIAL_ACCESS_TOKEN" ] + result=$(cat "${RELAYHOST_PASSWORD}" | grep -e 'refresh_token' | sed -r 's/\s*"[^"]+"\s*:\s*"([^,]*)"\s*,?/\1/') + [ "$result" == "$XOAUTH2_INITIAL_REFRESH_TOKEN" ] +} + +@test "pre-configure error trying to configure xoauth2 in postfix if relayhost is not configured" { + local XOAUTH2_CLIENT_ID="client_id" + local XOAUTH2_SECRET="secret" + + local RELAYHOST="[smtp.example.org]:597" + + run postfix_setup_xoauth2_pre_setup + + [ "$status" -eq 1 ] + [ "$output" == "‣ ERROR You need to specify RELAYHOST and RELAYHOST_USERNAME otherwise Postfix will not run!" ] + + unset RELAYHOST + local RELAYHOST_USERNAME="your.acount@example.org" + + run postfix_setup_xoauth2_pre_setup + + [ "$status" -eq 1 ] + [ "$output" == "‣ ERROR You need to specify RELAYHOST and RELAYHOST_USERNAME otherwise Postfix will not run!" ] +} + +@test "post-configure xoauth2 not needed" { + local XOAUTH2_CLIENT_ID="client_id" + + postfix_setup_xoauth2_post_setup + + postfix check + + result=$(cat /etc/postfix/main.cf | grep -e 'smtp_sasl_mechanism_filter' | sed -r 's/\s*[^\s]+\s*=\s*([^\s]*)/\1/') + [ "$result" != "xoauth2" ] +} + +@test "post-configure xoauth2 required" { + local XOAUTH2_CLIENT_ID="client_id" + local XOAUTH2_SECRET="secret" + + postfix_setup_xoauth2_post_setup + + postfix check + + cat /etc/postfix/main.cf | grep -q -E '^\s*smtp_sasl_security_options\s*=\s*$' + local status=$? + [ "$status" -eq 0 ] + + cat /etc/postfix/main.cf | grep -q -E '^\s*smtp_sasl_mechanism_filter\s*=\s*xoauth2$' + local status=$? + [ "$status" -eq 0 ] + + cat /etc/postfix/main.cf | grep -q -E '^\s*smtp_tls_session_cache_database\s*=\s*btree:\$\{data_directory\}/smtp_scache$' + local status=$? + [ "$status" -eq 0 ] +}