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 + * + */ + #include "common.h" #include #include @@ -25,14 +29,27 @@ extern server_options options; +#ifdef USE_WINNT +#include /* 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 + * 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 + * + */ + +/* Sanity check */ +#ifdef USE_WINNT + +#include +#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 +#ifdef USE_WINNT +#include "stevent.h" #endif +#else /* Use standard sockets */ +#include /* for read(), write() */ +#include /* for select() */ +#endif #include #include /* for va_* */ -#include /* for read(), write() */ #include -#include /* for select() */ #include /* 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 + * 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 + +/* 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 + * 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 +; * 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 +#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