mirror of https://github.com/OpenVPN/openvpn-gui
Add a test program for PLAP provider module
- instantiate OpenVPN PLAP provider which will enumerate configs in config-auto directory. - Attempt to connect each config found one after the other The test program is deliberately written in C++ as that's how most Windows programs (and likely, LogonUI.exe) may use the COM object. Note that duplicate configs are ignored, so ensure that config files in config-auto are not "shadowed" by identical named one's in user's profile or in global config folder. Additional notes: The test program is not linked to the plap dll. Instead it finds the module using CoGetClassObject, so the plap dll must be registered in the system. It also tests dynamically loading the dll from C:\Program Files\OpenVPN\bin\libopenvpn_plap.dll which should succeed even if the registration is not proper. Signed-off-by: Selva Nair <selva.nair@gmail.com>pull/529/head
parent
a60b3c540b
commit
2ea4bf9229
|
@ -6,7 +6,7 @@ if(NOT VCPKG_MANIFEST_DIR)
|
|||
set(VCPKG_MANIFEST_DIR ${CMAKE_SOURCE_DIR}/vcpkg_manifests/openssl_3)
|
||||
endif()
|
||||
|
||||
project(openvpn-gui C)
|
||||
project(openvpn-gui C CXX)
|
||||
|
||||
add_executable(${PROJECT_NAME} WIN32
|
||||
access.c
|
||||
|
@ -139,10 +139,33 @@ target_compile_definitions(${PROJECT_NAME_PLAP} PRIVATE
|
|||
WIN32_LEAN_AND_MEAN
|
||||
HAVE_CONFIG_H)
|
||||
|
||||
if (NOT TEST_PLAP_EXE)
|
||||
set(TEST_PLAP_EXE "test_plap")
|
||||
endif()
|
||||
|
||||
add_executable(${TEST_PLAP_EXE}
|
||||
plap/test_plap.cpp
|
||||
plap/plap_common.c)
|
||||
|
||||
target_link_libraries(${TEST_PLAP_EXE} PRIVATE
|
||||
Rpcrt4
|
||||
Ole32
|
||||
Gdi32)
|
||||
|
||||
target_include_directories(${TEST_PLAP_EXE} PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR})
|
||||
target_compile_definitions(${TEST_PLAP_EXE} PRIVATE
|
||||
_UNICODE
|
||||
UNICODE
|
||||
WIN32_LEAN_AND_MEAN
|
||||
HAVE_CONFIG_H)
|
||||
|
||||
if(MSVC)
|
||||
# work around msvc generator Debug/Release directory ugliness, doesn't apply for Ninja
|
||||
set_target_properties(${PROJECT_NAME} ${PROJECT_NAME_PLAP} PROPERTIES
|
||||
set_target_properties(${PROJECT_NAME} ${PROJECT_NAME_PLAP} ${TEST_PLAP_EXE} PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/$<0:>
|
||||
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/$<0:>
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/$<0:>)
|
||||
endif(MSVC)
|
||||
|
||||
set_target_properties(${TEST_PLAP_EXE} PROPERTIES
|
||||
LINK_FLAGS " /MANIFEST:EMBED /MANIFESTINPUT:${CMAKE_SOURCE_DIR}/plap/test-plap.manifest ")
|
||||
|
|
|
@ -33,6 +33,7 @@ AM_INIT_AUTOMAKE([subdir-objects])
|
|||
AC_CANONICAL_HOST
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
AC_PROG_CC_C99
|
||||
AC_PROG_CXX
|
||||
AC_CHECK_TOOL([WINDRES], [windres])
|
||||
LT_INIT([win32-dll])
|
||||
LT_LANG([Windows Resource])
|
||||
|
|
|
@ -30,9 +30,13 @@ LTRCCOMPILE = $(LIBTOOL) --mode=compile --tag=RC $(RCCOMPILE)
|
|||
MAINTAINERCLEANFILES = \
|
||||
$(srcdir)/Makefile.in $(srcdir)/credentialprovider.h
|
||||
|
||||
#if ENABLE_OPENVPN_PLAP_TEST
|
||||
bin_PROGRAMS = test_plap
|
||||
#endif
|
||||
lib_LTLIBRARIES = libopenvpn_plap.la
|
||||
|
||||
libopenvpn_plap_la_CFLAGS = -DDISABLE_PASSWORD_CHANGE -D_UNICODE -municode
|
||||
test_plap_CXXFLAGS = -DDEBUG -D_UNICODE -municode
|
||||
|
||||
libopenvpn_plap_la_RESOURCES = \
|
||||
$(top_srcdir)/res/openvpn-gui-res-cs.rc \
|
||||
|
@ -101,3 +105,7 @@ libopenvpn_plap_la_LDFLAGS = -no-undefined -avoid-version -static-libgcc
|
|||
|
||||
credentialprovider.h:
|
||||
wget https://raw.githubusercontent.com/mirror/mingw-w64/master/mingw-w64-headers/include/credentialprovider.h
|
||||
|
||||
test_plap_SOURCES = test_plap.cpp test-plap-res.rc test-plap.manifest plap_common.c credentialprovider.h
|
||||
test_plap_LDFLAGS = -static-libgcc -static-libstdc++
|
||||
test_plap_LDADD = -lrpcrt4 -lole32 -lgdi32 -lcomctl32
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* OpenVPN-GUI -- A Windows GUI for OpenVPN.
|
||||
*
|
||||
* Copyright (C) 2009 Heiko Hund <heikoh@users.sf.net>
|
||||
*
|
||||
* 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 (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
|
||||
*/
|
||||
|
||||
/* Manifest for visual styles */
|
||||
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "test-plap.manifest"
|
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
|
||||
manifestVersion="1.0">
|
||||
<assemblyIdentity
|
||||
name="PLAP.TEST.Manifest"
|
||||
version="1.0.0.0"
|
||||
type="win32"/>
|
||||
<description>OpenVPN GUI PLAP DLL Test Program</description>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.Windows.Common-Controls"
|
||||
version="6.0.0.0"
|
||||
processorArchitecture="*"
|
||||
publicKeyToken="6595b64144ccf1df"
|
||||
language="*"/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel
|
||||
level="asInvoker"
|
||||
uiAccess="false"/>
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- Windows Vista -->
|
||||
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
|
||||
<!-- Windows 7 -->
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||
<!-- Windows 8 -->
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||
<!-- Windows 8.1 -->
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||
<asmv3:windowsSettings
|
||||
xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
|
||||
<!-- Per Monitor V1 [OS >= Windows 8.1]
|
||||
Values: False, True, Per-monitor, True/PM -->
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
|
||||
<!-- Per Monitor V1 [OS >= Windows 10 Anniversary Update (1607, 10.0.14393, Redstone 1)]
|
||||
Values: Unaware, System, PerMonitor -->
|
||||
<!-- Per Monitor V2 [OS >= Windows 10 Creators Update (1703, 10.0.15063, Redstone 2)]
|
||||
Value: PerMonitorV2 -->
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
|
||||
</asmv3:windowsSettings>
|
||||
</asmv3:application>
|
||||
</assembly>
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* OpenVPN-PLAP-Provider
|
||||
*
|
||||
* Copyright (C) 2019-2022 Selva Nair <selva.nair@gmail.com>
|
||||
*
|
||||
* 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 (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
|
||||
*/
|
||||
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <initguid.h>
|
||||
#include "plap_common.h"
|
||||
#include <windows.h>
|
||||
#include <credentialprovider.h>
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
|
||||
#define error_return(fname, hr) do { fwprintf(stdout, L"Error in %ls: status = 0x%08x", fname, hr);\
|
||||
return 1;} while (0)
|
||||
typedef HRESULT (WINAPI * f_func)(REFCLSID rclsid, REFIID riid, LPVOID* ppv);
|
||||
|
||||
class MyQueryContinue : public IQueryContinueWithStatus
|
||||
{
|
||||
public:
|
||||
STDMETHODIMP_(ULONG) AddRef() {
|
||||
return InterlockedIncrement(&ref_count);
|
||||
}
|
||||
STDMETHODIMP_(ULONG) Release() {
|
||||
int count = InterlockedDecrement(&ref_count);
|
||||
if (ref_count == 0) delete this;
|
||||
return count;
|
||||
}
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { return E_FAIL; }
|
||||
STDMETHODIMP QueryContinue() {return time(NULL) > timeout ? S_FALSE : S_OK;}
|
||||
STDMETHODIMP SetStatusMessage(const wchar_t *ws) { wprintf(L"%ls\r", ws); return S_OK; }
|
||||
MyQueryContinue() : ref_count(1) {};
|
||||
time_t timeout;
|
||||
|
||||
private:
|
||||
~MyQueryContinue()=default;
|
||||
LONG ref_count;
|
||||
};
|
||||
|
||||
static int test_provider(IClassFactory *cf)
|
||||
{
|
||||
assert(cf != NULL);
|
||||
ICredentialProvider *o = NULL;
|
||||
HRESULT hr;
|
||||
|
||||
hr = cf->CreateInstance(NULL, IID_ICredentialProvider, (void**) &o);
|
||||
|
||||
if (!SUCCEEDED(hr)) error_return(L"IID_ICredentialProvider", hr);
|
||||
|
||||
hr = o->SetUsageScenario(CPUS_PLAP, 0);
|
||||
if (!SUCCEEDED(hr)) error_return(L"SetUsageScenario", hr);
|
||||
|
||||
DWORD count, def;
|
||||
BOOL auto_def;
|
||||
hr = o->GetCredentialCount(&count, &def, &auto_def);
|
||||
if (!SUCCEEDED(hr)) error_return(L"GetCredentialCount", hr);
|
||||
|
||||
fwprintf(stdout, L"credential count = %lu, default = %d, autologon = %d\n", count, (int) def, auto_def);
|
||||
if (count < 1) fwprintf(stdout, L"No persistent configs found!\n");
|
||||
|
||||
ICredentialProviderCredential *c = NULL;
|
||||
MyQueryContinue *qc = new MyQueryContinue();
|
||||
for (DWORD i = 0; i < count; i++)
|
||||
{
|
||||
hr = o->GetCredentialAt(i, &c);
|
||||
if (!SUCCEEDED(hr)) error_return(L"GetCredentialAt", hr);
|
||||
|
||||
fwprintf(stdout, L"credential # = %lu: ", i);
|
||||
wchar_t *ws;
|
||||
|
||||
for (DWORD j = 0; j < 4; j++)
|
||||
{
|
||||
hr = c->GetStringValue(j, &ws);
|
||||
if (!SUCCEEDED(hr)) error_return(L"GetStringValue", hr);
|
||||
CoTaskMemFree(ws);
|
||||
}
|
||||
|
||||
/* test getbitmap */
|
||||
HBITMAP bmp;
|
||||
hr = c->GetBitmapValue(0, &bmp);
|
||||
if (!SUCCEEDED(hr))
|
||||
fwprintf(stdout, L"Warning: could not get bitmap"); /* not fatal */
|
||||
else
|
||||
DeleteObject(bmp);
|
||||
|
||||
/* set a time out so that we can move to next config in case */
|
||||
qc->timeout = time(NULL) + 20;
|
||||
|
||||
/* get a connection instance and call connect on it */
|
||||
IConnectableCredentialProviderCredential *c1 = NULL;
|
||||
hr = c->QueryInterface(IID_IConnectableCredentialProviderCredential, (void**)&c1);
|
||||
|
||||
fwprintf(stdout, L"\nConnecting connection # <%lu>\n", i);
|
||||
c1->Connect(qc); /* this will return when connected/failed or qc timesout */
|
||||
|
||||
fwprintf(stdout, L"\nsleep for 2 sec\n");
|
||||
Sleep(2000);
|
||||
c1->Release();
|
||||
}
|
||||
|
||||
assert(o->Release() == 0); /* check refcount */
|
||||
assert(qc->Release() == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wmain()
|
||||
{
|
||||
HRESULT hr;
|
||||
_setmode(_fileno(stdout), _O_U16TEXT);
|
||||
_setmode(_fileno(stderr), _O_U16TEXT);
|
||||
|
||||
IClassFactory *cf = NULL;
|
||||
DWORD ctx = CLSCTX_INPROC_SERVER;
|
||||
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
if (!SUCCEEDED(hr)) error_return(L"CoIntialize", hr);
|
||||
|
||||
/* Test by loading the dll */
|
||||
fwprintf(stdout, L"Test plap dll direct loading\n");
|
||||
|
||||
HMODULE lib = LoadLibraryW(L"C:\\Program Files\\OpenVPN\\bin\\libopenvpn_plap.dll");
|
||||
f_func func = NULL;
|
||||
if (lib == NULL)
|
||||
{
|
||||
fwprintf(stderr, L"Failed to load the dll: error = 0x%08x\n", GetLastError());
|
||||
}
|
||||
else {
|
||||
func = (f_func) GetProcAddress(lib, "DllGetClassObject");
|
||||
if (!func)
|
||||
fwprintf(stderr, L"Failed to find DllGetClassObject in dll: error = 0x%08x\n", GetLastError());
|
||||
}
|
||||
if (func) {
|
||||
hr = func(CLSID_OpenVPNProvider, IID_IClassFactory, (void **)&cf);
|
||||
if (!SUCCEEDED(hr)) fwprintf(stdout, L"Error in DllGetClassObject: status = 0x%08x\n", hr);
|
||||
else {
|
||||
fwprintf(stdout, L"Success: found ovpn provider class factory by direct access\n");
|
||||
cf->Release();
|
||||
}
|
||||
}
|
||||
|
||||
/* Test by finding the class through COM's registration mechanism */
|
||||
fwprintf(stdout, L"Testing plap using CoGetclassobject -- requires proper dll registration\n");
|
||||
|
||||
hr = CoGetClassObject(CLSID_OpenVPNProvider, ctx, NULL, IID_IClassFactory, (void **)&cf);
|
||||
if (SUCCEEDED(hr)) {
|
||||
test_provider(cf);
|
||||
cf->Release();
|
||||
}
|
||||
else {
|
||||
fwprintf(stdout, L"CoGetClassObject (class not registered?): error = 0x%08x\n", hr);
|
||||
}
|
||||
|
||||
CoUninitialize();
|
||||
if (lib) {
|
||||
FreeLibrary(lib);
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue