Index: stunnel/INSTALL.W32
diff -u stunnel/INSTALL.W32:1.1.1.1 stunnel/INSTALL.W32:1.3
--- stunnel/INSTALL.W32:1.1.1.1	Sat Mar  3 14:57:01 2001
+++ stunnel/INSTALL.W32	Sun Mar  4 16:37:53 2001
@@ -28,3 +28,85 @@
 	6) run 'make' to compile stunnel
 
 	7) read the stunnel.html man page.
+
+
+To compile stunnel with MSVC:
+	First, you need to have OpenSSL.  stunnel will compile out of
+	the box if you install OpenSSL like this:
+
+	($VCROOT is \Program Files\Microsoft Visual Studio\VC98, or
+	wherever you have MSVC installed)
+
+	.DLLs go in \Windows\System or \Winnt\System32
+	.LIB files go in $VCROOT\Lib
+	.H files go in $VCROOT\Include\openssl
+
+	If you have OpenSSL in a different location, you will need to
+	edit stunnelvc6.mak, uncomment EXTRA_INCLUDE and EXTRA_LIB, and
+	point them to the location where openssl is installed.  If you
+	just downloaded OpenSSL and compiled it, it will probably be
+	something like this:
+
+	EXTRA_INCLUDE=/I "..\openssl-0.9.6\inc32"
+	EXTRA_LIB=/LIBPATH:"..\openssl-0.9.6\out32dll"
+
+	In any case, compile stunnel by using this command:
+
+	nmake /f stunnelvc6.mak
+
+	This has been tested with MSVC 6.0, it may or may not work on
+	other versions.  Of course, you'll need to make sure that the
+	OpenSSL DLLs are somewhere in your path when you run stunnel.
+
+	Read the stunnel.html man page.
+
+NT-specific features:
+	If you're running Windows NT or 2000, you can compile in some
+	extra features not available on the 95/98/ME version.
+
+	Edit stunnelvc6.mak and uncomment the USENT line (make sure
+	this is a clean copy of the source).  Compile as usual.
+
+	You can tell if you have a version of stunnel with NT features
+	enabled by running stunnel -V.  If it says WINNT instead of
+	WIN32 you can play with the fun stuff ;)
+
+	To set up stunnel to run as an NT service, include the -I
+	option.  The default name for the service is "STunnel Service";
+	you can override this with the -M flag.  Any command-line
+	arguments you give stunnel will be saved and used when the
+	service is started.
+
+	Here is an example (you need admin rights for this):
+
+	stunnel -M "Secure POP3" -I -d 995 -r 110
+
+	If all goes well, it will tell you that the service has been
+	installed.  Go to services in control panel, or under admin-
+	istrative tools in 2k, find Secure POP3, and fire it up!
+
+	If you later decide you don't want the service anymore, use
+	this:
+
+	stunnel -M "Secure POP3" -Z
+
+	This will Zap (remove) the service named Secure POP3.
+
+NT event logging:
+	When stunnel runs as an NT service, log messages will be dir-
+	ected to the NT event log.  They go under the Application log
+	with STunnel as the source name.
+
+	If you're planning on using service mode, you should probably
+	install the event log message library so event viewer doesn't
+	complain that it can't decode the messages.
+
+	When you build stunnel with USENT enabled, it should automat-
+	ically build the stevent.dll library; make sure you have it.
+
+	Edit stevent.reg and change EventMessageFile to an absolute
+	path to wherever you have stunnel.dll.  Don't forget to use
+	double-backslash escapes like in C strings.
+
+	Now run stevent.reg as an administrator and the events should
+	show up properly.
Index: stunnel/common.h
diff -u stunnel/common.h:1.1.1.1 stunnel/common.h:1.2
--- stunnel/common.h:1.1.1.1	Sat Mar  3 14:56:46 2001
+++ stunnel/common.h	Sun Mar  4 16:32:35 2001
@@ -26,6 +26,9 @@
 #define OPT_REMOTE      0x20
 #define OPT_TRANSPARENT 0x40
 #define OPT_PTY         0x80
+#ifdef USE_WINNT
+#define OPT_NTSVC       0x100
+#endif
 
 /* Certificate defaults */
 
@@ -51,6 +54,11 @@
 #define PEM_DIR	""
 #endif
 
+#ifdef USE_WINNT
+#ifndef USE_WIN32	/* This is implied by USE_WINNT */
+#define USE_WIN32
+#endif
+#endif
 
 #ifdef USE_WIN32
 
@@ -58,13 +66,27 @@
 #ifdef __MINGW32__
 #define HOST "x86-pc-mingw32-gnu"
 #else
+#ifdef _MSC_VER
+#define HOST "x86-pc-msvc"
+#else
 #define HOST "x86-pc-unknown"
 #endif
+#endif
 
 typedef unsigned char u8;
 typedef unsigned short u16;
 typedef unsigned long u32;
+#ifdef _MSC_VER
+/* Use _int64 instead of long long for MSVC */
+typedef unsigned _int64 u64;
+#else
 typedef unsigned long long u64;
+#endif
+
+#ifdef _MSC_VER
+#define strcasecmp stricmp
+#endif /* MSVC calls it stricmp... */
+/* assuming GNU C for Win32 has this function */
 
 #define HAVE_VSNPRINTF
 #define vsnprintf _vsnprintf
@@ -86,6 +108,13 @@
 #define LOG_INFO        6
 #define LOG_DEBUG       7
 
+#ifdef USE_WINNT
+void addntservice(int argc, const char *argv[]);
+void removentservice();
+void runntservice();
+int realmain();
+#endif
+
 #else /* USE_WIN32 */
 
 #if SIZEOF_UNSIGNED_CHAR == 1
@@ -148,9 +177,13 @@
 #ifdef USE_PTHREAD
 #define STUNNEL_TMP "stunnel " VERSION " on " HOST " PTHREAD"
 #endif
+#ifdef USE_WINNT
+#define STUNNEL_TMP "stunnel " VERSION " on " HOST " WINNT"
+#else
 #ifdef USE_WIN32
 #define STUNNEL_TMP "stunnel " VERSION " on " HOST " WIN32"
 #endif
+#endif
 #ifdef USE_FORK
 #define STUNNEL_TMP "stunnel " VERSION " on " HOST " FORK"
 #endif
@@ -202,6 +235,9 @@
     int random_bytes;	/* how many random bytes to read */
     char *pid_dir;
     int cert_defaults;
+#ifdef USE_WINNT
+    char *ntsvcname;	/* internal name of NT service */
+#endif
 } server_options;
 
 /* Prototypes for stunnel.c */
@@ -224,6 +260,11 @@
 
 void log_open();
 void log_close();
+#ifdef USE_WINNT
+void ntcode(int code);
+#else
+#define ntcode(x)
+#endif
 void log(int, char *, ...);
 int  parse_debug_level(char *);
 
Index: stunnel/log.c
diff -u stunnel/log.c:1.1.1.1 stunnel/log.c:1.2
--- stunnel/log.c:1.1.1.1	Sat Mar  3 14:57:01 2001
+++ stunnel/log.c	Sun Mar  4 16:32:35 2001
@@ -18,6 +18,10 @@
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+/* NT event logging code by Craig Boston
+ * <craig@eikqi.gank.org>
+ */
+
 #include "common.h"
 #include <stdio.h>
 #include <stdarg.h>
@@ -25,14 +29,27 @@
 
 extern server_options options;
 
+#ifdef USE_WINNT
+#include <windows.h>	/* For event logging prototypes */
+int lastcode = 0;
+HANDLE evt = NULL;
+#endif
+
 #ifdef USE_WIN32
 
 void log_open()
 {
+#ifdef USE_WINNT
+	if (options.option & OPT_NTSVC)
+		evt = RegisterEventSource(NULL, "STunnel");
+#endif
 }
 
 void log_close()
 {
+#ifdef USE_WINNT
+	if (evt) DeregisterEventSource(evt);
+#endif
 }
 
 #else /* USE_WIN32 */
@@ -140,20 +157,83 @@
 	return(0);
 }
 
