stunnel-5.56/0000775000175000017500000000000013566017555010161 500000000000000stunnel-5.56/INSTALL.FIPS.md0000664000175000017500000000200213527761351012260 00000000000000# stunnel 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.56/configure.ac0000664000175000017500000003773713527761606012410 00000000000000# Process this file with autoconf to produce a configure script. AC_INIT([stunnel],[5.56]) 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([foreign]) 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_SYS_LARGEFILE 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 \ sys/param.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 needed by OpenSSL AC_SEARCH_LIBS([dlopen], [dl]) AC_SEARCH_LIBS([shl_load], [dld]) # 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([**************************************** TLS]) check_ssl_dir() { : test -n "$1" -a -f "$1/include/openssl/ssl.h" && SSLDIR="$1" } iterate_ssl_dir() { : # OpenSSL directory search order: # - the user-specified prefix # - common locations for packages built from sources # - common locations for non-OS-default package managers # - common locations for OS-default package managers # - empty prefix for main_dir in "/usr/local" "/opt" "/opt/local" "/usr/local/opt" "/opt/csw" "/usr/pkg" "/usr/lib" "/usr" ""; do for sub_dir in "/ssl" "/openssl" "/ossl" ""; do check_ssl_dir "$1$main_dir$sub_dir" && return 0 done done return 1 } find_ssl_dir() { : # try Android *first* case "$host_os" in *androideabi*) iterate_ssl_dir "$ANDROID_NDK/sysroot" && return ;; esac test -d "$lt_sysroot" && iterate_ssl_dir "$lt_sysroot" && return test "$prefix" != "NONE" && iterate_ssl_dir "$prefix" && return test -d "$ac_default_prefix" && iterate_ssl_dir "$ac_default_prefix" && return iterate_ssl_dir "" && return # try Xcode *last* 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 TLS directory]) AC_ARG_WITH(ssl, [ --with-ssl=DIR location of installed TLS 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 TLS library installation dir Use --with-ssl option to fix this problem ]) fi AC_MSG_RESULT([$SSLDIR]) AC_SUBST([SSLDIR]) AC_DEFINE_UNQUOTED([SSLDIR], ["$SSLDIR"], [TLS 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 AC_MSG_CHECKING([whether DH parameters need to be updated]) # only build src/dhparam.c if sources are located in the current directory if test -f src/stunnel.c && ! grep -q " built for $PACKAGE_STRING " src/dhparam.c; then AC_MSG_RESULT([yes]) ( echo '/* dhparam.c: initial DH parameters for stunnel */' echo '#include "common.h"' echo '#ifndef OPENSSL_NO_DH' echo '#define DN_new DH_new' openssl dhparam -noout -C 2048 | sed 's/static DH/DH/' echo '#endif /* OPENSSL_NO_DH */' echo "/* built for $PACKAGE_STRING */" ) > src/dhparam.c else AC_MSG_RESULT([no]) fi SYSROOT="$lt_sysroot" CPPFLAGS="$valid_CPPFLAGS" LIBS="$valid_LIBS" AC_MSG_NOTICE([**************************************** write the results]) AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile tools/Makefile tests/Makefile tests/certs/Makefile]) AC_OUTPUT AC_MSG_NOTICE([**************************************** success]) # vim:ft=automake # End of configure.ac stunnel-5.56/COPYRIGHT.md0000644000175000017500000004302513527761172011773 00000000000000GNU General Public License ========================== _Version 2, June 1991_ _Copyright © 1989, 1991 Free Software Foundation, Inc.,_ _51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA_ Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. ### Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: **(1)** copyright the software, and **(2)** offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. ### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION **0.** This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The “Program”, below, refers to any such program or work, and a “work based on the Program” means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term “modification”.) Each licensee is addressed as “you”. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. **1.** You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. **2.** You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: * **a)** You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. * **b)** You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. * **c)** If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. **3.** You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: * **a)** Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, * **b)** Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, * **c)** Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. **4.** You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. **5.** You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. **6.** Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. **7.** If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. **8.** If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. **9.** The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and “any later version”, you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. **10.** If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. ### NO WARRANTY **11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. **12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS ### How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found. Copyright (C) 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w` and `show c` should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w` and `show c`; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a “copyright disclaimer” for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. stunnel-5.56/tests/0000775000175000017500000000000013566017555011323 500000000000000stunnel-5.56/tests/recipes/0000775000175000017500000000000013562354552012752 500000000000000stunnel-5.56/tests/recipes/043_session_delay0000664000175000017500000000206213467064764016053 00000000000000#!/bin/sh # Checking if the delay option works properly when the session is resumed. # This option delays DNS lookup for the connect option. # Delayed resolver inflicts failover = prio. # Just "1" "accepted: new session negotiated" log for [server_1] service is expected. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? else # the resumption of the session does not work for the FORK model exit_logs "043_session_delay" "skipped" exit 125 fi exit $? stunnel-5.56/tests/recipes/041_exec_connect0000664000175000017500000000133513467064764015647 00000000000000#!/bin/sh # Simple execute a local inetd-type program in the client service. # The execArgs option contains arguments for exec including the program name. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? stunnel-5.56/tests/recipes/052_resume_cache0000664000175000017500000000302213562354552015623 00000000000000#!/bin/sh # Checking the cache session resumption. # We expect exactly 1 "accepted: new session negotiated" to be logged by the # [server] service. # "options = NO_TICKET" turns off ticket support in TLSv1.2 and older. # In TLSv1.3, "options = NO_TICKET" switches from using stateful tickets to # stateless tickets (traditional cache with session id sent in tickets). # https://github.com/openssl/openssl/issues/10280 . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? else exit_logs "052_resume_cache" "skipped" exit 125 fi stunnel-5.56/tests/recipes/037_failover_prio10000664000175000017500000000155013467064764016137 00000000000000#!/bin/sh # Checking if the failover strategy for multiple "connect" targets. # The priority (prio) strategy uses the order specified in the config file. # All connections to the [server_1] service are expected. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? stunnel-5.56/tests/recipes/032_no_redirect0000664000175000017500000000262013467064764015505 00000000000000#!/bin/sh # Do not redirect TLS client connections on certificate-based authentication success. # [client_1] -> [server_1] -> [client_2] -> [server_2] # The success is expected because the client presents the *correct* certificate # and the client connection isn't redirected. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? stunnel-5.56/tests/recipes/014_PSK_secrets0000664000175000017500000000163613467064764015403 00000000000000#!/bin/sh # Checking if the PSK authentication works properly. # PSK identities and corresponding keys are stored in files specified with PSKsecrets. # The success is expected because the client presents the valid PSK. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? else # older OpenSSL doesn't support PSK exit_logs "014_PSK_secrets" "skipped" clean_logs exit 125 fi stunnel-5.56/tests/recipes/048_resume_noredirect0000664000175000017500000000304513467064764016737 00000000000000#!/bin/sh # Checking if redirect TLS client connections works properly when the session is resumed. # Do not redirect TLS client connections on certificate-based authentication success. # [client_1] -> [server_1] # Just "1" "accepted: new session negotiated" log for [server_1] service # is expected, because the client presents the correct certificate. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? else # the resumption of the session does not work for the FORK model exit_logs "048_resume_noredirect" "skipped" exit 125 fi exit $? stunnel-5.56/tests/recipes/011_verify_peer0000664000175000017500000000146013467064764015525 00000000000000#!/bin/sh # Checking if the verifyPeer option verifies the peer certificate. # The peer certificate is stored in the file specified with CAfile. # The success is expected because the client presents the valid certificate. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? stunnel-5.56/tests/recipes/030_simple_execute0000664000175000017500000000122213467064764016216 00000000000000#!/bin/sh # Simple execute a local inetd-type program. # The execArgs option contains arguments for exec including the program name. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? stunnel-5.56/tests/recipes/115_failure_wrong_config0000664000175000017500000000125713467064764017407 00000000000000#!/bin/sh # Checking the wrong configuration. # The failure is expected because there is no connect option in the client service. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? stunnel-5.56/tests/recipes/046_resume_PSK0000664000175000017500000000235313562354552015226 00000000000000#!/bin/sh # Checking if the PSK authentication works properly when the session is resumed. # PSK identities and corresponding keys are stored in files specified with PSKsecrets. # Just "1" "accepted: new session negotiated" log is expected for [server] service # because the client presents the valid PSK. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? else exit_logs "046_resume_PSK" "skipped" exit 125 fi exit $? stunnel-5.56/tests/recipes/113_failure_CRL_file0000664000175000017500000000171213467064764016337 00000000000000#!/bin/sh # Checking if the CRL is verified. # The verifyChain option verifies the peer certificate starting from the root CA. # The self-signed root CA certificate is stored in the file specified with CAfile. # Certificate Revocation Lists file is stored in the file specified with CRLfile. # The failure is expected because the server presents the revoked certificate. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? stunnel-5.56/tests/recipes/051_resume_cache_old0000664000175000017500000000262013562354552016463 00000000000000#!/bin/sh # Checking the cache session resumption. # Just "1" "accepted: new session negotiated" log is expected for [server] service. # Enabling NO_TICKET option turns off the ticket support in TLSv1.2 and below. # The cache session is only available when compiled with OpenSSL 0.9.8m and older. # This test is only available when compiled with OpenSSL 0.9.8m and older than 1.1.0 # because of unavailability the sslVersionMax option. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? else exit_logs "051_resume_cache_old" "skipped" exit 125 fi stunnel-5.56/tests/recipes/010_require_cert0000664000175000017500000000127113467064764015676 00000000000000#!/bin/sh # Checking if the requireCert option requires a client certificate. # The success is expected because the client presents a certificate. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? stunnel-5.56/tests/recipes/045_include0000664000175000017500000000173113467064764014641 00000000000000#!/bin/sh # Checking if stunnel works with the configuration placed in a few files. # All configuration file parts are located in the directory specified with include. . $(dirname $0)/../test_library set_config() { mkdir -p "${result_path}/conf.d" echo " debug = debug syslog = no pid = ${result_path}/stunnel.pid output = ${result_path}/stunnel.log" > "${result_path}/conf.d/00-global.conf" echo " [client] client = yes accept = 127.0.0.1:${http1} connect = 127.0.0.1:${https1}" > "${result_path}/conf.d/01-service.conf" echo " [server] accept = 127.0.0.1:${https1} connect = 127.0.0.1:${http_nc} cert = ${script_path}/certs/server_cert.pem" > "${result_path}/conf.d/02-service.conf" } start() { set_config ../../src/stunnel -fd 0 <> "stderr.log" result=$? if [ $result -eq 0 ] then rm -f -r "${result_path}/conf.d" fi exit $result stunnel-5.56/tests/recipes/047_resume_redirect0000664000175000017500000000315613562354552016375 00000000000000#!/bin/sh # Checking if redirect TLS client connections works properly when the session is resumed. # Redirect TLS client connections on certificate-based authentication failures. # [client_1] -> [server_1] -> [client_2] -> [server_2] # Exactly "2" "accepted: new session negotiated" logs for [server_1] # and [server_2] services are expected, because the client presents the wrong certificate. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? else # the resumption of the session does not work for the FORK model exit_logs "047_resume_redirect" "skipped" exit 125 fi exit $? stunnel-5.56/tests/recipes/040_reload0000664000175000017500000000262713467064764014464 00000000000000#!/bin/sh # Checking if the stunnel works correctly after reloading the configuration. # kill -HUP PID is called in reload_stunnel(). . $(dirname $0)/../test_library set_config() { # client doesn't present any certificate echo " debug = debug syslog = no pid = ${result_path}/stunnel.pid output = ${result_path}/stunnel.log [client_1] client = yes accept = 127.0.0.1:${http1} connect = 127.0.0.1:${https1} [server_1] accept = 127.0.0.1:${https1} connect = 127.0.0.1:${http_nc} verifyPeer = yes CAfile = ${script_path}/certs/PeerCerts.pem cert = ${script_path}/certs/server_cert.pem" > "stunnel.conf" } change_config() { # client presents the valid certificate echo " debug = debug syslog = no pid = ${result_path}/stunnel.pid output = ${result_path}/stunnel.log [client_2] client = yes accept = 127.0.0.1:${http1} connect = 127.0.0.1:${https1} cert = ${script_path}/certs/client_cert.pem [server_2] accept = 127.0.0.1:${https1} connect = 127.0.0.1:${http_nc} verifyPeer = yes CAfile = ${script_path}/certs/PeerCerts.pem cert = ${script_path}/certs/server_cert.pem" > "stunnel.conf" } start() { set_config ../../src/stunnel stunnel.conf } myglobal "$1" "$2" "$3" check_ports "040_reload" start_stunnel "040_reload" 2> "error.log" reload_stunnel "040_reload" 2>> "error.log" test_log_for "040_reload" "success" "0" "$1" "$2" "$3" 2>> "stderr.log" exit $? stunnel-5.56/tests/recipes/111_failure_verify_peer0000664000175000017500000000147213467064764017240 00000000000000#!/bin/sh # Checking if the verifyPeer option verifies the peer certificate. # The valid peer certificate is stored in the file specified with CAfile. # The failure is expected because the client presents an incorrect certificate. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? stunnel-5.56/tests/recipes/039_failover_rr0000664000175000017500000000176013467064764015535 00000000000000#!/bin/sh # Checking if the failover strategy for multiple "connect" targets. # The round robin (rr) strategy ensures fair load distribution. # At least one connection with each service is expected. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? stunnel-5.56/tests/recipes/013_CRL_file0000664000175000017500000000220513467064764014625 00000000000000#!/bin/sh # Checking if the CRL is verified. # The verifyChain option verifies the peer certificate starting from the root CA. # The self-signed root CA certificate is stored in the file specified with CAfile. # Certificate Revocation Lists file is stored in the file specified with CRLfile. # The success is expected because the server presents the valid certificate. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? else # older OpenSSL doesn't support sha256 exit_logs "013_CRL_file" "skipped" clean_logs exit 125 fi stunnel-5.56/tests/recipes/053_resume_ticket0000664000175000017500000000325513562354552016054 00000000000000#!/bin/sh # Checking the stateless session ticket resumption (RFC 4507bis) with TLS < 1.3. # We expect exactly 2 "accepted: new session negotiated" to be logged by the # [server] service for connections to [client_1] and [client_2]: # - [client_1] connected 3 times (1 new session, 2 reused sessions). # - [client_2] connected once (1 new session). # The following options are used to disable session cache: # - The "sessionCacheSize = 1" option sets the internal session cache size. # - "options = -NO_TICKET" (it is the default with OpenSSL 1.1.1 or later). . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? else exit_logs "053_resume_ticket" "skipped" exit 125 fi stunnel-5.56/tests/recipes/042_inetd0000664000175000017500000000120313467064764014310 00000000000000#!/bin/sh # inetd mode . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? stunnel-5.56/tests/recipes/054_resume_TLSv1_30000664000175000017500000000325313562354552015723 00000000000000#!/bin/sh # Checking the stateless session ticket resumption (RFC 4507bis) with TLS 1.3. # We expect exactly 2 "accepted: new session negotiated" to be logged by the # [server] service for connections to [client_1] and [client_2]: # - [client_1] connected 3 times (1 new session, 2 reused sessions). # - [client_2] connected once (1 new session). # The following options are used to disable session cache: # - The "sessionCacheSize = 1" option sets the internal session cache size. # - "options = -NO_TICKET" (it is the default with OpenSSL 1.1.1 or later). . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? else exit_logs "054_resume_TLSv1_3" "skipped" exit 125 fi stunnel-5.56/tests/recipes/035_SNI0000664000175000017500000000264113467064764013647 00000000000000#!/bin/sh # Use the service as a slave service (a name-based virtual server) for Server Name Indication TLS extension. # SERVICE_NAME (server_virtual) specifies the master service that accepts client connections with the accept option. # SERVER_NAME_PATTERN (*.mydomain.com) specifies the host name to be redirected. # The success is expected because the client presents the sni pattern (sni.mydomain.com) # corresponding with SERVER_NAME_PATTERN (*.mydomain.com). . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? else # older OpenSSL doesn't support sni exit_logs "035_SNI" "skipped" clean_logs exit 125 fi stunnel-5.56/tests/recipes/031_redirect0000664000175000017500000000264513467064764015017 00000000000000#!/bin/sh # Redirect TLS client connections on certificate-based authentication failures. # [client_1] -> [server_1] -> [client_3] -> [server_3] # The success is expected because the client presents the *wrong* certificate # and the client connection is redirected. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? stunnel-5.56/tests/recipes/112_failure_verify_chain0000664000175000017500000000146213467064764017367 00000000000000#!/bin/sh # Checking if the verifyChain option verifies the peer certificate starting from the root CA. # The self-signed root CA certificate is stored in the file specified with CAfile. # The failure is expected because the server presents an incorrect certificate. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? stunnel-5.56/tests/recipes/033_redirect_exec0000664000175000017500000000233713467064764016023 00000000000000#!/bin/sh # Redirect TLS client connections on certificate-based authentication failures. # [client_1] -> [server_1] -> [client_2] -> [server_2] # The success is expected because the client presents the *wrong* certificate # and the client connection is redirected. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? stunnel-5.56/tests/recipes/038_failover_prio20000664000175000017500000000156413467064764016146 00000000000000#!/bin/sh # Checking if the failover strategy for multiple "connect" targets. # The priority (prio) strategy uses the order specified in the config file. # All connections to the [server_2] service are expected. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? stunnel-5.56/tests/recipes/015_p12_cert0000664000175000017500000000155113467064764014632 00000000000000#!/bin/sh # Checking if the file containing certificates used by stunnel to authenticate # itself against the remote client or server may be in the P12 format. # The success is expected because the server presents the valid certificate in the P12 format. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? else exit_logs "015_p12_cert" "skipped" clean_logs exit 125 fi stunnel-5.56/tests/recipes/114_failure_PSK_secrets0000664000175000017500000000165313467064764017112 00000000000000#!/bin/sh # Checking if the PSK authentication works properly. # PSK identities and corresponding keys are stored in files specified with PSKsecrets. # The failure is expected because the client presented an incorrect key. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? else # older OpenSSL doesn't support PSK exit_logs "114_failure_PSK_secrets" "skipped" "error" exit 125 fi stunnel-5.56/tests/recipes/021_FIPS0000664000175000017500000000124113467064764013745 00000000000000#!/bin/sh # Checking FIPS mode. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? else exit_logs "021_FIPS" "skipped" clean_logs exit 125 fi stunnel-5.56/tests/recipes/110_failure_require_cert0000664000175000017500000000131413467064764017404 00000000000000#!/bin/sh # Checking if the requireCert option requires a client certificate. # The failure is expected because the client does not present the certificate. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? stunnel-5.56/tests/recipes/050_ticket_secrets0000664000175000017500000000340113562354552016212 00000000000000#!/bin/sh # Checking if the reloaded server resume the session with secret keys for # the session ticket processing. # Just "1" "accepted: new session negotiated" log for the [server] service # is expected for the first connection, and "0" for the second connection # because the server holds keys for the session ticket processing. # Disabling "NO_TICKET" option is required for the ticket support in OpenSSL older than 1.1.1. # The ticket session resumption also works for the FORK model. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 9 9<> "stderr.log" exit $? else exit_logs "050_ticket_secrets" "skipped" exit 125 fi stunnel-5.56/tests/recipes/012_verify_chain0000664000175000017500000000176513467064764015665 00000000000000#!/bin/sh # Checking if the verifyChain option verifies the peer certificate starting from the root CA. # The self-signed root CA certificate is stored in the file specified with CAfile. # The success is expected because the server presents the valid certificate. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? else # older OpenSSL doesn't support sha256 exit_logs "012_verify_chain" "skipped" clean_logs exit 125 fi stunnel-5.56/tests/recipes/044_session_nodelay0000664000175000017500000000241713467064764016415 00000000000000#!/bin/sh # Checking if disable delay option works properly when the session is resumed. # This option delays DNS lookup for the connect option. # Exactly "2" "accepted: new session negotiated" logs for [server_1] # and [server_2] services are expected, because failover = rr . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? else # the resumption of the session does not work for the FORK model exit_logs "044_session_nodelay" "skipped" exit 125 fi exit $? stunnel-5.56/tests/recipes/022_bind0000664000175000017500000000135613467064764014130 00000000000000#!/bin/sh # Checking if the service does't refuse to start if binding fails for some addresses:ports. # Expected logs: # LOG6[ui]: Service [server] (FD=7) bound to 127.0.0.1:4433 # LOG5[ui]: Binding service [server] to 127.0.0.1:4433: Address already in use (98) . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? stunnel-5.56/tests/recipes/020_IPv60000664000175000017500000000153413477473304013767 00000000000000#!/bin/sh # Checking if IPv6 is supported. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? else exit_logs "020_IPv6" "skipped" clean_logs exit 125 fi stunnel-5.56/tests/recipes/036_no_SNI0000664000175000017500000000237413467064764014347 00000000000000#!/bin/sh # Use the service as a slave service (a name-based virtual server) for Server Name Indication TLS extension. # SERVICE_NAME (server_virtual) specifies the master service that accepts client connections with the accept option. # SERVER_NAME_PATTERN sni.mydomain.com) specifies the host name to be redirected. # The success is expected because the client doesn't present any sni pattern. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? else # older OpenSSL doesn't support sni exit_logs "036_no_SNI" "skipped" clean_logs exit 125 fi stunnel-5.56/tests/recipes/034_no_redirect_exec0000664000175000017500000000225613467064764016520 00000000000000#!/bin/sh # Do not redirect TLS client connections on certificate-based authentication success. # [client_1] -> [server_1] # The success is expected because the client presents the *correct* certificate # and the client connection isn't redirected. . $(dirname $0)/../test_library start() { ../../src/stunnel -fd 0 <> "stderr.log" exit $? stunnel-5.56/tests/Makefile.am0000664000175000017500000000040113467064764013276 00000000000000## Process this file with automake to produce Makefile.in # by Michal Trojnara 1998-2019 SUBDIRS = certs EXTRA_DIST = make_test test_library recipes execute execute_read execute_write check-local: $(srcdir)/make_test distclean-local: rm -f logs/*.log stunnel-5.56/tests/test_library0000775000175000017500000005310213562354552013672 00000000000000# this file is a library sourced from recipes/* result_path=$(pwd) cd $(dirname "$0")/../ script_path=$(pwd) cd "${result_path}" result_logs() { # $1 = test name # $2 = status: "ok" / "failed" / "configuration failed" / "expected error" # "skipped" / "netcat failed" / "shouldn't work" # $3 = file name: "stunnel" / "error" if [ "$2" = "expected error" ] then # expected error - it's ok printf "%-35s\t%s\n" "test $1" "ok" else printf "%-35s\t%s\n" "test $1" "$2" fi if [ "$2" != "ok" ] then printf "%-35s\t%s\n" "test $1" "$2" >> "results.log" fi if [ "$2" = "failed" ] || [ "$2" = "configuration failed" ] || [ "$2" = "shouldn't work" ] then # file with stunnel error logs printf "%-35s\t%s\n" "error logs" "logs/$1.log" cat "$3.log" > "$1.log" else cat "temp.log" 2>> "stderr_nc.log" | head -n1 >> "results.log" fi if [ "$2" = "netcat failed" ] then printf "\n%s\n" "Netcat failed" >> "stderr_nc.log" fi return 0 } exit_logs() { # $1 = test name # $2 = status case "$2" in "ok") result_logs "$1" "ok" "UNUSED PATTERN";; "failed") result_logs "$1" "failed" "stunnel";; "configuration failed") result_logs "$1" "configuration failed" "error";; "expected error") result_logs "$1" "expected error" "UNUSED PATTERN";; "skipped") result_logs "$1" "skipped" "error";; "netcat failed") result_logs "$1" "netcat failed" "stunnel";; "shouldn't work") result_logs "$1" "shouldn't work" "stunnel";; *) echo "$1 exit_logs error" esac return 0 } clean_logs() { cat "stderr_nc.log" >> "stderr.log" rm -f "stderr_nc.log" rm -f "stunnel.log" rm -f "temp.log" rm -f "error.log" rm -f "stunnel.conf" rm -f "nodata" return 0 } finding_text() { # $1 = to find (yes) or not to find (no) # $2 = pattern # $3 = file 1 # $4 = file 2 local result=0 if grep -q "$2" "$3" "$4" then if [ $1 = "yes" ] then # to find exit_code="ok" else # not to find exit_code="failed" result=1 fi else # no matching if [ $1 = "yes" ] then # to find exit_code="failed" result=1 fi fi return $result } no_file() { # $1 = file local result=0 if [ -s "$1" ] then exit_code="configuration failed" result=1 fi return $result } waiting_for() { # waiting for string $2 to appear in the file $1.log mkfifo "fifo" 2>> "stderr_nc.log" (cat "$1.log"; tail -f "$1.log") > "fifo" 2>> "stderr_nc.log" & pid_tail=$! (sleep 3; echo "TIMEOUT") > "fifo" & pid_timeout=$! grep -q -e "$2" -e "TIMEOUT" "fifo" pid_children=$(ps -o pid,ppid | \ awk -v ppid1="${pid_tail}" -v ppid2="${pid_timeout}" \ '{if ($2==ppid1 || $2==ppid2) print $1}') kill -TERM ${pid_tail} ${pid_timeout} ${pid_children} 2>> "stderr_nc.log" wait ${pid_tail} ${pid_timeout} 2>> "stderr_nc.log" rm -f "fifo" return 0 } find_free() { # finding a free port # $1 = mynetstat name: "netstat -a -n" / "ss -a -n -l" / "lsof -i -n -P" while $mynetstat $opt_net | grep "$http_find" | grep "LISTEN" >> "stderr_nc.log" do http_find=$((http_find+1)) done return 0 } check_ports() { # seting the initial ports # $1 = test name result=0 printf "\n%s\n" "test $1" >> "stderr_nc.log" http_find=8080 find_free http_nc=$http_find http_find=4567 find_free https_free=$http_find http1=$((http_nc+1)) http2=$((http_nc+2)) http3=$((http_nc+3)) https1=4433 https2=4434 https3=4435 return 0 } bind_http_ports(){ grep "Binding service \[client.*to" "error.log" >> "stderr_nc.log" grep "Binding service \[client.*failed" "error.log" >> "stderr_nc.log" while [ -s "error.log" ] && grep -q "Binding service \[client.*failed" "error.log" do if [ $http_bind -eq $http1 ] then http1=$((http1+1)) http2=$((http2+1)) http3=$((http3+1)) elif [ $http_bind -eq $http2 ] then http2=$((http2+1)) http3=$((http3+1)) else http3=$((http3+1)) fi http_bind=$((http_bind+1)) start 2> "error.log" grep "Binding service \[client.*to" "error.log" >> "stderr_nc.log" grep "Binding service \[client.*failed" "error.log" >> "stderr_nc.log" done return 0 } bind_https_ports(){ grep "Binding service \[server.*to" "error.log" >> "stderr_nc.log" grep "Binding service \[server.*failed" "error.log" >> "stderr_nc.log" while [ -s "error.log" ] && grep -q "Binding service \[server.*failed" "error.log" do if [ $https_bind -eq $https1 ] then https1=$((https1+1)) https2=$((https2+1)) https3=$((https3+1)) elif [ $https_bind -eq $https2 ] then https2=$((https2+1)) https3=$((https3+1)) else https3=$((https3+1)) fi https_bind=$((https_bind+1)) start 2> "error.log" grep "Binding service \[server.*to" "error.log" >> "stderr_nc.log" grep "Binding service \[server.*failed" "error.log" >> "stderr_nc.log" done return 0 } start_stunnel() { # running stunnel until to bind free ports # $1 = test name start 2> "error.log" http_bind=$http1 bind_http_ports http_bind=$http2 bind_http_ports http_bind=$http3 bind_http_ports https_bind=$https1 bind_https_ports https_bind=$https2 bind_https_ports https_bind=$https3 bind_https_ports printf "\n%s %s %s %s %s %s %s\n" "test $1 ports: $http_nc $http1 $http2 $http3 $https1 $https2 $https3 $https_free" >> "stderr_nc.log" return 0 } close_process() { # $1 = file name # $2 = process pid wait $2 local result=$? case $result in "0") ;; # expected exit status of the stunnel process "127") ;; # non-existent stunnel process "139") echo "INTERNAL ERROR: $1 exit status $result Segmentation fault (core dumped)" >> "$1.log";; *) echo "INTERNAL ERROR: $1 exit status $result" >> "$1.log" esac return $result } killing_stunnel() { # $1 = file name local result=0 local pid_stunnel=$(tail "$1.pid") if kill -TERM ${pid_stunnel} 2>> "stderr_nc.log" then close_process $1 ${pid_stunnel} else exit_code="failed" result=1 fi return $result } reload_stunnel() { # $1 = test name local result=0 printf "\n%s\n" "test $1 - reload stunnel" >> "stderr_nc.log" if [ ! -s "error.log" ] then change_config waiting_for "stunnel" "stunnel.pid" kill -HUP $(tail "stunnel.pid") 2>> "stderr_nc.log" waiting_for "stunnel" "127.0.0.1:$http1" else printf "\n%s" "$1 error: failed to reload the configuration file" >> "error.log" result=1 fi return $result } check_listening() { # waiting for netcat listening on port # $1 = port number result=0 while [ $result -eq 0 ] && ! $mynetstat $opt_net | grep "$1" | grep "LISTEN" >> "stderr_nc.log" do printf "\n%s\n" "waiting for netcat listening on $1" >> "stderr_nc.log" if grep -q -e "failed:" -e "usage" -e "QUITTING" -e "invalid" -e "command not found" "stderr_nc.log" then result=1 fi done return $result } connecting_ncat() { # $1 = test name # $2 = string to send local result=0 mkfifo "nodata" 2>> "stderr_nc.log" printf "\n%s\n" "test $1 - netcat connection" >> "stderr_nc.log" if [ "$mynetcat" = "nc" ] then # nc if man "$mynetcat" | grep -q "error to use this option in conjunction" then # BSD nc cat "nodata" | $mybuffer $opt_buf $mynetcat -l "$http_nc" -vvv > "temp.log" 2>> "stderr_nc.log" & else # traditional nc cat "nodata" | $mybuffer $opt_buf $mynetcat -l -p "$http_nc" -vvv > "temp.log" 2>> "stderr_nc.log" & fi pid_nc=$! if check_listening "$http_nc" then printf "%-35s\t%s\n" "test $1" "$2" | $mynetcat 127.0.0.1 "$http1" -vv 1>&2 2>> "stderr_nc.log" & pid_nce=$! if [ "$2" = "shouldn't work" ] then waiting_for "stunnel" "Service .* finished" else waiting_for "temp" "test $1" fi else # nc failed exit_code="netcat failed" result=1 fi else # ncat cat "nodata" | $mybuffer $opt_buf $mynetcat -l -p $http_nc -vvv > temp.log 2>> stderr_nc.log & pid_nc=$! if check_listening "$http_nc" then if ncat --version 2>&1 | grep -q -e 'Version [0-5]\.' -e 'Version [6]\.[0-1]' -e 'Version [6]\.[2][0-4]' then # ncat version < 6.25 printf "%-35s\t%s\n" "test $1" "$2" | "$mynetcat" 127.0.0.1 "$http1" -vv 1>&2 2>> "stderr_nc.log" & else # ncat version >= 6.25 printf "%-35s\t%s\n" "test $1" "$2" | "$mynetcat" 127.0.0.1 "$http1" -vv 1>&2 2>> "stderr_nc.log" fi pid_nce=$! if [ "$2" = "shouldn't work" ] then waiting_for "stunnel" "Service .* finished" else waiting_for "temp" "test $1" fi else # ncat failed exit_code="netcat failed" result=1 fi fi kill -TERM ${pid_nc} ${pid_nce} 2>> "stderr_nc.log" echo "somedata" > "nodata" 2>> "stderr_nc.log" rm -f "nodata" return $result } sending_ncat() { # starting netcat for execute tests # $1 = test name mkfifo "nodata" 2>> "stderr_nc.log" cat "nodata" | $mybuffer $opt_buf $mynetcat 127.0.0.1 "$http1" -vv >"temp.log" 2>> "stderr_nc.log" & pid_nce=$(pgrep -P $!) waiting_for "temp" "test $1" kill -TERM ${pid_nce} 2>> "stderr_nc.log" echo "somedata" > "nodata" 2>> "stderr_nc.log" rm -f "nodata" return 0 } expected_success() { # expects to send the message using stunnel # $1 = test name local result=0 if [ "$1" != "040_reload" ] then check_ports "$1" start_stunnel "$1" fi if no_file "error.log" then if connecting_ncat "$1" "success" then finding_text "yes" "test $1.*success" "temp.log" "UNUSED PATTERN" result=$? else # ncat (nc) failed result=1 fi if ! killing_stunnel stunnel then result=1 fi else # configuration failed result=1 fi if ! finding_text "no" "INTERNAL ERROR" "stunnel.log" "error.log" then result=1 fi exit_logs "$1" "$exit_code" return $result } expected_failure() { # $1 = test name local result=0 check_ports "$1" start_stunnel "$1" if no_file "error.log" then if connecting_ncat "$1" "shouldn't work" then if ! finding_text "no" "test $1.*shouldn't work" "temp.log" "UNUSED PATTERN" then # ops...stunnel works exit_code="shouldn't work" result=1 else exit_code="expected error" fi else # ncat (nc) failed result=1 fi if ! killing_stunnel stunnel then result=1 fi else # configuration failed, but it is ok exit_code="expected error" fi if ! finding_text "no" "INTERNAL ERROR" "stunnel.log" "error.log" then result=1 fi exit_logs "$1" "$exit_code" return $result } execute_program() { # $1 = test name local result=0 check_ports "$1" start_stunnel "$1" if no_file "error.log" then sending_ncat "$1" if ! killing_stunnel stunnel then result=1 fi if [ $result -eq 0 ] then if finding_text "yes" "test $1.*success" "temp.log" "UNUSED PATTERN" then finding_text "no" "$1_error" "temp.log" "UNUSED PATTERN" result=$? else result=1 fi fi else # configuration failed result=1 fi if ! finding_text "no" "INTERNAL ERROR" "stunnel.log" "error.log" then result=1 fi exit_logs "$1" "$exit_code" return $result } execute_connect() { # $1 = test name local result=0 check_ports "$1" start_stunnel "$1" if [ "$1" = "042_inetd" ] then # inetd test mkfifo "nodata" 2>> "stderr_nc.log" start_inetd > "temp.log" 2>> "error.log" & pid_inetd=$! fi if no_file "error.log" then waiting_for "stunnel" "Service .* finished" if [ $1 = "042_inetd" ] then # inetd test close_process stunnel_inetd ${pid_inetd} fi finding_text "yes" "test $1.*success" "temp.log" "UNUSED PATTERN" result=$? if [ "$1" = "042_inetd" ] then # inetd test printf "%s\n" "*** inetd mode ***" >> "stunnel.log" cat "stunnel_inetd.log" >> "stunnel.log" fi if ! killing_stunnel stunnel then result=1 fi else # configuration failed result=1 fi if ! finding_text "no" "INTERNAL ERROR" "stunnel.log" "error.log" then result=1 fi rm -f "stunnel_inetd.log" exit_logs "$1" "$exit_code" return $result } loop_prio() { # $1 = test name local result=0 local i=1 local max=12 if [ $1 = "037_failover_prio1" ] then local serv="server_2\] accepted connection" else local serv="server_1\] accepted connection" fi check_ports "$1" start_stunnel "$1" if no_file "error.log" then waiting_for "stunnel" "Created pid file" mv "stunnel.log" "stunnel_0.log" kill -USR1 $(tail "stunnel.pid") 2>> "stderr_nc.log" while [ $i -le $max ] && [ $result -eq 0 ] do if connecting_ncat "$1" "success" then finding_text "yes" "test $1.*success" "temp.log" "UNUSED PATTERN" result=$? if [ $result -eq 0 ] && ! finding_text "no" "$serv" "stunnel.log" "UNUSED PATTERN" then # error - second server accepts a client result=1 fi else # ncat (nc) failed result=1 fi mv "stunnel.log" "stunnel_$i.log" kill -USR1 $(tail "stunnel.pid") 2>> "stderr_nc.log" i=$((i + 1)) done cat "stunnel_0.log" > "stunnel_all.log" rm -f "stunnel_0.log" local j=1 while [ $j -lt $i ] do printf "%s\n" "*** connection $j ***" >> "stunnel_all.log" cat "stunnel_$j.log" >> "stunnel_all.log" rm -f "stunnel_$j.log" j=$((j + 1)) done if ! killing_stunnel stunnel then result=1 fi cat "stunnel.log" >> "stunnel_all.log" cat "stunnel_all.log" > "stunnel.log" rm -f "stunnel_all.log" else # configuration failed result=1 fi if ! finding_text "no" "INTERNAL ERROR" "stunnel.log" "error.log" then result=1 fi exit_logs "$1" "$exit_code" return $result } loop_rr() { # $1 = test name local result=0 local i=1 local max=3 local first=0 local second=0 local third=0 check_ports "$1" start_stunnel "$1" if no_file "error.log" then waiting_for "stunnel" "Created pid file" mv "stunnel.log" "stunnel_0.log" kill -USR1 $(tail "stunnel.pid") 2>> "stderr_nc.log" while [ $i -le $max ] && [ $result -eq 0 ] do if connecting_ncat "$1" "success" then finding_text "yes" "test $1.*success" "temp.log" "UNUSED PATTERN" result=$? else # ncat (nc) failed result=1 fi mv "stunnel.log" "stunnel_$i.log" kill -USR1 $(tail "stunnel.pid") 2>> "stderr_nc.log" i=$((i + 1)) done cat "stunnel_0.log" > "stunnel_all.log" rm -f "stunnel_0.log" j=1 while [ $j -lt $i ] do printf "%s\n" "*** connection $j ***" >> "stunnel_all.log" cat "stunnel_$j.log" >> "stunnel_all.log" rm -f "stunnel_$j.log" j=$((j + 1)) done if ! killing_stunnel stunnel then result=1 fi cat "stunnel.log" >> "stunnel_all.log" cat "stunnel_all.log" > "stunnel.log" rm -f "stunnel_all.log" if [ $result -eq 0 ] then first=$(grep -c "server_1\] accepted connection" "stunnel.log") second=$(grep -c "server_2\] accepted connection" "stunnel.log") third=$(grep -c "server_3\] accepted connection" "stunnel.log") product=$((first * second * third)) if [ $product -ne 0 ] then # round robin printf "%-35s\t%s\n" "test $1: $first x $second x $third" "success" > "temp.log" else printf "%-35s\t%s\n" "test $1: $first x $second x $third" "failed" > "temp.log" exit_code="failed" result=1 fi fi else # configuration failed result=1 fi if ! finding_text "no" "INTERNAL ERROR" "stunnel.log" "error.log" then result=1 fi exit_logs "$1" "$exit_code" return $result } loop_session() { # $1 = test name # $2 = number of connections local result=0 local i=0 local j=0 local max=$((2*$2)) check_ports "$1" start_stunnel "$1" if no_file "error.log" then waiting_for "stunnel" "Created pid file" while [ $i -le $max ] do i=$(grep -c "Retrying an exec+connect section" "stunnel.log") done if ! killing_stunnel stunnel then result=1 fi if [ $result -eq 0 ] then finding_text "yes" "test $1.*success" "temp.log" "UNUSED PATTERN" result=$? fi j=$(grep -c "accepted: new session negotiated" "stunnel.log") if [ $result -eq 0 ] && [ $j -ne $2 ] then exit_code="failed" result=1 fi else # configuration failed result=1 fi if ! finding_text "no" "INTERNAL ERROR" "stunnel.log" "error.log" then result=1 fi exit_logs "$1" "$exit_code" return $result } two_instances() { # $1 = test name # $2 = number of new connections local result=0 local i=0 local j=0 start_server 2> "error.log" if no_file "error.log" then waiting_for "stunnel_server" "Created pid file" start_stunnel "$1" if no_file "error.log" then while [ $i -le 2 ] do i=$(grep -c "Retrying an exec+connect section" "stunnel.log") done if ! killing_stunnel stunnel_server then result=1 fi mv "stunnel_server.log" "stunnel_all.log" start_server 2>> "error.log" waiting_for "stunnel_server" "Service .* finished" if ! killing_stunnel stunnel_server then result=1 fi cat "stunnel_server.log" >> "stunnel_all.log" if ! killing_stunnel stunnel then result=1 fi cat "stunnel.log" >> "stunnel_all.log" cat "stunnel_all.log" > "stunnel.log" rm -f "stunnel_all.log" if [ $result -eq 0 ] then finding_text "yes" "test $1.*success" "temp.log" "UNUSED PATTERN" result=$? fi j=$(grep -c "accepted: new session negotiated" "stunnel.log") if [ $result -eq 0 ] && [ $j -ne $2 ] then exit_code="failed" result=1 fi else # client configuration failed killing_stunnel stunnel_server exit_code="configuration failed" result=1 fi else # server configuration failed cat "stunnel_server.log" >> "stunnel.log" result=1 fi if ! finding_text "no" "INTERNAL ERROR" "stunnel.log" "error.log" then result=1 fi rm -f "stunnel_server.log" exit_logs "$1" "$exit_code" return $result } resumption() { # $1 = test name # $2 = number of new connections local result=0 local i=0 local j=0 check_ports "$1" start_stunnel "$1" if no_file "error.log" then waiting_for "stunnel" "Service .* finished" connecting_ncat "$1" "success" while [ $i -le $2 ] do i=$(grep -c "Retrying an exec+connect section" "stunnel.log") done if ! killing_stunnel stunnel then result=1 fi if [ $result -eq 0 ] then finding_text "yes" "test $1.*success" "temp.log" "UNUSED PATTERN" result=$? fi j=$(grep -c "accepted: new session negotiated" "stunnel.log") if [ $result -eq 0 ] && [ $j -ne $2 ] then exit_code="failed" result=1 fi else # configuration failed result=1 fi if ! finding_text "no" "INTERNAL ERROR" "stunnel.log" "error.log" then result=1 fi exit_logs "$1" "$exit_code" return $result } myglobal() { # $1 = mynetcat name: "ncat" / "nc" # $2 = mynetstat name: "netstat" / "ss" / "lsof" # $3 = mybuffer name: "stdbuf" / "unbuffer" / "" mynetcat="$1" mynetstat="$2" mybuffer="$3" case "$mynetstat" in "netstat") opt_net="-a -n";; "ss") opt_net="-a -n -l";; "lsof") opt_net="-i -n -P";; esac case "$mybuffer" in "stdbuf") opt_buf="-o0";; esac return 0 } test_log_for() { # $1 = test name # $2 = function name # $3 = number of connections for loop_session # $4 = mynetcat name: "ncat" / "nc" # $5 = mynetstat name: "netstat" / "ss" / "lsof" # $6 = mybuffer name: "stdbuf" / "unbuffer" / "" myglobal "$4" "$5" "$6" case "$2" in "success") expected_success "$1";; "failure") expected_failure "$1";; "execute") execute_program "$1";; "exe_con") execute_connect "$1";; "prio") loop_prio "$1";; "rr") loop_rr "$1";; "session") loop_session "$1" "$3";; "instances") two_instances "$1" "$3";; "resumption") resumption "$1" "$3";; esac result=$? clean_logs return $result } stunnel-5.56/tests/certs/0000775000175000017500000000000013566017555012443 500000000000000stunnel-5.56/tests/certs/maketestcert.sh0000775000175000017500000001057013405402665015410 00000000000000#!/bin/sh ddays=1461 result_path=$(pwd) cd $(dirname "$0") script_path=$(pwd) cd "${result_path}" mkdir "tmp/" # create new psk secrets gen_psk () { tr -c -d 'A-Za-z0-9' > "maketestcert.log" | head -c 50 > tmp/psk.txt if [ -s tmp/psk.txt ] then printf "test$1:" > tmp/psk$1.txt cat tmp/psk.txt >> tmp/psk$1.txt 2>> "maketestcert.log" printf "\n" >> tmp/psk$1.txt fi rm -f tmp/psk.txt } export LC_ALL=C gen_psk 1 cat tmp/psk1.txt > tmp/secrets.txt 2>> "maketestcert.log" gen_psk 2 cat tmp/psk2.txt >> tmp/secrets.txt 2>> "maketestcert.log" gen_psk 2 # OpenSSL settings TEMP_LD_LIBRARY_PATH=$LD_LIBRARY_PATH LD_LIBRARY_PATH="" OPENSSL=openssl CONF="${script_path}/openssltest.cnf" mkdir "demoCA/" touch "demoCA/index.txt" touch "demoCA/index.txt.attr" echo 1000 > "demoCA/serial" # generate a self-signed certificate $OPENSSL req -config $CONF -new -x509 -days $ddays -keyout tmp/stunnel.pem -out tmp/stunnel.pem \ -subj "/C=PL/ST=Mazovia Province/L=Warsaw/O=Stunnel Developers/OU=Provisional CA/CN=localhost/emailAddress=stunnel@example.com" \ 1>&2 2>> "maketestcert.log" # generate root CA certificate $OPENSSL genrsa -out demoCA/CA.key 1>&2 2>> "maketestcert.log" $OPENSSL req -config $CONF -new -x509 -days $ddays -key demoCA/CA.key -out tmp/CACert.pem \ -subj "/C=PL/O=Stunnel Developers/OU=Root CA/CN=CA/emailAddress=CA@example.com" \ 1>&2 2>> "maketestcert.log" # generate a certificate to revoke $OPENSSL genrsa -out demoCA/revoked.key 1>&2 2>> "maketestcert.log" $OPENSSL req -config $CONF -new -key demoCA/revoked.key -out demoCA/revoked.csr \ -subj "/C=PL/O=Stunnel Developers/OU=revoked/CN=revoked/emailAddress=revoked@example.com" \ 1>&2 2>> "maketestcert.log" $OPENSSL ca -config $CONF -batch -days $ddays -in demoCA/revoked.csr -out demoCA/revoked.cer 1>&2 2>> "maketestcert.log" $OPENSSL x509 -in demoCA/revoked.cer -out tmp/revoked_cert.pem 1>&2 2>> "maketestcert.log" cat demoCA/revoked.key >> tmp/revoked_cert.pem 2>> "maketestcert.log" # revoke above certificate and generate CRL file $OPENSSL ca -config $CONF -revoke demoCA/1000.pem 1>&2 2>> "maketestcert.log" $OPENSSL ca -config $CONF -gencrl -crldays $ddays -out tmp/CACertCRL.pem 1>&2 2>> "maketestcert.log" # generate a client certificate $OPENSSL genrsa -out demoCA/client.key 1>&2 2>> "maketestcert.log" $OPENSSL req -config $CONF -new -key demoCA/client.key -out demoCA/client.csr \ -subj "/C=PL/O=Stunnel Developers/OU=client/CN=client/emailAddress=client@example.com" \ 1>&2 2>> "maketestcert.log" $OPENSSL ca -config $CONF -batch -days $ddays -in demoCA/client.csr -out demoCA/client.cer 1>&2 2>> "maketestcert.log" $OPENSSL x509 -in demoCA/client.cer -out tmp/client_cert.pem 1>&2 2>> "maketestcert.log" cat tmp/client_cert.pem > tmp/PeerCerts.pem 2>> "maketestcert.log" cat demoCA/client.key >> tmp/client_cert.pem 2>> "maketestcert.log" # generate a server certificate $OPENSSL genrsa -out demoCA/server.key 1>&2 2>> "maketestcert.log" $OPENSSL req -config $CONF -new -key demoCA/server.key -out demoCA/server.csr \ -subj "/C=PL/O=Stunnel Developers/OU=server/CN=server/emailAddress=server@example.com" \ 1>&2 2>> "maketestcert.log" $OPENSSL ca -config $CONF -batch -days $ddays -in demoCA/server.csr -out demoCA/server.cer 1>&2 2>> "maketestcert.log" $OPENSSL x509 -in demoCA/server.cer -out tmp/server_cert.pem 1>&2 2>> "maketestcert.log" cat tmp/server_cert.pem >> tmp/PeerCerts.pem 2>> "maketestcert.log" cat demoCA/server.key >> tmp/server_cert.pem 2>> "maketestcert.log" # create a PKCS#12 file with a server certificate $OPENSSL pkcs12 -export -in tmp/server_cert.pem -out tmp/server_cert.p12 -passout pass: 1>&2 2>> "maketestcert.log" # copy new files if [ -s tmp/stunnel.pem ] && [ -s tmp/CACert.pem ] && [ -s tmp/CACertCRL.pem ] && \ [ -s tmp/revoked_cert.pem ] && [ -s tmp/client_cert.pem ] && [ -s tmp/server_cert.pem ] && \ [ -s tmp/PeerCerts.pem ] && [ -s tmp/server_cert.p12 ] && \ [ -s tmp/psk1.txt ] && [ -s tmp/psk2.txt ] && [ -s tmp/secrets.txt ] then cp tmp/* ./ printf "%s\n" "keys & certificates successfully generated" printf "%s\n" "./maketestcert.sh finished" rm -f "maketestcert.log" else printf "%s\n" "./maketestcert.sh failed" printf "%s\n" "error logs ${result_path}/maketestcert.log" fi # remove the working directory rm -rf "demoCA/" rm -rf "tmp/" # restore settings LD_LIBRARY_PATH=$TEMP_LD_LIBRARY_PATH stunnel-5.56/tests/certs/Makefile.am0000664000175000017500000000064213467064764014425 00000000000000## Process this file with automake to produce Makefile.in # by Michal Trojnara 1998-2019 EXTRA_DIST = maketestcert.sh openssltest.cnf EXTRA_DIST += CACertCRL.pem CACert.pem EXTRA_DIST += server_cert.pem server_cert.p12 client_cert.pem EXTRA_DIST += revoked_cert.pem stunnel.pem PeerCerts.pem EXTRA_DIST += psk1.txt psk2.txt secrets.txt check-local: $(srcdir)/maketestcert.sh dist-local: $(srcdir)/maketestcert.sh stunnel-5.56/tests/certs/psk1.txt0000664000175000017500000000007113562354606013775 00000000000000test1:kvix8aMfwWEdGjJslhocucTcvGCr2qWT3E1PfwpGFIe0qOmhyi stunnel-5.56/tests/certs/psk2.txt0000664000175000017500000000007113562354606013776 00000000000000test2:wionOV9B956yI9rFjlyq46IWps8cBqTYTmz7sW1rROGhNkWgyF stunnel-5.56/tests/certs/client_cert.pem0000664000175000017500000000566513562354606015372 00000000000000-----BEGIN CERTIFICATE----- MIIDoDCCAoigAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwaDELMAkGA1UEBhMCUEwx GzAZBgNVBAoMElN0dW5uZWwgRGV2ZWxvcGVyczEQMA4GA1UECwwHUm9vdCBDQTEL MAkGA1UEAwwCQ0ExHTAbBgkqhkiG9w0BCQEWDkNBQGV4YW1wbGUuY29tMB4XDTE5 MTExMTIxNTgzMFoXDTIzMTExMTIxNTgzMFowbzELMAkGA1UEBhMCUEwxGzAZBgNV BAoMElN0dW5uZWwgRGV2ZWxvcGVyczEPMA0GA1UECwwGY2xpZW50MQ8wDQYDVQQD DAZjbGllbnQxITAfBgkqhkiG9w0BCQEWEmNsaWVudEBleGFtcGxlLmNvbTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALq/uXUhshKi4zWQw4ElNpMTvdjl +1hnq8xuVFmb/s5hMpZNKLm0st3tLtbiAt9RBC7yaNqRLN49AZsJpgcuagAc9U7k oUukal7XtnCSu62cZmhylSgZEoqeZUfIsbpbipQzIokPUfTjpW2LvCSrjAYFj2Zf yyadFe9deWFVzZs1OYyutMQnwzdWvsi27Syndm95y98ib8NddyP4GFjlJVdZTnoe fqTzvyKJYuEehh6gzuRoPAEn9zQCuUjznEa0P+gB8meFLo4ehGtmWnAByugngu0T w/huoVDnxVzQu2S8d/48bn4OTLX/BS4NoPc3faRW394Khi1jMhy/Y7iquu0CAwEA AaNNMEswCQYDVR0TBAIwADAdBgNVHQ4EFgQUXYHIEJEULLRMG3qTJJBls4L4Hd8w HwYDVR0jBBgwFoAUv5gO8NHd5OOOIZeU30Qpl87BUrswDQYJKoZIhvcNAQELBQAD ggEBABveCRNHqDZupucbNX0vgvGI3R0qBFUm3VWdTwn1OG+m8CDbcHdp1NQqY7zQ 4+dXZctbl2wnWVW+ENJ8nBhJklN4HZxHgDwSlYzHwNrHcUYoZKGh83tG6+G6dVQF /4Yky5/4fOkt69pz7Z+0leZUcphJynvt4DW3nXL+FBSnlkbZDyvxQ+Zbr2jBeJ3r Qib+4LIBngXSRwD/utcPC1HzzVPQ0gQcybd2Z+2ReZO4DR2AvYo0IiAEwT+vHXkZ vzmO4YK55u9o3QZnSgA+pqOQkZJuPKpapITvkVNtM8DDqVr1tFB5h4NTff5byyGK 5KKKrVdvkXMZun1Jr3CoI32aXp4= -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEAur+5dSGyEqLjNZDDgSU2kxO92OX7WGerzG5UWZv+zmEylk0o ubSy3e0u1uIC31EELvJo2pEs3j0BmwmmBy5qABz1TuShS6RqXte2cJK7rZxmaHKV KBkSip5lR8ixuluKlDMiiQ9R9OOlbYu8JKuMBgWPZl/LJp0V7115YVXNmzU5jK60 xCfDN1a+yLbtLKd2b3nL3yJvw113I/gYWOUlV1lOeh5+pPO/Ioli4R6GHqDO5Gg8 ASf3NAK5SPOcRrQ/6AHyZ4Uujh6Ea2ZacAHK6CeC7RPD+G6hUOfFXNC7ZLx3/jxu fg5Mtf8FLg2g9zd9pFbf3gqGLWMyHL9juKq67QIDAQABAoIBAQC3Tcl0N4ba1BfB VD8SXLyc0Rvf8p4rwFbZatJQwtXxLWbCMSpwXfXT8COxuFapbJR2oGpbX3RzD96r l2ToV56kTchbj/7iiJgAUCw7g0vEtWevzgiqOzH/7knrlAsfqQr1PNwBPJBtl6Wh SS97rwbaQkrnac+2LyqAsXebGuWeGYmeq/hS7osamqr13mqWzVhHlLiuJTsSfgHg UaixgQlq5MDRR9Era+lCvDNcPtvSLLxIZLLjeToAJz+0wRNNT2OMBdftv1bfRwnm hMlIfJmM5e7NAQeXWywtK6bImLyNLJxtAEKfSK31GlmR4HADO0xKKrGBRWS6jjxh uWaf+ijhAoGBAO1Iz4zcyHJi3ElyN+sHmRN/ucr86oQGoXoabssurWhPmG0a/Knv JI431iYQO+KhkYuSVU0UOzZojHe1/iYbNJVhKooQUGVeSIrZclGfHnKqpXHVM9Ks msNsMkdwIEZugVUsRtOrj3sAjUpqNMmJQ6fTo3YyG8xOA6D/x0aKNrF7AoGBAMl6 g2f2wQfjIdWUGE0JOycYcw2C8GkUeOwzxQ4dii8mUvb/JD2hqxHJJ3s/CCyKv0uD m7D4ZsszLm7MW4fAEgxpUrpOY+r4o5q0wZLnNtARcqzDggFvmejgMFWiUgIiesV/ /iN3v0y8MUPmu3LXoznrm2SoTrjanimMT7pCSNS3AoGBAOCFkL48+v4hRUfJ59dg bRviM686+bzLeWfMMyHWnQaiqhwy+Pji67gWZW/G1KNxNgLXCBfTGOQ2sRNlBYKR I4RlWJcjMK96MzIO5vkMkwb1KW84ybyCzj4z1q96DVAXqBErwCjxoOZGc2sCa8h3 NalLvNROPbdn6k8hNzIr/eyZAoGBAMhy3R2n/3ALZ3QH/Q1Xq8Q/rOe6Z9kDhzLo ZpqehQZXyJ74RGQU3g+540/Y7Bb0i1FjxJgS6qIrb3zIUCAE1XAHsUiuCPaTHKIk R5oR8xSa504+zK8FC0kHEs9/yLta9m5b4soCrw53BUSa389n/nr3jwhb8sYyqryH XiLfI3qNAoGAbV1RPIOob8n08gT5scu6DerTvCSe9P6qZWRyYjElSV/CVnBFBG6e 64PDOJ6y1/R4999zGRji8eMWdz7mUmMOFzkHvm/us5j4ZpuZwxZDRte9f4vV+yDP Iz2oFCMK9HJVMMecIaE9sqkKfGSVvqGV3t7ikihmgJBzeJi2YVL7/5Y= -----END RSA PRIVATE KEY----- stunnel-5.56/tests/certs/CACert.pem0000664000175000017500000000252313562354606014166 00000000000000-----BEGIN CERTIFICATE----- MIIDwTCCAqmgAwIBAgIUXE+sARWPLGgknSpOyFlDQSWC7DswDQYJKoZIhvcNAQEL BQAwaDELMAkGA1UEBhMCUEwxGzAZBgNVBAoMElN0dW5uZWwgRGV2ZWxvcGVyczEQ MA4GA1UECwwHUm9vdCBDQTELMAkGA1UEAwwCQ0ExHTAbBgkqhkiG9w0BCQEWDkNB QGV4YW1wbGUuY29tMB4XDTE5MTExMTIxNTgzMFoXDTIzMTExMTIxNTgzMFowaDEL MAkGA1UEBhMCUEwxGzAZBgNVBAoMElN0dW5uZWwgRGV2ZWxvcGVyczEQMA4GA1UE CwwHUm9vdCBDQTELMAkGA1UEAwwCQ0ExHTAbBgkqhkiG9w0BCQEWDkNBQGV4YW1w bGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAubPhK1yk1SJ5 EIJ1p2z/ujOh6BFOYeuKadoK8rUc8Yt8/tE7ah7qvHqD19szQ0fb84ZTIkhQNipp 4BhS5Cg358C6f3tWteLiM9zq9HaTePPuK+LzhJmLJb00Go4eHnm9SujBacO7SbqM odySB1p7EL5HVd1YT64nIgFpYcyhYcTqhVE0e4+5Ud+irLk/rsiqmDtlrUABNc/E krSozoZskk0YWR1RWh7qr23AKGr2sKqxdlrkjJqgPBx2VCEW9MTZrEX6jLn1SNF3 PuvUglPXADjjy/luFoDlKPuRpBXLsYVTx5j2Oi5hFsPPDJmqso2eFT39tJsqjGGh 25TZJiEdtQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS/mA7w 0d3k444hl5TfRCmXzsFSuzAfBgNVHSMEGDAWgBS/mA7w0d3k444hl5TfRCmXzsFS uzAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggEBADcEh1sUlM6AfrLC ITX/hrGPRPbHkLjImXNdvf5TW3gsx5meGqp74mgbT9foq4VLhcEdDzXvcRcSkpJ7 Cfs5ZJkKNzkZgO2sJ3JPBMw143iMs05iyyQXXybjP9LJBpKD0TQ6Dl2HYiiP0pU8 c/lDUETXL14tp42kgQ6knHByQQi9E2EhKJnXPhkC9gUe1wcaVaP3WIoKxXfrHfwT AsoeYVw+2CYdjyHj3XGBvZObqXKWU8zUkNbiqsntVxUg9bdQ9VFKKHw4o+yXyH6z aStIXWdpMiUNTHnGk315X3E3Pea/XpiL9UW/1AbX80+yKog/hqJlt33QKTyIGaA4 ZdW+QoQ= -----END CERTIFICATE----- stunnel-5.56/tests/certs/stunnel.pem0000644000175000017500000000625113562354606014555 00000000000000-----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCqok2NvyMMKWnL buYxcXic/T2j1OPDbeDzSy77t0hMGjbforHpHmnAHxdYPGTkgbbiaLRZJfNEBDD2 1H3c/YLC1cfwSc9tw1whbmmyxq1iPuNH1kE/o1kXNRVZta+oSzFGGzigD5c7Zp/F xytmtu+R7pMpQv1IPOx2SFzqzm3bTRBjyciG+EFX8ceyRbmNuwyGfaWD+awbxp+I gfChtD5Z6Kw/n6coaG4/VyxMni7GRB/MIyYmYqb/cfSQsGCq8EfvrAmUllqZ64Sl k63z5VyPv3uestIHKWWwPitqCioCzeOt1VAyA5UeL22QocC2YfuSnJTjQZk2ESjq FI41L155AgMBAAECggEASta0vR6/+G2RgTA6tiTWicRobJrK6sQejZbEHJLemsJE nwF0lpJIP4NjccfLWI2r8NGLiC4k7AgKkbfRHEP0PhAViUZWPAYbOm563XZWRWjf tno6U/cI9CzMGHSffmi8S8tUop8z7VGtcclRN9O0b4T79nTzMePGsno6hqHTfQMw dHAucZY43puCOQm0Lkm0Mzf+XUC1SzjfhYni2HrsfKWmzLZPSZufzl6toQVjhzNI EYl+4TpZFuScwB4Ox5bojsA9uLtluLEYGZ7Eu7J+ol4hIzyBDiZvosmkoEkbFjFt 2EvGAlzQhlcqUJECo69lfW5J9ZqASIKJqyH4q+NkIQKBgQDVcc9gniVhUQNIH1WE FBTo8IqhUUIZ9fPj5ALxvtaXjZAjldySNiZDST3oQNXf9KhEhEJVDqb/CLN7U/Q8 7/A/WfMg29ud34gRJ1JbUxhUva1Gw4kbdvg2CEs/3DnepPHDFBBLAmsH7RWMTA3h hWEVjD9gFUweVu/Zs+dy2h44uwKBgQDMp3ICJjMKTm1i9l4r/8J5ZdGD1K0A1a8D MPzj7sjNa1sjrmtEQb9FBVwP9xfabV8EEFxcJdRb7e3282TeWrDx8sRpY8o2UJfi QyDGvjvfzmUcHszD7z5jFl/dtt+nf6nKBFg8tLyBw4WahPUrmbjtCRvyb7ol2A0g WaBInkpcWwKBgDHtd1bgZ1oGO0BJpBVLJUD/00281juAXtZ15YJq44N757WLPpcs 93JR1ZtYXy8N6bZtQZ7n2IRborA8iSsf7RDEl6yeARdCzG9GxWr7Wvunirq8znuQ Lqtk8UU03IyKBMtfDBifri2idaHlwHF6Y6VIsyJkmPOX3m8MOB2Ti/I1AoGAXiM/ 3CE6JSmCQ51UICUbjb/6KgvwMIwaXvtvuGEkWOljGPyoNtOPae5XNLjSbhUVOcdU 1MZJ8qd1aLz4zxckgYbMNjZC080qsFd0gjcLT52fANpiElbAec/W9SOjqWad8WEi PXpdo8sOb89s/0tMtywTgOdH1xSUpSbVBdJaHjUCgYEAoUnR5XvNINIoG7oLDfFy MP4w6t0dFjbjVZ5gu4EY0Bsz03lhil50POubS4QLzw3HXLnHMCZvgDeSVLdQvIxD PexyOMWW9hgr0aP2U+NBu6uTGMizoKtGQcep7zypidKUrWYUmnuZ71t8ZldyisN2 b83EIZ4I3GVpI8ZulB/pmOM= -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- MIIEQTCCAymgAwIBAgIUB137S+cNuXYLmn5OBQ45oaesB18wDQYJKoZIhvcNAQEL BQAwgacxCzAJBgNVBAYTAlBMMRkwFwYDVQQIDBBNYXpvdmlhIFByb3ZpbmNlMQ8w DQYDVQQHDAZXYXJzYXcxGzAZBgNVBAoMElN0dW5uZWwgRGV2ZWxvcGVyczEXMBUG A1UECwwOUHJvdmlzaW9uYWwgQ0ExEjAQBgNVBAMMCWxvY2FsaG9zdDEiMCAGCSqG SIb3DQEJARYTc3R1bm5lbEBleGFtcGxlLmNvbTAeFw0xOTExMTEyMTU4MzBaFw0y MzExMTEyMTU4MzBaMIGnMQswCQYDVQQGEwJQTDEZMBcGA1UECAwQTWF6b3ZpYSBQ cm92aW5jZTEPMA0GA1UEBwwGV2Fyc2F3MRswGQYDVQQKDBJTdHVubmVsIERldmVs b3BlcnMxFzAVBgNVBAsMDlByb3Zpc2lvbmFsIENBMRIwEAYDVQQDDAlsb2NhbGhv c3QxIjAgBgkqhkiG9w0BCQEWE3N0dW5uZWxAZXhhbXBsZS5jb20wggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqok2NvyMMKWnLbuYxcXic/T2j1OPDbeDz Sy77t0hMGjbforHpHmnAHxdYPGTkgbbiaLRZJfNEBDD21H3c/YLC1cfwSc9tw1wh bmmyxq1iPuNH1kE/o1kXNRVZta+oSzFGGzigD5c7Zp/Fxytmtu+R7pMpQv1IPOx2 SFzqzm3bTRBjyciG+EFX8ceyRbmNuwyGfaWD+awbxp+IgfChtD5Z6Kw/n6coaG4/ VyxMni7GRB/MIyYmYqb/cfSQsGCq8EfvrAmUllqZ64Slk63z5VyPv3uestIHKWWw PitqCioCzeOt1VAyA5UeL22QocC2YfuSnJTjQZk2ESjqFI41L155AgMBAAGjYzBh MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOU5G8ScXk8i4W2ZgsMJoeB3C2Kk MB8GA1UdIwQYMBaAFOU5G8ScXk8i4W2ZgsMJoeB3C2KkMA4GA1UdDwEB/wQEAwIB hjANBgkqhkiG9w0BAQsFAAOCAQEAXd74EV07hNV4KQOl6km5J5l24koTYUK9JS8S 1MEjbhmmFqepSjwZRlXODsYGMT+qZOi7obOTW1Qn/8Y6OV0D3liSSYqRvgq10meG 7dWbSVGjbuJpY3v6aJPzpd5AhiYZPRpmlwqg8kolz50je5IxjQZT3QKCLs5XTBgy 6OMyH9uaAGFM6TNLXXVA5LNcske9zzRfzkkkVmjL2XUFAVveZbeqA+k2zxR0WYMo 6gQM7QE2GNbeyHRlPC4XM6mMO0tCsTfgw2hCZP98MD0Og4ejhClnSN1YdWRApQqY f7diPDDG6IyXH92iwMc4Idr6U/LiBUPMps62u8Knl9MBGABCDg== -----END CERTIFICATE----- stunnel-5.56/tests/certs/revoked_cert.pem0000664000175000017500000000567113562354606015550 00000000000000-----BEGIN CERTIFICATE----- MIIDozCCAougAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwaDELMAkGA1UEBhMCUEwx GzAZBgNVBAoMElN0dW5uZWwgRGV2ZWxvcGVyczEQMA4GA1UECwwHUm9vdCBDQTEL MAkGA1UEAwwCQ0ExHTAbBgkqhkiG9w0BCQEWDkNBQGV4YW1wbGUuY29tMB4XDTE5 MTExMTIxNTgzMFoXDTIzMTExMTIxNTgzMFowcjELMAkGA1UEBhMCUEwxGzAZBgNV BAoMElN0dW5uZWwgRGV2ZWxvcGVyczEQMA4GA1UECwwHcmV2b2tlZDEQMA4GA1UE AwwHcmV2b2tlZDEiMCAGCSqGSIb3DQEJARYTcmV2b2tlZEBleGFtcGxlLmNvbTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAObg8POTFshvLhXt/BhxBI8G +yb/OeaohYdmtDtBfV4eXAubH6uewRIh4+4l3NHL5DG41hOSNueOf5WnSKVD1sYY XoKlqukH7o1Z2x2x6IpHXGGnmVnIgMNJfBo3wuzBugeeepytYcQqYdmDugN6TB8f hZUc90E1ZdER6jyJ+F31UmB1FWKpBILbsc8HZVmfEUMV0lFXRH+h7S/ncYY7WTQf GglBlBzkOLfENTJRBKX7RRsh8ySf9LwjuxE58wOUwqFCzcgtyicLPg3JVNqbBqvW +9iYDWcd3K1bD3az0quadfWDwRnMDGfMfU3Evp3nDSVB86Bru5cVPvf8UglbWiEC AwEAAaNNMEswCQYDVR0TBAIwADAdBgNVHQ4EFgQUpAGy+3Vst01bjzeHY6vOJaAI K60wHwYDVR0jBBgwFoAUv5gO8NHd5OOOIZeU30Qpl87BUrswDQYJKoZIhvcNAQEL BQADggEBAELfKTDvo8X1AJrsZlkGS1QkdEbebVqMpvNO5AUnfH+DiUPUM8ejmSyL WnWl+/F8TJu0o2ph+Jf1zMAyXXxm3gGWE7L64BSOtrnKz8Npvlg2CyJKp8LRQ69i 2XsHqbbzpmiwnn7y7FTHhOpVOWsg/lZfCrP82RD3HRz7Hpx1M+wyKMsFnoIphIz1 99Hj2H6cyHdw01xMjLz6eiKzBAV1N2IPzCaX/lNkWjlJjo+CNoT2nPYsOoBrUdGO emu9o7jRLNqZK34roZW+ZbZGCL3lYuM1MYCkIDq8J6wyyquNNOShmk5pQBoaNtSb kSMBXIHQEJHJOoxXzScOGMJH69hfhVc= -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA5uDw85MWyG8uFe38GHEEjwb7Jv855qiFh2a0O0F9Xh5cC5sf q57BEiHj7iXc0cvkMbjWE5I2545/ladIpUPWxhhegqWq6QfujVnbHbHoikdcYaeZ WciAw0l8GjfC7MG6B556nK1hxCph2YO6A3pMHx+FlRz3QTVl0RHqPIn4XfVSYHUV YqkEgtuxzwdlWZ8RQxXSUVdEf6HtL+dxhjtZNB8aCUGUHOQ4t8Q1MlEEpftFGyHz JJ/0vCO7ETnzA5TCoULNyC3KJws+DclU2psGq9b72JgNZx3crVsPdrPSq5p19YPB GcwMZ8x9TcS+necNJUHzoGu7lxU+9/xSCVtaIQIDAQABAoIBAQCFKw+v3pJQj9hM K9Wxn1aazNMGXkZeZauHOtUQLKkMJYS/6Pyud8YzGDso/MvOcsUvbMaFyVtD2mx6 vF9pe6Sg5CN3Rek7uih9fWumSByxzZFaflo0cDLc8UDUun8DIoaTqHRedJ8kj7Ga zaD4Ko1Hkl3xcSCoiw0sNyIdQxNv1Vz2JdTuzgNAj29fuQH9BJeIRBX3i9LSf8b4 z+A1fZdYecKaM/gYd8YU0klShwlTiz32poq0broU/ZD2+DkXea6kLgDo4TwRFYH/ gEhmq6sHkjBPOWOkrI31/VeUGF3yZUnktw04Xx81SU70v1ajfvwlgm4K3RMX3ARP vb4R3KIxAoGBAPP3FwePhmqvdd8mKHALJgeOHQm0MyFVr8/+iWHLGvUiAPvwjXWn u9Snb7D9HFVUBPNVvesS3UcFzYATgD5bLu4baRXXhH+8aXoz/QMVoJauy5VqmXiN nKHLP2F2VKM41fOGB4giEK0APH6tckrpmwaPRiG5ltAaRGxsf6p1UoxNAoGBAPJE lqEaxeM6GFrbQRq+YZodIerE4epNJqMJZ7LD2AXr9HlfuI2FQaXaTFWizLQtwqZp fm8xBL0rJ53wC0jUxzqMcTwYfrojGwy7+k3VxeuU2eG+autAE6uLLT5DHrumdYPu oQDc8DhHNSmtbKv2hOboj7CE3Nt4tETsjBqADt8lAoGAJowNDHnGAEdW9Xo++20X hiwTNHxPc93pGJEcPeJskPzdcPFSOJvXFsOZ5zom5uiOm7AZgPILGnS1Qp5SLggU QzT7hqL14YTwmYlrWbhqFkTqD+K2+xBNBldp3UloGB4b2A1+VSkkv2EBLfbTzzhX 8VJj/2ImjR0JYKRIC7Pb5iUCgYBW21BFohugQ4vHxyOoOukzH46xZLS6E77uZMjQ xnYEaXvUqAS6eDP5CjKj4SIS1vUaRGgX5TMVvwsNDKp/CgoDa6aNLRsCEOP5xMsQ bLvwogUbcfFTNj3XGqa108qI7DzleAAxFwToqF7e+lYjsNYlEuuxFXE5HiVDMKtq NM8gIQKBgQCuXTirYre6mCuzdGGSHBmRkIUm/cOkQzF05N/iD+s6mtK3fRa3PgkY coLEgzTZBT+54u/7HfmS3OB6iWx+5Wrb2j1bSaD8zp70K9W1FE4ocPpT4pmJdK2r HCS59Ng2AqV5FvClfHHJ1SJHnnnQcjL7GYGvuV8FBR7M6Orky3pPcw== -----END RSA PRIVATE KEY----- stunnel-5.56/tests/certs/openssltest.cnf0000664000175000017500000000414513405402654015430 00000000000000# OpenSSL root CA configuration file [ ca ] default_ca = CA_default [ CA_default ] # Directory and file locations. dir = . certs = $dir/demoCA crl_dir = $dir/demoCA new_certs_dir = $dir/demoCA database = $dir/demoCA/index.txt serial = $dir/demoCA/serial crl_extensions = crl_ext default_md = sha256 preserve = no policy = policy_match x509_extensions = usr_cert private_key = $dir/demoCA/CA.key certificate = $dir/tmp/CACert.pem [ req ] encrypt_key = no default_bits = 2048 default_md = sha256 string_mask = utf8only x509_extensions = ca_extensions distinguished_name = req_distinguished_name [ crl_ext ] authorityKeyIdentifier = keyid:always [ usr_cert ] basicConstraints = CA:FALSE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid, issuer [ ca_extensions ] basicConstraints = critical, CA:true subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer keyUsage = critical, digitalSignature, cRLSign, keyCertSign [ policy_match ] countryName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional [ req_distinguished_name ] countryName = Country Name (2 letter code) stateOrProvinceName = State or Province Name localityName = Locality Name 0.organizationName = Organization Name organizationalUnitName = Organizational Unit Name commonName = Common Name emailAddress = Email Address stunnel-5.56/tests/certs/PeerCerts.pem0000664000175000017500000000511413562354606014760 00000000000000-----BEGIN CERTIFICATE----- MIIDoDCCAoigAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwaDELMAkGA1UEBhMCUEwx GzAZBgNVBAoMElN0dW5uZWwgRGV2ZWxvcGVyczEQMA4GA1UECwwHUm9vdCBDQTEL MAkGA1UEAwwCQ0ExHTAbBgkqhkiG9w0BCQEWDkNBQGV4YW1wbGUuY29tMB4XDTE5 MTExMTIxNTgzMFoXDTIzMTExMTIxNTgzMFowbzELMAkGA1UEBhMCUEwxGzAZBgNV BAoMElN0dW5uZWwgRGV2ZWxvcGVyczEPMA0GA1UECwwGY2xpZW50MQ8wDQYDVQQD DAZjbGllbnQxITAfBgkqhkiG9w0BCQEWEmNsaWVudEBleGFtcGxlLmNvbTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALq/uXUhshKi4zWQw4ElNpMTvdjl +1hnq8xuVFmb/s5hMpZNKLm0st3tLtbiAt9RBC7yaNqRLN49AZsJpgcuagAc9U7k oUukal7XtnCSu62cZmhylSgZEoqeZUfIsbpbipQzIokPUfTjpW2LvCSrjAYFj2Zf yyadFe9deWFVzZs1OYyutMQnwzdWvsi27Syndm95y98ib8NddyP4GFjlJVdZTnoe fqTzvyKJYuEehh6gzuRoPAEn9zQCuUjznEa0P+gB8meFLo4ehGtmWnAByugngu0T w/huoVDnxVzQu2S8d/48bn4OTLX/BS4NoPc3faRW394Khi1jMhy/Y7iquu0CAwEA AaNNMEswCQYDVR0TBAIwADAdBgNVHQ4EFgQUXYHIEJEULLRMG3qTJJBls4L4Hd8w HwYDVR0jBBgwFoAUv5gO8NHd5OOOIZeU30Qpl87BUrswDQYJKoZIhvcNAQELBQAD ggEBABveCRNHqDZupucbNX0vgvGI3R0qBFUm3VWdTwn1OG+m8CDbcHdp1NQqY7zQ 4+dXZctbl2wnWVW+ENJ8nBhJklN4HZxHgDwSlYzHwNrHcUYoZKGh83tG6+G6dVQF /4Yky5/4fOkt69pz7Z+0leZUcphJynvt4DW3nXL+FBSnlkbZDyvxQ+Zbr2jBeJ3r Qib+4LIBngXSRwD/utcPC1HzzVPQ0gQcybd2Z+2ReZO4DR2AvYo0IiAEwT+vHXkZ vzmO4YK55u9o3QZnSgA+pqOQkZJuPKpapITvkVNtM8DDqVr1tFB5h4NTff5byyGK 5KKKrVdvkXMZun1Jr3CoI32aXp4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDoDCCAoigAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwaDELMAkGA1UEBhMCUEwx GzAZBgNVBAoMElN0dW5uZWwgRGV2ZWxvcGVyczEQMA4GA1UECwwHUm9vdCBDQTEL MAkGA1UEAwwCQ0ExHTAbBgkqhkiG9w0BCQEWDkNBQGV4YW1wbGUuY29tMB4XDTE5 MTExMTIxNTgzMFoXDTIzMTExMTIxNTgzMFowbzELMAkGA1UEBhMCUEwxGzAZBgNV BAoMElN0dW5uZWwgRGV2ZWxvcGVyczEPMA0GA1UECwwGc2VydmVyMQ8wDQYDVQQD DAZzZXJ2ZXIxITAfBgkqhkiG9w0BCQEWEnNlcnZlckBleGFtcGxlLmNvbTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKZxU5tDdyU9rl2OA+u3SKXWyLmy vW+f+FEmzdQwRK+AjbZrj7hNcmmtKUDhiPobT/Y1NpwqXRn37mtZEstXi/Kv5P7m TKWIlwRn21/o2xVFAmKg1zwlAmzBTipsoSawSV+yYLG0LgKId3jCMvYVmekH1qpN XgQyAt2Z4DpE3JGKnGtLUIyokkB2DfE6uCvRL+ySrzzOAoiK1yELUtF4SanBkqwt GKyc8JHFXZ3ZIVZnYSnTGe8OhEkaOqMVmGtPzLnxt/1bj0cEYSlCXbz6UAZfLUqx muDxSBqgG2CqQyh+3YYgTrQ4RIT7r0vEzop/f+4xE6kJsiVNd5dKHTxISYsCAwEA AaNNMEswCQYDVR0TBAIwADAdBgNVHQ4EFgQUuBZiJEaBGeaketO4ZCodNbC8OrUw HwYDVR0jBBgwFoAUv5gO8NHd5OOOIZeU30Qpl87BUrswDQYJKoZIhvcNAQELBQAD ggEBAJ+0LcsCFTzVCo2VvbiGyYxJ9JPkYXMjCd9I+5zrzBx3RYH7V/cZrbx0DVOA AsDJPz4GF0hoSWpCwMvtWfa5R4sGvQcfnc55ogsBZLkpQf1VVrPCQEjnWcrD5P9j Ej3XImPSQrxWb4jvn7fQb0uqJTX/vpHNg2I7FCkbqxcrC99GnKn0fAm18HTT4iiF y9LLFO7Oip8czCr3vozQZugZl10LW2M3GtOTyuCUJx1m6XQzW4U+jdtmJC6qmOiA POo5bPcb7y97IbM6FxPpyKWzmn19iAXM3j/SSo+GlSypXAGN+L7mu2M8m5SITmRd SjDkNyEZRi8WLaQB3SKzaC6iheo= -----END CERTIFICATE----- stunnel-5.56/tests/certs/CACertCRL.pem0000664000175000017500000000132313562354606014524 00000000000000-----BEGIN X509 CRL----- MIIB7TCB1gIBATANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJQTDEbMBkGA1UE CgwSU3R1bm5lbCBEZXZlbG9wZXJzMRAwDgYDVQQLDAdSb290IENBMQswCQYDVQQD DAJDQTEdMBsGCSqGSIb3DQEJARYOQ0FAZXhhbXBsZS5jb20XDTE5MTExMTIxNTgz MFoXDTIzMTExMTIxNTgzMFowFTATAgIQABcNMTkxMTExMjE1ODMwWqAjMCEwHwYD VR0jBBgwFoAUv5gO8NHd5OOOIZeU30Qpl87BUrswDQYJKoZIhvcNAQELBQADggEB AER7D1Mf6+ASMOULNKQ8MB0lqjWAf8XN67Ez/spAbF5B7ySaFPJOuT+90oTpccrW 08KPZVrUkAsWSBty06jsZe8IB8YLdpkdDD59dwqIQ5CILbvx16l0nqrXqOQ3kRfT pfzikaOSrt7PWuHRRGnLiK88r+s1S5JqYtHAnhO4xyQzDmpyID/i5vS/3rfHCmEM drk4vkkUq0wRFRiq0fXECF8bgIr366oCmm09rKy4jgyDxSo81yJCRlkNFOY6zxjS RH7ckNLxJb77vaJGkNnaIefgQB+OML/UphzW/IcnKV03nGT6OEPUpVHeMAA365tV z5HRB+7G/oLzauOgrVVkjvE= -----END X509 CRL----- stunnel-5.56/tests/certs/server_cert.p120000644000175000017500000000474513562354606015237 000000000000000 0  *H   0 0G *H 8040- *H 0 *H  0ODeuSS0^c)⌾1Xw?B^)/2Q+_Y032;L8NM|Dd가]( )I .{]|4,V4hb1.a?^= (GR41g 804dD(zsKD4˾!*5s%$e]p4u$(rP{PB="q?e>2`oOtĤq+ U{ox\$xjVDƐW)uRh5Yp;=IǿnpcQ[N3TI5<Ѿ.$ۛs!jV;x UWvse0:\o8OFoX E.۾ l%39ST֣#Knƽg( s7Aщs؂gTb讙_pr*WFX~5q3Im 6& yOKKvZ/, o6(~D _x^_WHC&"O:7_eQtX6R{yU>P$r;L\lUncO;xAf'^ou5ãנ;{]eE~^t*=(C,~w3y5uo]"fEtyP[.7 y4a›u~LYۑ:Zo _=˟5icRe$EviKņOL -8J4y9yu0L0 seAS[ .! cU:ϫ k+"OerxC]\r Q(ܯ'RfXz.ظ@eڵ.Qu2Ԭ,*]`*mTH7: ͥp0fG-\ bҍ"A1>@0& [p4pX]R[b+ՙRvm f3Fٌ̹wmuS&WM{TʡcVRބvIL=VGA?J8JGIǖ7njx6z֯, j-{[3k/˸ͥ ZC*DY尅eU^`cJ[ǸG% M*|Bs3s3Qp-DKai5@~':9r|"P|GWПu5tсk:fhzx 'OSg._uNR!"m4"D~wU0Z@a-c%m"PF[76qa旯 Yb) yT8U*ë{b9VqZUsȊ[vZu4v}|sVv}tl mSI7 nH:#K澧\25NC5y󸞻%ڄ$ si1(7'X)Iv~SNufX> 3n` L#ñ .pZ7m`?}h^77i9=s֊G}$Ouvun@ 5@ 0d"~ăutP/*j MJiM F/l]l K𢥦_3+#s8ooE%d}ENLev!l`jdH^ɷG̜Ы*S bj wlgX2II1J/AZm~W٤okqo1ШFסzNQk^EXߋM;tMDg  x:̀3akωl|^GLu&ph.+#Eĕ ̰$&~7Vtv˜rmwJMdu)x,C ϖUy\U}ͼeL1%0# *H  1տZ%8Q!]tu010!0 + \g{@_`I }stunnel-5.56/tests/certs/secrets.txt0000664000175000017500000000016213562354606014570 00000000000000test1:kvix8aMfwWEdGjJslhocucTcvGCr2qWT3E1PfwpGFIe0qOmhyi test2:W42xCIe3Zbp65qEBpo3ER4EvWkHSErEn0Ps8w0ikmMHr5tHuvY stunnel-5.56/tests/certs/Makefile.in0000664000175000017500000003053013527763157014434 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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 1998-2019 VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } 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@ subdir = tests/certs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(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) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/src/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 = SOURCES = DIST_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) am__DIST_COMMON = $(srcdir)/Makefile.in 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@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ 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@ runstatedir = @runstatedir@ 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@ EXTRA_DIST = maketestcert.sh openssltest.cnf CACertCRL.pem CACert.pem \ server_cert.pem server_cert.p12 client_cert.pem \ revoked_cert.pem stunnel.pem PeerCerts.pem psk1.txt psk2.txt \ secrets.txt all: all-am .SUFFIXES: $(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) --foreign tests/certs/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign tests/certs/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__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ 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): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(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 check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-local check: check-am all-am: Makefile installdirs: 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: 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-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic 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-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 -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: check-am install-am install-strip .PHONY: all all-am check check-am check-local clean clean-generic \ clean-libtool cscopelist-am ctags-am distclean \ distclean-generic distclean-libtool distdir dvi dvi-am html \ html-am info info-am install install-am 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-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am .PRECIOUS: Makefile check-local: $(srcdir)/maketestcert.sh dist-local: $(srcdir)/maketestcert.sh # 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.56/tests/certs/server_cert.pem0000664000175000017500000000566113562354606015416 00000000000000-----BEGIN CERTIFICATE----- MIIDoDCCAoigAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwaDELMAkGA1UEBhMCUEwx GzAZBgNVBAoMElN0dW5uZWwgRGV2ZWxvcGVyczEQMA4GA1UECwwHUm9vdCBDQTEL MAkGA1UEAwwCQ0ExHTAbBgkqhkiG9w0BCQEWDkNBQGV4YW1wbGUuY29tMB4XDTE5 MTExMTIxNTgzMFoXDTIzMTExMTIxNTgzMFowbzELMAkGA1UEBhMCUEwxGzAZBgNV BAoMElN0dW5uZWwgRGV2ZWxvcGVyczEPMA0GA1UECwwGc2VydmVyMQ8wDQYDVQQD DAZzZXJ2ZXIxITAfBgkqhkiG9w0BCQEWEnNlcnZlckBleGFtcGxlLmNvbTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKZxU5tDdyU9rl2OA+u3SKXWyLmy vW+f+FEmzdQwRK+AjbZrj7hNcmmtKUDhiPobT/Y1NpwqXRn37mtZEstXi/Kv5P7m TKWIlwRn21/o2xVFAmKg1zwlAmzBTipsoSawSV+yYLG0LgKId3jCMvYVmekH1qpN XgQyAt2Z4DpE3JGKnGtLUIyokkB2DfE6uCvRL+ySrzzOAoiK1yELUtF4SanBkqwt GKyc8JHFXZ3ZIVZnYSnTGe8OhEkaOqMVmGtPzLnxt/1bj0cEYSlCXbz6UAZfLUqx muDxSBqgG2CqQyh+3YYgTrQ4RIT7r0vEzop/f+4xE6kJsiVNd5dKHTxISYsCAwEA AaNNMEswCQYDVR0TBAIwADAdBgNVHQ4EFgQUuBZiJEaBGeaketO4ZCodNbC8OrUw HwYDVR0jBBgwFoAUv5gO8NHd5OOOIZeU30Qpl87BUrswDQYJKoZIhvcNAQELBQAD ggEBAJ+0LcsCFTzVCo2VvbiGyYxJ9JPkYXMjCd9I+5zrzBx3RYH7V/cZrbx0DVOA AsDJPz4GF0hoSWpCwMvtWfa5R4sGvQcfnc55ogsBZLkpQf1VVrPCQEjnWcrD5P9j Ej3XImPSQrxWb4jvn7fQb0uqJTX/vpHNg2I7FCkbqxcrC99GnKn0fAm18HTT4iiF y9LLFO7Oip8czCr3vozQZugZl10LW2M3GtOTyuCUJx1m6XQzW4U+jdtmJC6qmOiA POo5bPcb7y97IbM6FxPpyKWzmn19iAXM3j/SSo+GlSypXAGN+L7mu2M8m5SITmRd SjDkNyEZRi8WLaQB3SKzaC6iheo= -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEApnFTm0N3JT2uXY4D67dIpdbIubK9b5/4USbN1DBEr4CNtmuP uE1yaa0pQOGI+htP9jU2nCpdGffua1kSy1eL8q/k/uZMpYiXBGfbX+jbFUUCYqDX PCUCbMFOKmyhJrBJX7JgsbQuAoh3eMIy9hWZ6QfWqk1eBDIC3ZngOkTckYqca0tQ jKiSQHYN8Tq4K9Ev7JKvPM4CiIrXIQtS0XhJqcGSrC0YrJzwkcVdndkhVmdhKdMZ 7w6ESRo6oxWYa0/MufG3/VuPRwRhKUJdvPpQBl8tSrGa4PFIGqAbYKpDKH7dhiBO tDhEhPuvS8TOin9/7jETqQmyJU13l0odPEhJiwIDAQABAoIBABiDUEDpqr59WxTE OaeZksV54I4Y2PV7peKtyFqb0UHXuQdIyB3oqhUOP6kijj3nj9s+8xAE3TlZ3m9I 6w+vkRjo9tzjph4rA7LOaOyzKrDzPOqxrYFaIgVKYuy0mvdLt0K0zrDdTHlrB81t LHw5qjU7xk3GnzYW930TkIaEZce5WXcG1SUBtdWrP6RGYAlOUCBSbnJcumpw2sE+ I7IoxMmQbVl9UOK1IRRltr76A2APoo7pPkz5ghqWgykjta8aMYEfEz6E19rTTPWE PM8M28MzNcGN7inIMlejxii/LTJQLFfUVdPH0wOWNTZcvOkgcuF34tZ6b7ukw/Ky XeOKJcECgYEA2RRytdmeOp7QDIaFTBwV2t5xuEBnVAQ9V0AEh3wr+PB9wDBLFkJv wIKp+oMjJOURNnq8aP3wg+xuyKW0+fsHmFbytK5g7cjn8oXFyk9PvpAuhDXjGcQv rjdwpaDzepUTjO77fHslqsfmreFZYGDTCA7X/jcXldnIPHygjbwvU5kCgYEAxEi6 XRBuhh2/U6aY4AdJxpwePTKi0LNSIsfb6IAlnqOyL8tGamJg3DSyD3xLnpo1UJjr sRhgVVbRfGVgpm1Qkd826ekFtSDg65fkD1zcCd/ijSineFB3cIQSIX9+L1bpEcir uey/qyc/a8+UZq/YEmXMnB6GDNtDClDriMQZ/MMCgYEAv8YRxNd4sp7ke3xHvEI/ iHjli/nRjuaj7jWPCsZG7og+/49qdkLBCRgl5Dr/zDNVroRleHeGiHVSNY42wHTl c860Yax/0vGe/6DwaFcCwv4LKh+U/olT+hveN2RmVM/oUqQ5pfIBB8vL3absV3mS VVcPt/ShsG+SNuV+zVgHk1kCgYBNLnPpqE5tekEDeZzfar491KGnWsPe4MRJXOFB +THRwXiNhpb3uhtwO2BQ6oUppmWUfa0gA//NTsgs7AgnKRDnayhCrhhKctU+jolk 6RS05U5GR1gi3TE6ExS2C1Xo83nOPmQYRdnQSSyNDiDCiB6kjVb5hJ8daxJfehZD vyig1QKBgBzpjUITbxy0uty5qL81aV1luMwlkSVhCHZCAjhFkbUxHFvMuoeFuwQm aDcm/XZqbBEO8D1BcjAonMmpuVwnnhfaXEZwzZqP0oJaaS5GzwdEP/aT9NuUd3uf 1PXdun7ArANAQayTWiDP613UUHY96GszYpxCHQTF9uYUjk+3ncUV -----END RSA PRIVATE KEY----- stunnel-5.56/tests/execute_read0000775000175000017500000000002713261702112013603 00000000000000#!/bin/sh cat >> "$1" stunnel-5.56/tests/make_test0000775000175000017500000000513013312441644013131 00000000000000#!/bin/sh result=0 count=0 fail=0 skip=0 result_path=$(pwd) cd $(dirname "$0") script_path=$(pwd) cd "${result_path}" result_path="${result_path}/logs" autodetection() { result=0 if [ -n "$(command -v ncat)" ] then # ncat mynetcat="ncat" elif [ -n "$(command -v nc)" ] then # nc mynetcat="nc" else # netcat is required printf "%s\n" "ncat / nc not found in \$PATH" result=1 fi if [ -n "$(command -v netstat)" ] && ! netstat -a -n 2>&1 | grep -q -e "usage" -e "invalid" -e "illegal" -e "command not found" then mynetstat="netstat" elif [ -n "$(command -v ss)" ] && ! ss -a -n -l 2>&1 | grep -q -e "usage" -e "invalid" -e "illegal" -e "command not found" then mynetstat="ss" elif [ -n "$(command -v lsof)" ] && ! lsof -i -n -P 2>&1 | grep -q -e "usage" -e "invalid" -e "illegal" -e "command not found" then mynetstat="lsof" else # netstat / ss / lsof is required printf "%s\n" "netstat / ss / lsof not found in \$PATH or some option error" result=1 fi if [ -n "$(command -v stdbuf)" ] then mybuffer="stdbuf" elif [ -n "$(command -v unbuffer)" ] then mybuffer="unbuffer" else mybuffer="" fi return $result } if autodetection then rm -rf "${result_path}" mkdir "${result_path}" cd "${result_path}" date > "results.log" ../../src/stunnel -version 2>> "results.log" printf "\n%s\n" "Testing..." >> "results.log" head -n5 "results.log" if ! grep -q "solaris" "results.log" then for plik in ${script_path}/recipes/* do /bin/sh $plik "$mynetcat" "$mynetstat" "$mybuffer" state=$? if [ "$state" -eq 0 ] then # $state=0 count=$((count + 1)) elif [ "$state" -eq 125 ] then # $state=125 skip=$((skip + 1)) else # $state=1 fail=$((fail + 1)) result=1 fi done if [ $count -eq 0 ] then # no test was done result=1 fi printf "%s\n" "summary: success $count, skip $skip, fail $fail" printf "%s\n" "summary: success $count, skip $skip, fail $fail" >> "results.log" printf "%s\n" "./make_test finished" cd .. else # skip make test for solaris printf "%s\n" "./make_test skipped" printf "%s\n" "./make_test skipped" >> "results.log" #result=125 fi else # netcat not found printf "%s\n" "./make_test skipped" #result=125 fi exit $result stunnel-5.56/tests/execute_write0000775000175000017500000000003413261702112014020 00000000000000#!/bin/sh echo "$@" > "$1" stunnel-5.56/tests/execute0000775000175000017500000000006413147206635012625 00000000000000#!/bin/sh printf "%-35s\t%s\n" "test $1" "success" stunnel-5.56/tests/Makefile.in0000664000175000017500000004475613527763157013333 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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 1998-2019 VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } 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@ subdir = tests ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(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) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/src/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # 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 DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" 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@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ 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@ runstatedir = @runstatedir@ 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@ SUBDIRS = certs EXTRA_DIST = make_test test_library recipes execute execute_read execute_write all: all-recursive .SUFFIXES: $(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) --foreign tests/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign tests/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__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ 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): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(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-recursive 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-recursive 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: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(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 @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-local check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive 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: 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-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-local \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) check-am install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am check-local clean clean-generic clean-libtool \ cscopelist-am ctags ctags-am distclean distclean-generic \ distclean-libtool distclean-local distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ 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-ps install-ps-am install-strip \ installcheck installcheck-am installdirs installdirs-am \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am .PRECIOUS: Makefile check-local: $(srcdir)/make_test distclean-local: rm -f logs/*.log # 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.56/TODO.md0000664000175000017500000000420213527761411011160 00000000000000# stunnel TODO ### High priority features. They will likely be supported some day. A sponsor could allocate my time to get them faster. * Extend session tickets and/or sessiond to also serialize application data ("redirect" state and session persistence). * Add client certificate autoselection based on the list of accepted issuers: SSL_CTX_set_client_cert_cb(), SSL_get_client_CA_list(). * Add an Apparmor profile. * Optional line-buffering of the log file. * Log rotation on Windows. * Configuration file option to limit the number of concurrent connections. * Command-line server control interface on both Unix and Windows. * Separate GUI process running as the current user on Windows. * An Android GUI. * OCSP stapling (tlsext_status). * Indirect CRL support (RFC 3280, section 5). * MSI installer for Windows. * Add user-defined headers to CONNECT proxy requests. This can be used to impersonate other software (e.g. web browsers). ### Low priority features. They will unlikely ever be supported. * Database and/or directory interface for retrieving PSK secrets. * Support static FIPS-enabled build. * Service-level logging destination. * Enforce key renegotiation (re-handshake) for long connections. * Logging to NT EventLog on Windows. * Internationalization of logged messages (i18n). * Generic scripting engine instead or static protocol.c. * Add 'leastconn' failover strategy to order defined 'connect' targets by the number of active connections. * Add '-status' command line option reporting the number of clients connected to each service. ### Features I won't support, unless convinced otherwise by a wealthy sponsor. * Support for adding X-Forwarded-For to HTTP request headers. This feature is less useful since PROXY protocol support is available. * Support for adding X-Forwarded-For to SMTP email headers. This feature is most likely to be implemented as a separate proxy. * Additional certificate checks (including wildcard comparison) based on: - O (Organization), and - OU (Organizational Unit). * Set processes title that appear on the ps(1) and top(1) commands. I could not find a portable *and* non-copyleft library for it. stunnel-5.56/Makefile.am0000664000175000017500000000373413527766022012141 00000000000000## Process this file with automake to produce Makefile.in # by Michal Trojnara 1998-2019 ACLOCAL_AMFLAGS = -I m4 SUBDIRS = src doc tools tests LIBTOOL_DEPS = @LIBTOOL_DEPS@ libtool: $(LIBTOOL_DEPS) $(SHELL) ./config.status libtool docdir = $(datadir)/doc/stunnel doc_DATA = README.md TODO.md COPYING.md AUTHORS.md NEWS.md doc_DATA += PORTS.md BUGS.md COPYRIGHT.md CREDITS.md doc_DATA += INSTALL.W32.md INSTALL.WCE.md INSTALL.FIPS.md EXTRA_DIST = build-android.sh .travis.yml $(doc_DATA) distcleancheck_listfiles = find -type f -exec sh -c 'test -f $(srcdir)/{} || echo {}' ';' distclean-local: rm -rf autom4te.cache rm -f $(distdir)-win64-installer.exe dist-hook: $(MAKE) -C src mingw64 $(MAKE) -C doc stunnel.html makensis -NOCD -DARCH=win64 -DVERSION=${VERSION} \ -DSTUNNEL_DIR=$(srcdir) \ -DDEST_DIR=. \ -DOPENSSL_DIR=/opt/openssl-mingw64 \ $(srcdir)/tools/stunnel.nsi -$(srcdir)/sign/sign.sh $(distdir)-win64-installer.exe -$(srcdir)/sign/verify.sh bin/win64/*.exe $(distdir)-win64-installer.exe sign: cp -f $(distdir).tar.gz $(distdir)-win64-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)-win64-installer.exe; gpg --yes --armor --detach-sign --force-v3-sigs $(distdir)-android.zip" sha256sum $(distdir).tar.gz >../dist/$(distdir).tar.gz.sha256 sha256sum $(distdir)-win64-installer.exe >../dist/$(distdir)-win64-installer.exe.sha256 sha256sum $(distdir)-android.zip >../dist/$(distdir)-android.zip.sha256 cat ../dist/$(distdir)*.sha256 | tac cert: $(MAKE) -C tools cert mingw: $(MAKE) -C src mingw mingw64: $(MAKE) -C src mingw64 test: check install-data-hook: @echo "*********************************************************" @echo "* Type 'make cert' to also install a sample certificate *" @echo "*********************************************************" .PHONY: sign cert mingw mingw64 test stunnel-5.56/aclocal.m40000664000175000017500000023270613527761614011752 00000000000000# generated automatically by aclocal 1.16.1 -*- Autoconf -*- # Copyright (C) 1996-2018 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'.])]) # ============================================================================ # https://www.gnu.org/software/autoconf-archive/ax_append_compile_flags.html # ============================================================================ # # SYNOPSIS # # AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # # For every FLAG1, FLAG2 it is checked whether the compiler works with the # flag. If it does, the flag is added FLAGS-VARIABLE # # If FLAGS-VARIABLE is not specified, the current language's flags (e.g. # CFLAGS) is used. During the check the flag is always added to the # current language's flags. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # INPUT gives an alternative input source to AC_COMPILE_IFELSE. # # NOTE: This macro depends on the AX_APPEND_FLAG and # AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with # AX_APPEND_LINK_FLAGS. # # LICENSE # # Copyright (c) 2011 Maarten Bosmans # # 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 3 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 . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 6 AC_DEFUN([AX_APPEND_COMPILE_FLAGS], [AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG]) AX_REQUIRE_DEFINED([AX_APPEND_FLAG]) for flag in $1; do AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3], [$4]) done ])dnl AX_APPEND_COMPILE_FLAGS # =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_append_flag.html # =========================================================================== # # SYNOPSIS # # AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE]) # # DESCRIPTION # # FLAG is appended to the FLAGS-VARIABLE shell variable, with a space # added in between. # # If FLAGS-VARIABLE is not specified, the current language's flags (e.g. # CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains # FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly # FLAG. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # 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 3 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 . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 7 AC_DEFUN([AX_APPEND_FLAG], [dnl AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])]) AS_VAR_SET_IF(FLAGS,[ AS_CASE([" AS_VAR_GET(FLAGS) "], [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])], [ AS_VAR_APPEND(FLAGS,[" $1"]) AC_RUN_LOG([: FLAGS="$FLAGS"]) ]) ], [ AS_VAR_SET(FLAGS,[$1]) AC_RUN_LOG([: FLAGS="$FLAGS"]) ]) AS_VAR_POPDEF([FLAGS])dnl ])dnl AX_APPEND_FLAG # =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_append_link_flags.html # =========================================================================== # # SYNOPSIS # # AX_APPEND_LINK_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # # For every FLAG1, FLAG2 it is checked whether the linker works with the # flag. If it does, the flag is added FLAGS-VARIABLE # # If FLAGS-VARIABLE is not specified, the linker's flags (LDFLAGS) is # used. During the check the flag is always added to the linker's flags. # # If EXTRA-FLAGS is defined, it is added to the linker's default flags # when the check is done. The check is thus made with the flags: "LDFLAGS # EXTRA-FLAGS FLAG". This can for example be used to force the linker to # issue an error when a bad flag is given. # # INPUT gives an alternative input source to AC_COMPILE_IFELSE. # # NOTE: This macro depends on the AX_APPEND_FLAG and AX_CHECK_LINK_FLAG. # Please keep this macro in sync with AX_APPEND_COMPILE_FLAGS. # # LICENSE # # Copyright (c) 2011 Maarten Bosmans # # 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 3 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 . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 6 AC_DEFUN([AX_APPEND_LINK_FLAGS], [AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) AX_REQUIRE_DEFINED([AX_APPEND_FLAG]) for flag in $1; do AX_CHECK_LINK_FLAG([$flag], [AX_APPEND_FLAG([$flag], [m4_default([$2], [LDFLAGS])])], [], [$3], [$4]) done ])dnl AX_APPEND_LINK_FLAGS # =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # # Check whether the given FLAG works with the current language's compiler # or gives an error. (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # INPUT gives an alternative input source to AC_COMPILE_IFELSE. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # 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 3 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 . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 5 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_COMPILE_FLAGS # =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # # Check whether the given FLAG works with the linker or gives an error. # (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the linker's default flags # when the check is done. The check is thus made with the flags: "LDFLAGS # EXTRA-FLAGS FLAG". This can for example be used to force the linker to # issue an error when a bad flag is given. # # INPUT gives an alternative input source to AC_LINK_IFELSE. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # 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 3 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 . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 5 AC_DEFUN([AX_CHECK_LINK_FLAG], [AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ ax_check_save_flags=$LDFLAGS LDFLAGS="$LDFLAGS $4 $1" AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) LDFLAGS=$ax_check_save_flags]) AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_LINK_FLAGS # =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_pthread.html # =========================================================================== # # SYNOPSIS # # AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) # # DESCRIPTION # # This macro figures out how to build C programs using POSIX threads. It # sets the PTHREAD_LIBS output variable to the threads library and linker # flags, and the PTHREAD_CFLAGS output variable to any special C compiler # flags that are needed. (The user can also force certain compiler # flags/libs to be tested by setting these environment variables.) # # Also sets PTHREAD_CC to any special C compiler that is needed for # multi-threaded programs (defaults to the value of CC otherwise). (This # is necessary on AIX to use the special cc_r compiler alias.) # # NOTE: You are assumed to not only compile your program with these flags, # but also to link with them as well. For example, you might link with # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # # If you are only building threaded programs, you may wish to use these # variables in your default LIBS, CFLAGS, and CC: # # LIBS="$PTHREAD_LIBS $LIBS" # CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # CC="$PTHREAD_CC" # # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant # has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to # that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the # PTHREAD_PRIO_INHERIT symbol is defined when compiling with # PTHREAD_CFLAGS. # # ACTION-IF-FOUND is a list of shell commands to run if a threads library # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it # is not found. If ACTION-IF-FOUND is not specified, the default action # will define HAVE_PTHREAD. # # Please let the authors know if this macro fails on any platform, or if # you have any other suggestions or comments. This macro was based on work # by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help # from M. Frigo), as well as ac_pthread and hb_pthread macros posted by # Alejandro Forero Cuervo to the autoconf macro repository. We are also # grateful for the helpful feedback of numerous users. # # Updated for Autoconf 2.68 by Daniel Richard G. # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2011 Daniel Richard G. # # 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 3 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 . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 24 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_PROG_SED]) AC_LANG_PUSH([C]) ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on Tru64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then ax_pthread_save_CC="$CC" ax_pthread_save_CFLAGS="$CFLAGS" ax_pthread_save_LIBS="$LIBS" AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) AC_MSG_RESULT([$ax_pthread_ok]) if test "x$ax_pthread_ok" = "xno"; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi CC="$ax_pthread_save_CC" CFLAGS="$ax_pthread_save_CFLAGS" LIBS="$ax_pthread_save_LIBS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 # (Note: HP C rejects this with "bad form for `-t' option") # -pthreads: Solaris/gcc (Note: HP C also rejects) # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads and # -D_REENTRANT too), HP C (must be checked before -lpthread, which # is present but should not be used directly; and before -mthreads, # because the compiler interprets this as "-mt" + "-hreads") # -mthreads: Mingw32/gcc, Lynx/gcc # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case $host_os in freebsd*) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) ax_pthread_flags="-kthread lthread $ax_pthread_flags" ;; hpux*) # From the cc(1) man page: "[-mt] Sets various -D flags to enable # multi-threading and also sets -lpthread." ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" ;; openedition*) # IBM z/OS requires a feature-test macro to be defined in order to # enable POSIX threads at all, so give the user a hint if this is # not set. (We don't define these ourselves, as they can affect # other portions of the system API in unpredictable ways.) AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], [ # if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) AX_PTHREAD_ZOS_MISSING # endif ], [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) ;; solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (N.B.: The stubs are missing # pthread_cleanup_push, or rather a function called by this macro, # so we could check for that, but who knows whether they'll stub # that too in a future libc.) So we'll check first for the # standard Solaris way of linking pthreads (-mt -lpthread). ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags" ;; esac # GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) AS_IF([test "x$GCC" = "xyes"], [ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"]) # The presence of a feature test macro requesting re-entrant function # definitions is, on some systems, a strong hint that pthreads support is # correctly enabled case $host_os in darwin* | hpux* | linux* | osf* | solaris*) ax_pthread_check_macro="_REENTRANT" ;; aix*) ax_pthread_check_macro="_THREAD_SAFE" ;; *) ax_pthread_check_macro="--" ;; esac AS_IF([test "x$ax_pthread_check_macro" = "x--"], [ax_pthread_check_cond=0], [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"]) # Are we compiling with Clang? AC_CACHE_CHECK([whether $CC is Clang], [ax_cv_PTHREAD_CLANG], [ax_cv_PTHREAD_CLANG=no # Note that Autoconf sets GCC=yes for Clang as well as GCC if test "x$GCC" = "xyes"; then AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ # if defined(__clang__) && defined(__llvm__) AX_PTHREAD_CC_IS_CLANG # endif ], [ax_cv_PTHREAD_CLANG=yes]) fi ]) ax_pthread_clang="$ax_cv_PTHREAD_CLANG" ax_pthread_clang_warning=no # Clang needs special handling, because older versions handle the -pthread # option in a rather... idiosyncratic way if test "x$ax_pthread_clang" = "xyes"; then # Clang takes -pthread; it has never supported any other flag # (Note 1: This will need to be revisited if a system that Clang # supports has POSIX threads in a separate library. This tends not # to be the way of modern systems, but it's conceivable.) # (Note 2: On some systems, notably Darwin, -pthread is not needed # to get POSIX threads support; the API is always present and # active. We could reasonably leave PTHREAD_CFLAGS empty. But # -pthread does define _REENTRANT, and while the Darwin headers # ignore this macro, third-party headers might not.) PTHREAD_CFLAGS="-pthread" PTHREAD_LIBS= ax_pthread_ok=yes # However, older versions of Clang make a point of warning the user # that, in an invocation where only linking and no compilation is # taking place, the -pthread option has no effect ("argument unused # during compilation"). They expect -pthread to be passed in only # when source code is being compiled. # # Problem is, this is at odds with the way Automake and most other # C build frameworks function, which is that the same flags used in # compilation (CFLAGS) are also used in linking. Many systems # supported by AX_PTHREAD require exactly this for POSIX threads # support, and in fact it is often not straightforward to specify a # flag that is used only in the compilation phase and not in # linking. Such a scenario is extremely rare in practice. # # Even though use of the -pthread flag in linking would only print # a warning, this can be a nuisance for well-run software projects # that build with -Werror. So if the active version of Clang has # this misfeature, we search for an option to squash it. AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown # Create an alternate version of $ac_link that compiles and # links in two steps (.c -> .o, .o -> exe) instead of one # (.c -> exe), because the warning occurs only in the second # step ax_pthread_save_ac_link="$ac_link" ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"` ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" ax_pthread_save_CFLAGS="$CFLAGS" for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" ac_link="$ax_pthread_save_ac_link" AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], [ac_link="$ax_pthread_2step_ac_link" AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], [break]) ]) done ac_link="$ax_pthread_save_ac_link" CFLAGS="$ax_pthread_save_CFLAGS" AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" ]) case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in no | unknown) ;; *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; esac fi # $ax_pthread_clang = yes if test "x$ax_pthread_ok" = "xno"; then for ax_pthread_try_flag in $ax_pthread_flags; do case $ax_pthread_try_flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -mt,pthread) AC_MSG_CHECKING([whether pthreads work with -mt -lpthread]) PTHREAD_CFLAGS="-mt" PTHREAD_LIBS="-lpthread" ;; -*) AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) PTHREAD_CFLAGS="$ax_pthread_try_flag" ;; pthread-config) AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) PTHREAD_LIBS="-l$ax_pthread_try_flag" ;; esac ax_pthread_save_CFLAGS="$CFLAGS" ax_pthread_save_LIBS="$LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_LINK_IFELSE([AC_LANG_PROGRAM([#include # if $ax_pthread_check_cond # error "$ax_pthread_check_macro must be defined" # endif static void routine(void *a) { a = 0; } static void *start_routine(void *a) { return a; }], [pthread_t th; pthread_attr_t attr; pthread_create(&th, 0, start_routine, 0); pthread_join(th, 0); pthread_attr_init(&attr); pthread_cleanup_push(routine, 0); pthread_cleanup_pop(0) /* ; */])], [ax_pthread_ok=yes], []) CFLAGS="$ax_pthread_save_CFLAGS" LIBS="$ax_pthread_save_LIBS" AC_MSG_RESULT([$ax_pthread_ok]) AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$ax_pthread_ok" = "xyes"; then ax_pthread_save_CFLAGS="$CFLAGS" ax_pthread_save_LIBS="$LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_CACHE_CHECK([for joinable pthread attribute], [ax_cv_PTHREAD_JOINABLE_ATTR], [ax_cv_PTHREAD_JOINABLE_ATTR=unknown for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], [int attr = $ax_pthread_attr; return attr /* ; */])], [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], []) done ]) AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ test "x$ax_pthread_joinable_attr_defined" != "xyes"], [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$ax_cv_PTHREAD_JOINABLE_ATTR], [Define to necessary symbol if this constant uses a non-standard name on your system.]) ax_pthread_joinable_attr_defined=yes ]) AC_CACHE_CHECK([whether more special flags are required for pthreads], [ax_cv_PTHREAD_SPECIAL_FLAGS], [ax_cv_PTHREAD_SPECIAL_FLAGS=no case $host_os in solaris*) ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" ;; esac ]) AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ test "x$ax_pthread_special_flags_added" != "xyes"], [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" ax_pthread_special_flags_added=yes]) AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], [ax_cv_PTHREAD_PRIO_INHERIT], [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int i = PTHREAD_PRIO_INHERIT;]])], [ax_cv_PTHREAD_PRIO_INHERIT=yes], [ax_cv_PTHREAD_PRIO_INHERIT=no]) ]) AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ test "x$ax_pthread_prio_inherit_defined" != "xyes"], [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) ax_pthread_prio_inherit_defined=yes ]) CFLAGS="$ax_pthread_save_CFLAGS" LIBS="$ax_pthread_save_LIBS" # More AIX lossage: compile with *_r variant if test "x$GCC" != "xyes"; then case $host_os in aix*) AS_CASE(["x/$CC"], [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], [#handle absolute path differently from PATH based program lookup AS_CASE(["x$CC"], [x/*], [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) ;; esac fi fi test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" AC_SUBST([PTHREAD_LIBS]) AC_SUBST([PTHREAD_CFLAGS]) AC_SUBST([PTHREAD_CC]) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test "x$ax_pthread_ok" = "xyes"; then ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) : else ax_pthread_ok=no $2 fi AC_LANG_POP ])dnl AX_PTHREAD # =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_require_defined.html # =========================================================================== # # SYNOPSIS # # AX_REQUIRE_DEFINED(MACRO) # # DESCRIPTION # # AX_REQUIRE_DEFINED is a simple helper for making sure other macros have # been defined and thus are available for use. This avoids random issues # where a macro isn't expanded. Instead the configure script emits a # non-fatal: # # ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found # # It's like AC_REQUIRE except it doesn't expand the required macro. # # Here's an example: # # AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) # # LICENSE # # Copyright (c) 2014 Mike Frysinger # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 2 AC_DEFUN([AX_REQUIRE_DEFINED], [dnl m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])]) ])dnl AX_REQUIRE_DEFINED # Copyright (C) 2002-2018 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.16' 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.16.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.16.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-2018 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-2018 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-2018 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-2018 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. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. AS_CASE([$CONFIG_FILES], [*\'*], [eval set x "$CONFIG_FILES"], [*], [set x $CONFIG_FILES]) shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`AS_DIRNAME(["$am_mf"])` am_filepart=`AS_BASENAME(["$am_mf"])` AM_RUN_LOG([cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles]) || am_rc=$? done if test $am_rc -ne 0; then AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments for automatic dependency tracking. Try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking).]) fi AS_UNSET([am_dirpart]) AS_UNSET([am_filepart]) AS_UNSET([am_mf]) AS_UNSET([am_rc]) rm -f conftest-deps.mk } ])# _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. # This creates each '.Po' and '.Plo' makefile fragment that we'll 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" MAKE="${MAKE-make}"])]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2018 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 (and possibly the TAP driver). 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 The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) 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-2018 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+set}" != 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-2018 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-2018 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 whether make has an 'include' directive that can support all # the idioms we need for our automatic dependency tracking code. AC_DEFUN([AM_MAKE_INCLUDE], [AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) AS_CASE([$?:`cat confinc.out 2>/dev/null`], ['0:this is the am__doit target'], [AS_CASE([$s], [BSD], [am__include='.include' am__quote='"'], [am__include='include' am__quote=''])]) if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* AC_MSG_RESULT([${_am_result}]) AC_SUBST([am__include])]) AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2018 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-2018 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-2018 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-2018 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-2018 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-2018 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-2018 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-2018 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-2018 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/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.56/INSTALL.W32.md0000664000175000017500000000623313527761357012112 00000000000000# stunnel Windows install notes ### Cross-compiling 64-bit stunnel from source with MinGW (optional): 1) Install the mingw64 cross-compiler on a Unix/Linux machine. On Debian (and derivatives, including Ubuntu): sudo apt install gcc-mingw-w64-x86-64 On Arch Linux: aurman -S mingw-w64-gcc-bin 2) Download the recent OpenSSL and unpack it: tar zvxf ~/openssl-(version).tar.gz mv openssl-(version) openssl-(version)-mingw64 cd openssl-(version)-mingw64/ 3) Build and install OpenSSL. ./Configure \ --cross-compile-prefix=x86_64-w64-mingw32- \ --prefix=/opt/openssl-mingw64 mingw64 shared sed -i 's/^\(OPENSSLDIR=\).*/\1..\/config/' Makefile sed -i 's/^\(ENGINESDIR=\).*/\1..\/engines/' Makefile make sudo make install sudo cp ms/applink.c /opt/openssl-mingw64/include/openssl/ 4) Download and unpack stunnel-(version).tar.gz. 5) Configure stunnel. cd stunnel-(version) ./configure 6) Build 64-bit Windows executables. cd src make mingw64 ### Cross-compiling 32-bit stunnel from source with MinGW (optional): 1) Install the mingw64 cross-compiler on a Unix/Linux machine. On Debian (and derivatives, including Ubuntu): sudo apt install gcc-mingw-w64-i686 On Arch Linux: aurman -S mingw-w64-gcc-bin 2) Download the recent OpenSSL and unpack it: tar zvxf ~/openssl-(version).tar.gz mv openssl-(version) openssl-(version)-mingw cd openssl-(version)-mingw/ 3) Build and install OpenSSL. ./Configure \ --cross-compile-prefix=i686-w64-mingw32- \ --prefix=/opt/openssl-mingw mingw shared sed -i 's/^\(OPENSSLDIR=\).*/\1..\/config/' Makefile sed -i 's/^\(ENGINESDIR=\).*/\1..\/engines/' Makefile make sudo make install sudo cp ms/applink.c /opt/openssl-mingw/include/openssl/ 4) Download and unpack stunnel-(version).tar.gz. 5) Configure stunnel. cd stunnel-(version) ./configure 6) Build 32-bit Windows executables. cd src make mingw ### Building stunnel from source with MinGW (optional): Building stunnel with MinGW on a Windows machine is possible, but not currently supported. ### Building stunnel from source with Visual Studio (optional): 1) Build your own or download pre-built OpenSSL library and headers. TODO 2) Configure path to your OpenSSL in the src\vc.mak file. 3) Build stunnel in Visual Studio Command Prompt. cd src nmake -f vc.mak ### Installing stunnel: 1) Install stunnel. Run installer to install the precompiled binaries. Alternatively, copy the stunnel.exe and/or tstunnel.exe executable located in /stunnel-(version)/bin/mingw/ or /stunnel-(version)/bin/mingw64/ directory into the destination directory on a Windows machine. Copy OpenSSL DLLs into the same directory if necessary. For a MinGW build also copy libssp-0.dll. For a Visual Studio build also install Microsoft Visual C++ Redistributable. 2) Read the manual (stunnel.html). 3) Create/edit the stunnel.conf configuration file. stunnel-5.56/src/0000775000175000017500000000000013566017555010750 500000000000000stunnel-5.56/src/ui_unix.c0000664000175000017500000002107613562337365012522 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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(SIGUSR2, signal_handler); /* connections */ 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 #ifdef USE_FORK setpgid(0, 0); /* create a new process group if needed */ #endif daemon_loop(); #ifdef USE_FORK s_log(LOG_NOTICE, "Terminating service processes"); signal(SIGCHLD, SIG_IGN); signal(SIGTERM, SIG_IGN); kill(0, SIGTERM); /* kill the whole process group */ while(wait(NULL)!=-1) ; s_log(LOG_NOTICE, "Service processes terminated"); #endif #if !defined(__vms) && !defined(USE_OS2) delete_pid(); #endif /* standard Unix */ } else { /* inetd mode */ CLI *c; #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 */ c=alloc_client_session(&service_options, 0, 1); tls_alloc(c, ui_tls, NULL); service_up_ref(&service_options); client_main(c); client_free(c); } return 0; } #ifndef USE_OS2 NOEXPORT void signal_handler(int sig) { int saved_errno; saved_errno=errno; signal_post((uint8_t)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; } /* silently remove the old pid file */ unlink(global_options.pidfile); /* create a new pid file */ 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", (unsigned long)getpid()); 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); return 0; } NOEXPORT void delete_pid(void) { if(global_options.pidfile) { if(unlink(global_options.pidfile)<0) ioerror(global_options.pidfile); /* not critical */ else s_log(LOG_DEBUG, "Removed pid file %s", global_options.pidfile); } else { s_log(LOG_DEBUG, "No pid file to remove"); } } #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 ui_passwd_cb(char *buf, int size, int rwflag, void *userdata) { return PEM_def_callback(buf, size, rwflag, userdata); } #ifndef OPENSSL_NO_ENGINE UI_METHOD *UI_stunnel() { return UI_OpenSSL(); } #endif /* end of ui_unix.c */ stunnel-5.56/src/env.c0000664000175000017500000000563513467064764011641 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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.56/src/vc.mak0000664000175000017500000000630713446441135011770 00000000000000# vc.mak by Michal Trojnara 1998-2019 # 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 SSLLIBS=libcrypto.lib libssl.lib # or change libraries for OpenSSL older than 1.1.0 #SSLLIBS=libeay32.lib ssleay32.lib !ELSE TARGET=win64 SSLLIBS=libcrypto.lib libssl.lib !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 /Zi /nologo /I"$(INCDIR)" $(UNICODEFLAGS) LDFLAGS=/NOLOGO /DEBUG SHAREDLIBS=ws2_32.lib user32.lib shell32.lib kernel32.lib GUILIBS=advapi32.lib comdlg32.lib crypt32.lib gdi32.lib psapi.lib CLILIBS= # 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) /LIBPATH:"$(LIBDIR)" $(SSLLIBS) /OUT:$@ $** IF EXIST $@.manifest \ mt -nologo -manifest $@.manifest -outputresource:$@;1 $(BIN)\tstunnel.exe: $(SHAREDOBJS) $(CLIOBJS) $(LINK) $(LDFLAGS) $(SHAREDLIBS) $(CLILIBS) /LIBPATH:"$(LIBDIR)" $(SSLLIBS) /OUT:$@ $** IF EXIST $@.manifest \ mt -nologo -manifest $@.manifest -outputresource:$@;1 # end of vc.mak stunnel-5.56/src/evc.mak0000664000175000017500000001644313467064764012153 00000000000000# wce.mak for stunnel.exe by Michal Trojnara 1998-2019 # 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.56/src/protocol.c0000664000175000017500000014445613467064764012717 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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 TLS (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); throw_exception(c, 2); /* don't reset */ } /* TODO: add USERNAME/PASSWORD authentication */ if(resp.method!=0x00) { s_log(LOG_ERR, "No supported SOCKS5 authentication method received"); throw_exception(c, 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)) throw_exception(c, 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); throw_exception(c, 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); throw_exception(c, 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); } throw_exception(c, 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); throw_exception(c, 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) throw_exception(c, 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; iconnect_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 */ throw_exception(c, 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 TLS 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"); throw_exception(c, 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)); throw_exception(c, 1); } addrlen=sizeof addr; if(getsockname(c->local_rfd.fd, &addr.sa, &addrlen)) { sockerror("getsockname"); throw_exception(c, 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)); throw_exception(c, 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"); throw_exception(c, 1); } if(buffer[2]!=0 || buffer[3]!=1) { /* length != 1 */ s_log(LOG_ERR, "Unexpected NetBIOS response size"); throw_exception(c, 1); } if(buffer[4]!=0x8e) { /* use TLS */ s_log(LOG_ERR, "Remote server does not require TLS"); throw_exception(c, 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"); throw_exception(c, 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); throw_exception(c, 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-TLS preferred */ if(buffer[0]!='S') { s_log(LOG_ERR, "PostgreSQL server rejected TLS"); throw_exception(c, 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 TLS, rejecting"); /* no way to send error on startup, so just drop the client */ throw_exception(c, 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) { char *line; ssl_putline(c, "HELO localhost"); line=ssl_getline(c); /* ignore the reply */ str_free(line); 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); throw_exception(c, 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); throw_exception(c, 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); throw_exception(c, 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); throw_exception(c, 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); throw_exception(c, 1); } str_free(line); encoded=base64(1, user, (int)strlen(user)); if(!encoded) { s_log(LOG_ERR, "Base64 encoder failed"); throw_exception(c, 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); throw_exception(c, 1); } str_free(line); encoded=base64(1, pass, (int)strlen(pass)); if(!encoded) { s_log(LOG_ERR, "Base64 encoder failed"); throw_exception(c, 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); throw_exception(c, 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, 0); 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)"); throw_exception(c, 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); throw_exception(c, 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); throw_exception(c, 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); throw_exception(c, 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); throw_exception(c, 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); throw_exception(c, 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); throw_exception(c, 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); throw_exception(c, 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); throw_exception(c, 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, 0); 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)"); throw_exception(c, 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); throw_exception(c, 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 capabilities */ 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); throw_exception(c, 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); throw_exception(c, 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); throw_exception(c, 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); throw_exception(c, 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); throw_exception(c, 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); throw_exception(c, 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"); throw_exception(c, 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"); throw_exception(c, 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"); throw_exception(c, 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); throw_exception(c, 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"); throw_exception(c, 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); throw_exception(c, 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); throw_exception(c, 1); } } } while(*line); if(!ntlm2_txt) { /* no Proxy-Authenticate: NTLM header */ s_log(LOG_ERR, "Proxy-Authenticate: NTLM header not found"); str_free(line); throw_exception(c, 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"); throw_exception(c, 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); memcpy((char *)phase3+domain_off, domain, domain_len); memcpy((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, unsigned char hash[7]) { DES_cblock key; DES_key_schedule sched; /* convert 56-bit hash to 64-bit DES key */ 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.56/src/make.bat0000664000175000017500000000063113012624541012256 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 improvements 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.56/src/Makefile.am0000664000175000017500000000477013467064764012740 00000000000000## Process this file with automake to produce Makefile.in # by Michal Trojnara 1998-2019 ############################################################################### # 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 ############################################################################### # 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$(SYSROOT)/usr/kerberos/include # Additional preprocesor definitions stunnel_CPPFLAGS += -I$(SSLDIR)/include stunnel_CPPFLAGS += -DLIBDIR='"$(pkglibdir)"' stunnel_CPPFLAGS += -DCONFDIR='"$(sysconfdir)/stunnel"' # TLS 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 # ############################################################################### mingw: $(MAKE) -f $(srcdir)/mingw.mk srcdir=$(srcdir) win32_arch=win32 win32_targetcpu=i686 win32_mingw=mingw mingw64: $(MAKE) -f $(srcdir)/mingw.mk srcdir=$(srcdir) win32_arch=win64 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.56/src/libwrap.c0000664000175000017500000002451313467064764012505 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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 uint8_t 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; uint8_t 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) { uint8_t result=0; /* deny by default */ #ifdef USE_LIBWRAP_POOL jmp_buf exception_buffer, *exception_backup; 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"); } while(num_busy==num_processes) { /* all child processes are busy */ retval=pthread_cond_wait(&cond, &mutex); if(retval) { errno=retval; ioerror("pthread_cond_wait"); } } 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"); } s_log(LOG_DEBUG, "Acquired libwrap process #%d", my_process); exception_backup=c->exception_pointer; c->exception_pointer=&exception_buffer; if(!setjmp(exception_buffer)) { 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], &result, sizeof result); } c->exception_pointer=exception_backup; s_log(LOG_DEBUG, "Releasing libwrap process #%d", my_process); retval=pthread_mutex_lock(&mutex); if(retval) { errno=retval; ioerror("pthread_mutex_lock"); } 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"); } retval=pthread_mutex_unlock(&mutex); if(retval) { errno=retval; ioerror("pthread_mutex_unlock"); } s_log(LOG_DEBUG, "Released libwrap process #%d", my_process); } else #endif /* USE_LIBWRAP_POOL */ { /* use original, synchronous libwrap calls */ CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_LIBWRAP]); result=check(c->opt->servname, c->local_rfd.fd); CRYPTO_THREAD_unlock(stunnel_locks[LOCK_LIBWRAP]); } if(!result) { s_log(LOG_WARNING, "Service [%s] REFUSED by libwrap from %s", c->opt->servname, c->accepted_address); s_log(LOG_DEBUG, "See hosts_access(5) manual for details"); throw_exception(c, 1); } s_log(LOG_DEBUG, "Service [%s] permitted by libwrap from %s", c->opt->servname, c->accepted_address); } NOEXPORT uint8_t 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)!=0; } #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.56/src/resources.rc0000664000175000017500000001162713467064764013243 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-2019" 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 "Co&nnections", IDM_CONNECTIONS 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 MENUITEM "Reopen &Log File", IDM_REOPEN_LOG, GRAYED MENUITEM "Co&nnections", IDM_CONNECTIONS MENUITEM SEPARATOR MENUITEM "&Edit Configuration", IDM_EDIT_CONFIG MENUITEM "&Reload Configuration", IDM_RELOAD_CONFIG MENUITEM SEPARATOR POPUP "&Save Peer Certificate" BEGIN MENUITEM "dummy", 0, GRAYED END 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-2019", -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.56/src/stunnel3.in0000775000175000017500000000534313261701506012767 00000000000000#!/usr/bin/perl # # stunnel3 Perl wrapper to use stunnel 3.x syntax in stunnel >=4.05 # Copyright (C) 1998-2018 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.56/src/ui_win_gui.c0000664000175000017500000014166613467064764013214 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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 TLS 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 void save_peer_certificate(WPARAM wParam); NOEXPORT LRESULT CALLBACK about_proc(HWND, UINT, WPARAM, LPARAM); NOEXPORT LRESULT CALLBACK pass_proc(HWND, UINT, WPARAM, LPARAM); NOEXPORT int pin_cb(UI *, UI_STRING *); 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 unsigned __stdcall daemon_thread(void *); NOEXPORT void valid_config(void); NOEXPORT void invalid_config(void); NOEXPORT void update_peer_menu(void); NOEXPORT void update_peer_menu_unlocked(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 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 BOOL new_logs=FALSE; 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; static char ui_pass[PEM_BUFSIZE]; /**************************************** 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() { HANDLE handle; #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 _beginthreadex() */ handle=(HANDLE)_beginthreadex(NULL, DEFAULT_STACK_SIZE, daemon_thread, NULL, 0, NULL); if(!handle) fatal("Failed to create the daemon thread"); CloseHandle(handle); 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; #if 0 switch(message) { case WM_CTLCOLORSTATIC: case WM_TIMER: 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: 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_CONNECTIONS: signal_post(SIGNAL_CONNECTIONS); 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; default: if(wParam>=IDM_PEER_MENU && wParamnext, ++section_number) ; if(section && !save_text_file(section->file, section->chain)) { #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); } CRYPTO_THREAD_unlock(stunnel_locks[LOCK_SECTIONS]); } 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); if(current_section) { /* should always be set */ key_file_name=str2tstr(current_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 passphrase to UTF-8 string (as ui_pass) */ pass_txt=tstr2str(pass_dialog.txt); strcpy(ui_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 ui_passwd_cb(char *buf, int size, int rwflag, void *userdata) { int len; (void)rwflag; /* squash the unused parameter warning */ (void)userdata; /* squash the unused parameter warning */ if(!DialogBox(ghInst, TEXT("PassBox"), hwnd, (DLGPROC)pass_proc)) return 0; /* dialog cancelled or failed */ len=(int)strlen(ui_pass); if(len<0 || size<0) /* the API uses signed integers */ return 0; if(len>size) /* truncate the returned data if needed */ len=size; memcpy(buf, ui_pass, (size_t)len); memset(ui_pass, 0, sizeof ui_pass); return len; } #ifndef OPENSSL_NO_ENGINE UI_METHOD *UI_stunnel() { static UI_METHOD *ui_method=NULL; if(ui_method) /* already initialized */ return ui_method; ui_method=UI_create_method("stunnel WIN32 UI"); if(!ui_method) { sslerror("UI_create_method"); return NULL; } UI_method_set_reader(ui_method, pin_cb); return ui_method; } NOEXPORT int pin_cb(UI *ui, UI_STRING *uis) { if(!DialogBox(ghInst, TEXT("PassBox"), hwnd, (DLGPROC)pass_proc)) return 0; /* dialog cancelled or failed */ UI_set_result(ui, uis, ui_pass); memset(ui_pass, 0, sizeof ui_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; CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_WIN_LOG]); txt=log_txt(); /* need to convert the result to UTF-8 */ CRYPTO_THREAD_unlock(stunnel_locks[LOCK_WIN_LOG]); 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_detached(sizeof(struct LIST)+txt_len*sizeof(TCHAR)); curr->len=txt_len; _tcscpy(curr->txt, txt); curr->next=NULL; /* this critical section is performance critical */ CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_WIN_LOG]); if(tail) tail->next=curr; tail=curr; if(!head) head=tail; log_len++; new_logs=TRUE; if(log_len>LOG_LINES) { curr=head; head=head->next; log_len--; } else { curr=NULL; } CRYPTO_THREAD_unlock(stunnel_locks[LOCK_WIN_LOG]); str_free(curr); } NOEXPORT void update_logs(void) { LPTSTR txt; CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_WIN_LOG]); if(new_logs) { txt=log_txt(); new_logs=FALSE; } else { txt=NULL; } CRYPTO_THREAD_unlock(stunnel_locks[LOCK_WIN_LOG]); if(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 unsigned __stdcall 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)) { if(cmdline.config_file && *cmdline.config_file=='-') 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); } PostMessage(hwnd, WM_VALID_CONFIG, 0, 0); /* start the main loop */ daemon_loop(); main_cleanup(); _endthreadex(0); /* SIGNAL_TERMINATE received */ return 0; } /**************************************** 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) { CRYPTO_THREAD_read_lock(stunnel_locks[LOCK_SECTIONS]); update_peer_menu_unlocked(); CRYPTO_THREAD_unlock(stunnel_locks[LOCK_SECTIONS]); } NOEXPORT void update_peer_menu_unlocked(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 */ 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("\tverifyPeer = yes\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); win_log(txt); str_free(txt); } 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.56/src/options.c0000664000175000017500000043507713562337365012547 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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 OPENSSL_VERSION_NUMBER >= 0x10101000L #define DEFAULT_CURVES "X25519:P-256:X448:P-521:P-384" #else /* OpenSSL version < 1.1.1 */ #define DEFAULT_CURVES "prime256v1" #endif /* OpenSSL version >= 1.1.1 */ #if defined(_WIN32_WCE) && !defined(CONFDIR) #define CONFDIR "\\stunnel" #endif #define CONFLINELEN (16*1024) #define INVALID_SSL_OPTION ((long unsigned)-1) typedef enum { CMD_SET_DEFAULTS, /* set default values */ CMD_SET_COPY, /* duplicate from new_service_options */ CMD_FREE, /* deallocate memory */ CMD_SET_VALUE, /* set a user-specified value */ CMD_INITIALIZE, /* initialize the global options or a section */ CMD_PRINT_DEFAULTS, /* print default values */ CMD_PRINT_HELP /* print help */ } CMD; NOEXPORT int options_file(char *, CONF_TYPE, SERVICE_OPTIONS **); NOEXPORT int init_section(int, 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 *); NOEXPORT void sni_free(SERVICE_OPTIONS *); #endif /* !defined(OPENSSL_NO_TLSEXT) */ #if OPENSSL_VERSION_NUMBER>=0x10100000L NOEXPORT int str_to_proto_version(const char *); #else /* OPENSSL_VERSION_NUMBER<0x10100000L */ NOEXPORT char *tls_methods_set(SERVICE_OPTIONS *, const char *); NOEXPORT char *tls_methods_check(SERVICE_OPTIONS *); #endif /* OPENSSL_VERSION_NUMBER<0x10100000L */ NOEXPORT char *parse_debug_level(char *, SERVICE_OPTIONS *); #ifndef OPENSSL_NO_PSK NOEXPORT PSK_KEYS *psk_read(char *); NOEXPORT PSK_KEYS *psk_dup(PSK_KEYS *); NOEXPORT void psk_free(PSK_KEYS *); #endif /* !defined(OPENSSL_NO_PSK) */ #if OPENSSL_VERSION_NUMBER>=0x10000000L NOEXPORT TICKET_KEY *key_read(char *, char *); NOEXPORT TICKET_KEY *key_dup(TICKET_KEY *); NOEXPORT void key_free(TICKET_KEY *); #endif /* OpenSSL 1.0.0 or later */ 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}, #else /* ignore if unsupported by OpenSSL */ {"NO_TLSv1.1", 0}, #endif #ifdef SSL_OP_NO_TLSv1_2 {"NO_TLSv1.2", SSL_OP_NO_TLSv1_2}, #else /* ignore if unsupported by OpenSSL */ {"NO_TLSv1.2", 0}, #endif #ifdef SSL_OP_NO_TLSv1_3 {"NO_TLSv1.3", SSL_OP_NO_TLSv1_3}, {"NO_TLSv1_3", SSL_OP_NO_TLSv1_3}, /* keep compatibility with our typo */ #else /* ignore if unsupported by OpenSSL */ {"NO_TLSv1.3", 0}, {"NO_TLSv1_3", 0}, /* keep compatibility with our typo */ #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 #ifdef SSL_OP_NO_DTLS_MASK {"NO_DTLS_MASK", SSL_OP_NO_DTLS_MASK}, #endif #ifdef SSL_OP_NO_ENCRYPT_THEN_MAC {"NO_ENCRYPT_THEN_MAC", SSL_OP_NO_ENCRYPT_THEN_MAC}, #endif #ifdef SSL_OP_ALLOW_NO_DHE_KEX {"ALLOW_NO_DHE_KEX", SSL_OP_ALLOW_NO_DHE_KEX}, #endif #ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT {"ENABLE_MIDDLEBOX_COMPAT", SSL_OP_ENABLE_MIDDLEBOX_COMPAT}, #endif #ifdef SSL_OP_NO_RENEGOTIATION {"NO_RENEGOTIATION", SSL_OP_NO_RENEGOTIATION}, #endif #ifdef SSL_OP_PRIORITIZE_CHACHA {"PRIORITIZE_CHACHA", SSL_OP_PRIORITIZE_CHACHA}, #endif {NULL, 0} }; NOEXPORT long unsigned parse_ssl_option(char *); NOEXPORT void print_ssl_options(void); NOEXPORT SOCK_OPT *socket_options_init(void); NOEXPORT void socket_option_set_int(SOCK_OPT *, char *, int, int); NOEXPORT SOCK_OPT *socket_options_dup(SOCK_OPT *); NOEXPORT void socket_options_free(SOCK_OPT *); NOEXPORT int socket_options_print(void); NOEXPORT char *socket_option_text(VAL_TYPE, OPT_UNION *); NOEXPORT int socket_option_parse(SOCK_OPT *, 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 char *include_config(char *, SERVICE_OPTIONS **); NOEXPORT void print_syntax(void); NOEXPORT void name_list_append(NAME_LIST **, char *); NOEXPORT void name_list_dup(NAME_LIST **, NAME_LIST *); NOEXPORT void name_list_free(NAME_LIST *); #ifndef USE_WIN32 NOEXPORT char **arg_alloc(char *); NOEXPORT char **arg_dup(char **); NOEXPORT void arg_free(char **arg); #endif char *configuration_file=NULL; GLOBAL_OPTIONS global_options; SERVICE_OPTIONS service_options; unsigned number_of_sections=0; 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:!aNULL:!SSLv2:!DH:!kDHEPSK"; #ifndef OPENSSL_NO_TLS1_3 static char *stunnel_ciphersuites= "TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256"; #endif /* TLS 1.3 */ /**************************************** 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_PRINT_HELP, NULL, NULL); parse_service_option(CMD_PRINT_HELP, NULL, NULL, NULL); log_flush(LOG_MODE_INFO); return 2; } else if(!strcasecmp(arg1, "-version")) { parse_global_option(CMD_PRINT_DEFAULTS, NULL, NULL); parse_service_option(CMD_PRINT_DEFAULTS, NULL, NULL, NULL); log_flush(LOG_MODE_INFO); return 2; } else if(!strcasecmp(arg1, "-sockets")) { socket_options_print(); 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; } if(type==CONF_FILE) { #ifdef HAVE_REALPATH char *real_path=NULL; #ifdef MAXPATHLEN /* a workaround for pre-POSIX.1-2008 4.4BSD and Solaris */ real_path=malloc(MAXPATHLEN); #endif real_path=realpath(name, real_path); if(!real_path) { s_log(LOG_ERR, "Invalid configuration file name \"%s\"", name); ioerror("realpath"); return 1; } configuration_file=str_dup(real_path); free(real_path); #else configuration_file=str_dup(name); #endif #ifndef USE_WIN32 } else if(type==CONF_FD) { configuration_file=str_dup(name); #endif } return options_parse(type); } /**************************************** parse configuration file */ int options_parse(CONF_TYPE type) { SERVICE_OPTIONS *section; options_defaults(); section=&new_service_options; if(options_file(configuration_file, type, §ion)) return 1; if(init_section(1, §ion)) return 1; s_log(LOG_NOTICE, "Configuration successful"); return 0; } NOEXPORT int options_file(char *path, CONF_TYPE type, SERVICE_OPTIONS **section_ptr) { 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 */ if(init_section(0, section_ptr)) { file_close(df); return 1; } /* append a new SERVICE_OPTIONS structure to the list */ { SERVICE_OPTIONS *new_section; new_section=str_alloc_detached(sizeof(SERVICE_OPTIONS)); new_section->next=NULL; (*section_ptr)->next=new_section; *section_ptr=new_section; } /* initialize the newly allocated section */ ++config_opt; config_opt[strlen(config_opt)-1]='\0'; (*section_ptr)->servname=str_dup_detached(config_opt); (*section_ptr)->session=NULL; parse_service_option(CMD_SET_COPY, section_ptr, NULL, NULL); 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 */ errstr=option_not_found; /* try global options first (e.g. for 'debug') */ if(!new_service_options.next) errstr=parse_global_option(CMD_SET_VALUE, config_opt, config_arg); if(errstr==option_not_found) errstr=parse_service_option(CMD_SET_VALUE, section_ptr, 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 init_section(int eof, SERVICE_OPTIONS **section_ptr) { char *errstr; #ifndef USE_WIN32 (*section_ptr)->option.log_stderr=new_global_options.option.log_stderr; #endif /* USE_WIN32 */ if(*section_ptr==&new_service_options) { /* end of global options or inetd mode -> initialize globals */ errstr=parse_global_option(CMD_INITIALIZE, NULL, NULL); if(errstr) { s_log(LOG_ERR, "Global options: %s", errstr); return 1; } } if(*section_ptr!=&new_service_options || eof) { /* end service section or inetd mode -> initialize service */ if(*section_ptr==&new_service_options) s_log(LOG_INFO, "Initializing inetd mode configuration"); else s_log(LOG_INFO, "Initializing service [%s]", (*section_ptr)->servname); errstr=parse_service_option(CMD_INITIALIZE, section_ptr, NULL, NULL); if(errstr) { if(*section_ptr==&new_service_options) s_log(LOG_ERR, "Inetd mode: %s", errstr); else s_log(LOG_ERR, "Service [%s]: %s", (*section_ptr)->servname, errstr); return 1; } } return 0; } #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() { SERVICE_OPTIONS *service; /* initialize globals *before* opening the config file */ memset(&new_global_options, 0, sizeof(GLOBAL_OPTIONS)); memset(&new_service_options, 0, sizeof(SERVICE_OPTIONS)); new_service_options.next=NULL; parse_global_option(CMD_SET_DEFAULTS, NULL, NULL); service=&new_service_options; parse_service_option(CMD_SET_DEFAULTS, &service, NULL, NULL); } void options_apply() { /* apply default/validated configuration */ unsigned num=0; SERVICE_OPTIONS *section; CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_SECTIONS]); memcpy(&global_options, &new_global_options, sizeof(GLOBAL_OPTIONS)); /* service_options are used for inetd mode and to enumerate services */ for(section=new_service_options.next; section; section=section->next) section->section_number=num++; memcpy(&service_options, &new_service_options, sizeof(SERVICE_OPTIONS)); number_of_sections=num; CRYPTO_THREAD_unlock(stunnel_locks[LOCK_SECTIONS]); } void options_free() { parse_global_option(CMD_FREE, NULL, NULL); } void service_up_ref(SERVICE_OPTIONS *section) { #ifdef USE_OS_THREADS int ref; CRYPTO_atomic_add(§ion->ref, 1, &ref, stunnel_locks[LOCK_REF]); #else ++(section->ref); #endif } void service_free(SERVICE_OPTIONS *section) { int ref; #ifdef USE_OS_THREADS CRYPTO_atomic_add(§ion->ref, -1, &ref, stunnel_locks[LOCK_REF]); #else ref=--(section->ref); #endif if(ref<0) fatal("Negative section reference counter"); if(ref==0) parse_service_option(CMD_FREE, §ion, NULL, NULL); } /**************************************** global options */ NOEXPORT char *parse_global_option(CMD cmd, char *opt, char *arg) { void *tmp; if(cmd==CMD_PRINT_DEFAULTS || cmd==CMD_PRINT_HELP) { s_log(LOG_NOTICE, " "); s_log(LOG_NOTICE, "Global options:"); } /* chroot */ #ifdef HAVE_CHROOT switch(cmd) { case CMD_SET_DEFAULTS: new_global_options.chroot_dir=NULL; break; case CMD_SET_COPY: /* not used for global options */ break; case CMD_FREE: tmp=global_options.chroot_dir; global_options.chroot_dir=NULL; str_free(tmp); break; case CMD_SET_VALUE: if(strcasecmp(opt, "chroot")) break; new_global_options.chroot_dir=str_dup(arg); return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_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_SET_DEFAULTS: new_global_options.compression=COMP_NONE; break; case CMD_SET_COPY: /* not used for global options */ break; case CMD_FREE: break; case CMD_SET_VALUE: if(strcasecmp(opt, "compression")) break; #if OPENSSL_VERSION_NUMBER < 0x10100000L /* only allow compression with OpenSSL 0.9.8 or later * with OpenSSL #1468 zlib memory leak fixed */ if(OpenSSL_version_num()<0x00908051L) /* 0.9.8e-beta1 */ return "Compression unsupported due to a memory leak"; #endif /* OpenSSL version < 1.1.0 */ if(!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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = compression type", "compression"); break; } #endif /* !defined(OPENSSL_NO_COMP) */ /* EGD */ switch(cmd) { case CMD_SET_DEFAULTS: #ifdef EGD_SOCKET new_global_options.egd_sock=EGD_SOCKET; #else new_global_options.egd_sock=NULL; #endif break; case CMD_SET_COPY: /* not used for global options */ break; case CMD_FREE: tmp=global_options.egd_sock; global_options.egd_sock=NULL; str_free(tmp); break; case CMD_SET_VALUE: if(strcasecmp(opt, "EGD")) break; new_global_options.egd_sock=str_dup(arg); return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: #ifdef EGD_SOCKET s_log(LOG_NOTICE, "%-22s = %s", "EGD", EGD_SOCKET); #endif break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = path to Entropy Gathering Daemon socket", "EGD"); break; } #ifndef OPENSSL_NO_ENGINE /* engine */ switch(cmd) { case CMD_SET_DEFAULTS: engine_reset_list(); break; case CMD_SET_COPY: /* not used for global options */ break; case CMD_FREE: /* FIXME: investigate if we can free it */ break; case CMD_SET_VALUE: if(strcasecmp(opt, "engine")) break; if(!strcasecmp(arg, "auto")) return engine_auto(); else return engine_open(arg); case CMD_INITIALIZE: engine_init(); break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = auto|engine_id", "engine"); break; } /* engineCtrl */ switch(cmd) { case CMD_SET_DEFAULTS: break; case CMD_SET_COPY: /* not used for global options */ break; case CMD_FREE: break; case CMD_SET_VALUE: if(strcasecmp(opt, "engineCtrl")) break; { char *tmp_str=strchr(arg, ':'); if(tmp_str) *tmp_str++='\0'; return engine_ctrl(arg, tmp_str); } case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = cmd[:arg]", "engineCtrl"); break; } /* engineDefault */ switch(cmd) { case CMD_SET_DEFAULTS: break; case CMD_SET_COPY: /* not used for global options */ break; case CMD_FREE: break; case CMD_SET_VALUE: if(strcasecmp(opt, "engineDefault")) break; return engine_default(arg); case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = TASK_LIST", "engineDefault"); break; } #endif /* !defined(OPENSSL_NO_ENGINE) */ /* fips */ switch(cmd) { case CMD_SET_DEFAULTS: #ifdef USE_FIPS new_global_options.option.fips=0; #endif /* USE_FIPS */ break; case CMD_SET_COPY: /* not used for global options */ break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_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_SET_DEFAULTS: new_global_options.option.foreground=0; new_global_options.option.log_stderr=0; break; case CMD_SET_COPY: /* not used for global options */ break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_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_SET_DEFAULTS: new_global_options.icon[ICON_ACTIVE]=load_icon_default(ICON_ACTIVE); break; case CMD_SET_COPY: /* not used for global options */ break; case CMD_FREE: /* FIXME: investigate if we can free it */ break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = icon when connections are established", "iconActive"); break; } /* iconError */ switch(cmd) { case CMD_SET_DEFAULTS: new_global_options.icon[ICON_ERROR]=load_icon_default(ICON_ERROR); break; case CMD_SET_COPY: /* not used for global options */ break; case CMD_FREE: /* FIXME: investigate if we can free it */ break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = icon for invalid configuration file", "iconError"); break; } /* iconIdle */ switch(cmd) { case CMD_SET_DEFAULTS: new_global_options.icon[ICON_IDLE]=load_icon_default(ICON_IDLE); break; case CMD_SET_COPY: /* not used for global options */ break; case CMD_FREE: /* FIXME: investigate if we can free it */ break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = icon when no connections were established", "iconIdle"); break; } #endif /* ICON_IMAGE */ /* log */ switch(cmd) { case CMD_SET_DEFAULTS: new_global_options.log_file_mode=FILE_MODE_APPEND; break; case CMD_SET_COPY: /* not used for global options */ break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = append|overwrite log file", "log"); break; } /* output */ switch(cmd) { case CMD_SET_DEFAULTS: new_global_options.output_file=NULL; break; case CMD_SET_COPY: /* not used for global options */ break; case CMD_FREE: tmp=global_options.output_file; global_options.output_file=NULL; str_free(tmp); break; case CMD_SET_VALUE: if(strcasecmp(opt, "output")) break; new_global_options.output_file=str_dup(arg); return NULL; /* OK */ case CMD_INITIALIZE: #ifndef USE_WIN32 if(!new_global_options.option.foreground /* daemonize() used */ && new_global_options.output_file /* log file enabled */ && new_global_options.output_file[0]!='/' /* relative path */) return "Log file must include full path name"; #endif break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = file to append log messages", "output"); break; } /* pid */ #ifndef USE_WIN32 switch(cmd) { case CMD_SET_DEFAULTS: new_global_options.pidfile=NULL; /* do not create a pid file */ break; case CMD_SET_COPY: /* not used for global options */ break; case CMD_FREE: tmp=global_options.pidfile; global_options.pidfile=NULL; str_free(tmp); break; case CMD_SET_VALUE: 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_INITIALIZE: if(!new_global_options.option.foreground /* daemonize() used */ && new_global_options.pidfile /* pid file enabled */ && new_global_options.pidfile[0]!='/' /* relative path */) return "Pid file must include full path name"; break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = pid file", "pid"); break; } #endif /* RNDbytes */ switch(cmd) { case CMD_SET_DEFAULTS: new_global_options.random_bytes=RANDOM_BYTES; break; case CMD_SET_COPY: /* not used for global options */ break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: s_log(LOG_NOTICE, "%-22s = %d", "RNDbytes", RANDOM_BYTES); break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = bytes to read from random seed files", "RNDbytes"); break; } /* RNDfile */ switch(cmd) { case CMD_SET_DEFAULTS: #ifdef RANDOM_FILE new_global_options.rand_file=str_dup(RANDOM_FILE); #else new_global_options.rand_file=NULL; #endif break; case CMD_SET_COPY: /* not used for global options */ break; case CMD_FREE: tmp=global_options.rand_file; global_options.rand_file=NULL; str_free(tmp); break; case CMD_SET_VALUE: if(strcasecmp(opt, "RNDfile")) break; new_global_options.rand_file=str_dup(arg); return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: #ifdef RANDOM_FILE s_log(LOG_NOTICE, "%-22s = %s", "RNDfile", RANDOM_FILE); #endif break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = path to file with random seed data", "RNDfile"); break; } /* RNDoverwrite */ switch(cmd) { case CMD_SET_DEFAULTS: new_global_options.option.rand_write=1; break; case CMD_SET_COPY: /* not used for global options */ break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: s_log(LOG_NOTICE, "%-22s = yes", "RNDoverwrite"); break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = yes|no overwrite seed datafiles with new random data", "RNDoverwrite"); break; } /* syslog */ #ifndef USE_WIN32 switch(cmd) { case CMD_SET_DEFAULTS: new_global_options.option.log_syslog=1; break; case CMD_SET_COPY: /* not used for global options */ break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = yes|no send logging messages to syslog", "syslog"); break; } #endif /* taskbar */ #ifdef USE_WIN32 switch(cmd) { case CMD_SET_DEFAULTS: new_global_options.option.taskbar=1; break; case CMD_SET_COPY: /* not used for global options */ break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: s_log(LOG_NOTICE, "%-22s = yes", "taskbar"); break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = yes|no enable the taskbar icon", "taskbar"); break; } #endif /* final checks */ switch(cmd) { case CMD_SET_DEFAULTS: break; case CMD_SET_COPY: break; case CMD_FREE: break; case CMD_SET_VALUE: return option_not_found; case CMD_INITIALIZE: /* FIPS needs to be initialized as early as possible */ if(ssl_configure(&new_global_options)) /* configure global TLS settings */ return "Failed to initialize TLS"; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: break; } return NULL; /* OK */ } /**************************************** service-level options */ NOEXPORT char *parse_service_option(CMD cmd, SERVICE_OPTIONS **section_ptr, char *opt, char *arg) { SERVICE_OPTIONS *section; int endpoints=0; #ifndef USE_WIN32 struct group *gr; struct passwd *pw; #endif section=section_ptr ? *section_ptr : NULL; if(cmd==CMD_SET_DEFAULTS || cmd==CMD_SET_COPY) { section->ref=1; } else if(cmd==CMD_FREE) { if(section==&service_options || section==&new_service_options) s_log(LOG_DEBUG, "Deallocating section defaults"); else s_log(LOG_DEBUG, "Deallocating section [%s]", section->servname); } else if(cmd==CMD_PRINT_DEFAULTS || cmd==CMD_PRINT_HELP) { s_log(LOG_NOTICE, " "); s_log(LOG_NOTICE, "Service-level options:"); } /* accept */ switch(cmd) { case CMD_SET_DEFAULTS: addrlist_clear(§ion->local_addr, 1); section->local_fd=NULL; break; case CMD_SET_COPY: addrlist_clear(§ion->local_addr, 1); section->local_fd=NULL; name_list_dup(§ion->local_addr.names, new_service_options.local_addr.names); break; case CMD_FREE: name_list_free(section->local_addr.names); str_free(section->local_addr.addr); str_free(section->local_fd); break; case CMD_SET_VALUE: if(strcasecmp(opt, "accept")) break; section->option.accept=1; name_list_append(§ion->local_addr.names, arg); return NULL; /* OK */ case CMD_INITIALIZE: if(section->local_addr.names) { unsigned i; if(!addrlist_resolve(§ion->local_addr)) return "Cannot resolve accept target"; section->local_fd=str_alloc_detached(section->local_addr.num*sizeof(SOCKET)); for(i=0; ilocal_addr.num; ++i) section->local_fd[i]=INVALID_SOCKET; ++endpoints; } break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = [host:]port accept connections on specified host:port", "accept"); break; } /* CApath */ switch(cmd) { case CMD_SET_DEFAULTS: #if 0 section->ca_dir=(char *)X509_get_default_cert_dir(); #endif section->ca_dir=NULL; break; case CMD_SET_COPY: section->ca_dir=str_dup_detached(new_service_options.ca_dir); break; case CMD_FREE: str_free(section->ca_dir); break; case CMD_SET_VALUE: if(strcasecmp(opt, "CApath")) break; str_free(section->ca_dir); if(arg[0]) /* not empty */ section->ca_dir=str_dup_detached(arg); else section->ca_dir=NULL; return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: #if 0 s_log(LOG_NOTICE, "%-22s = %s", "CApath", section->ca_dir ? section->ca_dir : "(none)"); #endif break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = CA certificate directory for 'verify' option", "CApath"); break; } /* CAfile */ switch(cmd) { case CMD_SET_DEFAULTS: #if 0 section->ca_file=(char *)X509_get_default_certfile(); #endif section->ca_file=NULL; break; case CMD_SET_COPY: section->ca_file=str_dup_detached(new_service_options.ca_file); break; case CMD_FREE: str_free(section->ca_file); break; case CMD_SET_VALUE: if(strcasecmp(opt, "CAfile")) break; str_free(section->ca_file); if(arg[0]) /* not empty */ section->ca_file=str_dup_detached(arg); else section->ca_file=NULL; return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: #if 0 s_log(LOG_NOTICE, "%-22s = %s", "CAfile", section->ca_file ? section->ca_file : "(none)"); #endif break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = CA certificate file for 'verify' option", "CAfile"); break; } /* cert */ switch(cmd) { case CMD_SET_DEFAULTS: section->cert=NULL; break; case CMD_SET_COPY: section->cert=str_dup_detached(new_service_options.cert); break; case CMD_FREE: str_free(section->cert); break; case CMD_SET_VALUE: if(strcasecmp(opt, "cert")) break; str_free(section->cert); section->cert=str_dup_detached(arg); return NULL; /* OK */ case CMD_INITIALIZE: #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 "TLS server needs a certificate"; break; case CMD_PRINT_DEFAULTS: break; /* no default certificate */ case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = certificate chain", "cert"); break; } #if OPENSSL_VERSION_NUMBER>=0x10002000L /* checkEmail */ switch(cmd) { case CMD_SET_DEFAULTS: section->check_email=NULL; break; case CMD_SET_COPY: name_list_dup(§ion->check_email, new_service_options.check_email); break; case CMD_FREE: name_list_free(section->check_email); break; case CMD_SET_VALUE: if(strcasecmp(opt, "checkEmail")) break; name_list_append(§ion->check_email, arg); return NULL; /* OK */ case CMD_INITIALIZE: if(section->check_email && !section->option.verify_chain && !section->option.verify_peer) return "Either \"verifyChain\" or \"verifyPeer\" has to be enabled"; break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = peer certificate email address", "checkEmail"); break; } /* checkHost */ switch(cmd) { case CMD_SET_DEFAULTS: section->check_host=NULL; break; case CMD_SET_COPY: name_list_dup(§ion->check_host, new_service_options.check_host); break; case CMD_FREE: name_list_free(section->check_host); break; case CMD_SET_VALUE: if(strcasecmp(opt, "checkHost")) break; name_list_append(§ion->check_host, arg); return NULL; /* OK */ case CMD_INITIALIZE: if(section->check_host && !section->option.verify_chain && !section->option.verify_peer) return "Either \"verifyChain\" or \"verifyPeer\" has to be enabled"; break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = peer certificate host name pattern", "checkHost"); break; } /* checkIP */ switch(cmd) { case CMD_SET_DEFAULTS: section->check_ip=NULL; break; case CMD_SET_COPY: name_list_dup(§ion->check_ip, new_service_options.check_ip); break; case CMD_FREE: name_list_free(section->check_ip); break; case CMD_SET_VALUE: if(strcasecmp(opt, "checkIP")) break; name_list_append(§ion->check_ip, arg); return NULL; /* OK */ case CMD_INITIALIZE: if(section->check_ip && !section->option.verify_chain && !section->option.verify_peer) return "Either \"verifyChain\" or \"verifyPeer\" has to be enabled"; break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = peer certificate IP address", "checkIP"); break; } #endif /* OPENSSL_VERSION_NUMBER>=0x10002000L */ /* ciphers */ switch(cmd) { case CMD_SET_DEFAULTS: section->cipher_list=NULL; break; case CMD_SET_COPY: section->cipher_list=str_dup_detached(new_service_options.cipher_list); break; case CMD_FREE: str_free(section->cipher_list); break; case CMD_SET_VALUE: if(strcasecmp(opt, "ciphers")) break; str_free(section->cipher_list); section->cipher_list=str_dup_detached(arg); return NULL; /* OK */ case CMD_INITIALIZE: if(!section->cipher_list) { /* this is only executed for global options, because * section->cipher_list is no longer NULL in sections */ #ifdef USE_FIPS if(new_global_options.option.fips) section->cipher_list=str_dup_detached("FIPS"); else #endif /* USE_FIPS */ section->cipher_list=str_dup_detached(stunnel_cipher_list); } break; case CMD_PRINT_DEFAULTS: #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_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = permitted ciphers for TLS 1.2 or older", "ciphers"); break; } #ifndef OPENSSL_NO_TLS1_3 /* ciphersuites */ switch(cmd) { case CMD_SET_DEFAULTS: section->ciphersuites=NULL; break; case CMD_SET_COPY: section->ciphersuites=str_dup_detached(new_service_options.ciphersuites); break; case CMD_FREE: str_free(section->ciphersuites); break; case CMD_SET_VALUE: if(strcasecmp(opt, "ciphersuites")) break; str_free(section->ciphersuites); section->ciphersuites=str_dup_detached(arg); return NULL; /* OK */ case CMD_INITIALIZE: if(!section->ciphersuites) { /* this is only executed for global options, because * section->ciphersuites is no longer NULL in sections */ section->ciphersuites=str_dup_detached(stunnel_ciphersuites); } break; case CMD_PRINT_DEFAULTS: s_log(LOG_NOTICE, "%-22s = %s %s", "ciphersuites", stunnel_ciphersuites, "(with TLSv1.3)"); break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = permitted ciphersuites for TLS 1.3", "ciphersuites"); break; } #endif /* TLS 1.3 */ /* client */ switch(cmd) { case CMD_SET_DEFAULTS: section->option.client=0; break; case CMD_SET_COPY: section->option.client=new_service_options.option.client; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = yes|no client mode (remote service uses TLS)", "client"); break; } #if OPENSSL_VERSION_NUMBER>=0x10002000L /* config */ switch(cmd) { case CMD_SET_DEFAULTS: section->config=NULL; break; case CMD_SET_COPY: name_list_dup(§ion->config, new_service_options.config); break; case CMD_FREE: name_list_free(section->config); break; case CMD_SET_VALUE: if(strcasecmp(opt, "config")) break; name_list_append(§ion->config, arg); return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = command[:parameter] to execute", "config"); break; } #endif /* OPENSSL_VERSION_NUMBER>=0x10002000L */ /* connect */ switch(cmd) { case CMD_SET_DEFAULTS: addrlist_clear(§ion->connect_addr, 0); section->connect_session=NULL; break; case CMD_SET_COPY: addrlist_clear(§ion->connect_addr, 0); section->connect_session=NULL; name_list_dup(§ion->connect_addr.names, new_service_options.connect_addr.names); break; case CMD_FREE: name_list_free(section->connect_addr.names); str_free(section->connect_addr.addr); str_free(section->connect_session); break; case CMD_SET_VALUE: if(strcasecmp(opt, "connect")) break; name_list_append(§ion->connect_addr.names, arg); return NULL; /* OK */ case CMD_INITIALIZE: 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->connect_addr.num=0; section->redirect_addr.num=0; section->option.delayed_lookup=1; } if(section->option.client) section->connect_session= str_alloc_detached(section->connect_addr.num*sizeof(SSL_SESSION *)); ++endpoints; } break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = [host:]port to connect", "connect"); break; } /* CRLpath */ switch(cmd) { case CMD_SET_DEFAULTS: section->crl_dir=NULL; break; case CMD_SET_COPY: section->crl_dir=str_dup_detached(new_service_options.crl_dir); break; case CMD_FREE: str_free(section->crl_dir); break; case CMD_SET_VALUE: if(strcasecmp(opt, "CRLpath")) break; str_free(section->crl_dir); if(arg[0]) /* not empty */ section->crl_dir=str_dup_detached(arg); else section->crl_dir=NULL; return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = CRL directory", "CRLpath"); break; } /* CRLfile */ switch(cmd) { case CMD_SET_DEFAULTS: section->crl_file=NULL; break; case CMD_SET_COPY: section->crl_file=str_dup_detached(new_service_options.crl_file); break; case CMD_FREE: str_free(section->crl_file); break; case CMD_SET_VALUE: if(strcasecmp(opt, "CRLfile")) break; str_free(section->crl_file); if(arg[0]) /* not empty */ section->crl_file=str_dup_detached(arg); else section->crl_file=NULL; return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = CRL file", "CRLfile"); break; } #ifndef OPENSSL_NO_ECDH /* curves */ switch(cmd) { case CMD_SET_DEFAULTS: section->curves=str_dup_detached(DEFAULT_CURVES); break; case CMD_SET_COPY: section->curves=str_dup_detached(new_service_options.curves); break; case CMD_FREE: str_free(section->curves); break; case CMD_SET_VALUE: if(strcasecmp(opt, "curves") && strcasecmp(opt, "curve")) break; str_free(section->curves); section->curves=str_dup_detached(arg); return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: s_log(LOG_NOTICE, "%-22s = %s", "curves", DEFAULT_CURVES); break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = ECDH curve names", "curves"); break; } #endif /* !defined(OPENSSL_NO_ECDH) */ /* debug */ switch(cmd) { case CMD_SET_DEFAULTS: section->log_level=LOG_NOTICE; #if !defined (USE_WIN32) && !defined (__vms) new_global_options.log_facility=LOG_DAEMON; #endif break; case CMD_SET_COPY: section->log_level=new_service_options.log_level; break; case CMD_FREE: break; case CMD_SET_VALUE: if(strcasecmp(opt, "debug")) break; return parse_debug_level(arg, section); case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: #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_PRINT_HELP: #if !defined (USE_WIN32) && !defined (__vms) s_log(LOG_NOTICE, "%-22s = [facility].level (e.g. daemon.info)", "debug"); #else s_log(LOG_NOTICE, "%-22s = level (e.g. info)", "debug"); #endif break; } /* delay */ switch(cmd) { case CMD_SET_DEFAULTS: section->option.delayed_lookup=0; break; case CMD_SET_COPY: section->option.delayed_lookup=new_service_options.option.delayed_lookup; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_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_SET_DEFAULTS: break; case CMD_SET_COPY: section->engine=new_service_options.engine; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = ID of engine to read the key from", "engineId"); break; } /* engineNum */ switch(cmd) { case CMD_SET_DEFAULTS: break; case CMD_SET_COPY: section->engine=new_service_options.engine; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_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_SET_DEFAULTS: section->exec_name=NULL; break; case CMD_SET_COPY: section->exec_name=str_dup_detached(new_service_options.exec_name); break; case CMD_FREE: str_free(section->exec_name); break; case CMD_SET_VALUE: if(strcasecmp(opt, "exec")) break; str_free(section->exec_name); section->exec_name=str_dup_detached(arg); #ifdef USE_WIN32 section->exec_args=str_dup_detached(arg); #else if(!section->exec_args) { section->exec_args=str_alloc_detached(2*sizeof(char *)); section->exec_args[0]=str_dup_detached(section->exec_name); section->exec_args[1]=NULL; /* null-terminate */ } #endif return NULL; /* OK */ case CMD_INITIALIZE: if(section->exec_name) ++endpoints; break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = file execute local inetd-type program", "exec"); break; } /* execArgs */ switch(cmd) { case CMD_SET_DEFAULTS: section->exec_args=NULL; break; case CMD_SET_COPY: #ifdef USE_WIN32 section->exec_args=str_dup_detached(new_service_options.exec_args); #else section->exec_args=arg_dup(new_service_options.exec_args); #endif break; case CMD_FREE: #ifdef USE_WIN32 str_free(section->exec_args); #else arg_free(section->exec_args); #endif break; case CMD_SET_VALUE: if(strcasecmp(opt, "execArgs")) break; #ifdef USE_WIN32 str_free(section->exec_args); section->exec_args=str_dup_detached(arg); #else arg_free(section->exec_args); section->exec_args=arg_alloc(arg); #endif return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = arguments for 'exec' (including $0)", "execArgs"); break; } /* failover */ switch(cmd) { case CMD_SET_DEFAULTS: section->failover=FAILOVER_PRIO; section->rr=0; break; case CMD_SET_COPY: section->failover=new_service_options.failover; section->rr=new_service_options.rr; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: if(section->option.delayed_lookup) section->failover=FAILOVER_PRIO; break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = rr|prio failover strategy", "failover"); break; } /* ident */ switch(cmd) { case CMD_SET_DEFAULTS: section->username=NULL; break; case CMD_SET_COPY: section->username=str_dup_detached(new_service_options.username); break; case CMD_FREE: str_free(section->username); break; case CMD_SET_VALUE: if(strcasecmp(opt, "ident")) break; str_free(section->username); section->username=str_dup_detached(arg); return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = username for IDENT (RFC 1413) checking", "ident"); break; } /* include */ switch(cmd) { case CMD_SET_DEFAULTS: break; case CMD_SET_COPY: break; case CMD_FREE: break; case CMD_SET_VALUE: if(strcasecmp(opt, "include")) break; return include_config(arg, section_ptr); case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = directory with configuration file snippets", "include"); break; } /* key */ switch(cmd) { case CMD_SET_DEFAULTS: section->key=NULL; break; case CMD_SET_COPY: section->key=str_dup_detached(new_service_options.key); break; case CMD_FREE: str_free(section->key); break; case CMD_SET_VALUE: if(strcasecmp(opt, "key")) break; str_free(section->key); section->key=str_dup_detached(arg); return NULL; /* OK */ case CMD_INITIALIZE: if(section->cert && !section->key) section->key=str_dup_detached(section->cert); break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = certificate private key", "key"); break; } /* libwrap */ #ifdef USE_LIBWRAP switch(cmd) { case CMD_SET_DEFAULTS: section->option.libwrap=0; /* disable libwrap by default */ break; case CMD_SET_COPY: section->option.libwrap=new_service_options.option.libwrap; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_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_SET_DEFAULTS: section->option.local=0; break; case CMD_SET_COPY: section->option.local=new_service_options.option.local; memcpy(§ion->source_addr, &new_service_options.source_addr, sizeof(SOCKADDR_UNION)); break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = IP address to be used as source for remote" " connections", "local"); break; } /* logId */ switch(cmd) { case CMD_SET_DEFAULTS: section->log_id=LOG_ID_SEQUENTIAL; break; case CMD_SET_COPY: section->log_id=new_service_options.log_id; break; case CMD_FREE: break; case CMD_SET_VALUE: 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 if(!strcasecmp(arg, "process")) section->log_id=LOG_ID_PROCESS; else return "Invalid connection identifier type"; return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: s_log(LOG_NOTICE, "%-22s = %s", "logId", "sequential"); break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = connection identifier type", "logId"); break; } #ifndef OPENSSL_NO_OCSP /* OCSP */ switch(cmd) { case CMD_SET_DEFAULTS: section->ocsp_url=NULL; break; case CMD_SET_COPY: section->ocsp_url=str_dup_detached(new_service_options.ocsp_url); break; case CMD_FREE: str_free(section->ocsp_url); break; case CMD_SET_VALUE: if(strcasecmp(opt, "ocsp")) break; str_free(section->ocsp_url); section->ocsp_url=str_dup_detached(arg); return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = OCSP responder URL", "OCSP"); break; } /* OCSPaia */ switch(cmd) { case CMD_SET_DEFAULTS: section->option.aia=0; /* disable AIA by default */ break; case CMD_SET_COPY: section->option.aia=new_service_options.option.aia; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = yes|no check the AIA responders from certificates", "OCSPaia"); break; } /* OCSPflag */ switch(cmd) { case CMD_SET_DEFAULTS: section->ocsp_flags=0; break; case CMD_SET_COPY: section->ocsp_flags=new_service_options.ocsp_flags; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = OCSP responder flags", "OCSPflag"); break; } /* OCSPnonce */ switch(cmd) { case CMD_SET_DEFAULTS: section->option.nonce=0; /* disable OCSP nonce by default */ break; case CMD_SET_COPY: section->option.nonce=new_service_options.option.nonce; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_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_SET_DEFAULTS: section->ssl_options_set=0; #if OPENSSL_VERSION_NUMBER>=0x009080dfL section->ssl_options_clear=0; #endif /* OpenSSL 0.9.8m or later */ break; case CMD_SET_COPY: section->ssl_options_set=new_service_options.ssl_options_set; #if OPENSSL_VERSION_NUMBER>=0x009080dfL section->ssl_options_clear=new_service_options.ssl_options_clear; #endif /* OpenSSL 0.9.8m or later */ break; case CMD_FREE: break; case CMD_SET_VALUE: if(strcasecmp(opt, "options")) break; #if OPENSSL_VERSION_NUMBER>=0x009080dfL if(*arg=='-') { long unsigned tmp=parse_ssl_option(arg+1); if(tmp==INVALID_SSL_OPTION) return "Illegal TLS 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==INVALID_SSL_OPTION) return "Illegal TLS option"; section->ssl_options_set|=tmp; } return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: s_log(LOG_NOTICE, "%-22s = %s", "options", "NO_SSLv2"); s_log(LOG_NOTICE, "%-22s = %s", "options", "NO_SSLv3"); break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = TLS option to set/reset", "options"); break; } /* protocol */ switch(cmd) { case CMD_SET_DEFAULTS: section->protocol=NULL; break; case CMD_SET_COPY: section->protocol=str_dup_detached(new_service_options.protocol); break; case CMD_FREE: str_free(section->protocol); break; case CMD_SET_VALUE: if(strcasecmp(opt, "protocol")) break; str_free(section->protocol); section->protocol=str_dup_detached(arg); return NULL; /* OK */ case CMD_INITIALIZE: /* 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; break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = protocol to negotiate before TLS initialization", "protocol"); s_log(LOG_NOTICE, "%25scurrently supported: cifs, connect, imap,", ""); s_log(LOG_NOTICE, "%25s nntp, pgsql, pop3, proxy, smtp, socks", ""); break; } /* protocolAuthentication */ switch(cmd) { case CMD_SET_DEFAULTS: section->protocol_authentication=str_dup_detached("basic"); break; case CMD_SET_COPY: section->protocol_authentication= str_dup_detached(new_service_options.protocol_authentication); break; case CMD_FREE: str_free(section->protocol_authentication); break; case CMD_SET_VALUE: if(strcasecmp(opt, "protocolAuthentication")) break; str_free(section->protocol_authentication); section->protocol_authentication=str_dup_detached(arg); return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = authentication type for protocol negotiations", "protocolAuthentication"); break; } /* protocolDomain */ switch(cmd) { case CMD_SET_DEFAULTS: section->protocol_domain=NULL; break; case CMD_SET_COPY: section->protocol_domain= str_dup_detached(new_service_options.protocol_domain); break; case CMD_FREE: str_free(section->protocol_domain); break; case CMD_SET_VALUE: if(strcasecmp(opt, "protocolDomain")) break; str_free(section->protocol_domain); section->protocol_domain=str_dup_detached(arg); return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = domain for protocol negotiations", "protocolDomain"); break; } /* protocolHost */ switch(cmd) { case CMD_SET_DEFAULTS: section->protocol_host=NULL; break; case CMD_SET_COPY: section->protocol_host= str_dup_detached(new_service_options.protocol_host); break; case CMD_FREE: str_free(section->protocol_host); break; case CMD_SET_VALUE: if(strcasecmp(opt, "protocolHost")) break; str_free(section->protocol_host); section->protocol_host=str_dup_detached(arg); return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = host:port for protocol negotiations", "protocolHost"); break; } /* protocolPassword */ switch(cmd) { case CMD_SET_DEFAULTS: section->protocol_password=NULL; break; case CMD_SET_COPY: section->protocol_password= str_dup_detached(new_service_options.protocol_password); break; case CMD_FREE: str_free(section->protocol_password); break; case CMD_SET_VALUE: if(strcasecmp(opt, "protocolPassword")) break; str_free(section->protocol_password); section->protocol_password=str_dup_detached(arg); return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = password for protocol negotiations", "protocolPassword"); break; } /* protocolUsername */ switch(cmd) { case CMD_SET_DEFAULTS: section->protocol_username=NULL; break; case CMD_SET_COPY: section->protocol_username= str_dup_detached(new_service_options.protocol_username); break; case CMD_FREE: str_free(section->protocol_username); break; case CMD_SET_VALUE: if(strcasecmp(opt, "protocolUsername")) break; str_free(section->protocol_username); section->protocol_username=str_dup_detached(arg); return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = username for protocol negotiations", "protocolUsername"); break; } #ifndef OPENSSL_NO_PSK /* PSKidentity */ switch(cmd) { case CMD_SET_DEFAULTS: section->psk_identity=NULL; section->psk_selected=NULL; section->psk_sorted.val=NULL; section->psk_sorted.num=0; break; case CMD_SET_COPY: section->psk_identity= str_dup_detached(new_service_options.psk_identity); break; case CMD_FREE: str_free(section->psk_identity); str_free(section->psk_sorted.val); break; case CMD_SET_VALUE: if(strcasecmp(opt, "PSKidentity")) break; str_free(section->psk_identity); section->psk_identity=str_dup_detached(arg); return NULL; /* OK */ case CMD_INITIALIZE: 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_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = identity for PSK authentication", "PSKidentity"); break; } /* PSKsecrets */ switch(cmd) { case CMD_SET_DEFAULTS: section->psk_keys=NULL; break; case CMD_SET_COPY: section->psk_keys=psk_dup(new_service_options.psk_keys); break; case CMD_FREE: psk_free(section->psk_keys); break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_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_SET_DEFAULTS: section->option.pty=0; break; case CMD_SET_COPY: section->option.pty=new_service_options.option.pty; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = yes|no allocate pseudo terminal for 'exec' option", "pty"); break; } #endif /* redirect */ switch(cmd) { case CMD_SET_DEFAULTS: addrlist_clear(§ion->redirect_addr, 0); break; case CMD_SET_COPY: addrlist_clear(§ion->redirect_addr, 0); name_list_dup(§ion->redirect_addr.names, new_service_options.redirect_addr.names); break; case CMD_FREE: name_list_free(section->redirect_addr.names); str_free(section->redirect_addr.addr); break; case CMD_SET_VALUE: if(strcasecmp(opt, "redirect")) break; name_list_append(§ion->redirect_addr.names, arg); return NULL; /* OK */ case CMD_INITIALIZE: if(section->redirect_addr.names) { if(section->option.client) return "\"redirect\" is unsupported in client sections"; if(section->option.connect_before_ssl) return "\"redirect\" is incompatible with the specified protocol negotiation"; 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; section->redirect_addr.num=0; section->option.delayed_lookup=1; } if(!section->option.verify_chain && !section->option.verify_peer) return "Either \"verifyChain\" or \"verifyPeer\" has to be enabled for \"redirect\" to work"; } break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = [host:]port to redirect on authentication failures", "redirect"); break; } /* renegotiation */ switch(cmd) { case CMD_SET_DEFAULTS: section->option.renegotiation=1; break; case CMD_SET_COPY: section->option.renegotiation=new_service_options.option.renegotiation; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = yes|no support renegotiation", "renegotiation"); break; } /* requireCert */ switch(cmd) { case CMD_SET_DEFAULTS: section->option.require_cert=0; break; case CMD_SET_COPY: section->option.require_cert=new_service_options.option.require_cert; break; case CMD_FREE: break; case CMD_SET_VALUE: if(strcasecmp(opt, "requireCert")) break; if(!strcasecmp(arg, "yes")) { section->option.request_cert=1; section->option.require_cert=1; } else if(!strcasecmp(arg, "no")) { section->option.require_cert=0; } else { return "The argument needs to be either 'yes' or 'no'"; } return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = yes|no require client certificate", "requireCert"); break; } /* reset */ switch(cmd) { case CMD_SET_DEFAULTS: section->option.reset=1; /* enabled by default */ break; case CMD_SET_COPY: section->option.reset=new_service_options.option.reset; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = yes|no send TCP RST on error", "reset"); break; } /* retry */ switch(cmd) { case CMD_SET_DEFAULTS: section->option.retry=0; break; case CMD_SET_COPY: section->option.retry=new_service_options.option.retry; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = yes|no retry connect+exec section", "retry"); break; } #ifndef USE_WIN32 /* service */ switch(cmd) { case CMD_SET_DEFAULTS: section->servname=str_dup_detached("stunnel"); break; case CMD_SET_COPY: /* servname is *not* copied from the global section */ break; case CMD_FREE: /* deallocation is performed at the end CMD_FREE */ break; case CMD_SET_VALUE: if(strcasecmp(opt, "service")) break; str_free(section->servname); section->servname=str_dup_detached(arg); return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = service name", "service"); break; } #endif #ifndef USE_WIN32 /* setgid */ switch(cmd) { case CMD_SET_DEFAULTS: section->gid=0; break; case CMD_SET_COPY: section->gid=new_service_options.gid; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = groupname for setgid()", "setgid"); break; } #endif #ifndef USE_WIN32 /* setuid */ switch(cmd) { case CMD_SET_DEFAULTS: section->uid=0; break; case CMD_SET_COPY: section->uid=new_service_options.uid; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = username for setuid()", "setuid"); break; } #endif /* sessionCacheSize */ switch(cmd) { case CMD_SET_DEFAULTS: section->session_size=1000L; break; case CMD_SET_COPY: section->session_size=new_service_options.session_size; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: s_log(LOG_NOTICE, "%-22s = %ld", "sessionCacheSize", 1000L); break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = session cache size", "sessionCacheSize"); break; } /* sessionCacheTimeout */ switch(cmd) { case CMD_SET_DEFAULTS: section->session_timeout=300L; break; case CMD_SET_COPY: section->session_timeout=new_service_options.session_timeout; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: s_log(LOG_NOTICE, "%-22s = %ld seconds", "sessionCacheTimeout", 300L); break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = session cache timeout (in seconds)", "sessionCacheTimeout"); break; } /* sessiond */ switch(cmd) { case CMD_SET_DEFAULTS: section->option.sessiond=0; memset(§ion->sessiond_addr, 0, sizeof(SOCKADDR_UNION)); section->sessiond_addr.in.sin_family=AF_INET; break; case CMD_SET_COPY: section->option.sessiond=new_service_options.option.sessiond; memcpy(§ion->sessiond_addr, &new_service_options.sessiond_addr, sizeof(SOCKADDR_UNION)); break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = [host:]port use sessiond at host:port", "sessiond"); break; } #ifndef OPENSSL_NO_TLSEXT /* sni */ switch(cmd) { case CMD_SET_DEFAULTS: section->servername_list_head=NULL; section->servername_list_tail=NULL; break; case CMD_SET_COPY: section->sni= str_dup_detached(new_service_options.sni); break; case CMD_FREE: str_free(section->sni); sni_free(section); break; case CMD_SET_VALUE: if(strcasecmp(opt, "sni")) break; str_free(section->sni); section->sni=str_dup_detached(arg); return NULL; /* OK */ case CMD_INITIALIZE: { char *tmp_str=sni_init(section); if(tmp_str) return tmp_str; } if(!section->option.client && section->sni) ++endpoints; break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = master_service:host_name for an SNI virtual service", "sni"); break; } #endif /* !defined(OPENSSL_NO_TLSEXT) */ /* socket */ switch(cmd) { case CMD_SET_DEFAULTS: section->sock_opts=socket_options_init(); break; case CMD_SET_COPY: section->sock_opts=socket_options_dup(new_service_options.sock_opts); break; case CMD_FREE: socket_options_free(section->sock_opts); break; case CMD_SET_VALUE: if(strcasecmp(opt, "socket")) break; if(socket_option_parse(section->sock_opts, arg)) return "Illegal socket option"; return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_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; } #if OPENSSL_VERSION_NUMBER>=0x10100000L /* sslVersion */ switch(cmd) { case CMD_SET_DEFAULTS: /* handled in sslVersionMax and sslVersionMin */ break; case CMD_SET_COPY: /* handled in sslVersionMax and sslVersionMin */ break; case CMD_FREE: break; case CMD_SET_VALUE: if(strcasecmp(opt, "sslVersion")) break; section->max_proto_version= section->min_proto_version=str_to_proto_version(arg); if(section->max_proto_version==-1) return "Invalid protocol version"; return NULL; /* OK */ case CMD_INITIALIZE: if(section->max_proto_version && section->min_proto_version && section->max_proto_versionmin_proto_version) return "Invalid protocol version range"; break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = all" "|SSLv3|TLSv1|TLSv1.1|TLSv1.2" #ifdef TLS1_3_VERSION "|TLSv1.3" #endif " TLS version", "sslVersion"); break; } /* sslVersionMax */ switch(cmd) { case CMD_SET_DEFAULTS: section->max_proto_version=0; /* highest supported */ break; case CMD_SET_COPY: section->max_proto_version=new_service_options.max_proto_version; break; case CMD_FREE: break; case CMD_SET_VALUE: if(strcasecmp(opt, "sslVersionMax")) break; section->max_proto_version=str_to_proto_version(arg); if(section->max_proto_version==-1) return "Invalid protocol version"; return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = all" "|SSLv3|TLSv1|TLSv1.1|TLSv1.2" #ifdef TLS1_3_VERSION "|TLSv1.3" #endif " TLS version", "sslVersionMax"); break; } /* sslVersionMin */ switch(cmd) { case CMD_SET_DEFAULTS: section->min_proto_version=TLS1_VERSION; break; case CMD_SET_COPY: section->min_proto_version=new_service_options.min_proto_version; break; case CMD_FREE: break; case CMD_SET_VALUE: if(strcasecmp(opt, "sslVersionMin")) break; section->min_proto_version=str_to_proto_version(arg); if(section->min_proto_version==-1) return "Invalid protocol version"; return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = all" "|SSLv3|TLSv1|TLSv1.1|TLSv1.2" #ifdef TLS1_3_VERSION "|TLSv1.3" #endif " TLS version", "sslVersionMin"); break; } #else /* OPENSSL_VERSION_NUMBER<0x10100000L */ /* sslVersion */ switch(cmd) { case CMD_SET_DEFAULTS: tls_methods_set(section, NULL); break; case CMD_SET_COPY: section->client_method=new_service_options.client_method; section->server_method=new_service_options.server_method; break; case CMD_FREE: break; case CMD_SET_VALUE: if(strcasecmp(opt, "sslVersion")) break; return tls_methods_set(section, arg); case CMD_INITIALIZE: { char *tmp_str=tls_methods_check(section); if(tmp_str) return tmp_str; } break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = all" "|SSLv2|SSLv3|TLSv1" #if OPENSSL_VERSION_NUMBER>=0x10001000L "|TLSv1.1|TLSv1.2" #endif /* OPENSSL_VERSION_NUMBER>=0x10001000L */ " TLS method", "sslVersion"); break; } #endif /* OPENSSL_VERSION_NUMBER<0x10100000L */ #ifndef USE_FORK /* stack */ switch(cmd) { case CMD_SET_DEFAULTS: section->stack_size=DEFAULT_STACK_SIZE; break; case CMD_SET_COPY: section->stack_size=new_service_options.stack_size; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: s_log(LOG_NOTICE, "%-22s = %d bytes", "stack", DEFAULT_STACK_SIZE); break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = thread stack size (in bytes)", "stack"); break; } #endif #if OPENSSL_VERSION_NUMBER>=0x10000000L /* ticketKeySecret */ switch(cmd) { case CMD_SET_DEFAULTS: section->ticket_key=NULL; break; case CMD_SET_COPY: section->ticket_key=key_dup(new_service_options.ticket_key); break; case CMD_FREE: key_free(section->ticket_key); break; case CMD_SET_VALUE: if(strcasecmp(opt, "ticketKeySecret")) break; section->ticket_key=key_read(arg, "ticketKeySecret"); if(!section->ticket_key) return "Failed to read ticketKeySecret"; return NULL; /* OK */ case CMD_INITIALIZE: if(!section->ticket_key) /* ticketKeySecret not configured */ break; if(section->option.client){ s_log(LOG_NOTICE, "ticketKeySecret is ignored in the client mode"); break; } if(section->ticket_key && !section->ticket_mac) return "\"ticketKeySecret\" and \"ticketMacSecret\" must be set together"; break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = secret key for encryption/decryption TLSv1.3 tickets", "ticketKeySecret"); break; } /* ticketMacSecret */ switch(cmd) { case CMD_SET_DEFAULTS: section->ticket_mac=NULL; break; case CMD_SET_COPY: section->ticket_mac=key_dup(new_service_options.ticket_mac); break; case CMD_FREE: key_free(section->ticket_mac); break; case CMD_SET_VALUE: if(strcasecmp(opt, "ticketMacSecret")) break; section->ticket_mac=key_read(arg, "ticketMacSecret"); if(!section->ticket_mac) return "Failed to read ticketMacSecret"; return NULL; /* OK */ case CMD_INITIALIZE: if(!section->ticket_mac) /* ticketMacSecret not configured */ break; if(section->option.client){ s_log(LOG_NOTICE, "ticketMacSecret is ignored in the client mode"); break; } if(section->ticket_mac && !section->ticket_key) return "\"ticketKeySecret\" and \"ticketMacSecret\" must be set together"; break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = key for HMAC operations on TLSv1.3 tickets", "ticketMacSecret"); break; } #endif /* OpenSSL 1.0.0 or later */ /* TIMEOUTbusy */ switch(cmd) { case CMD_SET_DEFAULTS: section->timeout_busy=300; /* 5 minutes */ break; case CMD_SET_COPY: section->timeout_busy=new_service_options.timeout_busy; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: s_log(LOG_NOTICE, "%-22s = %d seconds", "TIMEOUTbusy", 300); break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = seconds to wait for expected data", "TIMEOUTbusy"); break; } /* TIMEOUTclose */ switch(cmd) { case CMD_SET_DEFAULTS: section->timeout_close=60; /* 1 minute */ break; case CMD_SET_COPY: section->timeout_close=new_service_options.timeout_close; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: s_log(LOG_NOTICE, "%-22s = %d seconds", "TIMEOUTclose", 60); break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = seconds to wait for close_notify", "TIMEOUTclose"); break; } /* TIMEOUTconnect */ switch(cmd) { case CMD_SET_DEFAULTS: section->timeout_connect=10; /* 10 seconds */ break; case CMD_SET_COPY: section->timeout_connect=new_service_options.timeout_connect; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: s_log(LOG_NOTICE, "%-22s = %d seconds", "TIMEOUTconnect", 10); break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = seconds to connect remote host", "TIMEOUTconnect"); break; } /* TIMEOUTidle */ switch(cmd) { case CMD_SET_DEFAULTS: section->timeout_idle=43200; /* 12 hours */ break; case CMD_SET_COPY: section->timeout_idle=new_service_options.timeout_idle; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: break; case CMD_PRINT_DEFAULTS: s_log(LOG_NOTICE, "%-22s = %d seconds", "TIMEOUTidle", 43200); break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = seconds to keep an idle connection", "TIMEOUTidle"); break; } /* transparent */ #ifndef USE_WIN32 switch(cmd) { case CMD_SET_DEFAULTS: section->option.transparent_src=0; section->option.transparent_dst=0; break; case CMD_SET_COPY: section->option.transparent_src=new_service_options.option.transparent_src; section->option.transparent_dst=new_service_options.option.transparent_dst; break; case CMD_FREE: break; case CMD_SET_VALUE: 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_INITIALIZE: if(section->option.transparent_dst) ++endpoints; break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = none|source|destination|both transparent proxy mode", "transparent"); break; } #endif /* verify */ switch(cmd) { case CMD_SET_DEFAULTS: section->option.request_cert=0; break; case CMD_SET_COPY: section->option.request_cert=new_service_options.option.request_cert; break; case CMD_FREE: break; case CMD_SET_VALUE: if(strcasecmp(opt, "verify")) break; { char *tmp_str; int tmp_int=(int)strtol(arg, &tmp_str, 10); if(tmp_str==arg || *tmp_str || tmp_int<0 || tmp_int>4) return "Bad verify level"; section->option.request_cert=1; section->option.require_cert=(tmp_int>=2); section->option.verify_chain=(tmp_int>=1 && tmp_int<=3); section->option.verify_peer=(tmp_int>=3); } return NULL; /* OK */ case CMD_INITIALIZE: if((section->option.verify_chain || section->option.verify_peer) && !section->ca_file && !section->ca_dir) return "Either \"CAfile\" or \"CApath\" has to be configured"; break; case CMD_PRINT_DEFAULTS: s_log(LOG_NOTICE, "%-22s = none", "verify"); break; case CMD_PRINT_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; } /* verifyChain */ switch(cmd) { case CMD_SET_DEFAULTS: section->option.verify_chain=0; break; case CMD_SET_COPY: section->option.verify_chain=new_service_options.option.verify_chain; break; case CMD_FREE: break; case CMD_SET_VALUE: if(strcasecmp(opt, "verifyChain")) break; if(!strcasecmp(arg, "yes")) { section->option.request_cert=1; section->option.require_cert=1; section->option.verify_chain=1; } else if(!strcasecmp(arg, "no")) { section->option.verify_chain=0; } else { return "The argument needs to be either 'yes' or 'no'"; } return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = yes|no verify certificate chain", "verifyChain"); break; } /* verifyPeer */ switch(cmd) { case CMD_SET_DEFAULTS: section->option.verify_peer=0; break; case CMD_SET_COPY: section->option.verify_peer=new_service_options.option.verify_peer; break; case CMD_FREE: break; case CMD_SET_VALUE: if(strcasecmp(opt, "verifyPeer")) break; if(!strcasecmp(arg, "yes")) { section->option.request_cert=1; section->option.require_cert=1; section->option.verify_peer=1; } else if(!strcasecmp(arg, "no")) { section->option.verify_peer=0; } else { return "The argument needs to be either 'yes' or 'no'"; } return NULL; /* OK */ case CMD_INITIALIZE: break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = yes|no verify peer certificate", "verifyPeer"); break; } /* final checks */ switch(cmd) { case CMD_SET_DEFAULTS: break; case CMD_SET_COPY: break; case CMD_FREE: str_free(section->chain); if(section->session) SSL_SESSION_free(section->session); if(section->ctx) SSL_CTX_free(section->ctx); str_free(section->servname); if(section==&service_options) memset(section, 0, sizeof(SERVICE_OPTIONS)); else str_free(section); break; case CMD_SET_VALUE: return option_not_found; case CMD_INITIALIZE: if(section!=&new_service_options) { /* 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->sni in inetd mode, as it requires valid sections to be set */ if(endpoints!=1) return "Inetd mode must define one endpoint"; } #ifdef SSL_OP_NO_TICKET /* disable RFC4507 support introduced in OpenSSL 0.9.8f */ /* OpenSSL 1.1.1 is required to serialize application data * into session tickets */ /* server mode sections need it for the "redirect" option * and connect address session persistence */ if(OpenSSL_version_num()<0x10101000L && !section->option.client && !section->option.connect_before_ssl) section->ssl_options_set|=SSL_OP_NO_TICKET; #endif /* SSL_OP_NO_TICKET */ if(context_init(section)) /* initialize TLS context */ return "Failed to initialize TLS context"; break; case CMD_PRINT_DEFAULTS: break; case CMD_PRINT_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_detached(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_detached(sizeof(SERVERNAME_LIST)); tmpsrv->ssl_options_set|= SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION; } /* a slave section reference is needed to prevent a race condition while switching to a section after configuration file reload */ service_up_ref(section); tmpsrv->servername_list_tail->servername=str_dup_detached(tmp_str); tmpsrv->servername_list_tail->opt=section; tmpsrv->servername_list_tail->next=NULL; /* always negotiate a new session on renegotiation, as the TLS * 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_detached(section->protocol_host); else if(section->connect_addr.names) /* 'connect' option */ section->sni=str_dup_detached(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_detached("localhost"); } } } return NULL; } NOEXPORT void sni_free(SERVICE_OPTIONS *section) { SERVERNAME_LIST *curr=section->servername_list_head; while(curr) { SERVERNAME_LIST *next=curr->next; str_free(curr->servername); service_free(curr->opt); /* free the slave section */ str_free(curr); curr=next; } section->servername_list_head=NULL; section->servername_list_tail=NULL; } #endif /* !defined(OPENSSL_NO_TLSEXT) */ /**************************************** modern TLS version handling */ #if OPENSSL_VERSION_NUMBER>=0x10100000L NOEXPORT int str_to_proto_version(const char *name) { if(!strcasecmp(name, "all")) return 0; if(!strcasecmp(name, "SSLv3")) return SSL3_VERSION; if(!strcasecmp(name, "TLSv1")) return TLS1_VERSION; if(!strcasecmp(name, "TLSv1.1")) return TLS1_1_VERSION; if(!strcasecmp(name, "TLSv1.2")) return TLS1_2_VERSION; #ifdef TLS1_3_VERSION if(!strcasecmp(name, "TLSv1.3")) return TLS1_3_VERSION; #endif return -1; } /**************************************** deprecated TLS version handling */ #else /* OPENSSL_VERSION_NUMBER<0x10100000L */ #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif /* __GNUC__ */ NOEXPORT char *tls_methods_set(SERVICE_OPTIONS *section, const char *arg) { if(!arg) { /* defaults */ section->client_method=(SSL_METHOD *)SSLv23_client_method(); section->server_method=(SSL_METHOD *)SSLv23_server_method(); } else if(!strcasecmp(arg, "all")) { section->client_method=(SSL_METHOD *)SSLv23_client_method(); section->server_method=(SSL_METHOD *)SSLv23_server_method(); } 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 /* OPENSSL_NO_SSL2 */ return "SSLv2 not supported"; #endif /* !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 /* OPENSSL_NO_SSL3 */ return "SSLv3 not supported"; #endif /* !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 /* OPENSSL_NO_TLS1 */ return "TLSv1 not supported"; #endif /* !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 /* OPENSSL_NO_TLS1_1 */ return "TLSv1.1 not supported"; #endif /* !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 /* OPENSSL_NO_TLS1_2 */ return "TLSv1.2 not supported"; #endif /* !OPENSSL_NO_TLS1_2 */ } else return "Incorrect version of TLS protocol"; return NULL; /* OK */ } NOEXPORT char *tls_methods_check(SERVICE_OPTIONS *section) { (void)section; /* squash the unused parameter warning */ #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 /* !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 /* !OPENSSL_NO_SSL3 */ } #endif /* USE_FIPS */ return NULL; } #ifdef __GNUC__ #pragma GCC diagnostic pop #endif /* __GNUC__ */ #endif /* OPENSSL_VERSION_NUMBER<0x10100000L */ /**************************************** facility/debug level */ typedef struct { char *name; int value; } facilitylevel; NOEXPORT char *parse_debug_level(char *arg, SERVICE_OPTIONS *section) { 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} }; /* facilities only make sense on Unix */ #if !defined (USE_WIN32) && !defined (__vms) if(section==&new_service_options && strchr(arg, '.')) { /* a facility was specified in the global options */ new_global_options.log_facility=-1; arg=strtok(arg, "."); /* break it up */ for(fl=facilities; fl->name; ++fl) { if(!strcasecmp(fl->name, arg)) { new_global_options.log_facility=fl->value; break; } } if(new_global_options.log_facility==-1) return "Illegal syslog facility"; arg=strtok(NULL, "."); /* set to the remainder */ } #endif /* USE_WIN32, __vms */ /* time to check the syslog level */ if(arg && strlen(arg)==1 && *arg>='0' && *arg<='7') { section->log_level=*arg-'0'; return NULL; /* OK */ } section->log_level=8; /* illegal level */ for(fl=levels; fl->name; ++fl) { if(!strcasecmp(fl->name, arg)) { section->log_level=fl->value; break; } } if(section->log_level==8) return "Illegal debug level"; /* FAILED */ return NULL; /* OK */ } /**************************************** TLS 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 INVALID_SSL_OPTION; /* FAILED */ } NOEXPORT void print_ssl_options(void) { SSL_OPTION *option; s_log(LOG_NOTICE, " "); s_log(LOG_NOTICE, "Supported TLS 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_str; unsigned char *key_buf; long 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_str=strchr(line, ':'); if(!key_str) { s_log(LOG_ERR, "PSKsecrets line %d: Not in identity:key format", line_number); file_close(df); psk_free(head); return NULL; } *key_str++='\0'; 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; } key_buf=OPENSSL_hexstr2buf(key_str, &key_len); if(key_buf) { /* a valid hexadecimal value */ s_log(LOG_INFO, "PSKsecrets line %d: " "%ld-byte hexadecimal key configured for identity \"%s\"", line_number, key_len, line); } else { /* not a valid hexadecimal value -> copy as a string */ key_len=(long)strlen(key_str); key_buf=OPENSSL_malloc((size_t)key_len); memcpy(key_buf, key_str, (size_t)key_len); s_log(LOG_INFO, "PSKsecrets line %d: " "%ld-byte ASCII key configured for identity \"%s\"", line_number, key_len, line); } if(key_len>PSK_MAX_PSK_LEN) { s_log(LOG_ERR, "PSKsecrets line %d: Key longer than %d bytes", line_number, PSK_MAX_PSK_LEN); OPENSSL_free(key_buf); file_close(df); psk_free(head); return NULL; } if(key_len<16) { /* shorter keys are unlikely to have sufficient entropy */ s_log(LOG_ERR, "PSKsecrets line %d: Key shorter than 16 bytes", line_number); OPENSSL_free(key_buf); file_close(df); psk_free(head); return NULL; } curr=str_alloc_detached(sizeof(PSK_KEYS)); curr->identity=str_dup_detached(line); curr->key_val=str_alloc_detached((size_t)key_len); memcpy(curr->key_val, key_buf, (size_t)key_len); OPENSSL_free(key_buf); curr->key_len=(unsigned)key_len; curr->next=NULL; if(head) tail->next=curr; else head=curr; tail=curr; } file_close(df); return head; } NOEXPORT PSK_KEYS *psk_dup(PSK_KEYS *src) { PSK_KEYS *head=NULL, *tail=NULL, *curr; for(; src; src=src->next) { curr=str_alloc_detached(sizeof(PSK_KEYS)); curr->identity=str_dup_detached(src->identity); curr->key_val=str_alloc_detached(src->key_len); memcpy(curr->key_val, src->key_val, src->key_len); curr->key_len=src->key_len; curr->next=NULL; if(head) tail->next=curr; else head=curr; tail=curr; } return head; } NOEXPORT void psk_free(PSK_KEYS *head) { while(head) { PSK_KEYS *next=head->next; str_free(head->identity); str_free(head->key_val); str_free(head); head=next; } } #endif /**************************************** read ticket key */ #if OPENSSL_VERSION_NUMBER>=0x10000000L NOEXPORT TICKET_KEY *key_read(char *arg, char *option) { char *key_str; unsigned char *key_buf; long key_len; TICKET_KEY *head=NULL; key_str=str_dup_detached(arg); key_buf=OPENSSL_hexstr2buf(key_str, &key_len); if(key_buf) if((key_len == 16) || (key_len == 32)) /* a valid 16 or 32 byte hexadecimal value */ s_log(LOG_INFO, "%s configured", option); else { /* not a valid length */ s_log(LOG_ERR, "%s value has %ld bytes instead of required 16 or 32 bytes", option, key_len); OPENSSL_free(key_buf); key_free(head); return NULL; } else { /* not a valid hexadecimal form */ s_log(LOG_ERR, "Required %s is 16 or 32 byte hexadecimal key", option); key_free(head); return NULL; } head=str_alloc_detached(sizeof(TICKET_KEY)); head->key_val=str_alloc_detached((size_t)key_len); memcpy(head->key_val, key_buf, (size_t)key_len); OPENSSL_free(key_buf); head->key_len=(int)key_len; return head; } NOEXPORT TICKET_KEY *key_dup(TICKET_KEY *src) { TICKET_KEY *head=NULL; if (src) { head=str_alloc_detached(sizeof(TICKET_KEY)); head->key_val=(unsigned char *)str_dup_detached((char *)src->key_val); head->key_len=src->key_len; } return head; } NOEXPORT void key_free(TICKET_KEY *head) { if (head) { str_free(head->key_val); str_free(head); } } #endif /* OpenSSL 1.0.0 or later */ /**************************************** socket options */ #define VAL_TAB {NULL, NULL, NULL} SOCK_OPT sock_opts_def[]={ {"SO_DEBUG", SOL_SOCKET, SO_DEBUG, TYPE_FLAG, VAL_TAB}, {"SO_DONTROUTE", SOL_SOCKET, SO_DONTROUTE, TYPE_FLAG, VAL_TAB}, {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, TYPE_FLAG, VAL_TAB}, {"SO_LINGER", SOL_SOCKET, SO_LINGER, TYPE_LINGER, VAL_TAB}, {"SO_OOBINLINE", SOL_SOCKET, SO_OOBINLINE, TYPE_FLAG, VAL_TAB}, {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, TYPE_INT, VAL_TAB}, {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, TYPE_INT, VAL_TAB}, #ifdef SO_RCVLOWAT {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, TYPE_INT, VAL_TAB}, #endif #ifdef SO_SNDLOWAT {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, TYPE_INT, VAL_TAB}, #endif #ifdef SO_RCVTIMEO {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, TYPE_TIMEVAL, VAL_TAB}, #endif #ifdef SO_SNDTIMEO {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, TYPE_TIMEVAL, VAL_TAB}, #endif #ifdef USE_WIN32 {"SO_EXCLUSIVEADDRUSE", SOL_SOCKET, SO_EXCLUSIVEADDRUSE, TYPE_FLAG, VAL_TAB}, #endif {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, TYPE_FLAG, VAL_TAB}, #ifdef SO_BINDTODEVICE {"SO_BINDTODEVICE", SOL_SOCKET, SO_BINDTODEVICE, TYPE_STRING, VAL_TAB}, #endif #ifdef SOL_TCP #ifdef TCP_KEEPCNT {"TCP_KEEPCNT", SOL_TCP, TCP_KEEPCNT, TYPE_INT, VAL_TAB}, #endif #ifdef TCP_KEEPIDLE {"TCP_KEEPIDLE", SOL_TCP, TCP_KEEPIDLE, TYPE_INT, VAL_TAB}, #endif #ifdef TCP_KEEPINTVL {"TCP_KEEPINTVL", SOL_TCP, TCP_KEEPINTVL, TYPE_INT, VAL_TAB}, #endif #endif /* SOL_TCP */ #ifdef IP_TOS {"IP_TOS", IPPROTO_IP, IP_TOS, TYPE_INT, VAL_TAB}, #endif #ifdef IP_TTL {"IP_TTL", IPPROTO_IP, IP_TTL, TYPE_INT, VAL_TAB}, #endif #ifdef IP_MAXSEG {"TCP_MAXSEG", IPPROTO_TCP, TCP_MAXSEG, TYPE_INT, VAL_TAB}, #endif {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, TYPE_FLAG, VAL_TAB}, #ifdef IP_FREEBIND {"IP_FREEBIND", IPPROTO_IP, IP_FREEBIND, TYPE_FLAG, VAL_TAB}, #endif #ifdef IP_BINDANY {"IP_BINDANY", IPPROTO_IP, IP_BINDANY, TYPE_FLAG, VAL_TAB}, #endif #ifdef IPV6_BINDANY {"IPV6_BINDANY", IPPROTO_IPV6, IPV6_BINDANY, TYPE_FLAG, VAL_TAB}, #endif #ifdef IPV6_V6ONLY {"IPV6_V6ONLY", IPPROTO_IPV6, IPV6_V6ONLY, TYPE_FLAG, VAL_TAB}, #endif {NULL, 0, 0, TYPE_NONE, VAL_TAB} }; NOEXPORT SOCK_OPT *socket_options_init(void) { #ifdef USE_WIN32 DWORD version; int major, minor; #endif SOCK_OPT *opt=str_alloc_detached(sizeof sock_opts_def); memcpy(opt, sock_opts_def, sizeof sock_opts_def); #ifdef USE_WIN32 version=GetVersion(); major=LOBYTE(LOWORD(version)); minor=HIBYTE(LOWORD(version)); s_log(LOG_DEBUG, "Running on Windows %d.%d", major, minor); if(major>5) /* Vista or later */ socket_option_set_int(opt, "SO_EXCLUSIVEADDRUSE", 0, 1); /* accepting socket */ #else socket_option_set_int(opt, "SO_REUSEADDR", 0, 1); /* accepting socket */ #endif socket_option_set_int(opt, "TCP_NODELAY", 1, 1); /* local socket */ socket_option_set_int(opt, "TCP_NODELAY", 2, 1); /* remote socket */ return opt; } NOEXPORT void socket_option_set_int(SOCK_OPT *opt, char *name, int type, int value) { for(; opt->opt_str; ++opt) { if(!strcmp(name, opt->opt_str)) { opt->opt_val[type]=str_alloc_detached(sizeof(OPT_UNION)); opt->opt_val[type]->i_val=value; } } } NOEXPORT SOCK_OPT *socket_options_dup(SOCK_OPT *src) { SOCK_OPT *dst=str_alloc_detached(sizeof sock_opts_def); SOCK_OPT *ptr; memcpy(dst, sock_opts_def, sizeof sock_opts_def); for(ptr=dst; src->opt_str; ++src, ++ptr) { int type; for(type=0; type<3; ++type) { if(src->opt_val[type]) { ptr->opt_val[type]=str_alloc_detached(sizeof(OPT_UNION)); memcpy(ptr->opt_val[type], src->opt_val[type], sizeof(OPT_UNION)); } } } return dst; } NOEXPORT void socket_options_free(SOCK_OPT *opt) { SOCK_OPT *ptr; if(!opt) { s_log(LOG_ERR, "INTERNAL ERROR: Socket options not initialized"); return; } for(ptr=opt; ptr->opt_str; ++ptr) { int type; for(type=0; type<3; ++type) str_free(ptr->opt_val[type]); } str_free(opt); } NOEXPORT int socket_options_print(void) { SOCK_OPT *opt, *ptr; SOCKET fd; socklen_t optlen; OPT_UNION val; char *ta, *tl, *tr, *td; fd=socket(AF_INET, SOCK_STREAM, 0); opt=socket_options_init(); 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=opt; ptr->opt_str; ++ptr) { /* get OS default value */ optlen=sizeof val; if(getsockopt(fd, ptr->opt_level, ptr->opt_name, (void *)&val, &optlen)) { switch(get_last_socket_error()) { case S_ENOPROTOOPT: case S_EOPNOTSUPP: td=str_dup("write-only"); break; default: s_log(LOG_ERR, "Failed to get %s OS default", ptr->opt_str); sockerror("getsockopt"); closesocket(fd); return 1; /* FAILED */ } } else td=socket_option_text(ptr->opt_type, &val); /* get stunnel default values */ ta=socket_option_text(ptr->opt_type, ptr->opt_val[0]); tl=socket_option_text(ptr->opt_type, ptr->opt_val[1]); tr=socket_option_text(ptr->opt_type, ptr->opt_val[2]); /* print collected data and fee the memory */ s_log(LOG_NOTICE, " %-20s|%10s|%10s|%10s|%10s", ptr->opt_str, ta, tl, tr, td); str_free(ta); str_free(tl); str_free(tr); str_free(td); } socket_options_free(opt); closesocket(fd); return 0; /* OK */ } NOEXPORT char *socket_option_text(VAL_TYPE 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); case TYPE_NONE: return str_dup(" none "); /* internal error? */ } return str_dup(" Ooops? "); /* internal error? */ } NOEXPORT int socket_option_parse(SOCK_OPT *opt, char *arg) { int socket_type; /* 0-accept, 1-local, 2-remote */ char *opt_val_str, *opt_val2_str, *tmp_str; OPT_UNION opt_val; 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'; for(; opt->opt_str && strcmp(arg, opt->opt_str); ++opt) ; if(!opt->opt_str) return 1; /* FAILED */ switch(opt->opt_type) { case TYPE_FLAG: if(!strcasecmp(opt_val_str, "yes") || !strcmp(opt_val_str, "1")) { opt_val.i_val=1; break; /* OK */ } if(!strcasecmp(opt_val_str, "no") || !strcmp(opt_val_str, "0")) { opt_val.i_val=0; break; /* OK */ } return 1; /* FAILED */ case TYPE_INT: opt_val.i_val=(int)strtol(opt_val_str, &tmp_str, 10); if(tmp_str==arg || *tmp_str) /* not a number */ return 1; /* FAILED */ break; /* OK */ case TYPE_LINGER: opt_val2_str=strchr(opt_val_str, ':'); if(opt_val2_str) { *opt_val2_str++='\0'; opt_val.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 { opt_val.linger_val.l_linger=0; } opt_val.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 */ break; /* OK */ case TYPE_TIMEVAL: opt_val2_str=strchr(opt_val_str, ':'); if(opt_val2_str) { *opt_val2_str++='\0'; opt_val.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 { opt_val.timeval_val.tv_usec=0; } opt_val.timeval_val.tv_sec= (int)strtol(opt_val_str, &tmp_str, 10); if(tmp_str==arg || *tmp_str) /* not a number */ return 1; /* FAILED */ break; /* OK */ case TYPE_STRING: if(strlen(opt_val_str)+1>sizeof(OPT_UNION)) return 1; /* FAILED */ strcpy(opt_val.c_val, opt_val_str); break; /* OK */ default: return 1; /* FAILED */ } str_free(opt->opt_val[socket_type]); opt->opt_val[socket_type]=str_alloc_detached(sizeof(OPT_UNION)); memcpy(opt->opt_val[socket_type], &opt_val, sizeof(OPT_UNION)); return 0; } /**************************************** 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; if(ENGINE_ctrl(engines[current_engine], ENGINE_CTRL_SET_USER_INTERFACE, 0, UI_stunnel(), NULL)) { s_log(LOG_NOTICE, "UI set for engine #%d (%s)", current_engine+1, ENGINE_get_id(engines[current_engine])); } else { ERR_clear_error(); s_log(LOG_INFO, "UI not supported by engine #%d (%s)", current_engine+1, ENGINE_get_id(engines[current_engine])); } 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 /* engines can add new algorithms */ #if OPENSSL_VERSION_NUMBER>=0x10100000L OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS| OPENSSL_INIT_ADD_ALL_DIGESTS, NULL); #else OpenSSL_add_all_algorithms(); #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) */ /**************************************** include config directory */ NOEXPORT char *include_config(char *directory, SERVICE_OPTIONS **section_ptr) { struct dirent **namelist; int i, num, err=0; num=scandir(directory, &namelist, NULL, alphasort); if(num<0) { ioerror("scandir"); return "Failed to include directory"; } for(i=0; id_name); if(!stat(name, &sb) && S_ISREG(sb.st_mode)) err=options_file(name, CONF_FILE, section_ptr); else s_log(LOG_DEBUG, "\"%s\" is not a file", name); str_free(name); } free(namelist[i]); } free(namelist); if(err) return "Failed to include a file"; return NULL; } /**************************************** 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 | -start | -stop | -reload | -reopen | -exit] " #endif "[-quiet] " #endif "[] ] " #ifndef USE_WIN32 "-fd " #endif "| -help | -version | -sockets | -options"); 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, " -start - start NT service"); s_log(LOG_NOTICE, " -stop - stop NT service"); s_log(LOG_NOTICE, " -reload - reload configuration for NT service"); s_log(LOG_NOTICE, " -reopen - reopen log file for NT service"); s_log(LOG_NOTICE, " -exit - exit an already started stunnel"); #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"); s_log(LOG_NOTICE, " -options - display supported TLS 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_detached(sizeof(NAME_LIST)); (*ptr)->name=str_dup_detached(name); (*ptr)->next=NULL; } NOEXPORT void name_list_dup(NAME_LIST **dst, NAME_LIST *src) { for(; src; src=src->next) name_list_append(dst, src->name); } NOEXPORT void name_list_free(NAME_LIST *ptr) { while(ptr) { NAME_LIST *next=ptr->next; str_free(ptr->name); str_free(ptr); ptr=next; } } #ifndef USE_WIN32 /* allocate 'exec' arguments */ /* TODO: support quotes */ NOEXPORT char **arg_alloc(char *str) { size_t max_arg, i; char **tmp, **retval; max_arg=strlen(str)/2+1; tmp=str_alloc((max_arg+1)*sizeof(char *)); i=0; while(*str && 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) #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpragmas" #pragma GCC diagnostic ignored "-Wcast-function-type" #endif /* __GNUC__ */ 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 */ } #ifdef __GNUC__ #pragma GCC diagnostic pop #endif /* __GNUC__ */ #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 num; addr_list=str_alloc(sizeof(SOCKADDR_LIST)); addrlist_clear(addr_list, passive); num=hostport2addrlist(addr_list, host_name, port_name); if(num) addrlist2addr(addr, addr_list); str_free(addr_list->addr); str_free(addr_list); return num; } 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 (currently 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 num; /* 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_detached(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); ++(addr_list->num); return 1; /* ok - return the number of new 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 */ num=hostport2addrlist(addr_list, host_name, port_name); str_free(tmp); return num; /* ok - return the number of new addresses */ } unsigned hostport2addrlist(SOCKADDR_LIST *addr_list, char *host_name, char *port_name) { struct addrinfo hints, *res, *cur; int err, retry=0; unsigned num; 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_flags|=AI_PASSIVE; #ifdef AI_ADDRCONFIG hints.ai_flags|=AI_ADDRCONFIG; #endif for(;;) { res=NULL; err=getaddrinfo(host_name, port_name, &hints, &res); if(!err) /* success */ break; if(err==EAI_SERVICE) { s_log(LOG_ERR, "Unknown TCP service \"%s\"", port_name); return 0; /* error */ } if(err==EAI_AGAIN && ++retry<=3) { s_log(LOG_DEBUG, "getaddrinfo: EAI_AGAIN received: retrying"); s_poll_sleep(1, 0); continue; } #ifdef AI_ADDRCONFIG if(hints.ai_flags&AI_ADDRCONFIG) { hints.ai_flags&=~AI_ADDRCONFIG; continue; /* retry for unconfigured network interfaces */ } #endif 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 */ } /* find the number of newly resolved addresses */ num=0; 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 */ } ++num; } /* append the newly resolved addresses to addr_list->addr */ addr_list->addr=str_realloc_detached(addr_list->addr, (addr_list->num+num)*sizeof(SOCKADDR_UNION)); for(cur=res; cur; cur=cur->ai_next) memcpy(&addr_list->addr[(addr_list->num)++], cur->ai_addr, (size_t)cur->ai_addrlen); freeaddrinfo(res); return num; /* ok - return the number of new 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->start=0; addr_list->parent=addr_list; /* allow a copy to locate its parent */ } 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_detached(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=0; NAME_LIST *host; addrlist_reset(addr_list); for(host=addr_list->names; host; host=host->next) num+=name2addrlist(addr_list, host->name); if(num<2) { addr_list->start=0; } else { /* 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->start=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) { switch(addr->sa.sa_family) { case AF_UNSPEC: /* 0 */ return 0; case AF_INET: /* 2 (almost universally) */ return sizeof(struct sockaddr_in); #ifdef USE_IPv6 case AF_INET6: return sizeof(struct sockaddr_in6); #endif #ifdef HAVE_STRUCT_SOCKADDR_UN case 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_THREAD_write_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_THREAD_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 */ /* inet_ntoa is not mt-safe */ CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_INET]); strncpy(host, inet_ntoa(((struct sockaddr_in *)sa)->sin_addr), hostlen); CRYPTO_THREAD_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.56/src/version.h0000664000175000017500000000701713527755760012537 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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 56 /* 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.56/src/active.ico0000664000175000017500000000217612634035772012641 00000000000000 h(   #` # # # # # # #` # # #:1g o:1 # # # # # #{^׀׀g # # # # #nU`p{^ # # #` # #-(! # #` # #TCTC # # # #{^0@g # # # #TC ׀׀ nU # # # #:1:1 # # # # #x x # # # # # #-(!ȓȓ-(! # # # #` # # #-(!g՜՜g-(! # # # #` # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #` # # # # # # #`stunnel-5.56/src/pty.c0000664000175000017500000001477113467064764011666 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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 descriptors */ if(max_fds && max_fds<16) max_fds=16; if(max_fds) { max_clients=(int)(max_fds>=256 ? max_fds*125/256 : (max_fds-6)/2); s_log(LOG_DEBUG, "Clients allowed=%d", 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=%ld out of range (max %d)", msg, (long)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=%ld allocated (%sblocking mode)", msg, (long)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.56/src/log.c0000664000175000017500000004326013467064764011626 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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_queue(SERVICE_OPTIONS *, int, char *, char *, char *); NOEXPORT void log_raw(SERVICE_OPTIONS *, int, char *, char *, 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 log_mode=LOG_MODE_BUFFER; #if !defined(USE_WIN32) && !defined(__vms) static int syslog_opened=0; NOEXPORT void syslog_open(void) { if(global_options.option.log_syslog) { static char *servname=NULL; char *servname_old; /* openlog(3) requires a persistent copy of the "ident" parameter */ servname_old=servname; servname=str_dup(service_options.servname); #ifdef __ultrix__ openlog(servname, 0); #else openlog(servname, LOG_CONS|LOG_NDELAY, global_options.log_facility); #endif /* __ultrix__ */ str_free(servname_old); } syslog_opened=1; } NOEXPORT void syslog_close(void) { if(syslog_opened) { if(global_options.option.log_syslog) closelog(); syslog_opened=0; } } #endif /* !defined(USE_WIN32) && !defined(__vms) */ NOEXPORT int outfile_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; } } return 0; } NOEXPORT void outfile_close(void) { if(outfile) { file_close(outfile); outfile=NULL; } } int log_open(int sink) { #if !defined(USE_WIN32) && !defined(__vms) if(sink&SINK_SYSLOG) syslog_open(); #endif if(sink&SINK_OUTFILE && outfile_open()) return 1; return 0; } void log_close(int sink) { /* prevent changing the mode while logging */ CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_LOG_MODE]); #if !defined(USE_WIN32) && !defined(__vms) if(sink&SINK_SYSLOG) syslog_close(); #endif if(sink&SINK_OUTFILE) outfile_close(); CRYPTO_THREAD_unlock(stunnel_locks[LOCK_LOG_MODE]); } void s_log(int level, const char *format, ...) { va_list ap; char *text, *stamp, *id; #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; libc_error=get_last_error(); socket_error=get_last_socket_error(); 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(log_mode!=LOG_MODE_CONFIGURED || level<=tls_data->opt->log_level) { /* 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); /* either log or queue for logging */ CRYPTO_THREAD_read_lock(stunnel_locks[LOCK_LOG_MODE]); if(log_mode==LOG_MODE_BUFFER) log_queue(tls_data->opt, level, stamp, id, text); else log_raw(tls_data->opt, level, stamp, id, text); CRYPTO_THREAD_unlock(stunnel_locks[LOCK_LOG_MODE]); } set_last_error(libc_error); set_last_socket_error(socket_error); } NOEXPORT void log_queue(SERVICE_OPTIONS *opt, int level, char *stamp, char *id, char *text) { struct LIST *tmp; /* make a new element */ tmp=str_alloc_detached(sizeof(struct LIST)); tmp->next=NULL; tmp->opt=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); /* append the new element to the list */ CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_LOG_BUFFER]); if(tail) tail->next=tmp; else head=tmp; tail=tmp; if(stunnel_locks[LOCK_LOG_BUFFER]) CRYPTO_THREAD_unlock(stunnel_locks[LOCK_LOG_BUFFER]); } void log_flush(LOG_MODE new_mode) { CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_LOG_MODE]); /* prevent changing LOG_MODE_CONFIGURED to LOG_MODE_ERROR * once stderr file descriptor is closed */ if(log_mode!=LOG_MODE_CONFIGURED || new_mode!=LOG_MODE_ERROR) log_mode=new_mode; /* emit the buffered logs (unless we just started buffering) */ if(new_mode!=LOG_MODE_BUFFER) { /* log_raw() will use the new value of log_mode */ CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_LOG_BUFFER]); while(head) { struct LIST *tmp=head; head=head->next; log_raw(tmp->opt, tmp->level, tmp->stamp, tmp->id, tmp->text); str_free(tmp); } head=tail=NULL; CRYPTO_THREAD_unlock(stunnel_locks[LOCK_LOG_BUFFER]); } CRYPTO_THREAD_unlock(stunnel_locks[LOCK_LOG_MODE]); } NOEXPORT void log_raw(SERVICE_OPTIONS *opt, int level, char *stamp, char *id, char *text) { char *line; /* NOTE: opt->log_level may have changed since s_log(). * It is important to use the new value and not the old one. */ /* build the line and log it to syslog/file if configured */ switch(log_mode) { case LOG_MODE_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); } break; case LOG_MODE_ERROR: /* don't log the id or the time stamp */ if(level>=0 && level<=7) /* just in case */ line=str_printf("[%c] %s", "***!:. "[level], text); else line=str_printf("[?] %s", text); break; default: /* LOG_MODE_INFO */ /* don't log the level, the id or the time stamp */ line=str_dup(text); } /* free the memory */ str_free(stamp); str_free(id); str_free(text); /* log the line to the UI (GUI, stderr, etc.) */ if(log_mode==LOG_MODE_ERROR || (log_mode==LOG_MODE_INFO && levellog_level #else (level<=opt->log_level && opt->option.log_stderr) #endif ) ui_new_log(line); str_free(line); } #ifdef __GNUC__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic push #endif /* __GNUC__>=4.6 */ #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: memset(rnd, 0, sizeof rnd); 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; i 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic pop #endif /* __GNUC__>=4.6 */ #endif /* __GNUC__ */ /* critical problem handling */ /* str.c functions are not safe to use here */ #ifdef __GNUC__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-result" #endif /* __GNUC__>=4.6 */ #endif /* __GNUC__ */ void fatal_debug(char *txt, const char *file, int line) { char msg[80]; #ifdef USE_WIN32 DWORD num; #ifdef UNICODE TCHAR tmsg[80]; #endif #endif /* USE_WIN32 */ snprintf(msg, sizeof msg, /* with newline */ "INTERNAL ERROR: %s at %s, line %d\n", txt, file, line); if(outfile) { #ifdef USE_WIN32 WriteFile(outfile->fh, 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(log_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__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic pop #endif /* __GNUC__>=4.6 */ #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='.'; } /* provide hex string corresponding to the input string * will be NULL terminated */ void bin2hexstring(const unsigned char *in_data, size_t in_size, char *out_data, size_t out_size) { const char hex[16]="0123456789ABCDEF"; size_t i; for(i=0; i>4]; out_data[2*i+1]=hex[in_data[i]&0x0f]; } out_data[2*i]='\0'; } /* end of log.c */ stunnel-5.56/src/ctx.c0000664000175000017500000015023513554262513011631 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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" SERVICE_OPTIONS *current_section=NULL; /* try an empty passphrase first */ static char cached_passwd[PEM_BUFSIZE]=""; static int cached_len=0; #ifndef OPENSSL_NO_DH DH *dh_params=NULL; int dh_temp_params=0; #endif /* OPENSSL_NO_DH */ /**************************************** prototypes */ /* SNI */ #ifndef OPENSSL_NO_TLSEXT NOEXPORT int servername_cb(SSL *, int *, void *); NOEXPORT int matches_wildcard(const char *, const 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 *); NOEXPORT int pkcs12_extension(const char *); NOEXPORT int load_pkcs12_file(SERVICE_OPTIONS *); #ifndef OPENSSL_NO_ENGINE NOEXPORT int load_cert_engine(SERVICE_OPTIONS *); NOEXPORT int load_key_engine(SERVICE_OPTIONS *); #endif NOEXPORT int cache_passwd_get_cb(char *, int, int, void *); NOEXPORT int cache_passwd_set_cb(char *, int, int, void *); NOEXPORT void set_prompt(const char *); NOEXPORT int ui_retry(); /* session tickets */ #if OPENSSL_VERSION_NUMBER >= 0x10101000L NOEXPORT int generate_session_ticket_cb(SSL *, void *); NOEXPORT int decrypt_session_ticket_cb(SSL *, SSL_SESSION *, const unsigned char *, size_t, SSL_TICKET_STATUS, void *); #endif /* OpenSSL 1.1.1 or later */ #if OPENSSL_VERSION_NUMBER>=0x10000000L NOEXPORT int ssl_tlsext_ticket_key_cb(SSL *, unsigned char *, unsigned char *, EVP_CIPHER_CTX *, HMAC_CTX *, int); #endif /* OpenSSL 1.0.0 or later */ /* session callbacks */ NOEXPORT int sess_new_cb(SSL *, SSL_SESSION *); NOEXPORT void new_chain(CLI *); NOEXPORT void session_cache_save(CLI *, SSL_SESSION *); NOEXPORT SSL_SESSION *sess_get_cb(SSL *, #if OPENSSL_VERSION_NUMBER>=0x10100000L const #endif 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 *, const 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, const char *, int, char *); /**************************************** initialize section->ctx */ #if OPENSSL_VERSION_NUMBER>=0x10100000L typedef long unsigned SSL_OPTIONS_TYPE; #else typedef long SSL_OPTIONS_TYPE; #endif int context_init(SERVICE_OPTIONS *section) { /* init TLS context */ /* create TLS context */ #if OPENSSL_VERSION_NUMBER>=0x10100000L if(section->option.client) section->ctx=SSL_CTX_new(TLS_client_method()); else /* server mode */ section->ctx=SSL_CTX_new(TLS_server_method()); if(!SSL_CTX_set_min_proto_version(section->ctx, section->min_proto_version)) { s_log(LOG_ERR, "Failed to set the minimum protocol version 0x%X", section->min_proto_version); return 1; /* FAILED */ } if(!SSL_CTX_set_max_proto_version(section->ctx, section->max_proto_version)) { s_log(LOG_ERR, "Failed to set the maximum protocol version 0x%X", section->max_proto_version); return 1; /* FAILED */ } #else /* OPENSSL_VERSION_NUMBER<0x10100000L */ if(section->option.client) section->ctx=SSL_CTX_new(section->client_method); else /* server mode */ section->ctx=SSL_CTX_new(section->server_method); #endif /* OPENSSL_VERSION_NUMBER<0x10100000L */ if(!section->ctx) { sslerror("SSL_CTX_new"); return 1; /* FAILED */ } /* for callbacks */ if(!SSL_CTX_set_ex_data(section->ctx, index_ssl_ctx_opt, section)) { sslerror("SSL_CTX_set_ex_data"); return 1; /* FAILED */ } current_section=section; /* setup current section for callbacks */ /* ciphers */ if(section->cipher_list) { s_log(LOG_DEBUG, "Ciphers: %s", section->cipher_list); if(!SSL_CTX_set_cipher_list(section->ctx, section->cipher_list)) { sslerror("SSL_CTX_set_cipher_list"); return 1; /* FAILED */ } } #ifndef OPENSSL_NO_TLS1_3 /* ciphersuites */ if(section->ciphersuites) { s_log(LOG_DEBUG, "TLSv1.3 ciphersuites: %s", section->ciphersuites); if(!SSL_CTX_set_ciphersuites(section->ctx, section->ciphersuites)) { sslerror("SSL_CTX_set_ciphersuites"); return 1; /* FAILED */ } } #endif /* TLS 1.3 */ /* TLS options: configure the stunnel defaults first */ SSL_CTX_set_options(section->ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3); #ifdef SSL_OP_NO_COMPRESSION /* we implemented a better way to disable compression if needed */ SSL_CTX_clear_options(section->ctx, SSL_OP_NO_COMPRESSION); #endif /* SSL_OP_NO_COMPRESSION */ /* TLS options: configure the user-specified values */ 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)); #endif /* OpenSSL 0.9.8m or later */ /* TLS options: log the configured values */ #if OPENSSL_VERSION_NUMBER>=0x009080dfL s_log(LOG_DEBUG, "TLS 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, "TLS 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 */ /* mode */ #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 /* setup session tickets */ #if OPENSSL_VERSION_NUMBER >= 0x10101000L SSL_CTX_set_session_ticket_cb(section->ctx, generate_session_ticket_cb, decrypt_session_ticket_cb, NULL); #endif /* OpenSSL 1.1.1 or later */ #if OPENSSL_VERSION_NUMBER>=0x10000000L if((section->ticket_key)&&(section->ticket_mac)) SSL_CTX_set_tlsext_ticket_key_cb(section->ctx, ssl_tlsext_ticket_key_cb); #endif /* OpenSSL 1.0.0 or later */ /* 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 */ } } SSL_CTX_set_session_cache_mode(section->ctx, SSL_SESS_CACHE_BOTH | SSL_SESS_CACHE_NO_INTERNAL_STORE); 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); /* load certificate and private key to be verified by the peer server */ if(auth_init(section)) return 1; /* FAILED */ /* initialize verification of the peer server certificate */ if(verify_init(section)) return 1; /* FAILED */ /* initialize the DH/ECDH key agreement in the server mode */ if(!section->option.client) { #ifndef OPENSSL_NO_TLSEXT 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 */ } return 0; /* OK */ } /**************************************** SNI callback */ #ifndef OPENSSL_NO_TLSEXT NOEXPORT int servername_cb(SSL *ssl, int *ad, void *arg) { const char *servername=SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); CLI *c=SSL_get_ex_data(ssl, index_ssl_cli); SERVERNAME_LIST *list; /* leave the alert type at SSL_AD_UNRECOGNIZED_NAME */ (void)ad; /* squash the unused parameter warning */ (void)arg; /* squash the unused parameter warning */ /* handle trivial cases first */ if(!c->opt->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; } /* find a matching section */ s_log(LOG_INFO, "SNI: requested servername: %s", servername); for(list=c->opt->servername_list_head; list; list=list->next) if(matches_wildcard(servername, list->servername)) break; if(!list) { s_log(LOG_ERR, "SNI: no pattern matched servername: %s", servername); return SSL_TLSEXT_ERR_OK; } s_log(LOG_DEBUG, "SNI: matched pattern: %s", list->servername); /* switch to the new section */ #ifndef USE_FORK service_up_ref(list->opt); service_free(c->opt); #endif 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 libwrap_auth(c); /* retry on a service switch */ #endif /* USE_LIBWRAP */ return SSL_TLSEXT_ERR_OK; } /* 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(const char *servername, const char *pattern) { if(!servername || !pattern) return 0; if(*pattern=='*') { /* wildcard comparison */ ssize_t diff=(ssize_t)strlen(servername)-((ssize_t)strlen(pattern)-1); if(diff<0) /* pattern longer than servername */ return 0; return !strcasecmp(servername+diff, pattern+1); } else { /* string comparison */ return !strcasecmp(servername, pattern); } } #endif /* OPENSSL_NO_TLSEXT */ /**************************************** DH initialization */ #ifndef OPENSSL_NO_DH #if OPENSSL_VERSION_NUMBER<0x10100000L NOEXPORT STACK_OF(SSL_CIPHER) *SSL_CTX_get_ciphers(const SSL_CTX *ctx) { return ctx->cipher_list; } #endif NOEXPORT int dh_init(SERVICE_OPTIONS *section) { DH *dh=NULL; int i, n; char description[128]; STACK_OF(SSL_CIPHER) *ciphers; section->option.dh_temp_params=0; /* disable by default */ /* check if DH is actually enabled for this section */ ciphers=SSL_CTX_get_ciphers(section->ctx); if(!ciphers) return 1; /* ERROR (unlikely) */ n=sk_SSL_CIPHER_num(ciphers); for(i=0; iengine) /* 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_THREAD_read_lock(stunnel_locks[LOCK_DH]); SSL_CTX_set_tmp_dh(section->ctx, dh_params); CRYPTO_THREAD_unlock(stunnel_locks[LOCK_DH]); dh_temp_params=1; /* generate temporary DH parameters in cron */ section->option.dh_temp_params=1; /* update this section in cron */ 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 #if OPENSSL_VERSION_NUMBER < 0x10101000L /* simplified version that only supports a single curve */ NOEXPORT int SSL_CTX_set1_groups_list(SSL_CTX *ctx, char *list) { int nid; EC_KEY *ecdh; nid=OBJ_txt2nid(list); if(nid==NID_undef) { s_log(LOG_ERR, "Unsupported curve: %s", list); return 0; /* FAILED */ } ecdh=EC_KEY_new_by_curve_name(nid); if(!ecdh) { sslerror("EC_KEY_new_by_curve_name"); return 0; /* FAILED */ } if(!SSL_CTX_set_tmp_ecdh(ctx, ecdh)) { sslerror("SSL_CTX_set_tmp_ecdhSSL_CTX_set_tmp_ecdh"); EC_KEY_free(ecdh); return 0; /* FAILED */ } EC_KEY_free(ecdh); return 1; /* OK */ } #endif /* OpenSSL version < 1.1.1 */ NOEXPORT int ecdh_init(SERVICE_OPTIONS *section) { s_log(LOG_DEBUG, "ECDH initialization"); if(!SSL_CTX_set1_groups_list(section->ctx, section->curves)) { #if OPENSSL_VERSION_NUMBER >= 0x10101000L sslerror("SSL_CTX_set1_groups_list"); #endif /* OpenSSL version >= 1.1.1 */ return 1; /* FAILED */ } s_log(LOG_DEBUG, "ECDH initialized with curves %s", section->curves); 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; /* initialize PSK */ #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) */ /* initialize the client cert engine */ #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 */ while(ERR_get_error()) ; /* OpenSSL error queue cleanup */ s_log(LOG_INFO, "Client certificate engine (%s) not supported", ENGINE_get_id(section->engine)); } } #endif /* 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 && pkcs12_extension(section->cert)) { if (load_pkcs12_file(section)) { return 1; /* FAILED */ } cert_needed=key_needed=0; /* don't load any PEM files */ } 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_ssl_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; c=SSL_get_ex_data(ssl, index_ssl_cli); found=psk_find(&c->opt->psk_sorted, identity); if(!found) { s_log(LOG_INFO, "PSK identity not found (session resumption?)"); return 0; } if(found->key_len>max_psk_len) { s_log(LOG_ERR, "PSK too long (%u>%u)", found->key_len, max_psk_len); return 0; } memcpy(psk, found->key_val, found->key_len); s_log(LOG_NOTICE, "Key configured for PSK identity \"%s\"", identity); c->flag.psk=1; return found->key_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_detached(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 pkcs12_extension(const char *filename) { const char *ext=strrchr(filename, '.'); return ext && (!strcasecmp(ext, ".p12") || !strcasecmp(ext, ".pfx")); } NOEXPORT int load_pkcs12_file(SERVICE_OPTIONS *section) { size_t len; int i, success; BIO *bio=NULL; PKCS12 *p12=NULL; X509 *cert=NULL; STACK_OF(X509) *ca=NULL; EVP_PKEY *pkey=NULL; char pass[PEM_BUFSIZE]; s_log(LOG_INFO, "Loading certificate and private key from file: %s", section->cert); if(file_permissions(section->cert)) return 1; /* FAILED */ bio=BIO_new_file(section->cert, "rb"); if(!bio) { sslerror("BIO_new_file"); return 1; /* FAILED */ } p12=d2i_PKCS12_bio(bio, NULL); if(!p12) { sslerror("d2i_PKCS12_bio"); BIO_free(bio); return 1; /* FAILED */ } BIO_free(bio); /* try the cached value first */ set_prompt(section->cert); len=(size_t)cache_passwd_get_cb(pass, sizeof pass, 0, NULL); if(len>=sizeof pass) len=sizeof pass-1; pass[len]='\0'; /* null-terminate */ success=PKCS12_parse(p12, pass, &pkey, &cert, &ca); /* invoke the UI */ for(i=0; !success && i<3; i++) { if(!ui_retry()) break; if(i==0) { /* silence the cached attempt */ ERR_clear_error(); } else { sslerror_queue(); /* dump the error queue */ s_log(LOG_ERR, "Wrong passphrase: retrying"); } /* invoke the UI on subsequent calls */ len=(size_t)cache_passwd_set_cb(pass, sizeof pass, 0, NULL); if(len>=sizeof pass) len=sizeof pass-1; pass[len]='\0'; /* null-terminate */ success=PKCS12_parse(p12, pass, &pkey, &cert, &ca); } if(!success) { sslerror("PKCS12_parse"); PKCS12_free(p12); return 1; /* FAILED */ } PKCS12_free(p12); if(!SSL_CTX_use_certificate(section->ctx, cert)) { sslerror("SSL_CTX_use_certificate"); return 1; /* FAILED */ } if(!SSL_CTX_use_PrivateKey(section->ctx, pkey)) { sslerror("SSL_CTX_use_PrivateKey"); return 1; /* FAILED */ } s_log(LOG_INFO, "Certificate and private key loaded from file: %s", section->cert); return 0; /* OK */ } 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 */ } NOEXPORT int load_key_file(SERVICE_OPTIONS *section) { int i, success; s_log(LOG_INFO, "Loading private key from file: %s", section->key); if(file_permissions(section->key)) return 1; /* FAILED */ /* try the cached value first */ set_prompt(section->key); SSL_CTX_set_default_passwd_cb(section->ctx, cache_passwd_get_cb); success=SSL_CTX_use_PrivateKey_file(section->ctx, section->key, SSL_FILETYPE_PEM); /* invoke the UI on subsequent calls */ SSL_CTX_set_default_passwd_cb(section->ctx, cache_passwd_set_cb); /* invoke the UI */ for(i=0; !success && i<3; i++) { if(!ui_retry()) break; if(i==0) { /* silence the cached attempt */ ERR_clear_error(); } else { sslerror_queue(); /* dump the error queue */ s_log(LOG_ERR, "Wrong passphrase: retrying"); } success=SSL_CTX_use_PrivateKey_file(section->ctx, section->key, SSL_FILETYPE_PEM); } if(!success) { 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; EVP_PKEY *pkey; s_log(LOG_INFO, "Initializing private key on engine ID: %s", section->key); /* do not use caching for engine PINs to prevent device lockout */ SSL_CTX_set_default_passwd_cb(section->ctx, ui_passwd_cb); for(i=0; i<3; i++) { pkey=ENGINE_load_private_key(section->engine, section->key, UI_stunnel(), NULL); if(!pkey) { if(i<2 && ui_retry()) { /* 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) */ /* additional caching layer on top of ui_passwd_cb() */ /* retrieve the cached passwd */ NOEXPORT int cache_passwd_get_cb(char *buf, int size, int rwflag, void *userdata) { int len=cached_len; (void)rwflag; /* squash the unused parameter warning */ (void)userdata; /* squash the unused parameter warning */ if(len<0 || size<0) /* the API uses signed integers */ return 0; if(len>size) /* truncate the returned data if needed */ len=size; memcpy(buf, cached_passwd, (size_t)len); return len; } /* cache the passwd retrieved from UI */ NOEXPORT int cache_passwd_set_cb(char *buf, int size, int rwflag, void *userdata) { memset(cached_passwd, 0, sizeof cached_passwd); cached_len=ui_passwd_cb(cached_passwd, sizeof cached_passwd, rwflag, userdata); return cache_passwd_get_cb(buf, size, rwflag, userdata); } NOEXPORT void set_prompt(const char *name) { char *prompt; prompt=str_printf("Enter %s pass phrase:", name); EVP_set_pw_prompt(prompt); str_free(prompt); } NOEXPORT int ui_retry() { unsigned long err=ERR_peek_error(); switch(ERR_GET_LIB(err)) { case ERR_LIB_ASN1: return 1; case ERR_LIB_PKCS12: switch(ERR_GET_REASON(err)) { case PKCS12_R_MAC_VERIFY_FAILURE: return 1; default: return 0; } case ERR_LIB_EVP: switch(ERR_GET_REASON(err)) { case EVP_R_BAD_DECRYPT: return 1; default: return 0; } case ERR_LIB_PEM: switch(ERR_GET_REASON(err)) { case PEM_R_BAD_PASSWORD_READ: return 1; default: return 0; } case ERR_LIB_UI: switch(ERR_GET_REASON(err)) { case UI_R_RESULT_TOO_LARGE: case UI_R_RESULT_TOO_SMALL: return 1; default: return 0; } case ERR_LIB_USER: /* PKCS#11 hacks */ switch(ERR_GET_REASON(err)) { case 7UL: /* CKR_ARGUMENTS_BAD */ case 0xa0UL: /* CKR_PIN_INCORRECT */ return 1; default: return 0; } default: return 0; } } /**************************************** session tickets */ #if OPENSSL_VERSION_NUMBER >= 0x10101000L typedef struct { void *session_authenticated; #if 0 SOCKADDR_UNION addr; #endif } TICKET_DATA; NOEXPORT int generate_session_ticket_cb(SSL *ssl, void *arg) { SSL_SESSION *sess; TICKET_DATA ticket_data; #if 0 SOCKADDR_UNION *addr; #endif int retval; (void)arg; /* squash the unused parameter warning */ s_log(LOG_DEBUG, "Generate session ticket callback"); sess=SSL_get1_session(ssl); if(!sess) return 0; memset(&ticket_data, 0, sizeof(TICKET_DATA)); ticket_data.session_authenticated= SSL_SESSION_get_ex_data(sess, index_session_authenticated); #if 0 /* TODO: add remote_start() invocation here */ CRYPTO_THREAD_read_lock(stunnel_locks[LOCK_ADDR]); addr=SSL_SESSION_get_ex_data(sess, index_session_connect_address); if(addr) memcpy(&ticket_data.addr, addr, (size_t)addr_len(addr)); CRYPTO_THREAD_unlock(stunnel_locks[LOCK_ADDR]); #endif retval=SSL_SESSION_set1_ticket_appdata(sess, &ticket_data, sizeof(TICKET_DATA)); SSL_SESSION_free(sess); return retval; } NOEXPORT int decrypt_session_ticket_cb(SSL *ssl, SSL_SESSION *sess, const unsigned char *keyname, size_t keyname_len, SSL_TICKET_STATUS status, void *arg) { TICKET_DATA *ticket_data; size_t ticket_len; (void)ssl; /* squash the unused parameter warning */ (void)keyname; /* squash the unused parameter warning */ (void)keyname_len; /* squash the unused parameter warning */ (void)arg; /* squash the unused parameter warning */ s_log(LOG_DEBUG, "Decrypt session ticket callback"); switch(status) { case SSL_TICKET_EMPTY: case SSL_TICKET_NO_DECRYPT: return SSL_TICKET_RETURN_IGNORE_RENEW; case SSL_TICKET_SUCCESS: case SSL_TICKET_SUCCESS_RENEW: break; default: return SSL_TICKET_RETURN_ABORT; } if(!SSL_SESSION_get0_ticket_appdata(sess, (void **)&ticket_data, &ticket_len)) { s_log(LOG_WARNING, "Failed to get ticket application data"); return SSL_TICKET_RETURN_IGNORE_RENEW; } if(!ticket_data) { s_log(LOG_WARNING, "Invalid ticket application data value"); return SSL_TICKET_RETURN_IGNORE_RENEW; } if(ticket_len != sizeof(TICKET_DATA)) { s_log(LOG_WARNING, "Invalid ticket application data length"); return SSL_TICKET_RETURN_IGNORE_RENEW; } s_log(LOG_INFO, "Decrypted ticket for an authenticated session: %s", ticket_data->session_authenticated ? "yes" : "no"); SSL_SESSION_set_ex_data(sess, index_session_authenticated, ticket_data->session_authenticated); #if 0 if(ticket_data->addr.sa.sa_family) { char *addr_txt; SOCKADDR_UNION *old_addr; addr_txt=s_ntop(&ticket_data->addr, addr_len(&ticket_data->addr)); s_log(LOG_INFO, "Decrypted ticket persistence address: %s", addr_txt); str_free(addr_txt); CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_ADDR]); old_addr=SSL_SESSION_get_ex_data(sess, index_session_connect_address); if(SSL_SESSION_set_ex_data(sess, index_session_connect_address, &ticket_data->addr)) { CRYPTO_THREAD_unlock(stunnel_locks[LOCK_ADDR]); str_free(old_addr); /* NULL pointers are ignored */ } else { /* failed to store ticket_data->addr */ CRYPTO_THREAD_unlock(stunnel_locks[LOCK_ADDR]); sslerror("SSL_SESSION_set_ex_data"); } } else { s_log(LOG_INFO, "Decrypted ticket did not include a persistence address"); } #endif switch(status) { case SSL_TICKET_SUCCESS: return SSL_TICKET_RETURN_USE; case SSL_TICKET_SUCCESS_RENEW: return SSL_TICKET_RETURN_USE_RENEW; } return SSL_TICKET_RETURN_ABORT; /* it should never get executed */ } #endif #if OPENSSL_VERSION_NUMBER>=0x10000000L NOEXPORT int ssl_tlsext_ticket_key_cb(SSL *ssl, unsigned char *key_name, unsigned char *iv, EVP_CIPHER_CTX *ctx, HMAC_CTX *hctx, int enc) { CLI *c; const EVP_CIPHER *cipher; int iv_len; (void)key_name; /* squash the unused parameter warning */ s_log(LOG_DEBUG, "Session ticket processing callback"); c=SSL_get_ex_data(ssl, index_ssl_cli); if(!HMAC_Init_ex(hctx, (const unsigned char *)(c->opt->ticket_mac->key_val), c->opt->ticket_mac->key_len, EVP_sha256(), NULL)) { s_log(LOG_ERR, "HMAC_Init_ex failed"); return -1; } if(c->opt->ticket_key->key_len == 16) cipher = EVP_aes_128_cbc(); else /* c->opt->ticket_key->key_len == 32 */ cipher = EVP_aes_256_cbc(); if(enc) { /* create new session */ /* EVP_CIPHER_iv_length() returns 16 for either cipher EVP_aes_128_cbc() or EVP_aes_256_cbc() */ iv_len = EVP_CIPHER_iv_length(cipher); if(RAND_bytes(iv, iv_len) <= 0) { /* RAND_bytes error */ s_log(LOG_ERR, "RAND_bytes failed"); return -1; } if(!EVP_EncryptInit_ex(ctx, cipher, NULL, (const unsigned char *)(c->opt->ticket_key->key_val), iv)) { s_log(LOG_ERR, "EVP_EncryptInit_ex failed"); return -1; } } else /* retrieve session */ if(!EVP_DecryptInit_ex(ctx, cipher, NULL, (const unsigned char *)(c->opt->ticket_key->key_val), iv)) { s_log(LOG_ERR, "EVP_DecryptInit_ex failed"); return -1; } /* By default, in TLSv1.2 and below, a new session ticket */ /* is not issued on a successful resumption. */ /* In TLSv1.3 the default behaviour is to always issue a new ticket on resumption. */ /* This behaviour can NOT be changed if this ticket key callback is in use! */ if(strcmp(SSL_get_version(c->ssl), "TLSv1.3")) return 1; /* new session ticket is not issued */ else return 2; /* session ticket should be replaced */ } #endif /* OpenSSL 1.0.0 or later */ /**************************************** 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_ssl_cli); new_chain(c); /* new session -> we may have a new peer certificate chain */ if(c->opt->option.client) session_cache_save(c, sess); if(c->opt->option.sessiond) cache_new(ssl, sess); print_session_id(sess); return 0; /* the OpenSSL's manual is really bad -> use the source here */ } #if OPENSSL_VERSION_NUMBER<0x0090800fL NOEXPORT const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s, unsigned int *len) { if(len) *len=s->session_id_length; return (const unsigned char *)s->session_id; } #endif void print_session_id(SSL_SESSION *sess) { const unsigned char *session_id; unsigned int session_id_length; char session_id_txt[2*SSL_MAX_SSL_SESSION_ID_LENGTH+1]; session_id=SSL_SESSION_get_id(sess, &session_id_length); bin2hexstring(session_id, session_id_length, session_id_txt, sizeof session_id_txt); s_log(LOG_INFO, "Session id: %s", session_id_txt); } 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); } /* cache client sessions */ NOEXPORT void session_cache_save(CLI *c, SSL_SESSION *sess) { SSL_SESSION *old; #if OPENSSL_VERSION_NUMBER>=0x10100000L SSL_SESSION_up_ref(sess); #else sess=SSL_get1_session(c->ssl); #endif CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_SESSION]); if(c->opt->option.delayed_lookup) { old=c->opt->session; c->opt->session=sess; } else { /* per-destination client cache */ if(c->opt->connect_session) { old=c->opt->connect_session[c->idx]; c->opt->connect_session[c->idx]=sess; } else { s_log(LOG_ERR, "INTERNAL ERROR: Uninitialized client session cache"); old=NULL; } } CRYPTO_THREAD_unlock(stunnel_locks[LOCK_SESSION]); if(old) SSL_SESSION_free(old); } NOEXPORT SSL_SESSION *sess_get_cb(SSL *ssl, #if OPENSSL_VERSION_NUMBER>=0x10100000L const #endif 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_ssl_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_ssl_ctx_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); session_id=SSL_SESSION_get_id(sess, &session_id_length); 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, const unsigned char *key, int key_len) { unsigned char *val=NULL, *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>=0x0090707fL (const unsigned char **) #endif /* OpenSSL version >= 0.9.7g */ &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; session_id=SSL_SESSION_get_id(sess, &session_id_length); 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 *type_description[]={"new", "get", "remove"}; 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 */ bin2hexstring(key, key_len, session_id_txt, sizeof session_id_txt); 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); if(val && val_len) /* only check it to make code analysis tools happy */ 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_ssl_ctx_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_ssl_cli); if(c) { #if OPENSSL_VERSION_NUMBER>=0x10100000L OSSL_HANDSHAKE_STATE state=SSL_get_state(ssl); #else int state=SSL_get_state((SSL *)ssl); #endif #if 0 s_log(LOG_DEBUG, "state = %x", state); #endif /* log the client certificate request (if received) */ #ifndef SSL3_ST_CR_CERT_REQ_A if(state==TLS_ST_CR_CERT_REQ) #else if(state==SSL3_ST_CR_CERT_REQ_A) #endif print_client_CA_list(SSL_get_client_CA_list((SSL *)ssl)); #ifndef SSL3_ST_CR_SRVR_DONE_A if(state==TLS_ST_CR_SRVR_DONE) #else if(state==SSL3_ST_CR_SRVR_DONE_A) #endif if(!SSL_get_client_CA_list((SSL *)ssl)) s_log(LOG_INFO, "Client certificate not requested"); /* prevent renegotiation DoS attack */ 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) { #ifndef SSL3_ST_SR_CLNT_HELLO_A if(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)); } } } /**************************************** TLS error reporting */ void sslerror(char *txt) { /* OpenSSL error handler */ unsigned long err; const char *file; int line; err=ERR_get_error_line(&file, &line); if(err) { sslerror_queue(); sslerror_log(err, file, line, 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; const char *file; int line; err=ERR_get_error_line(&file, &line); if(err) { sslerror_queue(); sslerror_log(err, file, line, "error queue"); } } NOEXPORT void sslerror_log(unsigned long err, const char *file, int line, char *txt) { char *str; str=str_alloc(256); ERR_error_string_n(err, str, 256); s_log(LOG_ERR, "%s: %s:%d: %s", txt, file, line, str); str_free(str); } /* end of ctx.c */ stunnel-5.56/src/verify.c0000664000175000017500000006434013554262513012340 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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->option.request_cert) { verify_mode|=SSL_VERIFY_PEER; if(section->option.require_cert && !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; s_log(LOG_DEBUG, "Client CA list: %s", section->ca_file); ca_dn=SSL_load_client_CA_file(section->ca_file); SSL_CTX_set_client_CA_list(section->ctx, ca_dn); print_client_CA_list(ca_dn); } NOEXPORT 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) { #if OPENSSL_VERSION_NUMBER<0x10100000L /* do not cache CRLs (only required with OpenSSL version < 1.0.0) */ store->cache=0; #endif 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->option.verify_peer) /* verify_peer does not depend on PKI */ return; if(section->option.verify_chain) { #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 \"verifyChain\" 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"); return; } s_log(LOG_WARNING, "Service [%s] needs authentication to prevent MITM attacks", section->servname); } /**************************************** 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_ssl_cli); if(!c->opt->option.verify_chain && !c->opt->option.verify_peer) { s_log(LOG_INFO, "Certificate verification disabled"); return 1; /* accept */ } if(verify_checks(c, preverify_ok, callback_ctx)) { SSL_SESSION *sess=SSL_get1_session(c->ssl); if(sess) { int ok=SSL_SESSION_set_ex_data(sess, index_session_authenticated, (void *)(-1)); SSL_SESSION_free(sess); if(!ok) { sslerror("SSL_SESSION_set_ex_data"); return 0; /* reject */ } } return 1; /* accept */ } if(c->opt->option.client || c->opt->protocol) return 0; /* reject */ if(c->opt->redirect_addr.names) 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 err=X509_STORE_CTX_get_error(callback_ctx); 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->option.verify_chain || (depth==0 && err!=X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY && err!=X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE && err!=X509_V_ERR_CERT_UNTRUSTED)) { s_log(LOG_WARNING, "CERT: Pre-verification error: %s", X509_verify_cert_error_string(err)); /* retain the STORE_CTX error produced by pre-verification */ return 0; /* reject */ } s_log(LOG_INFO, "CERT: Pre-verification error ignored: %s", X509_verify_cert_error_string(err)); } 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->option.verify_peer && !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 && !c->opt->check_email && !c->opt->check_ip) { s_log(LOG_INFO, "CERT: No subject checks configured"); return 1; /* accept */ } for(ptr=c->opt->check_host; ptr; ptr=ptr->next) if(X509_check_host(cert, ptr->name, 0, 0, &peername)>0) { s_log(LOG_INFO, "CERT: Host name \"%s\" matched with \"%s\"", ptr->name, peername); OPENSSL_free(peername); return 1; /* accept */ } for(ptr=c->opt->check_email; ptr; ptr=ptr->next) if(X509_check_email(cert, ptr->name, 0, 0)>0) { s_log(LOG_INFO, "CERT: Email address \"%s\" matched", ptr->name); return 1; /* accept */ } for(ptr=c->opt->check_ip; ptr; ptr=ptr->next) if(X509_check_ip_asc(cert, ptr->name, 0)>0) { s_log(LOG_INFO, "CERT: IP address \"%s\" matched", ptr->name); return 1; /* accept */ } s_log(LOG_WARNING, "CERT: Subject checks failed"); return 0; /* reject */ } #endif /* OPENSSL_VERSION_NUMBER>=0x10002000L */ #if OPENSSL_VERSION_NUMBER>=0x10000000L /* modern implementation for OpenSSL version >= 1.0.0 */ NOEXPORT int cert_check_local(X509_STORE_CTX *callback_ctx) { X509 *cert; X509_NAME *subject; STACK_OF(X509) *sk; int i; cert=X509_STORE_CTX_get_current_cert(callback_ctx); subject=X509_get_subject_name(cert); #if OPENSSL_VERSION_NUMBER<0x10100006L #define X509_STORE_CTX_get1_certs X509_STORE_get1_certs #endif /* modern API allows retrieving multiple matching certificates */ sk=X509_STORE_CTX_get1_certs(callback_ctx, subject); if(sk) { for(i=0; i=0x10000000L */ NOEXPORT int compare_pubkeys(X509 *c1, X509 *c2) { ASN1_BIT_STRING *k1=X509_get0_pubkey_bitstr(c1); ASN1_BIT_STRING *k2=X509_get0_pubkey_bitstr(c2); if(!k1 || !k2 || k1->length!=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_get0_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: TLS 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, 0); 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_get0_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.56/src/mingw.mak0000664000175000017500000001523713467064764012517 00000000000000# Simple Makefile.w32 for stunnel.exe by Michal Trojnara 1998-2019 # # 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 -lkernel32 TLIBS=$(SSLLIBS) -lws2_32 -lpsapi -lcrypt32 -lkernel32 # 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.56/src/cron.c0000664000175000017500000002105213467064764012001 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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_OS_THREADS THREAD_ID cron_thread_id=(THREAD_ID)0; #endif #ifdef USE_PTHREAD NOEXPORT void *cron_thread(void *arg); #endif #ifdef USE_WIN32 NOEXPORT unsigned __stdcall cron_thread(void *arg); #endif #ifdef USE_OS_THREADS NOEXPORT void cron_worker(void); #ifndef OPENSSL_NO_DH #if OPENSSL_VERSION_NUMBER>=0x0090800fL NOEXPORT void cron_dh_param(BN_GENCB *); NOEXPORT BN_GENCB *cron_bn_gencb(void); NOEXPORT int bn_callback(int, int, BN_GENCB *); #else /* OpenSSL older than 0.9.8 */ NOEXPORT void cron_dh_param(void); NOEXPORT void dh_callback(int, int, void *); #endif /* OpenSSL 0.9.8 or later */ #endif /* OPENSSL_NO_DH */ #endif /* USE_OS_THREADS */ #if defined(USE_PTHREAD) int cron_init() { #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__*/ CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_THREAD_LIST]); if(pthread_create(&cron_thread_id, NULL, cron_thread, NULL)) ioerror("pthread_create"); CRYPTO_THREAD_unlock(stunnel_locks[LOCK_THREAD_LIST]); #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() { CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_THREAD_LIST]); cron_thread_id=(HANDLE)_beginthreadex(NULL, 0, cron_thread, NULL, 0, NULL); CRYPTO_THREAD_unlock(stunnel_locks[LOCK_THREAD_LIST]); if(!cron_thread_id) { ioerror("_beginthreadex"); return 1; } return 0; } NOEXPORT unsigned __stdcall 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(); _endthreadex(0); /* it should never be executed */ return 0; } #else /* USE_OS_THREADS */ int cron_init() { /* not implemented for now */ return 0; } #endif /* run the cron job every 24 hours */ #define CRON_PERIOD (24*60*60) #ifdef USE_OS_THREADS NOEXPORT void cron_worker(void) { time_t now, then; int delay; #if !defined(OPENSSL_NO_DH) && OPENSSL_VERSION_NUMBER>=0x0090800fL BN_GENCB *bn_gencb; #endif s_log(LOG_DEBUG, "Cron thread initialized"); #if !defined(OPENSSL_NO_DH) && OPENSSL_VERSION_NUMBER>=0x0090800fL bn_gencb=cron_bn_gencb(); #endif time(&then); for(;;) { s_log(LOG_INFO, "Executing cron jobs"); #ifndef OPENSSL_NO_DH #if OPENSSL_VERSION_NUMBER>=0x0090800fL cron_dh_param(bn_gencb); #else /* OpenSSL older than 0.9.8 */ cron_dh_param(); #endif /* OpenSSL 0.9.8 or later */ #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 s_poll_sleep() if it was interrupted by a signal */ s_poll_sleep(delay, 0); 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 #if OPENSSL_VERSION_NUMBER>=0x0090800fL NOEXPORT void cron_dh_param(BN_GENCB *bn_gencb) { #else /* OpenSSL older than 0.9.8 */ NOEXPORT void cron_dh_param(void) { #endif /* OpenSSL 0.9.8 or later */ SERVICE_OPTIONS *opt; DH *dh; if(!dh_temp_params || !service_options.next) 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, bn_gencb)) { DH_free(dh); sslerror("DH_generate_parameters_ex"); return; } #else /* OpenSSL older than 0.9.8 */ dh=DH_generate_parameters(2048, 2, dh_callback, NULL); if(!dh) { sslerror("DH_generate_parameters"); return; } #endif /* OpenSSL 0.9.8 or later */ /* update global dh_params for future configuration reloads */ CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_DH]); DH_free(dh_params); dh_params=dh; CRYPTO_THREAD_unlock(stunnel_locks[LOCK_DH]); /* set for all sections that require it */ CRYPTO_THREAD_read_lock(stunnel_locks[LOCK_SECTIONS]); for(opt=service_options.next; opt; opt=opt->next) if(opt->option.dh_temp_params) SSL_CTX_set_tmp_dh(opt->ctx, dh); CRYPTO_THREAD_unlock(stunnel_locks[LOCK_SECTIONS]); s_log(LOG_NOTICE, "DH parameters updated"); } #if OPENSSL_VERSION_NUMBER>=0x0090800fL NOEXPORT BN_GENCB *cron_bn_gencb(void) { #if OPENSSL_VERSION_NUMBER>=0x10100000L BN_GENCB *bn_gencb; bn_gencb=BN_GENCB_new(); if(!bn_gencb) { sslerror("BN_GENCB_new"); return NULL; } BN_GENCB_set(bn_gencb, bn_callback, NULL); return bn_gencb; #else static BN_GENCB bn_gencb; BN_GENCB_set(&bn_gencb, bn_callback, NULL); return &bn_gencb; #endif } NOEXPORT int bn_callback(int p, int n, BN_GENCB *cb) { (void)p; /* squash the unused parameter warning */ (void)n; /* squash the unused parameter warning */ (void)cb; /* squash the unused parameter warning */ s_poll_sleep(0, 100); /* 100ms */ return 1; /* return nonzero for success */ } #else /* OpenSSL older than 0.9.8 */ NOEXPORT void dh_callback(int p, int n, void *arg) { (void)p; /* squash the unused parameter warning */ (void)n; /* squash the unused parameter warning */ (void)arg; /* squash the unused parameter warning */ s_poll_sleep(0, 100); /* 100ms */ } #endif /* OpenSSL 0.9.8 or later */ #endif /* OPENSSL_NO_DH */ #endif /* USE_OS_THREADS */ /* end of cron.c */ stunnel-5.56/src/tls.c0000664000175000017500000001254713467064764011653 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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 CRYPTO_set_mem_functions(str_alloc_detached_debug, str_realloc_detached_debug, str_free_debug); #else CRYPTO_set_mem_ex_functions(str_alloc_detached_debug, str_realloc_detached_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.56/src/network.c0000664000175000017500000007422113473713602012524 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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 *); #ifndef USE_UCONTEXT NOEXPORT void check_terminate(s_poll_set *); #endif /**************************************** 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, int main_thread) { fds->nfds=0; fds->allocated=4; /* prealloc 4 file descriptors */ s_poll_realloc(fds); fds->main_thread=main_thread; s_poll_add(fds, main_thread ? signal_pipe[0] : terminate_pipe[0], 1, 0); } 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 */ } int s_poll_err(s_poll_set *fds, SOCKET fd) { unsigned i; for(i=0; infds; i++) if(fds->ufds[i].fd==fd) return fds->ufds[i].revents&POLLERR; 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=%ld,%s%s ->%s%s%s%s%s", context->id, (long)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); if(retval>0) check_terminate(fds); 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, int main_thread) { #ifdef USE_WIN32 fds->allocated=4; /* prealloc 4 file descriptors */ #endif s_poll_realloc(fds); FD_ZERO(fds->irfds); FD_ZERO(fds->iwfds); FD_ZERO(fds->ixfds); fds->max=0; /* no file descriptors */ fds->main_thread=main_thread; #ifdef USE_WIN32 /* there seems to be a deadlock in the Windows select() function when * waiting for the same terminate_pipe socket in multiple threads */ if(main_thread) s_poll_add(fds, signal_pipe[0], 1, 0); #else s_poll_add(fds, main_thread ? signal_pipe[0] : terminate_pipe[0], 1, 0); #endif } 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) { /* ignore exception if there is no error (WinCE 6.0 anomaly) */ return FD_ISSET(fd, fds->orfds) || (FD_ISSET(fd, fds->oxfds) && get_socket_error(fd)); } int s_poll_canwrite(s_poll_set *fds, SOCKET fd) { /* ignore exception if there is no error (WinCE 6.0 anomaly) */ return FD_ISSET(fd, fds->owfds) || (FD_ISSET(fd, fds->oxfds) && get_socket_error(fd)); } 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 the 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 the RDHUP condition with select()? */ } int s_poll_err(s_poll_set *fds, SOCKET fd) { return FD_ISSET(fd, fds->oxfds); } #ifdef USE_WIN32 #define FD_SIZE(fds) (8+(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)); #ifndef _WIN32_WCE memcpy(fds->oxfds, fds->ixfds, FD_SIZE(fds)); #else /* WinCE reports unexpected permanent exceptions */ FD_ZERO(fds->oxfds); #endif 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); if(retval>0) check_terminate(fds); 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+1; 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 */ void s_poll_sleep(int sec, int msec) { #ifdef USE_WIN32 Sleep(1000*(DWORD)sec+(DWORD)msec); #else s_poll_set *fds=s_poll_alloc(); s_poll_init(fds, 0); s_poll_wait(fds, sec, msec); s_poll_free(fds); #endif } #ifndef USE_UCONTEXT NOEXPORT void check_terminate(s_poll_set *fds) { if(!fds->main_thread && s_poll_canread(fds, terminate_pipe[0])) { #ifdef USE_PTHREAD pthread_exit(NULL); #endif /* USE_PTHREAD */ #if defined(USE_WIN32) || defined(USE_OS2) #if defined(_WIN32_WCE) /* FIXME */ #else /* !_WIN32_WCE */ _endthreadex(0); #endif /* _WIN32_WCE */ #endif /* USE_WIN32 || USE_OS2 */ #ifdef USE_UCONTEXT /* currently unused */ s_poll_wait(NULL, 0, 0); /* wait on poll() */ #endif /* USE_UCONTEXT */ #ifdef USE_FORK exit(0); #endif /* USE_FORK */ } } #endif /**************************************** fd management */ int socket_options_set(SERVICE_OPTIONS *service, SOCKET s, int type) { SOCK_OPT *ptr; static char *type_str[3]={"accept", "local", "remote"}; socklen_t opt_size; int retval=0; /* no error found */ s_log(LOG_DEBUG, "Setting %s socket options (FD=%ld)", type_str[type], (long)s); for(ptr=service->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 */ } } else { s_log(LOG_DEBUG, "Option %s set on %s socket", ptr->opt_str, type_str[type]); } } return retval; /* returns 0 when all options succeeded */ } 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, 0); s_poll_add(c->fds, c->fd, 1, 1); s_poll_dump(c->fds, LOG_DEBUG); 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, 0); 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"); throw_exception(c, 1); /* error */ case 0: s_log(LOG_INFO, "s_write: s_poll_wait:" " TIMEOUTbusy exceeded: sending reset"); throw_exception(c, 1); /* timeout */ case 1: break; /* OK */ default: s_log(LOG_ERR, "s_write: s_poll_wait: unknown result"); throw_exception(c, 1); /* error */ } num=writesocket(fd, (void *)ptr, len); if(num==-1) { /* error */ sockerror("writesocket (s_write)"); throw_exception(c, 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, 0); 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"); throw_exception(c, 1); /* error */ case 0: s_log(LOG_INFO, "s_read: s_poll_wait:" " TIMEOUTbusy exceeded: sending reset"); throw_exception(c, 1); /* timeout */ case 1: break; /* OK */ default: s_log(LOG_ERR, "s_read: s_poll_wait: unknown result"); throw_exception(c, 1); /* error */ } num=readsocket(fd, ptr, len); switch(num) { case -1: /* error */ sockerror("readsocket (s_read)"); throw_exception(c, 1); case 0: /* EOF */ s_log(LOG_ERR, "Unexpected socket close (s_read)"); throw_exception(c, 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); throw_exception(c, 1); } if(allocated0) { s_poll_init(c->fds, 0); 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"); throw_exception(c, 1); /* error */ case 0: s_log(LOG_INFO, "s_write: s_poll_wait:" " TIMEOUTbusy exceeded: sending reset"); throw_exception(c, 1); /* timeout */ case 1: break; /* OK */ default: s_log(LOG_ERR, "s_write: s_poll_wait: unknown result"); throw_exception(c, 1); /* error */ } num=SSL_write(c->ssl, (void *)ptr, len); if(num==-1) { /* error */ sockerror("SSL_write (s_ssl_write)"); throw_exception(c, 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, 0); 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"); throw_exception(c, 1); /* error */ case 0: s_log(LOG_INFO, "s_read: s_poll_wait:" " TIMEOUTbusy exceeded: sending reset"); throw_exception(c, 1); /* timeout */ case 1: break; /* OK */ default: s_log(LOG_ERR, "s_read: s_poll_wait: unknown result"); throw_exception(c, 1); /* error */ } } num=SSL_read(c->ssl, ptr, len); switch(num) { case -1: /* error */ sockerror("SSL_read (s_ssl_read)"); throw_exception(c, 1); case 0: /* EOF */ s_log(LOG_ERR, "Unexpected socket close (s_ssl_read)"); throw_exception(c, 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); throw_exception(c, 1); } if(allocated65536) { /* >64KB --> DoS protection */ s_log(LOG_ERR, "ssl_getline: Line too long"); str_free(line); throw_exception(c, 1); } if(allocatedINT_MAX) { /* paranoia */ s_log(LOG_ERR, "ssl_putline: Line too long"); str_free(tmpline); throw_exception(c, 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.56/src/str.c0000664000175000017500000005017313467064764011656 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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" /* Uncomment to see allocation sources in core dumps */ /* #define DEBUG_PADDING 64 */ /* reportedly, malloc does not always return 16-byte aligned addresses * for 64-bit targets as specified by * https://msdn.microsoft.com/en-us/library/6ewkz86d.aspx */ #ifdef USE_WIN32 #define system_malloc(n) _aligned_malloc((n),16) #define system_realloc(p,n) _aligned_realloc((p),(n),16) #define system_free(p) _aligned_free(p) #else #define system_malloc(n) malloc(n) #define system_realloc(p,n) realloc((p),(n)) #define system_free(p) free(p) #endif #define CANARY_INITIALIZED 0x0000c0ded0000000LL #define CANARY_UNINTIALIZED 0x0000abadbabe0000LL #define MAGIC_ALLOCATED 0x0000a110c8ed0000LL #define MAGIC_DEALLOCATED 0x0000defec8ed0000LL /* most platforms require allocations to be aligned */ #ifdef _MSC_VER __declspec(align(16)) #endif 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; #ifdef DEBUG_PADDING char debug[DEBUG_PADDING]; #endif uint64_t valid_canary, magic; #ifdef __GNUC__ } __attribute__((aligned(16))); #else #ifndef MSC_VER uint64_t :0; /* align the structure */ #endif }; #endif #define LEAK_TABLE_SIZE 997 typedef struct { const char *alloc_file; int alloc_line; int num, max; } LEAK_ENTRY; NOEXPORT LEAK_ENTRY leak_hash_table[LEAK_TABLE_SIZE], *leak_results[LEAK_TABLE_SIZE]; NOEXPORT volatile int leak_result_num=0; #ifdef USE_WIN32 NOEXPORT LPTSTR str_vtprintf(LPCTSTR, va_list); #endif /* USE_WIN32 */ NOEXPORT void *str_realloc_internal_debug(void *, size_t, const char *, int); NOEXPORT ALLOC_LIST *get_alloc_list_ptr(void *, const char *, int); NOEXPORT void str_leak_debug(const ALLOC_LIST *, int); NOEXPORT LEAK_ENTRY *leak_search(const ALLOC_LIST *); NOEXPORT void leak_report(); NOEXPORT long leak_threshold(); TLS_DATA *ui_tls; NOEXPORT uint8_t canary[10]; /* 80-bit canary value */ NOEXPORT 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; if(!str) return NULL; retval=str_alloc_debug(strlen(str)+1, file, line); strcpy(retval, str); return retval; } char *str_dup_detached_debug(const char *str, const char *file, int line) { char *retval; if(!str) return NULL; retval=str_alloc_detached_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__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic push #endif /* __GNUC__>=4.6 */ #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__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic pop #endif /* __GNUC__>=4.6 */ #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"); leak_report(); 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_CRIT, "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=system_malloc(sizeof(ALLOC_LIST)+size+sizeof canary); if(!alloc_list) fatal_debug("Out of memory", file, line); memset(alloc_list, 0, sizeof(ALLOC_LIST)+size+sizeof canary); 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; #ifdef DEBUG_PADDING snprintf(alloc_list->debug+1, DEBUG_PADDING-1, "ALLOC_%lu@%s:%d", (unsigned long)size, file, line); #endif 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) { if(ptr) return str_realloc_internal_debug(ptr, size, file, line); else return str_alloc_debug(size, file, line); } void *str_realloc_detached_debug(void *ptr, size_t size, const char *file, int line) { if(ptr) return str_realloc_internal_debug(ptr, size, file, line); else return str_alloc_detached_debug(size, file, line); } NOEXPORT void *str_realloc_internal_debug(void *ptr, size_t size, const char *file, int line) { ALLOC_LIST *prev_alloc_list, *alloc_list; 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=system_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; #ifdef DEBUG_PADDING snprintf(alloc_list->debug+1, DEBUG_PADDING-1, "ALLOC_%lu@%s:%d", (unsigned long)size, file, line); #endif 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, "INTERNAL ERROR: 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 */ system_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; } /**************************************** memory leak detection */ NOEXPORT void str_leak_debug(const ALLOC_LIST *alloc_list, int change) { static size_t entries=0; LEAK_ENTRY *entry; int new_entry; int allocations; if(service_options.log_levelalloc_line!=alloc_list->alloc_line || entry->alloc_file!=alloc_list->alloc_file; if(new_entry) { /* the file:line pair was encountered for the first time */ CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_LEAK_HASH]); entry=leak_search(alloc_list); /* the list may have changed */ if(entry->alloc_line==0) { if(entries>LEAK_TABLE_SIZE-100) { /* this should never happen */ CRYPTO_THREAD_unlock(stunnel_locks[LOCK_LEAK_HASH]); return; } entries++; entry->alloc_line=alloc_list->alloc_line; entry->alloc_file=alloc_list->alloc_file; } CRYPTO_THREAD_unlock(stunnel_locks[LOCK_LEAK_HASH]); } /* for performance we try to avoid calling CRYPTO_atomic_add() here */ #ifdef USE_OS_THREADS #if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) if(__atomic_is_lock_free(sizeof entry->num, &entry->num)) allocations=__atomic_add_fetch(&entry->num, change, __ATOMIC_ACQ_REL); else CRYPTO_atomic_add(&entry->num, change, &allocations, stunnel_locks[LOCK_LEAK_HASH]); #elif defined(_MSC_VER) allocations=InterlockedExchangeAdd(&entry->num, change)+change; #else /* atomic add not directly supported by the compiler */ CRYPTO_atomic_add(&entry->num, change, &allocations, stunnel_locks[LOCK_LEAK_HASH]); #endif #else /* USE_OS_THREADS */ allocations=(entry->num+=change); #endif /* USE_OS_THREADS */ if(allocations<=leak_threshold()) /* leak not detected */ return; if(allocations<=entry->max) /* not the biggest leak for this entry */ return; if(entry->max) { /* not the first time we found a leak for this entry */ entry->max=allocations; /* just update the value */ return; } /* we *may* need to allocate a new leak_results entry */ /* locking is slow, so we try to avoid it if possible */ CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_LEAK_RESULTS]); if(entry->max==0) { /* the table may have changed */ leak_results[leak_result_num]=entry; entry->max=allocations; ++leak_result_num; /* at the end to avoid a lock in leak_report() */ } else { /* gracefully handle the race condition */ entry->max=allocations; } CRYPTO_THREAD_unlock(stunnel_locks[LOCK_LEAK_RESULTS]); } /* O(1) hash table lookup */ NOEXPORT LEAK_ENTRY *leak_search(const ALLOC_LIST *alloc_list) { /* a trivial hash based on source file name *address* and line number */ unsigned i=((unsigned)(uintptr_t)alloc_list->alloc_file+ (unsigned)alloc_list->alloc_line)%LEAK_TABLE_SIZE; while(!(leak_hash_table[i].alloc_line==0 || (leak_hash_table[i].alloc_line==alloc_list->alloc_line && leak_hash_table[i].alloc_file==alloc_list->alloc_file))) i=(i+1)%LEAK_TABLE_SIZE; return leak_hash_table+i; } void leak_table_utilization() { int i, utilization=0; for(i=0; imax>limit /* the limit could have changed */) s_log(LOG_WARNING, "Possible memory leak at %s:%d: %d allocations", leak_results[i]->alloc_file, leak_results[i]->alloc_line, leak_results[i]->max); } NOEXPORT long leak_threshold() { long limit; limit=10000*((int)number_of_sections+1); #ifndef USE_FORK limit+=100*num_clients; #endif return limit; } /**************************************** memcmp() replacement */ /* a version of memcmp() with execution time not dependent on data values */ /* it does *not* allow testing whether s1 is greater or lesser than s2 */ int safe_memcmp(const void *s1, const void *s2, size_t n) { #ifdef _WIN64 typedef unsigned long long TL; #else typedef unsigned long TL; #endif typedef unsigned char TS; TL r=0, *pl1, *pl2; TS *ps1, *ps2; int n1=(int)((uintptr_t)s1&(sizeof(TL)-1)); /* unaligned bytes in s1 */ int n2=(int)((uintptr_t)s2&(sizeof(TL)-1)); /* unaligned bytes in s2 */ if(n1 || n2) { /* either pointer unaligned */ ps1=(TS *)s1; ps2=(TS *)s2; } else { /* both pointers aligned -> compare full words */ pl1=(TL *)s1; pl2=(TL *)s2; while(n>=sizeof(TL)) { n-=sizeof(TL); r|=(*pl1++)^(*pl2++); } ps1=(TS *)pl1; ps2=(TS *)pl2; } while(n--) r|=(*ps1++)^(*ps2++); return r!=0; } /* end of str.c */ stunnel-5.56/src/common.h0000664000175000017500000003512413527755760012342 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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 TLS record payload */ #define BUFFSIZE 18432 /* how many bytes of random input to read from files for PRNG */ /* security margin is huge to compensate for flawed entropy */ #define RANDOM_BYTES 1024 /**************************************** debugging */ /* for FormatGuard */ /* #define __NO_FORMATGUARD_ */ /* additional diagnostic messages */ /* #define DEBUG_FD_ALLOC */ #ifdef DEBUG_INFO #define NOEXPORT #else #define NOEXPORT static #endif #ifdef __GNUC__ #define NORETURN __attribute__((noreturn)) #else #define NORETURN #endif /* __GNUC__ */ /**************************************** 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 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 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 #ifdef HAVE_SYS_PARAM_H #include /* MAXPATHLEN */ #endif #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 /* 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<0x00908060L #define OPENSSL_NO_TLSEXT #endif /* OpenSSL older than 0.9.8f */ #if OPENSSL_VERSION_NUMBER<0x10000000L #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) */ #else /* OpenSSL older than 1.1.0 */ #define X509_STORE_CTX_get0_chain(x) X509_STORE_CTX_get_chain(x) #define OPENSSL_hexstr2buf string_to_hex #endif /* OpenSSL 1.1.0 or newer */ #if OPENSSL_VERSION_NUMBER<0x10101000L #define OPENSSL_NO_TLS1_3 #endif /* OpenSSL older than 1.1.1 */ #if defined(USE_WIN32) && defined(OPENSSL_FIPS) #define USE_FIPS #endif #include #include #include #include #include #include /* for CRYPTO_* and SSLeay_version */ #include #include #include #ifndef OPENSSL_NO_MD4 #include #endif /* !defined(OPENSSL_NO_MD4) */ #include #ifndef OPENSSL_NO_DH #include #if OPENSSL_VERSION_NUMBER<0x10100000L int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g); #endif /* OpenSSL older than 1.1.0 */ #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.56/src/sthreads.c0000664000175000017500000005234213467064764012663 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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" #ifndef USE_FORK CLI *thread_head=NULL; NOEXPORT void thread_list_add(CLI *); #endif /**************************************** thread ID callbacks */ #ifdef USE_UCONTEXT unsigned long stunnel_process_id(void) { return (unsigned long)getpid(); } unsigned long stunnel_thread_id(void) { return ready_head ? ready_head->id : 0; } #endif /* USE_UCONTEXT */ #ifdef USE_FORK unsigned long stunnel_process_id(void) { return (unsigned long)getpid(); } unsigned long stunnel_thread_id(void) { return 0L; } #endif /* USE_FORK */ #ifdef USE_PTHREAD 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 } #endif /* USE_PTHREAD */ #ifdef USE_WIN32 unsigned long stunnel_process_id(void) { return GetCurrentProcessId() & 0x00ffffff; } unsigned long stunnel_thread_id(void) { return GetCurrentThreadId() & 0x00ffffff; } #endif /* USE_WIN32 */ #if OPENSSL_VERSION_NUMBER>=0x10000000L && OPENSSL_VERSION_NUMBER<0x10100004L NOEXPORT void threadid_func(CRYPTO_THREADID *tid) { CRYPTO_THREADID_set_numeric(tid, stunnel_thread_id()); } #endif void thread_id_init(void) { #if OPENSSL_VERSION_NUMBER>=0x10000000L && OPENSSL_VERSION_NUMBER<0x10100000L CRYPTO_THREADID_set_callback(threadid_func); #endif #if OPENSSL_VERSION_NUMBER<0x10000000L || !defined(OPENSSL_NO_DEPRECATED) CRYPTO_set_id_callback(stunnel_thread_id); #endif } /**************************************** locking */ /* we only need to initialize locking with OpenSSL older than 1.1.0 */ #if OPENSSL_VERSION_NUMBER<0x10100004L #ifdef USE_PTHREAD NOEXPORT void s_lock_init_debug(struct CRYPTO_dynlock_value *lock, const char *file, int line) { pthread_rwlock_init(&lock->rwlock, NULL); lock->init_file=file; lock->init_line=line; } NOEXPORT void s_read_lock_debug(struct CRYPTO_dynlock_value *lock, const char *file, int line) { pthread_rwlock_rdlock(&lock->rwlock); lock->read_lock_file=file; lock->read_lock_line=line; } NOEXPORT void s_write_lock_debug(struct CRYPTO_dynlock_value *lock, const char *file, int line) { pthread_rwlock_wrlock(&lock->rwlock); lock->write_lock_file=file; lock->write_lock_line=line; } NOEXPORT void s_unlock_debug(struct CRYPTO_dynlock_value *lock, const char *file, int line) { pthread_rwlock_unlock(&lock->rwlock); lock->unlock_file=file; lock->unlock_line=line; } NOEXPORT void s_lock_destroy_debug(struct CRYPTO_dynlock_value *lock, const char *file, int line) { pthread_rwlock_destroy(&lock->rwlock); lock->destroy_file=file; lock->destroy_line=line; str_free(lock); } #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 */ NOEXPORT void s_lock_init_debug(struct CRYPTO_dynlock_value *lock, const char *file, int line) { InitializeCriticalSection(&lock->critical_section); lock->init_file=file; lock->init_line=line; } NOEXPORT void s_read_lock_debug(struct CRYPTO_dynlock_value *lock, const char *file, int line) { EnterCriticalSection(&lock->critical_section); lock->read_lock_file=file; lock->read_lock_line=line; } NOEXPORT void s_write_lock_debug(struct CRYPTO_dynlock_value *lock, const char *file, int line) { EnterCriticalSection(&lock->critical_section); lock->write_lock_file=file; lock->write_lock_line=line; } NOEXPORT void s_unlock_debug(struct CRYPTO_dynlock_value *lock, const char *file, int line) { LeaveCriticalSection(&lock->critical_section); lock->unlock_file=file; lock->unlock_line=line; } NOEXPORT void s_lock_destroy_debug(struct CRYPTO_dynlock_value *lock, const char *file, int line) { DeleteCriticalSection(&lock->critical_section); lock->destroy_file=file; lock->destroy_line=line; str_free(lock); } #endif /* USE_WIN32 */ NOEXPORT int s_atomic_add(int *val, int amount, CRYPTO_RWLOCK *lock) { int ret; (void)lock; /* squash the unused parameter warning */ #if !defined(USE_OS_THREADS) /* no synchronization is needed */ return *val+=amount; #elif defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) if(__atomic_is_lock_free(sizeof *val, val)) return __atomic_add_fetch(val, amount, __ATOMIC_ACQ_REL); #elif defined(_MSC_VER) return InterlockedExchangeAdd(val, amount)+amount; #endif CRYPTO_THREAD_write_lock(lock); ret=(*val+=amount); CRYPTO_THREAD_unlock(lock); return ret; } #endif /* OPENSSL_VERSION_NUMBER<0x10100004L */ CRYPTO_RWLOCK *stunnel_locks[STUNNEL_LOCKS]; #if OPENSSL_VERSION_NUMBER<0x10100004L #ifdef USE_OS_THREADS static struct CRYPTO_dynlock_value *lock_cs; NOEXPORT struct CRYPTO_dynlock_value *s_dynlock_create_cb(const char *file, int line) { struct CRYPTO_dynlock_value *lock; lock=str_alloc_detached(sizeof(struct CRYPTO_dynlock_value)); s_lock_init_debug(lock, file, line); return lock; } NOEXPORT void s_dynlock_lock_cb(int mode, struct CRYPTO_dynlock_value *lock, const char *file, int line) { 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) s_write_lock_debug(lock, file, line); else s_read_lock_debug(lock, file, line); } else s_unlock_debug(lock, file, line); } NOEXPORT void s_dynlock_destroy_cb(struct CRYPTO_dynlock_value *lock, const char *file, int line) { s_lock_destroy_debug(lock, file, line); str_free(lock); } NOEXPORT void s_locking_cb(int mode, int type, const char *file, int line) { s_dynlock_lock_cb(mode, lock_cs+type, file, line); } NOEXPORT int s_add_lock_cb(int *num, int amount, int type, const char *file, int line) { (void)file; /* squash the unused parameter warning */ (void)line; /* squash the unused parameter warning */ return s_atomic_add(num, amount, lock_cs+type); } CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void) { struct CRYPTO_dynlock_value *lock; lock=str_alloc_detached(sizeof(CRYPTO_RWLOCK)); s_lock_init_debug(lock, __FILE__, __LINE__); return lock; } int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock) { s_read_lock_debug(lock, __FILE__, __LINE__); return 1; } int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock) { s_write_lock_debug(lock, __FILE__, __LINE__); return 1; } int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock) { s_unlock_debug(lock, __FILE__, __LINE__); return 1; } void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock) { s_lock_destroy_debug(lock, __FILE__, __LINE__); str_free(lock); } #else /* USE_OS_THREADS */ CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void) { return NULL; } int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock) { (void)lock; /* squash the unused parameter warning */ return 1; } int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock) { (void)lock; /* squash the unused parameter warning */ return 1; } int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock) { (void)lock; /* squash the unused parameter warning */ return 1; } void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock) { (void)lock; /* squash the unused parameter warning */ } #endif /* USE_OS_THREADS */ int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock) { *ret=s_atomic_add(val, amount, lock); return 1; } #endif /* OPENSSL_VERSION_NUMBER<0x10100004L */ void locking_init(void) { size_t i; #if defined(USE_OS_THREADS) && OPENSSL_VERSION_NUMBER<0x10100004L size_t num; /* initialize the OpenSSL static locking */ num=(size_t)CRYPTO_num_locks(); lock_cs=str_alloc_detached(num*sizeof(struct CRYPTO_dynlock_value)); for(i=0; iid=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) { thread_id_init(); locking_init(); /* 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) { 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))client_thread, ARGC, arg); thread_list_add(arg); s_log(LOG_DEBUG, "New context created"); return 0; } #endif /* USE_UCONTEXT */ #ifdef USE_FORK int sthreads_init(void) { thread_id_init(); locking_init(); return 0; } 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) { 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); client_thread(arg); _exit(0); default: /* parent */ str_free(arg); if(s>=0) closesocket(s); } return 0; } #endif /* USE_FORK */ #ifdef USE_PTHREAD NOEXPORT void *dummy_thread(void *arg) { pthread_exit(arg); return arg; } int sthreads_init(void) { pthread_t thread_id; /* this is a workaround for NPTL threads failing to invoke * pthread_exit() or pthread_cancel() from a chroot jail */ if(!pthread_create(&thread_id, NULL, dummy_thread, NULL)) pthread_join(thread_id, NULL); thread_id_init(); locking_init(); return 0; } int create_client(SOCKET ls, SOCKET s, CLI *arg) { 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_setstacksize(&pth_attr, arg->opt->stack_size); CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_THREAD_LIST]); error=pthread_create(&arg->thread_id, &pth_attr, client_thread, 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"); CRYPTO_THREAD_unlock(stunnel_locks[LOCK_THREAD_LIST]); str_free(arg); if(s>=0) closesocket(s); return -1; } thread_list_add(arg); CRYPTO_THREAD_unlock(stunnel_locks[LOCK_THREAD_LIST]); return 0; } #endif /* USE_PTHREAD */ #ifdef USE_WIN32 #if !defined(_MT) #error _beginthreadex requires a multithreaded C run-time library #endif int sthreads_init(void) { thread_id_init(); locking_init(); return 0; } int create_client(SOCKET ls, SOCKET s, CLI *arg) { (void)ls; /* this parameter is only used with USE_FORK */ s_log(LOG_DEBUG, "Creating a new thread"); CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_THREAD_LIST]); arg->thread_id=(HANDLE)_beginthreadex(NULL, (unsigned)arg->opt->stack_size, client_thread, arg, STACK_SIZE_PARAM_IS_A_RESERVATION, NULL); if(!arg->thread_id) { ioerror("_beginthreadex"); CRYPTO_THREAD_unlock(stunnel_locks[LOCK_THREAD_LIST]); str_free(arg); if(s!=INVALID_SOCKET) closesocket(s); return -1; } thread_list_add(arg); CRYPTO_THREAD_unlock(stunnel_locks[LOCK_THREAD_LIST]); 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)ls; /* this parameter is only used with USE_FORK */ s_log(LOG_DEBUG, "Creating a new thread"); if((long)_beginthread(client_thread, 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 uintptr_t _beginthreadex(void *security, unsigned stack_size, unsigned ( __stdcall *start_address)(void *), void *arglist, unsigned initflag, unsigned *thrdaddr) { return CreateThread(NULL, stack_size, (LPTHREAD_START_ROUTINE)start_address, arglist, (DWORD)initflag, (LPDWORD)thrdaddr); } void _endthreadex(unsigned retval) { ExitThread(retval); } #endif /* _WIN32_WCE */ #ifdef DEBUG_STACK_SIZE #define STACK_RESERVE 16384 /* some heuristic to determine the usage of client stack size */ NOEXPORT size_t stack_num(size_t stack_size, int init) { #ifdef _WIN64 typedef unsigned long long TL; #else typedef unsigned long TL; #endif size_t verify_area, verify_num, i; TL test_value, *table; if(stack_size=16) return stack_size-i*sizeof(TL); /* the stack grows up */ for(i=0; i=16) return stack_size-(i*sizeof(TL)+STACK_RESERVE); return 0; /* not enough samples for meaningful results */ } } #ifdef __GNUC__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic push #endif /* __GNUC__>=4.6 */ #pragma GCC diagnostic ignored "-Wformat" #endif /* __GNUC__ */ void stack_info(size_t stack_size, int init) { /* 1-initialize, 0-display */ static size_t max_num=0; size_t num; #ifdef USE_WIN32 SYSTEM_INFO si; GetSystemInfo(&si); stack_size&=~((size_t)si.dwPageSize-1); #elif defined(_SC_PAGESIZE) stack_size&=~((size_t)sysconf(_SC_PAGESIZE)-1); #elif defined(_SC_PAGE_SIZE) stack_size&=~((size_t)sysconf(_SC_PAGE_SIZE)-1); #else stack_size&=~(4096-1); /* just a guess */ #endif num=stack_num(stack_size, init); if(init) return; if(!num) { s_log(LOG_NOTICE, "STACK_RESERVE is too high"); return; } if(num>max_num) max_num=num; s_log(LOG_NOTICE, #ifdef USE_WIN32 "stack_info: size=%Iu, current=%Iu (%Iu%%), maximum=%Iu (%Iu%%)", #else "stack_info: size=%zu, current=%zu (%zu%%), maximum=%zu (%zu%%)", #endif stack_size, num, num*100/stack_size, max_num, max_num*100/stack_size); } #ifdef __GNUC__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic pop #endif /* __GNUC__>=4.6 */ #endif /* __GNUC__ */ #endif /* DEBUG_STACK_SIZE */ #ifndef USE_FORK NOEXPORT void thread_list_add(CLI *c) { c->thread_next=thread_head; c->thread_prev=NULL; if(thread_head) thread_head->thread_prev=c; thread_head=c; } #endif /* !USE_FORK */ /* end of sthreads.c */ stunnel-5.56/src/idle.ico0000664000175000017500000000217612634035772012303 00000000000000 h(   #` # # # # # # #` # # ##*+I1^ 1^ ,N#* # # # # # #*D6s6s+I # # # # #(?6s`p6s*D # # #` # #5n6sܿܿ6s5n!$! # #` # #&46s6sӯӯ6s6s&4 # # # #*D6s6s\0h@6s6s+I # # # #&46s6s6sO O 6s6s6s(? # # # ##*6s6s6s6s6s6s6s6s6s6s#* # # # # #.T 6s6s6s6s6s6s6s6s.T # # # # # #!$!2c6s6s6s6s6s6s2c!$! # # # #` # # #!$!+I3i6s6s3i+I!$! # # # #` # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #` # # # # # # #`stunnel-5.56/src/prototypes.h0000664000175000017500000007011313467064764013277 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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 PROTOTYPES_H #define PROTOTYPES_H #include "common.h" #if defined(USE_PTHREAD) || defined(USE_WIN32) #define USE_OS_THREADS #endif /**************************************** forward declarations */ typedef struct tls_data_struct TLS_DATA; typedef struct sock_opt_struct SOCK_OPT; /**************************************** data structures */ #ifdef USE_PTHREAD typedef pthread_t THREAD_ID; #endif #ifdef USE_WIN32 typedef HANDLE THREAD_ID; #endif #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_BUFFER, LOG_MODE_ERROR, LOG_MODE_INFO, LOG_MODE_CONFIGURED } LOG_MODE; typedef enum { LOG_ID_SEQUENTIAL, LOG_ID_UNIQUE, LOG_ID_THREAD, LOG_ID_PROCESS } 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 */ struct sockaddr_list *parent; /* used by copies to locate their parent */ SOCKADDR_UNION *addr; /* array of resolved addresses */ unsigned start; /* initial address for round-robin failover */ 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 TLS 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 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 configuration */ #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; unsigned 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) */ #if OPENSSL_VERSION_NUMBER>=0x10000000L typedef struct ticket_key_struct { unsigned char *key_val; int key_len; } TICKET_KEY; #endif /* OpenSSL 1.0.0 or later */ typedef struct service_options_struct { struct service_options_struct *next; /* next node in the services list */ SSL_CTX *ctx; /* TLS context */ char *servname; /* service name for logging & permission checking */ int ref; /* reference counter for delayed deallocation */ /* service-specific data for stunnel.c */ #ifndef USE_WIN32 uid_t uid; gid_t gid; #endif int bound_ports; /* number of ports bound to this service */ /* 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 /* some global data for network.c */ SOCK_OPT *sock_opts; /* 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 */ #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; #ifndef OPENSSL_NO_TLS1_3 char *ciphersuites; #endif /* TLS 1.3 */ 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 */ #if OPENSSL_VERSION_NUMBER>=0x10100000L int min_proto_version, max_proto_version; #else /* OPENSSL_VERSION_NUMBER<0x10100000L */ SSL_METHOD *client_method, *server_method; #endif /* OPENSSL_VERSION_NUMBER<0x10100000L */ 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 char *curves; #endif /* !defined(OPENSSL_NO_ECDH) */ #ifndef OPENSSL_NO_ENGINE ENGINE *engine; /* engine to read the private key */ #endif /* !defined(OPENSSL_NO_ENGINE) */ #if OPENSSL_VERSION_NUMBER>=0x10000000L TICKET_KEY *ticket_key; /* key for handling session tickets */ TICKET_KEY *ticket_mac; /* key for protecting session tickets */ #endif /* OpenSSL 1.0.0 or later */ /* service-specific data for client.c */ 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 source_addr; SOCKADDR_LIST local_addr, connect_addr, redirect_addr; SOCKET *local_fd; /* array of accepting file descriptors */ SSL_SESSION **connect_session; /* per-destination client session cache */ SSL_SESSION *session; /* previous client session for delayed resolver */ 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 */ unsigned rr; /* per-service sequential number for round-robin failover */ 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 request_cert:1; /* request a peer certificate */ unsigned require_cert:1; /* require a client certificate */ unsigned verify_chain:1; /* verify certificate chain */ unsigned verify_peer:1; /* verify peer certificate */ 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 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_temp_params:1; #endif /* OPENSSL_NO_DH */ #ifndef USE_WIN32 unsigned log_stderr:1; /* a copy of the global switch */ #endif /* USE_WIN32 */ } 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; struct sock_opt_struct { char *opt_str; int opt_level; int opt_name; VAL_TYPE opt_type; OPT_UNION *opt_val[3]; }; 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 int main_thread; } s_poll_set; typedef struct disk_file { #ifdef USE_WIN32 HANDLE fh; #else int fd; #endif /* the interface 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 client_data_struct { jmp_buf *exception_pointer; SSL *ssl; /* TLS connection */ SERVICE_OPTIONS *opt; TLS_DATA *tls; #ifdef USE_OS_THREADS THREAD_ID thread_id; #endif #ifndef USE_FORK struct client_data_struct *thread_prev, *thread_next; #endif SOCKADDR_UNION peer_addr; /* peer address */ socklen_t peer_addr_len; char *accepted_address; /* textual representation of the peer address */ SOCKADDR_UNION *bind_addr; /* address to bind() the socket */ SOCKADDR_LIST connect_addr; /* either copied or resolved dynamically */ unsigned idx; /* actually connected address in connect_addr */ FD local_rfd, local_wfd; /* read and write local descriptors */ FD remote_fd; /* remote file descriptor */ 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 */ unsigned rr; /* per-client sequential number for round-robin failover */ /* data for transfer() function */ char sock_buff[BUFFSIZE]; /* socket read buffer */ char ssl_buff[BUFFSIZE]; /* TLS 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 TLS descriptors */ uint64_t sock_bytes, ssl_bytes; /* bytes written to socket and TLS */ s_poll_set *fds; /* file descriptors */ struct { unsigned psk:1; /* PSK identity was found */ } flag; } CLI; /**************************************** prototypes for stunnel.c */ #ifndef USE_FORK extern int max_clients; extern int num_clients; #endif extern SOCKET signal_pipe[2]; extern SOCKET terminate_pipe[2]; 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(uint8_t); #if !defined(USE_WIN32) && !defined(USE_OS2) void pid_status_hang(const char *); #endif void stunnel_info(int); /**************************************** prototypes for options.c */ extern char *configuration_file; extern unsigned number_of_sections; int options_cmdline(char *, char *); int options_parse(CONF_TYPE); void options_defaults(void); void options_apply(void); void options_free(void); void service_up_ref(SERVICE_OPTIONS *); void service_free(SERVICE_OPTIONS *); /**************************************** 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 */ #define SINK_SYSLOG 1 #define SINK_OUTFILE 2 int log_open(int); void log_close(int); 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) NORETURN; #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); void bin2hexstring(const unsigned char *, size_t, char *, size_t); /**************************************** prototypes for pty.c */ int pty_allocate(int *, int *, char *); /**************************************** prototypes for dhparam.c */ DH *get_dh2048(void); /**************************************** prototypes for cron.c */ #ifdef USE_OS_THREADS extern THREAD_ID cron_thread_id; #endif int cron_init(void); /**************************************** prototypes for ssl.c */ extern int index_ssl_cli, index_ssl_ctx_opt; extern int index_session_authenticated, index_session_connect_address; int ssl_init(void); int ssl_configure(GLOBAL_OPTIONS *); /**************************************** prototypes for ctx.c */ extern SERVICE_OPTIONS *current_section; #ifndef OPENSSL_NO_DH extern DH *dh_params; extern int dh_temp_params; #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 print_session_id(SSL_SESSION *); void sslerror(char *); /**************************************** prototypes for verify.c */ int verify_init(SERVICE_OPTIONS *); void print_client_CA_list(const STACK_OF(X509_NAME) *); 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 *, int); 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_err(s_poll_set *, SOCKET); int s_poll_wait(s_poll_set *, int, int); void s_poll_dump(s_poll_set *, int); void s_poll_sleep(int, int); #ifdef USE_WIN32 #define SIGNAL_TERMINATE 1 #define SIGNAL_RELOAD_CONFIG 2 #define SIGNAL_REOPEN_LOG 3 #define SIGNAL_CONNECTIONS 4 #else #define SIGNAL_TERMINATE SIGTERM #define SIGNAL_RELOAD_CONFIG SIGHUP #define SIGNAL_REOPEN_LOG SIGUSR1 #define SIGNAL_CONNECTIONS SIGUSR2 #endif int socket_options_set(SERVICE_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); #if defined(USE_WIN32) || defined(USE_OS2) unsigned __stdcall #else void * #endif client_thread(void *); void client_main(CLI *); void client_free(CLI *); void throw_exception(CLI *, int) NORETURN; /**************************************** prototypes for network.c */ int get_socket_error(const SOCKET); 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 *); 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 */ #ifndef USE_FORK extern CLI *thread_head; #endif #if OPENSSL_VERSION_NUMBER<0x10100004L #ifdef USE_OS_THREADS struct CRYPTO_dynlock_value { #ifdef USE_PTHREAD pthread_rwlock_t rwlock; #endif #ifdef USE_WIN32 CRITICAL_SECTION critical_section; #endif const char *init_file, *read_lock_file, *write_lock_file, *unlock_file, *destroy_file; int init_line, read_lock_line, write_lock_line, unlock_line, destroy_line; }; typedef struct CRYPTO_dynlock_value CRYPTO_RWLOCK; #else /* USE_OS_THREADS */ typedef void CRYPTO_RWLOCK; #endif /* USE_OS_THREADS */ #endif /* OPENSSL_VERSION_NUMBER<0x10100004L */ typedef enum { LOCK_THREAD_LIST, /* sthreads.c */ LOCK_SESSION, LOCK_ADDR, LOCK_CLIENTS, LOCK_SSL, /* client.c */ LOCK_REF, /* options.c */ LOCK_INET, /* resolver.c */ #ifndef USE_WIN32 LOCK_LIBWRAP, /* libwrap.c */ #endif LOCK_LOG_BUFFER, LOCK_LOG_MODE, /* log.c */ LOCK_LEAK_HASH, LOCK_LEAK_RESULTS, /* str.c */ #ifndef OPENSSL_NO_DH LOCK_DH, /* ctx.c */ #endif /* OPENSSL_NO_DH */ #ifdef USE_WIN32 LOCK_WIN_LOG, /* ui_win_gui.c */ #endif LOCK_SECTIONS, /* traversing section list */ STUNNEL_LOCKS /* number of locks */ } LOCK_TYPE; extern CRYPTO_RWLOCK *stunnel_locks[STUNNEL_LOCKS]; #if OPENSSL_VERSION_NUMBER<0x10100004L /* Emulate the OpenSSL 1.1 locking API for older OpenSSL versions */ CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void); int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *); int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *); int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *); void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *); int CRYPTO_atomic_add(int *, int, int *, CRYPTO_RWLOCK *); #endif int sthreads_init(void); unsigned long stunnel_process_id(void); unsigned long stunnel_thread_id(void); int create_client(SOCKET, SOCKET, CLI *); #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(size_t, int); void ignore_value(void *); #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 *); /**************************************** 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_dup_detached_debug(const char *, const char *, int); #define str_dup_detached(a) str_dup_detached_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_realloc_detached_debug(void *, size_t, const char *, int); #define str_realloc_detached(a, b) str_realloc_detached_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__) void leak_table_utilization(void); 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 ui_passwd_cb(char *, int, int, void *); #ifndef OPENSSL_NO_ENGINE UI_METHOD *UI_stunnel(void); #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.56/src/error.ico0000664000175000017500000000217612634035772012517 00000000000000 h(   #` # # # # # # #` # # #!<"##"!< # # # # # #"{$$" # # # # #"o$vq$"{ # # #` # #$$$$ 0 # #` # #!V$$$$!V # # # #"{$$MG[U$$" # # # #!V$$$?8?8$$$"o # # # #!<$$$$$$$$$$!< # # # # ##$$$$$$$$# # # # # # # 0#$$$$$$# 0 # # # #` # # # 0"$$$$" 0 # # # #` # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #` # # # # # # #`stunnel-5.56/src/dhparam.c0000664000175000017500000000456113527755760012462 00000000000000/* dhparam.c: initial DH parameters for stunnel */ #include "common.h" #ifndef OPENSSL_NO_DH #define DN_new DH_new DH *get_dh2048(void) { static unsigned char dhp_2048[] = { 0xD5, 0x75, 0xF1, 0x23, 0xC1, 0x81, 0x4B, 0x44, 0x23, 0xBE, 0x97, 0x81, 0x7A, 0xDA, 0x97, 0x1F, 0x1F, 0x0D, 0xD5, 0xEC, 0xC5, 0x5F, 0x86, 0x42, 0x7F, 0x38, 0xA3, 0x95, 0xEE, 0xA0, 0x52, 0x2C, 0xB7, 0x20, 0x29, 0xC1, 0xC7, 0xE6, 0x8E, 0x6F, 0xE5, 0xC1, 0x0D, 0xDD, 0x8A, 0xEF, 0x8D, 0xE7, 0xA8, 0x63, 0xB4, 0xF7, 0x58, 0x32, 0x0E, 0x24, 0xAC, 0x30, 0x94, 0xF5, 0xC7, 0x02, 0x81, 0x1B, 0xC7, 0x68, 0xE5, 0x71, 0xD7, 0x1E, 0x3D, 0xE4, 0x2E, 0x2F, 0xC0, 0x0A, 0xED, 0x34, 0xAC, 0xC0, 0x1F, 0x0A, 0x56, 0xA4, 0x12, 0x02, 0xFD, 0x68, 0xD2, 0x4D, 0x5E, 0x0A, 0x5D, 0x78, 0xE3, 0xA0, 0x85, 0x75, 0xD2, 0xA9, 0xC1, 0xF2, 0xAD, 0x65, 0x11, 0xDE, 0xE8, 0x05, 0x68, 0x36, 0x4C, 0x92, 0x99, 0x21, 0xB9, 0x69, 0xD0, 0x6F, 0xD8, 0xA3, 0xEA, 0x35, 0x13, 0x93, 0xDC, 0x1B, 0x13, 0x16, 0xB2, 0x15, 0x8E, 0x10, 0x22, 0xCE, 0x01, 0x1F, 0x1C, 0x09, 0x86, 0xD5, 0xE7, 0xCB, 0xCF, 0xFA, 0xED, 0x2F, 0xE2, 0x3A, 0x65, 0x14, 0xC9, 0xFA, 0x70, 0x99, 0xF7, 0xE0, 0x30, 0xBF, 0x7F, 0xEA, 0x84, 0x14, 0x8A, 0x51, 0xC9, 0xE9, 0x85, 0x73, 0x7F, 0xA1, 0xB0, 0xC3, 0x33, 0x9A, 0xAB, 0x69, 0x4E, 0x75, 0xFB, 0x12, 0xB0, 0x9E, 0xB1, 0xD9, 0xD1, 0xB9, 0x32, 0x1D, 0xC6, 0xD9, 0x2C, 0xAA, 0xB0, 0xC5, 0x3E, 0x69, 0x56, 0xA2, 0xB3, 0xA2, 0x81, 0xCA, 0x9D, 0x77, 0xBB, 0x52, 0x44, 0xA2, 0xED, 0xE0, 0xF0, 0x2A, 0x81, 0x85, 0x90, 0xB6, 0x04, 0x60, 0xEB, 0x09, 0x72, 0x08, 0x44, 0xAF, 0x28, 0xF5, 0x15, 0x34, 0x87, 0x5C, 0x8A, 0xB4, 0x5B, 0x15, 0x6A, 0xAD, 0x27, 0x4E, 0xA0, 0xDE, 0x99, 0x22, 0xCF, 0xAB, 0x4C, 0xFD, 0x75, 0x10, 0x5D, 0xFF, 0xE8, 0x81, 0x50, 0xC4, 0xC0, 0x4B }; static unsigned char dhg_2048[] = { 0x02 }; DH *dh = DH_new(); BIGNUM *p, *g; if (dh == NULL) return NULL; p = BN_bin2bn(dhp_2048, sizeof(dhp_2048), NULL); g = BN_bin2bn(dhg_2048, sizeof(dhg_2048), NULL); if (p == NULL || g == NULL || !DH_set0_pqg(dh, p, NULL, g)) { DH_free(dh); BN_free(p); BN_free(g); return NULL; } return dh; } #endif /* OPENSSL_NO_DH */ /* built for stunnel 5.56 */ stunnel-5.56/src/ui_win_cli.c0000664000175000017500000001120213467064764013155 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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 ui_passwd_cb(char *buf, int size, int rwflag, void *userdata) { return PEM_def_callback(buf, size, rwflag, userdata); } #ifndef OPENSSL_NO_ENGINE UI_METHOD *UI_stunnel() { return UI_OpenSSL(); } #endif /* end of ui_win_cli.c */ stunnel-5.56/src/os2.mak0000664000175000017500000000424313527755760012074 00000000000000prefix=. DEFS = -DPACKAGE_NAME=\"stunnel\" \ -DPACKAGE_TARNAME=\"stunnel\" \ -DPACKAGE_VERSION=\"5.56\" \ -DPACKAGE_STRING=\"stunnel\ 5.56\" \ -DPACKAGE_BUGREPORT=\"\" \ -DPACKAGE=\"stunnel\" \ -DVERSION=\"5.56\" \ -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.56/src/config.h.in0000664000175000017500000002317313527761630012716 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_PARAM_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 where 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 /* TLS 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 /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 #endif /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Use GNU source */ #undef _GNU_SOURCE /* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES /* 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.56/src/makew32.bat0000664000175000017500000000352612575611547012637 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.56/src/stunnel.c0000664000175000017500000010301013554262513012510 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic push #endif /* __GNUC__>=4.6 */ #pragma GCC diagnostic ignored "-Wpedantic" #endif /* __GNUC__ */ #include #ifdef __GNUC__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic pop #endif /* __GNUC__>=4.6 */ #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 #if !defined(USE_WIN32) && !defined(USE_OS2) NOEXPORT void pid_status_nohang(const char *); NOEXPORT void status_info(int, int, const char *); #endif NOEXPORT int accept_connection(SERVICE_OPTIONS *, unsigned); NOEXPORT int exec_connect_start(void); NOEXPORT void unbind_port(SERVICE_OPTIONS *, unsigned); NOEXPORT SOCKET bind_port(SERVICE_OPTIONS *, int, unsigned); #ifdef HAVE_CHROOT NOEXPORT int change_root(void); #endif NOEXPORT int pipe_init(SOCKET [2], char *); NOEXPORT int signal_pipe_dispatch(void); NOEXPORT void reload_config(); NOEXPORT int process_connections(void); NOEXPORT char *signal_name(int); /**************************************** global variables */ SOCKET signal_pipe[2]={INVALID_SOCKET, INVALID_SOCKET}; SOCKET terminate_pipe[2]={INVALID_SOCKET, INVALID_SOCKET}; #ifndef USE_FORK int max_clients=0; /* -1 before a valid config is loaded, then the current number of clients */ int 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) s_log(LOG_INFO, "Systemd socket activation: %d descriptors received", systemd_fds); } /* return values: 0 - configuration accepted 1 - error 2 - information printed */ /* configuration-dependent initialization */ int main_configure(char *arg1, char *arg2) { int cmdline_status; cmdline_status=options_cmdline(arg1, arg2); if(cmdline_status) /* cannot proceed */ return cmdline_status; options_apply(); str_canary_init(); /* needs prng initialization from options_cmdline */ /* log_open(SINK_SYSLOG) must be called before change_root() * to be able to access /dev/log socket */ log_open(SINK_SYSLOG); if(bind_ports()) return 1; #ifdef HAVE_CHROOT /* change_root() must be called before drop_privileges() * since chroot() needs root privileges */ if(change_root()) return 1; #endif /* HAVE_CHROOT */ if(drop_privileges(1)) return 1; /* log_open(SINK_OUTFILE) must be called after drop_privileges() * or logfile rotation won't be possible */ if(log_open(SINK_OUTFILE)) return 1; #ifndef USE_FORK num_clients=0; /* the first valid config */ #endif /* log_flush(LOG_MODE_CONFIGURED) must be called before daemonize() * since daemonize() invalidates stderr */ log_flush(LOG_MODE_CONFIGURED); return 0; } int drop_privileges(int critical) { #if defined(USE_WIN32) || defined(__vms) || defined(USE_OS2) (void)critical; /* squash the unused parameter warning */ #else #ifdef HAVE_SETGROUPS gid_t gr_list[1]; #endif /* set uid and gid */ if(service_options.gid) { if(setgid(service_options.gid) && critical) { sockerror("setgid"); return 1; } #ifdef HAVE_SETGROUPS gr_list[0]=service_options.gid; if(setgroups(1, gr_list) && critical) { sockerror("setgroups"); return 1; } #endif } if(service_options.uid) { if(setuid(service_options.uid) && critical) { sockerror("setuid"); return 1; } } #endif /* standard Unix */ return 0; } #ifdef __GNUC__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-result" #endif /* __GNUC__>=4.6 */ #endif /* __GNUC__ */ void main_cleanup() { #ifdef USE_OS_THREADS CLI *c; unsigned i, threads; THREAD_ID *thread_list; CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_THREAD_LIST]); threads=0; for(c=thread_head; c; c=c->thread_next) /* count client threads */ threads++; thread_list=str_alloc((threads+1)*sizeof(THREAD_ID)); i=0; for(c=thread_head; c; c=c->thread_next) { /* copy client threads */ thread_list[i++]=c->thread_id; s_log(LOG_DEBUG, "Terminating a thread for [%s]", c->opt->servname); } if(cron_thread_id) { /* append cron_thread_id if used */ thread_list[threads++]=cron_thread_id; s_log(LOG_DEBUG, "Terminating the cron thread"); } CRYPTO_THREAD_unlock(stunnel_locks[LOCK_THREAD_LIST]); if(threads) { s_log(LOG_NOTICE, "Terminating %u service thread(s)", threads); writesocket(terminate_pipe[1], "", 1); for(i=0; i 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic pop #endif /* __GNUC__>=4.6 */ #endif /* __GNUC__ */ /**************************************** Unix-specific initialization */ #if !defined(USE_WIN32) && !defined(USE_OS2) NOEXPORT void pid_status_nohang(const char *info) { int pid, status; #ifdef HAVE_WAITPID /* POSIX.1 */ s_log(LOG_DEBUG, "Retrieving pid statuses with waitpid()"); while((pid=waitpid(-1, &status, WNOHANG))>0) status_info(pid, status, info); #elif defined(HAVE_WAIT4) /* 4.3BSD */ s_log(LOG_DEBUG, "Retrieving pid statuses with wait4()"); while((pid=wait4(-1, &status, WNOHANG, NULL))>0) status_info(pid, status, info); #else /* no support for WNOHANG */ pid_status_hang(info); #endif } void pid_status_hang(const char *info) { int pid, status; s_log(LOG_DEBUG, "Retrieving a pid status with wait()"); if((pid=wait(&status))>0) status_info(pid, status, info); } NOEXPORT void status_info(int pid, int status, const char *info) { #ifdef WIFSIGNALED if(WIFSIGNALED(status)) { char *sig_name=signal_name(WTERMSIG(status)); s_log(LOG_INFO, "%s %d terminated on %s", info, pid, sig_name); str_free(sig_name); } else { s_log(LOG_INFO, "%s %d finished with code %d", info, pid, WEXITSTATUS(status)); } #else s_log(LOG_INFO, "%s %d finished with status %d", info, pid, status); #endif } #endif /* !defined(USE_WIN32) && !defined(USE_OS2) */ /**************************************** main loop accepting connections */ void daemon_loop(void) { if(cron_init()) { /* initialize periodic events */ s_log(LOG_CRIT, "Cron initialization failed"); exit(1); } if(exec_connect_start()) { s_log(LOG_CRIT, "Failed to start exec+connect services"); exit(1); } 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) { unsigned i; for(i=0; ilocal_addr.num; ++i) { SOCKET fd=opt->local_fd[i]; if(fd!=INVALID_SOCKET && s_poll_canread(fds, fd) && accept_connection(opt, i)) 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"); s_poll_sleep(1, 0); /* to avoid log trashing */ } } leak_table_utilization(); } /* return 1 when a short delay is needed before another try */ NOEXPORT int accept_connection(SERVICE_OPTIONS *opt, unsigned i) { SOCKADDR_UNION addr; char *from_address; SOCKET s, fd=opt->local_fd[i]; socklen_t addrlen; addrlen=sizeof addr; for(;;) { s=s_accept(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 (>=%d)", max_clients); closesocket(s); return 0; } #endif #ifndef USE_FORK service_up_ref(opt); #endif if(create_client(fd, s, alloc_client_session(opt, s, s))) { s_log(LOG_ERR, "Connection rejected: create_client failed"); closesocket(s); #ifndef USE_FORK service_free(opt); #endif return 0; } return 0; } /**************************************** initialization helpers */ NOEXPORT int exec_connect_start(void) { SERVICE_OPTIONS *opt; for(opt=service_options.next; opt; opt=opt->next) { if(opt->exec_name && opt->connect_addr.names) { s_log(LOG_DEBUG, "Starting exec+connect service [%s]", opt->servname); #ifndef USE_FORK service_up_ref(opt); #endif if(create_client(INVALID_SOCKET, INVALID_SOCKET, alloc_client_session(opt, INVALID_SOCKET, INVALID_SOCKET))) { s_log(LOG_ERR, "Failed to start exec+connect service [%s]", opt->servname); #ifndef USE_FORK service_free(opt); #endif return 1; /* fatal error */ } } } return 0; /* OK */ } /* clear fds, close old ports */ void unbind_ports(void) { SERVICE_OPTIONS *opt; s_poll_init(fds, 1); CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_SECTIONS]); opt=service_options.next; service_options.next=NULL; service_free(&service_options); while(opt) { unsigned i; s_log(LOG_DEBUG, "Unbinding service [%s]", opt->servname); for(i=0; ilocal_addr.num; ++i) unbind_port(opt, i); /* exec+connect service */ 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? */ /* FIXME: this won't work with FORK threads */ 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); { SERVICE_OPTIONS *garbage=opt; opt=opt->next; garbage->next=NULL; service_free(garbage); } } CRYPTO_THREAD_unlock(stunnel_locks[LOCK_SECTIONS]); } NOEXPORT void unbind_port(SERVICE_OPTIONS *opt, unsigned i) { SOCKET fd=opt->local_fd[i]; #ifdef HAVE_STRUCT_SOCKADDR_UN SOCKADDR_UNION *addr=opt->local_addr.addr+i; struct stat sb; /* buffer for lstat() */ #endif if(fd==INVALID_SOCKET) return; opt->local_fd[i]=INVALID_SOCKET; if(fd<(SOCKET)listen_fds_start || fd>=(SOCKET)(listen_fds_start+systemd_fds)) closesocket(fd); s_log(LOG_DEBUG, "Service [%s] closed (FD=%ld)", opt->servname, (long)fd); #ifdef HAVE_STRUCT_SOCKADDR_UN if(addr->sa.sa_family==AF_UNIX) { if(lstat(addr->un.sun_path, &sb)) sockerror(addr->un.sun_path); else if(!S_ISSOCK(sb.st_mode)) s_log(LOG_ERR, "Not a socket: %s", addr->un.sun_path); else if(unlink(addr->un.sun_path)) sockerror(addr->un.sun_path); else s_log(LOG_DEBUG, "Socket removed: %s", addr->un.sun_path); } #endif } /* open new ports, update fds */ int bind_ports(void) { SERVICE_OPTIONS *opt; int listening_section; #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, 1); /* allow clean unbind_ports() even though bind_ports() was not fully performed */ for(opt=service_options.next; opt; opt=opt->next) { unsigned i; for(i=0; ilocal_addr.num; ++i) opt->local_fd[i]=INVALID_SOCKET; } listening_section=0; for(opt=service_options.next; opt; opt=opt->next) { opt->bound_ports=0; if(opt->local_addr.num) { /* ports to bind for this service */ unsigned i; s_log(LOG_DEBUG, "Binding service [%s]", opt->servname); for(i=0; ilocal_addr.num; ++i) { SOCKET fd; fd=bind_port(opt, listening_section, i); opt->local_fd[i]=fd; if(fd!=INVALID_SOCKET) { s_poll_add(fds, fd, 1, 0); ++opt->bound_ports; } } if(!opt->bound_ports) { s_log(LOG_ERR, "Binding service [%s] failed", opt->servname); return 1; } ++listening_section; } else if(opt->exec_name && opt->connect_addr.names) { s_log(LOG_DEBUG, "Skipped exec+connect service [%s]", opt->servname); #ifndef OPENSSL_NO_TLSEXT } else if(!opt->option.client && opt->sni) { s_log(LOG_DEBUG, "Skipped SNI slave service [%s]", opt->servname); #endif } else { /* each service must define two endpoints */ s_log(LOG_ERR, "Invalid service [%s]", opt->servname); return 1; } } if(listening_sectionlocal_addr.addr+i; #ifdef HAVE_STRUCT_SOCKADDR_UN struct stat sb; /* buffer for lstat() */ #endif if(listening_sectionsa.sa_family, SOCK_STREAM, 0, 1, "accept socket"); if(fd==INVALID_SOCKET) return INVALID_SOCKET; s_log(LOG_DEBUG, "Listening file descriptor created (FD=%ld)", (long)fd); } if(socket_options_set(opt, fd, 0)<0) { closesocket(fd); return INVALID_SOCKET; } /* we don't bind or listen on a socket inherited from systemd */ if(listening_section>=systemd_fds) { if(bind(fd, &addr->sa, addr_len(addr))) { int err=get_last_socket_error(); char *requested_bind_address; /* local socket can't be unnamed */ requested_bind_address=s_ntop(addr, addr_len(addr)); s_log(LOG_NOTICE, "Binding service [%s] to %s: %s (%d)", opt->servname, requested_bind_address, s_strerror(err), err); str_free(requested_bind_address); closesocket(fd); return INVALID_SOCKET; } if(listen(fd, SOMAXCONN)) { sockerror("listen"); closesocket(fd); return INVALID_SOCKET; } } #ifdef HAVE_STRUCT_SOCKADDR_UN /* chown the UNIX socket, errors are ignored */ if(addr->sa.sa_family==AF_UNIX && (opt->uid || opt->gid)) { /* fchown() does *not* work on UNIX sockets */ if(!lchown(addr->un.sun_path, opt->uid, opt->gid)) s_log(LOG_DEBUG, "Socket chown succeeded: %s, UID=%u, GID=%u", addr->un.sun_path, (unsigned)opt->uid, (unsigned)opt->gid); else if(lstat(addr->un.sun_path, &sb)) sockerror(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", addr->un.sun_path, (unsigned)opt->uid, (unsigned)opt->gid); else s_log(LOG_ERR, "Socket chown failed: %s, UID=%u, GID=%u", addr->un.sun_path, (unsigned)opt->uid, (unsigned)opt->gid); } #endif { SOCKADDR_UNION assigned_addr; socklen_t assigned_addr_len=sizeof assigned_addr; char *assigned_bind_address; if(getsockname(fd, &assigned_addr.sa, &assigned_addr_len)) { sockerror("getsockname"); closesocket(fd); return INVALID_SOCKET; } assigned_bind_address=s_ntop(&assigned_addr, addr_len(&assigned_addr)); s_log(LOG_INFO, "Service [%s] (FD=%ld) bound to %s", opt->servname, (long)fd, assigned_bind_address); str_free(assigned_bind_address); } return fd; } #ifdef HAVE_CHROOT NOEXPORT int change_root(void) { if(!global_options.chroot_dir) return 0; if(chroot(global_options.chroot_dir)) { sockerror("chroot"); return 1; } if(chdir("/")) { sockerror("chdir"); return 1; } s_log(LOG_NOTICE, "Switched to chroot directory: %s", global_options.chroot_dir); return 0; } #endif /* HAVE_CHROOT */ /**************************************** signal pipe handling */ NOEXPORT int pipe_init(SOCKET socket_vector[2], char *name) { #ifdef USE_WIN32 (void)name; /* squash the unused parameter warning */ if(make_sockets(socket_vector)) return 1; #elif defined(__INNOTEK_LIBC__) /* Innotek port of GCC can not use select on a pipe: * use local socket instead */ struct sockaddr_un un; fd_set set_pipe; int pipe_in; FD_ZERO(&set_pipe); socket_vector[0]=s_socket(PF_OS2, SOCK_STREAM, 0, 0, "socket#1"); socket_vector[1]=s_socket(PF_OS2, SOCK_STREAM, 0, 0, "socket#2"); /* connect the two endpoints */ memset(&un, 0, sizeof un); un.sun_len=sizeof un; un.sun_family=AF_OS2; sprintf(un.sun_path, "\\socket\\stunnel-%s-%u", name, getpid()); /* make the first endpoint listen */ bind(socket_vector[0], (struct sockaddr *)&un, sizeof un); listen(socket_vector[0], 1); connect(socket_vector[1], (struct sockaddr *)&un, sizeof un); FD_SET(socket_vector[0], &set_pipe); if(select(socket_vector[0]+1, &set_pipe, NULL, NULL, NULL)>0) { pipe_in=socket_vector[0]; socket_vector[0]=s_accept(socket_vector[0], NULL, 0, 0, "accept"); closesocket(pipe_in); } else { sockerror("select"); return 1; } #else /* Unix */ if(s_pipe(socket_vector, 1, name)) return 1; #endif /* USE_WIN32 */ return 0; } #ifdef __GNUC__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-result" #endif /* __GNUC__>=4.6 */ #endif /* __GNUC__ */ void signal_post(uint8_t sig) { /* no meaningful way here to handle the result */ writesocket(signal_pipe[1], (char *)&sig, 1); } #ifdef __GNUC__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic pop #endif /* __GNUC__>=4.6 */ #endif /* __GNUC__ */ /* make a single attempt to dispatch a signal from the signal pipe */ /* return 1 on SIGNAL_TERMINATE or a fatal error, 0 otherwise */ NOEXPORT int signal_pipe_dispatch(void) { uint8_t sig=0xff; ssize_t num; char *sig_name; s_log(LOG_DEBUG, "Dispatching a signal from the signal pipe"); num=readsocket(signal_pipe[0], (char *)&sig, 1); if(num!=1) { if(num) { if(get_last_socket_error()==S_EWOULDBLOCK) { s_log(LOG_DEBUG, "Signal pipe is empty"); return 0; } 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(pipe_init(signal_pipe, "signal_pipe")) { 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; } switch(sig) { #ifndef USE_WIN32 case SIGCHLD: s_log(LOG_DEBUG, "Processing SIGCHLD"); #ifdef USE_FORK pid_status_nohang("Process"); /* client process */ #else /* USE_UCONTEXT || USE_PTHREAD */ pid_status_nohang("Child process"); /* 'exec' process */ #endif /* defined USE_FORK */ return 0; #endif /* !defind USE_WIN32 */ case SIGNAL_TERMINATE: s_log(LOG_DEBUG, "Processing SIGNAL_TERMINATE"); s_log(LOG_NOTICE, "Terminated"); return 1; case SIGNAL_RELOAD_CONFIG: s_log(LOG_DEBUG, "Processing SIGNAL_RELOAD_CONFIG"); reload_config(); return 0; case SIGNAL_REOPEN_LOG: s_log(LOG_DEBUG, "Processing SIGNAL_REOPEN_LOG"); log_flush(LOG_MODE_BUFFER); log_close(SINK_OUTFILE); log_open(SINK_OUTFILE); log_flush(LOG_MODE_CONFIGURED); s_log(LOG_NOTICE, "Log file reopened"); return 0; case SIGNAL_CONNECTIONS: return process_connections(); default: sig_name=signal_name(sig); s_log(LOG_ERR, "Received %s; terminating", sig_name); str_free(sig_name); return 1; } } NOEXPORT void reload_config() { static int delay=10; /* 10ms */ #ifdef HAVE_CHROOT struct stat sb; #endif /* HAVE_CHROOT */ if(options_parse(CONF_RELOAD)) { s_log(LOG_ERR, "Failed to reload the configuration file"); return; } unbind_ports(); log_flush(LOG_MODE_BUFFER); #ifdef HAVE_CHROOT /* we don't close SINK_SYSLOG if chroot is enabled and * there is no /dev/log inside it, which could allow * openlog(3) to reopen the syslog socket later */ if(global_options.chroot_dir && stat("/dev/log", &sb)) log_close(SINK_OUTFILE); else #endif /* HAVE_CHROOT */ log_close(SINK_SYSLOG|SINK_OUTFILE); /* there is no race condition here: * client threads are not allowed to use global options */ options_free(); options_apply(); /* we hope that a sane openlog(3) implementation won't * attempt to reopen /dev/log if it's already open */ log_open(SINK_SYSLOG|SINK_OUTFILE); log_flush(LOG_MODE_CONFIGURED); ui_config_reloaded(); /* we use "|" instead of "||" to attempt initialization of both subsystems */ if(bind_ports() | exec_connect_start()) { s_poll_sleep(delay/1000, delay%1000); /* sleep to avoid log trashing */ signal_post(SIGNAL_RELOAD_CONFIG); /* retry */ delay*=2; if(delay > 10000) /* 10s */ delay=10000; } else { delay=10; /* 10ms */ } } #ifdef __GNUC__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic push #endif /* __GNUC__>=4.6 */ #pragma GCC diagnostic ignored "-Wformat" #pragma GCC diagnostic ignored "-Wformat-extra-args" #endif /* __GNUC__ */ NOEXPORT int process_connections() { #ifndef USE_FORK CLI *c; s_log(LOG_NOTICE, "Active connections:"); CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_THREAD_LIST]); for(c=thread_head; c; c=c->thread_next) { s_log(LOG_NOTICE, "Service [%s]: " "%llu byte(s) sent to TLS, " "%llu byte(s) sent to socket", c->opt->servname, (unsigned long long)c->ssl_bytes, (unsigned long long)c->sock_bytes); } CRYPTO_THREAD_unlock(stunnel_locks[LOCK_THREAD_LIST]); #endif /* USE_FORK */ return 0; /* continue execution */ } #ifdef __GNUC__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic pop #endif /* __GNUC__>=4.6 */ #endif /* __GNUC__ */ /**************************************** signal name decoding */ #define check_signal(s) if(signum==s) return str_dup(#s); NOEXPORT char *signal_name(int signum) { #ifdef SIGHUP check_signal(SIGHUP) #endif #ifdef SIGINT check_signal(SIGINT) #endif #ifdef SIGQUIT check_signal(SIGQUIT) #endif #ifdef SIGILL check_signal(SIGILL) #endif #ifdef SIGTRAP check_signal(SIGTRAP) #endif #ifdef SIGABRT check_signal(SIGABRT) #endif #ifdef SIGIOT check_signal(SIGIOT) #endif #ifdef SIGBUS check_signal(SIGBUS) #endif #ifdef SIGFPE check_signal(SIGFPE) #endif #ifdef SIGKILL check_signal(SIGKILL) #endif #ifdef SIGUSR1 check_signal(SIGUSR1) #endif #ifdef SIGSEGV check_signal(SIGSEGV) #endif #ifdef SIGUSR2 check_signal(SIGUSR2) #endif #ifdef SIGPIPE check_signal(SIGPIPE) #endif #ifdef SIGALRM check_signal(SIGALRM) #endif #ifdef SIGTERM check_signal(SIGTERM) #endif #ifdef SIGSTKFLT check_signal(SIGSTKFLT) #endif #ifdef SIGCHLD check_signal(SIGCHLD) #endif #ifdef SIGCONT check_signal(SIGCONT) #endif #ifdef SIGSTOP check_signal(SIGSTOP) #endif #ifdef SIGTSTP check_signal(SIGTSTP) #endif #ifdef SIGTTIN check_signal(SIGTTIN) #endif #ifdef SIGTTOU check_signal(SIGTTOU) #endif #ifdef SIGURG check_signal(SIGURG) #endif #ifdef SIGXCPU check_signal(SIGXCPU) #endif #ifdef SIGXFSZ check_signal(SIGXFSZ) #endif #ifdef SIGVTALRM check_signal(SIGVTALRM) #endif #ifdef SIGPROF check_signal(SIGPROF) #endif #ifdef SIGWINCH check_signal(SIGWINCH) #endif #ifdef SIGIO check_signal(SIGIO) #endif #ifdef SIGPOLL check_signal(SIGPOLL) #endif #ifdef SIGLOST check_signal(SIGLOST) #endif #ifdef SIGPWR check_signal(SIGPWR) #endif #ifdef SIGSYS check_signal(SIGSYS) #endif #ifdef SIGUNUSED check_signal(SIGUNUSED) #endif return str_printf("signal %d", signum); } /**************************************** log build details */ void stunnel_info(int level) { s_log(level, "stunnel " STUNNEL_VERSION " on " HOST " platform"); if(strcmp(OPENSSL_VERSION_TEXT, OpenSSL_version(OPENSSL_VERSION))) { s_log(level, "Compiled with " OPENSSL_VERSION_TEXT); s_log(level, "Running with %s", OpenSSL_version(OPENSSL_VERSION)); #if OPENSSL_VERSION_NUMBER >= 0x30000000L if((OPENSSL_version_major()<<8 | OPENSSL_version_minor()) != OPENSSL_VERSION_NUMBER>>20) #else /* OpenSSL version < 3.0.0 */ if(OpenSSL_version_num()>>12 != OPENSSL_VERSION_NUMBER>>12) #endif /* OpenSSL version >= 3.0.0 */ s_log(level, "Update OpenSSL shared libraries or rebuild stunnel"); } else { s_log(level, "Compiled/running with " OPENSSL_VERSION_TEXT); } s_log(level, "Threading:" #ifdef USE_UCONTEXT "UCONTEXT" #endif #ifdef USE_PTHREAD "PTHREAD" #endif #ifdef USE_WIN32 "WIN32" #endif #ifdef USE_FORK "FORK" #endif " Sockets:" #ifdef USE_POLL "POLL" #else /* defined(USE_POLL) */ "SELECT" #endif /* defined(USE_POLL) */ ",IPv%c" #ifdef USE_SYSTEMD ",SYSTEMD" #endif /* defined(USE_SYSTEMD) */ " TLS:" #ifndef OPENSSL_NO_ENGINE #define TLS_FEATURE_FOUND "ENGINE" #endif /* !defined(OPENSSL_NO_ENGINE) */ #ifdef USE_FIPS #ifdef TLS_FEATURE_FOUND "," #else #define TLS_FEATURE_FOUND #endif "FIPS" #endif /* defined(USE_FIPS) */ #ifndef OPENSSL_NO_OCSP #ifdef TLS_FEATURE_FOUND "," #else #define TLS_FEATURE_FOUND #endif "OCSP" #endif /* !defined(OPENSSL_NO_OCSP) */ #ifndef OPENSSL_NO_PSK #ifdef TLS_FEATURE_FOUND "," #else #define TLS_FEATURE_FOUND #endif "PSK" #endif /* !defined(OPENSSL_NO_PSK) */ #ifndef OPENSSL_NO_TLSEXT #ifdef TLS_FEATURE_FOUND "," #else #define TLS_FEATURE_FOUND #endif "SNI" #endif /* !defined(OPENSSL_NO_TLSEXT) */ #ifndef TLS_FEATURE_FOUND "NONE" #endif /* !defined(TLS_FEATURE_FOUND) */ #ifdef USE_LIBWRAP " Auth:LIBWRAP" #endif , /* supported IP version parameter */ #if defined(USE_WIN32) && !defined(_WIN32_WCE) s_getaddrinfo ? '6' : '4' #else /* defined(USE_WIN32) */ #if defined(USE_IPv6) '6' #else /* defined(USE_IPv6) */ '4' #endif /* defined(USE_IPv6) */ #endif /* defined(USE_WIN32) */ ); #ifdef errno #define xstr(a) str(a) #define str(a) #a s_log(LOG_DEBUG, "errno: " xstr(errno)); #endif /* errno */ } /* end of stunnel.c */ stunnel-5.56/src/mingw.mk0000664000175000017500000000462313565276660012352 00000000000000## mingw/mingw64 Makefile # by Michal Trojnara 1998-2019 # 32-bit Windows #win32_arch=win32 #win32_targetcpu=i686 #win32_mingw=mingw # 64-bit Windows #win32_arch=win64 #win32_targetcpu=x86_64 #win32_mingw=mingw64 bindir = ../bin/$(win32_arch) objdir = ../obj/$(win32_arch) win32_ssl_dir = /opt/openssl-$(win32_mingw) win32_cppflags = -I$(win32_ssl_dir)/include win32_cflags = -g -mthreads -O2 #win32_cflags += -fstack-protector win32_cflags += -Wall -Wextra -Wpedantic -Wformat=2 -Wconversion -Wno-long-long win32_cflags += -D_FORTIFY_SOURCE=2 -DUNICODE -D_UNICODE win32_ldflags = -g -mthreads #win32_ldflags += -fstack-protector # -fstack-protector is broken (at least in x86_64-w64-mingw32-gcc 8.2.0) # compiling with -D_FORTIFY_SOURCE=2 may require linking with -lssp win32_common_libs = -lws2_32 -lkernel32 -lssp win32_ssl_libs = -L$(win32_ssl_dir)/lib -lcrypto -lssl win32_gui_libs = $(win32_common_libs) -lgdi32 -lpsapi $(win32_ssl_libs) win32_cli_libs = $(win32_common_libs) $(win32_ssl_libs) common_headers = common.h prototypes.h version.h win32_common = tls str file client log options protocol network resolver win32_common += ssl ctx verify sthreads fd dhparam cron stunnel win32_gui = ui_win_gui resources win32_cli = ui_win_cli win32_common_objs = $(addsuffix .o, $(addprefix $(objdir)/, $(win32_common))) win32_gui_objs = $(addsuffix .o, $(addprefix $(objdir)/, $(win32_gui))) win32_cli_objs = $(addsuffix .o, $(addprefix $(objdir)/, $(win32_cli))) win32_prefix = $(win32_targetcpu)-w64-mingw32- win32_cc = $(win32_prefix)gcc win32_windres = $(win32_prefix)windres all: mkdirs $(bindir)/stunnel.exe $(bindir)/tstunnel.exe mkdirs: mkdir -p $(bindir) $(objdir) $(bindir)/stunnel.exe: $(win32_common_objs) $(win32_gui_objs) $(win32_cc) -mwindows $(win32_ldflags) -o $(bindir)/stunnel.exe $(win32_common_objs) $(win32_gui_objs) $(win32_gui_libs) -$(srcdir)/../sign/sign.sh $(bindir)/stunnel.exe $(bindir)/tstunnel.exe: $(win32_common_objs) $(win32_cli_objs) $(win32_cc) $(win32_ldflags) -o $(bindir)/tstunnel.exe $(win32_common_objs) $(win32_cli_objs) $(win32_cli_libs) -$(srcdir)/../sign/sign.sh $(bindir)/tstunnel.exe $(objdir)/%.o: $(srcdir)/%.c $(win32_cc) -c $(win32_cppflags) $(win32_cflags) -o $@ $< $(objdir)/%.o: $(common_headers) $(win32_gui_objs): $(srcdir)/resources.h $(objdir)/resources.o: $(srcdir)/resources.rc $(win32_windres) --include-dir $(srcdir) $< $@ $(objdir)/resources.o: $(srcdir)/version.h stunnel-5.56/src/file.c0000664000175000017500000001651713467064764011771 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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_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(DISK_FILE)); 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(DISK_FILE)); 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.56/src/stunnel.ico0000664000175000017500000003535612634035772013064 0000000000000000 %6  % h6(0` $ #@ # # # # # # # # # # # # #@ #@ # # # # # # # # # # # # # # # # # # #@ #@ # # # # # # # # # # # # # # # # # # # # # # #@ # # # # # # # # # # # # # # # # # # # # # # # # # # # # #P # # # # # # # # #@>@SQRlijlijlijlijSQR@>@ # # # # # # # # # #P # # # # # # # #&%)SQR|{|{_]^-+/ # # # # # # # # # # # # # # # #SQR|{SQR&%) # # # # # # # # # # # # # #&%)rooroo325 # # # # # # # # # # # # # #325xvu|{325 # # # # # # # #P # # # # # #&%)xvu|{325 # # # # # # #P # # # # # # # #lijroo&%) # # # # # # # # # # # # # #SQRYWX # # # # # # # #@ # # # # # #&%)|{-+/ # # # # # # #@ # # # # # # #SQR_]^ # # # # # # # #@ # # # # # # #|{&%) # # # # # # #@ # # # # # # #98;FDF # # # # # # # # # # # # # #SQR_]^ # # # # # # # #@ # # # # # # #lijlij # # # # # # # #@ # # # # # # # #lij # # # # # # # # # # # # # # # #|{ # # # # # # # # # # # # # # # #|{ # # # # # # # # # # # # # # # #lij # # # # # # # # # # # # # # # #lijlij # # # # # # # # # # # # # # # #SQR_]^ # # # # # # # # # # # # # # # #@>@FDF # # # # # # # # # # # # # # # # #|{&%) # # # # # # # # # # # # # # # # #YWX_]^ # # # # # # # # # # # # # # # # # #-+/325 # # # # # # # # # # # # # # # # # # #SQRYWX # # # # # # # # # # # # # # # # # # # # #rooxvu&%) # # # # # # # # # # #@ # # # # # # # # # #-+/|{|{325 # # # # # # # # # # #@ # # # # # # # # # # #325|{|{325 # # # # # # # # # # # # # # # # # # # # # # #-+/rooxvu325 # # # # # # # # # # # # #@ # # # # # # # # # # # #&%)SQRYWX&%) # # # # # # # # # # # # #@ # # # # # # # # # # # # # #-+/_]^_]^-+/ # # # # # # # # # # # # # # #@ # # # # # # # # # # # # # # #&%)FDF_]^lij|{lij_]^FDF&%) # # # # # # # # # # # # # # # #@ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #P # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #P # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #P # # # # # # # # # # # # # # # # # # # # # # # # # # # # #P # # # # # # # # # # # # # # # # # # # # # # # # # # # # #@ # # # # # # # # # # # # # # # # # # # # # # #@ #@ # # # # # # # # # # # # # # # # # # #@ #@ # # # # # # # # # # # # #@??( @  #0 # # # # # # # # # # #0 #` # # # # # # # # # # # # # # #P # # # # # # # #98;98;98;98; # # # # # # # # #P # # # # #FDFecdrooFDF # # # # # #P #` # # # #325rooroo325 # # # # #` #P # # # #@>@|{FDF # # # # #P # # # # #325|{98; # # # # # # # # #&%)xvu|{&%) # # # # #` # # # #SQR_]^ # # # # #` # # # # #|{|{&%) # # # # #0 # # # #98;@>@ # # # # #0 # # # # #SQRSQR # # # # # # # # # #YWXlij # # # # # # # # # #ecdlij # # # # # # # # # #SQRecd # # # # # # # # # #LJLSQR # # # # # # # # # #32598; # # # # # # # # # # #xvuxvu # # # # # # # # # # # #FDFLJL # # # # # # # # # # # # #lijroo # # # # # # # # # # # # # #&%)roo|{-+/ # # # # # # # #0 # # # # # # #&%)rooroo325 # # # # # # # #0 # # # # # # # #&%)SQRYWX&%) # # # # # # # # #` # # # # # # # # #&%)LJLlij|{lijLJL-+/ # # # # # # # # # #` # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #P # # # # # # # # # # # # # # # # # # # # # # # # #P #` # # # # # # # # # # # # # # # # # # # # # # #` #P # # # # # # # # # # # # # # # # # # # # #P # # # # # # # # # # # # # # # # # # # # #` # # # # # # # # # # # # # # #` #0 # # # # # # # # # # #0??(   #` # # # # # # #` # # #-+/SQRlijlijYWX-+/ # # # # # #LJLSQR # # # # #FDFLJL # # #` # #|{|{&%) # #` # #98;98; # # # #LJLSQR # # # #98;FDF # # # #-+/-+/ # # # # #_]^_]^ # # # # # #&%)rooroo&%) # # # #` # # #&%)SQRxvuxvuSQR&%) # # # #` # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #` # # # # # # #`stunnel-5.56/src/client.c0000664000175000017500000017667313562337365012336 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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 exec_connect_loop(CLI *); NOEXPORT void exec_connect_once(CLI *); NOEXPORT void client_run(CLI *); NOEXPORT void local_start(CLI *); NOEXPORT void remote_start(CLI *); NOEXPORT void ssl_start(CLI *); NOEXPORT void session_cache_retrieve(CLI *); NOEXPORT void print_cipher(CLI *); NOEXPORT void transfer(CLI *); NOEXPORT int parse_socket_error(CLI *, const char *); NOEXPORT void auth_user(CLI *); 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 idx_cache_save(SSL_SESSION *, SOCKADDR_UNION *); NOEXPORT unsigned idx_cache_retrieve(CLI *); NOEXPORT void connect_setup(CLI *); NOEXPORT int connect_init(CLI *, int); NOEXPORT int redirect(CLI *); 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->seq=seq++; c->rr=c->opt->rr++; return c; } #if defined(USE_WIN32) || defined(USE_OS2) unsigned __stdcall #else void * #endif client_thread(void *arg) { CLI *c=arg; #ifdef DEBUG_STACK_SIZE size_t stack_size=c->opt->stack_size; #endif #ifdef USE_FORK /* do not use signal pipe in child processes */ signal(SIGCHLD, SIG_IGN); /* ignore dead children */ signal(SIGHUP, SIG_DFL); signal(SIGUSR1, SIG_DFL); signal(SIGUSR2, SIG_DFL); signal(SIGPIPE, SIG_IGN); /* ignore broken pipe */ signal(SIGTERM, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGINT, SIG_DFL); #endif /* USE_FORK */ /* make sure c->thread_* values are initialized */ CRYPTO_THREAD_read_lock(stunnel_locks[LOCK_THREAD_LIST]); CRYPTO_THREAD_unlock(stunnel_locks[LOCK_THREAD_LIST]); /* initialize */ c->tls=NULL; /* do not reuse */ tls_alloc(c, NULL, NULL); #ifdef DEBUG_STACK_SIZE stack_info(stack_size, 1); /* initialize */ #endif /* execute */ client_main(c); /* cleanup the thread */ #ifndef USE_FORK CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_THREAD_LIST]); if(thread_head==c) thread_head=c->thread_next; if(c->thread_prev) c->thread_prev->thread_next=c->thread_next; if(c->thread_next) c->thread_next->thread_prev=c->thread_prev; #ifdef USE_PTHREAD pthread_detach(c->thread_id); #endif #ifdef USE_WIN32 CloseHandle(c->thread_id); #endif CRYPTO_THREAD_unlock(stunnel_locks[LOCK_THREAD_LIST]); #endif /* !USE_FORK */ client_free(c); #ifdef DEBUG_STACK_SIZE stack_info(stack_size, 0); /* display computed value */ #endif str_stats(); /* client thread allocation tracking */ tls_cleanup(); /* s_log() is not allowed after tls_cleanup() */ /* terminate the thread */ #if defined(USE_WIN32) || defined(USE_OS2) #if !defined(_WIN32_WCE) _endthreadex(0); #endif return 0; #else #ifdef USE_UCONTEXT s_poll_wait(NULL, 0, 0); /* wait on poll() */ #endif return NULL; #endif } #ifdef DEBUG_STACK_SIZE void ignore_value(void *ptr) { (void)ptr; /* squash the unused parameter warning */ } #endif 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) { if(c->opt->option.retry) exec_connect_loop(c); else exec_connect_once(c); } else { client_run(c); } } void client_free(CLI *c) { #ifndef USE_FORK service_free(c->opt); #endif str_free(c); } #ifdef __GNUC__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic push #endif /* __GNUC__>=4.6 */ #pragma GCC diagnostic ignored "-Wformat" #pragma GCC diagnostic ignored "-Wformat-extra-args" #endif /* __GNUC__ */ NOEXPORT void exec_connect_loop(CLI *c) { unsigned long long seq=0; char *fresh_id=c->tls->id; unsigned retry; do { /* make sure c->tls->id is valid in str_printf() */ char *id=str_printf("%s_%llu", fresh_id, seq++); str_detach(id); c->tls->id=id; exec_connect_once(c); /* retry is asynchronously changed in the main thread, * so we make sure to use the same value for both checks */ retry=c->opt->option.retry; if(retry) { s_log(LOG_INFO, "Retrying an exec+connect section"); /* c and id are detached, so it is safe to call str_stats() */ str_stats(); /* client thread allocation tracking */ s_poll_sleep(1, 0); c->rr++; } /* make sure c->tls->id is valid in str_free() */ c->tls->id=fresh_id; str_free(id); } while(retry); /* retry is disabled on config reload */ } #ifdef __GNUC__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic pop #endif /* __GNUC__>=4.6 */ #endif /* __GNUC__ */ /* exec+connect options specified together * -> spawn a local program instead of stdio */ NOEXPORT void exec_connect_once(CLI *fresh_c) { jmp_buf exception_buffer, *exception_backup; /* connect_local() needs an unmodified copy of c each time */ CLI *c=str_alloc(sizeof(CLI)); memcpy(c, fresh_c, sizeof(CLI)); exception_backup=c->exception_pointer; c->exception_pointer=&exception_buffer; if(!setjmp(exception_buffer)) { c->local_rfd.fd=c->local_wfd.fd=connect_local(c); client_run(c); } c->exception_pointer=exception_backup; str_free(c); } #ifdef __GNUC__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic push #endif /* __GNUC__>=4.6 */ #pragma GCC diagnostic ignored "-Wformat" #pragma GCC diagnostic ignored "-Wformat-extra-args" #endif /* __GNUC__ */ NOEXPORT void client_run(CLI *c) { jmp_buf exception_buffer, *exception_backup; int err, rst; #ifndef USE_FORK int num; #endif #ifndef USE_FORK #ifdef USE_OS_THREADS CRYPTO_atomic_add(&num_clients, 1, &num, stunnel_locks[LOCK_CLIENTS]); #else num=++num_clients; #endif ui_clients(num); #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 */ exception_backup=c->exception_pointer; c->exception_pointer=&exception_buffer; err=setjmp(exception_buffer); if(!err) { client_try(c); } c->exception_pointer=exception_backup; rst=err==1 && c->opt->option.reset; s_log(LOG_NOTICE, "Connection %s: %llu byte(s) sent to TLS, %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 TLS context */ if(c->ssl) { /* TLS initialized */ SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); SSL_free(c->ssl); c->ssl=NULL; #if OPENSSL_VERSION_NUMBER >= 0x10100006L /* OpenSSL version >= 1.1.0-pre6 */ /* the function is no longer needed */ #elif OPENSSL_VERSION_NUMBER >= 0x10100004L /* OpenSSL version 1.1.0-pre4 or 1.1.0-pre5 */ ERR_remove_thread_state(); #elif OPENSSL_VERSION_NUMBER >= 0x10000000L /* OpenSSL version >= 1.0.0 */ ERR_remove_thread_state(NULL); #else /* OpenSSL version < 1.0.0 */ ERR_remove_state(0); #endif } /* 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 */ pid_status_hang("Child process"); /* null SIGCHLD handler was used */ s_log(LOG_DEBUG, "Service [%s] finished", c->opt->servname); #else #ifdef USE_OS_THREADS CRYPTO_atomic_add(&num_clients, -1, &num, stunnel_locks[LOCK_CLIENTS]); #else num=--num_clients; #endif ui_clients(num); s_log(LOG_DEBUG, "Service [%s] finished (%ld left)", c->opt->servname, num); #endif /* free the client context */ str_free(c->connect_addr.addr); /* a client does not have its own local copy of c->connect_addr.session and c->connect_addr.fd */ s_poll_free(c->fds); str_free(c->accepted_address); } #ifdef __GNUC__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic pop #endif /* __GNUC__>=4.6 */ #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; /* 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(socket_options_set(c->opt, 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)"); throw_exception(c, 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(socket_options_set(c->opt, 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)"); throw_exception(c, 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"); throw_exception(c, 1); } #endif s_log(LOG_NOTICE, "Service [%s] accepted connection", c->opt->servname); return; } /* authenticate based on retrieved IP address of the client */ c->accepted_address=s_ntop(&c->peer_addr, c->peer_addr_len); #ifdef USE_LIBWRAP libwrap_auth(c); #endif /* USE_LIBWRAP */ auth_user(c); s_log(LOG_NOTICE, "Service [%s] accepted connection from %s", c->opt->servname, c->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 && !redirect(c)) 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(socket_options_set(c->opt, 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 *sess; #if OPENSSL_VERSION_NUMBER < 0x10100000L int unsafe_openssl; #endif /* OpenSSL version < 1.1.0 */ c->ssl=SSL_new(c->opt->ctx); if(!c->ssl) { sslerror("SSL_new"); throw_exception(c, 1); } /* for callbacks */ if(!SSL_set_ex_data(c->ssl, index_ssl_cli, c)) { sslerror("SSL_set_ex_data"); throw_exception(c, 1); } if(c->opt->option.client) { #ifndef OPENSSL_NO_TLSEXT /* c->opt->sni should always be initialized at this point, * either explicitly with "sni" * or implicitly with "protocolHost" or "connect" */ if(c->opt->sni && *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"); throw_exception(c, 1); } } else { /* c->opt->sni was set to an empty value */ s_log(LOG_INFO, "SNI: extension disabled"); } #endif session_cache_retrieve(c); SSL_set_fd(c->ssl, (int)c->remote_fd.fd); SSL_set_connect_state(c->ssl); } else { /* TLS 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 TLS 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); } if(c->opt->option.require_cert) s_log(LOG_INFO, "Peer certificate required"); else s_log(LOG_INFO, "Peer certificate not required"); #if OPENSSL_VERSION_NUMBER < 0x10100000L unsafe_openssl=OpenSSL_version_num()<0x0090810fL || (OpenSSL_version_num()>=0x10000000L && OpenSSL_version_num()<0x1000002fL); #endif /* OpenSSL version < 1.1.0 */ 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 OPENSSL_VERSION_NUMBER < 0x10100000L if(unsafe_openssl) CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_SSL]); #endif /* OpenSSL version < 1.1.0 */ if(c->opt->option.client) i=SSL_connect(c->ssl); else i=SSL_accept(c->ssl); #if OPENSSL_VERSION_NUMBER < 0x10100000L if(unsafe_openssl) CRYPTO_THREAD_unlock(stunnel_locks[LOCK_SSL]); #endif /* OpenSSL version < 1.1.0 */ 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, 0); 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"); throw_exception(c, 1); case 0: s_log(LOG_INFO, "ssl_start: s_poll_wait:" " TIMEOUTbusy exceeded: sending reset"); s_poll_dump(c->fds, LOG_DEBUG); throw_exception(c, 1); case 1: break; /* OK */ default: s_log(LOG_ERR, "ssl_start: s_poll_wait: unknown result"); throw_exception(c, 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"); throw_exception(c, 1); } print_cipher(c); sess=SSL_get1_session(c->ssl); if(sess) { if(SSL_session_reused(c->ssl)) { print_session_id(sess); } else { /* a new session was negotiated */ /* SSL_SESS_CACHE_NO_INTERNAL_STORE prevented automatic caching */ if(!c->opt->option.client) SSL_CTX_add_session(c->opt->ctx, sess); } SSL_SESSION_free(sess); } } NOEXPORT void session_cache_retrieve(CLI *c) { SSL_SESSION *sess; CRYPTO_THREAD_read_lock(stunnel_locks[LOCK_SESSION]); if(c->opt->option.delayed_lookup) { sess=c->opt->session; } else { /* per-destination client cache */ if(c->opt->connect_session) { sess=c->opt->connect_session[c->idx]; } else { s_log(LOG_ERR, "INTERNAL ERROR: Uninitialized client session cache"); sess=NULL; } } if(sess) SSL_set_session(c->ssl, sess); CRYPTO_THREAD_unlock(stunnel_locks[LOCK_SESSION]); } 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_levelopt->option.client ? "connected" : "accepted", SSL_session_reused(c->ssl) && !c->flag.psk ? "previous session reused" : "new session negotiated"); cipher=(SSL_CIPHER *)SSL_get_current_cipher(c->ssl); s_log(LOG_INFO, "%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 } /****************************** transfer data */ NOEXPORT void transfer(CLI *c) { int timeout; /* s_poll_wait timeout in seconds */ int pending; /* either processed on unprocessed TLS data */ #if OPENSSL_VERSION_NUMBER >= 0x10100000L int has_pending=0, prev_has_pending; #endif 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 TLS 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, 0); /* 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 TLS file descriptors unless TLS 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 */ pending=SSL_pending(c->ssl); #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* only attempt to process SSL_has_pending() data once */ prev_has_pending=has_pending; has_pending=SSL_has_pending(c->ssl); pending=pending || (has_pending && !prev_has_pending); #endif if(read_wants_read && pending) { timeout=0; /* process any buffered data without delay */ } else if((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 TLS */) { timeout=c->opt->timeout_idle; } else { timeout=c->opt->timeout_close; } err=s_poll_wait(c->fds, timeout, 0); switch(err) { case -1: sockerror("transfer: s_poll_wait"); throw_exception(c, 1); case 0: /* timeout */ if(read_wants_read && pending) break; 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"); s_poll_dump(c->fds, LOG_DEBUG); throw_exception(c, 1); } /* already closing connection */ s_log(LOG_ERR, "transfer: s_poll_wait:" " TIMEOUTclose exceeded: closing"); s_poll_dump(c->fds, LOG_DEBUG); 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); /****************************** identify exceptions */ if(c->sock_rfd->fd==c->sock_wfd->fd) { if((sock_can_rd || sock_can_wr) && s_poll_err(c->fds, c->sock_rfd->fd)) { err=get_socket_error(c->sock_rfd->fd); if(err) log_error(LOG_INFO, err, "socket fd"); } } else { if(sock_can_rd && s_poll_err(c->fds, c->sock_rfd->fd)) { err=get_socket_error(c->sock_rfd->fd); if(err) log_error(LOG_INFO, err, "socket rfd"); } if(sock_can_wr && s_poll_err(c->fds, c->sock_wfd->fd)) { err=get_socket_error(c->sock_wfd->fd); if(err) log_error(LOG_INFO, err, "socket wfd"); } } if(c->ssl_rfd->fd==c->ssl_wfd->fd) { if((ssl_can_rd || ssl_can_wr) && s_poll_err(c->fds, c->ssl_rfd->fd)) { err=get_socket_error(c->ssl_rfd->fd); if(err) log_error(LOG_INFO, err, "TLS fd"); } } else { if(ssl_can_rd && s_poll_err(c->fds, c->ssl_rfd->fd)) { err=get_socket_error(c->ssl_rfd->fd); if(err) log_error(LOG_INFO, err, "TLS rfd"); } if(c->ssl_rfd->fd!=c->ssl_wfd->fd && ssl_can_wr && s_poll_err(c->fds, c->ssl_wfd->fd)) { err=get_socket_error(c->ssl_wfd->fd); if(err) log_error(LOG_INFO, err, "TLS wfd"); } } /****************************** 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); throw_exception(c, 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, "TLS socket closed (HUP) with %ld unsent byte(s)", (long)c->sock_ptr); throw_exception(c, 1); /* reset the sockets */ } s_log(LOG_INFO, "TLS socket closed (HUP)"); SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); } } if(c->reneg_state==RENEG_DETECTED && !c->opt->option.renegotiation) { s_log(LOG_ERR, "Aborting due to renegotiation request"); throw_exception(c, 1); } /****************************** send TLS 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_ZERO_RETURN: /* connection closed */ 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: /* TLS error */ sslerror("SSL_shutdown"); throw_exception(c, 1); default: s_log(LOG_ERR, "SSL_shutdown/SSL_get_error returned %d", err); throw_exception(c, 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; case 0: /* nothing was written: ignore */ s_log(LOG_DEBUG, "writesocket returned 0"); break; /* do not reset the watchdog */ 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 the 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; /* do not reset the watchdog */ default: c->sock_ptr+=(size_t)num; watchdog=0; /* reset the 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 TLS */ 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) { /* nothing was written: ignore */ s_log(LOG_DEBUG, "SSL_write returned 0"); break; /* do not reset the watchdog */ } 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 the 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: * TLS socket closed without close_notify alert */ if(c->sock_ptr) { /* TODO: what about buffered data? */ s_log(LOG_ERR, "TLS socket closed (SSL_write) with %ld unsent byte(s)", (long)c->sock_ptr); throw_exception(c, 1); /* reset the sockets */ } s_log(LOG_INFO, "TLS 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, "TLS 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"); throw_exception(c, 1); default: s_log(LOG_ERR, "SSL_write/SSL_get_error returned %d", err); throw_exception(c, 1); } } /****************************** read from TLS */ if((read_wants_read && (ssl_can_rd || pending)) || /* 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) { /* nothing was read: ignore */ s_log(LOG_DEBUG, "SSL_read returned 0"); break; /* do not reset the watchdog */ } c->ssl_ptr+=(size_t)num; watchdog=0; /* reset the 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: * TLS socket closed without close_notify alert */ if(c->sock_ptr || write_wants_write) { s_log(LOG_ERR, "TLS socket closed (SSL_read) with %ld unsent byte(s)", (long)c->sock_ptr); throw_exception(c, 1); /* reset the sockets */ } s_log(LOG_INFO, "TLS 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, "TLS 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"); throw_exception(c, 1); default: s_log(LOG_ERR, "SSL_read/SSL_get_error returned %d", err); throw_exception(c, 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); throw_exception(c, 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: * TLS socket closed without close_notify alert */ s_log(LOG_INFO, "TLS 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, "TLS socket closed (write hangup) with %ld unsent byte(s)", (long)c->sock_ptr); throw_exception(c, 1); /* reset the sockets */ } s_log(LOG_INFO, "TLS 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@stunnel.org"); stunnel_info(LOG_ERR); #if OPENSSL_VERSION_NUMBER >= 0x10100000L s_log(LOG_ERR, "protocol=%s, SSL_pending=%d, SSL_has_pending=%d", SSL_get_version(c->ssl), SSL_pending(c->ssl), SSL_has_pending(c->ssl)); #else s_log(LOG_ERR, "protocol=%s, SSL_pending=%d", SSL_get_version(c->ssl), SSL_pending(c->ssl)); #endif 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), " "TLS input buffer: %ld byte(s)", (long)c->sock_ptr, (long)c->ssl_ptr); throw_exception(c, 1); } } while(sock_open_wr || !(SSL_get_shutdown(c->ssl)&SSL_SENT_SHUTDOWN) || shutdown_wants_read || shutdown_wants_write); } #ifdef __GNUC__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic push #endif /* __GNUC__>=4.6 */ #if __GNUC__ >= 7 #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" #endif /* __GNUC__>=7 */ #endif /* __GNUC__ */ /* 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); s_poll_sleep(1, 0); /* 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; } /* fall through */ #endif default: sockerror(text); throw_exception(c, 1); return -1; /* some C compilers require a return value */ } } #ifdef __GNUC__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic pop #endif /* __GNUC__>=4.6 */ #endif /* __GNUC__ */ NOEXPORT void auth_user(CLI *c) { #ifndef _WIN32_WCE struct servent *s_ent; /* structure for getservbyname */ #endif SOCKADDR_UNION ident; /* IDENT socket name */ char *line, *type, *system, *user; unsigned remote_port, local_port; 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) throw_exception(c, 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))) throw_exception(c, 1); s_log(LOG_DEBUG, "IDENT server connected"); remote_port=ntohs(c->peer_addr.in.sin_port); local_port=(unsigned)(c->opt->local_addr.addr ? ntohs(c->opt->local_addr.addr[0].in.sin_port) : 0); fd_printf(c, c->fd, "%u , %u", remote_port, local_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); throw_exception(c, 1); } *type++='\0'; system=strchr(type, ':'); if(!system) { s_log(LOG_ERR, "Malformed IDENT response"); str_free(line); throw_exception(c, 1); } *system++='\0'; if(strcmp(type, " USERID ")) { s_log(LOG_ERR, "Incorrect IDENT response type"); str_free(line); throw_exception(c, 1); } user=strchr(system, ':'); if(!user) { s_log(LOG_ERR, "Malformed IDENT response"); str_free(line); throw_exception(c, 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\")", c->accepted_address, user); str_free(line); throw_exception(c, 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"); throw_exception(c, 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)) throw_exception(c, 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)) throw_exception(c, 1); s_log(LOG_DEBUG, "TTY=%s allocated", tty); } else if(make_sockets(fd)) throw_exception(c, 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"); throw_exception(c, 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(!c->opt->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(SIGUSR2, 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 idx_start, idx_try; connect_setup(c); switch(c->connect_addr.num) { case 0: s_log(LOG_ERR, "No remote host resolved"); throw_exception(c, 1); case 1: idx_start=0; break; default: idx_start=idx_cache_retrieve(c); } /* try to connect each host from the list */ for(idx_try=0; idx_tryconnect_addr.num; idx_try++) { c->idx=(idx_start+idx_try)%c->connect_addr.num; if(!connect_init(c, c->connect_addr.addr[c->idx].sa.sa_family) && !s_connect(c, &c->connect_addr.addr[c->idx], addr_len(&c->connect_addr.addr[c->idx]))) { if(c->ssl) { SSL_SESSION *sess=SSL_get1_session(c->ssl); if(sess) { idx_cache_save(sess, &c->connect_addr.addr[c->idx]); SSL_SESSION_free(sess); } } print_bound_address(c); fd=c->fd; c->fd=INVALID_SOCKET; return fd; /* success! */ } if(c->fd!=INVALID_SOCKET) { closesocket(c->fd); c->fd=INVALID_SOCKET; } } s_log(LOG_ERR, "No more addresses to connect"); throw_exception(c, 1); return INVALID_SOCKET; /* some C compilers require a return value */ } NOEXPORT void idx_cache_save(SSL_SESSION *sess, SOCKADDR_UNION *cur_addr) { SOCKADDR_UNION *old_addr, *new_addr; socklen_t len; char *addr_txt; int ok; /* 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_THREAD_write_lock(stunnel_locks[LOCK_ADDR]); old_addr=SSL_SESSION_get_ex_data(sess, index_session_connect_address); ok=SSL_SESSION_set_ex_data(sess, index_session_connect_address, new_addr); CRYPTO_THREAD_unlock(stunnel_locks[LOCK_ADDR]); if(ok) { str_free(old_addr); /* NULL pointers are ignored */ } else { /* failed to store new_addr -> remove it */ sslerror("SSL_SESSION_set_ex_data"); str_free(new_addr); /* NULL pointers are ignored */ } } NOEXPORT unsigned idx_cache_retrieve(CLI *c) { unsigned i; SOCKADDR_UNION addr, *ptr; socklen_t len; char *addr_txt; if(c->ssl && SSL_session_reused(c->ssl)) { SSL_SESSION *sess=SSL_get1_session(c->ssl); if(sess) { CRYPTO_THREAD_read_lock(stunnel_locks[LOCK_ADDR]); ptr=SSL_SESSION_get_ex_data(sess, index_session_connect_address); if(ptr) { len=addr_len(ptr); memcpy(&addr, ptr, (size_t)len); CRYPTO_THREAD_unlock(stunnel_locks[LOCK_ADDR]); SSL_SESSION_free(sess); /* 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_THREAD_unlock(stunnel_locks[LOCK_ADDR]); SSL_SESSION_free(sess); s_log(LOG_NOTICE, "persistence: No cached address found"); } } } if(c->opt->failover==FAILOVER_RR) { i=(c->connect_addr.start+c->rr)%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 connect_setup(CLI *c) { if(redirect(c)) { /* process "redirect" first */ 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)) throw_exception(c, 1); return; } /* default "connect" target */ addrlist_dup(&c->connect_addr, &c->opt->connect_addr); } NOEXPORT int connect_init(CLI *c, int domain) { SOCKADDR_UNION bind_addr; if(c->bind_addr) { /* setup bind_addr based on c->bind_addr */ #if 0 /* IPv6 addresses converted from IPv4 cause timeouts */ #ifdef USE_IPv6 if(c->bind_addr->sa.sa_family==AF_INET && domain==AF_INET6) { /* convert the binding address from IPv4 to IPv6 */ memset(&bind_addr, 0, sizeof bind_addr); bind_addr.in6.sin6_family=AF_INET6; bind_addr.in6.sin6_port=c->bind_addr->in.sin_port; /* address format example: ::ffff:192.0.2.128 */ memset((char *)&bind_addr.in6.sin6_addr+10, 0xff, 2); memcpy((char *)&bind_addr.in6.sin6_addr+12, &c->bind_addr->in.sin_addr, 4); } else /* just make a local copy */ #endif #endif memcpy(&bind_addr, c->bind_addr, (size_t)addr_len(c->bind_addr)); /* perform the initial sanity checks before creating a socket */ if(bind_addr.sa.sa_family!=domain) { s_log(LOG_DEBUG, "Cannot assign an AF=%d address an AF=%d socket", bind_addr.sa.sa_family, domain); return 1; /* failure */ } } /* create a new socket */ c->fd=s_socket(domain, SOCK_STREAM, 0, 1, "remote socket"); if(c->fd==INVALID_SOCKET) return 1; /* failure */ if(!c->bind_addr) return 0; /* success */ /* enable non-local bind if needed (and supported) */ #ifndef USE_WIN32 if(c->opt->option.transparent_src) { #if defined(__linux__) /* non-local bind on Linux */ int on=1; 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 */ int on=1; if(domain==AF_INET) { /* IPv4 */ if(setsockopt(c->fd, IPPROTO_IP, IP_BINDANY, &on, sizeof on)) { sockerror("setsockopt IP_BINDANY"); return 1; /* failure */ } } else { /* IPv6 */ if(setsockopt(c->fd, IPPROTO_IPV6, IPV6_BINDANY, &on, sizeof on)) { sockerror("setsockopt IPV6_BINDANY"); return 1; /* failure */ } } #else /* unsupported platform */ /* FIXME: move this check to options.c */ s_log(LOG_ERR, "Transparent proxy in remote mode is not supported" " on this platform"); throw_exception(c, 1); #endif } #endif /* !defined(USE_WIN32) */ /* explicit local bind or transparent proxy */ /* there is no need for a separate IPv6 logic here, * as port number is at the same offset in both structures */ if(ntohs(bind_addr.in.sin_port)>=1024) { /* security check */ /* this is currently only possible with transparent_src */ if(!bind(c->fd, &bind_addr.sa, addr_len(&bind_addr))) { s_log(LOG_INFO, "bind succeeded on the original port"); return 0; /* success */ } if(get_last_socket_error()!=S_EADDRINUSE) { sockerror("bind (original port)"); return 1; /* failure */ } } bind_addr.in.sin_port=htons(0); /* retry with ephemeral port */ if(!bind(c->fd, &bind_addr.sa, addr_len(&bind_addr))) { s_log(LOG_INFO, "bind succeeded on an ephemeral port"); return 0; /* success */ } sockerror("bind (ephemeral port)"); return 1; /* failure */ } NOEXPORT int redirect(CLI *c) { SSL_SESSION *sess; void *ex_data; if(!c->opt->redirect_addr.names) return 0; /* redirect not configured */ if(!c->ssl) return 1; /* TLS not established -> always redirect */ sess=SSL_get1_session(c->ssl); if(!sess) return 1; /* no TLS session -> always redirect */ ex_data=SSL_SESSION_get_ex_data(sess, index_session_authenticated); SSL_SESSION_free(sess); return ex_data == NULL; } 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); } void throw_exception(CLI *c, int v) { if(!c || !c->exception_pointer) fatal("No exception handler"); longjmp(*c->exception_pointer, v); } /* end of client.c */ stunnel-5.56/src/Makefile.in0000664000175000017500000020213313527763157012741 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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 1998-2019 ############################################################################### # File lists # ############################################################################### VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } 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 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(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) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkglibdir)" \ "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) 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; }; \ } 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 $@ 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__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/env.Plo \ ./$(DEPDIR)/stunnel-client.Po ./$(DEPDIR)/stunnel-cron.Po \ ./$(DEPDIR)/stunnel-ctx.Po ./$(DEPDIR)/stunnel-dhparam.Po \ ./$(DEPDIR)/stunnel-fd.Po ./$(DEPDIR)/stunnel-file.Po \ ./$(DEPDIR)/stunnel-libwrap.Po ./$(DEPDIR)/stunnel-log.Po \ ./$(DEPDIR)/stunnel-network.Po ./$(DEPDIR)/stunnel-options.Po \ ./$(DEPDIR)/stunnel-protocol.Po ./$(DEPDIR)/stunnel-pty.Po \ ./$(DEPDIR)/stunnel-resolver.Po ./$(DEPDIR)/stunnel-ssl.Po \ ./$(DEPDIR)/stunnel-sthreads.Po ./$(DEPDIR)/stunnel-str.Po \ ./$(DEPDIR)/stunnel-stunnel.Po ./$(DEPDIR)/stunnel-tls.Po \ ./$(DEPDIR)/stunnel-ui_unix.Po ./$(DEPDIR)/stunnel-verify.Po 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 am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \ $(top_srcdir)/auto/depcomp 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@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ 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@ runstatedir = @runstatedir@ 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$(SYSROOT)/usr/kerberos/include \ -I$(SSLDIR)/include -DLIBDIR='"$(pkglibdir)"' \ -DCONFDIR='"$(sysconfdir)/stunnel"' # TLS 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) --foreign src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/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__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ 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-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 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) 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@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-client.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-cron.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-ctx.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-dhparam.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-fd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-file.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-libwrap.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-log.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-network.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-options.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-protocol.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-pty.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-resolver.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-ssl.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-sthreads.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-str.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-stunnel.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-tls.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-ui_unix.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-verify.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .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: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(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 check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(SCRIPTS) config.h installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkglibdir)" "$(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 -f ./$(DEPDIR)/env.Plo -rm -f ./$(DEPDIR)/stunnel-client.Po -rm -f ./$(DEPDIR)/stunnel-cron.Po -rm -f ./$(DEPDIR)/stunnel-ctx.Po -rm -f ./$(DEPDIR)/stunnel-dhparam.Po -rm -f ./$(DEPDIR)/stunnel-fd.Po -rm -f ./$(DEPDIR)/stunnel-file.Po -rm -f ./$(DEPDIR)/stunnel-libwrap.Po -rm -f ./$(DEPDIR)/stunnel-log.Po -rm -f ./$(DEPDIR)/stunnel-network.Po -rm -f ./$(DEPDIR)/stunnel-options.Po -rm -f ./$(DEPDIR)/stunnel-protocol.Po -rm -f ./$(DEPDIR)/stunnel-pty.Po -rm -f ./$(DEPDIR)/stunnel-resolver.Po -rm -f ./$(DEPDIR)/stunnel-ssl.Po -rm -f ./$(DEPDIR)/stunnel-sthreads.Po -rm -f ./$(DEPDIR)/stunnel-str.Po -rm -f ./$(DEPDIR)/stunnel-stunnel.Po -rm -f ./$(DEPDIR)/stunnel-tls.Po -rm -f ./$(DEPDIR)/stunnel-ui_unix.Po -rm -f ./$(DEPDIR)/stunnel-verify.Po -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 -f ./$(DEPDIR)/env.Plo -rm -f ./$(DEPDIR)/stunnel-client.Po -rm -f ./$(DEPDIR)/stunnel-cron.Po -rm -f ./$(DEPDIR)/stunnel-ctx.Po -rm -f ./$(DEPDIR)/stunnel-dhparam.Po -rm -f ./$(DEPDIR)/stunnel-fd.Po -rm -f ./$(DEPDIR)/stunnel-file.Po -rm -f ./$(DEPDIR)/stunnel-libwrap.Po -rm -f ./$(DEPDIR)/stunnel-log.Po -rm -f ./$(DEPDIR)/stunnel-network.Po -rm -f ./$(DEPDIR)/stunnel-options.Po -rm -f ./$(DEPDIR)/stunnel-protocol.Po -rm -f ./$(DEPDIR)/stunnel-pty.Po -rm -f ./$(DEPDIR)/stunnel-resolver.Po -rm -f ./$(DEPDIR)/stunnel-ssl.Po -rm -f ./$(DEPDIR)/stunnel-sthreads.Po -rm -f ./$(DEPDIR)/stunnel-str.Po -rm -f ./$(DEPDIR)/stunnel-stunnel.Po -rm -f ./$(DEPDIR)/stunnel-tls.Po -rm -f ./$(DEPDIR)/stunnel-ui_unix.Po -rm -f ./$(DEPDIR)/stunnel-verify.Po -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 install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am 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 .PRECIOUS: Makefile stunnel3: Makefile $(edit) '$(srcdir)/$@.in' >$@ stunnel3: $(srcdir)/stunnel3.in ############################################################################### # Win32 executables # ############################################################################### mingw: $(MAKE) -f $(srcdir)/mingw.mk srcdir=$(srcdir) win32_arch=win32 win32_targetcpu=i686 win32_mingw=mingw mingw64: $(MAKE) -f $(srcdir)/mingw.mk srcdir=$(srcdir) win32_arch=win64 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.56/src/ssl.c0000664000175000017500000003044513554262513011634 00000000000000/* * stunnel TLS offloading and load-balancing proxy * Copyright (C) 1998-2019 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 */ #if OPENSSL_VERSION_NUMBER>=0x10100000L NOEXPORT int cb_dup_addr(CRYPTO_EX_DATA *to, const CRYPTO_EX_DATA *from, void *from_d, int idx, long argl, void *argp); #else NOEXPORT int cb_dup_addr(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from, void *from_d, int idx, long argl, void *argp); #endif NOEXPORT void cb_free_addr(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 *); NOEXPORT void update_rand_file(const char *); int index_ssl_cli, index_ssl_ctx_opt; int index_session_authenticated, index_session_connect_address; int ssl_init(void) { /* init TLS before parsing configuration file */ #if OPENSSL_VERSION_NUMBER>=0x10100000L OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS | OPENSSL_INIT_LOAD_CONFIG, NULL); #else OPENSSL_config(NULL); SSL_load_error_strings(); SSL_library_init(); #endif index_ssl_cli=SSL_get_ex_new_index(0, "CLI pointer", NULL, NULL, NULL); index_ssl_ctx_opt=SSL_CTX_get_ex_new_index(0, "SERVICE_OPTIONS pointer", NULL, NULL, NULL); index_session_authenticated=SSL_SESSION_get_ex_new_index(0, "session authenticated", NULL, NULL, NULL); index_session_connect_address=SSL_SESSION_get_ex_new_index(0, "session connect address", NULL, cb_dup_addr, cb_free_addr); if(index_ssl_cli<0 || index_ssl_ctx_opt<0 || index_session_authenticated<0 || index_session_connect_address<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; } #ifndef OPENSSL_NO_DH #if OPENSSL_VERSION_NUMBER<0x10100000L /* this is needed for dhparam.c generated with OpenSSL >= 1.1.0 * to be linked against the older versions */ int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) { if(!p || !g) /* q is optional */ return 0; BN_free(dh->p); BN_free(dh->q); BN_free(dh->g); dh->p = p; dh->q = q; dh->g = g; if(q) dh->length = BN_num_bits(q); return 1; } #endif #endif #if OPENSSL_VERSION_NUMBER>=0x10100000L NOEXPORT int cb_dup_addr(CRYPTO_EX_DATA *to, const CRYPTO_EX_DATA *from, void *from_d, int idx, long argl, void *argp) { #else NOEXPORT int cb_dup_addr(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from, void *from_d, int idx, long argl, void *argp) { #endif SOCKADDR_UNION *src, *dst; socklen_t len; (void)to; /* squash the unused parameter warning */ (void)from; /* squash the unused parameter warning */ (void)idx; /* squash the unused parameter warning */ (void)argl; /* squash the unused parameter warning */ s_log(LOG_DEBUG, "Duplicating application specific data for %s", (char *)argp); src=*(void **)from_d; len=addr_len(src); dst=str_alloc_detached((size_t)len); memcpy(dst, src, (size_t)len); *(void **)from_d=dst; return 1; } NOEXPORT void cb_free_addr(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 TLS 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)) { #if OPENSSL_VERSION_NUMBER>=0x10100000L OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); #else ERR_load_crypto_strings(); #endif 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; return 0; /* SUCCESS */ } #ifndef OPENSSL_NO_COMP #if OPENSSL_VERSION_NUMBER<0x10100000L NOEXPORT int COMP_get_type(const COMP_METHOD *meth) { return meth->type; } NOEXPORT const char *SSL_COMP_get0_name(const SSL_COMP *comp) { return comp->name; } NOEXPORT int SSL_COMP_get_id(const SSL_COMP *comp) { return comp->id; } #endif /* OPENSSL_VERSION_NUMBER<0x10100000L */ NOEXPORT int compression_init(GLOBAL_OPTIONS *global) { STACK_OF(SSL_COMP) *methods; int num_methods, i; 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) { /* 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 */ while(sk_SSL_COMP_num(methods)) OPENSSL_free(sk_SSL_COMP_pop(methods)); s_log(LOG_DEBUG, "Compression disabled"); return 0; /* success */ } if(!sk_SSL_COMP_num(methods)) { s_log(LOG_ERR, "No compression method is available"); return 1; } /* 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(!meth || COMP_get_type(meth)==NID_undef) { s_log(LOG_ERR, "ZLIB compression is not supported"); return 1; } if(SSL_COMP_add_compression_method(0xe0, meth)) { sslerror("SSL_COMP_add_compression_method"); return 1; } } num_methods=sk_SSL_COMP_num(methods); s_log(LOG_INFO, "Compression enabled: %d method%s", num_methods, num_methods==1 ? "" : "s"); for(i=0; istatus==NULL || meth->add==NULL) { s_log(LOG_DEBUG, "No PRNG seeding methods"); return 0; /* success */ } if(RAND_status()) { s_log(LOG_DEBUG, "No PRNG seeding was required"); return 0; /* success */ } /* 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 */ filename[0]='\0'; RAND_file_name(filename, sizeof filename); if(filename[0]) { totbytes+=add_rand_file(global, filename); if(RAND_status()) return 0; /* success */ } #ifdef USE_WIN32 #if OPENSSL_VERSION_NUMBER<0x10100000L 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"); #endif #else /* USE_WIN32 */ #ifndef OPENSSL_NO_EGD if(global->egd_sock) { int bytes=RAND_egd(global->egd_sock); if(bytes>=0) { 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 */ } s_log(LOG_WARNING, "EGD Socket %s failed", global->egd_sock); } #endif #ifndef RANDOM_FILE /* try the good-old default /dev/urandom, if no RANDOM_FILE is defined */ totbytes+=add_rand_file(global, "/dev/urandom"); if(RAND_status()) return 0; /* success */ #endif #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; struct stat sb; if(stat(filename, &sb)) return 0; /* could not stat() file --> return 0 bytes */ readbytes=RAND_load_file(filename, global->random_bytes); if(readbytes<0) { sslerror("RAND_load_file"); s_log(LOG_INFO, "Cannot retrieve any random data from %s", filename); return 0; } s_log(LOG_DEBUG, "Snagged %d random bytes from %s", readbytes, filename); /* write new random data for future seeding if it's a regular file */ if(global->option.rand_write && S_ISREG(sb.st_mode)) update_rand_file(filename); return readbytes; } NOEXPORT void update_rand_file(const char *filename) { int writebytes; writebytes=RAND_write_file(filename); if(writebytes<0) { sslerror("RAND_write_file"); s_log(LOG_WARNING, "Failed to write strong random data to %s - " "may be a permissions or seeding problem", filename); return; } s_log(LOG_DEBUG, "Wrote %d new random bytes to %s", writebytes, filename); } /* end of ssl.c */ stunnel-5.56/doc/0000775000175000017500000000000013566017555010726 500000000000000stunnel-5.56/doc/stunnel.pl.html.in0000644000175000017500000020554513477474603014256 00000000000000 stunnel TLS Proxy
 stunnel TLS Proxy

NAZWA

stunnel - uniwersalny tunel protokołu TLS

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ół TLS 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 TLS poprzez bezpieczne kanały TLS.

stunnel pozwala dodać funkcjonalność TLS 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 TLS

-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.

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.

engine = auto | IDENTYFIKATOR_URZĄDZENIA

wybór sprzętowego urządzenia kryptograficznego

domyślnie: bez wykorzystania urządzeń kryptograficznych

Sekcja PRZYKŁADY zawiera przykładowe konfiguracje wykorzystujące urządzenia kryptograficzne.

engineCtrl = KOMENDA[:PARAMETR]

konfiguracja 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

obsługa logów

Ta opcja pozwala określić, czy nowe logi w pliku (określonym w opcji output) będą dodawane czy nadpisywane.

domyślnie: append

output = PLIK

plik, do którego dopisane zostaną logi

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

Do kierowania komunikató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

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

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 verifyChain lub verifyPeer. 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ę verifyChain lub verifyPeer.

cert = PLIK_CERT

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. Plik powinien zawierać kompletny łańcuch certyfikatów począwszy od certyfikatu klienta/serwera, a skończywszy na samopodpisanym certyfikacie głównego CA. Obsługiwane są pliki w formacie PEM lub P12.

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 podmiotu przedstawionego certyfikatu

Pojedyncza sekcja może zawierać wiele wystąpień opcji checkEmail. Certyfikaty są akceptowane, jeżeli sekcja nie weryfikuje podmiotu certyfikatu, 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 podmiotu przedstawionego certyfikatu

Pojedyncza sekcja może zawierać wiele wystąpień opcji checkHost. Certyfikaty są akceptowane, jeżeli sekcja nie weryfikuje podmiotu certyfikatu, 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 podmiotu przedstawionego certyfikatu

Pojedyncza sekcja może zawierać wiele wystąpień opcji checkIP. Certyfikaty są akceptowane, jeżeli sekcja nie weryfikuje podmiotu certyfikatu, 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 dla protokołów SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2

Ta opcja nie wpływa na listę parametrów kryptograficznych dla protokołu TLSv1.3

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

ciphersuites = LISTA_PARAMETRÓW_KRYPTOGRAFICZNYCH

lista dozwolonych parametrów kryptograficznych dla protokołu TLSv1.3

Parametrem tej opcji są listy parametrów kryptograficznych w kolejności ich preferowania.

Opcja ciphersuites jest dostępna począwszy od OpenSSL 1.1.1.

domyślnie: TLS_CHACHA20_POLY1305_SHA256: TLS_AES_256_GCM_SHA384: TLS_AES_128_GCM_SHA256

client = yes | no

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

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 używanych przez opcje verifyChain i verifyPeer. 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 opcje verifyChain i verifyPeer.

curves = lista

krzywe ECDH odddzielone ':'

Wersje OpenSSL starsze niż 1.1.0 pozwalają na użycie tylko jednej krzywej.

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

    openssl ecparam -list_curves

domyślnie:

    X25519:P-256:X448:P-521:P-384 (począwszy od OpenSSL 1.1.1)

    prime256v1 (OpenSSL starszy niż 1.1.1)
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żyteczny 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ą.

process

Identyfikator procesu (PID) może być użyteczny w trybie inetd.

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.

domyślnie: 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: prio

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. Rekomendowana konwencja nazewnictwa plików

dla opcji globalnych:

        00-global.conf

dla lokalnych opcji usług:

        01-service.conf

        02-service.conf
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.

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 TLS w programie Eudora, można użyć opcji:

    options = DONT_INSERT_EMPTY_FRAGMENTS

domyślnie:

    options = NO_SSLv2
    options = NO_SSLv3

Począwszy od OpenSSL 1.1.0, zamiast wyłączać określone wersje protokołów TLS użyj opcji sslVersionMax lub sslVersionMin.

protocol = PROTOKÓŁ

negocjuj TLS podanym protokołem aplikacyjnym

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

Aktualnie wspierane protokoły:

cifs

Nieudokumentowane 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 oryginalnego IP klienta przez protokół HAProxy PROXY w wersji 1 https://www.haproxy.org/download/1.8/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 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 TLS, 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

Szesnastkowe klucze są automatycznie konwertowane do postaci binarnej. Klucz musi być mieć przynajmniej 16 bajtów, co w przypadku kluczy szesnastkowych przekłada się na przynajmniej 32 znaki. 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ę TLS

Zastosowania renegocjacji TLS zawierają niektóre scenariusze uwierzytelniania oraz renegocjację 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 TLS 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

requireCert = yes | no

wymagaj certyfikatu klienta dla verifyChain lub verifyPeer

Przy opcji requireCert ustawionej na no, stunnel akceptuje połączenia klientów, które nie wysłały certyfikatu.

Zarówno verifyChain = yes jak i verifyPeer = yes automatycznie ustawiają requireCert na yes.

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 TLS

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 TLS

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

sessiond = HOST:PORT

adres sessiond - servera cache sesji TLS

sni = NAZWA_USŁUGI: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 = NAZWA_SERWERA (tryb klienta)

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

Pusta wartość parametru NAZWA_SERWERA wyłącza wysyłanie rozszerzenia SNI.

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

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)
sslVersion = WERSJA_SSL

wersja protokołu TLS

Wspierane wersje: all, SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3

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

Przestarzałe protokoły SSLv2 i SSLv3 są domyślnie wyłączone.

Począwszy od OpenSSL 1.1.0, ustawienie

    sslVersion = WERSJA_SSL

jest równoważne opcjom

    sslVersionMax = WERSJA_SSL
    sslVersionMin = WERSJA_SSL
sslVersionMax = WERSJA_SSL

maksymalna wspierana wersja protokołu TLS

Wspierane wersje: all, SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3

all włącza wszystkie wersje protokołów aż do maksymalnej wersji wspieranej przez bibliotekę użytej wersji OpenSSL.

Dostępność konkretnych protokołów zależy od użytej wersji OpenSSL.

Opcja sslVersionMax jest dostępna począwszy od OpenSSL 1.1.0.

domyślnie: all

sslVersionMin = WERSJA_SSL

minimalna wspierana wersja protokołu TLS

Wspierane wersje: all, SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3

all włącza wszystkie wersje protokołów aż do minimalnej wersji wspieranej przez bibliotekę użytej wersji OpenSSL.

Dostępność konkretnych protokołów zależy od użytej wersji OpenSSL.

Opcja sslVersionMin jest dostępna począwszy od OpenSSL 1.1.0.

domyślnie: TLSv1

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

rozmiar stosu procesora tworzonych wątków

Zbyt duży stos zwiększa zużycie pamięci wirtualnej. Zbyt mały stos może powodować problemy ze stabilnością aplikacji.

domyślnie: 65536 bytes (wystarczający dla testowanych platform)

ticketKeySecret = SECRET

szesnastkowy klucz symetryczny używany przez serwer do zapewnienia poufności biletów sesji

Bilety sesji zdefiniowane w RFC 5077 zapewniają ulepszoną możliwość wznawiania sesji, w której implementacja serwera nie jest wymagana do utrzymania stanu sesji.

Łączne użycie opcji ticketKeySecret i ticketMacSecret umożliwia wznawianie sesji na klastrze serwerów lub wznowienie sesji po restarcie serwera.

Klucz musi mieć rozmiar 16 lub 32 bajtów, co przekłada się na dokładnie 32 lub 64 cyfry szesnastkowe. Poszczególne bajty mogą być opcjonalnie oddzielone dwukropkami.

Opcja działa wyłącznie w trybie serwera.

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

Wyłączenie opcji NO_TICKET jest wymagane dla obsługi biletów sesji w OpenSSL-u starszym niż 1.1.1, ale opcja ta jest niekompatybilna z opcją redirect.

ticketMacSecret = SECRET

szesnastkowy klucz symetryczny używany przez serwer zapewnienia integralności biletów sesji

Klucz musi mieć rozmiar 16 lub 32 bajtów, co przekłada się na dokładnie 32 lub 64 cyfry szesnastkowe. Poszczególne bajty mogą być opcjonalnie oddzielone dwukropkami.

Opcja działa wyłącznie w trybie serwera.

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

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 wartości:

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

Opcja ta jest przestarzała i należy ją zastąpić przez opcje verifyChain i verifyPeer.

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

verifyChain = yes | no

weryfikuj łańcuch certyfikatów drugiej strony

Do weryfikacji certyfikatu serwera kluczowe jest, aby wymagać również konkretnego certyfikatu przy pomocy checkHost lub checkIP.

Samopodpisany certyfikat głównego CA należy umieścić albo w pliku podanym w opcji CAfile, albo w katalogu podanym w opcji CApath.

domyślnie: no

verifyPeer = yes | no

weryfikuj certyfikat drugiej strony

Certyfikat drugiej strony należy umieścić albo w pliku podanym w opcji CAfile, albo w katalogu podanym w opcji CApath.

domyślnie: no

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.

SIGUSR2

Zapisz w logu listę aktywnych połączeń.

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 TLS 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
    verifyPeer = yes
    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/

Przykładowa konfiguracja serwera SNI:

    [virtual]
    ; usługa nadrzędna
    accept = 443
    cert =  default.pem
    connect = default.internal.mydomain.com:8080

    [sni1]
    ; usługa podrzędna 1
    sni = virtual:server1.mydomain.com
    cert = server1.pem
    connect = server1.internal.mydomain.com:8081

    [sni2]
    ; usługa podrzędna 2
    sni = virtual:server2.mydomain.com
    cert = server2.pem
    connect = server2.internal.mydomain.com:8082
    verifyPeer = yes
    CAfile = server2-allowed-clients.pem

Przykładowa konfiguracja umożliwiająca uwierzytelnienie z użyciem klucza prywatnego przechowywanego w Windows Certificate Store (tylko Windows). W przypadku użycia silnika CAPI, nie należy ustawiać opcji cert, gdyż klucz klienta zostanie automatycznie pobrany z Certificate Store na podstawie zaufanych certyfikatów CA przedstawionych przez serwer.

    engine = capi

    [service]
    engineId = capi
    client = yes
    accept = 127.0.0.1:8080
    connect = example.com:8443

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

    engine = pkcs11
    engineCtrl = MODULE_PATH:opensc-pkcs11.so
    engineCtrl = PIN:123456

    [service]
    engineId = pkcs11
    client = yes
    accept = 127.0.0.1:8080
    connect = example.com:843
    cert = pkcs11:token=MyToken;object=MyCert
    key = pkcs11:token=MyToken;object=MyKey

Przykładowa konfiguracja umożliwiająca użycie certyfikatu i klucza prywatnego umieszczonego na tokenie SoftHSM

    engine = pkcs11
    engineCtrl = MODULE_PATH:softhsm2.dll
    engineCtrl = PIN:12345

    [service]
    engineId = pkcs11
    client = yes
    accept = 127.0.0.1:8080
    connect = example.com:843
    cert = pkcs11:token=MyToken;object=KeyCert

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 TLS.

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ół TLS 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.

Plik .pem powinien zawierać klucz prywatny oraz podpisany certyfikat (nie żądanie certyfikatu). Otrzymany plik powinien mieć następującą postać:

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

LOSOWOŚĆ

stunnel potrzebuje zainicjować PRNG (generator liczb pseudolosowych), gdyż protokół TLS 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.

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@stunnel.org>

 stunnel TLS Proxy
stunnel-5.56/doc/stunnel.html.in0000644000175000017500000015545013477474603013643 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 TLS encryption wrapper between remote clients and local (inetd-startable) or remote servers. The concept is that having non-TLS aware daemons running on your system you can easily set them up to communicate with clients over secure TLS channels.

stunnel can be used to add TLS 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 TLS 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.

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.

engine = auto | ENGINE_ID

select hardware or software cryptographic engine

default: software-only cryptography

See Examples section for an engine configuration to use the certificate and the corresponding private key from a cryptographic device.

engineCtrl = COMMAND[:PARAMETER]

control hardware engine

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

RNDfile = FILE

path to file with random seed data

The OpenSSL 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

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 verifyChain or verifyPeer options. 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 = CA_FILE

Certificate Authority file

This file contains multiple CA certificates, to be used with the verifyChain and verifyPeer options.

cert = CERT_FILE

certificate chain file name

The parameter specifies the file containing certificates used by stunnel to authenticate itself against the remote client or server. The file should contain the whole certificate chain starting from the actual server/client certificate, and ending with the self-signed root CA certificate. The file must be either in PEM or P12 format.

A certificate chain 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 subject checks were 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 subject checks were 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 subject checks were 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 TLS ciphers (TLSv1.2 and below)

This option does not impact TLSv1.3 ciphersuites.

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

ciphersuites = CIPHERSUITES_LIST

select permitted TLSv1.3 ciphersuites

A colon-delimited list of TLSv1.3 ciphersuites names in order of preference.

This option requires OpenSSL 1.1.1 or later.

default: TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256

client = yes | no

client mode (remote service uses TLS)

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 verifyChain and verifyPeer options. 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 = CRL_FILE

Certificate Revocation Lists file

This file contains multiple CRLs, used with the verifyChain and verifyPeer options.

curves = list

ECDH curves separated with ':'

Only a single curve name is allowed for OpenSSL older than 1.1.0.

To get a list of supported curves use:

    openssl ecparam -list_curves

default:

    X25519:P-256:X448:P-521:P-384 (OpenSSL 1.1.1 or later)

    prime256v1 (OpenSSL older than 1.1.1)
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.

process

The operating system process identifier (PID) may be useful in the inetd mode.

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: prio

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. The recommended filename convention is

for global options:

        00-global.conf

for local service-level options:

        01-service.conf

        02-service.conf
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.

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 TLS implementation, the following option can be used:

    options = DONT_INSERT_EMPTY_FRAGMENTS

default:

    options = NO_SSLv2
    options = NO_SSLv3

Use sslVersionMax or sslVersionMin option instead of disabling specific TLS protocol versions when compiled with OpenSSL 1.1.0 or later.

protocol = PROTO

application protocol to negotiate TLS

This option enables initial, protocol-specific negotiation of the TLS encryption. The protocol option should not be used with TLS 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

Passing of the original client IP with HAProxy PROXY protocol version 1 https://www.haproxy.org/download/1.8/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 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 TLS 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

Hexadecimal keys are automatically converted to binary form. Keys are required to be at least 16 bytes long, which implies at least 32 characters for hexadecimal keys. The file should neither be world-readable nor world-writable.

pty = yes | no (Unix only)

allocate a pseudoterminal for 'exec' option

redirect = [HOST:]PORT

redirect TLS 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 TLS renegotiation

Applications of the TLS 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 TLS 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

requireCert = yes | no

require a client certificate for verifyChain or verifyPeer

With requireCert set to no, the stunnel server accepts client connections that did not present a certificate.

Both verifyChain = yes and verifyPeer = yes imply requireCert = yes.

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 TLS sessions.

sessiond = HOST:PORT

address of sessiond TLS cache server

sni = SERVICE_NAME:SERVER_NAME_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_NAME (client mode)

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

Empty SERVER_NAME disables sending the SNI extension.

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

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
sslVersion = SSL_VERSION

select the TLS protocol version

Supported versions: all, SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3

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

Obsolete SSLv2 and SSLv3 are currently disabled by default.

Setting the option

    sslVersion = SSL_VERSION

is equivalent to options

    sslVersionMax = SSL_VERSION
    sslVersionMin = SSL_VERSION

when compiled with OpenSSL 1.1.0 and later.

sslVersionMax = SSL_VERSION

maximum supported protocol versions

Supported versions: all, SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3

all enable protocol versions up to the highest version supported by the linked OpenSSL library.

Availability of specific protocols depends on the linked OpenSSL library.

The sslVersionMax option is only available when compiled with OpenSSL 1.1.0 and later.

default: all

sslVersionMin = SSL_VERSION

minimum supported protocol versions

Supported versions: all, SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3

all enable protocol versions down to the lowest version supported by the linked OpenSSL library.

Availability of specific protocols depends on the linked OpenSSL library.

The sslVersionMin option is only available when compiled with OpenSSL 1.1.0 and later.

default: TLSv1

stack = BYTES (except for FORK model)

CPU stack size of created threads

Excessive thread stack size increases virtual memory usage. Insufficient thread stack size may cause application crashes.

default: 65536 bytes (sufficient for all platforms we tested)

ticketKeySecret = SECRET

hexadecimal symmetric key used for session ticket confidentiality protection

Session tickets defined in RFC 5077 provide an enhanced session resumption capability, where the server-side caching is not required to maintain per session state.

Combining ticketKeySecret and ticketMacSecret options allow to resume a negotiated session on other cluster nodes, or to resume resume a negotiated session after server restart.

The key is required to be either 16 or 32 bytes long, which implies exactly 32 or 64 hexadecimal digits. Colons may optionally be used between two-character hexadecimal bytes.

This option only works in server mode.

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

Disabling NO_TICKET option is required for the ticket support in OpenSSL older than 1.1.1, but note that this option is incompatible with the redirect option.

ticketMacSecret = SECRET

hexadecimal symmetric key used for session ticket integrity protection

The key is required to be either 16 or 32 bytes long, which implies exactly 32 or 64 hexadecimal digits. Colons may optionally be used between two-character hexadecimal bytes.

This option only works in server mode.

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

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 TLS 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

This option is obsolete and should be replaced with the verifyChain and verifyPeer options.

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 against a locally installed certificate.

level 4

Ignore the chain and only verify the peer certificate.

default

No verify.

verifyChain = yes | no

verify the peer certificate chain starting from the root CA

For server certificate verification it is essential to also require a specific certificate with checkHost or checkIP.

The self-signed root CA certificate needs to be stored either in the file specified with CAfile, or in the directory specified with CApath.

default: no

verifyPeer = yes | no

verify the peer certificate

The peer certificate needs to be stored either in the file specified with CAfile, or in the directory specified with CApath.

default: no

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.

SIGUSR2

Log the list of active connections.

SIGTERM, SIGQUIT, SIGINT

Shut stunnel down.

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

EXAMPLES

In order to provide TLS 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 a TLS-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
    verifyPeer = yes
    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/

An example server mode SNI configuration:

    [virtual]
    ; master service
    accept = 443
    cert =  default.pem
    connect = default.internal.mydomain.com:8080

    [sni1]
    ; slave service 1
    sni = virtual:server1.mydomain.com
    cert = server1.pem
    connect = server1.internal.mydomain.com:8081

    [sni2]
    ; slave service 2
    sni = virtual:server2.mydomain.com
    cert = server2.pem
    connect = server2.internal.mydomain.com:8082
    verifyPeer = yes
    CAfile = server2-allowed-clients.pem

An example of advanced engine configuration allows for authentication with private keys stored in the Windows certificate store (Windows only). With the CAPI engine you don't need to manually select the client key to use. The client key is automatically selected based on the list of CAs trusted by the server.

    engine = capi

    [service]
    engineId = capi
    client = yes
    accept = 127.0.0.1:8080
    connect = example.com:8443

An example of advanced engine configuration to use the certificate and the corresponding private key from a pkcs11 engine:

    engine = pkcs11
    engineCtrl = MODULE_PATH:opensc-pkcs11.so
    engineCtrl = PIN:123456

    [service]
    engineId = pkcs11
    client = yes
    accept = 127.0.0.1:8080
    connect = example.com:843
    cert = pkcs11:token=MyToken;object=MyCert
    key = pkcs11:token=MyToken;object=MyKey

An example of advanced engine configuration to use the certificate and the corresponding private key from a SoftHSM token:

    engine = pkcs11
    engineCtrl = MODULE_PATH:softhsm2.dll
    engineCtrl = PIN:12345

    [service]
    engineId = pkcs11
    client = yes
    accept = 127.0.0.1:8080
    connect = example.com:843
    cert = pkcs11:token=MyToken;object=KeyCert

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 TLS-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 TLS-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 .pem file should contain the unencrypted private key and a signed certificate (not certificate request). So the file should look like this:

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

RANDOMNESS

stunnel needs to seed the PRNG (pseudo-random number generator) in order for TLS 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.

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@stunnel.org>

 stunnel TLS Proxy
stunnel-5.56/doc/en/0000755000175000017500000000000012540237351011313 500000000000000stunnel-5.56/doc/en/VNC_StunnelHOWTO.html0000664000175000017500000002035612540020663015104 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.56/doc/stunnel.pl.pod.in0000664000175000017500000013273413477473304014072 00000000000000=head1 NAZWA =encoding utf8 stunnel - uniwersalny tunel protokołu TLS =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 TLS =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. =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. =item B = auto | IDENTYFIKATOR_URZĄDZENIA wybór sprzętowego urządzenia kryptograficznego domyślnie: bez wykorzystania urządzeń kryptograficznych Sekcja PRZYKŁADY zawiera przykładowe konfiguracje wykorzystujące urządzenia kryptograficzne. =item B = KOMENDA[:PARAMETR] konfiguracja 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 obsługa logów Ta opcja pozwala określić, czy nowe logi w pliku (określonym w opcji I) będą dodawane czy nadpisywane. 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 kierowania komunikató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 =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 = 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 lub 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 lub I. =item B = PLIK_CERT 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. Plik powinien zawierać kompletny łańcuch certyfikatów począwszy od certyfikatu klienta/serwera, a skończywszy na samopodpisanym certyfikacie głównego CA. Obsługiwane są pliki w formacie PEM lub P12. 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 podmiotu przedstawionego certyfikatu Pojedyncza sekcja może zawierać wiele wystąpień opcji B. Certyfikaty są akceptowane, jeżeli sekcja nie weryfikuje podmiotu certyfikatu, 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 podmiotu przedstawionego certyfikatu Pojedyncza sekcja może zawierać wiele wystąpień opcji B. Certyfikaty są akceptowane, jeżeli sekcja nie weryfikuje podmiotu certyfikatu, 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 podmiotu przedstawionego certyfikatu Pojedyncza sekcja może zawierać wiele wystąpień opcji B. Certyfikaty są akceptowane, jeżeli sekcja nie weryfikuje podmiotu certyfikatu, 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 dla protokołów SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2 Ta opcja nie wpływa na listę parametrów kryptograficznych dla protokołu TLSv1.3 Parametrem tej opcji jest lista szyfrów, które będą użyte przy otwieraniu nowych połączeń TLS, np.: DES-CBC3-SHA:IDEA-CBC-MD5 =item B = LISTA_PARAMETRÓW_KRYPTOGRAFICZNYCH lista dozwolonych parametrów kryptograficznych dla protokołu TLSv1.3 Parametrem tej opcji są listy parametrów kryptograficznych w kolejności ich preferowania. Opcja I jest dostępna począwszy od B. domyślnie: TLS_CHACHA20_POLY1305_SHA256: TLS_AES_256_GCM_SHA384: TLS_AES_128_GCM_SHA256 =item B = yes | no tryb kliencki (zdalna usługa używa TLS) 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 używanych przez opcje I i 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 opcje I i I. =item B = lista krzywe ECDH odddzielone ':' Wersje OpenSSL starsze niż 1.1.0 pozwalają na użycie tylko jednej krzywej. Listę dostępnych krzywych można uzyskać poleceniem: openssl ecparam -list_curves domyślnie: X25519:P-256:X448:P-521:P-384 (począwszy od OpenSSL 1.1.1) prime256v1 (OpenSSL starszy niż 1.1.1) =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żyteczny 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ą. =item I Identyfikator procesu (PID) może być użyteczny w trybie inetd. =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. domyślnie: 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". =over 4 =item I round robin - sprawiedliwe rozłożenie obciążenia =item I priority - użyj kolejności opcji w pliku konfiguracyjnym =back domyślnie: prio =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. Rekomendowana konwencja nazewnictwa plików dla opcji globalnych: 00-global.conf dla lokalnych opcji usług: 01-service.conf 02-service.conf =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 = 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 TLS w programie Eudora, można użyć opcji: options = DONT_INSERT_EMPTY_FRAGMENTS domyślnie: options = NO_SSLv2 options = NO_SSLv3 Począwszy od B, zamiast wyłączać określone wersje protokołów TLS użyj opcji I lub I. =item B = PROTOKÓŁ negocjuj TLS podanym protokołem aplikacyjnym Opcja ta włącza wstępną negocjację szyfrowania TLS dla wybranego protokołu aplikacyjnego. Opcji I nie należy używać z szyfrowaniem TLS na osobnym porcie. Aktualnie wspierane protokoły: =over 4 =item I Nieudokumentowane 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 F =item I Negocjacja RFC 2449 - I =item I Przekazywanie oryginalnego IP klienta przez protokół HAProxy PROXY w wersji 1 F =item I Negocjacja RFC 2487 - I =item I Wspierany jest protokół SOCKS w wersjach 4, 4a i 5. Protokół SOCKS enkapsulowany jest w protokole 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 TLS, 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 Szesnastkowe klucze są automatycznie konwertowane do postaci binarnej. Klucz musi być mieć przynajmniej 16 bajtów, co w przypadku kluczy szesnastkowych przekłada się na przynajmniej 32 znaki. 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ę TLS Zastosowania renegocjacji TLS zawierają niektóre scenariusze uwierzytelniania oraz renegocjację 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 TLS 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 = yes | no wymagaj certyfikatu klienta dla I lub I Przy opcji I ustawionej na I, B akceptuje połączenia klientów, które nie wysłały certyfikatu. Zarówno I jak i I automatycznie ustawiają I na I. 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 TLS 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 TLS Parametr określa czas w sekundach, po którym sesja TLS zostanie usunięta z pamięci podręcznej. =item B = HOST:PORT adres sessiond - servera cache sesji TLS =item B = NAZWA_USŁUGI: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 = NAZWA_SERWERA (tryb klienta) Użyj parametru jako wartości rozszerzenia TLS Server Name Indication (RFC 3546). Pusta wartość parametru NAZWA_SERWERA wyłącza wysyłanie rozszerzenia SNI. Opcja I jest dostępna począwszy od B. =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 = WERSJA_SSL wersja protokołu TLS Wspierane wersje: all, SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3 Dostępność konkretnych protokołów zależy od użytej wersji OpenSSL. Starsze wersje OpenSSL nie wspierają TLSv1.1, TLSv1.2, TLSv1.3. Nowsze wersje OpenSSL nie wspierają SSLv2. Przestarzałe protokoły SSLv2 i SSLv3 są domyślnie wyłączone. Począwszy od B, ustawienie sslVersion = WERSJA_SSL jest równoważne opcjom sslVersionMax = WERSJA_SSL sslVersionMin = WERSJA_SSL =item B = WERSJA_SSL maksymalna wspierana wersja protokołu TLS Wspierane wersje: all, SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3 I włącza wszystkie wersje protokołów aż do maksymalnej wersji wspieranej przez bibliotekę użytej wersji OpenSSL. Dostępność konkretnych protokołów zależy od użytej wersji OpenSSL. Opcja I jest dostępna począwszy od B. domyślnie: all =item B = WERSJA_SSL minimalna wspierana wersja protokołu TLS Wspierane wersje: all, SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3 I włącza wszystkie wersje protokołów aż do minimalnej wersji wspieranej przez bibliotekę użytej wersji OpenSSL. Dostępność konkretnych protokołów zależy od użytej wersji OpenSSL. Opcja I jest dostępna począwszy od B. domyślnie: TLSv1 =item B = LICZBA_BAJTÓW (z wyjątkiem modelu FORK) rozmiar stosu procesora tworzonych wątków Zbyt duży stos zwiększa zużycie pamięci wirtualnej. Zbyt mały stos może powodować problemy ze stabilnością aplikacji. domyślnie: 65536 bytes (wystarczający dla testowanych platform) =item B = SECRET szesnastkowy klucz symetryczny używany przez serwer do zapewnienia poufności biletów sesji Bilety sesji zdefiniowane w RFC 5077 zapewniają ulepszoną możliwość wznawiania sesji, w której implementacja serwera nie jest wymagana do utrzymania stanu sesji. Łączne użycie opcji I i I umożliwia wznawianie sesji na klastrze serwerów lub wznowienie sesji po restarcie serwera. Klucz musi mieć rozmiar 16 lub 32 bajtów, co przekłada się na dokładnie 32 lub 64 cyfry szesnastkowe. Poszczególne bajty mogą być opcjonalnie oddzielone dwukropkami. Opcja działa wyłącznie w trybie serwera. Opcja I jest dostępna począwszy od B. Wyłączenie opcji I jest wymagane dla obsługi biletów sesji w OpenSSL-u starszym niż 1.1.1, ale opcja ta jest niekompatybilna z opcją I. =item B = SECRET szesnastkowy klucz symetryczny używany przez serwer zapewnienia integralności biletów sesji Klucz musi mieć rozmiar 16 lub 32 bajtów, co przekłada się na dokładnie 32 lub 64 cyfry szesnastkowe. Poszczególne bajty mogą być opcjonalnie oddzielone dwukropkami. Opcja działa wyłącznie w trybie serwera. Opcja I jest dostępna począwszy od B. =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 wartości: =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 Opcja ta jest przestarzała i należy ją zastąpić przez opcje I i I. =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 =item B = yes | no weryfikuj łańcuch certyfikatów drugiej strony Do weryfikacji certyfikatu serwera kluczowe jest, aby wymagać również konkretnego certyfikatu przy pomocy I lub I. Samopodpisany certyfikat głównego CA należy umieścić albo w pliku podanym w opcji I, albo w katalogu podanym w opcji I. domyślnie: no =item B = yes | no weryfikuj certyfikat drugiej strony Certyfikat drugiej strony należy umieścić albo w pliku podanym w opcji I, albo w katalogu podanym w opcji I. domyślnie: no =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 SIGUSR2 Zapisz w logu listę aktywnych połączeń. =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 TLS 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 verifyPeer = yes 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/ Przykładowa konfiguracja serwera SNI: [virtual] ; usługa nadrzędna accept = 443 cert = default.pem connect = default.internal.mydomain.com:8080 [sni1] ; usługa podrzędna 1 sni = virtual:server1.mydomain.com cert = server1.pem connect = server1.internal.mydomain.com:8081 [sni2] ; usługa podrzędna 2 sni = virtual:server2.mydomain.com cert = server2.pem connect = server2.internal.mydomain.com:8082 verifyPeer = yes CAfile = server2-allowed-clients.pem Przykładowa konfiguracja umożliwiająca uwierzytelnienie z użyciem klucza prywatnego przechowywanego w Windows Certificate Store (tylko Windows). W przypadku użycia silnika CAPI, nie należy ustawiać opcji cert, gdyż klucz klienta zostanie automatycznie pobrany z Certificate Store na podstawie zaufanych certyfikatów CA przedstawionych przez serwer. engine = capi [service] engineId = capi client = yes accept = 127.0.0.1:8080 connect = example.com:8443 Przykładowa konfiguracja umożliwiająca użycie certyfikatu i klucza prywatnego z urządzenia zgodnego z pkcs11: engine = pkcs11 engineCtrl = MODULE_PATH:opensc-pkcs11.so engineCtrl = PIN:123456 [service] engineId = pkcs11 client = yes accept = 127.0.0.1:8080 connect = example.com:843 cert = pkcs11:token=MyToken;object=MyCert key = pkcs11:token=MyToken;object=MyKey Przykładowa konfiguracja umożliwiająca użycie certyfikatu i klucza prywatnego umieszczonego na tokenie SoftHSM engine = pkcs11 engineCtrl = MODULE_PATH:softhsm2.dll engineCtrl = PIN:12345 [service] engineId = pkcs11 client = yes accept = 127.0.0.1:8080 connect = example.com:843 cert = pkcs11:token=MyToken;object=KeyCert =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ół TLS 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. Plik I<.pem> powinien zawierać klucz prywatny oraz podpisany certyfikat (nie żądanie certyfikatu). Otrzymany plik powinien mieć następującą postać: -----BEGIN RSA PRIVATE KEY----- [zakodowany klucz] -----END RSA PRIVATE KEY----- -----BEGIN CERTIFICATE----- [zakodowany certyfikat] -----END CERTIFICATE----- =head2 LOSOWOŚĆ B potrzebuje zainicjować PRNG (generator liczb pseudolosowych), gdyż protokół TLS 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 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.56/doc/Makefile.am0000664000175000017500000000200013467064764012676 00000000000000## Process this file with automake to produce Makefile.in # by Michal Trojnara 1998-2019 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) DISTCLEANFILES = $(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' \ -e '\|^ round robin - fair load distribution =item I priority - use the order specified in config file =back default: prio =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. The recommended filename convention is for global options: 00-global.conf for local service-level options: 01-service.conf 02-service.conf =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 = 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