Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MS Windows native TLS (via Schannel SSP), IDN, and DNS SRV handling. GitHub releases for binaries. #163

Draft
wants to merge 14 commits into
base: master
Choose a base branch
from
Draft
181 changes: 181 additions & 0 deletions .github/workflows/windows.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
name: Windows build

on: [push, pull_request]

jobs:
libressl:
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- name: Check out repository code
uses: actions/checkout@v4
- uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
update: true
install: >-
mingw-w64-ucrt-x86_64-gcc
mingw-w64-ucrt-x86_64-libidn2
mingw-w64-ucrt-x86_64-libressl
pkgconf
automake
autoconf
make
texinfo
- name: Build
run: |
autoreconf -i
./configure --with-tls=openssl --with-libidn --prefix=/ libssl_CFLAGS=-I/ucrt64/include/libressl "libssl_LIBS=-llibressl -L@prefix/lib -llibrecrypto" "CFLAGS=-Wno-incompatible-pointer-types -DNOCRYPT"
make
make install-strip DESTDIR=/d/a/msmtp/tmp
cp `ldd src/msmtp | awk '/\/ucrt64/ {print $3}' | uniq` /d/a/msmtp/tmp/bin/
- name: Artifacts
uses: actions/upload-artifact@v4
with:
name: msmtp-libressl
path: D:\a\msmtp\tmp\
nls:
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Install build dependencies
uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
update: true
install: >-
mingw-w64-ucrt-x86_64-gcc
pkgconf
automake
autoconf
make
texinfo
- name: Build
run: |
autoreconf -i
mkdir nls && cd nls
# The only function from libwinpthread is clock_gettime()
../configure --with-tls=sspi LDFLAGS=-Wl,-Bstatic,-lwinpthread CFLAGS=-DFIXME1
make
cd .. && mkdir norm && cd norm
../configure --with-tls=sspi LDFLAGS=-Wl,-Bstatic,-lwinpthread
make
- name: Set locale
shell: pwsh
run: |
Set-WinSystemLocale -SystemLocale ru-RU
- name: Test IDN fixme
continue-on-error: true
run: |
nls/src/msmtp --debug --serverinfo --tls --host=mx3.почта.рус --port=1234 > output.log 2>&1 || true
cat output.log | iconv -f cp1251 -t utf-8
grep -q 'connection refused' output.log && echo 🎉 The host was found successfully but the connection was refused.
- name: Test IDN fixme 2
continue-on-error: true
run: |
nls/src/msmtp --debug --serverinfo --tls --host=mx3.почта.рус --port=1234
- name: Test IDN norm 2
continue-on-error: true
run: |
norm/src/msmtp --debug --serverinfo --tls --host=mx3.почта.рус --port=1234
native:
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Install build dependencies
uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
update: true
install: >-
mingw-w64-ucrt-x86_64-gcc
pkgconf
automake
autoconf
make
texinfo
- name: Configure
run: |
autoreconf -i
# The only function from libwinpthread is clock_gettime()
./configure --with-tls=sspi --with-vault=credman --disable-nls LDFLAGS=-Wl,-Bstatic,-lwinpthread
- name: Build
run: |
make
strip --strip-all src/msmtp.exe
- name: List SO imports
run: |
ldd src/msmtp
src/msmtp --version
- name: Test DNS SRV record lookup
continue-on-error: true
run: |
src/msmtp --configure [email protected] | tee output.log
grep -q 'port 587' output.log && echo 🎉 Success
- name: Get server info
continue-on-error: true
run: |
src/msmtp --serverinfo --tls --host=smtp.gmail.com --port=587 | tee output.log
grep -q 'ESMTP' output.log && echo 🎉 Success
- name: Limit to TLSv1.2
continue-on-error: true
run: |
src/msmtp --serverinfo --tls-priorities=PROTOCOLS=TLSv1.2 --tls --host=smtp.gmail.com --port=587 | tee output.log
grep -q 'TLS1\.2' output.log && echo 🎉 Success
- name: Test with wrong host on certificate
continue-on-error: true
run: |
src/msmtp --serverinfo --tls --tls-starttls=off --host=wrong.host.badssl.com --port=443 2>&1 | tee output.log || true
grep -q 'the certificate owner does not match hostname' output.log && echo 🎉 Success
- name: Test with revoked certificate
continue-on-error: true
run: |
src/msmtp --serverinfo --tls --tls-starttls=off --host=revoked.badssl.com --port=443 2>&1 | tee output.log || true
grep -q 'revoked' output.log && echo 🎉 Success
- name: Test with expired certificate
continue-on-error: true
run: |
src/msmtp --serverinfo --tls --tls-starttls=off --host=expired.badssl.com --port=443 2>&1 | tee output.log || true
grep -q 'expired' output.log && echo 🎉 Success
- name: Test with self-signed certificate
continue-on-error: true
run: |
src/msmtp --serverinfo --tls --tls-starttls=off --host=self-signed.badssl.com --port=443 2>&1 | tee output.log || true
grep -q 'not trusted' output.log && echo 🎉 Success
- name: Test with non-secure protocol
continue-on-error: true
run: src/msmtp --serverinfo --tls --tls-starttls=off --host=dh480.badssl.com --port=443
- name: Set locale
shell: pwsh
run: |
Set-WinSystemLocale -SystemLocale ru-RU
- name: Test IDN
continue-on-error: true
run: |
src/msmtp --debug --serverinfo --tls --host=mx3.почта.рус --port=1234 > output.log 2>&1 || true
cat output.log | iconv -f cp1251 -t utf-8
grep -q 'connection refused' output.log && echo 🎉 The host was found successfully but the connection was refused.
- name: Upload release to GitHub
if: github.ref_type == 'tag'
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
run: |
7z a msmtp-native.zip src\msmtp.exe
gh release create ${{ github.ref_name }} --generate-notes || echo "Release already exists!"
gh release upload ${{ github.ref_name }} msmtp-native.zip#Windows native support for DNS-based configufation, IDN, and Schannel SSP for TLS
- name: Artifacts
uses: actions/upload-artifact@v4
with:
name: msmtp-native
path: src/msmtp.exe
60 changes: 41 additions & 19 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ else
fi
if test "$found_res_query" = "yes"; then
AC_DEFINE([HAVE_LIBRESOLV], [1], [Define to 1 if libresolv is available])
else
case "${target}" in *-*-mingw*) LIBS="$LIBS -ldnsapi" ;; esac
fi

