summaryrefslogtreecommitdiff
path: root/src/openvpn/service-win32
diff options
context:
space:
mode:
authorOthmar Gsenger <otti@anytun.org>2008-04-12 11:38:42 +0000
committerOthmar Gsenger <otti@anytun.org>2008-04-12 11:38:42 +0000
commitfffd213c8cba2135afda493d797c41c10354770e (patch)
treebb5eea1b12871d8c3fed0e687d83be3e504d11b2 /src/openvpn/service-win32
parentsvn cleanup (diff)
big svn cleanup
Diffstat (limited to 'src/openvpn/service-win32')
-rwxr-xr-xsrc/openvpn/service-win32/Makefile25
-rwxr-xr-xsrc/openvpn/service-win32/mkpatch4
-rwxr-xr-xsrc/openvpn/service-win32/openvpnserv.c513
-rwxr-xr-xsrc/openvpn/service-win32/service.patch353
4 files changed, 895 insertions, 0 deletions
diff --git a/src/openvpn/service-win32/Makefile b/src/openvpn/service-win32/Makefile
new file mode 100755
index 0000000..027b6dd
--- /dev/null
+++ b/src/openvpn/service-win32/Makefile
@@ -0,0 +1,25 @@
+# This makefile builds the OpenVPN win32 service
+# wrapper using the mingw environment.
+#
+# service.c and service.h should be generated by
+# applying service.patch to the Platform
+# SDK service sample.
+
+EXE = openvpnserv.exe
+
+HEADERS = service.h
+
+OBJS = openvpnserv.o service.o
+
+INCLUDE_DIRS =
+
+CC = gcc -g -O2 -Wall -Wno-unused-function -Wno-unused-variable -mno-cygwin
+
+all : ${OBJS}
+ ${CC} -o ${EXE} ${OBJS}
+
+clean :
+ rm -f ${OBJS} ${EXE}
+
+%.o : %.c ${HEADERS}
+ ${CC} ${INCLUDE_DIRS} -c $< -o $@
diff --git a/src/openvpn/service-win32/mkpatch b/src/openvpn/service-win32/mkpatch
new file mode 100755
index 0000000..5e65b94
--- /dev/null
+++ b/src/openvpn/service-win32/mkpatch
@@ -0,0 +1,4 @@
+# build service.[ch] patch against original
+# SDK sample
+diff -ub service.c.orig service.c >service.patch
+diff -ub service.h.orig service.h >>service.patch
diff --git a/src/openvpn/service-win32/openvpnserv.c b/src/openvpn/service-win32/openvpnserv.c
new file mode 100755
index 0000000..0a64a67
--- /dev/null
+++ b/src/openvpn/service-win32/openvpnserv.c
@@ -0,0 +1,513 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single TCP/UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * 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 (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * This program allows one or more OpenVPN processes to be started
+ * as a service. To build, you must get the service sample from the
+ * Platform SDK and replace Simple.c with this file.
+ *
+ * You should also apply service.patch to
+ * service.c and service.h from the Platform SDK service sample.
+ *
+ * This code is designed to be built with the mingw compiler.
+ */
+
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <process.h>
+#include "service.h"
+
+/* bool definitions */
+#define bool int
+#define true 1
+#define false 0
+
+/* These are new for 2000/XP, so they aren't in the mingw headers yet */
+#ifndef BELOW_NORMAL_PRIORITY_CLASS
+#define BELOW_NORMAL_PRIORITY_CLASS 0x00004000
+#endif
+#ifndef ABOVE_NORMAL_PRIORITY_CLASS
+#define ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
+#endif
+
+struct security_attributes
+{
+ SECURITY_ATTRIBUTES sa;
+ SECURITY_DESCRIPTOR sd;
+};
+
+/*
+ * This event is initially created in the non-signaled
+ * state. It will transition to the signaled state when
+ * we have received a terminate signal from the Service
+ * Control Manager which will cause an asynchronous call
+ * of ServiceStop below.
+ */
+#define EXIT_EVENT_NAME "openvpn_exit_1"
+
+/*
+ * Which registry key in HKLM should
+ * we get config info from?
+ */
+#define REG_KEY "SOFTWARE\\OpenVPN"
+
+static HANDLE exit_event = NULL;
+
+/* clear an object */
+#define CLEAR(x) memset(&(x), 0, sizeof(x))
+
+/* snprintf with guaranteed null termination */
+#define mysnprintf(out, args...) \
+ { \
+ snprintf (out, sizeof(out), args); \
+ out [sizeof (out) - 1] = '\0'; \
+ }
+
+/*
+ * Message handling
+ */
+#define M_INFO (0) // informational
+#define M_SYSERR (MSG_FLAGS_ERROR|MSG_FLAGS_SYS_CODE) // error + system code
+#define M_ERR (MSG_FLAGS_ERROR) // error
+
+/* write error to event log */
+#define MSG(flags, args...) \
+ { \
+ char x_msg[256]; \
+ mysnprintf (x_msg, args); \
+ AddToMessageLog ((flags), x_msg); \
+ }
+
+/* get a registry string */
+#define QUERY_REG_STRING(name, data) \
+ { \
+ len = sizeof (data); \
+ status = RegQueryValueEx(openvpn_key, name, NULL, &type, data, &len); \
+ if (status != ERROR_SUCCESS || type != REG_SZ) \
+ { \
+ SetLastError (status); \
+ MSG (M_SYSERR, error_format_str, name); \
+ RegCloseKey (openvpn_key); \
+ goto finish; \
+ } \
+ }
+
+/* get a registry string */
+#define QUERY_REG_DWORD(name, data) \
+ { \
+ len = sizeof (DWORD); \
+ status = RegQueryValueEx(openvpn_key, name, NULL, &type, (LPBYTE)&data, &len); \
+ if (status != ERROR_SUCCESS || type != REG_DWORD || len != sizeof (DWORD)) \
+ { \
+ SetLastError (status); \
+ MSG (M_SYSERR, error_format_dword, name); \
+ RegCloseKey (openvpn_key); \
+ goto finish; \
+ } \
+ }
+
+bool
+init_security_attributes_allow_all (struct security_attributes *obj)
+{
+ CLEAR (*obj);
+
+ obj->sa.nLength = sizeof (SECURITY_ATTRIBUTES);
+ obj->sa.lpSecurityDescriptor = &obj->sd;
+ obj->sa.bInheritHandle = TRUE;
+ if (!InitializeSecurityDescriptor (&obj->sd, SECURITY_DESCRIPTOR_REVISION))
+ return false;
+ if (!SetSecurityDescriptorDacl (&obj->sd, TRUE, NULL, FALSE))
+ return false;
+ return true;
+}
+
+HANDLE
+create_event (const char *name, bool allow_all, bool initial_state, bool manual_reset)
+{
+ if (allow_all)
+ {
+ struct security_attributes sa;
+ if (!init_security_attributes_allow_all (&sa))
+ return NULL;
+ return CreateEvent (&sa.sa, (BOOL)manual_reset, (BOOL)initial_state, name);
+ }
+ else
+ return CreateEvent (NULL, (BOOL)manual_reset, (BOOL)initial_state, name);
+}
+
+void
+close_if_open (HANDLE h)
+{
+ if (h != NULL)
+ CloseHandle (h);
+}
+
+static bool
+match (const WIN32_FIND_DATA *find, const char *ext)
+{
+ int i;
+
+ if (find->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ return false;
+
+ if (!strlen (ext))
+ return true;
+
+ i = strlen (find->cFileName) - strlen (ext) - 1;
+ if (i < 1)
+ return false;
+
+ return find->cFileName[i] == '.' && !strcasecmp (find->cFileName + i + 1, ext);
+}
+
+/*
+ * Modify the extension on a filename.
+ */
+static bool
+modext (char *dest, int size, const char *src, const char *newext)
+{
+ int i;
+
+ if (size > 0 && (strlen (src) + 1) <= size)
+ {
+ strcpy (dest, src);
+ dest [size - 1] = '\0';
+ i = strlen (dest);
+ while (--i >= 0)
+ {
+ if (dest[i] == '\\')
+ break;
+ if (dest[i] == '.')
+ {
+ dest[i] = '\0';
+ break;
+ }
+ }
+ if (strlen (dest) + strlen(newext) + 2 <= size)
+ {
+ strcat (dest, ".");
+ strcat (dest, newext);
+ return true;
+ }
+ dest [0] = '\0';
+ }
+ return false;
+}
+
+VOID ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv)
+{
+ char exe_path[MAX_PATH];
+ char config_dir[MAX_PATH];
+ char ext_string[16];
+ char log_dir[MAX_PATH];
+ char priority_string[64];
+ char append_string[2];
+
+ DWORD priority;
+ bool append;
+
+ ResetError ();
+
+ if (!ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000))
+ {
+ MSG (M_ERR, "ReportStatusToSCMgr #1 failed");
+ goto finish;
+ }
+
+ /*
+ * Create our exit event
+ */
+ exit_event = create_event (EXIT_EVENT_NAME, false, false, true);
+ if (!exit_event)
+ {
+ MSG (M_ERR, "CreateEvent failed");
+ goto finish;
+ }
+
+ /*
+ * If exit event is already signaled, it means we were not
+ * shut down properly.
+ */
+ if (WaitForSingleObject (exit_event, 0) != WAIT_TIMEOUT)
+ {
+ MSG (M_ERR, "Exit event is already signaled -- we were not shut down properly");
+ goto finish;
+ }
+
+ if (!ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000))
+ {
+ MSG (M_ERR, "ReportStatusToSCMgr #2 failed");
+ goto finish;
+ }
+
+ /*
+ * Read info from registry in key HKLM\SOFTWARE\OpenVPN
+ */
+ {
+ HKEY openvpn_key;
+ LONG status;
+ DWORD len;
+ DWORD type;
+ char error_string[256];
+
+ static const char error_format_str[] =
+ "Error querying registry key of type REG_SZ: HKLM\\" REG_KEY "\\%s";
+
+ static const char error_format_dword[] =
+ "Error querying registry key of type REG_DWORD: HKLM\\" REG_KEY "\\%s";
+
+ status = RegOpenKeyEx(
+ HKEY_LOCAL_MACHINE,
+ REG_KEY,
+ 0,
+ KEY_READ,
+ &openvpn_key);
+
+ if (status != ERROR_SUCCESS)
+ {
+ SetLastError (status);
+ MSG (M_SYSERR, "Registry key HKLM\\" REG_KEY " not found");
+ goto finish;
+ }
+
+ /* get path to openvpn.exe */
+ QUERY_REG_STRING ("exe_path", exe_path);
+
+ /* get path to configuration directory */
+ QUERY_REG_STRING ("config_dir", config_dir);
+
+ /* get extension on configuration files */
+ QUERY_REG_STRING ("config_ext", ext_string);
+
+ /* get path to log directory */
+ QUERY_REG_STRING ("log_dir", log_dir);
+
+ /* get priority for spawned OpenVPN subprocesses */
+ QUERY_REG_STRING ("priority", priority_string);
+
+ /* should we truncate or append to logfile? */
+ QUERY_REG_STRING ("log_append", append_string);
+
+ RegCloseKey (openvpn_key);
+ }
+
+ /* set process priority */
+ priority = NORMAL_PRIORITY_CLASS;
+ if (!strcasecmp (priority_string, "IDLE_PRIORITY_CLASS"))
+ priority = IDLE_PRIORITY_CLASS;
+ else if (!strcasecmp (priority_string, "BELOW_NORMAL_PRIORITY_CLASS"))
+ priority = BELOW_NORMAL_PRIORITY_CLASS;
+ else if (!strcasecmp (priority_string, "NORMAL_PRIORITY_CLASS"))
+ priority = NORMAL_PRIORITY_CLASS;
+ else if (!strcasecmp (priority_string, "ABOVE_NORMAL_PRIORITY_CLASS"))
+ priority = ABOVE_NORMAL_PRIORITY_CLASS;
+ else if (!strcasecmp (priority_string, "HIGH_PRIORITY_CLASS"))
+ priority = HIGH_PRIORITY_CLASS;
+ else
+ {
+ MSG (M_ERR, "Unknown priority name: %s", priority_string);
+ goto finish;
+ }
+
+ /* set log file append/truncate flag */
+ append = false;
+ if (append_string[0] == '0')
+ append = false;
+ else if (append_string[0] == '1')
+ append = true;
+ else
+ {
+ MSG (M_ERR, "Log file append flag (given as '%s') must be '0' or '1'", append_string);
+ goto finish;
+ }
+
+ /*
+ * Instantiate an OpenVPN process for each configuration
+ * file found.
+ */
+ {
+ WIN32_FIND_DATA find_obj;
+ HANDLE find_handle;
+ BOOL more_files;
+ char find_string[MAX_PATH];
+
+ mysnprintf (find_string, "%s\\*", config_dir);
+
+ find_handle = FindFirstFile (find_string, &find_obj);
+ if (find_handle == INVALID_HANDLE_VALUE)
+ {
+ MSG (M_ERR, "Cannot get configuration file list using: %s", find_string);
+ goto finish;
+ }
+
+ /*
+ * Loop over each config file
+ */
+ do {
+ HANDLE log_handle = NULL;
+ STARTUPINFO start_info;
+ PROCESS_INFORMATION proc_info;
+ struct security_attributes sa;
+ char log_file[MAX_PATH];
+ char log_path[MAX_PATH];
+ char command_line[256];
+
+ CLEAR (start_info);
+ CLEAR (proc_info);
+ CLEAR (sa);
+
+ if (!ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000))
+ {
+ MSG (M_ERR, "ReportStatusToSCMgr #3 failed");
+ FindClose (find_handle);
+ goto finish;
+ }
+
+ /* does file have the correct type and extension? */
+ if (match (&find_obj, ext_string))
+ {
+ /* get log file pathname */
+ if (!modext (log_file, sizeof (log_file), find_obj.cFileName, "log"))
+ {
+ MSG (M_ERR, "Cannot construct logfile name based on: %s", find_obj.cFileName);
+ FindClose (find_handle);
+ goto finish;
+ }
+ mysnprintf (log_path, "%s\\%s", log_dir, log_file);
+
+ /* construct command line */
+ mysnprintf (command_line, "openvpn --service %s 1 --config \"%s\"",
+ EXIT_EVENT_NAME,
+ find_obj.cFileName);
+
+ /* Make security attributes struct for logfile handle so it can
+ be inherited. */
+ if (!init_security_attributes_allow_all (&sa))
+ {
+ MSG (M_SYSERR, "InitializeSecurityDescriptor start_openvpn failed");
+ goto finish;
+ }
+
+ /* open logfile as stdout/stderr for soon-to-be-spawned subprocess */
+ log_handle = CreateFile (log_path,
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ &sa.sa,
+ append ? OPEN_ALWAYS : CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (log_handle == INVALID_HANDLE_VALUE)
+ {
+ MSG (M_SYSERR, "Cannot open logfile: %s", log_path);
+ FindClose (find_handle);
+ goto finish;
+ }
+
+ /* append to logfile? */
+ if (append)
+ {
+ if (SetFilePointer (log_handle, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
+ {
+ MSG (M_SYSERR, "Cannot seek to end of logfile: %s", log_path);
+ FindClose (find_handle);
+ goto finish;
+ }
+ }
+
+ /* fill in STARTUPINFO struct */
+ GetStartupInfo(&start_info);
+ start_info.cb = sizeof(start_info);
+ start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
+ start_info.wShowWindow = SW_HIDE;
+ start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ start_info.hStdOutput = start_info.hStdError = log_handle;
+
+ /* create an OpenVPN process for one config file */
+ if (!CreateProcess(exe_path,
+ command_line,
+ NULL,
+ NULL,
+ TRUE,
+ priority | CREATE_NEW_CONSOLE,
+ NULL,
+ config_dir,
+ &start_info,
+ &proc_info))
+ {
+ MSG (M_SYSERR, "CreateProcess failed, exe='%s' cmdline='%s' dir='%s'",
+ exe_path,
+ command_line,
+ config_dir);
+
+ FindClose (find_handle);
+ CloseHandle (log_handle);
+ goto finish;
+ }
+
+ /* close unneeded handles */
+ Sleep (1000); /* try to prevent race if we close logfile
+ handle before child process DUPs it */
+ if (!CloseHandle (proc_info.hProcess)
+ || !CloseHandle (proc_info.hThread)
+ || !CloseHandle (log_handle))
+ {
+ MSG (M_SYSERR, "CloseHandle failed");
+ goto finish;
+ }
+ }
+
+ /* more files to process? */
+ more_files = FindNextFile (find_handle, &find_obj);
+
+ } while (more_files);
+
+ FindClose (find_handle);
+ }
+
+ /* we are now fully started */
+ if (!ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0))
+ {
+ MSG (M_ERR, "ReportStatusToSCMgr SERVICE_RUNNING failed");
+ goto finish;
+ }
+
+ /* wait for our shutdown signal */
+ if (WaitForSingleObject (exit_event, INFINITE) != WAIT_OBJECT_0)
+ {
+ MSG (M_ERR, "wait for shutdown signal failed");
+ }
+
+ finish:
+ ServiceStop ();
+ if (exit_event)
+ CloseHandle (exit_event);
+}
+
+VOID ServiceStop()
+{
+ if (exit_event)
+ SetEvent(exit_event);
+}
diff --git a/src/openvpn/service-win32/service.patch b/src/openvpn/service-win32/service.patch
new file mode 100755
index 0000000..9edefd7
--- /dev/null
+++ b/src/openvpn/service-win32/service.patch
@@ -0,0 +1,353 @@
+--- service.c.orig Mon Jan 30 10:24:07 2006
++++ service.c Mon Jan 30 10:26:22 2006
+@@ -16,6 +16,7 @@
+ service_main(DWORD dwArgc, LPTSTR *lpszArgv);
+ CmdInstallService();
+ CmdRemoveService();
++ CmdStartService();
+ CmdDebugService(int argc, char **argv);
+ ControlHandler ( DWORD dwCtrlType );
+ GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );
+@@ -40,8 +41,9 @@
+ // internal function prototypes
+ VOID WINAPI service_ctrl(DWORD dwCtrlCode);
+ VOID WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv);
+-VOID CmdInstallService();
+-VOID CmdRemoveService();
++int CmdInstallService();
++int CmdRemoveService();
++int CmdStartService();
+ VOID CmdDebugService(int argc, char **argv);
+ BOOL WINAPI ControlHandler ( DWORD dwCtrlType );
+ LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );
+@@ -64,7 +66,7 @@
+ // main service thread. When the this call returns,
+ // the service has stopped, so exit.
+ //
+-void __cdecl main(int argc, char **argv)
++int __cdecl main(int argc, char **argv)
+ {
+ SERVICE_TABLE_ENTRY dispatchTable[] =
+ {
+@@ -77,11 +79,15 @@
+ {
+ if ( _stricmp( "install", argv[1]+1 ) == 0 )
+ {
+- CmdInstallService();
++ return CmdInstallService();
+ }
+ else if ( _stricmp( "remove", argv[1]+1 ) == 0 )
+ {
+- CmdRemoveService();
++ return CmdRemoveService();
++ }
++ else if ( _stricmp( "start", argv[1]+1 ) == 0)
++ {
++ return CmdStartService();
+ }
+ else if ( _stricmp( "debug", argv[1]+1 ) == 0 )
+ {
+@@ -92,7 +98,7 @@
+ {
+ goto dispatch;
+ }
+- exit(0);
++ return 0;
+ }
+
+ // if it doesn't match any of the above parameters
+@@ -101,13 +107,16 @@
+ dispatch:
+ // this is just to be friendly
+ printf( "%s -install to install the service\n", SZAPPNAME );
++ printf( "%s -start to start the service\n", SZAPPNAME );
+ printf( "%s -remove to remove the service\n", SZAPPNAME );
+ printf( "%s -debug <params> to run as a console app for debugging\n", SZAPPNAME );
+ printf( "\nStartServiceCtrlDispatcher being called.\n" );
+ printf( "This may take several seconds. Please wait.\n" );
+
+ if (!StartServiceCtrlDispatcher(dispatchTable))
+- AddToMessageLog(TEXT("StartServiceCtrlDispatcher failed."));
++ AddToMessageLog(MSG_FLAGS_ERROR, TEXT("StartServiceCtrlDispatcher failed."));
++
++ return 0;
+ }
+
+
+@@ -267,7 +276,7 @@
+ //
+ if (!(fResult = SetServiceStatus( sshStatusHandle, &ssStatus)))
+ {
+- AddToMessageLog(TEXT("SetServiceStatus"));
++ AddToMessageLog(MSG_FLAGS_ERROR, TEXT("SetServiceStatus"));
+ }
+ }
+ return fResult;
+@@ -288,28 +297,33 @@
+ //
+ // COMMENTS:
+ //
+-VOID AddToMessageLog(LPTSTR lpszMsg)
++void AddToMessageLog(DWORD flags, LPTSTR lpszMsg)
+ {
+ TCHAR szMsg [(sizeof(SZSERVICENAME) / sizeof(TCHAR)) + 100 ];
+ HANDLE hEventSource;
+- LPTSTR lpszStrings[2];
++ LPCSTR lpszStrings[2];
+
+ if ( !bDebug )
+ {
++ if (flags & MSG_FLAGS_SYS_CODE)
+ dwErr = GetLastError();
++ else
++ dwErr = 0;
+
+ // Use event logging to log the error.
+ //
+ hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME));
+
+- _stprintf(szMsg, TEXT("%s error: %d"), TEXT(SZSERVICENAME), dwErr);
++ _stprintf(szMsg, TEXT("%s error: %d"), TEXT(SZSERVICENAME), (int)dwErr);
+ lpszStrings[0] = szMsg;
+ lpszStrings[1] = lpszMsg;
+
+ if (hEventSource != NULL)
+ {
+ ReportEvent(hEventSource, // handle of event source
+- EVENTLOG_ERROR_TYPE, // event type
++ // event type
++ (flags & MSG_FLAGS_ERROR)
++ ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
+ 0, // event category
+ 0, // event ID
+ NULL, // current user's SID
+@@ -323,8 +337,10 @@
+ }
+ }
+
+-
+-
++void ResetError (void)
++{
++ dwErr = 0;
++}
+
+ ///////////////////////////////////////////////////////////////////
+ //
+@@ -341,21 +357,23 @@
+ // none
+ //
+ // RETURN VALUE:
+-// none
++// 0 if success
+ //
+ // COMMENTS:
+ //
+-void CmdInstallService()
++int CmdInstallService()
+ {
+ SC_HANDLE schService;
+ SC_HANDLE schSCManager;
+
+ TCHAR szPath[512];
+
++ int ret = 0;
++
+ if ( GetModuleFileName( NULL, szPath, 512 ) == 0 )
+ {
+ _tprintf(TEXT("Unable to install %s - %s\n"), TEXT(SZSERVICEDISPLAYNAME), GetLastErrorText(szErr, 256));
+- return;
++ return 1;
+ }
+
+ schSCManager = OpenSCManager(
+@@ -371,7 +389,7 @@
+ TEXT(SZSERVICEDISPLAYNAME), // name to display
+ SERVICE_QUERY_STATUS, // desired access
+ SERVICE_WIN32_OWN_PROCESS, // service type
+- SERVICE_DEMAND_START, // start type
++ SERVICE_DEMAND_START, // start type -- alternative: SERVICE_AUTO_START
+ SERVICE_ERROR_NORMAL, // error control type
+ szPath, // service's binary
+ NULL, // no load ordering group
+@@ -388,16 +406,79 @@
+ else
+ {
+ _tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText(szErr, 256));
++ ret = 1;
+ }
+
+ CloseServiceHandle(schSCManager);
+ }
+ else
++ {
+ _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
++ ret = 1;
++ }
++ return ret;
+ }
+
++//
++// FUNCTION: CmdStartService()
++//
++// PURPOSE: Start the service
++//
++// PARAMETERS:
++// none
++//
++// RETURN VALUE:
++// 0 if success
++//
++// COMMENTS:
++
++int CmdStartService()
++{
++ int ret = 0;
++
++ SC_HANDLE schSCManager;
++ SC_HANDLE schService;
+
+
++ // Open a handle to the SC Manager database.
++ schSCManager = OpenSCManager(
++ NULL, // local machine
++ NULL, // ServicesActive database
++ SC_MANAGER_ALL_ACCESS); // full access rights
++
++ if (NULL == schSCManager) {
++ _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
++ ret = 1;
++ }
++
++ schService = OpenService(
++ schSCManager, // SCM database
++ SZSERVICENAME, // service name
++ SERVICE_ALL_ACCESS);
++
++ if (schService == NULL) {
++ _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(szErr,256));
++ ret = 1;
++ }
++
++ if (!StartService(
++ schService, // handle to service
++ 0, // number of arguments
++ NULL) ) // no arguments
++ {
++ _tprintf(TEXT("StartService failed - %s\n"), GetLastErrorText(szErr,256));
++ ret = 1;
++ }
++ else
++ {
++ _tprintf(TEXT("Service Started\n"));
++ ret = 0;
++ }
++ CloseServiceHandle(schService);
++ CloseServiceHandle(schSCManager);
++ return ret;
++}
++
+ //
+ // FUNCTION: CmdRemoveService()
+ //
+@@ -407,15 +488,17 @@
+ // none
+ //
+ // RETURN VALUE:
+-// none
++// 0 if success
+ //
+ // COMMENTS:
+ //
+-void CmdRemoveService()
++int CmdRemoveService()
+ {
+ SC_HANDLE schService;
+ SC_HANDLE schSCManager;
+
++ int ret = 0;
++
+ schSCManager = OpenSCManager(
+ NULL, // machine (NULL == local)
+ NULL, // database (NULL == default)
+@@ -447,7 +530,10 @@
+ if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
+ _tprintf(TEXT("\n%s stopped.\n"), TEXT(SZSERVICEDISPLAYNAME) );
+ else
++ {
+ _tprintf(TEXT("\n%s failed to stop.\n"), TEXT(SZSERVICEDISPLAYNAME) );
++ ret = 1;
++ }
+
+ }
+
+@@ -455,18 +541,28 @@
+ if ( DeleteService(schService) )
+ _tprintf(TEXT("%s removed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
+ else
++ {
+ _tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(szErr,256));
++ ret = 1;
++ }
+
+
+ CloseServiceHandle(schService);
+ }
+ else
++ {
+ _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(szErr,256));
++ ret = 1;
++ }
+
+ CloseServiceHandle(schSCManager);
+ }
+ else
++ {
+ _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
++ ret = 1;
++ }
++ return ret;
+ }
+
+
+@@ -587,7 +683,7 @@
+ else
+ {
+ lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0'); //remove cr and newline character
+- _stprintf( lpszBuf, TEXT("%s (0x%x)"), lpszTemp, GetLastError() );
++ _stprintf( lpszBuf, TEXT("%s (0x%x)"), lpszTemp, (int)GetLastError() );
+ }
+
+ if ( lpszTemp )
+--- service.h.orig Mon Jan 30 10:24:07 2006
++++ service.h Mon Jan 30 10:24:07 2006
+@@ -62,13 +62,13 @@
+ //// todo: change to desired strings
+ ////
+ // name of the executable
+-#define SZAPPNAME "Simple"
++#define SZAPPNAME "openvpnserv"
+ // internal name of the service
+-#define SZSERVICENAME "SimpleService"
++#define SZSERVICENAME "OpenVPNService"
+ // displayed name of the service
+-#define SZSERVICEDISPLAYNAME "Simple Service"
++#define SZSERVICEDISPLAYNAME "OpenVPN Service"
+ // list of service dependencies - "dep1\0dep2\0\0"
+-#define SZDEPENDENCIES ""
++#define SZDEPENDENCIES "TAP0801\0\0"
+ //////////////////////////////////////////////////////////////////////////////
+
+
+@@ -126,7 +126,10 @@
+ // RETURN VALUE:
+ // none
+ //
+- void AddToMessageLog(LPTSTR lpszMsg);
++# define MSG_FLAGS_ERROR (1<<0)
++# define MSG_FLAGS_SYS_CODE (1<<1)
++ void AddToMessageLog(DWORD flags, LPTSTR lpszMsg);
++ void ResetError (void);
+ //////////////////////////////////////////////////////////////////////////////
+
+