+#ifdef USE_WINNT
+
+void ntcode(int code)	/* ugly hack but best we can do without breaking unix syslog */
+{
+	lastcode = code;
+}
+
+/* Event code layout (another hack :)
+ * 0001-1000        Information
+ * 1001-2000        Warning
+ * 2001-3000        Error
+ * 3001-4000        Success Audit
+ * 4001-5000        Failure Audit
+ *
+ * Events with no code are assigned to code 10000 and event type is
+ * determined based on syslog severity level.
+ */
+
+void vlogntevent(int level, char *text)
+{
+	WORD etype;
+	if (lastcode != 0)	/* do we have a valid NT event code? */
+	{
+		if (lastcode <= 1000)
+			etype = EVENTLOG_INFORMATION_TYPE;
+		else if (lastcode <= 2000)
+			etype = EVENTLOG_WARNING_TYPE;
+		else if (lastcode <= 3000)
+			etype = EVENTLOG_ERROR_TYPE;
+		else if (lastcode <= 4000)
+			etype = EVENTLOG_AUDIT_SUCCESS;
+		else if (lastcode <= 5000)
+			etype = EVENTLOG_AUDIT_FAILURE;
+	}
+	else			/* no, fall back on generic string logging */
+	{
+		lastcode = 10000;
+		if (level >= LOG_NOTICE)
+			etype = EVENTLOG_INFORMATION_TYPE;
+		else if (level >= LOG_WARNING)
+			etype = EVENTLOG_WARNING_TYPE;
+		else if (level >= LOG_EMERG)
+			etype = EVENTLOG_ERROR_TYPE;
+	}
+	ReportEvent(evt, etype, 0, lastcode, NULL, 1, 0, &text, text);
+	lastcode = 0;
+}
+
+#endif
+
 void log(int level, char *format, ...)
 {
     va_list arglist;
     char text[256];
 
     if(level>options.debug_level)
+#ifdef USE_WINNT
+    {
+	lastcode = 0;
+	return;
+    }
+#else
         return;
+#endif
     va_start(arglist, format);
+
 #ifdef HAVE_VSNPRINTF
     vsnprintf(text, 256, format, arglist);
 #else
     vsprintf(text, format, arglist);
 #endif
     va_end(arglist);
+#ifdef USE_WINNT
+    if (options.option & OPT_NTSVC)	/* Only do NT event logging if running as service */
+        vlogntevent(level, text);
+    else
+#endif
 #ifndef USE_WIN32
     if(!options.foreground)
         syslog(level, "%s", text);
@@ -163,4 +243,3 @@
             level, process_id(), thread_id(), text);
     fflush(stderr);
 }
-
Index: stunnel/ntservice.c
diff -u /dev/null stunnel/ntservice.c:1.2
--- /dev/null	Mon Mar  5 09:55:35 2001
+++ stunnel/ntservice.c	Sun Mar  4 16:37:53 2001
@@ -0,0 +1,256 @@
+/*
+ *   stunnel       Universal SSL tunnel
+ *   Copyright (c) 1998-2001 Michal Trojnara <Michal.Trojnara@mirt.net>
+ *                 All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* NT Service code by Craig Boston
+ * <craig@eikqi.gank.org>
+ */
+
+/* Sanity check */
+#ifdef USE_WINNT
+
+#include <windows.h>
+#include "common.h"
+#include "stevent.h"
+
+extern server_options options;
+
+/* Prototypes */
+void WINAPI stsvcmain(DWORD argc, LPTSTR *argv);	/* called by dispatcher */
+void WINAPI stctlf(DWORD Opcode);	/* control status handler (callback) */
+DWORD stsvcloop();			/* spinloop for main thread */
+DWORD __stdcall stsvcthd(void *n);	/* child thread that does all the work */
+
+SERVICE_STATUS          SvcStatus; 
+SERVICE_STATUS_HANDLE   SvcStatusHandle;
+
+void addntservice(int argc, const char *argv[])	/* Add service to the SCM */
+{
+    SC_HANDLE hScm;
+    SC_HANDLE hSvc;
+    char svcpath[STRLEN];
+    int i;
+    if (!options.ntsvcname)
+    {
+	ntcode(EVT_BADPARAM);
+	log(LOG_ERR, "No service name specified; use -M\n");
+	return;
+    }
+
+    if (!(hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)))
+    {
+	ntcode(EVT_INTERNALERR);
+	log(LOG_ERR, "Windows error code %i opening SCM\n", GetLastError());
+	/* TODO: this should probably use formatmessage to get the error text for the code */
+	return;
+    }
+
+    if (!GetModuleFileName(NULL, svcpath, STRLEN))
+    {
+	ntcode(EVT_INTERNALERR);
+	log(LOG_CRIT, "Windows error code %i... getting module name?!\n", GetLastError());
+	/* TODO: this should probably use formatmessage to get the error text for the code */
+	return;
+    }
+
+    safeconcat(svcpath, " -j");
+    for (i = 1; i < argc; i++)
+    {
+	if (strcmp(argv[i], "-I"))
+	{
+	    safeconcat(svcpath, " ");
+	    if (strchr(argv[i], ' ')) safeconcat(svcpath, "\"");
+	    safeconcat(svcpath, argv[i]);
+	    if (strchr(argv[i], ' ')) safeconcat(svcpath, "\"");
+	}
+    }
+
+    hSvc = CreateService(hScm, options.ntsvcname, options.ntsvcname,
+	SERVICE_ALL_ACCESS,
+	SERVICE_WIN32_OWN_PROCESS,
+	SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE,
+	svcpath,
+	NULL, NULL, NULL, NULL, NULL);
+
+    log(LOG_NOTICE, "Service \"%s\" successfully installed and set to Manual start\n", options.ntsvcname);
+}
+
+void removentservice()	/* Delete service from the SCM */
+{
+    SC_HANDLE hScm;
+    SC_HANDLE hSvc;
+    if (!options.ntsvcname)
+    {
+	ntcode(EVT_BADPARAM);
+	log(LOG_ERR, "No service name specified; use -M\n");
+	return;
+    }
+
+    if (!(hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)))
+    {
+	ntcode(EVT_INTERNALERR);
+	log(LOG_ERR, "Windows error code %i opening SCM\n", GetLastError());
+	/* TODO: this should probably use formatmessage to get the error text for the code */
+	return;
+    }
+
+    if (!(hSvc = OpenService(hScm, options.ntsvcname, SERVICE_ALL_ACCESS)))
+    {
+	ntcode(EVT_INTERNALERR);
+	log(LOG_ERR, "Windows error code %i opening service \"%s\"\n", GetLastError(),
+	    options.ntsvcname);
+	/* TODO: this should probably use formatmessage to get the error text for the code */
+	return;
+    }
+
+    if (!DeleteService(hSvc))
+    {
+	ntcode(EVT_INTERNALERR);
+	log(LOG_ERR, "Windows error code %i deleting service\n", GetLastError());
+	return;
+    }
+
+    log(LOG_NOTICE, "Service \"%s\" successfully removed\n", options.ntsvcname);
+}
+
+/* runntservice is called by main; its job is to jump though the dispatcher hoops
+ * that NT makes us */
+void runntservice()
+{
+    SERVICE_TABLE_ENTRY ste[2];
+
+    if (!options.ntsvcname) exit(1);	/* can't do any logging at this point :( */
+
+    ste[0].lpServiceName = options.ntsvcname;
+    ste[0].lpServiceProc = stsvcmain;
+    ste[1].lpServiceName = NULL;
+    ste[1].lpServiceProc = NULL;
+    StartServiceCtrlDispatcher(ste);
+    exit(0);
+}
+
+void WINAPI stsvcmain(DWORD argc, LPTSTR *argv)
+{
+    DWORD status;
+
+    SvcStatus.dwServiceType        = SERVICE_WIN32; 
+    SvcStatus.dwCurrentState       = SERVICE_START_PENDING; 
+    SvcStatus.dwControlsAccepted   = SERVICE_ACCEPT_STOP;
+    SvcStatus.dwWin32ExitCode      = 0; 
+    SvcStatus.dwServiceSpecificExitCode = 0; 
+    SvcStatus.dwCheckPoint         = 0; 
+    SvcStatus.dwWaitHint           = 0; 
+ 
+    SvcStatusHandle = RegisterServiceCtrlHandler(options.ntsvcname, stctlf); 
+    if (SvcStatusHandle == 0)		/* still can't log */
+        return;
+
+    /* Initialization complete - report running status. */
+    SvcStatus.dwCurrentState       = SERVICE_RUNNING; 
+    SvcStatus.dwCheckPoint         = 0; 
+    SvcStatus.dwWaitHint           = 0; 
+
+    if (!SetServiceStatus (SvcStatusHandle, &SvcStatus)) 
+        status = GetLastError(); 
+
+    status = stsvcloop();
+
+    SvcStatus.dwCurrentState       = SERVICE_STOPPED;
+    SvcStatus.dwCheckPoint         = 0; 
+    SvcStatus.dwWaitHint           = 0; 
+    SvcStatus.dwWin32ExitCode      = status; 
+ 
+    if (!SetServiceStatus (SvcStatusHandle, &SvcStatus)) 
+    { 
+        status = GetLastError(); 
+    } 
+
+}
+
+void WINAPI stctlf(DWORD opcode) 
+{ 
+    DWORD status;
+
+    switch(opcode) 
+    { 
+        case SERVICE_CONTROL_STOP: 
+        /* Do whatever it takes to stop here. */
+            SvcStatus.dwWin32ExitCode = 0; 
+            SvcStatus.dwCurrentState  = SERVICE_STOP_PENDING; 
+            SvcStatus.dwCheckPoint    = 0; 
+            SvcStatus.dwWaitHint      = 0; 
+ 
+            if (!SetServiceStatus (SvcStatusHandle, 
+                &SvcStatus))
+            { 
+                status = GetLastError(); 
+            } 
+ 
+            return; 
+ 
+        case SERVICE_CONTROL_INTERROGATE: 
+        /* Fall through to send current status. */
+            break; 
+ 
+        default: 
+			break;
+    } 
+ 
+    /* Send current status. */
+    if (!SetServiceStatus (SvcStatusHandle,  &SvcStatus)) 
+    { 
+        status = GetLastError(); 
+    } 
+    return; 
+}
+
+DWORD stsvcloop()
+{
+	HANDLE cthread;
+	DWORD status;
+
+	cthread = CreateThread(NULL, 0, &stsvcthd, NULL, 0, &status);
+	/* create a child thread to run the server */
+
+	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
+	/* set this thread to idle so we don't bother anybody */
+
+	do { Sleep(1000); GetExitCodeThread(cthread, &status); }
+	while (SvcStatus.dwCurrentState != SERVICE_STOP_PENDING && status == STILL_ACTIVE);
+	/* loop, polling every second to see if we are being asked to stop the service or if
+	 * the child thread has died unexpectedly */
+
+	if (status != STILL_ACTIVE)
+	{
+		CloseHandle(cthread);		/* child terminated all by itself... */
+		return ERROR_PROCESS_ABORTED;
+	}
+
+	TerminateThread(cthread, 1);		/* we were asked to stop so kill the thread */
+	CloseHandle(cthread);	/* SIGTERM on unix isn't handled any more gracefully anyway ;) */
+	return NO_ERROR;
+}
+
+DWORD __stdcall stsvcthd(void *n)
+{
+	return realmain();	/* not much here :) */
+}
+
+
+#endif
Index: stunnel/protocol.c
diff -u stunnel/protocol.c:1.1.1.1 stunnel/protocol.c:1.2
--- stunnel/protocol.c:1.1.1.1	Sat Mar  3 14:57:03 2001
+++ stunnel/protocol.c	Sun Mar  4 16:32:35 2001
@@ -23,13 +23,17 @@
 #ifdef USE_WIN32
 #define Win32_Winsock
 #include <windows.h>
