diff --git a/LegacyUpdate/LegacyUpdate.vcxproj b/LegacyUpdate/LegacyUpdate.vcxproj index 76ca3f5..688d5a6 100644 --- a/LegacyUpdate/LegacyUpdate.vcxproj +++ b/LegacyUpdate/LegacyUpdate.vcxproj @@ -477,14 +477,6 @@ CompileAsCpp CompileAsCpp - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp CompileAsCpp @@ -575,7 +567,6 @@ - diff --git a/LegacyUpdate/LegacyUpdate.vcxproj.filters b/LegacyUpdate/LegacyUpdate.vcxproj.filters index 628f48d..cd6b79c 100644 --- a/LegacyUpdate/LegacyUpdate.vcxproj.filters +++ b/LegacyUpdate/LegacyUpdate.vcxproj.filters @@ -81,9 +81,6 @@ Shared - - Shared - Shared @@ -146,9 +143,6 @@ Shared - - Shared - Shared diff --git a/LegacyUpdate/LegacyUpdateCtrl.cpp b/LegacyUpdate/LegacyUpdateCtrl.cpp index d4d048f..0d05302 100644 --- a/LegacyUpdate/LegacyUpdateCtrl.cpp +++ b/LegacyUpdate/LegacyUpdateCtrl.cpp @@ -10,7 +10,6 @@ #include "User.h" #include "Utils.h" #include "VersionInfo.h" -#include "Wow64.h" #include #include #include @@ -340,6 +339,7 @@ STDMETHODIMP CLegacyUpdateCtrl::GetUserType(UserType *retval) { // The control has no admin rights (although it may not have requested them yet). *retval = e_nonAdmin; } + return S_OK; } @@ -454,32 +454,37 @@ STDMETHODIMP CLegacyUpdateCtrl::ViewWindowsUpdateLog(void) { STDMETHODIMP CLegacyUpdateCtrl::OpenWindowsUpdateSettings(void) { DoIsPermittedCheck(); - // Some issues arise from the working directory being SysWOW64 rather than System32. Notably, - // Windows Vista - 8.1 don't have wuauclt.exe in SysWOW64. Disable WOW64 redirection temporarily - // to work around this. - PVOID oldValue; - BOOL isRedirected = DisableWow64FsRedirection(&oldValue); - - if (AtLeastWin10()) { - // Windows 10+: Open Settings app - Exec(NULL, L"ms-settings:windowsupdate-options", NULL, NULL, SW_SHOWDEFAULT, FALSE, NULL); - } else if (AtLeastWinVista()) { - // Windows Vista, 7, 8: Open Windows Update control panel - WCHAR wuauclt[MAX_PATH]; - ExpandEnvironmentStrings(L"%SystemRoot%\\System32\\wuauclt.exe", wuauclt, ARRAYSIZE(wuauclt)); - Exec(NULL, wuauclt, L"/ShowOptions", NULL, SW_SHOWDEFAULT, FALSE, NULL); - } else { - // Windows 2000, XP: Open Automatic Updates control panel - WCHAR wuaucpl[MAX_PATH]; - ExpandEnvironmentStrings(L"%SystemRoot%\\System32\\wuaucpl.cpl", wuaucpl, ARRAYSIZE(wuaucpl)); - Exec(NULL, wuaucpl, NULL, NULL, SW_SHOWDEFAULT, FALSE, NULL); + hr = GetInstallPath(&path); + if (!SUCCEEDED(hr)) { + goto end; } - // Revert WOW64 redirection if we changed it. - if (isRedirected) { - RevertWow64FsRedirection(oldValue); + PathAppend(path, L"LegacyUpdate.exe"); + + DWORD code; + hr = Exec(L"open", path, L"/options", NULL, SW_SHOW, TRUE, &code); + if (SUCCEEDED(hr)) { + hr = HRESULT_FROM_WIN32(code); } - return S_OK; + + if (!SUCCEEDED(hr)) { + TRACE(L"OpenWindowsUpdateSettings() failed: %ls\n", GetMessageForHresult(hr)); + + // Might happen if the site isn't trusted, and the user rejected the IE medium integrity prompt. + // Use the basic Automatic Updates dialog directly from COM. + CComPtr automaticUpdates; + hr = automaticUpdates.CoCreateInstance(CLSID_AutomaticUpdates, NULL, CLSCTX_INPROC_SERVER); + + if (SUCCEEDED(hr)) { + hr = automaticUpdates->ShowSettingsDialog(); + } + + if (!SUCCEEDED(hr)) { + TRACE(L"OpenWindowsUpdateSettings() failed: %ls\n", GetMessageForHresult(hr)); + } + } + + return hr; } STDMETHODIMP CLegacyUpdateCtrl::get_IsUsingWsusServer(VARIANT_BOOL *retval) { diff --git a/launcher/Options.c b/launcher/Options.c new file mode 100644 index 0000000..4f502d5 --- /dev/null +++ b/launcher/Options.c @@ -0,0 +1,40 @@ +#include +#include "Exec.h" +#include "VersionInfo.h" +#include "Wow64.h" + +void LaunchOptions(int nCmdShow) { +#if !_WIN64 + // Some issues arise from the working directory being SysWOW64 rather than System32. Notably, + // Windows Vista - 8.1 don't have wuauclt.exe in SysWOW64. Disable WOW64 redirection temporarily + // to work around this. + PVOID oldValue; + BOOL isRedirected = DisableWow64FsRedirection(&oldValue); +#endif + + HRESULT hr; + + if (AtLeastWin10()) { + // Windows 10+: Open Settings app + hr = Exec(NULL, L"ms-settings:windowsupdate-options", NULL, NULL, SW_SHOWDEFAULT, FALSE, NULL); + } else if (AtLeastWinVista()) { + // Windows Vista, 7, 8: Open Windows Update control panel + WCHAR wuauclt[MAX_PATH]; + ExpandEnvironmentStrings(L"%SystemRoot%\\System32\\wuauclt.exe", wuauclt, ARRAYSIZE(wuauclt)); + hr = Exec(NULL, wuauclt, L"/ShowOptions", NULL, SW_SHOWDEFAULT, FALSE, NULL); + } else { + // Windows 2000, XP: Open Automatic Updates control panel + WCHAR wuaucpl[MAX_PATH]; + ExpandEnvironmentStrings(L"%SystemRoot%\\System32\\wuaucpl.cpl", wuaucpl, ARRAYSIZE(wuaucpl)); + hr = Exec(NULL, wuaucpl, NULL, NULL, SW_SHOWDEFAULT, FALSE, NULL); + } + +#if !_WIN64 + // Revert WOW64 redirection if we changed it + if (isRedirected) { + RevertWow64FsRedirection(oldValue); + } +#endif + + PostQuitMessage(hr); +} diff --git a/launcher/RegisterServer.c b/launcher/RegisterServer.c index 9a78198..1391d9e 100644 --- a/launcher/RegisterServer.c +++ b/launcher/RegisterServer.c @@ -78,11 +78,6 @@ HRESULT RegisterServer(HWND hwnd, BOOL state, BOOL forLaunch) { goto end; } -#if _WIN64 - PVOID oldValue; - DisableWow64FsRedirection(&oldValue); -#endif - hr = GetInstallPath(&installPath); if (!SUCCEEDED(hr)) { goto end; @@ -132,8 +127,6 @@ HRESULT RegisterServer(HWND hwnd, BOOL state, BOOL forLaunch) { #endif hr = RegisterDllExternal(dllPath, state); - - RevertWow64FsRedirection(oldValue); #endif end: diff --git a/launcher/main.c b/launcher/main.c index 2ad0e21..fac20b8 100644 --- a/launcher/main.c +++ b/launcher/main.c @@ -10,8 +10,26 @@ HINSTANCE g_hInstance; extern void LaunchUpdateSite(int argc, LPWSTR *argv, int nCmdShow); +extern void LaunchOptions(int nCmdShow); extern void RunOnce(); +typedef enum Action { + ActionLaunch, + ActionOptions, + ActionRunOnce, + ActionRegServer, + ActionUnregServer +} Action; + +static const LPWSTR actions[] = { + L"/launch", + L"/options", + L"/runonce", + L"/regserver", + L"/unregserver", + NULL +}; + EXTERN_C __declspec(dllexport) int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) { g_hInstance = hInstance; @@ -20,9 +38,9 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine int argc; LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &argc); - LPWSTR action = L"/launch"; + LPWSTR actionFlag = L"/launch"; if (argc > 1) { - action = argv[1]; + actionFlag = argv[1]; } // All remaining args past the action @@ -33,21 +51,46 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine flagsCount = argc - 2; } - if (wcscmp(action, L"/launch") == 0) { + Action action = -1; + + for (int i = 0; actions[i] != NULL; i++) { + if (wcscmp(actionFlag, actions[i]) == 0) { + action = i; + break; + } + } + + switch (action) { + case ActionLaunch: LaunchUpdateSite(flagsCount, flags, nCmdShow); - } else if (wcscmp(action, L"/runonce") == 0) { + break; + + case ActionOptions: + LaunchOptions(nCmdShow); + break; + + case ActionRunOnce: RunOnce(); - } else if (wcscmp(action, L"/regserver") == 0 || wcscmp(action, L"/unregserver") == 0) { - BOOL state = wcscmp(action, L"/regserver") == 0; + break; + + case ActionRegServer: + case ActionUnregServer: { + BOOL state = action == ActionRegServer; HWND hwnd = flagsCount > 0 ? (HWND)(intptr_t)wcstol(flags[0], NULL, 10) : 0; RegisterServer(hwnd, state, FALSE); - } else { + break; + } + + default: { const LPWSTR usage = L"" L"LegacyUpdate.exe [/launch|/regserver|/unregserver]\n" L"\n" L"/launch\n" L" Launch Legacy Update website in Internet Explorer\n" L"\n" + L"/options\n" + L" Open the Windows Update Options control panel\n" + L"\n" L"/regserver\n" L" Register ActiveX control\n" L"\n" @@ -57,6 +100,8 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine L"If no parameters are provided, /launch is assumed."; MsgBox(NULL, L"LegacyUpdate.exe usage", usage, MB_OK); PostQuitMessage(1); + break; + } } MSG msg; diff --git a/setup/Constants.nsh b/setup/Constants.nsh index 18101bc..1b88179 100644 --- a/setup/Constants.nsh +++ b/setup/Constants.nsh @@ -45,6 +45,9 @@ !define CPL_GUID "{FFBE8D44-E9CF-4DD8-9FD6-976802C94D9C}" !define CPL_APPNAME "LegacyUpdate" +; IE elevation policy +!define ELEVATIONPOLICY_GUID "{3D800943-0434-49F2-89A1-472A259AD982}" + ; Legacy Update keys !define REGPATH_LEGACYUPDATE_SETUP "Software\Hashbang Productions\Legacy Update\Setup" !define REGPATH_UNINSTSUBKEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${NAME}" @@ -85,6 +88,9 @@ !define REGPATH_ZONEDOMAINS "${REGPATH_INETSETTINGS}\ZoneMap\Domains" !define REGPATH_ZONEESCDOMAINS "${REGPATH_INETSETTINGS}\ZoneMap\EscDomains" +; IE elevation policy keys +!define REGPATH_ELEVATIONPOLICY "Software\Microsoft\Internet Explorer\Low Rights\ElevationPolicy" + ; SChannel protocol keys !define REGPATH_SCHANNEL_PROTOCOLS "System\CurrentControlSet\Control\SecurityProviders\SChannel\Protocols" !define REGPATH_DOTNET "Software\Microsoft\.NETFramework" diff --git a/setup/setup.nsi b/setup/setup.nsi index ae876d6..e0b998f 100644 --- a/setup/setup.nsi +++ b/setup/setup.nsi @@ -417,6 +417,15 @@ ${MementoSection} "$(^Name)" LEGACYUPDATE WriteRegDword HKCU "${REGPATH_ZONEESCDOMAINS}\${DOMAIN}" "http" 2 WriteRegDword HKCU "${REGPATH_ZONEESCDOMAINS}\${DOMAIN}" "https" 2 + ; Add low rights elevation policy + WriteRegDword HKLM "${REGPATH_ELEVATIONPOLICY}\${ELEVATIONPOLICY_GUID}" "Policy" 3 + WriteRegStr HKLM "${REGPATH_ELEVATIONPOLICY}\${ELEVATIONPOLICY_GUID}" "AppPath" "$OUTDIR" + WriteRegStr HKLM "${REGPATH_ELEVATIONPOLICY}\${ELEVATIONPOLICY_GUID}" "AppName" "LegacyUpdate.exe" + + WriteRegDword HKCU "${REGPATH_ELEVATIONPOLICY}\${ELEVATIONPOLICY_GUID}" "Policy" 3 + WriteRegStr HKCU "${REGPATH_ELEVATIONPOLICY}\${ELEVATIONPOLICY_GUID}" "AppPath" "$OUTDIR" + WriteRegStr HKCU "${REGPATH_ELEVATIONPOLICY}\${ELEVATIONPOLICY_GUID}" "AppName" "LegacyUpdate.exe" + ; Delete LegacyUpdate.dll in System32 from 1.0 installer ${If} ${FileExists} $WINDIR\System32\LegacyUpdate.dll Delete $WINDIR\System32\LegacyUpdate.dll @@ -503,6 +512,10 @@ Section "-un.Legacy Update website" un.ACTIVEX DeleteRegKey HKLM "${REGPATH_ZONEESCDOMAINS}\${DOMAIN}" DeleteRegKey HKCU "${REGPATH_ZONEESCDOMAINS}\${DOMAIN}" + ; Remove IE elevation policy + DeleteRegKey HKLM "${REGPATH_ELEVATIONPOLICY}\${ELEVATIONPOLICY_GUID}" + DeleteRegKey HKCU "${REGPATH_ELEVATIONPOLICY}\${ELEVATIONPOLICY_GUID}" + ; Restart service !insertmacro RestartWUAUService SectionEnd diff --git a/shared/Wow64.c b/shared/Wow64.c index 102560d..ac133c7 100644 --- a/shared/Wow64.c +++ b/shared/Wow64.c @@ -8,6 +8,11 @@ static BOOL _loadedWow64; static _Wow64DisableWow64FsRedirection $Wow64DisableWow64FsRedirection; static _Wow64RevertWow64FsRedirection $Wow64RevertWow64FsRedirection; +#if _WIN64 +// Not needed +#define DisableWow64FsRedirection(OldValue) TRUE +#define RevertWow64FsRedirection(OldValue) TRUE +#else static void LoadWow64Symbols() { if (!_loadedWow64) { _loadedWow64 = TRUE; @@ -37,3 +42,4 @@ BOOL RevertWow64FsRedirection(PVOID OldValue) { return TRUE; } } +#endif