Skip to content
This repository has been archived by the owner on Jan 21, 2025. It is now read-only.

Commit

Permalink
Schedule user settings cleanup next time user logs on
Browse files Browse the repository at this point in the history
We are using Active Setup because eduVPN client is installed per-machine
and eduVPN client settings are stored per-user. Active Setup allows us
to cleanup the settings for all users, not just the one that performed
the uninstall.

On an eduVPN client uninstall, Active Setup is instructed to cleanup
user's client settings on next user logon. It does not cleanup the
settings immediately on uninstall for the user performing the uninstall,
as it would require a reliable detection to distinguish the ultimate
uninstall from an uninstall-before-next-version-install.

This means, if user wants to start the eduVPN experience anew, one needs
to uninstall the client, sign out&in or reboot, and reinstall the
client.

Fixes: #187
Fixes: #192
Signed-off-by: Simon Rozman <[email protected]>
  • Loading branch information
rozmansi committed May 5, 2022
1 parent 1611839 commit 6f3f2f0
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 7 deletions.
2 changes: 1 addition & 1 deletion WinStd
12 changes: 9 additions & 3 deletions doc/FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@
Right click on the server name. A menu should popup. Select _Forget_.

## How to reset all my client settings?
Close the eduVPN Client first. Open a command prompt and paste this:

### Resetting manually
Close the eduVPN and Let's Encrypt! clients first. Open a command prompt and paste one or both lines:

```cmd
rd /s "%LOCALAPPDATA%\SURF"
for /d %i in ("%LOCALAPPDATA%\SURF\eduVPN.Client.exe_Url_*") do rd /s /q "%i"
for /d %i in ("%LOCALAPPDATA%\SURF\LetsConnect.Client.exe_Url_*") do rd /s /q "%i"
```

Hit _Enter_ and confirm the deletition. This will reset eduVPN Client to factory defaults.
Don't forget to press _Enter_ key after the line is pasted. This will reset eduVPN and Let's Encrypt! clients to factory defaults.

### Resetting after uninstall
Uninstall the client. On next sign-in, the client settings of the user signing-in will be cleaned.
2 changes: 2 additions & 0 deletions eduMSICA/exports.def
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ EXPORTS
EvaluateComponents
RemoveWintunDriver
KillExecutableProcesses
UnpublishActiveSetup
PublishActiveSetup
130 changes: 129 additions & 1 deletion eduMSICA/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <WinStd/Win.h>
#include <wintun.h>

#include <memory>
#include <vector>

using namespace std;
Expand Down Expand Up @@ -170,7 +171,7 @@ EvaluateComponents(_In_ MSIHANDLE hInstall)
else
LOG_ERROR_NUM(uiResult, TEXT("MsiGetComponentState(\"%s\") failed"), WINTUN_COMPONENT);

static LPCTSTR szClientFilenames[] = {
static const LPCTSTR szClientFilenames[] = {
TEXT("eduVPN.Client.exe"),
TEXT("LetsConnect.Client.exe"),
};
Expand All @@ -188,6 +189,47 @@ EvaluateComponents(_In_ MSIHANDLE hInstall)
LOG_ERROR_NUM(uiResult, TEXT("MsiGetComponentState(\"%s\") failed"), szClientFilenames[i]);
}

static const LPCTSTR szActiveSetupActionCodes[] = {
TEXT("{B26CF707-1200-4760-A900-C4621CEEADC0}"),
TEXT("{B26CF707-1200-4760-A901-C4621CEEADC0}"),
};
for (size_t i = 0; i < _countof(szActiveSetupActionCodes) && i < _countof(szClientFilenames); ++i) {
// Get the client component state.
uiResult = MsiGetComponentState(hInstall, szClientFilenames[i], &iInstalled, &iAction);
if (uiResult == ERROR_SUCCESS) {
tstring sRegPath;
sprintf(sRegPath, TEXT("Software\\Microsoft\\Active Setup\\Installed Components\\%s"), szActiveSetupActionCodes[i]);
unsigned int uiVersion = 0;
reg_key key;
uiResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, sRegPath.c_str(), 0, KEY_QUERY_VALUE, key);
if (uiResult == ERROR_SUCCESS) {
DWORD dwType;
vector<TCHAR> aData;
if (RegQueryValueEx(key, TEXT("Version"), 0, &dwType, aData) == ERROR_SUCCESS && dwType == REG_SZ) {
aData.push_back(TEXT('\0'));
uiVersion = _tcstoul(aData.data(), NULL, 10);
}
}

if (iInstalled >= INSTALLSTATE_LOCAL && iAction >= INSTALLSTATE_REMOVED) {
// Client component is installed and shall be removed/upgraded/reinstalled.
// Schedule user configuration cleanup.
SetFormattedProperty(hInstall, TEXT("PublishActiveSetup"), tstring_printf(
TEXT("\"%s\" \"[ProductName]\" %u \"cmd.exe /c \\\"for /d %%i in (\\\"\\\"%%LOCALAPPDATA%%\\SURF\\%s_Url_*\\\"\\\") do rd /s /q \\\"\\\"%%i\\\"\\\"\\\"\""),
sRegPath.c_str(),
uiVersion + 1,
szClientFilenames[i]).c_str());
}
if (iAction >= INSTALLSTATE_LOCAL) {
// Client component shall be installed.
// Cancel user configuration cleanup.
MsiSetProperty(hInstall, TEXT("UnpublishActiveSetup"), tstring_printf(TEXT("\"%s\""), sRegPath.c_str()).c_str());
}
}
else if (uiResult != ERROR_UNKNOWN_COMPONENT)
LOG_ERROR_NUM(uiResult, TEXT("MsiGetComponentState(\"%s\") failed"), szClientFilenames[i]);
}