+#ifdef USE_WINNT
+#include "stevent.h"
 #endif
+#else	/* Use standard sockets */
+#include <unistd.h>    /* for read(), write() */
+#include <sys/time.h>  /* for select() */
+#endif
 
 #include <stdio.h>
 #include <stdarg.h>    /* for va_* */
-#include <unistd.h>    /* for read(), write() */
 #include <string.h>
-#include <sys/time.h>  /* for select() */
 #include <sys/types.h> /* Ultrix needs it for fd_set */
 
 /* protocol-specific function prototypes */
@@ -49,6 +53,7 @@
 {
     if(!protocol)
         return 0; /* No protocol negotiations */
+    ntcode(EVT_DEBUG);
     log(LOG_DEBUG, "Negotiations for %s(%s side) started", protocol,
         client ? "client" : "server");
     if(!strcmp(protocol, "smb")) {
@@ -69,6 +74,7 @@
         else
             return telnet_server(local, remote);
     }
+    ntcode(EVT_INTERNALERR);
     log(LOG_ERR, "Protocol %s not supported in %s mode",
         protocol, client ? "client" : "server");
     return -1;
@@ -76,18 +82,21 @@
 
 static int smb_client(int local, int remote)
 {
+    ntcode(EVT_NOPROTO);
     log(LOG_ERR, "Protocol not supported");
     return -1;
 }
 
 static int smb_server(int local, int remote)
 {
+    ntcode(EVT_NOPROTO);
     log(LOG_ERR, "Protocol not supported");
     return -1;
 }
 
 static int smtp_client(int local, int remote)
 {
+    ntcode(EVT_NOPROTO);
     log(LOG_ERR, "Protocol not supported");
     return -1;
 }
@@ -100,12 +109,14 @@
         return 0; /* Return if RFC 2487 is not used */
 
     if(fdscanf(remote, "220%[^\n]", line)!=1) {
+        ntcode(EVT_SMTPERR);
         log(LOG_ERR, "Unknown server welcome");
         return -1;
     }
     if(fdprintf(local, "220%s + stunnel", line)<0)
         return -1;
     if(fdscanf(local, "EHLO %[^\n]", line)!=1) {
+        ntcode(EVT_SMTPERR);
         log(LOG_ERR, "Unknown client EHLO");
         return -1;
     }
@@ -114,6 +125,7 @@
     if(fdprintf(local, "250 STARTTLS")<0)
         return -1;
     if(fdscanf(local, "STARTTLS", line)<0) {
+        ntcode(EVT_SMTPERR);
         log(LOG_ERR, "STARTTLS expected");
         return -1;
     }
@@ -124,12 +136,14 @@
 
 static int telnet_client(int local, int remote)
 {
+    ntcode(EVT_NOPROTO);
     log(LOG_ERR, "Protocol not supported");
     return -1;
 }
 
 static int telnet_server(int local, int remote)
 {
+    ntcode(EVT_NOPROTO);
     log(LOG_ERR, "Protocol not supported");
     return -1;
 }
@@ -155,6 +169,7 @@
         sockerror("writesocket (fdprintf)");
         return -1;
     }
+    ntcode(EVT_DEBUG);
     log(LOG_DEBUG, " -> %s", line);
     return len;
 }
@@ -171,6 +186,7 @@
             sockerror("readsocket (fdscanf)");
             return -1;
         case 0: /* EOF */
+            ntcode(EVT_SOCKERR);
             log(LOG_ERR, "Unexpected socket close (fdscanf)");
             return -1;
         }
@@ -182,6 +198,7 @@
             break;
     }
     line[ptr]='\0';
+    ntcode(EVT_DEBUG);
     log(LOG_DEBUG, " <- %s", line);
     return sscanf(line, format, buffer);
 }
@@ -208,9 +225,11 @@
 
     switch(select(fd+1, &fdsRead, NULL, NULL, &timeout)) {
     case 0: /* fd not ready to read */
+        ntcode(EVT_DEBUG);
         log(LOG_DEBUG, "RFC 2487 detected");
         return 1;
     case 1: /* fd ready to read */
+        ntcode(EVT_DEBUG);
         log(LOG_DEBUG, "RFC 2487 not detected");
         return 0;
     }
Index: stunnel/ssl.c
diff -u stunnel/ssl.c:1.1.1.1 stunnel/ssl.c:1.2
--- stunnel/ssl.c:1.1.1.1	Sat Mar  3 14:57:05 2001
+++ stunnel/ssl.c	Sun Mar  4 16:32:35 2001
@@ -74,6 +74,10 @@
 #define ECONNRESET WSAECONNRESET
 #define ENOTSOCK WSAENOTSOCK
 
+#ifdef USE_WINNT
+#include "stevent.h"
+#endif
+
 #else /* defined USE_WIN32 */
 
 /* Must be included before sys/stat.h for Ultrix */
@@ -147,6 +151,7 @@
 
 #if SSLEAY_VERSION_NUMBER >= 0x0090581fL
     if ( RAND_status() ) {
+    	ntcode(EVT_DEBUG);
     	log(LOG_DEBUG, "RAND_status claims sufficient entropy for the PRNG");
 	return(1);
     }
