aboutsummaryrefslogtreecommitdiffstats
path: root/api/adapter.c
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2021-05-04 18:46:59 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2021-05-05 11:17:39 +0200
commit747ba7121d1d94dac982b9148076d7006e2c170f (patch)
tree960900a770c9887c16613f7d02e8479451c12883 /api/adapter.c
parentapi: don't pass bogus previous buffer size argument (diff)
downloadwintun-747ba7121d1d94dac982b9148076d7006e2c170f.tar.xz
wintun-747ba7121d1d94dac982b9148076d7006e2c170f.zip
api: clean up NetSetup2 GUIDs
Recent versions of Windows fail to tidy up, causing issues when reusing GUIDs. Check to see if a GUID might be orphaned, and forcibly clear out the registry state if so. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'api/adapter.c')
-rw-r--r--api/adapter.c50
1 files changed, 50 insertions, 0 deletions
diff --git a/api/adapter.c b/api/adapter.c
index 0043ae3..a85d17b 100644
--- a/api/adapter.c
+++ b/api/adapter.c
@@ -1418,6 +1418,56 @@ static _Return_type_success_(return != NULL) WINTUN_ADAPTER *CreateAdapter(
{
LOG(WINTUN_LOG_INFO, L"Creating adapter");
+ if (RequestedGUID)
+ {
+ WCHAR RegPath[MAX_REG_PATH];
+ WCHAR RequestedGUIDStr[MAX_GUID_STRING_LEN];
+ int GuidStrLen = StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr)) * sizeof(WCHAR);
+ if (_snwprintf_s(
+ RegPath,
+ MAX_REG_PATH,
+ _TRUNCATE,
+ L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%.*s\\Connection",
+ GuidStrLen,
+ RequestedGUIDStr) == -1)
+ goto guidIsFresh;
+ HKEY Key;
+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, RegPath, 0, KEY_QUERY_VALUE, &Key) != ERROR_SUCCESS)
+ goto guidIsFresh;
+ WCHAR *InstanceID = RegistryQueryString(Key, L"PnPInstanceId", FALSE);
+ RegCloseKey(Key);
+ if (!InstanceID)
+ goto guidIsFresh;
+ int Ret = _snwprintf_s(RegPath, MAX_REG_PATH, _TRUNCATE, L"SYSTEM\\CurrentControlSet\\Enum\\%s", InstanceID);
+ Free(InstanceID);
+ if (Ret == -1)
+ goto guidIsFresh;
+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, RegPath, 0, KEY_QUERY_VALUE, &Key) == ERROR_SUCCESS)
+ {
+ RegCloseKey(Key);
+ SetLastError(LOG_ERROR(ERROR_ALREADY_EXISTS, L"Requested GUID is already in use: %s", RequestedGUIDStr));
+ return NULL;
+ }
+ LOG(WINTUN_LOG_WARN, L"Requested GUID %s has leftover residue", RequestedGUIDStr);
+ HANDLE OriginalToken;
+ if (!ImpersonateService(L"NetSetupSvc", &OriginalToken))
+ {
+ LOG_LAST_ERROR(L"Unable to impersonate NetSetupSvc");
+ goto guidIsFresh; // non-fatal
+ }
+ if (_snwprintf_s(
+ RegPath,
+ MAX_REG_PATH,
+ _TRUNCATE,
+ L"SYSTEM\\CurrentControlSet\\Control\\NetworkSetup2\\Interfaces\\%.*s",
+ GuidStrLen,
+ RequestedGUIDStr) == -1 ||
+ !RegistryDeleteKeyRecursive(HKEY_LOCAL_MACHINE, RegPath))
+ LOG_LAST_ERROR(L"Unable to delete NetworkSetup2 registry key"); // non-fatal
+ RestoreToken(OriginalToken);
+ guidIsFresh:;
+ }
+
HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL);
if (DevInfo == INVALID_HANDLE_VALUE)
{