Add copyright notice as required where Microsoft has contributed code Signed-off-by: Kevin Kane <kk...@microsoft.com> --- src/openvpnserv/service.c | 241 +++++++++++++++++++++++++++++++++++--- 1 file changed, 222 insertions(+), 19 deletions(-)
diff --git a/src/openvpnserv/service.c b/src/openvpnserv/service.c index 7157bea2..edb21b0d 100644 --- a/src/openvpnserv/service.c +++ b/src/openvpnserv/service.c @@ -6,6 +6,7 @@ * * Copyright (C) 1993 - 2000. Microsoft Corporation. All rights reserved. * 2013 Heiko Hund <heiko.h...@sophos.com> + * Portions Copyright (C) 2018 Microsoft Corporation */ #include "service.h" @@ -53,6 +54,195 @@ ReportStatusToSCMgr(SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status) return res; } +static const TCHAR DialerDllName[] = TEXT("libopenvpndialer-0.dll"); +static const TCHAR RegValueName[] = TEXT("CustomDLL"); + +static int +HandleDialerRegistration(int uninstall) +{ + TCHAR path[512], customDllString[1024]; + HKEY parametersKey; + LONG result; + DWORD customDllSize = sizeof(customDllString); + + /* Assumption is that the dialer DLL is installed to the same bin directory as everything else. */ + if (GetModuleFileName(NULL, path, sizeof(path)) == 0) + { + _tprintf(TEXT("Unable to get module path - %lu\n"), GetLastError()); + return 1; + } + + /* The version of NSIS we use to create the installer doesn't yet have support for + * writing multi-string registry entries, which we need to do in order to register our + * custom dialer DLL. Instead, we'll update this registry entry on install/uninstall. + */ + + TCHAR *lastBackslash = _tcsrchr(path, TEXT('\\')); + if (NULL == lastBackslash) + { + _tprintf(TEXT("Could not locate last backslash in path: %s\n"), path); + return 1; + } + + lastBackslash[1] = TEXT('\0'); + + /* Bounds checking. */ + if ((_tcslen(path) + _countof(DialerDllName)) > _countof(path)) + { + _tprintf(TEXT("Out of buffer adding dialer filename to path")); + return 1; + } + + _tcscat(path, DialerDllName); + + result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + TEXT("SYSTEM\\CurrentControlSet\\Services\\RasMan\\Parameters"), + 0, + KEY_ALL_ACCESS, + ¶metersKey); + if (ERROR_SUCCESS != result) + { + _tprintf(TEXT("Could not open RasMan parameters key: %ld\n"), result); + return 1; + } + + /* Must RegCloseKey(parametersKey) from this point */ + + result = RegGetValue(parametersKey, + NULL, + RegValueName, + RRF_RT_REG_MULTI_SZ, + NULL, + customDllString, + &customDllSize); + + /* If we're installing, the key being absent is okay. Any other error is fatal. */ + if (ERROR_FILE_NOT_FOUND == result) + { + if (0 != uninstall) + { + _tprintf(TEXT("CustomDLL value was not found; skipping unregistration step\n")); + RegCloseKey(parametersKey); + return 0; /* Not a fatal error but nothing to do */ + } + else + { + result = ERROR_SUCCESS; + customDllString[0] = TEXT('\0'); + customDllSize = 0; + } + } + else if (ERROR_SUCCESS != result) + { + _tprintf(TEXT("Could not open CustomDLL value: %ld\n"), result); + RegCloseKey(parametersKey); + return 1; + } + + /* Determine if the custom dialer DLL is present in the registry setting. This is a multi-string so we can't + * use _tcsstr. + */ + TCHAR* p; + for (p = customDllString; *p != TEXT('\0'); p += _tcslen(p) + 1) + { + if (0 == _tcsicmp(path, p)) + { + /* It is. p points to where it begins. */ + break; + } + } + /* If it's not present, p points at a NULL terminator. */ + + /* If we're installing and the DLL is present in the registry, do nothing. */ + /* If we're uninstalling and the DLL is not present in the registry, do nothing. */ + if ( ((0 == uninstall) && (*p != TEXT('\0'))) || + ((0 != uninstall) && (*p == TEXT('\0'))) ) + { + RegCloseKey(parametersKey); + return 0; + } + + /* If we're installing and the DLL is not present in the registry, append it at point p. */ + if ((0 == uninstall) && (*p == TEXT('\0'))) + { + /* Make sure the string buffer has enough space left. p points at the second in the double-terminating null + * (or the sole NULL if the registry entry was empty or absent). + */ + if (((p - customDllString) + _tcslen(path) + 2) > _countof(customDllString)) + { + _tprintf(TEXT("Not enough buffer to create new CustomDLL string\n")); + RegCloseKey(parametersKey); + return 1; + } + _tcscpy(p, path); + /* Add second terminating NULL we overwrote with the copy. */ + p += _tcslen(p) + 1; + *p++ = TEXT('\0'); + + /* Set in the registry. */ + result = RegSetValueEx(parametersKey, + RegValueName, + 0, + REG_MULTI_SZ, + (const BYTE*)customDllString, + (DWORD)(sizeof(TCHAR) * (p - customDllString))); + + RegCloseKey(parametersKey); + if (ERROR_SUCCESS != result) + { + _tprintf(TEXT("Failed to RegSetValueEx: %ld\n"), result); + return 1; + } + } + /* Else if we're uninstalling and the DLL is present, copy everything except strings matching path. */ + else if ((0 != uninstall) && (*p != TEXT('\0'))) + { + TCHAR newCustomDllString[1024]; + TCHAR *n, *c; + + /* newCustomDllString is the same size as customDllString, and we're only removing, so no + * way to overflow the buffer. + */ + for (c = customDllString, n = newCustomDllString; *c != TEXT('\0'); c += _tcslen(c) + 1) + { + if (0 != _tcsicmp(path, c)) + { + _tcscpy(n, c); + n += _tcslen(n) + 1; + } + } + + /* Add double-terminating NULL as is required for a multi-string. */ + *n++ = TEXT('\0'); + + /* If the new string is nonempty, set in the registry. Otherwise delete the value. */ + if (TEXT('\0') != *newCustomDllString) + { + result = RegSetValueEx(parametersKey, + RegValueName, + 0, + REG_MULTI_SZ, + (const BYTE*)newCustomDllString, + (DWORD)(sizeof(TCHAR) * (n - newCustomDllString))); + } + else + { + result = RegDeleteValue(parametersKey, RegValueName); + } + + RegCloseKey(parametersKey); + if (ERROR_SUCCESS != result) + { + _tprintf(TEXT("Failed to %s new registry value: %ld\n"), + (TEXT('\0') != *newCustomDllString)?TEXT("set"):TEXT("delete"), + result); + return 1; + } + } + + return 0; +} + static int CmdInstallServices() { @@ -77,27 +267,35 @@ CmdInstallServices() return 1; } - for (i = 0; i < _service_max; i++) + if (0 != HandleDialerRegistration(0)) { - service = CreateService(svc_ctl_mgr, - openvpn_service[i].name, - openvpn_service[i].display_name, - SERVICE_QUERY_STATUS, - SERVICE_WIN32_SHARE_PROCESS, - openvpn_service[i].start_type, - SERVICE_ERROR_NORMAL, - path, NULL, NULL, - openvpn_service[i].dependencies, - NULL, NULL); - if (service) - { - _tprintf(TEXT("%s installed.\n"), openvpn_service[i].display_name); - CloseServiceHandle(service); - --ret; - } - else + _tprintf(TEXT("HandleDialerRegistration failed\n")); + ret = 1; + } + else + { + for (i = 0; i < _service_max; i++) { - _tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText()); + service = CreateService(svc_ctl_mgr, + openvpn_service[i].name, + openvpn_service[i].display_name, + SERVICE_QUERY_STATUS, + SERVICE_WIN32_SHARE_PROCESS, + openvpn_service[i].start_type, + SERVICE_ERROR_NORMAL, + path, NULL, NULL, + openvpn_service[i].dependencies, + NULL, NULL); + if (service) + { + _tprintf(TEXT("%s installed.\n"), openvpn_service[i].display_name); + CloseServiceHandle(service); + --ret; + } + else + { + _tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText()); + } } } @@ -160,6 +358,11 @@ CmdRemoveServices() return 1; } + if (0 != HandleDialerRegistration(1)) + { + _tprintf(TEXT("HandleDialerRegistration uninstall failed; ignoring\n")); + } + for (i = 0; i < _service_max; i++) { openvpn_service_t *ovpn_svc = &openvpn_service[i]; -- 2.17.1.windows.2 ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Openvpn-devel mailing list Openvpn-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openvpn-devel