@@ -168,6 +173,7 @@
     if ( stat(filename, &sb) !=0 ) { return(0); }
     
     if ( (readbytes = RAND_load_file(filename, options.random_bytes )) ) {
+	ntcode(EVT_DEBUG);
 	log(LOG_DEBUG, "Snagged %d random bytes from %s", readbytes, filename);
     } else {
 	log(LOG_INFO, "Unable to retrieve any random data from %s", filename);
@@ -180,6 +186,7 @@
 		log(LOG_WARNING, "Failed to write strong random data to %s.  May "
 			"be a permissions or seeding problem", filename); 
 	} else {
+		ntcode(EVT_DEBUG);
 		log(LOG_DEBUG, "Wrote %d new random bytes to %s", writebytes, filename);
 	}
     }
@@ -220,9 +227,11 @@
 #ifdef USE_WIN32
     RAND_screen();
     if ( prng_seeded(totbytes) ) {
+        ntcode(EVT_DEBUG);
         log(LOG_DEBUG, "Seeded PRNG with RAND_screen");
 	goto SEEDED;
     } else {
+        ntcode(EVT_DEBUG);
         log(LOG_DEBUG, "RAND_screen failed to sufficiently seed PRNG");
     }
 #else
@@ -234,6 +243,7 @@
 	    bytes=0;
         } else {
 	    totbytes += bytes;
+            ntcode(EVT_DEBUG);
             log(LOG_DEBUG, "Snagged %d random bytes from EGD Socket %s",
                 bytes, options.egd_sock);
 	    goto SEEDED;  /* openssl always gets what it needs or fails,
@@ -245,6 +255,7 @@
         log(LOG_WARNING, "EGD Socket %s failed", EGD_SOCKET);
     } else {
 	totbytes += bytes;
+        ntcode(EVT_DEBUG);
         log(LOG_DEBUG, "Snagged %d random bytes from EGD Socket %s",
                 bytes, EGD_SOCKET);
 	goto SEEDED; /* ditto */
@@ -277,9 +288,11 @@
 	X509_STORE *store;
 
 	stack= SSL_CTX_get_client_CA_list(ctx);
+	ntcode(EVT_DEBUG);
 	log(LOG_DEBUG, "there are %d CA_list things", sk_X509_NAME_num(stack));
 
 	store=SSL_CTX_get_cert_store(ctx);
+	ntcode(EVT_DEBUG);
 	log(LOG_DEBUG, "it's a %p", store);
 	*/
 }
@@ -304,6 +317,7 @@
 #endif /* NO_RSA */
 #ifndef NO_DH
         if(!(bio=BIO_new_file(options.pem, "r"))) {
+            ntcode(EVT_IOERR);
             log(LOG_ERR, "DH: Could not read %s: %s", options.pem,
                 strerror(errno));
             goto dh_failed;
@@ -313,11 +327,13 @@
                 , NULL
 #endif
                 ))) {
+            ntcode(EVT_INTERNALERR);
             log(LOG_ERR, "Could not load DH parameters from %s",
                 options.pem);
             goto dh_failed;
         }
         SSL_CTX_set_tmp_dh(ctx, dh);
+        ntcode(EVT_DEBUG);
         log(LOG_DEBUG, "Diffie-Hellman initialized with %d bit key",
             8*DH_size(dh));
         goto dh_done;
@@ -336,10 +352,12 @@
     if(options.option&OPT_CERT) {
         if(!SSL_CTX_use_certificate_file(ctx, options.pem,
                 SSL_FILETYPE_PEM)) {
+            ntcode(EVT_IOERR);
             log(LOG_ERR, "Error reading certificate file: %s", options.pem);
             sslerror("SSL_CTX_use_certificate_file");
             exit(1);
         }
+        ntcode(EVT_DEBUG);
         log(LOG_DEBUG, "Certificate: %s", options.pem);
 #ifdef NO_RSA
         if(!SSL_CTX_use_PrivateKey_file(ctx, options.pem,
@@ -361,10 +379,14 @@
     }
     if(options.verify_level!=SSL_VERIFY_NONE) {
 
+	ntcode(EVT_DEBUG);
 	log(LOG_DEBUG, "cert_defaults is %d", options.cert_defaults);
+	ntcode(EVT_DEBUG);
 	log(LOG_DEBUG, "cert_dir is %s", options.cert_dir);
+	ntcode(EVT_DEBUG);
 	log(LOG_DEBUG, "cert_file is %s", options.cert_file);
 	if ( options.cert_defaults & SSL_CERT_DEFAULTS ) {
+		ntcode(EVT_DEBUG);
 		log(LOG_DEBUG, "Initializing SSL library verify paths.");
 		if ((!SSL_CTX_set_default_verify_paths(ctx))) { 
 		    sslerror("X509_set_default_verify_paths");
@@ -374,6 +396,7 @@
 
 	/* put in defaults (if not set on cmd line) if -S says to */
 	if ( options.cert_defaults & STUNNEL_CERT_DEFAULTS ) {
+		ntcode(EVT_DEBUG);
 		log(LOG_DEBUG, "installing defaults where not set");
 		if ( ! options.cert_file[0] ) 
 			safecopy(options.cert_file, CERT_FILE);
@@ -382,6 +405,7 @@
 	}
 	if ( options.cert_file[0] ) {
 	    if (!SSL_CTX_load_verify_locations(ctx, options.cert_file,NULL)) {
+		ntcode(EVT_IOERR);
 		log(LOG_ERR, "Error loading verify certificates from %s",
 		    options.cert_file);
 		sslerror("SSL_CTX_load_verify_locations");
@@ -389,16 +413,19 @@
 	    }
             SSL_CTX_set_client_CA_list(ctx, 
 		SSL_load_client_CA_file(options.cert_file));
+	    ntcode(EVT_DEBUG);
 	    log(LOG_DEBUG, "Loaded verify certificates from %s",
 		options.cert_file);
 	}
 	if ( options.cert_dir[0] ) {
 	    if (!SSL_CTX_load_verify_locations(ctx,NULL ,options.cert_dir)) {
+		ntcode(EVT_INTERNALERR);
 		log(LOG_ERR, "Error setting verify directory to %s",
 		    options.cert_dir);
 		sslerror("SSL_CTX_load_verify_locations");
 		exit(1);
 	    }
+	    ntcode(EVT_DEBUG);
 	    log(LOG_DEBUG, "Set verify directory to %s", options.cert_dir);
 	}
 
@@ -414,7 +441,10 @@
 
 
         if (options.verify_use_only_my)
+        {
+            ntcode(EVT_CERTINFO);
             log(LOG_NOTICE, "Peer certificate location %s", options.cert_dir);
+        }
 
 
     }
@@ -446,6 +476,7 @@
     struct request_info request;
 #endif
 
+    ntcode(EVT_DEBUG);
     log(LOG_DEBUG, "%s started", options.servname);
     l.l_onoff=1;
     l.l_linger=0;
@@ -481,6 +512,7 @@
                 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
             goto cleanup_local;
         }
+        ntcode(EVT_RMTCONNECT);
         log(LOG_NOTICE, "%s connected from %s:%d", options.servname,
             inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
     }
@@ -490,6 +522,7 @@
     if(options.option&OPT_REMOTE) { /* remote host */
         if((remote=connect_remote(ip))<0)
             goto cleanup_local; /* Failed to connect remote server */
+        ntcode(EVT_DEBUG);
         log(LOG_DEBUG, "Remote host connected");
 #ifdef SO_OOBINLINE
         on= 1;
@@ -502,12 +535,14 @@
     } else { /* local service */
         if((remote=connect_local(ip))<0)
             goto cleanup_local; /* Failed to spawn local service */
+        ntcode(EVT_DEBUG);
         log(LOG_DEBUG, "Local service connected");
     }
 
     /* negotiate protocol */
     if(negotiate(options.protocol, options.option&OPT_CLIENT,
             local, remote) <0) {
+        ntcode(EVT_PROTOERR);
         log(LOG_ERR, "Protocol negotiations failed");
         goto cleanup_remote;
     }
@@ -571,6 +606,7 @@
 done:
 #ifndef USE_FORK
     enter_critical_section(2); /* for multi-cpu machines */
+    ntcode(EVT_DEBUG);
     log(LOG_DEBUG, "%s finished (%d left)", options.servname,
         --options.clients);
     leave_critical_section(2);
@@ -605,6 +641,7 @@
         sockerror("ioctlsocket (sock)"); /* non-critical */
     if(ioctlsocket(ssl_fd, FIONBIO, &l)<0)
         sockerror("ioctlsocket (ssl)"); /* non-critical */
+    ntcode(EVT_DEBUG);
     log(LOG_DEBUG, "Sockets set to non-blocking mode");
 #endif
 
@@ -664,6 +701,7 @@
                 ssl_ptr-=num;
                 sock_bytes+=num;
             } else { /* close */
+                ntcode(EVT_DEBUG);
                 log(LOG_DEBUG, "Socket closed on write");
                 sock_open=0;
             }
@@ -692,6 +730,7 @@
             case SSL_ERROR_WANT_WRITE:
             case SSL_ERROR_WANT_READ:
             case SSL_ERROR_WANT_X509_LOOKUP:
+                ntcode(EVT_DEBUG);
                 log(LOG_DEBUG, "SSL_write returned WANT_ - retry");
                 break;
             case SSL_ERROR_SYSCALL:
@@ -700,6 +739,7 @@
                     goto error;
                 }
             case SSL_ERROR_ZERO_RETURN:
+                ntcode(EVT_DEBUG);
                 log(LOG_DEBUG, "SSL closed on write");
                 ssl_open=0;
                 break;
@@ -722,6 +762,7 @@
             } else if (num > 0) {
                 sock_ptr += num;
             } else { /* close */
+                ntcode(EVT_DEBUG);
                 log(LOG_DEBUG, "Socket closed on read");
                 sock_open = 0;
             }
