[packages] stunnel: update to 4.33 (closes: #7296)
authorNicolas Thill <nico@openwrt.org>
Thu, 13 May 2010 00:47:17 +0000 (00:47 +0000)
committerNicolas Thill <nico@openwrt.org>
Thu, 13 May 2010 00:47:17 +0000 (00:47 +0000)
SVN-Revision: 21439

net/stunnel/Makefile
net/stunnel/patches/100-cross-compile.patch
net/stunnel/patches/101-no-comp.patch
net/stunnel/patches/102-no-ssl2.patch
net/stunnel/patches/103-no-zlib-link.patch
net/stunnel/patches/104-fix-paths.patch
net/stunnel/patches/105-stunnel-conf.patch
net/stunnel/patches/106-stunnel-xforwardedfor.patch

index 12b7f7ced3cd1c3836ee5d19e39945b24b69ff9c..59acf976636fc55c5da574e773b2f56fa9940210 100644 (file)
@@ -1,11 +1,17 @@
+#
+# Copyright (C) 2006-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
 
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=stunnel
-PKG_VERSION:=4.29
-PKG_RELEASE:=4
+PKG_VERSION:=4.33
+PKG_RELEASE:=1
 
-PKG_MD5SUM:=14dc3f8412947f0548975cbce74d6863
+PKG_MD5SUM:=559a864066d8cc4afd8a97682c90d41c
 PKG_SOURCE_URL:=http://www.stunnel.org/download/stunnel/src/
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 
index 52052a02e097335408c04d64d2eb73acca281385..6d7648c4a60b85413d6e409df4c7a6a1f005e66e 100644 (file)
@@ -1,6 +1,6 @@
 --- a/configure
 +++ b/configure
-@@ -21536,56 +21536,56 @@ _ACEOF
+@@ -21552,56 +21552,56 @@ _ACEOF
  fi
  rm -f conftest*
  
  
  
  { echo "$as_me:$LINENO: **************************************** entropy" >&5
-@@ -24033,8 +24033,8 @@ _ACEOF
+@@ -24049,8 +24049,8 @@ _ACEOF
  
  
  # Add SSL includes and libraries
index 640bd8948261664ed21cbaaf67f69f0d01543e84..9fbe22c9e9a08ba10f9bb6215911c0513adf794d 100644 (file)
@@ -1,27 +1,28 @@
 --- a/src/ssl.c
 +++ b/src/ssl.c
-@@ -63,13 +63,16 @@ void ssl_init(void) { /* init SSL before
- }
void ssl_configure(void) { /* configure global SSL settings */
-+#ifndef OPENSSL_NO_COMP
-     if(options.compression!=COMP_NONE)
-         init_compression();
+@@ -72,14 +72,17 @@ int ssl_configure(void) { /* configure g
+     s_log(LOG_NOTICE, "FIPS mode %s",
+         global_options.option.fips ? "enabled" : "disabled");
#endif /* USE_FIPS */
++#ifndef OPENSSL_NO_COMP   
+     if(global_options.compression!=COMP_NONE && !init_compression())
+         return 0;
 +#endif
      if(!init_prng())
-         s_log(LOG_DEBUG, "PRNG seeded successfully");
+         return 0;
+     s_log(LOG_DEBUG, "PRNG seeded successfully");
+     return 1; /* SUCCESS */
  }
  
- static void init_compression(void) {
 +#ifndef OPENSSL_NO_COMP
+ static int init_compression(void) {
      int id=0;
      COMP_METHOD *cm=NULL;
-     char *name="unknown";
-@@ -98,6 +101,7 @@ static void init_compression(void) {
-         die(1);
-     }
+@@ -111,6 +114,7 @@ static int init_compression(void) {
      s_log(LOG_INFO, "Compression enabled using %s method", name);
-+#endif
+     return 1;
  }
++#endif
  
  static int init_prng(void) {
+     int totbytes=0;
index 9ebd4243a0196cf4bc9ce7e930376b5038ba13bf..e94184b04e717abac67e0500ef6b90a7d45a5fd2 100644 (file)
@@ -1,6 +1,6 @@
 --- a/src/options.c
 +++ b/src/options.c
-@@ -1198,8 +1198,10 @@ static char *service_options(CMD cmd, LO
+@@ -1234,8 +1234,10 @@ static char *parse_service_option(CMD cm
              section->client_method=(SSL_METHOD *)SSLv23_client_method();
              section->server_method=(SSL_METHOD *)SSLv23_server_method();
          } else if(!strcasecmp(arg, "SSLv2")) {
index 6e2a45651d35e9b7954f6801f1f68575f8b2892b..f627c53c850ca5c00d41ea5755ffcba65d001ec2 100644 (file)
@@ -1,7 +1,7 @@
 Avoid linking with zlib, which is a dependency of openssl, not ours.
 --- a/configure
 +++ b/configure
-@@ -23001,7 +23001,7 @@ if test $ac_cv_lib_z_inflateEnd = yes; t
+@@ -23017,7 +23017,7 @@ if test $ac_cv_lib_z_inflateEnd = yes; t
  #define HAVE_LIBZ 1
  _ACEOF
  
index 3c9966794b1c9be33c69201369bff0109a0332e3..aad310b94e2567b991928c823d6173411c4ff959 100644 (file)
@@ -1,41 +1,42 @@
 ## Do several path fixups, removing unneeded @prefix@s
 --- a/tools/stunnel.conf-sample.in
 +++ b/tools/stunnel.conf-sample.in
-@@ -3,14 +3,14 @@
- ; Please make sure you understand them (especially the effect of the chroot jail)
+@@ -4,15 +4,15 @@
+ ; please read the manual and make sure you understand them
  
- ; Certificate/key is needed in server mode and optional in client mode
+ ; certificate/key is needed in server mode and optional in client mode
 -cert = @prefix@/etc/stunnel/mail.pem
 -;key = @prefix@/etc/stunnel/mail.pem
 +cert = @sysconfdir@/stunnel/stunnel.pem
 +;key = @sysconfdir@/stunnel/stunnel.pem
  
- ; Protocol version (all, SSLv2, SSLv3, TLSv1)
+ ; protocol version (all, SSLv2, SSLv3, TLSv1)
  sslVersion = SSLv3
  
- ; Some security enhancements for UNIX systems - comment them out on Win32
+ ; security enhancements for UNIX systems - comment them out on Win32
+ ; for chroot a copy of some devices and files is needed within the jail
 -chroot = @prefix@/var/lib/stunnel/
 +chroot = @localstatedir@
  setuid = nobody
  setgid = @DEFAULT_GROUP@
  ; PID is created inside the chroot jail
-@@ -30,16 +30,16 @@ socket = r:TCP_NODELAY=1
+@@ -33,16 +33,16 @@ socket = r:TCP_NODELAY=1
  ; CApath is located inside chroot jail
  ;CApath = /certs
- ; It's often easier to use CAfile
+ ; it's often easier to use CAfile
 -;CAfile = @prefix@/etc/stunnel/certs.pem
 +;CAfile = @sysconfdir@/stunnel/certs.pem
- ; Don't forget to c_rehash CRLpath
+ ; don't forget to c_rehash CRLpath
  ; CRLpath is located inside chroot jail
  ;CRLpath = /crls
- ; Alternatively you can use CRLfile
+ ; alternatively CRLfile can be used
 -;CRLfile = @prefix@/etc/stunnel/crls.pem
 +;CRLfile = @sysconfdir@/stunnel/crls.pem
  
- ; Some debugging stuff useful for troubleshooting
+ ; debugging stuff (may useful for troubleshooting)
  ;debug = 7
 -;output = stunnel.log
 +;output = @localstatedir@/log/stunnel.log
  
- ; Use it for client mode
+ ; SSL client mode
  ;client = yes
index 3f213cee83890b613add2c2f7bc7dd08cdabf6bc..c22e0b441fd31391068df7a11a22a5b8b2d96ae5 100644 (file)
@@ -1,17 +1,17 @@
 --- a/tools/stunnel.conf-sample.in
 +++ b/tools/stunnel.conf-sample.in
-@@ -7,7 +7,7 @@ cert = @sysconfdir@/stunnel/stunnel.pem
+@@ -8,7 +8,7 @@ cert = @sysconfdir@/stunnel/stunnel.pem
  ;key = @sysconfdir@/stunnel/stunnel.pem
  
- ; Protocol version (all, SSLv2, SSLv3, TLSv1)
+ ; protocol version (all, SSLv2, SSLv3, TLSv1)
 -sslVersion = SSLv3
 +sslVersion = all
  
- ; Some security enhancements for UNIX systems - comment them out on Win32
- chroot = @localstatedir@
-@@ -46,21 +46,26 @@ socket = r:TCP_NODELAY=1
+ ; security enhancements for UNIX systems - comment them out on Win32
+ ; for chroot a copy of some devices and files is needed within the jail
+@@ -49,21 +49,26 @@ socket = r:TCP_NODELAY=1
  
- ; Service-level configuration
+ ; service-level configuration
  
 -[pop3s]
 -accept  = 995
index 2c0f1076d26cac5fc4011a01bcc4d3ab31373a5d..497ff6d53dbeb97b8a1d3e32571b6948ee959aeb 100644 (file)
@@ -1,6 +1,6 @@
 --- a/doc/stunnel.8
 +++ b/doc/stunnel.8
-@@ -497,7 +497,10 @@ time to keep an idle connection
+@@ -504,7 +504,10 @@ time to keep an idle connection
  .IP "\fBtransparent\fR = yes | no (Unix only)" 4
  .IX Item "transparent = yes | no (Unix only)"
  transparent proxy mode
  Re-write address to appear as if wrapped daemon is connecting
  from the \s-1SSL\s0 client machine instead of the machine running \fBstunnel\fR.
  .Sp
---- /dev/null
-+++ b/doc/stunnel.8.orig
-@@ -0,0 +1,729 @@
-+.\" Automatically generated by Pod::Man 2.1801 (Pod::Simple 3.05)
-+.\"
-+.\" Standard preamble:
-+.\" ========================================================================
-+.de Sp \" Vertical space (when we can't use .PP)
-+.if t .sp .5v
-+.if n .sp
-+..
-+.de Vb \" Begin verbatim text
-+.ft CW
-+.nf
-+.ne \\$1
-+..
-+.de Ve \" End verbatim text
-+.ft R
-+.fi
-+..
-+.\" Set up some character translations and predefined strings.  \*(-- will
-+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-+.\" double quote, and \*(R" will give a right double quote.  \*(C+ will
-+.\" give a nicer C++.  Capital omega is used to do unbreakable dashes and
-+.\" therefore won't be available.  \*(C` and \*(C' expand to `' in nroff,
-+.\" nothing in troff, for use with C<>.
-+.tr \(*W-
-+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-+.ie n \{\
-+.    ds -- \(*W-
-+.    ds PI pi
-+.    if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-+.    if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\"  diablo 12 pitch
-+.    ds L" ""
-+.    ds R" ""
-+.    ds C` ""
-+.    ds C' ""
-+'br\}
-+.el\{\
-+.    ds -- \|\(em\|
-+.    ds PI \(*p
-+.    ds L" ``
-+.    ds R" ''
-+'br\}
-+.\"
-+.\" Escape single quotes in literal strings from groff's Unicode transform.
-+.ie \n(.g .ds Aq \(aq
-+.el       .ds Aq '
-+.\"
-+.\" If the F register is turned on, we'll generate index entries on stderr for
-+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
-+.\" entries marked with X<> in POD.  Of course, you'll have to process the
-+.\" output yourself in some meaningful fashion.
-+.ie \nF \{\
-+.    de IX
-+.    tm Index:\\$1\t\\n%\t"\\$2"
-+..
-+.    nr % 0
-+.    rr F
-+.\}
-+.el \{\
-+.    de IX
-+..
-+.\}
-+.\" ========================================================================
-+.\"
-+.IX Title "STUNNEL 8"
-+.TH STUNNEL 8 "2009.11.20" "4.29" "stunnel"
-+.\" For nroff, turn off justification.  Always turn off hyphenation; it makes
-+.\" way too many mistakes in technical documents.
-+.if n .ad l
-+.nh
-+.SH "NAME"
-+stunnel \- universal SSL tunnel
-+.SH "SYNOPSIS"
-+.IX Header "SYNOPSIS"
-+.IP "\fBUnix:\fR" 4
-+.IX Item "Unix:"
-+\&\fBstunnel\fR [<filename>] | \-fd n | \-help | \-version | \-sockets
-+.IP "\fB\s-1WIN32:\s0\fR" 4
-+.IX Item "WIN32:"
-+\&\fBstunnel\fR [ [\-install | \-uninstall | \-start | \-stop]
-+    [\-quiet] [<filename>] ] | \-help | \-version | \-sockets
-+.SH "DESCRIPTION"
-+.IX Header "DESCRIPTION"
-+The \fBstunnel\fR program is designed to work as \fI\s-1SSL\s0\fR encryption wrapper 
-+between remote clients and local (\fIinetd\fR\-startable) or remote
-+servers. The concept is that having non-SSL aware daemons running on
-+your system you can easily set them up to communicate with clients over
-+secure \s-1SSL\s0 channels.
-+.PP
-+\&\fBstunnel\fR can be used to add \s-1SSL\s0 functionality to commonly used \fIInetd\fR
-+daemons like \s-1POP\-2\s0, \s-1POP\-3\s0, and \s-1IMAP\s0 servers, to standalone daemons like
-+\&\s-1NNTP\s0, \s-1SMTP\s0 and \s-1HTTP\s0, and in tunneling \s-1PPP\s0 over network sockets without
-+changes to the source code.
-+.PP
-+This product includes cryptographic software written by
-+Eric Young (eay@cryptsoft.com)
-+.SH "OPTIONS"
-+.IX Header "OPTIONS"
-+.IP "<\fBfilename\fR>" 4
-+.IX Item "<filename>"
-+Use specified configuration file
-+.IP "\fB\-fd n\fR (Unix only)" 4
-+.IX Item "-fd n (Unix only)"
-+Read the config file from specified file descriptor
-+.IP "\fB\-help\fR" 4
-+.IX Item "-help"
-+Print \fBstunnel\fR help menu
-+.IP "\fB\-version\fR" 4
-+.IX Item "-version"
-+Print \fBstunnel\fR version and compile time defaults
-+.IP "\fB\-sockets\fR" 4
-+.IX Item "-sockets"
-+Print default socket options
-+.IP "\fB\-install\fR (\s-1NT/2000/XP\s0 only)" 4
-+.IX Item "-install (NT/2000/XP only)"
-+Install \s-1NT\s0 Service
-+.IP "\fB\-uninstall\fR (\s-1NT/2000/XP\s0 only)" 4
-+.IX Item "-uninstall (NT/2000/XP only)"
-+Uninstall \s-1NT\s0 Service
-+.IP "\fB\-start\fR (\s-1NT/2000/XP\s0 only)" 4
-+.IX Item "-start (NT/2000/XP only)"
-+Start \s-1NT\s0 Service
-+.IP "\fB\-stop\fR (\s-1NT/2000/XP\s0 only)" 4
-+.IX Item "-stop (NT/2000/XP only)"
-+Stop \s-1NT\s0 Service
-+.IP "\fB\-quiet\fR (\s-1NT/2000/XP\s0 only)" 4
-+.IX Item "-quiet (NT/2000/XP only)"
-+Don't display a message box when successfully installed or uninstalled \s-1NT\s0 service
-+.SH "CONFIGURATION FILE"
-+.IX Header "CONFIGURATION FILE"
-+Each line of the configuration file can be either:
-+.IP "\(bu" 4
-+an empty line (ignored)
-+.IP "\(bu" 4
-+a comment starting with ';' (ignored)
-+.IP "\(bu" 4
-+an 'option_name = option_value' pair
-+.IP "\(bu" 4
-+\&'[service_name]' indicating a start of a service definition
-+.SS "\s-1GLOBAL\s0 \s-1OPTIONS\s0"
-+.IX Subsection "GLOBAL OPTIONS"
-+.IP "\fBchroot\fR = directory (Unix only)" 4
-+.IX Item "chroot = directory (Unix only)"
-+directory to chroot \fBstunnel\fR process
-+.Sp
-+\&\fBchroot\fR keeps \fBstunnel\fR in chrooted jail.  \fICApath\fR, \fICRLpath\fR, \fIpid\fR
-+and \fIexec\fR are located inside the jail and the patches have to be relative
-+to the directory specified with \fBchroot\fR.
-+.Sp
-+To have libwrap (\s-1TCP\s0 Wrappers) control effective in a chrooted environment
-+you also have to copy its configuration files (/etc/hosts.allow and
-+/etc/hosts.deny) there.
-+.IP "\fBcompression\fR = zlib | rle" 4
-+.IX Item "compression = zlib | rle"
-+select data compression algorithm
-+.Sp
-+default: no compression
-+.Sp
-+zlib compression of OpenSSL 0.9.8 or above is not backward compatible with
-+OpenSSL 0.9.7.
-+.Sp
-+rle compression is currently not implemented by the OpenSSL library.
-+.IP "\fBdebug\fR = [facility.]level" 4
-+.IX Item "debug = [facility.]level"
-+debugging level
-+.Sp
-+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 \fBdebug = debug\fR or
-+\&\fBdebug = 7\fR for greatest debugging output.  The default is notice (5).
-+.Sp
-+The syslog facility 'daemon' will be used unless a facility name is supplied.
-+(Facilities are not supported on Win32.)
-+.Sp
-+Case is ignored for both facilities and levels.
-+.IP "\fB\s-1EGD\s0\fR = egd path (Unix only)" 4
-+.IX Item "EGD = egd path (Unix only)"
-+path to Entropy Gathering Daemon socket
-+.Sp
-+Entropy Gathering Daemon socket to use to feed OpenSSL random number
-+generator.  (Available only if compiled with OpenSSL 0.9.5a or higher)
-+.IP "\fBengine\fR = auto | <engine id>" 4
-+.IX Item "engine = auto | <engine id>"
-+select hardware engine
-+.Sp
-+default: software-only cryptography
-+.Sp
-+There's an example in '\s-1EXAMPLES\s0' section.
-+.IP "\fBengineCtrl\fR = command[:parameter]" 4
-+.IX Item "engineCtrl = command[:parameter]"
-+control hardware engine
-+.Sp
-+Special commands \*(L"\s-1LOAD\s0\*(R" and \*(L"\s-1INIT\s0\*(R" can be used to load and initialize the
-+engine cryptogaphic module.
-+.IP "\fBfips\fR = yes | no" 4
-+.IX Item "fips = yes | no"
-+Enable or disable \s-1FIPS\s0 140\-2 mode.
-+.Sp
-+This option allows to disable entering \s-1FIPS\s0 mode if stunnel was compiled with
-+\&\s-1FIPS\s0 140\-2 support.
-+.Sp
-+default: yes
-+.IP "\fBforeground\fR = yes | no (Unix only)" 4
-+.IX Item "foreground = yes | no (Unix only)"
-+foreground mode
-+.Sp
-+Stay in foreground (don't fork) and log to stderr
-+instead of via syslog (unless \fBoutput\fR is specified).
-+.Sp
-+default: background in daemon mode
-+.IP "\fBoutput\fR = file" 4
-+.IX Item "output = file"
-+append log messages to a file instead of using syslog
-+.Sp
-+/dev/stdout device can be used to redirect log messages to the standard
-+output (for example to log them with daemontools splogger).
-+.IP "\fBpid\fR = file (Unix only)" 4
-+.IX Item "pid = file (Unix only)"
-+pid file location
-+.Sp
-+If the argument is empty, then no pid file will be created.
-+.Sp
-+\&\fIpid\fR path is relative to \fIchroot\fR directory if specified.
-+.IP "\fBRNDbytes\fR = bytes" 4
-+.IX Item "RNDbytes = bytes"
-+bytes to read from random seed files
-+.Sp
-+Number of bytes of data read from random seed files.  With \s-1SSL\s0 versions
-+less than 0.9.5a, also determines how many bytes of data are considered
-+sufficient to seed the \s-1PRNG\s0.  More recent OpenSSL versions have a builtin
-+function to determine when sufficient randomness is available.
-+.IP "\fBRNDfile\fR = file" 4
-+.IX Item "RNDfile = file"
-+path to file with random seed data
-+.Sp
-+The \s-1SSL\s0 library will use data from this file first to seed the random
-+number generator.
-+.IP "\fBRNDoverwrite\fR = yes | no" 4
-+.IX Item "RNDoverwrite = yes | no"
-+overwrite the random seed files with new random data
-+.Sp
-+default: yes
-+.IP "\fBservice\fR = servicename" 4
-+.IX Item "service = servicename"
-+use specified string as the service name
-+.Sp
-+\&\fBOn Unix:\fR \fIinetd\fR mode service name for \s-1TCP\s0 Wrapper library.
-+.Sp
-+\&\fBOn \s-1NT/2000/XP:\s0\fR \s-1NT\s0 service name in the Control Panel.
-+.Sp
-+default: stunnel
-+.IP "\fBsetgid\fR = groupname (Unix only)" 4
-+.IX Item "setgid = groupname (Unix only)"
-+\&\fIsetgid()\fR to groupname in daemon mode and clears all other groups
-+.IP "\fBsetuid\fR = username (Unix only)" 4
-+.IX Item "setuid = username (Unix only)"
-+\&\fIsetuid()\fR to username in daemon mode
-+.IP "\fBsocket\fR = a|l|r:option=value[:value]" 4
-+.IX Item "socket = a|l|r:option=value[:value]"
-+Set an option on accept/local/remote socket
-+.Sp
-+The values for linger option are l_onof:l_linger.
-+The values for time are tv_sec:tv_usec.
-+.Sp
-+Examples:
-+.Sp
-+.Vb 11
-+\&    socket = l:SO_LINGER=1:60
-+\&        set one minute timeout for closing local socket
-+\&    socket = r:TCP_NODELAY=1
-+\&        turn off the Nagle algorithm for remote sockets
-+\&    socket = r:SO_OOBINLINE=1
-+\&        place out\-of\-band data directly into the
-+\&        receive data stream for remote sockets
-+\&    socket = a:SO_REUSEADDR=0
-+\&        disable address reuse (enabled by default)
-+\&    socket = a:SO_BINDTODEVICE=lo
-+\&        only accept connections on loopback interface
-+.Ve
-+.IP "\fBsyslog\fR = yes | no (Unix only)" 4
-+.IX Item "syslog = yes | no (Unix only)"
-+enable logging via syslog
-+.Sp
-+default: yes
-+.IP "\fBtaskbar\fR = yes | no (\s-1WIN32\s0 only)" 4
-+.IX Item "taskbar = yes | no (WIN32 only)"
-+enable the taskbar icon
-+.Sp
-+default: yes
-+.SS "SERVICE-LEVEL \s-1OPTIONS\s0"
-+.IX Subsection "SERVICE-LEVEL OPTIONS"
-+Each configuration section begins with service name in square brackets.
-+The service name is used for libwrap (\s-1TCP\s0 Wrappers) access control and lets
-+you distinguish \fBstunnel\fR services in your log files.
-+.PP
-+Note that if you wish to run \fBstunnel\fR in \fIinetd\fR mode (where it
-+is provided a network socket by a server such as \fIinetd\fR, \fIxinetd\fR,
-+or \fItcpserver\fR) then you should read the section entitled \fI\s-1INETD\s0 \s-1MODE\s0\fR
-+below.
-+.IP "\fBaccept\fR = [host:]port" 4
-+.IX Item "accept = [host:]port"
-+accept connections on specified host:port
-+.Sp
-+If no host specified, defaults to all \s-1IP\s0 addresses for the local host.
-+.IP "\fBCApath\fR = directory" 4
-+.IX Item "CApath = directory"
-+Certificate Authority directory
-+.Sp
-+This is the directory in which \fBstunnel\fR will look for certificates when using
-+the \fIverify\fR. Note that the certificates in this directory should be named
-+\&\s-1XXXXXXXX\s0.0 where \s-1XXXXXXXX\s0 is the hash value of the \s-1DER\s0 encoded subject of the
-+cert (the first 4 bytes of the \s-1MD5\s0 hash in least significant byte order).
-+.Sp
-+\&\fICApath\fR path is relative to \fIchroot\fR directory if specified.
-+.IP "\fBCAfile\fR = certfile" 4
-+.IX Item "CAfile = certfile"
-+Certificate Authority file
-+.Sp
-+This file contains multiple \s-1CA\s0 certificates, used with the \fIverify\fR.
-+.IP "\fBcert\fR = pemfile" 4
-+.IX Item "cert = pemfile"
-+certificate chain \s-1PEM\s0 file name
-+.Sp
-+A \s-1PEM\s0 is always needed in server mode.
-+Specifying this flag in client mode will use this certificate chain
-+as a client side certificate chain.  Using client side certs is optional.
-+The certificates must be in \s-1PEM\s0 format and must be sorted starting with the
-+certificate to the highest level (root \s-1CA\s0).
-+.IP "\fBciphers\fR = cipherlist" 4
-+.IX Item "ciphers = cipherlist"
-+Select permitted \s-1SSL\s0 ciphers
-+.Sp
-+A colon delimited list of the ciphers to allow in the \s-1SSL\s0 connection.
-+For example \s-1DES\-CBC3\-SHA:IDEA\-CBC\-MD5\s0
-+.IP "\fBclient\fR = yes | no" 4
-+.IX Item "client = yes | no"
-+client mode (remote service uses \s-1SSL\s0)
-+.Sp
-+default: no (server mode)
-+.IP "\fBconnect\fR = [host:]port" 4
-+.IX Item "connect = [host:]port"
-+connect to a remote host:port
-+.Sp
-+If no host is specified, the host defaults to localhost.
-+.Sp
-+Multiple \fBconnect\fR options are allowed in a single service section.
-+.Sp
-+If host resolves to multiple addresses and/or if multiple \fBconnect\fR
-+options are specified, then the remote address is chosen using a
-+round-robin algorithm.
-+.IP "\fBCRLpath\fR = directory" 4
-+.IX Item "CRLpath = directory"
-+Certificate Revocation Lists directory
-+.Sp
-+This is the directory in which \fBstunnel\fR will look for CRLs when
-+using the \fIverify\fR. Note that the CRLs in this directory should
-+be named \s-1XXXXXXXX\s0.0 where \s-1XXXXXXXX\s0 is the hash value of the \s-1CRL\s0.
-+.Sp
-+\&\fICRLpath\fR path is relative to \fIchroot\fR directory if specified.
-+.IP "\fBCRLfile\fR = certfile" 4
-+.IX Item "CRLfile = certfile"
-+Certificate Revocation Lists file
-+.Sp
-+This file contains multiple CRLs, used with the \fIverify\fR.
-+.IP "\fBdelay\fR = yes | no" 4
-+.IX Item "delay = yes | no"
-+delay \s-1DNS\s0 lookup for 'connect' option
-+.IP "\fBengineNum\fR = engine number" 4
-+.IX Item "engineNum = engine number"
-+select engine number to read private key
-+.Sp
-+The engines are numbered starting from 1.
-+.IP "\fBexec\fR = executable_path (Unix only)" 4
-+.IX Item "exec = executable_path (Unix only)"
-+execute local inetd-type program
-+.Sp
-+\&\fIexec\fR path is relative to \fIchroot\fR directory if specified.
-+.ie n .IP "\fBexecargs\fR = $0 $1 $2 ... (Unix only)" 4
-+.el .IP "\fBexecargs\fR = \f(CW$0\fR \f(CW$1\fR \f(CW$2\fR ... (Unix only)" 4
-+.IX Item "execargs = $0 $1 $2 ... (Unix only)"
-+arguments for \fIexec\fR including program name ($0)
-+.Sp
-+Quoting is currently not supported.
-+Arguments are separated with arbitrary number of whitespaces.
-+.IP "\fBfailover\fR = rr | prio" 4
-+.IX Item "failover = rr | prio"
-+Failover strategy for multiple \*(L"connect\*(R" targets.
-+.Sp
-+.Vb 2
-+\&    rr (round robin) \- fair load distribution
-+\&    prio (priority) \- use the order specified in config file
-+.Ve
-+.Sp
-+default: rr
-+.IP "\fBident\fR = username" 4
-+.IX Item "ident = username"
-+use \s-1IDENT\s0 (\s-1RFC\s0 1413) username checking
-+.IP "\fBkey\fR = keyfile" 4
-+.IX Item "key = keyfile"
-+private key for certificate specified with \fIcert\fR option
-+.Sp
-+Private key is needed to authenticate certificate owner.
-+Since this file should be kept secret it should only be readable
-+to its owner.  On Unix systems you can use the following command:
-+.Sp
-+.Vb 1
-+\&    chmod 600 keyfile
-+.Ve
-+.Sp
-+default: value of \fIcert\fR option
-+.IP "\fBlocal\fR = host" 4
-+.IX Item "local = host"
-+\&\s-1IP\s0 of the outgoing interface is used as source for remote connections.
-+Use this option to bind a static local \s-1IP\s0 address, instead.
-+.IP "\fB\s-1OCSP\s0\fR = url" 4
-+.IX Item "OCSP = url"
-+select \s-1OCSP\s0 server for certificate verification
-+.IP "\fBOCSPflag\fR = flag" 4
-+.IX Item "OCSPflag = flag"
-+specify \s-1OCSP\s0 server flag
-+.Sp
-+Several \fIOCSPflag\fR can be used to specify multiple flags.
-+.Sp
-+currently supported flags: \s-1NOCERTS\s0, \s-1NOINTERN\s0 \s-1NOSIGS\s0, \s-1NOCHAIN\s0, \s-1NOVERIFY\s0,
-+\&\s-1NOEXPLICIT\s0, \s-1NOCASIGN\s0, \s-1NODELEGATED\s0, \s-1NOCHECKS\s0, \s-1TRUSTOTHER\s0, \s-1RESPID_KEY\s0, \s-1NOTIME\s0
-+.IP "\fBoptions\fR = SSL_options" 4
-+.IX Item "options = SSL_options"
-+OpenSSL library options
-+.Sp
-+The parameter is the OpenSSL option name as described in the
-+\&\fI\fISSL_CTX_set_options\fI\|(3ssl)\fR manual, but without \fI\s-1SSL_OP_\s0\fR prefix.
-+Several \fIoptions\fR can be used to specify multiple options.
-+.Sp
-+For example for compatibility with erroneous Eudora \s-1SSL\s0 implementation
-+the following option can be used:
-+.Sp
-+.Vb 1
-+\&    options = DONT_INSERT_EMPTY_FRAGMENTS
-+.Ve
-+.IP "\fBprotocol\fR = proto" 4
-+.IX Item "protocol = proto"
-+application protocol to negotiate \s-1SSL\s0
-+.Sp
-+currently supported: cifs, connect, imap, nntp, pop3, smtp, pgsql
-+.IP "\fBprotocolAuthentication\fR = auth_type" 4
-+.IX Item "protocolAuthentication = auth_type"
-+authentication type for protocol negotiations
-+.Sp
-+currently supported: basic, \s-1NTLM\s0
-+.Sp
-+Currently authentication type only applies to 'connect' protocol.
-+.Sp
-+default: basic
-+.IP "\fBprotocolHost\fR = host:port" 4
-+.IX Item "protocolHost = host:port"
-+destination address for protocol negotiations
-+.IP "\fBprotocolPassword\fR = password" 4
-+.IX Item "protocolPassword = password"
-+password for protocol negotiations
-+.IP "\fBprotocolUsername\fR = username" 4
-+.IX Item "protocolUsername = username"
-+username for protocol negotiations
-+.IP "\fBpty\fR = yes | no (Unix only)" 4
-+.IX Item "pty = yes | no (Unix only)"
-+allocate pseudo terminal for 'exec' option
-+.IP "\fBretry\fR = yes | no (Unix only)" 4
-+.IX Item "retry = yes | no (Unix only)"
-+reconnect a connect+exec section after it's disconnected
-+.Sp
-+default: no
-+.IP "\fBsession\fR = timeout" 4
-+.IX Item "session = timeout"
-+session cache timeout
-+.IP "\fBsessiond\fR = host:port" 4
-+.IX Item "sessiond = host:port"
-+address of sessiond \s-1SSL\s0 cache server
-+.IP "\fBsslVersion\fR = version" 4
-+.IX Item "sslVersion = version"
-+select version of \s-1SSL\s0 protocol
-+.Sp
-+Allowed options: all, SSLv2, SSLv3, TLSv1
-+.IP "\fBstack\fR = bytes (except for \s-1FORK\s0 model)" 4
-+.IX Item "stack = bytes (except for FORK model)"
-+thread stack size
-+.IP "\fBTIMEOUTbusy\fR = seconds" 4
-+.IX Item "TIMEOUTbusy = seconds"
-+time to wait for expected data
-+.IP "\fBTIMEOUTclose\fR = seconds" 4
-+.IX Item "TIMEOUTclose = seconds"
-+time to wait for close_notify (set to 0 for buggy \s-1MSIE\s0)
-+.IP "\fBTIMEOUTconnect\fR = seconds" 4
-+.IX Item "TIMEOUTconnect = seconds"
-+time to wait to connect a remote host
-+.IP "\fBTIMEOUTidle\fR = seconds" 4
-+.IX Item "TIMEOUTidle = seconds"
-+time to keep an idle connection
-+.IP "\fBtransparent\fR = yes | no (Unix only)" 4
-+.IX Item "transparent = yes | no (Unix only)"
-+transparent proxy mode
-+.Sp
-+Re-write address to appear as if wrapped daemon is connecting
-+from the \s-1SSL\s0 client machine instead of the machine running \fBstunnel\fR.
-+.Sp
-+This option is currently available in:
-+.Sp
-+.Vb 3
-+\&    remote mode (I<connect> option) on Linux >=2.6.28
-+\&    remote mode (I<connect> option) 2.2.x
-+\&    local mode (I<exec> option)
-+.Ve
-+.Sp
-+\&\fBRemote mode\fR (either 2.2.x and >=2.6.28) requires stunnel to be executed as
-+root.  \fBsetuid\fR option will also break this functionality.
-+.Sp
-+\&\fBLinux >=2.6.28\fR requires the following setup for iptables and routing
-+(possibly in /etc/rc.local or equivalent file):
-+.Sp
-+.Vb 6
-+\&    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
-+.Ve
-+.Sp
-+\&\fBLinux 2.2.x\fR requires kernel to be compiled with \fItransparent proxy\fR option.
-+Connected service must be installed on a separate host.
-+Routing towards the clients has to go through the stunnel box.
-+.Sp
-+\&\fBLocal mode\fR works by LD_PRELOADing env.so shared library.
-+.IP "\fBverify\fR = level" 4
-+.IX Item "verify = level"
-+verify peer certificate
-+.Sp
-+.Vb 4
-+\&    level 1 \- verify peer certificate if present
-+\&    level 2 \- verify peer certificate
-+\&    level 3 \- verify peer with locally installed certificate
-+\&    default \- no verify
-+.Ve
-+.Sp
-+It is important to understand, that this option was solely designed for access
-+control and not for authorization.  Specifically for level 2 every non-revoked
-+certificate is accepted regardless of its Common Name.  For this reason a
-+dedicated \s-1CA\s0 should be used with level 2, and not a generic \s-1CA\s0 commonly used
-+for webservers.  Level 3 is preferred for point-to-point connections.
-+.SH "RETURN VALUE"
-+.IX Header "RETURN VALUE"
-+\&\fBstunnel\fR returns zero on success, non-zero on error.
-+.SH "EXAMPLES"
-+.IX Header "EXAMPLES"
-+In order to provide \s-1SSL\s0 encapsulation to your local \fIimapd\fR service, use
-+.PP
-+.Vb 4
-+\&    [imapd]
-+\&    accept = 993
-+\&    exec = /usr/sbin/imapd
-+\&    execargs = imapd
-+.Ve
-+.PP
-+If you want to provide tunneling to your \fIpppd\fR daemon on port 2020,
-+use something like
-+.PP
-+.Vb 5
-+\&    [vpn]
-+\&    accept = 2020
-+\&    exec = /usr/sbin/pppd
-+\&    execargs = pppd local
-+\&    pty = yes
-+.Ve
-+.PP
-+If you want to use \fBstunnel\fR in \fIinetd\fR mode to launch your imapd
-+process, you'd use this \fIstunnel.conf\fR.
-+Note there must be no \fI[service_name]\fR section.
-+.PP
-+.Vb 2
-+\&    exec = /usr/sbin/imapd
-+\&    execargs = imapd
-+.Ve
-+.PP
-+Here is an example of advanced engine configuration to read private key from an
-+OpenSC engine
-+.PP
-+.Vb 7
-+\&    engine=dynamic
-+\&    engineCtrl=SO_PATH:/usr/lib/opensc/engine_pkcs11.so
-+\&    engineCtrl=ID:pkcs11
-+\&    engineCtrl=LIST_ADD:1
-+\&    engineCtrl=LOAD
-+\&    engineCtrl=MODULE_PATH:/usr/lib/pkcs11/opensc\-pkcs11.so
-+\&    engineCtrl=INIT
-+\&
-+\&    [service]
-+\&    engineNum=1
-+\&    key=id_45
-+.Ve
-+.SH "FILES"
-+.IX Header "FILES"
-+.IP "\fIstunnel.conf\fR" 4
-+.IX Item "stunnel.conf"
-+\&\fBstunnel\fR configuration file
-+.IP "\fIstunnel.pem\fR" 4
-+.IX Item "stunnel.pem"
-+\&\fBstunnel\fR certificate and private key
-+.SH "BUGS"
-+.IX Header "BUGS"
-+Option \fIexecargs\fR does not support quoting.
-+.SH "RESTRICTIONS"
-+.IX Header "RESTRICTIONS"
-+\&\fBstunnel\fR cannot be used for the \s-1FTP\s0 daemon because of the nature
-+of the \s-1FTP\s0 protocol which utilizes multiple ports for data transfers.
-+There are available \s-1SSL\s0 enabled versions of \s-1FTP\s0 and telnet daemons, however.
-+.SH "NOTES"
-+.IX Header "NOTES"
-+.SS "\s-1INETD\s0 \s-1MODE\s0"
-+.IX Subsection "INETD MODE"
-+The most common use of \fBstunnel\fR 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 \fIexec\fR option.
-+However there is a special case when you wish to have
-+some other program accept incoming connections and
-+launch \fBstunnel\fR, for example with \fIinetd\fR, \fIxinetd\fR,
-+or \fItcpserver\fR.
-+.PP
-+For example, if you have the following line in \fIinetd.conf\fR:
-+.PP
-+.Vb 1
-+\&    imaps stream tcp nowait root /usr/bin/stunnel stunnel /etc/stunnel/imaps.conf
-+.Ve
-+.PP
-+In these cases, the \fIinetd\fR\-style program is responsible
-+for binding a network socket (\fIimaps\fR above) and handing
-+it to \fBstunnel\fR when a connection is received.
-+Thus you do not want \fBstunnel\fR to have any \fIaccept\fR option.
-+All the \fIService Level Options\fR should be placed in the
-+global options section, and no \fI[service_name]\fR section
-+will be present.  See the \fI\s-1EXAMPLES\s0\fR section for example
-+configurations.
-+.SS "\s-1CERTIFICATES\s0"
-+.IX Subsection "CERTIFICATES"
-+Each \s-1SSL\s0 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 \fIOpenSSL\fR package. You can find more
-+information on certificates generation on pages listed below.
-+.PP
-+The order of contents of the \fI.pem\fR file is important.  It should contain the
-+unencrypted private key first, then a signed certificate (not certificate
-+request).  There should be also empty lines after certificate and private key.
-+Plaintext certificate information appended on the top of generated certificate
-+should be discarded. So the file should look like this:
-+.PP
-+.Vb 8
-+\&    \-\-\-\-\-BEGIN RSA PRIVATE KEY\-\-\-\-\-
-+\&    [encoded key]
-+\&    \-\-\-\-\-END RSA PRIVATE KEY\-\-\-\-\-
-+\&    [empty line]
-+\&    \-\-\-\-\-BEGIN CERTIFICATE\-\-\-\-\-
-+\&    [encoded certificate]
-+\&    \-\-\-\-\-END CERTIFICATE\-\-\-\-\-
-+\&    [empty line]
-+.Ve
-+.SS "\s-1RANDOMNESS\s0"
-+.IX Subsection "RANDOMNESS"
-+\&\fBstunnel\fR needs to seed the \s-1PRNG\s0 (pseudo random number generator) in
-+order for \s-1SSL\s0 to use good randomness.  The following sources are loaded
-+in order until sufficient random data has been gathered:
-+.IP "\(bu" 4
-+The file specified with the \fIRNDfile\fR flag.
-+.IP "\(bu" 4
-+The file specified by the \s-1RANDFILE\s0 environment variable, if set.
-+.IP "\(bu" 4
-+The file .rnd in your home directory, if \s-1RANDFILE\s0 not set.
-+.IP "\(bu" 4
-+The file specified with '\-\-with\-random' at compile time.
-+.IP "\(bu" 4
-+The contents of the screen if running on Windows.
-+.IP "\(bu" 4
-+The egd socket specified with the \fI\s-1EGD\s0\fR flag.
-+.IP "\(bu" 4
-+The egd socket specified with '\-\-with\-egd\-sock' at compile time.
-+.IP "\(bu" 4
-+The /dev/urandom device.
-+.PP
-+With recent (>=OpenSSL 0.9.5a) version of \s-1SSL\s0 it will stop loading
-+random data automatically when sufficient entropy has been gathered.
-+With previous versions it will continue to gather from all the above
-+sources since no \s-1SSL\s0 function exists to tell when enough data is available.
-+.PP
-+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 \fIRNDfile\fR flag.
-+.PP
-+Note that the file specified with the \fIRNDfile\fR flag should contain
-+random data \*(-- that means it should contain different information
-+each time \fBstunnel\fR is run.  This is handled automatically
-+unless the \fIRNDoverwrite\fR flag is used.  If you wish to update this file
-+manually, the \fIopenssl rand\fR command in recent versions of OpenSSL,
-+would be useful.
-+.PP
-+One important note \*(-- if /dev/urandom is available, OpenSSL has a habit of
-+seeding the \s-1PRNG\s0 with it even when checking the random state, so on
-+systems with /dev/urandom you're likely to use it even though it's listed
-+at the very bottom of the list above.  This isn't \fBstunnel's\fR behaviour, it's
-+OpenSSLs.
-+.SH "SEE ALSO"
-+.IX Header "SEE ALSO"
-+.IP "\fItcpd\fR\|(8)" 4
-+.IX Item "tcpd"
-+access control facility for internet services
-+.IP "\fIinetd\fR\|(8)" 4
-+.IX Item "inetd"
-+internet 'super\-server'
-+.IP "\fIhttp://stunnel.mirt.net/\fR" 4
-+.IX Item "http://stunnel.mirt.net/"
-+\&\fBstunnel\fR homepage
-+.IP "\fIhttp://www.stunnel.org/\fR" 4
-+.IX Item "http://www.stunnel.org/"
-+\&\fBstunnel\fR Frequently Asked Questions
-+.IP "\fIhttp://www.openssl.org/\fR" 4
-+.IX Item "http://www.openssl.org/"
-+OpenSSL project website
-+.SH "AUTHOR"
-+.IX Header "AUTHOR"
-+.IP "Michal Trojnara" 4
-+.IX Item "Michal Trojnara"
-+<\fIMichal.Trojnara@mirt.net\fR>
 --- a/doc/stunnel.fr.8
 +++ b/doc/stunnel.fr.8
 @@ -445,6 +445,10 @@ Cette option permet de relier une adress
  Alloue un pseudo-terminal pour l'option «\ exec\ »
 --- a/src/client.c
 +++ b/src/client.c
-@@ -90,6 +90,12 @@ CLI *alloc_client_session(LOCAL_OPTIONS 
+@@ -86,6 +86,12 @@ CLI *alloc_client_session(SERVICE_OPTION
          return NULL;
      }
      c->opt=opt;
      c->local_rfd.fd=rfd;
      c->local_wfd.fd=wfd;
      return c;
-@@ -382,6 +388,29 @@ static void init_ssl(CLI *c) {
+@@ -376,6 +382,29 @@ static void init_ssl(CLI *c) {
      }
  }
  
  /****************************** some defines for transfer() */
  /* is socket/SSL open for read/write? */
  #define sock_rd (c->sock_rfd->rd)
-@@ -416,13 +445,16 @@ static void transfer(CLI *c) {
+@@ -410,13 +439,16 @@ static void transfer(CLI *c) {
          check_SSL_pending=0;
  
          SSL_read_wants_read=
              s_poll_add(&c->fds, c->sock_rfd->fd, 1, 0);
          if(SSL_read_wants_read ||
                  SSL_write_wants_read ||
-@@ -521,7 +553,8 @@ static void transfer(CLI *c) {
+@@ -515,7 +547,8 @@ static void transfer(CLI *c) {
                  break;
              default:
                  memmove(c->ssl_buff, c->ssl_buff+num, c->ssl_ptr-num);
                      check_SSL_pending=1; /* check for data buffered by SSL */
                  c->ssl_ptr-=num;
                  c->sock_bytes+=num;
-@@ -581,7 +614,8 @@ static void transfer(CLI *c) {
+@@ -577,7 +610,8 @@ static void transfer(CLI *c) {
          /****************************** read from socket */
          if(sock_rd && sock_can_rd) {
              num=readsocket(c->sock_rfd->fd,
              switch(num) {
              case -1:
                  parse_socket_error(c, "readsocket");
-@@ -601,10 +635,73 @@ static void transfer(CLI *c) {
+@@ -597,10 +631,73 @@ static void transfer(CLI *c) {
                  (SSL_read_wants_write && ssl_can_wr) ||
                  (check_SSL_pending && SSL_pending(c->ssl))) {
              SSL_read_wants_write=0;
                  watchdog=0; /* reset watchdog */
                  break;
              case SSL_ERROR_WANT_WRITE:
---- /dev/null
-+++ b/src/client.c.orig
-@@ -0,0 +1,1042 @@
-+/*
-+ *   stunnel       Universal SSL tunnel
-+ *   Copyright (C) 1998-2009 Michal Trojnara <Michal.Trojnara@mirt.net>
-+ *
-+ *   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 <http://www.gnu.org/licenses>.
-+ * 
-+ *   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.
-+ */
-+
-+/* Undefine if you have problems with make_sockets() */
-+#define INET_SOCKET_PAIR
-+
-+#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
-+
-+#if SSLEAY_VERSION_NUMBER >= 0x0922
-+static char *sid_ctx="stunnel SID";
-+    /* const allowed here */
-+#endif
-+
-+static void do_client(CLI *);
-+static void run_client(CLI *);
-+static void init_local(CLI *);
-+static void init_remote(CLI *);
-+static void init_ssl(CLI *);
-+static void transfer(CLI *);
-+static void parse_socket_error(CLI *, const char *);
-+
-+static void print_cipher(CLI *);
-+static void auth_user(CLI *);
-+static int connect_local(CLI *);
-+#ifndef USE_WIN32
-+static void make_sockets(CLI *, int [2]);
-+#endif
-+static int connect_remote(CLI *);
-+static void local_bind(CLI *c);
-+static void print_bound_address(CLI *);
-+static void reset(int, char *);
-+
-+int max_clients;
-+#ifndef USE_WIN32
-+int max_fds;
-+#endif
-+
-+/* Allocate local data structure for the new thread */
-+CLI *alloc_client_session(LOCAL_OPTIONS *opt, int rfd, int wfd) {
-+    CLI *c;
-+
-+    c=calloc(1, sizeof(CLI));
-+    if(!c) {
-+        s_log(LOG_ERR, "Memory allocation failed");
-+        return NULL;
-+    }
-+    c->opt=opt;
-+    c->local_rfd.fd=rfd;
-+    c->local_wfd.fd=wfd;
-+    return c;
-+}
-+
-+void *client(void *arg) {
-+    CLI *c=arg;
-+
-+#ifdef DEBUG_STACK_SIZE
-+    stack_info(1); /* initialize */
-+#endif
-+    s_log(LOG_DEBUG, "%s started", c->opt->servname);
-+#ifndef USE_WIN32
-+    if(c->opt->option.remote && c->opt->option.program) {
-+            /* connect and exec options specified together */
-+            /* -> spawn a local program instead of stdio */
-+        while((c->local_rfd.fd=c->local_wfd.fd=connect_local(c))>=0) {
-+            run_client(c);
-+            if(!c->opt->option.retry)
-+                break;
-+            sleep(1); /* FIXME: not a good idea in ucontext threading */
-+        }
-+    } else
-+#endif
-+    {
-+        if(alloc_fd(c->local_rfd.fd))
-+            return NULL;
-+        if(c->local_wfd.fd!=c->local_rfd.fd)
-+            if(alloc_fd(c->local_wfd.fd))
-+                return NULL;
-+        run_client(c);
-+    }
-+    free(c);
-+#ifdef DEBUG_STACK_SIZE
-+    stack_info(0); /* display computed value */
-+#endif
-+#if defined(USE_WIN32) && !defined(_WIN32_WCE)
-+    _endthread();
-+#endif
-+#ifdef USE_UCONTEXT
-+    s_log(LOG_DEBUG, "Context %ld closed", ready_head->id);
-+    s_poll_wait(NULL, 0, 0); /* wait on poll() */
-+    s_log(LOG_ERR, "INTERNAL ERROR: failed to drop context");
-+#endif
-+    return NULL;
-+}
-+
-+static void run_client(CLI *c) {
-+    int error;
-+
-+    c->remote_fd.fd=-1;
-+    c->fd=-1;
-+    c->ssl=NULL;
-+    c->sock_bytes=c->ssl_bytes=0;
-+
-+    error=setjmp(c->err);
-+    if(!error)
-+        do_client(c);
-+
-+    s_log(LOG_NOTICE,
-+        "Connection %s: %d bytes sent to SSL, %d bytes sent to socket",
-+         error==1 ? "reset" : "closed", c->ssl_bytes, c->sock_bytes);
-+
-+        /* Cleanup IDENT socket */
-+    if(c->fd>=0)
-+        closesocket(c->fd);
-+
-+        /* Cleanup SSL */
-+    if(c->ssl) { /* SSL initialized */
-+        SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
-+        SSL_free(c->ssl);
-+        ERR_remove_state(0);
-+    }
-+
-+        /* Cleanup remote socket */
-+    if(c->remote_fd.fd>=0) { /* Remote socket initialized */
-+        if(error==1 && c->remote_fd.is_socket)
-+            reset(c->remote_fd.fd, "linger (remote)");
-+        closesocket(c->remote_fd.fd);
-+    }
-+
-+        /* Cleanup local socket */
-+    if(c->local_rfd.fd>=0) { /* Local socket initialized */
-+        if(c->local_rfd.fd==c->local_wfd.fd) {
-+            if(error==1 && c->local_rfd.is_socket)
-+                reset(c->local_rfd.fd, "linger (local)");
-+            closesocket(c->local_rfd.fd);
-+        } else { /* STDIO */
-+            if(error==1 && c->local_rfd.is_socket)
-+                reset(c->local_rfd.fd, "linger (local_rfd)");
-+            if(error==1 && c->local_wfd.is_socket)
-+                reset(c->local_wfd.fd, "linger (local_wfd)");
-+       }
-+    }
-+#ifdef USE_FORK
-+    if(!c->opt->option.remote) /* 'exec' specified */
-+        child_status(); /* null SIGCHLD handler was used */
-+#else
-+    enter_critical_section(CRIT_CLIENTS); /* for multi-cpu machines */
-+    s_log(LOG_DEBUG, "%s finished (%d left)", c->opt->servname,
-+        --num_clients);
-+    leave_critical_section(CRIT_CLIENTS);
-+#endif
-+}
-+
-+static void do_client(CLI *c) {
-+    init_local(c);
-+    if(!c->opt->option.client && !c->opt->protocol) {
-+        /* Server mode and no protocol negotiation needed */
-+        init_ssl(c);
-+        init_remote(c);
-+    } else {
-+        init_remote(c);
-+        negotiate(c);
-+        init_ssl(c);
-+    }
-+    transfer(c);
-+}
-+
-+static void init_local(CLI *c) {
-+    SOCKADDR_UNION addr;
-+    socklen_t addrlen;
-+
-+    addrlen=sizeof addr;
-+    if(getpeername(c->local_rfd.fd, &addr.sa, &addrlen)<0) {
-+        strcpy(c->accepted_address, "NOT A SOCKET");
-+        c->local_rfd.is_socket=0;
-+        c->local_wfd.is_socket=0; /* TODO: It's not always true */
-+#ifdef USE_WIN32
-+        if(get_last_socket_error()!=ENOTSOCK) {
-+#else
-+        if(c->opt->option.transparent || get_last_socket_error()!=ENOTSOCK) {
-+#endif
-+            sockerror("getpeerbyname");
-+            longjmp(c->err, 1);
-+        }
-+        /* Ignore ENOTSOCK error so 'local' doesn't have to be a socket */
-+    } else { /* success */
-+        /* copy addr to c->peer_addr */
-+        memcpy(&c->peer_addr.addr[0], &addr, sizeof addr);
-+        c->peer_addr.num=1;
-+        s_ntop(c->accepted_address, &c->peer_addr.addr[0]);
-+        c->local_rfd.is_socket=1;
-+        c->local_wfd.is_socket=1; /* TODO: It's not always true */
-+        /* It's a socket: lets setup options */
-+        if(set_socket_options(c->local_rfd.fd, 1)<0)
-+            longjmp(c->err, 1);
-+#ifdef USE_LIBWRAP
-+        auth_libwrap(c);
-+#endif /* USE_LIBWRAP */
-+        auth_user(c);
-+        s_log(LOG_NOTICE, "%s accepted connection from %s",
-+            c->opt->servname, c->accepted_address);
-+    }
-+}
-+
-+static void init_remote(CLI *c) {
-+    /* create connection to host/service */
-+    if(c->opt->source_addr.num)
-+        memcpy(&c->bind_addr, &c->opt->source_addr, sizeof(SOCKADDR_LIST));
-+#ifndef USE_WIN32
-+    else if(c->opt->option.transparent)
-+        memcpy(&c->bind_addr, &c->peer_addr, sizeof(SOCKADDR_LIST));
-+#endif
-+    else {
-+        c->bind_addr.num=0; /* don't bind connecting socket */
-+    }
-+
-+    /* setup c->remote_fd, now */
-+    if(c->opt->option.remote) {
-+        c->remote_fd.fd=connect_remote(c);
-+    } else /* NOT in remote mode */
-+        c->remote_fd.fd=connect_local(c);
-+    c->remote_fd.is_socket=1; /* Always! */
-+#ifndef USE_WIN32
-+    if(c->remote_fd.fd>=max_fds) {
-+        s_log(LOG_ERR, "Remote file descriptor out of range (%d>=%d)",
-+            c->remote_fd.fd, max_fds);
-+        longjmp(c->err, 1);
-+    }
-+#endif
-+    s_log(LOG_DEBUG, "Remote FD=%d initialized", c->remote_fd.fd);
-+    if(set_socket_options(c->remote_fd.fd, 2)<0)
-+        longjmp(c->err, 1);
-+}
-+
-+static void init_ssl(CLI *c) {
-+    int i, err;
-+    SSL_SESSION *old_session;
-+
-+    if(!(c->ssl=SSL_new(c->opt->ctx))) {
-+        sslerror("SSL_new");
-+        longjmp(c->err, 1);
-+    }
-+    SSL_set_ex_data(c->ssl, cli_index, c); /* for callbacks */
-+#if SSLEAY_VERSION_NUMBER >= 0x0922
-+    SSL_set_session_id_context(c->ssl, (unsigned char *)sid_ctx,
-+        strlen(sid_ctx));
-+#endif
-+    if(c->opt->option.client) {
-+        if(c->opt->session) {
-+            enter_critical_section(CRIT_SESSION);
-+            SSL_set_session(c->ssl, c->opt->session);
-+            leave_critical_section(CRIT_SESSION);
-+        }
-+        SSL_set_fd(c->ssl, c->remote_fd.fd);
-+        SSL_set_connect_state(c->ssl);
-+    } else {
-+        if(c->local_rfd.fd==c->local_wfd.fd)
-+            SSL_set_fd(c->ssl, c->local_rfd.fd);
-+        else {
-+           /* Does it make sence to have SSL on STDIN/STDOUT? */
-+            SSL_set_rfd(c->ssl, c->local_rfd.fd);
-+            SSL_set_wfd(c->ssl, c->local_wfd.fd);
-+        }
-+        SSL_set_accept_state(c->ssl);
-+    }
-+
-+    /* Setup some values for transfer() function */
-+    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);
-+    }
-+
-+    while(1) {
-+        /* crude workaround for random MT-safety problems in OpenSSL */
-+        /* performance penalty is not huge, as it's a non-blocking code */
-+        enter_critical_section(CRIT_SSL);
-+        if(c->opt->option.client)
-+            i=SSL_connect(c->ssl);
-+        else
-+            i=SSL_accept(c->ssl);
-+        leave_critical_section(CRIT_SSL);
-+        err=SSL_get_error(c->ssl, i);
-+        if(err==SSL_ERROR_NONE)
-+            break; /* ok -> done */
-+        if(err==SSL_ERROR_WANT_READ || err==SSL_ERROR_WANT_WRITE) {
-+            s_poll_init(&c->fds);
-+            s_poll_add(&c->fds, c->ssl_rfd->fd,
-+                err==SSL_ERROR_WANT_READ,
-+                err==SSL_ERROR_WANT_WRITE);
-+            switch(s_poll_wait(&c->fds, c->opt->timeout_busy, 0)) {
-+            case -1:
-+                sockerror("init_ssl: s_poll_wait");
-+                longjmp(c->err, 1);
-+            case 0:
-+                s_log(LOG_INFO, "init_ssl: s_poll_wait timeout");
-+                longjmp(c->err, 1);
-+            case 1:
-+                break; /* OK */
-+            default:
-+                s_log(LOG_ERR, "init_ssl: s_poll_wait unknown result");
-+                longjmp(c->err, 1);
-+            }
-+            continue; /* ok -> retry */
-+        }
-+        if(err==SSL_ERROR_SYSCALL) {
-+            switch(get_last_socket_error()) {
-+            case EINTR:
-+            case EAGAIN:
-+                continue;
-+            }
-+        }
-+        if(c->opt->option.client)
-+            sslerror("SSL_connect");
-+        else
-+            sslerror("SSL_accept");
-+        longjmp(c->err, 1);
-+    }
-+    if(SSL_session_reused(c->ssl)) {
-+        s_log(LOG_INFO, "SSL %s: previous session reused",
-+            c->opt->option.client ? "connected" : "accepted");
-+    } else { /* a new session was negotiated */
-+        if(c->opt->option.client) {
-+            s_log(LOG_INFO, "SSL connected: new session negotiated");
-+            enter_critical_section(CRIT_SESSION);
-+            old_session=c->opt->session;
-+            c->opt->session=SSL_get1_session(c->ssl); /* store it */
-+            if(old_session)
-+                SSL_SESSION_free(old_session); /* release the old one */
-+            leave_critical_section(CRIT_SESSION);
-+        } else
-+            s_log(LOG_INFO, "SSL accepted: new session negotiated");
-+        print_cipher(c);
-+    }
-+}
-+
-+/****************************** some defines for transfer() */
-+/* is socket/SSL open for read/write? */
-+#define sock_rd (c->sock_rfd->rd)
-+#define sock_wr (c->sock_wfd->wr)
-+#define ssl_rd  (c->ssl_rfd->rd)
-+#define ssl_wr  (c->ssl_wfd->wr)
-+/* NOTE: above defines are related to the logical data stream,
-+ * not the underlying file descriptors */
-+
-+/* is socket/SSL ready for read/write? */
-+#define sock_can_rd (s_poll_canread(&c->fds, c->sock_rfd->fd))
-+#define sock_can_wr (s_poll_canwrite(&c->fds, c->sock_wfd->fd))
-+#define ssl_can_rd  (s_poll_canread(&c->fds, c->ssl_rfd->fd))
-+#define ssl_can_wr  (s_poll_canwrite(&c->fds, c->ssl_wfd->fd))
-+
-+/****************************** transfer data */
-+static void transfer(CLI *c) {
-+    int watchdog=0; /* a counter to detect an infinite loop */
-+    int error;
-+    socklen_t optlen;
-+    int num, err, check_SSL_pending;
-+    int SSL_shutdown_wants_read=0, SSL_shutdown_wants_write=0;
-+    int SSL_write_wants_read=0, SSL_write_wants_write=0;
-+    int SSL_read_wants_read=0, SSL_read_wants_write=0;
-+
-+    c->sock_ptr=c->ssl_ptr=0;
-+    sock_rd=sock_wr=ssl_rd=ssl_wr=1;
-+
-+    do { /* main loop */
-+        /* set flag to try and read any buffered SSL data
-+         * if we made room in the buffer by writing to the socket */
-+        check_SSL_pending=0;
-+
-+        SSL_read_wants_read=
-+            ssl_rd && c->ssl_ptr<BUFFSIZE && !SSL_read_wants_write;
-+        SSL_write_wants_write=
-+            ssl_wr && c->sock_ptr && !SSL_write_wants_read;
-+
-+        /****************************** setup c->fds structure */
-+        s_poll_init(&c->fds); /* initialize the structure */
-+        if(sock_rd && c->sock_ptr<BUFFSIZE)
-+            s_poll_add(&c->fds, c->sock_rfd->fd, 1, 0);
-+        if(SSL_read_wants_read ||
-+                SSL_write_wants_read ||
-+                SSL_shutdown_wants_read)
-+            s_poll_add(&c->fds, c->ssl_rfd->fd, 1, 0);
-+        if(sock_wr && c->ssl_ptr)
-+            s_poll_add(&c->fds, c->sock_wfd->fd, 0, 1);
-+        if(SSL_read_wants_write ||
-+                SSL_write_wants_write ||
-+                SSL_shutdown_wants_write)
-+            s_poll_add(&c->fds, c->ssl_wfd->fd, 0, 1);
-+
-+        /****************************** wait for an event */
-+        err=s_poll_wait(&c->fds, (sock_rd && ssl_rd) /* both peers open */ ||
-+            c->ssl_ptr /* data buffered to write to socket */ ||
-+            c->sock_ptr /* data buffered to write to SSL */ ?
-+            c->opt->timeout_idle : c->opt->timeout_close, 0);
-+        switch(err) {
-+        case -1:
-+            sockerror("transfer: s_poll_wait");
-+            longjmp(c->err, 1);
-+        case 0: /* timeout */
-+            if((sock_rd && ssl_rd) || c->ssl_ptr || c->sock_ptr) {
-+                s_log(LOG_INFO, "s_poll_wait timeout: connection reset");
-+                longjmp(c->err, 1);
-+            } else { /* already closing connection */
-+                s_log(LOG_INFO, "s_poll_wait timeout: connection close");
-+                return; /* OK */
-+            }
-+        }
-+        if(!(sock_can_rd || sock_can_wr || ssl_can_rd || ssl_can_wr)) {
-+            s_log(LOG_ERR, "INTERNAL ERROR: "
-+                "s_poll_wait returned %d, but no descriptor is ready", err);
-+            longjmp(c->err, 1);
-+        }
-+        if(!sock_rd && sock_can_rd) {
-+            optlen=sizeof error;
-+            if(getsockopt(c->sock_rfd->fd, SOL_SOCKET, SO_ERROR,
-+                    (void *)&error, &optlen))
-+                error=get_last_socket_error(); /* failed -> ask why */
-+            if(error) { /* really an error? */
-+                s_log(LOG_ERR, "Closed socket ready to read: %s (%d)",
-+                    my_strerror(error), error);
-+                longjmp(c->err, 1);
-+            }
-+            if(c->ssl_ptr) { /* anything left to write */
-+                s_log(LOG_ERR, "Closed socket ready to read - reset");
-+                longjmp(c->err, 1);
-+            }
-+            s_log(LOG_INFO, "Closed socket ready to read - write close");
-+            sock_wr=0; /* no further write allowed */
-+            shutdown(c->sock_wfd->fd, SHUT_WR); /* send TCP FIN */
-+        }
-+
-+        /****************************** send SSL close_notify message */
-+        if(SSL_shutdown_wants_read || SSL_shutdown_wants_write) {
-+            SSL_shutdown_wants_read=SSL_shutdown_wants_write=0;
-+            num=SSL_shutdown(c->ssl); /* send close_notify */
-+            if(num<0) /* -1 - not completed */
-+                err=SSL_get_error(c->ssl, 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");
-+                break;
-+            case SSL_ERROR_WANT_WRITE:
-+                s_log(LOG_DEBUG, "SSL_shutdown returned WANT_WRITE: retrying");
-+                SSL_shutdown_wants_write=1;
-+                break;
-+            case SSL_ERROR_WANT_READ:
-+                s_log(LOG_DEBUG, "SSL_shutdown returned WANT_READ: retrying");
-+                SSL_shutdown_wants_read=1;
-+                break;
-+            case SSL_ERROR_SYSCALL: /* socket error */
-+                parse_socket_error(c, "SSL_shutdown");
-+                break;
-+            case SSL_ERROR_SSL: /* SSL error */
-+                sslerror("SSL_shutdown");
-+                longjmp(c->err, 1);
-+            default:
-+                s_log(LOG_ERR, "SSL_shutdown/SSL_get_error returned %d", err);
-+                longjmp(c->err, 1);
-+            }
-+        }
-+
-+        /****************************** write to socket */
-+        if(sock_wr && sock_can_wr) {
-+            num=writesocket(c->sock_wfd->fd, c->ssl_buff, c->ssl_ptr);
-+            switch(num) {
-+            case -1: /* error */
-+                parse_socket_error(c, "writesocket");
-+                break;
-+            case 0:
-+                s_log(LOG_DEBUG, "No data written to the socket: retrying");
-+                break;
-+            default:
-+                memmove(c->ssl_buff, c->ssl_buff+num, c->ssl_ptr-num);
-+                if(c->ssl_ptr==BUFFSIZE) /* buffer was previously full */
-+                    check_SSL_pending=1; /* check for data buffered by SSL */
-+                c->ssl_ptr-=num;
-+                c->sock_bytes+=num;
-+                watchdog=0; /* reset watchdog */
-+            }
-+        }
-+
-+        /****************************** write to SSL */
-+        if((SSL_write_wants_read && ssl_can_rd) ||
-+                (SSL_write_wants_write && ssl_can_wr)) {
-+            SSL_write_wants_read=0;
-+            num=SSL_write(c->ssl, c->sock_buff, c->sock_ptr);
-+            switch(err=SSL_get_error(c->ssl, num)) {
-+            case SSL_ERROR_NONE:
-+                memmove(c->sock_buff, c->sock_buff+num, c->sock_ptr-num);
-+                c->sock_ptr-=num;
-+                c->ssl_bytes+=num;
-+                watchdog=0; /* reset watchdog */
-+                break;
-+            case SSL_ERROR_WANT_WRITE: /* nothing unexpected */
-+                break;
-+            case SSL_ERROR_WANT_READ:
-+                s_log(LOG_DEBUG, "SSL_write returned WANT_READ: retrying");
-+                SSL_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) { /* EOF */
-+                    if(c->sock_ptr) {
-+                        s_log(LOG_ERR,
-+                            "SSL socket closed on SSL_write "
-+                                "with %d byte(s) in buffer",
-+                            c->sock_ptr);
-+                        longjmp(c->err, 1); /* reset the socket */
-+                    }
-+                    s_log(LOG_DEBUG, "SSL socket closed on SSL_write");
-+                    ssl_rd=ssl_wr=0; /* buggy or SSLv2 peer: no close_notify */
-+                } else
-+                    parse_socket_error(c, "SSL_write");
-+                break;
-+            case SSL_ERROR_ZERO_RETURN: /* close_notify received */
-+                s_log(LOG_DEBUG, "SSL closed on SSL_write");
-+                ssl_rd=0;
-+                break;
-+            case SSL_ERROR_SSL:
-+                sslerror("SSL_write");
-+                longjmp(c->err, 1);
-+            default:
-+                s_log(LOG_ERR, "SSL_write/SSL_get_error returned %d", err);
-+                longjmp(c->err, 1);
-+            }
-+        }
-+
-+        /****************************** read from socket */
-+        if(sock_rd && sock_can_rd) {
-+            num=readsocket(c->sock_rfd->fd,
-+                c->sock_buff+c->sock_ptr, BUFFSIZE-c->sock_ptr);
-+            switch(num) {
-+            case -1:
-+                parse_socket_error(c, "readsocket");
-+                break;
-+            case 0: /* close */
-+                s_log(LOG_DEBUG, "Socket closed on read");
-+                sock_rd=0;
-+                break;
-+            default:
-+                c->sock_ptr+=num;
-+                watchdog=0; /* reset watchdog */
-+            }
-+        }
-+
-+        /****************************** read from SSL */
-+        if((SSL_read_wants_read && ssl_can_rd) ||
-+                (SSL_read_wants_write && ssl_can_wr) ||
-+                (check_SSL_pending && SSL_pending(c->ssl))) {
-+            SSL_read_wants_write=0;
-+            num=SSL_read(c->ssl, c->ssl_buff+c->ssl_ptr, BUFFSIZE-c->ssl_ptr);
-+            switch(err=SSL_get_error(c->ssl, num)) {
-+            case SSL_ERROR_NONE:
-+                c->ssl_ptr+=num;
-+                watchdog=0; /* reset watchdog */
-+                break;
-+            case SSL_ERROR_WANT_WRITE:
-+                s_log(LOG_DEBUG, "SSL_read returned WANT_WRITE: retrying");
-+                SSL_read_wants_write=1;
-+                break;
-+            case SSL_ERROR_WANT_READ: /* nothing unexpected */
-+                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) { /* EOF */
-+                    if(c->sock_ptr) {
-+                        s_log(LOG_ERR,
-+                            "SSL socket closed on SSL_read "
-+                                "with %d byte(s) in buffer",
-+                            c->sock_ptr);
-+                        longjmp(c->err, 1); /* reset the socket */
-+                    }
-+                    s_log(LOG_DEBUG, "SSL socket closed on SSL_read");
-+                    ssl_rd=ssl_wr=0; /* buggy or SSLv2 peer: no close_notify */
-+                } else
-+                    parse_socket_error(c, "SSL_read");
-+                break;
-+            case SSL_ERROR_ZERO_RETURN: /* close_notify received */
-+                s_log(LOG_DEBUG, "SSL closed on SSL_read");
-+                ssl_rd=0;
-+                break;
-+            case SSL_ERROR_SSL:
-+                sslerror("SSL_read");
-+                longjmp(c->err, 1);
-+            default:
-+                s_log(LOG_ERR, "SSL_read/SSL_get_error returned %d", err);
-+                longjmp(c->err, 1);
-+            }
-+        }
-+
-+        /****************************** check write shutdown conditions */
-+        if(sock_wr && !ssl_rd && !c->ssl_ptr) {
-+            s_log(LOG_DEBUG, "Socket write shutdown");
-+            sock_wr=0; /* no further write allowed */
-+            shutdown(c->sock_wfd->fd, SHUT_WR); /* send TCP FIN */
-+        }
-+        if(ssl_wr && !sock_rd && !c->sock_ptr) {
-+            s_log(LOG_DEBUG, "SSL write shutdown");
-+            ssl_wr=0; /* no further write allowed */
-+            if(strcmp(SSL_get_version(c->ssl), "SSLv2")) { /* SSLv3, TLSv1 */
-+                SSL_shutdown_wants_write=1; /* initiate close_notify */
-+            } else { /* no alerts in SSLv2 including close_notify alert */
-+                shutdown(c->sock_rfd->fd, SHUT_RD); /* notify the kernel */
-+                shutdown(c->sock_wfd->fd, SHUT_WR); /* send TCP FIN */
-+                SSL_set_shutdown(c->ssl, /* notify the OpenSSL library */
-+                    SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
-+                ssl_rd=0; /* no further read allowed */
-+            }
-+        }
-+
-+        /****************************** check watchdog */
-+        if(++watchdog>100) { /* loop executes without transferring any data */
-+            s_log(LOG_ERR,
-+                "transfer() loop executes not transferring any data");
-+            s_log(LOG_ERR,
-+                "please report the problem to Michal.Trojnara@mirt.net");
-+            s_log(LOG_ERR, "socket open: rd=%s wr=%s, ssl open: rd=%s wr=%s",
-+                sock_rd ? "yes" : "no", sock_wr ? "yes" : "no",
-+                ssl_rd ? "yes" : "no", ssl_wr ? "yes" : "no");
-+            s_log(LOG_ERR, "socket ready: rd=%s wr=%s, ssl ready: rd=%s wr=%s",
-+                sock_can_rd ? "yes" : "no", sock_can_wr ? "yes" : "no",
-+                ssl_can_rd ? "yes" : "no", ssl_can_wr ? "yes" : "no");
-+            s_log(LOG_ERR,
-+                "wants: SSL_read rd=%s wr=%s, "
-+                "SSL_write rd=%s wr=%s, "
-+                "SSL_shutdown rd=%s wr=%s",
-+                SSL_read_wants_read ? "yes" : "no",
-+                SSL_read_wants_write ? "yes" : "no",
-+                SSL_write_wants_read ? "yes" : "no",
-+                SSL_write_wants_write ? "yes" : "no",
-+                SSL_shutdown_wants_read ? "yes" : "no",
-+                SSL_shutdown_wants_write ? "yes" : "no");
-+            s_log(LOG_ERR, "socket input buffer: %d byte(s), "
-+                "ssl input buffer: %d byte(s)", c->sock_ptr, c->ssl_ptr);
-+            s_log(LOG_ERR, "check_SSL_pending=%d", check_SSL_pending);
-+            longjmp(c->err, 1);
-+        }
-+
-+    } while(sock_wr || ssl_wr ||
-+            SSL_shutdown_wants_read || SSL_shutdown_wants_write);
-+}
-+
-+static void parse_socket_error(CLI *c, const char *text) {
-+    switch(get_last_socket_error()) {
-+    case EINTR:
-+        s_log(LOG_DEBUG, "%s interrupted by a signal: retrying", text);
-+        return;
-+    case EWOULDBLOCK:
-+        s_log(LOG_NOTICE, "%s would block: retrying", text);
-+        sleep(1); /* Microsoft bug KB177346 */
-+        return;
-+#if EAGAIN!=EWOULDBLOCK
-+    case EAGAIN:
-+        s_log(LOG_DEBUG, "%s temporary lack of resources: retrying", text);
-+        return;
-+#endif
-+    default:
-+        sockerror(text);
-+        longjmp(c->err, 1);
-+    }
-+}
-+
-+static void print_cipher(CLI *c) { /* print negotiated cipher */
-+#if SSLEAY_VERSION_NUMBER <= 0x0800
-+    s_log(LOG_INFO, "%s opened with SSLv%d, cipher %s",
-+        c->opt->servname, ssl->session->ssl_version, SSL_get_cipher(c->ssl));
-+#else
-+    SSL_CIPHER *cipher;
-+    char buf[STRLEN], *i, *j;
-+
-+    cipher=(SSL_CIPHER *)SSL_get_current_cipher(c->ssl);
-+    SSL_CIPHER_description(cipher, buf, STRLEN);
-+    i=j=buf;
-+    do {
-+        switch(*i) {
-+        case ' ':
-+            *j++=' ';
-+            while(i[1]==' ')
-+                ++i;
-+            break;
-+        case '\n':
-+            break;
-+        default:
-+            *j++=*i;
-+        }
-+    } while(*i++);
-+    s_log(LOG_INFO, "Negotiated ciphers: %s", buf);
-+#endif
-+}
-+
-+static void auth_user(CLI *c) {
-+#ifndef _WIN32_WCE
-+    struct servent *s_ent;    /* structure for getservbyname */
-+#endif
-+    SOCKADDR_UNION ident;     /* IDENT socket name */
-+    char name[STRLEN];
-+
-+    if(!c->opt->username)
-+        return; /* -u option not specified */
-+    if((c->fd=
-+            socket(c->peer_addr.addr[0].sa.sa_family, SOCK_STREAM, 0))<0) {
-+        sockerror("socket (auth_user)");
-+        longjmp(c->err, 1);
-+    }
-+    if(alloc_fd(c->fd))
-+        longjmp(c->err, 1);
-+    memcpy(&ident, &c->peer_addr.addr[0], sizeof ident);
-+#ifndef _WIN32_WCE
-+    s_ent=getservbyname("auth", "tcp");
-+    if(s_ent) {
-+        ident.in.sin_port=s_ent->s_port;
-+    } else
-+#endif
-+    {
-+        s_log(LOG_WARNING, "Unknown service 'auth': using default 113");
-+        ident.in.sin_port=htons(113);
-+    }
-+    if(connect_blocking(c, &ident, addr_len(ident)))
-+        longjmp(c->err, 1);
-+    s_log(LOG_DEBUG, "IDENT server connected");
-+    fdprintf(c, c->fd, "%u , %u",
-+        ntohs(c->peer_addr.addr[0].in.sin_port),
-+        ntohs(c->opt->local_addr.addr[0].in.sin_port));
-+    if(fdscanf(c, c->fd, "%*[^:]: USERID :%*[^:]:%s", name)!=1) {
-+        s_log(LOG_ERR, "Incorrect data from IDENT server");
-+        longjmp(c->err, 1);
-+    }
-+    closesocket(c->fd);
-+    c->fd=-1; /* avoid double close on cleanup */
-+    if(strcmp(name, c->opt->username)) {
-+        safestring(name);
-+        s_log(LOG_WARNING, "Connection from %s REFUSED by IDENT (user %s)",
-+            c->accepted_address, name);
-+        longjmp(c->err, 1);
-+    }
-+    s_log(LOG_INFO, "IDENT authentication passed");
-+}
-+
-+static int connect_local(CLI *c) { /* spawn local process */
-+#if defined (USE_WIN32) || defined (__vms)
-+    s_log(LOG_ERR, "LOCAL MODE NOT SUPPORTED ON WIN32 and OpenVMS PLATFORM");
-+    longjmp(c->err, 1);
-+    return -1; /* some C compilers require a return value */
-+#else /* USE_WIN32, __vms */
-+    char env[3][STRLEN], name[STRLEN], *portname;
-+    int fd[2], pid;
-+    X509 *peer;
-+#ifdef HAVE_PTHREAD_SIGMASK
-+    sigset_t newmask;
-+#endif
-+
-+    if (c->opt->option.pty) {
-+        char tty[STRLEN];
-+
-+        if(pty_allocate(fd, fd+1, tty, STRLEN))
-+            longjmp(c->err, 1);
-+        s_log(LOG_DEBUG, "%s allocated", tty);
-+    } else
-+        make_sockets(c, fd);
-+    pid=fork();
-+    c->pid=(unsigned long)pid;
-+    switch(pid) {
-+    case -1:    /* error */
-+        closesocket(fd[0]);
-+        closesocket(fd[1]);
-+        ioerror("fork");
-+        longjmp(c->err, 1);
-+    case  0:    /* child */
-+        closesocket(fd[0]);
-+        dup2(fd[1], 0);
-+        dup2(fd[1], 1);
-+        if(!options.option.foreground)
-+            dup2(fd[1], 2);
-+        closesocket(fd[1]);
-+        safecopy(env[0], "REMOTE_HOST=");
-+        safeconcat(env[0], c->accepted_address);
-+        portname=strrchr(env[0], ':');
-+        if(portname) /* strip the port name */
-+            *portname='\0';
-+        putenv(env[0]);
-+        if(c->opt->option.transparent) {
-+            putenv("LD_PRELOAD=" LIBDIR "/libstunnel.so");
-+            /* For Tru64 _RLD_LIST is used instead */
-+            putenv("_RLD_LIST=" LIBDIR "/libstunnel.so:DEFAULT");
-+        }
-+        if(c->ssl) {
-+            peer=SSL_get_peer_certificate(c->ssl);
-+            if(peer) {
-+                safecopy(env[1], "SSL_CLIENT_DN=");
-+                X509_NAME_oneline(X509_get_subject_name(peer), name, STRLEN);
-+                safestring(name);
-+                safeconcat(env[1], name);
-+                putenv(env[1]);
-+                safecopy(env[2], "SSL_CLIENT_I_DN=");
-+                X509_NAME_oneline(X509_get_issuer_name(peer), name, STRLEN);
-+                safestring(name);
-+                safeconcat(env[2], name);
-+                putenv(env[2]);
-+                X509_free(peer);
-+            }
-+        }
-+#ifdef HAVE_PTHREAD_SIGMASK
-+        sigemptyset(&newmask);
-+        sigprocmask(SIG_SETMASK, &newmask, NULL);
-+#endif
-+        execvp(c->opt->execname, c->opt->execargs);
-+        ioerror(c->opt->execname); /* execv failed */
-+        _exit(1);
-+    default:
-+        break;
-+    }
-+    /* parent */
-+    s_log(LOG_INFO, "Local mode child started (PID=%lu)", c->pid);
-+    closesocket(fd[1]);
-+#ifdef FD_CLOEXEC
-+    fcntl(fd[0], F_SETFD, FD_CLOEXEC);
-+#endif
-+    return fd[0];
-+#endif /* USE_WIN32,__vms */
-+}
-+
-+#ifndef USE_WIN32
-+
-+static void make_sockets(CLI *c, int fd[2]) { /* make a pair of connected sockets */
-+#ifdef INET_SOCKET_PAIR
-+    SOCKADDR_UNION addr;
-+    socklen_t addrlen;
-+    int s; /* temporary socket awaiting for connection */
-+
-+    if((s=socket(AF_INET, SOCK_STREAM, 0))<0) {
-+        sockerror("socket#1");
-+        longjmp(c->err, 1);
-+    }
-+    if((fd[1]=socket(AF_INET, SOCK_STREAM, 0))<0) {
-+        sockerror("socket#2");
-+        longjmp(c->err, 1);
-+    }
-+    addrlen=sizeof addr;
-+    memset(&addr, 0, addrlen);
-+    addr.in.sin_family=AF_INET;
-+    addr.in.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
-+    addr.in.sin_port=htons(0); /* dynamic port allocation */
-+    if(bind(s, &addr.sa, addrlen))
-+        log_error(LOG_DEBUG, get_last_socket_error(), "bind#1");
-+    if(bind(fd[1], &addr.sa, addrlen))
-+        log_error(LOG_DEBUG, get_last_socket_error(), "bind#2");
-+    if(listen(s, 5)) {
-+        sockerror("listen");
-+        longjmp(c->err, 1);
-+    }
-+    if(getsockname(s, &addr.sa, &addrlen)) {
-+        sockerror("getsockname");
-+        longjmp(c->err, 1);
-+    }
-+    if(connect(fd[1], &addr.sa, addrlen)) {
-+        sockerror("connect");
-+        longjmp(c->err, 1);
-+    }
-+    if((fd[0]=accept(s, &addr.sa, &addrlen))<0) {
-+        sockerror("accept");
-+        longjmp(c->err, 1);
-+    }
-+    closesocket(s); /* don't care about the result */
-+#else
-+    if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) {
-+        sockerror("socketpair");
-+        longjmp(c->err, 1);
-+    }
-+#endif
-+}
-+#endif
-+
-+static int connect_remote(CLI *c) { /* connect to remote host */
-+    SOCKADDR_UNION addr;
-+    SOCKADDR_LIST resolved_list, *address_list;
-+    int fd, ind_try, ind_cur;
-+
-+    /* setup address_list */
-+    if(c->opt->option.delayed_lookup) {
-+        resolved_list.num=0;
-+        if(!name2addrlist(&resolved_list,
-+                c->opt->remote_address, DEFAULT_LOOPBACK)) {
-+            s_log(LOG_ERR, "No host resolved");
-+            longjmp(c->err, 1);
-+        }
-+        address_list=&resolved_list;
-+    } else /* use pre-resolved addresses */
-+        address_list=&c->opt->remote_addr;
-+
-+    /* try to connect each host from the list */
-+    for(ind_try=0; ind_try<address_list->num; ind_try++) {
-+        if(c->opt->failover==FAILOVER_RR) {
-+            ind_cur=address_list->cur;
-+            /* the race condition here can be safely ignored */
-+            address_list->cur=(ind_cur+1)%address_list->num;
-+        } else { /* FAILOVER_PRIO */
-+            ind_cur=ind_try; /* ignore address_list->cur */
-+        }
-+        memcpy(&addr, address_list->addr+ind_cur, sizeof addr);
-+
-+        if((c->fd=socket(addr.sa.sa_family, SOCK_STREAM, 0))<0) {
-+            sockerror("remote socket");
-+            longjmp(c->err, 1);
-+        }
-+        if(alloc_fd(c->fd))
-+            longjmp(c->err, 1);
-+
-+        if(c->bind_addr.num) /* explicit local bind or transparent proxy */
-+            local_bind(c);
-+
-+        if(connect_blocking(c, &addr, addr_len(addr))) {
-+            closesocket(c->fd);
-+            c->fd=-1;
-+            continue; /* next IP */
-+        }
-+        print_bound_address(c);
-+        fd=c->fd;
-+        c->fd=-1;
-+        return fd; /* success! */
-+    }
-+    longjmp(c->err, 1);
-+    return -1; /* some C compilers require a return value */
-+}
-+
-+static void local_bind(CLI *c) {
-+    SOCKADDR_UNION addr;
-+
-+#ifdef IP_TRANSPARENT
-+    int on=1;
-+    if(setsockopt(c->fd, SOL_IP, IP_TRANSPARENT, &on, sizeof on))
-+        sockerror("setsockopt IP_TRANSPARENT");
-+    /* ignore the error to retain Linux 2.2 compatibility */
-+    /* the error will be handled by bind(), anyway */
-+#endif /* IP_TRANSPARENT */
-+
-+    memcpy(&addr, &c->bind_addr.addr[0], sizeof addr);
-+    if(ntohs(addr.in.sin_port)>=1024) { /* security check */
-+        if(!bind(c->fd, &addr.sa, addr_len(addr))) {
-+            s_log(LOG_INFO, "local_bind succeeded on the original port");
-+            return; /* success */
-+        }
-+        if(get_last_socket_error()!=EADDRINUSE
-+#ifndef USE_WIN32
-+                || !c->opt->option.transparent
-+#endif /* USE_WIN32 */
-+                ) {
-+            sockerror("local_bind (original port)");
-+            longjmp(c->err, 1);
-+        }
-+    }
-+
-+    addr.in.sin_port=htons(0); /* retry with ephemeral port */
-+    if(!bind(c->fd, &addr.sa, addr_len(addr))) {
-+        s_log(LOG_INFO, "local_bind succeeded on an ephemeral port");
-+        return; /* success */
-+    }
-+    sockerror("local_bind (ephemeral port)");
-+    longjmp(c->err, 1);
-+}
-+
-+static void print_bound_address(CLI *c) {
-+    char txt[IPLEN];
-+    SOCKADDR_UNION addr;
-+    socklen_t addrlen=sizeof addr;
-+
-+    memset(&addr, 0, addrlen);
-+    if(getsockname(c->fd, (struct sockaddr *)&addr, &addrlen)) {
-+        sockerror("getsockname");
-+    } else {
-+        s_ntop(txt, &addr);
-+        s_log(LOG_NOTICE,"%s connected remote server from %s",
-+            c->opt->servname, txt);
-+    }
-+}
-+
-+static void reset(int fd, char *txt) {
-+    /* Set lingering on a socket if needed*/
-+    struct linger l;
-+
-+    l.l_onoff=1;
-+    l.l_linger=0;
-+    if(setsockopt(fd, SOL_SOCKET, SO_LINGER, (void *)&l, sizeof l))
-+        log_error(LOG_DEBUG, get_last_socket_error(), txt);
-+}
-+
-+/* End of client.c */
 --- a/src/common.h
 +++ b/src/common.h
 @@ -53,6 +53,9 @@
  #define BUFFSIZE 16384
  
 +/* maximum space reserved for header insertion in BUFFSIZE */
-+#define BUFF_RESERVED 1024
++#define BUFF_RESERVED  1024
 +
- /* Length of strings (including the terminating '\0' character) */
- /* It can't be lower than 256 bytes or NTLM authentication will break */
+ /* length of strings (including the terminating '\0' character) */
+ /* it can't be lower than 256 bytes or NTLM authentication will break */
  #define STRLEN 256
---- /dev/null
-+++ b/src/common.h.orig
-@@ -0,0 +1,429 @@
-+/*
-+ *   stunnel       Universal SSL tunnel
-+ *   Copyright (C) 1998-2009 Michal Trojnara <Michal.Trojnara@mirt.net>
-+ *
-+ *   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 <http://www.gnu.org/licenses>.
-+ * 
-+ *   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
-+
-+#ifndef VERSION
-+#define VERSION "unknown"
-+#endif
-+
-+/**************************************** Common constants */
-+
-+#define LIBWRAP_CLIENTS 5
-+
-+/* CPU stack size */
-+#define DEFAULT_STACK_SIZE 65536
-+/* #define DEBUG_STACK_SIZE */
-+
-+/* I/O buffer size */
-+#define BUFFSIZE 16384
-+
-+/* Length of strings (including the terminating '\0' character) */
-+/* It can't be lower than 256 bytes or NTLM authentication will break */
-+#define STRLEN 256
-+
-+/* IP address and TCP port textual representation length */
-+#define IPLEN 128
-+
-+/* How many bytes of random input to read from files for PRNG */
-+/* OpenSSL likes at least 128 bits, so 64 bytes seems plenty. */
-+#define RANDOM_BYTES 64
-+
-+/* For FormatGuard */
-+/* #define __NO_FORMATGUARD_ */
-+
-+/**************************************** Platform */
-+
-+#ifdef USE_WIN32
-+#define USE_IPv6
-+/* #define USE_FIPS */
-+#endif
-+
-+#ifdef _WIN32_WCE
-+#define USE_WIN32
-+typedef int socklen_t;
-+#define EINTR WSAEINTR
-+#define EMFILE WSAEMFILE
-+#endif
-+
-+#ifdef USE_WIN32
-+#define HAVE_OPENSSL
-+#define HAVE_OSSL_ENGINE_H
-+/* prevent including wincrypt.h, as it defines it's own OCSP_RESPONSE */
-+#define __WINCRYPT_H__
-+#endif
-+
-+/**************************************** Generic headers */
-+
-+#ifdef __vms
-+#include <starlet.h>
-+#endif /* __vms */
-+
-+/* For nsr-tandem-nsk architecture */
-+#ifdef __TANDEM
-+#include <floss.h>
-+#endif
-+
-+/* threads model */
-+#ifdef USE_UCONTEXT
-+#define __MAKECONTEXT_V2_SOURCE
-+#include <ucontext.h>
-+#endif
-+
-+#ifdef USE_PTHREAD
-+#define THREADS
-+#define _REENTRANT
-+#define _THREAD_SAFE
-+#include <pthread.h>
-+#endif
-+
-+/* TCP wrapper */
-+#if HAVE_TCPD_H && HAVE_LIBWRAP
-+#define USE_LIBWRAP
-+#endif
-+
-+/* Must be included before sys/stat.h for Ultrix */
-+#include <sys/types.h>   /* u_short, u_long */
-+/* General headers */
-+#include <stdio.h>
-+/* Must be included before sys/stat.h for Ultrix */
-+#ifndef _WIN32_WCE
-+#include <errno.h>
-+#endif
-+#include <stdlib.h>
-+#include <stdarg.h>      /* va_ */
-+#include <string.h>
-+#include <ctype.h>       /* isalnum */
-+#include <time.h>
-+#include <sys/stat.h>    /* stat */
-+#include <setjmp.h>
-+
-+/**************************************** WIN32 headers */
-+
-+#ifdef USE_WIN32
-+
-+#ifndef HOST
-+#ifdef __MINGW32__
-+#define HOST "x86-pc-mingw32-gnu"
-+#else
-+#ifdef _MSC_VER
-+#define _QUOTEME(x) #x
-+#define QUOTEME(x) _QUOTEME(x)
-+#define HOST "x86-pc-msvc-" ## QUOTEME(_MSC_VER)
-+#else
-+#define HOST "x86-pc-unknown"
-+#endif
-+#endif
-+#endif
-+
-+typedef unsigned char u8;
-+typedef unsigned short u16;
-+typedef unsigned long u32;
-+
-+#define HAVE_SNPRINTF
-+#define snprintf _snprintf
-+#define HAVE_VSNPRINTF
-+#define vsnprintf _vsnprintf
-+#define strcasecmp _stricmp
-+#define strncasecmp _strnicmp
-+#define sleep(c) Sleep(1000*(c))
-+
-+#define get_last_socket_error() WSAGetLastError()
-+#define get_last_error()        GetLastError()
-+#define readsocket(s,b,n)       recv((s),(b),(n),0)
-+#define writesocket(s,b,n)      send((s),(b),(n),0)
-+
-+/* #define FD_SETSIZE 4096 */
-+/* #define Win32_Winsock */
-+#define __USE_W32_SOCKETS
-+
-+/* Winsock2 header for IPv6 definitions */
-+#ifdef _WIN32_WCE
-+#include <winsock.h>
-+#else
-+#include <winsock2.h>
-+#include <ws2tcpip.h>
-+#endif
-+#include <windows.h>
-+
-+#define ECONNRESET WSAECONNRESET
-+#define ENOTSOCK WSAENOTSOCK
-+#define ENOPROTOOPT WSAENOPROTOOPT
-+#define EINPROGRESS WSAEINPROGRESS
-+#define EWOULDBLOCK WSAEWOULDBLOCK
-+#define EISCONN WSAEISCONN
-+#define EADDRINUSE WSAEADDRINUSE
-+
-+#ifdef EINVAL
-+#undef EINVAL
-+#endif
-+#define EINVAL WSAEINVAL
-+
-+#include <process.h>     /* _beginthread */
-+#include <tchar.h>
-+
-+#define NO_IDEA
-+#define OPENSSL_NO_IDEA
-+
-+/**************************************** non-WIN32 headers */
-+
-+#else /* USE_WIN32 */
-+
-+#if SIZEOF_UNSIGNED_CHAR == 1
-+typedef unsigned char u8;
-+#endif
-+
-+#if SIZEOF_UNSIGNED_SHORT == 2
-+typedef unsigned short u16;
-+#else
-+typedef unsigned int u16;
-+#endif
-+
-+#if SIZEOF_UNSIGNED_INT == 4
-+typedef unsigned int u32;
-+#else
-+typedef unsigned long u32;
-+#endif
-+
-+#ifdef __INNOTEK_LIBC__
-+# define get_last_socket_error() sock_errno()
-+# define get_last_error()        errno
-+# 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 get_last_error()        errno
-+#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
-+    /* OpenVMS compatibility */
-+#ifdef __vms
-+#define libdir "__NA__"
-+#define PIDFILE "SYS$LOGIN:STUNNEL.PID"
-+#ifdef __alpha
-+#define HOST "alpha-openvms"
-+#else
-+#define HOST "vax-openvms"
-+#endif
-+#include <inet.h>
-+#include <unistd.h>
-+#else   /* __vms */
-+#include <syslog.h>
-+#endif  /* __vms */
-+
-+    /* Unix-specific headers */
-+#include <signal.h>      /* signal */
-+#include <sys/wait.h>    /* wait */
-+#ifdef HAVE_SYS_RESOURCE_H
-+#include <sys/resource.h> /* getrlimit */
-+#endif
-+#ifdef HAVE_UNISTD_H
-+#include <unistd.h>      /* getpid, fork, execvp, exit */
-+#endif
-+#ifdef HAVE_STROPTS_H
-+#include <stropts.h>
-+#endif
-+#ifdef HAVE_SYS_SELECT_H
-+#include <sys/select.h>  /* for aix */
-+#endif
-+
-+#ifndef BROKEN_POLL
-+#ifdef HAVE_POLL_H
-+#include <poll.h>
-+#define USE_POLL
-+#else /* HAVE_POLL_H */
-+#ifdef HAVE_SYS_POLL_H
-+#include <sys/poll.h>
-+#define USE_POLL
-+#endif /* HAVE_SYS_POLL_H */
-+#endif /* HAVE_POLL_H */
-+#endif /* BROKEN_POLL */
-+
-+#ifdef HAVE_SYS_FILIO_H
-+#include <sys/filio.h>   /* for FIONBIO */
-+#endif
-+#include <pwd.h>
-+#ifdef HAVE_GRP_H
-+#include <grp.h>
-+#endif
-+#ifdef __BEOS__
-+#include <posix/grp.h>
-+#endif
-+#include <fcntl.h>
-+
-+#include <netinet/in.h>  /* struct sockaddr_in */
-+#include <sys/socket.h>  /* getpeername */
-+#include <arpa/inet.h>   /* inet_ntoa */
-+#include <sys/time.h>    /* select */
-+#include <sys/ioctl.h>   /* ioctl */
-+#include <netinet/tcp.h>
-+#include <netdb.h>
-+#ifndef INADDR_ANY
-+#define INADDR_ANY       (u32)0x00000000
-+#endif
-+#ifndef INADDR_LOOPBACK
-+#define INADDR_LOOPBACK  (u32)0x7F000001
-+#endif
-+
-+#if defined(HAVE_WAITPID)
-+/* For SYSV systems */
-+#define wait_for_pid(a, b, c) waitpid((a), (b), (c))
-+#define HAVE_WAIT_FOR_PID 1
-+#elif defined(HAVE_WAIT4)
-+/* For BSD systems */
-+#define wait_for_pid(a, b, c) wait4((a), (b), (c), NULL)
-+#define HAVE_WAIT_FOR_PID 1
-+#endif
-+
-+/* SunOS 4 */
-+#if defined(sun) && !defined(__svr4__) && !defined(__SVR4)
-+#define atexit(a) on_exit((a), NULL)
-+extern int sys_nerr;
-+extern char *sys_errlist[];
-+#define strerror(num) ((num)==0 ? "No error" : \
-+    ((num)>=sys_nerr ? "Unknown error" : sys_errlist[num]))
-+#endif /* SunOS 4 */
-+
-+/* AIX does not have SOL_TCP defined */
-+#ifndef SOL_TCP
-+#define SOL_TCP SOL_SOCKET
-+#endif /* SOL_TCP */
-+
-+/* Linux */
-+#ifdef __linux__
-+#ifndef IP_TRANSPARENT
-+/* old kernel headers without IP_TRANSPARENT definition */
-+#define IP_TRANSPARENT 19
-+#endif /* IP_TRANSPARENT */
-+#endif /* __linux__ */
-+
-+#endif /* USE_WIN32 */
-+
-+/**************************************** OpenSSL headers */
-+
-+#ifdef HAVE_OPENSSL
-+
-+#define OPENSSL_THREAD_DEFINES
-+#include <openssl/opensslconf.h>
-+#if !defined(OPENSSL_THREADS) && defined(USE_PTHREAD)
-+#error OpenSSL library compiled without thread support
-+#endif /* !OPENSSL_THREADS && USE_PTHREAD */
-+
-+#include <openssl/lhash.h>
-+#include <openssl/ssl.h>
-+#include <openssl/err.h>
-+#include <openssl/crypto.h> /* for CRYPTO_* and SSLeay_version */
-+#include <openssl/rand.h>
-+#include <openssl/md4.h>
-+#include <openssl/des.h>
-+
-+#ifdef HAVE_OSSL_ENGINE_H
-+#include <openssl/engine.h>
-+#endif /* HAVE_OSSL_ENGINE_H */
-+
-+#if SSLEAY_VERSION_NUMBER >= 0x00907000L
-+#include <openssl/ocsp.h>
-+#endif /* OpenSSL-0.9.7 */
-+
-+#ifdef USE_FIPS
-+#include <openssl/fips.h>
-+#include <openssl/fips_rand.h>
-+#endif /* USE_FIPS */
-+
-+#else /* HAVE_OPENSSL */
-+
-+#include <lhash.h>
-+#include <ssl.h>
-+#include <err.h>
-+#include <crypto.h>
-+#include <md4.h>
-+#include <des.h>
-+
-+#endif /* HAVE_OPENSSL */
-+
-+/**************************************** Other defines */
-+
-+/* Safe copy for strings declarated as char[STRLEN] */
-+#define safecopy(dst, src) \
-+    (dst[STRLEN-1]='\0', strncpy((dst), (src), STRLEN-1))
-+#define safeconcat(dst, src) \
-+    (dst[STRLEN-1]='\0', strncat((dst), (src), STRLEN-strlen(dst)-1))
-+/* change all non-printable characters to '.' */
-+#define safestring(s) \
-+    do {unsigned char *p; for(p=(unsigned char *)(s); *p; p++) \
-+        if(!isprint((int)*p)) *p='.';} while(0)
-+/* change all unsafe characters to '.' */
-+#define safename(s) \
-+    do {unsigned char *p; for(p=(s); *p; p++) \
-+        if(!isalnum((int)*p)) *p='.';} while(0)
-+
-+/* Some definitions for IPv6 support */
-+#if defined(USE_IPv6)
-+#define addr_len(x) ((x).sa.sa_family==AF_INET ? \
-+    sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))
-+#else
-+#define addr_len(x) (sizeof(struct sockaddr_in))
-+#endif
-+
-+/* 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) */
-+#define LOG_RAW         -1
-+
-+#endif /* defined COMMON_H */
-+
-+/* End of common.h */
 --- a/src/options.c
 +++ b/src/options.c
-@@ -781,6 +781,28 @@ static char *service_options(CMD cmd, LO
+@@ -792,6 +792,28 @@ static char *parse_service_option(CMD cm
      }
  #endif
  
 +    }
 +
      /* exec */
- #ifndef USE_WIN32
      switch(cmd) {
---- /dev/null
-+++ b/src/options.c.orig
-@@ -0,0 +1,1994 @@
-+/*
-+ *   stunnel       Universal SSL tunnel
-+ *   Copyright (C) 1998-2009 Michal Trojnara <Michal.Trojnara@mirt.net>
-+ *
-+ *   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 <http://www.gnu.org/licenses>.
-+ * 
-+ *   Linking stunnel statically or dynamically with other modules is making
-+ *   a combined work based on stunnel. Thus, the terms and conditions of
-+ *   the GNU General Public License cover the whole combination.
-+ * 
-+ *   In addition, as a special exception, the copyright holder of stunnel
-+ *   gives you permission to combine stunnel with free software programs or
-+ *   libraries that are released under the GNU LGPL and with code included
-+ *   in the standard release of OpenSSL under the OpenSSL License (or
-+ *   modified versions of such code, with unchanged license). You may copy
-+ *   and distribute such a system following the terms of the GNU GPL for
-+ *   stunnel and the licenses of the other code concerned.
-+ * 
-+ *   Note that people who make modified versions of stunnel are not obligated
-+ *   to grant this special exception for their modified versions; it is their
-+ *   choice whether to do so. The GNU General Public License gives permission
-+ *   to release a modified version without this exception; this exception
-+ *   also makes it possible to release a modified version which carries
-+ *   forward this exception.
-+ */
-+
-+#include "common.h"
-+#include "prototypes.h"
-+
-+#if defined(_WIN32_WCE) && !defined(CONFDIR)
-+#define CONFDIR "\\stunnel"
-+#endif
-+
-+#ifdef USE_WIN32
-+#define CONFSEPARATOR "\\"
-+#else
-+#define CONFSEPARATOR "/"
-+#endif
-+
-+#define CONFLINELEN (16*1024)
-+
-+static void section_validate(char *, int, LOCAL_OPTIONS *, int);
-+static void config_error(char *, int, char *);
-+static char *stralloc(char *);
-+#ifndef USE_WIN32
-+static char **argalloc(char *);
-+#endif
-+
-+static int parse_debug_level(char *);
-+static int parse_ssl_option(char *);
-+static int print_socket_options(void);
-+static void print_option(char *, int, OPT_UNION *);
-+static int parse_socket_option(char *);
-+static char *parse_ocsp_url(LOCAL_OPTIONS *, char *);
-+static unsigned long parse_ocsp_flag(char *);
-+
-+GLOBAL_OPTIONS options;
-+LOCAL_OPTIONS local_options;
-+
-+typedef enum {
-+    CMD_INIT, /* initialize */
-+    CMD_EXEC,
-+    CMD_DEFAULT,
-+    CMD_HELP
-+} CMD;
-+
-+static char *option_not_found=
-+    "Specified option name is not valid here";
-+
-+static char *global_options(CMD cmd, char *opt, char *arg) {
-+    char *tmpstr;
-+#ifndef USE_WIN32
-+    struct group *gr;
-+    struct passwd *pw;
-+#endif
-+
-+    if(cmd==CMD_DEFAULT || cmd==CMD_HELP) {
-+        s_log(LOG_RAW, "Global options");
-+    }
-+
-+    /* chroot */
-+#ifdef HAVE_CHROOT
-+    switch(cmd) {
-+    case CMD_INIT:
-+        options.chroot_dir=NULL;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "chroot"))
-+            break;
-+        options.chroot_dir=stralloc(arg);
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = directory to chroot stunnel process", "chroot");
-+        break;
-+    }
-+#endif /* HAVE_CHROOT */
-+
-+    /* compression */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        options.compression=COMP_NONE;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "compression"))
-+            break;
-+        if(!strcasecmp(arg, "zlib"))
-+            options.compression=COMP_ZLIB;
-+        else if(!strcasecmp(arg, "rle"))
-+            options.compression=COMP_RLE;
-+        else
-+            return "Compression type should be either 'zlib' or 'rle'";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = zlib|rle compression type",
-+            "compression");
-+        break;
-+    }
-+
-+    /* debug */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        options.debug_level=5;
-+#if !defined (USE_WIN32) && !defined (__vms)
-+        options.facility=LOG_DAEMON;
-+#endif
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "debug"))
-+            break;
-+        if(!parse_debug_level(arg))
-+            return "Illegal debug argument";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        s_log(LOG_RAW, "%-15s = %d", "debug", options.debug_level);
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = [facility].level (e.g. daemon.info)", "debug");
-+        break;
-+    }
-+
-+    /* EGD is only supported when compiled with OpenSSL 0.9.5a or later */
-+#if SSLEAY_VERSION_NUMBER >= 0x0090581fL
-+    switch(cmd) {
-+    case CMD_INIT:
-+        options.egd_sock=NULL;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "EGD"))
-+            break;
-+        options.egd_sock=stralloc(arg);
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+#ifdef EGD_SOCKET
-+        s_log(LOG_RAW, "%-15s = %s", "EGD", EGD_SOCKET);
-+#endif
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = path to Entropy Gathering Daemon socket", "EGD");
-+        break;
-+    }
-+#endif /* OpenSSL 0.9.5a */
-+
-+#ifdef HAVE_OSSL_ENGINE_H
-+    /* engine */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "engine"))
-+            break;
-+        open_engine(arg);
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = auto|engine_id",
-+            "engine");
-+        break;
-+    }
-+
-+    /* engineCtrl */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "engineCtrl"))
-+            break;
-+        tmpstr=strchr(arg, ':');
-+        if(tmpstr)
-+            *tmpstr++='\0';
-+        ctrl_engine(arg, tmpstr);
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = cmd[:arg]",
-+            "engineCtrl");
-+        break;
-+    }
-+#endif
-+
-+    /* fips */
-+#ifdef USE_FIPS
-+    switch(cmd) {
-+    case CMD_INIT:
-+        options.option.fips=1;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "fips"))
-+            break;
-+        if(!strcasecmp(arg, "yes"))
-+            options.option.fips=1;
-+        else if(!strcasecmp(arg, "no"))
-+            options.option.fips=0;
-+        else
-+            return "Argument should be either 'yes' or 'no'";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = yes|no FIPS 140-2 mode",
-+            "fips");
-+        break;
-+    }
-+#endif /* USE_FIPS */
-+
-+    /* foreground */
-+#ifndef USE_WIN32
-+    switch(cmd) {
-+    case CMD_INIT:
-+        options.option.foreground=0;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "foreground"))
-+            break;
-+        if(!strcasecmp(arg, "yes"))
-+            options.option.foreground=1;
-+        else if(!strcasecmp(arg, "no"))
-+            options.option.foreground=0;
-+        else
-+            return "Argument should be either 'yes' or 'no'";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = yes|no foreground mode (don't fork, log to stderr)",
-+            "foreground");
-+        break;
-+    }
-+#endif
-+
-+    /* output */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        options.output_file=NULL;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "output"))
-+            break;
-+        options.output_file=stralloc(arg);
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = file to append log messages", "output");
-+        break;
-+    }
-+
-+    /* pid */
-+#ifndef USE_WIN32
-+    switch(cmd) {
-+    case CMD_INIT:
-+        options.pidfile=PIDFILE;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "pid"))
-+            break;
-+        if(arg[0]) /* is argument not empty? */
-+            options.pidfile=stralloc(arg);
-+        else
-+            options.pidfile=NULL; /* empty -> do not create a pid file */
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        s_log(LOG_RAW, "%-15s = %s", "pid", PIDFILE);
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = pid file (empty to disable creating)", "pid");
-+        break;
-+    }
-+#endif
-+
-+    /* RNDbytes */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        options.random_bytes=RANDOM_BYTES;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "RNDbytes"))
-+            break;
-+        options.random_bytes=atoi(arg);
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        s_log(LOG_RAW, "%-15s = %d", "RNDbytes", RANDOM_BYTES);
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = bytes to read from random seed files", "RNDbytes");
-+        break;
-+    }
-+
-+    /* RNDfile */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        options.rand_file=NULL;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "RNDfile"))
-+            break;
-+        options.rand_file=stralloc(arg);
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+#ifdef RANDOM_FILE
-+        s_log(LOG_RAW, "%-15s = %s", "RNDfile", RANDOM_FILE);
-+#endif
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = path to file with random seed data", "RNDfile");
-+        break;
-+    }
-+
-+    /* RNDoverwrite */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        options.option.rand_write=1;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "RNDoverwrite"))
-+            break;
-+        if(!strcasecmp(arg, "yes"))
-+            options.option.rand_write=1;
-+        else if(!strcasecmp(arg, "no"))
-+            options.option.rand_write=0;
-+        else
-+            return "Argument should be either 'yes' or 'no'";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        s_log(LOG_RAW, "%-15s = yes", "RNDoverwrite");
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = yes|no overwrite seed datafiles with new random data",
-+            "RNDoverwrite");
-+        break;
-+    }
-+
-+    /* service */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        local_options.servname=stralloc("stunnel");
-+#if defined(USE_WIN32) && !defined(_WIN32_WCE)
-+        options.win32_service="stunnel";
-+#endif
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "service"))
-+            break;
-+        local_options.servname=stralloc(arg);
-+#if defined(USE_WIN32) && !defined(_WIN32_WCE)
-+        options.win32_service=stralloc(arg);
-+#endif
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+#if defined(USE_WIN32) && !defined(_WIN32_WCE)
-+        s_log(LOG_RAW, "%-15s = %s", "service", options.win32_service);
-+#endif
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = service name", "service");
-+        break;
-+    }
-+
-+#ifndef USE_WIN32
-+    /* setgid */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        options.gid=0;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "setgid"))
-+            break;
-+        gr=getgrnam(arg);
-+        if(gr)
-+            options.gid=gr->gr_gid;
-+        else if(atoi(arg)) /* numerical? */
-+            options.gid=atoi(arg);
-+        else
-+            return "Illegal GID";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = groupname for setgid()", "setgid");
-+        break;
-+    }
-+#endif
-+
-+#ifndef USE_WIN32
-+    /* setuid */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        options.uid=0;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "setuid"))
-+            break;
-+        pw=getpwnam(arg);
-+        if(pw)
-+            options.uid=pw->pw_uid;
-+        else if(atoi(arg)) /* numerical? */
-+            options.uid=atoi(arg);
-+        else
-+            return "Illegal UID";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = username for setuid()", "setuid");
-+        break;
-+    }
-+#endif
-+
-+    /* socket */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "socket"))
-+            break;
-+        if(!parse_socket_option(arg))
-+            return "Illegal socket option";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = a|l|r:option=value[:value]", "socket");
-+        s_log(LOG_RAW, "%18sset an option on accept/local/remote socket", "");
-+        break;
-+    }
-+
-+    /* syslog */
-+#ifndef USE_WIN32
-+    switch(cmd) {
-+    case CMD_INIT:
-+        options.option.syslog=1;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "syslog"))
-+            break;
-+        if(!strcasecmp(arg, "yes"))
-+            options.option.syslog=1;
-+        else if(!strcasecmp(arg, "no"))
-+            options.option.syslog=0;
-+        else
-+            return "Argument should be either 'yes' or 'no'";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = yes|no send logging messages to syslog",
-+            "syslog");
-+        break;
-+    }
-+#endif
-+
-+    /* taskbar */
-+#ifdef USE_WIN32
-+    switch(cmd) {
-+    case CMD_INIT:
-+        options.option.taskbar=1;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "taskbar"))
-+            break;
-+        if(!strcasecmp(arg, "yes"))
-+            options.option.taskbar=1;
-+        else if(!strcasecmp(arg, "no"))
-+            options.option.taskbar=0;
-+        else
-+            return "Argument should be either 'yes' or 'no'";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        s_log(LOG_RAW, "%-15s = yes", "taskbar");
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = yes|no enable the taskbar icon", "taskbar");
-+        break;
-+    }
-+#endif
-+
-+    if(cmd==CMD_EXEC)
-+        return option_not_found;
-+    return NULL; /* OK */
-+}
-+
-+static char *service_options(CMD cmd, LOCAL_OPTIONS *section,
-+        char *opt, char *arg) {
-+    int tmpnum;
-+
-+    if(cmd==CMD_DEFAULT || cmd==CMD_HELP) {
-+        s_log(LOG_RAW, " ");
-+        s_log(LOG_RAW, "Service-level options");
-+    }
-+
-+    /* accept */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->option.accept=0;
-+        memset(&section->local_addr, 0, sizeof(SOCKADDR_LIST));
-+        section->local_addr.addr[0].in.sin_family=AF_INET;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "accept"))
-+            break;
-+        section->option.accept=1;
-+        if(!name2addrlist(&section->local_addr, arg, DEFAULT_ANY))
-+            return "Failed to resolve accepting address";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = [host:]port accept connections on specified host:port",
-+            "accept");
-+        break;
-+    }
-+
-+    /* CApath */
-+    switch(cmd) {
-+    case CMD_INIT:
-+#if 0
-+        section->ca_dir=(char *)X509_get_default_cert_dir();
-+#endif
-+        section->ca_dir=NULL;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "CApath"))
-+            break;
-+        if(arg[0]) /* not empty */
-+            section->ca_dir=stralloc(arg);
-+        else
-+            section->ca_dir=NULL;
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+#if 0
-+        s_log(LOG_RAW, "%-15s = %s", "CApath",
-+            section->ca_dir ? section->ca_dir : "(none)");
-+#endif
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = CA certificate directory for 'verify' option",
-+            "CApath");
-+        break;
-+    }
-+
-+    /* CAfile */
-+    switch(cmd) {
-+    case CMD_INIT:
-+#if 0
-+        section->ca_file=(char *)X509_get_default_certfile();
-+#endif
-+        section->ca_file=NULL;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "CAfile"))
-+            break;
-+        if(arg[0]) /* not empty */
-+            section->ca_file=stralloc(arg);
-+        else
-+            section->ca_file=NULL;
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+#if 0
-+        s_log(LOG_RAW, "%-15s = %s", "CAfile",
-+            section->ca_file ? section->ca_file : "(none)");
-+#endif
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = CA certificate file for 'verify' option",
-+            "CAfile");
-+        break;
-+    }
-+
-+    /* cert */
-+    switch(cmd) {
-+    case CMD_INIT:
-+#ifdef CONFDIR
-+        section->cert=CONFDIR CONFSEPARATOR "stunnel.pem";
-+#else
-+        section->cert="stunnel.pem";
-+#endif
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "cert"))
-+            break;
-+        section->cert=stralloc(arg);
-+        section->option.cert=1;
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        s_log(LOG_RAW, "%-15s = %s", "cert", section->cert);
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = certificate chain", "cert");
-+        break;
-+    }
-+
-+    /* ciphers */
-+#ifdef USE_FIPS
-+#define STUNNEL_DEFAULT_CIPHER_LIST "FIPS"
-+#else
-+#define STUNNEL_DEFAULT_CIPHER_LIST SSL_DEFAULT_CIPHER_LIST
-+#endif /* USE_FIPS */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->cipher_list=STUNNEL_DEFAULT_CIPHER_LIST;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "ciphers"))
-+            break;
-+        section->cipher_list=stralloc(arg);
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        s_log(LOG_RAW, "%-15s = %s", "ciphers", STUNNEL_DEFAULT_CIPHER_LIST);
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = list of permitted SSL ciphers", "ciphers");
-+        break;
-+    }
-+
-+    /* client */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->option.client=0;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "client"))
-+            break;
-+        if(!strcasecmp(arg, "yes"))
-+            section->option.client=1;
-+        else if(!strcasecmp(arg, "no"))
-+            section->option.client=0;
-+        else
-+            return "Argument should be either 'yes' or 'no'";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = yes|no client mode (remote service uses SSL)",
-+            "client");
-+        break;
-+    }
-+
-+    /* connect */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->option.remote=0;
-+        section->remote_address=NULL;
-+        section->remote_addr.num=0;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "connect"))
-+            break;
-+        section->option.remote=1;
-+        section->remote_address=stralloc(arg);
-+        if(!section->option.delayed_lookup &&
-+                !name2addrlist(&section->remote_addr, arg, DEFAULT_LOOPBACK)) {
-+            s_log(LOG_RAW, "Cannot resolve '%s' - delaying DNS lookup", arg);
-+            section->option.delayed_lookup=1;
-+        }
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = [host:]port connect remote host:port",
-+            "connect");
-+        break;
-+    }
-+
-+    /* CRLpath */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->crl_dir=NULL;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "CRLpath"))
-+            break;
-+        if(arg[0]) /* not empty */
-+            section->crl_dir=stralloc(arg);
-+        else
-+            section->crl_dir=NULL;
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = CRL directory", "CRLpath");
-+        break;
-+    }
-+
-+    /* CRLfile */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->crl_file=NULL;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "CRLfile"))
-+            break;
-+        if(arg[0]) /* not empty */
-+            section->crl_file=stralloc(arg);
-+        else
-+            section->crl_file=NULL;
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = CRL file", "CRLfile");
-+        break;
-+    }
-+
-+    /* delay */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->option.delayed_lookup=0;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "delay"))
-+            break;
-+        if(!strcasecmp(arg, "yes"))
-+            section->option.delayed_lookup=1;
-+        else if(!strcasecmp(arg, "no"))
-+            section->option.delayed_lookup=0;
-+        else
-+            return "Argument should be either 'yes' or 'no'";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = yes|no delay DNS lookup for 'connect' option",
-+            "delay");
-+        break;
-+    }
-+
-+#ifdef HAVE_OSSL_ENGINE_H
-+    /* engineNum */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "engineNum"))
-+            break;
-+        section->engine=get_engine(atoi(arg));
-+        if(!section->engine)
-+            return "Illegal engine number";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = number of engine to read the key from",
-+            "engineNum");
-+        break;
-+    }
-+#endif
-+
-+    /* exec */
-+#ifndef USE_WIN32
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->option.program=0;
-+        section->execname=NULL;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "exec"))
-+            break;
-+        section->option.program=1;
-+        section->execname=stralloc(arg);
-+        if(!section->execargs) {
-+            section->execargs=calloc(2, sizeof(char *));
-+            section->execargs[0]=section->execname;
-+            section->execargs[1]=NULL; /* to show that it's null-terminated */
-+        }
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = file execute local inetd-type program",
-+            "exec");
-+        break;
-+    }
-+#endif
-+
-+    /* execargs */
-+#ifndef USE_WIN32
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->execargs=NULL;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "execargs"))
-+            break;
-+        section->execargs=argalloc(arg);
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = arguments for 'exec' (including $0)",
-+            "execargs");
-+        break;
-+    }
-+#endif
-+
-+    /* failover */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->failover=FAILOVER_RR;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "failover"))
-+            break;
-+        if(!strcasecmp(arg, "rr"))
-+            section->failover=FAILOVER_RR;
-+        else if(!strcasecmp(arg, "prio"))
-+            section->failover=FAILOVER_PRIO;
-+        else
-+            return "Argument should be either 'rr' or 'prio'";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = rr|prio chose failover strategy",
-+            "failover");
-+        break;
-+    }
-+
-+    /* ident */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->username=NULL;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "ident"))
-+            break;
-+        section->username=stralloc(arg);
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = username for IDENT (RFC 1413) checking", "ident");
-+        break;
-+    }
-+
-+    /* key */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->key=NULL;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "key"))
-+            break;
-+        section->key=stralloc(arg);
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        s_log(LOG_RAW, "%-15s = %s", "key", section->cert); /* set in stunnel.c */
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = certificate private key", "key");
-+        break;
-+    }
-+
-+    /* local */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        memset(&section->source_addr, 0, sizeof(SOCKADDR_LIST));
-+        section->source_addr.addr[0].in.sin_family=AF_INET;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "local"))
-+            break;
-+        if(!hostport2addrlist(&section->source_addr, arg, "0"))
-+            return "Failed to resolve local address";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = IP address to be used as source for remote"
-+            " connections", "local");
-+        break;
-+    }
-+
-+#if SSLEAY_VERSION_NUMBER >= 0x00907000L
-+    /* OCSP */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->option.ocsp=0;
-+        memset(&section->ocsp_addr, 0, sizeof(SOCKADDR_LIST));
-+        section->ocsp_addr.addr[0].in.sin_family=AF_INET;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "ocsp"))
-+            break;
-+        section->option.ocsp=1;
-+        return parse_ocsp_url(section, arg);
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = OCSP server URL", "ocsp");
-+        break;
-+    }
-+
-+    /* OCSPflag */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->ocsp_flags=0;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "OCSPflag"))
-+            break;
-+        tmpnum=parse_ocsp_flag(arg);
-+        if(!tmpnum)
-+            return "Illegal OCSP flag";
-+        section->ocsp_flags|=tmpnum;
-+        return NULL;
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = OCSP server flags", "OCSPflag");
-+        break;
-+    }
-+#endif /* OpenSSL-0.9.7 */
-+
-+    /* options */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->ssl_options=0;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "options"))
-+            break;
-+        tmpnum=parse_ssl_option(arg);
-+        if(!tmpnum)
-+            return "Illegal SSL option";
-+        section->ssl_options|=tmpnum;
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = SSL option", "options");
-+        s_log(LOG_RAW, "%18sset an SSL option", "");
-+        break;
-+    }
-+
-+    /* protocol */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->protocol=NULL;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "protocol"))
-+            break;
-+        section->protocol=stralloc(arg);
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = protocol to negotiate before SSL initialization",
-+            "protocol");
-+        s_log(LOG_RAW, "%18scurrently supported: cifs, connect, nntp, pop3, smtp", "");
-+        break;
-+    }
-+
-+    /* protocolAuthentication */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->protocol_authentication="basic";
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "protocolAuthentication"))
-+            break;
-+        section->protocol_authentication=stralloc(arg);
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = authentication type for protocol negotiations",
-+            "protocolAuthentication");
-+        break;
-+    }
-+
-+    /* protocolHost */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->protocol_host=NULL;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "protocolHost"))
-+            break;
-+        section->protocol_host=stralloc(arg);
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = host:port for protocol negotiations",
-+            "protocolHost");
-+        break;
-+    }
-+
-+    /* protocolPassword */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->protocol_password=NULL;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "protocolPassword"))
-+            break;
-+        section->protocol_password=stralloc(arg);
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = password for protocol negotiations",
-+            "protocolPassword");
-+        break;
-+    }
-+
-+    /* protocolUsername */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->protocol_username=NULL;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "protocolUsername"))
-+            break;
-+        section->protocol_username=stralloc(arg);
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = username for protocol negotiations",
-+            "protocolUsername");
-+        break;
-+    }
-+
-+    /* pty */
-+#ifndef USE_WIN32
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->option.pty=0;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "pty"))
-+            break;
-+        if(!strcasecmp(arg, "yes"))
-+            section->option.pty=1;
-+        else if(!strcasecmp(arg, "no"))
-+            section->option.pty=0;
-+        else
-+            return "Argument should be either 'yes' or 'no'";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = yes|no allocate pseudo terminal for 'exec' option",
-+            "pty");
-+        break;
-+    }
-+#endif
-+
-+    /* retry */
-+#ifndef USE_WIN32
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->option.retry=0;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "retry"))
-+            break;
-+        if(!strcasecmp(arg, "yes"))
-+            section->option.retry=1;
-+        else if(!strcasecmp(arg, "no"))
-+            section->option.retry=0;
-+        else
-+            return "Argument should be either 'yes' or 'no'";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = yes|no retry connect+exec section",
-+            "retry");
-+        break;
-+    }
-+#endif
-+
-+    /* session */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->session_timeout=300;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "session"))
-+            break;
-+        if(atoi(arg)>0)
-+            section->session_timeout=atoi(arg);
-+        else
-+            return "Illegal session timeout";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        s_log(LOG_RAW, "%-15s = %ld seconds", "session", section->session_timeout);
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = session cache timeout (in seconds)", "session");
-+        break;
-+    }
-+
-+    /* sessiond */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->option.sessiond=0;
-+        memset(&section->sessiond_addr, 0, sizeof(SOCKADDR_LIST));
-+        section->sessiond_addr.addr[0].in.sin_family=AF_INET;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "sessiond"))
-+            break;
-+        section->option.sessiond=1;
-+#ifdef SSL_OP_NO_TICKET
-+        /* disable RFC4507 support introduced in OpenSSL 0.9.8f */
-+        /* this prevents session callbacks from beeing executed */
-+        section->ssl_options|=SSL_OP_NO_TICKET;
-+#endif
-+        if(!name2addrlist(&section->sessiond_addr, arg, DEFAULT_LOOPBACK))
-+            return "Failed to resolve sessiond server address";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = [host:]port use sessiond at host:port",
-+            "sessiond");
-+        break;
-+    }
-+
-+#ifndef USE_FORK
-+    /* stack */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->stack_size=DEFAULT_STACK_SIZE;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "stack"))
-+            break;
-+        if(atoi(arg)>0)
-+            section->stack_size=atoi(arg);
-+        else
-+            return "Illegal thread stack size";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        s_log(LOG_RAW, "%-15s = %d bytes", "stack", section->stack_size);
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = thread stack size (in bytes)", "stack");
-+        break;
-+    }
-+#endif
-+
-+    /* sslVersion */
-+    switch(cmd) {
-+    case CMD_INIT:
-+#ifdef USE_FIPS
-+        section->client_method=(SSL_METHOD *)TLSv1_client_method();
-+        section->server_method=(SSL_METHOD *)TLSv1_server_method();
-+#else
-+        section->client_method=(SSL_METHOD *)SSLv3_client_method();
-+        section->server_method=(SSL_METHOD *)SSLv23_server_method();
-+#endif
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "sslVersion"))
-+            break;
-+        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")) {
-+            section->client_method=(SSL_METHOD *)SSLv2_client_method();
-+            section->server_method=(SSL_METHOD *)SSLv2_server_method();
-+        } else if(!strcasecmp(arg, "SSLv3")) {
-+            section->client_method=(SSL_METHOD *)SSLv3_client_method();
-+            section->server_method=(SSL_METHOD *)SSLv3_server_method();
-+        } else if(!strcasecmp(arg, "TLSv1")) {
-+            section->client_method=(SSL_METHOD *)TLSv1_client_method();
-+            section->server_method=(SSL_METHOD *)TLSv1_server_method();
-+        } else
-+            return "Incorrect version of SSL protocol";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+#ifdef USE_FIPS
-+        s_log(LOG_RAW, "%-15s = TLSv1", "sslVersion");
-+#else
-+        s_log(LOG_RAW, "%-15s = SSLv3 for client, all for server", "sslVersion");
-+#endif
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = all|SSLv2|SSLv3|TLSv1 SSL method", "sslVersion");
-+        break;
-+    }
-+
-+    /* TIMEOUTbusy */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->timeout_busy=300; /* 5 minutes */
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "TIMEOUTbusy"))
-+            break;
-+        if(atoi(arg)>0)
-+            section->timeout_busy=atoi(arg);
-+        else
-+            return "Illegal busy timeout";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        s_log(LOG_RAW, "%-15s = %d seconds", "TIMEOUTbusy", section->timeout_busy);
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = seconds to wait for expected data", "TIMEOUTbusy");
-+        break;
-+    }
-+
-+    /* TIMEOUTclose */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->timeout_close=60; /* 1 minute */
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "TIMEOUTclose"))
-+            break;
-+        if(atoi(arg)>0 || !strcmp(arg, "0"))
-+            section->timeout_close=atoi(arg);
-+        else
-+            return "Illegal close timeout";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        s_log(LOG_RAW, "%-15s = %d seconds", "TIMEOUTclose", section->timeout_close);
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = seconds to wait for close_notify"
-+            " (set to 0 for buggy MSIE)", "TIMEOUTclose");
-+        break;
-+    }
-+
-+    /* TIMEOUTconnect */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->timeout_connect=10; /* 10 seconds */
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "TIMEOUTconnect"))
-+            break;
-+        if(atoi(arg)>0 || !strcmp(arg, "0"))
-+            section->timeout_connect=atoi(arg);
-+        else
-+            return "Illegal connect timeout";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        s_log(LOG_RAW, "%-15s = %d seconds", "TIMEOUTconnect",
-+            section->timeout_connect);
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = seconds to connect remote host", "TIMEOUTconnect");
-+        break;
-+    }
-+
-+    /* TIMEOUTidle */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->timeout_idle=43200; /* 12 hours */
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "TIMEOUTidle"))
-+            break;
-+        if(atoi(arg)>0)
-+            section->timeout_idle=atoi(arg);
-+        else
-+            return "Illegal idle timeout";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        s_log(LOG_RAW, "%-15s = %d seconds", "TIMEOUTidle", section->timeout_idle);
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = seconds to keep an idle connection", "TIMEOUTidle");
-+        break;
-+    }
-+
-+    /* transparent */
-+#ifndef USE_WIN32
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->option.transparent=0;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "transparent"))
-+            break;
-+        if(!strcasecmp(arg, "yes"))
-+            section->option.transparent=1;
-+        else if(!strcasecmp(arg, "no"))
-+            section->option.transparent=0;
-+        else
-+            return "Argument should be either 'yes' or 'no'";
-+        return NULL; /* OK */
-+    case CMD_DEFAULT:
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = yes|no transparent proxy mode",
-+            "transparent");
-+        break;
-+    }
-+#endif
-+
-+    /* verify */
-+    switch(cmd) {
-+    case CMD_INIT:
-+        section->verify_level=-1;
-+        section->verify_use_only_my=0;
-+        break;
-+    case CMD_EXEC:
-+        if(strcasecmp(opt, "verify"))
-+            break;
-+        section->verify_level=SSL_VERIFY_NONE;
-+        switch(atoi(arg)) {
-+        case 3:
-+            section->verify_use_only_my=1;
-+        case 2:
-+            section->verify_level|=SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
-+        case 1:
-+            section->verify_level|=SSL_VERIFY_PEER;
-+        case 0:
-+            return NULL; /* OK */
-+        default:
-+            return "Bad verify level";
-+        }
-+    case CMD_DEFAULT:
-+        s_log(LOG_RAW, "%-15s = none", "verify");
-+        break;
-+    case CMD_HELP:
-+        s_log(LOG_RAW, "%-15s = level of peer certificate verification", "verify");
-+        s_log(LOG_RAW, "%18slevel 1 - verify peer certificate if present", "");
-+        s_log(LOG_RAW, "%18slevel 2 - require valid peer certificate always", "");
-+        s_log(LOG_RAW, "%18slevel 3 - verify peer with locally installed certificate",
-+        "");
-+        break;
-+    }
-+
-+    if(cmd==CMD_EXEC)
-+        return option_not_found;
-+    return NULL; /* OK */
-+}
-+
-+static void syntax(char *confname) {
-+    s_log(LOG_RAW, " ");
-+    s_log(LOG_RAW, "Syntax:");
-+    s_log(LOG_RAW, "stunnel "
-+#ifdef USE_WIN32
-+#ifndef _WIN32_WCE
-+        "[ [-install | -uninstall] "
-+#endif
-+        "[-quiet] "
-+#endif
-+        "[<filename>] ] "
-+#ifndef USE_WIN32
-+        "-fd <n> "
-+#endif
-+        "| -help | -version | -sockets");
-+    s_log(LOG_RAW, "    <filename>  - use specified config file instead of %s",
-+        confname);
-+#ifdef USE_WIN32
-+#ifndef _WIN32_WCE
-+    s_log(LOG_RAW, "    -install    - install NT service");
-+    s_log(LOG_RAW, "    -uninstall  - uninstall NT service");
-+#endif
-+    s_log(LOG_RAW, "    -quiet      - don't display a message box on success");
-+#else
-+    s_log(LOG_RAW, "    -fd <n>     - read the config file from a file descriptor");
-+#endif
-+    s_log(LOG_RAW, "    -help       - get config file help");
-+    s_log(LOG_RAW, "    -version    - display version and defaults");
-+    s_log(LOG_RAW, "    -sockets    - display default socket options");
-+    die(1);
-+}
-+
-+void parse_config(char *name, char *parameter) {
-+#ifdef CONFDIR
-+    char *default_config_file=CONFDIR CONFSEPARATOR "stunnel.conf";
-+#else
-+    char *default_config_file="stunnel.conf";
-+#endif
-+    DISK_FILE *df;
-+    char confline[CONFLINELEN], *arg, *opt, *errstr, *filename;
-+    int line_number, i;
-+#ifdef MAX_FD
-+    int sections=0;
-+#endif
-+    LOCAL_OPTIONS *section, *new_section;
-+
-+    memset(&options, 0, sizeof(GLOBAL_OPTIONS)); /* reset global options */
-+
-+    memset(&local_options, 0, sizeof(LOCAL_OPTIONS)); /* reset local options */
-+    local_options.next=NULL;
-+    section=&local_options;
-+
-+    global_options(CMD_INIT, NULL, NULL);
-+    service_options(CMD_INIT, section, NULL, NULL);
-+    if(!name)
-+        name=default_config_file;
-+    if(!strcasecmp(name, "-help")) {
-+        global_options(CMD_HELP, NULL, NULL);
-+        service_options(CMD_HELP, section, NULL, NULL);
-+        die(1);
-+    }
-+    if(!strcasecmp(name, "-version")) {
-+        stunnel_info(1);
-+        s_log(LOG_RAW, " ");
-+        global_options(CMD_DEFAULT, NULL, NULL);
-+        service_options(CMD_DEFAULT, section, NULL, NULL);
-+        die(1);
-+    }
-+    if(!strcasecmp(name, "-sockets")) {
-+        print_socket_options();
-+        die(1);
-+    }
-+#ifndef USE_WIN32
-+    if(!strcasecmp(name, "-fd")) {
-+        if(!parameter) {
-+            s_log(LOG_RAW, "No file descriptor specified");
-+            syntax(default_config_file);
-+        }
-+        for(arg=parameter, i=0; *arg; ++arg) {
-+            if(*arg<'0' || *arg>'9') {
-+                s_log(LOG_RAW, "Invalid file descriptor %s", parameter);
-+                syntax(default_config_file);
-+            }
-+            i=10*i+*arg-'0';
-+        }
-+        df=file_fdopen(i);
-+        if(!df) {
-+            s_log(LOG_RAW, "Invalid file descriptor %s", parameter);
-+            syntax(default_config_file);
-+        }
-+        filename="descriptor";
-+    } else
-+#endif
-+    {
-+        df=file_open(name, 0);
-+        if(!df)
-+            syntax(default_config_file);
-+        filename=name;
-+    }
-+    line_number=0;
-+    while(file_getline(df, confline, CONFLINELEN)) {
-+        ++line_number;
-+        opt=confline;
-+        while(isspace((unsigned char)*opt))
-+            ++opt; /* remove initial whitespaces */
-+        for(i=strlen(opt)-1; i>=0 && isspace((unsigned char)opt[i]); --i)
-+            opt[i]='\0'; /* remove trailing whitespaces */
-+        if(opt[0]=='\0' || opt[0]=='#' || opt[0]==';') /* empty or comment */
-+            continue;
-+        if(opt[0]=='[' && opt[strlen(opt)-1]==']') { /* new section */
-+            section_validate(filename, line_number, section, 0);
-+            ++opt;
-+            opt[strlen(opt)-1]='\0';
-+            new_section=calloc(1, sizeof(LOCAL_OPTIONS));
-+            if(!new_section) {
-+                s_log(LOG_RAW, "Fatal memory allocation error");
-+                die(2);
-+            }
-+            memcpy(new_section, &local_options, sizeof(LOCAL_OPTIONS));
-+            new_section->servname=stralloc(opt);
-+            new_section->session=NULL;
-+            new_section->next=NULL;
-+            section->next=new_section;
-+            section=new_section;
-+#ifdef MAX_FD
-+            if(++sections>MAX_FD)
-+                config_error(filename, line_number, "Too many sections");
-+#endif
-+            continue;
-+        }
-+        arg=strchr(confline, '=');
-+        if(!arg)
-+            config_error(filename, line_number, "No '=' found");
-+        *arg++='\0'; /* split into option name and argument value */
-+        for(i=strlen(opt)-1; i>=0 && isspace((unsigned char)opt[i]); --i)
-+            opt[i]='\0'; /* remove trailing whitespaces */
-+        while(isspace((unsigned char)*arg))
-+            ++arg; /* remove initial whitespaces */
-+        errstr=service_options(CMD_EXEC, section, opt, arg);
-+        if(section==&local_options && errstr==option_not_found)
-+            errstr=global_options(CMD_EXEC, opt, arg);
-+        config_error(filename, line_number, errstr);
-+    }
-+    section_validate(filename, line_number, section, 1);
-+    file_close(df);
-+    if(!local_options.next) { /* inetd mode */
-+        if (section->option.accept) {
-+            s_log(LOG_RAW, "accept option is not allowed in inetd mode");
-+            s_log(LOG_RAW, "remove accept option or define a [section]");
-+            die(1);
-+        }
-+        if (!section->option.remote && !section->execname) {
-+            s_log(LOG_RAW, "inetd mode must define a remote host or an executable");
-+            die(1);
-+        }
-+    }
-+}
-+
-+static void section_validate(char *filename, int line_number,
-+        LOCAL_OPTIONS *section, int final) {
-+    if(section==&local_options) { /* global options just configured */
-+#ifdef HAVE_OSSL_ENGINE_H
-+        close_engine();
-+#endif
-+        ssl_configure(); /* configure global SSL settings */
-+        if(!final) /* no need to validate defaults */
-+            return;
-+    }
-+    if(!section->option.client)
-+        section->option.cert=1; /* Server always needs a certificate */
-+    context_init(section); /* initialize SSL context */
-+
-+    if(section==&local_options) { /* inetd mode */
-+        if(section->option.accept)
-+            config_error(filename, line_number,
-+                "accept is not allowed in inetd mode");
-+        /* TODO: some additional checks could be useful
-+        if((unsigned int)section->option.program +
-+                (unsigned int)section->option.remote != 1)
-+            config_error(filename, line_number,
-+                "Single endpoint is required in inetd mode");
-+        */
-+        return;
-+    }
-+
-+    /* standalone mode */
-+#ifdef USE_WIN32
-+    if(!section->option.accept || !section->option.remote)
-+#else
-+    if((unsigned int)section->option.accept +
-+            (unsigned int)section->option.program +
-+            (unsigned int)section->option.remote != 2)
-+#endif
-+        config_error(filename, line_number,
-+            "Each service section must define exactly two endpoints");
-+    return; /* All tests passed -- continue program execution */
-+}
-+
-+static void config_error(char *name, int num, char *str) {
-+    if(!str) /* NULL -> no error */
-+        return;
-+    s_log(LOG_RAW, "file %s line %d: %s", name, num, str);
-+    die(1);
-+}
-+
-+static char *stralloc(char *str) { /* Allocate static string */
-+    char *retval;
-+
-+    retval=calloc(strlen(str)+1, 1);
-+    if(!retval) {
-+        s_log(LOG_RAW, "Fatal memory allocation error");
-+        die(2);
-+    }
-+    strcpy(retval, str);
-+    return retval;
-+}
-+
-+#ifndef USE_WIN32
-+static char **argalloc(char *str) { /* Allocate 'exec' argumets */
-+    int max_arg, i;
-+    char *ptr, **retval;
-+
-+    max_arg=strlen(str)/2+1;
-+    ptr=stralloc(str);
-+    retval=calloc(max_arg+1, sizeof(char *));
-+    if(!retval) {
-+        s_log(LOG_RAW, "Fatal memory allocation error");
-+        die(2);
-+    }
-+    i=0;
-+    while(*ptr && i<max_arg) {
-+        retval[i++]=ptr;
-+        while(*ptr && !isspace((unsigned char)*ptr))
-+            ++ptr;
-+        while(*ptr && isspace((unsigned char)*ptr))
-+            *ptr++='\0';
-+    }
-+    retval[i]=NULL; /* to show that it's null-terminated */
-+    return retval;
-+}
-+#endif
-+
-+/* Parse out the facility/debug level stuff */
-+
-+typedef struct {
-+    char *name;
-+    int value;
-+} facilitylevel;
-+
-+static int parse_debug_level(char *arg) {
-+    char arg_copy[STRLEN];
-+    char *string;
-+    facilitylevel *fl;
-+
-+/* Facilities only make sense on unix */
-+#if !defined (USE_WIN32) && !defined (__vms)
-+    facilitylevel facilities[] = {
-+        {"auth", LOG_AUTH},     {"cron", LOG_CRON},     {"daemon", LOG_DAEMON},
-+        {"kern", LOG_KERN},     {"lpr", LOG_LPR},       {"mail", LOG_MAIL},
-+        {"news", LOG_NEWS},     {"syslog", LOG_SYSLOG}, {"user", LOG_USER},
-+        {"uucp", LOG_UUCP},     {"local0", LOG_LOCAL0}, {"local1", LOG_LOCAL1},
-+        {"local2", LOG_LOCAL2}, {"local3", LOG_LOCAL3}, {"local4", LOG_LOCAL4},
-+        {"local5", LOG_LOCAL5}, {"local6", LOG_LOCAL6}, {"local7", LOG_LOCAL7},
-+
-+        /* Some that are not on all unicies */
-+#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}
-+    };
-+
-+    safecopy(arg_copy, arg);
-+    string = arg_copy;
-+
-+/* Facilities only make sense on Unix */
-+#if !defined (USE_WIN32) && !defined (__vms)
-+    if(strchr(string, '.')) { /* We have a facility specified */
-+        options.facility=-1;
-+        string=strtok(arg_copy, "."); /* break it up */
-+
-+        for(fl=facilities; fl->name; ++fl) {
-+            if(!strcasecmp(fl->name, string)) {
-+                options.facility = fl->value;
-+                break;
-+            }
-+        }
-+        if(options.facility==-1)
-+            return 0; /* FAILED */
-+        string=strtok(NULL, ".");    /* set to the remainder */
-+    }
-+#endif /* USE_WIN32, __vms */
-+
-+    /* Time to check the syslog level */
-+    if(string && strlen(string)==1 && *string>='0' && *string<='7') {
-+        options.debug_level=*string-'0';
-+        return 1; /* OK */
-+    }
-+    options.debug_level=8;    /* illegal level */
-+    for(fl=levels; fl->name; ++fl) {
-+        if(!strcasecmp(fl->name, string)) {
-+            options.debug_level=fl->value;
-+            break;
-+        }
-+    }
-+    if (options.debug_level==8)
-+        return 0; /* FAILED */
-+    return 1; /* OK */
-+}
-+
-+/* Parse out SSL options stuff */
-+
-+static int parse_ssl_option(char *arg) {
-+    struct {
-+        char *name;
-+        long value;
-+    } ssl_opts[] = {
-+        {"MICROSOFT_SESS_ID_BUG", SSL_OP_MICROSOFT_SESS_ID_BUG},
-+        {"NETSCAPE_CHALLENGE_BUG", SSL_OP_NETSCAPE_CHALLENGE_BUG},
-+        {"NETSCAPE_REUSE_CIPHER_CHANGE_BUG",
-+            SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG},
-+        {"SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG},
-+        {"MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER},
-+        {"MSIE_SSLV2_RSA_PADDING", SSL_OP_MSIE_SSLV2_RSA_PADDING},
-+        {"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},
-+        {"DONT_INSERT_EMPTY_FRAGMENTS", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS},
-+#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
-+        {"NO_SESSION_RESUMPTION_ON_RENEGOTIATION",
-+            SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION},
-+#ifdef SSL_OP_NO_COMPRESSION
-+        {"NO_COMPRESSION", SSL_OP_NO_COMPRESSION},
-+#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},
-+        {"CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE},
-+        {"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},
-+        {"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},
-+        {"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
-+        {"ALL", SSL_OP_ALL},
-+        {NULL, 0}
-+    }, *option;
-+
-+    for(option=ssl_opts; option->name; ++option)
-+        if(!strcasecmp(option->name, arg))
-+            return option->value;
-+    return 0; /* FAILED */
-+}
-+
-+/* Parse out the socket options stuff */
-+
-+static int on=1;
-+
-+#define DEF_VALS {NULL, NULL, NULL}
-+#define DEF_ACCEPT {(void *)&on, NULL, NULL}
-+
-+SOCK_OPT sock_opts[] = {
-+    {"SO_DEBUG",        SOL_SOCKET,  SO_DEBUG,        TYPE_FLAG,    DEF_VALS},
-+    {"SO_DONTROUTE",    SOL_SOCKET,  SO_DONTROUTE,    TYPE_FLAG,    DEF_VALS},
-+    {"SO_KEEPALIVE",    SOL_SOCKET,  SO_KEEPALIVE,    TYPE_FLAG,    DEF_VALS},
-+    {"SO_LINGER",       SOL_SOCKET,  SO_LINGER,       TYPE_LINGER,  DEF_VALS},
-+    {"SO_OOBINLINE",    SOL_SOCKET,  SO_OOBINLINE,    TYPE_FLAG,    DEF_VALS},
-+    {"SO_RCVBUF",       SOL_SOCKET,  SO_RCVBUF,       TYPE_INT,     DEF_VALS},
-+    {"SO_SNDBUF",       SOL_SOCKET,  SO_SNDBUF,       TYPE_INT,     DEF_VALS},
-+#ifdef SO_RCVLOWAT
-+    {"SO_RCVLOWAT",     SOL_SOCKET,  SO_RCVLOWAT,     TYPE_INT,     DEF_VALS},
-+#endif
-+#ifdef SO_SNDLOWAT
-+    {"SO_SNDLOWAT",     SOL_SOCKET,  SO_SNDLOWAT,     TYPE_INT,     DEF_VALS},
-+#endif
-+#ifdef SO_RCVTIMEO
-+    {"SO_RCVTIMEO",     SOL_SOCKET,  SO_RCVTIMEO,     TYPE_TIMEVAL, DEF_VALS},
-+#endif
-+#ifdef SO_SNDTIMEO
-+    {"SO_SNDTIMEO",     SOL_SOCKET,  SO_SNDTIMEO,     TYPE_TIMEVAL, DEF_VALS},
-+#endif
-+    {"SO_REUSEADDR",    SOL_SOCKET,  SO_REUSEADDR,    TYPE_FLAG,    DEF_ACCEPT},
-+#ifdef SO_BINDTODEVICE
-+    {"SO_BINDTODEVICE", SOL_SOCKET,  SO_BINDTODEVICE, TYPE_STRING,  DEF_VALS},
-+#endif
-+#ifdef TCP_KEEPCNT
-+    {"TCP_KEEPCNT",     SOL_TCP,     TCP_KEEPCNT,     TYPE_INT,     DEF_VALS},
-+#endif
-+#ifdef TCP_KEEPIDLE
-+    {"TCP_KEEPIDLE",    SOL_TCP,     TCP_KEEPIDLE,    TYPE_INT,     DEF_VALS},
-+#endif
-+#ifdef TCP_KEEPINTVL
-+    {"TCP_KEEPINTVL",   SOL_TCP,     TCP_KEEPINTVL,   TYPE_INT,     DEF_VALS},
-+#endif
-+#ifdef IP_TOS
-+    {"IP_TOS",          IPPROTO_IP,  IP_TOS,          TYPE_INT,     DEF_VALS},
-+#endif
-+#ifdef IP_TTL
-+    {"IP_TTL",          IPPROTO_IP,  IP_TTL,          TYPE_INT,     DEF_VALS},
-+#endif
-+#ifdef IP_MAXSEG
-+    {"TCP_MAXSEG",      IPPROTO_TCP, TCP_MAXSEG,      TYPE_INT,     DEF_VALS},
-+#endif
-+    {"TCP_NODELAY",     IPPROTO_TCP, TCP_NODELAY,     TYPE_FLAG,    DEF_VALS},
-+    {NULL,              0,           0,               TYPE_NONE,    DEF_VALS}
-+};
-+
-+static int print_socket_options(void) {
-+    int fd;
-+    socklen_t optlen;
-+    SOCK_OPT *ptr;
-+    OPT_UNION val;
-+    char line[STRLEN];
-+
-+    fd=socket(AF_INET, SOCK_STREAM, 0);
-+
-+    s_log(LOG_RAW, "Socket option defaults:");
-+    s_log(LOG_RAW, "    %-16s%-10s%-10s%-10s%-10s",
-+        "Option", "Accept", "Local", "Remote", "OS default");
-+    for(ptr=sock_opts; ptr->opt_str; ++ptr) {
-+        /* display option name */
-+        sprintf(line, "    %-16s", ptr->opt_str);
-+        /* display stunnel default values */
-+        print_option(line, ptr->opt_type, ptr->opt_val[0]);
-+        print_option(line, ptr->opt_type, ptr->opt_val[1]);
-+        print_option(line, ptr->opt_type, ptr->opt_val[2]);
-+        /* display OS default value */
-+        optlen=sizeof val;
-+        if(getsockopt(fd, ptr->opt_level,
-+                ptr->opt_name, (void *)&val, &optlen)) {
-+            if(get_last_socket_error()!=ENOPROTOOPT) {
-+                s_log(LOG_RAW, "%s", line); /* dump the name and assigned values */
-+                sockerror("getsockopt");
-+                return 0; /* FAILED */
-+            }
-+            safeconcat(line, "    --    "); /* write-only value */
-+        } else
-+            print_option(line, ptr->opt_type, &val);
-+        s_log(LOG_RAW, "%s", line);
-+    }
-+    return 1; /* OK */
-+}
-+
-+static void print_option(char *line, int type, OPT_UNION *val) {
-+    char text[STRLEN];
-+
-+    if(!val) {
-+        safecopy(text, "    --    ");
-+    } else {
-+        switch(type) {
-+        case TYPE_FLAG:
-+        case TYPE_INT:
-+            sprintf(text, "%10d", val->i_val);
-+            break;
-+        case TYPE_LINGER:
-+            sprintf(text, "%d:%-8d",
-+                val->linger_val.l_onoff, val->linger_val.l_linger);
-+            break;
-+        case TYPE_TIMEVAL:
-+            sprintf(text, "%6d:%-3d",
-+                (int)val->timeval_val.tv_sec, (int)val->timeval_val.tv_usec);
-+            break;
-+        case TYPE_STRING:
-+            sprintf(text, "%10s", val->c_val);
-+            break;
-+        default:
-+            safecopy(text, "  Ooops?  "); /* Internal error? */
-+        }
-+    }
-+    safeconcat(line, text);
-+}
-+
-+static int parse_socket_option(char *arg) {
-+    int socket_type; /* 0-accept, 1-local, 2-remote */
-+    char *opt_val_str, *opt_val2_str;
-+    SOCK_OPT *ptr;
-+
-+    if(arg[1]!=':')
-+        return 0; /* FAILED */
-+    switch(arg[0]) {
-+    case 'a':
-+        socket_type=0; break;
-+    case 'l':
-+        socket_type=1; break;
-+    case 'r':
-+        socket_type=2; break;
-+    default:
-+        return 0; /* FAILED */
-+    }
-+    arg+=2;
-+    opt_val_str=strchr(arg, '=');
-+    if(!opt_val_str) /* No '='? */
-+        return 0; /* FAILED */
-+    *opt_val_str++='\0';
-+    ptr=sock_opts;
-+    for(;;) {
-+        if(!ptr->opt_str)
-+            return 0; /* FAILED */
-+        if(!strcmp(arg, ptr->opt_str))
-+            break; /* option name found */
-+        ++ptr;
-+    }
-+    ptr->opt_val[socket_type]=calloc(1, sizeof(OPT_UNION));
-+    switch(ptr->opt_type) {
-+    case TYPE_FLAG:
-+    case TYPE_INT:
-+        ptr->opt_val[socket_type]->i_val=atoi(opt_val_str);
-+        return 1; /* OK */
-+    case TYPE_LINGER:
-+        opt_val2_str=strchr(opt_val_str, ':');
-+        if(opt_val2_str) {
-+            *opt_val2_str++='\0';
-+            ptr->opt_val[socket_type]->linger_val.l_linger=atoi(opt_val2_str);
-+        } else {
-+            ptr->opt_val[socket_type]->linger_val.l_linger=0;
-+        }
-+        ptr->opt_val[socket_type]->linger_val.l_onoff=atoi(opt_val_str);
-+        return 1; /* OK */
-+    case TYPE_TIMEVAL:
-+        opt_val2_str=strchr(opt_val_str, ':');
-+        if(opt_val2_str) {
-+            *opt_val2_str++='\0';
-+            ptr->opt_val[socket_type]->timeval_val.tv_usec=atoi(opt_val2_str);
-+        } else {
-+            ptr->opt_val[socket_type]->timeval_val.tv_usec=0;
-+        }
-+        ptr->opt_val[socket_type]->timeval_val.tv_sec=atoi(opt_val_str);
-+        return 1; /* OK */
-+    case TYPE_STRING:
-+        if(strlen(opt_val_str)+1>sizeof(OPT_UNION))
-+            return 0; /* FAILED */
-+        strcpy(ptr->opt_val[socket_type]->c_val, opt_val_str);
-+        return 1; /* OK */
-+    default:
-+        ; /* ANSI C compiler needs it */
-+    }
-+    return 0; /* FAILED */
-+}
-+
-+/* Parse out OCSP URL */
-+
-+static char *parse_ocsp_url(LOCAL_OPTIONS *section, char *arg) {
-+    char *host, *port, *path;
-+    int ssl;
-+
-+    if(!OCSP_parse_url(arg, &host, &port, &path, &ssl))
-+        return "Failed to parse OCSP URL";
-+    if(ssl)
-+        return "SSL not supported for OCSP"
-+            " - additional stunnel service needs to be defined";
-+    if(!hostport2addrlist(&section->ocsp_addr, host, port))
-+        return "Failed to resolve OCSP server address";
-+    section->ocsp_path=stralloc(path);
-+    if(host)
-+        OPENSSL_free(host);
-+    if(port)
-+        OPENSSL_free(port);
-+    if(path)
-+        OPENSSL_free(path);
-+    return NULL; /* OK! */
-+}
-+
-+/* Parse out OCSP flags stuff */
-+
-+static 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 */
-+}
-+
-+/* End of options.c */
+     case CMD_INIT:
 --- a/src/prototypes.h
 +++ b/src/prototypes.h
-@@ -231,6 +231,7 @@ typedef struct local_options {
+@@ -177,6 +177,7 @@ typedef struct service_options_struct {
          unsigned int remote:1;
          unsigned int retry:1; /* loop remote+program */
          unsigned int sessiond:1;
-+                              unsigned int xforwardedfor:1;
- #ifndef USE_WIN32
++        unsigned int xforwardedfor:1;
          unsigned int program:1;
+ #ifndef USE_WIN32
          unsigned int pty:1;
-@@ -334,6 +335,8 @@ typedef struct {
-     FD *ssl_rfd, *ssl_wfd; /* Read and write SSL descriptors */
-     int sock_bytes, ssl_bytes; /* Bytes written to socket and ssl */
-     s_poll_set fds; /* File descriptors */
-+              int buffsize;  /* current buffer size, may be lower than BUFFSIZE */
-+              int crlf_seen; /* the number of successive CRLF seen */
+@@ -351,6 +352,8 @@ typedef struct {
+     FD *ssl_rfd, *ssl_wfd; /* read and write SSL descriptors */
+     int sock_bytes, ssl_bytes; /* bytes written to socket and ssl */
+     s_poll_set fds; /* file descriptors */
++    int buffsize;  /* current buffer size, may be lower than BUFFSIZE */
++    int crlf_seen; /* the number of successive CRLF seen */
  } CLI;
  
- extern int max_clients;
---- /dev/null
-+++ b/src/prototypes.h.orig
-@@ -0,0 +1,470 @@
-+/*
-+ *   stunnel       Universal SSL tunnel
-+ *   Copyright (C) 1998-2009 Michal Trojnara <Michal.Trojnara@mirt.net>
-+ *
-+ *   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 <http://www.gnu.org/licenses>.
-+ * 
-+ *   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"
-+
-+/**************************************** Network data structure */
-+
-+#define MAX_HOSTS 16
-+
-+typedef union sockaddr_union {
-+    struct sockaddr sa;
-+    struct sockaddr_in in;
-+#if defined(USE_IPv6)
-+    struct sockaddr_in6 in6;
-+#endif
-+} SOCKADDR_UNION;
-+
-+typedef struct sockaddr_list {      /* list of addresses */
-+    SOCKADDR_UNION addr[MAX_HOSTS]; /* the list of addresses */
-+    u16 cur;                        /* current address for round-robin */
-+    u16 num;                        /* how many addresses are used */
-+} SOCKADDR_LIST;
-+
-+#ifdef __INNOTEK_LIBC__
-+#define socklen_t    __socklen_t
-+#define strcasecmp   stricmp
-+#define strncasecmp  strnicmp
-+#define NI_NUMERICHOST 1
-+#define NI_NUMERICSERV 2
-+#endif
-+
-+
-+/**************************************** Prototypes for stunnel.c */
-+
-+extern volatile int num_clients;
-+
-+void main_initialize(char *, char *);
-+void main_execute(void);
-+#if !defined (USE_WIN32) && !defined (__vms) && !defined(USE_OS2)
-+void drop_privileges(void);
-+#endif
-+void stunnel_info(int);
-+void die(int);
-+
-+/**************************************** Prototypes for log.c */
-+
-+void log_open(void);
-+void log_close(void);
-+void log_flush(void);
-+void s_log(int, const char *, ...)
-+#ifdef __GNUC__
-+    __attribute__ ((format (printf, 2, 3)));
-+#else
-+    ;
-+#endif
-+void ioerror(const char *);
-+void sockerror(const char *);
-+void log_error(int, int, const char *);
-+char *my_strerror(int);
-+
-+/**************************************** Prototypes for pty.c */
-+/* Based on Public Domain code by Tatu Ylonen <ylo@cs.hut.fi>  */
-+
-+int pty_allocate(int *, int *, char *, int);
-+#if 0
-+void pty_release(char *);
-+void pty_make_controlling_tty(int *, char *);
-+#endif
-+
-+/**************************************** Prototypes for ssl.c */
-+
-+typedef enum {
-+    COMP_NONE, COMP_ZLIB, COMP_RLE
-+} COMP_TYPE;
-+
-+extern int cli_index, opt_index;;
-+
-+void ssl_init(void);
-+void ssl_configure(void);
-+#ifdef HAVE_OSSL_ENGINE_H
-+void open_engine(const char *);
-+void ctrl_engine(const char *, const char *);
-+void close_engine(void);
-+ENGINE *get_engine(int);
-+#endif
-+
-+/**************************************** Prototypes for options.c */
-+
-+typedef struct {
-+        /* some data for SSL initialization in ssl.c */
-+    COMP_TYPE compression;                               /* compression type */
-+    char *egd_sock;                       /* entropy gathering daemon socket */
-+    char *rand_file;                                /* file with random data */
-+    int random_bytes;                       /* how many random bytes to read */
-+
-+        /* some global data for stunnel.c */
-+#ifndef USE_WIN32
-+#ifdef HAVE_CHROOT
-+    char *chroot_dir;
-+#endif
-+    unsigned long dpid;
-+    char *pidfile;
-+    int uid, gid;
-+#endif
-+
-+        /* Win32 specific data for gui.c */
-+#if defined(USE_WIN32) && !defined(_WIN32_WCE)
-+    char *win32_service;
-+#endif
-+
-+        /* logging-support data for log.c */
-+    int debug_level;                              /* debug level for logging */
-+#ifndef USE_WIN32
-+    int facility;                               /* debug facility for syslog */
-+#endif
-+    char *output_file;
-+
-+        /* on/off switches */
-+    struct {
-+        unsigned int rand_write:1;                    /* overwrite rand_file */
-+#ifdef USE_WIN32
-+        unsigned int taskbar:1;                   /* enable the taskbar icon */
-+#else /* !USE_WIN32 */
-+        unsigned int foreground:1;
-+        unsigned int syslog:1;
-+#endif
-+#ifdef USE_FIPS
-+        unsigned int fips:1;                       /* enable FIPS 140-2 mode */
-+#endif
-+    } option;
-+} GLOBAL_OPTIONS;
-+
-+extern GLOBAL_OPTIONS options;
-+
-+typedef struct local_options {
-+    SSL_CTX *ctx;                                            /*  SSL context */
-+    X509_STORE *revocation_store;             /* cert store for CRL checking */
-+#ifdef HAVE_OSSL_ENGINE_H
-+    ENGINE *engine;                        /* engine to read the private key */
-+#endif
-+    struct local_options *next;            /* next node in the services list */
-+    char *servname;        /* service name for logging & permission checking */
-+    SSL_SESSION *session;                           /* jecently used session */
-+    char local_address[IPLEN];             /* dotted-decimal address to bind */
-+#ifndef USE_FORK
-+    int stack_size;                            /* stack size for this thread */
-+#endif
-+
-+        /* service-specific data for ctx.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 */
-+    char *cipher_list;
-+    char *cert;                                             /* cert filename */
-+    char *key;                               /* pem (priv key/cert) filename */
-+    long session_timeout;
-+    int verify_level;
-+    int verify_use_only_my;
-+    long ssl_options;
-+#if SSLEAY_VERSION_NUMBER >= 0x00907000L
-+    SOCKADDR_LIST ocsp_addr;
-+    char *ocsp_path;
-+    unsigned long ocsp_flags;
-+#endif /* OpenSSL-0.9.7 */
-+    SSL_METHOD *client_method, *server_method;
-+    SOCKADDR_LIST sessiond_addr;
-+
-+        /* service-specific data for client.c */
-+    int fd;        /* file descriptor accepting connections for this service */
-+    char *execname, **execargs; /* program name and arguments for local mode */
-+    SOCKADDR_LIST local_addr, remote_addr, source_addr;
-+    char *username;
-+    char *remote_address;
-+    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 */
-+
-+        /* protocol name for protocol.c */
-+    char *protocol;
-+    char *protocol_host;
-+    char *protocol_username;
-+    char *protocol_password;
-+    char *protocol_authentication;
-+
-+        /* on/off switches */
-+    struct {
-+        unsigned int cert:1;
-+        unsigned int client:1;
-+        unsigned int delayed_lookup:1;
-+        unsigned int accept:1;
-+        unsigned int remote:1;
-+        unsigned int retry:1; /* loop remote+program */
-+        unsigned int sessiond:1;
-+#ifndef USE_WIN32
-+        unsigned int program:1;
-+        unsigned int pty:1;
-+        unsigned int transparent:1;
-+#endif
-+#if SSLEAY_VERSION_NUMBER >= 0x00907000L
-+        unsigned int ocsp:1;
-+#endif
-+    } option;
-+} LOCAL_OPTIONS;
-+
-+extern LOCAL_OPTIONS local_options;
-+
-+typedef enum {
-+    TYPE_NONE, TYPE_FLAG, TYPE_INT, TYPE_LINGER, TYPE_TIMEVAL, TYPE_STRING
-+} VAL_TYPE;
-+
-+typedef union {
-+    int            i_val;
-+    long           l_val;
-+    char           c_val[16];
-+    struct linger  linger_val;
-+    struct timeval timeval_val;
-+} OPT_UNION;
-+
-+typedef struct {
-+    char *opt_str;
-+    int  opt_level;
-+    int  opt_name;
-+    VAL_TYPE opt_type;
-+    OPT_UNION *opt_val[3];
-+} SOCK_OPT;
-+
-+void parse_config(char *, char *);
-+
-+/**************************************** Prototypes for ctx.c */
-+
-+void context_init(LOCAL_OPTIONS *);
-+void sslerror(char *);
-+
-+/**************************************** Prototypes for verify.c */
-+
-+void verify_init(LOCAL_OPTIONS *);
-+
-+/**************************************** Prototypes for network.c */
-+
-+#ifdef USE_POLL
-+#define MAX_FD 256
-+#endif
-+
-+typedef struct {
-+#ifdef USE_POLL
-+    struct pollfd ufds[MAX_FD];
-+    unsigned int nfds;
-+#else
-+    fd_set irfds, iwfds, orfds, owfds;
-+    int max;
-+#endif
-+} s_poll_set;
-+
-+void s_poll_init(s_poll_set *);
-+void s_poll_add(s_poll_set *, int, int, int);
-+int s_poll_canread(s_poll_set *, int);
-+int s_poll_canwrite(s_poll_set *, int);
-+int s_poll_wait(s_poll_set *, int, int);
-+
-+#ifndef USE_WIN32
-+int signal_pipe_init(void);
-+void child_status(void);  /* dead libwrap or 'exec' process detected */
-+#endif
-+int set_socket_options(int, int);
-+int alloc_fd(int);
-+void setnonblock(int, unsigned long);
-+
-+/**************************************** Prototypes for client.c */
-+
-+typedef struct {
-+    int fd; /* File descriptor */
-+    int rd; /* Open for read */
-+    int wr; /* Open for write */
-+    int is_socket; /* File descriptor is a socket */
-+} FD;
-+
-+typedef struct {
-+    LOCAL_OPTIONS *opt;
-+    char accepted_address[IPLEN]; /* text */
-+    SOCKADDR_LIST peer_addr; /* Peer address */
-+    FD local_rfd, local_wfd; /* Read and write local descriptors */
-+    FD remote_fd; /* Remote file descriptor */
-+    SSL *ssl; /* SSL Connection */
-+    SOCKADDR_LIST bind_addr;
-+        /* IP for explicit local bind or transparent proxy */
-+    unsigned long pid; /* PID of local process */
-+    int fd; /* Temporary file descriptor */
-+    jmp_buf err;
-+
-+    char sock_buff[BUFFSIZE]; /* Socket read buffer */
-+    char ssl_buff[BUFFSIZE]; /* SSL read buffer */
-+    int sock_ptr, ssl_ptr; /* Index of first unused byte in buffer */
-+    FD *sock_rfd, *sock_wfd; /* Read and write socket descriptors */
-+    FD *ssl_rfd, *ssl_wfd; /* Read and write SSL descriptors */
-+    int sock_bytes, ssl_bytes; /* Bytes written to socket and ssl */
-+    s_poll_set fds; /* File descriptors */
-+} CLI;
-+
-+extern int max_clients;
-+#ifndef USE_WIN32
-+extern int max_fds;
-+#endif
-+
-+CLI *alloc_client_session(LOCAL_OPTIONS *, int, int);
-+void *client(void *);
-+
-+/**************************************** Prototypes for network.c */
-+
-+int connect_blocking(CLI *, SOCKADDR_UNION *, socklen_t);
-+void write_blocking(CLI *, int fd, void *, int);
-+void read_blocking(CLI *, int fd, void *, int);
-+void fdputline(CLI *, int, const char *);
-+void fdgetline(CLI *, int, char *);
-+/* descriptor versions of fprintf/fscanf */
-+int fdprintf(CLI *, int, const char *, ...)
-+#ifdef __GNUC__
-+       __attribute__ ((format (printf, 3, 4)));
-+#else
-+       ;
-+#endif
-+int fdscanf(CLI *, int, const char *, char *)
-+#ifdef __GNUC__
-+       __attribute__ ((format (scanf, 3, 0)));
-+#else
-+       ;
-+#endif
-+
-+/**************************************** Prototype for protocol.c */
-+
-+void negotiate(CLI *c);
-+
-+/**************************************** Prototypes for resolver.c */
-+
-+int name2addrlist(SOCKADDR_LIST *, char *, char *);
-+int hostport2addrlist(SOCKADDR_LIST *, char *, char *);
-+char *s_ntop(char *, SOCKADDR_UNION *);
-+
-+/**************************************** Prototypes for sthreads.c */
-+
-+typedef enum {
-+    CRIT_KEYGEN, CRIT_INET, CRIT_CLIENTS, CRIT_WIN_LOG, CRIT_SESSION,
-+    CRIT_LIBWRAP, CRIT_SSL, CRIT_SECTIONS
-+} SECTION_CODE;
-+
-+void enter_critical_section(SECTION_CODE);
-+void leave_critical_section(SECTION_CODE);
-+void sthreads_init(void);
-+unsigned long stunnel_process_id(void);
-+unsigned long stunnel_thread_id(void);
-+int create_client(int, int, CLI *, void *(*)(void *));
-+#ifdef USE_UCONTEXT
-+typedef struct CONTEXT_STRUCTURE {
-+    char *stack; /* CPU stack for this thread */
-+    unsigned long id;
-+    ucontext_t ctx;
-+    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 */
-+} CONTEXT;
-+extern CONTEXT *ready_head, *ready_tail;
-+extern CONTEXT *waiting_head, *waiting_tail;
-+#endif
-+#ifdef _WIN32_WCE
-+int _beginthread(void (*)(void *), int, void *);
-+void _endthread(void);
-+#endif
-+#ifdef DEBUG_STACK_SIZE
-+void stack_info(int);
-+#endif
-+
-+/**************************************** Prototypes for gui.c */
-+
-+typedef struct {
-+    LOCAL_OPTIONS *section;
-+    char pass[PEM_BUFSIZE];
-+} UI_DATA;
-+
-+#ifdef USE_WIN32
-+void win_log(char *);
-+void exit_win32(int);
-+int passwd_cb(char *, int, int, void *);
-+#ifdef HAVE_OSSL_ENGINE_H
-+int pin_cb(UI *, UI_STRING *);
-+#endif
-+
-+#ifndef _WIN32_WCE
-+typedef int (CALLBACK * GETADDRINFO) (const char *,
-+    const char *, const struct addrinfo *, struct addrinfo **);
-+typedef void (CALLBACK * FREEADDRINFO) (struct addrinfo FAR *);
-+typedef int (CALLBACK * GETNAMEINFO) (const struct sockaddr *, socklen_t,
-+    char *, size_t, char *, size_t, int);
-+extern GETADDRINFO s_getaddrinfo;
-+extern FREEADDRINFO s_freeaddrinfo;
-+extern GETNAMEINFO s_getnameinfo;
-+#endif /* ! _WIN32_WCE */
-+#endif /* USE_WIN32 */
-+
-+/**************************************** Prototypes for file.c */
-+
-+typedef struct disk_file {
-+#ifdef USE_WIN32
-+    HANDLE fh;
-+#else
-+    int fd;
-+#endif
-+    /* the inteface is prepared to easily implement buffering if needed */
-+} DISK_FILE;
-+
-+#ifndef USE_WIN32
-+DISK_FILE *file_fdopen(int);
-+#endif
-+DISK_FILE *file_open(char *, int);
-+void file_close(DISK_FILE *);
-+int file_getline(DISK_FILE *, char *, int);
-+int file_putline(DISK_FILE *, char *);
-+
-+#ifdef USE_WIN32
-+LPTSTR str2tstr(const LPSTR);
-+LPSTR tstr2str(const LPTSTR);
-+#endif
-+
-+/**************************************** Prototypes for libwrap.c */
-+
-+void libwrap_init(int);
-+void auth_libwrap(CLI *);
-+
-+#endif /* defined PROTOTYPES_H */
-+
-+/* End of prototypes.h */
+ extern int max_fds, max_clients;