From patchwork Mon Oct 15 23:26:26 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Rozman X-Patchwork-Id: 556 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director10.mail.ord1d.rsapps.net ([172.31.255.6]) by backend30.mail.ord1d.rsapps.net with LMTP id iMBFCCm9xVs8DQAAIUCqbw for ; Tue, 16 Oct 2018 06:27:53 -0400 Received: from proxy6.mail.iad3b.rsapps.net ([172.31.255.6]) by director10.mail.ord1d.rsapps.net with LMTP id AJ6YBSm9xVtiYQAApN4f7A ; Tue, 16 Oct 2018 06:27:53 -0400 Received: from smtp3.gate.iad3b ([172.31.255.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy6.mail.iad3b.rsapps.net with LMTP id QIFYOyi9xVuffAAARawThA ; Tue, 16 Oct 2018 06:27:52 -0400 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO X-Virus-Scanned: OK X-Orig-To: openvpnslackdevel@openvpn.net X-Originating-Ip: [216.105.38.7] Authentication-Results: smtp3.gate.iad3b.rsapps.net; iprev=pass policy.iprev="216.105.38.7"; spf=pass smtp.mailfrom="openvpn-devel-bounces@lists.sourceforge.net" smtp.helo="lists.sourceforge.net"; dkim=fail (signature verification failed) header.d=sourceforge.net; dkim=fail (signature verification failed) header.d=sf.net; dkim=fail (signature verification failed) header.d=rozman.si; dmarc=fail (p=none; dis=none) header.from=rozman.si X-Suspicious-Flag: YES X-Classification-ID: 2299f546-d12e-11e8-8d58-525400bb3479-1-1 Received: from [216.105.38.7] ([216.105.38.7:3445] helo=lists.sourceforge.net) by smtp3.gate.iad3b.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 3F/E9-13753-82DB5CB5; Tue, 16 Oct 2018 06:27:52 -0400 Received: from [127.0.0.1] (helo=sfs-ml-1.v29.lw.sourceforge.com) by sfs-ml-1.v29.lw.sourceforge.com with esmtp (Exim 4.90_1) (envelope-from ) id 1gCMYu-0006rq-VG; Tue, 16 Oct 2018 10:26:52 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-1.v29.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1gCMYt-0006rW-8E for openvpn-devel@lists.sourceforge.net; Tue, 16 Oct 2018 10:26:51 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=/wDATU51nQTp/Q6gjI8ag7nd0kZy6ZLd3zRi4fKXLFc=; b=lDsMHz4QdL9ahRGHkZ+rEfTYdI 6RDs3BB1AYyOO+VVivWliMqbNbaWhGEEN8wlsDN7o845e0AKx4/4EAyhgSXYdohhRrTy2KVkd294K RON/XtwDrC3S5FDUzoYF+7mMmV5/jmmFll1NolhrBJRSgcd5FB9VxbP+A2H1+DEbeHKY=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=/wDATU51nQTp/Q6gjI8ag7nd0kZy6ZLd3zRi4fKXLFc=; b=COYs/f71Z5+iqTrlPn5IROfSy5 KvDeOWCfFCHD3jEnttLFO0USAVjwIAdEN9oyo4VG3mqtuXed6ARbBLzvHIVMFzXrPxeQ/cDcP6iK1 BHjyf3Sjq+AWWOZ+qzZY8ZzVEsdm1ervHbRDGwmVoO9a8UvGTlxDbjfboOEv/dhXk9CQ=; Received: from pub5.amebis.si ([213.250.55.21]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) id 1gCMYq-004nwZ-44 for openvpn-devel@lists.sourceforge.net; Tue, 16 Oct 2018 10:26:51 +0000 Received: from s0.selo.doma (unknown [213.250.22.160]) by pub5.amebis.si (Postfix) with ESMTPS id 0478F20D86 for ; Tue, 16 Oct 2018 12:26:37 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=rozman.si; s=default; t=1539685598; bh=oClKOzG06iJLJbTJAhtBPCJEwLd8hO5+r/bMKQzKShk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=J1vStOXUgcJRRw/TuxogUKV1m2E7MbwjfHGPcWIiEVWPqKk7tU3zCdbpVcLuegIPl iflA6WxO9AHAFKEug7ajv3j0vfLjW/n1kAg7Rtnw2F6/mScUtn+b9PnCkwqUQ/dgFq nGKULJT/xY25wsXJLlL0zOF7ZIGQLZtPBX0USURk= Received: from s0.selo.doma ([127.0.0.1]) by s0.selo.doma with Microsoft SMTPSVC(10.0.14393.0); Tue, 16 Oct 2018 12:26:37 +0200 From: Simon Rozman To: openvpn-devel@lists.sourceforge.net Date: Tue, 16 Oct 2018 12:26:26 +0200 Message-Id: <20181016102627.18676-4-simon@rozman.si> X-Mailer: git-send-email 2.19.0.windows.1 In-Reply-To: <20181016102627.18676-1-simon@rozman.si> References: <20181010192337.6984-1-simon@rozman.si> <20181016102627.18676-1-simon@rozman.si> MIME-Version: 1.0 X-OriginalArrivalTime: 16 Oct 2018 10:26:37.0791 (UTC) FILETIME=[B8771EF0:01D4653A] X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -0.0 SPF_PASS SPF: sender matches SPF record -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-Headers-End: 1gCMYq-004nwZ-44 Subject: [Openvpn-devel] [PATCH 4/5] Add MSI custom action for reliable Windows 10 detection X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox This patch introduces a `FindSystemInfo()` MSI custom action to reliably detect Windows 10. The MSI built-in properties for Windows version detection depend on bootstrapper's manifest. We could provide our own Windows 10 compatible EXE bootstrapper, but that would cover the Windows 10 detection in the `InstallUISequence` only. The `InstallExecuteSequence` is launched by msiexec.exe which we cannot tamper with would still report `VersionNT` as Windows 8 (603). Acked-by: Jon Kunkee --- src/openvpnmsica/Makefile.am | 2 +- src/openvpnmsica/openvpnmsica.c | 124 ++++++++++++++++++++++++++++++-- src/openvpnmsica/openvpnmsica.h | 15 ++++ 3 files changed, 136 insertions(+), 5 deletions(-) diff --git a/src/openvpnmsica/Makefile.am b/src/openvpnmsica/Makefile.am index d46170b4..ecca74bc 100644 --- a/src/openvpnmsica/Makefile.am +++ b/src/openvpnmsica/Makefile.am @@ -41,7 +41,7 @@ libopenvpnmsica_la_CFLAGS = \ -municode -D_UNICODE \ -UNTDDI_VERSION -U_WIN32_WINNT \ -D_WIN32_WINNT=_WIN32_WINNT_VISTA -libopenvpnmsica_la_LDFLAGS = -ladvapi32 -lole32 -lmsi -lsetupapi -lshlwapi -no-undefined -avoid-version +libopenvpnmsica_la_LDFLAGS = -ladvapi32 -lole32 -lmsi -lsetupapi -lshlwapi -lversion -no-undefined -avoid-version endif libopenvpnmsica_la_SOURCES = \ diff --git a/src/openvpnmsica/openvpnmsica.c b/src/openvpnmsica/openvpnmsica.c index 3b90ce05..d1642d6a 100644 --- a/src/openvpnmsica/openvpnmsica.c +++ b/src/openvpnmsica/openvpnmsica.c @@ -36,13 +36,15 @@ #include #include #include -#ifdef _MSC_VER -#pragma comment(lib, "shlwapi.lib") -#endif #include #include #include +#ifdef _MSC_VER +#pragma comment(lib, "shlwapi.lib") +#pragma comment(lib, "version.lib") +#endif + /** * Local constants @@ -119,7 +121,7 @@ openvpnmsica_setup_sequence_filename( { size_t len_action_name_z = _tcslen(openvpnmsica_cleanup_action_seqs[i].szName) + 1; TCHAR *szPropertyEx = (TCHAR*)malloc((len_property_name + len_action_name_z) * sizeof(TCHAR)); - memcpy(szPropertyEx , szProperty , len_property_name * sizeof(TCHAR)); + memcpy(szPropertyEx , szProperty , len_property_name * sizeof(TCHAR)); memcpy(szPropertyEx + len_property_name, openvpnmsica_cleanup_action_seqs[i].szName, len_action_name_z * sizeof(TCHAR)); _stprintf_s( szFilenameEx, _countof(szFilenameEx), @@ -142,6 +144,120 @@ openvpnmsica_setup_sequence_filename( } +UINT __stdcall +FindSystemInfo(_In_ MSIHANDLE hInstall) +{ +#ifdef _MSC_VER +#pragma comment(linker, DLLEXP_EXPORT) +#endif + +#ifdef _DEBUG + MessageBox(NULL, TEXT("Attach debugger!"), TEXT(__FUNCTION__) TEXT(" v") TEXT(PACKAGE_VERSION), MB_OK); +#endif + + UINT uiResult; + BOOL bIsCoInitialized = SUCCEEDED(CoInitialize(NULL)); + + /* Set MSI session handle in TLS. */ + struct openvpnmsica_tls_data *s = (struct openvpnmsica_tls_data *)TlsGetValue(openvpnmsica_tlsidx_session); + s->hInstall = hInstall; + + // Get Windows version. + OSVERSIONINFOEX ver_info = { .dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX) }; + if (!GetVersionEx((LPOSVERSIONINFO)&ver_info)) { + uiResult = GetLastError(); + msg(M_NONFATAL | M_ERRNO, "%s: GetVersionEx() failed", __FUNCTION__); + goto cleanup_CoInitialize; + } + + // The Windows version is usually spoofed, check using RtlGetVersion(). + TCHAR szDllPath[0x1000]; + ExpandEnvironmentStrings(TEXT("%SystemRoot%\\System32\\ntdll.dll"), szDllPath, +#ifdef UNICODE + _countof(szDllPath) +#else + _countof(szDllPath) - 1 +#endif + ); + HMODULE hNtDllModule = LoadLibrary(szDllPath); + if (hNtDllModule) + { + typedef NTSTATUS (WINAPI* fnRtlGetVersion)(PRTL_OSVERSIONINFOW); + fnRtlGetVersion RtlGetVersion = (fnRtlGetVersion)GetProcAddress(hNtDllModule, "RtlGetVersion"); + if (RtlGetVersion) + { + RTL_OSVERSIONINFOW rtl_ver_info = { .dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW) }; + if (RtlGetVersion(&rtl_ver_info) == 0) + if ( + rtl_ver_info.dwMajorVersion > ver_info.dwMajorVersion || + rtl_ver_info.dwMajorVersion == ver_info.dwMajorVersion && rtl_ver_info.dwMinorVersion > ver_info.dwMinorVersion || + rtl_ver_info.dwMajorVersion == ver_info.dwMajorVersion && rtl_ver_info.dwMinorVersion == ver_info.dwMinorVersion && rtl_ver_info.dwBuildNumber > ver_info.dwBuildNumber) + { + // We got RtlGetVersion() and it reported newer version than GetVersionEx(). + ver_info.dwMajorVersion = rtl_ver_info.dwMajorVersion; + ver_info.dwMinorVersion = rtl_ver_info.dwMinorVersion; + ver_info.dwBuildNumber = rtl_ver_info.dwBuildNumber; + ver_info.dwPlatformId = rtl_ver_info.dwPlatformId; + } + } + + FreeLibrary(hNtDllModule); + } + + // We don't trust RtlGetVersion() either. Check the version resource of kernel32.dll. + ExpandEnvironmentStrings(TEXT("%SystemRoot%\\System32\\kernel32.dll"), szDllPath, +#ifdef UNICODE + _countof(szDllPath) +#else + _countof(szDllPath)-1 +#endif + ); + + DWORD dwHandle; + DWORD dwVerInfoSize = GetFileVersionInfoSize(szDllPath, &dwHandle); + if (dwVerInfoSize) + { + LPVOID pVersionInfo = malloc(dwVerInfoSize); + if (pVersionInfo) + { + // Read version info. + if (GetFileVersionInfo(szDllPath, dwHandle, dwVerInfoSize, pVersionInfo)) + { + // Get the value for the root block. + UINT uiSize = 0; + VS_FIXEDFILEINFO *pVSFixedFileInfo = NULL; + if (VerQueryValue(pVersionInfo, TEXT("\\"), &pVSFixedFileInfo, &uiSize) && uiSize && pVSFixedFileInfo) + if (HIWORD(pVSFixedFileInfo->dwProductVersionMS) > ver_info.dwMajorVersion || + HIWORD(pVSFixedFileInfo->dwProductVersionMS) == ver_info.dwMajorVersion && LOWORD(pVSFixedFileInfo->dwProductVersionMS) > ver_info.dwMinorVersion || + HIWORD(pVSFixedFileInfo->dwProductVersionMS) == ver_info.dwMajorVersion && LOWORD(pVSFixedFileInfo->dwProductVersionMS) == ver_info.dwMinorVersion && HIWORD(pVSFixedFileInfo->dwProductVersionLS) > ver_info.dwBuildNumber) + { + // We got kernel32.dll version and it is newer. + ver_info.dwMajorVersion = HIWORD(pVSFixedFileInfo->dwProductVersionMS); + ver_info.dwMinorVersion = LOWORD(pVSFixedFileInfo->dwProductVersionMS); + ver_info.dwBuildNumber = HIWORD(pVSFixedFileInfo->dwProductVersionLS); + } + } + + free(pVersionInfo); + } + } + + uiResult = MsiSetProperty(hInstall, TEXT("DriverCertification"), ver_info.dwMajorVersion >= 10 ? ver_info.wProductType > VER_NT_WORKSTATION ? TEXT("whql") : TEXT("attsgn") : TEXT("")); + if (uiResult != ERROR_SUCCESS) + { + SetLastError(uiResult); /* MSDN does not mention MsiSetProperty() to set GetLastError(). But we do have an error code. Set last error manually. */ + msg(M_NONFATAL | M_ERRNO, "%s: MsiSetProperty(\"TAPINTERFACES\") failed", __FUNCTION__); + goto cleanup_CoInitialize; + } + + uiResult = ERROR_SUCCESS; + +cleanup_CoInitialize: + if (bIsCoInitialized) CoUninitialize(); + return uiResult; +} + + UINT __stdcall FindTAPInterfaces(_In_ MSIHANDLE hInstall) { diff --git a/src/openvpnmsica/openvpnmsica.h b/src/openvpnmsica/openvpnmsica.h index bb8e28ec..da145062 100644 --- a/src/openvpnmsica/openvpnmsica.h +++ b/src/openvpnmsica/openvpnmsica.h @@ -63,6 +63,21 @@ extern "C" { #endif +/** + * Determines Windows information: + * - Sets `DriverCertification` MSI property to "", "attsgn" or "whql" + * according to the driver certification required by the running version of + * Windows. + * + * @param hInstall Handle to the installation provided to the DLL custom action + * + * @return ERROR_SUCCESS on success; An error code otherwise + * See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa368072.aspx + */ +DLLEXP_DECL UINT __stdcall +FindSystemInfo(_In_ MSIHANDLE hInstall); + + /** * Find existing TAP interfaces and set TAPINTERFACES property with semicolon delimited list * of installed TAP interface GUIDs.