@@ -752,6 +793,7 @@
             case SSL_ERROR_WANT_WRITE:
             case SSL_ERROR_WANT_READ:
             case SSL_ERROR_WANT_X509_LOOKUP:
+                ntcode(EVT_DEBUG);
                 log(LOG_DEBUG, "SSL_read returned WANT_ - retry");
                 break;
             case SSL_ERROR_SYSCALL:
@@ -760,6 +802,7 @@
                     goto error;
                 }
             case SSL_ERROR_ZERO_RETURN:
+                ntcode(EVT_DEBUG);
                 log(LOG_DEBUG, "SSL closed on read");
                 ssl_open=0;
                 break;
@@ -783,6 +826,7 @@
         sockerror("ioctlsocket (ssl)"); /* non-critical */
 #endif
 
+    ntcode(EVT_CLIENTDONE);
     log(LOG_NOTICE,
         "Connection %s: %d bytes sent to SSL, %d bytes sent to socket",
         retval<0 ? "reset" : "closed", ssl_bytes, sock_bytes);
@@ -794,12 +838,14 @@
 static RSA *make_temp_key(int keylen) {
     RSA *result;
 
+    ntcode(EVT_DEBUG);
     log(LOG_DEBUG, "Generating %d bit temporary RSA key...", keylen);
 #if SSLEAY_VERSION_NUMBER >= 0x0900
     result=RSA_generate_key(keylen, RSA_F4, NULL, NULL);
 # else
     result=RSA_generate_key(keylen, RSA_F4, NULL);
 # endif
+    ntcode(EVT_DEBUG);
     log(LOG_DEBUG, "Temporary RSA key created");
     return result;
 }
@@ -866,6 +912,7 @@
         txt, sizeof(txt));
     if(!state) {
         /* Remote site specified a certificate, but it's not correct */
+        ntcode(EVT_CERTWARN);
         log(LOG_WARNING, "VERIFY ERROR: depth=%d error=%s: %s",
             ctx->error_depth,
             X509_verify_cert_error_string (ctx->error), txt);
@@ -877,12 +924,14 @@
         log (LOG_WARNING, "VERIFY ERROR ONLY MY: no cert for: %s", txt);
         return 0; /* Reject connection */
     }
+    ntcode(EVT_CERTINFO);
     log(LOG_NOTICE, "VERIFY OK: depth=%d: %s", ctx->error_depth, txt);
     return 1; /* Accept connection */
 }
 
 static void info_callback(SSL *s, int where, int ret)
 {
+    ntcode(EVT_DEBUG);
     log(LOG_DEBUG, "%s", SSL_state_string_long(s));
     if(where==SSL_CB_HANDSHAKE_DONE)
         print_stats();
@@ -890,26 +939,36 @@
 
 static void print_stats() /* print statistics */
 {
+    ntcode(EVT_DEBUG);
     log(LOG_DEBUG, "%4ld items in the session cache",
         SSL_CTX_sess_number(ctx));
+    ntcode(EVT_DEBUG);
     log(LOG_DEBUG, "%4d client connects (SSL_connect())",
         SSL_CTX_sess_connect(ctx));
+    ntcode(EVT_DEBUG);
     log(LOG_DEBUG, "%4d client connects that finished",
         SSL_CTX_sess_connect_good(ctx));
 #if SSLEAY_VERSION_NUMBER >= 0x0922
+    ntcode(EVT_DEBUG);
     log(LOG_DEBUG, "%4d client renegotiatations requested",
         SSL_CTX_sess_connect_renegotiate(ctx));
 #endif
+    ntcode(EVT_DEBUG);
     log(LOG_DEBUG, "%4d server connects (SSL_accept())",
         SSL_CTX_sess_accept(ctx));
+    ntcode(EVT_DEBUG);
     log(LOG_DEBUG, "%4d server connects that finished",
         SSL_CTX_sess_accept_good(ctx));
 #if SSLEAY_VERSION_NUMBER >= 0x0922
+    ntcode(EVT_DEBUG);
     log(LOG_DEBUG, "%4d server renegotiatiations requested",
         SSL_CTX_sess_accept_renegotiate(ctx));
 #endif
+    ntcode(EVT_DEBUG);
     log(LOG_DEBUG, "%4d session cache hits", SSL_CTX_sess_hits(ctx));
+    ntcode(EVT_DEBUG);
     log(LOG_DEBUG, "%4d session cache misses", SSL_CTX_sess_misses(ctx));
+    ntcode(EVT_DEBUG);
     log(LOG_DEBUG, "%4d session cache timeouts", SSL_CTX_sess_timeouts(ctx));
 }
 
@@ -922,6 +981,7 @@
 #endif
 
 #if SSLEAY_VERSION_NUMBER <= 0x0800
+    ntcode(EVT_CRYPTINFO);
     log(LOG_INFO, "%s opened with SSLv%d, cipher %s",
         options.servname, ssl->session->ssl_version, SSL_get_cipher(ssl));
 #else
@@ -937,6 +997,7 @@
     }
     c=SSL_get_current_cipher(ssl);
     SSL_CIPHER_get_bits(c, &bits);
+    ntcode(EVT_CRYPTINFO);
     log(LOG_INFO, "%s opened with %s, cipher %s (%u bits)",
         options.servname, ver, SSL_CIPHER_get_name(c), bits);
 #endif
@@ -947,6 +1008,7 @@
     char string[120];
 
     ERR_error_string(ERR_get_error(), string);
+    ntcode(EVT_SSLERR);
     log(LOG_ERR, "%s: %s", txt, string);
 }
 
