stunnel-5.30/0000775000175000017500000000000012652443340010137 500000000000000stunnel-5.30/configure.ac0000664000175000017500000003574312652373710012364 00000000000000# Process this file with autoconf to produce a configure script. AC_INIT([stunnel],[5.30]) AC_MSG_NOTICE([**************************************** initialization]) AC_CONFIG_AUX_DIR(auto) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADERS([src/config.h]) AC_CONFIG_SRCDIR([src/stunnel.c]) AM_INIT_AUTOMAKE AM_CONDITIONAL([AUTHOR_TESTS], [test -d ".git"]) AC_CANONICAL_HOST AC_SUBST([host]) AC_DEFINE_UNQUOTED([HOST], ["$host"], [Host description]) define([esc], [`echo ]$1[ | tr abcdefghijklmnopqrstuvwxyz.- ABCDEFGHIJKLMNOPQRSTUVWXYZ__ | tr -dc ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_`]) AC_DEFINE_UNQUOTED(esc(CPU_$host_cpu)) AC_DEFINE_UNQUOTED(esc(VENDOR_$host_vendor)) AC_DEFINE_UNQUOTED(esc(OS_$host_os)) case "$host_os" in *darwin*) # OSX does not declare ucontext without _XOPEN_SOURCE AC_DEFINE([_XOPEN_SOURCE], [500], [Use X/Open 5 with POSIX 1995]) # OSX does not declare chroot() without _DARWIN_C_SOURCE AC_DEFINE([_DARWIN_C_SOURCE], [1], [Use Darwin source]) ;; *) AC_DEFINE([_GNU_SOURCE], [1], [Use GNU source]) ;; esac AC_PROG_CC AM_PROG_CC_C_O AC_PROG_INSTALL AC_PROG_MAKE_SET # silent build by default ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AC_MSG_NOTICE([**************************************** thread model]) # thread detection should be done first, as it may change the CC variable AC_ARG_WITH(threads, [ --with-threads=model select threading model (ucontext/pthread/fork)], [ case "$withval" in ucontext) AC_MSG_NOTICE([UCONTEXT mode selected]) AC_DEFINE([USE_UCONTEXT], [1], [Define to 1 to select UCONTEXT mode]) ;; pthread) AC_MSG_NOTICE([PTHREAD mode selected]) AX_PTHREAD() LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" CC="$PTHREAD_CC" AC_DEFINE([USE_PTHREAD], [1], [Define to 1 to select PTHREAD mode]) ;; fork) AC_MSG_NOTICE([FORK mode selected]) AC_DEFINE([USE_FORK], [1], [Define to 1 to select FORK mode]) ;; *) AC_MSG_ERROR([Unknown thread model \"${withval}\"]) ;; esac ], [ # do not attempt to autodetect UCONTEXT threading AX_PTHREAD([ AC_MSG_NOTICE([PTHREAD thread model detected]) LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" CC="$PTHREAD_CC" AC_DEFINE([USE_PTHREAD], [1], [Define to 1 to select PTHREAD mode]) ], [ AC_MSG_NOTICE([FORK thread model detected]) AC_DEFINE([USE_FORK], [1], [Define to 1 to select FORK mode]) ]) ]) AC_MSG_NOTICE([**************************************** compiler/linker flags]) if test "$GCC" = yes; then AX_APPEND_COMPILE_FLAGS([-Wall]) AX_APPEND_COMPILE_FLAGS([-Wextra]) AX_APPEND_COMPILE_FLAGS([-Wpedantic]) AX_APPEND_COMPILE_FLAGS([-Wformat=2]) AX_APPEND_COMPILE_FLAGS([-Wconversion]) AX_APPEND_COMPILE_FLAGS([-Wno-long-long]) AX_APPEND_COMPILE_FLAGS([-Wno-deprecated-declarations]) AX_APPEND_COMPILE_FLAGS([-fPIE]) case "${host}" in avr-*.* | powerpc-*-aix* | rl78-*.* | visium-*.*) ;; *) AX_APPEND_COMPILE_FLAGS([-fstack-protector]) ;; esac AX_APPEND_LINK_FLAGS([-fPIE -pie]) AX_APPEND_LINK_FLAGS([-Wl,-z,relro]) AX_APPEND_LINK_FLAGS([-Wl,-z,now]) AX_APPEND_LINK_FLAGS([-Wl,-z,noexecstack]) fi AX_APPEND_COMPILE_FLAGS([-D_FORTIFY_SOURCE=2]) AC_MSG_NOTICE([**************************************** libtool]) LT_INIT([disable-static]) AC_SUBST([LIBTOOL_DEPS]) AC_MSG_NOTICE([**************************************** types]) AC_TYPE_INT8_T AC_TYPE_INT16_T AC_TYPE_INT32_T AC_TYPE_INT64_T AC_TYPE_UINT8_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_TYPE_UID_T AC_MSG_CHECKING([for socklen_t]) AC_EGREP_HEADER(socklen_t, sys/socket.h, AC_MSG_RESULT([yes]), AC_MSG_RESULT([no (defined as int)]) AC_DEFINE([socklen_t], [int], [Type of socklen_t])) AC_CHECK_TYPES([struct sockaddr_un], [], [], [#include ]) AC_CHECK_TYPES([struct addrinfo], [], [], [#include ]) AC_MSG_NOTICE([**************************************** PTY device files]) if test "x$cross_compiling" = "xno"; then AC_CHECK_FILE("/dev/ptmx", AC_DEFINE([HAVE_DEV_PTMX], [1], [Define to 1 if you have '/dev/ptmx' device.])) AC_CHECK_FILE("/dev/ptc", AC_DEFINE([HAVE_DEV_PTS_AND_PTC], [1], [Define to 1 if you have '/dev/ptc' device.])) else AC_MSG_WARN([cross-compilation: assuming /dev/ptmx and /dev/ptc are not available]) fi AC_MSG_NOTICE([**************************************** entropy sources]) if test "x$cross_compiling" = "xno"; then AC_ARG_WITH(egd-socket, [ --with-egd-socket=FILE Entropy Gathering Daemon socket path], [EGD_SOCKET="$withval"] ) if test -n "$EGD_SOCKET"; then AC_DEFINE_UNQUOTED([EGD_SOCKET], ["$EGD_SOCKET"], [Entropy Gathering Daemon socket path]) fi # Check for user-specified random device AC_ARG_WITH(random, [ --with-random=FILE read randomness from file (default=/dev/urandom)], [RANDOM_FILE="$withval"], [ # Check for random device AC_CHECK_FILE("/dev/urandom", RANDOM_FILE="/dev/urandom") ] ) if test -n "$RANDOM_FILE"; then AC_SUBST([RANDOM_FILE]) AC_DEFINE_UNQUOTED([RANDOM_FILE], ["$RANDOM_FILE"], [Random file path]) fi else AC_MSG_WARN([cross-compilation: assuming entropy sources are not available]) fi AC_MSG_NOTICE([**************************************** default group]) DEFAULT_GROUP=nobody if test "x$cross_compiling" = "xno"; then grep '^nogroup:' /etc/group >/dev/null && DEFAULT_GROUP=nogroup else AC_MSG_WARN([cross-compilation: assuming nogroup is not available]) fi AC_MSG_CHECKING([for default group]) AC_MSG_RESULT([$DEFAULT_GROUP]) AC_SUBST([DEFAULT_GROUP]) AC_MSG_NOTICE([**************************************** header files]) # AC_HEADER_DIRENT # AC_HEADER_STDC # AC_HEADER_SYS_WAIT AC_CHECK_HEADERS([stdint.h inttypes.h malloc.h ucontext.h pthread.h poll.h \ tcpd.h stropts.h grp.h unistd.h util.h libutil.h pty.h limits.h]) AC_CHECK_HEADERS([sys/types.h sys/select.h sys/poll.h sys/socket.h sys/un.h \ sys/ioctl.h sys/filio.h sys/resource.h sys/uio.h sys/syscall.h]) AC_CHECK_HEADERS([linux/sched.h]) AC_CHECK_MEMBERS([struct msghdr.msg_control], [AC_DEFINE([HAVE_MSGHDR_MSG_CONTROL], [1], [Define to 1 if you have 'msghdr.msg_control' structure.])], [], [ AC_INCLUDES_DEFAULT #include ]) AC_CHECK_HEADERS([linux/netfilter_ipv4.h], , , [ #include #include #include #include ]) AC_MSG_NOTICE([**************************************** libraries]) # Checks for standard libraries AC_SEARCH_LIBS([gethostbyname], [nsl]) AC_SEARCH_LIBS([yp_get_default_domain], [nsl]) AC_SEARCH_LIBS([socket], [socket]) AC_SEARCH_LIBS([openpty], [util]) # Checks for dynamic loader and zlib needed by OpenSSL AC_SEARCH_LIBS([dlopen], [dl]) AC_SEARCH_LIBS([shl_load], [dld]) AC_SEARCH_LIBS([inflateEnd], [z]) # Add BeOS libraries if test "x$host_os" = "xbeos"; then LIBS="$LIBS -lbe -lroot -lbind" fi AC_MSG_NOTICE([**************************************** library functions]) # safe string operations AC_CHECK_FUNCS(snprintf vsnprintf) # pseudoterminal AC_CHECK_FUNCS(openpty _getpty) # Unix AC_CHECK_FUNCS(daemon waitpid wait4 setsid setgroups chroot realpath) # limits AC_CHECK_FUNCS(sysconf getrlimit) # threads/reentrant functions AC_CHECK_FUNCS(pthread_sigmask localtime_r) # threads AC_CHECK_FUNCS(getcontext __makecontext_v2) # sockets AC_CHECK_FUNCS(poll gethostbyname2 endhostent getnameinfo) AC_MSG_CHECKING([for getaddrinfo]) case "$host_os" in *androideabi*) # http://stackoverflow.com/questions/7818246/segmentation-fault-in-getaddrinfo AC_MSG_RESULT([no (buggy Android implementation)]) ;; *) # Tru64 UNIX has getaddrinfo() but has it renamed in libc as # something else so we must include to get the # redefinition. AC_LINK_IFELSE( [AC_LANG_PROGRAM( [ AC_INCLUDES_DEFAULT #include #include ], [ getaddrinfo(NULL, NULL, NULL, NULL); ],)], [AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_GETADDRINFO], [1], [Define to 1 if you have 'getaddrinfo' function.])], [AC_MSG_RESULT([no])]) ;; esac # poll() is not recommended on Mac OS X <= 10.3 and broken on Mac OS X 10.4 AC_MSG_CHECKING([for broken poll() implementation]) case "$host_os" in darwin[0-8].*) AC_MSG_RESULT([yes (poll() disabled)]) AC_DEFINE([BROKEN_POLL], [1], [Define to 1 if you have a broken 'poll' implementation.]) ;; *) AC_MSG_RESULT([no]) ;; esac # GNU extensions AC_CHECK_FUNCS(pipe2 accept4) AC_MSG_NOTICE([**************************************** optional features]) # Use IPv6? AC_MSG_CHECKING([whether to enable IPv6 support]) AC_ARG_ENABLE(ipv6, [ --disable-ipv6 disable IPv6 support], [ case "$enableval" in yes) AC_MSG_RESULT([yes]) AC_DEFINE([USE_IPv6], [1], [Define to 1 to enable IPv6 support]) ;; no) AC_MSG_RESULT([no]) ;; *) AC_MSG_RESULT([error]) AC_MSG_ERROR([bad value \"${enableval}\"]) ;; esac ], [ AC_MSG_RESULT([yes (default)]) AC_DEFINE([USE_IPv6], [1], [Define to 1 to enable IPv6 support]) ], [ AC_MSG_RESULT([no]) ] ) # FIPS Mode AC_MSG_CHECKING([whether to enable FIPS support]) AC_ARG_ENABLE(fips, [ --disable-fips disable OpenSSL FIPS support], [ case "$enableval" in yes) AC_MSG_RESULT([no]) use_fips="yes" AC_DEFINE([USE_FIPS], [1], [Define to 1 to enable OpenSSL FIPS support]) ;; no) AC_MSG_RESULT([no]) use_fips="no" ;; *) AC_MSG_RESULT([error]) AC_MSG_ERROR([bad value \"${enableval}\"]) ;; esac ], [ use_fips="auto" AC_MSG_RESULT([autodetecting]) ] ) # Disable systemd socket activation support AC_MSG_CHECKING([whether to enable systemd socket activation support]) AC_ARG_ENABLE(systemd, [ --disable-systemd disable systemd socket activation support], [ case "$enableval" in yes) AC_MSG_RESULT([yes]) AC_SEARCH_LIBS([sd_listen_fds], [systemd systemd-daemon]) AC_DEFINE([USE_SYSTEMD], [1], [Define to 1 to enable systemd socket activation]) ;; no) AC_MSG_RESULT([no]) ;; *) AC_MSG_RESULT([error]) AC_MSG_ERROR([Bad value \"${enableval}\"]) ;; esac ], [ AC_MSG_RESULT([autodetecting]) # the library name has changed to -lsystemd in systemd 209 AC_SEARCH_LIBS([sd_listen_fds], [systemd systemd-daemon], [ AC_CHECK_HEADERS([systemd/sd-daemon.h], [ AC_DEFINE([USE_SYSTEMD], [1], [Define to 1 to enable systemd socket activation]) AC_MSG_NOTICE([systemd support enabled]) ], [ AC_MSG_NOTICE([systemd header not found]) ]) ], [ AC_MSG_NOTICE([systemd library not found]) ]) ] ) # Disable use of libwrap (TCP wrappers) # it should be the last check! AC_MSG_CHECKING([whether to enable TCP wrappers support]) AC_ARG_ENABLE(libwrap, [ --disable-libwrap disable TCP wrappers support], [ case "$enableval" in yes) AC_MSG_RESULT([yes]) AC_DEFINE([USE_LIBWRAP], [1], [Define to 1 to enable TCP wrappers support]) LIBS="$LIBS -lwrap" ;; no) AC_MSG_RESULT([no]) ;; *) AC_MSG_RESULT([error]) AC_MSG_ERROR([Bad value \"${enableval}\"]) ;; esac ], [ AC_MSG_RESULT([autodetecting]) AC_MSG_CHECKING([for hosts_access in -lwrap]) valid_LIBS="$LIBS" LIBS="$valid_LIBS -lwrap" AC_LINK_IFELSE( [ AC_LANG_PROGRAM( [int hosts_access(); int allow_severity, deny_severity;], [hosts_access()]) ], [ AC_MSG_RESULT([yes]); AC_DEFINE([USE_LIBWRAP], [1], [Define to 1 to enable TCP wrappers support]) AC_MSG_NOTICE([libwrap support enabled]) ], [ AC_MSG_RESULT([no]) LIBS="$valid_LIBS" AC_MSG_NOTICE([libwrap library not found]) ] ) ] ) AC_MSG_NOTICE([**************************************** SSL]) AC_MSG_CHECKING([for compiler sysroot]) if test "x$GCC" = "xyes"; then sysroot=`$CC --print-sysroot 2>/dev/null` fi if test -z "$sysroot" -o "x$sysroot" = "x/"; then sysroot="" AC_MSG_RESULT([/]) else AC_MSG_RESULT([$sysroot]) fi check_ssl_dir() { : test -n "$1" -a -f "$1/include/openssl/ssl.h" && SSLDIR="$1" } find_ssl_dir() { : stunnel_prefix="$prefix" test "x$stunnel_prefix" = "xNONE" && stunnel_prefix=$ac_default_prefix for main_dir in "$stunnel_prefix" "/usr/local" "/usr/lib" "/usr/pkg" "/opt/local" "/opt" "/opt/csw" "/usr" ""; do for sub_dir in "/ssl" "/openssl" "/ossl" ""; do check_ssl_dir "$sysroot$main_dir$sub_dir" && return done done if test -x "/usr/bin/xcrun"; then sdk_path=`/usr/bin/xcrun --sdk macosx --show-sdk-path` check_ssl_dir "$sdk_path/usr" && return fi check_ssl_dir "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-migrator/sdk/MacOSX.sdk/usr" } SSLDIR="" AC_MSG_CHECKING([for SSL directory]) AC_ARG_WITH(ssl, [ --with-ssl=DIR location of installed SSL libraries/include files], [check_ssl_dir "$withval"], [find_ssl_dir] ) if test -z "$SSLDIR"; then AC_MSG_RESULT([not found]) AC_MSG_ERROR([ Could not find your SSL library installation dir Use --with-ssl option to fix this problem ]) fi AC_MSG_RESULT([$SSLDIR]) AC_SUBST([SSLDIR]) AC_DEFINE_UNQUOTED([SSLDIR], ["$SSLDIR"], [SSL directory]) valid_CPPFLAGS="$CPPFLAGS"; CPPFLAGS="$CPPFLAGS -I$SSLDIR/include" valid_LIBS="$LIBS"; LIBS="$LIBS -L$SSLDIR/lib64 -L$SSLDIR/lib -lssl -lcrypto" if test "x$use_fips" = "xauto"; then AC_CHECK_FUNCS(FIPS_mode_set, [ AC_DEFINE([USE_FIPS], [1], [Define to 1 to enable OpenSSL FIPS support]) AC_MSG_NOTICE([FIPS support enabled]) ], [ AC_MSG_NOTICE([FIPS support not found]) ]) fi CPPFLAGS="$valid_CPPFLAGS" LIBS="$valid_LIBS" AC_MSG_NOTICE([**************************************** write the results]) AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile tools/Makefile]) AC_OUTPUT AC_MSG_NOTICE([**************************************** success]) # vim:ft=automake # End of configure.ac stunnel-5.30/Makefile.am0000664000175000017500000000366612646221043012123 00000000000000## Process this file with automake to produce Makefile.in # by Michal Trojnara 2015-2016 ACLOCAL_AMFLAGS = -I m4 SUBDIRS = src doc tools LIBTOOL_DEPS = @LIBTOOL_DEPS@ libtool: $(LIBTOOL_DEPS) $(SHELL) ./config.status libtool EXTRA_DIST = PORTS BUGS COPYRIGHT.GPL CREDITS EXTRA_DIST += INSTALL.W32 INSTALL.WCE INSTALL.FIPS EXTRA_DIST += build-android.sh .travis.yml docdir = $(datadir)/doc/stunnel doc_DATA = INSTALL README TODO COPYING AUTHORS ChangeLog doc_DATA += PORTS BUGS COPYRIGHT.GPL CREDITS doc_DATA += INSTALL.W32 INSTALL.WCE INSTALL.FIPS distcleancheck_listfiles = find -type f -exec sh -c 'test -f $(srcdir)/{} || echo {}' ';' distclean-local: rm -rf autom4te.cache # rm -f $(distdir)-installer.exe #dist-hook: # makensis -NOCD -DVERSION=${VERSION} \ # -DSTUNNEL_DIR=$(srcdir) \ # -DROOT_DIR=/usr/src \ # $(srcdir)/tools/stunnel.nsi sign: dist cp -f $(distdir).tar.gz $(distdir)-installer.exe $(distdir)-android.zip ../dist gpg-agent --daemon /bin/sh -c "cd ../dist; gpg --yes --armor --detach-sign --force-v3-sigs $(distdir).tar.gz; gpg --yes --armor --detach-sign --force-v3-sigs $(distdir)-installer.exe; gpg --yes --armor --detach-sign --force-v3-sigs $(distdir)-android.zip" sha256sum $(distdir).tar.gz >../dist/$(distdir).tar.gz.sha256 sha256sum $(distdir)-installer.exe >../dist/$(distdir)-installer.exe.sha256 sha256sum $(distdir)-android.zip >../dist/$(distdir)-android.zip.sha256 cat ../dist/$(distdir)*.sha256 | tac cert: $(MAKE) -C tools cert test: $(abs_builddir)/src/stunnel -version @echo "No tests are currently implemented" install-data-hook: @echo "*********************************************************" @echo "* Type 'make cert' to also install a sample certificate *" @echo "*********************************************************" edit = sed \ -e 's|@bindir[@]|$(bindir)|g' \ -e 's|@sysconfdir[@]|$(sysconfdir)|g' stunnel.pod: Makefile $(edit) '$(srcdir)/$@.in' >$@ stunnel.pod: $(srcdir)/stunnel.pod stunnel-5.30/aclocal.m40000664000175000017500000012252412652373721011732 00000000000000# generated automatically by aclocal 1.14.1 -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # Copyright (C) 2002-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.14' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.14.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.14.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each '.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([m4/ax_append_compile_flags.m4]) m4_include([m4/ax_append_flag.m4]) m4_include([m4/ax_append_link_flags.m4]) m4_include([m4/ax_check_compile_flag.m4]) m4_include([m4/ax_check_link_flag.m4]) m4_include([m4/ax_pthread.m4]) m4_include([m4/ax_require_defined.m4]) m4_include([m4/libtool.m4]) m4_include([m4/ltoptions.m4]) m4_include([m4/ltsugar.m4]) m4_include([m4/ltversion.m4]) m4_include([m4/lt~obsolete.m4]) stunnel-5.30/README0000644000175000017500000000130111517764327010742 00000000000000stunnel overview Short description The stunnel program is designed to work as an SSL encryption wrapper between remote client and local (inetd-startable) or remote servers. The goal is to facilitate SSL encryption and authentication for non-SSL-aware programs. stunnel can be used to add SSL functionality to commonly used inetd daemons like POP-2, POP-3 and IMAP servers without any changes in the programs' code. Compile instructions See INSTALL file. License See COPYING file. Other files you should read Changelog What I did TODO What I'm going to do Reporting problems and other contacts See FAQ file. stunnel-5.30/src/0000775000175000017500000000000012652443340010726 500000000000000stunnel-5.30/src/ui_unix.c0000664000175000017500000002073212646221043012473 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #include "common.h" #include "prototypes.h" NOEXPORT int main_unix(int, char*[]); #if !defined(__vms) && !defined(USE_OS2) NOEXPORT int daemonize(int); NOEXPORT int create_pid(void); NOEXPORT void delete_pid(void); #endif #ifndef USE_OS2 NOEXPORT void signal_handler(int); #endif int main(int argc, char* argv[]) { /* execution begins here 8-) */ int retval; #ifdef M_MMAP_THRESHOLD mallopt(M_MMAP_THRESHOLD, 4096); #endif tls_init(); /* initialize thread-local storage */ retval=main_unix(argc, argv); main_cleanup(); return retval; } NOEXPORT int main_unix(int argc, char* argv[]) { int configure_status; #if !defined(__vms) && !defined(USE_OS2) int fd; fd=open("/dev/null", O_RDWR); /* open /dev/null before chroot */ if(fd==INVALID_SOCKET) fatal("Could not open /dev/null"); #endif main_init(); configure_status=main_configure(argc>1 ? argv[1] : NULL, argc>2 ? argv[2] : NULL); switch(configure_status) { case 1: /* error -> exit with 1 to indicate error */ close(fd); return 1; case 2: /* information printed -> exit with 0 to indicate success */ close(fd); return 0; } if(service_options.next) { /* there are service sections -> daemon mode */ #if !defined(__vms) && !defined(USE_OS2) if(daemonize(fd)) { close(fd); return 1; } close(fd); /* create_pid() must be called after drop_privileges() * or it won't be possible to remove the file on exit */ /* create_pid() must be called after daemonize() * since the final pid is not known beforehand */ if(create_pid()) return 1; #endif #ifndef USE_OS2 signal(SIGCHLD, signal_handler); /* handle dead children */ signal(SIGHUP, signal_handler); /* configuration reload */ signal(SIGUSR1, signal_handler); /* log reopen */ signal(SIGPIPE, SIG_IGN); /* ignore broken pipe */ if(signal(SIGTERM, SIG_IGN)!=SIG_IGN) signal(SIGTERM, signal_handler); /* fatal */ if(signal(SIGQUIT, SIG_IGN)!=SIG_IGN) signal(SIGQUIT, signal_handler); /* fatal */ if(signal(SIGINT, SIG_IGN)!=SIG_IGN) signal(SIGINT, signal_handler); /* fatal */ #endif daemon_loop(); } else { /* inetd mode */ #if !defined(__vms) && !defined(USE_OS2) close(fd); #endif /* standard Unix */ #ifndef USE_OS2 signal(SIGCHLD, SIG_IGN); /* ignore dead children */ signal(SIGPIPE, SIG_IGN); /* ignore broken pipe */ #endif set_nonblock(0, 1); /* stdin */ set_nonblock(1, 1); /* stdout */ client_main(alloc_client_session(&service_options, 0, 1)); } return 0; } #ifndef USE_OS2 NOEXPORT void signal_handler(int sig) { int saved_errno; saved_errno=errno; signal_post(sig); signal(sig, signal_handler); errno=saved_errno; } #endif #if !defined(__vms) && !defined(USE_OS2) NOEXPORT int daemonize(int fd) { /* go to background */ if(global_options.option.foreground) return 0; dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); #if defined(HAVE_DAEMON) && !defined(__BEOS__) /* set noclose option when calling daemon() function, * so it does not require /dev/null device in the chrooted directory */ if(daemon(0, 1)==-1) { ioerror("daemon"); return 1; } #else chdir("/"); switch(fork()) { case -1: /* fork failed */ ioerror("fork"); return 1; case 0: /* child */ break; default: /* parent */ exit(0); } #endif tls_alloc(NULL, ui_tls, "main"); /* reuse thread-local storage */ #ifdef HAVE_SETSID setsid(); /* ignore the error */ #endif return 0; } NOEXPORT int create_pid(void) { int pf; char *pid; if(!global_options.pidfile) { s_log(LOG_DEBUG, "No pid file being created"); return 0; } if(global_options.pidfile[0]!='/') { /* to prevent creating pid file relative to '/' after daemonize() */ s_log(LOG_ERR, "Pid file (%s) must be full path name", global_options.pidfile); return 1; } global_options.dpid=(unsigned long)getpid(); /* silently remove old pid file */ unlink(global_options.pidfile); pf=open(global_options.pidfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644); if(pf==-1) { s_log(LOG_ERR, "Cannot create pid file %s", global_options.pidfile); ioerror("create"); return 1; } pid=str_printf("%lu\n", global_options.dpid); if(write(pf, pid, strlen(pid))<(int)strlen(pid)) { s_log(LOG_ERR, "Cannot write pid file %s", global_options.pidfile); ioerror("write"); return 1; } str_free(pid); close(pf); s_log(LOG_DEBUG, "Created pid file %s", global_options.pidfile); atexit(delete_pid); return 0; } NOEXPORT void delete_pid(void) { if((unsigned long)getpid()!=global_options.dpid) return; /* current process is not main daemon process */ s_log(LOG_DEBUG, "removing pid file %s", global_options.pidfile); if(unlink(global_options.pidfile)<0) ioerror(global_options.pidfile); /* not critical */ } #endif /* standard Unix */ /**************************************** options callbacks */ void ui_config_reloaded(void) { /* no action */ } #ifdef ICON_IMAGE ICON_IMAGE load_icon_default(ICON_TYPE icon) { (void)icon; /* squash the unused parameter warning */ return (ICON_IMAGE)0; } ICON_IMAGE load_icon_file(const char *file) { (void)file; /* squash the unused parameter warning */ return (ICON_IMAGE)0; } #endif /**************************************** client callbacks */ void ui_new_chain(const unsigned section_number) { (void)section_number; /* squash the unused parameter warning */ } void ui_clients(const long num) { (void)num; /* squash the unused parameter warning */ } /**************************************** s_log callbacks */ void ui_new_log(const char *line) { fprintf(stderr, "%s\n", line); } /**************************************** ctx callbacks */ int passwd_cb(char *buf, int size, int rwflag, void *userdata) { (void)buf; /* squash the unused parameter warning */ (void)size; /* squash the unused parameter warning */ (void)rwflag; /* squash the unused parameter warning */ (void)userdata; /* squash the unused parameter warning */ return 0; /* not implemented */ } #ifndef OPENSSL_NO_ENGINE int pin_cb(UI *ui, UI_STRING *uis) { (void)ui; /* squash the unused parameter warning */ (void)uis; /* squash the unused parameter warning */ return 0; /* not implemented */ } #endif /* end of ui_unix.c */ stunnel-5.30/src/env.c0000664000175000017500000000563212646221043011605 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ /* getpeername() can't be declared in the following includes */ #define getpeername no_getpeername #include #include /* for AF_INET */ #include #include /* for inet_addr() */ #include /* for getenv() */ #ifdef __BEOS__ #include /* for AF_INET */ #include /* for AF_INET */ #else #include /* for AF_INET */ #endif #undef getpeername int getpeername(int s, struct sockaddr_in *name, int *len) { char *value; (void)s; /* squash the unused parameter warning */ (void)len; /* squash the unused parameter warning */ name->sin_family=AF_INET; if((value=getenv("REMOTE_HOST"))) name->sin_addr.s_addr=inet_addr(value); else name->sin_addr.s_addr=htonl(INADDR_ANY); if((value=getenv("REMOTE_PORT"))) name->sin_port=htons((uint16_t)atoi(value)); else name->sin_port=htons(0); /* dynamic port allocation */ return 0; } /* end of env.c */ stunnel-5.30/src/vc.mak0000664000175000017500000000605012561141776011760 00000000000000# vc.mak by Michal Trojnara 1998-2015 # with help of David Gillingham # with help of Pierre Delaage # the compilation requires: # - Visual C++ 2005 Express Edition with Platform SDK # http://social.msdn.microsoft.com/forums/en-US/Vsexpressvc/thread/c5c3afad-f4c6-4d27-b471-0291e099a742/ # - Visual C++ 2005 Professional Edition # - Visual C++ 2008 Express Edition !IF [ml64.exe /help >NUL 2>&1] TARGET=win32 !ELSE TARGET=win64 !ENDIF !MESSAGE Detected target: $(TARGET) !MESSAGE # modify this to point to your OpenSSL directory # either install a precompiled version (*not* the "Light" one) from # http://www.slproweb.com/products/Win32OpenSSL.html #SSLDIR=C:\OpenSSL-Win32 # or compile one yourself SSLDIR=\devel\$(TARGET)\openssl # or simply install with "nmake -f ms\ntdll.mak install" #SSLDIR=\usr\local\ssl INCDIR=$(SSLDIR)\include LIBDIR=$(SSLDIR)\lib SRC=..\src OBJROOT=..\obj OBJ=$(OBJROOT)\$(TARGET) BINROOT=..\bin BIN=$(BINROOT)\$(TARGET) SHAREDOBJS=$(OBJ)\stunnel.obj $(OBJ)\ssl.obj $(OBJ)\ctx.obj \ $(OBJ)\verify.obj $(OBJ)\file.obj $(OBJ)\client.obj \ $(OBJ)\protocol.obj $(OBJ)\sthreads.obj $(OBJ)\log.obj \ $(OBJ)\options.obj $(OBJ)\network.obj $(OBJ)\resolver.obj \ $(OBJ)\str.obj $(OBJ)\tls.obj $(OBJ)\fd.obj $(OBJ)\dhparam.obj \ $(OBJ)\cron.obj GUIOBJS=$(OBJ)\ui_win_gui.obj $(OBJ)\resources.res CLIOBJS=$(OBJ)\ui_win_cli.obj CC=cl LINK=link UNICODEFLAGS=/DUNICODE /D_UNICODE CFLAGS=/MD /W3 /O2 /nologo /I"$(INCDIR)" $(UNICODEFLAGS) LDFLAGS=/NOLOGO /DEBUG SHAREDLIBS=ws2_32.lib user32.lib shell32.lib GUILIBS=advapi32.lib comdlg32.lib crypt32.lib gdi32.lib psapi.lib CLILIBS= SSLLIBS=/LIBPATH:"$(LIBDIR)" libeay32.lib ssleay32.lib # static linking: # /LIBPATH:"$(LIBDIR)\VC\static" libeay32MD.lib ssleay32MD.lib {$(SRC)\}.c{$(OBJ)\}.obj: $(CC) $(CFLAGS) -Fo$@ -c $< {$(SRC)\}.rc{$(OBJ)\}.res: $(RC) -fo$@ -r $< all: build build: makedirs $(BIN)\stunnel.exe $(BIN)\tstunnel.exe clean: -@ del $(SHAREDOBJS) >NUL 2>&1 -@ del $(GUIOBJS) >NUL 2>&1 -@ del $(CLIOBJS) >NUL 2>&1 # -@ del *.manifest >NUL 2>&1 -@ del $(BIN)\stunnel.exe >NUL 2>&1 -@ del $(BIN)\stunnel.exe.manifest >NUL 2>&1 -@ del $(BIN)\tstunnel.exe >NUL 2>&1 -@ del $(BIN)\tstunnel.exe.manifest >NUL 2>&1 -@ rmdir $(OBJ) >NUL 2>&1 -@ rmdir $(BIN) >NUL 2>&1 makedirs: -@ IF NOT EXIST $(OBJROOT) mkdir $(OBJROOT) >NUL 2>&1 -@ IF NOT EXIST $(OBJ) mkdir $(OBJ) >NUL 2>&1 -@ IF NOT EXIST $(BINROOT) mkdir $(BINROOT) >NUL 2>&1 -@ IF NOT EXIST $(BIN) mkdir $(BIN) >NUL 2>&1 $(SHAREDOBJS): *.h vc.mak $(GUIOBJS): *.h vc.mak $(CLIOBJS): *.h vc.mak $(BIN)\stunnel.exe: $(SHAREDOBJS) $(GUIOBJS) $(LINK) $(LDFLAGS) $(SHAREDLIBS) $(GUILIBS) $(SSLLIBS) /OUT:$@ $** IF EXIST $@.manifest \ mt -nologo -manifest $@.manifest -outputresource:$@;1 $(BIN)\tstunnel.exe: $(SHAREDOBJS) $(CLIOBJS) $(LINK) $(LDFLAGS) $(SHAREDLIBS) $(CLILIBS) $(SSLLIBS) /OUT:$@ $** IF EXIST $@.manifest \ mt -nologo -manifest $@.manifest -outputresource:$@;1 # end of vc.mak stunnel-5.30/src/evc.mak0000664000175000017500000001644612530130423012116 00000000000000# wce.mak for stunnel.exe by Michal Trojnara 2006-2012 # with help of Pierre Delaage # pdelaage 20140610 : added UNICODE optional FLAG, always ACTIVE on WCE because of poor ANSI support # pdelaage 20140610 : added _WIN32_WCE flag for RC compilation, to preprocess out "HELP" unsupported menu flag on WCE # pdelaage 20140610 : ws2 lib is required to get WSAGetLastError routine (absent from winsock lib) # pdelaage 20140610 : /Dx86 flag required for X86/Emulator targets, to get proper definition for InterlockedExchange # pdelaage 20140610 : /MT flag is NON-SENSE for X86-WCE platforms, it is only meaningful for X86-W32-Desktop. # for X86-WCE targets, although compiler "cl.exe" is REALLY the same as desktop W32 VS6 C++ compiler, # the MT flags relating to LIBCMT is useless BECAUSE LIBCMT does NOT exist on WCE. No msvcrt on WCE either... # pdelaage 20140610 : Note on /MC flag # For other targets than X86/Emulator, /MC flag is redundant with "/nodefaultlib coredll.lib corelibc.lib" LD lib list. # For << X86 / Emulator >> target, as the cl.exe compiler IS the SAME as the standard VS6.0 C++ compiler for Desktop Pentium processor, # /MC flag is in fact NOT existing, thus requiring an explicit linking with core libs by using : # /NODEFAULTLIB coredll.lib corelibc.lib, # something that is correct for any WCE target, X86 and other, and leading /MC flag to be useless ALSO for other target than X86. # # DEFAULTLIB management: only 2 are necessary # defaultlibS, as given for CLxxx in the MS doc, ARE WRONG # !!!!!!!!!!!!!! # CUSTOMIZE THIS according to your wcecompat and openssl directories # !!!!!!!!!!!!!! # Modify this to point to your actual openssl compile directory # (You did already compile openssl, didn't you???) SSLDIR=C:\Users\pdelaage\Dvts\Contrib\openssl # Note that we currently use a multi-target customized version of legacy Essemer/wcecompat lib COMPATDIR=C:\Users\pdelaage\Dvts\Contrib\wcecompat\v12\patched3emu WCEVER=420 # !!!!!!!!!!!!!!!!!! # END CUSTOMIZATION # !!!!!!!!!!!!!!!!!! !IF "$(TARGETCPU)"=="X86" WCETARGETCPU=_X86_ LDTARGETCPU=X86 #pdelaage 20140621 /Dx86 for inline defs of InterlockedExchange inline in winbase.h; no more /MT MORECFLAGS=/Dx86 # TODO: continue list for other targets : see wcecompat/wcedefs.mak for a good ref. # see also openssl/util/pl/vc-32.pl, also link /? # for LDTARGETCPU: /MACHINE:{AM33|ARM|IA64|M32R|MIPS|MIPS16|MIPSFPU|MIPSFPU16|MIPSR41XX|SH3|SH3DSP|SH4|SH5|THUMB|X86} # see wce/include/winnt.h for other "target architecture" flag !ELSEIF "$(TARGETCPU)"=="emulator" WCETARGETCPU=_X86_ LDTARGETCPU=X86 #pdelaage 20140621 /Dx86 for inline defs of InterlockedExchange inline in winbase.h; no more /MT MORECFLAGS=/Dx86 !ELSEIF "$(TARGETCPU)"=="MIPS16" || "$(TARGETCPU)"=="MIPSII" || "$(TARGETCPU)"=="MIPSII_FP" || "$(TARGETCPU)"=="MIPSIV" || "$(TARGETCPU)"=="MIPSIV_FP" WCETARGETCPU=_MIPS_ LDTARGETCPU=MIPS #pdelaage 20140621 no more /MC required MORECFLAGS=/DMIPS !ELSEIF "$(TARGETCPU)"=="SH3" || "$(TARGETCPU)"=="SH4" WCETARGETCPU=SHx LDTARGETCPU=$(TARGETCPU) #pdelaage 20140621 no more /MC required MORECFLAGS= !ELSE # default is ARM ! # !IF "$(TARGETCPU)"=="ARMV4" || "$(TARGETCPU)"=="ARMV4I" || "$(TARGETCPU)"=="ARMV4T" # the following flag is required by (eg) winnt.h, and is different from targetcpu (armV4) WCETARGETCPU=ARM LDTARGETCPU=ARM #pdelaage 20140621 no more /MC required MORECFLAGS= !ENDIF # ceutilsdir probably useless (nb : were tools from essemer; but ms delivers a cecopy anyway, see ms dld site) CEUTILSDIR=..\..\ceutils # "ce:" is not a correct location , but we never "make install" DSTDIR=ce:\stunnel # use MS env vars, as in wcecompat and openssl makefiles SDKDIR=$(SDKROOT)\$(OSVERSION)\$(PLATFORM) INCLUDES=-I$(SSLDIR)\inc32 -I$(COMPATDIR)\include -I"$(SDKDIR)\include\$(TARGETCPU)" # for X86 and other it appears that /MC or /ML flags are absurd, # we always have to override runtime lib list to coredll and corelibc #LIBS=/NODEFAULTLIB winsock.lib wcecompatex.lib libeay32.lib ssleay32.lib coredll.lib corelibc.lib LIBS=/NODEFAULTLIB ws2.lib wcecompatex.lib libeay32.lib ssleay32.lib coredll.lib corelibc.lib DEFINES=/DHOST=\"$(TARGETCPU)-WCE-eVC-$(WCEVER)\" # pdelaage 20140610 added unicode flag : ALWAYS ACTIVE on WCE, because of poor ANSI support by the MS SDK UNICODEFLAGS=/DUNICODE -D_UNICODE # /O1 /Oi more correct vs MS doc CFLAGS=/nologo $(MORECFLAGS) /O1 /Oi /W3 /WX /GF /Gy $(DEFINES) /D$(WCETARGETCPU) /D$(TARGETCPU) /DUNDER_CE=$(WCEVER) /D_WIN32_WCE=$(WCEVER) $(UNICODEFLAGS) $(INCLUDES) # pdelaage 20140610 : RC compilation requires D_WIN32_WCE flag to comment out unsupported "HELP" flag in menu definition, in resources.rc file RFLAGS=$(DEFINES) /D_WIN32_WCE=$(WCEVER) $(INCLUDES) # LDFLAGS: since openssl >> 098a (eg 098h) out32dll is out32dll_targetCPU for WCE # delaage added $(TARGETCPU) in legacy Essemer/wcecompat libpath # to ease multitarget compilation without recompiling everything # this customized version is available on: # http://delaage.pierre.free.fr/contrib/wcecompat/wcecompat12_patched.zip LDFLAGS=/nologo /subsystem:windowsce,3.00 /machine:$(LDTARGETCPU) /libpath:"$(SDKDIR)\lib\$(TARGETCPU)" /libpath:"$(COMPATDIR)\lib\$(TARGETCPU)" /libpath:"$(SSLDIR)\out32dll_$(TARGETCPU)" # Multi-target support for stunnel SRC=..\src OBJROOT=..\obj OBJ=$(OBJROOT)\$(TARGETCPU) BINROOT=..\bin BIN=$(BINROOT)\$(TARGETCPU) OBJS=$(OBJ)\stunnel.obj $(OBJ)\ssl.obj $(OBJ)\ctx.obj $(OBJ)\verify.obj \ $(OBJ)\file.obj $(OBJ)\client.obj $(OBJ)\protocol.obj $(OBJ)\sthreads.obj \ $(OBJ)\log.obj $(OBJ)\options.obj $(OBJ)\network.obj $(OBJ)\resolver.obj \ $(OBJ)\str.obj $(OBJ)\tls.obj $(OBJ)\fd.obj $(OBJ)\dhparam.obj \ $(OBJ)\cron.obj GUIOBJS=$(OBJ)\ui_win_gui.obj $(OBJ)\resources.res CLIOBJS=$(OBJ)\ui_win_cli.obj {$(SRC)\}.c{$(OBJ)\}.obj: $(CC) $(CFLAGS) -Fo$@ -c $< {$(SRC)\}.cpp{$(OBJ)\}.obj: $(CC) $(CFLAGS) -Fo$@ -c $< {$(SRC)\}.rc{$(OBJ)\}.res: $(RC) $(RFLAGS) -fo$@ -r $< all: makedirs $(BIN)\stunnel.exe $(BIN)\tstunnel.exe makedirs: -@ IF NOT EXIST $(OBJROOT) mkdir $(OBJROOT) >NUL 2>&1 -@ IF NOT EXIST $(OBJ) mkdir $(OBJ) >NUL 2>&1 -@ IF NOT EXIST $(BINROOT) mkdir $(BINROOT) >NUL 2>&1 -@ IF NOT EXIST $(BIN) mkdir $(BIN) >NUL 2>&1 $(BIN)\stunnel.exe:$(OBJS) $(GUIOBJS) link $(LDFLAGS) /out:$(BIN)\stunnel.exe $(LIBS) commctrl.lib $** $(BIN)\tstunnel.exe:$(OBJS) $(CLIOBJS) link $(LDFLAGS) /out:$(BIN)\tstunnel.exe $(LIBS) $** $(OBJ)\resources.res: $(SRC)\resources.rc $(SRC)\resources.h $(SRC)\version.h $(OBJ)\ui_win_gui.obj: $(SRC)\ui_win_gui.c $(SRC)\version.h $(OBJ)\stunnel.obj: $(SRC)\stunnel.c $(SRC)\version.h # now list of openssl dll has more files, # but we do not use "make install" for stunnel # ceutils come from essemer/wcecompat website # some tools can be found at MS website # TODO: update all this ceutils stuff, or suppress it install: stunnel.exe tstunnel.exe $(CEUTILSDIR)\cemkdir $(DSTDIR) || echo Directory exists? $(CEUTILSDIR)\cecopy stunnel.exe $(DSTDIR) $(CEUTILSDIR)\cecopy tstunnel.exe $(DSTDIR) $(CEUTILSDIR)\cecopy $(SSLDIR)\out32dll_$(TARGETCPU)\libeay32.dll $(DSTDIR) $(CEUTILSDIR)\cecopy $(SSLDIR)\out32dll_$(TARGETCPU)\ssleay32.dll $(DSTDIR) clean: -@ IF NOT "$(TARGETCPU)"=="" del $(OBJS) $(GUIOBJS) $(CLIOBJS) $(BIN)\stunnel.exe $(BIN)\tstunnel.exe >NUL 2>&1 -@ IF NOT "$(TARGETCPU)"=="" rmdir $(OBJ) >NUL 2>&1 -@ IF NOT "$(TARGETCPU)"=="" rmdir $(BIN) >NUL 2>&1 stunnel-5.30/src/protocol.c0000664000175000017500000014371612646221043012664 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #include "common.h" #include "prototypes.h" #define is_prefix(a, b) (strncasecmp((a), (b), strlen(b))==0) /* protocol-specific function prototypes */ NOEXPORT char *socks_client(CLI *, SERVICE_OPTIONS *, const PHASE); NOEXPORT void socks5_client_method(CLI *); NOEXPORT void socks5_client_address(CLI *); NOEXPORT char *socks_server(CLI *, SERVICE_OPTIONS *, const PHASE); NOEXPORT void socks4_server(CLI *); NOEXPORT void socks5_server_method(CLI *); NOEXPORT void socks5_server(CLI *); NOEXPORT int validate(CLI *); NOEXPORT char *proxy_server(CLI *, SERVICE_OPTIONS *, const PHASE); NOEXPORT char *cifs_client(CLI *, SERVICE_OPTIONS *, const PHASE); NOEXPORT char *cifs_server(CLI *, SERVICE_OPTIONS *, const PHASE); NOEXPORT char *pgsql_client(CLI *, SERVICE_OPTIONS *, const PHASE); NOEXPORT char *pgsql_server(CLI *, SERVICE_OPTIONS *, const PHASE); NOEXPORT char *smtp_client(CLI *, SERVICE_OPTIONS *, const PHASE); NOEXPORT void smtp_client_negotiate(CLI *); NOEXPORT void smtp_client_plain(CLI *, const char *, const char *); NOEXPORT void smtp_client_login(CLI *, const char *, const char *); NOEXPORT char *smtp_server(CLI *, SERVICE_OPTIONS *, const PHASE); NOEXPORT char *pop3_client(CLI *, SERVICE_OPTIONS *, const PHASE); NOEXPORT char *pop3_server(CLI *, SERVICE_OPTIONS *, const PHASE); NOEXPORT char *imap_client(CLI *, SERVICE_OPTIONS *, const PHASE); NOEXPORT char *imap_server(CLI *, SERVICE_OPTIONS *, const PHASE); NOEXPORT char *nntp_client(CLI *, SERVICE_OPTIONS *, const PHASE); NOEXPORT char *connect_server(CLI *, SERVICE_OPTIONS *, const PHASE); NOEXPORT char *connect_client(CLI *, SERVICE_OPTIONS *, const PHASE); #ifndef OPENSSL_NO_MD4 NOEXPORT void ntlm(CLI *, SERVICE_OPTIONS *); NOEXPORT char *ntlm1(); NOEXPORT char *ntlm3(char *, char *, char *, char *); NOEXPORT void crypt_DES(DES_cblock, DES_cblock, DES_cblock); #endif NOEXPORT char *base64(int, const char *, int); /**************************************** framework */ char *protocol(CLI *c, SERVICE_OPTIONS *opt, const PHASE phase) { if(phase==PROTOCOL_CHECK) /* default to be overridden by protocols */ opt->option.connect_before_ssl=opt->option.client; if(!opt->protocol) /* no protocol specified */ return NULL; /* skip further actions */ if(!strcasecmp(opt->protocol, "socks")) return opt->option.client ? socks_client(c, opt, phase) : socks_server(c, opt, phase); if(!strcasecmp(opt->protocol, "proxy")) return opt->option.client ? "The 'proxy' protocol is not supported in the client mode" : proxy_server(c, opt, phase); if(!strcasecmp(opt->protocol, "cifs")) return opt->option.client ? cifs_client(c, opt, phase) : cifs_server(c, opt, phase); if(!strcasecmp(opt->protocol, "pgsql")) return opt->option.client ? pgsql_client(c, opt, phase) : pgsql_server(c, opt, phase); if(!strcasecmp(opt->protocol, "smtp")) return opt->option.client ? smtp_client(c, opt, phase) : smtp_server(c, opt, phase); if(!strcasecmp(opt->protocol, "pop3")) return opt->option.client ? pop3_client(c, opt, phase) : pop3_server(c, opt, phase); if(!strcasecmp(opt->protocol, "imap")) return opt->option.client ? imap_client(c, opt, phase) : imap_server(c, opt, phase); if(!strcasecmp(opt->protocol, "nntp")) return opt->option.client ? nntp_client(c, opt, phase) : "The 'nntp' protocol is not supported in the server mode"; if(!strcasecmp(opt->protocol, "connect")) return opt->option.client ? connect_client(c, opt, phase) : connect_server(c, opt, phase); return "Protocol not supported"; } /**************************************** socks */ /* SOCKS over SSL (SOCKS protocol itself is also encrypted) */ typedef union { struct { uint8_t ver, cmd, rsv, atyp; } req; struct { uint8_t ver, rep, rsv, atyp; } resp; struct { uint8_t ver, code, rsv, atyp, addr[4], port[2]; } v4; struct { uint8_t ver, code, rsv, atyp, addr[16], port[2]; } v6; } SOCKS5_UNION; NOEXPORT char *socks_client(CLI *c, SERVICE_OPTIONS *opt, const PHASE phase) { (void)opt; /* squash the unused parameter warning */ if(phase!=PROTOCOL_LATE) return NULL; socks5_client_method(c); socks5_client_address(c); return NULL; } NOEXPORT void socks5_client_method(CLI *c) { const struct { uint8_t ver, nmethods, method; } req={5, 1, 0x00}; /* NO AUTHENTICATION REQUIRED */ struct { uint8_t ver, method; } resp; s_ssl_write(c, &req, sizeof req); s_ssl_read(c, &resp, sizeof resp); if(resp.ver!=5) { s_log(LOG_ERR, "Invalid SOCKS5 message version 0x%02x", resp.ver); longjmp(c->err, 2); /* don't reset */ } /* TODO: add USERNAME/PASSWORD authentication */ if(resp.method!=0x00) { s_log(LOG_ERR, "No supported SOCKS5 authentication method received"); longjmp(c->err, 2); /* don't reset */ } } NOEXPORT void socks5_client_address(CLI *c) { SOCKADDR_UNION addr; SOCKS5_UNION socks; if(original_dst(c->local_rfd.fd, &addr)) longjmp(c->err, 2); /* don't reset */ memset(&socks, 0, sizeof socks); socks.req.ver=5; /* SOCKS5 */ socks.req.cmd=0x01; /* CONNECT */ switch(addr.sa.sa_family) { case AF_INET: socks.req.atyp=0x01; /* IP v4 address */ memcpy(&socks.v4.addr, &addr.in.sin_addr, 4); memcpy(&socks.v4.port, &addr.in.sin_port, 2); s_log(LOG_INFO, "Sending SOCKS5 IPv4 address"); s_ssl_write(c, &socks, sizeof socks.v4); break; #ifdef USE_IPv6 case AF_INET6: socks.req.atyp=0x04; /* IP v6 address */ memcpy(&socks.v6.addr, &addr.in6.sin6_addr, 16); memcpy(&socks.v6.port, &addr.in6.sin6_port, 2); s_log(LOG_INFO, "Sending SOCKS5 IPv6 address"); s_ssl_write(c, &socks, sizeof socks.v6); break; #endif default: s_log(LOG_ERR, "Unsupported address type 0x%02x", addr.sa.sa_family); longjmp(c->err, 2); /* don't reset */ } s_ssl_read(c, &socks, sizeof socks.resp); if(socks.resp.atyp==0x04) /* IP V6 address */ s_ssl_read(c, &socks.v6.addr, 16+2); else s_ssl_read(c, &socks.v4.addr, 4+2); if(socks.resp.ver!=5) { s_log(LOG_ERR, "Invalid SOCKS5 message version 0x%02x", socks.req.ver); longjmp(c->err, 2); /* don't reset */ } switch(socks.resp.rep) { case 0x00: s_log(LOG_INFO, "SOCKS5 request succeeded"); return; /* SUCCESS */ case 0x01: s_log(LOG_ERR, "SOCKS5 request failed: General SOCKS server failure"); break; case 0x02: s_log(LOG_ERR, "SOCKS5 request failed: Connection not allowed by ruleset"); break; case 0x03: s_log(LOG_ERR, "SOCKS5 request failed: Network unreachable"); break; case 0x04: s_log(LOG_ERR, "SOCKS5 request failed: Host unreachable"); break; case 0x05: s_log(LOG_ERR, "SOCKS5 request failed: Connection refused"); break; case 0x06: s_log(LOG_ERR, "SOCKS5 request failed: TTL expired"); break; case 0x07: s_log(LOG_ERR, "SOCKS5 request failed: Command not supported"); break; case 0x08: s_log(LOG_ERR, "SOCKS5 request failed: Address type not supported"); break; default: s_log(LOG_ERR, "SOCKS5 request failed: Unknown error 0x%02x", socks.resp.rep); } longjmp(c->err, 2); /* don't reset */ } NOEXPORT char *socks_server(CLI *c, SERVICE_OPTIONS *opt, const PHASE phase) { uint8_t version; switch(phase) { case PROTOCOL_CHECK: opt->option.protocol_endpoint=1; break; case PROTOCOL_MIDDLE: s_log(LOG_DEBUG, "Waiting for the SOCKS request"); s_ssl_read(c, &version, sizeof version); switch(version) { case 4: socks4_server(c); break; case 5: socks5_server_method(c); socks5_server(c); break; default: s_log(LOG_ERR, "Unsupported SOCKS version 0x%02x", version); longjmp(c->err, 1); } break; case PROTOCOL_LATE: /* TODO: send the SOCKS reply *after* the target is connected */ /* FIXME: the SOCKS replies do not report CONNECT failures */ /* FIXME: the SOCKS replies do not contain the bound IP address */ break; default: break; } return NULL; } /* SOCKS4 or SOCKS4a */ /* BIND command is not supported */ /* USERID parameter is ignored */ NOEXPORT void socks4_server(CLI *c) { struct { uint8_t vn, cd; u_short sin_port; struct in_addr sin_addr; } socks; char *user_name, *host_name, *port_name; SOCKADDR_UNION addr; int close_connection=1; s_ssl_read(c, &socks.cd, sizeof socks-sizeof socks.vn); socks.vn=0; /* response version 0 */ user_name=ssl_getstring(c); /* ignore the username */ str_free(user_name); if(socks.cd==0x01) { /* CONNECT */ if(ntohl(socks.sin_addr.s_addr)>0 && ntohl(socks.sin_addr.s_addr)<256) { /* 0.0.0.x */ host_name=ssl_getstring(c); port_name=str_printf("%u", ntohs(socks.sin_port)); hostport2addrlist(&c->connect_addr, host_name, port_name); str_free(port_name); if(c->connect_addr.num) { s_log(LOG_INFO, "SOCKS4a resolved \"%s\" to %u host(s)", host_name, c->connect_addr.num); if(validate(c)) { socks.cd=90; /* access granted */ close_connection=0; } else { socks.cd=91; /* rejected */ } } else { s_log(LOG_ERR, "SOCKS4a failed to resolve \"%s\"", host_name); socks.cd=91; /* failed */ } str_free(host_name); } else { c->connect_addr.num=1; c->connect_addr.addr=str_alloc(sizeof(SOCKADDR_UNION)); c->connect_addr.addr[0].in.sin_family=AF_INET; c->connect_addr.addr[0].in.sin_port=socks.sin_port; c->connect_addr.addr[0].in.sin_addr.s_addr=socks.sin_addr.s_addr; s_log(LOG_INFO, "SOCKS4 address received"); if(validate(c)) { socks.cd=90; /* access granted */ close_connection=0; } else { socks.cd=91; /* rejected */ } } } else if(socks.cd==0xf0) { /* RESOLVE (a TOR extension) */ host_name=ssl_getstring(c); if(hostport2addr(&addr, host_name, "0", 0) && addr.sa.sa_family==AF_INET) { memcpy(&socks.sin_addr, &addr.in.sin_addr, 4); s_log(LOG_INFO, "SOCKS4a/TOR resolved \"%s\"", host_name); socks.cd=90; /* access granted */ } else { s_log(LOG_ERR, "SOCKS4a/TOR failed to resolve \"%s\"", host_name); socks.cd=91; /* failed */ } str_free(host_name); } else { s_log(LOG_ERR, "Unsupported SOCKS4/SOCKS4a command 0x%02x", socks.cd); socks.cd=91; /* failed */ } s_ssl_write(c, &socks, sizeof socks); if(close_connection) longjmp(c->err, 2); /* don't reset */ } NOEXPORT void socks5_server_method(CLI *c) { uint8_t nmethods, *methods; struct { uint8_t ver, method; } response; int i; response.ver=0x05; response.method=0xff; /* NO ACCEPTABLE METHODS */ s_ssl_read(c, &nmethods, sizeof nmethods); methods=str_alloc(nmethods); s_ssl_read(c, methods, nmethods); for(i=0; ierr, 2); /* don't reset */ } } /* CONNECT does not return valid BND.ADDR and BND.PORT values */ NOEXPORT void socks5_server(CLI *c) { SOCKS5_UNION socks; uint8_t host_len; char *host_name, *port_name; u_short port_number; SOCKADDR_UNION addr; int close_connection=1; /* parse request */ memset(&socks, 0, sizeof socks); s_ssl_read(c, &socks, sizeof socks.req); if(socks.req.ver!=0x05) { s_log(LOG_ERR, "Invalid SOCKS5 message version 0x%02x", socks.req.ver); socks.resp.ver=0x05; /* response version 5 */ socks.resp.rep=0x01; /* general SOCKS server failure */ } else if(socks.req.cmd==0x01) { /* CONNECT */ if(socks.req.atyp==0x01) { /* IP v4 address */ c->connect_addr.num=1; c->connect_addr.addr=str_alloc(sizeof(SOCKADDR_UNION)); c->connect_addr.addr[0].in.sin_family=AF_INET; s_ssl_read(c, &socks.v4.addr, 4+2); memcpy(&c->connect_addr.addr[0].in.sin_addr, &socks.v4.addr, 4); memcpy(&c->connect_addr.addr[0].in.sin_port, &socks.v4.port, 2); s_log(LOG_INFO, "SOCKS5 IPv4 address received"); if(validate(c)) { socks.resp.rep=0x00; /* succeeded */ close_connection=0; } else { socks.resp.rep=0x02; /* connection not allowed by ruleset */ } } else if(socks.req.atyp==0x03) { /* DOMAINNAME */ s_ssl_read(c, &host_len, sizeof host_len); host_name=str_alloc((size_t)host_len+1); s_ssl_read(c, host_name, host_len); host_name[host_len]='\0'; s_ssl_read(c, &port_number, 2); port_name=str_printf("%u", ntohs(port_number)); hostport2addrlist(&c->connect_addr, host_name, port_name); str_free(port_name); if(c->connect_addr.num) { s_log(LOG_INFO, "SOCKS5 resolved \"%s\" to %u host(s)", host_name, c->connect_addr.num); if(validate(c)) { socks.resp.rep=0x00; /* succeeded */ close_connection=0; } else { socks.resp.rep=0x02; /* connection not allowed by ruleset */ } } else { s_log(LOG_ERR, "SOCKS5 failed to resolve \"%s\"", host_name); socks.resp.rep=0x04; /* Host unreachable */ } str_free(host_name); #ifdef USE_IPv6 } else if(socks.req.atyp==0x04) { /* IP v6 address */ c->connect_addr.num=1; c->connect_addr.addr=str_alloc(sizeof(SOCKADDR_UNION)); c->connect_addr.addr[0].in6.sin6_family=AF_INET6; s_ssl_read(c, &socks.v6.addr, 16+2); memcpy(&c->connect_addr.addr[0].in6.sin6_addr, &socks.v6.addr, 16); memcpy(&c->connect_addr.addr[0].in6.sin6_port, &socks.v6.port, 2); s_log(LOG_INFO, "SOCKS5 IPv6 address received"); if(validate(c)) { socks.resp.rep=0x00; /* succeeded */ close_connection=0; } else { socks.resp.rep=0x02; /* connection not allowed by ruleset */ } #endif } else { s_log(LOG_ERR, "Unsupported SOCKS5 address type 0x%02x", socks.req.atyp); socks.resp.rep=0x07; /* Address type not supported */ } } else if(socks.req.cmd==0xf0) { /* RESOLVE (a TOR extension) */ s_ssl_read(c, &host_len, sizeof host_len); host_name=str_alloc((size_t)host_len+1); s_ssl_read(c, host_name, host_len); host_name[host_len]='\0'; s_ssl_read(c, &port_number, 2); port_name=str_printf("%u", ntohs(port_number)); if(hostport2addr(&addr, host_name, port_name, 0)) { if(addr.sa.sa_family==AF_INET) { s_log(LOG_INFO, "SOCKS5/TOR resolved \"%s\" to IPv4", host_name); memcpy(&socks.v4.addr, &addr.in.sin_addr, 4); socks.resp.atyp=0x01; /* IP v4 address */ socks.resp.rep=0x00; /* succeeded */ #ifdef USE_IPv6 } else if(addr.sa.sa_family==AF_INET6) { s_log(LOG_INFO, "SOCKS5/TOR resolved \"%s\" to IPv6", host_name); memcpy(&socks.v6.addr, &addr.in6.sin6_addr, 16); socks.resp.atyp=0x04; /* IP v6 address */ socks.resp.rep=0x00; /* succeeded */ #endif } else { s_log(LOG_ERR, "SOCKS5/TOR unsupported address type for \"%s\"", host_name); socks.resp.rep=0x04; /* Host unreachable */ } } else { s_log(LOG_ERR, "SOCKS5/TOR failed to resolve \"%s\"", host_name); socks.resp.rep=0x04; /* Host unreachable */ } str_free(host_name); str_free(port_name); } else { s_log(LOG_ERR, "Unsupported SOCKS5 command 0x%02x", socks.req.cmd); socks.resp.rep=0x07; /* Command not supported */ } /* send response */ /* broken clients tend to expect the same address family for response, * so stunnel tries to preserve the address family if possible */ if(socks.resp.atyp==0x04) { /* IP V6 address */ s_ssl_write(c, &socks, sizeof socks.v6); } else { socks.resp.atyp=0x01; /* IP v4 address */ s_ssl_write(c, &socks, sizeof socks.v4); } if(close_connection) /* request failed */ longjmp(c->err, 2); /* don't reset */ } /* validate the allocated address */ NOEXPORT int validate(CLI *c) { #ifdef USE_IPv6 const unsigned char ipv6_loopback[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; #endif unsigned i; for(i=0; iconnect_addr.num; ++i) { SOCKADDR_UNION *addr=&c->connect_addr.addr[i]; #ifdef USE_IPv6 if(addr->sa.sa_family==AF_INET6) { if(!memcmp(&addr->in6.sin6_addr, ipv6_loopback, 16)) { s_log(LOG_ERR, "SOCKS connection to the IPv6 loopback rejected"); return 0; } /* TODO: implement more checks */ } else #endif if(addr->sa.sa_family==AF_INET) { if((ntohl(addr->in.sin_addr.s_addr)&0xff000000)==0x7f000000) { s_log(LOG_ERR, "SOCKS connection to the IPv4 loopback rejected"); return 0; } /* TODO: implement more checks */ } else { s_log(LOG_ERR, "Unsupported address type 0x%02x", addr->sa.sa_family); return 0; } } return 1; } /**************************************** proxy */ /* * PROXY protocol: http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt * this is a protocol client support for stunnel acting as an SSL server * I don't think anything else is useful, but feel free to discuss on the * stunnel-users mailing list if you disagree */ /* IP address textual representation length */ /* 1234:6789:1234:6789:1234:6789:1234:6789 -> 40 chars with '\0' */ #define IP_LEN 40 #define PORT_LEN 6 NOEXPORT char *proxy_server(CLI *c, SERVICE_OPTIONS *opt, const PHASE phase) { SOCKADDR_UNION addr; socklen_t addrlen; char src_host[IP_LEN], dst_host[IP_LEN]; char src_port[PORT_LEN], dst_port[PORT_LEN], *proto; int err; (void)opt; /* squash the unused parameter warning */ if(phase!=PROTOCOL_LATE) return NULL; addrlen=sizeof addr; if(getpeername(c->local_rfd.fd, &addr.sa, &addrlen)) { sockerror("getpeername"); longjmp(c->err, 1); } err=getnameinfo(&addr.sa, addr_len(&addr), src_host, IP_LEN, src_port, PORT_LEN, NI_NUMERICHOST|NI_NUMERICSERV); if(err) { s_log(LOG_ERR, "getnameinfo: %s", s_gai_strerror(err)); longjmp(c->err, 1); } addrlen=sizeof addr; if(getsockname(c->local_rfd.fd, &addr.sa, &addrlen)) { sockerror("getsockname"); longjmp(c->err, 1); } err=getnameinfo(&addr.sa, addr_len(&addr), dst_host, IP_LEN, dst_port, PORT_LEN, NI_NUMERICHOST|NI_NUMERICSERV); if(err) { s_log(LOG_ERR, "getnameinfo: %s", s_gai_strerror(err)); longjmp(c->err, 1); } switch(addr.sa.sa_family) { case AF_INET: proto="TCP4"; break; #ifdef USE_IPv6 case AF_INET6: proto="TCP6"; break; #endif default: /* AF_UNIX */ proto="UNKNOWN"; } fd_printf(c, c->remote_fd.fd, "PROXY %s %s %s %s %s", proto, src_host, dst_host, src_port, dst_port); return NULL; } /**************************************** cifs */ NOEXPORT char *cifs_client(CLI *c, SERVICE_OPTIONS *opt, const PHASE phase) { uint8_t buffer[5]; uint8_t request_dummy[4] = {0x81, 0, 0, 0}; /* a zero-length request */ (void)opt; /* squash the unused parameter warning */ if(phase!=PROTOCOL_MIDDLE) return NULL; s_write(c, c->remote_fd.fd, request_dummy, 4); s_read(c, c->remote_fd.fd, buffer, 5); if(buffer[0]!=0x83) { /* NB_SSN_NEGRESP */ s_log(LOG_ERR, "Negative response expected"); longjmp(c->err, 1); } if(buffer[2]!=0 || buffer[3]!=1) { /* length != 1 */ s_log(LOG_ERR, "Unexpected NetBIOS response size"); longjmp(c->err, 1); } if(buffer[4]!=0x8e) { /* use SSL */ s_log(LOG_ERR, "Remote server does not require SSL"); longjmp(c->err, 1); } return NULL; } NOEXPORT char *cifs_server(CLI *c, SERVICE_OPTIONS *opt, const PHASE phase) { uint8_t buffer[128]; uint8_t response_access_denied[5] = {0x83, 0, 0, 1, 0x81}; uint8_t response_use_ssl[5] = {0x83, 0, 0, 1, 0x8e}; uint16_t len; (void)opt; /* squash the unused parameter warning */ if(phase!=PROTOCOL_EARLY) return NULL; s_read(c, c->local_rfd.fd, buffer, 4) ;/* NetBIOS header */ len=(uint16_t)(((uint16_t)(buffer[2])<<8)|buffer[3]); if(len>sizeof buffer-4) { s_log(LOG_ERR, "Received block too long"); longjmp(c->err, 1); } s_read(c, c->local_rfd.fd, buffer+4, len); if(buffer[0]!=0x81) { /* NB_SSN_REQUEST */ s_log(LOG_ERR, "Client did not send session setup"); s_write(c, c->local_wfd.fd, response_access_denied, 5); longjmp(c->err, 1); } s_write(c, c->local_wfd.fd, response_use_ssl, 5); return NULL; } /**************************************** pgsql */ /* http://www.postgresql.org/docs/8.3/static/protocol-flow.html#AEN73982 */ static const uint8_t ssl_request[8]={0, 0, 0, 8, 0x04, 0xd2, 0x16, 0x2f}; NOEXPORT char *pgsql_client(CLI *c, SERVICE_OPTIONS *opt, const PHASE phase) { uint8_t buffer[1]; (void)opt; /* squash the unused parameter warning */ if(phase!=PROTOCOL_MIDDLE) return NULL; s_write(c, c->remote_fd.fd, ssl_request, sizeof ssl_request); s_read(c, c->remote_fd.fd, buffer, 1); /* S - accepted, N - rejected, non-SSL preferred */ if(buffer[0]!='S') { s_log(LOG_ERR, "PostgreSQL server rejected SSL"); longjmp(c->err, 1); } return NULL; } NOEXPORT char *pgsql_server(CLI *c, SERVICE_OPTIONS *opt, const PHASE phase) { uint8_t buffer[8], ssl_ok[1]={'S'}; (void)opt; /* squash the unused parameter warning */ if(phase!=PROTOCOL_EARLY) return NULL; memset(buffer, 0, sizeof buffer); s_read(c, c->local_rfd.fd, buffer, sizeof buffer); if(safe_memcmp(buffer, ssl_request, sizeof ssl_request)) { s_log(LOG_ERR, "PostgreSQL client did not request SSL, rejecting"); /* no way to send error on startup, so just drop the client */ longjmp(c->err, 1); } s_write(c, c->local_wfd.fd, ssl_ok, sizeof ssl_ok); return NULL; } /**************************************** smtp */ NOEXPORT char *smtp_client(CLI *c, SERVICE_OPTIONS *opt, const PHASE phase) { (void)opt; /* squash the unused parameter warning */ switch(phase) { case PROTOCOL_MIDDLE: smtp_client_negotiate(c); break; case PROTOCOL_LATE: if(opt->protocol_username && opt->protocol_password) { if(!strcasecmp(c->opt->protocol_authentication, "LOGIN")) smtp_client_login(c, opt->protocol_username, opt->protocol_password); else /* use PLAIN by default */ smtp_client_plain(c, opt->protocol_username, opt->protocol_password); } break; default: break; } return NULL; } NOEXPORT void smtp_client_negotiate(CLI *c) { char *line; line=str_dup(""); do { /* copy multiline greeting */ str_free(line); line=fd_getline(c, c->remote_fd.fd); fd_putline(c, c->local_wfd.fd, line); } while(is_prefix(line, "220-")); fd_putline(c, c->remote_fd.fd, "EHLO localhost"); do { /* skip multiline reply */ str_free(line); line=fd_getline(c, c->remote_fd.fd); } while(is_prefix(line, "250-")); if(!is_prefix(line, "250 ")) { /* error */ s_log(LOG_ERR, "Remote server is not RFC 1425 compliant"); str_free(line); longjmp(c->err, 1); } fd_putline(c, c->remote_fd.fd, "STARTTLS"); do { /* skip multiline reply */ str_free(line); line=fd_getline(c, c->remote_fd.fd); } while(is_prefix(line, "220-")); if(!is_prefix(line, "220 ")) { /* error */ s_log(LOG_ERR, "Remote server is not RFC 2487 compliant"); str_free(line); longjmp(c->err, 1); } str_free(line); } /* http://www.samlogic.net/articles/smtp-commands-reference-auth.htm */ NOEXPORT void smtp_client_plain(CLI *c, const char *user, const char *pass) { char *line, *encoded; line=str_printf("%c%s%c%s", '\0', user, '\0', pass); encoded=base64(1, line, (int)strlen(user) + (int)strlen(pass) + 2); if(!encoded) { s_log(LOG_ERR, "Base64 encoder failed"); str_free(line); longjmp(c->err, 1); } str_free(line); line=str_printf("AUTH PLAIN %s", encoded); str_free(encoded); ssl_putline(c, line); str_free(line); line=ssl_getline(c); if(!is_prefix(line, "235 ")) { /* not 'Authentication successful' */ s_log(LOG_ERR, "PLAIN Authentication Failed"); str_free(line); longjmp(c->err, 1); } str_free(line); } NOEXPORT void smtp_client_login(CLI *c, const char *user, const char *pass) { char *line, *encoded; ssl_putline(c, "AUTH LOGIN"); line=ssl_getline(c); if(!is_prefix(line, "334 ")) { /* not the username challenge */ s_log(LOG_ERR, "Remote server does not support LOGIN authentication"); str_free(line); longjmp(c->err, 1); } str_free(line); encoded=base64(1, user, (int)strlen(user)); if(!encoded) { s_log(LOG_ERR, "Base64 encoder failed"); longjmp(c->err, 1); } ssl_putline(c, encoded); str_free(encoded); line=ssl_getline(c); if(!is_prefix(line, "334 ")) { /* not the password challenge */ s_log(LOG_ERR, "LOGIN authentication failed"); str_free(line); longjmp(c->err, 1); } str_free(line); encoded=base64(1, pass, (int)strlen(pass)); if(!encoded) { s_log(LOG_ERR, "Base64 encoder failed"); longjmp(c->err, 1); } ssl_putline(c, encoded); str_free(encoded); line=ssl_getline(c); if(!is_prefix(line, "235 ")) { /* not 'Authentication successful' */ s_log(LOG_ERR, "LOGIN authentication failed"); str_free(line); longjmp(c->err, 1); } str_free(line); } NOEXPORT char *smtp_server(CLI *c, SERVICE_OPTIONS *opt, const PHASE phase) { char *line, *domain, *greeting; if(phase==PROTOCOL_CHECK) opt->option.connect_before_ssl=1; /* c->remote_fd needed */ if(phase!=PROTOCOL_MIDDLE) return NULL; /* detect RFC 2487 */ s_poll_init(c->fds); s_poll_add(c->fds, c->local_rfd.fd, 1, 0); switch(s_poll_wait(c->fds, 0, 200)) { /* wait up to 200ms */ case 0: /* fd not ready to read */ s_log(LOG_DEBUG, "RFC 2487 detected"); break; case 1: /* fd ready to read */ s_log(LOG_DEBUG, "RFC 2487 not detected"); return NULL; /* return if RFC 2487 is not used */ default: /* -1 */ sockerror("RFC2487 (s_poll_wait)"); longjmp(c->err, 1); } /* process server's greeting */ line=fd_getline(c, c->remote_fd.fd); if(!(is_prefix(line, "220 ") || is_prefix(line, "220-"))) { s_log(LOG_ERR, "Unknown server welcome"); str_free(line); longjmp(c->err, 1); } domain=str_dup(line+4); /* skip "220" and the separator */ line[4]='\0'; /* only leave "220" and the separator */ greeting=strchr(domain, ' '); if(greeting) { *greeting++='\0'; /* truncate anything after the domain name */ fd_printf(c, c->local_wfd.fd, "%s%s stunnel for %s", line, domain, greeting); } else { fd_printf(c, c->local_wfd.fd, "%s%s stunnel", line, domain); } while(is_prefix(line, "220-")) { /* copy multiline greeting */ str_free(line); line=fd_getline(c, c->remote_fd.fd); fd_putline(c, c->local_wfd.fd, line); } str_free(line); /* process client's EHLO */ line=fd_getline(c, c->local_rfd.fd); if(!is_prefix(line, "EHLO ")) { s_log(LOG_ERR, "Unknown client EHLO"); str_free(line); str_free(domain); longjmp(c->err, 1); } str_free(line); fd_printf(c, c->local_wfd.fd, "250-%s", domain); str_free(domain); fd_putline(c, c->local_wfd.fd, "250 STARTTLS"); /* process client's STARTTLS */ line=fd_getline(c, c->local_rfd.fd); if(!is_prefix(line, "STARTTLS")) { s_log(LOG_ERR, "STARTTLS expected"); str_free(line); longjmp(c->err, 1); } fd_putline(c, c->local_wfd.fd, "220 Go ahead"); str_free(line); return NULL; } /**************************************** pop3 */ NOEXPORT char *pop3_client(CLI *c, SERVICE_OPTIONS *opt, const PHASE phase) { char *line; (void)opt; /* squash the unused parameter warning */ if(phase!=PROTOCOL_MIDDLE) return NULL; line=fd_getline(c, c->remote_fd.fd); if(!is_prefix(line, "+OK ")) { s_log(LOG_ERR, "Unknown server welcome"); str_free(line); longjmp(c->err, 1); } fd_putline(c, c->local_wfd.fd, line); fd_putline(c, c->remote_fd.fd, "STLS"); str_free(line); line=fd_getline(c, c->remote_fd.fd); if(!is_prefix(line, "+OK ")) { s_log(LOG_ERR, "Server does not support TLS"); str_free(line); longjmp(c->err, 1); } str_free(line); return NULL; } NOEXPORT char *pop3_server(CLI *c, SERVICE_OPTIONS *opt, const PHASE phase) { char *line; if(phase==PROTOCOL_CHECK) opt->option.connect_before_ssl=1; /* c->remote_fd needed */ if(phase!=PROTOCOL_MIDDLE) return NULL; line=fd_getline(c, c->remote_fd.fd); fd_printf(c, c->local_wfd.fd, "%s + stunnel", line); str_free(line); line=fd_getline(c, c->local_rfd.fd); if(is_prefix(line, "CAPA")) { /* client wants RFC 2449 extensions */ fd_putline(c, c->local_wfd.fd, "+OK Stunnel capability list follows"); fd_putline(c, c->local_wfd.fd, "STLS"); fd_putline(c, c->local_wfd.fd, "."); str_free(line); line=fd_getline(c, c->local_rfd.fd); } if(!is_prefix(line, "STLS")) { s_log(LOG_ERR, "Client does not want TLS"); str_free(line); longjmp(c->err, 1); } str_free(line); fd_putline(c, c->local_wfd.fd, "+OK Stunnel starts TLS negotiation"); return NULL; } /**************************************** imap */ NOEXPORT char *imap_client(CLI *c, SERVICE_OPTIONS *opt, const PHASE phase) { char *line; (void)opt; /* squash the unused parameter warning */ if(phase!=PROTOCOL_MIDDLE) return NULL; line=fd_getline(c, c->remote_fd.fd); if(!is_prefix(line, "* OK")) { s_log(LOG_ERR, "Unknown server welcome"); str_free(line); longjmp(c->err, 1); } fd_putline(c, c->local_wfd.fd, line); fd_putline(c, c->remote_fd.fd, "stunnel STARTTLS"); str_free(line); line=fd_getline(c, c->remote_fd.fd); if(!is_prefix(line, "stunnel OK")) { fd_putline(c, c->local_wfd.fd, "* BYE stunnel: Server does not support TLS"); s_log(LOG_ERR, "Server does not support TLS"); str_free(line); longjmp(c->err, 2); /* don't reset */ } str_free(line); return NULL; } NOEXPORT char *imap_server(CLI *c, SERVICE_OPTIONS *opt, const PHASE phase) { char *line, *id, *tail, *capa; if(phase==PROTOCOL_CHECK) opt->option.connect_before_ssl=1; /* c->remote_fd needed */ if(phase!=PROTOCOL_MIDDLE) return NULL; s_poll_init(c->fds); s_poll_add(c->fds, c->local_rfd.fd, 1, 0); switch(s_poll_wait(c->fds, 0, 200)) { case 0: /* fd not ready to read */ s_log(LOG_DEBUG, "RFC 2595 detected"); break; case 1: /* fd ready to read */ s_log(LOG_DEBUG, "RFC 2595 not detected"); return NULL; /* return if RFC 2595 is not used */ default: /* -1 */ sockerror("RFC2595 (s_poll_wait)"); longjmp(c->err, 1); } /* process server welcome and send it to client */ line=fd_getline(c, c->remote_fd.fd); if(!is_prefix(line, "* OK")) { s_log(LOG_ERR, "Unknown server welcome"); str_free(line); longjmp(c->err, 1); } capa=strstr(line, "CAPABILITY"); if(!capa) capa=strstr(line, "capability"); if(capa) *capa='K'; /* disable CAPABILITY within greeting */ fd_printf(c, c->local_wfd.fd, "%s (stunnel)", line); id=str_dup(""); while(1) { /* process client commands */ str_free(line); line=fd_getline(c, c->local_rfd.fd); /* split line into id and tail */ str_free(id); id=str_dup(line); tail=strchr(id, ' '); if(!tail) break; *tail++='\0'; if(is_prefix(tail, "STARTTLS")) { fd_printf(c, c->local_wfd.fd, "%s OK Begin TLS negotiation now", id); str_free(line); str_free(id); return NULL; /* success */ } else if(is_prefix(tail, "CAPABILITY")) { fd_putline(c, c->remote_fd.fd, line); /* send it to server */ str_free(line); line=fd_getline(c, c->remote_fd.fd); /* get the capabilites */ if(*line=='*') { /* * append STARTTLS * should also add LOGINDISABLED, but can't because * of Mozilla bug #324138/#312009 * LOGIN would fail as "unexpected command", anyway */ fd_printf(c, c->local_wfd.fd, "%s STARTTLS", line); str_free(line); line=fd_getline(c, c->remote_fd.fd); /* next line */ } fd_putline(c, c->local_wfd.fd, line); /* forward to the client */ tail=strchr(line, ' '); if(!tail || !is_prefix(tail+1, "OK")) { /* not OK? */ fd_putline(c, c->local_wfd.fd, "* BYE unexpected server response"); s_log(LOG_ERR, "Unexpected server response: %s", line); break; } } else if(is_prefix(tail, "LOGOUT")) { fd_putline(c, c->local_wfd.fd, "* BYE server terminating"); fd_printf(c, c->local_wfd.fd, "%s OK LOGOUT completed", id); break; } else { fd_putline(c, c->local_wfd.fd, "* BYE stunnel: unexpected command"); fd_printf(c, c->local_wfd.fd, "%s BAD %s unexpected", id, tail); s_log(LOG_ERR, "Unexpected client command %s", tail); break; } } /* clean server shutdown */ str_free(id); fd_putline(c, c->remote_fd.fd, "stunnel LOGOUT"); str_free(line); line=fd_getline(c, c->remote_fd.fd); if(*line=='*') { str_free(line); line=fd_getline(c, c->remote_fd.fd); } str_free(line); longjmp(c->err, 2); /* don't reset */ return NULL; /* some C compilers require a return value */ } /**************************************** nntp */ NOEXPORT char *nntp_client(CLI *c, SERVICE_OPTIONS *opt, const PHASE phase) { char *line; (void)opt; /* squash the unused parameter warning */ if(phase!=PROTOCOL_MIDDLE) return NULL; line=fd_getline(c, c->remote_fd.fd); if(!is_prefix(line, "200 ") && !is_prefix(line, "201 ")) { s_log(LOG_ERR, "Unknown server welcome"); str_free(line); longjmp(c->err, 1); } fd_putline(c, c->local_wfd.fd, line); fd_putline(c, c->remote_fd.fd, "STARTTLS"); str_free(line); line=fd_getline(c, c->remote_fd.fd); if(!is_prefix(line, "382 ")) { s_log(LOG_ERR, "Server does not support TLS"); str_free(line); longjmp(c->err, 1); } str_free(line); return NULL; } /**************************************** connect */ NOEXPORT char *connect_server(CLI *c, SERVICE_OPTIONS *opt, const PHASE phase) { char *request, *proto, *header; (void)opt; /* squash the unused parameter warning */ if(phase!=PROTOCOL_EARLY) return NULL; request=fd_getline(c, c->local_rfd.fd); if(!is_prefix(request, "CONNECT ")) { fd_putline(c, c->local_wfd.fd, "HTTP/1.0 400 Bad Request Method"); fd_putline(c, c->local_wfd.fd, "Server: stunnel/" STUNNEL_VERSION); fd_putline(c, c->local_wfd.fd, ""); str_free(request); longjmp(c->err, 1); } proto=strchr(request+8, ' '); if(!proto || !is_prefix(proto, " HTTP/")) { fd_putline(c, c->local_wfd.fd, "HTTP/1.0 400 Bad Request Protocol"); fd_putline(c, c->local_wfd.fd, "Server: stunnel/" STUNNEL_VERSION); fd_putline(c, c->local_wfd.fd, ""); str_free(request); longjmp(c->err, 1); } *proto='\0'; header=str_dup(""); do { /* ignore any headers */ str_free(header); header=fd_getline(c, c->local_rfd.fd); } while(*header); /* not empty */ str_free(header); if(!name2addrlist(&c->connect_addr, request+8)) { fd_putline(c, c->local_wfd.fd, "HTTP/1.0 404 Not Found"); fd_putline(c, c->local_wfd.fd, "Server: stunnel/" STUNNEL_VERSION); fd_putline(c, c->local_wfd.fd, ""); str_free(request); longjmp(c->err, 1); } str_free(request); fd_putline(c, c->local_wfd.fd, "HTTP/1.0 200 OK"); fd_putline(c, c->local_wfd.fd, "Server: stunnel/" STUNNEL_VERSION); fd_putline(c, c->local_wfd.fd, ""); return NULL; } NOEXPORT char *connect_client(CLI *c, SERVICE_OPTIONS *opt, const PHASE phase) { char *line, *encoded; if(phase!=PROTOCOL_MIDDLE) return NULL; if(!opt->protocol_host) { s_log(LOG_ERR, "protocolHost not specified"); longjmp(c->err, 1); } fd_printf(c, c->remote_fd.fd, "CONNECT %s HTTP/1.1", opt->protocol_host); fd_printf(c, c->remote_fd.fd, "Host: %s", opt->protocol_host); if(opt->protocol_username && opt->protocol_password) { if(!strcasecmp(opt->protocol_authentication, "ntlm")) { #ifndef OPENSSL_NO_MD4 ntlm(c, opt); #else s_log(LOG_ERR, "NTLM authentication is not available"); longjmp(c->err, 1); #endif } else { /* basic authentication */ line=str_printf("%s:%s", opt->protocol_username, opt->protocol_password); encoded=base64(1, line, (int)strlen(line)); str_free(line); if(!encoded) { s_log(LOG_ERR, "Base64 encoder failed"); longjmp(c->err, 1); } fd_printf(c, c->remote_fd.fd, "Proxy-Authorization: basic %s", encoded); str_free(encoded); } } fd_putline(c, c->remote_fd.fd, ""); /* empty line */ line=fd_getline(c, c->remote_fd.fd); if(!is_prefix(line, "HTTP/1.0 2") && !is_prefix(line, "HTTP/1.1 2")) { /* not "HTTP/1.x 2xx Connection established" */ s_log(LOG_ERR, "CONNECT request rejected"); do { /* read all headers */ str_free(line); line=fd_getline(c, c->remote_fd.fd); } while(*line); str_free(line); longjmp(c->err, 1); } s_log(LOG_INFO, "CONNECT request accepted"); do { str_free(line); line=fd_getline(c, c->remote_fd.fd); /* read all headers */ } while(*line); str_free(line); return NULL; } #ifndef OPENSSL_NO_MD4 /* * NTLM code is based on the following documentation: * http://davenport.sourceforge.net/ntlm.html * http://www.innovation.ch/personal/ronald/ntlm.html */ #define s_min(a, b) ((a)>(b)?(b):(a)) NOEXPORT void ntlm(CLI *c, SERVICE_OPTIONS *opt) { char *line, buf[BUFSIZ], *ntlm1_txt, *ntlm2_txt, *ntlm3_txt, *tmpstr; long content_length=0; /* no HTTP content */ /* send Proxy-Authorization (phase 1) */ fd_printf(c, c->remote_fd.fd, "Proxy-Connection: keep-alive"); ntlm1_txt=ntlm1(); if(!ntlm1_txt) { s_log(LOG_ERR, "Proxy-Authenticate: Failed to build NTLM request"); longjmp(c->err, 1); } fd_printf(c, c->remote_fd.fd, "Proxy-Authorization: NTLM %s", ntlm1_txt); str_free(ntlm1_txt); fd_putline(c, c->remote_fd.fd, ""); /* empty line */ line=fd_getline(c, c->remote_fd.fd); /* receive Proxy-Authenticate (phase 2) */ if(!is_prefix(line, "HTTP/1.0 407") && !is_prefix(line, "HTTP/1.1 407")) { s_log(LOG_ERR, "Proxy-Authenticate: NTLM authorization request rejected"); do { /* read all headers */ str_free(line); line=fd_getline(c, c->remote_fd.fd); } while(*line); str_free(line); longjmp(c->err, 1); } ntlm2_txt=NULL; do { /* read all headers */ str_free(line); line=fd_getline(c, c->remote_fd.fd); if(is_prefix(line, "Proxy-Authenticate: NTLM ")) ntlm2_txt=str_dup(line+25); else if(is_prefix(line, "Content-Length: ")) { content_length=strtol(line+16, &tmpstr, 10); if(tmpstr>line+16) /* found some digits */ while(*tmpstr && isspace((int)*tmpstr)) ++tmpstr; if(tmpstr==line+16 || *tmpstr || content_length<0) { s_log(LOG_ERR, "Proxy-Authenticate: Invalid Content-Length"); str_free(line); longjmp(c->err, 1); } } } while(*line); if(!ntlm2_txt) { /* no Proxy-Authenticate: NTLM header */ s_log(LOG_ERR, "Proxy-Authenticate: NTLM header not found"); str_free(line); longjmp(c->err, 1); } /* read and ignore HTTP content (if any) */ while(content_length>0) { size_t n=s_min((size_t)content_length, BUFSIZ); s_read(c, c->remote_fd.fd, buf, n); content_length-=(long)n; } /* send Proxy-Authorization (phase 3) */ fd_printf(c, c->remote_fd.fd, "CONNECT %s HTTP/1.1", opt->protocol_host); fd_printf(c, c->remote_fd.fd, "Host: %s", opt->protocol_host); ntlm3_txt=ntlm3(opt->protocol_domain, opt->protocol_username, opt->protocol_password, ntlm2_txt); str_free(ntlm2_txt); if(!ntlm3_txt) { s_log(LOG_ERR, "Proxy-Authenticate: Failed to build NTLM response"); longjmp(c->err, 1); } fd_printf(c, c->remote_fd.fd, "Proxy-Authorization: NTLM %s", ntlm3_txt); str_free(ntlm3_txt); } NOEXPORT char *ntlm1() { char phase1[32]; memset(phase1, 0, sizeof phase1); strcpy(phase1, "NTLMSSP"); phase1[8]=1; /* type: 1 */ phase1[12]=2; /* flag: negotiate OEM */ phase1[13]=2; /* flag: negotiate NTLM */ /* bytes 16-23: supplied domain security buffer */ /* bytes 24-31: supplied workstation security buffer */ return base64(1, phase1, sizeof phase1); /* encode */ } NOEXPORT char *ntlm3(char *domain, char *user, char *password, char *phase2) { MD4_CTX md4; uint8_t *decoded; /* decoded reply from proxy */ uint8_t phase3[146]; uint8_t md4_hash[21]; const size_t ntlm_len=24; /* length of the NTLM hash response */ const size_t domain_len=strlen(domain); const size_t user_len=strlen(user); const size_t ntlm_off=64; /* start of the data block in version 2 */ const size_t domain_off=ntlm_off+ntlm_len; const size_t user_off=domain_off+domain_len; const size_t end_off=user_off+user_len; /* setup the phase3 structure */ if(end_off>sizeof phase3) return NULL; memset(phase3, 0, sizeof phase3); /* bytes 0-7: null-terminated NTLMSSP signature */ strcpy((char *)phase3, "NTLMSSP"); /* bytes 8-11: NTLM message type */ phase3[8]=3; /* type: 3 */ /* bytes 12-19: LM/LMv2 response */ phase3[16]=(uint8_t)end_off; /* LM response offset */ /* bytes 20-27: NTLM/NTLMv2 response */ phase3[20]=(uint8_t)ntlm_len; /* NTLM response length */ phase3[22]=(uint8_t)ntlm_len; /* NTLM response length */ phase3[24]=(uint8_t)ntlm_off; /* NTLM response offset */ /* bytes 28-35: target (domain/server) name */ phase3[28]=(uint8_t)domain_len; /* domain length */ phase3[30]=(uint8_t)domain_len; /* domain length */ phase3[32]=(uint8_t)domain_off; /* domain offset */ /* bytes 36-43: user name */ phase3[36]=(uint8_t)user_len; /* user length */ phase3[38]=(uint8_t)user_len; /* user length */ phase3[40]=(uint8_t)user_off; /* user offset */ /* bytes 44-51: workstation name */ phase3[48]=(uint8_t)end_off; /* host offset */ /* bytes 52-59: session key */ phase3[56]=(uint8_t)end_off; /* session key offset */ /* bytes 60-63: flags */ phase3[60]=2; /* flag: negotiate OEM */ phase3[61]=2; /* flag: negotiate NTLM */ /* calculate MD4 of the UTF-16 encoded password */ MD4_Init(&md4); while(*password) { MD4_Update(&md4, password++, 1); MD4_Update(&md4, "", 1); /* UTF-16 */ } MD4_Final(md4_hash, &md4); memset(md4_hash+16, 0, 5); /* pad to 21 bytes */ /* decode the challenge and calculate the response */ decoded=(uint8_t *)base64(0, phase2, (int)strlen(phase2)); /* decode */ if(!decoded) return NULL; crypt_DES(phase3+ntlm_off, decoded+24, md4_hash); crypt_DES(phase3+ntlm_off+8, decoded+24, md4_hash+7); crypt_DES(phase3+ntlm_off+16, decoded+24, md4_hash+14); str_free(decoded); strncpy((char *)phase3+domain_off, domain, domain_len); strncpy((char *)phase3+user_off, user, user_len); return base64(1, (char *)phase3, (int)end_off); /* encode */ } NOEXPORT void crypt_DES(DES_cblock dst, const_DES_cblock src, DES_cblock hash) { DES_cblock key; DES_key_schedule sched; /* convert key from 56 to 64 bits */ key[0]=hash[0]; key[1]=(unsigned char)(((hash[0]&1)<<7)|(hash[1]>>1)); key[2]=(unsigned char)(((hash[1]&3)<<6)|(hash[2]>>2)); key[3]=(unsigned char)(((hash[2]&7)<<5)|(hash[3]>>3)); key[4]=(unsigned char)(((hash[3]&15)<<4)|(hash[4]>>4)); key[5]=(unsigned char)(((hash[4]&31)<<3)|(hash[5]>>5)); key[6]=(unsigned char)(((hash[5]&63)<<2)|(hash[6]>>6)); key[7]=(unsigned char)(((hash[6]&127)<<1)); DES_set_odd_parity(&key); /* encrypt */ DES_set_key_unchecked(&key, &sched); DES_ecb_encrypt((const_DES_cblock *)src, (DES_cblock *)dst, &sched, DES_ENCRYPT); } #endif NOEXPORT char *base64(int encode, const char *in, int len) { BIO *bio, *b64; char *out; int n; b64=BIO_new(BIO_f_base64()); if(!b64) return NULL; BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); bio=BIO_new(BIO_s_mem()); if(!bio) { str_free(b64); return NULL; } if(encode) bio=BIO_push(b64, bio); BIO_write(bio, in, len); (void)BIO_flush(bio); /* ignore the error if any */ if(encode) { bio=BIO_pop(bio); BIO_free(b64); } else { bio=BIO_push(b64, bio); } n=BIO_pending(bio); /* 32 bytes as a safety precaution for passing decoded data to crypt_DES */ /* n+1 to get null-terminated string on encode */ out=str_alloc(n<32?32:(size_t)n+1); n=BIO_read(bio, out, n); if(n<0) { BIO_free_all(bio); str_free(out); return NULL; } BIO_free_all(bio); return out; } /* end of protocol.c */ stunnel-5.30/src/make.bat0000644000175000017500000000062711502216653012254 00000000000000@echo off :: pdelaage commented : make.exe -f mingw.mak %1 %2 %3 %4 %5 %6 %7 %8 %9 :: on Windows, make is Borland make, but mingw.mak is NOW only compatible :: with gnu make (due to various improvments I made, for compatibility between :: linux and Windows host environments. :: and echo OFF is the sign we are HERE on Windows, isn't it?... mingw32-make.exe -f mingw.mak %1 %2 %3 %4 %5 %6 %7 %8 %9 stunnel-5.30/src/Makefile.am0000664000175000017500000000604312646221043012702 00000000000000## Process this file with automake to produce Makefile.in # by Michal Trojnara 2015-2016 ############################################################################### # File lists # ############################################################################### common_headers = common.h prototypes.h version.h common_sources = tls.c str.c file.c client.c log.c options.c protocol.c common_sources += network.c resolver.c ssl.c ctx.c verify.c sthreads.c common_sources += fd.c dhparam.c cron.c stunnel.c unix_sources = pty.c libwrap.c ui_unix.c shared_sources = env.c win32_gui_sources = ui_win_gui.c resources.h resources.rc win32_gui_sources += stunnel.ico active.ico error.ico idle.ico win32_cli_sources = ui_win_cli.c ############################################################################### # Generate a new set of DH parameters for each version # ############################################################################### dhparam.c: version.h echo '#include "common.h"' >dhparam.c echo '#ifndef OPENSSL_NO_DH' >>dhparam.c echo '#define DN_new DH_new' >>dhparam.c openssl dhparam -noout -C 2048 >>dhparam.c echo '#endif /* OPENSSL_NO_DH */' >>dhparam.c ############################################################################### # Unix executables and shared library # ############################################################################### bin_PROGRAMS = stunnel stunnel_SOURCES = $(common_headers) $(common_sources) $(unix_sources) bin_SCRIPTS = stunnel3 EXTRA_DIST = stunnel3.in CLEANFILES = stunnel3 # Red Hat "by design" bug #82369 stunnel_CPPFLAGS = -I/usr/kerberos/include # Additional preprocesor definitions stunnel_CPPFLAGS += -I$(SSLDIR)/include stunnel_CPPFLAGS += -DLIBDIR='"$(pkglibdir)"' stunnel_CPPFLAGS += -DCONFDIR='"$(sysconfdir)/stunnel"' # SSL library stunnel_LDFLAGS = -L$(SSLDIR)/lib64 -L$(SSLDIR)/lib -lssl -lcrypto # stunnel3 script edit = sed \ -e 's|@bindir[@]|$(bindir)|g' stunnel3: Makefile $(edit) '$(srcdir)/$@.in' >$@ stunnel3: $(srcdir)/stunnel3.in # Unix shared library pkglib_LTLIBRARIES = libstunnel.la libstunnel_la_SOURCES = $(shared_sources) libstunnel_la_LDFLAGS = -avoid-version ############################################################################### # Win32 executables # ############################################################################### if AUTHOR_TESTS # Just check if the programs can be built, don't perform any actual tests check-local: mingw mingw64 endif mingw: $(MAKE) -f $(srcdir)/mingw.mk srcdir=$(srcdir) win32_targetcpu=i686 win32_mingw=mingw mingw64: $(MAKE) -f $(srcdir)/mingw.mk srcdir=$(srcdir) win32_targetcpu=x86_64 win32_mingw=mingw64 .PHONY: mingw mingw64 clean-local: rm -rf ../obj ../bin # Remaining files to be included EXTRA_DIST += $(win32_gui_sources) $(win32_cli_sources) EXTRA_DIST += make.bat makece.bat makew32.bat EXTRA_DIST += mingw.mk mingw.mak evc.mak vc.mak os2.mak stunnel-5.30/src/libwrap.c0000664000175000017500000002442512646221043012456 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #include "common.h" #include "prototypes.h" #ifdef USE_LIBWRAP #include #if defined(USE_PTHREAD) && !defined(__CYGWIN__) /* http://wiki.osdev.org/Cygwin_Issues#Passing_file_descriptors */ #define USE_LIBWRAP_POOL #endif /* USE_PTHREAD && !__CYGWIN__ */ NOEXPORT int check(char *, int); int allow_severity=LOG_NOTICE, deny_severity=LOG_WARNING; #ifdef USE_LIBWRAP_POOL #define SERVNAME_LEN 256 NOEXPORT ssize_t read_fd(int, void *, size_t, int *); NOEXPORT ssize_t write_fd(int, void *, size_t, int); unsigned num_processes=0; static int *ipc_socket, *busy; #endif /* USE_LIBWRAP_POOL */ #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-result" #endif /* __GNUC__ */ int libwrap_init() { #ifdef USE_LIBWRAP_POOL unsigned i, j; int rfd, result; char servname[SERVNAME_LEN]; static int initialized=0; SERVICE_OPTIONS *opt; if(initialized) /* during startup or previous configuration file reload */ return 0; for(opt=service_options.next; opt; opt=opt->next) if(opt->option.libwrap) /* libwrap is enabled for this service */ break; if(!opt) /* disabled for all sections or inetd mode (no sections) */ return 0; num_processes=LIBWRAP_CLIENTS; ipc_socket=str_alloc(2*num_processes*sizeof(int)); busy=str_alloc(num_processes*sizeof(int)); for(i=0; i=0) close(rfd); } default: /* parent */ close(ipc_socket[2*i+1]); /* child-side socket */ } } initialized=1; #endif /* USE_LIBWRAP_POOL */ return 0; } #ifdef __GNUC__ #pragma GCC diagnostic pop #endif /* __GNUC__ */ void libwrap_auth(CLI *c, char *accepted_address) { int result=0; /* deny by default */ #ifdef USE_LIBWRAP_POOL static volatile unsigned num_busy=0, roundrobin=0; unsigned my_process; int retval; static pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t cond=PTHREAD_COND_INITIALIZER; #endif /* USE_LIBWRAP_POOL */ if(!c->opt->option.libwrap) /* libwrap is disabled for this service */ return; /* allow connection */ #ifdef HAVE_STRUCT_SOCKADDR_UN if(c->peer_addr.sa.sa_family==AF_UNIX) { s_log(LOG_INFO, "Libwrap is not supported on Unix sockets"); return; } #endif #ifdef USE_LIBWRAP_POOL if(num_processes) { s_log(LOG_DEBUG, "Waiting for a libwrap process"); retval=pthread_mutex_lock(&mutex); if(retval) { errno=retval; ioerror("pthread_mutex_lock"); longjmp(c->err, 1); } while(num_busy==num_processes) { /* all child processes are busy */ retval=pthread_cond_wait(&cond, &mutex); if(retval) { errno=retval; ioerror("pthread_cond_wait"); longjmp(c->err, 1); } } while(busy[roundrobin]) /* find a free child process */ roundrobin=(roundrobin+1)%num_processes; my_process=roundrobin; /* the process allocated by this thread */ ++num_busy; /* the child process has been allocated */ busy[my_process]=1; /* mark the child process as busy */ retval=pthread_mutex_unlock(&mutex); if(retval) { errno=retval; ioerror("pthread_mutex_unlock"); longjmp(c->err, 1); } s_log(LOG_DEBUG, "Acquired libwrap process #%d", my_process); write_fd(ipc_socket[2*my_process], c->opt->servname, strlen(c->opt->servname)+1, c->local_rfd.fd); s_read(c, ipc_socket[2*my_process], (uint8_t *)&result, sizeof result); s_log(LOG_DEBUG, "Releasing libwrap process #%d", my_process); retval=pthread_mutex_lock(&mutex); if(retval) { errno=retval; ioerror("pthread_mutex_lock"); longjmp(c->err, 1); } busy[my_process]=0; /* mark the child process as free */ --num_busy; /* the child process has been released */ retval=pthread_cond_signal(&cond); /* signal a waiting thread */ if(retval) { errno=retval; ioerror("pthread_cond_signal"); longjmp(c->err, 1); } retval=pthread_mutex_unlock(&mutex); if(retval) { errno=retval; ioerror("pthread_mutex_unlock"); longjmp(c->err, 1); } s_log(LOG_DEBUG, "Released libwrap process #%d", my_process); } else #endif /* USE_LIBWRAP_POOL */ { /* use original, synchronous libwrap calls */ CRYPTO_w_lock(stunnel_locks[LOCK_LIBWRAP]); result=check(c->opt->servname, c->local_rfd.fd); CRYPTO_w_unlock(stunnel_locks[LOCK_LIBWRAP]); } if(!result) { s_log(LOG_WARNING, "Service [%s] REFUSED by libwrap from %s", c->opt->servname, accepted_address); s_log(LOG_DEBUG, "See hosts_access(5) manual for details"); longjmp(c->err, 1); } s_log(LOG_DEBUG, "Service [%s] permitted by libwrap from %s", c->opt->servname, accepted_address); } NOEXPORT int check(char *name, int fd) { struct request_info request; request_init(&request, RQ_DAEMON, name, RQ_FILE, fd, 0); fromhost(&request); return hosts_access(&request); } #ifdef USE_LIBWRAP_POOL NOEXPORT ssize_t read_fd(SOCKET fd, void *ptr, size_t nbytes, SOCKET *recvfd) { struct msghdr msg; struct iovec iov[1]; ssize_t n; #ifdef HAVE_MSGHDR_MSG_CONTROL union { struct cmsghdr cm; char control[CMSG_SPACE(sizeof(int))]; } control_un; struct cmsghdr *cmptr; msg.msg_control=control_un.control; msg.msg_controllen=sizeof control_un.control; #else int newfd; msg.msg_accrights=(caddr_t)&newfd; msg.msg_accrightslen=sizeof(int); #endif msg.msg_name=NULL; msg.msg_namelen=0; iov[0].iov_base=ptr; iov[0].iov_len=nbytes; msg.msg_iov=iov; msg.msg_iovlen=1; *recvfd=INVALID_SOCKET; /* descriptor was not passed */ n=recvmsg(fd, &msg, 0); if(n<=0) return n; #ifdef HAVE_MSGHDR_MSG_CONTROL cmptr=CMSG_FIRSTHDR(&msg); if(!cmptr || cmptr->cmsg_len!=CMSG_LEN(sizeof(int))) return n; if(cmptr->cmsg_level!=SOL_SOCKET) { s_log(LOG_ERR, "control level != SOL_SOCKET"); return -1; } if(cmptr->cmsg_type!=SCM_RIGHTS) { s_log(LOG_ERR, "control type != SCM_RIGHTS"); return -1; } memcpy(recvfd, CMSG_DATA(cmptr), sizeof(int)); #else if(msg.msg_accrightslen==sizeof(int)) *recvfd=newfd; #endif return n; } NOEXPORT ssize_t write_fd(int fd, void *ptr, size_t nbytes, int sendfd) { struct msghdr msg; struct iovec iov[1]; #ifdef HAVE_MSGHDR_MSG_CONTROL union { struct cmsghdr cm; char control[CMSG_SPACE(sizeof(int))]; } control_un; struct cmsghdr *cmptr; msg.msg_control=control_un.control; msg.msg_controllen=sizeof control_un.control; cmptr=CMSG_FIRSTHDR(&msg); cmptr->cmsg_len=CMSG_LEN(sizeof(int)); cmptr->cmsg_level=SOL_SOCKET; cmptr->cmsg_type=SCM_RIGHTS; memcpy(CMSG_DATA(cmptr), &sendfd, sizeof(int)); #else msg.msg_accrights=(caddr_t)&sendfd; msg.msg_accrightslen=sizeof(int); #endif msg.msg_name=NULL; msg.msg_namelen=0; iov[0].iov_base=ptr; iov[0].iov_len=nbytes; msg.msg_iov=iov; msg.msg_iovlen=1; return sendmsg(fd, &msg, 0); } #endif /* USE_LIBWRAP_POOL */ #endif /* USE_LIBWRAP */ /* end of libwrap.c */ stunnel-5.30/src/resources.rc0000664000175000017500000001140512646221043013204 00000000000000#include #include "resources.h" #include "version.h" VS_VERSION_INFO VERSIONINFO FILEVERSION STUNNEL_VERSION_FIELDS PRODUCTVERSION STUNNEL_VERSION_FIELDS FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS 0 FILEOS VOS__WINDOWS32 FILETYPE VFT_APP FILESUBTYPE VFT2_UNKNOWN BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" BEGIN VALUE "CompanyName", "Michal Trojnara" VALUE "FileDescription", "stunnel - TLS offloading and load-balancing proxy" VALUE "FileVersion", STUNNEL_VERSION VALUE "InternalName", "stunnel" VALUE "LegalCopyright", "© by Michal Trojnara, 1998-2016" VALUE "OriginalFilename", "stunnel.exe" VALUE "ProductName", STUNNEL_PRODUCTNAME VALUE "ProductVersion", STUNNEL_VERSION END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1252 END END IDI_STUNNEL_MAIN ICON "stunnel.ico" IDI_STUNNEL_ACTIVE ICON "active.ico" IDI_STUNNEL_ERROR ICON "error.ico" IDI_STUNNEL_IDLE ICON "idle.ico" IDM_MAINMENU MENU BEGIN POPUP "&File" BEGIN MENUITEM "&Save Log As", IDM_SAVE_LOG MENUITEM "Reopen &Log File", IDM_REOPEN_LOG, GRAYED MENUITEM SEPARATOR MENUITEM "E&xit", IDM_EXIT MENUITEM SEPARATOR MENUITEM "&Close", IDM_CLOSE END #ifdef _WIN32_WCE POPUP "&Config" #else POPUP "&Configuration" #endif BEGIN MENUITEM "&Edit Configuration", IDM_EDIT_CONFIG MENUITEM "&Reload Configuration", IDM_RELOAD_CONFIG END #ifdef _WIN32_WCE POPUP "&Save Peer Certs" #else POPUP "&Save Peer Certificate" #endif BEGIN MENUITEM "dummy", 0, GRAYED END POPUP "&Help" BEGIN MENUITEM "&About", IDM_ABOUT MENUITEM SEPARATOR MENUITEM "&Manual", IDM_MANPAGE MENUITEM "&Homepage", IDM_HOMEPAGE END END IDM_TRAYMENU MENU BEGIN POPUP "Ooops?" BEGIN MENUITEM "Show Log &Window", IDM_SHOW_LOG MENUITEM SEPARATOR POPUP "&Save Peer Certificate" BEGIN MENUITEM "dummy", 0, GRAYED END MENUITEM SEPARATOR MENUITEM "&Edit Configuration", IDM_EDIT_CONFIG MENUITEM "&Reload Configuration", IDM_RELOAD_CONFIG MENUITEM "Reopen &Log File", IDM_REOPEN_LOG, GRAYED MENUITEM SEPARATOR MENUITEM "&Homepage", IDM_HOMEPAGE MENUITEM "&Manual", IDM_MANPAGE MENUITEM "&About", IDM_ABOUT MENUITEM SEPARATOR MENUITEM "E&xit", IDM_EXIT END END ABOUTBOX DIALOG DISCARDABLE 0, 0, 140, 68 STYLE DS_MODALFRAME|DS_CENTER|WS_POPUP|WS_CAPTION|WS_SYSMENU CAPTION "About stunnel" FONT 8, "MS Sans Serif" BEGIN ICON IDI_STUNNEL_MAIN, -1, 6, 6, 20, 20 LTEXT "stunnel version", -1, 30, 4, 49, 8 LTEXT STUNNEL_VERSION, -1, 79, 4, 57, 8 LTEXT "© by Michal Trojnara, 1998-2016", -1, 30, 12, 106, 8 LTEXT "All Rights Reserved", -1, 30, 20, 106, 8 LTEXT "Licensed under the GNU GPL version 2", -1, 4, 28, 132, 8 LTEXT "with a special exception for OpenSSL", -1, 4, 36, 132, 8 DEFPUSHBUTTON "OK",IDOK, 54, 48, 32, 14, WS_GROUP END PASSBOX DIALOG DISCARDABLE 0, 0, 156, 51 STYLE DS_MODALFRAME|DS_CENTER|WS_POPUP|WS_CAPTION|WS_SYSMENU CAPTION "" FONT 8, "MS Sans Serif" BEGIN ICON IDI_STUNNEL_MAIN, -1, 6, 6, 20, 20 LTEXT "Key passphrase:", -1, 30, 13, 56, 8 EDITTEXT IDE_PASSEDIT, 86, 11, 64, 12, ES_PASSWORD|ES_AUTOHSCROLL DEFPUSHBUTTON "OK",IDOK, 6, 30, 50, 14 PUSHBUTTON "Cancel",IDCANCEL, 100, 30, 50, 14 END PINBOX DIALOG DISCARDABLE 0, 0, 156, 51 STYLE DS_MODALFRAME|DS_CENTER|WS_POPUP|WS_CAPTION|WS_SYSMENU CAPTION "" FONT 8, "MS Sans Serif" BEGIN ICON IDI_STUNNEL_MAIN, -1, 6, 6, 20, 20 LTEXT "SmartCard PIN:", -1, 30, 13, 56, 8 EDITTEXT IDE_PINEDIT, 86, 11, 64, 12, ES_PASSWORD|ES_AUTOHSCROLL DEFPUSHBUTTON "OK",IDOK, 6, 30, 50, 14 PUSHBUTTON "Cancel",IDCANCEL, 100, 30, 50, 14 END STRINGTABLE BEGIN IDS_SERVICE_DESC "TLS offloading and load-balancing proxy" END stunnel-5.30/src/stunnel3.in0000775000175000017500000000534012533065534012761 00000000000000#!/usr/bin/perl # # stunnel3 Perl wrapper to use stunnel 3.x syntax in stunnel >=4.05 # Copyright (C) 2004-2012 Michal Trojnara # Version: 2.03 # Date: 2011.10.22 # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, see . use POSIX; use Getopt::Std; # Configuration - path to stunnel (version >=4.05) $stunnel_bin='@bindir@/stunnel'; # stunnel3 script body begins here ($read_fd, $write_fd)=POSIX::pipe(); $pid=fork; die "Can't fork" unless defined $pid; if($pid) { # parent POSIX::close($write_fd); exec "$stunnel_bin -fd $read_fd"; die "$stunnel_bin exec failed"; } # child POSIX::close($read_fd); open(STUNNEL, ">&$write_fd"); # comment out the next line to see the config file select(STUNNEL); getopts('cTWfD:O:o:C:p:v:a:A:t:N:u:n:E:R:B:I:d:s:g:P:r:L:l:'); print("client = yes\n") if defined $opt_c; print("transparent = yes\n") if defined $opt_T; print("RNDoverwrite = yes\n") if defined $opt_W; print("foreground = yes\n") if defined $opt_f; print("debug = $opt_D\n") if defined $opt_D; print("socket = $opt_O\n") if defined $opt_O; print("output = $opt_o\n") if defined $opt_o; print("ciphers = $opt_C\n") if defined $opt_C; print("cert = $opt_p\n") if defined $opt_p; print("verify = $opt_v\n") if defined $opt_v; print("CApath = $opt_a\n") if defined $opt_a; print("CAfile = $opt_A\n") if defined $opt_A; print("session = $opt_t\n") if defined $opt_t; print("service = $opt_N\n") if defined $opt_N; print("ident = $opt_u\n") if defined $opt_u; print("protocol = $opt_n\n") if defined $opt_n; print("EGD = $opt_E\n") if defined $opt_E; print("RNDfile = $opt_R\n") if defined $opt_R; print("RNDbytes = $opt_B\n") if defined $opt_B; print("local = $opt_I\n") if defined $opt_I; print("accept = $opt_d\n") if defined $opt_d; print("setuid = $opt_s\n") if defined $opt_s; print("setgid = $opt_g\n") if defined $opt_g; print("pid = $opt_P\n") if defined $opt_P; print("connect = $opt_r\n") if defined $opt_r; print("pty = yes\n"), $opt_l=$opt_L if defined $opt_L; print("exec = $opt_l\nexecArgs = " . join(' ', $opt_l, @ARGV) . "\n") if defined $opt_l; print("[stunnel3]\n") if defined $opt_d; close(STUNNEL); # stunnel3 script body ends here stunnel-5.30/src/ui_win_gui.c0000664000175000017500000013723112646221043013154 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #include "common.h" #include "prototypes.h" #include #include #ifndef _WIN32_WCE #include #endif #include "resources.h" #define LOG_LINES 1000 #ifdef _WIN32_WCE #define STUNNEL_PLATFORM "WinCE" #else #ifdef _WIN64 #define STUNNEL_PLATFORM "Win64" #else /* MSDN claims that _WIN32 is always defined */ #define STUNNEL_PLATFORM "Win32" #endif #define SERVICE_NAME TEXT("stunnel") #define SERVICE_DISPLAY_NAME TEXT("Stunnel SSL wrapper") #endif /* mingw-Patches-1825044 is missing in Debian Squeeze */ WINBASEAPI BOOL WINAPI CheckTokenMembership(HANDLE, PSID, PBOOL); /* prototypes */ NOEXPORT BOOL CALLBACK enum_windows(HWND, LPARAM); NOEXPORT void gui_cmdline(); NOEXPORT int initialize_winsock(void); NOEXPORT int gui_loop(); NOEXPORT void CALLBACK timer_proc(HWND, UINT, UINT_PTR, DWORD); NOEXPORT LRESULT CALLBACK window_proc(HWND, UINT, WPARAM, LPARAM); NOEXPORT LRESULT CALLBACK about_proc(HWND, UINT, WPARAM, LPARAM); NOEXPORT LRESULT CALLBACK pass_proc(HWND, UINT, WPARAM, LPARAM); NOEXPORT void save_log(void); NOEXPORT void win_log(LPCTSTR); NOEXPORT int save_text_file(LPTSTR, char *); NOEXPORT void update_logs(void); NOEXPORT LPTSTR log_txt(void); NOEXPORT void daemon_thread(void *); NOEXPORT void valid_config(void); NOEXPORT void invalid_config(void); NOEXPORT void update_peer_menu(void); NOEXPORT void tray_update(const int); NOEXPORT void tray_delete(void); NOEXPORT void error_box(LPCTSTR); NOEXPORT void edit_config(HWND); /* NT Service related function */ #ifndef _WIN32_WCE NOEXPORT int service_initialize(void); NOEXPORT int service_install(void); NOEXPORT int service_uninstall(void); NOEXPORT int service_start(void); NOEXPORT int service_stop(void); NOEXPORT int service_user(DWORD); NOEXPORT void WINAPI service_main(DWORD, LPTSTR *); NOEXPORT void WINAPI control_handler(DWORD); #endif /* !defined(_WIN32_WCE) */ /* other functions */ NOEXPORT LPTSTR get_params(); /* global variables */ static struct LIST { struct LIST *next; size_t len; TCHAR txt[1]; /* single character for trailing '\0' */ } *head=NULL, *tail=NULL; static unsigned number_of_sections=0; static HINSTANCE ghInst; static HWND edit_handle=NULL; static HMENU tray_menu_handle=NULL; #ifndef _WIN32_WCE static HMENU main_menu_handle=NULL; #endif static HWND hwnd=NULL; /* main window handle */ #ifdef _WIN32_WCE static HWND command_bar_handle; /* command bar handle */ #endif /* win32_name is needed for any error_box(), message_box(), * and the initial main window title */ static TCHAR *win32_name=TEXT("stunnel ") TEXT(STUNNEL_VERSION) TEXT(" on ") TEXT(STUNNEL_PLATFORM) TEXT(" (not configured)"); #ifndef _WIN32_WCE static SERVICE_STATUS serviceStatus; static SERVICE_STATUS_HANDLE serviceStatusHandle=0; #define SERVICE_CONTROL_USER 128 #endif static BOOL visible=FALSE; static HANDLE main_initialized=NULL; /* global initialization performed */ static HANDLE config_ready=NULL; /* reload without a valid configuration */ static LONG new_logs=0; static UI_DATA *ui_data=NULL; static struct { char *config_file; unsigned service:1, install:1, uninstall:1, start:1, stop:1, quiet:1, exit:1, reload:1, reopen:1; } cmdline; /**************************************** initialization */ int WINAPI WinMain(HINSTANCE this_instance, HINSTANCE prev_instance, #ifdef _WIN32_WCE LPWSTR lpCmdLine, #else LPSTR lpCmdLine, #endif int nCmdShow) { TCHAR stunnel_exe_path[MAX_PATH]; LPTSTR c; #ifndef _WIN32_WCE LPTSTR errmsg; #endif (void)prev_instance; /* squash the unused parameter warning */ (void)lpCmdLine; /* squash the unused parameter warning */ (void)nCmdShow; /* squash the unused parameter warning */ tls_init(); /* initialize thread-local storage */ ghInst=this_instance; gui_cmdline(); /* setup global cmdline structure */ GetModuleFileName(0, stunnel_exe_path, MAX_PATH); #ifndef _WIN32_WCE /* find previous instances of the same executable */ if(!cmdline.service && !cmdline.install && !cmdline.uninstall && !cmdline.reload && !cmdline.reopen && !cmdline.start && !cmdline.stop) { EnumWindows(enum_windows, (LPARAM)stunnel_exe_path); if(cmdline.exit) return 1; /* in case EnumWindows didn't find a previous instance */ } #endif /* set current working directory and engine path */ c=_tcsrchr(stunnel_exe_path, TEXT('\\')); /* last backslash */ if(c) { /* found */ *c=TEXT('\0'); /* truncate the program name */ c=_tcsrchr(stunnel_exe_path, TEXT('\\')); /* previous backslash */ if(c && !_tcscmp(c+1, TEXT("bin"))) *c=TEXT('\0'); /* truncate "bin" */ } #ifndef _WIN32_WCE if(!SetCurrentDirectory(stunnel_exe_path)) { errmsg=str_tprintf(TEXT("Cannot set directory to %s"), stunnel_exe_path); message_box(errmsg, MB_ICONERROR); str_free(errmsg); return 1; } /* try to enter the "config" subdirectory, ignore the result */ SetCurrentDirectory(TEXT("config")); #endif _tputenv(str_tprintf(TEXT("OPENSSL_ENGINES=%s\\engines"), stunnel_exe_path)); if(initialize_winsock()) return 1; #ifndef _WIN32_WCE if(cmdline.service) /* "-service" must be processed before "-install" */ return service_initialize(); if(cmdline.install) return service_install(); if(cmdline.uninstall) return service_uninstall(); if(cmdline.start) return service_start(); if(cmdline.stop) return service_stop(); if(cmdline.reload) return service_user(SIGNAL_RELOAD_CONFIG); if(cmdline.reopen) return service_user(SIGNAL_REOPEN_LOG); #endif return gui_loop(); } #ifndef _WIN32_WCE NOEXPORT BOOL CALLBACK enum_windows(HWND other_window_handle, LPARAM lParam) { DWORD pid; HMODULE module; HANDLE process_handle; TCHAR window_exe_path[MAX_PATH]; LPTSTR stunnel_exe_path=(LPTSTR)lParam; if(!other_window_handle) return TRUE; module=(HMODULE)GetWindowLongPtr(other_window_handle, GWLP_HINSTANCE); GetWindowThreadProcessId(other_window_handle, &pid); process_handle=OpenProcess(SYNCHRONIZE| /* WaitForSingleObject() */ PROCESS_TERMINATE| /* TerminateProcess() */ PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, /* GetModuleFileNameEx() */ FALSE, pid); if(!process_handle) return TRUE; if(!GetModuleFileNameEx(process_handle, module, window_exe_path, MAX_PATH)) { CloseHandle(process_handle); return TRUE; } if(_tcscmp(stunnel_exe_path, window_exe_path)) { CloseHandle(process_handle); return TRUE; } if(cmdline.exit) { PostMessage(other_window_handle, WM_COMMAND, IDM_EXIT, 0); if(WaitForSingleObject(process_handle, 3000)==WAIT_TIMEOUT) { TerminateProcess(process_handle, 0); WaitForSingleObject(process_handle, 3000); } } else { ShowWindow(other_window_handle, SW_SHOWNORMAL); /* show window */ SetForegroundWindow(other_window_handle); /* bring on top */ } CloseHandle(process_handle); exit(0); return FALSE; /* should never be executed */ } #endif NOEXPORT void gui_cmdline() { char *line, *c, *opt; line=tstr2str(get_params()); memset(&cmdline, 0, sizeof cmdline); c=line; while(*c && (*c=='/' || *c=='-')) { opt=c; while(*c && !isspace(*c)) /* skip non-whitespaces */ c++; while(*c && isspace(*c)) /* replace whitespaces with '\0' */ *c++='\0'; if(!strcasecmp(opt+1, "install")) cmdline.install=1; else if(!strcasecmp(opt+1, "uninstall")) cmdline.uninstall=1; else if(!strcasecmp(opt+1, "reload")) cmdline.reload=1; else if(!strcasecmp(opt+1, "reopen")) cmdline.reopen=1; else if(!strcasecmp(opt+1, "start")) cmdline.start=1; else if(!strcasecmp(opt+1, "stop")) cmdline.stop=1; else if(!strcasecmp(opt+1, "service")) cmdline.service=1; else if(!strcasecmp(opt+1, "quiet")) cmdline.quiet=1; else if(!strcasecmp(opt+1, "exit")) cmdline.exit=1; else { /* an option to be processed in options.c */ c=opt; break; } } if(*c=='\"') { /* the option is within double quotes */ c++; opt=c; while(*c && *c!='\"') /* find the closing double quote */ c++; *c='\0'; } else /* the option is simply the rest of the line */ opt=c; cmdline.config_file=*opt ? str_dup(opt) : NULL; str_free(line); } /* try to load winsock2 resolver functions from a specified dll name */ NOEXPORT int initialize_winsock() { static struct WSAData wsa_state; if(WSAStartup(MAKEWORD( 2, 2 ), &wsa_state)) { message_box(TEXT("Failed to initialize winsock"), MB_ICONERROR); return 1; /* error */ } resolver_init(); return 0; /* IPv4 detected -> OK */ } /**************************************** GUI thread */ NOEXPORT int gui_loop() { #ifdef _WIN32_WCE WNDCLASS wc; #else WNDCLASSEX wc; #endif MSG msg; LPTSTR classname=TEXT("stunnel_main_window_class"); /* register the class */ #ifndef _WIN32_WCE wc.cbSize=sizeof wc; #endif wc.style=CS_VREDRAW|CS_HREDRAW; wc.lpfnWndProc=window_proc; wc.cbClsExtra=wc.cbWndExtra=0; wc.hInstance=ghInst; wc.hIcon=LoadIcon(ghInst, MAKEINTRESOURCE(IDI_STUNNEL_MAIN)); wc.hCursor=LoadCursor(NULL, IDC_ARROW); wc.hbrBackground=(HBRUSH)(COLOR_WINDOW+1); wc.lpszMenuName=NULL; wc.lpszClassName=classname; #ifdef _WIN32_WCE RegisterClass(&wc); #else /* load 16x16 icon */ wc.hIconSm=LoadImage(ghInst, MAKEINTRESOURCE(IDI_STUNNEL_MAIN), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0); RegisterClassEx(&wc); #endif /* create main window */ #ifdef _WIN32_WCE hwnd=CreateWindow(classname, win32_name, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, ghInst, NULL); #else main_menu_handle=LoadMenu(ghInst, MAKEINTRESOURCE(IDM_MAINMENU)); if(main_menu_handle && cmdline.service) { /* block unsafe operations in the service mode */ EnableMenuItem(main_menu_handle, IDM_EDIT_CONFIG, MF_GRAYED); EnableMenuItem(main_menu_handle, IDM_SAVE_LOG, MF_GRAYED); } hwnd=CreateWindow(classname, win32_name, WS_TILEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, main_menu_handle, ghInst, NULL); #endif /* auto-reset, non-signaled events */ main_initialized=CreateEvent(NULL, FALSE, FALSE, NULL); config_ready=CreateEvent(NULL, FALSE, FALSE, NULL); /* hwnd needs to be initialized before _beginthread() */ _beginthread(daemon_thread, DEFAULT_STACK_SIZE, NULL); WaitForSingleObject(main_initialized, INFINITE); /* logging subsystem is now available */ /* setup periodic event to trigger update_logs() */ SetTimer(NULL, 0, 1000, timer_proc); /* run callback once per second */ s_log(LOG_DEBUG, "GUI message loop initialized"); for(;;) switch(GetMessage(&msg, NULL, 0, 0)) { case -1: ioerror("GetMessage"); return 0; case 0: s_log(LOG_DEBUG, "GUI message loop terminated"); return (int)msg.wParam; default: TranslateMessage(&msg); DispatchMessage(&msg); } } NOEXPORT void CALLBACK timer_proc(HWND hwnd, UINT msg, UINT_PTR id, DWORD t) { (void)hwnd; /* squash the unused parameter warning */ (void)msg; /* squash the unused parameter warning */ (void)id; /* squash the unused parameter warning */ (void)t; /* squash the unused parameter warning */ if(visible) update_logs(); tray_update(num_clients); /* needed when explorer.exe (re)starts */ } NOEXPORT LRESULT CALLBACK window_proc(HWND main_window_handle, UINT message, WPARAM wParam, LPARAM lParam) { POINT pt; RECT rect; PAINTSTRUCT ps; SERVICE_OPTIONS *section; unsigned section_number; LPTSTR txt; #if 0 switch(message) { case WM_CTLCOLORSTATIC: case WM_TIMER: case WM_LOG: break; default: s_log(LOG_DEBUG, "Window message: 0x%x(0x%hx,0x%lx)", message, wParam, lParam); } #endif switch(message) { case WM_CREATE: #ifdef _WIN32_WCE /* create command bar */ command_bar_handle=CommandBar_Create(ghInst, main_window_handle, 1); if(!command_bar_handle) error_box(TEXT("CommandBar_Create")); if(!CommandBar_InsertMenubar(command_bar_handle, ghInst, IDM_MAINMENU, 0)) error_box(TEXT("CommandBar_InsertMenubar")); if(!CommandBar_AddAdornments(command_bar_handle, 0, 0)) error_box(TEXT("CommandBar_AddAdornments")); #endif /* create child edit window */ edit_handle=CreateWindowEx(WS_EX_STATICEDGE, TEXT("EDIT"), NULL, WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|ES_MULTILINE|ES_READONLY, 0, 0, 0, 0, main_window_handle, (HMENU)IDE_EDIT, ghInst, NULL); #ifndef _WIN32_WCE SendMessage(edit_handle, WM_SETFONT, (WPARAM)CreateFont(-12, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_RASTER_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH, TEXT("Courier")), MAKELPARAM(FALSE, 0)); /* no need to redraw right now */ #endif /* NOTE: there's no return statement here -> proceeding with resize */ case WM_SIZE: GetClientRect(main_window_handle, &rect); #ifdef _WIN32_WCE MoveWindow(edit_handle, 0, CommandBar_Height(command_bar_handle), rect.right, rect.bottom-CommandBar_Height(command_bar_handle), TRUE); SendMessage(command_bar_handle, TB_AUTOSIZE, 0L, 0L); CommandBar_AlignAdornments(command_bar_handle); #else MoveWindow(edit_handle, 0, 0, rect.right, rect.bottom, TRUE); #endif UpdateWindow(edit_handle); /* CommandBar_Show(command_bar_handle, TRUE); */ return 0; case WM_SETFOCUS: SetFocus(edit_handle); return 0; case WM_PAINT: BeginPaint(hwnd, &ps); EndPaint(hwnd, &ps); break; case WM_CLOSE: ShowWindow(main_window_handle, SW_HIDE); return 0; #ifdef WM_SHOWWINDOW case WM_SHOWWINDOW: visible=(BOOL)wParam; #else /* this works for Pierre Delaage, but not for me... */ case WM_WINDOWPOSCHANGED: visible=IsWindowVisible(main_window_handle); #endif if(tray_menu_handle) CheckMenuItem(tray_menu_handle, IDM_SHOW_LOG, visible ? MF_CHECKED : MF_UNCHECKED); if(visible) update_logs(); #ifdef WM_SHOWWINDOW return 0; #else break; /* proceed to DefWindowProc() */ #endif case WM_DESTROY: #ifdef _WIN32_WCE CommandBar_Destroy(command_bar_handle); #else if(main_menu_handle) { if(!DestroyMenu(main_menu_handle)) ioerror("DestroyMenu"); main_menu_handle=NULL; } #endif tray_delete(); /* remove the taskbark icon if exists */ PostQuitMessage(0); return 0; case WM_COMMAND: if(wParam>=IDM_PEER_MENU && wParamnext, ++section_number) ; if(!section) return 0; if(save_text_file(section->file, section->chain)) return 0; #ifndef _WIN32_WCE if(main_menu_handle) CheckMenuItem(main_menu_handle, (UINT)wParam, MF_CHECKED); #endif if(tray_menu_handle) CheckMenuItem(tray_menu_handle, (UINT)wParam, MF_CHECKED); message_box(section->help, MB_ICONINFORMATION); return 0; } switch(wParam) { case IDM_ABOUT: DialogBox(ghInst, TEXT("AboutBox"), main_window_handle, (DLGPROC)about_proc); break; case IDM_SHOW_LOG: if(visible) { ShowWindow(main_window_handle, SW_HIDE); /* hide window */ } else { ShowWindow(main_window_handle, SW_SHOWNORMAL); /* show window */ SetForegroundWindow(main_window_handle); /* bring on top */ } break; case IDM_CLOSE: ShowWindow(main_window_handle, SW_HIDE); /* hide window */ break; case IDM_EXIT: if(num_clients>=0) /* signal_pipe is active */ signal_post(SIGNAL_TERMINATE); DestroyWindow(main_window_handle); break; case IDM_SAVE_LOG: if(!cmdline.service) /* security */ save_log(); break; case IDM_EDIT_CONFIG: #ifndef _WIN32_WCE if(!cmdline.service) /* security */ edit_config(main_window_handle); #endif break; case IDM_RELOAD_CONFIG: if(num_clients>=0) /* signal_pipe is active */ signal_post(SIGNAL_RELOAD_CONFIG); else SetEvent(config_ready); /* unlock daemon_thread() */ break; case IDM_REOPEN_LOG: signal_post(SIGNAL_REOPEN_LOG); break; case IDM_MANPAGE: #ifndef _WIN32_WCE if(!cmdline.service) /* security */ ShellExecute(main_window_handle, TEXT("open"), TEXT("..\\doc\\stunnel.html"), NULL, NULL, SW_SHOWNORMAL); #endif break; case IDM_HOMEPAGE: #ifndef _WIN32_WCE if(!cmdline.service) /* security */ ShellExecute(main_window_handle, TEXT("open"), TEXT("http://www.stunnel.org/"), NULL, NULL, SW_SHOWNORMAL); #endif break; } return 0; case WM_SYSTRAY: /* a taskbar event */ switch(lParam) { #ifdef _WIN32_WCE case WM_LBUTTONDOWN: /* no right mouse button on Windows CE */ GetWindowRect(GetDesktopWindow(), &rect); /* no cursor position */ pt.x=rect.right; pt.y=rect.bottom-25; #else case WM_RBUTTONDOWN: GetCursorPos(&pt); #endif SetForegroundWindow(main_window_handle); if(tray_menu_handle) TrackPopupMenuEx(GetSubMenu(tray_menu_handle, 0), TPM_BOTTOMALIGN, pt.x, pt.y, main_window_handle, NULL); PostMessage(main_window_handle, WM_NULL, 0, 0); break; #ifndef _WIN32_WCE case WM_LBUTTONDBLCLK: /* switch log window visibility */ if(visible) { ShowWindow(main_window_handle, SW_HIDE); /* hide window */ } else { ShowWindow(main_window_handle, SW_SHOWNORMAL); /* show window */ SetForegroundWindow(main_window_handle); /* bring on top */ } break; #endif } return 0; case WM_VALID_CONFIG: valid_config(); return 0; case WM_INVALID_CONFIG: invalid_config(); return 0; case WM_LOG: txt=(LPTSTR)wParam; win_log(txt); str_free(txt); return 0; case WM_NEW_CHAIN: #ifndef _WIN32_WCE if(main_menu_handle) EnableMenuItem(main_menu_handle, (UINT)(IDM_PEER_MENU+wParam), MF_ENABLED); #endif if(tray_menu_handle) EnableMenuItem(tray_menu_handle, (UINT)(IDM_PEER_MENU+wParam), MF_ENABLED); return 0; case WM_CLIENTS: tray_update((int)wParam); return 0; } return DefWindowProc(main_window_handle, message, wParam, lParam); } NOEXPORT LRESULT CALLBACK about_proc(HWND dialog_handle, UINT message, WPARAM wParam, LPARAM lParam) { (void)lParam; /* squash the unused parameter warning */ switch(message) { case WM_INITDIALOG: return TRUE; case WM_COMMAND: switch(wParam) { case IDOK: case IDCANCEL: EndDialog(dialog_handle, TRUE); return TRUE; } } return FALSE; } NOEXPORT LRESULT CALLBACK pass_proc(HWND dialog_handle, UINT message, WPARAM wParam, LPARAM lParam) { LPTSTR titlebar; union { TCHAR txt[PEM_BUFSIZE]; WORD len; } pass_dialog; WORD pass_len; char* pass_txt; LPTSTR key_file_name; switch(message) { case WM_INITDIALOG: /* set the default push button to "Cancel" */ SendMessage(dialog_handle, DM_SETDEFID, (WPARAM)IDCANCEL, (LPARAM)0); key_file_name=str2tstr(ui_data->section->key); titlebar=str_tprintf(TEXT("Private key: %s"), key_file_name); str_free(key_file_name); SetWindowText(dialog_handle, titlebar); str_free(titlebar); return TRUE; case WM_COMMAND: /* set the default push button to "OK" when the user enters text */ if(HIWORD(wParam)==EN_CHANGE && LOWORD(wParam)==IDE_PASSEDIT) SendMessage(dialog_handle, DM_SETDEFID, (WPARAM)IDOK, (LPARAM)0); switch(wParam) { case IDOK: /* get number of characters */ pass_len=(WORD)SendDlgItemMessage(dialog_handle, IDE_PASSEDIT, EM_LINELENGTH, (WPARAM)0, (LPARAM)0); if(!pass_len || pass_len>=PEM_BUFSIZE) { EndDialog(dialog_handle, FALSE); return FALSE; } /* put the number of characters into first word of buffer */ pass_dialog.len=pass_len; /* get the characters */ SendDlgItemMessage(dialog_handle, IDE_PASSEDIT, EM_GETLINE, (WPARAM)0 /* line 0 */, (LPARAM)pass_dialog.txt); pass_dialog.txt[pass_len]='\0'; /* null-terminate the string */ /* convert input password to UTF-8 string (as ui_data->pass) */ pass_txt=tstr2str(pass_dialog.txt); strcpy(ui_data->pass, pass_txt); str_free(pass_txt); EndDialog(dialog_handle, TRUE); return TRUE; case IDCANCEL: EndDialog(dialog_handle, FALSE); return TRUE; } return 0; } return FALSE; UNREFERENCED_PARAMETER(lParam); } int passwd_cb(char *buf, int size, int rwflag, void *userdata) { (void)rwflag; /* squash the unused parameter warning */ ui_data=userdata; if(size<0) /* just in case */ return 0; if(!DialogBox(ghInst, TEXT("PassBox"), hwnd, (DLGPROC)pass_proc)) return 0; /* error */ strncpy(buf, ui_data->pass, (size_t)size); buf[size-1]='\0'; return (int)strlen(buf); } #ifndef OPENSSL_NO_ENGINE int pin_cb(UI *ui, UI_STRING *uis) { ui_data=UI_get0_user_data(ui); /* was: ui_data=UI_get_app_data(ui); */ if(!ui_data) { s_log(LOG_ERR, "INTERNAL ERROR: user data data pointer"); return 0; } if(!DialogBox(ghInst, TEXT("PassBox"), hwnd, (DLGPROC)pass_proc)) return 0; /* error */ UI_set_result(ui, uis, ui_data->pass); return 1; } #endif /**************************************** log handling */ NOEXPORT void save_log() { TCHAR file_name[MAX_PATH]; OPENFILENAME ofn; LPTSTR txt; LPSTR str; ZeroMemory(&ofn, sizeof ofn); file_name[0]='\0'; ofn.lStructSize=sizeof ofn; ofn.hwndOwner=hwnd; ofn.lpstrFilter=TEXT("Log Files (*.log)\0*.log\0All Files (*.*)\0*.*\0\0"); ofn.lpstrFile=file_name; ofn.nMaxFile=MAX_PATH; ofn.lpstrDefExt=TEXT("LOG"); ofn.lpstrInitialDir=TEXT("."); ofn.lpstrTitle=TEXT("Save Log"); ofn.Flags=OFN_EXPLORER|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY| OFN_OVERWRITEPROMPT; if(!GetSaveFileName(&ofn)) return; txt=log_txt(); /* need to convert the result to UTF-8 */ str=tstr2str(txt); str_free(txt); save_text_file(file_name, str); str_free(str); } NOEXPORT int save_text_file(LPTSTR file_name, char *str) { HANDLE file_handle; DWORD ignore; file_handle=CreateFile(file_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(file_handle==INVALID_HANDLE_VALUE) { error_box(TEXT("CreateFile")); return 1; } if(!WriteFile(file_handle, str, (DWORD)strlen(str), &ignore, NULL)) { CloseHandle(file_handle); error_box(TEXT("WriteFile")); return 1; } CloseHandle(file_handle); return 0; } NOEXPORT void win_log(LPCTSTR txt) { struct LIST *curr; size_t txt_len; static size_t log_len=0; txt_len=_tcslen(txt); curr=str_alloc(sizeof(struct LIST)+txt_len*sizeof(TCHAR)); curr->len=txt_len; _tcscpy(curr->txt, txt); curr->next=NULL; if(tail) tail->next=curr; tail=curr; if(!head) head=tail; log_len++; while(log_len>LOG_LINES) { curr=head; head=head->next; str_free(curr); log_len--; } new_logs=1; } NOEXPORT void update_logs(void) { LPTSTR txt; if(!InterlockedExchange(&new_logs, 0)) return; txt=log_txt(); SetWindowText(edit_handle, txt); str_free(txt); SendMessage(edit_handle, WM_VSCROLL, (WPARAM)SB_BOTTOM, (LPARAM)0); } NOEXPORT LPTSTR log_txt(void) { LPTSTR buff; size_t ptr=0, len=0; struct LIST *curr; for(curr=head; curr; curr=curr->next) len+=curr->len+2; /* +2 for trailing '\r\n' */ buff=str_alloc((len+1)*sizeof(TCHAR)); /* +1 for trailing '\0' */ for(curr=head; curr; curr=curr->next) { memcpy(buff+ptr, curr->txt, curr->len*sizeof(TCHAR)); ptr+=curr->len; if(curr->next) { buff[ptr++]=TEXT('\r'); buff[ptr++]=TEXT('\n'); } } buff[ptr]=TEXT('\0'); return buff; } /**************************************** worker thread */ NOEXPORT void daemon_thread(void *arg) { (void)arg; /* squash the unused parameter warning */ tls_alloc(NULL, NULL, "main"); /* new thread-local storage */ main_init(); SetEvent(main_initialized); /* unlock the GUI thread */ /* get a valid configuration */ while(main_configure(cmdline.config_file, NULL)) { cmdline.config_file=NULL; /* don't retry commandline switches */ unbind_ports(); /* in case initialization failed after bind_ports() */ log_flush(LOG_MODE_ERROR); /* otherwise logs are buffered */ PostMessage(hwnd, WM_INVALID_CONFIG, 0, 0); /* display error */ WaitForSingleObject(config_ready, INFINITE); log_close(); /* prevent main_configure() from logging in error mode */ } PostMessage(hwnd, WM_VALID_CONFIG, 0, 0); /* start the main loop */ daemon_loop(); main_cleanup(); _endthread(); /* SIGNAL_TERMINATE received */ } /**************************************** helper functions */ NOEXPORT void invalid_config() { /* update the main window title */ win32_name=TEXT("stunnel ") TEXT(STUNNEL_VERSION) TEXT(" on ") TEXT(STUNNEL_PLATFORM) TEXT(" (invalid configuration file)"); SetWindowText(hwnd, win32_name); /* log window is hidden by default */ ShowWindow(hwnd, SW_SHOWNORMAL); /* show window */ SetForegroundWindow(hwnd); /* bring on top */ tray_update(-1); /* error icon */ update_peer_menu(); /* purge the list of sections */ win_log(TEXT("")); s_log(LOG_ERR, "Server is down"); message_box(TEXT("Stunnel server is down due to an error.\n") TEXT("You need to exit and correct the problem.\n") TEXT("Click OK to see the error log window."), MB_ICONERROR); } NOEXPORT void valid_config() { /* update the main window title */ win32_name=TEXT("stunnel ") TEXT(STUNNEL_VERSION) TEXT(" on ") TEXT(STUNNEL_PLATFORM); SetWindowText(hwnd, win32_name); tray_update(num_clients); /* idle or busy icon (on reload) */ update_peer_menu(); /* one menu item per section */ /* enable IDM_REOPEN_LOG menu if a log file is used, disable otherwise */ #ifndef _WIN32_WCE EnableMenuItem(main_menu_handle, IDM_REOPEN_LOG, (UINT)(global_options.output_file ? MF_ENABLED : MF_GRAYED)); #endif if(tray_menu_handle) EnableMenuItem(tray_menu_handle, IDM_REOPEN_LOG, (UINT)(global_options.output_file ? MF_ENABLED : MF_GRAYED)); } NOEXPORT void update_peer_menu(void) { SERVICE_OPTIONS *section; #ifndef _WIN32_WCE HMENU main_peer_list=NULL; #endif HMENU tray_peer_list=NULL; unsigned section_number; LPTSTR servname; /* purge menu peer lists */ #ifndef _WIN32_WCE if(main_menu_handle) main_peer_list=GetSubMenu(main_menu_handle, 2); /* 3rd submenu */ if(main_peer_list) while(GetMenuItemCount(main_peer_list)) /* purge old menu */ DeleteMenu(main_peer_list, 0, MF_BYPOSITION); #endif if(tray_menu_handle) tray_peer_list=GetSubMenu(GetSubMenu(tray_menu_handle, 0), 2); if(tray_peer_list) while(GetMenuItemCount(tray_peer_list)) /* purge old menu */ DeleteMenu(tray_peer_list, 0, MF_BYPOSITION); /* initialize data structures */ number_of_sections=0; for(section=service_options.next; section; section=section->next) section->section_number=number_of_sections++; section_number=0; for(section=service_options.next; section; section=section->next) { servname=str2tstr(section->servname); /* setup LPTSTR section->file */ section->file=str_tprintf(TEXT("peer-%s.pem"), servname); /* setup section->help */ section->help=str_tprintf( TEXT("Peer certificate chain has been saved.\n") TEXT("Add the following lines to section [%s]:\n") TEXT("\tCAfile = peer-%s.pem\n") TEXT("\tverify = 3\n") TEXT("to enable cryptographic authentication.\n") TEXT("Then reload stunnel configuration file."), servname, servname); str_free(servname); /* setup section->chain */ section->chain=NULL; /* insert new menu item */ #ifndef _WIN32_WCE if(main_peer_list) if(!InsertMenu(main_peer_list, section_number, MF_BYPOSITION|MF_STRING|MF_GRAYED, IDM_PEER_MENU+section_number, section->file)) ioerror("InsertMenu"); #endif if(tray_peer_list) if(!InsertMenu(tray_peer_list, section_number, MF_BYPOSITION|MF_STRING|MF_GRAYED, IDM_PEER_MENU+section_number, section->file)) ioerror("InsertMenu"); ++section_number; } if(hwnd) DrawMenuBar(hwnd); } ICON_IMAGE load_icon_default(ICON_TYPE type) { WORD idi; ICON_IMAGE img; switch(type) { case ICON_ACTIVE: idi=IDI_STUNNEL_ACTIVE; break; case ICON_ERROR: idi=IDI_STUNNEL_ERROR; break; case ICON_IDLE: idi=IDI_STUNNEL_IDLE; break; default: return NULL; } img=LoadImage(ghInst, MAKEINTRESOURCE(idi), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0); return DuplicateIcon(NULL, img); } ICON_IMAGE load_icon_file(const char *name) { LPTSTR tname; ICON_IMAGE icon; tname=str2tstr((LPSTR)name); #ifndef _WIN32_WCE icon=LoadImage(NULL, tname, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_LOADFROMFILE); #else /* TODO: Implement a WCE version of LoadImage() */ /* icon=wceLoadIconFromFile(tname); */ s_log(LOG_ERR, "Loading image from file not implemented on WCE"); icon=NULL; #endif str_free(tname); return icon; } NOEXPORT void tray_update(const int num) { NOTIFYICONDATA nid; static ICON_TYPE previous_icon=ICON_NONE; ICON_TYPE current_icon; LPTSTR tip; if(!global_options.option.taskbar) { /* currently disabled */ tray_delete(); /* remove the taskbark icon if exists */ return; } if(!tray_menu_handle) /* initialize taskbar */ tray_menu_handle=LoadMenu(ghInst, MAKEINTRESOURCE(IDM_TRAYMENU)); if(!tray_menu_handle) { ioerror("LoadMenu"); return; } if(cmdline.service) EnableMenuItem(tray_menu_handle, IDM_EDIT_CONFIG, MF_GRAYED); ZeroMemory(&nid, sizeof nid); nid.cbSize=sizeof nid; nid.uID=1; /* application-defined icon ID */ nid.uFlags=NIF_MESSAGE|NIF_TIP; nid.uCallbackMessage=WM_SYSTRAY; /* notification message */ nid.hWnd=hwnd; /* window to receive notifications */ if(num<0) { tip=str_tprintf(TEXT("Server is down")); current_icon=ICON_ERROR; } else if(num>0) { tip=str_tprintf(TEXT("%d active session(s)"), num); current_icon=ICON_ACTIVE; } else { tip=str_tprintf(TEXT("Server is idle")); current_icon=ICON_IDLE; } _tcsncpy(nid.szTip, tip, 63); nid.szTip[63]=TEXT('\0'); str_free(tip); nid.hIcon=global_options.icon[current_icon]; if(current_icon!=previous_icon) { nid.uFlags|=NIF_ICON; previous_icon=current_icon; } if(Shell_NotifyIcon(NIM_MODIFY, &nid)) /* modify tooltip */ return; /* OK: taskbar icon exists */ /* tooltip update failed - try to create the icon */ nid.uFlags|=NIF_ICON; Shell_NotifyIcon(NIM_ADD, &nid); } NOEXPORT void tray_delete(void) { NOTIFYICONDATA nid; if(tray_menu_handle) { ZeroMemory(&nid, sizeof nid); nid.cbSize=sizeof nid; nid.uID=1; /* application-defined icon ID */ nid.hWnd=hwnd; /* window to receive notifications */ nid.uFlags=NIF_TIP; /* not really sure what to put here, but it works */ Shell_NotifyIcon(NIM_DELETE, &nid); /* this removes the icon */ if(!DestroyMenu(tray_menu_handle)) /* release menu resources */ ioerror("DestroyMenu"); tray_menu_handle=NULL; } } NOEXPORT void error_box(LPCTSTR text) { LPTSTR errmsg, fullmsg; DWORD dw; dw=GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&errmsg, 0, NULL); fullmsg=str_tprintf(TEXT("%s: error %ld: %s"), text, dw, errmsg); LocalFree(errmsg); message_box(fullmsg, MB_ICONERROR); str_free(fullmsg); } void message_box(LPCTSTR text, const UINT type) { if(cmdline.quiet) return; MessageBox(hwnd, text, win32_name, type); } void ui_new_chain(const unsigned section_number) { PostMessage(hwnd, WM_NEW_CHAIN, section_number, 0); } void ui_new_log(const char *line) { LPTSTR txt; txt=str2tstr(line); str_detach(txt); /* this allocation will be freed in the GUI thread */ PostMessage(hwnd, WM_LOG, (WPARAM)txt, 0); } void ui_config_reloaded(void) { PostMessage(hwnd, WM_VALID_CONFIG, 0, 0); } void ui_clients(const long num) { PostMessage(hwnd, WM_CLIENTS, (WPARAM)num, 0); } /* TODO: port it to WCE */ NOEXPORT void edit_config(HWND main_window_handle) { TCHAR cwd[MAX_PATH]; LPTSTR conf_file, conf_path; DISK_FILE *df; conf_file=str2tstr(configuration_file); if(*conf_file==TEXT('\"')) { conf_path=conf_file; } else if(_tcschr(conf_file, TEXT('\\'))) { conf_path=str_tprintf(TEXT("\"%s\""), conf_file); str_free(conf_file); } else { GetCurrentDirectory(MAX_PATH, cwd); conf_path=str_tprintf(TEXT("\"%s\\%s\""), cwd, conf_file); str_free(conf_file); } df=file_open(configuration_file, FILE_MODE_APPEND); if(df) { /* the configuration file is writable */ file_close(df); ShellExecute(main_window_handle, TEXT("open"), TEXT("notepad.exe"), conf_path, NULL, SW_SHOWNORMAL); } else { /* UAC workaround */ ShellExecute(main_window_handle, TEXT("runas"), TEXT("notepad.exe"), conf_path, NULL, SW_SHOWNORMAL); } str_free(conf_path); } /**************************************** windows service */ #ifndef _WIN32_WCE NOEXPORT int service_initialize(void) { SERVICE_TABLE_ENTRY serviceTable[]={{0, 0}, {0, 0}}; serviceTable[0].lpServiceName=SERVICE_NAME; serviceTable[0].lpServiceProc=service_main; /* disable taskbar for security */ /* global_options.option.taskbar=0; */ if(!StartServiceCtrlDispatcher(serviceTable)) { error_box(TEXT("StartServiceCtrlDispatcher")); return 1; } return 0; /* NT service started */ } #define DESCR_LEN 256 NOEXPORT int service_install() { SC_HANDLE scm, service; TCHAR stunnel_exe_path[MAX_PATH]; LPTSTR service_path; TCHAR descr_str[DESCR_LEN]; SERVICE_DESCRIPTION descr; scm=OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE); if(!scm) { error_box(TEXT("OpenSCManager")); return 1; } GetModuleFileName(0, stunnel_exe_path, MAX_PATH); service_path=str_tprintf(TEXT("\"%s\" -service %s"), stunnel_exe_path, get_params()); service=CreateService(scm, SERVICE_NAME, SERVICE_DISPLAY_NAME, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, service_path, NULL, NULL, TEXT("TCPIP\0"), NULL, NULL); if(!service) { error_box(TEXT("CreateService")); str_free(service_path); CloseServiceHandle(scm); return 1; } str_free(service_path); if(LoadString(ghInst, IDS_SERVICE_DESC, descr_str, DESCR_LEN)) { descr.lpDescription=descr_str; ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &descr); } message_box(TEXT("Service installed"), MB_ICONINFORMATION); CloseServiceHandle(service); CloseServiceHandle(scm); return 0; } NOEXPORT int service_uninstall(void) { SC_HANDLE scm, service; SERVICE_STATUS serviceStatus; scm=OpenSCManager(0, 0, SC_MANAGER_CONNECT); if(!scm) { error_box(TEXT("OpenSCManager")); return 1; } service=OpenService(scm, SERVICE_NAME, SERVICE_QUERY_STATUS|DELETE); if(!service) { error_box(TEXT("OpenService")); CloseServiceHandle(scm); return 1; } if(!QueryServiceStatus(service, &serviceStatus)) { error_box(TEXT("QueryServiceStatus")); CloseServiceHandle(service); CloseServiceHandle(scm); return 1; } if(serviceStatus.dwCurrentState!=SERVICE_STOPPED) { message_box(TEXT("The service is still running"), MB_ICONERROR); CloseServiceHandle(service); CloseServiceHandle(scm); return 1; } if(!DeleteService(service)) { error_box(TEXT("DeleteService")); CloseServiceHandle(service); CloseServiceHandle(scm); return 1; } message_box(TEXT("Service uninstalled"), MB_ICONINFORMATION); CloseServiceHandle(service); CloseServiceHandle(scm); return 0; } NOEXPORT int service_start(void) { SC_HANDLE scm, service; SERVICE_STATUS serviceStatus; scm=OpenSCManager(0, 0, SC_MANAGER_CONNECT); if(!scm) { error_box(TEXT("OpenSCManager")); return 1; } service=OpenService(scm, SERVICE_NAME, SERVICE_QUERY_STATUS|SERVICE_START); if(!service) { error_box(TEXT("OpenService")); CloseServiceHandle(scm); return 1; } if(!StartService(service, 0, NULL)) { error_box(TEXT("StartService")); CloseServiceHandle(service); CloseServiceHandle(scm); return 1; } do { Sleep(1000); if(!QueryServiceStatus(service, &serviceStatus)) { error_box(TEXT("QueryServiceStatus")); CloseServiceHandle(service); CloseServiceHandle(scm); return 1; } } while(serviceStatus.dwCurrentState==SERVICE_START_PENDING); if(serviceStatus.dwCurrentState!=SERVICE_RUNNING) { message_box(TEXT("Failed to start service"), MB_ICONERROR); CloseServiceHandle(service); CloseServiceHandle(scm); return 1; } message_box(TEXT("Service started"), MB_ICONINFORMATION); CloseServiceHandle(service); CloseServiceHandle(scm); return 0; } NOEXPORT int service_stop(void) { SC_HANDLE scm, service; SERVICE_STATUS serviceStatus; scm=OpenSCManager(0, 0, SC_MANAGER_CONNECT); if(!scm) { error_box(TEXT("OpenSCManager")); return 1; } service=OpenService(scm, SERVICE_NAME, SERVICE_QUERY_STATUS|SERVICE_STOP); if(!service) { error_box(TEXT("OpenService")); CloseServiceHandle(scm); return 1; } if(!QueryServiceStatus(service, &serviceStatus)) { error_box(TEXT("QueryServiceStatus")); CloseServiceHandle(service); CloseServiceHandle(scm); return 1; } if(serviceStatus.dwCurrentState==SERVICE_STOPPED) { message_box(TEXT("The service is already stopped"), MB_ICONERROR); CloseServiceHandle(service); CloseServiceHandle(scm); return 1; } if(!ControlService(service, SERVICE_CONTROL_STOP, &serviceStatus)) { error_box(TEXT("ControlService")); CloseServiceHandle(service); CloseServiceHandle(scm); return 1; } do { Sleep(1000); if(!QueryServiceStatus(service, &serviceStatus)) { error_box(TEXT("QueryServiceStatus")); CloseServiceHandle(service); CloseServiceHandle(scm); return 1; } } while(serviceStatus.dwCurrentState!=SERVICE_STOPPED); message_box(TEXT("Service stopped"), MB_ICONINFORMATION); CloseServiceHandle(service); CloseServiceHandle(scm); return 0; } NOEXPORT int service_user(DWORD sig) { SC_HANDLE scm, service; SERVICE_STATUS serviceStatus; scm=OpenSCManager(0, 0, SC_MANAGER_CONNECT); if(!scm) { error_box(TEXT("OpenSCManager")); return 1; } service=OpenService(scm, SERVICE_NAME, SERVICE_QUERY_STATUS|SERVICE_USER_DEFINED_CONTROL); if(!service) { error_box(TEXT("OpenService")); CloseServiceHandle(scm); return 1; } if(!QueryServiceStatus(service, &serviceStatus)) { error_box(TEXT("QueryServiceStatus")); CloseServiceHandle(service); CloseServiceHandle(scm); return 1; } if(serviceStatus.dwCurrentState==SERVICE_STOPPED) { message_box(TEXT("The service is stopped"), MB_ICONERROR); CloseServiceHandle(service); CloseServiceHandle(scm); return 1; } if(!ControlService(service, SERVICE_CONTROL_USER+sig, &serviceStatus)) { error_box(TEXT("ControlService")); CloseServiceHandle(service); CloseServiceHandle(scm); return 1; } switch(sig) { case SIGNAL_RELOAD_CONFIG: message_box(TEXT("Service configuration reloaded"), MB_ICONINFORMATION); break; case SIGNAL_REOPEN_LOG: message_box(TEXT("Service log file reopened"), MB_ICONINFORMATION); break; default: message_box(TEXT("Undefined operation requested"), MB_ICONINFORMATION); } CloseServiceHandle(service); CloseServiceHandle(scm); return 0; } NOEXPORT void WINAPI service_main(DWORD argc, LPTSTR* argv) { (void)argc; /* squash the unused parameter warning */ (void)argv; /* squash the unused parameter warning */ tls_alloc(NULL, NULL, "service"); /* new thread-local storage */ /* initialise service status */ serviceStatus.dwServiceType=SERVICE_WIN32; serviceStatus.dwCurrentState=SERVICE_STOPPED; serviceStatus.dwControlsAccepted=0; serviceStatus.dwWin32ExitCode=NO_ERROR; serviceStatus.dwServiceSpecificExitCode=NO_ERROR; serviceStatus.dwCheckPoint=0; serviceStatus.dwWaitHint=0; serviceStatusHandle= RegisterServiceCtrlHandler(SERVICE_NAME, control_handler); if(serviceStatusHandle) { /* service is starting */ serviceStatus.dwCurrentState=SERVICE_START_PENDING; SetServiceStatus(serviceStatusHandle, &serviceStatus); /* running */ serviceStatus.dwControlsAccepted|= (SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN); serviceStatus.dwCurrentState=SERVICE_RUNNING; SetServiceStatus(serviceStatusHandle, &serviceStatus); gui_loop(); /* service was stopped */ serviceStatus.dwCurrentState=SERVICE_STOP_PENDING; SetServiceStatus(serviceStatusHandle, &serviceStatus); /* service is now stopped */ serviceStatus.dwControlsAccepted&= (DWORD)~(SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN); serviceStatus.dwCurrentState=SERVICE_STOPPED; SetServiceStatus(serviceStatusHandle, &serviceStatus); } } NOEXPORT void WINAPI control_handler(DWORD controlCode) { switch(controlCode) { case SERVICE_CONTROL_INTERROGATE: break; case SERVICE_CONTROL_SHUTDOWN: case SERVICE_CONTROL_STOP: serviceStatus.dwCurrentState=SERVICE_STOP_PENDING; SetServiceStatus(serviceStatusHandle, &serviceStatus); PostMessage(hwnd, WM_COMMAND, IDM_EXIT, 0); return; case SERVICE_CONTROL_PAUSE: break; case SERVICE_CONTROL_CONTINUE: break; case SERVICE_CONTROL_USER+SIGNAL_RELOAD_CONFIG: signal_post(SIGNAL_RELOAD_CONFIG); break; case SERVICE_CONTROL_USER+SIGNAL_REOPEN_LOG: signal_post(SIGNAL_REOPEN_LOG); break; default: if(controlCode >= 128 && controlCode <= 255) break; /* user defined control code */ else break; /* unrecognised control code */ } SetServiceStatus(serviceStatusHandle, &serviceStatus); } #endif /* !defined(_WIN32_WCE) */ /**************************************** other functions */ NOEXPORT LPTSTR get_params() { LPTSTR c; TCHAR s; c=GetCommandLine(); if(*c==TEXT('\"')) { s=TEXT('\"'); ++c; } else { s=TEXT(' '); } for(; *c; ++c) if(*c==s) { ++c; break; } while(*c==TEXT(' ')) ++c; return c; } /* end of ui_win_gui.c */ stunnel-5.30/src/options.c0000664000175000017500000031625012646221043012511 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #include "common.h" #include "prototypes.h" #if defined(_WIN32_WCE) && !defined(CONFDIR) #define CONFDIR "\\stunnel" #endif #define CONFLINELEN (16*1024) typedef enum { CMD_BEGIN, /* initialize defaults */ CMD_EXEC, /* process command */ CMD_END, /* end of section */ CMD_FREE, /* TODO: deallocate memory */ CMD_DEFAULT, /* print default value */ CMD_HELP /* print help */ } CMD; NOEXPORT int options_file(char *, CONF_TYPE, SERVICE_OPTIONS **); NOEXPORT int options_include(char *, SERVICE_OPTIONS **); #ifdef USE_WIN32 struct dirent { char d_name[MAX_PATH]; }; int scandir(const char *, struct dirent ***, int (*)(const struct dirent *), int (*)(const struct dirent **, const struct dirent **)); int alphasort(const struct dirent **, const struct dirent **); #endif NOEXPORT char *parse_global_option(CMD, char *, char *); NOEXPORT char *parse_service_option(CMD, SERVICE_OPTIONS *, char *, char *); #ifndef OPENSSL_NO_TLSEXT NOEXPORT char *sni_init(SERVICE_OPTIONS *); #endif /* !defined(OPENSSL_NO_TLSEXT) */ NOEXPORT char *parse_debug_level(char *, SERVICE_OPTIONS *); #ifndef OPENSSL_NO_PSK NOEXPORT PSK_KEYS *psk_read(char *); NOEXPORT void psk_free(PSK_KEYS *); #endif /* !defined(OPENSSL_NO_PSK) */ typedef struct { char *name; long unsigned value; } SSL_OPTION; static const SSL_OPTION ssl_opts[] = { {"MICROSOFT_SESS_ID_BUG", SSL_OP_MICROSOFT_SESS_ID_BUG}, {"NETSCAPE_CHALLENGE_BUG", SSL_OP_NETSCAPE_CHALLENGE_BUG}, #ifdef SSL_OP_LEGACY_SERVER_CONNECT {"LEGACY_SERVER_CONNECT", SSL_OP_LEGACY_SERVER_CONNECT}, #endif {"NETSCAPE_REUSE_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG}, #ifdef SSL_OP_TLSEXT_PADDING {"TLSEXT_PADDING", SSL_OP_TLSEXT_PADDING}, #endif {"MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER}, #ifdef SSL_OP_SAFARI_ECDHE_ECDSA_BUG {"SAFARI_ECDHE_ECDSA_BUG", SSL_OP_SAFARI_ECDHE_ECDSA_BUG}, #endif {"SSLEAY_080_CLIENT_DH_BUG", SSL_OP_SSLEAY_080_CLIENT_DH_BUG}, {"TLS_D5_BUG", SSL_OP_TLS_D5_BUG}, {"TLS_BLOCK_PADDING_BUG", SSL_OP_TLS_BLOCK_PADDING_BUG}, #ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING {"MSIE_SSLV2_RSA_PADDING", SSL_OP_MSIE_SSLV2_RSA_PADDING}, #endif {"SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG}, #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS {"DONT_INSERT_EMPTY_FRAGMENTS", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS}, #endif {"ALL", SSL_OP_ALL}, #ifdef SSL_OP_NO_QUERY_MTU {"NO_QUERY_MTU", SSL_OP_NO_QUERY_MTU}, #endif #ifdef SSL_OP_COOKIE_EXCHANGE {"COOKIE_EXCHANGE", SSL_OP_COOKIE_EXCHANGE}, #endif #ifdef SSL_OP_NO_TICKET {"NO_TICKET", SSL_OP_NO_TICKET}, #endif #ifdef SSL_OP_CISCO_ANYCONNECT {"CISCO_ANYCONNECT", SSL_OP_CISCO_ANYCONNECT}, #endif #ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION {"NO_SESSION_RESUMPTION_ON_RENEGOTIATION", SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION}, #endif #ifdef SSL_OP_NO_COMPRESSION {"NO_COMPRESSION", SSL_OP_NO_COMPRESSION}, #endif #ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION {"ALLOW_UNSAFE_LEGACY_RENEGOTIATION", SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION}, #endif #ifdef SSL_OP_SINGLE_ECDH_USE {"SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE}, #endif {"SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE}, {"EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA}, #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE {"CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE}, #endif {"TLS_ROLLBACK_BUG", SSL_OP_TLS_ROLLBACK_BUG}, {"NO_SSLv2", SSL_OP_NO_SSLv2}, {"NO_SSLv3", SSL_OP_NO_SSLv3}, {"NO_TLSv1", SSL_OP_NO_TLSv1}, #ifdef SSL_OP_NO_TLSv1_1 {"NO_TLSv1.1", SSL_OP_NO_TLSv1_1}, #endif #ifdef SSL_OP_NO_TLSv1_2 {"NO_TLSv1.2", SSL_OP_NO_TLSv1_2}, #endif {"PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1}, {"PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2}, {"NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG}, #ifdef SSL_OP_NON_EXPORT_FIRST {"NON_EXPORT_FIRST", SSL_OP_NON_EXPORT_FIRST}, #endif {"NETSCAPE_DEMO_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG}, #ifdef SSL_OP_CRYPTOPRO_TLSEXT_BUG {"CRYPTOPRO_TLSEXT_BUG", SSL_OP_CRYPTOPRO_TLSEXT_BUG}, #endif #ifdef SSL_OP_NO_DTLSv1 {"NO_DTLSv1", SSL_OP_NO_DTLSv1}, #endif #ifdef SSL_OP_NO_DTLSv1_2 {"NO_DTLSv1_2", SSL_OP_NO_DTLSv1_2}, #endif #ifdef SSL_OP_NO_SSL_MASK {"NO_SSL_MASK", SSL_OP_NO_SSL_MASK}, #endif {NULL, 0} }; NOEXPORT long unsigned parse_ssl_option(char *); NOEXPORT void print_ssl_options(void); NOEXPORT int print_socket_options(void); NOEXPORT char *print_option(int, OPT_UNION *); NOEXPORT int parse_socket_option(char *); #ifndef OPENSSL_NO_OCSP NOEXPORT unsigned long parse_ocsp_flag(char *); #endif /* !defined(OPENSSL_NO_OCSP) */ #ifndef OPENSSL_NO_ENGINE NOEXPORT void engine_reset_list(void); NOEXPORT char *engine_auto(void); NOEXPORT char *engine_open(const char *); NOEXPORT char *engine_ctrl(const char *, const char *); NOEXPORT char *engine_default(const char *); NOEXPORT char *engine_init(void); NOEXPORT ENGINE *engine_get_by_id(const char *); NOEXPORT ENGINE *engine_get_by_num(const int); #endif /* !defined(OPENSSL_NO_ENGINE) */ NOEXPORT void print_syntax(void); NOEXPORT void name_list_append(NAME_LIST **, char *); #ifndef USE_WIN32 NOEXPORT char **argalloc(char *); #endif char configuration_file[PATH_MAX]; GLOBAL_OPTIONS global_options; SERVICE_OPTIONS service_options; static GLOBAL_OPTIONS new_global_options; static SERVICE_OPTIONS new_service_options; static char *option_not_found= "Specified option name is not valid here"; static char *stunnel_cipher_list= "HIGH:+3DES:+DH:!aNULL:!SSLv2"; /**************************************** parse commandline parameters */ /* return values: 0 - configuration accepted 1 - error 2 - information printed */ int options_cmdline(char *arg1, char *arg2) { char *name; CONF_TYPE type; #ifdef USE_WIN32 (void)arg2; /* squash the unused parameter warning */ #endif if(!arg1) { name= #ifdef CONFDIR CONFDIR #ifdef USE_WIN32 "\\" #else "/" #endif #endif "stunnel.conf"; type=CONF_FILE; } else if(!strcasecmp(arg1, "-help")) { parse_global_option(CMD_HELP, NULL, NULL); parse_service_option(CMD_HELP, NULL, NULL, NULL); log_flush(LOG_MODE_INFO); return 2; } else if(!strcasecmp(arg1, "-version")) { parse_global_option(CMD_DEFAULT, NULL, NULL); parse_service_option(CMD_DEFAULT, NULL, NULL, NULL); log_flush(LOG_MODE_INFO); return 2; } else if(!strcasecmp(arg1, "-sockets")) { print_socket_options(); log_flush(LOG_MODE_INFO); return 2; } else if(!strcasecmp(arg1, "-options")) { print_ssl_options(); log_flush(LOG_MODE_INFO); return 2; } else #ifndef USE_WIN32 if(!strcasecmp(arg1, "-fd")) { if(!arg2) { s_log(LOG_ERR, "No file descriptor specified"); print_syntax(); return 1; } name=arg2; type=CONF_FD; } else #endif { name=arg1; type=CONF_FILE; } #ifdef HAVE_REALPATH if(type==CONF_FILE) { if(!realpath(name, configuration_file)) { s_log(LOG_ERR, "Invalid configuration file name \"%s\"", name); ioerror("realpath"); return 1; } return options_parse(type); } #endif strncpy(configuration_file, name, PATH_MAX-1); configuration_file[PATH_MAX-1]='\0'; return options_parse(type); } /**************************************** parse configuration file */ int options_parse(CONF_TYPE type) { SERVICE_OPTIONS *section; char *errstr; options_defaults(); section=&new_service_options; if(options_file(configuration_file, type, §ion)) return 1; if(new_service_options.next) { /* daemon mode: initialize sections */ for(section=new_service_options.next; section; section=section->next) { s_log(LOG_INFO, "Initializing service [%s]", section->servname); errstr=parse_service_option(CMD_END, section, NULL, NULL); if(errstr) break; } } else { /* inetd mode: need to initialize global options */ errstr=parse_global_option(CMD_END, NULL, NULL); if(errstr) { s_log(LOG_ERR, "Global options: %s", errstr); return 1; } s_log(LOG_INFO, "Initializing inetd mode configuration"); section=&new_service_options; errstr=parse_service_option(CMD_END, section, NULL, NULL); } if(errstr) { s_log(LOG_ERR, "Service [%s]: %s", section->servname, errstr); return 1; } s_log(LOG_NOTICE, "Configuration successful"); return 0; } NOEXPORT int options_file(char *path, CONF_TYPE type, SERVICE_OPTIONS **section) { DISK_FILE *df; char line_text[CONFLINELEN], *errstr; char config_line[CONFLINELEN], *config_opt, *config_arg; int i, line_number=0; #ifndef USE_WIN32 int fd; char *tmp_str; #endif s_log(LOG_NOTICE, "Reading configuration from %s %s", type==CONF_FD ? "descriptor" : "file", path); #ifndef USE_WIN32 if(type==CONF_FD) { /* file descriptor */ fd=(int)strtol(path, &tmp_str, 10); if(tmp_str==path || *tmp_str) { /* not a number */ s_log(LOG_ERR, "Invalid file descriptor number"); print_syntax(); return 1; } df=file_fdopen(fd); } else #endif df=file_open(path, FILE_MODE_READ); if(!df) { s_log(LOG_ERR, "Cannot open configuration file"); if(type!=CONF_RELOAD) print_syntax(); return 1; } while(file_getline(df, line_text, CONFLINELEN)>=0) { memcpy(config_line, line_text, CONFLINELEN); ++line_number; config_opt=config_line; if(line_number==1) { if(config_opt[0]==(char)0xef && config_opt[1]==(char)0xbb && config_opt[2]==(char)0xbf) { s_log(LOG_NOTICE, "UTF-8 byte order mark detected"); config_opt+=3; } else { s_log(LOG_NOTICE, "UTF-8 byte order mark not detected"); } } while(isspace((unsigned char)*config_opt)) ++config_opt; /* remove initial whitespaces */ for(i=(int)strlen(config_opt)-1; i>=0 && isspace((unsigned char)config_opt[i]); --i) config_opt[i]='\0'; /* remove trailing whitespaces */ if(config_opt[0]=='\0' || config_opt[0]=='#' || config_opt[0]==';') /* empty or comment */ continue; if(config_opt[0]=='[' && config_opt[strlen(config_opt)-1]==']') { /* new section */ SERVICE_OPTIONS *new_section; if(!new_service_options.next) { /* initialize global options */ errstr=parse_global_option(CMD_END, NULL, NULL); if(errstr) { s_log(LOG_ERR, "%s:%d: \"%s\": %s", path, line_number, line_text, errstr); file_close(df); return 1; } } ++config_opt; config_opt[strlen(config_opt)-1]='\0'; new_section=str_alloc(sizeof(SERVICE_OPTIONS)); memcpy(new_section, &new_service_options, sizeof(SERVICE_OPTIONS)); new_section->servname=str_dup(config_opt); new_section->session=NULL; new_section->next=NULL; (*section)->next=new_section; *section=new_section; continue; } config_arg=strchr(config_line, '='); if(!config_arg) { s_log(LOG_ERR, "%s:%d: \"%s\": No '=' found", path, line_number, line_text); file_close(df); return 1; } *config_arg++='\0'; /* split into option name and argument value */ for(i=(int)strlen(config_opt)-1; i>=0 && isspace((unsigned char)config_opt[i]); --i) config_opt[i]='\0'; /* remove trailing whitespaces */ while(isspace((unsigned char)*config_arg)) ++config_arg; /* remove initial whitespaces */ if(!strcasecmp(config_opt, "include")) { if(options_include(config_arg, section)) { s_log(LOG_ERR, "%s:%d: Failed to include directory \"%s\"", path, line_number, config_arg); file_close(df); return 1; } continue; } errstr=option_not_found; /* try global options first (e.g. for 'debug') */ if(!new_service_options.next) errstr=parse_global_option(CMD_EXEC, config_opt, config_arg); if(errstr==option_not_found) errstr=parse_service_option(CMD_EXEC, *section, config_opt, config_arg); if(errstr) { s_log(LOG_ERR, "%s:%d: \"%s\": %s", path, line_number, line_text, errstr); file_close(df); return 1; } } file_close(df); return 0; } NOEXPORT int options_include(char *directory, SERVICE_OPTIONS **section) { struct dirent **namelist; int i, num, err=0; num=scandir(directory, &namelist, NULL, alphasort); if(num<0) { ioerror("scandir"); return 1; } for(i=0; id_name); stat(name, &sb); if(S_ISREG(sb.st_mode)) err=options_file(name, CONF_FILE, section); else s_log(LOG_DEBUG, "\"%s\" is not a file", name); str_free(name); } free(namelist[i]); } free(namelist); return err; } #ifdef USE_WIN32 int scandir(const char *dirp, struct dirent ***namelist, int (*filter)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **)) { WIN32_FIND_DATA data; HANDLE h; unsigned num=0, allocated=0; LPTSTR path, pattern; char *name; DWORD saved_errno; (void)filter; /* squash the unused parameter warning */ (void)compar; /* squash the unused parameter warning */ path=str2tstr(dirp); pattern=str_tprintf(TEXT("%s\\*"), path); str_free(path); h=FindFirstFile(pattern, &data); saved_errno=GetLastError(); str_free(pattern); SetLastError(saved_errno); if(h==INVALID_HANDLE_VALUE) return -1; *namelist=NULL; do { if(num>=allocated) { allocated+=16; *namelist=realloc(*namelist, allocated*sizeof(**namelist)); } (*namelist)[num]=malloc(sizeof(struct dirent)); if(!(*namelist)[num]) return -1; name=tstr2str(data.cFileName); strncpy((*namelist)[num]->d_name, name, MAX_PATH-1); (*namelist)[num]->d_name[MAX_PATH-1]='\0'; str_free(name); ++num; } while(FindNextFile(h, &data)); FindClose(h); return (int)num; } int alphasort(const struct dirent **a, const struct dirent **b) { (void)a; /* squash the unused parameter warning */ (void)b; /* squash the unused parameter warning */ /* most Windows filesystem return sorted data */ return 0; } #endif void options_defaults() { /* initialize globals *before* opening the config file */ memset(&new_global_options, 0, sizeof(GLOBAL_OPTIONS)); /* reset global options */ memset(&new_service_options, 0, sizeof(SERVICE_OPTIONS)); /* reset local options */ new_service_options.next=NULL; parse_global_option(CMD_BEGIN, NULL, NULL); parse_service_option(CMD_BEGIN, &new_service_options, NULL, NULL); } void options_apply() { /* apply default/validated configuration */ /* FIXME: this operation may be unsafe, as client() threads use it */ memcpy(&global_options, &new_global_options, sizeof(GLOBAL_OPTIONS)); /* service_options are used for inetd mode and to enumerate services */ memcpy(&service_options, &new_service_options, sizeof(SERVICE_OPTIONS)); } /**************************************** global options */ NOEXPORT char *parse_global_option(CMD cmd, char *opt, char *arg) { if(cmd==CMD_DEFAULT || cmd==CMD_HELP) { s_log(LOG_NOTICE, " "); s_log(LOG_NOTICE, "Global options:"); } /* chroot */ #ifdef HAVE_CHROOT switch(cmd) { case CMD_BEGIN: new_global_options.chroot_dir=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "chroot")) break; new_global_options.chroot_dir=str_dup(arg); return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = directory to chroot stunnel process", "chroot"); break; } #endif /* HAVE_CHROOT */ /* compression */ #ifndef OPENSSL_NO_COMP switch(cmd) { case CMD_BEGIN: new_global_options.compression=COMP_NONE; break; case CMD_EXEC: if(strcasecmp(opt, "compression")) break; if(OpenSSL_version_num()>=0x00908051L && !strcasecmp(arg, "deflate")) new_global_options.compression=COMP_DEFLATE; else if(!strcasecmp(arg, "zlib")) new_global_options.compression=COMP_ZLIB; else return "Specified compression type is not available"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = compression type", "compression"); break; } #endif /* !defined(OPENSSL_NO_COMP) */ /* debug */ switch(cmd) { case CMD_BEGIN: new_service_options.log_level=LOG_NOTICE; #if !defined (USE_WIN32) && !defined (__vms) new_global_options.log_facility=LOG_DAEMON; #endif break; case CMD_EXEC: if(strcasecmp(opt, "debug")) break; return parse_debug_level(arg, &new_service_options); case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: #if !defined (USE_WIN32) && !defined (__vms) s_log(LOG_NOTICE, "%-22s = %s", "debug", "daemon.notice"); #else s_log(LOG_NOTICE, "%-22s = %s", "debug", "notice"); #endif break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = [facility].level (e.g. daemon.info)", "debug"); break; } /* EGD */ switch(cmd) { case CMD_BEGIN: #ifdef EGD_SOCKET new_global_options.egd_sock=EGD_SOCKET; #else new_global_options.egd_sock=NULL; #endif break; case CMD_EXEC: if(strcasecmp(opt, "EGD")) break; new_global_options.egd_sock=str_dup(arg); return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: #ifdef EGD_SOCKET s_log(LOG_NOTICE, "%-22s = %s", "EGD", EGD_SOCKET); #endif break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = path to Entropy Gathering Daemon socket", "EGD"); break; } #ifndef OPENSSL_NO_ENGINE /* engine */ switch(cmd) { case CMD_BEGIN: engine_reset_list(); break; case CMD_EXEC: if(strcasecmp(opt, "engine")) break; if(!strcasecmp(arg, "auto")) return engine_auto(); else return engine_open(arg); case CMD_END: engine_init(); break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = auto|engine_id", "engine"); break; } /* engineCtrl */ switch(cmd) { case CMD_BEGIN: break; case CMD_EXEC: if(strcasecmp(opt, "engineCtrl")) break; { char *tmp_str=strchr(arg, ':'); if(tmp_str) *tmp_str++='\0'; return engine_ctrl(arg, tmp_str); } case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = cmd[:arg]", "engineCtrl"); break; } /* engineDefault */ switch(cmd) { case CMD_BEGIN: break; case CMD_EXEC: if(strcasecmp(opt, "engineDefault")) break; return engine_default(arg); case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = TASK_LIST", "engineDefault"); break; } #endif /* !defined(OPENSSL_NO_ENGINE) */ /* fips */ switch(cmd) { case CMD_BEGIN: #ifdef USE_FIPS new_global_options.option.fips=0; #endif /* USE_FIPS */ break; case CMD_EXEC: if(strcasecmp(opt, "fips")) break; #ifdef USE_FIPS if(!strcasecmp(arg, "yes")) new_global_options.option.fips=1; else if(!strcasecmp(arg, "no")) new_global_options.option.fips=0; else return "The argument needs to be either 'yes' or 'no'"; #else if(strcasecmp(arg, "no")) return "FIPS support is not available"; #endif /* USE_FIPS */ return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: #ifdef USE_FIPS s_log(LOG_NOTICE, "%-22s = yes|no FIPS 140-2 mode", "fips"); #endif /* USE_FIPS */ break; } /* foreground */ #ifndef USE_WIN32 switch(cmd) { case CMD_BEGIN: new_global_options.option.foreground=0; new_global_options.option.log_stderr=0; break; case CMD_EXEC: if(strcasecmp(opt, "foreground")) break; if(!strcasecmp(arg, "yes")) { new_global_options.option.foreground=1; new_global_options.option.log_stderr=1; } else if(!strcasecmp(arg, "quiet")) { new_global_options.option.foreground=1; new_global_options.option.log_stderr=0; } else if(!strcasecmp(arg, "no")) { new_global_options.option.foreground=0; new_global_options.option.log_stderr=0; } else return "The argument needs to be either 'yes', 'quiet' or 'no'"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = yes|quiet|no foreground mode (don't fork, log to stderr)", "foreground"); break; } #endif #ifdef ICON_IMAGE /* iconActive */ switch(cmd) { case CMD_BEGIN: new_global_options.icon[ICON_ACTIVE]=load_icon_default(ICON_ACTIVE); break; case CMD_EXEC: if(strcasecmp(opt, "iconActive")) break; if(!(new_global_options.icon[ICON_ACTIVE]=load_icon_file(arg))) return "Failed to load the specified icon"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = icon when connections are established", "iconActive"); break; } /* iconError */ switch(cmd) { case CMD_BEGIN: new_global_options.icon[ICON_ERROR]=load_icon_default(ICON_ERROR); break; case CMD_EXEC: if(strcasecmp(opt, "iconError")) break; if(!(new_global_options.icon[ICON_ERROR]=load_icon_file(arg))) return "Failed to load the specified icon"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = icon for invalid configuration file", "iconError"); break; } /* iconIdle */ switch(cmd) { case CMD_BEGIN: new_global_options.icon[ICON_IDLE]=load_icon_default(ICON_IDLE); break; case CMD_EXEC: if(strcasecmp(opt, "iconIdle")) break; if(!(new_global_options.icon[ICON_IDLE]=load_icon_file(arg))) return "Failed to load the specified icon"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = icon when no connections were established", "iconIdle"); break; } #endif /* ICON_IMAGE */ /* log */ switch(cmd) { case CMD_BEGIN: new_global_options.log_file_mode=FILE_MODE_APPEND; break; case CMD_EXEC: if(strcasecmp(opt, "log")) break; if(!strcasecmp(arg, "append")) new_global_options.log_file_mode=FILE_MODE_APPEND; else if(!strcasecmp(arg, "overwrite")) new_global_options.log_file_mode=FILE_MODE_OVERWRITE; else return "The argument needs to be either 'append' or 'overwrite'"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = append|overwrite log file", "log"); break; } /* output */ switch(cmd) { case CMD_BEGIN: new_global_options.output_file=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "output")) break; new_global_options.output_file=str_dup(arg); return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = file to append log messages", "output"); break; } /* pid */ #ifndef USE_WIN32 switch(cmd) { case CMD_BEGIN: new_global_options.pidfile=NULL; /* do not create a pid file */ break; case CMD_EXEC: if(strcasecmp(opt, "pid")) break; if(arg[0]) /* is argument not empty? */ new_global_options.pidfile=str_dup(arg); else new_global_options.pidfile=NULL; /* empty -> do not create a pid file */ return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = pid file", "pid"); break; } #endif /* RNDbytes */ switch(cmd) { case CMD_BEGIN: new_global_options.random_bytes=RANDOM_BYTES; break; case CMD_EXEC: if(strcasecmp(opt, "RNDbytes")) break; { char *tmp_str; new_global_options.random_bytes=(long)strtol(arg, &tmp_str, 10); if(tmp_str==arg || *tmp_str) /* not a number */ return "Illegal number of bytes to read from random seed files"; } return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: s_log(LOG_NOTICE, "%-22s = %d", "RNDbytes", RANDOM_BYTES); break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = bytes to read from random seed files", "RNDbytes"); break; } /* RNDfile */ switch(cmd) { case CMD_BEGIN: new_global_options.rand_file=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "RNDfile")) break; new_global_options.rand_file=str_dup(arg); return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: #ifdef RANDOM_FILE s_log(LOG_NOTICE, "%-22s = %s", "RNDfile", RANDOM_FILE); #endif break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = path to file with random seed data", "RNDfile"); break; } /* RNDoverwrite */ switch(cmd) { case CMD_BEGIN: new_global_options.option.rand_write=1; break; case CMD_EXEC: if(strcasecmp(opt, "RNDoverwrite")) break; if(!strcasecmp(arg, "yes")) new_global_options.option.rand_write=1; else if(!strcasecmp(arg, "no")) new_global_options.option.rand_write=0; else return "The argument needs to be either 'yes' or 'no'"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: s_log(LOG_NOTICE, "%-22s = yes", "RNDoverwrite"); break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = yes|no overwrite seed datafiles with new random data", "RNDoverwrite"); break; } #ifndef USE_WIN32 /* service */ switch(cmd) { case CMD_BEGIN: new_service_options.servname=str_dup("stunnel"); break; case CMD_EXEC: if(strcasecmp(opt, "service")) break; new_service_options.servname=str_dup(arg); return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = service name", "service"); break; } #endif /* socket */ switch(cmd) { case CMD_BEGIN: break; case CMD_EXEC: if(strcasecmp(opt, "socket")) break; if(parse_socket_option(arg)) return "Illegal socket option"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = a|l|r:option=value[:value]", "socket"); s_log(LOG_NOTICE, "%25sset an option on accept/local/remote socket", ""); break; } /* syslog */ #ifndef USE_WIN32 switch(cmd) { case CMD_BEGIN: new_global_options.option.log_syslog=1; break; case CMD_EXEC: if(strcasecmp(opt, "syslog")) break; if(!strcasecmp(arg, "yes")) new_global_options.option.log_syslog=1; else if(!strcasecmp(arg, "no")) new_global_options.option.log_syslog=0; else return "The argument needs to be either 'yes' or 'no'"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = yes|no send logging messages to syslog", "syslog"); break; } #endif /* taskbar */ #ifdef USE_WIN32 switch(cmd) { case CMD_BEGIN: new_global_options.option.taskbar=1; break; case CMD_EXEC: if(strcasecmp(opt, "taskbar")) break; if(!strcasecmp(arg, "yes")) new_global_options.option.taskbar=1; else if(!strcasecmp(arg, "no")) new_global_options.option.taskbar=0; else return "The argument needs to be either 'yes' or 'no'"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: s_log(LOG_NOTICE, "%-22s = yes", "taskbar"); break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = yes|no enable the taskbar icon", "taskbar"); break; } #endif if(cmd==CMD_EXEC) return option_not_found; if(cmd==CMD_END) { /* FIPS needs to be initialized as early as possible */ if(ssl_configure(&new_global_options)) /* configure global SSL settings */ return "Failed to initialize SSL"; } return NULL; /* OK */ } /**************************************** service-level options */ NOEXPORT char *parse_service_option(CMD cmd, SERVICE_OPTIONS *section, char *opt, char *arg) { int endpoints=0; #ifndef USE_WIN32 struct group *gr; struct passwd *pw; #endif if(cmd==CMD_DEFAULT || cmd==CMD_HELP) { s_log(LOG_NOTICE, " "); s_log(LOG_NOTICE, "Service-level options:"); } /* accept */ switch(cmd) { case CMD_BEGIN: section->option.accept=0; memset(§ion->local_addr, 0, sizeof(SOCKADDR_UNION)); section->local_addr.in.sin_family=AF_INET; section->fd=INVALID_SOCKET; break; case CMD_EXEC: if(strcasecmp(opt, "accept")) break; section->option.accept=1; if(!name2addr(§ion->local_addr, arg, 1)) return "Failed to resolve accepting address"; return NULL; /* OK */ case CMD_END: if(section->option.accept) ++endpoints; break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = [host:]port accept connections on specified host:port", "accept"); break; } /* CApath */ switch(cmd) { case CMD_BEGIN: #if 0 section->ca_dir=(char *)X509_get_default_cert_dir(); #endif section->ca_dir=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "CApath")) break; if(arg[0]) /* not empty */ section->ca_dir=str_dup(arg); else section->ca_dir=NULL; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: #if 0 s_log(LOG_NOTICE, "%-22s = %s", "CApath", section->ca_dir ? section->ca_dir : "(none)"); #endif break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = CA certificate directory for 'verify' option", "CApath"); break; } /* CAfile */ switch(cmd) { case CMD_BEGIN: #if 0 section->ca_file=(char *)X509_get_default_certfile(); #endif section->ca_file=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "CAfile")) break; if(arg[0]) /* not empty */ section->ca_file=str_dup(arg); else section->ca_file=NULL; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: #if 0 s_log(LOG_NOTICE, "%-22s = %s", "CAfile", section->ca_file ? section->ca_file : "(none)"); #endif break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = CA certificate file for 'verify' option", "CAfile"); break; } /* cert */ switch(cmd) { case CMD_BEGIN: section->cert=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "cert")) break; section->cert=str_dup(arg); return NULL; /* OK */ case CMD_END: #ifndef OPENSSL_NO_PSK if(section->psk_keys) break; #endif /* !defined(OPENSSL_NO_PSK) */ #ifndef OPENSSL_NO_ENGINE if(section->engine) break; #endif /* !defined(OPENSSL_NO_ENGINE) */ if(!section->option.client && !section->cert) return "SSL server needs a certificate"; break; case CMD_FREE: break; case CMD_DEFAULT: break; /* no default certificate */ case CMD_HELP: s_log(LOG_NOTICE, "%-22s = certificate chain", "cert"); break; } #if OPENSSL_VERSION_NUMBER>=0x10002000L /* checkEmail */ switch(cmd) { case CMD_BEGIN: section->check_email=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "checkEmail")) break; name_list_append(§ion->check_email, arg); return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = peer certificate email address", "checkEmail"); break; } /* checkHost */ switch(cmd) { case CMD_BEGIN: section->check_host=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "checkHost")) break; name_list_append(§ion->check_host, arg); return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = peer certificate host name pattern", "checkHost"); break; } /* checkIP */ switch(cmd) { case CMD_BEGIN: section->check_ip=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "checkIP")) break; name_list_append(§ion->check_ip, arg); return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = peer certificate IP address", "checkIP"); break; } #endif /* OPENSSL_VERSION_NUMBER>=0x10002000L */ /* ciphers */ switch(cmd) { case CMD_BEGIN: section->cipher_list=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "ciphers")) break; section->cipher_list=str_dup(arg); return NULL; /* OK */ case CMD_END: #ifdef USE_FIPS if(new_global_options.option.fips) { if(!new_service_options.cipher_list) new_service_options.cipher_list="FIPS"; } else #endif /* USE_FIPS */ { if(!new_service_options.cipher_list) new_service_options.cipher_list=stunnel_cipher_list; } break; case CMD_FREE: break; case CMD_DEFAULT: #ifdef USE_FIPS s_log(LOG_NOTICE, "%-22s = %s %s", "ciphers", "FIPS", "(with \"fips = yes\")"); s_log(LOG_NOTICE, "%-22s = %s %s", "ciphers", stunnel_cipher_list, "(with \"fips = no\")"); #else s_log(LOG_NOTICE, "%-22s = %s", "ciphers", stunnel_cipher_list); #endif /* USE_FIPS */ break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = list of permitted SSL ciphers", "ciphers"); break; } /* client */ switch(cmd) { case CMD_BEGIN: section->option.client=0; break; case CMD_EXEC: if(strcasecmp(opt, "client")) break; if(!strcasecmp(arg, "yes")) section->option.client=1; else if(!strcasecmp(arg, "no")) section->option.client=0; else return "The argument needs to be either 'yes' or 'no'"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = yes|no client mode (remote service uses SSL)", "client"); break; } #if OPENSSL_VERSION_NUMBER>=0x10002000L /* config */ switch(cmd) { case CMD_BEGIN: section->config=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "config")) break; name_list_append(§ion->config, arg); return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = command[:parameter] to execute", "config"); break; } #endif /* OPENSSL_VERSION_NUMBER>=0x10002000L */ /* connect */ switch(cmd) { case CMD_BEGIN: addrlist_clear(§ion->connect_addr, 0); break; case CMD_EXEC: if(strcasecmp(opt, "connect")) break; name_list_append(§ion->connect_addr.names, arg); return NULL; /* OK */ case CMD_END: if(section->connect_addr.names) { if(!section->option.delayed_lookup && !addrlist_resolve(§ion->connect_addr)) { s_log(LOG_INFO, "Cannot resolve connect target - delaying DNS lookup"); section->redirect_addr.num=0; str_free(section->redirect_addr.names); section->redirect_addr.names=NULL; section->option.delayed_lookup=1; } ++endpoints; } break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = [host:]port to connect", "connect"); break; } /* CRLpath */ switch(cmd) { case CMD_BEGIN: section->crl_dir=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "CRLpath")) break; if(arg[0]) /* not empty */ section->crl_dir=str_dup(arg); else section->crl_dir=NULL; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = CRL directory", "CRLpath"); break; } /* CRLfile */ switch(cmd) { case CMD_BEGIN: section->crl_file=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "CRLfile")) break; if(arg[0]) /* not empty */ section->crl_file=str_dup(arg); else section->crl_file=NULL; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = CRL file", "CRLfile"); break; } #ifndef OPENSSL_NO_ECDH /* curve */ #define DEFAULT_CURVE NID_X9_62_prime256v1 switch(cmd) { case CMD_BEGIN: section->curve=DEFAULT_CURVE; break; case CMD_EXEC: if(strcasecmp(opt, "curve")) break; section->curve=OBJ_txt2nid(arg); if(section->curve==NID_undef) return "Curve name not supported"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: s_log(LOG_NOTICE, "%-22s = %s", "curve", OBJ_nid2ln(DEFAULT_CURVE)); break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = ECDH curve name", "curve"); break; } #endif /* !defined(OPENSSL_NO_ECDH) */ /* debug */ switch(cmd) { case CMD_BEGIN: new_service_options.log_level=LOG_NOTICE; break; case CMD_EXEC: if(strcasecmp(opt, "debug")) break; return parse_debug_level(arg, section); case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: s_log(LOG_NOTICE, "%-22s = %s", "debug", "notice"); break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = level (e.g. info)", "debug"); break; } /* delay */ switch(cmd) { case CMD_BEGIN: section->option.delayed_lookup=0; break; case CMD_EXEC: if(strcasecmp(opt, "delay")) break; if(!strcasecmp(arg, "yes")) section->option.delayed_lookup=1; else if(!strcasecmp(arg, "no")) section->option.delayed_lookup=0; else return "The argument needs to be either 'yes' or 'no'"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = yes|no delay DNS lookup for 'connect' option", "delay"); break; } #ifndef OPENSSL_NO_ENGINE /* engineId */ switch(cmd) { case CMD_BEGIN: break; case CMD_EXEC: if(strcasecmp(opt, "engineId")) break; section->engine=engine_get_by_id(arg); if(!section->engine) return "Engine ID not found"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = ID of engine to read the key from", "engineId"); break; } /* engineNum */ switch(cmd) { case CMD_BEGIN: break; case CMD_EXEC: if(strcasecmp(opt, "engineNum")) break; { char *tmp_str; int tmp_int=(int)strtol(arg, &tmp_str, 10); if(tmp_str==arg || *tmp_str) /* not a number */ return "Illegal engine number"; section->engine=engine_get_by_num(tmp_int-1); } if(!section->engine) return "Illegal engine number"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = number of engine to read the key from", "engineNum"); break; } #endif /* !defined(OPENSSL_NO_ENGINE) */ /* exec */ switch(cmd) { case CMD_BEGIN: section->exec_name=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "exec")) break; section->exec_name=str_dup(arg); #ifdef USE_WIN32 section->exec_args=str_dup(arg); #else if(!section->exec_args) { section->exec_args=str_alloc(2*sizeof(char *)); section->exec_args[0]=section->exec_name; section->exec_args[1]=NULL; /* to show that it's null-terminated */ } #endif return NULL; /* OK */ case CMD_END: if(section->exec_name) ++endpoints; break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = file execute local inetd-type program", "exec"); break; } /* execArgs */ switch(cmd) { case CMD_BEGIN: section->exec_args=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "execArgs")) break; #ifdef USE_WIN32 section->exec_args=str_dup(arg); #else section->exec_args=argalloc(arg); #endif return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = arguments for 'exec' (including $0)", "execArgs"); break; } /* failover */ switch(cmd) { case CMD_BEGIN: section->failover=FAILOVER_RR; break; case CMD_EXEC: if(strcasecmp(opt, "failover")) break; if(!strcasecmp(arg, "rr")) section->failover=FAILOVER_RR; else if(!strcasecmp(arg, "prio")) section->failover=FAILOVER_PRIO; else return "The argument needs to be either 'rr' or 'prio'"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = rr|prio failover strategy", "failover"); break; } /* ident */ switch(cmd) { case CMD_BEGIN: section->username=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "ident")) break; section->username=str_dup(arg); return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = username for IDENT (RFC 1413) checking", "ident"); break; } /* key */ switch(cmd) { case CMD_BEGIN: section->key=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "key")) break; section->key=str_dup(arg); return NULL; /* OK */ case CMD_END: if(section->cert && !section->key) section->key=str_dup(section->cert); break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = certificate private key", "key"); break; } #ifdef USE_LIBWRAP switch(cmd) { case CMD_BEGIN: section->option.libwrap=0; /* disable libwrap by default */ break; case CMD_EXEC: if(strcasecmp(opt, "libwrap")) break; if(!strcasecmp(arg, "yes")) section->option.libwrap=1; else if(!strcasecmp(arg, "no")) section->option.libwrap=0; else return "The argument needs to be either 'yes' or 'no'"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = yes|no use /etc/hosts.allow and /etc/hosts.deny", "libwrap"); break; } #endif /* USE_LIBWRAP */ /* local */ switch(cmd) { case CMD_BEGIN: section->option.local=0; break; case CMD_EXEC: if(strcasecmp(opt, "local")) break; if(!hostport2addr(§ion->source_addr, arg, "0", 1)) return "Failed to resolve local address"; section->option.local=1; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = IP address to be used as source for remote" " connections", "local"); break; } /* logId */ switch(cmd) { case CMD_BEGIN: section->log_id=LOG_ID_SEQUENTIAL; break; case CMD_EXEC: if(strcasecmp(opt, "logId")) break; if(!strcasecmp(arg, "sequential")) section->log_id=LOG_ID_SEQUENTIAL; else if(!strcasecmp(arg, "unique")) section->log_id=LOG_ID_UNIQUE; else if(!strcasecmp(arg, "thread")) section->log_id=LOG_ID_THREAD; else return "Invalid connection identifier type"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: s_log(LOG_NOTICE, "%-22s = %s", "logId", "sequential"); break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = connection identifier type", "logId"); break; } #ifndef OPENSSL_NO_OCSP /* OCSP */ switch(cmd) { case CMD_BEGIN: section->ocsp_url=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "ocsp")) break; section->ocsp_url=str_dup(arg); return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = OCSP responder URL", "ocsp"); break; } /* OCSPaia */ switch(cmd) { case CMD_BEGIN: section->option.aia=0; /* disable AIA by default */ break; case CMD_EXEC: if(strcasecmp(opt, "OCSPaia")) break; if(!strcasecmp(arg, "yes")) section->option.aia=1; else if(!strcasecmp(arg, "no")) section->option.aia=0; else return "The argument needs to be either 'yes' or 'no'"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = yes|no check the AIA responders from certificates", "OCSPaia"); break; } /* OCSPflag */ switch(cmd) { case CMD_BEGIN: section->ocsp_flags=0; break; case CMD_EXEC: if(strcasecmp(opt, "OCSPflag")) break; { unsigned long tmp_ulong=parse_ocsp_flag(arg); if(!tmp_ulong) return "Illegal OCSP flag"; section->ocsp_flags|=tmp_ulong; } return NULL; case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = OCSP responder flags", "OCSPflag"); break; } /* OCSPnonce */ switch(cmd) { case CMD_BEGIN: section->option.nonce=0; /* disable OCSP nonce by default */ break; case CMD_EXEC: if(strcasecmp(opt, "OCSPnonce")) break; if(!strcasecmp(arg, "yes")) section->option.nonce=1; else if(!strcasecmp(arg, "no")) section->option.nonce=0; else return "The argument needs to be either 'yes' or 'no'"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = yes|no send and verify the OCSP nonce extension", "OCSPnonce"); break; } #endif /* !defined(OPENSSL_NO_OCSP) */ /* options */ switch(cmd) { case CMD_BEGIN: section->ssl_options_set|=SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3; #if OPENSSL_VERSION_NUMBER>=0x009080dfL section->ssl_options_clear=0; #endif /* OpenSSL 0.9.8m or later */ break; case CMD_EXEC: if(strcasecmp(opt, "options")) break; #if OPENSSL_VERSION_NUMBER>=0x009080dfL if(*arg=='-') { long unsigned tmp=parse_ssl_option(arg+1); if(!tmp) return "Illegal SSL option"; section->ssl_options_clear|=tmp; return NULL; /* OK */ } #endif /* OpenSSL 0.9.8m or later */ { long unsigned tmp=parse_ssl_option(arg); if(!tmp) return "Illegal SSL option"; section->ssl_options_set|=tmp; } return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: s_log(LOG_NOTICE, "%-22s = %s", "options", "NO_SSLv2"); s_log(LOG_NOTICE, "%-22s = %s", "options", "NO_SSLv3"); break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = SSL option to set/reset", "options"); break; } /* protocol */ switch(cmd) { case CMD_BEGIN: section->protocol=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "protocol")) break; section->protocol=str_dup(arg); return NULL; /* OK */ case CMD_END: /* PROTOCOL_CHECK also initializes: section->option.connect_before_ssl section->option.protocol_endpoint */ { char *tmp_str=protocol(NULL, section, PROTOCOL_CHECK); if(tmp_str) return tmp_str; } endpoints+=section->option.protocol_endpoint; #ifdef SSL_OP_NO_TICKET /* disable RFC4507 support introduced in OpenSSL 0.9.8f */ /* session tickets do not support SSL_SESSION_*_ex_data() */ if(!section->option.connect_before_ssl) /* address cache can be used */ section->ssl_options_set|=SSL_OP_NO_TICKET; #endif break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = protocol to negotiate before SSL initialization", "protocol"); s_log(LOG_NOTICE, "%25scurrently supported: cifs, connect, imap,", ""); s_log(LOG_NOTICE, "%25s nntp, pgsql, pop3, proxy, smtp", ""); break; } /* protocolAuthentication */ switch(cmd) { case CMD_BEGIN: section->protocol_authentication="basic"; break; case CMD_EXEC: if(strcasecmp(opt, "protocolAuthentication")) break; section->protocol_authentication=str_dup(arg); return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = authentication type for protocol negotiations", "protocolAuthentication"); break; } /* protocolDomain */ switch(cmd) { case CMD_BEGIN: section->protocol_domain=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "protocolDomain")) break; section->protocol_domain=str_dup(arg); return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = domain for protocol negotiations", "protocolDomain"); break; } /* protocolHost */ switch(cmd) { case CMD_BEGIN: section->protocol_host=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "protocolHost")) break; section->protocol_host=str_dup(arg); return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = host:port for protocol negotiations", "protocolHost"); break; } /* protocolPassword */ switch(cmd) { case CMD_BEGIN: section->protocol_password=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "protocolPassword")) break; section->protocol_password=str_dup(arg); return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = password for protocol negotiations", "protocolPassword"); break; } /* protocolUsername */ switch(cmd) { case CMD_BEGIN: section->protocol_username=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "protocolUsername")) break; section->protocol_username=str_dup(arg); return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = username for protocol negotiations", "protocolUsername"); break; } #ifndef OPENSSL_NO_PSK /* PSKidentity */ switch(cmd) { case CMD_BEGIN: section->psk_identity=NULL; section->psk_selected=NULL; section->psk_sorted.val=NULL; section->psk_sorted.num=0; break; case CMD_EXEC: if(strcasecmp(opt, "PSKidentity")) break; section->psk_identity=str_dup(arg); return NULL; /* OK */ case CMD_END: if(!section->psk_keys) /* PSK not configured */ break; psk_sort(§ion->psk_sorted, section->psk_keys); if(section->option.client) { if(section->psk_identity) { section->psk_selected= psk_find(§ion->psk_sorted, section->psk_identity); if(!section->psk_selected) return "No key found for the specified PSK identity"; } else { /* take the first specified identity as default */ section->psk_selected=section->psk_keys; } } else { if(section->psk_identity) s_log(LOG_NOTICE, "PSK identity is ignored in the server mode"); } break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = identity for PSK authentication", "PSKidentity"); break; } /* PSKsecrets */ switch(cmd) { case CMD_BEGIN: section->psk_keys=NULL; break; case CMD_EXEC: if(strcasecmp(opt, "PSKsecrets")) break; section->psk_keys=psk_read(arg); if(!section->psk_keys) return "Failed to read PSK secrets"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: psk_free(section->psk_keys); break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = secrets for PSK authentication", "PSKsecrets"); break; } #endif /* !defined(OPENSSL_NO_PSK) */ /* pty */ #ifndef USE_WIN32 switch(cmd) { case CMD_BEGIN: section->option.pty=0; break; case CMD_EXEC: if(strcasecmp(opt, "pty")) break; if(!strcasecmp(arg, "yes")) section->option.pty=1; else if(!strcasecmp(arg, "no")) section->option.pty=0; else return "The argument needs to be either 'yes' or 'no'"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = yes|no allocate pseudo terminal for 'exec' option", "pty"); break; } #endif /* redirect */ switch(cmd) { case CMD_BEGIN: addrlist_clear(§ion->redirect_addr, 0); break; case CMD_EXEC: if(strcasecmp(opt, "redirect")) break; #ifdef SSL_OP_NO_TICKET /* disable RFC4507 support introduced in OpenSSL 0.9.8f */ /* session tickets do not support SSL_SESSION_*_ex_data() */ section->ssl_options_set|=SSL_OP_NO_TICKET; #endif name_list_append(§ion->redirect_addr.names, arg); return NULL; /* OK */ case CMD_END: if(section->redirect_addr.names) { if(!section->option.delayed_lookup && !addrlist_resolve(§ion->redirect_addr)) { s_log(LOG_INFO, "Cannot resolve redirect target - delaying DNS lookup"); section->connect_addr.num=0; str_free(section->connect_addr.names); section->connect_addr.names=NULL; section->option.delayed_lookup=1; } if(section->verify_level<1) return "\"verify\" needs to be 1 or higher for \"redirect\" to work"; } break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = [host:]port to redirect on authentication failures", "redirect"); break; } /* renegotiation */ switch(cmd) { case CMD_BEGIN: section->option.renegotiation=1; break; case CMD_EXEC: if(strcasecmp(opt, "renegotiation")) break; if(!strcasecmp(arg, "yes")) section->option.renegotiation=1; else if(!strcasecmp(arg, "no")) section->option.renegotiation=0; else return "The argument needs to be either 'yes' or 'no'"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = yes|no support renegotiation", "renegotiation"); break; } /* reset */ switch(cmd) { case CMD_BEGIN: section->option.reset=1; /* enabled by default */ break; case CMD_EXEC: if(strcasecmp(opt, "reset")) break; if(!strcasecmp(arg, "yes")) section->option.reset=1; else if(!strcasecmp(arg, "no")) section->option.reset=0; else return "The argument needs to be either 'yes' or 'no'"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = yes|no send TCP RST on error", "retry"); break; } /* retry */ switch(cmd) { case CMD_BEGIN: section->option.retry=0; break; case CMD_EXEC: if(strcasecmp(opt, "retry")) break; if(!strcasecmp(arg, "yes")) section->option.retry=1; else if(!strcasecmp(arg, "no")) section->option.retry=0; else return "The argument needs to be either 'yes' or 'no'"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = yes|no retry connect+exec section", "retry"); break; } #ifndef USE_WIN32 /* setgid */ switch(cmd) { case CMD_BEGIN: section->gid=0; break; case CMD_EXEC: if(strcasecmp(opt, "setgid")) break; gr=getgrnam(arg); if(gr) { section->gid=gr->gr_gid; return NULL; /* OK */ } { char *tmp_str; section->gid=(gid_t)strtol(arg, &tmp_str, 10); if(tmp_str==arg || *tmp_str) /* not a number */ return "Illegal GID"; } return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = groupname for setgid()", "setgid"); break; } #endif #ifndef USE_WIN32 /* setuid */ switch(cmd) { case CMD_BEGIN: section->uid=0; break; case CMD_EXEC: if(strcasecmp(opt, "setuid")) break; pw=getpwnam(arg); if(pw) { section->uid=pw->pw_uid; return NULL; /* OK */ } { char *tmp_str; section->uid=(uid_t)strtol(arg, &tmp_str, 10); if(tmp_str==arg || *tmp_str) /* not a number */ return "Illegal UID"; } return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = username for setuid()", "setuid"); break; } #endif /* sessionCacheSize */ switch(cmd) { case CMD_BEGIN: section->session_size=1000L; break; case CMD_EXEC: if(strcasecmp(opt, "sessionCacheSize")) break; { char *tmp_str; section->session_size=strtol(arg, &tmp_str, 10); if(tmp_str==arg || *tmp_str) /* not a number */ return "Illegal session cache size"; } return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: s_log(LOG_NOTICE, "%-22s = %ld", "sessionCacheSize", 1000L); break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = session cache size", "sessionCacheSize"); break; } /* sessionCacheTimeout */ switch(cmd) { case CMD_BEGIN: section->session_timeout=300L; break; case CMD_EXEC: if(strcasecmp(opt, "sessionCacheTimeout") && strcasecmp(opt, "session")) break; { char *tmp_str; section->session_timeout=strtol(arg, &tmp_str, 10); if(tmp_str==arg || *tmp_str) /* not a number */ return "Illegal session cache timeout"; } return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: s_log(LOG_NOTICE, "%-22s = %ld seconds", "sessionCacheTimeout", 300L); break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = session cache timeout (in seconds)", "sessionCacheTimeout"); break; } /* sessiond */ switch(cmd) { case CMD_BEGIN: section->option.sessiond=0; memset(§ion->sessiond_addr, 0, sizeof(SOCKADDR_UNION)); section->sessiond_addr.in.sin_family=AF_INET; break; case CMD_EXEC: if(strcasecmp(opt, "sessiond")) break; section->option.sessiond=1; #ifdef SSL_OP_NO_TICKET /* disable RFC4507 support introduced in OpenSSL 0.9.8f */ /* this prevents session callbacks from being executed */ section->ssl_options_set|=SSL_OP_NO_TICKET; #endif if(!name2addr(§ion->sessiond_addr, arg, 0)) return "Failed to resolve sessiond server address"; return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = [host:]port use sessiond at host:port", "sessiond"); break; } #ifndef OPENSSL_NO_TLSEXT /* sni */ switch(cmd) { case CMD_BEGIN: section->servername_list_head=NULL; section->servername_list_tail=NULL; section->option.sni=0; break; case CMD_EXEC: if(strcasecmp(opt, "sni")) break; section->sni=str_dup(arg); return NULL; /* OK */ case CMD_END: { char *tmp_str=sni_init(section); if(tmp_str) return tmp_str; } if(section->option.sni) ++endpoints; break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = master_service:host_name for an SNI virtual service", "sni"); break; } #endif /* !defined(OPENSSL_NO_TLSEXT) */ /* sslVersion */ switch(cmd) { case CMD_BEGIN: #if OPENSSL_VERSION_NUMBER>=0x10100000L section->client_method=(SSL_METHOD *)TLS_client_method(); section->server_method=(SSL_METHOD *)TLS_server_method(); #else section->client_method=(SSL_METHOD *)SSLv23_client_method(); section->server_method=(SSL_METHOD *)SSLv23_server_method(); #endif break; case CMD_EXEC: if(strcasecmp(opt, "sslVersion")) break; if(!strcasecmp(arg, "all")) { #if OPENSSL_VERSION_NUMBER>=0x10100000L section->client_method=(SSL_METHOD *)TLS_client_method(); section->server_method=(SSL_METHOD *)TLS_server_method(); #else section->client_method=(SSL_METHOD *)SSLv23_client_method(); section->server_method=(SSL_METHOD *)SSLv23_server_method(); #endif } else if(!strcasecmp(arg, "SSLv2")) { #ifndef OPENSSL_NO_SSL2 section->client_method=(SSL_METHOD *)SSLv2_client_method(); section->server_method=(SSL_METHOD *)SSLv2_server_method(); #else /* defined(OPENSSL_NO_SSL2) */ return "SSLv2 not supported"; #endif /* !defined(OPENSSL_NO_SSL2) */ } else if(!strcasecmp(arg, "SSLv3")) { #ifndef OPENSSL_NO_SSL3 section->client_method=(SSL_METHOD *)SSLv3_client_method(); section->server_method=(SSL_METHOD *)SSLv3_server_method(); #else /* defined(OPENSSL_NO_SSL3) */ return "SSLv3 not supported"; #endif /* !defined(OPENSSL_NO_SSL3) */ } else if(!strcasecmp(arg, "TLSv1")) { #ifndef OPENSSL_NO_TLS1 section->client_method=(SSL_METHOD *)TLSv1_client_method(); section->server_method=(SSL_METHOD *)TLSv1_server_method(); #else /* defined(OPENSSL_NO_TLS1) */ return "TLSv1 not supported"; #endif /* !defined(OPENSSL_NO_TLS1) */ } else if(!strcasecmp(arg, "TLSv1.1")) { #ifndef OPENSSL_NO_TLS1_1 section->client_method=(SSL_METHOD *)TLSv1_1_client_method(); section->server_method=(SSL_METHOD *)TLSv1_1_server_method(); #else /* defined(OPENSSL_NO_TLS1_1) */ return "TLSv1.1 not supported"; #endif /* !defined(OPENSSL_NO_TLS1_1) */ } else if(!strcasecmp(arg, "TLSv1.2")) { #ifndef OPENSSL_NO_TLS1_2 section->client_method=(SSL_METHOD *)TLSv1_2_client_method(); section->server_method=(SSL_METHOD *)TLSv1_2_server_method(); #else /* defined(OPENSSL_NO_TLS1_2) */ return "TLSv1.2 not supported"; #endif /* !defined(OPENSSL_NO_TLS1_2) */ } else return "Incorrect version of SSL protocol"; return NULL; /* OK */ case CMD_END: #ifdef USE_FIPS if(new_global_options.option.fips) { #ifndef OPENSSL_NO_SSL2 if(section->option.client ? section->client_method==(SSL_METHOD *)SSLv2_client_method() : section->server_method==(SSL_METHOD *)SSLv2_server_method()) return "\"sslVersion = SSLv2\" not supported in FIPS mode"; #endif /* !defined(OPENSSL_NO_SSL2) */ #ifndef OPENSSL_NO_SSL3 if(section->option.client ? section->client_method==(SSL_METHOD *)SSLv3_client_method() : section->server_method==(SSL_METHOD *)SSLv3_server_method()) return "\"sslVersion = SSLv3\" not supported in FIPS mode"; #endif /* !defined(OPENSSL_NO_SSL3) */ } #endif /* USE_FIPS */ break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = all|SSLv2|SSLv3|TLSv1" #if OPENSSL_VERSION_NUMBER>=0x10001000L "|TLSv1.1|TLSv1.2" #endif " SSL method", "sslVersion"); break; } #ifndef USE_FORK /* stack */ switch(cmd) { case CMD_BEGIN: section->stack_size=DEFAULT_STACK_SIZE; break; case CMD_EXEC: if(strcasecmp(opt, "stack")) break; { char *tmp_str; section->stack_size=(size_t)strtol(arg, &tmp_str, 10); if(tmp_str==arg || *tmp_str) /* not a number */ return "Illegal thread stack size"; } return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: s_log(LOG_NOTICE, "%-22s = %d bytes", "stack", DEFAULT_STACK_SIZE); break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = thread stack size (in bytes)", "stack"); break; } #endif /* TIMEOUTbusy */ switch(cmd) { case CMD_BEGIN: section->timeout_busy=300; /* 5 minutes */ break; case CMD_EXEC: if(strcasecmp(opt, "TIMEOUTbusy")) break; { char *tmp_str; section->timeout_busy=(int)strtol(arg, &tmp_str, 10); if(tmp_str==arg || *tmp_str) /* not a number */ return "Illegal busy timeout"; } return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: s_log(LOG_NOTICE, "%-22s = %d seconds", "TIMEOUTbusy", 300); break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = seconds to wait for expected data", "TIMEOUTbusy"); break; } /* TIMEOUTclose */ switch(cmd) { case CMD_BEGIN: section->timeout_close=60; /* 1 minute */ break; case CMD_EXEC: if(strcasecmp(opt, "TIMEOUTclose")) break; { char *tmp_str; section->timeout_close=(int)strtol(arg, &tmp_str, 10); if(tmp_str==arg || *tmp_str) /* not a number */ return "Illegal close timeout"; } return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: s_log(LOG_NOTICE, "%-22s = %d seconds", "TIMEOUTclose", 60); break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = seconds to wait for close_notify", "TIMEOUTclose"); break; } /* TIMEOUTconnect */ switch(cmd) { case CMD_BEGIN: section->timeout_connect=10; /* 10 seconds */ break; case CMD_EXEC: if(strcasecmp(opt, "TIMEOUTconnect")) break; { char *tmp_str; section->timeout_connect=(int)strtol(arg, &tmp_str, 10); if(tmp_str==arg || *tmp_str) /* not a number */ return "Illegal connect timeout"; } return NULL; /* OK */ case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: s_log(LOG_NOTICE, "%-22s = %d seconds", "TIMEOUTconnect", 10); break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = seconds to connect remote host", "TIMEOUTconnect"); break; } /* TIMEOUTidle */ switch(cmd) { case CMD_BEGIN: section->timeout_idle=43200; /* 12 hours */ break; case CMD_EXEC: if(strcasecmp(opt, "TIMEOUTidle")) break; { char *tmp_str; section->timeout_idle=(int)strtol(arg, &tmp_str, 10); if(tmp_str==arg || *tmp_str) /* not a number */ return "Illegal idle timeout"; return NULL; /* OK */ } case CMD_END: break; case CMD_FREE: break; case CMD_DEFAULT: s_log(LOG_NOTICE, "%-22s = %d seconds", "TIMEOUTidle", 43200); break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = seconds to keep an idle connection", "TIMEOUTidle"); break; } /* transparent */ #ifndef USE_WIN32 switch(cmd) { case CMD_BEGIN: section->option.transparent_src=0; section->option.transparent_dst=0; break; case CMD_EXEC: if(strcasecmp(opt, "transparent")) break; if(!strcasecmp(arg, "none") || !strcasecmp(arg, "no")) { section->option.transparent_src=0; section->option.transparent_dst=0; } else if(!strcasecmp(arg, "source") || !strcasecmp(arg, "yes")) { section->option.transparent_src=1; section->option.transparent_dst=0; } else if(!strcasecmp(arg, "destination")) { section->option.transparent_src=0; section->option.transparent_dst=1; } else if(!strcasecmp(arg, "both")) { section->option.transparent_src=1; section->option.transparent_dst=1; } else return "Selected transparent proxy mode is not available"; return NULL; /* OK */ case CMD_END: if(section->option.transparent_dst) ++endpoints; break; case CMD_FREE: break; case CMD_DEFAULT: break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = none|source|destination|both transparent proxy mode", "transparent"); break; } #endif /* verify */ switch(cmd) { case CMD_BEGIN: section->verify_level=-1; /* do not even request a certificate */ break; case CMD_EXEC: if(strcasecmp(opt, "verify")) break; { char *tmp_str; section->verify_level=(int)strtol(arg, &tmp_str, 10); if(tmp_str==arg || *tmp_str) /* not a number */ return "Bad verify level"; } if(section->verify_level<0 || section->verify_level>4) return "Bad verify level"; return NULL; /* OK */ case CMD_END: if(section->verify_level>0 && !section->ca_file && !section->ca_dir) return "Either \"CAfile\" or \"CApath\" has to be configured"; break; case CMD_FREE: break; case CMD_DEFAULT: s_log(LOG_NOTICE, "%-22s = none", "verify"); break; case CMD_HELP: s_log(LOG_NOTICE, "%-22s = level of peer certificate verification", "verify"); s_log(LOG_NOTICE, "%25slevel 0 - request and ignore peer cert", ""); s_log(LOG_NOTICE, "%25slevel 1 - only validate peer cert if present", ""); s_log(LOG_NOTICE, "%25slevel 2 - always require a valid peer cert", ""); s_log(LOG_NOTICE, "%25slevel 3 - verify peer with locally installed cert", ""); s_log(LOG_NOTICE, "%25slevel 4 - ignore CA chain and only verify peer cert", ""); break; } /* final checks */ switch(cmd) { case CMD_BEGIN: break; case CMD_EXEC: return option_not_found; case CMD_END: if(new_service_options.next) { /* daemon mode checks */ if(endpoints!=2) return "Each service must define two endpoints"; } else { /* inetd mode checks */ if(section->option.accept) return "'accept' option is only allowed in a [section]"; /* no need to check for section->option.sni in inetd mode, as it requires valid sections to be set */ if(endpoints!=1) return "Inetd mode must define one endpoint"; } if(context_init(section)) /* initialize SSL context */ return "Failed to initialize SSL context"; case CMD_FREE: case CMD_DEFAULT: case CMD_HELP: break; } return NULL; /* OK */ } /**************************************** validate and initialize configuration */ #ifndef OPENSSL_NO_TLSEXT NOEXPORT char *sni_init(SERVICE_OPTIONS *section) { char *tmp_str; SERVICE_OPTIONS *tmpsrv; /* server mode: update servername_list based on the SNI option */ if(!section->option.client && section->sni) { tmp_str=strchr(section->sni, ':'); if(!tmp_str) return "Invalid SNI parameter format"; *tmp_str++='\0'; for(tmpsrv=new_service_options.next; tmpsrv; tmpsrv=tmpsrv->next) if(!strcmp(tmpsrv->servname, section->sni)) break; if(!tmpsrv) return "SNI section name not found"; if(tmpsrv->option.client) return "SNI master service is a TLS client"; if(tmpsrv->servername_list_tail) { tmpsrv->servername_list_tail->next=str_alloc(sizeof(SERVERNAME_LIST)); tmpsrv->servername_list_tail=tmpsrv->servername_list_tail->next; } else { /* first virtual service */ tmpsrv->servername_list_head= tmpsrv->servername_list_tail= str_alloc(sizeof(SERVERNAME_LIST)); tmpsrv->ssl_options_set|= SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION; } tmpsrv->servername_list_tail->servername=str_dup(tmp_str); tmpsrv->servername_list_tail->opt=section; tmpsrv->servername_list_tail->next=NULL; section->option.sni=1; /* always negotiate a new session on renegotiation, as the SSL * context settings (including access control) may be different */ section->ssl_options_set|= SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION; } /* client mode: setup SNI default based on 'protocolHost' and 'connect' options */ if(section->option.client && !section->sni) { /* setup host_name for SNI, prefer SNI and protocolHost if specified */ if(section->protocol_host) /* 'protocolHost' option */ section->sni=str_dup(section->protocol_host); else if(section->connect_addr.names) /* 'connect' option */ section->sni=str_dup(section->connect_addr.names->name); /* first hostname */ if(section->sni) { /* either 'protocolHost' or 'connect' specified */ tmp_str=strrchr(section->sni, ':'); if(tmp_str) { /* 'host:port' -> drop ':port' */ *tmp_str='\0'; } else { /* 'port' -> default to 'localhost' */ str_free(section->sni); section->sni=str_dup("localhost"); } } } return NULL; } #endif /* !defined(OPENSSL_NO_TLSEXT) */ /**************************************** facility/debug level */ typedef struct { char *name; int value; } facilitylevel; NOEXPORT char *parse_debug_level(char *arg, SERVICE_OPTIONS *section) { char *arg_copy; char *string; facilitylevel *fl; /* facilities only make sense on unix */ #if !defined (USE_WIN32) && !defined (__vms) facilitylevel facilities[] = { {"auth", LOG_AUTH}, {"cron", LOG_CRON}, {"daemon", LOG_DAEMON}, {"kern", LOG_KERN}, {"lpr", LOG_LPR}, {"mail", LOG_MAIL}, {"news", LOG_NEWS}, {"syslog", LOG_SYSLOG}, {"user", LOG_USER}, {"uucp", LOG_UUCP}, {"local0", LOG_LOCAL0}, {"local1", LOG_LOCAL1}, {"local2", LOG_LOCAL2}, {"local3", LOG_LOCAL3}, {"local4", LOG_LOCAL4}, {"local5", LOG_LOCAL5}, {"local6", LOG_LOCAL6}, {"local7", LOG_LOCAL7}, /* some facilities are not defined on all Unices */ #ifdef LOG_AUTHPRIV {"authpriv", LOG_AUTHPRIV}, #endif #ifdef LOG_FTP {"ftp", LOG_FTP}, #endif #ifdef LOG_NTP {"ntp", LOG_NTP}, #endif {NULL, 0} }; #endif /* USE_WIN32, __vms */ facilitylevel levels[] = { {"emerg", LOG_EMERG}, {"alert", LOG_ALERT}, {"crit", LOG_CRIT}, {"err", LOG_ERR}, {"warning", LOG_WARNING}, {"notice", LOG_NOTICE}, {"info", LOG_INFO}, {"debug", LOG_DEBUG}, {NULL, -1} }; arg_copy=str_dup(arg); string=arg_copy; /* facilities only make sense on Unix */ #if !defined (USE_WIN32) && !defined (__vms) if(section==&new_service_options && strchr(string, '.')) { /* a facility was specified in the global options */ new_global_options.log_facility=-1; string=strtok(arg_copy, "."); /* break it up */ for(fl=facilities; fl->name; ++fl) { if(!strcasecmp(fl->name, string)) { new_global_options.log_facility=fl->value; break; } } if(new_global_options.log_facility==-1) return "Illegal syslog facility"; string=strtok(NULL, "."); /* set to the remainder */ } #endif /* USE_WIN32, __vms */ /* time to check the syslog level */ if(string && strlen(string)==1 && *string>='0' && *string<='7') { section->log_level=*string-'0'; return NULL; /* OK */ } section->log_level=8; /* illegal level */ for(fl=levels; fl->name; ++fl) { if(!strcasecmp(fl->name, string)) { section->log_level=fl->value; break; } } if(section->log_level==8) return "Illegal debug level"; /* FAILED */ return NULL; /* OK */ } /**************************************** SSL options */ NOEXPORT long unsigned parse_ssl_option(char *arg) { SSL_OPTION *option; for(option=(SSL_OPTION *)ssl_opts; option->name; ++option) if(!strcasecmp(option->name, arg)) return option->value; return 0; /* FAILED */ } NOEXPORT void print_ssl_options(void) { SSL_OPTION *option; s_log(LOG_NOTICE, " "); s_log(LOG_NOTICE, "Supported SSL options:"); for(option=(SSL_OPTION *)ssl_opts; option->name; ++option) s_log(LOG_NOTICE, "options = %s", option->name); } /**************************************** read PSK file */ #ifndef OPENSSL_NO_PSK NOEXPORT PSK_KEYS *psk_read(char *key_file) { DISK_FILE *df; char line[CONFLINELEN], *key_val; size_t key_len; PSK_KEYS *head=NULL, *tail=NULL, *curr; int line_number=0; if(file_permissions(key_file)) return NULL; df=file_open(key_file, FILE_MODE_READ); if(!df) { s_log(LOG_ERR, "Cannot open PSKsecrets file"); return NULL; } while(file_getline(df, line, CONFLINELEN)>=0) { ++line_number; if(!line[0]) /* empty line */ continue; key_val=strchr(line, ':'); if(!key_val) { s_log(LOG_ERR, "PSKsecrets line %d: Not in identity:key format", line_number); file_close(df); psk_free(head); return NULL; } *key_val++='\0'; key_len=strlen(key_val); if(strlen(line)+1>PSK_MAX_IDENTITY_LEN) { /* with the trailing '\0' */ s_log(LOG_ERR, "PSKsecrets line %d: Identity longer than %d characters", line_number, PSK_MAX_IDENTITY_LEN); file_close(df); psk_free(head); return NULL; } if(key_len>PSK_MAX_PSK_LEN) { s_log(LOG_ERR, "PSKsecrets line %d: Key longer than %d characters", line_number, PSK_MAX_PSK_LEN); file_close(df); psk_free(head); return NULL; } if(key_len<20) { /* shorter keys are unlikely to have sufficient entropy */ s_log(LOG_ERR, "PSKsecrets line %d: Key shorter than 20 characters", line_number); file_close(df); psk_free(head); return NULL; } curr=str_alloc(sizeof(PSK_KEYS)); curr->identity=str_dup(line); curr->key_val=(unsigned char *)str_dup(key_val); curr->key_len=key_len; curr->next=NULL; if(head) tail->next=curr; else head=curr; tail=curr; } file_close(df); return head; } NOEXPORT void psk_free(PSK_KEYS *head) { PSK_KEYS *next; while(head) { next=head->next; str_free(head->identity); str_free(head->key_val); str_free(head); head=next; } } #endif /**************************************** socket options */ static int on=1; #define DEF_ON ((void *)&on) SOCK_OPT sock_opts[] = { {"SO_DEBUG", SOL_SOCKET, SO_DEBUG, TYPE_FLAG, {NULL, NULL, NULL}}, {"SO_DONTROUTE", SOL_SOCKET, SO_DONTROUTE, TYPE_FLAG, {NULL, NULL, NULL}}, {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, TYPE_FLAG, {NULL, NULL, NULL}}, {"SO_LINGER", SOL_SOCKET, SO_LINGER, TYPE_LINGER, {NULL, NULL, NULL}}, {"SO_OOBINLINE", SOL_SOCKET, SO_OOBINLINE, TYPE_FLAG, {NULL, NULL, NULL}}, {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, TYPE_INT, {NULL, NULL, NULL}}, {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, TYPE_INT, {NULL, NULL, NULL}}, #ifdef SO_RCVLOWAT {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, TYPE_INT, {NULL, NULL, NULL}}, #endif #ifdef SO_SNDLOWAT {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, TYPE_INT, {NULL, NULL, NULL}}, #endif #ifdef SO_RCVTIMEO {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, TYPE_TIMEVAL, {NULL, NULL, NULL}}, #endif #ifdef SO_SNDTIMEO {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, TYPE_TIMEVAL, {NULL, NULL, NULL}}, #endif {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, TYPE_FLAG, {DEF_ON, NULL, NULL}}, #ifdef SO_BINDTODEVICE {"SO_BINDTODEVICE", SOL_SOCKET, SO_BINDTODEVICE, TYPE_STRING, {NULL, NULL, NULL}}, #endif #ifdef TCP_KEEPCNT {"TCP_KEEPCNT", SOL_TCP, TCP_KEEPCNT, TYPE_INT, {NULL, NULL, NULL}}, #endif #ifdef TCP_KEEPIDLE {"TCP_KEEPIDLE", SOL_TCP, TCP_KEEPIDLE, TYPE_INT, {NULL, NULL, NULL}}, #endif #ifdef TCP_KEEPINTVL {"TCP_KEEPINTVL", SOL_TCP, TCP_KEEPINTVL, TYPE_INT, {NULL, NULL, NULL}}, #endif #ifdef IP_TOS {"IP_TOS", IPPROTO_IP, IP_TOS, TYPE_INT, {NULL, NULL, NULL}}, #endif #ifdef IP_TTL {"IP_TTL", IPPROTO_IP, IP_TTL, TYPE_INT, {NULL, NULL, NULL}}, #endif #ifdef IP_MAXSEG {"TCP_MAXSEG", IPPROTO_TCP, TCP_MAXSEG, TYPE_INT, {NULL, NULL, NULL}}, #endif {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, TYPE_FLAG, {NULL, DEF_ON, DEF_ON}}, #ifdef IP_FREEBIND {"IP_FREEBIND", IPPROTO_IP, IP_FREEBIND, TYPE_FLAG, {NULL, NULL, NULL}}, #endif #ifdef IP_BINDANY {"IP_BINDANY", IPPROTO_IP, IP_BINDANY, TYPE_FLAG, {NULL, NULL, NULL}}, #endif #ifdef IPV6_BINDANY {"IPV6_BINDANY", IPPROTO_IPV6,IPV6_BINDANY, TYPE_FLAG, {NULL, NULL, NULL}}, #endif {NULL, 0, 0, TYPE_NONE, {NULL, NULL, NULL}} }; NOEXPORT int print_socket_options(void) { SOCKET fd; socklen_t optlen; SOCK_OPT *ptr; OPT_UNION val; char *ta, *tl, *tr, *td; fd=socket(AF_INET, SOCK_STREAM, 0); s_log(LOG_NOTICE, " "); s_log(LOG_NOTICE, "Socket option defaults:"); s_log(LOG_NOTICE, " Option Name | Accept | Local | Remote |OS default"); s_log(LOG_NOTICE, " ----------------+----------+----------+----------+----------"); for(ptr=sock_opts; ptr->opt_str; ++ptr) { /* get OS default value */ optlen=sizeof val; if(getsockopt(fd, ptr->opt_level, ptr->opt_name, (void *)&val, &optlen)) { if(get_last_socket_error()!=S_ENOPROTOOPT) { s_log(LOG_ERR, "Failed to get %s OS default", ptr->opt_str); sockerror("getsockopt"); closesocket(fd); return 1; /* FAILED */ } td=str_dup("write-only"); } else td=print_option(ptr->opt_type, &val); /* get stunnel default values */ ta=print_option(ptr->opt_type, ptr->opt_val[0]); tl=print_option(ptr->opt_type, ptr->opt_val[1]); tr=print_option(ptr->opt_type, ptr->opt_val[2]); /* print collected data and fee the memory */ s_log(LOG_NOTICE, " %-16s|%10s|%10s|%10s|%10s", ptr->opt_str, ta, tl, tr, td); str_free(ta); str_free(tl); str_free(tr); str_free(td); } closesocket(fd); return 0; /* OK */ } NOEXPORT char *print_option(int type, OPT_UNION *val) { if(!val) return str_dup(" -- "); switch(type) { case TYPE_FLAG: return str_printf("%s", val->i_val ? "yes" : "no"); case TYPE_INT: return str_printf("%d", val->i_val); case TYPE_LINGER: return str_printf("%d:%d", val->linger_val.l_onoff, val->linger_val.l_linger); case TYPE_TIMEVAL: return str_printf("%d:%d", (int)val->timeval_val.tv_sec, (int)val->timeval_val.tv_usec); case TYPE_STRING: return str_printf("%s", val->c_val); } return str_dup(" Ooops? "); /* internal error? */ } NOEXPORT int parse_socket_option(char *arg) { int socket_type; /* 0-accept, 1-local, 2-remote */ char *opt_val_str, *opt_val2_str, *tmp_str; SOCK_OPT *ptr; if(arg[1]!=':') return 1; /* FAILED */ switch(arg[0]) { case 'a': socket_type=0; break; case 'l': socket_type=1; break; case 'r': socket_type=2; break; default: return 1; /* FAILED */ } arg+=2; opt_val_str=strchr(arg, '='); if(!opt_val_str) /* no '='? */ return 1; /* FAILED */ *opt_val_str++='\0'; ptr=sock_opts; for(;;) { if(!ptr->opt_str) return 1; /* FAILED */ if(!strcmp(arg, ptr->opt_str)) break; /* option name found */ ++ptr; } ptr->opt_val[socket_type]=str_alloc(sizeof(OPT_UNION)); switch(ptr->opt_type) { case TYPE_FLAG: if(!strcasecmp(opt_val_str, "yes") || !strcmp(opt_val_str, "1")) { ptr->opt_val[socket_type]->i_val=1; return 0; /* OK */ } if(!strcasecmp(opt_val_str, "no") || !strcmp(opt_val_str, "0")) { ptr->opt_val[socket_type]->i_val=0; return 0; /* OK */ } return 1; /* FAILED */ case TYPE_INT: ptr->opt_val[socket_type]->i_val=(int)strtol(opt_val_str, &tmp_str, 10); if(tmp_str==arg || *tmp_str) /* not a number */ return 1; /* FAILED */ return 0; /* OK */ case TYPE_LINGER: opt_val2_str=strchr(opt_val_str, ':'); if(opt_val2_str) { *opt_val2_str++='\0'; ptr->opt_val[socket_type]->linger_val.l_linger= (u_short)strtol(opt_val2_str, &tmp_str, 10); if(tmp_str==arg || *tmp_str) /* not a number */ return 1; /* FAILED */ } else { ptr->opt_val[socket_type]->linger_val.l_linger=0; } ptr->opt_val[socket_type]->linger_val.l_onoff= (u_short)strtol(opt_val_str, &tmp_str, 10); if(tmp_str==arg || *tmp_str) /* not a number */ return 1; /* FAILED */ return 0; /* OK */ case TYPE_TIMEVAL: opt_val2_str=strchr(opt_val_str, ':'); if(opt_val2_str) { *opt_val2_str++='\0'; ptr->opt_val[socket_type]->timeval_val.tv_usec= (int)strtol(opt_val2_str, &tmp_str, 10); if(tmp_str==arg || *tmp_str) /* not a number */ return 1; /* FAILED */ } else { ptr->opt_val[socket_type]->timeval_val.tv_usec=0; } ptr->opt_val[socket_type]->timeval_val.tv_sec= (int)strtol(opt_val_str, &tmp_str, 10); if(tmp_str==arg || *tmp_str) /* not a number */ return 1; /* FAILED */ return 0; /* OK */ case TYPE_STRING: if(strlen(opt_val_str)+1>sizeof(OPT_UNION)) return 1; /* FAILED */ strcpy(ptr->opt_val[socket_type]->c_val, opt_val_str); return 0; /* OK */ default: ; /* ANSI C compiler needs it */ } return 1; /* FAILED */ } /**************************************** OCSP */ #ifndef OPENSSL_NO_OCSP NOEXPORT unsigned long parse_ocsp_flag(char *arg) { struct { char *name; unsigned long value; } ocsp_opts[] = { {"NOCERTS", OCSP_NOCERTS}, {"NOINTERN", OCSP_NOINTERN}, {"NOSIGS", OCSP_NOSIGS}, {"NOCHAIN", OCSP_NOCHAIN}, {"NOVERIFY", OCSP_NOVERIFY}, {"NOEXPLICIT", OCSP_NOEXPLICIT}, {"NOCASIGN", OCSP_NOCASIGN}, {"NODELEGATED", OCSP_NODELEGATED}, {"NOCHECKS", OCSP_NOCHECKS}, {"TRUSTOTHER", OCSP_TRUSTOTHER}, {"RESPID_KEY", OCSP_RESPID_KEY}, {"NOTIME", OCSP_NOTIME}, {NULL, 0} }, *option; for(option=ocsp_opts; option->name; ++option) if(!strcasecmp(option->name, arg)) return option->value; return 0; /* FAILED */ } #endif /* !defined(OPENSSL_NO_OCSP) */ /**************************************** engine */ #ifndef OPENSSL_NO_ENGINE #define MAX_ENGINES 256 static ENGINE *engines[MAX_ENGINES]; /* table of engines for config parser */ static int current_engine; static int engine_initialized; NOEXPORT void engine_reset_list(void) { current_engine=-1; engine_initialized=1; } NOEXPORT char *engine_auto(void) { ENGINE *e; s_log(LOG_INFO, "Enabling automatic engine support"); ENGINE_register_all_complete(); /* rebuild the internal list of engines */ engine_reset_list(); for(e=ENGINE_get_first(); e; e=ENGINE_get_next(e)) { if(++current_engine>=MAX_ENGINES) return "Too many open engines"; engines[current_engine]=e; s_log(LOG_INFO, "Engine #%d (%s) registered", current_engine+1, ENGINE_get_id(e)); } s_log(LOG_INFO, "Automatic engine support enabled"); return NULL; /* OK */ } NOEXPORT char *engine_open(const char *name) { engine_init(); /* initialize the previous engine (if any) */ if(++current_engine>=MAX_ENGINES) return "Too many open engines"; s_log(LOG_DEBUG, "Enabling support for engine \"%s\"", name); engines[current_engine]=ENGINE_by_id(name); if(!engines[current_engine]) { sslerror("ENGINE_by_id"); return "Failed to open the engine"; } engine_initialized=0; return NULL; /* OK */ } NOEXPORT char *engine_ctrl(const char *cmd, const char *arg) { if(current_engine<0) return "No engine was defined"; if(!strcasecmp(cmd, "INIT")) /* special control command */ return engine_init(); if(arg) s_log(LOG_DEBUG, "Executing engine control command %s:%s", cmd, arg); else s_log(LOG_DEBUG, "Executing engine control command %s", cmd); if(!ENGINE_ctrl_cmd_string(engines[current_engine], cmd, arg, 0)) { sslerror("ENGINE_ctrl_cmd_string"); return "Failed to execute the engine control command"; } return NULL; /* OK */ } NOEXPORT char *engine_default(const char *list) { if(current_engine<0) return "No engine was defined"; if(!ENGINE_set_default_string(engines[current_engine], list)) { sslerror("ENGINE_set_default_string"); return "Failed to set engine as default"; } s_log(LOG_INFO, "Engine #%d (%s) set as default for %s", current_engine+1, ENGINE_get_id(engines[current_engine]), list); return NULL; } NOEXPORT char *engine_init(void) { if(engine_initialized) /* either first or already initialized */ return NULL; /* OK */ s_log(LOG_DEBUG, "Initializing engine #%d (%s)", current_engine+1, ENGINE_get_id(engines[current_engine])); if(!ENGINE_init(engines[current_engine])) { if(ERR_peek_last_error()) /* really an error */ sslerror("ENGINE_init"); else s_log(LOG_ERR, "Engine #%d (%s) not initialized", current_engine+1, ENGINE_get_id(engines[current_engine])); return "Engine initialization failed"; } #if 0 /* it is a bad idea to set the engine as default for all sections */ /* the "engine=auto" or "engineDefault" options should be used instead */ if(!ENGINE_set_default(engines[current_engine], ENGINE_METHOD_ALL)) { sslerror("ENGINE_set_default"); return "Selecting default engine failed"; } #endif s_log(LOG_INFO, "Engine #%d (%s) initialized", current_engine+1, ENGINE_get_id(engines[current_engine])); engine_initialized=1; return NULL; /* OK */ } NOEXPORT ENGINE *engine_get_by_id(const char *id) { int i; for(i=0; i<=current_engine; ++i) if(!strcmp(id, ENGINE_get_id(engines[i]))) return engines[i]; return NULL; } NOEXPORT ENGINE *engine_get_by_num(const int i) { if(i<0 || i>current_engine) return NULL; return engines[i]; } #endif /* !defined(OPENSSL_NO_ENGINE) */ /**************************************** fatal error */ NOEXPORT void print_syntax(void) { s_log(LOG_NOTICE, " "); s_log(LOG_NOTICE, "Syntax:"); s_log(LOG_NOTICE, "stunnel " #ifdef USE_WIN32 #ifndef _WIN32_WCE "[ [-install | -uninstall | -reload | -reopen] " #endif "[-quiet] " #endif "[] ] " #ifndef USE_WIN32 "-fd " #endif "| -help | -version | -sockets"); s_log(LOG_NOTICE, " - use specified config file"); #ifdef USE_WIN32 #ifndef _WIN32_WCE s_log(LOG_NOTICE, " -install - install NT service"); s_log(LOG_NOTICE, " -uninstall - uninstall NT service"); s_log(LOG_NOTICE, " -reload - reload configuration for NT service"); s_log(LOG_NOTICE, " -reopen - reopen log file for NT service"); #endif s_log(LOG_NOTICE, " -quiet - don't display message boxes"); #else s_log(LOG_NOTICE, " -fd - read the config file from a file descriptor"); #endif s_log(LOG_NOTICE, " -help - get config file help"); s_log(LOG_NOTICE, " -version - display version and defaults"); s_log(LOG_NOTICE, " -sockets - display default socket options"); } /**************************************** various supporting functions */ NOEXPORT void name_list_append(NAME_LIST **ptr, char *name) { while(*ptr) /* find the null pointer */ ptr=&(*ptr)->next; *ptr=str_alloc(sizeof(NAME_LIST)); (*ptr)->name=str_dup(name); (*ptr)->next=NULL; } #ifndef USE_WIN32 NOEXPORT char **argalloc(char *str) { /* allocate 'exec' argumets */ size_t max_arg, i; char *ptr, **retval; max_arg=strlen(str)/2+1; ptr=str_dup(str); retval=str_alloc((max_arg+1)*sizeof(char *)); i=0; while(*ptr && i * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #include "common.h" #include "prototypes.h" /**************************************** prototypes */ #if defined(USE_WIN32) && !defined(_WIN32_WCE) NOEXPORT int get_ipv6(LPTSTR); #endif NOEXPORT void addrlist2addr(SOCKADDR_UNION *, SOCKADDR_LIST *); NOEXPORT void addrlist_reset(SOCKADDR_LIST *); #ifndef HAVE_GETADDRINFO #ifndef EAI_MEMORY #define EAI_MEMORY 1 #endif #ifndef EAI_NONAME #define EAI_NONAME 2 #endif #ifndef EAI_SERVICE #define EAI_SERVICE 8 #endif /* rename some potentially locally shadowed declarations */ #define getaddrinfo local_getaddrinfo #define freeaddrinfo local_freeaddrinfo #ifndef HAVE_STRUCT_ADDRINFO struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; int ai_addrlen; struct sockaddr *ai_addr; char *ai_canonname; struct addrinfo *ai_next; }; #endif #ifndef AI_PASSIVE #define AI_PASSIVE 1 #endif NOEXPORT int getaddrinfo(const char *, const char *, const struct addrinfo *, struct addrinfo **); NOEXPORT int alloc_addresses(struct hostent *, const struct addrinfo *, u_short port, struct addrinfo **, struct addrinfo **); NOEXPORT void freeaddrinfo(struct addrinfo *); #endif /* !defined HAVE_GETADDRINFO */ /**************************************** resolver initialization */ #if defined(USE_WIN32) && !defined(_WIN32_WCE) GETADDRINFO s_getaddrinfo; FREEADDRINFO s_freeaddrinfo; GETNAMEINFO s_getnameinfo; #endif void resolver_init() { #if defined(USE_WIN32) && !defined(_WIN32_WCE) if(get_ipv6(TEXT("ws2_32.dll"))) /* IPv6 in Windows XP or higher */ return; if(get_ipv6(TEXT("wship6.dll"))) /* experimental IPv6 for Windows 2000 */ return; /* fall back to the built-in emulation */ #endif } #if defined(USE_WIN32) && !defined(_WIN32_WCE) NOEXPORT int get_ipv6(LPTSTR file) { HINSTANCE handle; handle=LoadLibrary(file); if(!handle) return 0; s_getaddrinfo=(GETADDRINFO)GetProcAddress(handle, "getaddrinfo"); s_freeaddrinfo=(FREEADDRINFO)GetProcAddress(handle, "freeaddrinfo"); s_getnameinfo=(GETNAMEINFO)GetProcAddress(handle, "getnameinfo"); if(!s_getaddrinfo || !s_freeaddrinfo || !s_getnameinfo) { s_getaddrinfo=NULL; s_freeaddrinfo=NULL; s_getnameinfo=NULL; FreeLibrary(handle); return 0; } return 1; /* IPv6 detected -> OK */ } #endif /**************************************** stunnel resolver API */ unsigned name2addr(SOCKADDR_UNION *addr, char *name, int passive) { SOCKADDR_LIST *addr_list; unsigned retval; addr_list=str_alloc(sizeof(SOCKADDR_LIST)); addrlist_clear(addr_list, passive); retval=name2addrlist(addr_list, name); if(retval) addrlist2addr(addr, addr_list); str_free(addr_list->addr); str_free(addr_list); return retval; } unsigned hostport2addr(SOCKADDR_UNION *addr, char *host_name, char *port_name, int passive) { SOCKADDR_LIST *addr_list; unsigned retval; addr_list=str_alloc(sizeof(SOCKADDR_LIST)); addrlist_clear(addr_list, passive); retval=hostport2addrlist(addr_list, host_name, port_name); if(retval) addrlist2addr(addr, addr_list); str_free(addr_list->addr); str_free(addr_list); return retval; } NOEXPORT void addrlist2addr(SOCKADDR_UNION *addr, SOCKADDR_LIST *addr_list) { unsigned i; for(i=0; inum; ++i) { /* find the first IPv4 address */ if(addr_list->addr[i].in.sin_family==AF_INET) { memcpy(addr, &addr_list->addr[i], sizeof(SOCKADDR_UNION)); return; } } #ifdef USE_IPv6 for(i=0; inum; ++i) { /* find the first IPv6 address */ if(addr_list->addr[i].in.sin_family==AF_INET6) { memcpy(addr, &addr_list->addr[i], sizeof(SOCKADDR_UNION)); return; } } #endif /* copy the first address resolved (curently AF_UNIX) */ memcpy(addr, &addr_list->addr[0], sizeof(SOCKADDR_UNION)); } unsigned name2addrlist(SOCKADDR_LIST *addr_list, char *name) { char *tmp, *host_name, *port_name; unsigned retval; /* first check if this is a UNIX socket */ #ifdef HAVE_STRUCT_SOCKADDR_UN if(*name=='/') { if(offsetof(struct sockaddr_un, sun_path)+strlen(name)+1 > sizeof(struct sockaddr_un)) { s_log(LOG_ERR, "Unix socket path is too long"); return 0; /* no results */ } addr_list->addr=str_realloc(addr_list->addr, (addr_list->num+1)*sizeof(SOCKADDR_UNION)); addr_list->addr[addr_list->num].un.sun_family=AF_UNIX; strcpy(addr_list->addr[addr_list->num].un.sun_path, name); return ++(addr_list->num); /* ok - return the number of addresses */ } #endif /* setup host_name and port_name */ tmp=str_dup(name); port_name=strrchr(tmp, ':'); if(port_name) { host_name=tmp; *port_name++='\0'; } else { /* no ':' - use default host IP */ host_name=NULL; port_name=tmp; } /* fill addr_list structure */ retval=hostport2addrlist(addr_list, host_name, port_name); str_free(tmp); return retval; } unsigned hostport2addrlist(SOCKADDR_LIST *addr_list, char *host_name, char *port_name) { struct addrinfo hints, *res=NULL, *cur; int err, retry=0; memset(&hints, 0, sizeof hints); #if defined(USE_IPv6) || defined(USE_WIN32) hints.ai_family=AF_UNSPEC; #else hints.ai_family=AF_INET; #endif hints.ai_socktype=SOCK_STREAM; hints.ai_protocol=IPPROTO_TCP; hints.ai_flags=0; if(addr_list->passive) { hints.ai_family=AF_INET; /* first try IPv4 for passive requests */ hints.ai_flags|=AI_PASSIVE; } for(;;) { err=getaddrinfo(host_name, port_name, &hints, &res); if(!err) break; if(res) freeaddrinfo(res); if(err==EAI_AGAIN && ++retry<=3) { s_log(LOG_DEBUG, "getaddrinfo: EAI_AGAIN received: retrying"); sleep(1); continue; } #if defined(USE_IPv6) || defined(USE_WIN32) if(hints.ai_family==AF_INET) { hints.ai_family=AF_UNSPEC; continue; /* retry for non-IPv4 addresses */ } #endif break; } if(err==EAI_SERVICE) { s_log(LOG_ERR, "Unknown TCP service \"%s\"", port_name); return 0; /* error */ } if(err) { s_log(LOG_ERR, "Error resolving \"%s\": %s", host_name ? host_name : (addr_list->passive ? DEFAULT_ANY : DEFAULT_LOOPBACK), s_gai_strerror(err)); return 0; /* error */ } /* copy the list of addresses */ for(cur=res; cur; cur=cur->ai_next) { if(cur->ai_addrlen>(int)sizeof(SOCKADDR_UNION)) { s_log(LOG_ERR, "INTERNAL ERROR: ai_addrlen value too big"); freeaddrinfo(res); return 0; /* no results */ } addr_list->addr=str_realloc(addr_list->addr, (addr_list->num+1)*sizeof(SOCKADDR_UNION)); memcpy(&addr_list->addr[addr_list->num], cur->ai_addr, (size_t)cur->ai_addrlen); ++(addr_list->num); } freeaddrinfo(res); return addr_list->num; /* ok - return the number of addresses */ } /* initialize the structure */ void addrlist_clear(SOCKADDR_LIST *addr_list, int passive) { addrlist_reset(addr_list); addr_list->names=NULL; addr_list->passive=passive; } /* prepare the structure to resolve new hosts */ NOEXPORT void addrlist_reset(SOCKADDR_LIST *addr_list) { addr_list->num=0; addr_list->addr=NULL; addr_list->rr_val=0; /* reset the round-robin counter */ /* allow structures created with sockaddr_dup() to modify * the original rr_val rather than its local copy */ addr_list->rr_ptr=&addr_list->rr_val; } unsigned addrlist_dup(SOCKADDR_LIST *dst, const SOCKADDR_LIST *src) { memcpy(dst, src, sizeof(SOCKADDR_LIST)); if(src->num) { /* already resolved */ dst->addr=str_alloc(src->num*sizeof(SOCKADDR_UNION)); memcpy(dst->addr, src->addr, src->num*sizeof(SOCKADDR_UNION)); } else { /* delayed resolver */ addrlist_resolve(dst); } return dst->num; } unsigned addrlist_resolve(SOCKADDR_LIST *addr_list) { unsigned num=0, rnd; NAME_LIST *host; addrlist_reset(addr_list); for(host=addr_list->names; host; host=host->next) num+=name2addrlist(addr_list, host->name); switch(num) { case 0: case 1: addr_list->rr_val=0; break; default: /* randomize the initial value of round-robin counter */ /* ignore the error value and the distribution bias */ RAND_bytes((unsigned char *)&rnd, sizeof rnd); addr_list->rr_val=rnd%num; } return num; } char *s_ntop(SOCKADDR_UNION *addr, socklen_t addrlen) { int err; char *host, *port, *retval; if(addrlen==sizeof(u_short)) /* see UNIX(7) manual for details */ return str_dup("unnamed socket"); host=str_alloc(256); port=str_alloc(256); /* needs to be long enough for AF_UNIX path */ err=getnameinfo(&addr->sa, addrlen, host, 256, port, 256, NI_NUMERICHOST|NI_NUMERICSERV); if(err) { s_log(LOG_ERR, "getnameinfo: %s", s_gai_strerror(err)); retval=str_dup("unresolvable address"); } else retval=str_printf("%s:%s", host, port); str_free(host); str_free(port); return retval; } socklen_t addr_len(const SOCKADDR_UNION *addr) { if(addr->sa.sa_family==AF_INET) return sizeof(struct sockaddr_in); #ifdef USE_IPv6 if(addr->sa.sa_family==AF_INET6) return sizeof(struct sockaddr_in6); #endif #ifdef HAVE_STRUCT_SOCKADDR_UN if(addr->sa.sa_family==AF_UNIX) return sizeof(struct sockaddr_un); #endif s_log(LOG_ERR, "INTERNAL ERROR: Unknown sa_family: %d", addr->sa.sa_family); return sizeof(SOCKADDR_UNION); } /**************************************** my getaddrinfo() */ /* implementation is limited to functionality needed by stunnel */ #ifndef HAVE_GETADDRINFO NOEXPORT int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { struct hostent *h; #ifndef _WIN32_WCE struct servent *p; #endif u_short port; struct addrinfo *ai; int retval; char *tmpstr; if(!node) node=hints->ai_flags&AI_PASSIVE ? DEFAULT_ANY : DEFAULT_LOOPBACK; #if defined(USE_WIN32) && !defined(_WIN32_WCE) if(s_getaddrinfo) return s_getaddrinfo(node, service, hints, res); #endif /* decode service name */ port=htons((u_short)strtol(service, &tmpstr, 10)); if(tmpstr==service || *tmpstr) { /* not a number */ #ifdef _WIN32_WCE return EAI_NONAME; #else /* defined(_WIN32_WCE) */ p=getservbyname(service, "tcp"); if(!p) return EAI_NONAME; port=(u_short)p->s_port; #endif /* defined(_WIN32_WCE) */ } /* allocate addrlist structure */ ai=str_alloc(sizeof(struct addrinfo)); if(hints) memcpy(ai, hints, sizeof(struct addrinfo)); /* try to decode numerical address */ #if defined(USE_IPv6) && !defined(USE_WIN32) ai->ai_family=AF_INET6; ai->ai_addrlen=sizeof(struct sockaddr_in6); ai->ai_addr=str_alloc((size_t)ai->ai_addrlen); ai->ai_addr->sa_family=AF_INET6; if(inet_pton(AF_INET6, node, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr)>0) { #else ai->ai_family=AF_INET; ai->ai_addrlen=sizeof(struct sockaddr_in); ai->ai_addr=str_alloc(ai->ai_addrlen); ai->ai_addr->sa_family=AF_INET; ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr=inet_addr(node); if(((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr+1) { /* (signed)((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr!=-1 */ #endif ((struct sockaddr_in *)ai->ai_addr)->sin_port=port; *res=ai; return 0; /* numerical address resolved */ } str_free(ai->ai_addr); str_free(ai); /* not numerical: need to call resolver library */ *res=NULL; ai=NULL; CRYPTO_w_lock(stunnel_locks[LOCK_INET]); #ifdef HAVE_GETHOSTBYNAME2 h=gethostbyname2(node, AF_INET6); if(h) /* some IPv6 addresses found */ alloc_addresses(h, hints, port, res, &ai); /* ignore the error */ #endif h=gethostbyname(node); /* get list of addresses */ if(h) retval=ai ? alloc_addresses(h, hints, port, &ai->ai_next, &ai) : alloc_addresses(h, hints, port, res, &ai); else if(!*res) retval=EAI_NONAME; /* no results */ else retval=0; #ifdef HAVE_ENDHOSTENT endhostent(); #endif CRYPTO_w_unlock(stunnel_locks[LOCK_INET]); if(retval) { /* error: free allocated memory */ freeaddrinfo(*res); *res=NULL; } return retval; } NOEXPORT int alloc_addresses(struct hostent *h, const struct addrinfo *hints, u_short port, struct addrinfo **head, struct addrinfo **tail) { int i; struct addrinfo *ai; /* copy addresses */ for(i=0; h->h_addr_list[i]; i++) { ai=str_alloc(sizeof(struct addrinfo)); if(hints) memcpy(ai, hints, sizeof(struct addrinfo)); ai->ai_next=NULL; /* just in case */ if(*tail) { /* list not empty: add a node */ (*tail)->ai_next=ai; *tail=ai; } else { /* list empty: create it */ *head=ai; *tail=ai; } ai->ai_family=h->h_addrtype; #if defined(USE_IPv6) if(h->h_addrtype==AF_INET6) { ai->ai_addrlen=sizeof(struct sockaddr_in6); ai->ai_addr=str_alloc((size_t)ai->ai_addrlen); memcpy(&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, h->h_addr_list[i], (size_t)h->h_length); } else #endif { ai->ai_addrlen=sizeof(struct sockaddr_in); ai->ai_addr=str_alloc((size_t)ai->ai_addrlen); memcpy(&((struct sockaddr_in *)ai->ai_addr)->sin_addr, h->h_addr_list[i], (size_t)h->h_length); } ai->ai_addr->sa_family=(u_short)h->h_addrtype; /* offsets of sin_port and sin6_port should be the same */ ((struct sockaddr_in *)ai->ai_addr)->sin_port=port; } return 0; /* success */ } NOEXPORT void freeaddrinfo(struct addrinfo *current) { struct addrinfo *next; #if defined(USE_WIN32) && !defined(_WIN32_WCE) if(s_freeaddrinfo) { s_freeaddrinfo(current); return; } #endif while(current) { str_free(current->ai_addr); str_free(current->ai_canonname); next=current->ai_next; str_free(current); current=next; } } #endif /* !defined HAVE_GETADDRINFO */ /* due to a problem with Mingw32 I decided to define my own gai_strerror() */ const char *s_gai_strerror(int err) { switch(err) { #ifdef EAI_BADFLAGS case EAI_BADFLAGS: return "Invalid value for ai_flags (EAI_BADFLAGS)"; #endif case EAI_NONAME: return "Neither nodename nor servname known (EAI_NONAME)"; #ifdef EAI_AGAIN case EAI_AGAIN: return "Temporary failure in name resolution (EAI_AGAIN)"; #endif #ifdef EAI_FAIL case EAI_FAIL: return "Non-recoverable failure in name resolution (EAI_FAIL)"; #endif #ifdef EAI_NODATA #if EAI_NODATA!=EAI_NONAME case EAI_NODATA: return "No address associated with nodename (EAI_NODATA)"; #endif /* EAI_NODATA!=EAI_NONAME */ #endif /* defined EAI_NODATA */ #ifdef EAI_FAMILY case EAI_FAMILY: return "ai_family not supported (EAI_FAMILY)"; #endif #ifdef EAI_SOCKTYPE case EAI_SOCKTYPE: return "ai_socktype not supported (EAI_SOCKTYPE)"; #endif #ifdef EAI_SERVICE case EAI_SERVICE: return "servname is not supported for ai_socktype (EAI_SERVICE)"; #endif #ifdef EAI_ADDRFAMILY case EAI_ADDRFAMILY: return "Address family for nodename not supported (EAI_ADDRFAMILY)"; #endif /* EAI_ADDRFAMILY */ case EAI_MEMORY: return "Memory allocation failure (EAI_MEMORY)"; #ifdef EAI_SYSTEM case EAI_SYSTEM: return "System error returned in errno (EAI_SYSTEM)"; #endif /* EAI_SYSTEM */ default: return "Unknown error"; } } /**************************************** my getnameinfo() */ /* implementation is limited to functionality needed by stunnel */ #ifndef HAVE_GETNAMEINFO int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) { #if defined(USE_WIN32) && !defined(_WIN32_WCE) if(s_getnameinfo) return s_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); #endif if(host && hostlen) { #if defined(USE_IPv6) && !defined(USE_WIN32) inet_ntop(sa->sa_family, sa->sa_family==AF_INET6 ? (void *)&((struct sockaddr_in6 *)sa)->sin6_addr : (void *)&((struct sockaddr_in *)sa)->sin_addr, host, hostlen); #else /* USE_IPv6 */ CRYPTO_w_lock(stunnel_locks[LOCK_INET]); /* inet_ntoa is not mt-safe */ strncpy(host, inet_ntoa(((struct sockaddr_in *)sa)->sin_addr), hostlen); CRYPTO_w_unlock(stunnel_locks[LOCK_INET]); host[hostlen-1]='\0'; #endif /* USE_IPv6 */ } if(serv && servlen) sprintf(serv, "%u", ntohs(((struct sockaddr_in *)sa)->sin_port)); /* sin_port is in the same place both in sockaddr_in and sockaddr_in6 */ /* ignore servlen since it's long enough in stunnel code */ return 0; } #endif /* end of resolver.c */ stunnel-5.30/src/version.h0000664000175000017500000000701412646221043012503 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #ifndef VERSION_MAJOR #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ /* HOST may be undefined on Win32 platform */ #ifndef HOST #if defined(_WIN64) #define PLATFORM "x64" #elif defined(_WIN32) #define PLATFORM "x86" #else /* although MSDN claims that _WIN32 is always defined */ #define PLATFORM "unknown" #endif #ifdef __MINGW32__ #define HOST PLATFORM "-pc-mingw32-gnu" #else /* __MINGW32__ */ #ifdef _MSC_VER #define xstr(a) str(a) #define str(a) #a #define HOST PLATFORM "-pc-msvc-" xstr(_MSC_VER) #else /* _MSC_VER */ #define HOST PLATFORM "-pc-unknown" #endif /* _MSC_VER */ #endif /* __MINGW32__ */ #endif /* HOST */ /* START CUSTOMIZE */ #define VERSION_MAJOR 5 #define VERSION_MINOR 30 /* END CUSTOMIZE */ /* all the following macros are ABSOLUTELY NECESSARY to have proper string * construction with VARIOUS C preprocessors (EVC, VC, BCC, GCC) */ #define STRINGIZE0(x) #x #define STRINGIZE(x) STRINGIZE0(x) #define STRZCONCAT30(a,b,c) a##b##c #define STRZCONCAT3(a,b,c) STRZCONCAT30(a,b,c) /* for resource.rc, stunnel.c, gui.c */ #define STUNNEL_VERSION0 STRZCONCAT3(VERSION_MAJOR, . , VERSION_MINOR) #define STUNNEL_VERSION STRINGIZE(STUNNEL_VERSION0) /* for resources.rc */ #define STUNNEL_VERSION_FIELDS VERSION_MAJOR,VERSION_MINOR,0,0 #define STUNNEL_PRODUCTNAME "stunnel " STUNNEL_VERSION " for " HOST /* some useful tricks for preprocessing debugging */ #if 0 #pragma message ( "VERSION.H: STUNNEL_VERSION is " STUNNEL_VERSION ) #pragma message ( "VERSION.H: HOST is " HOST ) #pragma message ( "VERSION.H: STUNNEL_PRODUCTNAME is " STUNNEL_PRODUCTNAME ) #endif #endif /* VERSION_MAJOR */ /* end of version.h */ stunnel-5.30/src/active.ico0000664000175000017500000000217612634035772012631 00000000000000 h(   #` #¿ #ÿ #ÿ #ÿ #ÿ #¿ #` # #Ï #ÿ:1ÿˆgÿ»Š ÿ»Š ÿ”oÿ:1ÿ #ÿ #Ï # # #ï #ÿ{^ÿï®ÿ÷×€ÿýõßÿýõßÿ÷×€ÿï®ÿˆgÿ #ÿ #ï # #Ï #ÿnUÿï®ÿõÌ`ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿöÑpÿï®ÿ{^ÿ #ÿ #Ï #` #ÿ #ÿâ¥ÿï®ÿûë¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûë¿ÿï®ÿâ¥ÿ-(!ÿ #ÿ #` #¿ #ÿTCÿï®ÿï®ÿúæ¯ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúæ¯ÿï®ÿï®ÿTCÿ #ÿ #¿ #ÿ #ÿ{^ÿï®ÿï®ÿò½0ÿþúïÿÿÿÿÿÿÿÿÿÿÿÿÿóÂ@ÿï®ÿï®ÿˆgÿ #ÿ #ÿ #ÿ #ÿTCÿï®ÿï®ÿï®ÿñ¸ ÿ÷×€ÿ÷×€ÿñ¸ ÿï®ÿï®ÿï®ÿnUÿ #ÿ #ÿ #ÿ #ÿ:1ÿï®ÿï®ÿï®ÿï®ÿï®ÿï®ÿï®ÿï®ÿï®ÿï®ÿ:1ÿ #ÿ #ÿ #ÿ #ÿ #ÿ¡x ÿï®ÿï®ÿï®ÿï®ÿï®ÿï®ÿï®ÿï®ÿ¡x ÿ #ÿ #ÿ #ÿ #¿ #ÿ #ÿ-(!ÿÈ“ÿï®ÿï®ÿï®ÿï®ÿï®ÿï®ÿÈ“ÿ-(!ÿ #ÿ #ÿ #¿ #` #ÿ #ÿ #ÿ-(!ÿˆgÿÕœÿï®ÿï®ÿÕœÿˆgÿ-(!ÿ #ÿ #ÿ #ÿ #` #Ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #Ï # #ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ï # # #Ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #Ï # #` #¿ #ÿ #ÿ #ÿ #ÿ #¿ #`øàÀ€€€€Ààøstunnel-5.30/src/pty.c0000664000175000017500000001476612646221043011641 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #include "common.h" #include "prototypes.h" #ifdef HAVE_UTIL_H #include #endif /* HAVE_UTIL_H */ #ifdef HAVE_SYS_IOCTL_H #include #endif /* HAVE_SYS_IOCTL_H */ /* pty allocated with _getpty gets broken if we do I_PUSH:es to it. */ #if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY) #undef HAVE_DEV_PTMX #endif /* HAVE__GETPTY || HAVE_OPENPTY */ #ifdef HAVE_PTY_H #include #endif /* HAVE_PTY_H */ #ifdef HAVE_LIBUTIL_H #include #endif /* HAVE_LIBUTIL_H */ #ifndef O_NOCTTY #define O_NOCTTY 0 #endif /* O_NOCTTY */ /* * allocates and opens a pty * returns -1 if no pty could be allocated, or zero if a pty was successfully * allocated * on success, open file descriptors for the pty and tty sides and the name of * the tty side are returned * the buffer must be able to hold at least 64 characters */ int pty_allocate(int *ptyfd, int *ttyfd, char *namebuf) { #if defined(HAVE_OPENPTY) || defined(BSD4_4) && !defined(__INNOTEK_LIBC__) /* openpty(3) exists in OSF/1 and some other os'es */ char buf[64]; int i; i=openpty(ptyfd, ttyfd, buf, NULL, NULL); if(i<0) { ioerror("openpty"); return -1; } strcpy(namebuf, buf); /* possible truncation */ return 0; #else /* HAVE_OPENPTY */ #ifdef HAVE__GETPTY /* * _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more * pty's automagically when needed */ char *slave; slave=_getpty(ptyfd, O_RDWR, 0622, 0); if(slave==NULL) { ioerror("_getpty"); return -1; } strcpy(namebuf, slave); /* open the slave side */ *ttyfd=open(namebuf, O_RDWR|O_NOCTTY); if(*ttyfd<0) { ioerror(namebuf); close(*ptyfd); return -1; } return 0; #else /* HAVE__GETPTY */ #if defined(HAVE_DEV_PTMX) /* * this code is used e.g. on Solaris 2.x * note that Solaris 2.3 * also has bsd-style ptys, but they simply do not * work */ int ptm; char *pts; ptm=open("/dev/ptmx", O_RDWR|O_NOCTTY); if(ptm<0) { ioerror("/dev/ptmx"); return -1; } if(grantpt(ptm)<0) { ioerror("grantpt"); /* return -1; */ /* can you tell me why it doesn't work? */ } if(unlockpt(ptm)<0) { ioerror("unlockpt"); return -1; } pts=ptsname(ptm); if(pts==NULL) s_log(LOG_ERR, "Slave pty side name could not be obtained"); strcpy(namebuf, pts); *ptyfd=ptm; /* open the slave side */ *ttyfd=open(namebuf, O_RDWR|O_NOCTTY); if(*ttyfd<0) { ioerror(namebuf); close(*ptyfd); return -1; } /* push the appropriate streams modules, as described in Solaris pts(7) */ if(ioctl(*ttyfd, I_PUSH, "ptem")<0) ioerror("ioctl I_PUSH ptem"); if(ioctl(*ttyfd, I_PUSH, "ldterm")<0) ioerror("ioctl I_PUSH ldterm"); if(ioctl(*ttyfd, I_PUSH, "ttcompat")<0) ioerror("ioctl I_PUSH ttcompat"); return 0; #else /* HAVE_DEV_PTMX */ #ifdef HAVE_DEV_PTS_AND_PTC /* AIX-style pty code. */ const char *name; *ptyfd=open("/dev/ptc", O_RDWR|O_NOCTTY); if(*ptyfd<0) { ioerror("open(/dev/ptc)"); return -1; } name=ttyname(*ptyfd); if(!name) { s_log(LOG_ERR, "Open of /dev/ptc returns device for which ttyname fails"); return -1; } strcpy(namebuf, name); *ttyfd=open(name, O_RDWR|O_NOCTTY); if(*ttyfd<0) { ioerror(name); close(*ptyfd); return -1; } return 0; #else /* HAVE_DEV_PTS_AND_PTC */ /* BSD-style pty code. */ char buf[64]; size_t i; const char *ptymajors="pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ"; const char *ptyminors="0123456789abcdef"; size_t num_minors=strlen(ptyminors); size_t num_ptys=strlen(ptymajors)*num_minors; for(i=0; i * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #include "common.h" #include "prototypes.h" #if defined HAVE_PIPE2 && defined HAVE_ACCEPT4 #define USE_NEW_LINUX_API 1 #endif /* try to use non-POSIX O_NDELAY on obsolete BSD systems */ #if !defined O_NONBLOCK && defined O_NDELAY #define O_NONBLOCK O_NDELAY #endif /**************************************** prototypes */ NOEXPORT SOCKET setup_fd(SOCKET, int, char *); /**************************************** internal limit of file descriptors */ #ifndef USE_FORK static SOCKET max_fds; void get_limits(void) { /* set max_fds and max_clients */ /* start with current ulimit */ #if defined(HAVE_SYSCONF) errno=0; max_fds=(SOCKET)sysconf(_SC_OPEN_MAX); if(errno) ioerror("sysconf"); if(max_fds<0) max_fds=0; /* unlimited */ #elif defined(HAVE_GETRLIMIT) struct rlimit rlim; if(getrlimit(RLIMIT_NOFILE, &rlim)<0) { ioerror("getrlimit"); max_fds=0; /* unlimited */ } else max_fds=rlim.rlim_cur!=RLIM_INFINITY ? rlim.rlim_cur : 0; #else max_fds=0; /* unlimited */ #endif /* HAVE_SYSCONF || HAVE_GETRLIMIT */ #if !defined(USE_WIN32) && !defined(USE_POLL) && !defined(__INNOTEK_LIBC__) /* apply FD_SETSIZE if select() is used on Unix */ if(!max_fds || max_fds>FD_SETSIZE) max_fds=FD_SETSIZE; /* start with select() limit */ #endif /* select() on Unix */ /* stunnel needs at least 16 file desriptors */ if(max_fds && max_fds<16) max_fds=16; if(max_fds) { max_clients=(long)(max_fds>=256 ? max_fds*125/256 : (max_fds-6)/2); s_log(LOG_DEBUG, "Clients allowed=%ld", max_clients); } else { max_clients=0; s_log(LOG_DEBUG, "No limit detected for the number of clients"); } } #endif /**************************************** file descriptor validation */ SOCKET s_socket(int domain, int type, int protocol, int nonblock, char *msg) { SOCKET fd; #ifdef USE_NEW_LINUX_API if(nonblock) type|=SOCK_NONBLOCK; type|=SOCK_CLOEXEC; #endif #ifdef USE_WIN32 /* http://stackoverflow.com/questions/4993119 */ /* CreateProcess() needs a non-overlapped handle */ fd=WSASocket(domain, type, protocol, NULL, 0, 0); #else /* USE_WIN32 */ fd=socket(domain, type, protocol); #endif /* USE_WIN32 */ return setup_fd(fd, nonblock, msg); } SOCKET s_accept(SOCKET sockfd, struct sockaddr *addr, socklen_t *addrlen, int nonblock, char *msg) { SOCKET fd; #ifdef USE_NEW_LINUX_API if(nonblock) fd=accept4(sockfd, addr, addrlen, SOCK_NONBLOCK|SOCK_CLOEXEC); else fd=accept4(sockfd, addr, addrlen, SOCK_CLOEXEC); #else fd=accept(sockfd, addr, addrlen); #endif return setup_fd(fd, nonblock, msg); } #ifndef USE_WIN32 int s_socketpair(int domain, int type, int protocol, SOCKET sv[2], int nonblock, char *msg) { #ifdef USE_NEW_LINUX_API if(nonblock) type|=SOCK_NONBLOCK; type|=SOCK_CLOEXEC; #endif if(socketpair(domain, type, protocol, sv)<0) { ioerror(msg); return -1; } if(setup_fd(sv[0], nonblock, msg)<0) { closesocket(sv[1]); return -1; } if(setup_fd(sv[1], nonblock, msg)<0) { closesocket(sv[0]); return -1; } return 0; } int s_pipe(int pipefd[2], int nonblock, char *msg) { int retval; #ifdef USE_NEW_LINUX_API if(nonblock) retval=pipe2(pipefd, O_NONBLOCK|O_CLOEXEC); else retval=pipe2(pipefd, O_CLOEXEC); #else retval=pipe(pipefd); #endif if(retval<0) { ioerror(msg); return -1; } if(setup_fd(pipefd[0], nonblock, msg)<0) { close(pipefd[1]); return -1; } if(setup_fd(pipefd[1], nonblock, msg)<0) { close(pipefd[0]); return -1; } return 0; } #endif /* USE_WIN32 */ NOEXPORT SOCKET setup_fd(SOCKET fd, int nonblock, char *msg) { #if !defined USE_NEW_LINUX_API && defined FD_CLOEXEC int err; #endif if(fd==INVALID_SOCKET) { sockerror(msg); return INVALID_SOCKET; } #ifndef USE_FORK if(max_fds && fd>=max_fds) { s_log(LOG_ERR, "%s: FD=%d out of range (max %d)", msg, (int)fd, (int)max_fds); closesocket(fd); return INVALID_SOCKET; } #endif #ifdef USE_NEW_LINUX_API (void)nonblock; /* squash the unused parameter warning */ #else /* set O_NONBLOCK and F_SETFD */ set_nonblock(fd, (unsigned long)nonblock); #ifdef FD_CLOEXEC do { err=fcntl(fd, F_SETFD, FD_CLOEXEC); } while(err<0 && get_last_socket_error()==S_EINTR); if(err<0) sockerror("fcntl SETFD"); /* non-critical */ #endif /* FD_CLOEXEC */ #endif /* USE_NEW_LINUX_API */ #ifdef DEBUG_FD_ALLOC s_log(LOG_DEBUG, "%s: FD=%d allocated (%sblocking mode)", msg, fd, nonblock?"non-":""); #endif /* DEBUG_FD_ALLOC */ return fd; } void set_nonblock(SOCKET fd, unsigned long nonblock) { #if defined F_GETFL && defined F_SETFL && defined O_NONBLOCK && !defined __INNOTEK_LIBC__ int err, flags; do { flags=fcntl(fd, F_GETFL, 0); } while(flags<0 && get_last_socket_error()==S_EINTR); if(flags<0) { sockerror("fcntl GETFL"); /* non-critical */ return; } if(nonblock) flags|=O_NONBLOCK; else flags&=~O_NONBLOCK; do { err=fcntl(fd, F_SETFL, flags); } while(err<0 && get_last_socket_error()==S_EINTR); if(err<0) sockerror("fcntl SETFL"); /* non-critical */ #else /* WIN32 or similar */ if(ioctlsocket(fd, (long)FIONBIO, &nonblock)<0) sockerror("ioctlsocket"); /* non-critical */ #if 0 else s_log(LOG_DEBUG, "Socket %d set to %s mode", fd, nonblock ? "non-blocking" : "blocking"); #endif #endif } /* end of fd.c */ stunnel-5.30/src/log.c0000664000175000017500000003630612646221043011600 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #include "common.h" #include "prototypes.h" NOEXPORT void log_raw(const SERVICE_OPTIONS *, const int, const char *, const char *, const char *); NOEXPORT void safestring(char *); static DISK_FILE *outfile=NULL; static struct LIST { /* single-linked list of log lines */ struct LIST *next; SERVICE_OPTIONS *opt; int level; char *stamp, *id, *text; } *head=NULL, *tail=NULL; static LOG_MODE mode=LOG_MODE_NONE; #if !defined(USE_WIN32) && !defined(__vms) static int syslog_opened=0; void syslog_open(void) { syslog_close(); if(global_options.option.log_syslog) #ifdef __ultrix__ openlog(service_options.servname, 0); #else openlog(service_options.servname, LOG_CONS|LOG_NDELAY, global_options.log_facility); #endif /* __ultrix__ */ syslog_opened=1; } void syslog_close(void) { if(syslog_opened) { if(global_options.option.log_syslog) closelog(); syslog_opened=0; } } #endif /* !defined(USE_WIN32) && !defined(__vms) */ int log_open(void) { if(global_options.output_file) { /* 'output' option specified */ outfile=file_open(global_options.output_file, global_options.log_file_mode); #if defined(USE_WIN32) && !defined(_WIN32_WCE) if(!outfile) { char appdata[MAX_PATH], *path; if(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE, NULL, 0, appdata)==S_OK) { path=str_printf("%s\\%s", appdata, global_options.output_file); outfile=file_open(path, global_options.log_file_mode); if(outfile) s_log(LOG_NOTICE, "Logging to %s", path); str_free(path); } } #endif if(!outfile) { s_log(LOG_ERR, "Cannot open log file: %s", global_options.output_file); return 1; } } log_flush(LOG_MODE_CONFIGURED); return 0; } void log_close(void) { mode=LOG_MODE_NONE; if(outfile) { file_close(outfile); outfile=NULL; } } void log_flush(LOG_MODE new_mode) { struct LIST *tmp; /* prevent changing LOG_MODE_CONFIGURED to LOG_MODE_ERROR * once stderr file descriptor is closed */ if(mode!=LOG_MODE_CONFIGURED) mode=new_mode; CRYPTO_w_lock(stunnel_locks[LOCK_LOG]); while(head) { log_raw(head->opt, head->level, head->stamp, head->id, head->text); str_free(head->stamp); str_free(head->id); str_free(head->text); tmp=head; head=head->next; str_free(tmp); } CRYPTO_w_unlock(stunnel_locks[LOCK_LOG]); head=tail=NULL; } void s_log(int level, const char *format, ...) { va_list ap; char *text, *stamp, *id; struct LIST *tmp; #ifdef USE_WIN32 DWORD libc_error; #else int libc_error; #endif int socket_error; time_t gmt; struct tm *timeptr; #if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT) struct tm timestruct; #endif TLS_DATA *tls_data; tls_data=tls_get(); if(!tls_data) { tls_data=tls_alloc(NULL, NULL, "log"); s_log(LOG_ERR, "INTERNAL ERROR: Uninitialized TLS at %s, line %d", __FILE__, __LINE__); } /* performance optimization: skip the trivial case early */ if(mode==LOG_MODE_CONFIGURED && level>tls_data->opt->log_level) return; libc_error=get_last_error(); socket_error=get_last_socket_error(); /* format the id to be logged */ time(&gmt); #if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT) timeptr=localtime_r(&gmt, ×truct); #else timeptr=localtime(&gmt); #endif stamp=str_printf("%04d.%02d.%02d %02d:%02d:%02d", timeptr->tm_year+1900, timeptr->tm_mon+1, timeptr->tm_mday, timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec); id=str_printf("LOG%d[%s]", level, tls_data->id); /* format the text to be logged */ va_start(ap, format); text=str_vprintf(format, ap); va_end(ap); safestring(text); if(mode==LOG_MODE_NONE) { /* save the text to log it later */ CRYPTO_w_lock(stunnel_locks[LOCK_LOG]); tmp=str_alloc_detached(sizeof(struct LIST)); tmp->next=NULL; tmp->opt=tls_data->opt; tmp->level=level; tmp->stamp=stamp; str_detach(tmp->stamp); tmp->id=id; str_detach(tmp->id); tmp->text=text; str_detach(tmp->text); if(tail) tail->next=tmp; else head=tmp; tail=tmp; CRYPTO_w_unlock(stunnel_locks[LOCK_LOG]); } else { /* ready log the text directly */ log_raw(tls_data->opt, level, stamp, id, text); str_free(stamp); str_free(id); str_free(text); } set_last_error(libc_error); set_last_socket_error(socket_error); } NOEXPORT void log_raw(const SERVICE_OPTIONS *opt, const int level, const char *stamp, const char *id, const char *text) { char *line; /* build the line and log it to syslog/file */ if(mode==LOG_MODE_CONFIGURED) { /* configured */ line=str_printf("%s %s: %s", stamp, id, text); if(level<=opt->log_level) { #if !defined(USE_WIN32) && !defined(__vms) if(global_options.option.log_syslog) syslog(level, "%s: %s", id, text); #endif /* USE_WIN32, __vms */ if(outfile) file_putline(outfile, line); /* send log to file */ } } else if(mode==LOG_MODE_ERROR) { if(level>=0 && level<=7) /* just in case */ line=str_printf("[%c] %s", "***!:. "[level], text); else line=str_printf("[?] %s", text); } else /* LOG_MODE_INFO */ line=str_dup(text); /* don't log the time stamp in error mode */ /* log the line to the UI (GUI, stderr, etc.) */ if(mode==LOG_MODE_ERROR || (mode==LOG_MODE_INFO && levellog_level #else (level<=opt->log_level && global_options.option.log_stderr) #endif ) ui_new_log(line); str_free(line); } #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat" #pragma GCC diagnostic ignored "-Wformat-extra-args" #endif /* __GNUC__ */ char *log_id(CLI *c) { const char table[62]= "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; unsigned char rnd[22]; char *uniq; size_t i; unsigned long tid; switch(c->opt->log_id) { case LOG_ID_SEQUENTIAL: return str_printf("%llu", c->seq); case LOG_ID_UNIQUE: if(RAND_bytes(rnd, sizeof rnd)<=0) /* log2(62^22)=130.99 */ return str_dup("error"); for(i=0; i=62) { if(RAND_bytes(rnd+i, 1)<=0) return str_dup("error"); rnd[i]&=63; } } uniq=str_alloc(sizeof rnd+1); for(i=0; ifh, msg, (DWORD)strlen(msg), &num, NULL); #else /* USE_WIN32 */ /* no file -> write to stderr */ /* no meaningful way here to handle the result */ write(outfile ? outfile->fd : 2, msg, strlen(msg)); #endif /* USE_WIN32 */ } #ifndef USE_WIN32 if(mode!=LOG_MODE_CONFIGURED || global_options.option.log_stderr) { fputs(msg, stderr); fflush(stderr); } #endif /* !USE_WIN32 */ snprintf(msg, sizeof msg, /* without newline */ "INTERNAL ERROR: %s at %s, line %d", txt, file, line); #if !defined(USE_WIN32) && !defined(__vms) if(global_options.option.log_syslog) syslog(LOG_CRIT, "%s", msg); #endif /* USE_WIN32, __vms */ #ifdef USE_WIN32 #ifdef UNICODE if(MultiByteToWideChar(CP_UTF8, 0, msg, -1, tmsg, 80)) message_box(tmsg, MB_ICONERROR); #else message_box(msg, MB_ICONERROR); #endif #endif /* USE_WIN32 */ abort(); } #ifdef __GNUC__ #pragma GCC diagnostic pop #endif /* __GNUC__ */ void ioerror(const char *txt) { /* input/output error */ log_error(LOG_ERR, (int)get_last_error(), txt); } void sockerror(const char *txt) { /* socket error */ log_error(LOG_ERR, get_last_socket_error(), txt); } void log_error(int level, int error, const char *txt) { /* generic error */ s_log(level, "%s: %s (%d)", txt, s_strerror(error), error); } char *s_strerror(int errnum) { switch(errnum) { #ifdef USE_WIN32 case 10004: return "Interrupted system call (WSAEINTR)"; case 10009: return "Bad file number (WSAEBADF)"; case 10013: return "Permission denied (WSAEACCES)"; case 10014: return "Bad address (WSAEFAULT)"; case 10022: return "Invalid argument (WSAEINVAL)"; case 10024: return "Too many open files (WSAEMFILE)"; case 10035: return "Operation would block (WSAEWOULDBLOCK)"; case 10036: return "Operation now in progress (WSAEINPROGRESS)"; case 10037: return "Operation already in progress (WSAEALREADY)"; case 10038: return "Socket operation on non-socket (WSAENOTSOCK)"; case 10039: return "Destination address required (WSAEDESTADDRREQ)"; case 10040: return "Message too long (WSAEMSGSIZE)"; case 10041: return "Protocol wrong type for socket (WSAEPROTOTYPE)"; case 10042: return "Bad protocol option (WSAENOPROTOOPT)"; case 10043: return "Protocol not supported (WSAEPROTONOSUPPORT)"; case 10044: return "Socket type not supported (WSAESOCKTNOSUPPORT)"; case 10045: return "Operation not supported on socket (WSAEOPNOTSUPP)"; case 10046: return "Protocol family not supported (WSAEPFNOSUPPORT)"; case 10047: return "Address family not supported by protocol family (WSAEAFNOSUPPORT)"; case 10048: return "Address already in use (WSAEADDRINUSE)"; case 10049: return "Can't assign requested address (WSAEADDRNOTAVAIL)"; case 10050: return "Network is down (WSAENETDOWN)"; case 10051: return "Network is unreachable (WSAENETUNREACH)"; case 10052: return "Net dropped connection or reset (WSAENETRESET)"; case 10053: return "Software caused connection abort (WSAECONNABORTED)"; case 10054: return "Connection reset by peer (WSAECONNRESET)"; case 10055: return "No buffer space available (WSAENOBUFS)"; case 10056: return "Socket is already connected (WSAEISCONN)"; case 10057: return "Socket is not connected (WSAENOTCONN)"; case 10058: return "Can't send after socket shutdown (WSAESHUTDOWN)"; case 10059: return "Too many references, can't splice (WSAETOOMANYREFS)"; case 10060: return "Connection timed out (WSAETIMEDOUT)"; case 10061: return "Connection refused (WSAECONNREFUSED)"; case 10062: return "Too many levels of symbolic links (WSAELOOP)"; case 10063: return "File name too long (WSAENAMETOOLONG)"; case 10064: return "Host is down (WSAEHOSTDOWN)"; case 10065: return "No Route to Host (WSAEHOSTUNREACH)"; case 10066: return "Directory not empty (WSAENOTEMPTY)"; case 10067: return "Too many processes (WSAEPROCLIM)"; case 10068: return "Too many users (WSAEUSERS)"; case 10069: return "Disc Quota Exceeded (WSAEDQUOT)"; case 10070: return "Stale NFS file handle (WSAESTALE)"; case 10091: return "Network SubSystem is unavailable (WSASYSNOTREADY)"; case 10092: return "WINSOCK DLL Version out of range (WSAVERNOTSUPPORTED)"; case 10093: return "Successful WSASTARTUP not yet performed (WSANOTINITIALISED)"; case 10071: return "Too many levels of remote in path (WSAEREMOTE)"; case 11001: return "Host not found (WSAHOST_NOT_FOUND)"; case 11002: return "Non-Authoritative Host not found (WSATRY_AGAIN)"; case 11003: return "Non-Recoverable errors: FORMERR, REFUSED, NOTIMP (WSANO_RECOVERY)"; case 11004: return "Valid name, no data record of requested type (WSANO_DATA)"; #if 0 case 11004: /* typically, only WSANO_DATA is reported */ return "No address, look for MX record (WSANO_ADDRESS)"; #endif #endif /* defined USE_WIN32 */ default: return strerror(errnum); } } /* replace non-UTF-8 and non-printable control characters with '.' */ NOEXPORT void safestring(char *c) { for(; *c; ++c) if(!(*c&0x80 || isprint((int)*c))) *c='.'; } /* end of log.c */ stunnel-5.30/src/ctx.c0000664000175000017500000010510512646221043011607 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #include "common.h" #include "prototypes.h" #ifndef OPENSSL_NO_DH DH *dh_params=NULL; int dh_needed=0; #endif /* OPENSSL_NO_DH */ /**************************************** prototypes */ /* SNI */ #ifndef OPENSSL_NO_TLSEXT NOEXPORT int servername_cb(SSL *, int *, void *); NOEXPORT int matches_wildcard(char *, char *); #endif /* DH/ECDH */ #ifndef OPENSSL_NO_DH NOEXPORT int dh_init(SERVICE_OPTIONS *); NOEXPORT DH *dh_read(char *); #endif /* OPENSSL_NO_DH */ #ifndef OPENSSL_NO_ECDH NOEXPORT int ecdh_init(SERVICE_OPTIONS *); #endif /* USE_ECDH */ /* configuration commands */ NOEXPORT int conf_init(SERVICE_OPTIONS *section); /* authentication */ NOEXPORT int auth_init(SERVICE_OPTIONS *); #ifndef OPENSSL_NO_PSK NOEXPORT unsigned psk_client_callback(SSL *, const char *, char *, unsigned, unsigned char *, unsigned); NOEXPORT unsigned psk_server_callback(SSL *, const char *, unsigned char *, unsigned); #endif /* !defined(OPENSSL_NO_PSK) */ NOEXPORT int load_cert_file(SERVICE_OPTIONS *); NOEXPORT int load_key_file(SERVICE_OPTIONS *); #ifndef OPENSSL_NO_ENGINE NOEXPORT int load_cert_engine(SERVICE_OPTIONS *); NOEXPORT int load_key_engine(SERVICE_OPTIONS *); #endif NOEXPORT int password_cb(char *, int, int, void *); /* session callbacks */ NOEXPORT int sess_new_cb(SSL *, SSL_SESSION *); NOEXPORT SSL_SESSION *sess_get_cb(SSL *, unsigned char *, int, int *); NOEXPORT void sess_remove_cb(SSL_CTX *, SSL_SESSION *); /* sessiond interface */ NOEXPORT void cache_new(SSL *, SSL_SESSION *); NOEXPORT SSL_SESSION *cache_get(SSL *, unsigned char *, int); NOEXPORT void cache_remove(SSL_CTX *, SSL_SESSION *); NOEXPORT void cache_transfer(SSL_CTX *, const u_char, const long, const u_char *, const size_t, const u_char *, const size_t, unsigned char **, size_t *); /* info callbacks */ NOEXPORT void info_callback(const SSL *, int, int); NOEXPORT void sslerror_queue(void); NOEXPORT void sslerror_log(unsigned long, char *); /**************************************** initialize section->ctx */ #if OPENSSL_VERSION_NUMBER<0x10100000L typedef long SSL_OPTIONS_TYPE; #else /* OpenSSL >= 1.1.0 */ typedef long unsigned SSL_OPTIONS_TYPE; #endif int context_init(SERVICE_OPTIONS *section) { /* init SSL context */ /* create SSL context */ if(section->option.client) section->ctx=SSL_CTX_new(section->client_method); else /* server mode */ section->ctx=SSL_CTX_new(section->server_method); if(!section->ctx) { sslerror("SSL_CTX_new"); return 1; /* FAILED */ } SSL_CTX_set_ex_data(section->ctx, index_opt, section); /* for callbacks */ /* load certificate and private key to be verified by the peer server */ #if !defined(OPENSSL_NO_ENGINE) && OPENSSL_VERSION_NUMBER>=0x0090809fL /* SSL_CTX_set_client_cert_engine() was introduced in OpenSSL 0.9.8i */ if(section->option.client && section->engine) { if(SSL_CTX_set_client_cert_engine(section->ctx, section->engine)) s_log(LOG_INFO, "Client certificate engine (%s) enabled", ENGINE_get_id(section->engine)); else /* no client certificate functionality in this engine */ sslerror("SSL_CTX_set_client_cert_engine"); /* ignore error */ } #endif if(auth_init(section)) return 1; /* FAILED */ /* initialize verification of the peer server certificate */ if(verify_init(section)) return 1; /* FAILED */ /* initialize DH/ECDH server mode */ if(!section->option.client) { #ifndef OPENSSL_NO_TLSEXT SSL_CTX_set_tlsext_servername_arg(section->ctx, section); SSL_CTX_set_tlsext_servername_callback(section->ctx, servername_cb); #endif /* OPENSSL_NO_TLSEXT */ #ifndef OPENSSL_NO_DH dh_init(section); /* ignore the result (errors are not critical) */ #endif /* OPENSSL_NO_DH */ #ifndef OPENSSL_NO_ECDH ecdh_init(section); /* ignore the result (errors are not critical) */ #endif /* OPENSSL_NO_ECDH */ } /* setup session cache */ if(!section->option.client) { unsigned servname_len=(unsigned)strlen(section->servname); if(servname_len>SSL_MAX_SSL_SESSION_ID_LENGTH) servname_len=SSL_MAX_SSL_SESSION_ID_LENGTH; if(!SSL_CTX_set_session_id_context(section->ctx, (unsigned char *)section->servname, servname_len)) { sslerror("SSL_CTX_set_session_id_context"); return 1; /* FAILED */ } } #ifdef SSL_SESS_CACHE_NO_INTERNAL_STORE /* the default cache mode is just SSL_SESS_CACHE_SERVER */ SSL_CTX_set_session_cache_mode(section->ctx, SSL_SESS_CACHE_SERVER|SSL_SESS_CACHE_NO_INTERNAL_STORE); #endif SSL_CTX_sess_set_cache_size(section->ctx, section->session_size); SSL_CTX_set_timeout(section->ctx, section->session_timeout); SSL_CTX_sess_set_new_cb(section->ctx, sess_new_cb); SSL_CTX_sess_set_get_cb(section->ctx, sess_get_cb); SSL_CTX_sess_set_remove_cb(section->ctx, sess_remove_cb); /* set info callback */ SSL_CTX_set_info_callback(section->ctx, info_callback); /* ciphers, options, mode */ if(section->cipher_list) if(!SSL_CTX_set_cipher_list(section->ctx, section->cipher_list)) { sslerror("SSL_CTX_set_cipher_list"); return 1; /* FAILED */ } SSL_CTX_set_options(section->ctx, (SSL_OPTIONS_TYPE)(section->ssl_options_set)); #if OPENSSL_VERSION_NUMBER>=0x009080dfL SSL_CTX_clear_options(section->ctx, (SSL_OPTIONS_TYPE)(section->ssl_options_clear)); s_log(LOG_DEBUG, "SSL options: 0x%08lX (+0x%08lX, -0x%08lX)", SSL_CTX_get_options(section->ctx), section->ssl_options_set, section->ssl_options_clear); #else /* OpenSSL older than 0.9.8m */ s_log(LOG_DEBUG, "SSL options: 0x%08lX (+0x%08lX)", SSL_CTX_get_options(section->ctx), section->ssl_options_set); #endif /* OpenSSL 0.9.8m or later */ /* initialize OpenSSL CONF options */ if(conf_init(section)) return 1; /* FAILED */ #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode(section->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_RELEASE_BUFFERS); #else SSL_CTX_set_mode(section->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); #endif return 0; /* OK */ } /**************************************** SNI callback */ #ifndef OPENSSL_NO_TLSEXT NOEXPORT int servername_cb(SSL *ssl, int *ad, void *arg) { SERVICE_OPTIONS *section=(SERVICE_OPTIONS *)arg; const char *servername=SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); SERVERNAME_LIST *list; CLI *c; #ifdef USE_LIBWRAP char *accepted_address; #endif /* USE_LIBWRAP */ /* leave the alert type at SSL_AD_UNRECOGNIZED_NAME */ (void)ad; /* squash the unused parameter warning */ if(!section->servername_list_head) { s_log(LOG_DEBUG, "SNI: no virtual services defined"); return SSL_TLSEXT_ERR_OK; } if(!servername) { s_log(LOG_NOTICE, "SNI: no servername received"); return SSL_TLSEXT_ERR_NOACK; } s_log(LOG_INFO, "SNI: requested servername: %s", servername); for(list=section->servername_list_head; list; list=list->next) if(matches_wildcard((char *)servername, list->servername)) { s_log(LOG_DEBUG, "SNI: matched pattern: %s", list->servername); c=SSL_get_ex_data(ssl, index_cli); c->opt=list->opt; SSL_set_SSL_CTX(ssl, c->opt->ctx); SSL_set_verify(ssl, SSL_CTX_get_verify_mode(c->opt->ctx), SSL_CTX_get_verify_callback(c->opt->ctx)); s_log(LOG_NOTICE, "SNI: switched to service [%s]", c->opt->servname); #ifdef USE_LIBWRAP accepted_address=s_ntop(&c->peer_addr, c->peer_addr_len); libwrap_auth(c, accepted_address); /* retry on a service switch */ str_free(accepted_address); #endif /* USE_LIBWRAP */ return SSL_TLSEXT_ERR_OK; } s_log(LOG_ERR, "SNI: no pattern matched servername: %s", servername); return SSL_TLSEXT_ERR_ALERT_FATAL; } /* TLSEXT callback return codes: * - SSL_TLSEXT_ERR_OK * - SSL_TLSEXT_ERR_ALERT_WARNING * - SSL_TLSEXT_ERR_ALERT_FATAL * - SSL_TLSEXT_ERR_NOACK */ NOEXPORT int matches_wildcard(char *servername, char *pattern) { ssize_t diff; if(!servername || !pattern) return 0; if(*pattern=='*') { /* wildcard comparison */ diff=(ssize_t)strlen(servername)-(ssize_t)strlen(++pattern); if(diff<0) /* pattern longer than servername */ return 0; servername+=diff; } return !strcasecmp(servername, pattern); } #endif /* OPENSSL_NO_TLSEXT */ /**************************************** DH initialization */ #ifndef OPENSSL_NO_DH NOEXPORT int dh_init(SERVICE_OPTIONS *section) { DH *dh=NULL; s_log(LOG_DEBUG, "DH initialization"); #ifndef OPENSSL_NO_ENGINE if(!section->engine) /* cert is a file and not an identifier */ #endif dh=dh_read(section->cert); if(dh) { SSL_CTX_set_tmp_dh(section->ctx, dh); s_log(LOG_INFO, "%d-bit DH parameters loaded", 8*DH_size(dh)); DH_free(dh); return 0; /* OK */ } CRYPTO_r_lock(stunnel_locks[LOCK_DH]); SSL_CTX_set_tmp_dh(section->ctx, dh_params); CRYPTO_r_unlock(stunnel_locks[LOCK_DH]); dh_needed=1; /* generate temporary DH parameters in cron */ section->option.dh_needed=1; /* update this context */ s_log(LOG_INFO, "Using dynamic DH parameters"); return 0; /* OK */ } NOEXPORT DH *dh_read(char *cert) { DH *dh; BIO *bio; if(!cert) { s_log(LOG_DEBUG, "No certificate available to load DH parameters"); return NULL; /* FAILED */ } bio=BIO_new_file(cert, "r"); if(!bio) { sslerror("BIO_new_file"); return NULL; /* FAILED */ } dh=PEM_read_bio_DHparams(bio, NULL, NULL, NULL); BIO_free(bio); if(!dh) { while(ERR_get_error()) ; /* OpenSSL error queue cleanup */ s_log(LOG_DEBUG, "Could not load DH parameters from %s", cert); return NULL; /* FAILED */ } s_log(LOG_DEBUG, "Using DH parameters from %s", cert); return dh; } #endif /* OPENSSL_NO_DH */ /**************************************** ECDH initialization */ #ifndef OPENSSL_NO_ECDH NOEXPORT int ecdh_init(SERVICE_OPTIONS *section) { EC_KEY *ecdh; s_log(LOG_DEBUG, "ECDH initialization"); ecdh=EC_KEY_new_by_curve_name(section->curve); if(!ecdh) { sslerror("EC_KEY_new_by_curve_name"); s_log(LOG_ERR, "Cannot create curve %s", OBJ_nid2ln(section->curve)); return 1; /* FAILED */ } SSL_CTX_set_tmp_ecdh(section->ctx, ecdh); EC_KEY_free(ecdh); s_log(LOG_DEBUG, "ECDH initialized with curve %s", OBJ_nid2ln(section->curve)); return 0; /* OK */ } #endif /* OPENSSL_NO_ECDH */ /**************************************** initialize OpenSSL CONF */ NOEXPORT int conf_init(SERVICE_OPTIONS *section) { #if OPENSSL_VERSION_NUMBER>=0x10002000L SSL_CONF_CTX *cctx; NAME_LIST *curr; char *cmd, *param; if(!section->config) return 0; /* OK */ cctx=SSL_CONF_CTX_new(); if(!cctx) { sslerror("SSL_CONF_CTX_new"); return 1; /* FAILED */ } SSL_CONF_CTX_set_ssl_ctx(cctx, section->ctx); SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE); SSL_CONF_CTX_set_flags(cctx, section->option.client ? SSL_CONF_FLAG_CLIENT : SSL_CONF_FLAG_SERVER); SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CERTIFICATE); for(curr=section->config; curr; curr=curr->next) { cmd=str_dup(curr->name); param=strchr(cmd, ':'); if(param) *param++='\0'; switch(SSL_CONF_cmd(cctx, cmd, param)) { case 2: s_log(LOG_DEBUG, "OpenSSL config \"%s\" set to \"%s\"", cmd, param); break; case 1: s_log(LOG_DEBUG, "OpenSSL config command \"%s\" executed", cmd); break; case -2: s_log(LOG_ERR, "OpenSSL config command \"%s\" was not recognised", cmd); str_free(cmd); SSL_CONF_CTX_free(cctx); return 1; /* FAILED */ case -3: s_log(LOG_ERR, "OpenSSL config command \"%s\" requires a parameter", cmd); str_free(cmd); SSL_CONF_CTX_free(cctx); return 1; /* FAILED */ default: sslerror("SSL_CONF_cmd"); str_free(cmd); SSL_CONF_CTX_free(cctx); return 1; /* FAILED */ } str_free(cmd); } if(!SSL_CONF_CTX_finish(cctx)) { sslerror("SSL_CONF_CTX_finish"); SSL_CONF_CTX_free(cctx); return 1; /* FAILED */ } SSL_CONF_CTX_free(cctx); #else /* OpenSSL earlier than 1.0.2 */ (void)section; /* squash the unused parameter warning */ #endif /* OpenSSL 1.0.2 or later */ return 0; /* OK */ } /**************************************** initialize authentication */ NOEXPORT int auth_init(SERVICE_OPTIONS *section) { int cert_needed=1, key_needed=1; #ifndef OPENSSL_NO_PSK if(section->psk_keys) { if(section->option.client) SSL_CTX_set_psk_client_callback(section->ctx, psk_client_callback); else SSL_CTX_set_psk_server_callback(section->ctx, psk_server_callback); } #endif /* !defined(OPENSSL_NO_PSK) */ /* load the certificate and private key */ if(!section->cert || !section->key) { s_log(LOG_DEBUG, "No certificate or private key specified"); return 0; /* OK */ } #ifndef OPENSSL_NO_ENGINE if(section->engine) { /* try to use the engine first */ cert_needed=load_cert_engine(section); key_needed=load_key_engine(section); } #endif if(cert_needed && load_cert_file(section)) return 1; /* FAILED */ if(key_needed && load_key_file(section)) return 1; /* FAILED */ /* validate the private key against the certificate */ if(!SSL_CTX_check_private_key(section->ctx)) { sslerror("Private key does not match the certificate"); return 1; /* FAILED */ } s_log(LOG_DEBUG, "Private key check succeeded"); return 0; /* OK */ } #ifndef OPENSSL_NO_PSK NOEXPORT unsigned psk_client_callback(SSL *ssl, const char *hint, char *identity, unsigned max_identity_len, unsigned char *psk, unsigned max_psk_len) { CLI *c; size_t identity_len; (void)hint; /* squash the unused parameter warning */ c=SSL_get_ex_data(ssl, index_cli); if(!c->opt->psk_selected) { s_log(LOG_ERR, "INTERNAL ERROR: No PSK identity selected"); return 0; } /* the source seems to have its buffer large enough for * the trailing null character, but the manual page says * nothing about it -- lets play safe */ identity_len=strlen(c->opt->psk_selected->identity)+1; if(identity_len>max_identity_len) { s_log(LOG_ERR, "PSK identity too long (%lu>%d bytes)", (long unsigned)identity_len, max_psk_len); return 0; } if(c->opt->psk_selected->key_len>max_psk_len) { s_log(LOG_ERR, "PSK too long (%lu>%d bytes)", (long unsigned)c->opt->psk_selected->key_len, max_psk_len); return 0; } strcpy(identity, c->opt->psk_selected->identity); memcpy(psk, c->opt->psk_selected->key_val, c->opt->psk_selected->key_len); s_log(LOG_INFO, "PSK client configured for identity \"%s\"", identity); return (unsigned)(c->opt->psk_selected->key_len); } NOEXPORT unsigned psk_server_callback(SSL *ssl, const char *identity, unsigned char *psk, unsigned max_psk_len) { CLI *c; PSK_KEYS *found; size_t len; c=SSL_get_ex_data(ssl, index_cli); found=psk_find(&c->opt->psk_sorted, identity); if(found) { len=found->key_len; } else { s_log(LOG_ERR, "No key found for PSK identity \"%s\"", identity); len=0; } if(len>max_psk_len) { s_log(LOG_ERR, "PSK too long (%lu>%d bytes)", (long unsigned)len, max_psk_len); len=0; } if(len) { memcpy(psk, found->key_val, len); s_log(LOG_NOTICE, "Key configured for PSK identity \"%s\"", identity); } else { /* block identity probes if possible */ if(max_psk_len>=32 && RAND_bytes(psk, 32)>0) { len=32; /* 256 random bits */ s_log(LOG_ERR, "Configured random PSK"); } else { s_log(LOG_ERR, "Rejecting with unknown_psk_identity alert"); } } return (unsigned)len; } NOEXPORT int psk_compar(const void *a, const void *b) { PSK_KEYS *x=*(PSK_KEYS **)a, *y=*(PSK_KEYS **)b; #if 0 s_log(LOG_DEBUG, "PSK cmp: %s %s", x->identity, y->identity); #endif return strcmp(x->identity, y->identity); } void psk_sort(PSK_TABLE *table, PSK_KEYS *head) { PSK_KEYS *curr; size_t i; table->num=0; for(curr=head; curr; curr=curr->next) ++table->num; s_log(LOG_INFO, "PSK identities: %lu retrieved", (long unsigned)table->num); table->val=str_alloc(table->num*sizeof(PSK_KEYS *)); for(curr=head, i=0; inum; ++i) { table->val[i]=curr; curr=curr->next; } qsort(table->val, table->num, sizeof(PSK_KEYS *), psk_compar); #if 0 for(i=0; inum; ++i) s_log(LOG_DEBUG, "PSK table: %s", table->val[i]->identity); #endif } PSK_KEYS *psk_find(const PSK_TABLE *table, const char *identity) { PSK_KEYS key, *ptr=&key, **ret; key.identity=(char *)identity; ret=bsearch(&ptr, table->val, table->num, sizeof(PSK_KEYS *), psk_compar); return ret ? *ret : NULL; } #endif /* !defined(OPENSSL_NO_PSK) */ NOEXPORT int load_cert_file(SERVICE_OPTIONS *section) { s_log(LOG_INFO, "Loading certificate from file: %s", section->cert); if(!SSL_CTX_use_certificate_chain_file(section->ctx, section->cert)) { sslerror("SSL_CTX_use_certificate_chain_file"); return 1; /* FAILED */ } s_log(LOG_INFO, "Certificate loaded from file: %s", section->cert); return 0; /* OK */ } static int cache_initialized=0; NOEXPORT int load_key_file(SERVICE_OPTIONS *section) { int i, reason; UI_DATA ui_data; s_log(LOG_INFO, "Loading private key from file: %s", section->key); if(file_permissions(section->key)) return 1; /* FAILED */ ui_data.section=section; /* setup current section for callbacks */ SSL_CTX_set_default_passwd_cb(section->ctx, password_cb); for(i=0; i<=3; i++) { if(!i && !cache_initialized) continue; /* there is no cached value */ SSL_CTX_set_default_passwd_cb_userdata(section->ctx, i ? &ui_data : NULL); /* try the cached password first */ if(SSL_CTX_use_PrivateKey_file(section->ctx, section->key, SSL_FILETYPE_PEM)) break; reason=ERR_GET_REASON(ERR_peek_error()); if(i<=2 && reason==EVP_R_BAD_DECRYPT) { sslerror_queue(); /* dump the error queue */ s_log(LOG_ERR, "Wrong pass phrase: retrying"); continue; } sslerror("SSL_CTX_use_PrivateKey_file"); return 1; /* FAILED */ } s_log(LOG_INFO, "Private key loaded from file: %s", section->key); return 0; /* OK */ } #ifndef OPENSSL_NO_ENGINE NOEXPORT int load_cert_engine(SERVICE_OPTIONS *section) { struct { const char *id; X509 *cert; } parms; s_log(LOG_INFO, "Loading certificate from engine ID: %s", section->cert); parms.id=section->cert; parms.cert=NULL; ENGINE_ctrl_cmd(section->engine, "LOAD_CERT_CTRL", 0, &parms, NULL, 1); if(!parms.cert) { sslerror("ENGINE_ctrl_cmd"); return 1; /* FAILED */ } if(!SSL_CTX_use_certificate(section->ctx, parms.cert)) { sslerror("SSL_CTX_use_certificate"); return 1; /* FAILED */ } s_log(LOG_INFO, "Certificate loaded from engine ID: %s", section->cert); return 0; /* OK */ } NOEXPORT int load_key_engine(SERVICE_OPTIONS *section) { int i, reason; UI_DATA ui_data; EVP_PKEY *pkey; UI_METHOD *ui_method; s_log(LOG_INFO, "Initializing private key on engine ID: %s", section->key); ui_data.section=section; /* setup current section for callbacks */ SSL_CTX_set_default_passwd_cb(section->ctx, password_cb); #ifdef USE_WIN32 ui_method=UI_create_method("stunnel WIN32 UI"); UI_method_set_reader(ui_method, pin_cb); #else /* USE_WIN32 */ ui_method=UI_OpenSSL(); /* workaround for broken engines */ /* ui_data.section=NULL; */ #endif /* USE_WIN32 */ for(i=1; i<=3; i++) { pkey=ENGINE_load_private_key(section->engine, section->key, ui_method, &ui_data); if(!pkey) { reason=ERR_GET_REASON(ERR_peek_error()); if(i<=2 && (reason==7 || reason==160)) { /* wrong PIN */ sslerror_queue(); /* dump the error queue */ s_log(LOG_ERR, "Wrong PIN: retrying"); continue; } sslerror("ENGINE_load_private_key"); return 1; /* FAILED */ } if(SSL_CTX_use_PrivateKey(section->ctx, pkey)) break; /* success */ sslerror("SSL_CTX_use_PrivateKey"); return 1; /* FAILED */ } s_log(LOG_INFO, "Private key initialized on engine ID: %s", section->key); return 0; /* OK */ } #endif /* !defined(OPENSSL_NO_ENGINE) */ NOEXPORT int password_cb(char *buf, int size, int rwflag, void *userdata) { static char cache[PEM_BUFSIZE]; int len; if(size>PEM_BUFSIZE) size=PEM_BUFSIZE; if(userdata) { /* prompt the user */ #ifdef USE_WIN32 len=passwd_cb(buf, size, rwflag, userdata); #else len=PEM_def_callback(buf, size, rwflag, NULL); #endif memcpy(cache, buf, (size_t)size); /* save in cache */ cache_initialized=1; } else { /* try the cached value */ strncpy(buf, cache, (size_t)size); buf[size-1]='\0'; len=(int)strlen(buf); } return len; } /**************************************** session callbacks */ NOEXPORT int sess_new_cb(SSL *ssl, SSL_SESSION *sess) { CLI *c; s_log(LOG_DEBUG, "New session callback"); c=SSL_get_ex_data(ssl, index_cli); if(c->opt->option.sessiond) cache_new(ssl, sess); return 1; /* leave the session in local cache for reuse */ } NOEXPORT SSL_SESSION *sess_get_cb(SSL *ssl, unsigned char *key, int key_len, int *do_copy) { CLI *c; s_log(LOG_DEBUG, "Get session callback"); *do_copy=0; /* allow the session to be freed automatically */ c=SSL_get_ex_data(ssl, index_cli); if(c->opt->option.sessiond) return cache_get(ssl, key, key_len); return NULL; /* no session to resume */ } NOEXPORT void sess_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess) { SERVICE_OPTIONS *opt; s_log(LOG_DEBUG, "Remove session callback"); opt=SSL_CTX_get_ex_data(ctx, index_opt); if(opt->option.sessiond) cache_remove(ctx, sess); } /**************************************** sessiond functionality */ #define CACHE_CMD_NEW 0x00 #define CACHE_CMD_GET 0x01 #define CACHE_CMD_REMOVE 0x02 #define CACHE_RESP_ERR 0x80 #define CACHE_RESP_OK 0x81 NOEXPORT void cache_new(SSL *ssl, SSL_SESSION *sess) { unsigned char *val, *val_tmp; ssize_t val_len; const unsigned char *session_id; unsigned int session_id_length; val_len=i2d_SSL_SESSION(sess, NULL); val_tmp=val=str_alloc((size_t)val_len); i2d_SSL_SESSION(sess, &val_tmp); #if OPENSSL_VERSION_NUMBER>=0x0090800fL session_id=SSL_SESSION_get_id(sess, &session_id_length); #else session_id=(const unsigned char *)sess->session_id; session_id_length=sess->session_id_length; #endif cache_transfer(SSL_get_SSL_CTX(ssl), CACHE_CMD_NEW, SSL_SESSION_get_timeout(sess), session_id, session_id_length, val, (size_t)val_len, NULL, NULL); str_free(val); } NOEXPORT SSL_SESSION *cache_get(SSL *ssl, unsigned char *key, int key_len) { unsigned char *val, *val_tmp=NULL; ssize_t val_len=0; SSL_SESSION *sess; cache_transfer(SSL_get_SSL_CTX(ssl), CACHE_CMD_GET, 0, key, (size_t)key_len, NULL, 0, &val, (size_t *)&val_len); if(!val) return NULL; val_tmp=val; sess=d2i_SSL_SESSION(NULL, #if OPENSSL_VERSION_NUMBER>=0x0090800fL (const unsigned char **) #endif /* OpenSSL version >= 0.8.0 */ &val_tmp, (long)val_len); str_free(val); return sess; } NOEXPORT void cache_remove(SSL_CTX *ctx, SSL_SESSION *sess) { const unsigned char *session_id; unsigned int session_id_length; #if OPENSSL_VERSION_NUMBER>=0x0090800fL session_id=SSL_SESSION_get_id(sess, &session_id_length); #else session_id=(const unsigned char *)sess->session_id; session_id_length=sess->session_id_length; #endif cache_transfer(ctx, CACHE_CMD_REMOVE, 0, session_id, session_id_length, NULL, 0, NULL, NULL); } #define MAX_VAL_LEN 512 typedef struct { u_char version, type; u_short timeout; u_char key[SSL_MAX_SSL_SESSION_ID_LENGTH]; u_char val[MAX_VAL_LEN]; } CACHE_PACKET; NOEXPORT void cache_transfer(SSL_CTX *ctx, const u_char type, const long timeout, const u_char *key, const size_t key_len, const u_char *val, const size_t val_len, unsigned char **ret, size_t *ret_len) { char session_id_txt[2*SSL_MAX_SSL_SESSION_ID_LENGTH+1]; const char hex[16]="0123456789ABCDEF"; const char *type_description[]={"new", "get", "remove"}; unsigned i; SOCKET s; ssize_t len; struct timeval t; CACHE_PACKET *packet; SERVICE_OPTIONS *section; if(ret) /* set error as the default result if required */ *ret=NULL; /* log the request information */ for(i=0; i>4]; session_id_txt[2*i+1]=hex[key[i]&0x0f]; } session_id_txt[2*i]='\0'; s_log(LOG_INFO, "cache_transfer: request=%s, timeout=%ld, id=%s, length=%lu", type_description[type], timeout, session_id_txt, (long unsigned)val_len); /* allocate UDP packet buffer */ if(key_len>SSL_MAX_SSL_SESSION_ID_LENGTH) { s_log(LOG_ERR, "cache_transfer: session id too big (%lu bytes)", (unsigned long)key_len); return; } if(val_len>MAX_VAL_LEN) { s_log(LOG_ERR, "cache_transfer: encoded session too big (%lu bytes)", (unsigned long)key_len); return; } packet=str_alloc(sizeof(CACHE_PACKET)); /* setup packet */ packet->version=1; packet->type=type; packet->timeout=htons((u_short)(timeout<64800?timeout:64800));/* 18 hours */ memcpy(packet->key, key, key_len); memcpy(packet->val, val, val_len); /* create the socket */ s=s_socket(AF_INET, SOCK_DGRAM, 0, 0, "cache_transfer: socket"); if(s==INVALID_SOCKET) { str_free(packet); return; } /* retrieve pointer to the section structure of this ctx */ section=SSL_CTX_get_ex_data(ctx, index_opt); if(sendto(s, (void *)packet, #ifdef USE_WIN32 (int) #endif (sizeof(CACHE_PACKET)-MAX_VAL_LEN+val_len), 0, §ion->sessiond_addr.sa, addr_len(§ion->sessiond_addr))<0) { sockerror("cache_transfer: sendto"); closesocket(s); str_free(packet); return; } if(!ret || !ret_len) { /* no response is required */ closesocket(s); str_free(packet); return; } /* set recvfrom timeout to 200ms */ t.tv_sec=0; t.tv_usec=200; if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (void *)&t, sizeof t)<0) { sockerror("cache_transfer: setsockopt SO_RCVTIMEO"); closesocket(s); str_free(packet); return; } /* retrieve response */ len=recv(s, (void *)packet, sizeof(CACHE_PACKET), 0); closesocket(s); if(len<0) { if(get_last_socket_error()==S_EWOULDBLOCK || get_last_socket_error()==S_EAGAIN) s_log(LOG_INFO, "cache_transfer: recv timeout"); else sockerror("cache_transfer: recv"); str_free(packet); return; } /* parse results */ if(len<(int)sizeof(CACHE_PACKET)-MAX_VAL_LEN || /* too short */ packet->version!=1 || /* wrong version */ safe_memcmp(packet->key, key, key_len)) { /* wrong session id */ s_log(LOG_DEBUG, "cache_transfer: malformed packet received"); str_free(packet); return; } if(packet->type!=CACHE_RESP_OK) { s_log(LOG_INFO, "cache_transfer: session not found"); str_free(packet); return; } *ret_len=(size_t)len-(sizeof(CACHE_PACKET)-MAX_VAL_LEN); *ret=str_alloc(*ret_len); s_log(LOG_INFO, "cache_transfer: session found"); memcpy(*ret, packet->val, *ret_len); str_free(packet); } /**************************************** informational callback */ NOEXPORT void info_callback(const SSL *ssl, int where, int ret) { CLI *c; SSL_CTX *ctx; const char *state_string; c=SSL_get_ex_data((SSL *)ssl, index_cli); if(c) { if((where&SSL_CB_HANDSHAKE_DONE) && c->reneg_state==RENEG_INIT) { /* first (initial) handshake was completed, remember this, * so that further renegotiation attempts can be detected */ c->reneg_state=RENEG_ESTABLISHED; } else if((where&SSL_CB_ACCEPT_LOOP) && c->reneg_state==RENEG_ESTABLISHED) { int state=SSL_get_state((SSL *)ssl); #ifndef SSL3_ST_SR_CLNT_HELLO_A if(state==TLS_ST_SR_CLNT_HELLO || state==TLS_ST_SR_CLNT_HELLO) { #else if(state==SSL3_ST_SR_CLNT_HELLO_A || state==SSL23_ST_SR_CLNT_HELLO_A) { #endif /* client hello received after initial handshake, * this means renegotiation -> mark it */ c->reneg_state=RENEG_DETECTED; } } if(c->opt->log_levelopt->option.client) { s_log(LOG_DEBUG, "%6ld client connect(s) requested", SSL_CTX_sess_connect(ctx)); s_log(LOG_DEBUG, "%6ld client connect(s) succeeded", SSL_CTX_sess_connect_good(ctx)); s_log(LOG_DEBUG, "%6ld client renegotiation(s) requested", SSL_CTX_sess_connect_renegotiate(ctx)); } else { s_log(LOG_DEBUG, "%6ld server accept(s) requested", SSL_CTX_sess_accept(ctx)); s_log(LOG_DEBUG, "%6ld server accept(s) succeeded", SSL_CTX_sess_accept_good(ctx)); s_log(LOG_DEBUG, "%6ld server renegotiation(s) requested", SSL_CTX_sess_accept_renegotiate(ctx)); } /* according to the source it not only includes internal and external session caches, but also session tickets */ s_log(LOG_DEBUG, "%6ld session reuse(s)", SSL_CTX_sess_hits(ctx)); if(!c->opt->option.client) { /* server session cache stats */ s_log(LOG_DEBUG, "%6ld internal session cache item(s)", SSL_CTX_sess_number(ctx)); s_log(LOG_DEBUG, "%6ld internal session cache fill-up(s)", SSL_CTX_sess_cache_full(ctx)); s_log(LOG_DEBUG, "%6ld internal session cache miss(es)", SSL_CTX_sess_misses(ctx)); s_log(LOG_DEBUG, "%6ld external session cache hit(s)", SSL_CTX_sess_cb_hits(ctx)); s_log(LOG_DEBUG, "%6ld expired session(s) retrieved", SSL_CTX_sess_timeouts(ctx)); } } } /**************************************** SSL error reporting */ void sslerror(char *txt) { /* OpenSSL error handler */ unsigned long err; err=ERR_get_error(); if(err) { sslerror_queue(); sslerror_log(err, txt); } else { s_log(LOG_ERR, "%s: Peer suddenly disconnected", txt); } } NOEXPORT void sslerror_queue(void) { /* recursive dump of the error queue */ unsigned long err; err=ERR_get_error(); if(err) { sslerror_queue(); sslerror_log(err, "error queue"); } } NOEXPORT void sslerror_log(unsigned long err, char *txt) { char *error_string; error_string=str_alloc(256); ERR_error_string_n(err, error_string, 256); s_log(LOG_ERR, "%s: %lX: %s", txt, err, error_string); str_free(error_string); } /* end of ctx.c */ stunnel-5.30/src/verify.c0000664000175000017500000006122712646221043012323 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #include "common.h" #include "prototypes.h" /**************************************** prototypes */ /* verify initialization */ NOEXPORT void set_client_CA_list(SERVICE_OPTIONS *section); NOEXPORT void auth_warnings(SERVICE_OPTIONS *); NOEXPORT int crl_init(SERVICE_OPTIONS *section); NOEXPORT int load_file_lookup(X509_STORE *, char *); NOEXPORT int add_dir_lookup(X509_STORE *, char *); /* verify callback */ NOEXPORT int verify_callback(int, X509_STORE_CTX *); NOEXPORT int verify_checks(CLI *, int, X509_STORE_CTX *); NOEXPORT int cert_check(CLI *, X509_STORE_CTX *, int); #if OPENSSL_VERSION_NUMBER>=0x10002000L NOEXPORT int cert_check_subject(CLI *, X509_STORE_CTX *); #endif /* OPENSSL_VERSION_NUMBER>=0x10002000L */ NOEXPORT int cert_check_local(X509_STORE_CTX *); NOEXPORT int compare_pubkeys(X509 *, X509 *); #ifndef OPENSSL_NO_OCSP NOEXPORT int ocsp_check(CLI *, X509_STORE_CTX *); NOEXPORT int ocsp_request(CLI *, X509_STORE_CTX *, OCSP_CERTID *, char *); NOEXPORT OCSP_RESPONSE *ocsp_get_response(CLI *, OCSP_REQUEST *, char *); #endif /* utility functions */ #ifndef OPENSSL_NO_OCSP NOEXPORT X509 *get_current_issuer(X509_STORE_CTX *); NOEXPORT void log_time(const int, const char *, ASN1_TIME *); #endif /**************************************** verify initialization */ int verify_init(SERVICE_OPTIONS *section) { int verify_mode=0; /* CA initialization */ if(section->ca_file || section->ca_dir) { if(!SSL_CTX_load_verify_locations(section->ctx, section->ca_file, section->ca_dir)) { sslerror("SSL_CTX_load_verify_locations"); return 1; /* FAILED */ } } if(section->ca_file && !section->option.client) set_client_CA_list(section); /* only performed on the server */ /* CRL initialization */ if(section->crl_file || section->crl_dir) if(crl_init(section)) return 1; /* FAILED */ /* verify callback setup */ if(section->verify_level>=0) verify_mode|=SSL_VERIFY_PEER; if(section->verify_level>=2 && !section->redirect_addr.names) verify_mode|=SSL_VERIFY_FAIL_IF_NO_PEER_CERT; SSL_CTX_set_verify(section->ctx, verify_mode, verify_callback); auth_warnings(section); return 0; /* OK */ } /* trusted CA names sent to clients for client cert selection */ NOEXPORT void set_client_CA_list(SERVICE_OPTIONS *section) { STACK_OF(X509_NAME) *ca_dn; char *ca_name; int i; s_log(LOG_DEBUG, "Client CA list: %s", section->ca_file); ca_dn=SSL_load_client_CA_file(section->ca_file); for(i=0; ictx, ca_dn); } int crl_init(SERVICE_OPTIONS *section) { X509_STORE *store; store=SSL_CTX_get_cert_store(section->ctx); if(section->crl_file) { if(load_file_lookup(store, section->crl_file)) return 1; /* FAILED */ } if(section->crl_dir) { store->cache=0; /* don't cache CRLs */ if(add_dir_lookup(store, section->crl_dir)) return 1; /* FAILED */ } X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK); return 0; /* OK */ } NOEXPORT int load_file_lookup(X509_STORE *store, char *name) { X509_LOOKUP *lookup; lookup=X509_STORE_add_lookup(store, X509_LOOKUP_file()); if(!lookup) { sslerror("X509_STORE_add_lookup(X509_LOOKUP_file)"); return 1; /* FAILED */ } if(!X509_load_crl_file(lookup, name, X509_FILETYPE_PEM)) { s_log(LOG_ERR, "Failed to load %s revocation lookup file", name); sslerror("X509_load_crl_file"); return 1; /* FAILED */ } s_log(LOG_DEBUG, "Loaded %s revocation lookup file", name); return 0; /* OK */ } NOEXPORT int add_dir_lookup(X509_STORE *store, char *name) { X509_LOOKUP *lookup; lookup=X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); if(!lookup) { sslerror("X509_STORE_add_lookup(X509_LOOKUP_hash_dir)"); return 1; /* FAILED */ } if(!X509_LOOKUP_add_dir(lookup, name, X509_FILETYPE_PEM)) { s_log(LOG_ERR, "Failed to add %s revocation lookup directory", name); sslerror("X509_LOOKUP_add_dir"); return 1; /* FAILED */ } s_log(LOG_DEBUG, "Added %s revocation lookup directory", name); return 0; /* OK */ } /* issue warnings on insecure/missing authentication */ NOEXPORT void auth_warnings(SERVICE_OPTIONS *section) { #ifndef OPENSSL_NO_PSK if(section->psk_keys) return; #endif /* !defined(OPENSSL_NO_PSK) */ /* for servers it is usually okay to accept all client certificates signed by a specified certificate authority */ if(!section->option.client) return; if(section->verify_level<2) { s_log(LOG_WARNING, "Service [%s] needs authentication to prevent MITM attacks", section->servname); return; } if(section->verify_level>=3) /* levels>=3 don't rely on PKI */ return; #if OPENSSL_VERSION_NUMBER>=0x10002000L if(section->check_email || section->check_host || section->check_ip) return; #endif /* OPENSSL_VERSION_NUMBER>=0x10002000L */ s_log(LOG_WARNING, "Service [%s] uses \"verify = 2\" without subject checks", section->servname); #if OPENSSL_VERSION_NUMBER<0x10002000L s_log(LOG_WARNING, "Rebuild your stunnel against OpenSSL version 1.0.2 or higher"); #endif /* OPENSSL_VERSION_NUMBER<0x10002000L */ s_log(LOG_WARNING, "Use \"checkHost\" or \"checkIP\" to restrict trusted certificates"); } /**************************************** verify callback */ NOEXPORT int verify_callback(int preverify_ok, X509_STORE_CTX *callback_ctx) { /* our verify callback function */ SSL *ssl; CLI *c; /* retrieve application specific data */ ssl=X509_STORE_CTX_get_ex_data(callback_ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); c=SSL_get_ex_data(ssl, index_cli); if(c->opt->verify_level<1) { s_log(LOG_INFO, "Certificate verification disabled"); return 1; /* accept */ } if(verify_checks(c, preverify_ok, callback_ctx)) return 1; /* accept */ if(c->opt->option.client || c->opt->protocol) return 0; /* reject */ if(c->opt->redirect_addr.names) { c->redirect=REDIRECT_ON; return 1; /* accept */ } return 0; /* reject */ } NOEXPORT int verify_checks(CLI *c, int preverify_ok, X509_STORE_CTX *callback_ctx) { X509 *cert; int depth; char *subject; cert=X509_STORE_CTX_get_current_cert(callback_ctx); depth=X509_STORE_CTX_get_error_depth(callback_ctx); subject=X509_NAME2text(X509_get_subject_name(cert)); s_log(LOG_DEBUG, "Verification started at depth=%d: %s", depth, subject); if(!cert_check(c, callback_ctx, preverify_ok)) { s_log(LOG_WARNING, "Rejected by CERT at depth=%d: %s", depth, subject); str_free(subject); return 0; /* reject */ } #ifndef OPENSSL_NO_OCSP if((c->opt->ocsp_url || c->opt->option.aia) && !ocsp_check(c, callback_ctx)) { s_log(LOG_WARNING, "Rejected by OCSP at depth=%d: %s", depth, subject); str_free(subject); return 0; /* reject */ } #endif /* !defined(OPENSSL_NO_OCSP) */ s_log(depth ? LOG_INFO : LOG_NOTICE, "Certificate accepted at depth=%d: %s", depth, subject); str_free(subject); return 1; /* accept */ } /**************************************** certificate checking */ NOEXPORT int cert_check(CLI *c, X509_STORE_CTX *callback_ctx, int preverify_ok) { int depth=X509_STORE_CTX_get_error_depth(callback_ctx); if(preverify_ok) { s_log(LOG_DEBUG, "CERT: Pre-verification succeeded"); } else { /* remote site sent an invalid certificate */ if(c->opt->verify_level>=4 && depth>0) { s_log(LOG_INFO, "CERT: Invalid CA certificate ignored"); return 1; /* accept */ } s_log(LOG_WARNING, "CERT: Pre-verification error: %s", X509_verify_cert_error_string( X509_STORE_CTX_get_error(callback_ctx))); /* retain the STORE_CTX error produced by pre-verification */ return 0; /* reject */ } if(depth==0) { /* additional peer certificate checks */ #if OPENSSL_VERSION_NUMBER>=0x10002000L if(!cert_check_subject(c, callback_ctx)) return 0; /* reject */ #endif /* OPENSSL_VERSION_NUMBER>=0x10002000L */ if(c->opt->verify_level>=3 && !cert_check_local(callback_ctx)) return 0; /* reject */ } return 1; /* accept */ } #if OPENSSL_VERSION_NUMBER>=0x10002000L NOEXPORT int cert_check_subject(CLI *c, X509_STORE_CTX *callback_ctx) { X509 *cert=X509_STORE_CTX_get_current_cert(callback_ctx); NAME_LIST *ptr; char *peername=NULL; if(c->opt->check_host) { for(ptr=c->opt->check_host; ptr; ptr=ptr->next) if(X509_check_host(cert, ptr->name, 0, 0, &peername)>0) break; if(!ptr) { s_log(LOG_WARNING, "CERT: No matching host name found"); return 0; /* reject */ } s_log(LOG_INFO, "CERT: Host name \"%s\" matched with \"%s\"", ptr->name, peername); OPENSSL_free(peername); } if(c->opt->check_email) { for(ptr=c->opt->check_email; ptr; ptr=ptr->next) if(X509_check_email(cert, ptr->name, 0, 0)>0) break; if(!ptr) { s_log(LOG_WARNING, "CERT: No matching email address found"); return 0; /* reject */ } s_log(LOG_INFO, "CERT: Email address \"%s\" matched", ptr->name); } if(c->opt->check_ip) { for(ptr=c->opt->check_ip; ptr; ptr=ptr->next) if(X509_check_ip_asc(cert, ptr->name, 0)>0) break; if(!ptr) { s_log(LOG_WARNING, "CERT: No matching IP address found"); return 0; /* reject */ } s_log(LOG_INFO, "CERT: IP address \"%s\" matched", ptr->name); } return 1; /* accept */ } #endif /* OPENSSL_VERSION_NUMBER>=0x10002000L */ NOEXPORT int cert_check_local(X509_STORE_CTX *callback_ctx) { X509 *cert; X509_NAME *subject; #if OPENSSL_VERSION_NUMBER>=0x10000000L STACK_OF(X509) *sk; int i; #endif X509_OBJECT obj; int success; cert=X509_STORE_CTX_get_current_cert(callback_ctx); subject=X509_get_subject_name(cert); #if OPENSSL_VERSION_NUMBER>=0x10000000L /* modern API allows retrieving multiple matching certificates */ sk=X509_STORE_get1_certs(callback_ctx, subject); if(sk) { for(i=0; ilength!=k2->length || k1->length<0 || safe_memcmp(k1->data, k2->data, (size_t)k1->length)) return 0; /* reject */ s_log(LOG_INFO, "CERT: Locally installed certificate matched"); return 1; /* accept */ } /**************************************** OCSP checking */ #ifndef OPENSSL_NO_OCSP #ifdef DEFINE_STACK_OF /* defined in openssl/safestack.h: * DEFINE_SPECIAL_STACK_OF(OPENSSL_STRING, char) */ #else /* DEFINE_STACK_OF */ #ifndef sk_OPENSSL_STRING_num #define sk_OPENSSL_STRING_num(st) sk_num(st) #endif /* sk_OPENSSL_STRING_num */ #ifndef sk_OPENSSL_STRING_value #define sk_OPENSSL_STRING_value(st, i) sk_value((st),(i)) #endif /* sk_OPENSSL_STRING_value */ #endif /* DEFINE_STACK_OF */ NOEXPORT int ocsp_check(CLI *c, X509_STORE_CTX *callback_ctx) { X509 *cert; OCSP_CERTID *cert_id; STACK_OF(OPENSSL_STRING) *aia; int i, ocsp_status=V_OCSP_CERTSTATUS_UNKNOWN, saved_error; char *url; /* the original error code is restored unless we report our own error */ saved_error=X509_STORE_CTX_get_error(callback_ctx); /* get the current certificate ID */ cert=X509_STORE_CTX_get_current_cert(callback_ctx); if(!cert) { s_log(LOG_ERR, "OCSP: Failed to get the current certificate"); X509_STORE_CTX_set_error(callback_ctx, X509_V_ERR_APPLICATION_VERIFICATION); return 0; /* reject */ } if(!X509_NAME_cmp(X509_get_subject_name(cert), X509_get_issuer_name(cert))) { s_log(LOG_DEBUG, "OCSP: Ignoring root certificate"); return 1; /* accept */ } cert_id=OCSP_cert_to_id(NULL, cert, get_current_issuer(callback_ctx)); if(!cert_id) { sslerror("OCSP: OCSP_cert_to_id"); X509_STORE_CTX_set_error(callback_ctx, X509_V_ERR_APPLICATION_VERIFICATION); return 0; /* reject */ } /* use the responder specified in the configuration file */ if(c->opt->ocsp_url) { s_log(LOG_NOTICE, "OCSP: Connecting the configured responder \"%s\"", c->opt->ocsp_url); if(ocsp_request(c, callback_ctx, cert_id, c->opt->ocsp_url)!= V_OCSP_CERTSTATUS_GOOD) { OCSP_CERTID_free(cert_id); return 0; /* reject */ } } /* use the responder from AIA (Authority Information Access) */ if(c->opt->option.aia && (aia=X509_get1_ocsp(cert))) { for(i=0; iopt->option.nonce) OCSP_request_add1_nonce(request, NULL, -1); /* send the request and get a response */ response=ocsp_get_response(c, request, url); if(!response) goto cleanup; response_status=OCSP_response_status(response); if(response_status!=OCSP_RESPONSE_STATUS_SUCCESSFUL) { s_log(LOG_ERR, "OCSP: Responder error: %d: %s", response_status, OCSP_response_status_str(response_status)); goto cleanup; } /* verify the response */ basic_response=OCSP_response_get1_basic(response); if(!basic_response) { sslerror("OCSP: OCSP_response_get1_basic"); goto cleanup; } if(c->opt->option.nonce && OCSP_check_nonce(request, basic_response)<=0) { s_log(LOG_ERR, "OCSP: Invalid or unsupported nonce"); goto cleanup; } if(OCSP_basic_verify(basic_response, X509_STORE_CTX_get_chain(callback_ctx), SSL_CTX_get_cert_store(c->opt->ctx), c->opt->ocsp_flags)<=0) { sslerror("OCSP: OCSP_basic_verify"); goto cleanup; } if(!OCSP_resp_find_status(basic_response, cert_id, &ocsp_status, &reason, &revoked_at, &this_update, &next_update)) { sslerror("OCSP: OCSP_resp_find_status"); goto cleanup; } s_log(LOG_INFO, "OCSP: Status: %s", OCSP_cert_status_str(ocsp_status)); log_time(LOG_INFO, "OCSP: This update", this_update); log_time(LOG_INFO, "OCSP: Next update", next_update); /* check if the response is valid for at least one minute */ if(!OCSP_check_validity(this_update, next_update, 60, -1)) { sslerror("OCSP: OCSP_check_validity"); ocsp_status=V_OCSP_CERTSTATUS_UNKNOWN; goto cleanup; } switch(ocsp_status) { case V_OCSP_CERTSTATUS_GOOD: s_log(LOG_NOTICE, "OCSP: Certificate accepted"); break; case V_OCSP_CERTSTATUS_REVOKED: if(reason==-1) s_log(LOG_ERR, "OCSP: Certificate revoked"); else s_log(LOG_ERR, "OCSP: Certificate revoked: %d: %s", reason, OCSP_crl_reason_str(reason)); log_time(LOG_NOTICE, "OCSP: Revoked at", revoked_at); ctx_err=X509_V_ERR_CERT_REVOKED; break; case V_OCSP_CERTSTATUS_UNKNOWN: s_log(LOG_WARNING, "OCSP: Unknown verification status"); } cleanup: if(request) OCSP_REQUEST_free(request); if(response) OCSP_RESPONSE_free(response); if(basic_response) OCSP_BASICRESP_free(basic_response); if(ocsp_status!=V_OCSP_CERTSTATUS_GOOD) X509_STORE_CTX_set_error(callback_ctx, ctx_err); return ocsp_status; } NOEXPORT OCSP_RESPONSE *ocsp_get_response(CLI *c, OCSP_REQUEST *req, char *url) { BIO *bio=NULL; OCSP_REQ_CTX *req_ctx=NULL; OCSP_RESPONSE *resp=NULL; char *host=NULL, *port=NULL, *path=NULL; SOCKADDR_UNION addr; int ssl; /* parse the OCSP URL */ if(!OCSP_parse_url(url, &host, &port, &path, &ssl)) { s_log(LOG_ERR, "OCSP: Failed to parse the OCSP URL"); goto cleanup; } if(ssl) { s_log(LOG_ERR, "OCSP: SSL not supported for OCSP" " - an additional stunnel service needs to be defined"); goto cleanup; } if(!hostport2addr(&addr, host, port, 0)) { s_log(LOG_ERR, "OCSP: Failed to resolve the OCSP responder address"); goto cleanup; } /* connect specified OCSP responder */ c->fd=s_socket(addr.sa.sa_family, SOCK_STREAM, 0, 1, "OCSP: socket"); if(c->fd==INVALID_SOCKET) goto cleanup; if(s_connect(c, &addr, addr_len(&addr))) goto cleanup; bio=BIO_new_socket((int)c->fd, BIO_NOCLOSE); if(!bio) { sslerror("OCSP: BIO_new_socket"); goto cleanup; } s_log(LOG_DEBUG, "OCSP: Connected %s:%s", host, port); /* initialize an HTTP request with the POST method */ #if OPENSSL_VERSION_NUMBER>=0x10000000L req_ctx=OCSP_sendreq_new(bio, path, NULL, -1); #else /* there is no way to send the Host header with older OpenSSL versions */ req_ctx=OCSP_sendreq_new(bio, path, req, -1); #endif if(!req_ctx) { sslerror("OCSP: OCSP_sendreq_new"); goto cleanup; } #if OPENSSL_VERSION_NUMBER>=0x10000000L /* add the HTTP headers */ if(!OCSP_REQ_CTX_add1_header(req_ctx, "Host", host)) { sslerror("OCSP: OCSP_REQ_CTX_add1_header"); goto cleanup; } if(!OCSP_REQ_CTX_add1_header(req_ctx, "User-Agent", "stunnel")) { sslerror("OCSP: OCSP_REQ_CTX_add1_header"); goto cleanup; } /* add the remaining HTTP headers and the OCSP request body */ if(!OCSP_REQ_CTX_set1_req(req_ctx, req)) { sslerror("OCSP: OCSP_REQ_CTX_set1_req"); goto cleanup; } #endif /* OCSP protocol communication loop */ while(OCSP_sendreq_nbio(&resp, req_ctx)==-1) { s_poll_init(c->fds); s_poll_add(c->fds, c->fd, BIO_should_read(bio), BIO_should_write(bio)); switch(s_poll_wait(c->fds, c->opt->timeout_busy, 0)) { case -1: sockerror("OCSP: s_poll_wait"); goto cleanup; case 0: s_log(LOG_INFO, "OCSP: s_poll_wait: TIMEOUTbusy exceeded"); goto cleanup; } } #if 0 s_log(LOG_DEBUG, "OCSP: context state: 0x%x", *(int *)req_ctx); #endif /* http://www.mail-archive.com/openssl-users@openssl.org/msg61691.html */ if(resp) { s_log(LOG_DEBUG, "OCSP: Response received"); } else { if(ERR_peek_error()) sslerror("OCSP: OCSP_sendreq_nbio"); else /* OpenSSL error: OCSP_sendreq_nbio does not use OCSPerr */ s_log(LOG_ERR, "OCSP: OCSP_sendreq_nbio: OpenSSL internal error"); } cleanup: if(req_ctx) OCSP_REQ_CTX_free(req_ctx); if(bio) BIO_free_all(bio); if(c->fd!=INVALID_SOCKET) { closesocket(c->fd); c->fd=INVALID_SOCKET; /* avoid double close on cleanup */ } if(host) OPENSSL_free(host); if(port) OPENSSL_free(port); if(path) OPENSSL_free(path); return resp; } /* find the issuer certificate without lookups */ NOEXPORT X509 *get_current_issuer(X509_STORE_CTX *callback_ctx) { STACK_OF(X509) *chain; int depth; chain=X509_STORE_CTX_get_chain(callback_ctx); depth=X509_STORE_CTX_get_error_depth(callback_ctx); if(depth makece ARMV4 all :: NEVER DO makece clean ! but makece TARGETCPU clean ! :: Note : adapt EVC/bin/WCE.bat scripts Title WCE STUNNEL :: !!!!!!!!!!!!!! :: CUSTOMIZE THIS according to your EVC INSTALLED ENVIRONMENT :: !!!!!!!!!!!!!! set OSVERSION=WCE420 set PLATFORM=STANDARDSDK set WCEROOT=C:\Program Files\MSEVC4 set SDKROOT=C:\Program Files\Microsoft SDKs :: !!!!!!!!!!!!!!!!!! :: END CUSTOMIZATION :: !!!!!!!!!!!!!!!!!! :: Define TARGET CPU :: ----------------- :: define "new" target (useful if one wants to compile for various WCE target CPUs) if "%1"=="" echo "USAGE : makece TARGETCPU other_make_options..." if "%1"=="" echo "TARGETCPU=(ARMV4|ARMV4I|ARMV4T|MIPS16|MIPSII|MIPSII_FP|MIPSIV|MIPSIV_FP|SH3|SH4|X86), other cpu: see bat scripts in evc/bin" if "%1"=="" echo "!!! do not hesitate to adapt evc.mak for CPU and/or better compilation flags !!!" if "%1"=="" exit /B :: old code to default to ARMV4, but it is better that users are WARNED that the script now need an explicit target! ::if "%1"=="" set NEWTGTCPU=ARMV4 if NOT DEFINED TARGETCPU set TARGETCPU=XXXXX if NOT "%1"=="" set NEWTGTCPU=%1 if NOT "%1"=="" shift echo WCE TARGET CPU is %NEWTGTCPU% rem Adjust MS EVC env vars rem ---------------------- rem Check MSenv vars against our ref values set isenvok=0 if "%NEWTGTCPU%"=="%TARGETCPU%" set /A "isenvok+=1" if %isenvok%==1 echo WCE ENVIRONMENT OK if %isenvok%==1 goto envisok :: useless since separated tgt folders ::echo WCE TARGET CPU changed, destroying every obj files ::del .\*.obj :: if env is NOT ok, adjust MS EVC env vars to be used by MS WCE.BAT :: (this is to avoid repetitive pollution of PATH) echo WCE ENVIRONMENT ADJUSTED :: call "%WCEROOT%\EVC\WCE420\BIN\WCE%NEWTGTCPU%.BAT" call "%WCEROOT%\EVC\%OSVERSION%\bin\WCE%NEWTGTCPU%.BAT" set TARGETCPU=%NEWTGTCPU% :envisok ::exit /B rem make everything rem --------------- nmake /NOLOGO -f evc.mak %1 %2 %3 %4 %5 %6 %7 %8 %9 stunnel-5.30/src/mingw.mak0000664000175000017500000001522212632527653012473 00000000000000# Simple Makefile.w32 for stunnel.exe by Michal Trojnara 1998-2007 # # Modified by Brian Hatch (bri@stunnel.org) # 20101030 pdelaage: # + multi-HOST management (if used on Windows host or Linux Host) # + lack of gnu-win32 (rm) detection # note: rm is used INTERNALLY by gcc for deletion if intermediate files. # This makefile is only tested on the mingw compiler. Mingw can successfully # compile both openssl and stunnel. If you want to use another compiler, give # it a shot, and tell us how it went. # pdelaage : THIS makefile can be used with mingw-make on Windows or gnu make # on Linux, to produce the Win32 version of stunnel (target is win32). It # requires, on Windows, the use of gnu-win32 tools: rm, mkdir, rmdir that # manages files and dirs BOTH on linux and Windows with / as path separator. # Note: Native windows equivalent, del and mkdir/rmdir, badly manage / and \, # so they cannot be used here. # On Windows host, download: # http://gnuwin32.sourceforge.net/downlinks/coreutils.php # if you have forgotten this, this makefile will remind you... # Modify this to point to your actual openssl compile directory # (You did already compile openssl, didn't you???) #SSLDIR=../../openssl-0.9.8zh #SSLDIR=../../openssl-1.0.0t SSLDIR=../../openssl-1.0.1q # For 0.9.8 mingw compiled openssl #SSLINC=$(SSLDIR)/outinc #SSLLIBS=-L$(SSLDIR)/out -leay32 -lssl32 # for 1.0.0/1.0.1 mingw (msys2) compiled SSLINC=$(SSLDIR)/include SSLLIBS=-L$(SSLDIR) -lcrypto.dll -lssl.dll # For MSVC compiled openssl #SSLINC=$(SSLDIR)/inc32 #SSLLIBS=-L$(SSLDIR)/out32dll -lssleay32 -llibeay32 # c:\, backslash is not correctly recognized by mingw32-make, produces some # "missing separator" issue. # pdelaage: simple trick to detect if we are using mingw-gcc on a Windows host, # or on a linux host. windir is a system environment variable on windows NT # and above, and then redefine some macros. # note: ifdef is !IFDEF in MS nmake or Borland make. # $(info is !MESSAGE in MS nmake or Borland make. ifdef windir $(info host machine is a Windows machine ) NULLDEV=NUL MKDIR="C:\Program Files\GnuWin32\bin\mkdir.exe" DELFILES="C:\Program Files\GnuWin32\bin\rm.exe" -f DELDIR="C:\Program Files\GnuWin32\bin\rm.exe" -rf COPYFILES="C:\Program Files\GnuWin32\bin\cp.exe" -f else $(info host machine is a linux machine ) NULLDEV=/dev/null MKDIR=mkdir DELFILES=rm -f DELDIR=rm -rf COPYFILES=cp -f endif TARGETCPU=MGW32 SRC=../src OBJROOT=../obj OBJ=$(OBJROOT)/$(TARGETCPU) BINROOT=../bin BIN=$(BINROOT)/$(TARGETCPU) OBJS=$(OBJ)/stunnel.o $(OBJ)/ssl.o $(OBJ)/ctx.o $(OBJ)/verify.o \ $(OBJ)/file.o $(OBJ)/client.o $(OBJ)/protocol.o $(OBJ)/sthreads.o \ $(OBJ)/log.o $(OBJ)/options.o $(OBJ)/network.o $(OBJ)/resolver.o \ $(OBJ)/ui_win_gui.o $(OBJ)/resources.o $(OBJ)/str.o $(OBJ)/tls.o \ $(OBJ)/fd.o $(OBJ)/dhparam.o $(OBJ)/cron.o TOBJS=$(OBJ)/stunnel.o $(OBJ)/ssl.o $(OBJ)/ctx.o $(OBJ)/verify.o \ $(OBJ)/file.o $(OBJ)/client.o $(OBJ)/protocol.o $(OBJ)/sthreads.o \ $(OBJ)/log.o $(OBJ)/options.o $(OBJ)/network.o $(OBJ)/resolver.o \ $(OBJ)/ui_win_cli.o $(OBJ)/str.o $(OBJ)/tls.o \ $(OBJ)/fd.o $(OBJ)/dhparam.o $(OBJ)/cron.o CC=gcc RC=windres # pdelaage note: as a workaround for windres bug on resources.rc, equivalent to # "use a temp file instead of popen" option between cpp and windres! RCP=gcc -E -xc-header -DRC_INVOKED DEFINES=-D_WIN32_WINNT=0x0501 # some preprocessing debug : $(info DEFINES is $(DEFINES) ) CFLAGS=-g -O2 -Wall $(DEFINES) -I$(SSLINC) # RFLAGS, note of pdelaage: windres accepts -fo for compatibility with ms tools # default options : -J rc -O coff, input rc file, output coff file. RFLAGS=-v --use-temp-file $(DEFINES) # following RFLAGS2 useful if one day use-temp-file does not exist anymore RFLAGS2=-v $(DEFINES) LDFLAGS=-s LIBS=$(SSLLIBS) -lws2_32 -lpsapi -lgdi32 -lcrypt32 TLIBS=$(SSLLIBS) -lws2_32 -lpsapi -lcrypt32 # IMPORTANT pdelaage : restore this if you need (but I do not see why) -lzdll $(OBJ)/%.o: $(SRC)/%.c $(CC) $(CFLAGS) -o$@ -c $< $(OBJ)/%.o: $(SRC)/%.cpp $(CC) $(CFLAGS) -o$@ -c $< $(OBJ)/%.o: $(SRC)/%.rc $(RC) $(RFLAGS) -o$@ $< # pdelaage : trick for windres preprocessing popen bug on Windows, in case the windres option # use_temp_file disappear one day... # comment out the $(RC) rule above to activate the following $(OBJ)/%.rcp: $(SRC)/%.rc $(RCP) $(DEFINES) -o$@ $< $(OBJ)/%.o: $(OBJ)/%.rcp $(RC) $(RFLAGS2) -o$@ $< # Note : gnu-make will automatically RM the intermediate "rcp" file # BUT it will ABSOLUTELY NEED the "rm" command available : not a problem on linux # but on a windows dev host machine, one will need to install gnu-win32/rm command # in the system... # for debug of the preprocessed rcp file, because it is automatically deleted by gnu-make: cp $< $<.2 all: testenv makedirs $(BIN)/stunnel.exe $(BIN)/tstunnel.exe testopenssl: @if not exist $(SSLDIR) echo You mush have a compiled OpenSSL tree @if not exist $(SSLINC)/openssl/applink.c $(COPYFILES) $(SSLDIR)/ms/applink.c $(SSLINC)/openssl #pdelaage : testenv purpose is to detect, on windows, whether Gnu-win32 has been properly installed... # a first call to "true" is made to detect availability, a second is made to stop the make process. ifdef windir testenv: testopenssl -@ echo OFF -@ true >$(NULLDEV) 2>&1 || echo You MUST install Gnu-Win32 coreutils \ from http://gnuwin32.sourceforge.net/downlinks/coreutils.php \ and set PATH to include C:\Program Files\GnuWin32\bin @true >$(NULLDEV) 2>&1 else testenv: -@ true >$(NULLDEV) 2>&1 || echo Your system lacks Gnu coreutils tools !!! @true >$(NULLDEV) 2>&1 endif clean: -@ $(DELFILES) $(OBJ)/*.o -@ $(DELFILES) $(BIN)/stunnel.exe >$(NULLDEV) 2>&1 -@ $(DELDIR) $(OBJ) >$(NULLDEV) 2>&1 -@ $(DELDIR) $(BIN) >$(NULLDEV) 2>&1 makedirs: -@ $(MKDIR) $(OBJROOT) >$(NULLDEV) 2>&1 -@ $(MKDIR) $(OBJ) >$(NULLDEV) 2>&1 -@ $(MKDIR) $(BINROOT) >$(NULLDEV) 2>&1 -@ $(MKDIR) $(BIN) >$(NULLDEV) 2>&1 # pseudo-target for RC-preprocessor debugging # result appears OK, as a text file faketest: gcc -E -xc-header -DRC_INVOKED $(DEFINES) -o $(SRC)/resources.rcp $(SRC)/resources.rc $(OBJS): *.h mingw.mak $(BIN)/stunnel.exe: $(OBJS) $(CC) $(LDFLAGS) -o $(BIN)/stunnel.exe $(OBJS) $(LIBS) -mwindows $(BIN)/tstunnel.exe: $(TOBJS) $(CC) $(LDFLAGS) -o $(BIN)/tstunnel.exe $(TOBJS) $(TLIBS) # "missing separator" issue with mingw32-make: tabs MUST BE TABS in your text # editor, and not set of spaces even if your development host is windows. # Some \ are badly tolerated by mingw32-make "!" directives, eg as !IF, # accepted in MS nmake and Borland make ARE NOT supported by gnu make but they # all have their equivalents. # Gnu-make is case sensitive, while ms nmake or borland make are not. Anyway, # on reference to env vars nmake convert env vars to UPPERCASE macro names... stunnel-5.30/src/cron.c0000664000175000017500000001452012646221043011752 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #include "common.h" #include "prototypes.h" #ifdef USE_PTHREAD NOEXPORT void *cron_thread(void *arg); #endif #ifdef USE_WIN32 NOEXPORT void cron_thread(void *arg); #endif #if defined(USE_PTHREAD) || defined(USE_WIN32) NOEXPORT void cron_worker(void); NOEXPORT void cron_dh_param(void); #endif #if defined(USE_PTHREAD) int cron_init() { pthread_t thread; pthread_attr_t pth_attr; #if defined(HAVE_PTHREAD_SIGMASK) && !defined(__APPLE__) sigset_t new_set, old_set; #endif /* HAVE_PTHREAD_SIGMASK && !__APPLE__*/ #if defined(HAVE_PTHREAD_SIGMASK) && !defined(__APPLE__) sigfillset(&new_set); pthread_sigmask(SIG_SETMASK, &new_set, &old_set); /* block signals */ #endif /* HAVE_PTHREAD_SIGMASK && !__APPLE__*/ pthread_attr_init(&pth_attr); pthread_attr_setdetachstate(&pth_attr, PTHREAD_CREATE_DETACHED); if(pthread_create(&thread, &pth_attr, cron_thread, NULL)) ioerror("pthread_create"); pthread_attr_destroy(&pth_attr); #if defined(HAVE_PTHREAD_SIGMASK) && !defined(__APPLE__) pthread_sigmask(SIG_SETMASK, &old_set, NULL); /* unblock signals */ #endif /* HAVE_PTHREAD_SIGMASK && !__APPLE__*/ return 0; } NOEXPORT void *cron_thread(void *arg) { #ifdef SCHED_BATCH struct sched_param param; #endif (void)arg; /* squash the unused parameter warning */ tls_alloc(NULL, NULL, "cron"); #ifdef SCHED_BATCH param.sched_priority=0; if(pthread_setschedparam(pthread_self(), SCHED_BATCH, ¶m)) ioerror("pthread_getschedparam"); #endif cron_worker(); return NULL; /* it should never be executed */ } #elif defined(USE_WIN32) int cron_init() { if((long)_beginthread(cron_thread, 0, NULL)==-1) ioerror("_beginthread"); return 0; } NOEXPORT void cron_thread(void *arg) { (void)arg; /* squash the unused parameter warning */ tls_alloc(NULL, NULL, "cron"); if(!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST)) ioerror("SetThreadPriority"); cron_worker(); _endthread(); /* it should never be executed */ } #else /* !defined(USE_PTHREAD) && !defined(USE_WIN32) */ int cron_init() { /* not implemented for now */ return 0; } #endif /* run the cron job every 24 hours */ #define CRON_PERIOD (24*60*60) #if defined(USE_PTHREAD) || defined(USE_WIN32) NOEXPORT void cron_worker(void) { time_t now, then; int delay; s_log(LOG_DEBUG, "Cron thread initialized"); sleep(60); /* allow the other services to start with idle CPU */ time(&then); for(;;) { s_log(LOG_INFO, "Executing cron jobs"); #ifndef OPENSSL_NO_DH cron_dh_param(); #endif /* OPENSSL_NO_DH */ time(&now); s_log(LOG_INFO, "Cron jobs completed in %d seconds", (int)(now-then)); then+=CRON_PERIOD; if(then>now) { delay=(int)(then-now); } else { s_log(LOG_NOTICE, "Cron backlog cleared (possible hibernation)"); delay=CRON_PERIOD-(int)(now-then)%CRON_PERIOD; then=now+delay; } s_log(LOG_DEBUG, "Waiting %d seconds", delay); do { /* retry sleep() if it was interrupted by a signal */ sleep((unsigned)delay); time(&now); delay=(int)(then-now); } while(delay>0); s_log(LOG_INFO, "Reopening log file"); signal_post(SIGNAL_REOPEN_LOG); } } #ifndef OPENSSL_NO_DH NOEXPORT void cron_dh_param(void) { SERVICE_OPTIONS *opt; DH *dh; if(!dh_needed) return; s_log(LOG_NOTICE, "Updating DH parameters"); #if OPENSSL_VERSION_NUMBER>=0x0090800fL /* generate 2048-bit DH parameters */ dh=DH_new(); if(!dh) { sslerror("DH_new"); return; } if(!DH_generate_parameters_ex(dh, 2048, 2, NULL)) { DH_free(dh); sslerror("DH_generate_parameters_ex"); return; } #else /* OpenSSL older than 0.9.8 */ dh=DH_generate_parameters(2048, 2, NULL, NULL); if(!dh) { sslerror("DH_generate_parameters"); return; } #endif /* update global dh_params for future configuration reloads */ CRYPTO_w_lock(stunnel_locks[LOCK_DH]); DH_free(dh_params); dh_params=dh; CRYPTO_w_unlock(stunnel_locks[LOCK_DH]); /* set for all sections that require it */ for(opt=service_options.next; opt; opt=opt->next) if(opt->option.dh_needed) SSL_CTX_set_tmp_dh(opt->ctx, dh); s_log(LOG_NOTICE, "DH parameters updated"); } #endif /* OPENSSL_NO_DH */ #endif /* USE_PTHREAD || USE_WIN32 */ /* end of cron.c */ stunnel-5.30/src/tls.c0000664000175000017500000001251612646221043011616 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #include "common.h" #include "prototypes.h" volatile int tls_initialized=0; NOEXPORT void tls_platform_init(); #if OPENSSL_VERSION_NUMBER<0x10100000L NOEXPORT void free_function(void *); #endif /**************************************** thread local storage */ /* this has to be the first function called from ui_*.c */ void tls_init() { tls_platform_init(); tls_initialized=1; ui_tls=tls_alloc(NULL, NULL, "ui"); #if OPENSSL_VERSION_NUMBER<0x10100000L /* the ability to set the "memory debug" functions * at runtme was removed in OpenSSL 1.1 */ CRYPTO_set_mem_ex_functions(str_alloc_detached_debug, str_realloc_debug, free_function); #endif } /* this has to be the first function called by a new thread */ TLS_DATA *tls_alloc(CLI *c, TLS_DATA *inherited, char *txt) { TLS_DATA *tls_data; if(inherited) { /* reuse the thread-local storage after fork() */ tls_data=inherited; str_free(tls_data->id); } else { tls_data=calloc(1, sizeof(TLS_DATA)); if(!tls_data) fatal("Out of memory"); if(c) c->tls=tls_data; str_init(tls_data); tls_data->c=c; tls_data->opt=c?c->opt:&service_options; } tls_data->id="unconfigured"; tls_set(tls_data); /* str.c functions can be used below this point */ if(txt) { tls_data->id=str_dup(txt); str_detach(tls_data->id); /* it is deallocated after str_stats() */ } else if(c) { tls_data->id=log_id(c); str_detach(tls_data->id); /* it is deallocated after str_stats() */ } return tls_data; } /* per-thread thread-local storage cleanup */ void tls_cleanup() { TLS_DATA *tls_data; tls_data=tls_get(); if(!tls_data) return; str_cleanup(tls_data); str_free(tls_data->id); /* detached allocation */ tls_set(NULL); free(tls_data); } #ifdef USE_UCONTEXT static TLS_DATA *global_tls=NULL; NOEXPORT void tls_platform_init() { } void tls_set(TLS_DATA *tls_data) { if(ready_head) ready_head->tls=tls_data; else /* ucontext threads not initialized */ global_tls=tls_data; } TLS_DATA *tls_get() { if(ready_head) return ready_head->tls; else /* ucontext threads not initialized */ return global_tls; } #endif /* USE_UCONTEXT */ #ifdef USE_FORK static TLS_DATA *global_tls=NULL; NOEXPORT void tls_platform_init() { } void tls_set(TLS_DATA *tls_data) { global_tls=tls_data; } TLS_DATA *tls_get() { return global_tls; } #endif /* USE_FORK */ #ifdef USE_PTHREAD static pthread_key_t pthread_key; NOEXPORT void tls_platform_init() { pthread_key_create(&pthread_key, NULL); } void tls_set(TLS_DATA *tls_data) { pthread_setspecific(pthread_key, tls_data); } TLS_DATA *tls_get() { return pthread_getspecific(pthread_key); } #endif /* USE_PTHREAD */ #ifdef USE_WIN32 static DWORD tls_index; NOEXPORT void tls_platform_init() { tls_index=TlsAlloc(); } void tls_set(TLS_DATA *tls_data) { TlsSetValue(tls_index, tls_data); } TLS_DATA *tls_get() { return TlsGetValue(tls_index); } #endif /* USE_WIN32 */ /**************************************** OpenSSL allocator hook */ #if OPENSSL_VERSION_NUMBER<0x10100000L NOEXPORT void free_function(void *ptr) { /* CRYPTO_set_mem_ex_functions() needs a function rather than a macro */ /* unfortunately, OpenSSL provides no file:line information here */ str_free_debug(ptr, "OpenSSL", 0); } #endif /* end of tls.c */ stunnel-5.30/src/network.c0000664000175000017500000006770212646221043012514 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #if defined(_WIN32) || defined(_WIN32_WCE) /* bypass automatic index bound checks in the FD_SET() macro */ #define FD_SETSIZE 1000000 #endif #include "common.h" #include "prototypes.h" /* #define DEBUG_UCONTEXT */ NOEXPORT void s_poll_realloc(s_poll_set *); NOEXPORT int get_socket_error(const SOCKET); /**************************************** s_poll functions */ #ifdef USE_POLL s_poll_set *s_poll_alloc() { /* it needs to be filled with zeros */ return str_alloc(sizeof(s_poll_set)); } void s_poll_free(s_poll_set *fds) { if(fds) { str_free(fds->ufds); str_free(fds); } } void s_poll_init(s_poll_set *fds) { fds->nfds=0; fds->allocated=4; /* prealloc 4 file desciptors */ s_poll_realloc(fds); } void s_poll_add(s_poll_set *fds, SOCKET fd, int rd, int wr) { unsigned i; for(i=0; infds && fds->ufds[i].fd!=fd; i++) ; if(i==fds->nfds) { /* not found */ if(i==fds->allocated) { fds->allocated=i+1; s_poll_realloc(fds); } fds->ufds[i].fd=fd; fds->ufds[i].events=0; fds->nfds++; } if(rd) { fds->ufds[i].events|=POLLIN; #ifdef POLLRDHUP fds->ufds[i].events|=POLLRDHUP; #endif } if(wr) fds->ufds[i].events|=POLLOUT; } void s_poll_remove(s_poll_set *fds, SOCKET fd) { unsigned i; for(i=0; infds && fds->ufds[i].fd!=fd; i++) ; if(infds) { /* found */ memmove(fds->ufds+i, fds->ufds+i+1, (fds->nfds-i-1)*sizeof(struct pollfd)); fds->nfds--; } } int s_poll_canread(s_poll_set *fds, SOCKET fd) { unsigned i; for(i=0; infds; i++) if(fds->ufds[i].fd==fd) return fds->ufds[i].revents&(POLLIN|POLLERR); return 0; /* not listed in fds */ } int s_poll_canwrite(s_poll_set *fds, SOCKET fd) { unsigned i; for(i=0; infds; i++) if(fds->ufds[i].fd==fd) return fds->ufds[i].revents&(POLLOUT|POLLERR); return 0; /* not listed in fds */ } /* best doc: http://lxr.free-electrons.com/source/net/ipv4/tcp.c#L456 */ int s_poll_hup(s_poll_set *fds, SOCKET fd) { unsigned i; for(i=0; infds; i++) if(fds->ufds[i].fd==fd) return fds->ufds[i].revents&POLLHUP; /* read and write closed */ return 0; /* not listed in fds */ } int s_poll_rdhup(s_poll_set *fds, SOCKET fd) { unsigned i; for(i=0; infds; i++) if(fds->ufds[i].fd==fd) #ifdef POLLRDHUP return fds->ufds[i].revents&POLLRDHUP; /* read closed */ #else return fds->ufds[i].revents&POLLHUP; /* read and write closed */ #endif return 0; /* not listed in fds */ } NOEXPORT void s_poll_realloc(s_poll_set *fds) { fds->ufds=str_realloc(fds->ufds, fds->allocated*sizeof(struct pollfd)); } void s_poll_dump(s_poll_set *fds, int level) { unsigned i; for(i=0; infds; i++) s_log(level, "FD=%ld events=0x%X revents=0x%X", (long)fds->ufds[i].fd, fds->ufds[i].events, fds->ufds[i].revents); } #ifdef USE_UCONTEXT /* move ready contexts from waiting queue to ready queue */ NOEXPORT void scan_waiting_queue(void) { int retval; CONTEXT *context, *prev; int min_timeout; unsigned nfds, i; time_t now; static unsigned max_nfds=0; static struct pollfd *ufds=NULL; time(&now); /* count file descriptors */ min_timeout=-1; /* infinity */ nfds=0; for(context=waiting_head; context; context=context->next) { nfds+=context->fds->nfds; if(context->finish>=0) /* finite time */ if(min_timeout<0 || min_timeout>context->finish-now) min_timeout= (int)(context->finish-now<0 ? 0 : context->finish-now); } /* setup ufds structure */ if(nfds>max_nfds) { /* need to allocate more memory */ ufds=str_realloc(ufds, nfds*sizeof(struct pollfd)); max_nfds=nfds; } nfds=0; for(context=waiting_head; context; context=context->next) for(i=0; ifds->nfds; i++) { ufds[nfds].fd=context->fds->ufds[i].fd; ufds[nfds].events=context->fds->ufds[i].events; nfds++; } #ifdef DEBUG_UCONTEXT s_log(LOG_DEBUG, "Waiting %d second(s) for %d file descriptor(s)", min_timeout, nfds); #endif do { /* skip "Interrupted system call" errors */ retval=poll(ufds, nfds, min_timeout<0 ? -1 : 1000*min_timeout); } while(retval<0 && get_last_socket_error()==S_EINTR); time(&now); /* process the returned data */ nfds=0; prev=NULL; /* previous element of the waiting queue */ context=waiting_head; while(context) { context->ready=0; /* count ready file descriptors in each context */ for(i=0; ifds->nfds; i++) { context->fds->ufds[i].revents=ufds[nfds].revents; #ifdef DEBUG_UCONTEXT s_log(LOG_DEBUG, "CONTEXT %ld, FD=%d,%s%s ->%s%s%s%s%s", context->id, ufds[nfds].fd, ufds[nfds].events & POLLIN ? " IN" : "", ufds[nfds].events & POLLOUT ? " OUT" : "", ufds[nfds].revents & POLLIN ? " IN" : "", ufds[nfds].revents & POLLOUT ? " OUT" : "", ufds[nfds].revents & POLLERR ? " ERR" : "", ufds[nfds].revents & POLLHUP ? " HUP" : "", ufds[nfds].revents & POLLNVAL ? " NVAL" : ""); #endif if(ufds[nfds].revents) context->ready++; nfds++; } if(context->ready || (context->finish>=0 && context->finish<=now)) { /* remove context from the waiting queue */ if(prev) prev->next=context->next; else waiting_head=context->next; if(!context->next) /* same as context==waiting_tail */ waiting_tail=prev; /* append context context to the ready queue */ context->next=NULL; if(ready_tail) ready_tail->next=context; ready_tail=context; if(!ready_head) ready_head=context; } else { /* leave the context context in the waiting queue */ prev=context; } context=prev ? prev->next : waiting_head; } } int s_poll_wait(s_poll_set *fds, int sec, int msec) { CONTEXT *context; /* current context */ static CONTEXT *to_free=NULL; /* delayed memory deallocation */ /* FIXME: msec parameter is currently ignored with UCONTEXT threads */ (void)msec; /* squash the unused parameter warning */ /* remove the current context from ready queue */ context=ready_head; ready_head=ready_head->next; if(!ready_head) /* the queue is empty */ ready_tail=NULL; /* it is safe to s_log() after new ready_head is set */ /* it is illegal to deallocate the stack of the current context */ if(to_free) { /* a delayed deallocation is scheduled */ #ifdef DEBUG_UCONTEXT s_log(LOG_DEBUG, "Releasing context %ld", to_free->id); #endif str_free(to_free->stack); str_free(to_free); to_free=NULL; } /* manage the current thread */ if(fds) { /* something to wait for -> swap the context */ context->fds=fds; /* set file descriptors to wait for */ context->finish=sec<0 ? -1 : time(NULL)+sec; /* append the current context to the waiting queue */ context->next=NULL; if(waiting_tail) waiting_tail->next=context; waiting_tail=context; if(!waiting_head) waiting_head=context; } else { /* nothing to wait for -> drop the context */ to_free=context; /* schedule for delayed deallocation */ } while(!ready_head) /* wait until there is a thread to switch to */ scan_waiting_queue(); /* switch threads */ if(fds) { /* swap the current context */ if(context->id!=ready_head->id) { #ifdef DEBUG_UCONTEXT s_log(LOG_DEBUG, "Context swap: %ld -> %ld", context->id, ready_head->id); #endif swapcontext(&context->context, &ready_head->context); #ifdef DEBUG_UCONTEXT s_log(LOG_DEBUG, "Current context: %ld", ready_head->id); #endif } return ready_head->ready; } else { /* drop the current context */ #ifdef DEBUG_UCONTEXT s_log(LOG_DEBUG, "Context set: %ld (dropped) -> %ld", context->id, ready_head->id); #endif setcontext(&ready_head->context); ioerror("setcontext"); /* should not ever happen */ return 0; } } #else /* USE_UCONTEXT */ int s_poll_wait(s_poll_set *fds, int sec, int msec) { int retval; do { /* skip "Interrupted system call" errors */ retval=poll(fds->ufds, fds->nfds, sec<0 ? -1 : 1000*sec+msec); } while(retval<0 && get_last_socket_error()==S_EINTR); return retval; } #endif /* USE_UCONTEXT */ #else /* select */ s_poll_set *s_poll_alloc() { /* it needs to be filled with zeros */ return str_alloc(sizeof(s_poll_set)); } void s_poll_free(s_poll_set *fds) { if(fds) { str_free(fds->irfds); str_free(fds->iwfds); str_free(fds->ixfds); str_free(fds->orfds); str_free(fds->owfds); str_free(fds->oxfds); str_free(fds); } } void s_poll_init(s_poll_set *fds) { #ifdef USE_WIN32 fds->allocated=4; /* prealloc 4 file desciptors */ #endif s_poll_realloc(fds); FD_ZERO(fds->irfds); FD_ZERO(fds->iwfds); FD_ZERO(fds->ixfds); fds->max=0; /* no file descriptors */ } void s_poll_add(s_poll_set *fds, SOCKET fd, int rd, int wr) { #ifdef USE_WIN32 /* fds->ixfds contains union of fds->irfds and fds->iwfds */ if(fds->ixfds->fd_count>=fds->allocated) { fds->allocated=fds->ixfds->fd_count+1; s_poll_realloc(fds); } #endif if(rd) FD_SET(fd, fds->irfds); if(wr) FD_SET(fd, fds->iwfds); /* always expect errors (and the Spanish Inquisition) */ FD_SET(fd, fds->ixfds); if(fd>fds->max) fds->max=fd; } void s_poll_remove(s_poll_set *fds, SOCKET fd) { FD_CLR(fd, fds->irfds); FD_CLR(fd, fds->iwfds); FD_CLR(fd, fds->ixfds); } int s_poll_canread(s_poll_set *fds, SOCKET fd) { return FD_ISSET(fd, fds->orfds) || FD_ISSET(fd, fds->oxfds); } int s_poll_canwrite(s_poll_set *fds, SOCKET fd) { return FD_ISSET(fd, fds->owfds) || FD_ISSET(fd, fds->oxfds); } int s_poll_hup(s_poll_set *fds, SOCKET fd) { (void)fds; /* squash the unused parameter warning */ (void)fd; /* squash the unused parameter warning */ return 0; /* FIXME: how to detect HUP condition with select()? */ } int s_poll_rdhup(s_poll_set *fds, SOCKET fd) { (void)fds; /* squash the unused parameter warning */ (void)fd; /* squash the unused parameter warning */ return 0; /* FIXME: how to detect RDHUP condition with select()? */ } #ifdef USE_WIN32 #define FD_SIZE(fds) (sizeof(u_int)+(fds)->allocated*sizeof(SOCKET)) #else #define FD_SIZE(fds) (sizeof(fd_set)) #endif int s_poll_wait(s_poll_set *fds, int sec, int msec) { int retval; struct timeval tv, *tv_ptr; do { /* skip "Interrupted system call" errors */ memcpy(fds->orfds, fds->irfds, FD_SIZE(fds)); memcpy(fds->owfds, fds->iwfds, FD_SIZE(fds)); memcpy(fds->oxfds, fds->ixfds, FD_SIZE(fds)); if(sec<0) { /* infinite timeout */ tv_ptr=NULL; } else { tv.tv_sec=sec; tv.tv_usec=1000*msec; tv_ptr=&tv; } retval=select((int)fds->max+1, fds->orfds, fds->owfds, fds->oxfds, tv_ptr); } while(retval<0 && get_last_socket_error()==S_EINTR); return retval; } NOEXPORT void s_poll_realloc(s_poll_set *fds) { fds->irfds=str_realloc(fds->irfds, FD_SIZE(fds)); fds->iwfds=str_realloc(fds->iwfds, FD_SIZE(fds)); fds->ixfds=str_realloc(fds->ixfds, FD_SIZE(fds)); fds->orfds=str_realloc(fds->orfds, FD_SIZE(fds)); fds->owfds=str_realloc(fds->owfds, FD_SIZE(fds)); fds->oxfds=str_realloc(fds->oxfds, FD_SIZE(fds)); } void s_poll_dump(s_poll_set *fds, int level) { SOCKET fd; int ir, iw, ix, or, ow, ox; for(fd=0; fdmax; fd++) { ir=FD_ISSET(fd, fds->irfds); iw=FD_ISSET(fd, fds->iwfds); ix=FD_ISSET(fd, fds->ixfds); or=FD_ISSET(fd, fds->orfds); ow=FD_ISSET(fd, fds->owfds); ox=FD_ISSET(fd, fds->oxfds); if(ir || iw || ix || or || ow || ox) s_log(level, "FD=%ld ifds=%c%c%c ofds=%c%c%c", (long)fd, ir?'r':'-', iw?'w':'-', ix?'x':'-', or?'r':'-', ow?'w':'-', ox?'x':'-'); } } #endif /* USE_POLL */ /**************************************** fd management */ int set_socket_options(SOCKET s, int type) { SOCK_OPT *ptr; extern SOCK_OPT sock_opts[]; static char *type_str[3]={"accept", "local", "remote"}; socklen_t opt_size; int retval=0; /* no error found */ for(ptr=sock_opts; ptr->opt_str; ptr++) { if(!ptr->opt_val[type]) continue; /* default */ switch(ptr->opt_type) { case TYPE_LINGER: opt_size=sizeof(struct linger); break; case TYPE_TIMEVAL: opt_size=sizeof(struct timeval); break; case TYPE_STRING: opt_size=(socklen_t)strlen(ptr->opt_val[type]->c_val)+1; break; default: opt_size=sizeof(int); } if(setsockopt(s, ptr->opt_level, ptr->opt_name, (void *)ptr->opt_val[type], opt_size)) { if(get_last_socket_error()==S_EOPNOTSUPP) { /* most likely stdin/stdout or AF_UNIX socket */ s_log(LOG_DEBUG, "Option %s not supported on %s socket", ptr->opt_str, type_str[type]); } else { sockerror(ptr->opt_str); retval=-1; /* failed to set this option */ } } #ifdef DEBUG_FD_ALLOC else { s_log(LOG_DEBUG, "Option %s set on %s socket", ptr->opt_str, type_str[type]); } #endif /* DEBUG_FD_ALLOC */ } return retval; /* returns 0 when all options succeeded */ } NOEXPORT int get_socket_error(const SOCKET fd) { int err; socklen_t optlen=sizeof err; if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&err, &optlen)) err=get_last_socket_error(); /* failed -> ask why */ return err==S_ENOTSOCK ? 0 : err; } /**************************************** simulate blocking I/O */ int s_connect(CLI *c, SOCKADDR_UNION *addr, socklen_t addrlen) { int error; char *dst; dst=s_ntop(addr, addrlen); s_log(LOG_INFO, "s_connect: connecting %s", dst); if(!connect(c->fd, &addr->sa, addrlen)) { s_log(LOG_INFO, "s_connect: connected %s", dst); str_free(dst); return 0; /* no error -> success (on some OSes over the loopback) */ } error=get_last_socket_error(); if(error!=S_EINPROGRESS && error!=S_EWOULDBLOCK) { s_log(LOG_ERR, "s_connect: connect %s: %s (%d)", dst, s_strerror(error), error); str_free(dst); return -1; } s_log(LOG_DEBUG, "s_connect: s_poll_wait %s: waiting %d seconds", dst, c->opt->timeout_connect); s_poll_init(c->fds); s_poll_add(c->fds, c->fd, 1, 1); switch(s_poll_wait(c->fds, c->opt->timeout_connect, 0)) { case -1: error=get_last_socket_error(); s_log(LOG_ERR, "s_connect: s_poll_wait %s: %s (%d)", dst, s_strerror(error), error); str_free(dst); return -1; case 0: s_log(LOG_ERR, "s_connect: s_poll_wait %s:" " TIMEOUTconnect exceeded", dst); str_free(dst); return -1; default: error=get_socket_error(c->fd); if(error) { s_log(LOG_ERR, "s_connect: connect %s: %s (%d)", dst, s_strerror(error), error); str_free(dst); return -1; } if(s_poll_canwrite(c->fds, c->fd)) { s_log(LOG_NOTICE, "s_connect: connected %s", dst); str_free(dst); return 0; /* success */ } s_log(LOG_ERR, "s_connect: s_poll_wait %s: internal error", dst); str_free(dst); return -1; } return -1; /* should not be possible */ } void s_write(CLI *c, SOCKET fd, const void *buf, size_t len) { /* simulate a blocking write */ uint8_t *ptr=(uint8_t *)buf; ssize_t num; while(len>0) { s_poll_init(c->fds); s_poll_add(c->fds, fd, 0, 1); /* write */ switch(s_poll_wait(c->fds, c->opt->timeout_busy, 0)) { case -1: sockerror("s_write: s_poll_wait"); longjmp(c->err, 1); /* error */ case 0: s_log(LOG_INFO, "s_write: s_poll_wait:" " TIMEOUTbusy exceeded: sending reset"); longjmp(c->err, 1); /* timeout */ case 1: break; /* OK */ default: s_log(LOG_ERR, "s_write: s_poll_wait: unknown result"); longjmp(c->err, 1); /* error */ } num=writesocket(fd, (void *)ptr, len); if(num==-1) { /* error */ sockerror("writesocket (s_write)"); longjmp(c->err, 1); } ptr+=(size_t)num; len-=(size_t)num; } } void s_read(CLI *c, SOCKET fd, void *ptr, size_t len) { /* simulate a blocking read */ ssize_t num; while(len>0) { s_poll_init(c->fds); s_poll_add(c->fds, fd, 1, 0); /* read */ switch(s_poll_wait(c->fds, c->opt->timeout_busy, 0)) { case -1: sockerror("s_read: s_poll_wait"); longjmp(c->err, 1); /* error */ case 0: s_log(LOG_INFO, "s_read: s_poll_wait:" " TIMEOUTbusy exceeded: sending reset"); longjmp(c->err, 1); /* timeout */ case 1: break; /* OK */ default: s_log(LOG_ERR, "s_read: s_poll_wait: unknown result"); longjmp(c->err, 1); /* error */ } num=readsocket(fd, ptr, len); switch(num) { case -1: /* error */ sockerror("readsocket (s_read)"); longjmp(c->err, 1); case 0: /* EOF */ s_log(LOG_ERR, "Unexpected socket close (s_read)"); longjmp(c->err, 1); } ptr=(uint8_t *)ptr+num; len-=(size_t)num; } } void fd_putline(CLI *c, SOCKET fd, const char *line) { char *tmpline; const char crlf[]="\r\n"; size_t len; tmpline=str_printf("%s%s", line, crlf); len=strlen(tmpline); s_write(c, fd, tmpline, len); str_free(tmpline); s_log(LOG_DEBUG, " -> %s", line); } char *fd_getline(CLI *c, SOCKET fd) { char *line; size_t ptr=0, allocated=32; line=str_alloc(allocated); for(;;) { if(ptr>65536) { /* >64KB --> DoS protection */ s_log(LOG_ERR, "fd_getline: Line too long"); str_free(line); longjmp(c->err, 1); } if(allocatederr, 1); } fd_putline(c, fd, line); str_free(line); } void s_ssl_write(CLI *c, const void *buf, int len) { /* simulate a blocking SSL_write */ uint8_t *ptr=(uint8_t *)buf; int num; while(len>0) { s_poll_init(c->fds); s_poll_add(c->fds, c->ssl_wfd->fd, 0, 1); /* write */ switch(s_poll_wait(c->fds, c->opt->timeout_busy, 0)) { case -1: sockerror("s_write: s_poll_wait"); longjmp(c->err, 1); /* error */ case 0: s_log(LOG_INFO, "s_write: s_poll_wait:" " TIMEOUTbusy exceeded: sending reset"); longjmp(c->err, 1); /* timeout */ case 1: break; /* OK */ default: s_log(LOG_ERR, "s_write: s_poll_wait: unknown result"); longjmp(c->err, 1); /* error */ } num=SSL_write(c->ssl, (void *)ptr, len); if(num==-1) { /* error */ sockerror("SSL_write (s_ssl_write)"); longjmp(c->err, 1); } ptr+=num; len-=num; } } void s_ssl_read(CLI *c, void *ptr, int len) { /* simulate a blocking SSL_read */ int num; while(len>0) { if(!SSL_pending(c->ssl)) { s_poll_init(c->fds); s_poll_add(c->fds, c->ssl_rfd->fd, 1, 0); /* read */ switch(s_poll_wait(c->fds, c->opt->timeout_busy, 0)) { case -1: sockerror("s_read: s_poll_wait"); longjmp(c->err, 1); /* error */ case 0: s_log(LOG_INFO, "s_read: s_poll_wait:" " TIMEOUTbusy exceeded: sending reset"); longjmp(c->err, 1); /* timeout */ case 1: break; /* OK */ default: s_log(LOG_ERR, "s_read: s_poll_wait: unknown result"); longjmp(c->err, 1); /* error */ } } num=SSL_read(c->ssl, ptr, len); switch(num) { case -1: /* error */ sockerror("SSL_read (s_ssl_read)"); longjmp(c->err, 1); case 0: /* EOF */ s_log(LOG_ERR, "Unexpected socket close (s_ssl_read)"); longjmp(c->err, 1); } ptr=(uint8_t *)ptr+num; len-=num; } } char *ssl_getstring(CLI *c) { /* get null-terminated string */ char *line; size_t ptr=0, allocated=32; line=str_alloc(allocated); for(;;) { if(ptr>65536) { /* >64KB --> DoS protection */ s_log(LOG_ERR, "ssl_getstring: Line too long"); str_free(line); longjmp(c->err, 1); } if(allocated65536) { /* >64KB --> DoS protection */ s_log(LOG_ERR, "ssl_getline: Line too long"); str_free(line); longjmp(c->err, 1); } if(allocatedINT_MAX) { /* paranoia */ s_log(LOG_ERR, "ssl_putline: Line too long"); str_free(tmpline); longjmp(c->err, 1); } s_ssl_write(c, tmpline, (int)len); str_free(tmpline); s_log(LOG_DEBUG, " -> %s", line); } /**************************************** network helpers */ #define INET_SOCKET_PAIR int make_sockets(SOCKET fd[2]) { /* make a pair of connected ipv4 sockets */ #ifdef INET_SOCKET_PAIR struct sockaddr_in addr; socklen_t addrlen; SOCKET s; /* temporary socket awaiting for connection */ /* create two *blocking* sockets first */ s=s_socket(AF_INET, SOCK_STREAM, 0, 0, "make_sockets: s_socket#1"); if(s==INVALID_SOCKET) return 1; fd[1]=s_socket(AF_INET, SOCK_STREAM, 0, 0, "make_sockets: s_socket#2"); if(fd[1]==INVALID_SOCKET) { closesocket(s); return 1; } addrlen=sizeof addr; memset(&addr, 0, sizeof addr); addr.sin_family=AF_INET; addr.sin_addr.s_addr=htonl(INADDR_LOOPBACK); addr.sin_port=htons(0); /* dynamic port allocation */ if(bind(s, (struct sockaddr *)&addr, addrlen)) log_error(LOG_DEBUG, get_last_socket_error(), "make_sockets: bind#1"); if(bind(fd[1], (struct sockaddr *)&addr, addrlen)) log_error(LOG_DEBUG, get_last_socket_error(), "make_sockets: bind#2"); if(listen(s, 1)) { sockerror("make_sockets: listen"); closesocket(s); closesocket(fd[1]); return 1; } if(getsockname(s, (struct sockaddr *)&addr, &addrlen)) { sockerror("make_sockets: getsockname"); closesocket(s); closesocket(fd[1]); return 1; } if(connect(fd[1], (struct sockaddr *)&addr, addrlen)) { sockerror("make_sockets: connect"); closesocket(s); closesocket(fd[1]); return 1; } fd[0]=s_accept(s, (struct sockaddr *)&addr, &addrlen, 1, "make_sockets: s_accept"); if(fd[0]==INVALID_SOCKET) { closesocket(s); closesocket(fd[1]); return 1; } closesocket(s); /* don't care about the result */ set_nonblock(fd[0], 1); set_nonblock(fd[1], 1); #else if(s_socketpair(AF_UNIX, SOCK_STREAM, 0, fd, 1, "make_sockets: socketpair")) return 1; #endif return 0; } /* returns 0 on success, and -1 on error */ int original_dst(const SOCKET fd, SOCKADDR_UNION *addr) { socklen_t addrlen; memset(addr, 0, sizeof(SOCKADDR_UNION)); addrlen=sizeof(SOCKADDR_UNION); #ifdef SO_ORIGINAL_DST #ifdef USE_IPv6 if(!getsockopt(fd, SOL_IPV6, SO_ORIGINAL_DST, &addr->sa, &addrlen)) return 0; /* succeeded */ #endif /* USE_IPv6 */ if(!getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, &addr->sa, &addrlen)) return 0; /* succeeded */ sockerror("getsockopt SO_ORIGINAL_DST"); #else /* SO_ORIGINAL_DST */ if(!getsockname(fd, &addr->sa, &addrlen)) return 0; /* succeeded */ sockerror("getsockname"); #endif /* SO_ORIGINAL_DST */ return -1; /* failed */ } /* end of network.c */ stunnel-5.30/src/str.c0000664000175000017500000003371312646221043011626 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #include "common.h" #include "prototypes.h" #define CANARY_INITIALIZED 0x0000c0ded0000000L #define CANARY_UNINTIALIZED 0x0000abadbabe0000L #define MAGIC_ALLOCATED 0x0000a110c8ed0000L #define MAGIC_DEALLOCATED 0x0000defec8ed0000L struct alloc_list_struct { ALLOC_LIST *prev, *next; TLS_DATA *tls; size_t size; const char *alloc_file, *free_file; int alloc_line, free_line; uint64_t valid_canary, magic; /* at least on IA64 allocations need to be aligned */ #ifdef __GNUC__ } __attribute__((aligned(16))); #else uint64_t :0; /* align the structure */ }; #endif #ifdef USE_WIN32 NOEXPORT LPTSTR str_vtprintf(LPCTSTR, va_list); #endif /* USE_WIN32 */ NOEXPORT ALLOC_LIST *get_alloc_list_ptr(void *, const char *, int); NOEXPORT void str_leak_debug(ALLOC_LIST *, int); TLS_DATA *ui_tls; static uint8_t canary[10]; /* 80-bit canary value */ static volatile uint64_t canary_initialized=CANARY_UNINTIALIZED; /**************************************** string manipulation functions */ #ifndef va_copy #ifdef __va_copy #define va_copy(dst, src) __va_copy((dst), (src)) #else /* __va_copy */ #define va_copy(dst, src) memcpy(&(dst), &(src), sizeof(va_list)) #endif /* __va_copy */ #endif /* va_copy */ char *str_dup_debug(const char *str, const char *file, int line) { char *retval; retval=str_alloc_debug(strlen(str)+1, file, line); strcpy(retval, str); return retval; } char *str_printf(const char *format, ...) { char *txt; va_list arglist; va_start(arglist, format); txt=str_vprintf(format, arglist); va_end(arglist); return txt; } #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif /* __GNUC__ */ char *str_vprintf(const char *format, va_list start_ap) { int n; size_t size=32; char *p; va_list ap; p=str_alloc(size); for(;;) { va_copy(ap, start_ap); n=vsnprintf(p, size, format, ap); if(n>-1 && n<(int)size) return p; if(n>-1) /* glibc 2.1 */ size=(size_t)n+1; /* precisely what is needed */ else /* glibc 2.0, WIN32, etc. */ size*=2; /* twice the old size */ p=str_realloc(p, size); } } #ifdef __GNUC__ #pragma GCC diagnostic pop #endif /* __GNUC__ */ #ifdef USE_WIN32 LPTSTR str_tprintf(LPCTSTR format, ...) { LPTSTR txt; va_list arglist; va_start(arglist, format); txt=str_vtprintf(format, arglist); va_end(arglist); return txt; } NOEXPORT LPTSTR str_vtprintf(LPCTSTR format, va_list start_ap) { int n; size_t size=32; LPTSTR p; va_list ap; p=str_alloc(size*sizeof(TCHAR)); for(;;) { va_copy(ap, start_ap); n=_vsntprintf(p, size, format, ap); if(n>-1 && n<(int)size) return p; size*=2; p=str_realloc(p, size*sizeof(TCHAR)); } } #endif /**************************************** memory allocation wrappers */ void str_init(TLS_DATA *tls_data) { tls_data->alloc_head=NULL; tls_data->alloc_bytes=tls_data->alloc_blocks=0; } void str_cleanup(TLS_DATA *tls_data) { /* free all attached allocations */ while(tls_data->alloc_head) /* str_free macro requires an lvalue */ str_free_expression(tls_data->alloc_head+1); } void str_canary_init() { if(canary_initialized!=CANARY_UNINTIALIZED) return; /* prevent double initialization on config reload */ RAND_bytes(canary, (int)sizeof canary); /* an error would reduce the effectiveness of canaries */ /* this is nothing critical, so the return value is ignored here */ canary_initialized=CANARY_INITIALIZED; /* after RAND_bytes */ } void str_stats() { TLS_DATA *tls_data; ALLOC_LIST *alloc_list; int i=0; if(!tls_initialized) fatal("str not initialized"); tls_data=tls_get(); if(!tls_data || (!tls_data->alloc_blocks && !tls_data->alloc_bytes)) return; /* skip if no data is allocated */ s_log(LOG_DEBUG, "str_stats: %lu block(s), " "%lu data byte(s), %lu control byte(s)", (unsigned long)tls_data->alloc_blocks, (unsigned long)tls_data->alloc_bytes, (unsigned long)(tls_data->alloc_blocks* (sizeof(ALLOC_LIST)+sizeof canary))); for(alloc_list=tls_data->alloc_head; alloc_list; alloc_list=alloc_list->next) { if(++i>10) /* limit the number of results */ break; s_log(LOG_DEBUG, "str_stats: %lu byte(s) at %s:%d", (unsigned long)alloc_list->size, alloc_list->alloc_file, alloc_list->alloc_line); } } void *str_alloc_debug(size_t size, const char *file, int line) { TLS_DATA *tls_data; ALLOC_LIST *alloc_list; if(!tls_initialized) fatal_debug("str not initialized", file, line); tls_data=tls_get(); if(!tls_data) { tls_data=tls_alloc(NULL, NULL, "alloc"); s_log(LOG_ERR, "INTERNAL ERROR: Uninitialized TLS at %s, line %d", file, line); } alloc_list=(ALLOC_LIST *)str_alloc_detached_debug(size, file, line)-1; alloc_list->prev=NULL; alloc_list->next=tls_data->alloc_head; alloc_list->tls=tls_data; if(tls_data->alloc_head) tls_data->alloc_head->prev=alloc_list; tls_data->alloc_head=alloc_list; tls_data->alloc_bytes+=size; tls_data->alloc_blocks++; return alloc_list+1; } void *str_alloc_detached_debug(size_t size, const char *file, int line) { ALLOC_LIST *alloc_list; #if 0 printf("allocating %lu bytes at %s:%d\n", (unsigned long)size, file, line); #endif alloc_list=calloc(1, sizeof(ALLOC_LIST)+size+sizeof canary); if(!alloc_list) fatal_debug("Out of memory", file, line); alloc_list->prev=NULL; /* for debugging */ alloc_list->next=NULL; /* for debugging */ alloc_list->tls=NULL; alloc_list->size=size; alloc_list->alloc_file=file; alloc_list->alloc_line=line; alloc_list->free_file="none"; alloc_list->free_line=0; alloc_list->valid_canary=canary_initialized; /* before memcpy */ memcpy((uint8_t *)(alloc_list+1)+size, canary, sizeof canary); alloc_list->magic=MAGIC_ALLOCATED; str_leak_debug(alloc_list, 1); return alloc_list+1; } void *str_realloc_debug(void *ptr, size_t size, const char *file, int line) { ALLOC_LIST *prev_alloc_list, *alloc_list; if(!ptr) return str_alloc_debug(size, file, line); prev_alloc_list=get_alloc_list_ptr(ptr, file, line); str_leak_debug(prev_alloc_list, -1); if(prev_alloc_list->size>size) /* shrinking the allocation */ memset((uint8_t *)ptr+size, 0, prev_alloc_list->size-size); /* paranoia */ alloc_list=realloc(prev_alloc_list, sizeof(ALLOC_LIST)+size+sizeof canary); if(!alloc_list) fatal_debug("Out of memory", file, line); ptr=alloc_list+1; if(size>alloc_list->size) /* growing the allocation */ memset((uint8_t *)ptr+alloc_list->size, 0, size-alloc_list->size); if(alloc_list->tls) { /* not detached */ /* refresh possibly invalidated linked list pointers */ if(alloc_list->tls->alloc_head==prev_alloc_list) alloc_list->tls->alloc_head=alloc_list; if(alloc_list->next) alloc_list->next->prev=alloc_list; if(alloc_list->prev) alloc_list->prev->next=alloc_list; /* update statistics while the old size is still available */ alloc_list->tls->alloc_bytes+=size-alloc_list->size; } alloc_list->size=size; alloc_list->alloc_file=file; alloc_list->alloc_line=line; alloc_list->free_file="none"; alloc_list->free_line=0; alloc_list->valid_canary=canary_initialized; /* before memcpy */ memcpy((uint8_t *)ptr+size, canary, sizeof canary); str_leak_debug(alloc_list, 1); return ptr; } /* detach from thread automatic deallocation list */ /* it has no effect if the allocation is already detached */ void str_detach_debug(void *ptr, const char *file, int line) { ALLOC_LIST *alloc_list; if(!ptr) /* do not attempt to free null pointers */ return; alloc_list=get_alloc_list_ptr(ptr, file, line); if(alloc_list->tls) { /* not detached */ /* remove from linked list */ if(alloc_list->tls->alloc_head==alloc_list) alloc_list->tls->alloc_head=alloc_list->next; if(alloc_list->next) alloc_list->next->prev=alloc_list->prev; if(alloc_list->prev) alloc_list->prev->next=alloc_list->next; /* update statistics */ alloc_list->tls->alloc_bytes-=alloc_list->size; alloc_list->tls->alloc_blocks--; /* clear pointers */ alloc_list->next=NULL; alloc_list->prev=NULL; alloc_list->tls=NULL; } } void str_free_debug(void *ptr, const char *file, int line) { ALLOC_LIST *alloc_list; if(!ptr) /* do not attempt to free null pointers */ return; alloc_list=(ALLOC_LIST *)ptr-1; if(alloc_list->magic==MAGIC_DEALLOCATED) { /* double free */ /* this may (unlikely) log garbage instead of file names */ s_log(LOG_CRIT, "Double free attempt: ptr=%p alloc=%s:%d free#1=%s:%d free#2=%s:%d", ptr, alloc_list->alloc_file, alloc_list->alloc_line, alloc_list->free_file, alloc_list->free_line, file, line); return; } str_detach_debug(ptr, file, line); str_leak_debug(alloc_list, -1); alloc_list->free_file=file; alloc_list->free_line=line; alloc_list->magic=MAGIC_DEALLOCATED; /* detect double free attempts */ memset(ptr, 0, alloc_list->size+sizeof canary); /* paranoia */ free(alloc_list); } NOEXPORT ALLOC_LIST *get_alloc_list_ptr(void *ptr, const char *file, int line) { ALLOC_LIST *alloc_list; if(!tls_initialized) fatal_debug("str not initialized", file, line); alloc_list=(ALLOC_LIST *)ptr-1; if(alloc_list->magic!=MAGIC_ALLOCATED) /* not allocated by str_alloc() */ fatal_debug("Bad magic", file, line); /* LOL */ if(alloc_list->tls /* not detached */ && alloc_list->tls!=tls_get()) fatal_debug("Memory allocated in a different thread", file, line); if(alloc_list->valid_canary!=CANARY_UNINTIALIZED && safe_memcmp((uint8_t *)ptr+alloc_list->size, canary, sizeof canary)) fatal_debug("Dead canary", file, line); /* LOL */ return alloc_list; } /* #define STR_LEAK_DEBUG */ /* the implementation is slow, but it's not going to be used in production */ NOEXPORT void str_leak_debug(ALLOC_LIST *alloc_list, int change) { #ifndef STR_LEAK_DEBUG (void)alloc_list; /* squash the unused parameter warning */ (void)change; /* squash the unused parameter warning */ #else #define ALLOC_TABLE_SIZE 1000 #define MAX_ALLOCS 200 static struct { const char *alloc_file; int alloc_line; int num; } alloc_table[ALLOC_TABLE_SIZE]; static size_t alloc_num=0; size_t i; CRYPTO_w_lock(stunnel_locks[LOCK_LEAK]); for(i=0; ialloc_file && alloc_table[i].alloc_line==alloc_list->alloc_line) break; if(i==alloc_num) { if(alloc_num==ALLOC_TABLE_SIZE) { CRYPTO_w_unlock(stunnel_locks[LOCK_LEAK]); return; } alloc_table[i].alloc_file=alloc_list->alloc_file; alloc_table[i].alloc_line=alloc_list->alloc_line; alloc_table[i].num=0; ++alloc_num; } alloc_table[i].num+=change; CRYPTO_w_unlock(stunnel_locks[LOCK_LEAK]); if(alloc_table[i].num>MAX_ALLOCS && strcmp(alloc_table[i].alloc_file, "lhash.c")) fprintf(stderr, "%d allocations detected at %s:%d\n", alloc_table[i].num, alloc_table[i].alloc_file, alloc_table[i].alloc_line); #endif } /**************************************** memcmp() replacement */ /* a version of memcmp() with execution time not dependent on data values */ /* it does *not* allow to test whether s1 is greater or lesser than s2 */ int safe_memcmp(const void *s1, const void *s2, size_t n) { uint8_t *p1=(uint8_t *)s1, *p2=(uint8_t *)s2; int r=0; while(n--) r|=(*p1++)^(*p2++); return r; } /* end of str.c */ stunnel-5.30/src/common.h0000664000175000017500000003433112646221043012310 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #ifndef COMMON_H #define COMMON_H #include "version.h" /**************************************** common constants */ #define LIBWRAP_CLIENTS 5 /* CPU stack size */ #define DEFAULT_STACK_SIZE 65536 /* #define DEBUG_STACK_SIZE */ /* I/O buffer size: 18432 (0x4800) is the maximum size of SSL record payload */ #define BUFFSIZE 18432 /* how many bytes of random input to read from files for PRNG */ /* OpenSSL likes at least 128 bits, so 64 bytes seems plenty. */ #define RANDOM_BYTES 64 /* for FormatGuard */ /* #define __NO_FORMATGUARD_ */ /* additional diagnostic messages */ /* #define DEBUG_FD_ALLOC */ #ifdef DEBUG_INFO #define NOEXPORT #else #define NOEXPORT static #endif /**************************************** platform */ #ifdef _WIN32 #define USE_WIN32 #endif #ifdef _WIN32_WCE #define USE_WIN32 typedef int socklen_t; #endif #ifdef USE_WIN32 typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; typedef signed long long int64_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef unsigned long long uint64_t; #ifndef __MINGW32__ #ifdef _WIN64 typedef __int64 ssize_t; #else /* _WIN64 */ typedef int ssize_t; #endif /* _WIN64 */ #endif /* !__MINGW32__ */ #define PATH_MAX MAX_PATH #define USE_IPv6 #define _CRT_SECURE_NO_DEPRECATE #define _CRT_NONSTDC_NO_DEPRECATE #define _CRT_NON_CONFORMING_SWPRINTFS /* prevent including wincrypt.h, as it defines its own OCSP_RESPONSE */ #define __WINCRYPT_H__ #define S_EADDRINUSE WSAEADDRINUSE /* winsock does not define WSAEAGAIN */ /* in most (but not all!) BSD implementations EAGAIN==EWOULDBLOCK */ #define S_EAGAIN WSAEWOULDBLOCK #define S_ECONNRESET WSAECONNRESET #define S_EINPROGRESS WSAEINPROGRESS #define S_EINTR WSAEINTR #define S_EINVAL WSAEINVAL #define S_EISCONN WSAEISCONN #define S_EMFILE WSAEMFILE /* winsock does not define WSAENFILE */ #define S_ENOBUFS WSAENOBUFS /* winsock does not define WSAENOMEM */ #define S_ENOPROTOOPT WSAENOPROTOOPT #define S_ENOTSOCK WSAENOTSOCK #define S_EOPNOTSUPP WSAEOPNOTSUPP #define S_EWOULDBLOCK WSAEWOULDBLOCK #define S_ECONNABORTED WSAECONNABORTED #else /* USE_WIN32 */ #define S_EADDRINUSE EADDRINUSE #define S_EAGAIN EAGAIN #define S_ECONNRESET ECONNRESET #define S_EINPROGRESS EINPROGRESS #define S_EINTR EINTR #define S_EINVAL EINVAL #define S_EISCONN EISCONN #define S_EMFILE EMFILE #ifdef ENFILE #define S_ENFILE ENFILE #endif #ifdef ENOBUFS #define S_ENOBUFS ENOBUFS #endif #ifdef ENOMEM #define S_ENOMEM ENOMEM #endif #define S_ENOPROTOOPT ENOPROTOOPT #define S_ENOTSOCK ENOTSOCK #define S_EOPNOTSUPP EOPNOTSUPP #define S_EWOULDBLOCK EWOULDBLOCK #define S_ECONNABORTED ECONNABORTED #endif /* USE_WIN32 */ /**************************************** generic headers */ #ifdef __vms #include #endif /* __vms */ /* for nsr-tandem-nsk architecture */ #ifdef __TANDEM #include #endif /* threads model */ #ifdef USE_UCONTEXT #define __MAKECONTEXT_V2_SOURCE #include #endif #ifdef USE_PTHREAD #ifndef THREADS #define THREADS #endif #ifndef _REENTRANT /* _REENTRANT is required for thread-safe errno on Solaris */ #define _REENTRANT #endif #ifndef _THREAD_SAFE #define _THREAD_SAFE #endif #include #endif /* systemd */ #ifdef USE_SYSTEMD #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif /* must be included before sys/stat.h for Ultrix */ /* must be included before sys/socket.h for OpenBSD */ #include /* u_short, u_long */ /* general headers */ #include /* must be included before sys/stat.h for Ultrix */ #ifndef _WIN32_WCE #include #endif #include #include /* va_ */ #include #include /* isalnum */ #include #include /* stat */ #include #include /**************************************** WIN32 headers */ #ifdef USE_WIN32 #define HAVE_STRUCT_ADDRINFO #define HAVE_SNPRINTF #define snprintf _snprintf #define HAVE_VSNPRINTF #define vsnprintf _vsnprintf #define strcasecmp _stricmp #define strncasecmp _strnicmp #define sleep(c) Sleep(1000*(c)) #define get_last_socket_error() WSAGetLastError() #define set_last_socket_error(e) WSASetLastError(e) #define get_last_error() GetLastError() #define set_last_error(e) SetLastError(e) #define readsocket(s,b,n) recv((s),(b),(int)(n),0) #define writesocket(s,b,n) send((s),(b),(int)(n),0) /* #define Win32_Winsock */ #define __USE_W32_SOCKETS /* Winsock2 header for IPv6 definitions */ #include #include #include #include /* _beginthread */ #include /* SHGetFolderPath */ #include #include "resources.h" /**************************************** non-WIN32 headers */ #else /* USE_WIN32 */ #ifdef __INNOTEK_LIBC__ #define socklen_t __socklen_t #define strcasecmp stricmp #define strncasecmp strnicmp #define NI_NUMERICHOST 1 #define NI_NUMERICSERV 2 #define get_last_socket_error() sock_errno() #define set_last_socket_error(e) () #define get_last_error() errno #define set_last_error(e) (errno=(e)) #define readsocket(s,b,n) recv((s),(b),(n),0) #define writesocket(s,b,n) send((s),(b),(n),0) #define closesocket(s) close(s) #define ioctlsocket(a,b,c) so_ioctl((a),(b),(c)) #else #define get_last_socket_error() errno #define set_last_socket_error(e) (errno=(e)) #define get_last_error() errno #define set_last_error(e) (errno=(e)) #define readsocket(s,b,n) read((s),(b),(n)) #define writesocket(s,b,n) write((s),(b),(n)) #define closesocket(s) close(s) #define ioctlsocket(a,b,c) ioctl((a),(b),(c)) #endif typedef int SOCKET; #define INVALID_SOCKET (-1) /* OpenVMS compatibility */ #ifdef __vms #define LIBDIR "__NA__" #ifdef __alpha #define HOST "alpha-openvms" #else #define HOST "vax-openvms" #endif #include #include #else /* __vms */ #include #endif /* __vms */ /* Unix-specific headers */ #include /* signal */ #include /* wait */ #ifdef HAVE_LIMITS_H #include /* INT_MAX */ #endif #ifdef HAVE_SYS_RESOURCE_H #include /* getrlimit */ #endif #ifdef HAVE_UNISTD_H #include /* getpid, fork, execvp, exit */ #endif #ifdef HAVE_STROPTS_H #include #endif #ifdef HAVE_MALLOC_H #include /* mallopt */ #endif #ifdef HAVE_SYS_SELECT_H #include /* for aix */ #endif #include #if defined(HAVE_POLL) && !defined(BROKEN_POLL) #ifdef HAVE_POLL_H #include #define USE_POLL #else /* HAVE_POLL_H */ #ifdef HAVE_SYS_POLL_H #include #define USE_POLL #endif /* HAVE_SYS_POLL_H */ #endif /* HAVE_POLL_H */ #endif /* HAVE_POLL && !BROKEN_POLL */ #ifdef HAVE_SYS_FILIO_H #include /* for FIONBIO */ #endif #include #ifdef HAVE_GRP_H #include #endif #ifdef __BEOS__ #include #endif #ifdef HAVE_SYS_UIO_H #include /* struct iovec */ #endif /* HAVE_SYS_UIO_H */ /* BSD sockets */ #include /* struct sockaddr_in */ #include /* getpeername */ #include /* inet_ntoa */ #include /* select */ #include /* ioctl */ #ifdef HAVE_SYS_UN_H #include #endif #include #include #ifndef INADDR_ANY #define INADDR_ANY (u32)0x00000000 #endif #ifndef INADDR_LOOPBACK #define INADDR_LOOPBACK (u32)0x7F000001 #endif #if defined(HAVE_WAITPID) /* for SYSV systems */ #define wait_for_pid(a, b, c) waitpid((a), (b), (c)) #define HAVE_WAIT_FOR_PID 1 #elif defined(HAVE_WAIT4) /* for BSD systems */ #define wait_for_pid(a, b, c) wait4((a), (b), (c), NULL) #define HAVE_WAIT_FOR_PID 1 #endif /* SunOS 4 */ #if defined(sun) && !defined(__svr4__) && !defined(__SVR4) #define atexit(a) on_exit((a), NULL) extern int sys_nerr; extern char *sys_errlist[]; #define strerror(num) ((num)==0 ? "No error" : \ ((num)>=sys_nerr ? "Unknown error" : sys_errlist[num])) #endif /* SunOS 4 */ /* AIX does not have SOL_TCP defined */ #ifndef SOL_TCP #define SOL_TCP SOL_SOCKET #endif /* SOL_TCP */ /* Linux */ #ifdef __linux__ #ifndef IP_FREEBIND /* kernel headers without IP_FREEBIND definition */ #define IP_FREEBIND 15 #endif /* IP_FREEBIND */ #ifndef IP_TRANSPARENT /* kernel headers without IP_TRANSPARENT definition */ #define IP_TRANSPARENT 19 #endif /* IP_TRANSPARENT */ #ifdef HAVE_LINUX_NETFILTER_IPV4_H #include #include #include #endif /* HAVE_LINUX_NETFILTER_IPV4_H */ #endif /* __linux__ */ #ifdef HAVE_SYS_SYSCALL_H #include /* SYS_gettid */ #endif #ifdef HAVE_LINUX_SCHED_H #include /* SCHED_BATCH */ #endif #endif /* USE_WIN32 */ #ifndef S_ISREG #define S_ISREG(m) (((m)&S_IFMT)==S_IFREG) #endif /**************************************** OpenSSL headers */ #define OPENSSL_THREAD_DEFINES #include /* opensslv.h requires prior opensslconf.h to include -fips in version string */ #include #if OPENSSL_VERSION_NUMBER<0x0090700fL #error OpenSSL 0.9.7 or later is required #endif /* OpenSSL older than 0.9.7 */ #if defined(USE_PTHREAD) && !defined(OPENSSL_THREADS) #error OpenSSL library compiled without thread support #endif /* !OPENSSL_THREADS && USE_PTHREAD */ #if OPENSSL_VERSION_NUMBER<0x0090800fL #define OPENSSL_NO_ECDH #define OPENSSL_NO_COMP #endif /* OpenSSL older than 0.9.8 */ /* non-blocking OCSP API is not available before OpenSSL 0.9.8h */ #if OPENSSL_VERSION_NUMBER<0x00908080L #ifndef OPENSSL_NO_OCSP #define OPENSSL_NO_OCSP #endif /* !defined(OPENSSL_NO_OCSP) */ #endif /* OpenSSL older than 0.9.8h */ #if OPENSSL_VERSION_NUMBER<0x10000000L #define OPENSSL_NO_TLSEXT #define OPENSSL_NO_PSK #endif /* OpenSSL older than 1.0.0 */ #if OPENSSL_VERSION_NUMBER<0x10001000L || defined(OPENSSL_NO_TLS1) #define OPENSSL_NO_TLS1_1 #define OPENSSL_NO_TLS1_2 #endif /* OpenSSL older than 1.0.1 || defined(OPENSSL_NO_TLS1) */ #if OPENSSL_VERSION_NUMBER>=0x10100000L #ifndef OPENSSL_NO_SSL2 #define OPENSSL_NO_SSL2 #endif /* !defined(OPENSSL_NO_SSL2) */ #endif /* OpenSSL 1.1.0 or newer */ #if defined(USE_WIN32) && defined(OPENSSL_FIPS) #define USE_FIPS #endif #include #include #include #include #include #include /* for CRYPTO_* and SSLeay_version */ #include #include #ifndef OPENSSL_NO_MD4 #include #endif /* !defined(OPENSSL_NO_MD4) */ #include #ifndef OPENSSL_NO_DH #include #endif /* !defined(OPENSSL_NO_DH) */ #ifndef OPENSSL_NO_ENGINE #include #endif /* !defined(OPENSSL_NO_ENGINE) */ #ifndef OPENSSL_NO_OCSP #include #endif /* !defined(OPENSSL_NO_OCSP) */ #ifndef OPENSSL_NO_COMP /* not defined in public headers before OpenSSL 0.9.8 */ STACK_OF(SSL_COMP) *SSL_COMP_get_compression_methods(void); #endif /* !defined(OPENSSL_NO_COMP) */ #ifndef OPENSSL_VERSION #define OPENSSL_VERSION SSLEAY_VERSION #define OpenSSL_version_num() SSLeay() #define OpenSSL_version(x) SSLeay_version(x) #endif /**************************************** other defines */ /* always use IPv4 defaults! */ #define DEFAULT_LOOPBACK "127.0.0.1" #define DEFAULT_ANY "0.0.0.0" #if 0 #define DEFAULT_LOOPBACK "::1" #define DEFAULT_ANY "::" #endif #if defined (USE_WIN32) || defined (__vms) #define LOG_EMERG 0 #define LOG_ALERT 1 #define LOG_CRIT 2 #define LOG_ERR 3 #define LOG_WARNING 4 #define LOG_NOTICE 5 #define LOG_INFO 6 #define LOG_DEBUG 7 #endif /* defined (USE_WIN32) || defined (__vms) */ #ifndef offsetof #define offsetof(T, F) ((unsigned)((char *)&((T *)0L)->F - (char *)0L)) #endif #endif /* defined COMMON_H */ /* end of common.h */ stunnel-5.30/src/sthreads.c0000664000175000017500000003726212646221043012636 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #ifdef USE_OS2 #define INCL_DOSPROCESS #include #endif #include "common.h" #include "prototypes.h" int stunnel_locks[STUNNEL_LOCKS]; #if defined(USE_UCONTEXT) || defined(USE_FORK) /* no need for critical sections */ #endif /* USE_UCONTEXT || USE_FORK */ #ifdef USE_UCONTEXT #if defined(CPU_SPARC) && ( \ defined(OS_SOLARIS2_0) || \ defined(OS_SOLARIS2_1) || \ defined(OS_SOLARIS2_2) || \ defined(OS_SOLARIS2_3) || \ defined(OS_SOLARIS2_4) || \ defined(OS_SOLARIS2_5) || \ defined(OS_SOLARIS2_6) || \ defined(OS_SOLARIS2_7) || \ defined(OS_SOLARIS2_8)) #define ARGC 2 #else #define ARGC 1 #endif /* first context on the ready list is the active context */ CONTEXT *ready_head=NULL, *ready_tail=NULL; /* ready to execute */ CONTEXT *waiting_head=NULL, *waiting_tail=NULL; /* waiting on poll() */ unsigned long stunnel_process_id(void) { return (unsigned long)getpid(); } unsigned long stunnel_thread_id(void) { return ready_head ? ready_head->id : 0; } NOEXPORT CONTEXT *new_context(void) { static unsigned long next_id=1; CONTEXT *context; /* allocate and fill the CONTEXT structure */ context=str_alloc_detached(sizeof(CONTEXT)); context->id=next_id++; context->fds=NULL; context->ready=0; /* append to the tail of the ready queue */ context->next=NULL; if(ready_tail) ready_tail->next=context; ready_tail=context; if(!ready_head) ready_head=context; return context; } int sthreads_init(void) { /* create the first (listening) context and put it in the running queue */ if(!new_context()) { s_log(LOG_ERR, "Cannot create the listening context"); return 1; } /* update tls for newly allocated ready_head */ ui_tls=tls_alloc(NULL, ui_tls, "ui"); /* no need to initialize ucontext_t structure here it will be initialied with swapcontext() call */ return 0; } int create_client(SOCKET ls, SOCKET s, CLI *arg, void *(*cli)(void *)) { CONTEXT *context; (void)ls; /* this parameter is only used with USE_FORK */ s_log(LOG_DEBUG, "Creating a new context"); context=new_context(); if(!context) { str_free(arg); if(s>=0) closesocket(s); return -1; } /* initialize context_t structure */ if(getcontext(&context->context)<0) { str_free(context); str_free(arg); if(s>=0) closesocket(s); ioerror("getcontext"); return -1; } context->context.uc_link=NULL; /* stunnel does not use uc_link */ /* create stack */ context->stack=str_alloc_detached(arg->opt->stack_size); #if defined(__sgi) || ARGC==2 /* obsolete ss_sp semantics */ context->context.uc_stack.ss_sp=context->stack+arg->opt->stack_size-8; #else context->context.uc_stack.ss_sp=context->stack; #endif context->context.uc_stack.ss_size=arg->opt->stack_size; context->context.uc_stack.ss_flags=0; makecontext(&context->context, (void(*)(void))cli, ARGC, arg); s_log(LOG_DEBUG, "New context created"); return 0; } #endif /* USE_UCONTEXT */ #ifdef USE_FORK int sthreads_init(void) { return 0; } unsigned long stunnel_process_id(void) { return (unsigned long)getpid(); } unsigned long stunnel_thread_id(void) { return 0L; } NOEXPORT void null_handler(int sig) { (void)sig; /* squash the unused parameter warning */ signal(SIGCHLD, null_handler); } int create_client(SOCKET ls, SOCKET s, CLI *arg, void *(*cli)(void *)) { switch(fork()) { case -1: /* error */ str_free(arg); if(s>=0) closesocket(s); return -1; case 0: /* child */ if(ls>=0) closesocket(ls); signal(SIGCHLD, null_handler); cli(arg); _exit(0); default: /* parent */ str_free(arg); if(s>=0) closesocket(s); } return 0; } #endif /* USE_FORK */ #ifdef USE_PTHREAD struct CRYPTO_dynlock_value { pthread_rwlock_t rwlock; }; static struct CRYPTO_dynlock_value *lock_cs; NOEXPORT struct CRYPTO_dynlock_value *dyn_create_function(const char *file, int line) { struct CRYPTO_dynlock_value *value; (void)file; /* squash the unused parameter warning */ (void)line; /* squash the unused parameter warning */ value=str_alloc_detached(sizeof(struct CRYPTO_dynlock_value)); pthread_rwlock_init(&value->rwlock, NULL); return value; } NOEXPORT void dyn_lock_function(int mode, struct CRYPTO_dynlock_value *value, const char *file, int line) { (void)file; /* squash the unused parameter warning */ (void)line; /* squash the unused parameter warning */ if(mode&CRYPTO_LOCK) { /* either CRYPTO_READ or CRYPTO_WRITE (but not both) are needed */ if(!(mode&CRYPTO_READ)==!(mode&CRYPTO_WRITE)) fatal("Invalid locking mode"); if(mode&CRYPTO_WRITE) pthread_rwlock_wrlock(&value->rwlock); else pthread_rwlock_rdlock(&value->rwlock); } else pthread_rwlock_unlock(&value->rwlock); } NOEXPORT void dyn_destroy_function(struct CRYPTO_dynlock_value *value, const char *file, int line) { (void)file; /* squash the unused parameter warning */ (void)line; /* squash the unused parameter warning */ pthread_rwlock_destroy(&value->rwlock); str_free(value); } NOEXPORT void locking_callback(int mode, int type, const char *file, int line) { dyn_lock_function(mode, lock_cs+type, file, line); } unsigned long stunnel_process_id(void) { return (unsigned long)getpid(); } unsigned long stunnel_thread_id(void) { #if defined(SYS_gettid) && defined(__linux__) return (unsigned long)syscall(SYS_gettid); #else return (unsigned long)pthread_self(); #endif } #if OPENSSL_VERSION_NUMBER>=0x10000000L NOEXPORT void threadid_func(CRYPTO_THREADID *tid) { CRYPTO_THREADID_set_numeric(tid, stunnel_thread_id()); } #endif int sthreads_init(void) { int i; /* initialize OpenSSL dynamic locks callbacks */ CRYPTO_set_dynlock_create_callback(dyn_create_function); CRYPTO_set_dynlock_lock_callback(dyn_lock_function); CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function); /* initialize stunnel critical sections */ for(i=0; i=0x10000000L CRYPTO_THREADID_set_callback(threadid_func); #else CRYPTO_set_id_callback(stunnel_thread_id); #endif CRYPTO_set_locking_callback(locking_callback); return 0; } int create_client(SOCKET ls, SOCKET s, CLI *arg, void *(*cli)(void *)) { pthread_t thread; pthread_attr_t pth_attr; int error; #if defined(HAVE_PTHREAD_SIGMASK) && !defined(__APPLE__) /* disabled on OS X due to strange problems on Mac OS X 10.5 it seems to restore signal mask somewhere (I couldn't find where) effectively blocking signals after first accepted connection */ sigset_t new_set, old_set; #endif /* HAVE_PTHREAD_SIGMASK && !__APPLE__*/ (void)ls; /* this parameter is only used with USE_FORK */ #if defined(HAVE_PTHREAD_SIGMASK) && !defined(__APPLE__) /* the idea is that only the main thread handles all the signals with * posix threads; signals are blocked for any other thread */ sigfillset(&new_set); pthread_sigmask(SIG_SETMASK, &new_set, &old_set); /* block signals */ #endif /* HAVE_PTHREAD_SIGMASK && !__APPLE__*/ pthread_attr_init(&pth_attr); pthread_attr_setdetachstate(&pth_attr, PTHREAD_CREATE_DETACHED); pthread_attr_setstacksize(&pth_attr, arg->opt->stack_size); error=pthread_create(&thread, &pth_attr, cli, arg); pthread_attr_destroy(&pth_attr); #if defined(HAVE_PTHREAD_SIGMASK) && !defined(__APPLE__) pthread_sigmask(SIG_SETMASK, &old_set, NULL); /* unblock signals */ #endif /* HAVE_PTHREAD_SIGMASK && !__APPLE__*/ if(error) { errno=error; ioerror("pthread_create"); str_free(arg); if(s>=0) closesocket(s); return -1; } return 0; } #endif /* USE_PTHREAD */ #ifdef USE_WIN32 /* Slim Reader/Writer (SRW) Lock would be better than CRITICAL_SECTION, * but it is unsupported on Windows XP (and earlier versions of Windows): * https://msdn.microsoft.com/en-us/library/windows/desktop/aa904937%28v=vs.85%29.aspx */ struct CRYPTO_dynlock_value { CRITICAL_SECTION mutex; }; static struct CRYPTO_dynlock_value *lock_cs; NOEXPORT struct CRYPTO_dynlock_value *dyn_create_function(const char *file, int line) { struct CRYPTO_dynlock_value *value; (void)file; /* squash the unused parameter warning */ (void)line; /* squash the unused parameter warning */ value=str_alloc_detached(sizeof(struct CRYPTO_dynlock_value)); InitializeCriticalSection(&value->mutex); return value; } NOEXPORT void dyn_lock_function(int mode, struct CRYPTO_dynlock_value *value, const char *file, int line) { (void)file; /* squash the unused parameter warning */ (void)line; /* squash the unused parameter warning */ if(mode&CRYPTO_LOCK) EnterCriticalSection(&value->mutex); else LeaveCriticalSection(&value->mutex); } NOEXPORT void dyn_destroy_function(struct CRYPTO_dynlock_value *value, const char *file, int line) { (void)file; /* squash the unused parameter warning */ (void)line; /* squash the unused parameter warning */ DeleteCriticalSection(&value->mutex); str_free(value); } NOEXPORT void locking_callback(int mode, int type, const char *file, int line) { dyn_lock_function(mode, lock_cs+type, file, line); } unsigned long stunnel_process_id(void) { return GetCurrentProcessId() & 0x00ffffff; } unsigned long stunnel_thread_id(void) { return GetCurrentThreadId() & 0x00ffffff; } int sthreads_init(void) { int i; /* initialize OpenSSL dynamic locks callbacks */ CRYPTO_set_dynlock_create_callback(dyn_create_function); CRYPTO_set_dynlock_lock_callback(dyn_lock_function); CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function); /* initialize stunnel critical sections */ for(i=0; iopt->stack_size, arg)==-1) { ioerror("_beginthread"); str_free(arg); if(s!=INVALID_SOCKET) closesocket(s); return -1; } s_log(LOG_DEBUG, "New thread created"); return 0; } #endif /* USE_WIN32 */ #ifdef USE_OS2 int sthreads_init(void) { return 0; } unsigned long stunnel_process_id(void) { PTIB ptib=NULL; DosGetInfoBlocks(&ptib, NULL); return (unsigned long)ptib->tib_ordinal; } unsigned long stunnel_thread_id(void) { PPIB ppib=NULL; DosGetInfoBlocks(NULL, &ppib); return (unsigned long)ppib->pib_ulpid; } int create_client(SOCKET ls, SOCKET s, CLI *arg, void *(*cli)(void *)) { (void)ls; /* this parameter is only used with USE_FORK */ s_log(LOG_DEBUG, "Creating a new thread"); if((long)_beginthread((void(*)(void *))cli, NULL, arg->opt->stack_size, arg)==-1L) { ioerror("_beginthread"); str_free(arg); if(s>=0) closesocket(s); return -1; } s_log(LOG_DEBUG, "New thread created"); return 0; } #endif /* USE_OS2 */ #ifdef _WIN32_WCE long _beginthread(void (*start_address)(void *), int stack_size, void *arglist) { DWORD thread_id; HANDLE handle; handle=CreateThread(NULL, stack_size, (LPTHREAD_START_ROUTINE)start_address, arglist, STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_id); if(!handle) return -1L; CloseHandle(handle); return 0; } void _endthread(void) { ExitThread(0); } #endif /* _WIN32_WCE */ #ifdef DEBUG_STACK_SIZE #define STACK_RESERVE (STACK_SIZE/8) #define VERIFY_AREA ((STACK_SIZE-STACK_RESERVE)/sizeof(uint32_t)) #define TEST_VALUE 0xdeadbeef /* some heuristic to determine the usage of client stack size */ void stack_info(int init) { /* 1-initialize, 0-display */ uint32_t table[VERIFY_AREA]; int i, num; static int min_num=VERIFY_AREA; if(init) { for(i=0; inum) /* use the higher value */ num=i; if(num<64) { s_log(LOG_NOTICE, "STACK_RESERVE is too high"); return; } if(num * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #ifndef PROTOTYPES_H #define PROTOTYPES_H #include "common.h" /**************************************** forward declarations */ typedef struct tls_data_struct TLS_DATA; /**************************************** data structures */ /* non-zero constants for the "redirect" option */ #define REDIRECT_ON 1 #define REDIRECT_OFF 2 #if defined (USE_WIN32) #define ICON_IMAGE HICON #elif defined(__APPLE__) #define ICON_IMAGE void * #endif typedef enum { ICON_ERROR, ICON_IDLE, ICON_ACTIVE, ICON_NONE /* it has to be the last one */ } ICON_TYPE; typedef enum { LOG_MODE_NONE, LOG_MODE_ERROR, LOG_MODE_INFO, LOG_MODE_CONFIGURED } LOG_MODE; typedef enum { LOG_ID_SEQUENTIAL, LOG_ID_UNIQUE, LOG_ID_THREAD } LOG_ID; typedef enum { FILE_MODE_READ, FILE_MODE_APPEND, FILE_MODE_OVERWRITE } FILE_MODE; typedef union sockaddr_union { struct sockaddr sa; struct sockaddr_in in; #ifdef USE_IPv6 struct sockaddr_in6 in6; #endif #ifdef HAVE_STRUCT_SOCKADDR_UN struct sockaddr_un un; #endif } SOCKADDR_UNION; typedef struct name_list_struct { char *name; struct name_list_struct *next; } NAME_LIST; typedef struct sockaddr_list { /* list of addresses */ SOCKADDR_UNION *addr; /* the list of addresses */ unsigned *rr_ptr, rr_val; /* current address for round-robin */ unsigned num; /* how many addresses are used */ int passive; /* listening socket */ NAME_LIST *names; /* a list of unresolved names */ } SOCKADDR_LIST; #ifndef OPENSSL_NO_COMP typedef enum { COMP_NONE, COMP_DEFLATE, COMP_ZLIB } COMP_TYPE; #endif /* !defined(OPENSSL_NO_COMP) */ typedef struct { /* some data for SSL initialization in ssl.c */ #ifndef OPENSSL_NO_COMP COMP_TYPE compression; /* compression type */ #endif /* !defined(OPENSSL_NO_COMP) */ char *egd_sock; /* entropy gathering daemon socket */ char *rand_file; /* file with random data */ long random_bytes; /* how many random bytes to read */ /* some global data for stunnel.c */ #ifndef USE_WIN32 #ifdef HAVE_CHROOT char *chroot_dir; #endif unsigned long dpid; char *pidfile; #endif /* logging-support data for log.c */ #ifndef USE_WIN32 int log_facility; /* debug facility for syslog */ #endif char *output_file; FILE_MODE log_file_mode; /* user interface configuraion */ #ifdef ICON_IMAGE ICON_IMAGE icon[ICON_NONE]; /* user-specified GUI icons */ #endif /* on/off switches */ struct { unsigned rand_write:1; /* overwrite rand_file */ #ifdef USE_WIN32 unsigned taskbar:1; /* enable the taskbar icon */ #else /* !USE_WIN32 */ unsigned foreground:1; unsigned log_stderr:1; unsigned log_syslog:1; #endif #ifdef USE_FIPS unsigned fips:1; /* enable FIPS 140-2 mode */ #endif } option; } GLOBAL_OPTIONS; extern GLOBAL_OPTIONS global_options; #ifndef OPENSSL_NO_TLSEXT typedef struct servername_list_struct SERVERNAME_LIST;/* forward declaration */ #endif /* !defined(OPENSSL_NO_TLSEXT) */ #ifndef OPENSSL_NO_PSK typedef struct psk_keys_struct { char *identity; unsigned char *key_val; size_t key_len; struct psk_keys_struct *next; } PSK_KEYS; typedef struct psk_table_struct { PSK_KEYS **val; size_t num; } PSK_TABLE; #endif /* !defined(OPENSSL_NO_PSK) */ typedef struct service_options_struct { struct service_options_struct *next; /* next node in the services list */ SSL_CTX *ctx; /* SSL context */ char *servname; /* service name for logging & permission checking */ /* service-specific data for stunnel.c */ #ifndef USE_WIN32 uid_t uid; gid_t gid; #endif /* service-specific data for log.c */ int log_level; /* debug level for logging */ LOG_ID log_id; /* logging session id type */ /* service-specific data for sthreads.c */ #ifndef USE_FORK size_t stack_size; /* stack size for this thread */ #endif /* service-specific data for verify.c */ char *ca_dir; /* directory for hashed certs */ char *ca_file; /* file containing bunches of certs */ char *crl_dir; /* directory for hashed CRLs */ char *crl_file; /* file containing bunches of CRLs */ int verify_level; #ifndef OPENSSL_NO_OCSP char *ocsp_url; unsigned long ocsp_flags; #endif /* !defined(OPENSSL_NO_OCSP) */ #if OPENSSL_VERSION_NUMBER>=0x10002000L NAME_LIST *check_host, *check_email, *check_ip; /* cert subject checks */ NAME_LIST *config; /* OpenSSL CONF options */ #endif /* OPENSSL_VERSION_NUMBER>=0x10002000L */ /* service-specific data for ctx.c */ char *cipher_list; char *cert; /* cert filename */ char *key; /* pem (priv key/cert) filename */ long session_size, session_timeout; long unsigned ssl_options_set; #if OPENSSL_VERSION_NUMBER>=0x009080dfL long unsigned ssl_options_clear; #endif /* OpenSSL 0.9.8m or later */ SSL_METHOD *client_method, *server_method; SOCKADDR_UNION sessiond_addr; #ifndef OPENSSL_NO_TLSEXT char *sni; SERVERNAME_LIST *servername_list_head, *servername_list_tail; #endif /* !defined(OPENSSL_NO_TLSEXT) */ #ifndef OPENSSL_NO_PSK char *psk_identity; PSK_KEYS *psk_keys, *psk_selected; PSK_TABLE psk_sorted; #endif /* !defined(OPENSSL_NO_PSK) */ #ifndef OPENSSL_NO_ECDH int curve; #endif /* !defined(OPENSSL_NO_ECDH) */ #ifndef OPENSSL_NO_ENGINE ENGINE *engine; /* engine to read the private key */ #endif /* !defined(OPENSSL_NO_ENGINE) */ /* service-specific data for client.c */ SOCKET fd; /* file descriptor accepting connections for this service */ SSL_SESSION *session; /* recently used session */ char *exec_name; /* program name for local mode */ #ifdef USE_WIN32 char *exec_args; /* program arguments for local mode */ #else char **exec_args; /* program arguments for local mode */ #endif SOCKADDR_UNION local_addr, source_addr; SOCKADDR_LIST connect_addr, redirect_addr; int timeout_busy; /* maximum waiting for data time */ int timeout_close; /* maximum close_notify time */ int timeout_connect; /* maximum connect() time */ int timeout_idle; /* maximum idle connection time */ enum {FAILOVER_RR, FAILOVER_PRIO} failover; /* failover strategy */ char *username; /* service-specific data for protocol.c */ char * protocol; char *protocol_host; char *protocol_domain; char *protocol_username; char *protocol_password; char *protocol_authentication; /* service-specific data for ui_*.c */ #ifdef USE_WIN32 LPTSTR file, help; #endif unsigned section_number; char *chain; /* on/off switches */ struct { unsigned accept:1; /* endpoint: accept */ unsigned client:1; unsigned delayed_lookup:1; #ifdef USE_LIBWRAP unsigned libwrap:1; #endif unsigned local:1; /* outgoing interface specified */ unsigned retry:1; /* loop remote+program */ unsigned sessiond:1; #ifndef OPENSSL_NO_TLSEXT unsigned sni:1; /* endpoint: sni */ #endif /* !defined(OPENSSL_NO_TLSEXT) */ #ifndef USE_WIN32 unsigned pty:1; unsigned transparent_src:1; #endif unsigned transparent_dst:1; /* endpoint: transparent destination */ unsigned protocol_endpoint:1; /* dynamic target from the protocol */ unsigned reset:1; /* reset sockets on error */ unsigned renegotiation:1; unsigned connect_before_ssl:1; #ifndef OPENSSL_NO_OCSP unsigned aia:1; /* Authority Information Access */ unsigned nonce:1; /* send and verify OCSP nonce */ #endif /* !defined(OPENSSL_NO_OCSP) */ #ifndef OPENSSL_NO_DH unsigned dh_needed:1; #endif /* OPENSSL_NO_DH */ } option; } SERVICE_OPTIONS; extern SERVICE_OPTIONS service_options; #ifndef OPENSSL_NO_TLSEXT struct servername_list_struct { char *servername; SERVICE_OPTIONS *opt; struct servername_list_struct *next; }; #endif /* !defined(OPENSSL_NO_TLSEXT) */ typedef enum { TYPE_NONE, TYPE_FLAG, TYPE_INT, TYPE_LINGER, TYPE_TIMEVAL, TYPE_STRING } VAL_TYPE; typedef union { int i_val; long l_val; char c_val[16]; struct linger linger_val; struct timeval timeval_val; } OPT_UNION; typedef struct { char *opt_str; int opt_level; int opt_name; VAL_TYPE opt_type; OPT_UNION *opt_val[3]; } SOCK_OPT; typedef enum { CONF_RELOAD, CONF_FILE, CONF_FD } CONF_TYPE; /* s_poll_set definition for network.c */ typedef struct { #ifdef USE_POLL struct pollfd *ufds; unsigned nfds; unsigned allocated; #else /* select */ fd_set *irfds, *iwfds, *ixfds, *orfds, *owfds, *oxfds; SOCKET max; #ifdef USE_WIN32 unsigned allocated; #endif #endif } s_poll_set; typedef struct disk_file { #ifdef USE_WIN32 HANDLE fh; #else int fd; #endif /* the inteface is prepared to easily implement buffering if needed */ } DISK_FILE; /* definitions for client.c */ typedef struct { SOCKET fd; /* file descriptor */ int is_socket; /* file descriptor is a socket */ } FD; typedef enum { RENEG_INIT, /* initial state */ RENEG_ESTABLISHED, /* initial handshake completed */ RENEG_DETECTED /* renegotiation detected */ } RENEG_STATE; typedef struct { jmp_buf err; /* exception handler needs to be 16-byte aligned on Itanium */ SSL *ssl; /* SSL connnection */ SERVICE_OPTIONS *opt; TLS_DATA *tls; SOCKADDR_UNION peer_addr; /* peer address */ socklen_t peer_addr_len; SOCKADDR_UNION *bind_addr; /* address to bind() the socket */ SOCKADDR_LIST connect_addr; /* either copied or resolved dynamically */ FD local_rfd, local_wfd; /* read and write local descriptors */ FD remote_fd; /* remote file descriptor */ /* IP for explicit local bind or transparent proxy */ unsigned long pid; /* PID of the local process */ SOCKET fd; /* temporary file descriptor */ RENEG_STATE reneg_state; /* used to track renegotiation attempts */ unsigned long long seq; /* sequential thread number for logging */ /* data for transfer() function */ char sock_buff[BUFFSIZE]; /* socket read buffer */ char ssl_buff[BUFFSIZE]; /* SSL read buffer */ size_t sock_ptr, ssl_ptr; /* index of the first unused byte */ FD *sock_rfd, *sock_wfd; /* read and write socket descriptors */ FD *ssl_rfd, *ssl_wfd; /* read and write SSL descriptors */ uint64_t sock_bytes, ssl_bytes; /* bytes written to socket and SSL */ s_poll_set *fds; /* file descriptors */ uintptr_t redirect; /* redirect to another destination after failed auth */ } CLI; /**************************************** prototypes for stunnel.c */ #ifndef USE_FORK extern long max_clients; extern volatile long num_clients; #endif void main_init(void); int main_configure(char *, char *); void main_cleanup(void); int drop_privileges(int); void daemon_loop(void); void unbind_ports(void); int bind_ports(void); void signal_post(int); #if !defined(USE_WIN32) && !defined(USE_OS2) void child_status(void); /* dead libwrap or 'exec' process detected */ #endif void stunnel_info(int); /**************************************** prototypes for options.c */ extern char configuration_file[PATH_MAX]; int options_cmdline(char *, char *); int options_parse(CONF_TYPE); void options_defaults(void); void options_apply(void); /**************************************** prototypes for fd.c */ #ifndef USE_FORK void get_limits(void); /* setup global max_clients and max_fds */ #endif SOCKET s_socket(int, int, int, int, char *); int s_pipe(int[2], int, char *); int s_socketpair(int, int, int, SOCKET[2], int, char *); SOCKET s_accept(SOCKET, struct sockaddr *, socklen_t *, int, char *); void set_nonblock(SOCKET, unsigned long); /**************************************** prototypes for log.c */ #if !defined(USE_WIN32) && !defined(__vms) void syslog_open(void); void syslog_close(void); #endif int log_open(void); void log_close(void); void log_flush(LOG_MODE); void s_log(int, const char *, ...) #ifdef __GNUC__ __attribute__((format(printf, 2, 3))); #else ; #endif char *log_id(CLI *); void fatal_debug(char *, const char *, int); #define fatal(a) fatal_debug((a), __FILE__, __LINE__) void ioerror(const char *); void sockerror(const char *); void log_error(int, int, const char *); char *s_strerror(int); /**************************************** prototypes for pty.c */ int pty_allocate(int *, int *, char *); /**************************************** prototypes for dhparam.c */ DH *get_dh2048(void); /**************************************** prototypes for cron.c */ int cron_init(void); /**************************************** prototypes for ssl.c */ extern int index_cli, index_opt, index_redirect, index_addr; int ssl_init(void); int ssl_configure(GLOBAL_OPTIONS *); /**************************************** prototypes for ctx.c */ typedef struct { SERVICE_OPTIONS *section; char pass[PEM_BUFSIZE]; } UI_DATA; #ifndef OPENSSL_NO_DH extern DH *dh_params; extern int dh_needed; #endif /* OPENSSL_NO_DH */ int context_init(SERVICE_OPTIONS *); #ifndef OPENSSL_NO_PSK void psk_sort(PSK_TABLE *, PSK_KEYS *); PSK_KEYS *psk_find(const PSK_TABLE *, const char *); #endif /* !defined(OPENSSL_NO_PSK) */ void sslerror(char *); /**************************************** prototypes for verify.c */ int verify_init(SERVICE_OPTIONS *); char *X509_NAME2text(X509_NAME *); /**************************************** prototypes for network.c */ s_poll_set *s_poll_alloc(void); void s_poll_free(s_poll_set *); void s_poll_init(s_poll_set *); void s_poll_add(s_poll_set *, SOCKET, int, int); void s_poll_remove(s_poll_set *, SOCKET); int s_poll_canread(s_poll_set *, SOCKET); int s_poll_canwrite(s_poll_set *, SOCKET); int s_poll_hup(s_poll_set *, SOCKET); int s_poll_rdhup(s_poll_set *, SOCKET); int s_poll_wait(s_poll_set *, int, int); void s_poll_dump(s_poll_set *, int); #ifdef USE_WIN32 #define SIGNAL_RELOAD_CONFIG 1 #define SIGNAL_REOPEN_LOG 2 #define SIGNAL_TERMINATE 3 #else #define SIGNAL_RELOAD_CONFIG SIGHUP #define SIGNAL_REOPEN_LOG SIGUSR1 #define SIGNAL_TERMINATE SIGTERM #endif int set_socket_options(SOCKET, int); int make_sockets(SOCKET[2]); int original_dst(const SOCKET, SOCKADDR_UNION *); /**************************************** prototypes for client.c */ CLI *alloc_client_session(SERVICE_OPTIONS *, SOCKET, SOCKET); void *client_thread(void *); void client_main(CLI *); /**************************************** prototypes for network.c */ int s_connect(CLI *, SOCKADDR_UNION *, socklen_t); void s_write(CLI *, SOCKET fd, const void *, size_t); void s_read(CLI *, SOCKET fd, void *, size_t); void fd_putline(CLI *, SOCKET, const char *); char *fd_getline(CLI *, SOCKET); /* descriptor versions of fprintf/fscanf */ void fd_printf(CLI *, SOCKET, const char *, ...) #ifdef __GNUC__ __attribute__((format(printf, 3, 4))); #else ; #endif void s_ssl_write(CLI *, const void *, int); void s_ssl_read(CLI *, void *, int); char *ssl_getstring(CLI *c); char *ssl_getline(CLI *c); void ssl_putline(CLI *c, const char *); /**************************************** prototype for protocol.c */ typedef enum { PROTOCOL_CHECK, PROTOCOL_EARLY, PROTOCOL_MIDDLE, PROTOCOL_LATE } PHASE; char *protocol(CLI *, SERVICE_OPTIONS *opt, const PHASE); /**************************************** prototypes for resolver.c */ void resolver_init(); unsigned name2addr(SOCKADDR_UNION *, char *, int); unsigned hostport2addr(SOCKADDR_UNION *, char *, char *, int); unsigned name2addrlist(SOCKADDR_LIST *, char *); unsigned hostport2addrlist(SOCKADDR_LIST *, char *, char *); void addrlist_clear(SOCKADDR_LIST *, int); unsigned addrlist_dup(SOCKADDR_LIST *, const SOCKADDR_LIST *); unsigned addrlist_resolve(SOCKADDR_LIST *); char *s_ntop(SOCKADDR_UNION *, socklen_t); socklen_t addr_len(const SOCKADDR_UNION *); const char *s_gai_strerror(int); #ifndef HAVE_GETNAMEINFO #ifndef NI_NUMERICHOST #define NI_NUMERICHOST 2 #endif #ifndef NI_NUMERICSERV #define NI_NUMERICSERV 8 #endif #ifdef USE_WIN32 /* rename some locally shadowed declarations */ #define getnameinfo local_getnameinfo #ifndef _WIN32_WCE typedef int (CALLBACK * GETADDRINFO) (const char *, const char *, const struct addrinfo *, struct addrinfo **); typedef void (CALLBACK * FREEADDRINFO) (struct addrinfo FAR *); typedef int (CALLBACK * GETNAMEINFO) (const struct sockaddr *, socklen_t, char *, size_t, char *, size_t, int); extern GETADDRINFO s_getaddrinfo; extern FREEADDRINFO s_freeaddrinfo; extern GETNAMEINFO s_getnameinfo; #endif /* ! _WIN32_WCE */ #endif /* USE_WIN32 */ int getnameinfo(const struct sockaddr *, socklen_t, char *, size_t, char *, size_t, int); #endif /* !defined HAVE_GETNAMEINFO */ /**************************************** prototypes for sthreads.c */ typedef enum { LOCK_SESSION, LOCK_ADDR, LOCK_CLIENTS, LOCK_SSL, /* client.c */ LOCK_INET, /* resolver.c */ #ifndef USE_WIN32 LOCK_LIBWRAP, /* libwrap.c */ #endif LOCK_LOG, LOCK_LEAK, /* log.c */ #ifndef OPENSSL_NO_DH LOCK_DH, /* ctx.c */ #endif /* OPENSSL_NO_DH */ STUNNEL_LOCKS /* number of locks */ } LOCK_TYPE; extern int stunnel_locks[STUNNEL_LOCKS]; int sthreads_init(void); unsigned long stunnel_process_id(void); unsigned long stunnel_thread_id(void); int create_client(SOCKET, SOCKET, CLI *, void *(*)(void *)); #ifdef USE_UCONTEXT typedef struct CONTEXT_STRUCTURE { char *stack; /* CPU stack for this thread */ unsigned long id; ucontext_t context; s_poll_set *fds; int ready; /* number of ready file descriptors */ time_t finish; /* when to finish poll() for this context */ struct CONTEXT_STRUCTURE *next; /* next context on a list */ void *tls; /* thread local storage for tls.c */ } CONTEXT; extern CONTEXT *ready_head, *ready_tail; extern CONTEXT *waiting_head, *waiting_tail; #endif #ifdef _WIN32_WCE long _beginthread(void (*)(void *), int, void *); void _endthread(void); #endif #ifdef DEBUG_STACK_SIZE void stack_info(int); #endif /**************************************** prototypes for file.c */ #ifndef USE_WIN32 DISK_FILE *file_fdopen(int); #endif DISK_FILE *file_open(char *, FILE_MODE mode); void file_close(DISK_FILE *); ssize_t file_getline(DISK_FILE *, char *, int); ssize_t file_putline(DISK_FILE *, char *); int file_permissions(const char *); #ifdef USE_WIN32 LPTSTR str2tstr(LPCSTR); LPSTR tstr2str(LPCTSTR); #endif /**************************************** prototypes for libwrap.c */ int libwrap_init(); void libwrap_auth(CLI *, char *); /**************************************** prototypes for tls.c */ extern volatile int tls_initialized; void tls_init(); TLS_DATA *tls_alloc(CLI *, TLS_DATA *, char *); void tls_cleanup(); void tls_set(TLS_DATA *); TLS_DATA *tls_get(); /**************************************** prototypes for str.c */ extern TLS_DATA *ui_tls; typedef struct alloc_list_struct ALLOC_LIST; struct tls_data_struct { ALLOC_LIST *alloc_head; size_t alloc_bytes, alloc_blocks; CLI *c; SERVICE_OPTIONS *opt; char *id; }; void str_init(TLS_DATA *); void str_cleanup(TLS_DATA *); char *str_dup_debug(const char *, const char *, int); #define str_dup(a) str_dup_debug((a), __FILE__, __LINE__) char *str_vprintf(const char *, va_list); char *str_printf(const char *, ...) #ifdef __GNUC__ __attribute__((format(printf, 1, 2))); #else ; #endif #ifdef USE_WIN32 LPTSTR str_tprintf(LPCTSTR, ...); #endif void str_canary_init(); void str_stats(); void *str_alloc_debug(size_t, const char *, int); #define str_alloc(a) str_alloc_debug((a), __FILE__, __LINE__) void *str_alloc_detached_debug(size_t, const char *, int); #define str_alloc_detached(a) str_alloc_detached_debug((a), __FILE__, __LINE__) void *str_realloc_debug(void *, size_t, const char *, int); #define str_realloc(a, b) str_realloc_debug((a), (b), __FILE__, __LINE__) void str_detach_debug(void *, const char *, int); #define str_detach(a) str_detach_debug((a), __FILE__, __LINE__) void str_free_debug(void *, const char *, int); #define str_free(a) str_free_debug((a), __FILE__, __LINE__), (a)=NULL #define str_free_expression(a) str_free_debug((a), __FILE__, __LINE__) int safe_memcmp(const void *, const void *, size_t); /**************************************** prototypes for ui_*.c */ void ui_config_reloaded(void); void ui_new_chain(const unsigned); void ui_clients(const long); void ui_new_log(const char *); #ifdef USE_WIN32 void message_box(LPCTSTR, const UINT); #endif /* USE_WIN32 */ int passwd_cb(char *, int, int, void *); #ifndef OPENSSL_NO_ENGINE int pin_cb(UI *, UI_STRING *); #endif /* !defined(OPENSSL_NO_ENGINE) */ #ifdef ICON_IMAGE ICON_IMAGE load_icon_default(ICON_TYPE); ICON_IMAGE load_icon_file(const char *); #endif #endif /* defined PROTOTYPES_H */ /* end of prototypes.h */ stunnel-5.30/src/error.ico0000664000175000017500000000217612634035772012507 00000000000000 h(   #` #¿ #ÿ #ÿ #ÿ #ÿ #¿ #` # #Ï #ÿ!<ÿ"ˆÿ#»ÿ#»ÿ"•ÿ!<ÿ #ÿ #Ï # # #ï #ÿ"{ÿ$íÿ’Žöÿäãýÿäãýÿ’Žöÿ$íÿ"ˆÿ #ÿ #ï # #Ï #ÿ"oÿ$íÿvqôÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ„õÿ$íÿ"{ÿ #ÿ #Ï #` #ÿ #ÿ$àÿ$íÿÈÆûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÈÆûÿ$íÿ$àÿ 0ÿ #ÿ #` #¿ #ÿ!Vÿ$íÿ$íÿ»¸ùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ»¸ùÿ$íÿ$íÿ!Vÿ #ÿ #¿ #ÿ #ÿ"{ÿ$íÿ$íÿMGðÿññþÿÿÿÿÿÿÿÿÿÿÿÿÿ[Uòÿ$íÿ$íÿ"ˆÿ #ÿ #ÿ #ÿ #ÿ!Vÿ$íÿ$íÿ$íÿ?8ïÿ’Žöÿ’Žöÿ?8ïÿ$íÿ$íÿ$íÿ"oÿ #ÿ #ÿ #ÿ #ÿ!<ÿ$íÿ$íÿ$íÿ$íÿ$íÿ$íÿ$íÿ$íÿ$íÿ$íÿ!<ÿ #ÿ #ÿ #ÿ #ÿ #ÿ#¡ÿ$íÿ$íÿ$íÿ$íÿ$íÿ$íÿ$íÿ$íÿ#¡ÿ #ÿ #ÿ #ÿ #¿ #ÿ #ÿ 0ÿ#Çÿ$íÿ$íÿ$íÿ$íÿ$íÿ$íÿ#Çÿ 0ÿ #ÿ #ÿ #¿ #` #ÿ #ÿ #ÿ 0ÿ"ˆÿ$Ôÿ$íÿ$íÿ$Ôÿ"ˆÿ 0ÿ #ÿ #ÿ #ÿ #` #Ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #Ï # #ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ï # # #Ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #Ï # #` #¿ #ÿ #ÿ #ÿ #ÿ #¿ #`øàÀ€€€€Ààøstunnel-5.30/src/dhparam.c0000664000175000017500000000411312647013607012430 00000000000000#include "common.h" #ifndef OPENSSL_NO_DH #define DN_new DH_new #ifndef HEADER_DH_H # include #endif DH *get_dh2048() { static unsigned char dhp_2048[] = { 0xCB, 0x35, 0x0E, 0x68, 0xA7, 0x31, 0xA6, 0x99, 0x92, 0x3E, 0x1B, 0x41, 0x32, 0xE0, 0xD9, 0x4D, 0x96, 0x27, 0xD0, 0xE6, 0x77, 0x2B, 0x5C, 0xAB, 0xF5, 0xF4, 0x0A, 0x79, 0xF4, 0x7E, 0x7F, 0xC8, 0x8D, 0x44, 0x6B, 0xCC, 0x57, 0x6D, 0xF8, 0x5A, 0x31, 0x2D, 0x6B, 0x38, 0x2A, 0x91, 0x9E, 0x02, 0x8D, 0x99, 0x65, 0x14, 0x05, 0x68, 0x79, 0x58, 0xA3, 0x9A, 0xF8, 0xF7, 0x1B, 0x51, 0x55, 0x1C, 0xEE, 0x5E, 0x28, 0x86, 0x02, 0xD4, 0xFD, 0x9D, 0x8F, 0x62, 0x92, 0x98, 0x5D, 0x4F, 0x04, 0xB4, 0x77, 0xA8, 0x86, 0xD5, 0x34, 0xB9, 0x6B, 0x6C, 0xFD, 0x0B, 0x85, 0x3F, 0x70, 0x86, 0x67, 0xB8, 0x47, 0xBA, 0x62, 0xF3, 0x1F, 0x8C, 0x91, 0x84, 0x03, 0xD9, 0xD0, 0x94, 0xCC, 0xAD, 0x31, 0x41, 0x83, 0x50, 0x1E, 0x11, 0xD7, 0x09, 0x53, 0x3A, 0x5B, 0x11, 0xC1, 0x46, 0x19, 0xF1, 0x4D, 0x9A, 0x2A, 0x10, 0x3B, 0xE6, 0x47, 0xD4, 0x19, 0x63, 0xFF, 0x6D, 0x70, 0x40, 0xEA, 0xFA, 0x66, 0x43, 0xFB, 0xB8, 0xDB, 0xFE, 0xCE, 0xC5, 0x53, 0xAB, 0x22, 0xD7, 0x30, 0xDD, 0x55, 0xD0, 0xF2, 0x5D, 0xF8, 0x84, 0x50, 0xC7, 0x28, 0xDC, 0x5F, 0x5C, 0xF7, 0xED, 0x67, 0xE9, 0x0B, 0xAA, 0xD7, 0x63, 0xCC, 0xC5, 0x70, 0x49, 0xDA, 0x68, 0x94, 0xF0, 0x66, 0x5D, 0xB7, 0x9E, 0xE1, 0xD8, 0x47, 0xF6, 0x87, 0x54, 0xA5, 0x9B, 0x20, 0x0F, 0x26, 0x77, 0xCC, 0x67, 0xFB, 0xFB, 0x5B, 0x9F, 0x1F, 0x90, 0x53, 0x90, 0x99, 0x83, 0x4F, 0xC2, 0x1D, 0x86, 0x98, 0x51, 0x78, 0x62, 0x5B, 0x9C, 0x04, 0xCE, 0x3F, 0x46, 0x5F, 0xC7, 0xF0, 0xE7, 0x26, 0x47, 0x28, 0xC0, 0xC0, 0x6D, 0xDA, 0x87, 0xA4, 0x54, 0xDE, 0xD8, 0x53, 0x1C, 0xF9, 0xC0, 0xC5, 0x93, 0xAD, 0x84, 0x11, 0x92, 0x3C, 0x1C, 0x31, 0x23 }; static unsigned char dhg_2048[] = { 0x02 }; DH *dh = DN_new(); if (dh == NULL) return NULL; dh->p = BN_bin2bn(dhp_2048, sizeof (dhp_2048), NULL); dh->g = BN_bin2bn(dhg_2048, sizeof (dhg_2048), NULL); if (!dh->p || !dh->g) { DH_free(dh); return NULL; } return dh; } #endif /* OPENSSL_NO_DH */ stunnel-5.30/src/ui_win_cli.c0000664000175000017500000001173212646221043013134 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #include "common.h" #include "prototypes.h" int main(int argc, char *argv[]) { static struct WSAData wsa_state; TCHAR *c, stunnel_exe_path[MAX_PATH]; tls_init(); /* initialize thread-local storage */ /* set current working directory and engine path */ GetModuleFileName(0, stunnel_exe_path, MAX_PATH); c=_tcsrchr(stunnel_exe_path, TEXT('\\')); /* last backslash */ if(c) { /* found */ *c=TEXT('\0'); /* truncate the program name */ c=_tcsrchr(stunnel_exe_path, TEXT('\\')); /* previous backslash */ if(c && !_tcscmp(c+1, TEXT("bin"))) *c=TEXT('\0'); /* truncate "bin" */ } #ifndef _WIN32_WCE if(!SetCurrentDirectory(stunnel_exe_path)) { /* log to stderr, as s_log() is not initialized */ _ftprintf(stderr, TEXT("Cannot set directory to %s"), stunnel_exe_path); return 1; } /* try to enter the "config" subdirectory, ignore the result */ SetCurrentDirectory(TEXT("config")); #endif _tputenv(str_tprintf(TEXT("OPENSSL_ENGINES=%s\\engines"), stunnel_exe_path)); if(WSAStartup(MAKEWORD(1, 1), &wsa_state)) return 1; resolver_init(); main_init(); if(!main_configure(argc>1 ? argv[1] : NULL, argc>2 ? argv[2] : NULL)) daemon_loop(); main_cleanup(); return 0; } /**************************************** options callbacks */ void ui_config_reloaded(void) { /* no action */ } ICON_IMAGE load_icon_default(ICON_TYPE type) { (void)type; /* squash the unused parameter warning */ return NULL; } ICON_IMAGE load_icon_file(const char *name) { (void)name; /* squash the unused parameter warning */ return NULL; } /**************************************** client callbacks */ void ui_new_chain(const unsigned section_number) { (void)section_number; /* squash the unused parameter warning */ } void ui_clients(const long num) { (void)num; /* squash the unused parameter warning */ } /**************************************** s_log callbacks */ void message_box(LPCTSTR text, const UINT type) { MessageBox(NULL, text, TEXT("stunnel"), type); } void ui_new_log(const char *line) { LPTSTR tstr; tstr=str2tstr(line); #ifdef _WIN32_WCE /* log to Windows CE debug output stream */ RETAILMSG(TRUE, (TEXT("%s\r\n"), tstr)); #else /* use UTF-16 or native codepage rather than UTF-8 */ _ftprintf(stderr, TEXT("%s\r\n"), tstr); fflush(stderr); #endif str_free(tstr); } /**************************************** ctx callbacks */ int passwd_cb(char *buf, int size, int rwflag, void *userdata) { (void)buf; /* squash the unused parameter warning */ (void)size; /* squash the unused parameter warning */ (void)rwflag; /* squash the unused parameter warning */ (void)userdata; /* squash the unused parameter warning */ return 0; /* not implemented */ } #ifndef OPENSSL_NO_ENGINE int pin_cb(UI *ui, UI_STRING *uis) { (void)ui; /* squash the unused parameter warning */ (void)uis; /* squash the unused parameter warning */ return 0; /* not implemented */ } #endif /* end of ui_win_cli.c */ stunnel-5.30/src/os2.mak0000664000175000017500000000424312644666077012065 00000000000000prefix=. DEFS = -DPACKAGE_NAME=\"stunnel\" \ -DPACKAGE_TARNAME=\"stunnel\" \ -DPACKAGE_VERSION=\"5.30\" \ -DPACKAGE_STRING=\"stunnel\ 5.30\" \ -DPACKAGE_BUGREPORT=\"\" \ -DPACKAGE=\"stunnel\" \ -DVERSION=\"5.30\" \ -DSTDC_HEADERS=1 \ -DHAVE_SYS_TYPES_H=1 \ -DHAVE_SYS_STAT_H=1 \ -DHAVE_STDLIB_H=1 \ -DHAVE_STRING_H=1 \ -DHAVE_MEMORY_H=1 \ -DHAVE_STRINGS_H=1 \ -DHAVE_UNISTD_H=1 \ -DSSLDIR=\"/usr\" \ -DHOST=\"i386-pc-os2-emx\" \ -DHAVE_LIBSOCKET=1 \ -DHAVE_GRP_H=1 \ -DHAVE_UNISTD_H=1 \ -DHAVE_SYS_SELECT_H=1 \ -DHAVE_SYS_IOCTL_H=1 \ -DHAVE_SYS_RESOURCE_H=1 \ -DHAVE_SNPRINTF=1 \ -DHAVE_VSNPRINTF=1 \ -DHAVE_WAITPID=1 \ -DHAVE_SYSCONF=1 \ -DHAVE_ENDHOSTENT=1 \ -DUSE_OS2=1 \ -DSIZEOF_UNSIGNED_CHAR=1 \ -DSIZEOF_UNSIGNED_SHORT=2 \ -DSIZEOF_UNSIGNED_INT=4 \ -DSIZEOF_UNSIGNED_LONG=4 \ -DLIBDIR=\"$(prefix)/lib\" \ -DCONFDIR=\"$(prefix)/etc\" CC = gcc .SUFFIXES = .c .o OPENSSLDIR = u:/extras #SYSLOGDIR = /unixos2/workdir/syslog INCLUDES = -I$(OPENSSLDIR)/outinc LIBS = -lsocket -L$(OPENSSLDIR)/out -lssl -lcrypto -lz -lsyslog OBJS = file.o client.o log.o options.o protocol.o network.o ssl.o ctx.o verify.o sthreads.o stunnel.o pty.o resolver.o str.o tls.o fd.o dhparam.o cron.o LIBDIR = . CFLAGS = -O2 -Wall -Wshadow -Wcast-align -Wpointer-arith all: stunnel.exe stunnel.exe: $(OBJS) $(CC) -Zmap $(CFLAGS) -o $@ $(OBJS) $(LIBS) .c.o: $(CC) $(CFLAGS) $(DEFS) $(INCLUDES) -o $@ -c $< client.o: client.c common.h prototypes.h #env.o: env.c common.h prototypes.h #gui.o: gui.c common.h prototypes.h file.o: file.c common.h prototypes.h network.o: network.c common.h prototypes.h options.o: options.c common.h prototypes.h protocol.o: protocol.c common.h prototypes.h pty.o: pty.c common.h prototypes.h ssl.o: ssl.c common.h prototypes.h ctx.o: ctx.c common.h prototypes.h verify.o: verify.c common.h prototypes.h sthreads.o: sthreads.c common.h prototypes.h stunnel.o: stunnel.c common.h prototypes.h resolver.o: resolver.c common.h prototypes.h str.o: str.c common.h prototypes.h tls.o: tls.c common.h prototypes.h fd.o: fd.c common.h prototypes.h dhparam.o: dhparam.c common.h prototypes.h cron.o: cron.c common.h prototypes.h clean: rm -f *.o *.exe stunnel-5.30/src/config.h.in0000664000175000017500000002240112652373741012677 00000000000000/* src/config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have a broken 'poll' implementation. */ #undef BROKEN_POLL /* Entropy Gathering Daemon socket path */ #undef EGD_SOCKET /* Define to 1 if you have the `accept4' function. */ #undef HAVE_ACCEPT4 /* Define to 1 if you have the `chroot' function. */ #undef HAVE_CHROOT /* Define to 1 if you have the `daemon' function. */ #undef HAVE_DAEMON /* Define to 1 if you have '/dev/ptmx' device. */ #undef HAVE_DEV_PTMX /* Define to 1 if you have '/dev/ptc' device. */ #undef HAVE_DEV_PTS_AND_PTC /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the `endhostent' function. */ #undef HAVE_ENDHOSTENT /* Define to 1 if you have the `FIPS_mode_set' function. */ #undef HAVE_FIPS_MODE_SET /* Define to 1 if you have 'getaddrinfo' function. */ #undef HAVE_GETADDRINFO /* Define to 1 if you have the `getcontext' function. */ #undef HAVE_GETCONTEXT /* Define to 1 if you have the `gethostbyname2' function. */ #undef HAVE_GETHOSTBYNAME2 /* Define to 1 if you have the `getnameinfo' function. */ #undef HAVE_GETNAMEINFO /* Define to 1 if you have the `getrlimit' function. */ #undef HAVE_GETRLIMIT /* Define to 1 if you have the header file. */ #undef HAVE_GRP_H /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_LIBUTIL_H /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_NETFILTER_IPV4_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_SCHED_H /* Define to 1 if you have the `localtime_r' function. */ #undef HAVE_LOCALTIME_R /* Define to 1 if you have the header file. */ #undef HAVE_MALLOC_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have 'msghdr.msg_control' structure. */ #undef HAVE_MSGHDR_MSG_CONTROL /* Define to 1 if you have the `openpty' function. */ #undef HAVE_OPENPTY /* Define to 1 if you have the `pipe2' function. */ #undef HAVE_PIPE2 /* Define to 1 if you have the `poll' function. */ #undef HAVE_POLL /* Define to 1 if you have the header file. */ #undef HAVE_POLL_H /* Define if you have POSIX threads libraries and header files. */ #undef HAVE_PTHREAD /* Define to 1 if you have the header file. */ #undef HAVE_PTHREAD_H /* Have PTHREAD_PRIO_INHERIT. */ #undef HAVE_PTHREAD_PRIO_INHERIT /* Define to 1 if you have the `pthread_sigmask' function. */ #undef HAVE_PTHREAD_SIGMASK /* Define to 1 if you have the header file. */ #undef HAVE_PTY_H /* Define to 1 if you have the `realpath' function. */ #undef HAVE_REALPATH /* Define to 1 if you have the `setgroups' function. */ #undef HAVE_SETGROUPS /* Define to 1 if you have the `setsid' function. */ #undef HAVE_SETSID /* Define to 1 if you have the `snprintf' function. */ #undef HAVE_SNPRINTF /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_STROPTS_H /* Define to 1 if the system has the type `struct addrinfo'. */ #undef HAVE_STRUCT_ADDRINFO /* Define to 1 if `msg_control' is a member of `struct msghdr'. */ #undef HAVE_STRUCT_MSGHDR_MSG_CONTROL /* Define to 1 if the system has the type `struct sockaddr_un'. */ #undef HAVE_STRUCT_SOCKADDR_UN /* Define to 1 if you have the `sysconf' function. */ #undef HAVE_SYSCONF /* Define to 1 if you have the header file. */ #undef HAVE_SYSTEMD_SD_DAEMON_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_FILIO_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_POLL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_RESOURCE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SYSCALL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UIO_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UN_H /* Define to 1 if you have the header file. */ #undef HAVE_TCPD_H /* Define to 1 if you have the header file. */ #undef HAVE_UCONTEXT_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the header file. */ #undef HAVE_UTIL_H /* Define to 1 if you have the `vsnprintf' function. */ #undef HAVE_VSNPRINTF /* Define to 1 if you have the `wait4' function. */ #undef HAVE_WAIT4 /* Define to 1 if you have the `waitpid' function. */ #undef HAVE_WAITPID /* Define to 1 if you have the `_getpty' function. */ #undef HAVE__GETPTY /* Define to 1 if you have the `__makecontext_v2' function. */ #undef HAVE___MAKECONTEXT_V2 /* Host description */ #undef HOST /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to necessary symbol if this constant uses a non-standard name on your system. */ #undef PTHREAD_CREATE_JOINABLE /* Random file path */ #undef RANDOM_FILE /* SSL directory */ #undef SSLDIR /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to 1 to enable OpenSSL FIPS support */ #undef USE_FIPS /* Define to 1 to select FORK mode */ #undef USE_FORK /* Define to 1 to enable IPv6 support */ #undef USE_IPv6 /* Define to 1 to enable TCP wrappers support */ #undef USE_LIBWRAP /* Define to 1 to select PTHREAD mode */ #undef USE_PTHREAD /* Define to 1 to enable systemd socket activation */ #undef USE_SYSTEMD /* Define to 1 to select UCONTEXT mode */ #undef USE_UCONTEXT /* Version number of package */ #undef VERSION /* Use Darwin source */ #undef _DARWIN_C_SOURCE /* Use GNU source */ #undef _GNU_SOURCE /* Define for Solaris 2.5.1 so the uint32_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT32_T /* Define for Solaris 2.5.1 so the uint64_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT64_T /* Define for Solaris 2.5.1 so the uint8_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT8_T /* Use X/Open 5 with POSIX 1995 */ #undef _XOPEN_SOURCE /* Define to `int' if doesn't define. */ #undef gid_t /* Define to the type of a signed integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ #undef int16_t /* Define to the type of a signed integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef int32_t /* Define to the type of a signed integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ #undef int64_t /* Define to the type of a signed integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ #undef int8_t /* Define to `unsigned int' if does not define. */ #undef size_t /* Type of socklen_t */ #undef socklen_t /* Define to `int' if does not define. */ #undef ssize_t /* Define to `int' if doesn't define. */ #undef uid_t /* Define to the type of an unsigned integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ #undef uint16_t /* Define to the type of an unsigned integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef uint32_t /* Define to the type of an unsigned integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ #undef uint64_t /* Define to the type of an unsigned integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ #undef uint8_t stunnel-5.30/src/makew32.bat0000664000175000017500000000352612575611547012627 00000000000000@echo off TITLE W32 STUNNEL :: In a multi-target compilation environment, it is better to open :: a new cmd.exe window in order to avoid PATH pollution :: (for example with some previous WCE compilation attempts) set NEWTGTCPU=W32 rem Adjust the MS VC environment variables rem --------------------- rem Detect the latest Visual Studio rem Visual Studio 2008 if DEFINED VS90COMNTOOLS if exist "%VS90COMNTOOLS%..\..\vc\vcvarsall.bat" set vsTools=%VS90COMNTOOLS% rem Visual Studio 2010 if DEFINED VS100COMNTOOLS if exist "%VS100COMNTOOLS%..\..\vc\vcvarsall.bat" set vsTools=%VS100COMNTOOLS% rem Visual Studio 2012 if DEFINED VS110COMNTOOLS if exist "%VS110COMNTOOLS%..\..\vc\vcvarsall.bat" set vsTools=%VS110COMNTOOLS% rem Visual Studio 2013 if DEFINED VS120COMNTOOLS if exist "%VS120COMNTOOLS%..\..\vc\vcvarsall.bat" set vsTools=%VS120COMNTOOLS% rem Visual Studio 2015 if DEFINED VS140COMNTOOLS if exist "%VS140COMNTOOLS%..\..\vc\vcvarsall.bat" set vsTools=%VS140COMNTOOLS% ::rem Initialize the Visual Studio tools ::call "%vsTools%..\..\vc\vcvarsall.bat" rem Check the MSenv variables against our reference values set isenvok=0 if NOT DEFINED TARGETCPU set TARGETCPU=XXXXX if "%NEWTGTCPU%"=="%TARGETCPU%" set /A "isenvok+=1" if %isenvok%==1 echo W32 ENVIRONMENT OK if %isenvok%==1 goto envisok :: Useless with separated target folders ::echo W32 TARGET CPU changed, destroying every obj files ::del .\*.obj :: if env is NOT ok, adjust the MS VC environment variables :: (this is to avoid repetitive pollution of PATH) echo W32 ENVIRONMENT ADJUSTED :: Reset of INCLUDE is needed because of accumulation of includes in vcvars32 set INCLUDE= call "%vsTools%..\..\vc\bin\vcvars32.bat" set TARGETCPU=%NEWTGTCPU% :envisok rem Make everything rem --------------- nmake.exe -f vc.mak %1 %2 %3 %4 %5 %6 %7 %8 %9 stunnel-5.30/src/stunnel.c0000664000175000017500000006464212646221043012513 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #include "common.h" #include "prototypes.h" /* http://www.openssl.org/support/faq.html#PROG2 */ #ifdef USE_WIN32 #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-pedantic" #endif /* __GNUC__ */ #include #ifdef __GNUC__ #pragma GCC diagnostic pop #endif /* __GNUC__ */ #endif /* USE_WIN32 */ /**************************************** prototypes */ #ifdef __INNOTEK_LIBC__ struct sockaddr_un { u_char sun_len; /* sockaddr len including null */ u_char sun_family; /* AF_OS2 or AF_UNIX */ char sun_path[108]; /* path name */ }; #endif NOEXPORT int accept_connection(SERVICE_OPTIONS *); #ifdef HAVE_CHROOT NOEXPORT int change_root(void); #endif NOEXPORT int signal_pipe_init(void); NOEXPORT int signal_pipe_dispatch(void); #ifdef USE_FORK NOEXPORT void client_status(void); /* dead children detected */ #endif NOEXPORT char *signal_name(int); /**************************************** global variables */ static SOCKET signal_pipe[2]={INVALID_SOCKET, INVALID_SOCKET}; #ifndef USE_FORK long max_clients=0; /* -1 before a valid config is loaded, then the current number of clients */ volatile long num_clients=-1; #endif s_poll_set *fds; /* file descriptors of listening sockets */ int systemd_fds; /* number of file descriptors passed by systemd */ int listen_fds_start; /* base for systemd-provided file descriptors */ /**************************************** startup */ void main_init() { /* one-time initialization */ #ifdef USE_SYSTEMD int i; systemd_fds=sd_listen_fds(1); if(systemd_fds<0) fatal("systemd initialization failed"); listen_fds_start=SD_LISTEN_FDS_START; /* set non-blocking mode on systemd file descriptors */ for(i=0; i0) { #else if((pid=wait(&status))>0) { #endif #ifdef WIFSIGNALED if(WIFSIGNALED(status)) { sig_name=signal_name(WTERMSIG(status)); s_log(LOG_DEBUG, "Process %d terminated on %s", pid, sig_name); str_free(sig_name); } else { s_log(LOG_DEBUG, "Process %d finished with code %d", pid, WEXITSTATUS(status)); } } #else s_log(LOG_DEBUG, "Process %d finished with code %d", pid, status); } #endif } #endif /* defined USE_FORK */ #ifndef USE_OS2 void child_status(void) { /* dead libwrap or 'exec' process detected */ int pid, status; char *sig_name; #ifdef HAVE_WAIT_FOR_PID while((pid=wait_for_pid(-1, &status, WNOHANG))>0) { #else if((pid=wait(&status))>0) { #endif #ifdef WIFSIGNALED if(WIFSIGNALED(status)) { sig_name=signal_name(WTERMSIG(status)); s_log(LOG_INFO, "Child process %d terminated on %s", pid, sig_name); str_free(sig_name); } else { s_log(LOG_INFO, "Child process %d finished with code %d", pid, WEXITSTATUS(status)); } #else s_log(LOG_INFO, "Child process %d finished with status %d", pid, status); #endif } } #endif /* !defined(USE_OS2) */ #endif /* !defined(USE_WIN32) */ /**************************************** main loop accepting connections */ void daemon_loop(void) { while(1) { int temporary_lack_of_resources=0; int num=s_poll_wait(fds, -1, -1); if(num>=0) { SERVICE_OPTIONS *opt; s_log(LOG_DEBUG, "Found %d ready file descriptor(s)", num); if(service_options.log_level>=LOG_DEBUG) /* performance optimization */ s_poll_dump(fds, LOG_DEBUG); if(s_poll_canread(fds, signal_pipe[0])) if(signal_pipe_dispatch()) /* SIGNAL_TERMINATE or error */ break; /* terminate daemon_loop */ for(opt=service_options.next; opt; opt=opt->next) if(opt->option.accept && s_poll_canread(fds, opt->fd)) if(accept_connection(opt)) temporary_lack_of_resources=1; } else { log_error(LOG_NOTICE, get_last_socket_error(), "daemon_loop: s_poll_wait"); temporary_lack_of_resources=1; } if(temporary_lack_of_resources) { s_log(LOG_NOTICE, "Accepting new connections suspended for 1 second"); sleep(1); /* to avoid log trashing */ } } } /* return 1 when a short delay is needed before another try */ NOEXPORT int accept_connection(SERVICE_OPTIONS *opt) { SOCKADDR_UNION addr; char *from_address; SOCKET s; socklen_t addrlen; addrlen=sizeof addr; for(;;) { s=s_accept(opt->fd, &addr.sa, &addrlen, 1, "local socket"); if(s!=INVALID_SOCKET) /* success! */ break; switch(get_last_socket_error()) { case S_EINTR: /* interrupted by a signal */ break; /* retry now */ case S_EMFILE: #ifdef S_ENFILE case S_ENFILE: #endif #ifdef S_ENOBUFS case S_ENOBUFS: #endif #ifdef S_ENOMEM case S_ENOMEM: #endif return 1; /* temporary lack of resources */ default: return 0; /* any other error */ } } from_address=s_ntop(&addr, addrlen); s_log(LOG_DEBUG, "Service [%s] accepted (FD=%ld) from %s", opt->servname, (long)s, from_address); str_free(from_address); #ifdef USE_FORK RAND_add("", 1, 0.0); /* each child needs a unique entropy pool */ #else if(max_clients && num_clients>=max_clients) { s_log(LOG_WARNING, "Connection rejected: too many clients (>=%ld)", max_clients); closesocket(s); return 0; } #endif if(create_client(opt->fd, s, alloc_client_session(opt, s, s), client_thread)) { s_log(LOG_ERR, "Connection rejected: create_client failed"); closesocket(s); return 0; } return 0; } /**************************************** initialization helpers */ /* clear fds, close old ports */ void unbind_ports(void) { SERVICE_OPTIONS *opt; #ifdef HAVE_STRUCT_SOCKADDR_UN struct stat sb; /* buffer for lstat() */ #endif s_poll_init(fds); s_poll_add(fds, signal_pipe[0], 1, 0); for(opt=service_options.next; opt; opt=opt->next) { s_log(LOG_DEBUG, "Closing service [%s]", opt->servname); if(opt->option.accept && opt->fd!=INVALID_SOCKET) { if(opt->fd<(SOCKET)listen_fds_start || opt->fd>=(SOCKET)(listen_fds_start+systemd_fds)) closesocket(opt->fd); s_log(LOG_DEBUG, "Service [%s] closed (FD=%ld)", opt->servname, (long)opt->fd); opt->fd=INVALID_SOCKET; #ifdef HAVE_STRUCT_SOCKADDR_UN if(opt->local_addr.sa.sa_family==AF_UNIX) { if(lstat(opt->local_addr.un.sun_path, &sb)) sockerror(opt->local_addr.un.sun_path); else if(!S_ISSOCK(sb.st_mode)) s_log(LOG_ERR, "Not a socket: %s", opt->local_addr.un.sun_path); else if(unlink(opt->local_addr.un.sun_path)) sockerror(opt->local_addr.un.sun_path); else s_log(LOG_DEBUG, "Socket removed: %s", opt->local_addr.un.sun_path); } #endif } else if(opt->exec_name && opt->connect_addr.names) { /* create exec+connect services */ /* FIXME: this is just a crude workaround */ /* is it better to kill the service? */ opt->option.retry=0; } /* purge session cache of the old SSL_CTX object */ /* this workaround won't be needed anymore after */ /* delayed deallocation calls SSL_CTX_free() */ if(opt->ctx) SSL_CTX_flush_sessions(opt->ctx, (long)time(NULL)+opt->session_timeout+1); s_log(LOG_DEBUG, "Service [%s] closed", opt->servname); } } /* open new ports, update fds */ int bind_ports(void) { SERVICE_OPTIONS *opt; char *local_address; int listening_section; #ifdef HAVE_STRUCT_SOCKADDR_UN struct stat sb; /* buffer for lstat() */ #endif #ifdef USE_LIBWRAP /* execute after options_cmdline() to know service_options.next, * but as early as possible to avoid leaking file descriptors */ /* retry on each bind_ports() in case stunnel.conf was reloaded without "libwrap = no" */ libwrap_init(); #endif /* USE_LIBWRAP */ s_poll_init(fds); s_poll_add(fds, signal_pipe[0], 1, 0); /* allow clean unbind_ports() even though bind_ports() was not fully performed */ for(opt=service_options.next; opt; opt=opt->next) if(opt->option.accept) opt->fd=INVALID_SOCKET; listening_section=0; for(opt=service_options.next; opt; opt=opt->next) { if(opt->option.accept) { if(listening_sectionfd=(SOCKET)(listen_fds_start+listening_section); s_log(LOG_DEBUG, "Listening file descriptor received from systemd (FD=%ld)", (long)opt->fd); } else { opt->fd=s_socket(opt->local_addr.sa.sa_family, SOCK_STREAM, 0, 1, "accept socket"); if(opt->fd==INVALID_SOCKET) return 1; s_log(LOG_DEBUG, "Listening file descriptor created (FD=%ld)", (long)opt->fd); } if(set_socket_options(opt->fd, 0)<0) { closesocket(opt->fd); opt->fd=INVALID_SOCKET; return 1; } /* local socket can't be unnamed */ local_address=s_ntop(&opt->local_addr, addr_len(&opt->local_addr)); /* we don't bind or listen on a socket inherited from systemd */ if(listening_section>=systemd_fds) { if(bind(opt->fd, &opt->local_addr.sa, addr_len(&opt->local_addr))) { sockerror("bind"); s_log(LOG_ERR, "Error binding service [%s] to %s", opt->servname, local_address); closesocket(opt->fd); opt->fd=INVALID_SOCKET; str_free(local_address); return 1; } if(listen(opt->fd, SOMAXCONN)) { sockerror("listen"); closesocket(opt->fd); opt->fd=INVALID_SOCKET; str_free(local_address); return 1; } } #ifdef HAVE_STRUCT_SOCKADDR_UN /* chown the UNIX socket, errors are ignored */ if(opt->local_addr.sa.sa_family==AF_UNIX && (opt->uid || opt->gid)) { /* fchown() does *not* work on UNIX sockets */ if(!lchown(opt->local_addr.un.sun_path, opt->uid, opt->gid)) s_log(LOG_DEBUG, "Socket chown succeeded: %s, UID=%u, GID=%u", opt->local_addr.un.sun_path, (unsigned)opt->uid, (unsigned)opt->gid); else if(lstat(opt->local_addr.un.sun_path, &sb)) sockerror(opt->local_addr.un.sun_path); else if(sb.st_uid==opt->uid && sb.st_gid==opt->gid) s_log(LOG_DEBUG, "Socket chown unneeded: %s, UID=%u, GID=%u", opt->local_addr.un.sun_path, (unsigned)opt->uid, (unsigned)opt->gid); else s_log(LOG_ERR, "Socket chown failed: %s, UID=%u, GID=%u", opt->local_addr.un.sun_path, (unsigned)opt->uid, (unsigned)opt->gid); } #endif s_poll_add(fds, opt->fd, 1, 0); s_log(LOG_DEBUG, "Service [%s] (FD=%ld) bound to %s", opt->servname, (long)opt->fd, local_address); str_free(local_address); ++listening_section; } else if(opt->exec_name && opt->connect_addr.names) { /* create exec+connect services */ /* FIXME: needs to be delayed on reload with opt->option.retry set */ create_client(INVALID_SOCKET, INVALID_SOCKET, alloc_client_session(opt, INVALID_SOCKET, INVALID_SOCKET), client_thread); } } if(listening_section0) { pipe_in=signal_pipe[0]; signal_pipe[0]=s_accept(signal_pipe[0], NULL, 0, 0, "accept"); closesocket(pipe_in); } else { sockerror("select"); return 1; } #else /* Unix */ if(s_pipe(signal_pipe, 1, "signal_pipe")) return 1; #endif /* USE_WIN32 */ return 0; } #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-result" #endif /* __GNUC__ */ void signal_post(int sig) { /* no meaningful way here to handle the result */ writesocket(signal_pipe[1], (char *)&sig, sizeof sig); } #ifdef __GNUC__ #pragma GCC diagnostic pop #endif /* __GNUC__ */ NOEXPORT int signal_pipe_dispatch(void) { static int sig; static size_t ptr=0; ssize_t num; char *sig_name; s_log(LOG_DEBUG, "Dispatching signals from the signal pipe"); for(;;) { num=readsocket(signal_pipe[0], (char *)&sig+ptr, sizeof sig-ptr); if(num==-1 && get_last_socket_error()==S_EWOULDBLOCK) { s_log(LOG_DEBUG, "Signal pipe is empty"); return 0; } if(num==-1 || num==0) { if(num) sockerror("signal pipe read"); else s_log(LOG_ERR, "Signal pipe closed"); s_poll_remove(fds, signal_pipe[0]); closesocket(signal_pipe[0]); closesocket(signal_pipe[1]); if(signal_pipe_init()) { s_log(LOG_ERR, "Signal pipe reinitialization failed; terminating"); return 1; } s_poll_add(fds, signal_pipe[0], 1, 0); s_log(LOG_ERR, "Signal pipe reinitialized"); return 0; } ptr+=(size_t)num; if(ptr * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #include "common.h" #include "prototypes.h" #ifdef USE_WIN32 DISK_FILE *file_open(char *name, FILE_MODE mode) { DISK_FILE *df; LPTSTR tname; HANDLE fh; DWORD desired_access, creation_disposition; /* open file */ switch(mode) { case FILE_MODE_READ: desired_access=GENERIC_READ; creation_disposition=OPEN_EXISTING; break; case FILE_MODE_APPEND: /* reportedly more compatible than FILE_APPEND_DATA */ desired_access=GENERIC_WRITE; creation_disposition=OPEN_ALWAYS; /* keep the data */ break; case FILE_MODE_OVERWRITE: desired_access=GENERIC_WRITE; creation_disposition=CREATE_ALWAYS; /* remove the data */ break; default: /* invalid mode */ return NULL; } tname=str2tstr(name); fh=CreateFile(tname, desired_access, FILE_SHARE_READ, NULL, creation_disposition, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL); str_free(tname); /* str_free() overwrites GetLastError() value */ if(fh==INVALID_HANDLE_VALUE) return NULL; if(mode==FILE_MODE_APPEND) /* workaround for FILE_APPEND_DATA */ SetFilePointer(fh, 0, NULL, FILE_END); /* setup df structure */ df=str_alloc(sizeof df); df->fh=fh; return df; } #else /* USE_WIN32 */ DISK_FILE *file_fdopen(int fd) { DISK_FILE *df; df=str_alloc(sizeof(DISK_FILE)); df->fd=fd; return df; } DISK_FILE *file_open(char *name, FILE_MODE mode) { DISK_FILE *df; int fd, flags; /* open file */ switch(mode) { case FILE_MODE_READ: flags=O_RDONLY; break; case FILE_MODE_APPEND: flags=O_CREAT|O_WRONLY|O_APPEND; break; case FILE_MODE_OVERWRITE: flags=O_CREAT|O_WRONLY|O_TRUNC; break; default: /* invalid mode */ return NULL; } #ifdef O_NONBLOCK flags|=O_NONBLOCK; #elif defined O_NDELAY flags|=O_NDELAY; #endif #ifdef O_CLOEXEC flags|=O_CLOEXEC; #endif /* O_CLOEXEC */ fd=open(name, flags, 0640); if(fd==INVALID_SOCKET) return NULL; /* setup df structure */ df=str_alloc(sizeof df); df->fd=fd; return df; } #endif /* USE_WIN32 */ void file_close(DISK_FILE *df) { if(!df) /* nothing to do */ return; #ifdef USE_WIN32 CloseHandle(df->fh); #else /* USE_WIN32 */ if(df->fd>2) /* never close stdin/stdout/stder */ close(df->fd); #endif /* USE_WIN32 */ str_free(df); } ssize_t file_getline(DISK_FILE *df, char *line, int len) { /* this version is really slow, but performance is not important here */ /* (no buffering is implemented) */ ssize_t i; #ifdef USE_WIN32 DWORD num; #else /* USE_WIN32 */ ssize_t num; #endif /* USE_WIN32 */ if(!df) /* not opened */ return -1; for(i=0; ifh, line+i, 1, &num, NULL); #else /* USE_WIN32 */ num=read(df->fd, line+i, 1); #endif /* USE_WIN32 */ if(num!=1) { /* EOF */ if(i) /* any previously retrieved data */ break; else return -1; } if(line[i]=='\n') /* LF */ break; if(line[i]=='\r') /* CR */ --i; /* ignore - it must be the last check */ } line[i]='\0'; return i; } ssize_t file_putline(DISK_FILE *df, char *line) { char *buff; size_t len; #ifdef USE_WIN32 DWORD num; #else /* USE_WIN32 */ ssize_t num; #endif /* USE_WIN32 */ len=strlen(line); buff=str_alloc(len+2); /* +2 for CR+LF */ strcpy(buff, line); #ifdef USE_WIN32 buff[len++]='\r'; /* CR */ #endif /* USE_WIN32 */ buff[len++]='\n'; /* LF */ #ifdef USE_WIN32 WriteFile(df->fh, buff, (DWORD)len, &num, NULL); #else /* USE_WIN32 */ /* no file -> write to stderr */ num=write(df ? df->fd : 2, buff, len); #endif /* USE_WIN32 */ str_free(buff); return (ssize_t)num; } int file_permissions(const char *file_name) { #if !defined(USE_WIN32) && !defined(USE_OS2) struct stat sb; /* buffer for stat */ /* check permissions of the private key file */ if(stat(file_name, &sb)) { ioerror(file_name); return 1; /* FAILED */ } if(sb.st_mode & 7) s_log(LOG_WARNING, "Insecure file permissions on %s", file_name); #else (void)file_name; /* squash the unused parameter warning */ #endif return 0; } #ifdef USE_WIN32 LPTSTR str2tstr(LPCSTR in) { LPTSTR out; #ifdef UNICODE int len; len=MultiByteToWideChar(CP_UTF8, 0, in, -1, NULL, 0); if(!len) return str_tprintf(TEXT("MultiByteToWideChar() failed")); out=str_alloc(((size_t)len+1)*sizeof(WCHAR)); len=MultiByteToWideChar(CP_UTF8, 0, in, -1, out, len); if(!len) { str_free(out); return str_tprintf(TEXT("MultiByteToWideChar() failed")); } #else /* FIXME: convert UTF-8 to native codepage */ out=str_dup(in); #endif return out; } LPSTR tstr2str(LPCTSTR in) { LPSTR out; #ifdef UNICODE int len; len=WideCharToMultiByte(CP_UTF8, 0, in, -1, NULL, 0, NULL, NULL); if(!len) return str_printf("WideCharToMultiByte() failed"); out=str_alloc((size_t)len+1); len=WideCharToMultiByte(CP_UTF8, 0, in, -1, out, len, NULL, NULL); if(!len) { str_free(out); return str_printf("WideCharToMultiByte() failed"); } #else /* FIXME: convert native codepage to UTF-8 */ out=str_dup(in); #endif return out; } #endif /* USE_WIN32 */ /* end of file.c */ stunnel-5.30/src/stunnel.ico0000664000175000017500000003535612634035772013054 0000000000000000 ¨%6  ¨Þ% h†6(0` $ #@ #€ #¿ #ß #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ß #¿ #€ #@ #@ #Ÿ #ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ï #Ÿ #@ #@ #¿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #¿ #@ # #¯ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #¯ # #P #ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ@>@ÿSQRÿlijÿlijÿ…‚ÿ…‚ÿlijÿlijÿSQRÿ@>@ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ï #P # #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ&%)ÿSQRÿ|{ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ|{ÿ_]^ÿ-+/ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ # #Ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿSQRÿ|{ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿЉÿ¤¡¡ÿÂÁÀÿÂÁÀÿ«©¨ÿЉÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿSQRÿ&%)ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #Ÿ #Ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ&%)ÿrooÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ”’‘ÿÑÐÐÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙØØÿ”’‘ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿrooÿ325ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #Ÿ # #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ325ÿxvuÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿœ™™ÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷ÿ³±°ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ|{ÿ325ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ # #P #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ&%)ÿxvuÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿœ™™ÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ«©¨ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ|{ÿ325ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #P # #ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿlijÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿðïïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷ÿЉÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿrooÿ&%)ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ï # #¯ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿSQRÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ³±°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿº¹¸ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿYWXÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #¯ #@ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ&%)ÿ|{ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿÙØØÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáààÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ-+/ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #@ #¿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿSQRÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿáààÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ_]^ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #¿ #@ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ|{ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ&%)ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #@ #Ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ98;ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿáààÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿFDFÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #Ÿ #ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿSQRÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿÑÐÐÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáààÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ_]^ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ï #@ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿlijÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ«©¨ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿº¹¸ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿlijÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #@ #€ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿlijÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿèèçÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðïïÿЉÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #€ #¿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ|{ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿœ™™ÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¤¡¡ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #¿ #ß #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ|{ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿœ™™ÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷ÿ³±°ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ß #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿlijÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿЉÿÑÐÐÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÑÐÐÿ”’‘ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿlijÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ¤¡¡ÿ³±°ÿº¹¸ÿ¤¡¡ÿЉÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿlijÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿSQRÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ_]^ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ@>@ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿFDFÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ|{ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ&%)ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿYWXÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ_]^ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ß #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ-+/ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ325ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ß #¿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿSQRÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿYWXÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #¿ #€ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿrooÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿxvuÿ&%)ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #€ #@ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ-+/ÿ|{ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ|{ÿ325ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #@ #ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ325ÿ|{ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ|{ÿ325ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ï #Ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ-+/ÿrooÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿxvuÿ325ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #Ÿ #@ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ&%)ÿSQRÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿYWXÿ&%)ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #@ #¿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ-+/ÿ_]^ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ_]^ÿ-+/ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #¿ #@ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ&%)ÿFDFÿ_]^ÿlijÿ|{ÿ…‚ÿ…‚ÿ…‚ÿlijÿ_]^ÿFDFÿ&%)ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #@ #¯ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #¯ # #ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ï # #P #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #P # #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ # #Ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #Ÿ #Ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #Ÿ # #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ # #P #ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ï #P # #¯ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #¯ # #@ #¿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #¿ #@ #@ #Ÿ #ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ï #Ÿ #@ #@ #€ #¿ #ß #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ß #¿ #€ #@ÿÿÀÿÿÿþÿÿøÿÿàÿÿÀÿÿÿþü?øøðààÀÀ€€€€€€ÀÀààðøøü?þÿÿÿÀÿÿàÿÿøÿÿþÿÿÿÀÿÿ( @  #0 #€ #¿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #¿ #€ #0 #` #Ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #Ï #P # #¿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ98;ÿ98;ÿ98;ÿ98;ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #¿ # #P #ï #ÿ #ÿ #ÿ #ÿFDFÿecdÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿrooÿFDFÿ #ÿ #ÿ #ÿ #ÿ #ï #P #` #ÿ #ÿ #ÿ #ÿ325ÿrooÿ…‚ÿ…‚ÿ”’‘ÿº¹¸ÿÙØØÿÙØØÿÂÁÀÿ”’‘ÿ…‚ÿ…‚ÿrooÿ325ÿ #ÿ #ÿ #ÿ #ÿ #` #P #ÿ #ÿ #ÿ #ÿ@>@ÿ|{ÿ…‚ÿ…‚ÿ³±°ÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ³±°ÿ…‚ÿ…‚ÿ…‚ÿFDFÿ #ÿ #ÿ #ÿ #ÿ #P # #ï #ÿ #ÿ #ÿ325ÿ|{ÿ…‚ÿ…‚ÿ«©¨ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ³±°ÿ…‚ÿ…‚ÿ…‚ÿ98;ÿ #ÿ #ÿ #ÿ #ï # #¿ #ÿ #ÿ #ÿ&%)ÿxvuÿ…‚ÿ…‚ÿ…‚ÿðïïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷ÿ…‚ÿ…‚ÿ…‚ÿ|{ÿ&%)ÿ #ÿ #ÿ #ÿ #¿ #` #ÿ #ÿ #ÿ #ÿSQRÿ…‚ÿ…‚ÿ…‚ÿœ™™ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¤¡¡ÿ…‚ÿ…‚ÿ…‚ÿ_]^ÿ #ÿ #ÿ #ÿ #ÿ #` #Ï #ÿ #ÿ #ÿ #ÿ|{ÿ…‚ÿ…‚ÿ…‚ÿ¤¡¡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¤¡¡ÿ…‚ÿ…‚ÿ…‚ÿ|{ÿ&%)ÿ #ÿ #ÿ #ÿ #Ï #0 #ÿ #ÿ #ÿ #ÿ98;ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ¤¡¡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¤¡¡ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ@>@ÿ #ÿ #ÿ #ÿ #ÿ #0 #€ #ÿ #ÿ #ÿ #ÿSQRÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿЉÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿSQRÿ #ÿ #ÿ #ÿ #ÿ #€ #¿ #ÿ #ÿ #ÿ #ÿYWXÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿÂÁÀÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÊÈÈÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿlijÿ #ÿ #ÿ #ÿ #ÿ #¿ #ÿ #ÿ #ÿ #ÿ #ÿecdÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿÑÐÐÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáààÿЉÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿlijÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿSQRÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ³±°ÿáààÿÿÿÿÿÿÿÿÿèèçÿ³±°ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿecdÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿLJLÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿSQRÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ325ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ98;ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿxvuÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿxvuÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿFDFÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿLJLÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #¿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿlijÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿrooÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #¿ #€ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ&%)ÿrooÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ|{ÿ-+/ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #€ #0 #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ&%)ÿrooÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿrooÿ325ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #0 #Ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ&%)ÿSQRÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿYWXÿ&%)ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #Ï #` #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ&%)ÿLJLÿlijÿ|{ÿ…‚ÿ…‚ÿ…‚ÿlijÿLJLÿ-+/ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #` #¿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #¿ # #ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ï # #P #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #P #` #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #` #P #ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ï #P # #¿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #¿ # #` #Ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #Ï #` #0 #€ #¿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #¿ #€ #0ÿàÿÿ€ÿþü?øðàÀÀ€€€€ÀÀàðøü?þÿ€ÿÿàÿ(   #` #¿ #ÿ #ÿ #ÿ #ÿ #¿ #` # #Ï #ÿ-+/ÿSQRÿlijÿlijÿYWXÿ-+/ÿ #ÿ #Ï # # #ï #ÿLJLÿ…‚ÿÂÁÀÿðïïÿðïïÿÂÁÀÿ…‚ÿSQRÿ #ÿ #ï # #Ï #ÿFDFÿ…‚ÿ³±°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿº¹¸ÿ…‚ÿLJLÿ #ÿ #Ï #` #ÿ #ÿ|{ÿ…‚ÿáààÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáààÿ…‚ÿ|{ÿ&%)ÿ #ÿ #` #¿ #ÿ98;ÿ…‚ÿ…‚ÿÙØØÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙØØÿ…‚ÿ…‚ÿ98;ÿ #ÿ #¿ #ÿ #ÿLJLÿ…‚ÿ…‚ÿœ™™ÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿ¤¡¡ÿ…‚ÿ…‚ÿSQRÿ #ÿ #ÿ #ÿ #ÿ98;ÿ…‚ÿ…‚ÿ…‚ÿ”’‘ÿÂÁÀÿÂÁÀÿ”’‘ÿ…‚ÿ…‚ÿ…‚ÿFDFÿ #ÿ #ÿ #ÿ #ÿ-+/ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ-+/ÿ #ÿ #ÿ #ÿ #ÿ #ÿ_]^ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ_]^ÿ #ÿ #ÿ #ÿ #¿ #ÿ #ÿ&%)ÿrooÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿ…‚ÿrooÿ&%)ÿ #ÿ #ÿ #¿ #` #ÿ #ÿ #ÿ&%)ÿSQRÿxvuÿ…‚ÿ…‚ÿxvuÿSQRÿ&%)ÿ #ÿ #ÿ #ÿ #` #Ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #Ï # #ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ï # # #Ï #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #ÿ #Ï # #` #¿ #ÿ #ÿ #ÿ #ÿ #¿ #`øàÀ€€€€Ààøstunnel-5.30/src/client.c0000664000175000017500000015512012646221043012271 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #include "common.h" #include "prototypes.h" #ifndef SHUT_RD #define SHUT_RD 0 #endif #ifndef SHUT_WR #define SHUT_WR 1 #endif #ifndef SHUT_RDWR #define SHUT_RDWR 2 #endif NOEXPORT void client_try(CLI *); NOEXPORT void client_run(CLI *); NOEXPORT void local_start(CLI *); NOEXPORT void remote_start(CLI *); NOEXPORT void ssl_start(CLI *); NOEXPORT void new_chain(CLI *); NOEXPORT void transfer(CLI *); NOEXPORT int parse_socket_error(CLI *, const char *); NOEXPORT void print_cipher(CLI *); NOEXPORT void auth_user(CLI *, char *); NOEXPORT SOCKET connect_local(CLI *); #if !defined(USE_WIN32) && !defined(__vms) NOEXPORT char **env_alloc(CLI *); NOEXPORT void env_free(char **); #endif NOEXPORT SOCKET connect_remote(CLI *); NOEXPORT void connect_cache(SSL_SESSION *, SOCKADDR_UNION *); NOEXPORT unsigned connect_index(CLI *); NOEXPORT void setup_connect_addr(CLI *); NOEXPORT void local_bind(CLI *c); NOEXPORT void print_bound_address(CLI *); NOEXPORT void reset(SOCKET, char *); /* allocate local data structure for the new thread */ CLI *alloc_client_session(SERVICE_OPTIONS *opt, SOCKET rfd, SOCKET wfd) { static unsigned long long seq=0; CLI *c; c=str_alloc_detached(sizeof(CLI)); c->opt=opt; c->local_rfd.fd=rfd; c->local_wfd.fd=wfd; c->redirect=REDIRECT_OFF; c->seq=seq++; return c; } void *client_thread(void *arg) { CLI *c=arg; c->tls=NULL; /* do not reuse */ tls_alloc(c, NULL, NULL); #ifdef DEBUG_STACK_SIZE stack_info(1); /* initialize */ #endif client_main(c); #ifdef DEBUG_STACK_SIZE stack_info(0); /* display computed value */ #endif str_stats(); /* client thread allocation tracking */ tls_cleanup(); /* s_log() is not allowed after tls_cleanup() */ #if defined(USE_WIN32) && !defined(_WIN32_WCE) _endthread(); #endif #ifdef USE_UCONTEXT s_poll_wait(NULL, 0, 0); /* wait on poll() */ #endif return NULL; } void client_main(CLI *c) { s_log(LOG_DEBUG, "Service [%s] started", c->opt->servname); if(c->opt->exec_name && c->opt->connect_addr.names) { /* exec+connect options specified together * -> spawn a local program instead of stdio */ for(;;) { SERVICE_OPTIONS *opt=c->opt; memset(c, 0, sizeof(CLI)); /* connect_local needs clean c */ c->opt=opt; if(!setjmp(c->err)) c->local_rfd.fd=c->local_wfd.fd=connect_local(c); else break; client_run(c); if(!c->opt->option.retry) break; sleep(1); /* FIXME: not a good idea in ucontext threading */ s_poll_free(c->fds); c->fds=NULL; str_stats(); /* client thread allocation tracking */ /* c allocation is detached, so it is safe to call str_stats() */ if(service_options.next) /* no tls_cleanup() in inetd mode */ tls_cleanup(); } } else client_run(c); str_free(c); } #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat" #pragma GCC diagnostic ignored "-Wformat-extra-args" #endif /* __GNUC__ */ NOEXPORT void client_run(CLI *c) { int err, rst; #ifndef USE_FORK long num_clients_copy; #endif #ifndef USE_FORK CRYPTO_w_lock(stunnel_locks[LOCK_CLIENTS]); ui_clients(++num_clients); CRYPTO_w_unlock(stunnel_locks[LOCK_CLIENTS]); #endif /* initialize the client context */ c->remote_fd.fd=INVALID_SOCKET; c->fd=INVALID_SOCKET; c->ssl=NULL; c->sock_bytes=c->ssl_bytes=0; if(c->opt->option.client) { c->sock_rfd=&(c->local_rfd); c->sock_wfd=&(c->local_wfd); c->ssl_rfd=c->ssl_wfd=&(c->remote_fd); } else { c->sock_rfd=c->sock_wfd=&(c->remote_fd); c->ssl_rfd=&(c->local_rfd); c->ssl_wfd=&(c->local_wfd); } c->fds=s_poll_alloc(); addrlist_clear(&c->connect_addr, 0); /* try to process the request */ err=setjmp(c->err); if(!err) client_try(c); rst=err==1 && c->opt->option.reset; s_log(LOG_NOTICE, "Connection %s: %llu byte(s) sent to SSL, %llu byte(s) sent to socket", rst ? "reset" : "closed", (unsigned long long)c->ssl_bytes, (unsigned long long)c->sock_bytes); /* cleanup temporary (e.g. IDENT) socket */ if(c->fd!=INVALID_SOCKET) closesocket(c->fd); c->fd=INVALID_SOCKET; /* cleanup the SSL context */ if(c->ssl) { /* SSL initialized */ SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); SSL_free(c->ssl); c->ssl=NULL; #if OPENSSL_VERSION_NUMBER>=0x10000000L ERR_remove_thread_state(NULL); #else /* OpenSSL version < 1.0.0 */ ERR_remove_state(0); #endif /* OpenSSL version >= 1.0.0 */ } /* cleanup the remote socket */ if(c->remote_fd.fd!=INVALID_SOCKET) { /* remote socket initialized */ if(rst && c->remote_fd.is_socket) /* reset */ reset(c->remote_fd.fd, "linger (remote)"); closesocket(c->remote_fd.fd); s_log(LOG_DEBUG, "Remote descriptor (FD=%ld) closed", (long)c->remote_fd.fd); c->remote_fd.fd=INVALID_SOCKET; } /* cleanup the local socket */ if(c->local_rfd.fd!=INVALID_SOCKET) { /* local socket initialized */ if(c->local_rfd.fd==c->local_wfd.fd) { if(rst && c->local_rfd.is_socket) reset(c->local_rfd.fd, "linger (local)"); closesocket(c->local_rfd.fd); s_log(LOG_DEBUG, "Local descriptor (FD=%ld) closed", (long)c->local_rfd.fd); } else { /* stdin/stdout */ if(rst && c->local_rfd.is_socket) reset(c->local_rfd.fd, "linger (local_rfd)"); if(rst && c->local_wfd.is_socket) reset(c->local_wfd.fd, "linger (local_wfd)"); } c->local_rfd.fd=c->local_wfd.fd=INVALID_SOCKET; } #ifdef USE_FORK /* display child return code if it managed to arrive on time */ /* otherwise it will be retrieved by the init process and ignored */ if(c->opt->exec_name) /* 'exec' specified */ child_status(); /* null SIGCHLD handler was used */ s_log(LOG_DEBUG, "Service [%s] finished", c->opt->servname); #else CRYPTO_w_lock(stunnel_locks[LOCK_CLIENTS]); ui_clients(--num_clients); num_clients_copy=num_clients; /* to move s_log() away from CRIT_CLIENTS */ CRYPTO_w_unlock(stunnel_locks[LOCK_CLIENTS]); s_log(LOG_DEBUG, "Service [%s] finished (%ld left)", c->opt->servname, num_clients_copy); #endif /* free the client context */ str_free(c->connect_addr.addr); s_poll_free(c->fds); c->fds=NULL; } #ifdef __GNUC__ #pragma GCC diagnostic pop #endif /* __GNUC__ */ NOEXPORT void client_try(CLI *c) { local_start(c); protocol(c, c->opt, PROTOCOL_EARLY); if(c->opt->option.connect_before_ssl) { remote_start(c); protocol(c, c->opt, PROTOCOL_MIDDLE); ssl_start(c); } else { ssl_start(c); protocol(c, c->opt, PROTOCOL_MIDDLE); remote_start(c); } protocol(c, c->opt, PROTOCOL_LATE); transfer(c); } NOEXPORT void local_start(CLI *c) { SOCKADDR_UNION addr; socklen_t addr_len; char *accepted_address; /* check if local_rfd is a socket and get peer address */ addr_len=sizeof(SOCKADDR_UNION); c->local_rfd.is_socket=!getpeername(c->local_rfd.fd, &addr.sa, &addr_len); if(c->local_rfd.is_socket) { memcpy(&c->peer_addr.sa, &addr.sa, (size_t)addr_len); c->peer_addr_len=addr_len; if(set_socket_options(c->local_rfd.fd, 1)) s_log(LOG_WARNING, "Failed to set local socket options"); } else { if(get_last_socket_error()!=S_ENOTSOCK) { sockerror("getpeerbyname (local_rfd)"); longjmp(c->err, 1); } } /* check if local_wfd is a socket and get peer address */ if(c->local_rfd.fd==c->local_wfd.fd) { c->local_wfd.is_socket=c->local_rfd.is_socket; } else { addr_len=sizeof(SOCKADDR_UNION); c->local_wfd.is_socket=!getpeername(c->local_wfd.fd, &addr.sa, &addr_len); if(c->local_wfd.is_socket) { if(!c->local_rfd.is_socket) { /* already retrieved */ memcpy(&c->peer_addr.sa, &addr.sa, (size_t)addr_len); c->peer_addr_len=addr_len; } if(set_socket_options(c->local_wfd.fd, 1)) s_log(LOG_WARNING, "Failed to set local socket options"); } else { if(get_last_socket_error()!=S_ENOTSOCK) { sockerror("getpeerbyname (local_wfd)"); longjmp(c->err, 1); } } } /* neither of local descriptors is a socket */ if(!c->local_rfd.is_socket && !c->local_wfd.is_socket) { #ifndef USE_WIN32 if(c->opt->option.transparent_src) { s_log(LOG_ERR, "Transparent source needs a socket"); longjmp(c->err, 1); } #endif s_log(LOG_NOTICE, "Service [%s] accepted connection", c->opt->servname); return; } /* authenticate based on retrieved IP address of the client */ accepted_address=s_ntop(&c->peer_addr, c->peer_addr_len); #ifdef USE_LIBWRAP libwrap_auth(c, accepted_address); #endif /* USE_LIBWRAP */ auth_user(c, accepted_address); s_log(LOG_NOTICE, "Service [%s] accepted connection from %s", c->opt->servname, accepted_address); str_free(accepted_address); } NOEXPORT void remote_start(CLI *c) { /* where to bind connecting socket */ if(c->opt->option.local) /* outgoing interface */ c->bind_addr=&c->opt->source_addr; #ifndef USE_WIN32 else if(c->opt->option.transparent_src) c->bind_addr=&c->peer_addr; #endif else c->bind_addr=NULL; /* don't bind */ /* setup c->remote_fd, now */ if(c->opt->exec_name && !c->opt->connect_addr.names) c->remote_fd.fd=connect_local(c); /* not for exec+connect targets */ else c->remote_fd.fd=connect_remote(c); #ifndef USE_WIN32 if(c->opt->option.pty) { /* descriptor created with pty_allocate() */ c->remote_fd.is_socket=0; } else #endif { c->remote_fd.is_socket=1; if(set_socket_options(c->remote_fd.fd, 2)) s_log(LOG_WARNING, "Failed to set remote socket options"); } s_log(LOG_DEBUG, "Remote descriptor (FD=%ld) initialized", (long)c->remote_fd.fd); } NOEXPORT void ssl_start(CLI *c) { int i, err; SSL_SESSION *old_session; int unsafe_openssl; X509 *peer_cert; c->ssl=SSL_new(c->opt->ctx); if(!c->ssl) { sslerror("SSL_new"); longjmp(c->err, 1); } SSL_set_ex_data(c->ssl, index_cli, c); /* for callbacks */ if(c->opt->option.client) { #ifndef OPENSSL_NO_TLSEXT if(c->opt->sni) { s_log(LOG_INFO, "SNI: sending servername: %s", c->opt->sni); if(!SSL_set_tlsext_host_name(c->ssl, c->opt->sni)) { sslerror("SSL_set_tlsext_host_name"); longjmp(c->err, 1); } } #endif if(c->opt->session) { CRYPTO_w_lock(stunnel_locks[LOCK_SESSION]); SSL_set_session(c->ssl, c->opt->session); CRYPTO_w_unlock(stunnel_locks[LOCK_SESSION]); } SSL_set_fd(c->ssl, (int)c->remote_fd.fd); SSL_set_connect_state(c->ssl); } else { /* SSL server */ if(c->local_rfd.fd==c->local_wfd.fd) SSL_set_fd(c->ssl, (int)c->local_rfd.fd); else { /* does it make sense to have SSL on STDIN/STDOUT? */ SSL_set_rfd(c->ssl, (int)c->local_rfd.fd); SSL_set_wfd(c->ssl, (int)c->local_wfd.fd); } SSL_set_accept_state(c->ssl); } unsafe_openssl=OpenSSL_version_num()<0x0090810fL || (OpenSSL_version_num()>=0x10000000L && OpenSSL_version_num()<0x1000002fL); while(1) { /* critical section for OpenSSL version < 0.9.8p or 1.x.x < 1.0.0b * * this critical section is a crude workaround for CVE-2010-3864 * * see http://www.securityfocus.com/bid/44884 for details * * alternative solution is to disable internal session caching * * NOTE: this critical section also covers callbacks (e.g. OCSP) */ if(unsafe_openssl) CRYPTO_w_lock(stunnel_locks[LOCK_SSL]); if(c->opt->option.client) i=SSL_connect(c->ssl); else i=SSL_accept(c->ssl); if(unsafe_openssl) CRYPTO_w_unlock(stunnel_locks[LOCK_SSL]); err=SSL_get_error(c->ssl, i); if(err==SSL_ERROR_NONE) break; /* ok -> done */ if(err==SSL_ERROR_WANT_READ || err==SSL_ERROR_WANT_WRITE) { s_poll_init(c->fds); s_poll_add(c->fds, c->ssl_rfd->fd, err==SSL_ERROR_WANT_READ, err==SSL_ERROR_WANT_WRITE); switch(s_poll_wait(c->fds, c->opt->timeout_busy, 0)) { case -1: sockerror("ssl_start: s_poll_wait"); longjmp(c->err, 1); case 0: s_log(LOG_INFO, "ssl_start: s_poll_wait:" " TIMEOUTbusy exceeded: sending reset"); longjmp(c->err, 1); case 1: break; /* OK */ default: s_log(LOG_ERR, "ssl_start: s_poll_wait: unknown result"); longjmp(c->err, 1); } continue; /* ok -> retry */ } if(err==SSL_ERROR_SYSCALL) { switch(get_last_socket_error()) { case S_EINTR: case S_EWOULDBLOCK: #if S_EAGAIN!=S_EWOULDBLOCK case S_EAGAIN: #endif continue; } } if(c->opt->option.client) sslerror("SSL_connect"); else sslerror("SSL_accept"); longjmp(c->err, 1); } s_log(LOG_INFO, "SSL %s: %s", c->opt->option.client ? "connected" : "accepted", SSL_session_reused(c->ssl) ? "previous session reused" : "new session negotiated"); if(SSL_session_reused(c->ssl)) { c->redirect=(uintptr_t)SSL_SESSION_get_ex_data(SSL_get_session(c->ssl), index_redirect); if(c->opt->redirect_addr.names && !c->redirect) { s_log(LOG_ERR, "No application data found in the reused session"); longjmp(c->err, 1); } } else { /* a new session was negotiated */ new_chain(c); peer_cert=SSL_get_peer_certificate(c->ssl); if(peer_cert) /* c->redirect was set by the callback */ X509_free(peer_cert); else if(c->opt->redirect_addr.names) c->redirect=REDIRECT_ON; SSL_SESSION_set_ex_data(SSL_get_session(c->ssl), index_redirect, (void *)c->redirect); if(c->opt->option.client) { CRYPTO_w_lock(stunnel_locks[LOCK_SESSION]); old_session=c->opt->session; c->opt->session=SSL_get1_session(c->ssl); /* store it */ CRYPTO_w_unlock(stunnel_locks[LOCK_SESSION]); if(old_session) SSL_SESSION_free(old_session); /* release the old one */ } else { /* SSL server */ SSL_CTX_add_session(c->opt->ctx, SSL_get_session(c->ssl)); } print_cipher(c); } } NOEXPORT void new_chain(CLI *c) { BIO *bio; int i, len; X509 *peer_cert; STACK_OF(X509) *sk; char *chain; if(c->opt->chain) /* already cached */ return; /* this race condition is safe to ignore */ bio=BIO_new(BIO_s_mem()); if(!bio) return; sk=SSL_get_peer_cert_chain(c->ssl); for(i=0; sk && iopt->option.client) { peer_cert=SSL_get_peer_certificate(c->ssl); if(peer_cert) { PEM_write_bio_X509(bio, peer_cert); X509_free(peer_cert); } } len=BIO_pending(bio); if(len<=0) { s_log(LOG_INFO, "No peer certificate received"); BIO_free(bio); return; } /* prevent automatic deallocation of the cached value */ chain=str_alloc_detached((size_t)len+1); len=BIO_read(bio, chain, len); if(len<0) { s_log(LOG_ERR, "BIO_read failed"); BIO_free(bio); str_free(chain); return; } chain[len]='\0'; BIO_free(bio); c->opt->chain=chain; /* this race condition is safe to ignore */ ui_new_chain(c->opt->section_number); s_log(LOG_DEBUG, "Peer certificate was cached (%d bytes)", len); } /****************************** transfer data */ NOEXPORT void transfer(CLI *c) { int watchdog=0; /* a counter to detect an infinite loop */ ssize_t num; int err; /* logical channels (not file descriptors!) open for read or write */ int sock_open_rd=1, sock_open_wr=1; /* awaited conditions on SSL file descriptors */ int shutdown_wants_read=0, shutdown_wants_write=0; int read_wants_read=0, read_wants_write=0; int write_wants_read=0, write_wants_write=0; /* actual conditions on file descriptors */ int sock_can_rd, sock_can_wr, ssl_can_rd, ssl_can_wr; #ifdef USE_WIN32 unsigned long bytes; #else int bytes; #endif c->sock_ptr=c->ssl_ptr=0; do { /* main loop of client data transfer */ /****************************** initialize *_wants_* */ read_wants_read|=!(SSL_get_shutdown(c->ssl)&SSL_RECEIVED_SHUTDOWN) && c->ssl_ptrssl)&SSL_SENT_SHUTDOWN) && c->sock_ptr && !write_wants_read; /****************************** setup c->fds structure */ s_poll_init(c->fds); /* initialize the structure */ /* for plain socket open data strem = open file descriptor */ /* make sure to add each open socket to receive exceptions! */ if(sock_open_rd) /* only poll if the read file descriptor is open */ s_poll_add(c->fds, c->sock_rfd->fd, c->sock_ptrfds, c->sock_wfd->fd, 0, c->ssl_ptr>0); /* poll SSL file descriptors unless SSL shutdown was completed */ if(SSL_get_shutdown(c->ssl)!= (SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN)) { s_poll_add(c->fds, c->ssl_rfd->fd, read_wants_read || write_wants_read || shutdown_wants_read, 0); s_poll_add(c->fds, c->ssl_wfd->fd, 0, read_wants_write || write_wants_write || shutdown_wants_write); } /****************************** wait for an event */ err=s_poll_wait(c->fds, (sock_open_rd && /* both peers open */ !(SSL_get_shutdown(c->ssl)&SSL_RECEIVED_SHUTDOWN)) || c->ssl_ptr /* data buffered to write to socket */ || c->sock_ptr /* data buffered to write to SSL */ ? c->opt->timeout_idle : c->opt->timeout_close, 0); switch(err) { case -1: sockerror("transfer: s_poll_wait"); longjmp(c->err, 1); case 0: /* timeout */ if((sock_open_rd && !(SSL_get_shutdown(c->ssl)&SSL_RECEIVED_SHUTDOWN)) || c->ssl_ptr || c->sock_ptr) { s_log(LOG_INFO, "transfer: s_poll_wait:" " TIMEOUTidle exceeded: sending reset"); longjmp(c->err, 1); } else { /* already closing connection */ s_log(LOG_ERR, "transfer: s_poll_wait:" " TIMEOUTclose exceeded: closing"); return; /* OK */ } } /****************************** retrieve results from c->fds */ sock_can_rd=s_poll_canread(c->fds, c->sock_rfd->fd); sock_can_wr=s_poll_canwrite(c->fds, c->sock_wfd->fd); ssl_can_rd=s_poll_canread(c->fds, c->ssl_rfd->fd); ssl_can_wr=s_poll_canwrite(c->fds, c->ssl_wfd->fd); /****************************** hangups without read or write */ if(!(sock_can_rd || sock_can_wr || ssl_can_rd || ssl_can_wr)) { if(s_poll_hup(c->fds, c->sock_rfd->fd) || s_poll_hup(c->fds, c->sock_wfd->fd)) { if(c->ssl_ptr) { s_log(LOG_ERR, "Socket closed (HUP) with %ld unsent byte(s)", (long)c->ssl_ptr); longjmp(c->err, 1); /* reset the sockets */ } s_log(LOG_INFO, "Socket closed (HUP)"); sock_open_rd=sock_open_wr=0; } else if(s_poll_hup(c->fds, c->ssl_rfd->fd) || s_poll_hup(c->fds, c->ssl_wfd->fd)) { if(c->sock_ptr) { s_log(LOG_ERR, "SSL socket closed (HUP) with %ld unsent byte(s)", (long)c->sock_ptr); longjmp(c->err, 1); /* reset the sockets */ } s_log(LOG_INFO, "SSL socket closed (HUP)"); SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); } else { /* please report it to the stunnel-users mailing list */ s_log(LOG_ERR, "INTERNAL ERROR: " "s_poll_wait returned %d, but no descriptor is ready", err); s_poll_dump(c->fds, LOG_ERR); longjmp(c->err, 1); } } if(c->reneg_state==RENEG_DETECTED && !c->opt->option.renegotiation) { s_log(LOG_ERR, "Aborting due to renegotiation request"); longjmp(c->err, 1); } /****************************** send SSL close_notify alert */ if(shutdown_wants_read || shutdown_wants_write) { num=SSL_shutdown(c->ssl); /* send close_notify alert */ if(num<0) /* -1 - not completed */ err=SSL_get_error(c->ssl, (int)num); else /* 0 or 1 - success */ err=SSL_ERROR_NONE; switch(err) { case SSL_ERROR_NONE: /* the shutdown was successfully completed */ s_log(LOG_INFO, "SSL_shutdown successfully sent close_notify alert"); shutdown_wants_read=shutdown_wants_write=0; break; case SSL_ERROR_SYSCALL: /* socket error */ if(parse_socket_error(c, "SSL_shutdown")) break; /* a non-critical error: retry */ SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); shutdown_wants_read=shutdown_wants_write=0; break; case SSL_ERROR_WANT_WRITE: s_log(LOG_DEBUG, "SSL_shutdown returned WANT_WRITE: retrying"); shutdown_wants_read=0; shutdown_wants_write=1; break; case SSL_ERROR_WANT_READ: s_log(LOG_DEBUG, "SSL_shutdown returned WANT_READ: retrying"); shutdown_wants_read=1; shutdown_wants_write=0; break; case SSL_ERROR_SSL: /* SSL error */ sslerror("SSL_shutdown"); longjmp(c->err, 1); default: s_log(LOG_ERR, "SSL_shutdown/SSL_get_error returned %d", err); longjmp(c->err, 1); } } /****************************** write to socket */ if(sock_open_wr && sock_can_wr) { num=writesocket(c->sock_wfd->fd, c->ssl_buff, c->ssl_ptr); switch(num) { case -1: /* error */ if(parse_socket_error(c, "writesocket")) break; /* a non-critical error: retry */ sock_open_rd=sock_open_wr=0; break; default: memmove(c->ssl_buff, c->ssl_buff+num, c->ssl_ptr-(size_t)num); c->ssl_ptr-=(size_t)num; memset(c->ssl_buff+c->ssl_ptr, 0, (size_t)num); /* paranoia */ c->sock_bytes+=(size_t)num; watchdog=0; /* reset watchdog */ } } /****************************** read from socket */ if(sock_open_rd && sock_can_rd) { num=readsocket(c->sock_rfd->fd, c->sock_buff+c->sock_ptr, BUFFSIZE-c->sock_ptr); switch(num) { case -1: if(parse_socket_error(c, "readsocket")) break; /* a non-critical error: retry */ sock_open_rd=sock_open_wr=0; break; case 0: /* close */ s_log(LOG_INFO, "Read socket closed (readsocket)"); sock_open_rd=0; break; default: c->sock_ptr+=(size_t)num; watchdog=0; /* reset watchdog */ } } /****************************** update *_wants_* based on new *_ptr */ /* this update is also required for SSL_pending() to be used */ read_wants_read|=!(SSL_get_shutdown(c->ssl)&SSL_RECEIVED_SHUTDOWN) && c->ssl_ptrssl)&SSL_SENT_SHUTDOWN) && c->sock_ptr && !write_wants_read; /****************************** write to SSL */ if((write_wants_read && ssl_can_rd) || (write_wants_write && ssl_can_wr)) { write_wants_read=0; write_wants_write=0; num=SSL_write(c->ssl, c->sock_buff, (int)(c->sock_ptr)); switch(err=SSL_get_error(c->ssl, (int)num)) { case SSL_ERROR_NONE: if(num==0) s_log(LOG_DEBUG, "SSL_write returned 0"); memmove(c->sock_buff, c->sock_buff+num, c->sock_ptr-(size_t)num); c->sock_ptr-=(size_t)num; memset(c->sock_buff+c->sock_ptr, 0, (size_t)num); /* paranoia */ c->ssl_bytes+=(size_t)num; watchdog=0; /* reset watchdog */ break; case SSL_ERROR_WANT_WRITE: /* buffered data? */ s_log(LOG_DEBUG, "SSL_write returned WANT_WRITE: retrying"); write_wants_write=1; break; case SSL_ERROR_WANT_READ: s_log(LOG_DEBUG, "SSL_write returned WANT_READ: retrying"); write_wants_read=1; break; case SSL_ERROR_WANT_X509_LOOKUP: s_log(LOG_DEBUG, "SSL_write returned WANT_X509_LOOKUP: retrying"); break; case SSL_ERROR_SYSCALL: /* socket error */ if(num && parse_socket_error(c, "SSL_write")) break; /* a non-critical error: retry */ /* EOF -> buggy (e.g. Microsoft) peer: * SSL socket closed without close_notify alert */ if(c->sock_ptr) { /* TODO: what about buffered data? */ s_log(LOG_ERR, "SSL socket closed (SSL_write) with %ld unsent byte(s)", (long)c->sock_ptr); longjmp(c->err, 1); /* reset the sockets */ } s_log(LOG_INFO, "SSL socket closed (SSL_write)"); SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); break; case SSL_ERROR_ZERO_RETURN: /* close_notify alert received */ s_log(LOG_INFO, "SSL closed (SSL_write)"); if(SSL_version(c->ssl)==SSL2_VERSION) SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); break; case SSL_ERROR_SSL: sslerror("SSL_write"); longjmp(c->err, 1); default: s_log(LOG_ERR, "SSL_write/SSL_get_error returned %d", err); longjmp(c->err, 1); } } /****************************** read from SSL */ if((read_wants_read && (ssl_can_rd || SSL_pending(c->ssl))) || /* it may be possible to read some pending data after * writesocket() above made some room in c->ssl_buff */ (read_wants_write && ssl_can_wr)) { read_wants_read=0; read_wants_write=0; num=SSL_read(c->ssl, c->ssl_buff+c->ssl_ptr, (int)(BUFFSIZE-c->ssl_ptr)); switch(err=SSL_get_error(c->ssl, (int)num)) { case SSL_ERROR_NONE: if(num==0) s_log(LOG_DEBUG, "SSL_read returned 0"); c->ssl_ptr+=(size_t)num; watchdog=0; /* reset watchdog */ break; case SSL_ERROR_WANT_WRITE: s_log(LOG_DEBUG, "SSL_read returned WANT_WRITE: retrying"); read_wants_write=1; break; case SSL_ERROR_WANT_READ: /* happens quite often */ #if 0 s_log(LOG_DEBUG, "SSL_read returned WANT_READ: retrying"); #endif read_wants_read=1; break; case SSL_ERROR_WANT_X509_LOOKUP: s_log(LOG_DEBUG, "SSL_read returned WANT_X509_LOOKUP: retrying"); break; case SSL_ERROR_SYSCALL: if(num && parse_socket_error(c, "SSL_read")) break; /* a non-critical error: retry */ /* EOF -> buggy (e.g. Microsoft) peer: * SSL socket closed without close_notify alert */ if(c->sock_ptr || write_wants_write) { s_log(LOG_ERR, "SSL socket closed (SSL_read) with %ld unsent byte(s)", (long)c->sock_ptr); longjmp(c->err, 1); /* reset the sockets */ } s_log(LOG_INFO, "SSL socket closed (SSL_read)"); SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); break; case SSL_ERROR_ZERO_RETURN: /* close_notify alert received */ s_log(LOG_INFO, "SSL closed (SSL_read)"); if(SSL_version(c->ssl)==SSL2_VERSION) SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); break; case SSL_ERROR_SSL: sslerror("SSL_read"); longjmp(c->err, 1); default: s_log(LOG_ERR, "SSL_read/SSL_get_error returned %d", err); longjmp(c->err, 1); } } /****************************** check for hangup conditions */ /* http://marc.info/?l=linux-man&m=128002066306087 */ /* readsocket() must be the last sock_rfd operation before FIONREAD */ if(sock_open_rd && s_poll_rdhup(c->fds, c->sock_rfd->fd) && (ioctlsocket(c->sock_rfd->fd, FIONREAD, &bytes) || !bytes)) { s_log(LOG_INFO, "Read socket closed (read hangup)"); sock_open_rd=0; } if(sock_open_wr && s_poll_hup(c->fds, c->sock_wfd->fd)) { if(c->ssl_ptr) { s_log(LOG_ERR, "Write socket closed (write hangup) with %ld unsent byte(s)", (long)c->ssl_ptr); longjmp(c->err, 1); /* reset the sockets */ } s_log(LOG_INFO, "Write socket closed (write hangup)"); sock_open_wr=0; } /* SSL_read() must be the last ssl_rfd operation before FIONREAD */ if(!(SSL_get_shutdown(c->ssl)&SSL_RECEIVED_SHUTDOWN) && s_poll_rdhup(c->fds, c->ssl_rfd->fd) && (ioctlsocket(c->ssl_rfd->fd, FIONREAD, &bytes) || !bytes)) { /* hangup -> buggy (e.g. Microsoft) peer: * SSL socket closed without close_notify alert */ s_log(LOG_INFO, "SSL socket closed (read hangup)"); SSL_set_shutdown(c->ssl, SSL_get_shutdown(c->ssl)|SSL_RECEIVED_SHUTDOWN); } if(!(SSL_get_shutdown(c->ssl)&SSL_SENT_SHUTDOWN) && s_poll_hup(c->fds, c->ssl_wfd->fd)) { if(c->sock_ptr || write_wants_write) { s_log(LOG_ERR, "SSL socket closed (write hangup) with %ld unsent byte(s)", (long)c->sock_ptr); longjmp(c->err, 1); /* reset the sockets */ } s_log(LOG_INFO, "SSL socket closed (write hangup)"); SSL_set_shutdown(c->ssl, SSL_get_shutdown(c->ssl)|SSL_SENT_SHUTDOWN); } /****************************** check write shutdown conditions */ if(sock_open_wr && SSL_get_shutdown(c->ssl)&SSL_RECEIVED_SHUTDOWN && !c->ssl_ptr) { sock_open_wr=0; /* no further write allowed */ if(!c->sock_wfd->is_socket) { s_log(LOG_DEBUG, "Closing the file descriptor"); sock_open_rd=0; /* file descriptor is ready to be closed */ } else if(!shutdown(c->sock_wfd->fd, SHUT_WR)) { /* send TCP FIN */ s_log(LOG_DEBUG, "Sent socket write shutdown"); } else { s_log(LOG_DEBUG, "Failed to send socket write shutdown"); sock_open_rd=0; /* file descriptor is ready to be closed */ } } if(!(SSL_get_shutdown(c->ssl)&SSL_SENT_SHUTDOWN) && !sock_open_rd && !c->sock_ptr && !write_wants_write) { if(SSL_version(c->ssl)!=SSL2_VERSION) { s_log(LOG_DEBUG, "Sending close_notify alert"); shutdown_wants_write=1; } else { /* no alerts in SSLv2, including the close_notify alert */ s_log(LOG_DEBUG, "Closing SSLv2 socket"); if(c->ssl_rfd->is_socket) shutdown(c->ssl_rfd->fd, SHUT_RD); /* notify the kernel */ if(c->ssl_wfd->is_socket) shutdown(c->ssl_wfd->fd, SHUT_WR); /* send TCP FIN */ /* notify the OpenSSL library */ SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); } } /****************************** check watchdog */ if(++watchdog>100) { /* loop executes without transferring any data */ s_log(LOG_ERR, "transfer() loop executes not transferring any data"); s_log(LOG_ERR, "please report the problem to Michal.Trojnara@mirt.net"); stunnel_info(LOG_ERR); s_log(LOG_ERR, "protocol=%s, SSL_pending=%d", SSL_get_version(c->ssl), SSL_pending(c->ssl)); s_log(LOG_ERR, "sock_open_rd=%s, sock_open_wr=%s", sock_open_rd ? "Y" : "n", sock_open_wr ? "Y" : "n"); s_log(LOG_ERR, "SSL_RECEIVED_SHUTDOWN=%s, SSL_SENT_SHUTDOWN=%s", SSL_get_shutdown(c->ssl)&SSL_RECEIVED_SHUTDOWN ? "Y" : "n", SSL_get_shutdown(c->ssl)&SSL_SENT_SHUTDOWN ? "Y" : "n"); s_log(LOG_ERR, "sock_can_rd=%s, sock_can_wr=%s", sock_can_rd ? "Y" : "n", sock_can_wr ? "Y" : "n"); s_log(LOG_ERR, "ssl_can_rd=%s, ssl_can_wr=%s", ssl_can_rd ? "Y" : "n", ssl_can_wr ? "Y" : "n"); s_log(LOG_ERR, "read_wants_read=%s, read_wants_write=%s", read_wants_read ? "Y" : "n", read_wants_write ? "Y" : "n"); s_log(LOG_ERR, "write_wants_read=%s, write_wants_write=%s", write_wants_read ? "Y" : "n", write_wants_write ? "Y" : "n"); s_log(LOG_ERR, "shutdown_wants_read=%s, shutdown_wants_write=%s", shutdown_wants_read ? "Y" : "n", shutdown_wants_write ? "Y" : "n"); s_log(LOG_ERR, "socket input buffer: %ld byte(s), " "ssl input buffer: %ld byte(s)", (long)c->sock_ptr, (long)c->ssl_ptr); longjmp(c->err, 1); } } while(sock_open_wr || !(SSL_get_shutdown(c->ssl)&SSL_SENT_SHUTDOWN) || shutdown_wants_read || shutdown_wants_write); } /* returns 0 on close and 1 on non-critical errors */ NOEXPORT int parse_socket_error(CLI *c, const char *text) { switch(get_last_socket_error()) { /* http://tangentsoft.net/wskfaq/articles/bsd-compatibility.html */ case 0: /* close on read, or close on write on WIN32 */ #ifndef USE_WIN32 case EPIPE: /* close on write on Unix */ #endif case S_ECONNABORTED: s_log(LOG_INFO, "%s: Socket is closed", text); return 0; case S_EINTR: s_log(LOG_DEBUG, "%s: Interrupted by a signal: retrying", text); return 1; case S_EWOULDBLOCK: s_log(LOG_NOTICE, "%s: Would block: retrying", text); sleep(1); /* Microsoft bug KB177346 */ return 1; #if S_EAGAIN!=S_EWOULDBLOCK case S_EAGAIN: s_log(LOG_DEBUG, "%s: Temporary lack of resources: retrying", text); return 1; #endif #ifdef USE_WIN32 case S_ECONNRESET: /* dying "exec" processes on Win32 cause reset instead of close */ if(c->opt->exec_name) { s_log(LOG_INFO, "%s: Socket is closed (exec)", text); return 0; } #endif default: sockerror(text); longjmp(c->err, 1); return -1; /* some C compilers require a return value */ } } NOEXPORT void print_cipher(CLI *c) { /* print negotiated cipher */ SSL_CIPHER *cipher; #ifndef OPENSSL_NO_COMP const COMP_METHOD *compression, *expansion; #endif if(c->opt->log_levelssl); s_log(LOG_INFO, "Negotiated %s ciphersuite %s (%d-bit encryption)", SSL_get_version(c->ssl), SSL_CIPHER_get_name(cipher), SSL_CIPHER_get_bits(cipher, NULL)); #ifndef OPENSSL_NO_COMP compression=SSL_get_current_compression(c->ssl); expansion=SSL_get_current_expansion(c->ssl); s_log(compression||expansion ? LOG_INFO : LOG_DEBUG, "Compression: %s, expansion: %s", compression ? SSL_COMP_get_name(compression) : "null", expansion ? SSL_COMP_get_name(expansion) : "null"); #endif } NOEXPORT void auth_user(CLI *c, char *accepted_address) { #ifndef _WIN32_WCE struct servent *s_ent; /* structure for getservbyname */ #endif SOCKADDR_UNION ident; /* IDENT socket name */ char *line, *type, *system, *user; if(!c->opt->username) return; /* -u option not specified */ #ifdef HAVE_STRUCT_SOCKADDR_UN if(c->peer_addr.sa.sa_family==AF_UNIX) { s_log(LOG_INFO, "IDENT not supported on Unix sockets"); return; } #endif c->fd=s_socket(c->peer_addr.sa.sa_family, SOCK_STREAM, 0, 1, "socket (auth_user)"); if(c->fd==INVALID_SOCKET) longjmp(c->err, 1); memcpy(&ident, &c->peer_addr, (size_t)c->peer_addr_len); #ifndef _WIN32_WCE s_ent=getservbyname("auth", "tcp"); if(s_ent) { ident.in.sin_port=(u_short)s_ent->s_port; } else #endif { s_log(LOG_WARNING, "Unknown service 'auth': using default 113"); ident.in.sin_port=htons(113); } if(s_connect(c, &ident, addr_len(&ident))) longjmp(c->err, 1); s_log(LOG_DEBUG, "IDENT server connected"); fd_printf(c, c->fd, "%u , %u", ntohs(c->peer_addr.in.sin_port), ntohs(c->opt->local_addr.in.sin_port)); line=fd_getline(c, c->fd); closesocket(c->fd); c->fd=INVALID_SOCKET; /* avoid double close on cleanup */ type=strchr(line, ':'); if(!type) { s_log(LOG_ERR, "Malformed IDENT response"); str_free(line); longjmp(c->err, 1); } *type++='\0'; system=strchr(type, ':'); if(!system) { s_log(LOG_ERR, "Malformed IDENT response"); str_free(line); longjmp(c->err, 1); } *system++='\0'; if(strcmp(type, " USERID ")) { s_log(LOG_ERR, "Incorrect INETD response type"); str_free(line); longjmp(c->err, 1); } user=strchr(system, ':'); if(!user) { s_log(LOG_ERR, "Malformed IDENT response"); str_free(line); longjmp(c->err, 1); } *user++='\0'; while(*user==' ') /* skip leading spaces */ ++user; if(strcmp(user, c->opt->username)) { s_log(LOG_WARNING, "Connection from %s REFUSED by IDENT (user \"%s\")", accepted_address, user); str_free(line); longjmp(c->err, 1); } s_log(LOG_INFO, "IDENT authentication passed"); str_free(line); } #if defined(_WIN32_WCE) || defined(__vms) NOEXPORT int connect_local(CLI *c) { /* spawn local process */ s_log(LOG_ERR, "Local mode is not supported on this platform"); longjmp(c->err, 1); return -1; /* some C compilers require a return value */ } #elif defined(USE_WIN32) NOEXPORT SOCKET connect_local(CLI *c) { /* spawn local process */ SOCKET fd[2]; STARTUPINFO si; PROCESS_INFORMATION pi; LPTSTR name, args; if(make_sockets(fd)) longjmp(c->err, 1); memset(&si, 0, sizeof si); si.cb=sizeof si; si.dwFlags=STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES; si.wShowWindow=SW_HIDE; si.hStdInput=si.hStdOutput=si.hStdError=(HANDLE)fd[1]; memset(&pi, 0, sizeof pi); name=str2tstr(c->opt->exec_name); args=str2tstr(c->opt->exec_args); CreateProcess(name, args, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); str_free(name); str_free(args); closesocket(fd[1]); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return fd[0]; } #else /* standard Unix version */ extern char **environ; NOEXPORT SOCKET connect_local(CLI *c) { /* spawn local process */ int fd[2], pid; char **env; #ifdef HAVE_PTHREAD_SIGMASK sigset_t newmask; #endif if(c->opt->option.pty) { char tty[64]; if(pty_allocate(fd, fd+1, tty)) longjmp(c->err, 1); s_log(LOG_DEBUG, "TTY=%s allocated", tty); } else if(make_sockets(fd)) longjmp(c->err, 1); set_nonblock(fd[1], 0); /* switch back to the blocking mode */ env=env_alloc(c); pid=fork(); c->pid=(unsigned long)pid; switch(pid) { case -1: /* error */ closesocket(fd[0]); closesocket(fd[1]); env_free(env); ioerror("fork"); longjmp(c->err, 1); case 0: /* child */ /* the child is not allowed to play with thread-local storage */ /* see http://linux.die.net/man/3/pthread_atfork for details */ closesocket(fd[0]); /* dup2() does not copy FD_CLOEXEC flag */ dup2(fd[1], 0); dup2(fd[1], 1); if(!global_options.option.log_stderr) dup2(fd[1], 2); closesocket(fd[1]); /* not really needed due to FD_CLOEXEC */ #ifdef HAVE_PTHREAD_SIGMASK sigemptyset(&newmask); sigprocmask(SIG_SETMASK, &newmask, NULL); #endif signal(SIGCHLD, SIG_DFL); signal(SIGHUP, SIG_DFL); signal(SIGUSR1, SIG_DFL); signal(SIGPIPE, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGINT, SIG_DFL); execve(c->opt->exec_name, c->opt->exec_args, env); _exit(1); /* failed, but there is no way to report an error here */ default: /* parent */ closesocket(fd[1]); env_free(env); s_log(LOG_INFO, "Local mode child started (PID=%lu)", c->pid); return fd[0]; } } char **env_alloc(CLI *c) { char **env=NULL, **p; unsigned n=0; /* (n+2) keeps the list NULL-terminated */ char *name, host[40], port[6]; X509 *peer_cert; if(!getnameinfo(&c->peer_addr.sa, c->peer_addr_len, host, 40, port, 6, NI_NUMERICHOST|NI_NUMERICSERV)) { /* just don't set these variables if getnameinfo() fails */ env=str_realloc(env, (n+2)*sizeof(char *)); env[n++]=str_printf("REMOTE_HOST=%s", host); env=str_realloc(env, (n+2)*sizeof(char *)); env[n++]=str_printf("REMOTE_PORT=%s", port); if(c->opt->option.transparent_src) { #ifndef LIBDIR #define LIBDIR "." #endif #ifdef MACH64 env=str_realloc(env, (n+2)*sizeof(char *)); env[n++]=str_dup("LD_PRELOAD_32=" LIBDIR "/libstunnel.so"); env=str_realloc(env, (n+2)*sizeof(char *)); env[n++]=str_dup("LD_PRELOAD_64=" LIBDIR "/" MACH64 "/libstunnel.so"); #elif __osf /* for Tru64 _RLD_LIST is used instead */ env=str_realloc(env, (n+2)*sizeof(char *)); env[n++]=str_dup("_RLD_LIST=" LIBDIR "/libstunnel.so:DEFAULT"); #else env=str_realloc(env, (n+2)*sizeof(char *)); env[n++]=str_dup("LD_PRELOAD=" LIBDIR "/libstunnel.so"); #endif } } if(c->ssl) { peer_cert=SSL_get_peer_certificate(c->ssl); if(peer_cert) { name=X509_NAME2text(X509_get_subject_name(peer_cert)); env=str_realloc(env, (n+2)*sizeof(char *)); env[n++]=str_printf("SSL_CLIENT_DN=%s", name); str_free(name); name=X509_NAME2text(X509_get_issuer_name(peer_cert)); env=str_realloc(env, (n+2)*sizeof(char *)); env[n++]=str_printf("SSL_CLIENT_I_DN=%s", name); str_free(name); X509_free(peer_cert); } } for(p=environ; *p; ++p) { env=str_realloc(env, (n+2)*sizeof(char *)); env[n++]=str_dup(*p); } return env; } void env_free(char **env) { char **p; for(p=env; *p; ++p) str_free(*p); str_free(env); } #endif /* not USE_WIN32 or __vms */ /* connect remote host */ NOEXPORT SOCKET connect_remote(CLI *c) { SOCKET fd; unsigned ind_start, ind_try, ind_cur; setup_connect_addr(c); switch(c->connect_addr.num) { case 0: s_log(LOG_ERR, "No remote host resolved"); longjmp(c->err, 1); case 1: ind_start=0; break; default: ind_start=connect_index(c); } /* try to connect each host from the list */ for(ind_try=0; ind_tryconnect_addr.num; ind_try++) { ind_cur=(ind_start+ind_try)%c->connect_addr.num; c->fd=s_socket(c->connect_addr.addr[ind_cur].sa.sa_family, SOCK_STREAM, 0, 1, "remote socket"); if(c->fd==INVALID_SOCKET) longjmp(c->err, 1); local_bind(c); /* explicit local bind or transparent proxy */ if(s_connect(c, &c->connect_addr.addr[ind_cur], addr_len(&c->connect_addr.addr[ind_cur]))) { closesocket(c->fd); c->fd=INVALID_SOCKET; continue; /* next IP */ } if(c->ssl) connect_cache(SSL_get_session(c->ssl), &c->connect_addr.addr[ind_cur]); print_bound_address(c); fd=c->fd; c->fd=INVALID_SOCKET; return fd; /* success! */ } longjmp(c->err, 1); return INVALID_SOCKET; /* some C compilers require a return value */ } NOEXPORT void connect_cache(SSL_SESSION *sess, SOCKADDR_UNION *cur_addr) { SOCKADDR_UNION *old_addr, *new_addr; socklen_t len; char *addr_txt; /* make a copy of the address, so it may work with delayed resolver */ len=addr_len(cur_addr); new_addr=str_alloc_detached((size_t)len); memcpy(new_addr, cur_addr, (size_t)len); addr_txt=s_ntop(cur_addr, len); s_log(LOG_INFO, "persistence: %s cached", addr_txt); str_free(addr_txt); CRYPTO_w_lock(stunnel_locks[LOCK_ADDR]); old_addr=SSL_SESSION_get_ex_data(sess, index_addr); SSL_SESSION_set_ex_data(sess, index_addr, new_addr); CRYPTO_w_unlock(stunnel_locks[LOCK_ADDR]); str_free(old_addr); /* NULL pointers are ignored */ } NOEXPORT unsigned connect_index(CLI *c) { unsigned i; SOCKADDR_UNION addr, *ptr; socklen_t len; char *addr_txt; if(c->ssl && SSL_session_reused(c->ssl)) { CRYPTO_r_lock(stunnel_locks[LOCK_ADDR]); ptr=SSL_SESSION_get_ex_data(SSL_get_session(c->ssl), index_addr); if(ptr) { len=addr_len(ptr); memcpy(&addr, ptr, (size_t)len); CRYPTO_r_unlock(stunnel_locks[LOCK_ADDR]); /* address was copied, ptr itself is no longer valid */ for(i=0; iconnect_addr.num; ++i) { if(addr_len(&c->connect_addr.addr[i])==len && !memcmp(&c->connect_addr.addr[i], &addr, (size_t)len)) { addr_txt=s_ntop(&addr, len); s_log(LOG_INFO, "persistence: %s reused", addr_txt); str_free(addr_txt); return i; } } addr_txt=s_ntop(&addr, len); s_log(LOG_INFO, "persistence: %s not available", addr_txt); str_free(addr_txt); } else { CRYPTO_r_unlock(stunnel_locks[LOCK_ADDR]); s_log(LOG_NOTICE, "persistence: No cached address found"); } } if(c->opt->failover==FAILOVER_RR) { /* the race condition here can be safely ignored */ i=*c->connect_addr.rr_ptr; *c->connect_addr.rr_ptr=(i+1)%c->connect_addr.num; s_log(LOG_INFO, "failover: round-robin, starting at entry #%d", i); } else { i=0; s_log(LOG_INFO, "failover: priority, starting at entry #0"); } return i; } NOEXPORT void setup_connect_addr(CLI *c) { /* process "redirect" first */ if(c->redirect==REDIRECT_ON) { s_log(LOG_NOTICE, "Redirecting connection"); /* c->connect_addr.addr may be allocated in protocol negotiations */ str_free(c->connect_addr.addr); addrlist_dup(&c->connect_addr, &c->opt->redirect_addr); return; } /* check if the address was already set in protocol negotiations */ /* used by the following protocols: CONNECT, SOCKS */ if(c->connect_addr.num) return; /* transparent destination */ if(c->opt->option.transparent_dst) { c->connect_addr.num=1; c->connect_addr.addr=str_alloc(sizeof(SOCKADDR_UNION)); if(original_dst(c->local_rfd.fd, c->connect_addr.addr)) longjmp(c->err, 1); return; } /* default "connect" target */ addrlist_dup(&c->connect_addr, &c->opt->connect_addr); } NOEXPORT void local_bind(CLI *c) { #if defined(__linux__) || (defined(IP_BINDANY) && defined(IPV6_BINDANY)) int on; on=1; #endif if(!c->bind_addr) return; #if defined(USE_WIN32) /* do nothing */ #elif defined(__linux__) /* non-local bind on Linux */ if(c->opt->option.transparent_src) { if(setsockopt(c->fd, SOL_IP, IP_TRANSPARENT, &on, sizeof on)) { sockerror("setsockopt IP_TRANSPARENT"); if(setsockopt(c->fd, SOL_IP, IP_FREEBIND, &on, sizeof on)) sockerror("setsockopt IP_FREEBIND"); else s_log(LOG_INFO, "IP_FREEBIND socket option set"); } else s_log(LOG_INFO, "IP_TRANSPARENT socket option set"); /* ignore the error to retain Linux 2.2 compatibility */ /* the error will be handled by bind(), anyway */ } #elif defined(IP_BINDANY) && defined(IPV6_BINDANY) /* non-local bind on FreeBSD */ if(c->opt->option.transparent_src) { if(c->bind_addr->sa.sa_family==AF_INET) { /* IPv4 */ if(setsockopt(c->fd, IPPROTO_IP, IP_BINDANY, &on, sizeof on)) { sockerror("setsockopt IP_BINDANY"); longjmp(c->err, 1); } } else { /* IPv6 */ if(setsockopt(c->fd, IPPROTO_IPV6, IPV6_BINDANY, &on, sizeof on)) { sockerror("setsockopt IPV6_BINDANY"); longjmp(c->err, 1); } } } #else /* unsupported platform */ /* FIXME: move this check to options.c */ if(c->opt->option.transparent_src) { s_log(LOG_ERR, "Transparent proxy in remote mode is not supported" " on this platform"); longjmp(c->err, 1); } #endif if(ntohs(c->bind_addr->in.sin_port)>=1024) { /* security check */ /* this is currently only possible with transparent_src */ if(!bind(c->fd, &c->bind_addr->sa, addr_len(c->bind_addr))) { s_log(LOG_INFO, "local_bind succeeded on the original port"); return; /* success */ } if(get_last_socket_error()!=S_EADDRINUSE) { sockerror("local_bind (original port)"); longjmp(c->err, 1); } } c->bind_addr->in.sin_port=htons(0); /* retry with ephemeral port */ if(!bind(c->fd, &c->bind_addr->sa, addr_len(c->bind_addr))) { s_log(LOG_INFO, "local_bind succeeded on an ephemeral port"); return; /* success */ } sockerror("local_bind (ephemeral port)"); longjmp(c->err, 1); } NOEXPORT void print_bound_address(CLI *c) { char *txt; SOCKADDR_UNION addr; socklen_t addrlen=sizeof addr; if(c->opt->log_levelfd, (struct sockaddr *)&addr, &addrlen)) { sockerror("getsockname"); return; } txt=s_ntop(&addr, addrlen); s_log(LOG_NOTICE,"Service [%s] connected remote server from %s", c->opt->servname, txt); str_free(txt); } NOEXPORT void reset(SOCKET fd, char *txt) { /* set lingering on a socket */ struct linger l; l.l_onoff=1; l.l_linger=0; if(setsockopt(fd, SOL_SOCKET, SO_LINGER, (void *)&l, sizeof l)) log_error(LOG_DEBUG, get_last_socket_error(), txt); } /* end of client.c */ stunnel-5.30/src/Makefile.in0000664000175000017500000017572712652373722012744 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # by Michal Trojnara 2015-2016 ############################################################################### # File lists # ############################################################################### VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = stunnel$(EXEEXT) subdir = src DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/config.h.in $(top_srcdir)/auto/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_append_compile_flags.m4 \ $(top_srcdir)/m4/ax_append_flag.m4 \ $(top_srcdir)/m4/ax_append_link_flags.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_check_link_flag.m4 \ $(top_srcdir)/m4/ax_pthread.m4 \ $(top_srcdir)/m4/ax_require_defined.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(bindir)" LTLIBRARIES = $(pkglib_LTLIBRARIES) libstunnel_la_LIBADD = am__objects_1 = env.lo am_libstunnel_la_OBJECTS = $(am__objects_1) libstunnel_la_OBJECTS = $(am_libstunnel_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libstunnel_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libstunnel_la_LDFLAGS) $(LDFLAGS) -o $@ PROGRAMS = $(bin_PROGRAMS) am__objects_2 = am__objects_3 = stunnel-tls.$(OBJEXT) stunnel-str.$(OBJEXT) \ stunnel-file.$(OBJEXT) stunnel-client.$(OBJEXT) \ stunnel-log.$(OBJEXT) stunnel-options.$(OBJEXT) \ stunnel-protocol.$(OBJEXT) stunnel-network.$(OBJEXT) \ stunnel-resolver.$(OBJEXT) stunnel-ssl.$(OBJEXT) \ stunnel-ctx.$(OBJEXT) stunnel-verify.$(OBJEXT) \ stunnel-sthreads.$(OBJEXT) stunnel-fd.$(OBJEXT) \ stunnel-dhparam.$(OBJEXT) stunnel-cron.$(OBJEXT) \ stunnel-stunnel.$(OBJEXT) am__objects_4 = stunnel-pty.$(OBJEXT) stunnel-libwrap.$(OBJEXT) \ stunnel-ui_unix.$(OBJEXT) am_stunnel_OBJECTS = $(am__objects_2) $(am__objects_3) \ $(am__objects_4) stunnel_OBJECTS = $(am_stunnel_OBJECTS) stunnel_LDADD = $(LDADD) stunnel_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(stunnel_LDFLAGS) $(LDFLAGS) -o $@ SCRIPTS = $(bin_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/auto/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libstunnel_la_SOURCES) $(stunnel_SOURCES) DIST_SOURCES = $(libstunnel_la_SOURCES) $(stunnel_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ $(LISP)config.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_GROUP = @DEFAULT_GROUP@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ RANDOM_FILE = @RANDOM_FILE@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SSLDIR = @SSLDIR@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ ax_pthread_config = @ax_pthread_config@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ common_headers = common.h prototypes.h version.h common_sources = tls.c str.c file.c client.c log.c options.c \ protocol.c network.c resolver.c ssl.c ctx.c verify.c \ sthreads.c fd.c dhparam.c cron.c stunnel.c unix_sources = pty.c libwrap.c ui_unix.c shared_sources = env.c win32_gui_sources = ui_win_gui.c resources.h resources.rc stunnel.ico \ active.ico error.ico idle.ico win32_cli_sources = ui_win_cli.c stunnel_SOURCES = $(common_headers) $(common_sources) $(unix_sources) bin_SCRIPTS = stunnel3 # Remaining files to be included EXTRA_DIST = stunnel3.in $(win32_gui_sources) $(win32_cli_sources) \ make.bat makece.bat makew32.bat mingw.mk mingw.mak evc.mak \ vc.mak os2.mak CLEANFILES = stunnel3 # Red Hat "by design" bug #82369 # Additional preprocesor definitions stunnel_CPPFLAGS = -I/usr/kerberos/include -I$(SSLDIR)/include \ -DLIBDIR='"$(pkglibdir)"' -DCONFDIR='"$(sysconfdir)/stunnel"' # SSL library stunnel_LDFLAGS = -L$(SSLDIR)/lib64 -L$(SSLDIR)/lib -lssl -lcrypto # stunnel3 script edit = sed \ -e 's|@bindir[@]|$(bindir)|g' # Unix shared library pkglib_LTLIBRARIES = libstunnel.la libstunnel_la_SOURCES = $(shared_sources) libstunnel_la_LDFLAGS = -avoid-version all: config.h $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): config.h: stamp-h1 @test -f $@ || rm -f stamp-h1 @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status src/config.h $(srcdir)/config.h.in: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \ } uninstall-pkglibLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \ done clean-pkglibLTLIBRARIES: -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES) @list='$(pkglib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libstunnel.la: $(libstunnel_la_OBJECTS) $(libstunnel_la_DEPENDENCIES) $(EXTRA_libstunnel_la_DEPENDENCIES) $(AM_V_CCLD)$(libstunnel_la_LINK) -rpath $(pkglibdir) $(libstunnel_la_OBJECTS) $(libstunnel_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list stunnel$(EXEEXT): $(stunnel_OBJECTS) $(stunnel_DEPENDENCIES) $(EXTRA_stunnel_DEPENDENCIES) @rm -f stunnel$(EXEEXT) $(AM_V_CCLD)$(stunnel_LINK) $(stunnel_OBJECTS) $(stunnel_LDADD) $(LIBS) install-binSCRIPTS: $(bin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/env.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-cron.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-ctx.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-dhparam.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-fd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-file.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-libwrap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-log.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-network.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-options.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-protocol.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-pty.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-resolver.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-ssl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-sthreads.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-str.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-stunnel.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-tls.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-ui_unix.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-verify.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< stunnel-tls.o: tls.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-tls.o -MD -MP -MF $(DEPDIR)/stunnel-tls.Tpo -c -o stunnel-tls.o `test -f 'tls.c' || echo '$(srcdir)/'`tls.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-tls.Tpo $(DEPDIR)/stunnel-tls.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tls.c' object='stunnel-tls.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-tls.o `test -f 'tls.c' || echo '$(srcdir)/'`tls.c stunnel-tls.obj: tls.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-tls.obj -MD -MP -MF $(DEPDIR)/stunnel-tls.Tpo -c -o stunnel-tls.obj `if test -f 'tls.c'; then $(CYGPATH_W) 'tls.c'; else $(CYGPATH_W) '$(srcdir)/tls.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-tls.Tpo $(DEPDIR)/stunnel-tls.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tls.c' object='stunnel-tls.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-tls.obj `if test -f 'tls.c'; then $(CYGPATH_W) 'tls.c'; else $(CYGPATH_W) '$(srcdir)/tls.c'; fi` stunnel-str.o: str.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-str.o -MD -MP -MF $(DEPDIR)/stunnel-str.Tpo -c -o stunnel-str.o `test -f 'str.c' || echo '$(srcdir)/'`str.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-str.Tpo $(DEPDIR)/stunnel-str.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='str.c' object='stunnel-str.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-str.o `test -f 'str.c' || echo '$(srcdir)/'`str.c stunnel-str.obj: str.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-str.obj -MD -MP -MF $(DEPDIR)/stunnel-str.Tpo -c -o stunnel-str.obj `if test -f 'str.c'; then $(CYGPATH_W) 'str.c'; else $(CYGPATH_W) '$(srcdir)/str.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-str.Tpo $(DEPDIR)/stunnel-str.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='str.c' object='stunnel-str.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-str.obj `if test -f 'str.c'; then $(CYGPATH_W) 'str.c'; else $(CYGPATH_W) '$(srcdir)/str.c'; fi` stunnel-file.o: file.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-file.o -MD -MP -MF $(DEPDIR)/stunnel-file.Tpo -c -o stunnel-file.o `test -f 'file.c' || echo '$(srcdir)/'`file.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-file.Tpo $(DEPDIR)/stunnel-file.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='file.c' object='stunnel-file.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-file.o `test -f 'file.c' || echo '$(srcdir)/'`file.c stunnel-file.obj: file.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-file.obj -MD -MP -MF $(DEPDIR)/stunnel-file.Tpo -c -o stunnel-file.obj `if test -f 'file.c'; then $(CYGPATH_W) 'file.c'; else $(CYGPATH_W) '$(srcdir)/file.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-file.Tpo $(DEPDIR)/stunnel-file.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='file.c' object='stunnel-file.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-file.obj `if test -f 'file.c'; then $(CYGPATH_W) 'file.c'; else $(CYGPATH_W) '$(srcdir)/file.c'; fi` stunnel-client.o: client.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-client.o -MD -MP -MF $(DEPDIR)/stunnel-client.Tpo -c -o stunnel-client.o `test -f 'client.c' || echo '$(srcdir)/'`client.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-client.Tpo $(DEPDIR)/stunnel-client.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='client.c' object='stunnel-client.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-client.o `test -f 'client.c' || echo '$(srcdir)/'`client.c stunnel-client.obj: client.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-client.obj -MD -MP -MF $(DEPDIR)/stunnel-client.Tpo -c -o stunnel-client.obj `if test -f 'client.c'; then $(CYGPATH_W) 'client.c'; else $(CYGPATH_W) '$(srcdir)/client.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-client.Tpo $(DEPDIR)/stunnel-client.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='client.c' object='stunnel-client.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-client.obj `if test -f 'client.c'; then $(CYGPATH_W) 'client.c'; else $(CYGPATH_W) '$(srcdir)/client.c'; fi` stunnel-log.o: log.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-log.o -MD -MP -MF $(DEPDIR)/stunnel-log.Tpo -c -o stunnel-log.o `test -f 'log.c' || echo '$(srcdir)/'`log.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-log.Tpo $(DEPDIR)/stunnel-log.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='log.c' object='stunnel-log.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-log.o `test -f 'log.c' || echo '$(srcdir)/'`log.c stunnel-log.obj: log.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-log.obj -MD -MP -MF $(DEPDIR)/stunnel-log.Tpo -c -o stunnel-log.obj `if test -f 'log.c'; then $(CYGPATH_W) 'log.c'; else $(CYGPATH_W) '$(srcdir)/log.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-log.Tpo $(DEPDIR)/stunnel-log.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='log.c' object='stunnel-log.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-log.obj `if test -f 'log.c'; then $(CYGPATH_W) 'log.c'; else $(CYGPATH_W) '$(srcdir)/log.c'; fi` stunnel-options.o: options.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-options.o -MD -MP -MF $(DEPDIR)/stunnel-options.Tpo -c -o stunnel-options.o `test -f 'options.c' || echo '$(srcdir)/'`options.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-options.Tpo $(DEPDIR)/stunnel-options.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='options.c' object='stunnel-options.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-options.o `test -f 'options.c' || echo '$(srcdir)/'`options.c stunnel-options.obj: options.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-options.obj -MD -MP -MF $(DEPDIR)/stunnel-options.Tpo -c -o stunnel-options.obj `if test -f 'options.c'; then $(CYGPATH_W) 'options.c'; else $(CYGPATH_W) '$(srcdir)/options.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-options.Tpo $(DEPDIR)/stunnel-options.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='options.c' object='stunnel-options.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-options.obj `if test -f 'options.c'; then $(CYGPATH_W) 'options.c'; else $(CYGPATH_W) '$(srcdir)/options.c'; fi` stunnel-protocol.o: protocol.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-protocol.o -MD -MP -MF $(DEPDIR)/stunnel-protocol.Tpo -c -o stunnel-protocol.o `test -f 'protocol.c' || echo '$(srcdir)/'`protocol.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-protocol.Tpo $(DEPDIR)/stunnel-protocol.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='protocol.c' object='stunnel-protocol.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-protocol.o `test -f 'protocol.c' || echo '$(srcdir)/'`protocol.c stunnel-protocol.obj: protocol.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-protocol.obj -MD -MP -MF $(DEPDIR)/stunnel-protocol.Tpo -c -o stunnel-protocol.obj `if test -f 'protocol.c'; then $(CYGPATH_W) 'protocol.c'; else $(CYGPATH_W) '$(srcdir)/protocol.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-protocol.Tpo $(DEPDIR)/stunnel-protocol.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='protocol.c' object='stunnel-protocol.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-protocol.obj `if test -f 'protocol.c'; then $(CYGPATH_W) 'protocol.c'; else $(CYGPATH_W) '$(srcdir)/protocol.c'; fi` stunnel-network.o: network.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-network.o -MD -MP -MF $(DEPDIR)/stunnel-network.Tpo -c -o stunnel-network.o `test -f 'network.c' || echo '$(srcdir)/'`network.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-network.Tpo $(DEPDIR)/stunnel-network.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network.c' object='stunnel-network.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-network.o `test -f 'network.c' || echo '$(srcdir)/'`network.c stunnel-network.obj: network.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-network.obj -MD -MP -MF $(DEPDIR)/stunnel-network.Tpo -c -o stunnel-network.obj `if test -f 'network.c'; then $(CYGPATH_W) 'network.c'; else $(CYGPATH_W) '$(srcdir)/network.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-network.Tpo $(DEPDIR)/stunnel-network.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network.c' object='stunnel-network.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-network.obj `if test -f 'network.c'; then $(CYGPATH_W) 'network.c'; else $(CYGPATH_W) '$(srcdir)/network.c'; fi` stunnel-resolver.o: resolver.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-resolver.o -MD -MP -MF $(DEPDIR)/stunnel-resolver.Tpo -c -o stunnel-resolver.o `test -f 'resolver.c' || echo '$(srcdir)/'`resolver.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-resolver.Tpo $(DEPDIR)/stunnel-resolver.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='resolver.c' object='stunnel-resolver.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-resolver.o `test -f 'resolver.c' || echo '$(srcdir)/'`resolver.c stunnel-resolver.obj: resolver.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-resolver.obj -MD -MP -MF $(DEPDIR)/stunnel-resolver.Tpo -c -o stunnel-resolver.obj `if test -f 'resolver.c'; then $(CYGPATH_W) 'resolver.c'; else $(CYGPATH_W) '$(srcdir)/resolver.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-resolver.Tpo $(DEPDIR)/stunnel-resolver.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='resolver.c' object='stunnel-resolver.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-resolver.obj `if test -f 'resolver.c'; then $(CYGPATH_W) 'resolver.c'; else $(CYGPATH_W) '$(srcdir)/resolver.c'; fi` stunnel-ssl.o: ssl.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-ssl.o -MD -MP -MF $(DEPDIR)/stunnel-ssl.Tpo -c -o stunnel-ssl.o `test -f 'ssl.c' || echo '$(srcdir)/'`ssl.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-ssl.Tpo $(DEPDIR)/stunnel-ssl.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ssl.c' object='stunnel-ssl.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-ssl.o `test -f 'ssl.c' || echo '$(srcdir)/'`ssl.c stunnel-ssl.obj: ssl.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-ssl.obj -MD -MP -MF $(DEPDIR)/stunnel-ssl.Tpo -c -o stunnel-ssl.obj `if test -f 'ssl.c'; then $(CYGPATH_W) 'ssl.c'; else $(CYGPATH_W) '$(srcdir)/ssl.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-ssl.Tpo $(DEPDIR)/stunnel-ssl.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ssl.c' object='stunnel-ssl.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-ssl.obj `if test -f 'ssl.c'; then $(CYGPATH_W) 'ssl.c'; else $(CYGPATH_W) '$(srcdir)/ssl.c'; fi` stunnel-ctx.o: ctx.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-ctx.o -MD -MP -MF $(DEPDIR)/stunnel-ctx.Tpo -c -o stunnel-ctx.o `test -f 'ctx.c' || echo '$(srcdir)/'`ctx.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-ctx.Tpo $(DEPDIR)/stunnel-ctx.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ctx.c' object='stunnel-ctx.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-ctx.o `test -f 'ctx.c' || echo '$(srcdir)/'`ctx.c stunnel-ctx.obj: ctx.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-ctx.obj -MD -MP -MF $(DEPDIR)/stunnel-ctx.Tpo -c -o stunnel-ctx.obj `if test -f 'ctx.c'; then $(CYGPATH_W) 'ctx.c'; else $(CYGPATH_W) '$(srcdir)/ctx.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-ctx.Tpo $(DEPDIR)/stunnel-ctx.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ctx.c' object='stunnel-ctx.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-ctx.obj `if test -f 'ctx.c'; then $(CYGPATH_W) 'ctx.c'; else $(CYGPATH_W) '$(srcdir)/ctx.c'; fi` stunnel-verify.o: verify.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-verify.o -MD -MP -MF $(DEPDIR)/stunnel-verify.Tpo -c -o stunnel-verify.o `test -f 'verify.c' || echo '$(srcdir)/'`verify.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-verify.Tpo $(DEPDIR)/stunnel-verify.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='verify.c' object='stunnel-verify.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-verify.o `test -f 'verify.c' || echo '$(srcdir)/'`verify.c stunnel-verify.obj: verify.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-verify.obj -MD -MP -MF $(DEPDIR)/stunnel-verify.Tpo -c -o stunnel-verify.obj `if test -f 'verify.c'; then $(CYGPATH_W) 'verify.c'; else $(CYGPATH_W) '$(srcdir)/verify.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-verify.Tpo $(DEPDIR)/stunnel-verify.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='verify.c' object='stunnel-verify.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-verify.obj `if test -f 'verify.c'; then $(CYGPATH_W) 'verify.c'; else $(CYGPATH_W) '$(srcdir)/verify.c'; fi` stunnel-sthreads.o: sthreads.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-sthreads.o -MD -MP -MF $(DEPDIR)/stunnel-sthreads.Tpo -c -o stunnel-sthreads.o `test -f 'sthreads.c' || echo '$(srcdir)/'`sthreads.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-sthreads.Tpo $(DEPDIR)/stunnel-sthreads.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sthreads.c' object='stunnel-sthreads.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-sthreads.o `test -f 'sthreads.c' || echo '$(srcdir)/'`sthreads.c stunnel-sthreads.obj: sthreads.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-sthreads.obj -MD -MP -MF $(DEPDIR)/stunnel-sthreads.Tpo -c -o stunnel-sthreads.obj `if test -f 'sthreads.c'; then $(CYGPATH_W) 'sthreads.c'; else $(CYGPATH_W) '$(srcdir)/sthreads.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-sthreads.Tpo $(DEPDIR)/stunnel-sthreads.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sthreads.c' object='stunnel-sthreads.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-sthreads.obj `if test -f 'sthreads.c'; then $(CYGPATH_W) 'sthreads.c'; else $(CYGPATH_W) '$(srcdir)/sthreads.c'; fi` stunnel-fd.o: fd.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-fd.o -MD -MP -MF $(DEPDIR)/stunnel-fd.Tpo -c -o stunnel-fd.o `test -f 'fd.c' || echo '$(srcdir)/'`fd.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-fd.Tpo $(DEPDIR)/stunnel-fd.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fd.c' object='stunnel-fd.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-fd.o `test -f 'fd.c' || echo '$(srcdir)/'`fd.c stunnel-fd.obj: fd.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-fd.obj -MD -MP -MF $(DEPDIR)/stunnel-fd.Tpo -c -o stunnel-fd.obj `if test -f 'fd.c'; then $(CYGPATH_W) 'fd.c'; else $(CYGPATH_W) '$(srcdir)/fd.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-fd.Tpo $(DEPDIR)/stunnel-fd.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fd.c' object='stunnel-fd.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-fd.obj `if test -f 'fd.c'; then $(CYGPATH_W) 'fd.c'; else $(CYGPATH_W) '$(srcdir)/fd.c'; fi` stunnel-dhparam.o: dhparam.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-dhparam.o -MD -MP -MF $(DEPDIR)/stunnel-dhparam.Tpo -c -o stunnel-dhparam.o `test -f 'dhparam.c' || echo '$(srcdir)/'`dhparam.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-dhparam.Tpo $(DEPDIR)/stunnel-dhparam.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhparam.c' object='stunnel-dhparam.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-dhparam.o `test -f 'dhparam.c' || echo '$(srcdir)/'`dhparam.c stunnel-dhparam.obj: dhparam.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-dhparam.obj -MD -MP -MF $(DEPDIR)/stunnel-dhparam.Tpo -c -o stunnel-dhparam.obj `if test -f 'dhparam.c'; then $(CYGPATH_W) 'dhparam.c'; else $(CYGPATH_W) '$(srcdir)/dhparam.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-dhparam.Tpo $(DEPDIR)/stunnel-dhparam.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhparam.c' object='stunnel-dhparam.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-dhparam.obj `if test -f 'dhparam.c'; then $(CYGPATH_W) 'dhparam.c'; else $(CYGPATH_W) '$(srcdir)/dhparam.c'; fi` stunnel-cron.o: cron.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-cron.o -MD -MP -MF $(DEPDIR)/stunnel-cron.Tpo -c -o stunnel-cron.o `test -f 'cron.c' || echo '$(srcdir)/'`cron.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-cron.Tpo $(DEPDIR)/stunnel-cron.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cron.c' object='stunnel-cron.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-cron.o `test -f 'cron.c' || echo '$(srcdir)/'`cron.c stunnel-cron.obj: cron.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-cron.obj -MD -MP -MF $(DEPDIR)/stunnel-cron.Tpo -c -o stunnel-cron.obj `if test -f 'cron.c'; then $(CYGPATH_W) 'cron.c'; else $(CYGPATH_W) '$(srcdir)/cron.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-cron.Tpo $(DEPDIR)/stunnel-cron.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cron.c' object='stunnel-cron.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-cron.obj `if test -f 'cron.c'; then $(CYGPATH_W) 'cron.c'; else $(CYGPATH_W) '$(srcdir)/cron.c'; fi` stunnel-stunnel.o: stunnel.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-stunnel.o -MD -MP -MF $(DEPDIR)/stunnel-stunnel.Tpo -c -o stunnel-stunnel.o `test -f 'stunnel.c' || echo '$(srcdir)/'`stunnel.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-stunnel.Tpo $(DEPDIR)/stunnel-stunnel.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='stunnel.c' object='stunnel-stunnel.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-stunnel.o `test -f 'stunnel.c' || echo '$(srcdir)/'`stunnel.c stunnel-stunnel.obj: stunnel.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-stunnel.obj -MD -MP -MF $(DEPDIR)/stunnel-stunnel.Tpo -c -o stunnel-stunnel.obj `if test -f 'stunnel.c'; then $(CYGPATH_W) 'stunnel.c'; else $(CYGPATH_W) '$(srcdir)/stunnel.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-stunnel.Tpo $(DEPDIR)/stunnel-stunnel.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='stunnel.c' object='stunnel-stunnel.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-stunnel.obj `if test -f 'stunnel.c'; then $(CYGPATH_W) 'stunnel.c'; else $(CYGPATH_W) '$(srcdir)/stunnel.c'; fi` stunnel-pty.o: pty.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-pty.o -MD -MP -MF $(DEPDIR)/stunnel-pty.Tpo -c -o stunnel-pty.o `test -f 'pty.c' || echo '$(srcdir)/'`pty.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-pty.Tpo $(DEPDIR)/stunnel-pty.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pty.c' object='stunnel-pty.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-pty.o `test -f 'pty.c' || echo '$(srcdir)/'`pty.c stunnel-pty.obj: pty.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-pty.obj -MD -MP -MF $(DEPDIR)/stunnel-pty.Tpo -c -o stunnel-pty.obj `if test -f 'pty.c'; then $(CYGPATH_W) 'pty.c'; else $(CYGPATH_W) '$(srcdir)/pty.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-pty.Tpo $(DEPDIR)/stunnel-pty.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pty.c' object='stunnel-pty.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-pty.obj `if test -f 'pty.c'; then $(CYGPATH_W) 'pty.c'; else $(CYGPATH_W) '$(srcdir)/pty.c'; fi` stunnel-libwrap.o: libwrap.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-libwrap.o -MD -MP -MF $(DEPDIR)/stunnel-libwrap.Tpo -c -o stunnel-libwrap.o `test -f 'libwrap.c' || echo '$(srcdir)/'`libwrap.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-libwrap.Tpo $(DEPDIR)/stunnel-libwrap.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libwrap.c' object='stunnel-libwrap.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-libwrap.o `test -f 'libwrap.c' || echo '$(srcdir)/'`libwrap.c stunnel-libwrap.obj: libwrap.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-libwrap.obj -MD -MP -MF $(DEPDIR)/stunnel-libwrap.Tpo -c -o stunnel-libwrap.obj `if test -f 'libwrap.c'; then $(CYGPATH_W) 'libwrap.c'; else $(CYGPATH_W) '$(srcdir)/libwrap.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-libwrap.Tpo $(DEPDIR)/stunnel-libwrap.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libwrap.c' object='stunnel-libwrap.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-libwrap.obj `if test -f 'libwrap.c'; then $(CYGPATH_W) 'libwrap.c'; else $(CYGPATH_W) '$(srcdir)/libwrap.c'; fi` stunnel-ui_unix.o: ui_unix.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-ui_unix.o -MD -MP -MF $(DEPDIR)/stunnel-ui_unix.Tpo -c -o stunnel-ui_unix.o `test -f 'ui_unix.c' || echo '$(srcdir)/'`ui_unix.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-ui_unix.Tpo $(DEPDIR)/stunnel-ui_unix.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ui_unix.c' object='stunnel-ui_unix.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-ui_unix.o `test -f 'ui_unix.c' || echo '$(srcdir)/'`ui_unix.c stunnel-ui_unix.obj: ui_unix.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-ui_unix.obj -MD -MP -MF $(DEPDIR)/stunnel-ui_unix.Tpo -c -o stunnel-ui_unix.obj `if test -f 'ui_unix.c'; then $(CYGPATH_W) 'ui_unix.c'; else $(CYGPATH_W) '$(srcdir)/ui_unix.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-ui_unix.Tpo $(DEPDIR)/stunnel-ui_unix.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ui_unix.c' object='stunnel-ui_unix.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-ui_unix.obj `if test -f 'ui_unix.c'; then $(CYGPATH_W) 'ui_unix.c'; else $(CYGPATH_W) '$(srcdir)/ui_unix.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @AUTHOR_TESTS_FALSE@check-local: check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-local check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(SCRIPTS) config.h installdirs: for dir in "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool clean-local \ clean-pkglibLTLIBRARIES mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-binSCRIPTS \ install-pkglibLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \ uninstall-pkglibLTLIBRARIES .MAKE: all check-am install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am check-local clean \ clean-binPROGRAMS clean-generic clean-libtool clean-local \ clean-pkglibLTLIBRARIES cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-hdr \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-binSCRIPTS install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-pkglibLTLIBRARIES \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-binSCRIPTS uninstall-pkglibLTLIBRARIES ############################################################################### # Generate a new set of DH parameters for each version # ############################################################################### dhparam.c: version.h echo '#include "common.h"' >dhparam.c echo '#ifndef OPENSSL_NO_DH' >>dhparam.c echo '#define DN_new DH_new' >>dhparam.c openssl dhparam -noout -C 2048 >>dhparam.c echo '#endif /* OPENSSL_NO_DH */' >>dhparam.c stunnel3: Makefile $(edit) '$(srcdir)/$@.in' >$@ stunnel3: $(srcdir)/stunnel3.in ############################################################################### # Win32 executables # ############################################################################### # Just check if the programs can be built, don't perform any actual tests @AUTHOR_TESTS_TRUE@check-local: mingw mingw64 mingw: $(MAKE) -f $(srcdir)/mingw.mk srcdir=$(srcdir) win32_targetcpu=i686 win32_mingw=mingw mingw64: $(MAKE) -f $(srcdir)/mingw.mk srcdir=$(srcdir) win32_targetcpu=x86_64 win32_mingw=mingw64 .PHONY: mingw mingw64 clean-local: rm -rf ../obj ../bin # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: stunnel-5.30/src/ssl.c0000664000175000017500000002230612652373710011621 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2016 Michal Trojnara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see . * * Linking stunnel statically or dynamically with other modules is making * a combined work based on stunnel. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holder of stunnel * gives you permission to combine stunnel with free software programs or * libraries that are released under the GNU LGPL and with code included * in the standard release of OpenSSL under the OpenSSL License (or * modified versions of such code, with unchanged license). You may copy * and distribute such a system following the terms of the GNU GPL for * stunnel and the licenses of the other code concerned. * * Note that people who make modified versions of stunnel are not obligated * to grant this special exception for their modified versions; it is their * choice whether to do so. The GNU General Public License gives permission * to release a modified version without this exception; this exception * also makes it possible to release a modified version which carries * forward this exception. */ #include "common.h" #include "prototypes.h" /* global OpenSSL initialization: compression, engine, entropy */ NOEXPORT void cb_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp); #ifndef OPENSSL_NO_COMP NOEXPORT int compression_init(GLOBAL_OPTIONS *); #endif NOEXPORT int prng_init(GLOBAL_OPTIONS *); NOEXPORT int add_rand_file(GLOBAL_OPTIONS *, const char *); int index_cli, index_opt, index_redirect, index_addr; int ssl_init(void) { /* init SSL before parsing configuration file */ SSL_load_error_strings(); SSL_library_init(); index_cli=SSL_get_ex_new_index(0, "cli index", NULL, NULL, NULL); index_opt=SSL_CTX_get_ex_new_index(0, "opt index", NULL, NULL, NULL); index_redirect=SSL_SESSION_get_ex_new_index(0, "redirect index", NULL, NULL, NULL); index_addr=SSL_SESSION_get_ex_new_index(0, "addr index", NULL, NULL, cb_free); if(index_cli<0 || index_opt<0 || index_redirect<0 || index_addr<0) { s_log(LOG_ERR, "Application specific data initialization failed"); return 1; } #ifndef OPENSSL_NO_ENGINE ENGINE_load_builtin_engines(); #endif #ifndef OPENSSL_NO_DH dh_params=get_dh2048(); if(!dh_params) { s_log(LOG_ERR, "Failed to get default DH parameters"); return 1; } #endif /* OPENSSL_NO_DH */ return 0; } NOEXPORT void cb_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp) { (void)parent; /* squash the unused parameter warning */ (void)ad; /* squash the unused parameter warning */ (void)idx; /* squash the unused parameter warning */ (void)argl; /* squash the unused parameter warning */ s_log(LOG_DEBUG, "Deallocating application specific data for %s", (char *)argp); str_free(ptr); } int ssl_configure(GLOBAL_OPTIONS *global) { /* configure global SSL settings */ #ifdef USE_FIPS if(FIPS_mode()!=global->option.fips) { RAND_set_rand_method(NULL); /* reset RAND methods */ if(!FIPS_mode_set(global->option.fips)) { ERR_load_crypto_strings(); sslerror("FIPS_mode_set"); return 1; } } s_log(LOG_NOTICE, "FIPS mode %s", global->option.fips ? "enabled" : "disabled"); #endif /* USE_FIPS */ #ifndef OPENSSL_NO_COMP if(compression_init(global)) return 1; #endif /* OPENSSL_NO_COMP */ if(prng_init(global)) return 1; s_log(LOG_DEBUG, "PRNG seeded successfully"); return 0; /* SUCCESS */ } #ifndef OPENSSL_NO_COMP NOEXPORT int compression_init(GLOBAL_OPTIONS *global) { STACK_OF(SSL_COMP) *methods; methods=SSL_COMP_get_compression_methods(); if(!methods) { if(global->compression==COMP_NONE) { s_log(LOG_NOTICE, "Failed to get compression methods"); return 0; /* ignore */ } else { s_log(LOG_ERR, "Failed to get compression methods"); return 1; } } if(global->compression==COMP_NONE || OpenSSL_version_num()<0x00908051L /* 0.9.8e-beta1 */) { /* delete OpenSSL defaults (empty the SSL_COMP stack) */ /* cannot use sk_SSL_COMP_pop_free, * as it also destroys the stack itself */ /* only leave the standard RFC 1951 (DEFLATE) algorithm, * if any of the private algorithms is enabled */ /* only allow DEFLATE with OpenSSL 0.9.8 or later * with OpenSSL #1468 zlib memory leak fixed */ while(sk_SSL_COMP_num(methods)) #if OPENSSL_VERSION_NUMBER>=0x10100000L /* FIXME: remove when sk_SSL_COMP_pop() works again */ OPENSSL_free(sk_pop((void *)methods)); #else OPENSSL_free(sk_SSL_COMP_pop(methods)); #endif } if(global->compression==COMP_NONE) { s_log(LOG_DEBUG, "Compression disabled"); return 0; /* success */ } /* also insert the obsolete ZLIB algorithm */ if(global->compression==COMP_ZLIB) { /* 224 - within the private range (193 to 255) */ COMP_METHOD *meth=COMP_zlib(); #if OPENSSL_VERSION_NUMBER>=0x10100000L if(!meth || COMP_get_type(meth)==NID_undef) { #else if(!meth || meth->type==NID_undef) { #endif s_log(LOG_ERR, "ZLIB compression is not supported"); return 1; } SSL_COMP_add_compression_method(0xe0, meth); } s_log(LOG_INFO, "Compression enabled: %d method(s)", sk_SSL_COMP_num(methods)); return 0; /* success */ } #endif /* OPENSSL_NO_COMP */ NOEXPORT int prng_init(GLOBAL_OPTIONS *global) { int totbytes=0; char filename[256]; filename[0]='\0'; /* if they specify a rand file on the command line we assume that they really do want it, so try it first */ if(global->rand_file) { totbytes+=add_rand_file(global, global->rand_file); if(RAND_status()) return 0; /* success */ } /* try the $RANDFILE or $HOME/.rnd files */ RAND_file_name(filename, 256); if(filename[0]) { totbytes+=add_rand_file(global, filename); if(RAND_status()) return 0; /* success */ } #ifdef RANDOM_FILE totbytes+=add_rand_file(global, RANDOM_FILE); if(RAND_status()) return 0; /* success */ #endif #ifdef USE_WIN32 RAND_screen(); if(RAND_status()) { s_log(LOG_DEBUG, "Seeded PRNG with RAND_screen"); return 0; /* success */ } s_log(LOG_DEBUG, "RAND_screen failed to sufficiently seed PRNG"); #else #ifndef OPENSSL_NO_EGD if(global->egd_sock) { int bytes=RAND_egd(global->egd_sock); if(bytes==-1) { s_log(LOG_WARNING, "EGD Socket %s failed", global->egd_sock); bytes=0; } else { totbytes+=bytes; s_log(LOG_DEBUG, "Snagged %d random bytes from EGD Socket %s", bytes, global->egd_sock); return 0; /* OpenSSL always gets what it needs or fails, so no need to check if seeded sufficiently */ } } #endif /* try the good-old default /dev/urandom, if available */ totbytes+=add_rand_file(global, "/dev/urandom"); if(RAND_status()) return 0; /* success */ #endif /* USE_WIN32 */ /* random file specified during configure */ s_log(LOG_ERR, "PRNG seeded with %d bytes total", totbytes); s_log(LOG_ERR, "PRNG was not seeded with enough random bytes"); return 1; /* FAILED */ } NOEXPORT int add_rand_file(GLOBAL_OPTIONS *global, const char *filename) { int readbytes; int writebytes; struct stat sb; if(stat(filename, &sb)) return 0; /* could not stat() file --> return 0 bytes */ if((readbytes=RAND_load_file(filename, global->random_bytes))) s_log(LOG_DEBUG, "Snagged %d random bytes from %s", readbytes, filename); else s_log(LOG_INFO, "Cannot retrieve any random data from %s", filename); /* write new random data for future seeding if it's a regular file */ if(global->option.rand_write && S_ISREG(sb.st_mode)) { writebytes=RAND_write_file(filename); if(writebytes==-1) s_log(LOG_WARNING, "Failed to write strong random data to %s - " "may be a permissions or seeding problem", filename); else s_log(LOG_DEBUG, "Wrote %d new random bytes to %s", writebytes, filename); } return readbytes; } /* end of ssl.c */ stunnel-5.30/ChangeLog0000664000175000017500000023051512652434512011640 00000000000000stunnel change log Version 5.30, 2016.01.28, urgency: HIGH * Security bugfixes - OpenSSL DLLs updated to version 1.0.2f. https://www.openssl.org/news/secadv_20160128.txt * New features - Improved compatibility with the current OpenSSL 1.1.0-dev tree. - Added OpenSSL autodetection for the recent versions of Xcode. * Bugfixes - Fixed references to /etc removed from stunnel.init.in. - Stopped even trying -fstack-protector on unsupported platforms (thx to Rob Lockhart). Version 5.29, 2016.01.08, urgency: LOW * New features - New WIN32 icons. - Performance improvement: rwlocks used for locking with pthreads. * Bugfixes - Compilation fix for *BSD. - Fixed configuration file reload for relative stunnel.conf path on Unix. - Fixed ignoring CRLfile unless CAfile was also specified (thx to Strukov Petr). Version 5.28, 2015.12.11, urgency: HIGH * New features - Build matrix (.travis.yml) extended with ./configure options. - mingw.mak updated to build tstunnel.exe (thx to Jose Alf.). * Bugfixes - Fixed incomplete initialization. - Fixed UCONTEXT threading on OSX. - Fixed exit codes for information requests (as in "stunnel -version" or "stunnel -help"). Version 5.27, 2015.12.03, urgency: MEDIUM * Security bugfixes - OpenSSL DLLs updated to version 1.0.2e. https://www.openssl.org/news/secadv_20151203.txt * New features - Automated build testing configured with .travis.yml. - Added reading server certificates from hardware engines. For example: cert = id_45 - Only attempt to use potentially harmful compiler or linker options if gcc was detected. - /opt/csw added to the OpenSSL directory lookup list. - mingw.mak updates (thx to Jose Alf.). - TODO list updated. Version 5.26, 2015.11.06, urgency: MEDIUM * Bugfixes - Compilation fixes for OSX, *BSD and Solaris. Version 5.25, 2015.11.02, urgency: MEDIUM * New features - SMTP client protocol negotiation support for "protocolUsername", "protocolPassword", and "protocolAuthentication" (thx to Douglas Harris). - New service-level option "config" to specify configuration commands introduced in OpenSSL 1.0.2 (thx to Stephen Wall). - The global option "foreground" now also accepts "quiet" parameter, which does not enable logging to stderr. - Manual page updated. - Obsolete OpenSSL engines removed from the Windows build: 4758cca, aep, atalla, cswift, nuron, sureware. - Improved compatibility with the current OpenSSL 1.1.0-dev tree: gracefully handle symbols renamed from SSLeay* to OpenSSL*. * Bugfixes - Fixed the "s_poll_wait returned 1, but no descriptor is ready" internal error. - Fixed "exec" hangs due to incorrect thread-local storage handling (thx to Philip Craig). - Fixed PRNG initialization (thx to Philip Craig). - Setting socket options no longer performed on PTYs. - Fixed 64-bit Windows build. Version 5.24, 2015.10.08, urgency: MEDIUM * New features - Custom CRL verification was replaced with the internal OpenSSL functionality. - *BSD support for "transparent = destination" and client-side "protocol = socks". This feature should work at least on FreeBSD, OpenBSD and OS X. - Added a new "protocolDomain" option for the NTLM authentication (thx to Andreas Botsikas). - Improved compatibility of the NTLM phase 1 message (thx to Andreas Botsikas). - "setuid" and "setgid" options are now also available in service sections. They can be used to set owner and group of the Unix socket specified with "accept". - Added support for the new OpenSSL 1.0.2 SSL options. - Added OPENSSL_NO_EGD support (thx to Bernard Spil). - VC autodetection added to makew32.bat (thx to Andreas Botsikas). * Bugfixes - Fixed the RESOLVE [F0] TOR extension support in SOCKS5. - Fixed the error code reported on the failed bind() requests. - Fixed the sequential log id with the FORK threading. - Restored the missing Microsoft.VC90.CRT.manifest file. Version 5.23, 2015.09.02, urgency: LOW * New features - Client-side support for the SOCKS protocol. See https://www.stunnel.org/socksvpn.html for details. - Reject SOCKS requests to connect loopback addresses. - New service-level option "OCSPnonce". The default value is "OCSPnonce = no". - Win32 directory structure rearranged. The installer script provides automatic migration for common setups. - Added Win32 installer option to install stunnel for the current user only. This feature does not deploy the NT service, but it also does not require aministrative privileges to install and configure stunnel. - stunnel.cnf was renamed to openssl.cnf in order to to prevent users from mixing it up with stunnel.conf. - Win32 desktop is automatically refreshed when the icon is created or removed. - The ca-certs.pem file is now updated on stunnel upgrade. - Inactive ports were removed from the PORTS file. - Added IPv6 support to the transparent proxy code. * Bugfixes - Compilation fix for OpenSSL version older than 1.0.0. - Compilation fix for mingw. Version 5.22, 2015.07.30, urgency: HIGH * New features - "OCSPaia = yes" added to the configuration file templates. - Improved double free detection. * Bugfixes - Fixed a number of OCSP bugs. The most severe of those bugs caused stunnel to treat OCSP responses that failed OCSP_basic_verify() checks as if they were successful. - Fixed the passive IPv6 resolver (broken in stunnel 5.21). Version 5.21, 2015.07.27, urgency: MEDIUM * New features - Signal names are displayed instead of numbers. - First resolve IPv4 addresses on passive resolver requests. This speeds up stunnel startup on Win32 with a slow/defunct DNS service. - The "make check" target was modified to only build Win32 executables when stunnel is built from a git repository (thx to Peter Pentchev). - More elaborate descriptions were added to the warning about using "verify = 2" without "checkHost" or "checkIP". - Performance optimization was performed on the debug code. * Bugfixes - Fixed the FORK and UCONTEXT threading support. - Fixed "failover=prio" (broken since stunnel 5.15). - Added a retry when sleep(3) was interrupted by a signal in the cron thread scheduler. Version 5.20, 2015.07.09, urgency: HIGH * Security bugfixes - OpenSSL DLLs updated to version 1.0.2d. https://www.openssl.org/news/secadv_20150709.txt * New features - poll(2) re-enabled on MacOS X 10.5 and later. - Xcode SDK is automatically used on MacOS X if no other locally installed OpenSSL directory is found. - The SSL library detection algorithm was made a bit smarter. - Warnings about insecure authentication were modified to include the name of the affected service section. - A warning was added to stunnel.init if no pid file was specified in the configuration file (thx to Peter Pentchev). - Optional debugging symbols are included in the Win32 installer. - Documentation updates (closes Debian bug #781669). * Bugfixes - Signal pipe reinitialization added to prevent turning the main accepting thread into a busy wait loop when an external condition breaks the signal pipe. This bug was found to surface on Win32, but other platforms may also be affected. - Fixed removing the disabled taskbar icon. - Generated temporary DH parameters are used for configuration reload instead of the static defaults. - LSB compatibility fixes added to the stunnel.init script (thx to Peter Pentchev). - Fixed the manual page headers (thx to Gleydson Soares). Version 5.19, 2015.06.16, urgency: MEDIUM: * New features - OpenSSL DLLs updated to version 1.0.2c. - Added a runtime check whether COMP_zlib() method is implemented in order to improve compatibility with the Debian OpenSSL build. * Bugfixes - Improved socket error handling. - Cron thread priority on Win32 platform changed to THREAD_PRIORITY_LOWEST to improve portability. - Makefile bugfixes for stunnel 5.18 regressions. - Fixed some typos in docs and scripts (thx to Peter Pentchev). - Fixed a log level check condition (thx to Peter Pentchev). Version 5.18, 2015.06.12, urgency: MEDIUM: * New features - OpenSSL DLLs updated to version 1.0.2b. https://www.openssl.org/news/secadv_20150611.txt - Added "include" configuration file option to include all configuration file parts located in a specified directory. - Log file is reopened every 24 hours. With "log = overwrite" this feature can be used to prevent filling up disk space. - Temporary DH parameters are refreshed every 24 hours, unless static DH parameters were provided in the certificate file. - Unique initial DH parameters are distributed with each release. - Warnings are logged on potentially insecure authentication. - Improved compatibility with the current OpenSSL 1.1.0-dev tree: removed RLE compression support, etc. - Updated stunnel.spec (thx to Bill Quayle). * Bugfixes - Fixed handling of dynamic connect targets. - Fixed handling of trailing whitespaces in the Content-Length header of the NTLM authentication. - Fixed --sysconfdir and --localstatedir handling (thx to Dagobert Michelsen). Version 5.17, 2015.04.29, urgency: HIGH: * Bugfixes - Fixed a NULL pointer dereference causing the service to crash. This bug was introduced in stunnel 5.15. Version 5.16, 2015.04.19, urgency: MEDIUM: * Bugfixes - Fixed compilation with old versions of gcc. Version 5.15, 2015.04.16, urgency: LOW: * New features - Added new service-level options "checkHost", "checkEmail" and "checkIP" for additional checks of the peer certificate subject. These options require OpenSSL version 1.0.2 or higher. - Win32 binary distribution now ships with the Mozilla root CA bundle. This bundle is intended be used together with the new "checkHost" option to validate server certs accepted by Mozilla. - New commandline options "-reload" to reload the configuration file and "-reopen" to reopen the log file of stunnel running as a Windows service (thx to Marc McLaughlin). - Added session persistence based on negotiated TLS sessions. https://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence The current implementation does not support external TLS session caching with sessiond. - MEDIUM ciphers (currently SEED and RC4) are removed from the default cipher list. - The "redirect" option was improved to not only redirect sessions established with an untrusted certificate, but also sessions established without a client certificate. - OpenSSL version checking modified to distinguish FIPS and non-FIPS builds. - Improved compatibility with the current OpenSSL 1.1.0-dev tree. - Removed support for OpenSSL versions older than 0.9.7. The final update for the OpenSSL 0.9.6 branch was 17 Mar 2004. - "sessiond" support improved to also work in OpenSSL 0.9.7. - Randomize the initial value of the round-robin counter. - New stunnel.conf templates are provided for Windows and Unix. * Bugfixes - Fixed compilation against old versions of OpenSSL. - Fixed memory leaks in certificate verification. Version 5.14, 2015.03.25, urgency: HIGH: * Security bugfixes - The "redirect" option now also redirects clients on SSL session reuse. In stunnel versions 5.00 to 5.13 reused sessions were instead always connected hosts specified with the "connect" option regardless of their certificate verification result. This vulnerability was reported by Johan Olofsson. * New features - Windows service is automatically restarted after upgrade. * Bugfixes - Fixed a memory allocation error during Unix daemon shutdown. - Fixed handling multiple connect/redirect destinations. - OpenSSL FIPS builds are now correctly reported on startup. Version 5.13, 2015.03.20, urgency: MEDIUM: * New features - The "service" option was modified to also control the syslog service name. * Bugfixes - Fixed Windows service crash. Version 5.12, 2015.03.19, urgency: HIGH: * Security bugfixes - OpenSSL DLLs updated to version 1.0.2a. https://www.openssl.org/news/secadv_20150319.txt * New features - New service-level option "logId" to specify the connection identifier type. Currently supported types: "sequential" (default), "unique", and "thread". - New service-level option "debug" to individually control logging verbosity of defined services. * Bugfixes - OCSP fixed on Windows platform (thx to Alec Kosky). Version 5.11, 2015.03.11, urgency: LOW: * New features - OpenSSL DLLs updated to version 1.0.2. - Removed dereferences of internal OpenSSL data structures. - PSK key lookup algorithm performance improved from O(N) (linear) to O(log N) (logarithmic). * Bugfixes - Fixed peer certificate list in the main window on Win32 (thx to @fyer for reporting it). - Fixed console logging in tstunnel.exe. - _tputenv_s() replaced with more portable _tputenv() on Win32. Version 5.10, 2015.01.22, urgency: LOW: * New features - OCSP AIA (Authority Information Access) support. This feature can be enabled with the new service-level option "OCSPaia". - Additional security features of the linker are enabled: "-z relro", "-z now", "-z noexecstack". * Bugfixes - OpenSSL DLLs updated to version 1.0.1l. https://www.openssl.org/news/secadv_20150108.txt - FIPS canister updated to version 2.0.9 in the Win32 binary build. Version 5.09, 2015.01.02, urgency: LOW: * New features - Added PSK authentication with two new service-level configuration file options "PSKsecrets" and "PSKidentity". - Added additional security checks to the OpenSSL memory management functions. - Added support for the OPENSSL_NO_OCSP and OPENSSL_NO_ENGINE OpenSSL configuration flags. - Added compatibility with the current OpenSSL 1.1.0-dev tree. * Bugfixes - Removed defective s_poll_error() code occasionally causing connections to be prematurely closed (truncated). This bug was introduced in stunnel 4.34. - Fixed ./configure systemd detection (thx to Kip Walraven). - Fixed ./configure sysroot detection (thx to Kip Walraven). - Fixed compilation against old versions of OpenSSL. - Removed outdated French manual page. Version 5.08, 2014.12.09, urgency: MEDIUM: * New features - Added SOCKS4/SOCKS4a protocol support. - Added SOCKS5 protocol support. - Added SOCKS RESOLVE [F0] TOR extension support. - Updated automake to version 1.14.1. - OpenSSL directory searching is now relative to the sysroot. * Bugfixes - Fixed improper hangup condition handling. - Fixed missing -pic linker option. This is required for Android 5.0 and improves security. Version 5.07, 2014.11.01, urgency: MEDIUM: * New features - Several SMTP server protocol negotiation improvements. - Added UTF-8 byte order marks to stunnel.conf templates. - DH parameters are no longer generated by "make cert". The hardcoded DH parameters are sufficiently secure, and modern TLS implementations will use ECDH anyway. - Updated manual for the "options" configuration file option. - Added support for systemd 209 or later. - New --disable-systemd ./configure option. - setuid/setgid commented out in stunnel.conf-sample. * Bugfixes - Added support for UTF-8 byte order mark in stunnel.conf. - Compilation fix for OpenSSL with disabled SSLv2 or SSLv3. - Non-blocking mode set on inetd and systemd descriptors. - shfolder.h replaced with shlobj.h for compatibility with modern Microsoft compilers. Version 5.06, 2014.10.15, urgency: HIGH: * Security bugfixes - OpenSSL DLLs updated to version 1.0.1j. https://www.openssl.org/news/secadv_20141015.txt - The insecure SSLv2 protocol is now disabled by default. It can be enabled with "options = -NO_SSLv2". - The insecure SSLv3 protocol is now disabled by default. It can be enabled with "options = -NO_SSLv3". - Default sslVersion changed to "all" (also in FIPS mode) to autonegotiate the highest supported TLS version. * New features - Added missing SSL options to match OpenSSL 1.0.1j. - New "-options" commandline option to display the list of supported SSL options. * Bugfixes - Fixed FORK threading build regression bug. - Fixed missing periodic Win32 GUI log updates. Version 5.05, 2014.10.10, urgency: MEDIUM: * New features - Asynchronous communication with the GUI thread for faster logging on Win32. - systemd socket activation (thx to Mark Theunissen). - The parameter of "options" can now be prefixed with "-" to clear an SSL option, for example: "options = -LEGACY_SERVER_CONNECT". - Improved "transparent = destination" manual page (thx to Vadim Penzin). * Bugfixes - Fixed POLLIN|POLLHUP condition handling error resulting in prematurely closed (truncated) connection. - Fixed a null pointer dereference regression bug in the "transparent = destination" functionality (thx to Vadim Penzin). This bug was introduced in stunnel 5.00. - Fixed startup thread synchronization with Win32 GUI. - Fixed erroneously closed stdin/stdout/stderr if specified as the -fd commandline option parameter. - A number of minor Win32 GUI bugfixes and improvements. - Merged most of the Windows CE patches (thx to Pierre Delaage). - Fixed incorrect CreateService() error message on Win32. - Implemented a workaround for defective Cygwin file descriptor passing breaking the libwrap support: http://wiki.osdev.org/Cygwin_Issues#Passing_file_descriptors Version 5.04, 2014.09.21, urgency: LOW: * New features - Support for local mode ("exec" option) on Win32. - Support for UTF-8 config file and log file. - Win32 UTF-16 build (thx to Pierre Delaage for support). - Support for Unicode file names on Win32. - A more explicit service description provided for the Windows SCM (thx to Pierre Delaage). - TCP/IP dependency added for NT service in order to prevent initialization failure at boot time. - FIPS canister updated to version 2.0.8 in the Win32 binary build. * Bugfixes - load_icon_default() modified to return copies of default icons instead of the original resources to prevent the resources from being destroyed. - Partially merged Windows CE patches (thx to Pierre Delaage). - Fixed typos in stunnel.init.in and vc.mak. - Fixed incorrect memory allocation statistics update in str_realloc(). - Missing REMOTE_PORT environmental variable is provided to processes spawned with "exec" on Unix platforms. - Taskbar icon is no longer disabled for NT service. - Fixed taskbar icon initialization when commandline options are specified. - Reportedly more compatible values used for the dwDesiredAccess parameter of the CreateFile() function (thx to Pierre Delaage). - A number of minor Win32 GUI bugfixes and improvements. Version 5.03, 2014.08.07, urgency: HIGH: * Security bugfixes - OpenSSL DLLs updated to version 1.0.1i. See https://www.openssl.org/news/secadv_20140806.txt * New features - FIPS autoconfiguration cleanup. - FIPS canister updated to version 2.0.6. - Improved SNI diagnostic logging. * Bugfixes - Compilation fixes for old versions of OpenSSL. - Fixed whitespace handling in the stunnel.init script. Version 5.02, 2014.06.09, urgency: HIGH: * Security bugfixes - OpenSSL DLLs updated to version 1.0.1h. See https://www.openssl.org/news/secadv_20140605.txt * New features - Major rewrite of the protocol.c interface: it is now possible to add protocol negotiations at multiple connection phases, protocols can individually decide whether the remote connection will be established before or after SSL/TLS is negotiated. - Heap memory blocks are wiped before release. This only works for block allocated by stunnel, and not by OpenSSL or other libraries. - The safe_memcmp() function implemented with execution time not dependent on the compared data. - Updated the stunnel.conf and stunnel.init templates. - Added a client-mode example to the manual. * Bugfixes - Fixed "failover = rr" broken since version 5.00. - Fixed "taskbar = no" broken since version 5.00. - Compilation fix for missing SSL_OP_MSIE_SSLV2_RSA_PADDING option. Version 5.01, 2014.04.08, urgency: HIGH: * Security bugfixes - OpenSSL DLLs updated to version 1.0.1g. This version mitigates TLS heartbeat read overrun (CVE-2014-0160). * New features - X.509 extensions added to the created self-signed stunnel.pem. - "FIPS = no" also allowed in non-FIPS builds of stunnel. - Search all certificates with the same subject name for a matching public key rather than only the first one (thx to Leon Winter). - Create logs in the local application data folder if stunnel folder is not writable on Win32. * Bugfixes - close_notify not sent when SSL still has some data buffered. - Protocol negotiation with server-side SNI fixed. - A Mac OS X missing symbols fixed. - Win32 configuration file reload crash fixed. - Added s_pool_free() on exec+connect service retires. - Line-buffering enforced on stderr output. stunnel 5.00 disables some features previously enabled by default. Users should review whether the new defaults are appropriate for their particular deployments. Packages maintainers may consider prepending the old defaults for "fips" (if supported by their OpenSSL library), "pid" and "libwrap" to stunnel.conf during automated updates. Version 5.00, 2014.03.06, urgency: HIGH: * Security bugfixes - Added PRNG state update in fork threading (CVE-2014-0016). * New global configuration file defaults - Default "fips" option value is now "no", as FIPS mode is only helpful for compliance, and never for actual security. - Default "pid" is now "", i.e. not to create a pid file at startup. * New service-level configuration file defaults - Default "ciphers" updated to "HIGH:MEDIUM:+3DES:+DH:!aNULL:!SSLv2" due to AlFBPPS attack and bad performance of DH ciphersuites. - Default "libwrap" setting is now "no" to improve performance. * New features - OpenSSL DLLs updated to version 1.0.1f. - zlib DLL updated to version 1.2.8. - autoconf scripts upgraded to version 2.69. - TLS 1.1 and TLS 1.2 are now allowed in the FIPS mode. - New service-level option "redirect" to redirect SSL client connections on authentication failures instead of rejecting them. - New global "engineDefault" configuration file option to control which OpenSSL tasks are delegated to the current engine. Available tasks: ALL, RSA, DSA, ECDH, ECDSA, DH, RAND, CIPHERS, DIGESTS, PKEY, PKEY_CRYPTO, PKEY_ASN1. - New service-level configuration file option "engineId" to select the engine by identifier, e.g. "engineId = capi". - New global configuration file option "log" to control whether to append (the default), or to overwrite log file while (re)opening. - Different taskbar icon colors to indicate the service state. - New global configuration file options "iconIdle", "iconActive", and "iconError" to select status icon on GUI taskbar. - Removed the limit of 63 stunnel.conf sections on Win32 platform. - Installation of a sample certificate was moved to a separate "cert" target in order to allow unattended (e.g. scripted) installations. - Reduced length of the logged thread identifier. It is still based on the OS thread ID, and thus not unique over long periods of time. - Improved readability of error messages printed when stunnel refuses to start due to a critical error. * Bugfixes - LD_PRELOAD Solaris compatibility bug fixed (thx to Norm Jacobs). - CRYPTO_NUM_LOCKS replaced with CRYPTO_num_locks() to improve binary compatibility with diverse builds of OpenSSL (thx to Norm Jacobs). - Corrected round-robin failover behavior under heavy load. - Numerous fixes in the engine support code. - On Win32 platform .rnd file moved from c:\ to the stunnel folder. Version 4.57, 2015.04.01, urgency: HIGH: * Security bugfixes - Added PRNG state update in fork threading (CVE-2014-0016). Version 4.56, 2013.03.22, urgency: HIGH: * New features - Win32 installer automatically configures firewall exceptions. - Win32 installer configures administrative shortcuts to invoke UAC. - Improved Win32 GUI shutdown time. * Bugfixes - Fixed a regression bug introduced in version 4.55 causing random crashes on several platforms, including Windows 7. - Fixed startup crashes on some Win32 systems. - Fixed incorrect "stunnel -exit" process synchronisation. - Fixed FIPS detection with new versions of the OpenSSL library. - Failure to open the log file at startup is no longer ignored. Version 4.55, 2013.03.03, urgency: HIGH: * Security bugfixes - Buffer overflow vulnerability fixed in the NTLM authentication of the CONNECT protocol negotiation. See https://www.stunnel.org/CVE-2013-1762.html for details. - OpenSSL updated to version 1.0.1e in Win32/Android builds. * New features - SNI wildcard matching in server mode. - Terminal version of stunnel (tstunnel.exe) build for Win32. * Bugfixes - Fixed write half-close handling in the transfer() function (thx to Dustin Lundquist). - Fixed EAGAIN error handling in the transfer() function (thx to Jan Bee). - Restored default signal handlers before execvp() (thx to Michael Weiser). - Fixed memory leaks in protocol negotiation (thx to Arthur Mesh). - Fixed a file descriptor leak during configuration file reload (thx to Arthur Mesh). - Closed SSL sockets were removed from the transfer() c->fds poll. - Minor fix in handling exotic inetd-mode configurations. - WCE compilation fixes. - IPv6 compilation fix in protocol.c. - Windows installer fixes. Version 4.54, 2012.10.09, urgency: MEDIUM: * New Win32 features - FIPS module updated to version 2.0. - OpenSSL DLLs updated to version 1.0.1c. - zlib DLL updated to version 1.2.7. - Engine DLLs added: 4758cca, aep, atalla, capi, chil, cswift, gmp, gost, nuron, padlock, sureware, ubsec. * Other new features - "session" option renamed to more readable "sessionCacheTimeout". The old name remains accepted for backward compatibility. - New service-level "sessionCacheSize" option to control session cache size. - New service-level option "reset" to control whether TCP RST flag is used to indicate errors. The default value is "reset = yes". - New service-level option "renegotiation" to disable SSL renegotiation. This feature is based on a public-domain patch by Janusz Dziemidowicz. - New FreeBSD socket options: IP_FREEBIND, IP_BINDANY, IPV6_BINDANY (thx to Janusz Dziemidowicz). - New parameters to configure TLS v1.1/v1.2 with OpenSSL version 1.0.1 or higher (thx to Henrik Riomar). * Bugfixes - Fixed "Application Failed to Initialize Properly (0xc0150002)" error. - Fixed missing SSL state debug log entries. - Fixed a race condition in libwrap code resulting in random stalls (thx to Andrew Skalski). - Session cache purged at configuration file reload to reduce memory leak. Remaining leak of a few kilobytes per section is yet to be fixed. - Fixed a regression bug in "transparent = destination" functionality (thx to Stefan Lauterbach). This bug was introduced in stunnel 4.51. - "transparent = destination" is now a valid endpoint in inetd mode. - "delay = yes" fixed to work even if specified *after* "connect" option. - Multiple "connect" targets fixed to also work with delayed resolver. - The number of resolver retries of EAI_AGAIN error has been limited to 3 in order to prevent infinite loops. Version 4.53, 2012.03.19, urgency: MEDIUM: * New features - Added client-mode "sni" option to directly control the value of TLS Server Name Indication (RFC 3546) extension. - Added support for IP_FREEBIND socket option with a pached Linux kernel. - Glibc-specific dynamic allocation tuning was applied to help unused memory deallocation. - Non-blocking OCSP implementation. * Bugfixes - Compilation fixes for old versions of OpenSSL (tested against 0.9.6). - Usage of uninitialized variables fixed in exec+connect services. - Occasional logging subsystem crash with exec+connect services. - OpenBSD compilation fix (thx to Michele Orru'). - Session id context initialized with session name rather than a constant. - Fixed handling of a rare inetd mode use case, where either stdin or stdout is a socket, but not both of them at the same time. - Fixed missing OPENSSL_Applink http://www.openssl.org/support/faq.html#PROG2 - Fixed crash on termination with FORK threading model. - Fixed dead canary after configuration reload with open connections. - Fixed missing file descriptors passed to local mode processes. - Fixed required jmp_buf alignment on Itanium platform. - Removed creating /dev/zero in the chroot jail on Solaris platform. - Fixed detection of WSAECONNREFUSED Winsock error. - Missing Microsoft.VC90.CRT.manifest added to Windows installer. Version 4.52, 2012.01.12, urgency: MEDIUM: * Bugfixes - Fixed write closure notification for non-socket file descriptors. - Removed a line logged to stderr in inetd mode. - Fixed "Socket operation on non-socket" error in inetd mode on Mac OS X platform. - Removed direct access to the fields of the X509_STORE_CTX data structure. Version 4.51, 2012.01.09, urgency: MEDIUM: * New features - Updated Win32 binary distribution OpenSSL DLLs to version 0.9.8s-fips. - Updated Android binary OpenSSL to version 1.0.0f. - Zlib support added to Win32 and Android binary builds. - New "compression = deflate" global option to enable RFC 2246 compresion. For compatibility with previous versions "compression = zlib" and "compression = rle" also enable the deflate (RFC 2246) compression. - Compression is disabled by default. - Separate default ciphers and sslVersion for "fips = yes" and "fips = no". - UAC support for editing configuration file with Windows GUI. * Bugfixes - Fixed exec+connect sections. - Added a workaround for broken Android getaddrinfo(): http://stackoverflow.com/questions/7818246/segmentation-fault-in-getaddrinfo Version 4.50, 2011.12.03, urgency: MEDIUM: * New features - Added Android port. - Updated INSTALL.FIPS. * Bugfixes - Fixed internal memory allocation problem in inetd mode. - Fixed FIPS mode on Microsoft Vista, Server 2008, and Windows 7. This fix required to compile OpenSSL FIPS-compliant DLLs with MSVC 9.0, instead of MSVC 10.0. msvcr100.dll was replaced with msvcr90.dll. GPL compatibility issues are explained in the GPL FAQ: http://www.gnu.org/licenses/gpl-faq.html#WindowsRuntimeAndGPL - POP3 server-side protocol negotiation updated to report STLS capability (thx to Anthony Morgan). Version 4.49, 2011.11.28, urgency: MEDIUM: * Bugfixes - Missing Microsoft Visual C++ Redistributable (msvcr100.dll) required by FIPS-compliant OpenSSL library was added to the Windows installer. - A bug was fixed causing crashes on MacOS X and some other platforms. Version 4.48, 2011.11.26, urgency: MEDIUM: * New features - FIPS support on Win32 platform added. OpenSSL 0.9.8r DLLs based on FIPS 1.2.3 canister are included with this version of stunnel. FIPS mode can be disabled with "fips = no" configuration file option. * Bugfixes - Fixed canary initialization problem on Win32 platform. Version 4.47, 2011.11.21, urgency: MEDIUM: * Internal improvements - CVE-2010-3864 workaround improved to check runtime version of OpenSSL rather than compiled version, and to allow OpenSSL 0.x.x >= 0.9.8p. - Encoding of man page sources changed to UTF-8. * Bugfixes - Handling of socket/SSL close in transfer() function was fixed. - Logging was modified to save and restore system error codes. - Option "service" was restricted to Unix, as since stunnel 4.42 it wasn't doing anything useful on Windows platform. Version 4.46, 2011.11.04, urgency: LOW: * New features - Added Unix socket support (e.g. "connect = /var/run/stunnel/socket"). - Added "verify = 4" mode to ignore CA chain and only verify peer certificate. - Removed the limit of 16 IP addresses for a single 'connect' option. - Removed the limit of 256 stunnel.conf sections in PTHREAD threading model. It is still not possible have more than 63 sections on Win32 platform. http://msdn.microsoft.com/en-us/library/windows/desktop/ms740141(v=vs.85).aspx * Optimizations - Reduced per-connection memory usage. - Performed a major refactoring of internal data structures. Extensive internal testing was performed, but some regression bugs are expected. * Bugfixes - Fixed Win32 compilation with Mingw32. - Fixed non-blocking API emulation layer in UCONTEXT threading model. - Fixed signal handling in UCONTEXT threading model. Version 4.45, 2011.10.24, urgency: LOW: * New features - "protocol = proxy" support to send original client IP address to haproxy: http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt This requires accept-proxy bind option of haproxy 1.5-dev3 or later. - Added Win32 configuration reload without a valid configuration loaded. - Added compatibility with LTS OpenSSL versions 0.9.6 and 0.9.7. Some features are only available in OpenSSL 1.0.0 and later. * Performance optimizations - Use SSL_MODE_RELEASE_BUFFERS if supported by the OpenSSL library. - Libwrap helper processes are no longer started if libwrap is disabled in all sections of the configuration file. * Internal improvements - Protocol negotiation framework was rewritten to support additional code to be executed after SSL_accept()/SSL_connect(). - Handling of memory allocation errors was rewritten to gracefully terminate the process (thx to regenrecht for the idea). * Bugfixes - Fixed -l option handling in stunnel3 script (thx to Kai Gülzau). - Script to build default stunnel.pem was fixed (thx to Sebastian Kayser). - MinGW compilation script (mingw.mak) was fixed (thx to Jose Alf). - MSVC compilation script (vc.mak) was fixed. - A number of problems in WINSOCK error handling were fixed. Version 4.44, 2011.09.17, urgency: MEDIUM: * New features - Major automake/autoconf cleanup. - Heap buffer overflow protection with canaries. - Stack buffer overflow protection with -fstack-protector. * Bugfixes - Fixed garbled error messages on errors with setuid/setgid options. - SNI fixes (thx to Alexey Drozdov). - Use after free in fdprintf() (thx to Alexey Drozdov). This issue might cause GPF with "protocol" or "ident" options. Version 4.43, 2011.09.07, urgency: MEDIUM: * New features - Updated Win32 DLLs for OpenSSL 1.0.0e. - Major optimization of the logging subsystem. Benchmarks indicate up to 15% stunnel performance improvement. * Bugfixes - Fixed Win32 configuration file reload. - Fixed FORK and UCONTEXT threading models. - Corrected INSTALL.W32 file. Version 4.42, 2011.08.18, urgency: HIGH: * New features - New verify level 0 to request and ignore peer certificate. This feature is useful with the new Windows GUI menu to save cached peer certificate chains, as SSL client certificates are not sent by default. - Manual page has been updated. - Removed support for changing Windows Service name with "service" option. * Bugfixes - Fixed a heap corruption vulnerability in versions 4.40 and 4.41. It may possibly be leveraged to perform DoS or remote code execution attacks. - The -quiet commandline option was applied to *all* message boxes. - Silent install (/S option) no longer attempts to create stunnel.pem. Version 4.41, 2011.07.25, urgency: MEDIUM: * Bugfixes - Fixed Windows service crash of stunnel 4.40. Version 4.40, 2011.07.23, urgency: LOW: * New Win32 features - Added a GUI menu to save cached peer certificate chains. - Added comandline "-exit" option to stop stunnel *not* running as a service. This option may be useful for scripts. - Added file version information to stunnel.exe. - A number of other GUI improvements. * Other new features - Hardcoded 2048-bit DH parameters are used as a fallback if DH parameters are not provided in stunnel.pem. - Default "ciphers" value updated to prefer ECDH: "ALL:!SSLv2:!aNULL:!EXP:!LOW:-MEDIUM:RC4:+HIGH". - Default ECDH curve updated to "prime256v1". - Removed support for temporary RSA keys (used in obsolete export ciphers). Version 4.39, 2011.07.06, urgency: LOW: * New features - New Win32 installer module to build self-signed stunnel.pem. - Added configuration file editing with Windows GUI. - Added log file reopening file editing with Windows GUI. It might be useful to also implement log file rotation. - Improved configuration file reload with Windows GUI. Version 4.38, 2011.06.28, urgency: MEDIUM: * New features - Server-side SNI implemented (RFC 3546 section 3.1) with a new service-level option "nsi". - "socket" option also accepts "yes" and "no" for flags. - Nagle's algorithm is now disabled by default for improved interactivity. * Bugfixes - A compilation fix was added for OpenSSL version < 1.0.0. - Signal pipe set to non-blocking mode. This bug caused hangs of stunnel features based on signals, e.g. local mode, FORK threading, or configuration file reload on Unix. Win32 platform was not affected. Version 4.37, 2011.06.17, urgency: MEDIUM: * New features - Client-side SNI implemented (RFC 3546 section 3.1). - Default "ciphers" changed from the OpenSSL default to a more secure and faster "RC4-MD5:HIGH:!aNULL:!SSLv2". A paranoid (and usually slower) setting would be "HIGH:!aNULL:!SSLv2". - Recommended "options = NO_SSLv2" added to the sample stunnel.conf file. - Default client method upgraded from SSLv3 to TLSv1. To connect servers without TLS support use "sslVersion = SSLv3" option. - Improved --enable-fips and --disable-fips ./configure option handling. - On startup stunnel now compares the compiled version of OpenSSL against the running version of OpenSSL. A warning is logged on mismatch. * Bugfixes - Non-blocking socket handling in local mode fixed (Debian bug #626856). - UCONTEXT threading mode fixed. - Removed the use of gcc Thread-Local Storage for improved portability. - va_copy macro defined for platforms that do not have it. - Fixed "local" option parsing on IPv4 systems. - Solaris compilation fix (redefinition of "STR"). Version 4.36, 2011.05.03, urgency: LOW: * New features - Updated Win32 DLLs for OpenSSL 1.0.0d. - Dynamic memory management for strings manipulation: no more static STRLEN limit, lower stack footprint. - Strict public key comparison added for "verify = 3" certificate checking mode (thx to Philipp Hartwig). - Backlog parameter of listen(2) changed from 5 to SOMAXCONN: improved behavior on heavy load. - Example tools/stunnel.service file added for systemd service manager. * Bugfixes - Missing pthread_attr_destroy() added to fix memory leak (thx to Paul Allex and Peter Pentchev). - Fixed the incorrect way of setting FD_CLOEXEC flag. - Fixed --enable-libwrap option of ./configure script. - /opt/local added to OpenSSL search path for MacPorts compatibility. - Workaround implemented for signal handling on MacOS X. - A trivial bug fixed in the stunnel.init script. - Retry implemented on EAI_AGAIN error returned by resolver calls. Version 4.35, 2011.02.05, urgency: LOW: * New features - Updated Win32 DLLs for OpenSSL 1.0.0c. - Transparent source (non-local bind) added for FreeBSD 8.x. - Transparent destination ("transparent = destination") added for Linux. * Bugfixes - Fixed reload of FIPS-enabled stunnel. - Compiler options are now auto-detected by ./configure script in order to support obsolete versions of gcc. - Async-signal-unsafe s_log() removed from SIGTERM/SIGQUIT/SIGINT handler. - CLOEXEC file descriptor leaks fixed on Linux >= 2.6.28 with glibc >= 2.10. Irreparable race condition leaks remain on other Unix platforms. This issue may have security implications on some deployments: http://udrepper.livejournal.com/20407.html - Directory lib64 included in the OpenSSL library search path. - Windows CE compilation fixes (thx to Pierre Delaage). - Deprecated RSA_generate_key() replaced with RSA_generate_key_ex(). * Domain name changes (courtesy of Bri Hatch) - http://stunnel.mirt.net/ --> http://www.stunnel.org/ - ftp://stunnel.mirt.net/ --> http://ftp.stunnel.org/ - stunnel.mirt.net::stunnel --> rsync.stunnel.org::stunnel - stunnel-users@mirt.net --> stunnel-users@stunnel.org - stunnel-announce@mirt.net --> stunnel-announce@stunnel.org Version 4.34, 2010.09.19, urgency: LOW: * New features - Updated Win32 DLLs for OpenSSL 1.0.0a. - Updated Win32 DLLs for zlib 1.2.5. - Updated automake to version 1.11.1 - Updated libtool to version 2.2.6b - Added ECC support with a new service-level "curve" option. - DH support is now enabled by default. - Added support for OpenSSL builds with some algorithms disabled. - ./configure modified to support cross-compilation. - Sample stunnel.init updated based on Debian init script. * Bugfixes - Implemented fixes in user interface to enter engine PIN. - Fixed a transfer() loop issue on socket errors. - Fixed missing Win32 taskbar icon while displaying a global option error. Version 4.33, 2010.04.05, urgency: MEDIUM: * New features - Win32 DLLs for OpenSSL 1.0.0. This library requires to c_rehash CApath/CRLpath directories on upgrade. - Win32 DLLs for zlib 1.2.4. - Experimental support for local mode on Win32 platform. Try "exec = c:\windows\system32\cmd.exe". * Bugfixes - Inetd mode fixed. Version 4.32, 2010.03.24, urgency: MEDIUM: * New features - New service-level "libwrap" option for run-time control whether /etc/hosts.allow and /etc/hosts.deny are used for access control. Disabling libwrap significantly increases performance of stunnel. - Win32 DLLs for OpenSSL 0.9.8m. * Bugfixes - Fixed a transfer() loop issue with SSLv2 connections. - Fixed a "setsockopt IP_TRANSPARENT" warning with "local" option. - Logging subsystem bugfixes and cleanup. - Installer bugfixes for Vista and later versions of Windows. - FIPS mode can be enabled/disabled at runtime. Version 4.31, 2010.02.03, urgency: MEDIUM: * New features - Log file reopen on USR1 signal was added. * Bugfixes - Some regression issues introduced in 4.30 were fixed. Version 4.30, 2010.01.21, urgency: LOW/EXPERIMENTAL: * New features - Graceful configuration reload with HUP signal on Unix and with GUI on Windows. Version 4.29, 2009.12.02, urgency: MEDIUM: * New feature sponsored by Searchtech Limited http://www.astraweb.com/ - sessiond, a high performance SSL session cache was built for stunnel. A new service-level "sessiond" option was added. sessiond is available for download on ftp://ftp.stunnel.org/stunnel/sessiond/ . stunnel clusters will be a lot faster, now! * Bugfixes - "execargs" defaults to the "exec" parameter (thx to Peter Pentchev). - Compilation fixes added for AIX and old versions of OpenSSL. - Missing "fips" option was added to the manual. Version 4.28, 2009.11.08, urgency: MEDIUM: * New features - Win32 DLLs for OpenSSL 0.9.8l. - Transparent proxy support on Linux kernels >=2.6.28. See the manual for details. - New socket options to control TCP keepalive on Linux: TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL. - SSL options updated for the recent version of OpenSSL library. * Bugfixes - A serious bug in asynchronous shutdown code fixed. - Data alignment updated in libwrap.c. - Polish manual encoding fixed. - Notes on compression implementation in OpenSSL added to the manual. Version 4.27, 2009.04.16, urgency: MEDIUM: * New features - Win32 DLLs for OpenSSL 0.9.8k. - FIPS support was updated for openssl-fips 1.2. - New priority failover strategy for multiple "connect" targets, controlled with "failover=rr" (default) or "failover=prio". - pgsql protocol negotiation by Marko Kreen . - Building instructions were updated in INSTALL.W32 file. * Bugfixes - Libwrap helper processes fixed to close standard input/output/error file descriptors. - OS2 compilation fixes. - WCE fixes by Pierre Delaage . Version 4.26, 2008.09.20, urgency: MEDIUM: * New features - Win32 DLLs for OpenSSL 0.9.8i. - /etc/hosts.allow and /etc/hosts.deny no longer need to be copied to the chrooted directory, as the libwrap processes are no longer chrooted. - A more informative error messages for invalid port number specified in stunnel.conf file. - Support for Microsoft Visual C++ 9.0 Express Edition. * Bugfixes - Killing all libwrap processes at stunnel shutdown fixed. - A minor bug in stunnel.init sample SysV startup file fixed. Version 4.25, 2008.06.01, urgency: MEDIUM: * New features - Win32 DLLs for OpenSSL 0.9.8h. * Bugfixes - Spawning libwrap processes delayed until privileges are dropped. - Compilation fix for systems without struct msghdr.msg_control. Version 4.24, 2008.05.19, urgency: HIGH: * Bugfixes - OCSP code was fixed to properly reject revoked certificates. Version 4.23, 2008.05.03, urgency: HIGH: * Bugfixes - Local privilege escalation bug on Windows NT based systems fixed. A local user could exploit stunnel running as a service to gain localsystem privileges. Version 4.22, 2008.03.28, urgency: MEDIUM: * New features - Makefile was updated to use standard autoconf variables: sysconfdir, localstatedir and pkglibdir. - A new global option to control logging to syslog: syslog = yes|no Simultaneous logging to a file and the syslog is now possible. - A new service-level option to control stack size: stack = * Bugfixes - Restored chroot() to be executed after decoding numerical userid and groupid values in drop_privileges(). - A few bugs fixed the in the new libwrap support code. - TLSv1 method used by default in FIPS mode instead of SSLv3 client and SSLv23 server methods. - OpenSSL GPL license exception update based on http://www.gnu.org/licenses/gpl-faq.html#GPLIncompatibleLibs Version 4.21, 2007.10.27, urgency: LOW/EXPERIMENTAL: * New features sponsored by Open-Source Software Institute - Initial FIPS 140-2 support (see INSTALL.FIPS for details). Win32 platform is not currently supported. * New features - Experimental fast support for non-MT-safe libwrap is provided with pre-spawned processes. - Stunnel binary moved from /usr/local/sbin to /usr/local/bin in order to meet FHS and LSB requirements. Please delete the /usr/local/sbin/stunnel when upgrading. - Added code to disallow compiling stunnel with pthreads when OpenSSL is compiled without threads support. - Win32 DLLs for OpenSSL 0.9.8g. - Minor manual update. - TODO file updated. * Bugfixes - Dynamic locking callbacks added (needed by some engines to work). - AC_ARG_ENABLE fixed in configure.am to accept yes/no arguments. - On some systems libwrap requires yp_get_default_domain from libnsl, additional checking for libnsl was added to the ./configure script. - Sending a list of trusted CAs for the client to choose the right certificate restored. - Some compatibility issues with NTLM authentication fixed. - Taskbar icon (unless there is a config file parsing error) and "Save As" disabled in the service mode for local Win32 security (it's much like Yeti -- some people claim they have seen it). Version 4.20, 2006.11.30, urgency: MEDIUM: * Release notes - The new transfer() function has been well tested. I recommend upgrading any previous version with this one. * Bugfixes - Fixed support for encrypted passphrases on Unix (broken in 4.19). - Reduced amount of debug logs. - A minor man page update. Version 4.19, 2006.11.11, urgency: LOW/EXPERIMENTAL: * Release notes - There are a lot of new features in this version. I recommend to test it well before upgrading your mission-critical systems. * New features - New service-level option to specify an OCSP responder flag: OCSPflag = - "protocolCredentials" option changed to "protocolUsername" and "protocolPassword" - NTLM support to be enabled with the new service-level option: protocolAuthentication = NTLM - imap protocol negotiation support added. - Passphrase cache was added so the user does not need to reenter the same passphrase for each defined service any more. - New service-level option to retry exec+connect section: retry = yes|no - Local IP and port is logged for each established connection. - Win32 DLLs for OpenSSL 0.9.8d. * Bugfixes - Serious problem with SSL_WANT_* retries fixed. The new code requires extensive testing! Version 4.18, 2006.09.26, urgency: MEDIUM: * Bugfixes - GPF on entering private key pass phrase on Win32 fixed. - Updated OpenSSL Win32 DLLs. - Minor configure script update. Version 4.17, 2006.09.10, urgency: MEDIUM: * New features - Win32 DLLs for OpenSSL 0.9.8c. * Bugfixes - Problem with detecting getaddrinfo() in ./configure fixed. - Compilation problem due to misplaced #endif in ssl.c fixed. - Duplicate 220 in smtp_server() function in protocol.c fixed. - Minor os2.mak update. - Minor update of safestring()/safename() macros. Version 4.16, 2006.08.31, urgency: MEDIUM: * New features sponsored by Hewlett-Packard - A new global option to control engine: engineCtrl = [:] - A new service-level option to select engine to read private key: engineNum = - OCSP support: ocsp = * New features - A new option to select version of SSL protocol: sslVersion = all|SSLv2|SSLv3|TLSv1 - Visual Studio vc.mak by David Gillingham . - OS2 support by Paul Smedley (http://smedley.info) * Bugfixes - An ordinary user can install stunnel again. - Compilation problem with --enable-dh fixed. - Some minor compilation warnings fixed. - Service-level CRL cert store implemented. - GPF on protocol negotiations fixed. - Problem detecting addrinfo() on Tru64 fixed. - Default group is now detected by configure script. - Check for maximum number of defined services added. - OpenSSL_add_all_algorithms() added to SSL initialization. - configure script sections reordered to detect pthread library functions. - RFC 2487 autodetection improved. High resolution s_poll_wait() not currently supported by UCONTEXT threading. - More precise description of cert directory file names (thx to Muhammad Muquit). * Other changes - Maximum number of services increased from 64 to 256 when poll() is used. Version 4.15, 2006.03.11, urgency: LOW: * Release notes - There are a lot of new features in this version. I recommend to test it well before upgrading your mission-critical systems. * Bugfixes - Fix for pthreads on Solaris 10. - Attempt to autodetect socklen_t type in configure script. - Default threading model changed to pthread for better portability. - DH parameters are not included in the certificate by default. * New features sponsored by Software House http://www.swhouse.com/ - Most SSL-related options (including client, cert, key) are now available on service-level, so it is possible to have an SSL client and an SSL server in a single stunnel process. - Windows CE (version 3.0 and higher) support. * New features - Client mode CONNECT protocol support (RFC 2817 section 5.2). http://www.ietf.org/rfc/rfc2817.txt - Retrying exec+connect services added. * File locations are more compliant to Filesystem Hierarchy Standard 2.3 - configuration and certificates are in $prefix/etc/stunnel/ - binaries are in $prefix/sbin/ - default pid file is $prefix/var/run/stunnel.pid - manual is $prefix/man/man8/stunnel.8 - other docs are in $prefix/share/doc/stunnel/ - libstunnel is in $prefix/lib - chroot directory is setup in $prefix/var/lib/stunnel/ this directory is chmoded 1770 and group nogroup Version 4.14, 2005.11.02, urgency: HIGH: * Bugfixes - transfer() fixed to avoid random stalls introduced in version 4.12. - poll() error handing bug fixed. - Checking for dynamic loader libraries added again. - Default pidfile changed from $localstatedir/run/stunnel.pid to $localstatedir/stunnel/stunnel.pid. - Basic SSL library initialization moved to the beginning of execution. * Release notes - This is an important bugfix release. Upgrade is recommended. Version 4.13, 2005.10.21, urgency: MEDIUM: * DLLs for OpenSSL 0.9.7i included because protection faults were reported in 0.9.8 and 0.9.8a. * New features - Libwrap code is executed as a separate process (no more delays due to a global and potentially long critical section). * Bugfixes - Problem with zombies in UCONTEXT threading fixed. - Workaround for non-standard makecontext() uc_stack.ss_sp parameter semantics on SGI IRIX. - Protection fault in signals handling on IRIX fixed. - Problem finding pthread library on AIX fixed. - size_t printf() fixed in stack_info() (the previous fix didn't work). - socklen_t is used instead of int where required. Version 4.12, 2005.09.29, urgency: MEDIUM: * New features - Win32 installer added. - New Win32 commandline options: -start and -stop. - Log level and thread number are reported to syslog. - DLLs for OpenSSL 0.9.8. - stunnel.spec updated by neeo . * Bugfixes - Use of broken poll() is disabled on Mac OS X. - Yet another transfer() infinite loop condition fixed. - Workaround for a serious M$ bug (KB177346). - IPv6 DLLs allocation problem resulting in GPF on W2K fixed. - zlib added to shared libraries (OpenSSL may need it). - size_t printf() fixed in stack_info(). * Release notes - This is a bugfix release. Upgrade is recommended. Version 4.11, 2005.07.09, urgency: MEDIUM: * New features - New ./configure option --with-threads to select thread model. - ./configure option --with-tcp-wrappers renamed to --disable-libwrap. I hope the meaning of the option is much more clear, now. * Bugfixes - Workaround for non-standard makecontext() uc_stack.ss_sp parameter semantics on Sparc/Solaris 9 and earlier. - scan_waiting_queue() no longer drops contexts. - Inetd mode GPFs with UCONTEXT fixed. - Cleanup context is no longer used. - Releasing memory of the current context is delayed. - Win32 headers reordered for Visual Studio 7. - Some Solaris compilation warnings fixed. - Rejected inetd mode without 'connect' or 'exec'. * Release notes - UCONTEXT threading seems stable, now. Upgrade is recommended. Version 4.10, 2005.04.23, urgency: LOW/EXPERIMENTAL: * DLLs for OpenSSL 0.9.7g. * Bugfixes - Missing locking on Win32 platform was added (thx to Yi Lin ) - Some problems with closing SSL fixed. * New features - New UCONTEXT user-level non-preemptive threads model is used on systems that support SYSV-compatible ucontext.h. - Improved stunnel3 script with getopt-compatible syntax. * Release notes - This version should be thoroughly tested before using it in the mission-critical environment. Version 4.09, 2005.03.26, urgency: MEDIUM: * DLLs for OpenSSL 0.9.7f. * Bugfixes - Compilation problem with undeclared socklen_t fixed. - TIMEOUTclose is not used when there is any data in the buffers. - Stunnel no longer relies on close_notify with SSL 2.0 connections, since SSL 2.0 protocol does not have any alerts defined. - Closing SSL socket when there is some data in SSL output buffer is detected and reported as an error. - Install/chmod race condition when installing default certificate fixed. - Stunnel no longer installs signal_handler on ignored signals. Version 4.08, 2005.02.27, urgency: LOW: * New features - New -quiet option was added to install NT service without a message box. * Bugfixes - Using $(DESTDIR) in tools/Makefile.am. - Define NI_NUMERICHOST and NI_NUMERICSERV when needed. - Length of configuration file line increased from 256B to 16KB. - Stunnel sends close_notify when a close_notify is received from SSL peer and all remaining data is sent to SSL peer. - Some fixes for bugs detected by the watchdog. * Release notes - There were many changes in the transfer() function (the main loop). - This version should be thoroughly tested before using it in the mission-critical environment. Version 4.07, 2005.01.03, urgency: MEDIUM: * Bugfixes - Problem with infinite poll() timeout negative, but not equal to -1 fixed. - Problem with a file descriptor ready to be read just after a non-blocking connect call fixed. - Compile error with EAI_NODATA not defined or equal to EAI_NONAME fixed. - IP address and TCP port textual representation length (IPLEN) increased to 128 bytes. - OpenSSL engine support is only used if engine.h header file exists. - Broken NT Service mode on Win32 platform fixed. - Support for IPv4-only Win32 machines restored. Version 4.06, 2004.12.26, urgency: LOW: * New feature sponsored by SURFnet http://www.surfnet.nl/ - IPv6 support (to be enabled with ./configure --enable-ipv6). * New features - poll() support - no more FD_SETSIZE limit! - Multiple connect=host:port options are allowed in a single service section. Remote hosts are connected using round-robin algorithm. This feature is not compatible with delayed resolver. - New 'compression' option to enable compression. To use zlib algorithm you have to enable it when building OpenSSL library. - New 'engine' option to select a hardware engine. - New 'TIMEOUTconnect' option with 10 seconds default added. - stunnel3 perl script to emulate version 3.x command line options. - French manual updated by Bernard Choppy . - A watchdog to detect transfer() infinite loops added. - Configuration file comment character changed from '#' to ';'. '#' will still be recognized to keep compatibility. - MT-safe getaddrinfo() and getnameinfo() are used where available to get better performance on resolver calls. - Automake upgraded from 1.4-p4 to 1.7.9. * Bugfixes - log() changed to s_log() to avoid conflicts on some systems. - Common CRIT_INET critical section introduced instead of separate CRIT_NTOA and CRIT_RESOLVER to avoid potential problems with libwrap (TCP Wrappers) library. - CreateThread() finally replaced with _beginthread() on Win32. - make install creates $(localstatedir)/stunnel. $(localstatedir)/stunnel/dev/zero is also created on Solaris. - Race condition with client session cache fixed. - Other minor bugfixes. * Release notes - Win32 port requires Winsock2 to work. Some Win95 systems may need a free update from Microsoft. http://www.microsoft.com/windows95/downloads/ - Default is *not* to use IPv6 '::' for accept and '::1' for connect. For example to accept pop3s on IPv6 you could use: 'accept = :::995'. I hope the new syntax is clear enough. Version 4.05, 2004.02.14, urgency: MEDIUM: * New feature sponsored by SURFnet http://www.surfnet.nl/ - Support for CIFS aka SMB protocol SSL negotiation. * New features - CRL support with new CRLpath and CRLfile global options. - New 'taskbar' option on Win32 (thx to Ken Mattsen ). - New -fd command line parameter to read configuration from a specified file descriptor instead of a file. - accept is reported as error when no '[section]' is defined (in stunnel 4.04 it was silently ignored causing problems for lusers who did not read the fine manual). - Use fcntl() instead of ioctlsocket() to set socket nonblocking where it is supported. - Basic support for hardware engines with OpenSSL >= 0.9.7. - French manual by Bernard Choppy . - Thread stack size reduced to 64KB for maximum scalability. - Added optional code to debug thread stack usage. - Support for nsr-tandem-nsk (thx to Tom Bates ). * Bugfixes - TCP wrappers code moved to CRIT_NTOA critical section since it uses static inet_ntoa() result buffer. - SSL_ERROR_SYSCALL handling problems fixed. - added code to retry nonblocking SSL_shutdown() calls. - Use FD_SETSIZE instead of 16 file descriptors in inetd mode. - fdscanf groks lowercase protocol negotiation commands. - Win32 taskbar GDI objects leak fixed. - Libwrap detection bug in ./configure script fixed. - grp.h header detection fixed for NetBSD and possibly other systems. - Some other minor updates. Version 4.04, 2003.01.12, urgency: MEDIUM: * New feature sponsored by SURFnet http://www.surfnet.nl/ - Encrypted private key can be used with Win32 GUI. * New features - New 'options' configuration option to setup OpenSSL library hacks with SSL_CTX_set_options(). - 'service' option also changes the name for TCP Wrappers access control in inetd mode. - Support for BeOS (thx to Mike I. Kozin ) - SSL is negotiated before connecting remote host or spawning local process whenever possible. - REMOTE_HOST variable is always placed in the enrivonment of a process spawned with 'exec'. - Whole SSL error stack is dumped on errors. - 'make cert' rule is back (was missing since 4.00). - Manual page updated (special thanks to Brian Hatch). - TODO updated. * Bugfixes - Major code cleanup (thx to Steve Grubb ). - Unsafe functions are removed from SIGCHLD handler. - Several bugs in auth_user() fixed. - Incorrect port when using 'local' option fixed. - OpenSSL tools '-rand' option is no longer directly used with a device (like '/dev/urandom'). Temporary random file is created with 'dd' instead. * DLLs for OpenSSL 0.9.7. Version 4.03, 2002.10.27, urgency: HIGH: * NT Service (broken since 4.01) is operational again. * Memory leak in FORK environments fixed. * sigprocmask() mistake corrected. * struct timeval is reinitialized before select(). * EAGAIN handled in client.c for AIX. * Manual page updated. Version 4.02, 2002.10.21, urgency: HIGH: * Serious bug in ECONNRESET handling fixed. Version 4.01, 2002.10.20, urgency: MEDIUM: * New features - OpenVMS support. - Polish manual and some manual updates. - 'service' option added on Win32 platform. - Obsolete FAQ has been removed. - Log file is created with 0640 mode. - exec->connect service sections (need more testing). * Bugfixes - EINTR ingored in main select() loop. - Fixed problem with stunnel closing connections on TIMEOUTclose before all the data is sent. - Fixed EWOULDBLOCK on writesocket problem. - Potential DOS in Win32 GUI fixed. - Solaris compilation problem fixed. - Libtool configuration problems fixed. - Signal mask is cleared just before exec in local mode. - Accepting sockets and log file descriptors are no longer leaked to the child processes. Special thanks to Steve Grubb for the source code audit. Version 4.00, 2002.08.30, urgency: LOW: * New features sponsored by MAXIMUS http://www.maximus.com/ - New user interface (config file). - Single daemon can listen on multiple ports, now. - Native Win32 GUI added. - Native NT/2000/XP service added. - Delayed DNS lookup added. * Other new features - All the timeouts are now configurable including TIMEOUTclose that can be set to 0 for MSIE and other buggy clients that do not send close_notify. - Stunnel process can be chrooted in a specified directory. - Numerical values for setuid() and setgid() are allowed, now. - Confusing code for setting certificate defaults introduced in version 3.8p3 was removed to simplify stunnel setup. There are no built-in defaults for CApath and CAfile options. - Private key file for a certificate can be kept in a separate file. Default remains to keep it in the cert file. - Manual page updated. - New FHS-compatible build system based on automake and libtool. * Bugfixes - `SSL socket closed on SSL_write' problem fixed. - Problem with localtime() crashing Solaris 8 fixed. - Problem with tcp wrappers library detection fixed. - Cygwin (http://www.cygwin.com/) support added. - __svr4__ macro defined for Sun C/C++ compiler. * DLLs for OpenSSL 0.9.6g. Version 3.22, 2001.12.20, urgency: HIGH: * Format string bug fixed in protocol.c smtp, pop3 and nntp in client mode were affected. (stunnel clients could be attacked by malicious servers) * Certificate chain can be supplied with -p option or in stunnel.pem. * Problem with -r and -l options used together fixed. * memmove() instead of memcpy() is used to move data in buffers. * More detailed information about negotiated ciphers is printed. * New ./configure options: '--enable-no-rsa' and '--enable-dh'. Version 3.21c, 2001.11.11, urgency: LOW: * autoconf scripts upgraded to version 2.52. * Problem with pthread_sigmask on Darwin fixed (I hope). * Some documentation typos corrected. * Attempt to ignore EINTR in transfer(). * Shared library version reported on startup. * DLLs for OpenSSL 0.9.6b. Version 3.21b, 2001.11.03, urgency: MEDIUM: * File descriptor leak on failed connect() fixed. Version 3.21a, 2001.10.31, urgency: MEDIUM: * Small bug in Makefile fixed. Version 3.21, 2001.10.31, urgency: MEDIUM: * Problem with errno and posix threads fixed. * It is assumed that system has getopt() if it has getopt.h header file. * SSL_CLIENT_DN and SSL_CLIENT_I_DN environment variables set in local mode (-l) process. This feature doesn't work if client mode (-c) or protocol negotiation (-n) is used. * Winsock error descriptions hardcoded (English version only). * SetConsoleCtrlHandler() used to handle CTRL+C, logoff and shutdown on Win32. * Stunnel always requests peer certificate with -v 0. * sysconf()/getrlimit() used to calculate number of clients allowed. * SSL mode changed for OpenSSL >= 0.9.6. * close-on-exec option used to avoid socket inheriting. * Buffer size increased from 8KB to 16KB. * fdscanf()/fdprintf() changes: - non-blocking socket support, - timeout after 1 minute of inactivity. * auth_user() redesigned to force 1 minute timeout. * Some source arrangement towards 4.x architecture. * No need for 'goto' any more. * New Makefile 'test' rule. It performs basic test of standalone/inetd, remote/local and server/client mode. * pop3 server mode support added. Version 3.20, 2001.08.15, urgency: LOW: * setsockopt() optlen set according to the optval for Solaris. * Minor NetBSD compatibility fixes by Martti Kuparinen. * Minor MSVC 6.0 compatibility fixes by Patrick Mayweg. * SSL close_notify timeout reduced to 10 seconds of inactivity. * Socket close instead of reset on close_notify timeout. * Some source arrangement and minor bugfixes. Version 3.19, 2001.08.10, urgency: MEDIUM: * Critical section added around non MT-safe TCP Wrappers code. * Problem with 'select: Interrupted system call' error fixed. * errno replaced with get_last_socket_error() for Win32. * Some FreeBSD/NetBSD patches to ./configure from Martti Kuparinen. * Local mode process pid logged. * Default FQDN (localhost) removed from stunnel.cnf * ./configure changed to recognize POSIX threads library on OSF. * New -O option to set socket options. Version 3.18, 2001.07.31, urgency: MEDIUM: * MAX_CLIENTS is calculated based on FD_SETSIZE, now. * Problems with closing SSL in transfer() fixed. * -I option to bind a static local IP address added. * Debug output of info_callback redesigned. Version 3.17, 2001.07.29, urgency: MEDIUM: * Problem with GPF on exit with active threads fixed. * Timeout for transfer() function added: - 1 hour if socket is open for read - 1 minute if socket is closed for read Version 3.16, 2001.07.22, urgency: MEDIUM: * Some transfer() bugfixes/improvements. * STDIN/STDOUT are no longer assumed to be non-socket descriptors. * Problem with --with-tcp-wrappers patch fixed. * pop3 and nntp support bug fixed by Martin Germann. * -o option to append log messages to a file added. * Changed error message for SSL error 0. Version 3.15, 2001.07.15, urgency: MEDIUM: * Serious bug resulting in random transfer() hangs fixed. * Separate file descriptors are used for inetd mode. * -f (foreground) logs are now stamped with time. * New ./configure option: --with-tcp-wrappers by Brian Hatch. * pop3 protocol client support (-n pop3) by Martin Germann. * nntp protocol client support (-n nntp) by Martin Germann. * RFC 2487 (smtp STARTTLS) client mode support. * Transparency support for Tru64 added. * Some #includes for AIX added. Version 3.14, 2001.02.21, urgency: LOW: * Pidfile creation algorithm has been changed. Version 3.13, 2001.01.25, urgency: MEDIUM: * pthread_sigmask() argument in sthreads.c corrected. * OOB data is now handled correctly. Version 3.12, 2001.01.24, urgency: LOW: * Attempted to fix problem with zombies in local mode. * Patch for 64-bit machines by Nalin Dahyabhai applied. * Tiny bugfix for OSF cc by Dobrica Pavlinusic added. * PORTS file updated. Version 3.11, 2000.12.21, urgency: MEDIUM: * New problem with zombies fixed. * Attempt to be integer-size independent. * SIGHUP handler added. Version 3.10, 2000.12.19, urgency: MEDIUM: * Internal thread synchronization code added. * libdl added to stunnel dependencies if it exists. * Manpage converted to sdf format. * stunnel deletes pid file before attempting to create it. * Documentation updates. * -D option now takes [facility].level as argument. 0-7 still supported. * Problems with occasional zombies in FORK mode fixed. * 'stunnel.exe' rule added to Makefile. You can cross-compile stunnel.exe on Unix, now. I'd like to be able to compile OpenSSL this way, too... Version 3.9, 2000.12.13, urgency: HIGH: * Updated temporary key generation: - stunnel is now honoring requested key-lengths correctly, - temporary key is changed every hour. * transfer() no longer hangs on some platforms. Special thanks to Peter Wagemans for the patch. * Potential security problem with syslog() call fixed. Version 3.8p4, 2000.06.25 bri@stunnel.org: * fixes for Windows platform Version 3.8p3, 2000.06.24 bri@stunnel.org: * Compile time definitions for the following: --with-cert-dir --with-cert-file --with-pem-dir --enable-ssllib-cs * use daemon() function instead of daemonize, if available * fixed FreeBSD threads checking (patch from robertw@wojo.com) * added -S flag, allowing you to choose which default verify sources to use * relocated service name output logging until after log_open. (no longer outputs log info to inetd socket, causing bad SSL) * -V flag now outputs the default values used by stunnel * Removed DH param generation in Makefile.in * Moved stunnel.pem to sample.pem to keep people from blindly using it * Removed confusing stunnel.pem check from Makefile. * UPGRADE NOTE: this version seriously changes several previous stunnel default behaviours. There are no longer any default cert file/dirs compiled into stunnel, you must use the --with-cert-dir and --with-cert-file configure arguments to set these manually, if desired. Stunnel does not use the underlying ssl library defaults by default unless configured with --enable-ssllib-cs. Note that these can always be enabled at run time with the -A,-a, and -S flags. Additionally, unless --with-pem-dir is specified at compile time, stunnel will default to looking for stunnel.pem in the current directory. Version 3.8p2, 2000.06.13 bri@stunnel.org: * Fixes for Win32 platform * Minor output formatting changes * Fixed version number in files Version 3.8p1, 2000.06.11 bri@stunnel.org: * Added rigorous PRNG seeding * PID changes (and related security-fix) * Man page fixes * Client SSL Session-IDs now used * -N flag to specify tcpwrapper service name Version 3.8, 2000.02.24: * Checking for threads in c_r library for FreeBSD. * Some compatibility fixes for Ultrix. * configure.in has been cleaned up. Separate directories for SSL certs and SSL libraries/headers are no longer supported. SSL ports maintainers should create softlinks in the main openssl directory if necessary. * Added --with-ssl option to specify SSL directory. * Added setgid (-g) option. (Special thanks to Brian Hatch for his feedback and support) * Added pty.c based on a Public Domain code by Tatu Ylonen * Distribution files are now signed with GnuPG Version 3.7, 2000.02.10: * /usr/pkg added to list of possible SSL directories for pkgsrc installs of OpenSSL under NetBSD. * Added the -s option, which setuid()s to the specified user when running in daemon mode. Useful for cyrus imapd. (both based on patch by George Coulouris) * PTY code ported to Solaris. The port needs some more testing. * Added handler for SIGINT. * Added --with-random option to ./configure script. * Fixed some problems with autoconfiguration on Solaris and others. It doesn't use config.h any more. * /var/run changed to @localstatedir@/stunnel for better portability. The directory is chmoded a=rwx,+t. * FAQ has been updated. 3.6 2000.02.03 * Automatic RFC 2487 detection based on patch by Pascual Perez and Borja Perez. * Non-blocking sockets not used by default. * DH support is disabled by default. * (both can be enabled in ssl.c) 3.5 2000.02.02 * Support for openssl 0.9.4 added. * /usr/ssl added to configure by Christian Zuckschwerdt. * Added tunneling for PPP through the addition of PTY handling. * Added some documentation. 3.4a 1999.07.13 (bugfix release) * Problem with cipher negotiation fixed. * setenv changed to putenv. 3.4 1999.07.12 * Local transparent proxy added with LD_PRELOADed shared library. * DH code rewritten. * Added -C option to set cipher list. * stderr fflushed after fprintf(). * Minor portability bugfixes. * Manual updated (but still not perfect). 3.3 1999.06.18 * Support for openssl 0.9.3 added. * Generic support for protocol negotiation added (protocol.c). * SMTP protocol negotiation support for Netscape client added. * Transparent proxy mode (currently works on Linux only). * SO_REUSEADDR enabled on listening socket in daemon mode. * ./configure now accepts --prefix parameter. * -Wall is only used with gcc compiler. * Makefile.in and configure.in updated. * SSL-related functions moved to a separate file. * vsprintf changed to vsnprintf in log.c on systems have it. * Pidfile in /var/run added for daemon mode. * RSAref support fix (not tested). * Some compatibility fixes for Solaris and NetBSD added. 3.2 1999.04.28 * RSAref support (not tested). * Added full duplex with non-blocking sockets. * RST sent instead of FIN on peer error (on error peer socket is reset - not just closed). * RSA temporary key length changed back to 512 bits to fix a problem with Netscape. * Added NO_RSA for US citizens having problems with patents. 3.1 1999.04.22 * Changed -l syntax (first argument specified is now argv[0]). * Fixed problem with options passed to locally executed daemon. * Fixed problem with ':' passed to libwrap in a service name: - ':' has been changed to '.'; - user can specify his own service name as an argument. * RSA temporary key length changed from 512 to 1024 bits. * Added safecopy to avoid buffer overflows in stunnel.c. * Fixed problems with GPF after unsuccessful resolver call and incorrect parameters passed to getopt() in Win32. * FAQ updated. 3.0 1999.04.19 * Some bugfixes. * FAQ added. 3.0b7 1999.04.14 * Win32 native port fixed (looks quite stable). * New transfer() function algorithm. * New 'make cert' to be compatible with openssl-0.9.2b. * Removed support for memory leaks debugging. 3.0b6 1999.04.01 * Fixed problems with session cache (by Adam). * Added client mode session cache. * Source structure, autoconf script and Makefile changed. * Added -D option to set debug level. * Added support for memory leaks debugging (SSL library needs to be compiled with -DMFUNC). 3.0b5 1999.03.25 * Lots of changes to make threads work. * Peer (client and server) authentication works! * Added -V option to display version. 3.0b4 1999.03.22 * Early POSIX threads implementation. * Work on porting to native Win32 application started. 3.0b3 1999.03.05 * Improved behavior on heavy load. 3.0b2 1999.03.04 * Fixed -v parsing bug. 3.0b1 1999.01.18 * New user interface. * Client mode added. * Peer certificate verification added (=strong authentication). * Win32 port added. * Other minor problems fixed. 2.1 1998.06.01 * Few bugs fixed. 2.0 1998.05.25 * Remote mode added! * Standalone mode added! * tcpd functionality added by libwrap utilization. * DH callbacks removed by kravietZ. * bind loopback on Intel and other bugs fixed by kravietZ. * New manual page by kravietZ & myself. 1.6 1998.02.24 * Linux bind fix. * New TODO ideas! 1.5 1998.02.24 * make_sockets() implemented with Internet sockets instead of Unix sockets for better compatibility. (i.e. to avoid random data returned by getpeername(2)) This feature can be disabled in stunnel.c. 1.4 1998.02.16 * Ported to HP-UX, Solaris and probably other UNIXes. * Autoconfiguration added. 1.3 1998.02.14 * Man page by Pawel Krawczyk added! * Copyrights added. * Minor errors corrected. 1.2 1998.02.14 * Separate certificate for each service added. * Connection logging support. 1.1 1998.02.14 * Callback functions added by Pawel Krawczyk . 1.0 1998.02.11 * First version with SSL support - special thx to Adam Hernik . 0.1 1998.02.10 * Testing skeleton. stunnel-5.30/COPYING0000664000175000017500000000334412451525543011121 00000000000000stunnel license (see COPYRIGHT.GPL for detailed GPL conditions) Copyright (C) 1998-2015 Michal Trojnara This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . Linking stunnel statically or dynamically with other modules is making a combined work based on stunnel. Thus, the terms and conditions of the GNU General Public License cover the whole combination. In addition, as a special exception, the copyright holder of stunnel gives you permission to combine stunnel with free software programs or libraries that are released under the GNU LGPL and with code included in the standard release of OpenSSL under the OpenSSL License (or modified versions of such code, with unchanged license). You may copy and distribute such a system following the terms of the GNU GPL for stunnel and the licenses of the other code concerned. Note that people who make modified versions of stunnel are not obligated to grant this special exception for their modified versions; it is their choice whether to do so. The GNU General Public License gives permission to release a modified version without this exception; this exception also makes it possible to release a modified version which carries forward this exception. stunnel-5.30/CREDITS0000644000175000017500000000310312413434561011072 00000000000000stunnel code contributions The code contributions are licensed as public domain unless stated otherwise. Several Win32 and WCE improvements and bugfixes: * Pierre Delaage systemd socket activation in version 5.05: Copyright (c) 2014 Mark Theunissen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Several bugfixes and improvements mostly in versions 3.xx: * Brian Hatch Initial PTY support in version 3.05: * Dirk O. Siebnich Initial SSL support in versions 1.x: * Adam Hernik * Pawel Krawczyk and many others... stunnel-5.30/INSTALL.FIPS0000664000175000017500000000177312171043343011653 00000000000000stunnel FIPS install notes Unix HOWTO: * Only dynamic linking of the FIPS-enabled OpenSSL is currently supported, i.e. FIPS-enabled OpenSSL has to be configured with "shared" parameter. * FIPS mode is autodetected if possible. It can be forced with: ./configure --enable-fips or disable with: ./configure --disable-fips WIN32 HOWTO: * On 32-bit Windows install one of the following compilers: - MSVC 8.0 (VS 2005) Standard or Professional Edition - MSVC 9.0 (VS 2008) any edition including Express Edition * On 64-bit Windows install one of the following compilers: - MSVC 8.0 (VS 2005) Standard or Professional Edition - MSVC 9.0 (VS 2008) Standard or Professional Edition * Build FIPS-compliant OpenSSL DLLS according to: https://www.openssl.org/docs/fips/UserGuide-2.0.pdf * Build stunnel normally with MSVC or Mingw. Mingw build requires DLL stubs. Stubs can be built with: dlltool --def ms/libeay32.def --output-lib libcrypto.a dlltool --def ms/ssleay32.def --output-lib libssl.a stunnel-5.30/doc/0000775000175000017500000000000012652443340010704 500000000000000stunnel-5.30/doc/stunnel.pl.html.in0000644000175000017500000016652712630656304014242 00000000000000 stunnel TLS Proxy
 stunnel TLS Proxy

NAZWA

stunnel - uniwersalny tunel protokołu SSL

SKŁADNIA

Unix:

stunnel [PLIK] | -fd N | -help | -version | -sockets | -options

WIN32:

stunnel [ [ -install | -uninstall | -start | -stop | -reload | -reopen | -exit ] [-quiet] [PLIK] ] | -help | -version | -sockets | -options

OPIS

Program stunnel został zaprojektowany do opakowywania w protokół SSL połączeń pomiędzy zdalnymi klientami a lokalnymi lub zdalnymi serwerami. Przez serwer lokalny rozumiana jest aplikacja przeznaczona do uruchamiania przy pomocy inetd. Stunnel pozwala na proste zestawienie komunikacji serwerów nie posiadających funkcjonalności SSL poprzez bezpieczne kanały SSL.

stunnel pozwala dodać funkcjonalność SSL do powszechnie stosowanych demonów inetd, np. pop3 lub imap, do samodzielnych demonów, np. nntp, smtp lub http, a nawet tunelować ppp poprzez gniazda sieciowe bez zmian w kodzie źródłowym.

OPCJE

PLIK

użyj podanego pliku konfiguracyjnego

-fd N (tylko Unix)

wczytaj konfigurację z podanego deskryptora pliku

-help

drukuj listę wspieranych opcji

-version

drukuj wersję programu i domyślne wartości parametrów

-sockets

drukuj domyślne opcje gniazd

-options

drukuj wspierane opcje SSL

-install (tylko Windows NT lub nowszy)

instaluj serwis NT

-uninstall (tylko Windows NT lub nowszy)

odinstaluj serwis NT

-start (tylko Windows NT lub nowszy)

uruchom serwis NT

-stop (tylko Windows NT lub nowszy)

zatrzymaj serwis NT

-reload (tylko Windows NT lub nowszy)

przeładuj plik konfiguracyjny uruchomionego serwisu NT

-reopen (tylko Windows NT lub nowszy)

otwórz ponownie log uruchomionego serwisu NT

-exit (tylko Win32)

zatrzymaj uruchomiony program

-quiet (tylko Win32)

nie wyświetlaj okienek z komunikatami

PLIK KONFIGURACYJNY

Linia w pliku konfiguracyjnym może być:

  • pusta (ignorowana)

  • komentarzem rozpoczynającym się znakiem ';' (ignorowana)

  • parą 'nazwa_opcji = wartość_opcji'

  • tekstem '[nazwa_usługi]' wskazującym początek definicji usługi

Parametr adres może być:

  • numerem portu

  • oddzieloną średnikiem parą adresu (IPv4, IPv6, lub nazwą domenową) i numeru portu

  • ścieżką do gniazda Unix (tylko Unix)

OPCJE GLOBALNE

chroot = KATALOG (tylko Unix)

katalog roboczego korzenia systemu plików

Opcja określa katalog, w którym uwięziony zostanie proces programu stunnel tuż po jego inicjalizacji, a przed rozpoczęciem odbierania połączeń. Ścieżki podane w opcjach CApath, CRLpath, pid oraz exec muszą być umieszczone wewnątrz katalogu podanego w opcji chroot i określone względem tego katalogu.

Niektóre funkcje systemu operacyjnego mogą wymagać dodatkowych plików umieszczonych w katalogu podanego w parametrze chroot:

  • opóźnione rozwinięcie adresów DNS typowo wymaga /etc/nsswitch.conf i /etc/resolv.conf

  • lokalizacja strefy czasowej w logach wymaga pliku /etc/timezone

  • niektóre inne pliki mogą potrzebować plików urządzeń, np. /dev/zero lub /dev/null

compression = deflate | zlib

wybór algorytmu kompresji przesyłanych danych

domyślnie: bez kompresji

Algorytm deflate jest standardową metodą kompresji zgodnie z RFC 1951.

Kompresja zlib zaimplementowana w OpenSSL 0.9.8 i nowszych nie jest kompatybilna implementacją OpenSSL 0.9.7.

debug = [PODSYSTEM].POZIOM

szczegółowość logowania

Poziom logowania można określić przy pomocy jednej z nazw lub liczb: emerg (0), alert (1), crit (2), err (3), warning (4), notice (5), info (6) lub debug (7). Zapisywane są komunikaty o poziomie niższym (numerycznie) lub równym podanemu. Do uzyskania najwyższego poziomu szczegółowości można użyć opcji debug = debug lub debug = 7. Domyślnym poziomem jest notice (5).

O ile nie wyspecyfikowano podsystemu użyty będzie domyślny: daemon. Podsystemy nie są wspierane przez platformę Win32.

Wielkość liter jest ignorowana zarówno dla poziomu jak podsystemu.

EGD = ŚCIEŻKA_DO_EGD (tylko Unix)

ścieżka do gniazda programu Entropy Gathering Daemon

Opcja pozwala określić ścieżkę do gniazda programu Entropy Gathering Daemon używanego do zainicjalizowania generatora ciągów pseudolosowych biblioteki OpenSSL. Opcja jest dostępna z biblioteką OpenSSL 0.9.5a lub nowszą.

engine = auto | IDENTYFIKATOR_URZĄDZENIA

wybór sprzętowego urządzenia kryptograficznego

domyślnie: bez wykorzystania urządzeń kryptograficznych

Przykładowa konfiguracja umożliwiająca użycie certyfikatu i klucza prywatnego z urządzenia zgodnego z OpenSC:

    engine = dynamic
    engineCtrl = SO_PATH:/usr/local/lib/engines/libpkcs11.so
    engineCtrl = LOAD
    engineCtrl = MODULE_PATH:opensc-pkcs11.so
    engineCtrl = PIN:123456

    [service]
    engineId = pkcs11
    cert = id_45
engineCtrl = KOMENDA[:PARAMETR]

konfiguracja urządzenia kryptograficznego

Specjalna komenda "LOAD" pozwala na załadowanie modułu urządzenia kryptograficznego.

engineDefault = LISTA_ZADAŃ

lista zadań OpenSSL oddelegowanych do bieżącego urządzenia

Parametrem jest lista oddzielonych przecinkami zadań OpenSSL, które mają zostać oddelegowane do bieżącego urządzenia kryptograficznego.

W zależności od konkretnego urządzenia dostępne mogą być następujące zadania: ALL, RSA, DSA, ECDH, ECDSA, DH, RAND, CIPHERS, DIGESTS, PKEY, PKEY_CRYPTO, PKEY_ASN1.

fips = yes | no

tryb FIPS 140-2

Opcja pozwala wyłączyć wejście w tryb FIPS, jeśli stunnel został skompilowany ze wsparciem dla FIPS 140-2.

domyślnie: no (od wersji 5.00)

foreground = yes | quiet | no (tylko Unix)

tryb pierwszoplanowy

Użycie tej opcji powoduje, że stunnel nie przechodzi w tło.

Parametr yes powoduje dodatkowo, że komunikaty diagnostyczne logowane są na standardowy strumień błędów (stderr) oprócz wyjść zdefiniowanych przy pomocy opcji syslog i output.

iconActive = PLIK_Z_IKONKĄ (tylko GUI)

ikonka wyświetlana przy obecności aktywnych połączeń do usługi

W systemie Windows ikonka to plik .ico zawierający obrazek 16x16 pikseli.

iconError = PLIK_Z_IKONKĄ (tylko GUI)

ikonka wyświetlana, jeżeli nie został załadowany poprawny plik konfiguracyjny

W systemie Windows ikonka to plik .ico zawierający obrazek 16x16 pikseli.

iconIdle = PLIK_Z_IKONKĄ (tylko GUI)

ikonka wyświetlana przy braku aktywnych połączeń do usługi

W systemie Windows ikonka to plik .ico zawierający obrazek 16x16 pikseli.

log = append | overwrite

log file handling

This option allows to choose whether the log file (specified with the output option) is appended or overwritten when opened or re-opened.

domyślnie: append

output = PLIK

plik, do którego dopisane zostaną logi

Użycie tej opcji powoduje dopisanie logów do podanego pliku.

Do kierowaniakomunikatów na standardowe wyjście (na przykład po to, żeby zalogować je programem splogger z pakietu daemontools) można podać jako parametr urządzenie /dev/stdout.

pid = PLIK (tylko Unix)

położenie pliku z numerem procesu

Jeżeli argument jest pusty plik nie zostanie stworzony.

Jeżeli zdefiniowano katalog chroot, to ścieżka do pid jest określona względem tego katalogu.

RNDbytes = LICZBA_BAJTÓW

liczba bajtów do zainicjowania generatora pseudolosowego

W wersjach biblioteki OpenSSL starszych niż 0.9.5a opcja ta określa również liczbę bajtów wystarczających do zainicjowania PRNG. Nowsze wersje biblioteki mają wbudowaną funkcję określającą, czy dostarczona ilość losowości jest wystarczająca do zainicjowania generatora.

RNDfile = PLIK

ścieżka do pliku zawierającego losowe dane

Biblioteka OpenSSL użyje danych z tego pliku do zainicjowania generatora pseudolosowego.

RNDoverwrite = yes | no

nadpisz plik nowymi wartościami pseudolosowymi

domyślnie: yes (nadpisz)

service = SERWIS (tylko Unix)

nazwa usługi

Podana nazwa usługi będzie używana jako nazwa usługi dla inicjalizacji sysloga, oraz dla biblioteki TCP Wrapper w trybie inetd. Chociaż technicznie można użyć tej opcji w trybie w sekcji usług, to jest ona użyteczna jedynie w opcjach globalnych.

domyślnie: stunnel

socket = a|l|r:OPCJA=WARTOŚĆ[:WARTOŚĆ]

ustaw opcję na akceptującym/lokalnym/zdalnym gnieździe

Dla opcji linger wartości mają postać l_onof:l_linger. Dla opcji time wartości mają postać tv_sec:tv_usec.

Przykłady:

    socket = l:SO_LINGER=1:60
        ustaw jednominutowe przeterminowanie
        przy zamykaniu lokalnego gniazda
    socket = r:SO_OOBINLINE=yes
        umieść dane pozapasmowe (out-of-band)
        bezpośrednio w strumieniu danych
        wejściowych dla zdalnych gniazd
    socket = a:SO_REUSEADDR=no
        zablokuj ponowne używanie portu
        (domyślnie włączone)
    socket = a:SO_BINDTODEVICE=lo
        przyjmuj połączenia wyłącznie na
        interfejsie zwrotnym (ang. loopback)
syslog = yes | no (tylko Unix)

włącz logowanie poprzez mechanizm syslog

domyślnie: yes (włącz)

taskbar = yes | no (tylko WIN32)

włącz ikonkę w prawym dolnym rogu ekranu

domyślnie: yes (włącz)

OPCJE USŁUG

Każda sekcja konfiguracji usługi zaczyna się jej nazwą ujętą w nawias kwadratowy. Nazwa usługi używana jest do kontroli dostępu przez bibliotekę libwrap (TCP wrappers) oraz pozwala rozróżnić poszczególne usługi w logach.

Jeżeli stunnel ma zostać użyty w trybie inetd, gdzie za odebranie połączenia odpowiada osobny program (zwykle inetd, xinetd lub tcpserver), należy przeczytać sekcję TRYB INETD poniżej.

accept = [HOST:]PORT

nasłuchuje na połączenia na podanym adresie i porcie

Jeżeli nie został podany adres, stunnel domyślnie nasłuchuje na wszystkich adresach IPv4 lokalnych interfejsów.

Aby nasłuchiwać na wszystkich adresach IPv6 należy użyć:

    accept = :::port
CApath = KATALOG_CA

katalog Centrum Certyfikacji

Opcja określa katalog, w którym stunnel będzie szukał certyfikatów, jeżeli użyta została opcja verify. Pliki z certyfikatami muszą posiadać specjalne nazwy XXXXXXXX.0, gdzie XXXXXXXX jest skrótem kryptograficznym reprezentacji DER nazwy podmiotu certyfikatu.

Funkcja skrótu została zmieniona w OpenSSL 1.0.0. Należy wykonać c_rehash przy zmianie OpenSSL 0.x.x na 1.x.x.

Jeżeli zdefiniowano katalog chroot, to ścieżka do CApath jest określona względem tego katalogu.

CAfile = PLIK_CA

plik Centrum Certyfikacji

Opcja pozwala określić położenie pliku zawierającego certyfikaty używane przez opcję verify.

cert = PLIK_PEM

plik z łańcuchem certyfikatów

Opcja określa położenie pliku zawierającego certyfikaty używane przez program stunnel do uwierzytelnienia się przed drugą stroną połączenia. Certyfikat jest konieczny, aby używać programu w trybie serwera. W trybie klienta certyfikat jest opcjonalny.

Jeżeli używane jest sprzętowe urządzenie kryptograficzne, to opcja cert pozwala wybrać identyfikator używanego certyfikatu.

checkEmail = EMAIL

adres email przedstawionego certyfikatu

Pojedyncza sekcja może zawierać wiele wystąpień opcji checkEmail. Certyfikaty są akceptowane, jeżeli sekcja nie zawiera opcji checkEmail, albo adres email przedstawionego certyfikatu pasuje do jednego z adresów email określonych przy pomocy checkEmail.

Opcja ta wymaga biblioteki OpenSSL w wersji 1.0.2 lub nowszej.

checkHost = NAZWA_SERWERA

nazwa serwera przedstawionego certyfikatu

Pojedyncza sekcja może zawierać wiele wystąpień opcji checkHost. Certyfikaty są akceptowane, jeżeli sekcja nie zawiera opcji checkHost, albo nazwa serwera przedstawionego certyfikatu pasuje do jednego nazw określonych przy pomocy checkHost.

Opcja ta wymaga biblioteki OpenSSL w wersji 1.0.2 lub nowszej.

checkIP = IP

adres IP przedstawionego certyfikatu

Pojedyncza sekcja może zawierać wiele wystąpień opcji checkIP. Certyfikaty są akceptowane, jeżeli sekcja nie zawiera opcji checkIP, albo adres IP przedstawionego certyfikatu pasuje do jednego z adresów IP określonych przy pomocy checkIP.

Opcja ta wymaga biblioteki OpenSSL w wersji 1.0.2 lub nowszej.

ciphers = LISTA_SZYFRÓW

lista dozwolonych szyfrów SSL

Parametrem tej opcji jest lista szyfrów, które będą użyte przy otwieraniu nowych połączeń SSL, np.: DES-CBC3-SHA:IDEA-CBC-MD5

client = yes | no

tryb kliencki (zdalna usługa używa SSL)

domyślnie: no (tryb serwerowy)

config = KOMENDA[:PARAMETR]

komenda konfiguracyjna OpenSSL

Komenda konfiguracyjna OpenSSL zostaje wykonana z podanym parametrem. Pozwala to na wydawanie komend konfiguracyjnych OpenSSL z pliku konfiguracyjnego stunnela. Dostępne komendy opisane są w manualu SSL_CONF_cmd(3ssl).

Możliwe jest wyspecyfikowanie wielu opcji OpenSSL przez wielokrotne użycie komendy config.

Opcja ta wymaga biblioteki OpenSSL w wersji 1.0.2 lub nowszej.

connect = [HOST:]PORT

połącz się ze zdalnym serwerem na podany port

Jeżeli nie został podany adres, stunnel domyślnie łączy się z lokalnym serwerem.

Komenda może być użyta wielokrotnie w pojedynczej sekcji celem zapewnienia wysokiej niezawodności lub rozłożenia ruchu pomiędzy wiele serwerów.

CRLpath = KATALOG_CRL

katalog List Odwołanych Certyfikatów (CRL)

Opcja określa katalog, w którym stunnel będzie szukał list CRL, jeżeli użyta została opcja verify. Pliki z listami CRL muszą posiadać specjalne nazwy XXXXXXXX.r0, gdzie XXXXXXXX jest skrótem listy CRL.

Funkcja skrótu została zmieniona OpenSSL 1.0.0. Należy wykonać c_rehash przy zmianie OpenSSL 0.x.x na 1.x.x.

Jeżeli zdefiniowano katalog chroot, to ścieżka do CRLpath jest określona względem tego katalogu.

CRLfile = PLIK_CRL

plik List Odwołanych Certyfikatów (CRL)

Opcja pozwala określić położenie pliku zawierającego listy CRL używane przez opcję verify.

curve = NID

krzywa dla ECDH

Listę dostępnych krzywych można uzyskać poleceniem:

    openssl ecparam -list_curves

domyślnie: prime256v1

logId = TYP

typ identyfikatora połączenia klienta

Identyfikator ten pozwala rozróżnić wpisy w logu wygenerowane dla poszczególnych połączeń.

Aktualnie wspierane typy:

sequential

Kolejny numer połączenia jest unikalny jedynie w obrębie pojedynczej instancji programu stunnel, ale bardzo krótki. Jest on szczególnie użytczny przy ręcznej analizie logów.

unique

Ten rodzaj identyfikatora jest globalnie unikalny, ale znacznie dłuższy, niż kolejny numer połączenia. Jest on szczególnie użyteczny przy zautomatyzowanej analizie logów.

thread

Identyfikator wątku systemu operacyjnego nie jest ani unikalny (nawet w obrębie pojedynczej instancji programu stunnel), ani krótki. Jest on szczególnie użyteczny przy diagnozowaniu problemów z oprogramowaniem lub konfiguracją.

domyślnie: sequential

debug = POZIOM

szczegółowość logowania

Poziom logowania można określić przy pomocy jednej z nazw lub liczb: emerg (0), alert (1), crit (2), err (3), warning (4), notice (5), info (6) lub debug (7). Zapisywane są komunikaty o poziomie niższym (numerycznie) lub równym podanemu. Do uzyskania najwyższego poziomu szczegółowości można użyć opcji debug = debug lub debug = 7. Domyślnym poziomem jest notice (5).

delay = yes | no

opóźnij rozwinięcie adresu DNS podanego w opcji connect

Opcja jest przydatna przy dynamicznym DNS, albo gdy usługa DNS nie jest dostępna przy starcie programu stunnel (klient VPN, połączenie wdzwaniane).

Opóźnione rozwijanie adresu DNS jest włączane automatycznie, jeżeli nie powiedzie się rozwinięcie któregokolwiek z adresów connect dla danej usługi.

Opóźnione rozwijanie adresu automatycznie aktywuje failover = prio.

default: no

engineId = NUMER_URZĄDZENIA

wybierz urządzenie dla usługi

engineNum = NUMER_URZĄDZENIA

wybierz urządzenie dla usługi

Urządzenia są numerowane od 1 w górę.

exec = ŚCIEŻKA_DO_PROGRAMU

wykonaj lokalny program przystosowany do pracy z superdemonem inetd

Jeżeli zdefiniowano katalog chroot, to ścieżka do exec jest określona względem tego katalogu.

Na platformach Unix ustawiane są następujące zmienne środowiskowe: REMOTE_HOST, REMOTE_PORT, SSL_CLIENT_DN, SSL_CLIENT_I_DN.

execArgs = $0 $1 $2 ...

argumenty do opcji exec włącznie z nazwą programu ($0)

Cytowanie nie jest wspierane w obecnej wersji programu. Argumenty są rozdzielone dowolną liczbą białych znaków.

failover = rr | prio

Strategia wybierania serwerów wyspecyfikowanych parametrami "connect".

    rr (round robin) - sprawiedliwe rozłożenie obciążenia
    prio (priority) - użyj kolejności opcji w pliku konfiguracyjnym

domyślnie: rr

ident = NAZWA_UŻYTKOWNIKA

weryfikuj nazwę zdalnego użytkownika korzystając z protokołu IDENT (RFC 1413)

include = KATALOG

wczytaj fragmenty plików konfiguracyjnych z podanego katalogu

Pliki są wczytywane w rosnącej kolejności alfabetycznej ich nazw.

key = PLIK_KLUCZA

klucz prywatny do certyfikatu podanego w opcji cert

Klucz prywatny jest potrzebny do uwierzytelnienia właściciela certyfikatu. Ponieważ powinien on być zachowany w tajemnicy, prawa do jego odczytu powinien mieć wyłącznie właściciel pliku. W systemie Unix można to osiągnąć komendą:

    chmod 600 keyfile

Jeżeli używane jest sprzętowe urządzenie kryptograficzne, to opcja key pozwala wybrać identyfikator używanego klucza prywatnego.

domyślnie: wartość opcji cert

libwrap = yes | no

włącz lub wyłącz korzystanie z /etc/hosts.allow i /etc/hosts.deny.

domyślnie: no (od wersji 5.00)

local = HOST

IP źródła do nawiązywania zdalnych połączeń

Domyślnie używane jest IP najbardziej zewnętrznego interfejsu w stronę serwera, do którego nawiązywane jest połączenie.

sni = USŁUGA:WZORZEC_NAZWY_SERWERA (tryb serwera)

Użyj usługi jako podrzędnej (virtualnego serwera) dla rozszerzenia TLS Server Name Indication (RFC 3546).

nazwa_usługi wskazuje usługę nadrzędną, która odbiera połączenia od klientów przy pomocy opcji accept. wzorzec_nazwy_serwera wskazuje nazwę serwera wirtualnego. Wzorzec może zaczynać się znakiem '*', np. '*.example.com". Z pojedyńczą usługą nadrzędną powiązane jest zwykle wiele usług podrzędnych. Opcja sni może być rownież użyta wielokrotnie w ramach jednej usługi podrzędnej.

Zarówno usługa nadrzędna jak i podrzędna nie może być skonfigurowana w trybie klienckim.

Opcja connect usługi podrzędnej jest ignorowana w połączeniu z opcją protocol, gdyż połączenie do zdalnego serwera jest w tym wypadku nawiązywane przed negocjacją TLS.

Uwierzytelnienie przy pomocy biblioteki libwrap jest realizowane dwukrotnie: najpierw dla usługi nadrzędnej po odebraniu połączenia TCP, a następnie dla usługi podrzędnej podczas negocjacji TLS.

Opcja sni jest dostępna począwszy od OpenSSL 1.0.0.

sni = HOST (tryb klienta)

Użyj parametru jako wartości rozszerzenia TLS Server Name Indication (RFC 3546).

Opcja sni jest dostępna począwszy od OpenSSL 1.0.0.

OCSP = URL

responder OCSP do weryfikacji certyfikatów

OCSPaia = yes | no

weryfikuj certyfikaty przy użyciu respondertów AIA

Opcja OCSPaia pozwala na weryfikowanie certyfikatów przy pomocy listy URLi responderów OCSP przesłanych w rozszerzeniach AIA (Authority Information Access).

OCSPflag = FLAGA_OCSP

flaga respondera OCSP

aktualnie wspierane flagi: NOCERTS, NOINTERN NOSIGS, NOCHAIN, NOVERIFY, NOEXPLICIT, NOCASIGN, NODELEGATED, NOCHECKS, TRUSTOTHER, RESPID_KEY, NOTIME

Aby wyspecyfikować kilka flag należy użyć OCSPflag wielokrotnie.

OCSPnonce = yes | no

wysyłaj i weryfikuj OCSP nonce

Opcja OCSPnonce zabezpiecza protokół OCSP przed atakami powtórzeniowymi. Ze względu na złożoność obliczeniową rozszerzenie nonce jest zwykle wspierane jedynie przez wewnętrzne (np. korporacyjne), a nie przez publiczne respondery OCSP.

options = OPCJE_SSL

opcje biblioteki OpenSSL

Parametrem jest nazwa opcji zgodnie z opisem w SSL_CTX_set_options(3ssl), ale bez przedrostka SSL_OP_. stunnel -options wyświetla opcje dozwolone w aktualnej kombinacji programu stunnel i biblioteki OpenSSL.

Aby wyspecyfikować kilka opcji należy użyć options wielokrotnie. Nazwa opcji może być poprzedzona myślnikiem ("-") celem wyłączenia opcji.

Na przykład, dla zachowania kompatybilności z błędami implementacji SSL w programie Eudora, można użyć opcji:

    options = DONT_INSERT_EMPTY_FRAGMENTS

domyślnie:

    options = NO_SSLv2
    options = NO_SSLv3
protocol = PROTOKÓŁ

negocjuj SSL podanym protokołem aplikacyjnym

Opcja ta włącza wstępną negocjację szyfrowania SSL dla wybranego protokołu aplikacyjnego. Opcji protocol nie należy używać z szyfrowaniem SSL na osobnym porcie.

Aktualnie wspierane protokoły:

cifs

Unieudokumentowane rozszerzenie protokołu CIFS wspierane przez serwer Samba. Wsparcie dla tego rozrzeczenia zostało zarzucone w wersji 3.0.0 serwera Samba.

connect

Negocjacja RFC 2817 - Upgrading to TLS Within HTTP/1.1, rozdział 5.2 - Requesting a Tunnel with CONNECT

Ten protokół jest wspierany wyłącznie w trybie klienckim.

imap

Negocjacja RFC 2595 - Using TLS with IMAP, POP3 and ACAP

nntp

Negocjacja RFC 4642 - Using Transport Layer Security (TLS) with Network News Transfer Protocol (NNTP)

Ten protokół jest wspierany wyłącznie w trybie klienckim.

pgsql

Negocjacja http://www.postgresql.org/docs/8.3/static/protocol-flow.html#AEN73982

pop3

Negocjacja RFC 2449 - POP3 Extension Mechanism

proxy

Przekazywanie adresu IP haproxy http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt

smtp

Negocjacja RFC 2487 - SMTP Service Extension for Secure SMTP over TLS

socks

Wspierany jest protokół SOCKS w wersjach 4, 4a i 5. Protokół SOCKS enkapsulowany jest w protokole SSL/TLS, więc adres serwera docelowego nie jest widoczny dla napastnika przechwytującego ruch sieciowy.

http://www.openssh.com/txt/socks4.protocol

http://www.openssh.com/txt/socks4a.protocol

Nie jest wspierana komenda BIND protokołu SOCKS. Przesłana wartość parametru USERID jest ignorowana.

Sekcja PRZYKŁADY zawiera przykładowe pliki konfiguracyjne VPNa zbudowanego w oparciu o szyfrowany protokół SOCKS.

protocolAuthentication = UWIERZYTELNIENIE

rodzaj uwierzytelnienia do negocjacji protokołu

Opcja ta jest wpierana wyłącznie w klienckich protokołach 'connect' i 'smtp'.

W protokole 'connect' wspierane jest uwierzytelnienie 'basic' oraz 'ntlm'. Domyślnym rodzajem uwierzytelnienia protokołu 'connect' jest 'basic'.

W protokole 'smtp' wspierane jest uwierzytelnienie 'plain' oraz 'login'. Domyślnym rodzajem uwierzytelnienia protokołu 'smtp' jest 'plain'.

protocolDomain = DOMENA

domena do negocjacji protokołu

W obecnej wersji wybrana domena ma zastosowanie wyłącznie w protokole 'connect'.

protocolHost = HOST:PORT

adres docelowy do negocjacji protokołu

protocolHost określa docelowy serwer SSL, do którego połączyć ma się proxy. Nie jest to adres serwera proxy, do którego połączenie zestawia stunnel. Adres serwera proxy powinien być określony przy pomocy opcji 'connect'.

W obecnej wersji adres docelowy protokołu ma zastosowanie wyłącznie w protokole 'connect'.

protocolPassword = HASŁO

hasło do negocjacji protokołu

Opcja ta jest wspierana wyłącznie w klienckich protokołach 'connect' i 'smtp'.

protocolUsername = UŻYTKOWNIK

nazwa użytkownika do negocjacji protokołu

Opcja ta jest wspierana wyłącznie w klienckich protokołach 'connect' i 'smtp'.

PSKidentity = TOŻSAMOŚĆ

tożsamość klienta PSK

PSKidentity może zostać użyte w sekcjach klienckich do wybrania tożsamości użytej do uwierzytelnienia PSK. Opcja jest ignorowana w sekcjach serwerowych.

domyślnie: pierwsza tożsamość zdefiniowana w pliku PSKsecrets

PSKsecrets = PLIK

plik z tożsamościami i kluczami PSK

Każda linia pliku jest w następującym formacie:

    TOŻSAMOŚĆ:KLUCZ

Klucz musi być mieć przynajmniej 20 znaków. Należy ograniczyć dostęp do czytania lub pisania do tego pliku.

pty = yes | no (tylko Unix)

alokuj pseudoterminal dla programu uruchamianego w opcji 'exec'

redirect = [HOST:]PORT

przekieruj klienta, któremu nie udało się poprawnie uwierzytelnić przy pomocy certyfikatu

Opcja działa wyłącznie w trybie serwera. Część negocjacji protokołów jest niekompatybilna z opcją redirect.

renegotiation = yes | no

pozwalaj na renegocjację SSL

Wśród zastosowań renegocjacji SSL są niektóre scenariusze uwierzytelnienia, oraz renegocjacja kluczy dla długotrwałych połączeń.

Z drugiej strony własność na może ułatwić trywialny atak DoS poprzez wygenerowanie obciążenia procesora:

http://vincent.bernat.im/en/blog/2011-ssl-dos-mitigation.html

Warto zauważyć, że zablokowanie renegocjacji SSL nie zebezpiecza w pełni przed opisanym problemem.

domyślnie: yes (o ile wspierane przez OpenSSL)

reset = yes | no

sygnalizuj wystąpienie błędu przy pomocy flagi TCP RST

Opcja nie jest wspierana na niektórych platformach.

domyślnie: yes

retry = yes | no

połącz ponownie sekcję connect+exec po rozłączeniu

domyślnie: no

setgid = IDENTYFIKATOR_GRUPY (tylko Unix)

identyfikator grupy Unix

Jako opcja globalna: grupa, z której prawami pracował będzie stunnel.

Jako opcja usługi: grupa gniazda Unix utworzonego przy pomocy opcji "accept".

setuid = IDENTYFIKATOR_UŻYTKOWNIKA (tylko Unix)

identyfikator użytkownika Unix

Jako opcja globalna: użytkownik, z którego prawami pracował będzie stunnel.

Jako opcja usługi: właściciel gniazda Unix utworzonego przy pomocy opcji "accept".

sessionCacheSize = LICZBA_POZYCJI_CACHE

rozmiar pamięci podręcznej sesji SSL

Parametr określa maksymalną liczbę pozycji wewnętrznej pamięci podręcznej sesji.

Wartość 0 oznacza brak ograniczenia rozmiaru. Nie jest to zalecane dla systemów produkcyjnych z uwagi na ryzyko ataku DoS przez wyczerpanie pamięci RAM.

sessionCacheTimeout = LICZBA_SEKUND

przeterminowanie pamięci podręcznej sesji SSL

Parametr określa czas w sekundach, po którym sesja SSL zostanie usunięta z pamięci podręcznej.

sessiond = HOST:PORT

adres sessiond - servera cache sesji SSL

sslVersion = WERSJA_SSL

wersja protokołu SSL

Wspierane opcje: all, SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2

Dostępność konkretnych protokołów zależy od użytej wersji OpenSSL. Starsze wersje OpenSSL nie wspierają TLSv1.1 i TLSv1.2. Nowsze wersje OpenSSL nie wspierają SSLv2.

Przestarzałe protokoły SSLv2 i SSLv3 są domyślnie wyłączone. Szczegółowe informacje dostępne są w opisie opcji options.

stack = LICZBA_BAJTÓW (z wyjątkiem modelu FORK)

rozmiar stosu procesora wątku

TIMEOUTbusy = LICZBA_SEKUND

czas oczekiwania na spodziewane dane

TIMEOUTclose = LICZBA_SEKUND

czas oczekiwania na close_notify (ustaw na 0, jeżeli klientem jest MSIE)

TIMEOUTconnect = LICZBA_SEKUND

czas oczekiwania na nawiązanie połączenia

TIMEOUTidle = LICZBA_SEKUND

maksymalny czas utrzymywania bezczynnego połączenia

transparent = none | source | destination | both (tylko Unix)

tryb przezroczystego proxy na wspieranych platformach

Wspierane opcje:

none

Zablokuj wsparcie dla przezroczystago proxy. Jest to wartość domyślna.

source

Przepisz adres, aby nawiązywane połączenie wydawało się pochodzić bezpośrednio od klienta, a nie od programu stunnel.

Opcja jest aktualnie obsługiwana w:

Trybie zdalnym (opcja connect) w systemie Linux >=2.6.28

Konfiguracja wymaga następujących ustawień iptables oraz routingu (na przykład w pliku /etc/rc.local lub analogicznym):

    iptables -t mangle -N DIVERT
    iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT
    iptables -t mangle -A DIVERT -j MARK --set-mark 1
    iptables -t mangle -A DIVERT -j ACCEPT
    ip rule add fwmark 1 lookup 100
    ip route add local 0.0.0.0/0 dev lo table 100
    echo 0 >/proc/sys/net/ipv4/conf/lo/rp_filter

Konfiguracja ta wymaga, aby stunnel był wykonywany jako root i bez opcji setuid.

Trybie zdalnym (opcja connect) w systemie Linux 2.2.x

Konfiguracja ta wymaga skompilowania jądra z opcją transparent proxy. Docelowa usługa musi być umieszczona na osobnej maszynie, do której routing kierowany jest poprzez serwer stunnela.

Dodatkowo stunnel powinien być wykonywany jako root i bez opcji setuid.

Trybie zdalnym (opcja connect) w systemie FreeBSD >=8.0

Konfiguracja ta wymaga skonfigurowania firewalla i routingu. stunnel musi być wykonywany jako root i bez opcji setuid.

Trybie lokalnym (opcja exec)

Konfiguracja ta jest realizowana przy pomocy biblioteki libstunnel.so. Do załadowania biblioteki wykorzystywana jest zmienna środowiskowa _RLD_LIST na platformie Tru64 lub LD_PRELOAD na innych platformach.

destination

Oryginalny adres docelowy jest używany zamiast opcji connect.

Przykładowana konfiguracja przezroczystego adresu docelowego:

    [transparent]
    client = yes
    accept = <port_stunnela>
    transparent = destination

Konfiguracja wymaga ustawień iptables, na przykład w pliku /etc/rc.local lub analogicznym.

W przypadku docelowej usługi umieszczonej na tej samej maszynie:

    /sbin/iptables -t nat -I OUTPUT -p tcp --dport <port_przekierowany> \
        -m ! --uid-owner <identyfikator_użytkownika_stunnela> \
        -j DNAT --to-destination <lokalne_ip>:<lokalny_port>

W przypadku docelowej usługi umieszczonej na zdalnej maszynie:

    /sbin/iptables -I INPUT -i eth0 -p tcp --dport <port_stunnela> -j ACCEPT
    /sbin/iptables -t nat -I PREROUTING -p tcp --dport <port_przekierowany> \
        -i eth0 -j DNAT --to-destination <lokalne_ip>:<port_stunnela>

Przezroczysty adres docelowy jest aktualnie wspierany wyłącznie w systemie Linux.

both

Użyj przezroczystego proxy zarówno dla adresu źródłowego jak i docelowego.

Dla zapewnienia kompatybilności z wcześniejszymim wersjami wspierane są dwie dodatkowe opcje:

yes

Opcja została przemianowana na source.

no

Opcja została przemianowana na none.

verify = POZIOM

weryfikuj certyfikat drugiej strony połączenia

poziom 0

zarządaj certyfikatu i zignoruj go

poziom 1

weryfikuj, jeżeli został przedstawiony

poziom 2

weryfikuj z zainstalowanym certyfikatem Centrum Certyfikacji

poziom 3

weryfikuj z lokalnie zainstalowanym certyfikatem drugiej strony

poziom 4

weryfikuj z certyfikatem drugiej strony ignorując łańcuch CA

domyślnie

nie weryfikuj

ZWRACANA WARTOŚĆ

stunnel zwraca zero w przypadku sukcesu, lub wartość niezerową w przypadku błędu.

SIGNAŁY

Następujące sygnały mogą być użyte do sterowania programem w systemie Unix:

SIGHUP

Załaduj ponownie plik konfiguracyjny.

Niektóre globalne opcje nie będą przeładowane:

  • chroot

  • foreground

  • pid

  • setgid

  • setuid

Jeżeli wykorzystywana jest opcja 'setuid' stunnel nie będzie mógł załadować ponownie konfiguracji wykorzystującej uprzywilejowane (<1024) porty.

Jeżeli wykorzystywana jest opcja 'chroot' stunnel będzie szukał wszystkich potrzebnych plików (łącznie z plikiem konfiguracyjnym, certyfikatami, logiem i plikiem pid) wewnątrz katalogu wskazanego przez 'chroot'.

SIGUSR1

Zamknij i otwórz ponownie log. Funkcja ta może zostać użyta w skrypcie rotującym log programu stunnel.

SIGTERM, SIGQUIT, SIGINT

Zakończ działanie programu.

Skutek wysłania innych sygnałów jest niezdefiniowany.

PRZYKŁADY

Szyfrowanie połączeń do lokalnego serwera imapd można użyć:

    [imapd]
    accept = 993
    exec = /usr/sbin/imapd
    execArgs = imapd

albo w trybie zdalnym:

    [imapd]
    accept = 993
    connect = 143

Aby umożliwić lokalnemu klientowi poczty elektronicznej korzystanie z serwera imapd przez SSL należy skonfigurować pobieranie poczty z adresu localhost i portu 119, oraz użyć następującej konfiguracji:

    [imap]
    client = yes
    accept = 143
    connect = serwer:993

W połączeniu z programem pppd stunnel pozwala zestawić prosty VPN. Po stronie serwera nasłuchującego na porcie 2020 jego konfiguracja może wyglądać następująco:

    [vpn]
    accept = 2020
    exec = /usr/sbin/pppd
    execArgs = pppd local
    pty = yes

Poniższy plik konfiguracyjny może być wykorzystany do uruchomienia programu stunnel w trybie inetd. Warto zauważyć, że w pliku konfiguracyjnym nie ma sekcji [nazwa_usługi].

    exec = /usr/sbin/imapd
    execArgs = imapd

Aby skonfigurować VPN można użyć następującej konfiguracji klienta:

    [socks_client]
    client = yes
    accept = 127.0.0.1:1080
    connect = vpn_server:9080
    verify = 4
    CAfile = stunnel.pem

Odpowiadająca jej konfiguracja serwera vpn_server:

    [socks_server]
    protocol = socks
    accept = 9080
    cert = stunnel.pem
    key = stunnel.key

Do przetestowania konfiguracji można wydać na maszynie klienckiej komendę:

    curl --socks4a localhost http://www.example.com/

NOTKI

OGRANICZENIA

stunnel nie może być używany do szyfrowania protokołu FTP, ponieważ do przesyłania poszczególnych plików używa on dodatkowych połączeń otwieranych na portach o dynamicznie przydzielanych numerach. Istnieją jednak specjalne wersje klientów i serwerów FTP pozwalające na szyfrowanie przesyłanych danych przy pomocy protokołu SSL.

TRYB INETD (tylko Unix)

W większości zastosowań stunnel samodzielnie nasłuchuje na porcie podanym w pliku konfiguracyjnym i tworzy połączenie z innym portem podanym w opcji connect lub nowym programem podanym w opcji exec. Niektórzy wolą jednak wykorzystywać oddzielny program, który odbiera połączenia, po czym uruchamia program stunnel. Przykładami takich programów są inetd, xinetd i tcpserver.

Przykładowa linia pliku /etc/inetd.conf może wyglądać tak:

    imaps stream tcp nowait root @bindir@/stunnel
        stunnel @sysconfdir@/stunnel/imaps.conf

Ponieważ w takich przypadkach połączenie na zdefiniowanym porcie (tutaj imaps) nawiązuje osobny program (tutaj inetd), stunnel nie może używać opcji accept. W pliku konfiguracyjnym nie może być również zdefiniowana żadna usługa ([nazwa_usługi]), ponieważ konfiguracja taka pozwala na nawiązanie tylko jednego połączenia. Wszystkie OPCJE USŁUG powinny być umieszczone razem z opcjami globalnymi. Przykład takiej konfiguracji znajduje się w sekcji PRZYKŁADY.

CERTYFIKATY

Protokół SSL wymaga, aby każdy serwer przedstawiał się nawiązującemu połączenie klientowi prawidłowym certyfikatem X.509. Potwierdzenie tożsamości serwera polega na wykazaniu, że posiada on odpowiadający certyfikatowi klucz prywatny. Najprostszą metodą uzyskania certyfikatu jest wygenerowanie go przy pomocy wolnego pakietu OpenSSL. Więcej informacji na temat generowania certyfikatów można znaleźć na umieszczonych poniżej stronach.

Istotną kwestią jest kolejność zawartości pliku .pem. W pierwszej kolejności powinien on zawierać klucz prywatny, a dopiero za nim podpisany certyfikat (nie żądanie certyfikatu). Po certyfikacie i kluczu prywatnym powinny znajdować się puste linie. Jeżeli przed certyfikatem znajdują się dodatkowe informacje tekstowe, to powinny one zostać usunięte. Otrzymany plik powinien mieć następującą postać:

    -----BEGIN RSA PRIVATE KEY-----
    [zakodowany klucz]
    -----END RSA PRIVATE KEY-----
    [pusta linia]
    -----BEGIN CERTIFICATE-----
    [zakodowany certyfikat]
    -----END CERTIFICATE-----
    [pusta linia]

LOSOWOŚĆ

stunnel potrzebuje zainicjować PRNG (generator liczb pseudolosowych), gdyż protokół SSL wymaga do bezpieczeństwa kryptograficznego źródła dobrej losowości. Następujące źródła są kolejno odczytywane aż do uzyskania wystarczającej ilości entropii:

  • Zawartość pliku podanego w opcji RNDfile.

  • Zawartość pliku o nazwie określonej przez zmienną środowiskową RANDFILE, o ile jest ona ustawiona.

  • Plik .rnd umieszczony w katalogu domowym użytkownika, jeżeli zmienna RANDFILE nie jest ustawiona.

  • Plik podany w opcji '--with-random' w czasie konfiguracji programu.

  • Zawartość ekranu w systemie Windows.

  • Gniazdo egd, jeżeli użyta została opcja EGD.

  • Gniazdo egd podane w opcji '--with-egd-socket' w czasie konfiguracji programu.

  • Urządzenie /dev/urandom.

Współczesne (0.9.5a lub nowsze) wersje biblioteki OpenSSL automatycznie zaprzestają ładowania kolejnych danych w momencie uzyskania wystarczającej ilości entropii. Wcześniejsze wersje biblioteki wykorzystają wszystkie powyższe źródła, gdyż nie istnieje tam funkcja pozwalająca określić, czy uzyskano już wystarczająco dużo danych.

Warto zwrócić uwagę, że na maszynach z systemem Windows, na których konsoli nie pracuje użytkownik, zawartość ekranu nie jest wystarczająco zmienna, aby zainicjować PRNG. W takim przypadku do zainicjowania generatora należy użyć opcji RNDfile.

Plik RNDfile powinien zawierać dane losowe -- również w tym sensie, że powinny być one inne przy każdym uruchomieniu programu stunnel. O ile nie użyta została opcja RNDoverwrite jest to robione automatycznie. Do ręcznego uzyskania takiego pliku użyteczna może być komenda openssl rand dostarczana ze współczesnymi wersjami pakietu OpenSSL.

Jeszcze jedna istotna informacja -- jeżeli dostępne jest urządzenie /dev/urandom biblioteka OpenSSL ma zwyczaj zasilania nim PRNG w trakcie sprawdzania stanu generatora. W systemach z /dev/urandom urządzenie to będzie najprawdopodobniej użyte, pomimo że znajduje się na samym końcu powyższej listy. Jest to właściwość biblioteki OpenSSL, a nie programu stunnel.

PARAMETRY DH

Począwszy od wersji 4.40 stunnel zawiera w kodzie programu 2048-bitowe parametry DH. Od wersji 5.18 te początkowe wartości parametrów DH są wymieniane na autogenerowane parametry tymczasowe. Wygenerowanie parametrów DH może zająć nawet wiele minut.

Alternatywnie parametry DH można umieścić w pliku razem z certyfikatem, co wyłącza generowanie parametrów tymczasowych:

    openssl dhparam 2048 >> stunnel.pem

PLIKI

@sysconfdir@/stunnel/stunnel.conf

plik konfiguracyjny programu

BŁĘDY

Opcja execArgs oraz linia komend Win32 nie obsługuje cytowania.

ZOBACZ RÓWNIEŻ

tcpd(8)

biblioteka kontroli dostępu do usług internetowych

inetd(8)

'super-serwer' internetowy

http://www.stunnel.org/

strona domowa programu stunnel

http://www.openssl.org/

strona projektu OpenSSL

AUTOR

Michał Trojnara

<Michal.Trojnara@mirt.net>

 stunnel TLS Proxy
stunnel-5.30/doc/stunnel.html.in0000644000175000017500000014106212630656304013613 00000000000000 stunnel TLS Proxy
 stunnel TLS Proxy

NAME

stunnel - TLS offloading and load-balancing proxy

SYNOPSIS

Unix:

stunnel [FILE] | -fd N | -help | -version | -sockets | -options

WIN32:

stunnel [ [ -install | -uninstall | -start | -stop | -reload | -reopen | -exit ] [-quiet] [FILE] ] | -help | -version | -sockets | -options

DESCRIPTION

The stunnel program is designed to work as SSL encryption wrapper between remote clients and local (inetd-startable) or remote servers. The concept is that having non-SSL aware daemons running on your system you can easily set them up to communicate with clients over secure SSL channels.

stunnel can be used to add SSL functionality to commonly used Inetd daemons like POP-2, POP-3, and IMAP servers, to standalone daemons like NNTP, SMTP and HTTP, and in tunneling PPP over network sockets without changes to the source code.

This product includes cryptographic software written by Eric Young (eay@cryptsoft.com)

OPTIONS

FILE

Use specified configuration file

-fd N (Unix only)

Read the config file from specified file descriptor

-help

Print stunnel help menu

-version

Print stunnel version and compile time defaults

-sockets

Print default socket options

-options

Print supported SSL options

-install (Windows NT and later only)

Install NT Service

-uninstall (Windows NT and later only)

Uninstall NT Service

-start (Windows NT and later only)

Start NT Service

-stop (Windows NT and later only)

Stop NT Service

-reload (Windows NT and later only)

Reload the configuration file of the running NT Service

-reopen (Windows NT and later only)

Reopen the log file of the running NT Service

-exit (Win32 only)

Exit an already started stunnel

-quiet (Win32 only)

Don't display any message boxes

CONFIGURATION FILE

Each line of the configuration file can be either:

  • An empty line (ignored).

  • A comment starting with ';' (ignored).

  • An 'option_name = option_value' pair.

  • '[service_name]' indicating a start of a service definition.

An address parameter of an option may be either:

  • A port number.

  • A colon-separated pair of IP address (either IPv4, IPv6, or domain name) and port number.

  • A Unix socket path (Unix only).

GLOBAL OPTIONS

chroot = DIRECTORY (Unix only)

directory to chroot stunnel process

chroot keeps stunnel in a chrooted jail. CApath, CRLpath, pid and exec are located inside the jail and the patches have to be relative to the directory specified with chroot.

Several functions of the operating system also need their files to be located within the chroot jail, e.g.:

  • Delayed resolver typically needs /etc/nsswitch.conf and /etc/resolv.conf.

  • Local time in log files needs /etc/timezone.

  • Some other functions may need devices, e.g. /dev/zero or /dev/null.

compression = deflate | zlib

select data compression algorithm

default: no compression

deflate is the standard compression method as described in RFC 1951.

zlib compression of OpenSSL 0.9.8 or above is not backward compatible with OpenSSL 0.9.7.

debug = [FACILITY.]LEVEL

debugging level

Level is one of the syslog level names or numbers emerg (0), alert (1), crit (2), err (3), warning (4), notice (5), info (6), or debug (7). All logs for the specified level and all levels numerically less than it will be shown. Use debug = debug or debug = 7 for greatest debugging output. The default is notice (5).

The syslog facility 'daemon' will be used unless a facility name is supplied. (Facilities are not supported on Win32.)

Case is ignored for both facilities and levels.

EGD = EGD_PATH (Unix only)

path to Entropy Gathering Daemon socket

Entropy Gathering Daemon socket to use to feed the OpenSSL random number generator. (Available only if compiled with OpenSSL 0.9.5a or higher)

engine = auto | ENGINE_ID

select hardware engine

default: software-only cryptography

An example of advanced engine configuration to use the certificate and the corresponding private key from an OpenSC PKCS#11 engine:

    engine = dynamic
    engineCtrl = SO_PATH:/usr/local/lib/engines/libpkcs11.so
    engineCtrl = LOAD
    engineCtrl = MODULE_PATH:opensc-pkcs11.so
    engineCtrl = PIN:123456

    [service]
    engineId = pkcs11
    cert = id_45
engineCtrl = COMMAND[:PARAMETER]

control hardware engine

A special command "LOAD" can be used to load engine cryptographic module.

engineDefault = TASK_LIST

set OpenSSL tasks delegated to the current engine

The parameter specifies a comma-separated list of task to be delegated to the current engine.

The following tasks may be available, if supported by the engine: ALL, RSA, DSA, ECDH, ECDSA, DH, RAND, CIPHERS, DIGESTS, PKEY, PKEY_CRYPTO, PKEY_ASN1.

fips = yes | no

Enable or disable FIPS 140-2 mode.

This option allows you to disable entering FIPS mode if stunnel was compiled with FIPS 140-2 support.

default: no (since version 5.00)

foreground = yes | quiet | no (Unix only)

foreground mode

Stay in foreground (don't fork).

With the yes parameter it also logs to stderr in addition to the destinations specified with syslog and output.

default: background in daemon mode

iconActive = ICON_FILE (GUI only)

GUI icon to be displayed when there are established connections

On Windows platform the parameter should be an .ico file containing a 16x16 pixel image.

iconError = ICON_FILE (GUI only)

GUI icon to be displayed when no valid configuration is loaded

On Windows platform the parameter should be an .ico file containing a 16x16 pixel image.

iconIdle = ICON_FILE (GUI only)

GUI icon to be displayed when there are no established connections

On Windows platform the parameter should be an .ico file containing a 16x16 pixel image.

log = append | overwrite

log file handling

This option allows you to choose whether the log file (specified with the output option) is appended or overwritten when opened or re-opened.

default: append

output = FILE

append log messages to a file

/dev/stdout device can be used to send log messages to the standard output (for example to log them with daemontools splogger).

pid = FILE (Unix only)

pid file location

If the argument is empty, then no pid file will be created.

pid path is relative to the chroot directory if specified.

RNDbytes = BYTES

bytes to read from random seed files

Number of bytes of data read from random seed files. With SSL versions less than 0.9.5a, also determines how many bytes of data are considered sufficient to seed the PRNG. More recent OpenSSL versions have a builtin function to determine when sufficient randomness is available.

RNDfile = FILE

path to file with random seed data

The SSL library will use data from this file first to seed the random number generator.

RNDoverwrite = yes | no

overwrite the random seed files with new random data

default: yes

service = SERVICE (Unix only)

stunnel service name

The specified service name is used for syslog and as the inetd mode service name for TCP Wrappers. While this option can technically be specified in the service sections, it is only useful in global options.

default: stunnel

socket = a|l|r:OPTION=VALUE[:VALUE]

Set an option on the accept/local/remote socket

The values for the linger option are l_onof:l_linger. The values for the time are tv_sec:tv_usec.

Examples:

    socket = l:SO_LINGER=1:60
        set one minute timeout for closing local socket
    socket = r:SO_OOBINLINE=yes
        place out-of-band data directly into the
        receive data stream for remote sockets
    socket = a:SO_REUSEADDR=no
        disable address reuse (enabled by default)
    socket = a:SO_BINDTODEVICE=lo
        only accept connections on loopback interface
syslog = yes | no (Unix only)

enable logging via syslog

default: yes

taskbar = yes | no (WIN32 only)

enable the taskbar icon

default: yes

SERVICE-LEVEL OPTIONS

Each configuration section begins with a service name in square brackets. The service name is used for libwrap (TCP Wrappers) access control and lets you distinguish stunnel services in your log files.

Note that if you wish to run stunnel in inetd mode (where it is provided a network socket by a server such as inetd, xinetd, or tcpserver) then you should read the section entitled INETD MODE below.

accept = [HOST:]PORT

accept connections on specified address

If no host specified, defaults to all IPv4 addresses for the local host.

To listen on all IPv6 addresses use:

    accept = :::PORT
CApath = DIRECTORY

Certificate Authority directory

This is the directory in which stunnel will look for certificates when using the verify option. Note that the certificates in this directory should be named XXXXXXXX.0 where XXXXXXXX is the hash value of the DER encoded subject of the cert.

The hash algorithm has been changed in OpenSSL 1.0.0. It is required to c_rehash the directory on upgrade from OpenSSL 0.x.x to OpenSSL 1.x.x.

CApath path is relative to the chroot directory if specified.

CAfile = CERT_FILE

Certificate Authority file

This file contains multiple CA certificates, used with the verify option.

cert = PEM_FILE

certificate chain PEM file name

The certificates must be in PEM format, and must be from the actual server/client certificate to the self-signed root CA certificate.

A certificate is required in server mode, and optional in client mode.

This parameter is also used as the certificate identifier when a hardware engine is enabled.

checkEmail = EMAIL

email address of the peer certificate subject

Multiple checkEmail options are allowed in a single service section. Certificates are accepted if no checkEmail option was specified, or the email address of the peer certificate matches any of the email addresses specified with checkEmail.

This option requires OpenSSL 1.0.2 or later.

checkHost = HOST

host of the peer certificate subject

Multiple checkHost options are allowed in a single service section. Certificates are accepted if no checkHost option was specified, or the host name of the peer certificate matches any of the hosts specified with checkHost.

This option requires OpenSSL 1.0.2 or later.

checkIP = IP

IP address of the peer certificate subject

Multiple checkIP options are allowed in a single service section. Certificates are accepted if no checkIP option was specified, or the IP address of the peer certificate matches any of the IP addresses specified with checkIP.

This option requires OpenSSL 1.0.2 or later.

ciphers = CIPHER_LIST

Select permitted SSL ciphers

A colon-delimited list of the ciphers to allow in the SSL connection, for example DES-CBC3-SHA:IDEA-CBC-MD5.

client = yes | no

client mode (remote service uses SSL)

default: no (server mode)

config = COMMAND[:PARAMETER]

OpenSSL configuration command

The OpenSSL configuration command is executed with the specified parameter. This allows any configuration commands to be invoked from the stunnel configuration file. Supported commands are described on the SSL_CONF_cmd(3ssl) manual page.

Several config lines can be used to specify multiple configuration commands.

This option requires OpenSSL 1.0.2 or later.

connect = [HOST:]PORT

connect to a remote address

If no host is specified, the host defaults to localhost.

Multiple connect options are allowed in a single service section.

If host resolves to multiple addresses and/or if multiple connect options are specified, then the remote address is chosen using a round-robin algorithm.

CRLpath = DIRECTORY

Certificate Revocation Lists directory

This is the directory in which stunnel will look for CRLs when using the verify option. Note that the CRLs in this directory should be named XXXXXXXX.r0 where XXXXXXXX is the hash value of the CRL.

The hash algorithm has been changed in OpenSSL 1.0.0. It is required to c_rehash the directory on upgrade from OpenSSL 0.x.x to OpenSSL 1.x.x.

CRLpath path is relative to the chroot directory if specified.

CRLfile = CERT_FILE

Certificate Revocation Lists file

This file contains multiple CRLs, used with the verify option.

curve = NID

specify ECDH curve name

To get a list of supported curves use:

    openssl ecparam -list_curves

default: prime256v1

logId = TYPE

connection identifier type

This identifier allows you to distinguish log entries generated for each of the connections.

Currently supported types:

sequential

The numeric sequential identifier is only unique within a single instance of stunnel, but very compact. It is most useful for manual log analysis.

unique

This alphanumeric identifier is globally unique, but longer than the sequential number. It is most useful for automated log analysis.

thread

The operating system thread identifier is neither unique (even within a single instance of stunnel) nor short. It is most useful for debugging software or configuration issues.

default: sequential

debug = LEVEL

debugging level

Level is a one of the syslog level names or numbers emerg (0), alert (1), crit (2), err (3), warning (4), notice (5), info (6), or debug (7). All logs for the specified level and all levels numerically less than it will be shown. Use debug = debug or debug = 7 for greatest debugging output. The default is notice (5).

delay = yes | no

delay DNS lookup for the connect option

This option is useful for dynamic DNS, or when DNS is not available during stunnel startup (road warrior VPN, dial-up configurations).

Delayed resolver mode is automatically engaged when stunnel fails to resolve on startup any of the connect targets for a service.

Delayed resolver inflicts failover = prio.

default: no

engineId = ENGINE_ID

select engine ID for the service

engineNum = ENGINE_NUMBER

select engine number for the service

The engines are numbered starting from 1.

exec = EXECUTABLE_PATH

execute a local inetd-type program

exec path is relative to the chroot directory if specified.

The following environmental variables are set on Unix platforms: REMOTE_HOST, REMOTE_PORT, SSL_CLIENT_DN, SSL_CLIENT_I_DN.

execArgs = $0 $1 $2 ...

arguments for exec including the program name ($0)

Quoting is currently not supported. Arguments are separated with an arbitrary amount of whitespace.

failover = rr | prio

Failover strategy for multiple "connect" targets.

    rr (round robin) - fair load distribution
    prio (priority) - use the order specified in config file

default: rr

ident = USERNAME

use IDENT (RFC 1413) username checking

include = DIRECTORY

include all configuration file parts located in DIRECTORY

The files are included in the ascending alphabetical order of their names.

key = KEY_FILE

private key for the certificate specified with cert option

A private key is needed to authenticate the certificate owner. Since this file should be kept secret it should only be readable by its owner. On Unix systems you can use the following command:

    chmod 600 keyfile

This parameter is also used as the private key identifier when a hardware engine is enabled.

default: the value of the cert option

libwrap = yes | no

Enable or disable the use of /etc/hosts.allow and /etc/hosts.deny.

default: no (since version 5.00)

local = HOST

By default, the IP address of the outgoing interface is used as the source for remote connections. Use this option to bind a static local IP address instead.

sni = SERVICE:SERVER_PATTERN (server mode)

Use the service as a slave service (a name-based virtual server) for Server Name Indication TLS extension (RFC 3546).

service_name specifies the master service that accepts client connections with the accept option. server_name_pattern specifies the host name to be redirected. The pattern may start with the '*' character, e.g. '*.example.com'. Multiple slave services are normally specified for a single master service. The sni option can also be specified more than once within a single slave service.

This service, as well as the master service, may not be configured in client mode.

The connect option of the slave service is ignored when the protocol option is specified, as protocol connects to the remote host before TLS handshake.

Libwrap checks (Unix only) are performed twice: with the master service name after TCP connection is accepted, and with the slave service name during the TLS handshake.

The sni option is only available when compiled with OpenSSL 1.0.0 and later.

sni = SERVER (client mode)

Use the parameter as the value of TLS Server Name Indication (RFC 3546) extension.

The sni option is only available when compiled with OpenSSL 1.0.0 and later.

OCSP = URL

select OCSP responder for certificate verification

OCSPaia = yes | no

validate certificates with their AIA OCSP responders

This option enables stunnel to validate certificates with the list of OCSP responder URLs retrieved from their AIA (Authority Information Access) extension.

OCSPflag = OCSP_FLAG

specify OCSP responder flag

Several OCSPflag can be used to specify multiple flags.

currently supported flags: NOCERTS, NOINTERN NOSIGS, NOCHAIN, NOVERIFY, NOEXPLICIT, NOCASIGN, NODELEGATED, NOCHECKS, TRUSTOTHER, RESPID_KEY, NOTIME

OCSPnonce = yes | no

send and verify the OCSP nonce extension

This option protects the OCSP protocol against replay attacks. Due to its computational overhead, the nonce extension is usually only supported on internal (e.g. corporate) responders, and not on public OCSP responders.

options = SSL_OPTIONS

OpenSSL library options

The parameter is the OpenSSL option name as described in the SSL_CTX_set_options(3ssl) manual, but without SSL_OP_ prefix. stunnel -options lists the options found to be allowed in the current combination of stunnel and the OpenSSL library used to build it.

Several option lines can be used to specify multiple options. An option name can be prepended with a dash ("-") to disable the option.

For example, for compatibility with the erroneous Eudora SSL implementation, the following option can be used:

    options = DONT_INSERT_EMPTY_FRAGMENTS

default:

    options = NO_SSLv2
    options = NO_SSLv3
protocol = PROTO

application protocol to negotiate SSL

This option enables initial, protocol-specific negotiation of the SSL/TLS encryption. The protocol option should not be used with SSL encryption on a separate port.

Currently supported protocols:

cifs

Proprietary (undocummented) extension of CIFS protocol implemented in Samba. Support for this extension was dropped in Samba 3.0.0.

connect

Based on RFC 2817 - Upgrading to TLS Within HTTP/1.1, section 5.2 - Requesting a Tunnel with CONNECT

This protocol is only supported in client mode.

imap

Based on RFC 2595 - Using TLS with IMAP, POP3 and ACAP

nntp

Based on RFC 4642 - Using Transport Layer Security (TLS) with Network News Transfer Protocol (NNTP)

This protocol is only supported in client mode.

pgsql

Based on http://www.postgresql.org/docs/8.3/static/protocol-flow.html#AEN73982

pop3

Based on RFC 2449 - POP3 Extension Mechanism

proxy

Haproxy client IP address http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt

smtp

Based on RFC 2487 - SMTP Service Extension for Secure SMTP over TLS

socks

SOCKS versions 4, 4a, and 5 are supported. The SOCKS protocol itself is encapsulated within SSL/TLS encryption layer to protect the final destination address.

http://www.openssh.com/txt/socks4.protocol

http://www.openssh.com/txt/socks4a.protocol

The BIND command of the SOCKS protocol is not supported. The USERID parameter is ignored.

See Examples section for sample configuration files for VPN based on SOCKS encryption.

protocolAuthentication = AUTHENTICATION

authentication type for the protocol negotiations

Currently, this option is only supported in the client-side 'connect' and 'smtp' protocols.

Supported authentication types for the 'connect' protocol are 'basic' or 'ntlm'. The default 'connect' authentication type is 'basic'.

Supported authentication types for the 'smtp' protocol are 'plain' or 'login'. The default 'smtp' authentication type is 'plain'.

protocolDomain = DOMAIN

domain for the protocol negotiations

Currently, this option is only supported in the client-side 'connect' protocol.

protocolHost = HOST:PORT

destination address for the protocol negotiations

protocolHost specifies the final SSL server to be connected to by the proxy, and not the proxy server directly connected by stunnel. The proxy server should be specified with the 'connect' option.

Currently the protocol destination address only applies to the 'connect' protocol.

protocolPassword = PASSWORD

password for the protocol negotiations

Currently, this option is only supported in the client-side 'connect' and 'smtp' protocols.

protocolUsername = USERNAME

username for the protocol negotiations

Currently, this option is only supported in the client-side 'connect' and 'smtp' protocols.

PSKidentity = IDENTITY

PSK identity for the PSK client

PSKidentity can be used on stunnel clients to select the PSK identity used for authentication. This option is ignored in server sections.

default: the first identity specified in the PSKsecrets file.

PSKsecrets = FILE

file with PSK identities and corresponding keys

Each line of the file in the following format:

    IDENTITY:KEY

The key is required to be at least 20 characters long. The file should not be world-readable nor world-writable.

pty = yes | no (Unix only)

allocate a pseudoterminal for 'exec' option

redirect = [HOST:]PORT

redirect SSL client connections on certificate-based authentication failures

This option only works in server mode. Some protocol negotiations are also incompatible with the redirect option.

renegotiation = yes | no

support SSL renegotiation

Applications of the SSL renegotiation include some authentication scenarios, or re-keying long lasting connections.

On the other hand this feature can facilitate a trivial CPU-exhaustion DoS attack:

http://vincent.bernat.im/en/blog/2011-ssl-dos-mitigation.html

Please note that disabling SSL renegotiation does not fully mitigate this issue.

default: yes (if supported by OpenSSL)

reset = yes | no

attempt to use the TCP RST flag to indicate an error

This option is not supported on some platforms.

default: yes

retry = yes | no

reconnect a connect+exec section after it was disconnected

default: no

setgid = GROUP (Unix only)

Unix group id

As a global option: setgid() to the specified group in daemon mode and clear all other groups.

As a service-level option: set the group of the Unix socket specified with "accept".

setuid = USER (Unix only)

Unix user id

As a global option: setuid() to the specified user in daemon mode.

As a service-level option: set the owner of the Unix socket specified with "accept".

sessionCacheSize = NUM_ENTRIES

session cache size

sessionCacheSize specifies the maximum number of the internal session cache entries.

The value of 0 can be used for unlimited size. It is not recommended for production use due to the risk of a memory exhaustion DoS attack.

sessionCacheTimeout = TIMEOUT

session cache timeout

This is the number of seconds to keep cached SSL sessions.

sessiond = HOST:PORT

address of sessiond SSL cache server

sslVersion = SSL_VERSION

select the SSL protocol version

Supported values: all, SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2

Availability of specific protocols depends on the linked OpenSSL library. Older versions of OpenSSL do not support TLSv1.1 and TLSv1.2. Newer versions of OpenSSL do not support SSLv2.

Obsolete SSLv2 and SSLv3 are currently disabled by default. See the options option documentation for details.

stack = BYTES (except for FORK model)

thread stack size

TIMEOUTbusy = SECONDS

time to wait for expected data

TIMEOUTclose = SECONDS

time to wait for close_notify (set to 0 for buggy MSIE)

TIMEOUTconnect = SECONDS

time to wait to connect to a remote host

TIMEOUTidle = SECONDS

time to keep an idle connection

transparent = none | source | destination | both (Unix only)

enable transparent proxy support on selected platforms

Supported values:

none

Disable transparent proxy support. This is the default.

source

Re-write the address to appear as if a wrapped daemon is connecting from the SSL client machine instead of the machine running stunnel.

This option is currently available in:

Remote mode (connect option) on Linux >=2.6.28

This configuration requires stunnel to be executed as root and without the setuid option.

This configuration requires the following setup for iptables and routing (possibly in /etc/rc.local or equivalent file):

    iptables -t mangle -N DIVERT
    iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT
    iptables -t mangle -A DIVERT -j MARK --set-mark 1
    iptables -t mangle -A DIVERT -j ACCEPT
    ip rule add fwmark 1 lookup 100
    ip route add local 0.0.0.0/0 dev lo table 100
    echo 0 >/proc/sys/net/ipv4/conf/lo/rp_filter

stunnel must also to be executed as root and without the setuid option.

Remote mode (connect option) on Linux 2.2.x

This configuration requires the kernel to be compiled with the transparent proxy option. Connected service must be installed on a separate host. Routing towards the clients has to go through the stunnel box.

stunnel must also to be executed as root and without the setuid option.

Remote mode (connect option) on FreeBSD >=8.0

This configuration requires additional firewall and routing setup. stunnel must also to be executed as root and without the setuid option.

Local mode (exec option)

This configuration works by pre-loading the libstunnel.so shared library. _RLD_LIST environment variable is used on Tru64, and LD_PRELOAD variable on other platforms.

destination

The original destination is used instead of the connect option.

A service section for transparent destination may look like this:

    [transparent]
    client = yes
    accept = <stunnel_port>
    transparent = destination

This configuration requires iptables setup to work, possibly in /etc/rc.local or equivalent file.

For a connect target installed on the same host:

    /sbin/iptables -t nat -I OUTPUT -p tcp --dport <redirected_port> \
        -m ! --uid-owner <stunnel_user_id> \
        -j DNAT --to-destination <local_ip>:<stunnel_port>

For a connect target installed on a remote host:

    /sbin/iptables -I INPUT -i eth0 -p tcp --dport <stunnel_port> -j ACCEPT
    /sbin/iptables -t nat -I PREROUTING -p tcp --dport <redirected_port> \
        -i eth0 -j DNAT --to-destination <local_ip>:<stunnel_port>

The transparent destination option is currently only supported on Linux.

both

Use both source and destination transparent proxy.

Two legacy options are also supported for backward compatibility:

yes

This option has been renamed to source.

no

This option has been renamed to none.

verify = LEVEL

verify the peer certificate

level 0

Request and ignore the peer certificate.

level 1

Verify the peer certificate if present.

level 2

Verify the peer certificate.

level 3

Verify the peer with locally installed certificate.

level 4

Ignore the CA chain and only verify the peer certificate.

default

No verify.

It is important to understand that this option was solely designed for access control and not for authorization. Specifically for level 2 every non-revoked certificate is accepted regardless of its Common Name. For this reason a dedicated CA should be used with level 2, and not a generic CA commonly used for webservers. Level 3 is preferred for point-to-point connections.

RETURN VALUE

stunnel returns zero on success, non-zero on error.

SIGNALS

The following signals can be used to control stunnel in Unix environment:

SIGHUP

Force a reload of the configuration file.

Some global options will not be reloaded:

  • chroot

  • foreground

  • pid

  • setgid

  • setuid

The use of the 'setuid' option will also prevent stunnel from binding to privileged (<1024) ports during configuration reloading.

When the 'chroot' option is used, stunnel will look for all its files (including the configuration file, certificates, the log file and the pid file) within the chroot jail.

SIGUSR1

Close and reopen the stunnel log file. This function can be used for log rotation.

SIGTERM, SIGQUIT, SIGINT

Shut stunnel down.

The result of sending any other signals to the server is undefined.

EXAMPLES

In order to provide SSL encapsulation to your local imapd service, use:

    [imapd]
    accept = 993
    exec = /usr/sbin/imapd
    execArgs = imapd

or in remote mode:

    [imapd]
    accept = 993
    connect = 143

In order to let your local e-mail client connect to an SSL-enabled imapd service on another server, configure the e-mail client to connect to localhost on port 119 and use:

    [imap]
    client = yes
    accept = 143
    connect = servername:993

If you want to provide tunneling to your pppd daemon on port 2020, use something like:

    [vpn]
    accept = 2020
    exec = /usr/sbin/pppd
    execArgs = pppd local
    pty = yes

If you want to use stunnel in inetd mode to launch your imapd process, you'd use this stunnel.conf. Note there must be no [service_name] section.

    exec = /usr/sbin/imapd
    execArgs = imapd

To setup SOCKS VPN configure the following client service:

    [socks_client]
    client = yes
    accept = 127.0.0.1:1080
    connect = vpn_server:9080
    verify = 4
    CAfile = stunnel.pem

The corresponding configuration on the vpn_server host:

    [socks_server]
    protocol = socks
    accept = 9080
    cert = stunnel.pem
    key = stunnel.key

Now test your configuration on the client machine with:

    curl --socks4a localhost http://www.example.com/

NOTES

RESTRICTIONS

stunnel cannot be used for the FTP daemon because of the nature of the FTP protocol which utilizes multiple ports for data transfers. There are available SSL-enabled versions of FTP and telnet daemons, however.

INETD MODE

The most common use of stunnel is to listen on a network port and establish communication with either a new port via the connect option, or a new program via the exec option. However there is a special case when you wish to have some other program accept incoming connections and launch stunnel, for example with inetd, xinetd, or tcpserver.

For example, if you have the following line in inetd.conf:

    imaps stream tcp nowait root @bindir@/stunnel stunnel @sysconfdir@/stunnel/imaps.conf

In these cases, the inetd-style program is responsible for binding a network socket (imaps above) and handing it to stunnel when a connection is received. Thus you do not want stunnel to have any accept option. All the Service Level Options should be placed in the global options section, and no [service_name] section will be present. See the EXAMPLES section for example configurations.

CERTIFICATES

Each SSL-enabled daemon needs to present a valid X.509 certificate to the peer. It also needs a private key to decrypt the incoming data. The easiest way to obtain a certificate and a key is to generate them with the free OpenSSL package. You can find more information on certificates generation on pages listed below.

The order of contents of the .pem file is important. It should contain the unencrypted private key first, then a signed certificate (not certificate request). There should also be empty lines after the certificate and the private key. Any plaintext certificate information appended on the top of generated certificate should be discarded. So the file should look like this:

    -----BEGIN RSA PRIVATE KEY-----
    [encoded key]
    -----END RSA PRIVATE KEY-----
    [empty line]
    -----BEGIN CERTIFICATE-----
    [encoded certificate]
    -----END CERTIFICATE-----
    [empty line]

RANDOMNESS

stunnel needs to seed the PRNG (pseudo-random number generator) in order for SSL to use good randomness. The following sources are loaded in order until sufficient random data has been gathered:

  • The file specified with the RNDfile flag.

  • The file specified by the RANDFILE environment variable, if set.

  • The file .rnd in your home directory, if RANDFILE not set.

  • The file specified with '--with-random' at compile time.

  • The contents of the screen if running on Windows.

  • The egd socket specified with the EGD flag.

  • The egd socket specified with '--with-egd-sock' at compile time.

  • The /dev/urandom device.

With recent (OpenSSL 0.9.5a or later) version of SSL it will stop loading random data automatically when sufficient entropy has been gathered. With previous versions it will continue to gather from all the above sources since no SSL function exists to tell when enough data is available.

Note that on Windows machines that do not have console user interaction (mouse movements, creating windows, etc.) the screen contents are not variable enough to be sufficient, and you should provide a random file for use with the RNDfile flag.

Note that the file specified with the RNDfile flag should contain random data -- that means it should contain different information each time stunnel is run. This is handled automatically unless the RNDoverwrite flag is used. If you wish to update this file manually, the openssl rand command in recent versions of OpenSSL, would be useful.

Important note: If /dev/urandom is available, OpenSSL often seeds the PRNG with it while checking the random state. On systems with /dev/urandom OpenSSL is likely to use it even though it is listed at the very bottom of the list above. This is the behaviour of OpenSSL and not stunnel.

DH PARAMETERS

stunnel 4.40 and later contains hardcoded 2048-bit DH parameters. Starting with stunnel 5.18, these hardcoded DH parameters are replaced every 24 hours with autogenerated temporary DH parameters. DH parameter generation may take several minutes.

Alternatively, it is possible to specify static DH parameters in the certificate file, which disables generating temporary DH parameters:

    openssl dhparam 2048 >> stunnel.pem

FILES

@sysconfdir@/stunnel/stunnel.conf

stunnel configuration file

BUGS

The execArgs option and the Win32 command line do not support quoting.

SEE ALSO

tcpd(8)

access control facility for internet services

inetd(8)

internet 'super-server'

http://www.stunnel.org/

stunnel homepage

http://www.openssl.org/

OpenSSL project website

AUTHOR

Michał Trojnara

<Michal.Trojnara@mirt.net>

 stunnel TLS Proxy
stunnel-5.30/doc/en/0000755000175000017500000000000012540237351011303 500000000000000stunnel-5.30/doc/en/VNC_StunnelHOWTO.html0000664000175000017500000002035612540020663015074 00000000000000

VNC over STUNNEL with a Linux server and Windows 2000 client HOWTO


19 February 2001

ver 1.0

by Craig Furter and Arno van der Walt

contact us at cfurter@vexen.co.za and arnovdw@mycomax.com



We assume that you have already downloaded VNCServer and VNCViewer.


First of all there is a step by step HOWTO and then we'll look at the theory behind all this.


  1. Download and install OpenSSL, SSLeay, and Stunnel on the Linux/Unix box. Download the modules.

a) [root@anthrax$]gunzip openssl-x.xx.tar.gz (repeat for all 3 the modules)

b) [root@anthrax$]tar – xvf openssl-x.xx.tar (repeat for all 3 the modules)


  1. Copy the following to Notepad and save the file as VNCRegEdit.REG on the Windows 2000 box

--cut here and copy to VNCRegEdit.REG then double click the file to import--
REGEDIT4

[HKEY_LOCAL_MACHINE\Software\ORL\WinVNC3]
AllowLoopback=dword:00000001

[HKEY_LOCAL_MACHINE\Software\ORL\WinVNC3\Default]
AllowLoopback=dword:00000001
--stop here--


  1. Install Stunnel on the Windows 2000 machine by copying the following files to your \WINNT\SYSTEM32\ directory

a)libeay32.dll

b)libssl.dll

c)stunnel.pem


  1. On the Linux box execute the following command as root and let it run in its own terminal.

./stunnel -d 5900 -r 5901


  1. Execute vncserver (it should run as display:1 when you execute the ps aux |grep vnc command)


  1. Now on the Windows 2000 machine execute the following command and let it run in its own terminal.

stunnel -d 5900 -r unix.ip.address:5900 -c

.

  1. And on the Windows 2000 machine open VNCviewer and connect to localhost specifying no display

ie. 10.10.1.53 in the window


  1. For each additional display repeat steps 4 – 6 and increment the specified ports with 2 ie. The Linux command will look as follows:

./stunnel -d 5902 -r 5903

and the Windows 2000 command as follows:

stunnel -d 5902 -r unix.ip.address:5902

and remember to start another vncserver on the Linux box for each VNC display



  1. The display number on the vncviewer must also be incremented with two ie:

10.10.1.53:2 etc.


The THEORY


Tunneling:


What this means is that software (daemon) runs on the client and server machine. In this case, the Windows 2000 machine is the client and the server is the *NIX machine. Stunnel will then run as client on Windows 2000 and server mode on the UNIX box.

eg:
Windows:
stunnel -d 5900 -r unix.ip.address:5900 -c

UNIX
stunnel -d 5900 -r 5901

This means that connecting to VNC display 0 in the localhost will transfer all the calls to the *NIX machine on display 1. So the VNC server on the *NIX machine must be running on display 1. Not display 0. If you run stunnel before VNC, VNC will automatically move to display 1 noticing that port 5900 ("display" 0) is already in use).

What happens now is that when you connect to port 5900 on the Windows machine via an "unsecured" connection, a secure "tunnel" is opened from Windows 2000 to the *NIX machine on port 5900. The *NIX machine then opens a "unsecured" connection to itself on port 5901. We now have a secure tunnel available.


A bit about VNC and displays


The -d is the listening IPaddress:port and the -r is the remote IPaddress:port. VNC uses port 5900 for display 0. That means that display 1 will be 5901. If you want VNC server to listen for a connection on port 80 then the display number will be 80 - 5900 = -5820. If you want VNC server to
listen on port 14000 then the display number is 14000 - 5900 = 8100.

So all you have to do is run stunnel on the UNIX machine and VNC on the desired "display" number.


VNC on the Windows 2000 machine


To connect from the client machine you need to enter the client machine's IP address and the "display" (from the port conversion). But VNC will think that you are trying to connect to the local machine and does not allow this. To override this add the following to your registry.

--cut here and copy to anything.reg. then double click the file to import--
REGEDIT4

[HKEY_LOCAL_MACHINE\Software\ORL\WinVNC3]
AllowLoopback=dword:00000001

[HKEY_LOCAL_MACHINE\Software\ORL\WinVNC3\Default]
AllowLoopback=dword:00000001
--stop here--

Now VNC will not complain. So you need to always run stunnel in client mode on the Windows machine and then connect with VNCViewer to the localhost on the correct "display". By the way, *NIX doesn't complain about this. There is no setting needed if *NIX to *NIX.


VNC's Java client


Unfortunately this will not work well with the built-in web version. If you did not known about it, try http'ing into a machine running VNC server on it, to port 58XX (where XX is the display number), and the Java client will be loaded.

stunnel-5.30/doc/stunnel.pl.pod.in0000664000175000017500000011764512630656244014062 00000000000000=head1 NAZWA =encoding utf8 stunnel - uniwersalny tunel protokoÅ‚u SSL =head1 SKÅADNIA =over 4 =item B B [S] | S<-fd N> | S<-help> | S<-version> | S<-sockets> | S<-options> =item B B [ [ S<-install> | S<-uninstall> | S<-start> | S<-stop> | S<-reload> | S<-reopen> | S<-exit> ] [S<-quiet>] [S] ] | S<-help> | S<-version> | S<-sockets> | S<-options> =back =head1 OPIS Program B zostaÅ‚ zaprojektowany do opakowywania w protokół I połączeÅ„ pomiÄ™dzy zdalnymi klientami a lokalnymi lub zdalnymi serwerami. Przez serwer lokalny rozumiana jest aplikacja przeznaczona do uruchamiania przy pomocy I. Stunnel pozwala na proste zestawienie komunikacji serwerów nie posiadajÄ…cych funkcjonalnoÅ›ci I poprzez bezpieczne kanaÅ‚y I. B pozwala dodać funkcjonalność I do powszechnie stosowanych demonów I, np. I lub I, do samodzielnych demonów, np. I, I lub I, a nawet tunelować ppp poprzez gniazda sieciowe bez zmian w kodzie źródÅ‚owym. =head1 OPCJE =over 4 =item B użyj podanego pliku konfiguracyjnego =item B<-fd N> (tylko Unix) wczytaj konfiguracjÄ™ z podanego deskryptora pliku =item B<-help> drukuj listÄ™ wspieranych opcji =item B<-version> drukuj wersjÄ™ programu i domyÅ›lne wartoÅ›ci parametrów =item B<-sockets> drukuj domyÅ›lne opcje gniazd =item B<-options> drukuj wspierane opcje SSL =item B<-install> (tylko Windows NT lub nowszy) instaluj serwis NT =item B<-uninstall> (tylko Windows NT lub nowszy) odinstaluj serwis NT =item B<-start> (tylko Windows NT lub nowszy) uruchom serwis NT =item B<-stop> (tylko Windows NT lub nowszy) zatrzymaj serwis NT =item B<-reload> (tylko Windows NT lub nowszy) przeÅ‚aduj plik konfiguracyjny uruchomionego serwisu NT =item B<-reopen> (tylko Windows NT lub nowszy) otwórz ponownie log uruchomionego serwisu NT =item B<-exit> (tylko Win32) zatrzymaj uruchomiony program =item B<-quiet> (tylko Win32) nie wyÅ›wietlaj okienek z komunikatami =back =head1 PLIK KONFIGURACYJNY Linia w pliku konfiguracyjnym może być: =over 4 =item * pusta (ignorowana) =item * komentarzem rozpoczynajÄ…cym siÄ™ znakiem ';' (ignorowana) =item * parÄ… 'nazwa_opcji = wartość_opcji' =item * tekstem '[nazwa_usÅ‚ugi]' wskazujÄ…cym poczÄ…tek definicji usÅ‚ugi =back Parametr adres może być: =over 4 =item * numerem portu =item * oddzielonÄ… Å›rednikiem parÄ… adresu (IPv4, IPv6, lub nazwÄ… domenowÄ…) i numeru portu =item * Å›cieżkÄ… do gniazda Unix (tylko Unix) =back =head2 OPCJE GLOBALNE =over 4 =item B = KATALOG (tylko Unix) katalog roboczego korzenia systemu plików Opcja okreÅ›la katalog, w którym uwiÄ™ziony zostanie proces programu B tuż po jego inicjalizacji, a przed rozpoczÄ™ciem odbierania połączeÅ„. Åšcieżki podane w opcjach I, I, I oraz I muszÄ… być umieszczone wewnÄ…trz katalogu podanego w opcji I i okreÅ›lone wzglÄ™dem tego katalogu. Niektóre funkcje systemu operacyjnego mogÄ… wymagać dodatkowych plików umieszczonych w katalogu podanego w parametrze chroot: =over 4 =item * opóźnione rozwiniÄ™cie adresów DNS typowo wymaga /etc/nsswitch.conf i /etc/resolv.conf =item * lokalizacja strefy czasowej w logach wymaga pliku /etc/timezone =item * niektóre inne pliki mogÄ… potrzebować plików urzÄ…dzeÅ„, np. /dev/zero lub /dev/null =back =item B = deflate | zlib wybór algorytmu kompresji przesyÅ‚anych danych domyÅ›lnie: bez kompresji Algorytm deflate jest standardowÄ… metodÄ… kompresji zgodnie z RFC 1951. Kompresja zlib zaimplementowana w B i nowszych nie jest kompatybilna implementacjÄ… B. =item B = [PODSYSTEM].POZIOM szczegółowość logowania Poziom logowania można okreÅ›lić przy pomocy jednej z nazw lub liczb: emerg (0), alert (1), crit (2), err (3), warning (4), notice (5), info (6) lub debug (7). Zapisywane sÄ… komunikaty o poziomie niższym (numerycznie) lub równym podanemu. Do uzyskania najwyższego poziomu szczegółowoÅ›ci można użyć opcji I lub I. DomyÅ›lnym poziomem jest notice (5). O ile nie wyspecyfikowano podsystemu użyty bÄ™dzie domyÅ›lny: daemon. Podsystemy nie sÄ… wspierane przez platformÄ™ Win32. Wielkość liter jest ignorowana zarówno dla poziomu jak podsystemu. =item B = ÅšCIEÅ»KA_DO_EGD (tylko Unix) Å›cieżka do gniazda programu Entropy Gathering Daemon Opcja pozwala okreÅ›lić Å›cieżkÄ™ do gniazda programu Entropy Gathering Daemon używanego do zainicjalizowania generatora ciÄ…gów pseudolosowych biblioteki B. Opcja jest dostÄ™pna z bibliotekÄ… B lub nowszÄ…. =item B = auto | IDENTYFIKATOR_URZÄ„DZENIA wybór sprzÄ™towego urzÄ…dzenia kryptograficznego domyÅ›lnie: bez wykorzystania urzÄ…dzeÅ„ kryptograficznych PrzykÅ‚adowa konfiguracja umożliwiajÄ…ca użycie certyfikatu i klucza prywatnego z urzÄ…dzenia zgodnego z OpenSC: engine = dynamic engineCtrl = SO_PATH:/usr/local/lib/engines/libpkcs11.so engineCtrl = LOAD engineCtrl = MODULE_PATH:opensc-pkcs11.so engineCtrl = PIN:123456 [service] engineId = pkcs11 cert = id_45 =item B = KOMENDA[:PARAMETR] konfiguracja urzÄ…dzenia kryptograficznego Specjalna komenda "LOAD" pozwala na zaÅ‚adowanie moduÅ‚u urzÄ…dzenia kryptograficznego. =item B = LISTA_ZADAŃ lista zadaÅ„ OpenSSL oddelegowanych do bieżącego urzÄ…dzenia Parametrem jest lista oddzielonych przecinkami zadaÅ„ OpenSSL, które majÄ… zostać oddelegowane do bieżącego urzÄ…dzenia kryptograficznego. W zależnoÅ›ci od konkretnego urzÄ…dzenia dostÄ™pne mogÄ… być nastÄ™pujÄ…ce zadania: ALL, RSA, DSA, ECDH, ECDSA, DH, RAND, CIPHERS, DIGESTS, PKEY, PKEY_CRYPTO, PKEY_ASN1. =item B = yes | no tryb FIPS 140-2 Opcja pozwala wyłączyć wejÅ›cie w tryb FIPS, jeÅ›li B zostaÅ‚ skompilowany ze wsparciem dla FIPS 140-2. domyÅ›lnie: no (od wersji 5.00) =item B = yes | quiet | no (tylko Unix) tryb pierwszoplanowy Użycie tej opcji powoduje, że B nie przechodzi w tÅ‚o. Parametr I powoduje dodatkowo, że komunikaty diagnostyczne logowane sÄ… na standardowy strumieÅ„ błędów (stderr) oprócz wyjść zdefiniowanych przy pomocy opcji I i I. =item B = PLIK_Z_IKONKÄ„ (tylko GUI) ikonka wyÅ›wietlana przy obecnoÅ›ci aktywnych połączeÅ„ do usÅ‚ugi W systemie Windows ikonka to plik .ico zawierajÄ…cy obrazek 16x16 pikseli. =item B = PLIK_Z_IKONKÄ„ (tylko GUI) ikonka wyÅ›wietlana, jeżeli nie zostaÅ‚ zaÅ‚adowany poprawny plik konfiguracyjny W systemie Windows ikonka to plik .ico zawierajÄ…cy obrazek 16x16 pikseli. =item B = PLIK_Z_IKONKÄ„ (tylko GUI) ikonka wyÅ›wietlana przy braku aktywnych połączeÅ„ do usÅ‚ugi W systemie Windows ikonka to plik .ico zawierajÄ…cy obrazek 16x16 pikseli. =item B = append | overwrite log file handling This option allows to choose whether the log file (specified with the I option) is appended or overwritten when opened or re-opened. domyÅ›lnie: append =item B = PLIK plik, do którego dopisane zostanÄ… logi Użycie tej opcji powoduje dopisanie logów do podanego pliku. Do kierowaniakomunikatów na standardowe wyjÅ›cie (na przykÅ‚ad po to, żeby zalogować je programem splogger z pakietu daemontools) można podać jako parametr urzÄ…dzenie /dev/stdout. =item B = PLIK (tylko Unix) poÅ‚ożenie pliku z numerem procesu Jeżeli argument jest pusty plik nie zostanie stworzony. Jeżeli zdefiniowano katalog I, to Å›cieżka do I jest okreÅ›lona wzglÄ™dem tego katalogu. =item B = LICZBA_BAJTÓW liczba bajtów do zainicjowania generatora pseudolosowego W wersjach biblioteki B starszych niż B<0.9.5a> opcja ta okreÅ›la również liczbÄ™ bajtów wystarczajÄ…cych do zainicjowania PRNG. Nowsze wersje biblioteki majÄ… wbudowanÄ… funkcjÄ™ okreÅ›lajÄ…cÄ…, czy dostarczona ilość losowoÅ›ci jest wystarczajÄ…ca do zainicjowania generatora. =item B = PLIK Å›cieżka do pliku zawierajÄ…cego losowe dane Biblioteka B użyje danych z tego pliku do zainicjowania generatora pseudolosowego. =item B = yes | no nadpisz plik nowymi wartoÅ›ciami pseudolosowymi domyÅ›lnie: yes (nadpisz) =item B = SERWIS (tylko Unix) nazwa usÅ‚ugi Podana nazwa usÅ‚ugi bÄ™dzie używana jako nazwa usÅ‚ugi dla inicjalizacji sysloga, oraz dla biblioteki TCP Wrapper w trybie I. Chociaż technicznie można użyć tej opcji w trybie w sekcji usÅ‚ug, to jest ona użyteczna jedynie w opcjach globalnych. domyÅ›lnie: stunnel =item B = a|l|r:OPCJA=WARTOŚĆ[:WARTOŚĆ] ustaw opcjÄ™ na akceptujÄ…cym/lokalnym/zdalnym gnieździe Dla opcji linger wartoÅ›ci majÄ… postać l_onof:l_linger. Dla opcji time wartoÅ›ci majÄ… postać tv_sec:tv_usec. PrzykÅ‚ady: socket = l:SO_LINGER=1:60 ustaw jednominutowe przeterminowanie przy zamykaniu lokalnego gniazda socket = r:SO_OOBINLINE=yes umieść dane pozapasmowe (out-of-band) bezpoÅ›rednio w strumieniu danych wejÅ›ciowych dla zdalnych gniazd socket = a:SO_REUSEADDR=no zablokuj ponowne używanie portu (domyÅ›lnie włączone) socket = a:SO_BINDTODEVICE=lo przyjmuj połączenia wyłącznie na interfejsie zwrotnym (ang. loopback) =item B = yes | no (tylko Unix) włącz logowanie poprzez mechanizm syslog domyÅ›lnie: yes (włącz) =item B = yes | no (tylko WIN32) włącz ikonkÄ™ w prawym dolnym rogu ekranu domyÅ›lnie: yes (włącz) =back =head2 OPCJE USÅUG Każda sekcja konfiguracji usÅ‚ugi zaczyna siÄ™ jej nazwÄ… ujÄ™tÄ… w nawias kwadratowy. Nazwa usÅ‚ugi używana jest do kontroli dostÄ™pu przez bibliotekÄ™ libwrap (TCP wrappers) oraz pozwala rozróżnić poszczególne usÅ‚ugi w logach. Jeżeli B ma zostać użyty w trybie I, gdzie za odebranie połączenia odpowiada osobny program (zwykle I, I lub I), należy przeczytać sekcjÄ™ I poniżej. =over 4 =item B = [HOST:]PORT nasÅ‚uchuje na połączenia na podanym adresie i porcie Jeżeli nie zostaÅ‚ podany adres, B domyÅ›lnie nasÅ‚uchuje na wszystkich adresach IPv4 lokalnych interfejsów. Aby nasÅ‚uchiwać na wszystkich adresach IPv6 należy użyć: accept = :::port =item B = KATALOG_CA katalog Centrum Certyfikacji Opcja okreÅ›la katalog, w którym B bÄ™dzie szukaÅ‚ certyfikatów, jeżeli użyta zostaÅ‚a opcja I. Pliki z certyfikatami muszÄ… posiadać specjalne nazwy XXXXXXXX.0, gdzie XXXXXXXX jest skrótem kryptograficznym reprezentacji DER nazwy podmiotu certyfikatu. Funkcja skrótu zostaÅ‚a zmieniona w B. Należy wykonać c_rehash przy zmianie B na B<1.x.x>. Jeżeli zdefiniowano katalog I, to Å›cieżka do I jest okreÅ›lona wzglÄ™dem tego katalogu. =item B = PLIK_CA plik Centrum Certyfikacji Opcja pozwala okreÅ›lić poÅ‚ożenie pliku zawierajÄ…cego certyfikaty używane przez opcjÄ™ I. =item B = PLIK_PEM plik z Å‚aÅ„cuchem certyfikatów Opcja okreÅ›la poÅ‚ożenie pliku zawierajÄ…cego certyfikaty używane przez program B do uwierzytelnienia siÄ™ przed drugÄ… stronÄ… połączenia. Certyfikat jest konieczny, aby używać programu w trybie serwera. W trybie klienta certyfikat jest opcjonalny. Jeżeli używane jest sprzÄ™towe urzÄ…dzenie kryptograficzne, to opcja B pozwala wybrać identyfikator używanego certyfikatu. =item B = EMAIL adres email przedstawionego certyfikatu Pojedyncza sekcja może zawierać wiele wystÄ…pieÅ„ opcji B. Certyfikaty sÄ… akceptowane, jeżeli sekcja nie zawiera opcji B, albo adres email przedstawionego certyfikatu pasuje do jednego z adresów email okreÅ›lonych przy pomocy B. Opcja ta wymaga biblioteki OpenSSL w wersji 1.0.2 lub nowszej. =item B = NAZWA_SERWERA nazwa serwera przedstawionego certyfikatu Pojedyncza sekcja może zawierać wiele wystÄ…pieÅ„ opcji B. Certyfikaty sÄ… akceptowane, jeżeli sekcja nie zawiera opcji B, albo nazwa serwera przedstawionego certyfikatu pasuje do jednego nazw okreÅ›lonych przy pomocy B. Opcja ta wymaga biblioteki OpenSSL w wersji 1.0.2 lub nowszej. =item B = IP adres IP przedstawionego certyfikatu Pojedyncza sekcja może zawierać wiele wystÄ…pieÅ„ opcji B. Certyfikaty sÄ… akceptowane, jeżeli sekcja nie zawiera opcji B, albo adres IP przedstawionego certyfikatu pasuje do jednego z adresów IP okreÅ›lonych przy pomocy B. Opcja ta wymaga biblioteki OpenSSL w wersji 1.0.2 lub nowszej. =item B = LISTA_SZYFRÓW lista dozwolonych szyfrów SSL Parametrem tej opcji jest lista szyfrów, które bÄ™dÄ… użyte przy otwieraniu nowych połączeÅ„ SSL, np.: DES-CBC3-SHA:IDEA-CBC-MD5 =item B = yes | no tryb kliencki (zdalna usÅ‚uga używa SSL) domyÅ›lnie: no (tryb serwerowy) =item B = KOMENDA[:PARAMETR] komenda konfiguracyjna B Komenda konfiguracyjna B zostaje wykonana z podanym parametrem. Pozwala to na wydawanie komend konfiguracyjnych B z pliku konfiguracyjnego stunnela. DostÄ™pne komendy opisane sÄ… w manualu I. Możliwe jest wyspecyfikowanie wielu opcji B przez wielokrotne użycie komendy B. Opcja ta wymaga biblioteki OpenSSL w wersji 1.0.2 lub nowszej. =item B = [HOST:]PORT połącz siÄ™ ze zdalnym serwerem na podany port Jeżeli nie zostaÅ‚ podany adres, B domyÅ›lnie łączy siÄ™ z lokalnym serwerem. Komenda może być użyta wielokrotnie w pojedynczej sekcji celem zapewnienia wysokiej niezawodnoÅ›ci lub rozÅ‚ożenia ruchu pomiÄ™dzy wiele serwerów. =item B = KATALOG_CRL katalog List OdwoÅ‚anych Certyfikatów (CRL) Opcja okreÅ›la katalog, w którym B bÄ™dzie szukaÅ‚ list CRL, jeżeli użyta zostaÅ‚a opcja I. Pliki z listami CRL muszÄ… posiadać specjalne nazwy XXXXXXXX.r0, gdzie XXXXXXXX jest skrótem listy CRL. Funkcja skrótu zostaÅ‚a zmieniona B. Należy wykonać c_rehash przy zmianie B na B<1.x.x>. Jeżeli zdefiniowano katalog I, to Å›cieżka do I jest okreÅ›lona wzglÄ™dem tego katalogu. =item B = PLIK_CRL plik List OdwoÅ‚anych Certyfikatów (CRL) Opcja pozwala okreÅ›lić poÅ‚ożenie pliku zawierajÄ…cego listy CRL używane przez opcjÄ™ I. =item B = NID krzywa dla ECDH ListÄ™ dostÄ™pnych krzywych można uzyskać poleceniem: openssl ecparam -list_curves domyÅ›lnie: prime256v1 =item B = TYP typ identyfikatora połączenia klienta Identyfikator ten pozwala rozróżnić wpisy w logu wygenerowane dla poszczególnych połączeÅ„. Aktualnie wspierane typy: =over 4 =item I Kolejny numer połączenia jest unikalny jedynie w obrÄ™bie pojedynczej instancji programu B, ale bardzo krótki. Jest on szczególnie użytczny przy rÄ™cznej analizie logów. =item I Ten rodzaj identyfikatora jest globalnie unikalny, ale znacznie dÅ‚uższy, niż kolejny numer połączenia. Jest on szczególnie użyteczny przy zautomatyzowanej analizie logów. =item I Identyfikator wÄ…tku systemu operacyjnego nie jest ani unikalny (nawet w obrÄ™bie pojedynczej instancji programu B), ani krótki. Jest on szczególnie użyteczny przy diagnozowaniu problemów z oprogramowaniem lub konfiguracjÄ…. =back domyÅ›lnie: sequential =item B = POZIOM szczegółowość logowania Poziom logowania można okreÅ›lić przy pomocy jednej z nazw lub liczb: emerg (0), alert (1), crit (2), err (3), warning (4), notice (5), info (6) lub debug (7). Zapisywane sÄ… komunikaty o poziomie niższym (numerycznie) lub równym podanemu. Do uzyskania najwyższego poziomu szczegółowoÅ›ci można użyć opcji I lub I. DomyÅ›lnym poziomem jest notice (5). =item B = yes | no opóźnij rozwiniÄ™cie adresu DNS podanego w opcji I Opcja jest przydatna przy dynamicznym DNS, albo gdy usÅ‚uga DNS nie jest dostÄ™pna przy starcie programu B (klient VPN, połączenie wdzwaniane). Opóźnione rozwijanie adresu DNS jest włączane automatycznie, jeżeli nie powiedzie siÄ™ rozwiniÄ™cie któregokolwiek z adresów I dla danej usÅ‚ugi. Opóźnione rozwijanie adresu automatycznie aktywuje I. default: no =item B = NUMER_URZÄ„DZENIA wybierz urzÄ…dzenie dla usÅ‚ugi =item B = NUMER_URZÄ„DZENIA wybierz urzÄ…dzenie dla usÅ‚ugi UrzÄ…dzenia sÄ… numerowane od 1 w górÄ™. =item B = ÅšCIEÅ»KA_DO_PROGRAMU wykonaj lokalny program przystosowany do pracy z superdemonem inetd Jeżeli zdefiniowano katalog I, to Å›cieżka do I jest okreÅ›lona wzglÄ™dem tego katalogu. Na platformach Unix ustawiane sÄ… nastÄ™pujÄ…ce zmienne Å›rodowiskowe: REMOTE_HOST, REMOTE_PORT, SSL_CLIENT_DN, SSL_CLIENT_I_DN. =item B = $0 $1 $2 ... argumenty do opcji I włącznie z nazwÄ… programu ($0) Cytowanie nie jest wspierane w obecnej wersji programu. Argumenty sÄ… rozdzielone dowolnÄ… liczbÄ… biaÅ‚ych znaków. =item B = rr | prio Strategia wybierania serwerów wyspecyfikowanych parametrami "connect". rr (round robin) - sprawiedliwe rozÅ‚ożenie obciążenia prio (priority) - użyj kolejnoÅ›ci opcji w pliku konfiguracyjnym domyÅ›lnie: rr =item B = NAZWA_UÅ»YTKOWNIKA weryfikuj nazwÄ™ zdalnego użytkownika korzystajÄ…c z protokoÅ‚u IDENT (RFC 1413) =item B = KATALOG wczytaj fragmenty plików konfiguracyjnych z podanego katalogu Pliki sÄ… wczytywane w rosnÄ…cej kolejnoÅ›ci alfabetycznej ich nazw. =item B = PLIK_KLUCZA klucz prywatny do certyfikatu podanego w opcji I Klucz prywatny jest potrzebny do uwierzytelnienia wÅ‚aÅ›ciciela certyfikatu. Ponieważ powinien on być zachowany w tajemnicy, prawa do jego odczytu powinien mieć wyłącznie wÅ‚aÅ›ciciel pliku. W systemie Unix można to osiÄ…gnąć komendÄ…: chmod 600 keyfile Jeżeli używane jest sprzÄ™towe urzÄ…dzenie kryptograficzne, to opcja B pozwala wybrać identyfikator używanego klucza prywatnego. domyÅ›lnie: wartość opcji I =item B = yes | no włącz lub wyłącz korzystanie z /etc/hosts.allow i /etc/hosts.deny. domyÅ›lnie: no (od wersji 5.00) =item B = HOST IP źródÅ‚a do nawiÄ…zywania zdalnych połączeÅ„ DomyÅ›lnie używane jest IP najbardziej zewnÄ™trznego interfejsu w stronÄ™ serwera, do którego nawiÄ…zywane jest połączenie. =item B = USÅUGA:WZORZEC_NAZWY_SERWERA (tryb serwera) Użyj usÅ‚ugi jako podrzÄ™dnej (virtualnego serwera) dla rozszerzenia TLS Server Name Indication (RFC 3546). I wskazuje usÅ‚ugÄ™ nadrzÄ™dnÄ…, która odbiera połączenia od klientów przy pomocy opcji I. I wskazuje nazwÄ™ serwera wirtualnego. Wzorzec może zaczynać siÄ™ znakiem '*', np. '*.example.com". Z pojedyÅ„czÄ… usÅ‚ugÄ… nadrzÄ™dnÄ… powiÄ…zane jest zwykle wiele usÅ‚ug podrzÄ™dnych. Opcja I może być rownież użyta wielokrotnie w ramach jednej usÅ‚ugi podrzÄ™dnej. Zarówno usÅ‚uga nadrzÄ™dna jak i podrzÄ™dna nie może być skonfigurowana w trybie klienckim. Opcja I usÅ‚ugi podrzÄ™dnej jest ignorowana w połączeniu z opcjÄ… I, gdyż połączenie do zdalnego serwera jest w tym wypadku nawiÄ…zywane przed negocjacjÄ… TLS. Uwierzytelnienie przy pomocy biblioteki libwrap jest realizowane dwukrotnie: najpierw dla usÅ‚ugi nadrzÄ™dnej po odebraniu połączenia TCP, a nastÄ™pnie dla usÅ‚ugi podrzÄ™dnej podczas negocjacji TLS. Opcja I jest dostÄ™pna poczÄ…wszy od B. =item B = HOST (tryb klienta) Użyj parametru jako wartoÅ›ci rozszerzenia TLS Server Name Indication (RFC 3546). Opcja I jest dostÄ™pna poczÄ…wszy od B. =item B = URL responder OCSP do weryfikacji certyfikatów =item B = yes | no weryfikuj certyfikaty przy użyciu respondertów AIA Opcja I pozwala na weryfikowanie certyfikatów przy pomocy listy URLi responderów OCSP przesÅ‚anych w rozszerzeniach AIA (Authority Information Access). =item B = FLAGA_OCSP flaga respondera OCSP aktualnie wspierane flagi: NOCERTS, NOINTERN NOSIGS, NOCHAIN, NOVERIFY, NOEXPLICIT, NOCASIGN, NODELEGATED, NOCHECKS, TRUSTOTHER, RESPID_KEY, NOTIME Aby wyspecyfikować kilka flag należy użyć I wielokrotnie. =item B = yes | no wysyÅ‚aj i weryfikuj OCSP nonce Opcja B zabezpiecza protokół OCSP przed atakami powtórzeniowymi. Ze wzglÄ™du na zÅ‚ożoność obliczeniowÄ… rozszerzenie nonce jest zwykle wspierane jedynie przez wewnÄ™trzne (np. korporacyjne), a nie przez publiczne respondery OCSP. =item B = OPCJE_SSL opcje biblioteki B Parametrem jest nazwa opcji zgodnie z opisem w I, ale bez przedrostka I. I wyÅ›wietla opcje dozwolone w aktualnej kombinacji programu I i biblioteki I. Aby wyspecyfikować kilka opcji należy użyć I wielokrotnie. Nazwa opcji może być poprzedzona myÅ›lnikiem ("-") celem wyłączenia opcji. Na przykÅ‚ad, dla zachowania kompatybilnoÅ›ci z błędami implementacji SSL w programie Eudora, można użyć opcji: options = DONT_INSERT_EMPTY_FRAGMENTS domyÅ›lnie: options = NO_SSLv2 options = NO_SSLv3 =item B = PROTOKÓŠnegocjuj SSL podanym protokoÅ‚em aplikacyjnym Opcja ta włącza wstÄ™pnÄ… negocjacjÄ™ szyfrowania SSL dla wybranego protokoÅ‚u aplikacyjnego. Opcji I nie należy używać z szyfrowaniem SSL na osobnym porcie. Aktualnie wspierane protokoÅ‚y: =over 4 =item I Unieudokumentowane rozszerzenie protokoÅ‚u CIFS wspierane przez serwer Samba. Wsparcie dla tego rozrzeczenia zostaÅ‚o zarzucone w wersji 3.0.0 serwera Samba. =item I Negocjacja RFC 2817 - I, rozdziaÅ‚ 5.2 - I Ten protokół jest wspierany wyłącznie w trybie klienckim. =item I Negocjacja RFC 2595 - I =item I Negocjacja RFC 4642 - I Ten protokół jest wspierany wyłącznie w trybie klienckim. =item I Negocjacja http://www.postgresql.org/docs/8.3/static/protocol-flow.html#AEN73982 =item I Negocjacja RFC 2449 - I =item I Przekazywanie adresu IP haproxy http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt =item I Negocjacja RFC 2487 - I =item I Wspierany jest protokół SOCKS w wersjach 4, 4a i 5. Protokół SOCKS enkapsulowany jest w protokole SSL/TLS, wiÄ™c adres serwera docelowego nie jest widoczny dla napastnika przechwytujÄ…cego ruch sieciowy. F F Nie jest wspierana komenda BIND protokoÅ‚u SOCKS. PrzesÅ‚ana wartość parametru USERID jest ignorowana. Sekcja PRZYKÅADY zawiera przykÅ‚adowe pliki konfiguracyjne VPNa zbudowanego w oparciu o szyfrowany protokół SOCKS. =back =item B = UWIERZYTELNIENIE rodzaj uwierzytelnienia do negocjacji protokoÅ‚u Opcja ta jest wpierana wyłącznie w klienckich protokoÅ‚ach 'connect' i 'smtp'. W protokole 'connect' wspierane jest uwierzytelnienie 'basic' oraz 'ntlm'. DomyÅ›lnym rodzajem uwierzytelnienia protokoÅ‚u 'connect' jest 'basic'. W protokole 'smtp' wspierane jest uwierzytelnienie 'plain' oraz 'login'. DomyÅ›lnym rodzajem uwierzytelnienia protokoÅ‚u 'smtp' jest 'plain'. =item B = DOMENA domena do negocjacji protokoÅ‚u W obecnej wersji wybrana domena ma zastosowanie wyłącznie w protokole 'connect'. =item B = HOST:PORT adres docelowy do negocjacji protokoÅ‚u I okreÅ›la docelowy serwer SSL, do którego połączyć ma siÄ™ proxy. Nie jest to adres serwera proxy, do którego połączenie zestawia B. Adres serwera proxy powinien być okreÅ›lony przy pomocy opcji 'connect'. W obecnej wersji adres docelowy protokoÅ‚u ma zastosowanie wyłącznie w protokole 'connect'. =item B = HASÅO hasÅ‚o do negocjacji protokoÅ‚u Opcja ta jest wspierana wyłącznie w klienckich protokoÅ‚ach 'connect' i 'smtp'. =item B = UÅ»YTKOWNIK nazwa użytkownika do negocjacji protokoÅ‚u Opcja ta jest wspierana wyłącznie w klienckich protokoÅ‚ach 'connect' i 'smtp'. =item B = TOÅ»SAMOŚĆ tożsamość klienta PSK I może zostać użyte w sekcjach klienckich do wybrania tożsamoÅ›ci użytej do uwierzytelnienia PSK. Opcja jest ignorowana w sekcjach serwerowych. domyÅ›lnie: pierwsza tożsamość zdefiniowana w pliku I =item B = PLIK plik z tożsamoÅ›ciami i kluczami PSK Każda linia pliku jest w nastÄ™pujÄ…cym formacie: TOÅ»SAMOŚĆ:KLUCZ Klucz musi być mieć przynajmniej 20 znaków. Należy ograniczyć dostÄ™p do czytania lub pisania do tego pliku. =item B = yes | no (tylko Unix) alokuj pseudoterminal dla programu uruchamianego w opcji 'exec' =item B = [HOST:]PORT przekieruj klienta, któremu nie udaÅ‚o siÄ™ poprawnie uwierzytelnić przy pomocy certyfikatu Opcja dziaÅ‚a wyłącznie w trybie serwera. Część negocjacji protokołów jest niekompatybilna z opcjÄ… I. =item B = yes | no pozwalaj na renegocjacjÄ™ SSL WÅ›ród zastosowaÅ„ renegocjacji SSL sÄ… niektóre scenariusze uwierzytelnienia, oraz renegocjacja kluczy dla dÅ‚ugotrwaÅ‚ych połączeÅ„. Z drugiej strony wÅ‚asność na może uÅ‚atwić trywialny atak DoS poprzez wygenerowanie obciążenia procesora: http://vincent.bernat.im/en/blog/2011-ssl-dos-mitigation.html Warto zauważyć, że zablokowanie renegocjacji SSL nie zebezpiecza w peÅ‚ni przed opisanym problemem. domyÅ›lnie: yes (o ile wspierane przez B) =item B = yes | no sygnalizuj wystÄ…pienie błędu przy pomocy flagi TCP RST Opcja nie jest wspierana na niektórych platformach. domyÅ›lnie: yes =item B = yes | no połącz ponownie sekcjÄ™ connect+exec po rozłączeniu domyÅ›lnie: no =item B = IDENTYFIKATOR_GRUPY (tylko Unix) identyfikator grupy Unix Jako opcja globalna: grupa, z której prawami pracowaÅ‚ bÄ™dzie B. Jako opcja usÅ‚ugi: grupa gniazda Unix utworzonego przy pomocy opcji "accept". =item B = IDENTYFIKATOR_UÅ»YTKOWNIKA (tylko Unix) identyfikator użytkownika Unix Jako opcja globalna: użytkownik, z którego prawami pracowaÅ‚ bÄ™dzie B. Jako opcja usÅ‚ugi: wÅ‚aÅ›ciciel gniazda Unix utworzonego przy pomocy opcji "accept". =item B = LICZBA_POZYCJI_CACHE rozmiar pamiÄ™ci podrÄ™cznej sesji SSL Parametr okreÅ›la maksymalnÄ… liczbÄ™ pozycji wewnÄ™trznej pamiÄ™ci podrÄ™cznej sesji. Wartość 0 oznacza brak ograniczenia rozmiaru. Nie jest to zalecane dla systemów produkcyjnych z uwagi na ryzyko ataku DoS przez wyczerpanie pamiÄ™ci RAM. =item B = LICZBA_SEKUND przeterminowanie pamiÄ™ci podrÄ™cznej sesji SSL Parametr okreÅ›la czas w sekundach, po którym sesja SSL zostanie usuniÄ™ta z pamiÄ™ci podrÄ™cznej. =item B = HOST:PORT adres sessiond - servera cache sesji SSL =item B = WERSJA_SSL wersja protokoÅ‚u SSL Wspierane opcje: all, SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2 DostÄ™pność konkretnych protokołów zależy od użytej wersji OpenSSL. Starsze wersje OpenSSL nie wspierajÄ… TLSv1.1 i TLSv1.2. Nowsze wersje OpenSSL nie wspierajÄ… SSLv2. PrzestarzaÅ‚e protokoÅ‚y SSLv2 i SSLv3 sÄ… domyÅ›lnie wyłączone. Szczegółowe informacje dostÄ™pne sÄ… w opisie opcji B. =item B = LICZBA_BAJTÓW (z wyjÄ…tkiem modelu FORK) rozmiar stosu procesora wÄ…tku =item B = LICZBA_SEKUND czas oczekiwania na spodziewane dane =item B = LICZBA_SEKUND czas oczekiwania na close_notify (ustaw na 0, jeżeli klientem jest MSIE) =item B = LICZBA_SEKUND czas oczekiwania na nawiÄ…zanie połączenia =item B = LICZBA_SEKUND maksymalny czas utrzymywania bezczynnego połączenia =item B = none | source | destination | both (tylko Unix) tryb przezroczystego proxy na wspieranych platformach Wspierane opcje: =over 4 =item B Zablokuj wsparcie dla przezroczystago proxy. Jest to wartość domyÅ›lna. =item B Przepisz adres, aby nawiÄ…zywane połączenie wydawaÅ‚o siÄ™ pochodzić bezpoÅ›rednio od klienta, a nie od programu B. Opcja jest aktualnie obsÅ‚ugiwana w: =over 4 =item Trybie zdalnym (opcja I) w systemie I=2.6.28> Konfiguracja wymaga nastÄ™pujÄ…cych ustawieÅ„ iptables oraz routingu (na przykÅ‚ad w pliku /etc/rc.local lub analogicznym): iptables -t mangle -N DIVERT iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT iptables -t mangle -A DIVERT -j MARK --set-mark 1 iptables -t mangle -A DIVERT -j ACCEPT ip rule add fwmark 1 lookup 100 ip route add local 0.0.0.0/0 dev lo table 100 echo 0 >/proc/sys/net/ipv4/conf/lo/rp_filter Konfiguracja ta wymaga, aby B byÅ‚ wykonywany jako root i bez opcji I. =item Trybie zdalnym (opcja I) w systemie I Konfiguracja ta wymaga skompilowania jÄ…dra z opcjÄ… I. Docelowa usÅ‚uga musi być umieszczona na osobnej maszynie, do której routing kierowany jest poprzez serwer B. Dodatkowo B powinien być wykonywany jako root i bez opcji I. =item Trybie zdalnym (opcja I) w systemie I=8.0> Konfiguracja ta wymaga skonfigurowania firewalla i routingu. B musi być wykonywany jako root i bez opcji I. =item Trybie lokalnym (opcja I) Konfiguracja ta jest realizowana przy pomocy biblioteki I. Do zaÅ‚adowania biblioteki wykorzystywana jest zmienna Å›rodowiskowa _RLD_LIST na platformie Tru64 lub LD_PRELOAD na innych platformach. =back =item I Oryginalny adres docelowy jest używany zamiast opcji I. PrzykÅ‚adowana konfiguracja przezroczystego adresu docelowego: [transparent] client = yes accept = transparent = destination Konfiguracja wymaga ustawieÅ„ iptables, na przykÅ‚ad w pliku /etc/rc.local lub analogicznym. W przypadku docelowej usÅ‚ugi umieszczonej na tej samej maszynie: /sbin/iptables -t nat -I OUTPUT -p tcp --dport \ -m ! --uid-owner \ -j DNAT --to-destination : W przypadku docelowej usÅ‚ugi umieszczonej na zdalnej maszynie: /sbin/iptables -I INPUT -i eth0 -p tcp --dport -j ACCEPT /sbin/iptables -t nat -I PREROUTING -p tcp --dport \ -i eth0 -j DNAT --to-destination : Przezroczysty adres docelowy jest aktualnie wspierany wyłącznie w systemie Linux. =item I Użyj przezroczystego proxy zarówno dla adresu źródÅ‚owego jak i docelowego. =back Dla zapewnienia kompatybilnoÅ›ci z wczeÅ›niejszymim wersjami wspierane sÄ… dwie dodatkowe opcje: =over 4 =item I Opcja zostaÅ‚a przemianowana na I. =item I Opcja zostaÅ‚a przemianowana na I. =back =item B = POZIOM weryfikuj certyfikat drugiej strony połączenia =over 4 =item I zarzÄ…daj certyfikatu i zignoruj go =item I weryfikuj, jeżeli zostaÅ‚ przedstawiony =item I weryfikuj z zainstalowanym certyfikatem Centrum Certyfikacji =item I weryfikuj z lokalnie zainstalowanym certyfikatem drugiej strony =item I weryfikuj z certyfikatem drugiej strony ignorujÄ…c Å‚aÅ„cuch CA =item I nie weryfikuj =back =back =head1 ZWRACANA WARTOŚĆ B zwraca zero w przypadku sukcesu, lub wartość niezerowÄ… w przypadku błędu. =head1 SIGNAÅY NastÄ™pujÄ…ce sygnaÅ‚y mogÄ… być użyte do sterowania programem w systemie Unix: =over 4 =item SIGHUP ZaÅ‚aduj ponownie plik konfiguracyjny. Niektóre globalne opcje nie bÄ™dÄ… przeÅ‚adowane: =over 4 =item * chroot =item * foreground =item * pid =item * setgid =item * setuid =back Jeżeli wykorzystywana jest opcja 'setuid' B nie bÄ™dzie mógÅ‚ zaÅ‚adować ponownie konfiguracji wykorzystujÄ…cej uprzywilejowane (<1024) porty. Jeżeli wykorzystywana jest opcja 'chroot' B bÄ™dzie szukaÅ‚ wszystkich potrzebnych plików (łącznie z plikiem konfiguracyjnym, certyfikatami, logiem i plikiem pid) wewnÄ…trz katalogu wskazanego przez 'chroot'. =item SIGUSR1 Zamknij i otwórz ponownie log. Funkcja ta może zostać użyta w skrypcie rotujÄ…cym log programu B. =item SIGTERM, SIGQUIT, SIGINT ZakoÅ„cz dziaÅ‚anie programu. =back Skutek wysÅ‚ania innych sygnałów jest niezdefiniowany. =head1 PRZYKÅADY Szyfrowanie połączeÅ„ do lokalnego serwera I można użyć: [imapd] accept = 993 exec = /usr/sbin/imapd execArgs = imapd albo w trybie zdalnym: [imapd] accept = 993 connect = 143 Aby umożliwić lokalnemu klientowi poczty elektronicznej korzystanie z serwera I przez SSL należy skonfigurować pobieranie poczty z adresu localhost i portu 119, oraz użyć nastÄ™pujÄ…cej konfiguracji: [imap] client = yes accept = 143 connect = serwer:993 W połączeniu z programem I B pozwala zestawić prosty VPN. Po stronie serwera nasÅ‚uchujÄ…cego na porcie 2020 jego konfiguracja może wyglÄ…dać nastÄ™pujÄ…co: [vpn] accept = 2020 exec = /usr/sbin/pppd execArgs = pppd local pty = yes Poniższy plik konfiguracyjny może być wykorzystany do uruchomienia programu B w trybie I. Warto zauważyć, że w pliku konfiguracyjnym nie ma sekcji I<[nazwa_usÅ‚ugi]>. exec = /usr/sbin/imapd execArgs = imapd Aby skonfigurować VPN można użyć nastÄ™pujÄ…cej konfiguracji klienta: [socks_client] client = yes accept = 127.0.0.1:1080 connect = vpn_server:9080 verify = 4 CAfile = stunnel.pem OdpowiadajÄ…ca jej konfiguracja serwera vpn_server: [socks_server] protocol = socks accept = 9080 cert = stunnel.pem key = stunnel.key Do przetestowania konfiguracji można wydać na maszynie klienckiej komendÄ™: curl --socks4a localhost http://www.example.com/ =head1 NOTKI =head2 OGRANICZENIA B nie może być używany do szyfrowania protokoÅ‚u I, ponieważ do przesyÅ‚ania poszczególnych plików używa on dodatkowych połączeÅ„ otwieranych na portach o dynamicznie przydzielanych numerach. IstniejÄ… jednak specjalne wersje klientów i serwerów FTP pozwalajÄ…ce na szyfrowanie przesyÅ‚anych danych przy pomocy protokoÅ‚u I. =head2 TRYB INETD (tylko Unix) W wiÄ™kszoÅ›ci zastosowaÅ„ B samodzielnie nasÅ‚uchuje na porcie podanym w pliku konfiguracyjnym i tworzy połączenie z innym portem podanym w opcji I lub nowym programem podanym w opcji I. Niektórzy wolÄ… jednak wykorzystywać oddzielny program, który odbiera połączenia, po czym uruchamia program B. PrzykÅ‚adami takich programów sÄ… inetd, xinetd i tcpserver. PrzykÅ‚adowa linia pliku /etc/inetd.conf może wyglÄ…dać tak: imaps stream tcp nowait root @bindir@/stunnel stunnel @sysconfdir@/stunnel/imaps.conf Ponieważ w takich przypadkach połączenie na zdefiniowanym porcie (tutaj I) nawiÄ…zuje osobny program (tutaj I), B nie może używać opcji I. W pliku konfiguracyjnym nie może być również zdefiniowana żadna usÅ‚uga (I<[nazwa_usÅ‚ugi]>), ponieważ konfiguracja taka pozwala na nawiÄ…zanie tylko jednego połączenia. Wszystkie I powinny być umieszczone razem z opcjami globalnymi. PrzykÅ‚ad takiej konfiguracji znajduje siÄ™ w sekcji I. =head2 CERTYFIKATY Protokół SSL wymaga, aby każdy serwer przedstawiaÅ‚ siÄ™ nawiÄ…zujÄ…cemu połączenie klientowi prawidÅ‚owym certyfikatem X.509. Potwierdzenie tożsamoÅ›ci serwera polega na wykazaniu, że posiada on odpowiadajÄ…cy certyfikatowi klucz prywatny. NajprostszÄ… metodÄ… uzyskania certyfikatu jest wygenerowanie go przy pomocy wolnego pakietu B. WiÄ™cej informacji na temat generowania certyfikatów można znaleźć na umieszczonych poniżej stronach. IstotnÄ… kwestiÄ… jest kolejność zawartoÅ›ci pliku I<.pem>. W pierwszej kolejnoÅ›ci powinien on zawierać klucz prywatny, a dopiero za nim podpisany certyfikat (nie żądanie certyfikatu). Po certyfikacie i kluczu prywatnym powinny znajdować siÄ™ puste linie. Jeżeli przed certyfikatem znajdujÄ… siÄ™ dodatkowe informacje tekstowe, to powinny one zostać usuniÄ™te. Otrzymany plik powinien mieć nastÄ™pujÄ…cÄ… postać: -----BEGIN RSA PRIVATE KEY----- [zakodowany klucz] -----END RSA PRIVATE KEY----- [pusta linia] -----BEGIN CERTIFICATE----- [zakodowany certyfikat] -----END CERTIFICATE----- [pusta linia] =head2 LOSOWOŚĆ B potrzebuje zainicjować PRNG (generator liczb pseudolosowych), gdyż protokół SSL wymaga do bezpieczeÅ„stwa kryptograficznego źródÅ‚a dobrej losowoÅ›ci. NastÄ™pujÄ…ce źródÅ‚a sÄ… kolejno odczytywane aż do uzyskania wystarczajÄ…cej iloÅ›ci entropii: =over 4 =item * Zawartość pliku podanego w opcji I. =item * Zawartość pliku o nazwie okreÅ›lonej przez zmiennÄ… Å›rodowiskowÄ… RANDFILE, o ile jest ona ustawiona. =item * Plik .rnd umieszczony w katalogu domowym użytkownika, jeżeli zmienna RANDFILE nie jest ustawiona. =item * Plik podany w opcji '--with-random' w czasie konfiguracji programu. =item * Zawartość ekranu w systemie Windows. =item * Gniazdo egd, jeżeli użyta zostaÅ‚a opcja I. =item * Gniazdo egd podane w opcji '--with-egd-socket' w czasie konfiguracji programu. =item * UrzÄ…dzenie /dev/urandom. =back Współczesne (B<0.9.5a> lub nowsze) wersje biblioteki B automatycznie zaprzestajÄ… Å‚adowania kolejnych danych w momencie uzyskania wystarczajÄ…cej iloÅ›ci entropii. WczeÅ›niejsze wersje biblioteki wykorzystajÄ… wszystkie powyższe źródÅ‚a, gdyż nie istnieje tam funkcja pozwalajÄ…ca okreÅ›lić, czy uzyskano już wystarczajÄ…co dużo danych. Warto zwrócić uwagÄ™, że na maszynach z systemem Windows, na których konsoli nie pracuje użytkownik, zawartość ekranu nie jest wystarczajÄ…co zmienna, aby zainicjować PRNG. W takim przypadku do zainicjowania generatora należy użyć opcji I. Plik I powinien zawierać dane losowe -- również w tym sensie, że powinny być one inne przy każdym uruchomieniu programu B. O ile nie użyta zostaÅ‚a opcja I jest to robione automatycznie. Do rÄ™cznego uzyskania takiego pliku użyteczna może być komenda I dostarczana ze współczesnymi wersjami pakietu B. Jeszcze jedna istotna informacja -- jeżeli dostÄ™pne jest urzÄ…dzenie I biblioteka B ma zwyczaj zasilania nim PRNG w trakcie sprawdzania stanu generatora. W systemach z I urzÄ…dzenie to bÄ™dzie najprawdopodobniej użyte, pomimo że znajduje siÄ™ na samym koÅ„cu powyższej listy. Jest to wÅ‚aÅ›ciwość biblioteki B, a nie programu B. =head2 PARAMETRY DH PoczÄ…wszy od wersji 4.40 B zawiera w kodzie programu 2048-bitowe parametry DH. Od wersji 5.18 te poczÄ…tkowe wartoÅ›ci parametrów DH sÄ… wymieniane na autogenerowane parametry tymczasowe. Wygenerowanie parametrów DH może zająć nawet wiele minut. Alternatywnie parametry DH można umieÅ›cić w pliku razem z certyfikatem, co wyłącza generowanie parametrów tymczasowych: openssl dhparam 2048 >> stunnel.pem =head1 PLIKI =over 4 =item F<@sysconfdir@/stunnel/stunnel.conf> plik konfiguracyjny programu =back =head1 BÅĘDY Opcja I oraz linia komend Win32 nie obsÅ‚uguje cytowania. =head1 ZOBACZ RÓWNIEÅ» =over 4 =item L biblioteka kontroli dostÄ™pu do usÅ‚ug internetowych =item L 'super-serwer' internetowy =item F strona domowa programu B =item F strona projektu B =back =head1 AUTOR =over 4 =item MichaÅ‚ Trojnara > =back =for comment vim:spelllang=pl:spell stunnel-5.30/doc/Makefile.am0000664000175000017500000000171212646221043012656 00000000000000## Process this file with automake to produce Makefile.in # by Michal Trojnara 2015-2016 EXTRA_DIST = stunnel.pod.in stunnel.8.in stunnel.html.in en EXTRA_DIST += stunnel.pl.pod.in stunnel.pl.8.in stunnel.pl.html.in pl man_MANS = stunnel.8 stunnel.pl.8 docdir = $(datadir)/doc/stunnel doc_DATA = stunnel.html stunnel.pl.html CLEANFILES = $(man_MANS) $(doc_DATA) SUFFIXES = .pod.in .8.in .html.in .pod.in.8.in: pod2man -u -n stunnel -s 8 -r $(VERSION) \ -c "stunnel TLS Proxy" -d `date +%Y.%m.%d` $< $@ .pod.in.html.in: pod2html --index --backlink --header \ --title "stunnel TLS Proxy" --infile=$< --outfile=$@ rm -f pod2htmd.tmp pod2htmi.tmp edit = sed \ -e 's|@bindir[@]|$(bindir)|g' \ -e 's|@sysconfdir[@]|$(sysconfdir)|g' $(man_MANS) $(doc_DATA): Makefile $(edit) '$(srcdir)/$@.in' >$@ stunnel.8: $(srcdir)/stunnel.8.in stunnel.html: $(srcdir)/stunnel.html.in stunnel.pl.8: $(srcdir)/stunnel.pl.8.in stunnel.pl.html: $(srcdir)/stunnel.pl.html.in stunnel-5.30/doc/stunnel.pod.in0000664000175000017500000010765712630656244013452 00000000000000=head1 NAME =encoding utf8 stunnel - TLS offloading and load-balancing proxy =head1 SYNOPSIS =over 4 =item B B [S] | S<-fd N> | S<-help> | S<-version> | S<-sockets> | S<-options> =item B B [ [ S<-install> | S<-uninstall> | S<-start> | S<-stop> | S<-reload> | S<-reopen> | S<-exit> ] [S<-quiet>] [S] ] | S<-help> | S<-version> | S<-sockets> | S<-options> =back =head1 DESCRIPTION The B program is designed to work as I encryption wrapper between remote clients and local (I-startable) or remote servers. The concept is that having non-SSL aware daemons running on your system you can easily set them up to communicate with clients over secure SSL channels. B can be used to add SSL functionality to commonly used I daemons like POP-2, POP-3, and IMAP servers, to standalone daemons like NNTP, SMTP and HTTP, and in tunneling PPP over network sockets without changes to the source code. This product includes cryptographic software written by Eric Young (eay@cryptsoft.com) =head1 OPTIONS =over 4 =item B Use specified configuration file =item B<-fd N> (Unix only) Read the config file from specified file descriptor =item B<-help> Print B help menu =item B<-version> Print B version and compile time defaults =item B<-sockets> Print default socket options =item B<-options> Print supported SSL options =item B<-install> (Windows NT and later only) Install NT Service =item B<-uninstall> (Windows NT and later only) Uninstall NT Service =item B<-start> (Windows NT and later only) Start NT Service =item B<-stop> (Windows NT and later only) Stop NT Service =item B<-reload> (Windows NT and later only) Reload the configuration file of the running NT Service =item B<-reopen> (Windows NT and later only) Reopen the log file of the running NT Service =item B<-exit> (Win32 only) Exit an already started stunnel =item B<-quiet> (Win32 only) Don't display any message boxes =back =head1 CONFIGURATION FILE Each line of the configuration file can be either: =over 4 =item * An empty line (ignored). =item * A comment starting with ';' (ignored). =item * An 'option_name = option_value' pair. =item * '[service_name]' indicating a start of a service definition. =back An address parameter of an option may be either: =over 4 =item * A port number. =item * A colon-separated pair of IP address (either IPv4, IPv6, or domain name) and port number. =item * A Unix socket path (Unix only). =back =head2 GLOBAL OPTIONS =over 4 =item B = DIRECTORY (Unix only) directory to chroot B process B keeps B in a chrooted jail. I, I, I and I are located inside the jail and the patches have to be relative to the directory specified with B. Several functions of the operating system also need their files to be located within the chroot jail, e.g.: =over 4 =item * Delayed resolver typically needs /etc/nsswitch.conf and /etc/resolv.conf. =item * Local time in log files needs /etc/timezone. =item * Some other functions may need devices, e.g. /dev/zero or /dev/null. =back =item B = deflate | zlib select data compression algorithm default: no compression deflate is the standard compression method as described in RFC 1951. zlib compression of B or above is not backward compatible with B. =item B = [FACILITY.]LEVEL debugging level Level is one of the syslog level names or numbers emerg (0), alert (1), crit (2), err (3), warning (4), notice (5), info (6), or debug (7). All logs for the specified level and all levels numerically less than it will be shown. Use I or I for greatest debugging output. The default is notice (5). The syslog facility 'daemon' will be used unless a facility name is supplied. (Facilities are not supported on Win32.) Case is ignored for both facilities and levels. =item B = EGD_PATH (Unix only) path to Entropy Gathering Daemon socket Entropy Gathering Daemon socket to use to feed the B random number generator. (Available only if compiled with B or higher) =item B = auto | ENGINE_ID select hardware engine default: software-only cryptography An example of advanced engine configuration to use the certificate and the corresponding private key from an OpenSC PKCS#11 engine: engine = dynamic engineCtrl = SO_PATH:/usr/local/lib/engines/libpkcs11.so engineCtrl = LOAD engineCtrl = MODULE_PATH:opensc-pkcs11.so engineCtrl = PIN:123456 [service] engineId = pkcs11 cert = id_45 =item B = COMMAND[:PARAMETER] control hardware engine A special command "LOAD" can be used to load engine cryptographic module. =item B = TASK_LIST set OpenSSL tasks delegated to the current engine The parameter specifies a comma-separated list of task to be delegated to the current engine. The following tasks may be available, if supported by the engine: ALL, RSA, DSA, ECDH, ECDSA, DH, RAND, CIPHERS, DIGESTS, PKEY, PKEY_CRYPTO, PKEY_ASN1. =item B = yes | no Enable or disable FIPS 140-2 mode. This option allows you to disable entering FIPS mode if B was compiled with FIPS 140-2 support. default: no (since version 5.00) =item B = yes | quiet | no (Unix only) foreground mode Stay in foreground (don't fork). With the I parameter it also logs to stderr in addition to the destinations specified with I and I. default: background in daemon mode =item B = ICON_FILE (GUI only) GUI icon to be displayed when there are established connections On Windows platform the parameter should be an .ico file containing a 16x16 pixel image. =item B = ICON_FILE (GUI only) GUI icon to be displayed when no valid configuration is loaded On Windows platform the parameter should be an .ico file containing a 16x16 pixel image. =item B = ICON_FILE (GUI only) GUI icon to be displayed when there are no established connections On Windows platform the parameter should be an .ico file containing a 16x16 pixel image. =item B = append | overwrite log file handling This option allows you to choose whether the log file (specified with the I option) is appended or overwritten when opened or re-opened. default: append =item B = FILE append log messages to a file /dev/stdout device can be used to send log messages to the standard output (for example to log them with daemontools splogger). =item B = FILE (Unix only) pid file location If the argument is empty, then no pid file will be created. I path is relative to the I directory if specified. =item B = BYTES bytes to read from random seed files Number of bytes of data read from random seed files. With SSL versions less than B<0.9.5a>, also determines how many bytes of data are considered sufficient to seed the PRNG. More recent B versions have a builtin function to determine when sufficient randomness is available. =item B = FILE path to file with random seed data The SSL library will use data from this file first to seed the random number generator. =item B = yes | no overwrite the random seed files with new random data default: yes =item B = SERVICE (Unix only) stunnel service name The specified service name is used for syslog and as the I mode service name for TCP Wrappers. While this option can technically be specified in the service sections, it is only useful in global options. default: stunnel =item B = a|l|r:OPTION=VALUE[:VALUE] Set an option on the accept/local/remote socket The values for the linger option are l_onof:l_linger. The values for the time are tv_sec:tv_usec. Examples: socket = l:SO_LINGER=1:60 set one minute timeout for closing local socket socket = r:SO_OOBINLINE=yes place out-of-band data directly into the receive data stream for remote sockets socket = a:SO_REUSEADDR=no disable address reuse (enabled by default) socket = a:SO_BINDTODEVICE=lo only accept connections on loopback interface =item B = yes | no (Unix only) enable logging via syslog default: yes =item B = yes | no (WIN32 only) enable the taskbar icon default: yes =back =head2 SERVICE-LEVEL OPTIONS Each configuration section begins with a service name in square brackets. The service name is used for libwrap (TCP Wrappers) access control and lets you distinguish B services in your log files. Note that if you wish to run B in I mode (where it is provided a network socket by a server such as I, I, or I) then you should read the section entitled I below. =over 4 =item B = [HOST:]PORT accept connections on specified address If no host specified, defaults to all IPv4 addresses for the local host. To listen on all IPv6 addresses use: accept = :::PORT =item B = DIRECTORY Certificate Authority directory This is the directory in which B will look for certificates when using the I option. Note that the certificates in this directory should be named XXXXXXXX.0 where XXXXXXXX is the hash value of the DER encoded subject of the cert. The hash algorithm has been changed in B. It is required to c_rehash the directory on upgrade from B to B. I path is relative to the I directory if specified. =item B = CERT_FILE Certificate Authority file This file contains multiple CA certificates, used with the I option. =item B = PEM_FILE certificate chain PEM file name The certificates must be in PEM format, and must be from the actual server/client certificate to the self-signed root CA certificate. A certificate is required in server mode, and optional in client mode. This parameter is also used as the certificate identifier when a hardware engine is enabled. =item B = EMAIL email address of the peer certificate subject Multiple I options are allowed in a single service section. Certificates are accepted if no I option was specified, or the email address of the peer certificate matches any of the email addresses specified with I. This option requires OpenSSL 1.0.2 or later. =item B = HOST host of the peer certificate subject Multiple I options are allowed in a single service section. Certificates are accepted if no I option was specified, or the host name of the peer certificate matches any of the hosts specified with I. This option requires OpenSSL 1.0.2 or later. =item B = IP IP address of the peer certificate subject Multiple I options are allowed in a single service section. Certificates are accepted if no I option was specified, or the IP address of the peer certificate matches any of the IP addresses specified with I. This option requires OpenSSL 1.0.2 or later. =item B = CIPHER_LIST Select permitted SSL ciphers A colon-delimited list of the ciphers to allow in the SSL connection, for example DES-CBC3-SHA:IDEA-CBC-MD5. =item B = yes | no client mode (remote service uses SSL) default: no (server mode) =item B = COMMAND[:PARAMETER] B configuration command The B configuration command is executed with the specified parameter. This allows any configuration commands to be invoked from the stunnel configuration file. Supported commands are described on the I manual page. Several I lines can be used to specify multiple configuration commands. This option requires OpenSSL 1.0.2 or later. =item B = [HOST:]PORT connect to a remote address If no host is specified, the host defaults to localhost. Multiple I options are allowed in a single service section. If host resolves to multiple addresses and/or if multiple I options are specified, then the remote address is chosen using a round-robin algorithm. =item B = DIRECTORY Certificate Revocation Lists directory This is the directory in which B will look for CRLs when using the I option. Note that the CRLs in this directory should be named XXXXXXXX.r0 where XXXXXXXX is the hash value of the CRL. The hash algorithm has been changed in B. It is required to c_rehash the directory on upgrade from B to B. I path is relative to the I directory if specified. =item B = CERT_FILE Certificate Revocation Lists file This file contains multiple CRLs, used with the I option. =item B = NID specify ECDH curve name To get a list of supported curves use: openssl ecparam -list_curves default: prime256v1 =item B = TYPE connection identifier type This identifier allows you to distinguish log entries generated for each of the connections. Currently supported types: =over 4 =item I The numeric sequential identifier is only unique within a single instance of B, but very compact. It is most useful for manual log analysis. =item I This alphanumeric identifier is globally unique, but longer than the sequential number. It is most useful for automated log analysis. =item I The operating system thread identifier is neither unique (even within a single instance of B) nor short. It is most useful for debugging software or configuration issues. =back default: sequential =item B = LEVEL debugging level Level is a one of the syslog level names or numbers emerg (0), alert (1), crit (2), err (3), warning (4), notice (5), info (6), or debug (7). All logs for the specified level and all levels numerically less than it will be shown. Use I or I for greatest debugging output. The default is notice (5). =item B = yes | no delay DNS lookup for the I option This option is useful for dynamic DNS, or when DNS is not available during B startup (road warrior VPN, dial-up configurations). Delayed resolver mode is automatically engaged when stunnel fails to resolve on startup any of the I targets for a service. Delayed resolver inflicts I. default: no =item B = ENGINE_ID select engine ID for the service =item B = ENGINE_NUMBER select engine number for the service The engines are numbered starting from 1. =item B = EXECUTABLE_PATH execute a local inetd-type program I path is relative to the I directory if specified. The following environmental variables are set on Unix platforms: REMOTE_HOST, REMOTE_PORT, SSL_CLIENT_DN, SSL_CLIENT_I_DN. =item B = $0 $1 $2 ... arguments for I including the program name ($0) Quoting is currently not supported. Arguments are separated with an arbitrary amount of whitespace. =item B = rr | prio Failover strategy for multiple "connect" targets. rr (round robin) - fair load distribution prio (priority) - use the order specified in config file default: rr =item B = USERNAME use IDENT (RFC 1413) username checking =item B = DIRECTORY include all configuration file parts located in DIRECTORY The files are included in the ascending alphabetical order of their names. =item B = KEY_FILE private key for the certificate specified with I option A private key is needed to authenticate the certificate owner. Since this file should be kept secret it should only be readable by its owner. On Unix systems you can use the following command: chmod 600 keyfile This parameter is also used as the private key identifier when a hardware engine is enabled. default: the value of the I option =item B = yes | no Enable or disable the use of /etc/hosts.allow and /etc/hosts.deny. default: no (since version 5.00) =item B = HOST By default, the IP address of the outgoing interface is used as the source for remote connections. Use this option to bind a static local IP address instead. =item B = SERVICE:SERVER_PATTERN (server mode) Use the service as a slave service (a name-based virtual server) for Server Name Indication TLS extension (RFC 3546). I specifies the master service that accepts client connections with the I option. I specifies the host name to be redirected. The pattern may start with the '*' character, e.g. '*.example.com'. Multiple slave services are normally specified for a single master service. The I option can also be specified more than once within a single slave service. This service, as well as the master service, may not be configured in client mode. The I option of the slave service is ignored when the I option is specified, as I connects to the remote host before TLS handshake. Libwrap checks (Unix only) are performed twice: with the master service name after TCP connection is accepted, and with the slave service name during the TLS handshake. The I option is only available when compiled with B and later. =item B = SERVER (client mode) Use the parameter as the value of TLS Server Name Indication (RFC 3546) extension. The I option is only available when compiled with B and later. =item B = URL select OCSP responder for certificate verification =item B = yes | no validate certificates with their AIA OCSP responders This option enables I to validate certificates with the list of OCSP responder URLs retrieved from their AIA (Authority Information Access) extension. =item B = OCSP_FLAG specify OCSP responder flag Several I can be used to specify multiple flags. currently supported flags: NOCERTS, NOINTERN NOSIGS, NOCHAIN, NOVERIFY, NOEXPLICIT, NOCASIGN, NODELEGATED, NOCHECKS, TRUSTOTHER, RESPID_KEY, NOTIME =item B = yes | no send and verify the OCSP nonce extension This option protects the OCSP protocol against replay attacks. Due to its computational overhead, the nonce extension is usually only supported on internal (e.g. corporate) responders, and not on public OCSP responders. =item B = SSL_OPTIONS B library options The parameter is the B option name as described in the I manual, but without I prefix. I lists the options found to be allowed in the current combination of I and the I library used to build it. Several I