api: test the temporary driver idea
1. Add driver to the store: SetupCopyOEMInfW() 2. Create the adapter using explicit path to .inf file: DI_ENUMSINGLEINF 3. Delete all Wintun drivers from the store. This is a subject of further research: - It appears those adapters survive a reboot. So, Windows must store the driver somewhere on the disk and the driver removal is not completed. If the driver removal is not completed until there are existing adapters, this is excellent, as it will provide a self-cleanup. - Test multiple adapters with different driver versions. Which driver wins? - Are other Wintun adapters interrupted when adding a new one? - Test Windows 7 behaviour. Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
parent
8272da638e
commit
d04721dee6
190
api/adapter.c
190
api/adapter.c
@ -5,6 +5,8 @@
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#pragma warning(disable : 4221) /* nonstandard: address of automatic in initializer */
|
||||
|
||||
#define WAIT_FOR_REGISTRY_TIMEOUT 10000 /* ms */
|
||||
#define MAX_POOL_DEVICE_TYPE (MAX_POOL + 8) /* Should accommodate a pool name with " Tunnel" appended */
|
||||
|
||||
@ -819,8 +821,106 @@ IsNewer(_In_ const SP_DRVINFO_DATA_W *DrvInfoData, _In_ const FILETIME *DriverDa
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WINTUN_STATUS WINAPI
|
||||
WintunCreateAdapter(
|
||||
#if defined(HAVE_EV) || defined(HAVE_WHQL)
|
||||
|
||||
/* We can't use RtlGetVersion, because appcompat's aclayers.dll shims it to report Vista
|
||||
* when run from legacy contexts. So, we instead use the undocumented RtlGetNtVersionNumbers.
|
||||
*
|
||||
* Another way would be reading from the PEB directly:
|
||||
* ((DWORD *)NtCurrentTeb()->ProcessEnvironmentBlock)[sizeof(void *) == 8 ? 70 : 41]
|
||||
* Or just read from KUSER_SHARED_DATA the same way on 32-bit and 64-bit:
|
||||
* *(DWORD *)0x7FFE026C
|
||||
*/
|
||||
extern VOID NTAPI
|
||||
RtlGetNtVersionNumbers(_Out_opt_ DWORD *MajorVersion, _Out_opt_ DWORD *MinorVersion, _Out_opt_ DWORD *BuildNumber);
|
||||
|
||||
static BOOL
|
||||
HaveWHQL()
|
||||
{
|
||||
# if defined(HAVE_EV) && defined(HAVE_WHQL)
|
||||
DWORD MajorVersion;
|
||||
RtlGetNtVersionNumbers(&MajorVersion, NULL, NULL);
|
||||
return MajorVersion >= 10;
|
||||
# elif defined(HAVE_EV)
|
||||
return FALSE;
|
||||
# elif defined(HAVE_WHQL)
|
||||
return TRUE;
|
||||
# endif
|
||||
}
|
||||
|
||||
static WINTUN_STATUS
|
||||
InstallCertificate(_In_z_ const WCHAR *SignedResource)
|
||||
{
|
||||
LOG(WINTUN_LOG_INFO, L"Trusting code signing certificate");
|
||||
const VOID *LockedResource;
|
||||
DWORD SizeResource;
|
||||
DWORD Result = ResourceGetAddress(SignedResource, &LockedResource, &SizeResource);
|
||||
if (Result != ERROR_SUCCESS)
|
||||
return LOG(WINTUN_LOG_ERR, L"Failed to locate resource"), Result;
|
||||
const CERT_BLOB CertBlob = { .cbData = SizeResource, .pbData = (BYTE *)LockedResource };
|
||||
HCERTSTORE QueriedStore;
|
||||
if (!CryptQueryObject(
|
||||
CERT_QUERY_OBJECT_BLOB,
|
||||
&CertBlob,
|
||||
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
|
||||
CERT_QUERY_FORMAT_FLAG_ALL,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
&QueriedStore,
|
||||
0,
|
||||
NULL))
|
||||
return LOG_LAST_ERROR(L"Failed to find certificate");
|
||||
HCERTSTORE TrustedStore =
|
||||
CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"TrustedPublisher");
|
||||
if (!TrustedStore)
|
||||
{
|
||||
Result = LOG_LAST_ERROR(L"Failed to open store");
|
||||
goto cleanupQueriedStore;
|
||||
}
|
||||
LPSTR CodeSigningOid[] = { szOID_PKIX_KP_CODE_SIGNING };
|
||||
CERT_ENHKEY_USAGE EnhancedUsage = { .cUsageIdentifier = 1, .rgpszUsageIdentifier = CodeSigningOid };
|
||||
for (const CERT_CONTEXT *CertContext = NULL; (CertContext = CertFindCertificateInStore(
|
||||
QueriedStore,
|
||||
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
|
||||
CERT_FIND_ENHKEY_USAGE,
|
||||
&EnhancedUsage,
|
||||
CertContext)) != NULL;)
|
||||
{
|
||||
CERT_EXTENSION *Ext = CertFindExtension(
|
||||
szOID_BASIC_CONSTRAINTS2, CertContext->pCertInfo->cExtension, CertContext->pCertInfo->rgExtension);
|
||||
CERT_BASIC_CONSTRAINTS2_INFO Constraints;
|
||||
DWORD Size = sizeof(Constraints);
|
||||
if (Ext &&
|
||||
CryptDecodeObjectEx(
|
||||
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||
szOID_BASIC_CONSTRAINTS2,
|
||||
Ext->Value.pbData,
|
||||
Ext->Value.cbData,
|
||||
0,
|
||||
NULL,
|
||||
&Constraints,
|
||||
&Size) &&
|
||||
!Constraints.fCA)
|
||||
if (!CertAddCertificateContextToStore(TrustedStore, CertContext, CERT_STORE_ADD_REPLACE_EXISTING, NULL))
|
||||
{
|
||||
LOG_LAST_ERROR(L"Failed to add certificate to store");
|
||||
Result = Result != ERROR_SUCCESS ? Result : GetLastError();
|
||||
}
|
||||
}
|
||||
CertCloseStore(TrustedStore, 0);
|
||||
cleanupQueriedStore:
|
||||
CertCloseStore(QueriedStore, 0);
|
||||
return Result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static WINTUN_STATUS
|
||||
CreateAdapter(
|
||||
_In_z_count_c_(MAX_PATH) const WCHAR *InfPath,
|
||||
_In_z_count_c_(MAX_POOL) const WCHAR *Pool,
|
||||
_In_z_count_c_(MAX_ADAPTER_NAME) const WCHAR *Name,
|
||||
_In_opt_ const GUID *RequestedGUID,
|
||||
@ -856,7 +956,19 @@ WintunCreateAdapter(
|
||||
Result = LOG_LAST_ERROR(L"Creating new device information element failed");
|
||||
goto cleanupDevInfo;
|
||||
}
|
||||
SetQuietInstall(DevInfo, &DevInfoData);
|
||||
SP_DEVINSTALL_PARAMS_W DevInstallParams = { .cbSize = sizeof(SP_DEVINSTALL_PARAMS_W) };
|
||||
if (!SetupDiGetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams))
|
||||
{
|
||||
Result = LOG_LAST_ERROR(L"Retrieving device installation parameters failed");
|
||||
goto cleanupDevInfo;
|
||||
}
|
||||
DevInstallParams.Flags |= DI_QUIETINSTALL | DI_ENUMSINGLEINF;
|
||||
wcscpy_s(DevInstallParams.DriverPath, _countof(DevInstallParams.DriverPath), InfPath);
|
||||
if (!SetupDiSetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams))
|
||||
{
|
||||
Result = LOG_LAST_ERROR(L"Setting device installation parameters failed");
|
||||
goto cleanupDevInfo;
|
||||
}
|
||||
|
||||
if (!SetupDiSetSelectedDevice(DevInfo, &DevInfoData))
|
||||
{
|
||||
@ -1091,6 +1203,78 @@ cleanupMutex:
|
||||
return Result;
|
||||
}
|
||||
|
||||
WINTUN_STATUS WINAPI
|
||||
WintunCreateAdapter(
|
||||
_In_z_count_c_(MAX_POOL) const WCHAR *Pool,
|
||||
_In_z_count_c_(MAX_ADAPTER_NAME) const WCHAR *Name,
|
||||
_In_opt_ const GUID *RequestedGUID,
|
||||
_Out_ WINTUN_ADAPTER **Adapter,
|
||||
_Inout_ BOOL *RebootRequired)
|
||||
{
|
||||
#if defined(HAVE_EV) || defined(HAVE_WHQL)
|
||||
WCHAR WindowsDirectory[MAX_PATH];
|
||||
if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory)))
|
||||
return LOG_LAST_ERROR(L"Failed to get Windows folder");
|
||||
WCHAR WindowsTempDirectory[MAX_PATH];
|
||||
if (!PathCombineW(WindowsTempDirectory, WindowsDirectory, L"Temp"))
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
UCHAR RandomBytes[32] = { 0 };
|
||||
# pragma warning(suppress : 6387)
|
||||
if (!RtlGenRandom(RandomBytes, sizeof(RandomBytes)))
|
||||
return LOG_LAST_ERROR(L"Failed to generate random");
|
||||
WCHAR RandomSubDirectory[sizeof(RandomBytes) * 2 + 1];
|
||||
for (int i = 0; i < sizeof(RandomBytes); ++i)
|
||||
swprintf_s(&RandomSubDirectory[i * 2], 3, L"%02x", RandomBytes[i]);
|
||||
WCHAR RandomTempSubDirectory[MAX_PATH];
|
||||
if (!PathCombineW(RandomTempSubDirectory, WindowsTempDirectory, RandomSubDirectory))
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
if (!CreateDirectoryW(RandomTempSubDirectory, SecurityAttributes))
|
||||
return LOG_LAST_ERROR(L"Failed to create temporary folder");
|
||||
|
||||
DWORD Result = ERROR_SUCCESS;
|
||||
WCHAR CatPath[MAX_PATH] = { 0 };
|
||||
WCHAR SysPath[MAX_PATH] = { 0 };
|
||||
WCHAR InfPath[MAX_PATH] = { 0 };
|
||||
if (!PathCombineW(CatPath, RandomTempSubDirectory, L"wintun.cat") ||
|
||||
!PathCombineW(SysPath, RandomTempSubDirectory, L"wintun.sys") ||
|
||||
!PathCombineW(InfPath, RandomTempSubDirectory, L"wintun.inf"))
|
||||
{
|
||||
Result = ERROR_BUFFER_OVERFLOW;
|
||||
goto cleanupDirectory;
|
||||
}
|
||||
|
||||
BOOL UseWHQL = HaveWHQL();
|
||||
if (!UseWHQL && (Result = InstallCertificate(L"wintun.sys")) != ERROR_SUCCESS)
|
||||
LOG(WINTUN_LOG_WARN, L"Unable to install code signing certificate");
|
||||
|
||||
LOG(WINTUN_LOG_INFO, L"Copying resources to temporary path");
|
||||
if ((Result = ResourceCopyToFile(CatPath, UseWHQL ? L"wintun-whql.cat" : L"wintun.cat")) != ERROR_SUCCESS ||
|
||||
(Result = ResourceCopyToFile(SysPath, UseWHQL ? L"wintun-whql.sys" : L"wintun.sys")) != ERROR_SUCCESS ||
|
||||
(Result = ResourceCopyToFile(InfPath, UseWHQL ? L"wintun-whql.inf" : L"wintun.inf")) != ERROR_SUCCESS)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Failed to copy resources");
|
||||
goto cleanupDelete;
|
||||
}
|
||||
|
||||
LOG(WINTUN_LOG_INFO, L"Installing driver");
|
||||
if (!SetupCopyOEMInfW(InfPath, NULL, SPOST_PATH, 0, NULL, 0, NULL, NULL))
|
||||
{
|
||||
Result = LOG_LAST_ERROR(L"Could not install driver to store");
|
||||
goto cleanupDelete;
|
||||
}
|
||||
|
||||
Result = CreateAdapter(InfPath, Pool, Name, RequestedGUID, Adapter, RebootRequired);
|
||||
DriverRemoveAllOurs();
|
||||
cleanupDelete:
|
||||
DeleteFileW(CatPath);
|
||||
DeleteFileW(SysPath);
|
||||
DeleteFileW(InfPath);
|
||||
cleanupDirectory:
|
||||
RemoveDirectoryW(RandomTempSubDirectory);
|
||||
return Result;
|
||||
#endif
|
||||
}
|
||||
|
||||
WINTUN_STATUS WINAPI
|
||||
WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _Inout_ BOOL *RebootRequired)
|
||||
{
|
||||
|
378
api/driver.c
378
api/driver.c
@ -26,330 +26,7 @@ DriverIsOurDrvInfoDetail(_In_ const SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData)
|
||||
|
||||
#if defined(HAVE_EV) || defined(HAVE_WHQL)
|
||||
|
||||
/* We can't use RtlGetVersion, because appcompat's aclayers.dll shims it to report Vista
|
||||
* when run from legacy contexts. So, we instead use the undocumented RtlGetNtVersionNumbers.
|
||||
*
|
||||
* Another way would be reading from the PEB directly:
|
||||
* ((DWORD *)NtCurrentTeb()->ProcessEnvironmentBlock)[sizeof(void *) == 8 ? 70 : 41]
|
||||
* Or just read from KUSER_SHARED_DATA the same way on 32-bit and 64-bit:
|
||||
* *(DWORD *)0x7FFE026C
|
||||
*/
|
||||
extern VOID NTAPI
|
||||
RtlGetNtVersionNumbers(_Out_opt_ DWORD *MajorVersion, _Out_opt_ DWORD *MinorVersion, _Out_opt_ DWORD *BuildNumber);
|
||||
|
||||
static BOOL
|
||||
HaveWHQL()
|
||||
{
|
||||
# if defined(HAVE_EV) && defined(HAVE_WHQL)
|
||||
DWORD MajorVersion;
|
||||
RtlGetNtVersionNumbers(&MajorVersion, NULL, NULL);
|
||||
return MajorVersion >= 10;
|
||||
# elif defined(HAVE_EV)
|
||||
return FALSE;
|
||||
# elif defined(HAVE_WHQL)
|
||||
return TRUE;
|
||||
# endif
|
||||
}
|
||||
|
||||
static const CHAR *
|
||||
SkipWSpace(_In_ const CHAR *Beg, _In_ const CHAR *End)
|
||||
{
|
||||
for (; Beg < End && iswspace(*Beg); ++Beg)
|
||||
;
|
||||
return Beg;
|
||||
}
|
||||
|
||||
static const CHAR *
|
||||
SkipNonLF(_In_ const CHAR *Beg, _In_ const CHAR *End)
|
||||
{
|
||||
for (; Beg < End && *Beg != '\n'; ++Beg)
|
||||
;
|
||||
return Beg;
|
||||
}
|
||||
|
||||
WINTUN_STATUS
|
||||
DriverGetVersion(_Out_ FILETIME *DriverDate, _Out_ DWORDLONG *DriverVersion)
|
||||
{
|
||||
const VOID *LockedResource;
|
||||
DWORD SizeResource;
|
||||
DWORD Result = ResourceGetAddress(HaveWHQL() ? L"wintun-whql.inf" : L"wintun.inf", &LockedResource, &SizeResource);
|
||||
if (Result != ERROR_SUCCESS)
|
||||
return LOG(WINTUN_LOG_ERR, L"Failed to locate resource"), Result;
|
||||
enum
|
||||
{
|
||||
SectNone,
|
||||
SectUnknown,
|
||||
SectVersion
|
||||
} Section = SectNone;
|
||||
for (const CHAR *Inf = (const CHAR *)LockedResource, *InfEnd = Inf + SizeResource; Inf < InfEnd; ++Inf)
|
||||
{
|
||||
if (*Inf == ';')
|
||||
{
|
||||
Inf = SkipNonLF(Inf + 1, InfEnd);
|
||||
continue;
|
||||
}
|
||||
Inf = SkipWSpace(Inf, InfEnd);
|
||||
if (*Inf == '[')
|
||||
{
|
||||
Section = Inf + 9 <= InfEnd && !_strnicmp(Inf, "[Version]", 9) ? SectVersion : SectUnknown;
|
||||
}
|
||||
else if (Section == SectVersion)
|
||||
{
|
||||
if (Inf + 9 <= InfEnd && !_strnicmp(Inf, "DriverVer", 9))
|
||||
{
|
||||
Inf = SkipWSpace(Inf + 9, InfEnd);
|
||||
if (Inf < InfEnd && *Inf == '=')
|
||||
{
|
||||
Inf = SkipWSpace(Inf + 1, InfEnd);
|
||||
/* Duplicate buffer, as RT_RCDATA resource is not guaranteed to be zero-terminated. */
|
||||
CHAR buf[0x100];
|
||||
size_t n = InfEnd - Inf;
|
||||
if (n >= _countof(buf))
|
||||
n = _countof(buf) - 1;
|
||||
strncpy_s(buf, _countof(buf), Inf, n);
|
||||
buf[n] = 0;
|
||||
const CHAR *p = buf;
|
||||
CHAR *p_next;
|
||||
unsigned long date[3] = { 0, 0, 0 };
|
||||
for (size_t i = 0;; ++i, ++p)
|
||||
{
|
||||
date[i] = strtoul(p, &p_next, 10);
|
||||
p = p_next;
|
||||
if (i >= _countof(date) - 1)
|
||||
break;
|
||||
if (*p != '/' && *p != '-')
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Unexpected date delimiter");
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
}
|
||||
if (date[0] < 1 || date[0] > 12 || date[1] < 1 || date[1] > 31 || date[2] < 1601 || date[2] > 30827)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Invalid date");
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
const SYSTEMTIME st = { .wYear = (WORD)date[2], .wMonth = (WORD)date[0], .wDay = (WORD)date[1] };
|
||||
SystemTimeToFileTime(&st, DriverDate);
|
||||
p = SkipWSpace(p, buf + n);
|
||||
ULONGLONG version[4] = { 0, 0, 0, 0 };
|
||||
if (*p == ',')
|
||||
{
|
||||
p = SkipWSpace(p + 1, buf + n);
|
||||
for (size_t i = 0;; ++i, ++p)
|
||||
{
|
||||
version[i] = strtoul(p, &p_next, 10);
|
||||
if (version[i] > 0xffff)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Version field may not exceed 65535");
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
p = p_next;
|
||||
if (i >= _countof(version) - 1 || !*p || *p == ';' || iswspace(*p))
|
||||
break;
|
||||
if (*p != '.')
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Unexpected version delimiter");
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
}
|
||||
}
|
||||
*DriverVersion = (version[0] << 48) | (version[1] << 32) | (version[2] << 16) | version[3];
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
Inf = SkipNonLF(Inf, InfEnd);
|
||||
}
|
||||
LOG(WINTUN_LOG_ERR, L"DriverVer not found in INF resource");
|
||||
return ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* This function does not log any errors, not to flood the log when called from the EnsureDriverUnloaded() loop. */
|
||||
static BOOL IsDriverLoaded(VOID)
|
||||
{
|
||||
VOID *StackBuffer[0x80];
|
||||
VOID **Drivers = StackBuffer;
|
||||
DWORD Size = 0;
|
||||
if (!EnumDeviceDrivers(Drivers, sizeof(StackBuffer), &Size))
|
||||
return FALSE;
|
||||
if (Size > sizeof(StackBuffer))
|
||||
{
|
||||
HANDLE Heap = GetProcessHeap();
|
||||
Drivers = HeapAlloc(Heap, 0, Size);
|
||||
if (!Drivers)
|
||||
{
|
||||
SetLastError(ERROR_OUTOFMEMORY);
|
||||
return FALSE;
|
||||
}
|
||||
if (!EnumDeviceDrivers(Drivers, Size, &Size))
|
||||
{
|
||||
DWORD Result = GetLastError();
|
||||
HeapFree(Heap, 0, Drivers);
|
||||
SetLastError(Result);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
BOOL Found = FALSE;
|
||||
for (DWORD i = Size / sizeof(Drivers[0]); i-- > 0;)
|
||||
{
|
||||
WCHAR MaybeWintun[11];
|
||||
if (GetDeviceDriverBaseNameW(Drivers[i], MaybeWintun, _countof(MaybeWintun)) == 10 &&
|
||||
!_wcsicmp(MaybeWintun, L"wintun.sys"))
|
||||
{
|
||||
Found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Drivers != StackBuffer)
|
||||
HeapFree(GetProcessHeap(), 0, Drivers);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
return Found;
|
||||
}
|
||||
|
||||
static BOOL EnsureDriverUnloaded(VOID)
|
||||
{
|
||||
BOOL Loaded;
|
||||
for (int i = 0; (Loaded = IsDriverLoaded()) != 0 && i < 300; ++i)
|
||||
Sleep(50);
|
||||
return !Loaded;
|
||||
}
|
||||
|
||||
static WINTUN_STATUS
|
||||
InstallCertificate(_In_z_ const WCHAR *SignedResource)
|
||||
{
|
||||
LOG(WINTUN_LOG_INFO, L"Trusting code signing certificate");
|
||||
const VOID *LockedResource;
|
||||
DWORD SizeResource;
|
||||
DWORD Result = ResourceGetAddress(SignedResource, &LockedResource, &SizeResource);
|
||||
if (Result != ERROR_SUCCESS)
|
||||
return LOG(WINTUN_LOG_ERR, L"Failed to locate resource"), Result;
|
||||
const CERT_BLOB CertBlob = { .cbData = SizeResource, .pbData = (BYTE *)LockedResource };
|
||||
HCERTSTORE QueriedStore;
|
||||
if (!CryptQueryObject(
|
||||
CERT_QUERY_OBJECT_BLOB,
|
||||
&CertBlob,
|
||||
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
|
||||
CERT_QUERY_FORMAT_FLAG_ALL,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
&QueriedStore,
|
||||
0,
|
||||
NULL))
|
||||
return LOG_LAST_ERROR(L"Failed to find certificate");
|
||||
HCERTSTORE TrustedStore =
|
||||
CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"TrustedPublisher");
|
||||
if (!TrustedStore)
|
||||
{
|
||||
Result = LOG_LAST_ERROR(L"Failed to open store");
|
||||
goto cleanupQueriedStore;
|
||||
}
|
||||
LPSTR CodeSigningOid[] = { szOID_PKIX_KP_CODE_SIGNING };
|
||||
CERT_ENHKEY_USAGE EnhancedUsage = { .cUsageIdentifier = 1, .rgpszUsageIdentifier = CodeSigningOid };
|
||||
for (const CERT_CONTEXT *CertContext = NULL; (CertContext = CertFindCertificateInStore(
|
||||
QueriedStore,
|
||||
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
|
||||
CERT_FIND_ENHKEY_USAGE,
|
||||
&EnhancedUsage,
|
||||
CertContext)) != NULL;)
|
||||
{
|
||||
CERT_EXTENSION *Ext = CertFindExtension(
|
||||
szOID_BASIC_CONSTRAINTS2, CertContext->pCertInfo->cExtension, CertContext->pCertInfo->rgExtension);
|
||||
CERT_BASIC_CONSTRAINTS2_INFO Constraints;
|
||||
DWORD Size = sizeof(Constraints);
|
||||
if (Ext &&
|
||||
CryptDecodeObjectEx(
|
||||
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||
szOID_BASIC_CONSTRAINTS2,
|
||||
Ext->Value.pbData,
|
||||
Ext->Value.cbData,
|
||||
0,
|
||||
NULL,
|
||||
&Constraints,
|
||||
&Size) &&
|
||||
!Constraints.fCA)
|
||||
if (!CertAddCertificateContextToStore(TrustedStore, CertContext, CERT_STORE_ADD_REPLACE_EXISTING, NULL))
|
||||
{
|
||||
LOG_LAST_ERROR(L"Failed to add certificate to store");
|
||||
Result = Result != ERROR_SUCCESS ? Result : GetLastError();
|
||||
}
|
||||
}
|
||||
CertCloseStore(TrustedStore, 0);
|
||||
cleanupQueriedStore:
|
||||
CertCloseStore(QueriedStore, 0);
|
||||
return Result;
|
||||
}
|
||||
|
||||
static WINTUN_STATUS
|
||||
InstallDriver(_In_ BOOL UpdateExisting)
|
||||
{
|
||||
WCHAR WindowsDirectory[MAX_PATH];
|
||||
if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory)))
|
||||
return LOG_LAST_ERROR(L"Failed to get Windows folder");
|
||||
WCHAR WindowsTempDirectory[MAX_PATH];
|
||||
if (!PathCombineW(WindowsTempDirectory, WindowsDirectory, L"Temp"))
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
UCHAR RandomBytes[32] = { 0 };
|
||||
# pragma warning(suppress : 6387)
|
||||
if (!RtlGenRandom(RandomBytes, sizeof(RandomBytes)))
|
||||
return LOG_LAST_ERROR(L"Failed to generate random");
|
||||
WCHAR RandomSubDirectory[sizeof(RandomBytes) * 2 + 1];
|
||||
for (int i = 0; i < sizeof(RandomBytes); ++i)
|
||||
swprintf_s(&RandomSubDirectory[i * 2], 3, L"%02x", RandomBytes[i]);
|
||||
WCHAR RandomTempSubDirectory[MAX_PATH];
|
||||
if (!PathCombineW(RandomTempSubDirectory, WindowsTempDirectory, RandomSubDirectory))
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
if (!CreateDirectoryW(RandomTempSubDirectory, SecurityAttributes))
|
||||
return LOG_LAST_ERROR(L"Failed to create temporary folder");
|
||||
|
||||
DWORD Result = ERROR_SUCCESS;
|
||||
WCHAR CatPath[MAX_PATH] = { 0 };
|
||||
WCHAR SysPath[MAX_PATH] = { 0 };
|
||||
WCHAR InfPath[MAX_PATH] = { 0 };
|
||||
if (!PathCombineW(CatPath, RandomTempSubDirectory, L"wintun.cat") ||
|
||||
!PathCombineW(SysPath, RandomTempSubDirectory, L"wintun.sys") ||
|
||||
!PathCombineW(InfPath, RandomTempSubDirectory, L"wintun.inf"))
|
||||
{
|
||||
Result = ERROR_BUFFER_OVERFLOW;
|
||||
goto cleanupDirectory;
|
||||
}
|
||||
|
||||
BOOL UseWHQL = HaveWHQL();
|
||||
if (!UseWHQL && (Result = InstallCertificate(L"wintun.sys")) != ERROR_SUCCESS)
|
||||
LOG(WINTUN_LOG_WARN, L"Unable to install code signing certificate");
|
||||
|
||||
LOG(WINTUN_LOG_INFO, L"Copying resources to temporary path");
|
||||
if ((Result = ResourceCopyToFile(CatPath, UseWHQL ? L"wintun-whql.cat" : L"wintun.cat")) != ERROR_SUCCESS ||
|
||||
(Result = ResourceCopyToFile(SysPath, UseWHQL ? L"wintun-whql.sys" : L"wintun.sys")) != ERROR_SUCCESS ||
|
||||
(Result = ResourceCopyToFile(InfPath, UseWHQL ? L"wintun-whql.inf" : L"wintun.inf")) != ERROR_SUCCESS)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Failed to copy resources");
|
||||
goto cleanupDelete;
|
||||
}
|
||||
|
||||
LOG(WINTUN_LOG_INFO, L"Installing driver");
|
||||
if (!SetupCopyOEMInfW(InfPath, NULL, SPOST_PATH, 0, NULL, 0, NULL, NULL))
|
||||
Result = LOG_LAST_ERROR(L"Could not install driver to store");
|
||||
BOOL RebootRequired = FALSE;
|
||||
if (UpdateExisting &&
|
||||
!UpdateDriverForPlugAndPlayDevicesW(
|
||||
NULL, WINTUN_HWID, InfPath, INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE, &RebootRequired))
|
||||
LOG_LAST_ERROR(L"Could not update existing adapters");
|
||||
if (RebootRequired)
|
||||
LOG(WINTUN_LOG_WARN, L"A reboot might be required, which really should not be the case");
|
||||
|
||||
cleanupDelete:
|
||||
DeleteFileW(CatPath);
|
||||
DeleteFileW(SysPath);
|
||||
DeleteFileW(InfPath);
|
||||
cleanupDirectory:
|
||||
RemoveDirectoryW(RandomTempSubDirectory);
|
||||
return Result;
|
||||
}
|
||||
|
||||
static WINTUN_STATUS RemoveDriver(VOID)
|
||||
WINTUN_STATUS DriverRemoveAllOurs(VOID)
|
||||
{
|
||||
HDEVINFO DevInfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_NET, NULL, NULL, 0);
|
||||
if (!DevInfo)
|
||||
@ -396,57 +73,4 @@ cleanupDeviceInfoSet:
|
||||
return Result;
|
||||
}
|
||||
|
||||
WINTUN_STATUS DriverInstallOrUpdate(VOID)
|
||||
{
|
||||
HANDLE Heap = GetProcessHeap();
|
||||
HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL);
|
||||
if (DevInfo == INVALID_HANDLE_VALUE)
|
||||
return LOG_LAST_ERROR(L"Failed to get present class devices");
|
||||
SP_DEVINFO_DATA_LIST *ExistingAdapters = NULL;
|
||||
if (IsDriverLoaded())
|
||||
{
|
||||
AdapterDisableAllOurs(DevInfo, &ExistingAdapters);
|
||||
LOG(WINTUN_LOG_INFO, L"Waiting for driver to unload from kernel");
|
||||
if (!EnsureDriverUnloaded())
|
||||
LOG(WINTUN_LOG_WARN, L"Unable to unload driver, which means a reboot will likely be required");
|
||||
}
|
||||
DWORD Result = ERROR_SUCCESS;
|
||||
if ((Result = RemoveDriver()) != ERROR_SUCCESS)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Failed to uninstall old drivers");
|
||||
goto cleanupAdapters;
|
||||
}
|
||||
if ((Result = InstallDriver(!!ExistingAdapters)) != ERROR_SUCCESS)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Failed to install driver");
|
||||
goto cleanupAdapters;
|
||||
}
|
||||
LOG(WINTUN_LOG_INFO, L"Installation successful");
|
||||
|
||||
cleanupAdapters:;
|
||||
if (ExistingAdapters)
|
||||
{
|
||||
AdapterEnableAll(DevInfo, ExistingAdapters);
|
||||
while (ExistingAdapters)
|
||||
{
|
||||
SP_DEVINFO_DATA_LIST *Next = ExistingAdapters->Next;
|
||||
HeapFree(Heap, 0, ExistingAdapters);
|
||||
ExistingAdapters = Next;
|
||||
}
|
||||
}
|
||||
SetupDiDestroyDeviceInfoList(DevInfo);
|
||||
return Result;
|
||||
}
|
||||
|
||||
WINTUN_STATUS DriverUninstall(VOID)
|
||||
{
|
||||
AdapterDeleteAllOurs();
|
||||
DWORD Result = RemoveDriver();
|
||||
if (Result == ERROR_SUCCESS)
|
||||
LOG(WINTUN_LOG_INFO, L"Uninstallation successful");
|
||||
else
|
||||
LOG(WINTUN_LOG_ERR, L"Failed to uninstall driver");
|
||||
return Result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
29
api/driver.h
29
api/driver.h
@ -30,32 +30,9 @@ DriverIsOurHardwareID(_In_z_ const WCHAR *Hwids);
|
||||
BOOL
|
||||
DriverIsOurDrvInfoDetail(_In_ const SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData);
|
||||
|
||||
#if defined(HAVE_EV) || defined(HAVE_WHQL)
|
||||
|
||||
/**
|
||||
* Queries the version of the driver this wintun.dll is packing.
|
||||
* Removes all Wintun drivers from the driver store.
|
||||
*
|
||||
* DriverDate Pointer to a variable to receive the driver date.
|
||||
*
|
||||
* DriverVersion Pointer to a variable to receive the driver version.
|
||||
*
|
||||
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
|
||||
* @return ERROR_SUCCESS on success or the adapter was not found; Win32 error code otherwise.
|
||||
*/
|
||||
WINTUN_STATUS
|
||||
DriverGetVersion(_Out_ FILETIME *DriverDate, _Out_ DWORDLONG *DriverVersion);
|
||||
|
||||
/**
|
||||
* Installs or updates Wintun driver.
|
||||
*
|
||||
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
|
||||
*/
|
||||
WINTUN_STATUS DriverInstallOrUpdate(VOID);
|
||||
|
||||
/**
|
||||
* Uninstalls Wintun driver.
|
||||
*
|
||||
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
|
||||
*/
|
||||
WINTUN_STATUS DriverUninstall(VOID);
|
||||
|
||||
#endif
|
||||
WINTUN_STATUS DriverRemoveAllOurs(VOID);
|
||||
|
Loading…
Reference in New Issue
Block a user