return ERROR_SUCCESS;
}

Expand Down Expand Up @@ -297,3 +339,89 @@ KillExecutableProcesses(_In_ MSIHANDLE hInstall)
}
return ERROR_SUCCESS;
}

static LSTATUS
RegSetValueEx(_In_ HKEY hKey, _In_opt_ LPCTSTR lpValueName, _Reserved_ DWORD Reserved, _In_ DWORD dwData)
{
return RegSetValueEx(hKey, lpValueName, Reserved, REG_DWORD, reinterpret_cast<const BYTE*>(&dwData), sizeof(dwData));
}

static LSTATUS
RegSetValueExW(_In_ HKEY hKey, _In_opt_ LPCWSTR lpValueName, _Reserved_ DWORD Reserved, _In_z_ LPCWSTR szData)
{
size_t nSize = (wcslen(szData) + 1) * sizeof(WCHAR);
if (nSize > MAXDWORD)
return ERROR_INVALID_PARAMETER;
return RegSetValueExW(hKey, lpValueName, Reserved, REG_SZ, reinterpret_cast<const BYTE*>(szData), (DWORD)nSize);
}

_Return_type_success_(return == ERROR_SUCCESS) UINT __stdcall
UnpublishActiveSetup(_In_ MSIHANDLE hInstall)
{
com_initializer com_init(NULL);
s_hInstall = hInstall;

wstring sData;
UINT uiResult = MsiGetPropertyW(hInstall, L"CustomActionData", sData);
if (uiResult != ERROR_SUCCESS) {
LOG_ERROR_NUM(uiResult, TEXT("MsiGetProperty(\"CustomActionData\") failed"));
return ERROR_SUCCESS;
}
if (sData.empty())
return ERROR_SUCCESS;
int wargc;
unique_ptr<LPWSTR[], LocalFree_delete<LPWSTR[]>> wargv(CommandLineToArgvW(sData.c_str(), &wargc));
if (wargv == NULL) {
LOG_ERROR_NUM(GetLastError(), TEXT("CommandLineToArgvW failed"));
return ERROR_SUCCESS;
}
if (wargc < 1)
return ERROR_SUCCESS;

reg_key key;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wargv[0], 0, KEY_SET_VALUE, key) != ERROR_SUCCESS)
return ERROR_SUCCESS;
RegSetValueEx(key, TEXT("IsInstalled"), 0, 0ul);
if (wargc > 1)
RegSetValueExW(key, L"StubPath", 0, wargv[1]);
else
RegDeleteValue(key, TEXT("StubPath"));
return ERROR_SUCCESS;
}

_Return_type_success_(return == ERROR_SUCCESS) UINT __stdcall
PublishActiveSetup(_In_ MSIHANDLE hInstall)
{
com_initializer com_init(NULL);
s_hInstall = hInstall;

wstring sData;
UINT uiResult = MsiGetPropertyW(hInstall, L"CustomActionData", sData);
if (uiResult != ERROR_SUCCESS) {
LOG_ERROR_NUM(uiResult, TEXT("MsiGetProperty(\"CustomActionData\") failed"));
return ERROR_SUCCESS;
}
if (sData.empty())
return ERROR_SUCCESS;
int wargc;
unique_ptr<LPWSTR[], LocalFree_delete<LPWSTR[]>> wargv(CommandLineToArgvW(sData.c_str(), &wargc));
if (wargv == NULL) {
LOG_ERROR_NUM(GetLastError(), TEXT("CommandLineToArgvW failed"));
return ERROR_SUCCESS;
}
if (wargc < 3)
return ERROR_SUCCESS;

reg_key key;
if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, wargv[0], 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, key, NULL) != ERROR_SUCCESS)
return ERROR_SUCCESS;
RegSetValueExW(key, NULL, 0, wargv[1]);
RegSetValueExW(key, L"Version", 0, wargv[2]);
RegSetValueEx(key, TEXT("IsInstalled"), 0, 1ul);
RegSetValueEx(key, TEXT("DontAsk"), 0, 2ul);
if (wargc > 3)
RegSetValueExW(key, L"StubPath", 0, wargv[3]);
else
RegDeleteValue(key, TEXT("StubPath"));
return ERROR_SUCCESS;
}
26 changes: 24 additions & 2 deletions eduVPNClient.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,21 @@
BinaryKey="eduMSICA.dll"
DllEntry="KillExecutableProcesses"
Execute="deferred"
Impersonate="no" />
Impersonate="no"/>

<CustomAction
Id="UnpublishActiveSetup"
BinaryKey="eduMSICA.dll"
DllEntry="UnpublishActiveSetup"
Execute="deferred"
Impersonate="no"/>

<CustomAction
Id="PublishActiveSetup"
BinaryKey="eduMSICA.dll"
DllEntry="PublishActiveSetup"
Execute="deferred"
Impersonate="no"/>

<InstallExecuteSequence>
<Custom
Expand All @@ -566,7 +580,15 @@

<Custom
Action="KillExecutableProcesses"
Before="StopServices" />
Before="StopServices"/>

<Custom
Action="UnpublishActiveSetup"
Before="UnpublishFeatures"/>

<Custom
Action="PublishActiveSetup"
After="PublishFeatures"/>
</InstallExecuteSequence>

<UI>
Expand Down

0 comments on commit 6f3f2f0

Please sign in to comment.