dnl pkg-config (required to detect libraries)
Expand All @@ -94,11 +96,12 @@ want_tls="yes"
want_gnutls="yes"
want_openssl="no"
want_libtls="no"
want_sspi="no"
tls_CFLAGS=""
tls_LIBS=""
with_ssl_was_used=no
AC_ARG_WITH([tls], [AS_HELP_STRING([--with-tls=[gnutls|openssl|libtls|no]],
[TLS support: GnuTLS (default), OpenSSL (discouraged), libtls, or none.])],
AC_ARG_WITH([tls], [AS_HELP_STRING([--with-tls=[gnutls|openssl|libtls|sspi|no]],
[TLS support: GnuTLS (default), OpenSSL (discouraged), libtls, SSPI (Schannel), or none.])],
if test "$withval" = "gnutls"; then
want_tls=yes
want_gnutls=yes
Expand All @@ -114,13 +117,17 @@ AC_ARG_WITH([tls], [AS_HELP_STRING([--with-tls=[gnutls|openssl|libtls|no]],
want_gnutls=no
want_openssl=no
want_libtls=yes
elif test "$withval" = "sspi"; then
want_tls=yes
want_gnutls=no
want_sspi=yes
elif test "$withval" = "no"; then
want_tls=no
want_gnutls=no
want_openssl=no
want_libtls=no
else
AC_MSG_ERROR([Use --with-tls=gnutls or --with-tls=openssl or --with-tls=libtls or --with-tls=no])
[AC_MSG_ERROR([Invalid --with-tls=$withval. Use --with-tls=gnutls|openssl|libtls|sspi|no])]
fi)
if test "$want_gnutls" = "yes"; then
PKG_CHECK_MODULES([libgnutls], [gnutls >= 3.7.2], [HAVE_LIBGNUTLS=1], [HAVE_LIBGNUTLS=0])
Expand Down Expand Up @@ -165,15 +172,23 @@ if test "$want_libtls" = "yes" -a "$have_tls" = "no"; then
AC_DEFINE([HAVE_LIBTLS], [1], [Define to 1 if libtls is available])
fi
fi
if test "$want_sspi" = "yes"; then
have_tls="yes"
tls_lib="Schannel"
tls_LIBS="-lsecur32 -lcrypt32"
AC_DEFINE([HAVE_LIBSSL], [1], [Define to 1 if libssl is available])
fi
if test "$have_tls" = "yes"; then
AC_DEFINE([HAVE_TLS], [1], [Define to 1 to build with TLS/SSL support])
elif test "$want_tls" = "yes"; then
AC_MSG_WARN([Disabling TLS support, which is very bad. Consider using GnuTLS!])
fi
AC_DEFINE_UNQUOTED([TLS_LIB], ["$tls_lib"], [TLS library used])
AM_CONDITIONAL([HAVE_TLS], [test "$have_tls" = "yes"])
AM_CONDITIONAL([HAVE_GNUTLS], [test "$tls_lib" = "GnuTLS"])
AM_CONDITIONAL([HAVE_OPENSSL], [test "$tls_lib" = "OpenSSL"])
AM_CONDITIONAL([HAVE_LIBTLS], [test "$tls_lib" = "libtls"])
AM_CONDITIONAL([HAVE_SSPI], [test "$tls_lib" = "Schannel"])
AC_SUBST([tls_CFLAGS])
AC_SUBST([tls_LIBS])

Expand Down Expand Up @@ -280,17 +295,21 @@ if test "$libidn" != "no"; then
AC_MSG_WARN([$libidn_PKG_ERRORS])
AC_MSG_WARN([libidn is provided by GNU Libidn])
libidn="no"
case "${target}" in *-*-mingw*)
AC_MSG_WARN([Using Windows native IDN support])
want_libidn=no
esac
else
libidn="yes"
AC_DEFINE([HAVE_LIBIDN], [1], [Define to 1 if libidn is available])
fi
fi

dnl libsecret support (requires pkg-config).
AC_ARG_WITH([libsecret], [AS_HELP_STRING([--with-libsecret],
[Support libsecret (GNOME password management)])],
[libsecret=$withval],[libsecret=yes])
if test "$libsecret" != "no"; then
AC_ARG_WITH([vault], [AS_HELP_STRING([--with-vault=libsecret|macosx-keyring|credman|no],
[Password vault support: libsecret (GNOME password management), Mac OS X Keyring, Windows Credential Manager, or none.])],
[vault=$withval], [vault=none])
AS_CASE([$vault],
[libsecret], [
PKG_CHECK_MODULES([libsecret], [libsecret-1], [HAVE_LIBSECRET=1], [HAVE_LIBSECRET=0])
if test "$HAVE_LIBSECRET" != "1"; then
AC_MSG_WARN([library libsecret not found:])
Expand All @@ -301,13 +320,7 @@ if test "$libsecret" != "no"; then
libsecret="yes"
AC_DEFINE([HAVE_LIBSECRET], [1], [Define to 1 if libsecret is available])
fi
fi

dnl MacOS X Keychain Services (Security Framework)
AC_ARG_WITH([macosx-keyring], [AS_HELP_STRING([--with-macosx-keyring],
[Support Mac OS X Keyring])],
[macosx_keyring=$withval],[macosx_keyring=yes])
if test "$macosx_keyring" != "no"; then
], [macosx_keyring], [
AC_CACHE_CHECK([for SecKeychainGetVersion],
ac_cv_func_SecKeychainGetVersion,
[ac_save_LIBS="$LIBS"
Expand All @@ -322,7 +335,17 @@ if test "$macosx_keyring" != "no"; then
else
macosx_keyring=no
fi
fi
], [credman], [
credman=yes
LIBS="$LIBS -lcredui -lole32"
AC_DEFINE([USE_CREDMAN], [1], [Define to 1 if you want to use Windows Credential Manager])
], [none], [
libsecret="no"
macosx_keyring=no
credman=no
],
[AC_MSG_ERROR([Invalid --with-vault=$vault. Use --with-vault=libsecret|macosx-keyring|credman|no])]
)

dnl Check if msmtpd should be built
AC_ARG_WITH([msmtpd],
Expand Down Expand Up @@ -353,6 +376,5 @@ else
echo "IDN support ............ : no"
fi
echo "GNU SASL support ....... : $libgsasl"
echo "Libsecret support (GNOME): $libsecret"
echo "MacOS X Keychain support : $macosx_keyring"
echo "Build msmtpd ............: $build_msmtpd"
echo "Password vault ......... : $vault"
echo "Build msmtpd ........... : $build_msmtpd"
3 changes: 3 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ endif
if HAVE_LIBTLS
msmtp_SOURCES += mtls-libtls.c
endif
if HAVE_SSPI
msmtp_SOURCES += mtls-sspi.c
endif

AM_CPPFLAGS = $(tls_CFLAGS) $(libgsasl_CFLAGS) $(libidn2_CFLAGS) $(libsecret_CFLAGS)

Expand Down
Loading