Index: stunnel/stevent.c
diff -u /dev/null stunnel/stevent.c:1.2
--- /dev/null	Mon Mar  5 09:55:35 2001
+++ stunnel/stevent.c	Sun Mar  4 16:37:53 2001
@@ -0,0 +1,33 @@
+/*
+ *   stunnel       Universal SSL tunnel
+ *   Copyright (c) 1998-2001 Michal Trojnara <Michal.Trojnara@mirt.net>
+ *                 All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Sanity check */
+#ifdef USE_WINNT
+
+#include <windows.h>
+
+/* This is just a stub to create a DLL for the resources */
+
+BOOL WINAPI DllMain(HINSTANCE hI, DWORD Reason, LPVOID whatever)
+{
+	return TRUE;
+}
+
+#endif
Index: stunnel/stevent.h
diff -u /dev/null stunnel/stevent.h:1.1
--- /dev/null	Mon Mar  5 09:55:35 2001
+++ stunnel/stevent.h	Sun Mar  4 16:32:36 2001
@@ -0,0 +1,250 @@
+/*
+ *   stunnel       Universal SSL tunnel
+ *   Copyright (c) 1998-2001 Michal Trojnara <Michal.Trojnara@mirt.net>
+ *                 All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ /* DO NOT EDIT THIS FILE!  It is generated from stevent.mc during
+  * compilation.
+  */
+
+//
+//  Values are 32 bit values layed out as follows:
+//
+//   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+//   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+//  +---+-+-+-----------------------+-------------------------------+
+//  |Sev|C|R|     Facility          |               Code            |
+//  +---+-+-+-----------------------+-------------------------------+
+//
+//  where
+//
+//      Sev - is the severity code
+//
+//          00 - Success
+//          01 - Informational
+//          10 - Warning
+//          11 - Error
+//
+//      C - is the Customer code flag
+//
+//      R - is a reserved bit
+//
+//      Facility - is the facility code
+//
+//      Code - is the facility's status code
+//
+//
+// Define the facility codes
+//
+
+
+//
+// Define the severity codes
+//
+
+
+//
+// MessageId: EVT_STARTUP
+//
+// MessageText:
+//
+//  STunnel is starting up.  Version: %1
+//
+#define EVT_STARTUP                      ((DWORD)0x00000001L)
+
+//
+// MessageId: EVT_SERVNAME
+//
+// MessageText:
+//
+//  %1
+//
+#define EVT_SERVNAME                     ((DWORD)0x00000002L)
+
+//
+// MessageId: EVT_BOUND
+//
+// MessageText:
+//
+//  %1
+//
+#define EVT_BOUND                        ((DWORD)0x00000003L)
+
+//
+// MessageId: EVT_CONNECTING
+//
+// MessageText:
+//
+//  Initiating connection.
+//  %1
+//
+#define EVT_CONNECTING                   ((DWORD)0x00000004L)
+
+//
+// MessageId: EVT_CERTINFO
+//
+// MessageText:
+//
+//  %1
+//
+#define EVT_CERTINFO                     ((DWORD)0x00000005L)
+
+//
+// MessageId: EVT_RMTCONNECT
+//
+// MessageText:
+//
+//  Incoming connection: %1
+//
+#define EVT_RMTCONNECT                   ((DWORD)0x00000006L)
+
+//
+// MessageId: EVT_CRYPTINFO
+//
+// MessageText:
+//
+//  A client has successfully connected.  %1
+//
+#define EVT_CRYPTINFO                    ((DWORD)0x00000007L)
+
+//
+// MessageId: EVT_CLIENTDONE
+//
+// MessageText:
+//
+//  Client disconnected.  %1
+//
+#define EVT_CLIENTDONE                   ((DWORD)0x00000008L)
+
+//
+// MessageId: EVT_DEBUG
+//
+// MessageText:
+//
+//  DEBUG: %1
+//
+#define EVT_DEBUG                        ((DWORD)0x000001F4L)
+
+//
+// MessageId: EVT_TOOMANYCLIENTS
+//
+// MessageText:
+//
+//  %1
+//
+#define EVT_TOOMANYCLIENTS               ((DWORD)0x000003E9L)
+
+//
+// MessageId: EVT_CCFAILED
+//
+// MessageText:
+//
+//  %1
+//
+#define EVT_CCFAILED                     ((DWORD)0x000003EAL)
+
+//
+// MessageId: EVT_CERTWARN
+//
+// MessageText:
+//
+//  %1
+//
+#define EVT_CERTWARN                     ((DWORD)0x000003EBL)
+
+//
+// MessageId: EVT_BADPARAM
+//
+// MessageText:
+//
+//  An option on the command-line was specified incorrectly.  %1
+//
+#define EVT_BADPARAM                     ((DWORD)0x000007D1L)
+
+//
+// MessageId: EVT_INTERNALERR
+//
+// MessageText:
+//
+//  An internal error has occurred.  %1
+//
+#define EVT_INTERNALERR                  ((DWORD)0x000007D2L)
+
+//
+// MessageId: EVT_IOERR
+//
+// MessageText:
+//
+//  An I/O error has occurred.  %1
+//
+#define EVT_IOERR                        ((DWORD)0x000007D3L)
+
+//
+// MessageId: EVT_SOCKERR
+//
+// MessageText:
+//
+//  A socket error has occurred.  %1
+//
+#define EVT_SOCKERR                      ((DWORD)0x000007D4L)
+
+//
+// MessageId: EVT_NOPROTO
+//
+// MessageText:
+//
+//  %1
+//
+#define EVT_NOPROTO                      ((DWORD)0x000007D5L)
+
+//
+// MessageId: EVT_SMTPERR
+//
+// MessageText:
+//
+//  SMTP Error: %1
+//
+#define EVT_SMTPERR                      ((DWORD)0x000007D6L)
+
+//
+// MessageId: EVT_PROTOERR
+//
+// MessageText:
+//
+//  Protocol Error: %1
+//
+#define EVT_PROTOERR                     ((DWORD)0x000007D7L)
+
+//
+// MessageId: EVT_SSLERR
+//
+// MessageText:
+//
+//  SSL Error: %1
+//
+#define EVT_SSLERR                       ((DWORD)0x000007D8L)
+
+//
+// MessageId: EVT_MISC
+//
+// MessageText:
+//
+//  %1
+//
+#define EVT_MISC                         ((DWORD)0x00002710L)
+
Index: stunnel/stevent.mc
diff -u /dev/null stunnel/stevent.mc:1.1
--- /dev/null	Mon Mar  5 09:55:35 2001
+++ stunnel/stevent.mc	Sun Mar  4 16:32:36 2001
@@ -0,0 +1,153 @@
+;/*
+; *   stunnel       Universal SSL tunnel
+; *   Copyright (c) 1998-2001 Michal Trojnara <Michal.Trojnara@mirt.net>
+; *                 All Rights Reserved
+; *
+; *   This program is free software; you can redistribute it and/or modify
+; *   it under the terms of the GNU General Public License as published by
+; *   the Free Software Foundation; either version 2 of the License, or
+; *   (at your option) any later version.
+; *
+; *   This program is distributed in the hope that it will be useful,
+; *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+; *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; *   GNU General Public License for more details.
+; *
+; *   You should have received a copy of the GNU General Public License
+; *   along with this program; if not, write to the Free Software
+; *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+; */
+;
+; /* DO NOT EDIT THIS FILE!  It is generated from stevent.mc during
+;  * compilation.
+;  */
+;
+
+MessageIdTypedef=DWORD
+
+MessageId=1
+SymbolicName=EVT_STARTUP
+Language=English
+STunnel is starting up.  Version: %1
+.
+
+MessageId=2
+SymbolicName=EVT_SERVNAME
+Language=English
+%1
+.
+
+MessageId=3
+SymbolicName=EVT_BOUND
+Language=English
+%1
+.
+
+MessageId=4
+SymbolicName=EVT_CONNECTING
+Language=English
+Initiating connection.
+%1
+.
+
+MessageId=5
+SymbolicName=EVT_CERTINFO
+Language=English
+%1
+.
+
+MessageId=6
+SymbolicName=EVT_RMTCONNECT
+Language=English
+Incoming connection: %1
+.
+
+MessageId=7
+SymbolicName=EVT_CRYPTINFO
+Language=English
+A client has successfully connected.  %1
+.
+
+MessageId=8
+SymbolicName=EVT_CLIENTDONE
+Language=English
+Client disconnected.  %1
+.
+
+MessageId=500
+SymbolicName=EVT_DEBUG
+Language=English
+DEBUG: %1
+.
+
+MessageId=1001
+SymbolicName=EVT_TOOMANYCLIENTS
+Language=English
+%1
+.
+
+MessageId=1002
+SymbolicName=EVT_CCFAILED
+Language=English
+%1
+.
+
+MessageId=1003
+SymbolicName=EVT_CERTWARN
+Language=English
+%1
+.
+
+MessageId=2001
+SymbolicName=EVT_BADPARAM
+Language=English
+An option on the command-line was specified incorrectly.  %1
+.
+
+MessageId=2002
+SymbolicName=EVT_INTERNALERR
+Language=English
+An internal error has occurred.  %1
+.
+
+MessageId=2003
+SymbolicName=EVT_IOERR
+Language=English
+An I/O error has occurred.  %1
+.
+
+MessageId=2004
+SymbolicName=EVT_SOCKERR
+Language=English
+A socket error has occurred.  %1
+.
+
+MessageId=2005
+SymbolicName=EVT_NOPROTO
+Language=English
+%1
+.
+
+MessageId=2006
+SymbolicName=EVT_SMTPERR
+Language=English
+SMTP Error: %1
+.
+
+MessageId=2007
+SymbolicName=EVT_PROTOERR
+Language=English
+Protocol Error: %1
+.
+
+MessageId=2008
+SymbolicName=EVT_SSLERR
+Language=English
+SSL Error: %1
+.
+
+MessageId=10000
+SymbolicName=EVT_MISC
+Language=English
+%1
+.
Index: stunnel/stevent.reg
diff -u /dev/null stunnel/stevent.reg:1.1
--- /dev/null	Mon Mar  5 09:55:35 2001
+++ stunnel/stevent.reg	Sun Mar  4 16:45:46 2001
@@ -0,0 +1,5 @@
+REGEDIT4
+
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\STunnel]
+"EventMessageFile"="C:\\stunnel\\stevent.dll"
+"TypesSupported"=dword:0000001f
Index: stunnel/stunnel.c
diff -u stunnel/stunnel.c:1.1.1.1 stunnel/stunnel.c:1.2
--- stunnel/stunnel.c:1.1.1.1	Sat Mar  3 14:57:11 2001
+++ stunnel/stunnel.c	Sun Mar  4 16:32:36 2001
@@ -57,6 +57,9 @@
 #define Win32_Winsock
 #include <windows.h>
 
