diff options
Diffstat (limited to 'src/openvpnserv')
-rw-r--r-- | src/openvpnserv/Makefile.am | 2 | ||||
-rw-r--r-- | src/openvpnserv/Makefile.in | 84 | ||||
-rw-r--r-- | src/openvpnserv/automatic.c | 42 | ||||
-rw-r--r-- | src/openvpnserv/common.c | 84 | ||||
-rw-r--r-- | src/openvpnserv/interactive.c | 314 | ||||
-rw-r--r-- | src/openvpnserv/service.c | 81 | ||||
-rw-r--r-- | src/openvpnserv/service.h | 9 | ||||
-rw-r--r-- | src/openvpnserv/validate.c | 4 |
8 files changed, 336 insertions, 284 deletions
diff --git a/src/openvpnserv/Makefile.am b/src/openvpnserv/Makefile.am index 21efc7c..bc65070 100644 --- a/src/openvpnserv/Makefile.am +++ b/src/openvpnserv/Makefile.am @@ -5,7 +5,7 @@ # packet encryption, packet authentication, and # packet compression. # -# Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> +# Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net> # Copyright (C) 2006-2012 Alon Bar-Lev <alon.barlev@gmail.com> # diff --git a/src/openvpnserv/Makefile.in b/src/openvpnserv/Makefile.in index ce618fb..68cb4a0 100644 --- a/src/openvpnserv/Makefile.in +++ b/src/openvpnserv/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.14.1 from Makefile.am. +# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -21,7 +21,7 @@ # packet encryption, packet authentication, and # packet compression. # -# Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> +# Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net> # Copyright (C) 2006-2012 Alon Bar-Lev <alon.barlev@gmail.com> # @@ -37,7 +37,17 @@ # Required to build Windows resource file VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -100,8 +110,6 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -DIST_COMMON = $(top_srcdir)/build/ltrc.inc $(srcdir)/Makefile.in \ - $(srcdir)/Makefile.am $(top_srcdir)/depcomp @WIN32_TRUE@sbin_PROGRAMS = openvpnserv$(EXEEXT) subdir = src/openvpnserv ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -114,6 +122,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_emptyarray.m4 \ $(top_srcdir)/compat.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h \ $(top_builddir)/include/openvpn-plugin.h @@ -150,7 +159,13 @@ am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/openvpnserv-automatic.Po \ + ./$(DEPDIR)/openvpnserv-block_dns.Po \ + ./$(DEPDIR)/openvpnserv-common.Po \ + ./$(DEPDIR)/openvpnserv-interactive.Po \ + ./$(DEPDIR)/openvpnserv-service.Po \ + ./$(DEPDIR)/openvpnserv-validate.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) @@ -196,6 +211,8 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/build/ltrc.inc \ + $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ @@ -244,6 +261,7 @@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ LZ4_CFLAGS = @LZ4_CFLAGS@ LZ4_LIBS = @LZ4_LIBS@ LZO_CFLAGS = @LZO_CFLAGS@ @@ -418,16 +436,15 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/build/ltrc.inc $(am_ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/openvpnserv/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/openvpnserv/Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; -$(top_srcdir)/build/ltrc.inc: +$(top_srcdir)/build/ltrc.inc $(am__empty): $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh @@ -497,12 +514,18 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openvpnserv-automatic.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openvpnserv-block_dns.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openvpnserv-common.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openvpnserv-interactive.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openvpnserv-service.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openvpnserv-validate.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openvpnserv-automatic.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openvpnserv-block_dns.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openvpnserv-common.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openvpnserv-interactive.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openvpnserv-service.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openvpnserv-validate.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -667,7 +690,10 @@ cscopelist-am: $(am__tagged_files) distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -distdir: $(DISTFILES) +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ @@ -741,7 +767,12 @@ clean-am: clean-generic clean-libtool clean-sbinPROGRAMS \ mostlyclean-am distclean: distclean-am - -rm -rf ./$(DEPDIR) + -rm -f ./$(DEPDIR)/openvpnserv-automatic.Po + -rm -f ./$(DEPDIR)/openvpnserv-block_dns.Po + -rm -f ./$(DEPDIR)/openvpnserv-common.Po + -rm -f ./$(DEPDIR)/openvpnserv-interactive.Po + -rm -f ./$(DEPDIR)/openvpnserv-service.Po + -rm -f ./$(DEPDIR)/openvpnserv-validate.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags @@ -787,7 +818,12 @@ install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) + -rm -f ./$(DEPDIR)/openvpnserv-automatic.Po + -rm -f ./$(DEPDIR)/openvpnserv-block_dns.Po + -rm -f ./$(DEPDIR)/openvpnserv-common.Po + -rm -f ./$(DEPDIR)/openvpnserv-interactive.Po + -rm -f ./$(DEPDIR)/openvpnserv-service.Po + -rm -f ./$(DEPDIR)/openvpnserv-validate.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic @@ -808,9 +844,9 @@ uninstall-am: uninstall-sbinPROGRAMS .MAKE: install-am install-strip -.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ - clean-libtool clean-sbinPROGRAMS cscopelist-am ctags ctags-am \ - distclean distclean-compile distclean-generic \ +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-sbinPROGRAMS cscopelist-am \ + ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ @@ -822,6 +858,8 @@ uninstall-am: uninstall-sbinPROGRAMS mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-sbinPROGRAMS +.PRECIOUS: Makefile + .rc.lo: $(LTRCCOMPILE) -i "$<" -o "$@" diff --git a/src/openvpnserv/automatic.c b/src/openvpnserv/automatic.c index 4123d0f..5569ce9 100644 --- a/src/openvpnserv/automatic.c +++ b/src/openvpnserv/automatic.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2002-2018 OpenVPN Inc <sales@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 @@ -44,7 +44,7 @@ #define false 0 static SERVICE_STATUS_HANDLE service; -static SERVICE_STATUS status; +static SERVICE_STATUS status = { .dwServiceType = SERVICE_WIN32_SHARE_PROCESS }; openvpn_service_t automatic_service = { automatic, @@ -60,12 +60,6 @@ struct security_attributes SECURITY_DESCRIPTOR sd; }; -/* - * Which registry key in HKLM should - * we get config info from? - */ -#define REG_KEY "SOFTWARE\\" PACKAGE_NAME - static HANDLE exit_event = NULL; /* clear an object */ @@ -91,15 +85,6 @@ init_security_attributes_allow_all(struct security_attributes *obj) return true; } -/* - * 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 TEXT(PACKAGE "_exit_1") - HANDLE create_event(LPCTSTR name, bool allow_all, bool initial_state, bool manual_reset) { @@ -212,10 +197,19 @@ ServiceCtrlAutomatic(DWORD ctrl_code, DWORD event, LPVOID data, LPVOID ctx) VOID WINAPI +ServiceStartAutomaticOwn(DWORD dwArgc, LPTSTR *lpszArgv) +{ + status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + ServiceStartAutomatic(dwArgc, lpszArgv); +} + + +VOID WINAPI ServiceStartAutomatic(DWORD dwArgc, LPTSTR *lpszArgv) { DWORD error = NO_ERROR; settings_t settings; + TCHAR event_name[256]; service = RegisterServiceCtrlHandlerEx(automatic_service.name, ServiceCtrlAutomatic, &status); if (!service) @@ -223,7 +217,6 @@ ServiceStartAutomatic(DWORD dwArgc, LPTSTR *lpszArgv) return; } - status.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; status.dwCurrentState = SERVICE_START_PENDING; status.dwServiceSpecificExitCode = NO_ERROR; status.dwWin32ExitCode = NO_ERROR; @@ -237,8 +230,15 @@ ServiceStartAutomatic(DWORD dwArgc, LPTSTR *lpszArgv) /* * Create our exit event + * 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. */ - exit_event = create_event(EXIT_EVENT_NAME, false, false, true); + + openvpn_sntprintf(event_name, _countof(event_name), TEXT(PACKAGE "%s_exit_1"), service_instance); + exit_event = create_event(event_name, false, false, true); if (!exit_event) { MsgToEventLog(M_ERR, TEXT("CreateEvent failed")); @@ -327,8 +327,8 @@ ServiceStartAutomatic(DWORD dwArgc, LPTSTR *lpszArgv) TEXT("%s\\%s"), settings.log_dir, log_file); /* construct command line */ - openvpn_sntprintf(command_line, _countof(command_line), TEXT(PACKAGE " --service %s 1 --config \"%s\""), - EXIT_EVENT_NAME, + openvpn_sntprintf(command_line, _countof(command_line), TEXT("openvpn --service \"" PACKAGE "%s_exit_1\" 1 --config \"%s\""), + service_instance, find_obj.cFileName); /* Make security attributes struct for logfile handle so it can diff --git a/src/openvpnserv/common.c b/src/openvpnserv/common.c index 0c9098f..73c418f 100644 --- a/src/openvpnserv/common.c +++ b/src/openvpnserv/common.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2011-2017 Heiko Hund <heiko.hund@sophos.com> + * Copyright (C) 2011-2018 Heiko Hund <heiko.hund@sophos.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -21,8 +21,12 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include <service.h> -#include <validate.h> +#include "service.h" +#include "validate.h" + +LPCTSTR service_instance = TEXT(""); +static wchar_t win_sys_path[MAX_PATH]; + /* * These are necessary due to certain buggy implementations of (v)snprintf, * that don't guarantee null termination for size > 0. @@ -52,23 +56,25 @@ openvpn_sntprintf(LPTSTR str, size_t size, LPCTSTR format, ...) return len; } -#define REG_KEY TEXT("SOFTWARE\\" PACKAGE_NAME) - static DWORD -GetRegString(HKEY key, LPCTSTR value, LPTSTR data, DWORD size) +GetRegString(HKEY key, LPCTSTR value, LPTSTR data, DWORD size, LPCTSTR default_value) { - DWORD type; - LONG status = RegQueryValueEx(key, value, NULL, &type, (LPBYTE) data, &size); + LONG status = RegGetValue(key, NULL, value, RRF_RT_REG_SZ, + NULL, (LPBYTE) data, &size); - if (status == ERROR_SUCCESS && type != REG_SZ) + if (status == ERROR_FILE_NOT_FOUND && default_value) { - status = ERROR_DATATYPE_MISMATCH; + size_t len = size/sizeof(data[0]); + if (openvpn_sntprintf(data, len, default_value) > 0) + { + status = ERROR_SUCCESS; + } } if (status != ERROR_SUCCESS) { SetLastError(status); - return MsgToEventLog(M_SYSERR, TEXT("Error querying registry value: HKLM\\%s\\%s"), REG_KEY, value); + return MsgToEventLog(M_SYSERR, TEXT("Error querying registry value: HKLM\\SOFTWARE\\" PACKAGE_NAME "%s\\%s"), service_instance, value); } return ERROR_SUCCESS; @@ -78,60 +84,78 @@ GetRegString(HKEY key, LPCTSTR value, LPTSTR data, DWORD size) DWORD GetOpenvpnSettings(settings_t *s) { + TCHAR reg_path[256]; TCHAR priority[64]; TCHAR append[2]; DWORD error; HKEY key; + TCHAR install_path[MAX_PATH]; + TCHAR default_value[MAX_PATH]; + + openvpn_sntprintf(reg_path, _countof(reg_path), TEXT("SOFTWARE\\" PACKAGE_NAME "%s"), service_instance); - LONG status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_KEY, 0, KEY_READ, &key); + LONG status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, reg_path, 0, KEY_READ, &key); if (status != ERROR_SUCCESS) { SetLastError(status); - return MsgToEventLog(M_SYSERR, TEXT("Could not open Registry key HKLM\\%s not found"), REG_KEY); + return MsgToEventLog(M_SYSERR, TEXT("Could not open Registry key HKLM\\%s not found"), reg_path); + } + + /* The default value of REG_KEY is the install path */ + if (GetRegString(key, NULL, install_path, sizeof(install_path), NULL) != ERROR_SUCCESS) + { + goto out; } - error = GetRegString(key, TEXT("exe_path"), s->exe_path, sizeof(s->exe_path)); + openvpn_sntprintf(default_value, _countof(default_value), TEXT("%s\\bin\\openvpn.exe"), + install_path); + error = GetRegString(key, TEXT("exe_path"), s->exe_path, sizeof(s->exe_path), default_value); if (error != ERROR_SUCCESS) { goto out; } - error = GetRegString(key, TEXT("config_dir"), s->config_dir, sizeof(s->config_dir)); + openvpn_sntprintf(default_value, _countof(default_value), TEXT("%s\\config"), install_path); + error = GetRegString(key, TEXT("config_dir"), s->config_dir, sizeof(s->config_dir), + default_value); if (error != ERROR_SUCCESS) { goto out; } - error = GetRegString(key, TEXT("config_ext"), s->ext_string, sizeof(s->ext_string)); + error = GetRegString(key, TEXT("config_ext"), s->ext_string, sizeof(s->ext_string), + TEXT(".ovpn")); if (error != ERROR_SUCCESS) { goto out; } - error = GetRegString(key, TEXT("log_dir"), s->log_dir, sizeof(s->log_dir)); + openvpn_sntprintf(default_value, _countof(default_value), TEXT("%s\\log"), install_path); + error = GetRegString(key, TEXT("log_dir"), s->log_dir, sizeof(s->log_dir), default_value); if (error != ERROR_SUCCESS) { goto out; } - error = GetRegString(key, TEXT("priority"), priority, sizeof(priority)); + error = GetRegString(key, TEXT("priority"), priority, sizeof(priority), + TEXT("NORMAL_PRIORITY_CLASS")); if (error != ERROR_SUCCESS) { goto out; } - error = GetRegString(key, TEXT("log_append"), append, sizeof(append)); + error = GetRegString(key, TEXT("log_append"), append, sizeof(append), TEXT("0")); if (error != ERROR_SUCCESS) { goto out; } /* read if present, else use default */ - error = GetRegString(key, TEXT("ovpn_admin_group"), s->ovpn_admin_group, sizeof(s->ovpn_admin_group)); + error = GetRegString(key, TEXT("ovpn_admin_group"), s->ovpn_admin_group, + sizeof(s->ovpn_admin_group), OVPN_ADMIN_GROUP); if (error != ERROR_SUCCESS) { - openvpn_sntprintf(s->ovpn_admin_group, _countof(s->ovpn_admin_group), OVPN_ADMIN_GROUP); - error = 0; /* this error is not fatal */ + goto out; } /* set process priority */ if (!_tcsicmp(priority, TEXT("IDLE_PRIORITY_CLASS"))) @@ -231,7 +255,7 @@ MsgToEventLog(DWORD flags, LPCTSTR format, ...) if (hEventSource != NULL) { openvpn_sntprintf(msg[0], _countof(msg[0]), - TEXT("%s%s: %s"), APPNAME, + TEXT("%s%s%s: %s"), APPNAME, service_instance, (flags & MSG_FLAGS_ERROR) ? TEXT(" error") : TEXT(""), err_msg); va_start(arglist, format); @@ -261,3 +285,17 @@ utf8to16(const char *utf8) MultiByteToWideChar(CP_UTF8, 0, utf8, -1, utf16, n); return utf16; } + +const wchar_t * +get_win_sys_path(void) +{ + const wchar_t *default_sys_path = L"C:\\Windows\\system32"; + + if (!GetSystemDirectoryW(win_sys_path, _countof(win_sys_path))) + { + wcsncpy(win_sys_path, default_sys_path, _countof(win_sys_path)); + win_sys_path[_countof(win_sys_path) - 1] = L'\0'; + } + + return win_sys_path; +} diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index 607c8a9..d7c9eea 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2012-2017 Heiko Hund <heiko.hund@sophos.com> + * Copyright (C) 2012-2018 Heiko Hund <heiko.hund@sophos.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -33,6 +33,7 @@ #include <stdio.h> #include <sddl.h> #include <shellapi.h> +#include <mstcpip.h> #ifdef HAVE_VERSIONHELPERS_H #include <versionhelpers.h> @@ -52,7 +53,7 @@ #define ERROR_MESSAGE_TYPE 0x20000003 static SERVICE_STATUS_HANDLE service; -static SERVICE_STATUS status; +static SERVICE_STATUS status = { .dwServiceType = SERVICE_WIN32_SHARE_PROCESS }; static HANDLE exit_event = NULL; static settings_t settings; static HANDLE rdns_semaphore = NULL; @@ -276,7 +277,7 @@ ReturnProcessId(HANDLE pipe, DWORD pid, DWORD count, LPHANDLE events) * Same format as error messages (3 line string) with error = 0 in * 0x%08x format, PID on line 2 and a description "Process ID" on line 3 */ - _snwprintf(buf, _countof(buf), L"0x%08x\n0x%08x\n%s", 0, pid, msg); + swprintf(buf, _countof(buf), L"0x%08x\n0x%08x\n%s", 0, pid, msg); buf[_countof(buf) - 1] = '\0'; WritePipeAsync(pipe, buf, wcslen(buf) * 2, count, events); @@ -370,12 +371,12 @@ ValidateOptions(HANDLE pipe, const WCHAR *workdir, const WCHAR *options) BOOL ret = FALSE; int i; const WCHAR *msg1 = L"You have specified a config file location (%s relative to %s)" - " that requires admin approval. This error may be avoided" - " by adding your account to the \"%s\" group"; + L" that requires admin approval. This error may be avoided" + L" by adding your account to the \"%s\" group"; const WCHAR *msg2 = L"You have specified an option (%s) that may be used" - " only with admin approval. This error may be avoided" - " by adding your account to the \"%s\" group"; + L" only with admin approval. This error may be avoided" + L" by adding your account to the \"%s\" group"; argv = CommandLineToArgvW(options, &argc); @@ -402,8 +403,8 @@ ValidateOptions(HANDLE pipe, const WCHAR *workdir, const WCHAR *options) if (!CheckOption(workdir, 2, argv_tmp, &settings)) { - snwprintf(buf, _countof(buf), msg1, argv[0], workdir, - settings.ovpn_admin_group); + swprintf(buf, _countof(buf), msg1, argv[0], workdir, + settings.ovpn_admin_group); buf[_countof(buf) - 1] = L'\0'; ReturnError(pipe, ERROR_STARTUP_DATA, buf, 1, &exit_event); } @@ -421,15 +422,15 @@ ValidateOptions(HANDLE pipe, const WCHAR *workdir, const WCHAR *options) { if (wcscmp(L"--config", argv[i]) == 0 && argc-i > 1) { - snwprintf(buf, _countof(buf), msg1, argv[i+1], workdir, - settings.ovpn_admin_group); + swprintf(buf, _countof(buf), msg1, argv[i+1], workdir, + settings.ovpn_admin_group); buf[_countof(buf) - 1] = L'\0'; ReturnError(pipe, ERROR_STARTUP_DATA, buf, 1, &exit_event); } else { - snwprintf(buf, _countof(buf), msg2, argv[i], - settings.ovpn_admin_group); + swprintf(buf, _countof(buf), msg2, argv[i], + settings.ovpn_admin_group); buf[_countof(buf) - 1] = L'\0'; ReturnError(pipe, ERROR_STARTUP_DATA, buf, 1, &exit_event); } @@ -452,7 +453,6 @@ static BOOL GetStartupData(HANDLE pipe, STARTUP_DATA *sud) { size_t len; - BOOL ret = FALSE; WCHAR *data = NULL; DWORD size, bytes, read; @@ -461,16 +461,23 @@ GetStartupData(HANDLE pipe, STARTUP_DATA *sud) { MsgToEventLog(M_SYSERR, TEXT("PeekNamedPipeAsync failed")); ReturnLastError(pipe, L"PeekNamedPipeAsync"); - goto out; + goto err; } size = bytes / sizeof(*data); + if (size == 0) + { + MsgToEventLog(M_SYSERR, TEXT("malformed startup data: 1 byte received")); + ReturnError(pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event); + goto err; + } + data = malloc(bytes); if (data == NULL) { MsgToEventLog(M_SYSERR, TEXT("malloc failed")); ReturnLastError(pipe, L"malloc"); - goto out; + goto err; } read = ReadPipeAsync(pipe, data, bytes, 1, &exit_event); @@ -478,14 +485,14 @@ GetStartupData(HANDLE pipe, STARTUP_DATA *sud) { MsgToEventLog(M_SYSERR, TEXT("ReadPipeAsync failed")); ReturnLastError(pipe, L"ReadPipeAsync"); - goto out; + goto err; } if (data[size - 1] != 0) { MsgToEventLog(M_ERR, TEXT("Startup data is not NULL terminated")); ReturnError(pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event); - goto out; + goto err; } sud->directory = data; @@ -495,7 +502,7 @@ GetStartupData(HANDLE pipe, STARTUP_DATA *sud) { MsgToEventLog(M_ERR, TEXT("Startup data ends at working directory")); ReturnError(pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event); - goto out; + goto err; } sud->options = sud->directory + len; @@ -505,16 +512,16 @@ GetStartupData(HANDLE pipe, STARTUP_DATA *sud) { MsgToEventLog(M_ERR, TEXT("Startup data ends at command line options")); ReturnError(pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event); - goto out; + goto err; } sud->std_input = sud->options + len; - data = NULL; /* don't free data */ - ret = TRUE; + return TRUE; -out: +err: + sud->directory = NULL; /* caller must not free() */ free(data); - return ret; + return FALSE; } @@ -546,32 +553,17 @@ static DWORD InterfaceLuid(const char *iface_name, PNET_LUID luid) { NETIO_STATUS status; - LPWSTR wide_name; - int n; + LPWSTR wide_name = utf8to16(iface_name); - typedef NETIO_STATUS WINAPI (*ConvertInterfaceAliasToLuidFn) (LPCWSTR, PNET_LUID); - static ConvertInterfaceAliasToLuidFn ConvertInterfaceAliasToLuid = NULL; - if (!ConvertInterfaceAliasToLuid) + if (wide_name) { - HMODULE iphlpapi = GetModuleHandle(TEXT("iphlpapi.dll")); - if (iphlpapi == NULL) - { - return GetLastError(); - } - - ConvertInterfaceAliasToLuid = (ConvertInterfaceAliasToLuidFn) GetProcAddress(iphlpapi, "ConvertInterfaceAliasToLuid"); - if (!ConvertInterfaceAliasToLuid) - { - return GetLastError(); - } + status = ConvertInterfaceAliasToLuid(wide_name, luid); + free(wide_name); + } + else + { + status = ERROR_OUTOFMEMORY; } - - n = MultiByteToWideChar(CP_UTF8, 0, iface_name, -1, NULL, 0); - wide_name = malloc(n * sizeof(WCHAR)); - MultiByteToWideChar(CP_UTF8, 0, iface_name, -1, wide_name, n); - status = ConvertInterfaceAliasToLuid(wide_name, luid); - free(wide_name); - return status; } @@ -584,24 +576,6 @@ CmpAddress(LPVOID item, LPVOID address) static DWORD DeleteAddress(PMIB_UNICASTIPADDRESS_ROW addr_row) { - typedef NETIOAPI_API (*DeleteUnicastIpAddressEntryFn) (const PMIB_UNICASTIPADDRESS_ROW); - static DeleteUnicastIpAddressEntryFn DeleteUnicastIpAddressEntry = NULL; - - if (!DeleteUnicastIpAddressEntry) - { - HMODULE iphlpapi = GetModuleHandle(TEXT("iphlpapi.dll")); - if (iphlpapi == NULL) - { - return GetLastError(); - } - - DeleteUnicastIpAddressEntry = (DeleteUnicastIpAddressEntryFn) GetProcAddress(iphlpapi, "DeleteUnicastIpAddressEntry"); - if (!DeleteUnicastIpAddressEntry) - { - return GetLastError(); - } - } - return DeleteUnicastIpAddressEntry(addr_row); } @@ -612,32 +586,6 @@ HandleAddressMessage(address_message_t *msg, undo_lists_t *lists) PMIB_UNICASTIPADDRESS_ROW addr_row; BOOL add = msg->header.type == msg_add_address; - typedef NETIOAPI_API (*CreateUnicastIpAddressEntryFn) (const PMIB_UNICASTIPADDRESS_ROW); - typedef NETIOAPI_API (*InitializeUnicastIpAddressEntryFn) (PMIB_UNICASTIPADDRESS_ROW); - static CreateUnicastIpAddressEntryFn CreateUnicastIpAddressEntry = NULL; - static InitializeUnicastIpAddressEntryFn InitializeUnicastIpAddressEntry = NULL; - - if (!CreateUnicastIpAddressEntry || !InitializeUnicastIpAddressEntry) - { - HMODULE iphlpapi = GetModuleHandle(TEXT("iphlpapi.dll")); - if (iphlpapi == NULL) - { - return GetLastError(); - } - - CreateUnicastIpAddressEntry = (CreateUnicastIpAddressEntryFn) GetProcAddress(iphlpapi, "CreateUnicastIpAddressEntry"); - if (!CreateUnicastIpAddressEntry) - { - return GetLastError(); - } - - InitializeUnicastIpAddressEntry = (InitializeUnicastIpAddressEntryFn) GetProcAddress(iphlpapi, "InitializeUnicastIpAddressEntry"); - if (!InitializeUnicastIpAddressEntry) - { - return GetLastError(); - } - } - addr_row = malloc(sizeof(*addr_row)); if (addr_row == NULL) { @@ -706,24 +654,6 @@ CmpRoute(LPVOID item, LPVOID route) static DWORD DeleteRoute(PMIB_IPFORWARD_ROW2 fwd_row) { - typedef NETIOAPI_API (*DeleteIpForwardEntry2Fn) (PMIB_IPFORWARD_ROW2); - static DeleteIpForwardEntry2Fn DeleteIpForwardEntry2 = NULL; - - if (!DeleteIpForwardEntry2) - { - HMODULE iphlpapi = GetModuleHandle(TEXT("iphlpapi.dll")); - if (iphlpapi == NULL) - { - return GetLastError(); - } - - DeleteIpForwardEntry2 = (DeleteIpForwardEntry2Fn) GetProcAddress(iphlpapi, "DeleteIpForwardEntry2"); - if (!DeleteIpForwardEntry2) - { - return GetLastError(); - } - } - return DeleteIpForwardEntry2(fwd_row); } @@ -734,24 +664,6 @@ HandleRouteMessage(route_message_t *msg, undo_lists_t *lists) PMIB_IPFORWARD_ROW2 fwd_row; BOOL add = msg->header.type == msg_add_route; - typedef NETIOAPI_API (*CreateIpForwardEntry2Fn) (PMIB_IPFORWARD_ROW2); - static CreateIpForwardEntry2Fn CreateIpForwardEntry2 = NULL; - - if (!CreateIpForwardEntry2) - { - HMODULE iphlpapi = GetModuleHandle(TEXT("iphlpapi.dll")); - if (iphlpapi == NULL) - { - return GetLastError(); - } - - CreateIpForwardEntry2 = (CreateIpForwardEntry2Fn) GetProcAddress(iphlpapi, "CreateIpForwardEntry2"); - if (!CreateIpForwardEntry2) - { - return GetLastError(); - } - } - fwd_row = malloc(sizeof(*fwd_row)); if (fwd_row == NULL) { @@ -820,36 +732,12 @@ out: static DWORD HandleFlushNeighborsMessage(flush_neighbors_message_t *msg) { - typedef NETIOAPI_API (*FlushIpNetTable2Fn) (ADDRESS_FAMILY, NET_IFINDEX); - static FlushIpNetTable2Fn flush_fn = NULL; - if (msg->family == AF_INET) { return FlushIpNetTable(msg->iface.index); } - if (!flush_fn) - { - HMODULE iphlpapi = GetModuleHandle(TEXT("iphlpapi.dll")); - if (iphlpapi == NULL) - { - return GetLastError(); - } - - flush_fn = (FlushIpNetTable2Fn) GetProcAddress(iphlpapi, "FlushIpNetTable2"); - if (!flush_fn) - { - if (GetLastError() == ERROR_PROC_NOT_FOUND) - { - return WSAEPFNOSUPPORT; - } - else - { - return GetLastError(); - } - } - } - return flush_fn(msg->family, msg->iface.index); + return FlushIpNetTable2(msg->family, msg->iface.index); } static void @@ -915,17 +803,18 @@ HandleBlockDNSMessage(const block_dns_message_t *msg, undo_lists_t *lists) } interface_data->engine = engine; interface_data->index = msg->iface.index; + int is_auto = 0; interface_data->metric_v4 = get_interface_metric(msg->iface.index, - AF_INET); - if (interface_data->metric_v4 < 0) + AF_INET, &is_auto); + if (is_auto) { - interface_data->metric_v4 = -1; + interface_data->metric_v4 = 0; } interface_data->metric_v6 = get_interface_metric(msg->iface.index, - AF_INET6); - if (interface_data->metric_v6 < 0) + AF_INET6, &is_auto); + if (is_auto) { - interface_data->metric_v6 = -1; + interface_data->metric_v6 = 0; } err = AddListItem(&(*lists)[block_dns], interface_data); if (!err) @@ -1045,11 +934,10 @@ RegisterDNS(LPVOID unused) { DWORD err; DWORD i; - WCHAR sys_path[MAX_PATH]; DWORD timeout = RDNS_TIMEOUT * 1000; /* in milliseconds */ - /* default path of ipconfig command */ - WCHAR ipcfg[MAX_PATH] = L"C:\\Windows\\system32\\ipconfig.exe"; + /* path of ipconfig command */ + WCHAR ipcfg[MAX_PATH]; struct { @@ -1064,11 +952,8 @@ RegisterDNS(LPVOID unused) HANDLE wait_handles[2] = {rdns_semaphore, exit_event}; - if (GetSystemDirectory(sys_path, MAX_PATH)) - { - _snwprintf(ipcfg, MAX_PATH, L"%s\\%s", sys_path, L"ipconfig.exe"); - ipcfg[MAX_PATH-1] = L'\0'; - } + swprintf(ipcfg, _countof(ipcfg), L"%s\\%s", get_win_sys_path(), L"ipconfig.exe"); + ipcfg[_countof(ipcfg) - 1] = L'\0'; if (WaitForMultipleObjects(2, wait_handles, FALSE, timeout) == WAIT_OBJECT_0) { @@ -1132,6 +1017,7 @@ netsh_dns_cmd(const wchar_t *action, const wchar_t *proto, const wchar_t *if_nam DWORD err = 0; int timeout = 30000; /* in msec */ wchar_t argv0[MAX_PATH]; + wchar_t *cmdline = NULL; if (!addr) { @@ -1146,15 +1032,8 @@ netsh_dns_cmd(const wchar_t *action, const wchar_t *proto, const wchar_t *if_nam } /* Path of netsh */ - int n = GetSystemDirectory(argv0, MAX_PATH); - if (n > 0 && n < MAX_PATH) /* got system directory */ - { - wcsncat(argv0, L"\\netsh.exe", MAX_PATH - n - 1); - } - else - { - wcsncpy(argv0, L"C:\\Windows\\system32\\netsh.exe", MAX_PATH); - } + swprintf(argv0, _countof(argv0), L"%s\\%s", get_win_sys_path(), L"netsh.exe"); + argv0[_countof(argv0) - 1] = L'\0'; /* cmd template: * netsh interface $proto $action dns $if_name $addr [validate=no] @@ -1163,7 +1042,7 @@ netsh_dns_cmd(const wchar_t *action, const wchar_t *proto, const wchar_t *if_nam /* max cmdline length in wchars -- include room for worst case and some */ int ncmdline = wcslen(fmt) + wcslen(if_name) + wcslen(addr) + 32 + 1; - wchar_t *cmdline = malloc(ncmdline*sizeof(wchar_t)); + cmdline = malloc(ncmdline*sizeof(wchar_t)); if (!cmdline) { err = ERROR_OUTOFMEMORY; @@ -1287,6 +1166,45 @@ out: return err; } +static DWORD +HandleEnableDHCPMessage(const enable_dhcp_message_t *dhcp) +{ + DWORD err = 0; + DWORD timeout = 5000; /* in milli seconds */ + wchar_t argv0[MAX_PATH]; + + /* Path of netsh */ + swprintf(argv0, _countof(argv0), L"%s\\%s", get_win_sys_path(), L"netsh.exe"); + argv0[_countof(argv0) - 1] = L'\0'; + + /* cmd template: + * netsh interface ipv4 set address name=$if_index source=dhcp + */ + const wchar_t *fmt = L"netsh interface ipv4 set address name=\"%d\" source=dhcp"; + + /* max cmdline length in wchars -- include room for if index: + * 10 chars for 32 bit int in decimal and +1 for NUL + */ + size_t ncmdline = wcslen(fmt) + 10 + 1; + wchar_t *cmdline = malloc(ncmdline*sizeof(wchar_t)); + if (!cmdline) + { + err = ERROR_OUTOFMEMORY; + return err; + } + + openvpn_sntprintf(cmdline, ncmdline, fmt, dhcp->iface.index); + + err = ExecCommand(argv0, cmdline, timeout); + + /* Note: This could fail if dhcp is already enabled, so the caller + * may not want to treat errors as FATAL. + */ + + free(cmdline); + return err; +} + static VOID HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists) { @@ -1298,6 +1216,7 @@ HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists flush_neighbors_message_t flush_neighbors; block_dns_message_t block_dns; dns_cfg_message_t dns; + enable_dhcp_message_t dhcp; } msg; ack_message_t ack = { .header = { @@ -1358,6 +1277,13 @@ HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists ack.error_number = HandleDNSConfigMessage(&msg.dns, lists); break; + case msg_enable_dhcp: + if (msg.header.size == sizeof(msg.dhcp)) + { + ack.error_number = HandleEnableDHCPMessage(&msg.dhcp); + } + break; + default: ack.error_number = ERROR_MESSAGE_TYPE; MsgToEventLog(MSG_FLAGS_ERROR, TEXT("Unknown message type %d"), msg.header.type); @@ -1427,7 +1353,7 @@ RunOpenvpn(LPVOID p) { HANDLE pipe = p; HANDLE ovpn_pipe, svc_pipe; - PTOKEN_USER svc_user, ovpn_user; + PTOKEN_USER svc_user = NULL, ovpn_user = NULL; HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL; HANDLE stdin_read = NULL, stdin_write = NULL; HANDLE stdout_write = NULL; @@ -1436,7 +1362,7 @@ RunOpenvpn(LPVOID p) STARTUPINFOW startup_info; PROCESS_INFORMATION proc_info; LPVOID user_env = NULL; - TCHAR ovpn_pipe_name[36]; + TCHAR ovpn_pipe_name[256]; /* The entire pipe name string can be up to 256 characters long according to MSDN. */ LPCWSTR exe_path; WCHAR *cmdline = NULL; size_t cmdline_size; @@ -1480,7 +1406,6 @@ RunOpenvpn(LPVOID p) goto out; } len = 0; - svc_user = NULL; while (!GetTokenInformation(svc_token, TokenUser, svc_user, len, &len)) { if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) @@ -1513,7 +1438,6 @@ RunOpenvpn(LPVOID p) goto out; } len = 0; - ovpn_user = NULL; while (!GetTokenInformation(imp_token, TokenUser, ovpn_user, len, &len)) { if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) @@ -1598,7 +1522,7 @@ RunOpenvpn(LPVOID p) } openvpn_sntprintf(ovpn_pipe_name, _countof(ovpn_pipe_name), - TEXT("\\\\.\\pipe\\openvpn\\service_%lu"), GetCurrentThreadId()); + TEXT("\\\\.\\pipe\\" PACKAGE "%s\\service_%lu"), service_instance, GetCurrentThreadId()); ovpn_pipe = CreateNamedPipe(ovpn_pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 128, 128, 0, NULL); @@ -1706,8 +1630,8 @@ RunOpenvpn(LPVOID p) else if (exit_code != 0) { WCHAR buf[256]; - int len = _snwprintf(buf, _countof(buf), - L"OpenVPN exited with error: exit code = %lu", exit_code); + swprintf(buf, _countof(buf), + L"OpenVPN exited with error: exit code = %lu", exit_code); buf[_countof(buf) - 1] = L'\0'; ReturnError(pipe, ERROR_OPENVPN_STARTUP, buf, 1, &exit_event); } @@ -1765,6 +1689,7 @@ ServiceCtrlInteractive(DWORD ctrl_code, DWORD event, LPVOID data, LPVOID ctx) static HANDLE CreateClientPipeInstance(VOID) { + TCHAR pipe_name[256]; /* The entire pipe name string can be up to 256 characters long according to MSDN. */ HANDLE pipe = NULL; PACL old_dacl, new_dacl; PSECURITY_DESCRIPTOR sd; @@ -1801,7 +1726,8 @@ CreateClientPipeInstance(VOID) initialized = TRUE; } - pipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\openvpn\\service"), flags, + openvpn_sntprintf(pipe_name, _countof(pipe_name), TEXT("\\\\.\\pipe\\" PACKAGE "%s\\service"), service_instance); + pipe = CreateNamedPipe(pipe_name, flags, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, NULL); if (pipe == INVALID_HANDLE_VALUE) @@ -1890,6 +1816,20 @@ FreeWaitHandles(LPHANDLE h) free(h); } +static BOOL +CmpHandle(LPVOID item, LPVOID hnd) +{ + return item == hnd; +} + + +VOID WINAPI +ServiceStartInteractiveOwn(DWORD dwArgc, LPTSTR *lpszArgv) +{ + status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + ServiceStartInteractive(dwArgc, lpszArgv); +} + VOID WINAPI ServiceStartInteractive(DWORD dwArgc, LPTSTR *lpszArgv) @@ -1900,11 +1840,6 @@ ServiceStartInteractive(DWORD dwArgc, LPTSTR *lpszArgv) list_item_t *threads = NULL; PHANDLE handles = NULL; DWORD handle_count; - BOOL - CmpHandle(LPVOID item, LPVOID hnd) - { - return item == hnd; - } service = RegisterServiceCtrlHandlerEx(interactive_service.name, ServiceCtrlInteractive, &status); if (!service) @@ -1912,7 +1847,6 @@ ServiceStartInteractive(DWORD dwArgc, LPTSTR *lpszArgv) return; } - status.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; status.dwCurrentState = SERVICE_START_PENDING; status.dwServiceSpecificExitCode = NO_ERROR; status.dwWin32ExitCode = NO_ERROR; diff --git a/src/openvpnserv/service.c b/src/openvpnserv/service.c index b79e999..7157bea 100644 --- a/src/openvpnserv/service.c +++ b/src/openvpnserv/service.c @@ -223,46 +223,81 @@ out: int _tmain(int argc, TCHAR *argv[]) { - SERVICE_TABLE_ENTRY dispatchTable[] = { + /* + * Automatic + Interactive service (as a SERVICE_WIN32_SHARE_PROCESS) + * This is the default. + */ + const SERVICE_TABLE_ENTRY dispatchTable_shared[] = { { automatic_service.name, ServiceStartAutomatic }, { interactive_service.name, ServiceStartInteractive }, { NULL, NULL } }; + /* Automatic service only (as a SERVICE_WIN32_OWN_PROCESS) */ + const SERVICE_TABLE_ENTRY dispatchTable_automatic[] = { + { TEXT(""), ServiceStartAutomaticOwn }, + { NULL, NULL } + }; + + /* Interactive service only (as a SERVICE_WIN32_OWN_PROCESS) */ + const SERVICE_TABLE_ENTRY dispatchTable_interactive[] = { + { TEXT(""), ServiceStartInteractiveOwn }, + { NULL, NULL } + }; + + const SERVICE_TABLE_ENTRY *dispatchTable = dispatchTable_shared; + openvpn_service[0] = automatic_service; openvpn_service[1] = interactive_service; - if (argc > 1 && (*argv[1] == TEXT('-') || *argv[1] == TEXT('/'))) + for (int i = 1; i < argc; i++) { - if (_tcsicmp(TEXT("install"), argv[1] + 1) == 0) - { - return CmdInstallServices(); - } - else if (_tcsicmp(TEXT("remove"), argv[1] + 1) == 0) - { - return CmdRemoveServices(); - } - else if (_tcsicmp(TEXT("start"), argv[1] + 1) == 0) - { - BOOL is_auto = argc < 3 || _tcsicmp(TEXT("interactive"), argv[2]) != 0; - return CmdStartService(is_auto ? automatic : interactive); - } - else + if (*argv[i] == TEXT('-') || *argv[i] == TEXT('/')) { - goto dispatch; - } + if (_tcsicmp(TEXT("install"), argv[i] + 1) == 0) + { + return CmdInstallServices(); + } + else if (_tcsicmp(TEXT("remove"), argv[i] + 1) == 0) + { + return CmdRemoveServices(); + } + else if (_tcsicmp(TEXT("start"), argv[i] + 1) == 0) + { + BOOL is_auto = argc < i + 2 || _tcsicmp(TEXT("interactive"), argv[i + 1]) != 0; + return CmdStartService(is_auto ? automatic : interactive); + } + else if (argc > i + 2 && _tcsicmp(TEXT("instance"), argv[i] + 1) == 0) + { + dispatchTable = _tcsicmp(TEXT("interactive"), argv[i + 1]) != 0 ? + dispatchTable_automatic : + dispatchTable_interactive; - return 0; + service_instance = argv[i + 2]; + i += 2; + } + else + { + _tprintf(TEXT("%s -install to install the services\n"), APPNAME); + _tprintf(TEXT("%s -start <name> to start a service (\"automatic\" or \"interactive\")\n"), APPNAME); + _tprintf(TEXT("%s -remove to remove the services\n"), APPNAME); + + _tprintf(TEXT("\nService run-time parameters:\n")); + _tprintf(TEXT("-instance <name> <id>\n") + TEXT(" Runs the service as an alternate instance. <name> can be \"automatic\" or\n") + TEXT(" \"interactive\". The service settings will be loaded from\n") + TEXT(" HKLM\\Software\\" PACKAGE_NAME "<id> registry key, and the interactive service will accept\n") + TEXT(" requests on \\\\.\\pipe\\" PACKAGE "<id>\\service named pipe.\n")); + + return 0; + } + } } /* If it doesn't match any of the above parameters * the service control manager may be starting the service * so we must call StartServiceCtrlDispatcher */ -dispatch: - _tprintf(TEXT("%s -install to install the services\n"), APPNAME); - _tprintf(TEXT("%s -start <name> to start a service (\"automatic\" or \"interactive\")\n"), APPNAME); - _tprintf(TEXT("%s -remove to remove the services\n"), APPNAME); _tprintf(TEXT("\nStartServiceCtrlDispatcher being called.\n")); _tprintf(TEXT("This may take several seconds. Please wait.\n")); diff --git a/src/openvpnserv/service.h b/src/openvpnserv/service.h index 9fe573e..23b105f 100644 --- a/src/openvpnserv/service.h +++ b/src/openvpnserv/service.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2013-2017 Heiko Hund <heiko.hund@sophos.com> + * Copyright (C) 2013-2018 Heiko Hund <heiko.hund@sophos.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -73,10 +73,12 @@ typedef struct { extern openvpn_service_t automatic_service; extern openvpn_service_t interactive_service; +extern LPCTSTR service_instance; - +VOID WINAPI ServiceStartAutomaticOwn(DWORD argc, LPTSTR *argv); VOID WINAPI ServiceStartAutomatic(DWORD argc, LPTSTR *argv); +VOID WINAPI ServiceStartInteractiveOwn(DWORD argc, LPTSTR *argv); VOID WINAPI ServiceStartInteractive(DWORD argc, LPTSTR *argv); int openvpn_vsntprintf(LPTSTR str, size_t size, LPCTSTR format, va_list arglist); @@ -94,4 +96,7 @@ DWORD MsgToEventLog(DWORD flags, LPCTSTR lpszMsg, ...); /* Convert a utf8 string to utf16. Caller should free the result */ wchar_t *utf8to16(const char *utf8); +/* return windows system directory as a pointer to a static string */ +const wchar_t *get_win_sys_path(void); + #endif /* ifndef _SERVICE_H */ diff --git a/src/openvpnserv/validate.c b/src/openvpnserv/validate.c index f6a97e9..d35938c 100644 --- a/src/openvpnserv/validate.c +++ b/src/openvpnserv/validate.c @@ -44,6 +44,8 @@ static const WCHAR *white_list[] = L"setenv", L"service", L"verb", + L"pull-filter", + L"script-security", NULL /* last value */ }; @@ -65,7 +67,7 @@ CheckConfigPath(const WCHAR *workdir, const WCHAR *fname, const settings_t *s) /* convert fname to full path */ if (PathIsRelativeW(fname) ) { - snwprintf(tmp, _countof(tmp), L"%s\\%s", workdir, fname); + swprintf(tmp, _countof(tmp), L"%s\\%s", workdir, fname); tmp[_countof(tmp)-1] = L'\0'; config_file = tmp; } |