+#ifdef USE_WINNT
+#include "stevent.h"
+#endif
 
 static struct WSAData wsa_state;
 
@@ -99,6 +102,10 @@
 
 #endif /* defined USE_WIN32 */
 
+#ifdef USE_WINNT
+static int svcop = 0;	/* NT service operation */
+#endif
+
     /* Prototypes */
 static void get_options(int, char *[]);
 static void daemon_loop();
@@ -140,7 +147,9 @@
     /* Functions */
 int main(int argc, char* argv[])
 { /* execution begins here 8-) */
+#ifndef USE_WINNT
     struct stat st; /* buffer for stat */
+#endif
 
 #ifdef USE_WIN32
     if(WSAStartup(0x0101, &wsa_state)!=0) {
@@ -165,10 +174,42 @@
     safeconcat(options.pem, "stunnel.pem");
 
     get_options(argc, argv);
+#ifdef USE_WINNT
+    switch(svcop)	/* See if we need to add/delete service */
+    {
+	case 1:
+	    addntservice(argc, argv);
+	    exit(0);
+	    break;
+	case 2:
+	    removentservice();
+	    exit(0);
+	    break;
+    }
+#endif
+
+#ifdef USE_WINNT
+/* This is hack to work with NT services, which need a funciton to call when
+ * started, but it has to be split off after parsing the command line arguments
+ * so that the program will know if it needs to run as a service or not...
+ */
+
+    if (options.option & OPT_NTSVC)
+	runntservice();
+
+    return realmain();
+}
+
+int realmain()
+{
+    struct stat st; /* buffer for stat */
+#endif
+
     if(!(options.option&OPT_FOREGROUND)) {
         options.foreground=0;
         log_open();
     }
+    ntcode(EVT_SERVNAME);
     log(LOG_NOTICE, "Using '%s' as tcpwrapper service name", options.servname);
 
     /* check if certificate exists */
@@ -186,6 +227,7 @@
     /* check if started from inetd */
     context_init(); /* initialize global SSL context */
     sthreads_init(); /* initialize threads */
+    ntcode(EVT_STARTUP);
     log(LOG_NOTICE, STUNNEL_INFO);
     if (options.option & OPT_DAEMON) {
         /* client or server, daemon mode */
@@ -242,8 +284,11 @@
     options.rand_file=NULL;
     options.rand_write=1;
     options.random_bytes=RANDOM_BYTES;
+#ifdef USE_WINNT
+    options.ntsvcname="STunnel Service";
+#endif
     opterr=0;
-    while ((c = getopt(argc, argv, "A:a:cp:v:d:fTl:L:r:s:g:t:u:n:N:hC:D:E:R:WB:VP:S:")) != EOF)
+    while ((c = getopt(argc, argv, "A:a:cp:v:d:fTl:L:r:s:g:t:u:n:N:hC:D:E:R:WB:VP:S:IZjM:")) != EOF)
         switch (c) {
 	    case 'A':
 	    	safecopy(options.cert_file,optarg);
@@ -255,6 +300,7 @@
 		options.cert_defaults = atoi(optarg);
 		if ( options.cert_defaults < 0 ||
 		     options.cert_defaults > 3 ) {
+		     ntcode(EVT_BADPARAM);
 		     log(LOG_ERR, "Bad -S value '%d'", options.cert_defaults);
 		     print_help();
 		}
@@ -278,12 +324,14 @@
                         /* SSL_VERIFY_PEER */
                     break;
                 default:
+                    ntcode(EVT_BADPARAM);
                     log(LOG_ERR, "Bad verify level");
                     print_help();
                 }
                 break;
              case 'd':
                 if(options.option&OPT_DAEMON) {
+                    ntcode(EVT_BADPARAM);
                     log(LOG_ERR, "Multiple daemons not allowed");
                     print_help();
                 }
@@ -314,6 +362,7 @@
 #if SSLEAY_VERSION_NUMBER >= 0x0090581fL
 	    	options.egd_sock=optarg;
 #else
+		ntcode(EVT_BADPARAM);
 		log(LOG_ERR, "-E is only supported when compiled with OpenSSL 0.9.5a or later");
 		/* exit(1) ??? */
 #endif
@@ -352,6 +401,7 @@
                 break;
             case 't':
                 if(!(options.session_timeout=atoi(optarg))) {
+                    ntcode(EVT_BADPARAM);
                     log(LOG_ERR, "Illegal session timeout: %s", optarg);
                     print_help();
                 }
@@ -370,6 +420,7 @@
                 break;
             case 'D':
 	    	if ( ! parse_debug_level(optarg) ) {
+                    ntcode(EVT_BADPARAM);
                     log(LOG_ERR, "Illegal debug argument: %s", optarg);
                     fprintf(stderr, "Illegal debug argument: %s\n", optarg);
                     print_help();
@@ -381,32 +432,73 @@
 	    case 'P':
 	    	options.pid_dir=optarg;
 		break;
+#ifdef USE_WINNT
+	    case 'M':
+		options.ntsvcname = optarg;
+		break;
+	    case 'I':
+		svcop = 1;
+		break;
+	    case 'Z':
+		svcop = 2;
+		break;
+	    case 'j':
+		options.option |= OPT_NTSVC;
+		break;
+#else
+	    case 'I':
+	    case 'Z':
+	    case 'M':
+		log(LOG_ERR, "The -I, -M and -Z options can only be used when stunnel is "
+			"compiled for Windows NT\n");
+		break;
+	    case 'j':
+		log(LOG_ERR, "-j only works in the NT version.  You shouldn't be using "
+			"it anyway...\n");
+		print_help();	/* Serves 'em right! */
+		break;
+#endif
+
             case '?':
+                ntcode(EVT_BADPARAM);
                 log(LOG_ERR, "Illegal option: '%c'", optopt);
             case 'h':
                 print_help();
             default:
+                ntcode(EVT_BADPARAM);
                 log(LOG_ERR, "INTERNAL ERROR: Illegal option: '%c'", c);
                 print_help();
         }
 #ifdef USE_WIN32
+#ifdef USE_WINNT
+    if (svcop == 2)
+	return;		/* don't need to do param checking for deleting service */
+    if (!(options.option & OPT_NTSVC))
+	options.option|=OPT_FOREGROUND;	/* run foreground in NT if not service */
+#else
+    options.option|=OPT_FOREGROUND;	/* always run foreground in Windows */
+#endif
     if (! (options.option & OPT_DAEMON) ) {
+    	ntcode(EVT_BADPARAM);
     	log(LOG_ERR, "You must use daemon mode (-d) in Windows.");
 	print_help();
     }
 #endif
     if (options.option & OPT_CLIENT) {
         if (!(options.option & OPT_REMOTE)) {
+            ntcode(EVT_BADPARAM);
             log(LOG_ERR, "Remote service must be specified");
             print_help();
         }
         if (options.option & OPT_TRANSPARENT) {
+            ntcode(EVT_BADPARAM);
             log(LOG_ERR,
                 "Client mode not available in transparent proxy mode");
             print_help();
         }
         if ((options.option & OPT_PROGRAM) &&
             (options.option & OPT_DAEMON)) {
+            ntcode(EVT_BADPARAM);
             log(LOG_ERR,
                 "Only one of program or daemon mode can be specified");
             print_help();
@@ -414,10 +506,12 @@
     } else {
         options.option |= OPT_CERT; /* Server always needs a certificate */
         if (!(options.option & (OPT_PROGRAM | OPT_REMOTE))) {
+            ntcode(EVT_BADPARAM);
             log(LOG_ERR, "Either program or remote service must be specified");
             print_help();
         }
         if ((options.option & OPT_PROGRAM) && (options.option & OPT_REMOTE)) {
+            ntcode(EVT_BADPARAM);
             log(LOG_ERR, "Only one of program or remote service can be specified");
             print_help();
         }
@@ -462,6 +556,7 @@
         }
         if(options.clients<MAX_CLIENTS) {
             if(create_client(ls, s, client)) {
+                ntcode(EVT_CCFAILED);
                 log(LOG_WARNING,
                     "%s create_client failed - connection from %s:%d REJECTED",
                     options.servname,
@@ -473,6 +568,7 @@
                 leave_critical_section(2);
             }
         } else {
+            ntcode(EVT_TOOMANYCLIENTS);
             log(LOG_WARNING,
                 "%s has too many clients - connection from %s:%d REJECTED",
                 options.servname, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
@@ -607,6 +703,7 @@
         sockerror("bind");
         exit(1);
     }
+    ntcode(EVT_BOUND);
     log(LOG_DEBUG, "%s bound to %s:%d", options.servname,
         inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
     if(listen(ls, 5)) {
@@ -664,6 +761,7 @@
 int connect_local(u32 ip) /* spawn local process */
 {
 #ifdef USE_WIN32
+    ntcode(EVT_BADPARAM);
     log(LOG_ERR, "LOCAL MODE NOT SUPPORTED ON WIN32 PLATFORM");
     return -1;
 #else
@@ -745,6 +843,7 @@
     /* connect each host from the list*/
     for(list=options.remotenames; *list!=-1; list++) {
         addr.sin_addr.s_addr=*list;
+	ntcode(EVT_CONNECTING);
         log(LOG_DEBUG, "%s connecting %s:%d", options.servname,
             inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
         if(!connect(s, (struct sockaddr *) &addr, sizeof(addr)))
@@ -806,7 +905,7 @@
     closesocket(s);
     buff[ptr]='\0';
     if(sscanf(buff, "%*[^:]: USERID :%*[^:]:%s", name)!=1) {
-        log(LOG_ERR, "Incorrect data from inetd server");
+        log(LOG_ERR, "Incorrect data from identd server");
         return -1;
     }
     log(LOG_INFO, "IDENT resolved remote user to %s", name);
@@ -891,6 +990,7 @@
     else
         port=htons(atoi(portname));
     if(!port) {
+        ntcode(EVT_INTERNALERR);
         log(LOG_ERR, "Invalid port: %s", portname);
         exit(2);
     }
@@ -929,6 +1029,7 @@
     int error;
 
     error=get_last_error();
+    ntcode(EVT_IOERR);
     log(LOG_ERR, "%s: %s (%d)", txt, strerror(error), error);
 }
 
@@ -937,6 +1038,7 @@
     int error;
 
     error=get_last_socket_error();
+    ntcode(EVT_SOCKERR);
     log(LOG_ERR, "%s: %s (%d)", txt, strerror(error), error);
 }
 
@@ -1022,6 +1124,7 @@
         free(*ptr);
     *ptr=malloc((len+1)*sizeof(u32));
     if (!*ptr) {
+        ntcode(EVT_INTERNALERR);
         log(LOG_ERR, "Fatal memory allocation error");
         exit(2);
     }
@@ -1055,6 +1158,9 @@
 #ifndef USE_WIN32
     fprintf(stderr, "\t-P pid dir\t%s\n", options.pid_dir);
 #endif
+#ifdef USE_WINNT
+    fprintf(stderr, "\t-M svcname\t%s\n", options.ntsvcname);
+#endif
     fprintf(stderr, "\t-p pemfile\t"
         "in server mode: %s\n"
         "\t\t\tin client mode: none\n", options.pem);
@@ -1089,6 +1195,10 @@
 	"[-E egdsock] "
 #endif
 	"[-B bytes] "
+#ifdef USE_WINNT
+	"[ -M svcname ] "
+	"[ -I | -Z ] "
+#endif
 
 #ifndef USE_WIN32
 	"[-P { dir/ | filename | none } ] "
@@ -1098,7 +1208,6 @@
 	"\n\t-d [host:]port -r [host:]port"
 #endif
 
-
 	/* Argument notes */
 
 	"\n\n  -h\t\tprint this help screen"
@@ -1155,6 +1264,11 @@
 #endif
 	"\n  -W\t\tDo not overwrite random seed datafiles with new random data"
         "\n  -D [fac.]lev\tdebug level (e.g. daemon.info)"
+#ifdef USE_WINNT
+	"\n  -M name\tSets the service name to use for NT services"
+	"\n  -I\t\tInstall as NT service (Use -M to set the service name)"
+	"\n  -Z\t\tRemoves a previously installed NT service"
+#endif
 	"\n"
 	"\nSee stunnel -V output for default values\n"
 	"\n");
Index: stunnel/stunnelvc6.mak
diff -u /dev/null stunnel/stunnelvc6.mak:1.1
--- /dev/null	Mon Mar  5 09:55:35 2001
+++ stunnel/stunnelvc6.mak	Sun Mar  4 16:32:36 2001
@@ -0,0 +1,79 @@
+# Makefile for compiling stunnel under MSVC 6.0
+# Created by Craig Boston 5/3/01
+#
+# NOTE: This makefile assumes that you are using OpenSSL installed
+# "unix-style".  i.e. the dlls have been placed in the system directory,
+# the import libraries have been copied to the compiler default location
+# (usually Program Files\Microsoft Visual Studio\VC98\Lib), and the
+# include files are in VC98\Include\openssl.
+#
+# If this is not the case, modify the variables below and add the
+# appropriate include and library paths.  As usual, the OpenSSL dlls
+# need to be somewhere in your path at execution time.
+
+VERSION=stunnel-3.14
+STBASE=stunnel
+CFLAGS=/MD /W3 /Od
+LDFLAGS=/machine:I386 /incremental:yes
+#USENT=/D "USE_WINNT"
+#EXTRA_INCLUDE=/I "C:\openssl\include"
+#EXTRA_LIB=/LIBPATH:"C:\openssl\lib"
+
+CC=cl.exe
+LINK=link.exe
+RC=rc.exe
+MC=mc.exe
+CC_DEFAULTS=/nologo /c /D "USE_WIN32" /D "WIN32" /D "NDEBUG" \
+	/D "_CONSOLE" /D "HAVE_OPENSSL" /D "_MBCS" $(USENT)
+LD_DEFAULTS=/nologo /subsystem:console \
+	wsock32.lib ssleay32.lib libeay32.lib advapi32.lib
+
+STOFILES=log.obj protocol.obj ssl.obj sthreads.obj stunnel.obj
+!IFDEF USENT
+STOFILES=$(STOFILES) ntservice.obj
+!ENDIF
+
+EVOFILES=stevent.obj
+EVBASE=stevent
+
+ALLTARGETS=$(STBASE).exe
+!IFDEF USENT
+ALLTARGETS=$(ALLTARGETS) stevent.dll
+!ENDIF
+
+ALL: $(ALLTARGETS)
+
+CLEAN:
+	-@erase $(STBASE).exe $(STBASE).ilk
+	-@erase $(STOFILES)
+	-@erase $(EVBASE).dll $(EVBASE).dll $(EVBASE).ilk \
+		$(EVBASE).res $(EVBASE).rc *.bin
+	-@erase $(EVOFILES)
+
+.c.obj:
+	$(CC) $< $(CC_DEFAULTS) $(CFLAGS) $(EXTRA_INCLUDE)
+
+$(STBASE).exe: $(STOFILES)
+	$(LINK) $(LD_DEFAULTS) $(LDFLAGS) $(EXTRA_LIB) \
+	$(STOFILES) /out:$@
+
+$(EVBASE).res: $(EVBASE).rc $(EVBASE).h
+	$(RC) $(EVBASE).rc
+
+$(EVBASE).rc $(EVBASE).h: $(EVBASE).mc
+	$(MC) $(EVBASE).mc
+
+$(EVBASE).dll: $(EVBASE).res $(EVOFILES)
+	$(LINK) /dll $(LD_DEFAULT) $(LDFLAGS) $(EVOFILES) \
+	$(EVBASE).res /out:$@
+
+!IFDEF USENT
+EVINCLUDE=$(EVBASE).h
+!ENDIF
+
+log.c: common.h
+protocol.c: common.h $(EVINCLUDE)
+ssl.c: common.h $(EVINCLUDE)
+sthreads.c: common.h
+stunnel.c: common.h $(EVINCLUDE)
+ntservice.c: common.h $(EVINCLUDE)
