diff options
Diffstat (limited to '')
23 files changed, 917 insertions, 166 deletions
diff --git a/src/VBox/Installer/darwin/Makefile.kmk b/src/VBox/Installer/darwin/Makefile.kmk index 494fd990..1b7a16f8 100644 --- a/src/VBox/Installer/darwin/Makefile.kmk +++ b/src/VBox/Installer/darwin/Makefile.kmk @@ -483,6 +483,12 @@ if defined(VBOX_WITH_PYTHON) && !defined(VBOX_WITHOUT_VBOXPYTHON_FOR_OSX_10_7) VBOX_DI_VBAPP_DYLIBS += \ MacOS/VBoxPython2_7.so endif +if defined(VBOX_WITH_PYTHON) \ + && !defined(VBOX_WITHOUT_PYTHON_LIMITED_API) \ + && exists "$(VBOX_PATH_DIST)/VirtualBox.app/Contents/MacOS/VBoxPython3.so" + VBOX_DI_VBAPP_DYLIBS += \ + MacOS/VBoxPython3.so +endif ifdef VBOX_WITH_VMSVGA3D VBOX_DI_VBAPP_DYLIBS += \ MacOS/VBoxSVGA3D.dylib \ diff --git a/src/VBox/Installer/linux/VBox.sh b/src/VBox/Installer/linux/VBox.sh index fb584d48..31e32f91 100755 --- a/src/VBox/Installer/linux/VBox.sh +++ b/src/VBox/Installer/linux/VBox.sh @@ -96,15 +96,33 @@ WARNING: The compilation of the vboxdrv.ko kernel module failed during the EOF fi -SERVER_PID=`ps -U \`whoami\` | grep VBoxSVC | awk '{ print $1 }'` +# Get effective user name to use it in order to compose XPCOM IPC socket path. +VBOX_EFFECTIVE_USER="$(whoami)" +if [ -z "$VBOX_EFFECTIVE_USER" ]; then + cat << EOF +WARNING: Unable to detect effective user name. VirtualBox might run incorrectly. +EOF +fi + +# Variables LOGNAME and USER are used by XPCOM code in order to +# compose IPC socket path. If they set to something which is different +# from the effective user name, it might result in misbehavior. +# Setting VBOX_IPC_SOCKETID will tell XPCOM code which path it should use explicitly. +[ -n "$LOGNAME" ] && [ "$LOGNAME" = "$VBOX_EFFECTIVE_USER" ] || vbox_override_env="1" +[ -n "$USER" ] && [ "$USER" = "$VBOX_EFFECTIVE_USER" ] || vbox_override_env="1" + +if [ -n "$vbox_override_env" ]; then +cat << EOF +WARNING: Environment variable LOGNAME or USER does not correspond to effective user id. +EOF + export VBOX_IPC_SOCKETID="$VBOX_EFFECTIVE_USER" +fi + +SERVER_PID=`ps -U "$VBOX_EFFECTIVE_USER" | grep VBoxSVC | awk '{ print $1 }'` if [ -z "$SERVER_PID" ]; then # Server not running yet/anymore, cleanup socket path. # See IPC_GetDefaultSocketPath()! - if [ -n "$LOGNAME" ]; then - rm -rf /tmp/.vbox-$LOGNAME-ipc > /dev/null 2>&1 - else - rm -rf /tmp/.vbox-$USER-ipc > /dev/null 2>&1 - fi + rm -rf "/tmp/.vbox-$VBOX_EFFECTIVE_USER-ipc" > /dev/null 2>&1 fi if [ "$SHUTDOWN" = "true" ]; then diff --git a/src/VBox/Installer/linux/install.sh b/src/VBox/Installer/linux/install.sh index 9c11eb9b..d32d9270 100755 --- a/src/VBox/Installer/linux/install.sh +++ b/src/VBox/Installer/linux/install.sh @@ -289,11 +289,8 @@ if [ "$ACTION" = "install" ]; then # create symlinks for working around unsupported $ORIGIN/.. in VBoxC.so (setuid), # and finally make sure the directory is only writable by the user (paranoid). if [ -n "$HARDENED" ]; then - if [ -f $INSTALLATION_DIR/VirtualBoxVM ]; then - test -e $INSTALLATION_DIR/VirtualBoxVM && chmod 4511 $INSTALLATION_DIR/VirtualBoxVM - else - test -e $INSTALLATION_DIR/VirtualBox && chmod 4511 $INSTALLATION_DIR/VirtualBox - fi + # Note! Update vboxdrv.sh if the VirtualBoxVM entry changes (bugref:10642). + test -e $INSTALLATION_DIR/VirtualBoxVM && chmod 4511 $INSTALLATION_DIR/VirtualBoxVM test -e $INSTALLATION_DIR/VBoxSDL && chmod 4511 $INSTALLATION_DIR/VBoxSDL test -e $INSTALLATION_DIR/VBoxHeadless && chmod 4511 $INSTALLATION_DIR/VBoxHeadless test -e $INSTALLATION_DIR/VBoxNetDHCP && chmod 4511 $INSTALLATION_DIR/VBoxNetDHCP @@ -325,9 +322,7 @@ if [ "$ACTION" = "install" ]; then # Create symlinks to start binaries ln -sf $INSTALLATION_DIR/VBox.sh /usr/bin/VirtualBox - if [ -f $INSTALLATION_DIR/VirtualBoxVM ]; then - ln -sf $INSTALLATION_DIR/VBox.sh /usr/bin/VirtualBoxVM - fi + ln -sf $INSTALLATION_DIR/VBox.sh /usr/bin/VirtualBoxVM ln -sf $INSTALLATION_DIR/VBox.sh /usr/bin/VBoxManage ln -sf $INSTALLATION_DIR/VBox.sh /usr/bin/VBoxSDL ln -sf $INSTALLATION_DIR/VBox.sh /usr/bin/VBoxVRDP @@ -362,9 +357,7 @@ if [ "$ACTION" = "install" ]; then # Convenience symlinks. The creation fails if the FS is not case sensitive ln -sf VirtualBox /usr/bin/virtualbox > /dev/null 2>&1 - if [ -f $INSTALLATION_DIR/VirtualBoxVM ]; then - ln -sf VirtualBoxVM /usr/bin/virtualboxvm > /dev/null 2>&1 - fi + ln -sf VirtualBoxVM /usr/bin/virtualboxvm > /dev/null 2>&1 ln -sf VBoxManage /usr/bin/vboxmanage > /dev/null 2>&1 ln -sf VBoxSDL /usr/bin/vboxsdl > /dev/null 2>&1 ln -sf VBoxHeadless /usr/bin/vboxheadless > /dev/null 2>&1 diff --git a/src/VBox/Installer/linux/rpm/VirtualBox.tmpl.spec b/src/VBox/Installer/linux/rpm/VirtualBox.tmpl.spec index 829322aa..bab95a70 100644 --- a/src/VBox/Installer/linux/rpm/VirtualBox.tmpl.spec +++ b/src/VBox/Installer/linux/rpm/VirtualBox.tmpl.spec @@ -223,13 +223,8 @@ if [ -f $RPM_BUILD_ROOT/usr/lib/virtualbox/libQt5CoreVBox.so.5 ]; then fi rm -f $RPM_BUILD_ROOT/usr/lib/virtualbox/chrpath ln -s ../VBoxVMM.so $RPM_BUILD_ROOT/usr/lib/virtualbox/components/VBoxVMM.so -for i in VBoxHeadless VBoxNetDHCP VBoxNetNAT VBoxNetAdpCtl; do +for i in VirtualBoxVM VBoxHeadless VBoxNetDHCP VBoxNetNAT VBoxNetAdpCtl; do chmod 4511 $RPM_BUILD_ROOT/usr/lib/virtualbox/$i; done -if test -e $RPM_BUILD_ROOT/usr/lib/virtualbox/VirtualBoxVM; then - chmod 4511 $RPM_BUILD_ROOT/usr/lib/virtualbox/VirtualBoxVM -else - chmod 4511 $RPM_BUILD_ROOT/usr/lib/virtualbox/VirtualBox -fi if [ -f $RPM_BUILD_ROOT/usr/lib/virtualbox/VBoxVolInfo ]; then chmod 4511 $RPM_BUILD_ROOT/usr/lib/virtualbox/VBoxVolInfo fi diff --git a/src/VBox/Installer/linux/vboxdrv.sh b/src/VBox/Installer/linux/vboxdrv.sh index 4077c169..5e6842cf 100755 --- a/src/VBox/Installer/linux/vboxdrv.sh +++ b/src/VBox/Installer/linux/vboxdrv.sh @@ -85,10 +85,12 @@ else # Applies to Debian packages only (but shouldn't hurt elsewhere) exit 0 fi -VIRTUALBOX="${INSTALL_DIR}/VirtualBox" VBOXMANAGE="${INSTALL_DIR}/VBoxManage" BUILDINTMP="${MODULE_SRC}/build_in_tmp" -if test -u "${VIRTUALBOX}"; then + +# If the VirtualBoxVM file has the set-uid bit set or if it doesn't exist, setup vboxdrv +# in hardened mode. Otherwise, do the developer mode using vboxusers for access control. +if test -u "${INSTALL_DIR}/VirtualBoxVM" || test '!' -e "${INSTALL_DIR}/VirtualBoxVM"; then GROUP=root DEVICE_MODE=0600 else diff --git a/src/VBox/Installer/win/InstallHelper/Makefile.kmk b/src/VBox/Installer/win/InstallHelper/Makefile.kmk index cad3c4c3..38525a7d 100644 --- a/src/VBox/Installer/win/InstallHelper/Makefile.kmk +++ b/src/VBox/Installer/win/InstallHelper/Makefile.kmk @@ -33,9 +33,16 @@ DLLS += VBoxInstallHelper VBoxInstallHelper_TEMPLATE = VBoxR3StaticDllNoAsan VBoxInstallHelper_SDKS = ReorderCompilerIncs $(VBOX_WINPSDK) $(VBOX_WINDDK) VBoxInstallHelper_DEFS = _WIN32_WINNT=0x0501 _UNICODE UNICODE VBOX_SVN_REV=$(VBOX_SVN_REV) -ifdef VBOX_WITH_NETFLT +if defined(VBOX_WITH_NETFLT) || defined(VBOX_WITH_NETADP) VBoxInstallHelper_SDKS += VBoxWinNewDevLib - VBoxInstallHelper_DEFS += VBOX_WITH_NETFLT=1 + VBoxInstallHelper_DEFS += \ + $(if $(VBOX_WITH_NETFLT),VBOX_WITH_NETFLT,) \ + $(if $(VBOX_WITH_NETADP),VBOX_WITH_NETADP,) + VBoxInstallHelper_LIBS += \ + $(PATH_STAGE_LIB)/WinNetConfigSharedStatic.lib \ + $(PATH_STAGE_LIB)/VBoxDrvCfgSharedStatic.lib \ + $(PATH_TOOL_$(VBOX_VCC_TOOL)_LIB)/comsupp.lib \ + $(PATH_SDK_$(VBOX_WINPSDK)_LIB)/WbemUuid.Lib endif VBoxInstallHelper_DEPS = $(VBOX_SVN_REV_KMK) VBoxInstallHelper_SOURCES = \ @@ -47,15 +54,8 @@ ifndef VBOX_OSE VBoxInstallHelper_SOURCES += \ internal/VBoxSerial.cpp endif -VBoxInstallHelper_LIBS = \ +VBoxInstallHelper_LIBS += \ $(PATH_SDK_$(VBOX_WINPSDK)_LIB)/Msi.lib -ifdef VBOX_WITH_NETFLT - VBoxInstallHelper_LIBS += \ - $(PATH_STAGE_LIB)/WinNetConfigSharedStatic.lib \ - $(PATH_STAGE_LIB)/VBoxDrvCfgSharedStatic.lib \ - $(PATH_TOOL_$(VBOX_VCC_TOOL)_LIB)/comsupp.lib \ - $(PATH_SDK_$(VBOX_WINPSDK)_LIB)/WbemUuid.Lib -endif if "$(KBUILD_TARGET)" == "win" && defined(VBOX_WITH_TESTCASES) && !defined(VBOX_OSE) include $(PATH_SUB_CURRENT)/testcase/Makefile.kmk diff --git a/src/VBox/Installer/win/InstallHelper/VBoxCommon.cpp b/src/VBox/Installer/win/InstallHelper/VBoxCommon.cpp index f02447bc..d76cb438 100644 --- a/src/VBox/Installer/win/InstallHelper/VBoxCommon.cpp +++ b/src/VBox/Installer/win/InstallHelper/VBoxCommon.cpp @@ -38,27 +38,28 @@ #include <iprt/string.h> #include <iprt/utf16.h> +#include "VBoxCommon.h" + +#ifndef TESTCASE +/** + * Retrieves a MSI property (in UTF-16). + * + * Convenience function for VBoxGetMsiProp(). + * + * @returns VBox status code. + * @param hMsi MSI handle to use. + * @param pwszName Name of property to retrieve. + * @param pwszValueBuf Where to store the allocated value on success. + * @param cwcValueBuf Size (in WCHARs) of \a pwszValueBuf. + */ UINT VBoxGetMsiProp(MSIHANDLE hMsi, const WCHAR *pwszName, WCHAR *pwszValueBuf, DWORD cwcValueBuf) { - RT_BZERO(pwszValueBuf, cwcValueBuf * sizeof(pwszValueBuf[0])); - - /** @todo r=bird: why do we need to query the size first and then the data. - * The API should be perfectly capable of doing that without our help. */ - DWORD cwcNeeded = 0; - UINT uiRet = MsiGetPropertyW(hMsi, pwszName, L"", &cwcNeeded); - if (uiRet == ERROR_MORE_DATA) - { - ++cwcNeeded; /* On output does not include terminating null, so add 1. */ - - if (cwcNeeded > cwcValueBuf) - return ERROR_MORE_DATA; - uiRet = MsiGetPropertyW(hMsi, pwszName, pwszValueBuf, &cwcNeeded); - } - return uiRet; + RT_BZERO(pwszValueBuf, cwcValueBuf * sizeof(WCHAR)); + return MsiGetPropertyW(hMsi, pwszName, pwszValueBuf, &cwcValueBuf); } +#endif -#if 0 /* unused */ /** * Retrieves a MSI property (in UTF-8). * @@ -77,7 +78,7 @@ int VBoxGetMsiPropUtf8(MSIHANDLE hMsi, const char *pcszName, char **ppszValue) if (RT_SUCCESS(rc)) { WCHAR wszValue[1024]; /* 1024 should be enough for everybody (tm). */ - if (VBoxGetMsiProp(hMsi, pwszName, wszValue, sizeof(wszValue)) == ERROR_SUCCESS) + if (VBoxGetMsiProp(hMsi, pwszName, wszValue, RT_ELEMENTS(wszValue)) == ERROR_SUCCESS) rc = RTUtf16ToUtf8(wszValue, ppszValue); else rc = VERR_NOT_FOUND; @@ -87,12 +88,13 @@ int VBoxGetMsiPropUtf8(MSIHANDLE hMsi, const char *pcszName, char **ppszValue) return rc; } -#endif +#ifndef TESTCASE UINT VBoxSetMsiProp(MSIHANDLE hMsi, const WCHAR *pwszName, const WCHAR *pwszValue) { return MsiSetPropertyW(hMsi, pwszName, pwszValue); } +#endif UINT VBoxSetMsiPropDWORD(MSIHANDLE hMsi, const WCHAR *pwszName, DWORD dwVal) { diff --git a/src/VBox/Installer/win/InstallHelper/VBoxInstallHelper.cpp b/src/VBox/Installer/win/InstallHelper/VBoxInstallHelper.cpp index f82f0848..d4ac6104 100644 --- a/src/VBox/Installer/win/InstallHelper/VBoxInstallHelper.cpp +++ b/src/VBox/Installer/win/InstallHelper/VBoxInstallHelper.cpp @@ -29,22 +29,24 @@ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ -#ifdef VBOX_WITH_NETFLT +#if defined(VBOX_WITH_NETFLT) || defined(VBOX_WITH_NETADP) # include "VBox/VBoxNetCfg-win.h" # include "VBox/VBoxDrvCfg-win.h" #endif -#include <msi.h> -#include <msiquery.h> - #define _WIN32_DCOM #include <iprt/win/windows.h> +#include <aclapi.h> +#include <msi.h> +#include <msiquery.h> + #include <shellapi.h> #define INITGUID #include <guiddef.h> #include <cfgmgr32.h> #include <devguid.h> +#include <sddl.h> /* For ConvertSidToStringSidW. */ #include <iprt/win/objbase.h> #include <iprt/win/setupapi.h> @@ -54,9 +56,14 @@ #include <iprt/assert.h> #include <iprt/alloca.h> +#include <iprt/dir.h> +#include <iprt/err.h> +#include <iprt/file.h> #include <iprt/mem.h> #include <iprt/path.h> /* RTPATH_MAX, RTPATH_IS_SLASH */ #include <iprt/string.h> /* RT_ZERO */ +#include <iprt/stream.h> +#include <iprt/thread.h> #include <iprt/utf16.h> #include "VBoxCommon.h" @@ -78,6 +85,48 @@ #define MY_WTEXT(a_str) MY_WTEXT_HLP(a_str) +/********************************************************************************************************************************* +* Internal structures * +*********************************************************************************************************************************/ +/** + * Structure for keeping a target's directory security context. + */ +typedef struct TGTDIRSECCTX +{ + /** Initialized status. */ + bool fInitialized; + /** Handle of the target's parent directory. + * + * Kept open while the context is around and initialized. */ + RTDIR hParentDir; + /** Absolute (resolved) path of the target directory. */ + char szTargetDirAbs[RTPATH_MAX]; + /** Access mask which is forbidden for an ACE of type ACCESS_ALLOWED_ACE_TYPE. */ + uint32_t fAccessMaskForbidden; + /** Array of well-known SIDs which are forbidden. */ + PSID *paWellKnownSidsForbidden; + /** Number of entries in \a paWellKnownSidsForbidden. */ + size_t cWellKnownSidsForbidden; +} TGTDIRSECCTX; +/** Pointer to a target's directory security context. */ +typedef TGTDIRSECCTX *PTGTDIRSECCTX; + + +/********************************************************************************************************************************* +* Prototypes * +*********************************************************************************************************************************/ +static void destroyTargetDirSecurityCtx(PTGTDIRSECCTX pCtx); + + +/********************************************************************************************************************************* +* Globals * +*********************************************************************************************************************************/ +static uint32_t g_cRef = 0; +/** Our target directory security context. + * + * Has to be global in order to keep it around as long as the DLL is being loaded. */ +static TGTDIRSECCTX g_TargetDirSecCtx = { 0 }; + /** * DLL entry point. @@ -86,59 +135,94 @@ BOOL WINAPI DllMain(HANDLE hInst, ULONG uReason, LPVOID pReserved) { RT_NOREF(hInst, uReason, pReserved); -#if 0 - /* - * This is a trick for allowing the debugger to be attached, don't know if - * there is an official way to do that, but this is a pretty efficient. - * - * Monitor the debug output in DbgView and be ready to start windbg when - * the message below appear. This will happen 3-4 times during install, - * and 2-3 times during uninstall. - * - * Note! The DIFxApp.DLL will automatically trigger breakpoints when a - * debugger is attached. Just continue on these. - */ - if (uReason == DLL_PROCESS_ATTACH) +#ifdef DEBUG + WCHAR wszMsg[128]; + RTUtf16Printf(wszMsg, RT_ELEMENTS(wszMsg), "DllMain: hInst=%#x, uReason=%u (PID %u), g_cRef=%RU32\n", + hInst, uReason, GetCurrentProcessId(), g_cRef); + OutputDebugStringW(wszMsg); +#endif + + switch (uReason) { - WCHAR wszMsg[128]; - RTUtf16Printf(wszMsg, RT_ELEMENTS(wszMsg), "Waiting for debugger to attach: windbg -g -G -p %u\n", GetCurrentProcessId()); - for (unsigned i = 0; i < 128 && !IsDebuggerPresent(); i++) + case DLL_PROCESS_ATTACH: + { + g_cRef++; +#if 0 + /* + * This is a trick for allowing the debugger to be attached, don't know if + * there is an official way to do that, but this is a pretty efficient. + * + * Monitor the debug output in DbgView and be ready to start windbg when + * the message below appear. This will happen 3-4 times during install, + * and 2-3 times during uninstall. + * + * Note! The DIFxApp.DLL will automatically trigger breakpoints when a + * debugger is attached. Just continue on these. + */ + RTUtf16Printf(wszMsg, RT_ELEMENTS(wszMsg), "Waiting for debugger to attach: windbg -g -G -p %u\n", GetCurrentProcessId()); + for (unsigned i = 0; i < 128 && !IsDebuggerPresent(); i++) + { + OutputDebugStringW(wszMsg); + Sleep(1001); + } + Sleep(1002); + __debugbreak(); +#endif + break; + } + + case DLL_PROCESS_DETACH: { - OutputDebugStringW(wszMsg); - Sleep(1001); + g_cRef--; + break; } - Sleep(1002); - __debugbreak(); + + default: + break; } -#endif return TRUE; } /** - * Format and add message to the MSI log. + * Format a log message and print it to whatever is there (i.e. to the MSI log). * * UTF-16 strings are formatted using '%ls' (lowercase). * ANSI strings are formatted using '%s' (uppercase). + * + * @returns VBox status code. + * @param hInstall MSI installer handle. Optional and can be NULL. + * @param pszFmt Format string. + * @param ... Variable arguments for format string. */ -static UINT logStringF(MSIHANDLE hInstall, const char *pszFmt, ...) +static int logStringF(MSIHANDLE hInstall, const char *pszFmt, ...) { + RTUTF16 wszVa[RTPATH_MAX + 256]; + va_list va; + va_start(va, pszFmt); + ssize_t cwc = RTUtf16PrintfV(wszVa, RT_ELEMENTS(wszVa), pszFmt, va); + va_end(va); + + RTUTF16 wszMsg[RTPATH_MAX + 256]; + cwc = RTUtf16Printf(wszMsg, sizeof(wszMsg), "VBoxInstallHelper: %ls", wszVa); + if (cwc <= 0) + return VERR_BUFFER_OVERFLOW; + +#ifdef DEBUG + OutputDebugStringW(wszMsg); +#endif +#ifdef TESTCASE + RTPrintf("%ls\n", wszMsg); +#endif PMSIHANDLE hMSI = MsiCreateRecord(2 /* cParms */); if (hMSI) { - wchar_t wszBuf[RTPATH_MAX + 256]; - va_list va; - va_start(va, pszFmt); - ssize_t cwc = RTUtf16PrintfV(wszBuf, RT_ELEMENTS(wszBuf), pszFmt, va); - va_end(va); - - MsiRecordSetStringW(hMSI, 0, wszBuf); + MsiRecordSetStringW(hMSI, 0, wszMsg); MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_INFO), hMSI); - MsiCloseHandle(hMSI); - return cwc < RT_ELEMENTS(wszBuf) ? ERROR_SUCCESS : ERROR_BUFFER_OVERFLOW; } - return ERROR_ACCESS_DENIED; + + return cwc < RT_ELEMENTS(wszVa) ? VINF_SUCCESS : VERR_BUFFER_OVERFLOW; } UINT __stdcall IsSerialCheckNeeded(MSIHANDLE hModule) @@ -162,6 +246,483 @@ UINT __stdcall CheckSerial(MSIHANDLE hModule) } /** + * Initializes a target security context. + * + * @returns VBox status code. + * @param pCtx Target directory security context to initialize. + * @param hModule Windows installer module handle. + * @param pszPath Target directory path to use. + */ +static int initTargetDirSecurityCtx(PTGTDIRSECCTX pCtx, MSIHANDLE hModule, const char *pszPath) +{ + if (pCtx->fInitialized) + return VINF_SUCCESS; + +#ifdef DEBUG + logStringF(hModule, "initTargetDirSecurityCtx: pszPath=%s\n", pszPath); +#endif + + char szPathTemp[RTPATH_MAX]; + int vrc = RTStrCopy(szPathTemp, sizeof(szPathTemp), pszPath); + if (RT_FAILURE(vrc)) + return vrc; + + /* Try to find a parent path which exists. */ + char szPathParentAbs[RTPATH_MAX] = { 0 }; + for (int i = 0; i < 256; i++) /* Failsafe counter. */ + { + RTPathStripTrailingSlash(szPathTemp); + RTPathStripFilename(szPathTemp); + vrc = RTPathReal(szPathTemp, szPathParentAbs, sizeof(szPathParentAbs)); + if (RT_SUCCESS(vrc)) + break; + } + + if (RT_FAILURE(vrc)) + { + logStringF(hModule, "initTargetDirSecurityCtx: No existing / valid parent directory found (%Rrc), giving up\n", vrc); + return vrc; + } + + RTDIR hParentDir; + vrc = RTDirOpen(&hParentDir, szPathParentAbs); + if (RT_FAILURE(vrc)) + { + logStringF(hModule, "initTargetDirSecurityCtx: Locking parent directory '%s' failed with %Rrc\n", szPathParentAbs, vrc); + return vrc; + } + +#ifdef DEBUG + logStringF(hModule, "initTargetDirSecurityCtx: Locked parent directory '%s'\n", szPathParentAbs); +#endif + + char szPathTargetAbs[RTPATH_MAX]; + vrc = RTPathReal(pszPath, szPathTargetAbs, sizeof(szPathTargetAbs)); + if (RT_FAILURE(vrc)) + vrc = RTStrCopy(szPathTargetAbs, sizeof(szPathTargetAbs), pszPath); + if (RT_FAILURE(vrc)) + { + logStringF(hModule, "initTargetDirSecurityCtx: Failed to resolve absolute target path (%Rrc)\n", vrc); + return vrc; + } + +#ifdef DEBUG + logStringF(hModule, "initTargetDirSecurityCtx: szPathTargetAbs=%s, szPathParentAbs=%s\n", szPathTargetAbs, szPathParentAbs); +#endif + + /* Target directory validation. */ + if ( !RTStrCmp(szPathTargetAbs, szPathParentAbs) /* Don't allow installation into root directories. */ + || RTStrStr(szPathTargetAbs, "..")) + { + logStringF(hModule, "initTargetDirSecurityCtx: Directory '%s' invalid", szPathTargetAbs); + vrc = VERR_INVALID_NAME; + } + + if (RT_SUCCESS(vrc)) + { + RTFSOBJINFO fsObjInfo; + vrc = RTPathQueryInfo(szPathParentAbs, &fsObjInfo, RTFSOBJATTRADD_NOTHING); + if (RT_SUCCESS(vrc)) + { + if (RTFS_IS_DIRECTORY(fsObjInfo.Attr.fMode)) /* No symlinks or other fun stuff. */ + { + static WELL_KNOWN_SID_TYPE aForbiddenWellKnownSids[] = + { + WinNullSid, + WinWorldSid, + WinAuthenticatedUserSid, + WinBuiltinUsersSid, + WinBuiltinGuestsSid, + WinBuiltinPowerUsersSid + }; + + pCtx->paWellKnownSidsForbidden = (PSID *)RTMemAlloc(sizeof(PSID) * RT_ELEMENTS(aForbiddenWellKnownSids)); + AssertPtrReturn(pCtx->paWellKnownSidsForbidden, VERR_NO_MEMORY); + + size_t i = 0; + for(; i < RT_ELEMENTS(aForbiddenWellKnownSids); i++) + { + pCtx->paWellKnownSidsForbidden[i] = RTMemAlloc(SECURITY_MAX_SID_SIZE); + AssertPtrBreakStmt(pCtx->paWellKnownSidsForbidden, vrc = VERR_NO_MEMORY); + DWORD cbSid = SECURITY_MAX_SID_SIZE; + if (!CreateWellKnownSid(aForbiddenWellKnownSids[i], NULL, pCtx->paWellKnownSidsForbidden[i], &cbSid)) + { + vrc = RTErrConvertFromWin32(GetLastError()); + logStringF(hModule, "initTargetDirSecurityCtx: Creating SID (index %zu) failed with %Rrc\n", i, vrc); + break; + } + } + + if (RT_SUCCESS(vrc)) + { + vrc = RTStrCopy(pCtx->szTargetDirAbs, sizeof(pCtx->szTargetDirAbs), szPathTargetAbs); + if (RT_SUCCESS(vrc)) + { + pCtx->fInitialized = true; + pCtx->hParentDir = hParentDir; + pCtx->cWellKnownSidsForbidden = i; + pCtx->fAccessMaskForbidden = FILE_WRITE_DATA + | FILE_APPEND_DATA + | FILE_WRITE_ATTRIBUTES + | FILE_WRITE_EA; + + RTFILE fh; + RTFileOpen(&fh, "c:\\temp\\targetdir.ctx", RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE | RTFILE_O_WRITE); + RTFileClose(fh); + + return VINF_SUCCESS; + } + } + } + else + vrc = VERR_INVALID_NAME; + } + } + + RTDirClose(hParentDir); + + while (pCtx->cWellKnownSidsForbidden--) + { + RTMemFree(pCtx->paWellKnownSidsForbidden[pCtx->cWellKnownSidsForbidden]); + pCtx->paWellKnownSidsForbidden[pCtx->cWellKnownSidsForbidden] = NULL; + } + + logStringF(hModule, "initTargetDirSecurityCtx: Initialization failed failed with %Rrc\n", vrc); + return vrc; +} + +/** + * Destroys a target security context. + * + * @returns VBox status code. + * @param pCtx Target directory security context to destroy. + */ +static void destroyTargetDirSecurityCtx(PTGTDIRSECCTX pCtx) +{ + if ( !pCtx + || !pCtx->fInitialized) + return; + + if (pCtx->hParentDir != NIL_RTDIR) + { + RTDirClose(pCtx->hParentDir); + pCtx->hParentDir = NIL_RTDIR; + } + RT_ZERO(pCtx->szTargetDirAbs); + + for (size_t i = 0; i < pCtx->cWellKnownSidsForbidden; i++) + RTMemFree(pCtx->paWellKnownSidsForbidden[i]); + pCtx->cWellKnownSidsForbidden = 0; + + RTMemFree(pCtx->paWellKnownSidsForbidden); + pCtx->paWellKnownSidsForbidden = NULL; + + RTFileDelete("c:\\temp\\targetdir.ctx"); + + logStringF(NULL, "destroyTargetDirSecurityCtx\n"); +} + +#ifdef DEBUG +/** + * Returns a stingified version of an ACE type. + * + * @returns Stingified version of an ACE type. + * @param uType ACE type. + */ +inline const char *dbgAceTypeToString(uint8_t uType) +{ + switch (uType) + { + RT_CASE_RET_STR(ACCESS_ALLOWED_ACE_TYPE); + RT_CASE_RET_STR(ACCESS_DENIED_ACE_TYPE); + RT_CASE_RET_STR(SYSTEM_AUDIT_ACE_TYPE); + RT_CASE_RET_STR(SYSTEM_ALARM_ACE_TYPE); + default: break; + } + + return "<Invalid>"; +} + +/** + * Returns an allocated string for a SID containing the user/domain name. + * + * @returns Allocated string (UTF-8). Must be free'd using RTStrFree(). + * @param pSid SID to return allocated string for. + */ +inline char *dbgSidToNameA(const PSID pSid) +{ + char *pszName = NULL; + int vrc = VINF_SUCCESS; + + LPWSTR pwszSid = NULL; + if (ConvertSidToStringSid(pSid, &pwszSid)) + { + SID_NAME_USE SidNameUse; + + WCHAR wszUser[MAX_PATH]; + DWORD cbUser = sizeof(wszUser); + WCHAR wszDomain[MAX_PATH]; + DWORD cbDomain = sizeof(wszDomain); + if (LookupAccountSid(NULL, pSid, wszUser, &cbUser, wszDomain, &cbDomain, &SidNameUse)) + { + RTUTF16 wszName[RTPATH_MAX]; + if (RTUtf16Printf(wszName, RT_ELEMENTS(wszName), "%ls%s%ls (%ls)", + wszUser, wszDomain[0] == L'\0' ? "" : "\\", wszDomain, pwszSid)) + { + vrc = RTUtf16ToUtf8(wszName, &pszName); + } + else + vrc = VERR_NO_MEMORY; + } + else + vrc = RTStrAPrintf(&pszName, "<Lookup Error>"); + + LocalFree(pwszSid); + } + else + vrc = VERR_NOT_FOUND; + + return RT_SUCCESS(vrc) ? pszName : "<Invalid>"; +} +#endif /* DEBUG */ + +/** + * Checks a single target path whether it's safe to use or not. + * + * We check if the given path is owned by "NT Service\TrustedInstaller" and therefore assume that it's safe to use. + * + * @returns VBox status code. On error the path should be considered unsafe. + * @retval VERR_INVALID_NAME if the given path is considered unsafe. + * @retval VINF_SUCCESS if the given path is found to be safe to use. + * @param hModule Windows installer module handle. + * @param pszPath Path to check. + */ +static int checkTargetDirOne(MSIHANDLE hModule, PTGTDIRSECCTX pCtx, const char *pszPath) +{ + logStringF(hModule, "checkTargetDirOne: Checking '%s' ...", pszPath); + + PRTUTF16 pwszPath; + int vrc = RTStrToUtf16(pszPath, &pwszPath); + if (RT_FAILURE(vrc)) + return vrc; + + PACL pDacl = NULL; + PSECURITY_DESCRIPTOR pSecurityDescriptor = { 0 }; + DWORD dwErr = GetNamedSecurityInfo(pwszPath, SE_FILE_OBJECT, GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + NULL, NULL, NULL, NULL, &pSecurityDescriptor); + if (dwErr == ERROR_SUCCESS) + { + BOOL fDaclPresent = FALSE; + BOOL fDaclDefaultedIgnored = FALSE; + if (GetSecurityDescriptorDacl(pSecurityDescriptor, &fDaclPresent, + &pDacl, &fDaclDefaultedIgnored)) + { + if ( !fDaclPresent + || !pDacl) + { + /* Bail out early if the DACL isn't provided or is missing. */ + vrc = VERR_INVALID_NAME; + } + else + { + ACL_SIZE_INFORMATION aclSizeInfo; + RT_ZERO(aclSizeInfo); + if (GetAclInformation(pDacl, &aclSizeInfo, sizeof(aclSizeInfo), AclSizeInformation)) + { + for(DWORD idxACE = 0; idxACE < aclSizeInfo.AceCount; idxACE++) + { + ACE_HEADER *pAceHdr = NULL; + if (GetAce(pDacl, idxACE, (LPVOID *)&pAceHdr)) + { +#ifdef DEBUG + logStringF(hModule, "checkTargetDirOne: ACE type=%s, flags=%#x, size=%#x", + dbgAceTypeToString(pAceHdr->AceType), pAceHdr->AceFlags, pAceHdr->AceSize); +#endif + /* Note: We print the ACEs in canonoical order. */ + switch (pAceHdr->AceType) + { + case ACCESS_ALLOWED_ACE_TYPE: /* We're only interested in the ALLOW ACE. */ + { + ACCESS_ALLOWED_ACE const *pAce = (ACCESS_ALLOWED_ACE *)pAceHdr; + PSID const pSid = (PSID)&pAce->SidStart; +#ifdef DEBUG + char *pszSid = dbgSidToNameA(pSid); + logStringF(hModule, "checkTargetDirOne:\t%s fMask=%#x", pszSid, pAce->Mask); + RTStrFree(pszSid); +#endif + /* We check the flags here first for performance reasons. */ + if ((pAce->Mask & pCtx->fAccessMaskForbidden) == pCtx->fAccessMaskForbidden) + { + for (size_t idxSID = 0; idxSID < pCtx->cWellKnownSidsForbidden; idxSID++) + { + PSID const pSidForbidden = pCtx->paWellKnownSidsForbidden[idxSID]; + bool const fForbidden = EqualSid(pSid, pSidForbidden); +#ifdef DEBUG + char *pszName = dbgSidToNameA(pSidForbidden); + logStringF(hModule, "checkTargetDirOne:\t%s : %s", + fForbidden ? "** FORBIDDEN **" : "ALLOWED ", pszName); + RTStrFree(pszName); +#endif /* DEBUG */ + if (fForbidden) + { + vrc = VERR_INVALID_NAME; + break; + } + } + } + + break; + } +#ifdef DEBUG + case ACCESS_DENIED_ACE_TYPE: /* We're only interested in the ALLOW ACE. */ + { + ACCESS_DENIED_ACE const *pAce = (ACCESS_DENIED_ACE *)pAceHdr; + + LPWSTR pwszSid = NULL; + ConvertSidToStringSid((PSID)&pAce->SidStart, &pwszSid); + + logStringF(hModule, "checkTargetDirOne:\t%ls fMask=%#x (generic %#x specific %#x)", + pwszSid ? pwszSid : L"<Allocation Error>", pAce->Mask); + + LocalFree(pwszSid); + break; + } +#endif /* DEBUG */ + default: + /* Ignore everything else. */ + break; + } + } + else + dwErr = GetLastError(); + + /* No point in checking further if we failed somewhere above. */ + if (RT_FAILURE(vrc)) + break; + + } /* for ACE */ + } + else + dwErr = GetLastError(); + } + } + else + dwErr = GetLastError(); + + LocalFree(pSecurityDescriptor); + } + else + dwErr = GetLastError(); + + if (RT_SUCCESS(vrc)) + vrc = RTErrConvertFromWin32(dwErr); + +#ifdef DEBUG + logStringF(hModule, "checkTargetDirOne: Returning %Rrc", vrc); +#endif + + if ( RT_FAILURE(vrc) + && vrc != VERR_INVALID_NAME) + logStringF(hModule, "checkTargetDirOne: Failed with %Rrc (%#x)", vrc, dwErr); + + return vrc; +} + +/** + * Checks whether the path in the public property INSTALLDIR has the correct ACL permissions and returns whether + * it's valid or not. + * + * Called from the MSI installer as a custom action. + * + * @returns Success status (acccording to MSI custom actions). + * @retval ERROR_SUCCESS if checking the target directory turned out to be valid. + * @retval ERROR_NO_NET_OR_BAD_PATH is the target directory is invalid. + * @param hModule Windows installer module handle. + * + * @note Sets private property VBox_Target_Dir_Is_Valid to "1" (true) if the given target path is valid, + * or "0" (false) if it is not. An empty target directory is considered to be valid (i.e. INSTALLDIR not set yet). + * + * @sa @bugref{10616} + */ +UINT __stdcall CheckTargetDir(MSIHANDLE hModule) +{ + char *pszTargetDir; + + int vrc = VBoxGetMsiPropUtf8(hModule, "INSTALLDIR", &pszTargetDir); + if (RT_SUCCESS(vrc)) + { + logStringF(hModule, "CheckTargetDir: Checking target directory '%s' ...", pszTargetDir); + + if (!RTStrNLen(pszTargetDir, RTPATH_MAX)) + { + logStringF(hModule, "CheckTargetDir: No INSTALLDIR set (yet), skipping ..."); + VBoxSetMsiProp(hModule, L"VBox_Target_Dir_Is_Valid", L"1"); + } + else + { + union + { + RTPATHPARSED Parsed; + uint8_t ab[RTPATH_MAX]; + } u; + + vrc = RTPathParse(pszTargetDir, &u.Parsed, sizeof(u), RTPATH_STR_F_STYLE_DOS); + if (RT_SUCCESS(vrc)) + { + if (u.Parsed.fProps & RTPATH_PROP_DOTDOT_REFS) + vrc = VERR_INVALID_PARAMETER; + if (RT_SUCCESS(vrc)) + { + vrc = initTargetDirSecurityCtx(&g_TargetDirSecCtx, hModule, pszTargetDir); + if (RT_SUCCESS(vrc)) + { + uint16_t idxComp = u.Parsed.cComps; + char szPathToCheck[RTPATH_MAX]; + while (idxComp > 1) /* We traverse backwards from INSTALLDIR and leave out the root (e.g. C:\"). */ + { + u.Parsed.cComps = idxComp; + vrc = RTPathParsedReassemble(pszTargetDir, &u.Parsed, RTPATH_STR_F_STYLE_DOS, + szPathToCheck, sizeof(szPathToCheck)); + if (RT_FAILURE(vrc)) + break; + if (RTDirExists(szPathToCheck)) + { + vrc = checkTargetDirOne(hModule, &g_TargetDirSecCtx, szPathToCheck); + if (RT_FAILURE(vrc)) + break; + } + else + logStringF(hModule, "CheckTargetDir: Path '%s' does not exist (yet)", szPathToCheck); + idxComp--; + } + + destroyTargetDirSecurityCtx(&g_TargetDirSecCtx); + } + else + logStringF(hModule, "CheckTargetDir: initTargetDirSecurityCtx failed with %Rrc\n", vrc); + + if (RT_SUCCESS(vrc)) + VBoxSetMsiProp(hModule, L"VBox_Target_Dir_Is_Valid", L"1"); + } + } + else + logStringF(hModule, "CheckTargetDir: Parsing path failed with %Rrc", vrc); + } + + RTStrFree(pszTargetDir); + } + + if (RT_FAILURE(vrc)) /* On failure (or when in doubt), mark the installation directory as invalid. */ + { + logStringF(hModule, "CheckTargetDir: Checking failed with %Rrc", vrc); + VBoxSetMsiProp(hModule, L"VBox_Target_Dir_Is_Valid", L"0"); + } + + /* Return back outcome to the MSI engine. */ + return RT_SUCCESS(vrc) ? ERROR_SUCCESS : ERROR_NO_NET_OR_BAD_PATH; +} + +/** * Runs an executable on the OS. * * @returns Windows error code. @@ -869,7 +1430,7 @@ UINT __stdcall InstallBranding(MSIHANDLE hModule) return ERROR_SUCCESS; /* Do not fail here. */ } -#ifdef VBOX_WITH_NETFLT +#if defined(VBOX_WITH_NETFLT) || defined(VBOX_WITH_NETADP) /** @todo should use some real VBox app name */ #define VBOX_NETCFG_APP_NAME L"VirtualBox Installer" @@ -1051,7 +1612,9 @@ static UINT doNetCfgInit(MSIHANDLE hModule, INetCfg **ppnc, BOOL bWrite) return uErr; } +#endif /* defined(VBOX_WITH_NETFLT) || defined(VBOX_WITH_NETADP) */ +#ifdef VBOX_WITH_NETFLT static UINT vboxNetFltQueryInfArray(MSIHANDLE hModule, OUT LPWSTR pwszPtInf, DWORD cwcPtInf, OUT LPWSTR pwszMpInf, DWORD cwcMpInf) { @@ -1082,11 +1645,8 @@ static UINT vboxNetFltQueryInfArray(MSIHANDLE hModule, OUT LPWSTR pwszPtInf, DWO return uErr; } -#endif /*VBOX_WITH_NETFLT*/ - -/*static*/ UINT _uninstallNetFlt(MSIHANDLE hModule) +static UINT _uninstallNetFlt(MSIHANDLE hModule) { -#ifdef VBOX_WITH_NETFLT INetCfg *pNetCfg; UINT uErr; @@ -1123,21 +1683,26 @@ static UINT vboxNetFltQueryInfArray(MSIHANDLE hModule, OUT LPWSTR pwszPtInf, DWO } netCfgLoggerDisable(); } -#endif /* VBOX_WITH_NETFLT */ /* Never fail the uninstall even if we did not succeed. */ return ERROR_SUCCESS; } +#endif /* VBOX_WITH_NETFLT */ UINT __stdcall UninstallNetFlt(MSIHANDLE hModule) { - (void)_uninstallNetLwf(hModule); +#ifdef VBOX_WITH_NETFLT + _uninstallNetLwf(hModule); return _uninstallNetFlt(hModule); +#else + RT_NOREF(hModule); + return ERROR_SUCCESS; +#endif } +#ifdef VBOX_WITH_NETFLT static UINT _installNetFlt(MSIHANDLE hModule) { -#ifdef VBOX_WITH_NETFLT UINT uErr; INetCfg *pNetCfg; @@ -1184,22 +1749,26 @@ static UINT _installNetFlt(MSIHANDLE hModule) } netCfgLoggerDisable(); } -#endif /* VBOX_WITH_NETFLT */ /* Never fail the install even if we did not succeed. */ return ERROR_SUCCESS; } +#endif /* VBOX_WITH_NETFLT */ UINT __stdcall InstallNetFlt(MSIHANDLE hModule) { - (void)_uninstallNetLwf(hModule); +#ifdef VBOX_WITH_NETFLT + _uninstallNetLwf(hModule); return _installNetFlt(hModule); +#else + RT_NOREF(hModule); + return ERROR_SUCCESS; +#endif } - -/*static*/ UINT _uninstallNetLwf(MSIHANDLE hModule) -{ #ifdef VBOX_WITH_NETFLT +static UINT _uninstallNetLwf(MSIHANDLE hModule) +{ INetCfg *pNetCfg; UINT uErr; @@ -1236,21 +1805,26 @@ UINT __stdcall InstallNetFlt(MSIHANDLE hModule) } netCfgLoggerDisable(); } -#endif /* VBOX_WITH_NETFLT */ /* Never fail the uninstall even if we did not succeed. */ return ERROR_SUCCESS; } +#endif /* VBOX_WITH_NETFLT */ UINT __stdcall UninstallNetLwf(MSIHANDLE hModule) { - (void)_uninstallNetFlt(hModule); +#ifdef VBOX_WITH_NETFLT + _uninstallNetFlt(hModule); return _uninstallNetLwf(hModule); +#else + RT_NOREF(hModule); + return ERROR_SUCCESS; +#endif } +#ifdef VBOX_WITH_NETFLT static UINT _installNetLwf(MSIHANDLE hModule) { -#ifdef VBOX_WITH_NETFLT UINT uErr; INetCfg *pNetCfg; @@ -1313,20 +1887,25 @@ static UINT _installNetLwf(MSIHANDLE hModule) } netCfgLoggerDisable(); } -#endif /* VBOX_WITH_NETFLT */ /* Never fail the install even if we did not succeed. */ return ERROR_SUCCESS; } +#endif /* VBOX_WITH_NETFLT */ UINT __stdcall InstallNetLwf(MSIHANDLE hModule) { - (void)_uninstallNetFlt(hModule); +#ifdef VBOX_WITH_NETFLT + _uninstallNetFlt(hModule); return _installNetLwf(hModule); +#else + RT_NOREF(hModule); + return ERROR_SUCCESS; +#endif } -#if 0 +#if 0 /** @todo r=andy Remove this? */ static BOOL RenameHostOnlyConnectionsCallback(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pContext) { WCHAR DevName[256]; @@ -1382,11 +1961,11 @@ static BOOL RenameHostOnlyConnectionsCallback(HDEVINFO hDevInfo, PSP_DEVINFO_DAT return TRUE; } -#endif +#endif /* 0 */ +#ifdef VBOX_WITH_NETADP static UINT _createHostOnlyInterface(MSIHANDLE hModule, LPCWSTR pwszId, LPCWSTR pwszInfName) { -#ifdef VBOX_WITH_NETFLT netCfgLoggerEnable(hModule); BOOL fSetupModeInteractive = SetupSetNonInteractiveMode(FALSE); @@ -1455,12 +2034,12 @@ static UINT _createHostOnlyInterface(MSIHANDLE hModule, LPCWSTR pwszId, LPCWSTR //in fail case call CreateHostOnlyInterface logStringF(hModule, "CreateHostOnlyInterface: VBoxNetCfgWinUpdateHostOnlyNetworkInterface failed, hr = %#x", hr); logStringF(hModule, "CreateHostOnlyInterface: calling VBoxNetCfgWinCreateHostOnlyNetworkInterface"); -#ifdef VBOXNETCFG_DELAYEDRENAME +# ifdef VBOXNETCFG_DELAYEDRENAME BSTR devId; hr = VBoxNetCfgWinCreateHostOnlyNetworkInterface(pwszInfPath, fIsFile, NULL, &guid, &devId, NULL); -#else /* !VBOXNETCFG_DELAYEDRENAME */ +# else /* !VBOXNETCFG_DELAYEDRENAME */ hr = VBoxNetCfgWinCreateHostOnlyNetworkInterface(pwszInfPath, fIsFile, NULL, &guid, NULL, NULL); -#endif /* !VBOXNETCFG_DELAYEDRENAME */ +# endif /* !VBOXNETCFG_DELAYEDRENAME */ logStringF(hModule, "CreateHostOnlyInterface: VBoxNetCfgWinCreateHostOnlyNetworkInterface returns %#x", hr); if (SUCCEEDED(hr)) { @@ -1471,12 +2050,12 @@ static UINT _createHostOnlyInterface(MSIHANDLE hModule, LPCWSTR pwszId, LPCWSTR logStringF(hModule, "CreateHostOnlyInterface: VBoxNetCfgWinEnableStaticIpConfig returns %#x", hr); if (FAILED(hr)) logStringF(hModule, "CreateHostOnlyInterface: VBoxNetCfgWinEnableStaticIpConfig failed, error = %#x", hr); -#ifdef VBOXNETCFG_DELAYEDRENAME +# ifdef VBOXNETCFG_DELAYEDRENAME hr = VBoxNetCfgWinRenameHostOnlyConnection(&guid, devId, NULL); if (FAILED(hr)) logStringF(hModule, "CreateHostOnlyInterface: VBoxNetCfgWinRenameHostOnlyConnection failed, error = %#x", hr); SysFreeString(devId); -#endif /* VBOXNETCFG_DELAYEDRENAME */ +# endif /* VBOXNETCFG_DELAYEDRENAME */ } else logStringF(hModule, "CreateHostOnlyInterface: VBoxNetCfgWinCreateHostOnlyNetworkInterface failed, error = %#x", hr); @@ -1493,21 +2072,26 @@ static UINT _createHostOnlyInterface(MSIHANDLE hModule, LPCWSTR pwszId, LPCWSTR netCfgLoggerDisable(); -#endif /* VBOX_WITH_NETFLT */ - logStringF(hModule, "CreateHostOnlyInterface: Returns success (ignoring all failures)"); /* Never fail the install even if we did not succeed. */ return ERROR_SUCCESS; } +#endif /* VBOX_WITH_NETADP */ UINT __stdcall CreateHostOnlyInterface(MSIHANDLE hModule) { +#ifdef VBOX_WITH_NETADP return _createHostOnlyInterface(hModule, NETADP_ID, L"VBoxNetAdp.inf"); +#else + RT_NOREF(hModule); + return ERROR_SUCCESS; +#endif } UINT __stdcall Ndis6CreateHostOnlyInterface(MSIHANDLE hModule) { -#if 0 /* Trick for allowing the debugger to be attached. */ +#ifdef VBOX_WITH_NETADP +# if 0 /* Trick for allowing the debugger to be attached. */ for (unsigned i = 0; i < 128 && !IsDebuggerPresent(); i++) { logStringF(hModule, "Waiting for debugger to attach: windbg -p %u", GetCurrentProcessId()); @@ -1515,13 +2099,17 @@ UINT __stdcall Ndis6CreateHostOnlyInterface(MSIHANDLE hModule) } Sleep(1002); __debugbreak(); -#endif +# endif return _createHostOnlyInterface(hModule, NETADP_ID, L"VBoxNetAdp6.inf"); +#else /* !VBOX_WITH_NETADP */ + RT_NOREF(hModule); + return ERROR_SUCCESS; +#endif } +#ifdef VBOX_WITH_NETADP static UINT _removeHostOnlyInterfaces(MSIHANDLE hModule, LPCWSTR pwszId) { -#ifdef VBOX_WITH_NETFLT netCfgLoggerEnable(hModule); logStringF(hModule, "RemoveHostOnlyInterfaces: Removing all host-only interfaces"); @@ -1545,20 +2133,25 @@ static UINT _removeHostOnlyInterfaces(MSIHANDLE hModule, LPCWSTR pwszId) SetupSetNonInteractiveMode(fSetupModeInteractive); netCfgLoggerDisable(); -#endif /* VBOX_WITH_NETFLT */ /* Never fail the uninstall even if we did not succeed. */ return ERROR_SUCCESS; } +#endif /* VBOX_WITH_NETADP */ UINT __stdcall RemoveHostOnlyInterfaces(MSIHANDLE hModule) { +#ifdef VBOX_WITH_NETADP return _removeHostOnlyInterfaces(hModule, NETADP_ID); +#else + RT_NOREF(hModule); + return ERROR_SUCCESS; +#endif } +#ifdef VBOX_WITH_NETADP static UINT _stopHostOnlyInterfaces(MSIHANDLE hModule, LPCWSTR pwszId) { -#ifdef VBOX_WITH_NETFLT netCfgLoggerEnable(hModule); logStringF(hModule, "StopHostOnlyInterfaces: Stopping all host-only interfaces"); @@ -1576,20 +2169,25 @@ static UINT _stopHostOnlyInterfaces(MSIHANDLE hModule, LPCWSTR pwszId) SetupSetNonInteractiveMode(fSetupModeInteractive); netCfgLoggerDisable(); -#endif /* VBOX_WITH_NETFLT */ /* Never fail the uninstall even if we did not succeed. */ return ERROR_SUCCESS; } +#endif /* VBOX_WITH_NETADP */ UINT __stdcall StopHostOnlyInterfaces(MSIHANDLE hModule) { +#ifdef VBOX_WITH_NETADP return _stopHostOnlyInterfaces(hModule, NETADP_ID); +#else + RT_NOREF(hModule); + return ERROR_SUCCESS; +#endif } +#ifdef VBOX_WITH_NETADP static UINT _updateHostOnlyInterfaces(MSIHANDLE hModule, LPCWSTR pwszInfName, LPCWSTR pwszId) { -#ifdef VBOX_WITH_NETFLT netCfgLoggerEnable(hModule); logStringF(hModule, "UpdateHostOnlyInterfaces: Updating all host-only interfaces"); @@ -1656,25 +2254,35 @@ static UINT _updateHostOnlyInterfaces(MSIHANDLE hModule, LPCWSTR pwszInfName, LP SetupSetNonInteractiveMode(fSetupModeInteractive); netCfgLoggerDisable(); -#endif /* VBOX_WITH_NETFLT */ /* Never fail the update even if we did not succeed. */ return ERROR_SUCCESS; } +#endif /* VBOX_WITH_NETADP */ UINT __stdcall UpdateHostOnlyInterfaces(MSIHANDLE hModule) { +#ifdef VBOX_WITH_NETADP return _updateHostOnlyInterfaces(hModule, L"VBoxNetAdp.inf", NETADP_ID); +#else + RT_NOREF(hModule); + return ERROR_SUCCESS; +#endif } UINT __stdcall Ndis6UpdateHostOnlyInterfaces(MSIHANDLE hModule) { +#ifdef VBOX_WITH_NETADP return _updateHostOnlyInterfaces(hModule, L"VBoxNetAdp6.inf", NETADP_ID); +#else + RT_NOREF(hModule); + return ERROR_SUCCESS; +#endif } +#ifdef VBOX_WITH_NETADP static UINT _uninstallNetAdp(MSIHANDLE hModule, LPCWSTR pwszId) { -#ifdef VBOX_WITH_NETFLT INetCfg *pNetCfg; UINT uErr; @@ -1711,15 +2319,20 @@ static UINT _uninstallNetAdp(MSIHANDLE hModule, LPCWSTR pwszId) } netCfgLoggerDisable(); } -#endif /* VBOX_WITH_NETFLT */ /* Never fail the uninstall even if we did not succeed. */ return ERROR_SUCCESS; } +#endif /* VBOX_WITH_NETADP */ UINT __stdcall UninstallNetAdp(MSIHANDLE hModule) { +#ifdef VBOX_WITH_NETADP return _uninstallNetAdp(hModule, NETADP_ID); +#else + RT_NOREF(hModule); + return ERROR_SUCCESS; +#endif } static bool isTAPDevice(const WCHAR *pwszGUID) diff --git a/src/VBox/Installer/win/InstallHelper/VBoxInstallHelper.def b/src/VBox/Installer/win/InstallHelper/VBoxInstallHelper.def index 03cb5d60..3ab891c1 100644 --- a/src/VBox/Installer/win/InstallHelper/VBoxInstallHelper.def +++ b/src/VBox/Installer/win/InstallHelper/VBoxInstallHelper.def @@ -29,6 +29,7 @@ LIBRARY "VBoxInstallHelper" EXPORTS IsSerialCheckNeeded CheckSerial + CheckTargetDir IsMSCRTInstalled IsPythonInstalled IsWindows10 @@ -38,8 +39,8 @@ EXPORTS UninstallBranding InstallNetFlt UninstallNetFlt - UninstallNetAdp - InstallNetLwf + UninstallNetAdp + InstallNetLwf UninstallNetLwf UninstallTAPInstances UninstallVBoxDrv diff --git a/src/VBox/Installer/win/NLS/de_DE.wxl b/src/VBox/Installer/win/NLS/de_DE.wxl index dcd4d3e1..d4b004f1 100644 --- a/src/VBox/Installer/win/NLS/de_DE.wxl +++ b/src/VBox/Installer/win/NLS/de_DE.wxl @@ -63,8 +63,7 @@ <String Id="VB_NetAdpDriver">[ProductName] Treiber für virtuellen Netzwerk-Adapter für Host-only Netzwerke.</String> <String Id="VB_NetLwfDriver">[ProductName] Treiber für NDIS6-Netzwerkbrücke.</String> <String Id="VB_NetAdp6Driver">[ProductName] Treiber für virtuellen Netzwerk-Adapter für NDIS6-Host-only-Netzwerke.</String> - - <String Id="VB_Python">Python-Support für VirtualBox.</String> + <String Id="VB_Python">Python-Support für VirtualBox.</String> <!----> @@ -75,6 +74,7 @@ <String Id="Only64Bit">Diese Applikation läuft nur auf 64-bit Windows-Systemen. Bitte installieren Sie die 32-bit Version von [ProductName]!</String> <String Id="SunFound">Eine alte Sun Version von VirtualBox wurde auf diesem Computer gefunden. Bitte deinstallieren Sie diese Version zuerst. Danach können Sie [ProductName] installieren!</String> <String Id="InnotekFound">Eine alte innotek Version von VirtualBox wurde auf diesem Computer gefunden. Bitte deinstallieren Sie diese Version zuerst. Danach können Sie [ProductName] installieren!</String> + <String Id="InvalidTargetDir">Ungültiges Installationsverzeichnis angegeben. Bitte ein anderes Installationsverzeichnis wählen, um [ProductName] zu installieren.</String> <!----> @@ -93,6 +93,11 @@ <String Id="LicenseAgreementDlg_Decline">Ich &akzeptiere die Bedingungen des Lizenzvertrags nicht.</String> <!----> + <String Id="InvalidTargetDirDlg_Header">Ungültiges Installationsverzeichnis</String> + <String Id="InvalidTargetDirDlg_Desc1">Das gewählte Installationsverzeichnis is ungültig, da dieses nicht den Sicherheitsrichtlinien entspricht.</String> + <String Id="InvalidTargetDirDlg_Desc2">Bitte ein anderes Installationsverzeichnis wählen um [ProductName] zu installieren.</String> + + <!----> <String Id="CheckSerialDlg_Header">Seriennummer</String> <String Id="CheckSerialDlg_Body">Bitte geben Sie die Seriennummer in die unten stehenden Felder ein. Sie finden die Nummer auf dem Aufkleber in der VirtualBox CD-Hülle.</String> diff --git a/src/VBox/Installer/win/NLS/el_GR.wxl b/src/VBox/Installer/win/NLS/el_GR.wxl index 8d98eab9..071a61e0 100644 --- a/src/VBox/Installer/win/NLS/el_GR.wxl +++ b/src/VBox/Installer/win/NLS/el_GR.wxl @@ -63,7 +63,6 @@ <String Id="VB_NetAdpDriver">Οδηγός [ProductName] εικονικής κάρτας δικτύου για μόνο-με-οικοδεσπότη δίκτυα.</String> <String Id="VB_NetLwfDriver">Οδηγός [ProductName] για NDIS6 γεφυρωμένα δίκτυα.</String> <String Id="VB_NetAdp6Driver">Οδηγός [ProductName] εικονικής κάρτας δικτύου για NDIS6 μόνο-με-οικοδεσπότη δίκτυα.</String> - <String Id="VB_Python">Υποστήριξη Python για το VirtualBox.</String> <!----> @@ -75,6 +74,7 @@ <String Id="Only64Bit">Αυτή η εφαρμογή τρέχει μόνο σε συστήματα Windows 64 bit. Εγκαταστήστε την έκδοση 32-bit του [ProductName]!</String> <String Id="SunFound">Βρέθηκε μία παλιότερη εγκατάσταση του Sun VirtualBox στον υπολογιστή. Καταργήστε πρώτα την εγκατάσταση αυτού του πακέτου και μετά εγκαταστήστε το [ProductName]!</String> <String Id="InnotekFound">Βρέθηκε μία παλιότερη εγκατάσταση του innotek VirtualBox στον υπολογιστή. Καταργήστε πρώτα την εγκατάσταση αυτού του πακέτου και μετά εγκαταστήστε το [ProductName]!</String> + <String Id="InvalidTargetDir">Invalid installation directory specified! Please use another installation directory to install [ProductName].</String> <!----> @@ -94,6 +94,12 @@ <!----> + <String Id="InvalidTargetDirDlg_Header">Invalid installation directory</String> + <String Id="InvalidTargetDirDlg_Desc1">The chosen installation directory is invalid, as it does not meet the security requirements.</String> + <String Id="InvalidTargetDirDlg_Desc2">Please choose another directory for installing [ProductName].</String> + + <!----> + <String Id="CheckSerialDlg_Header">Σειριακός Αριθμός</String> <String Id="CheckSerialDlg_Body">Εισάγετε τον σειριακό αριθμό σας στα παρακάτω πεδία. Θα το βρείτε στο αυτοκόλλητο μέσα στην θήκη του CD του VirtualBox.</String> <String Id="CheckSerialDlg_Footer">Όταν ολοκληρώσετε την εισαγωγή του σειριακού αριθμού, πατήστε το κουμπί "Check" παρακάτω.</String> diff --git a/src/VBox/Installer/win/NLS/en_US.wxl b/src/VBox/Installer/win/NLS/en_US.wxl index b3be4e45..3eac3530 100644 --- a/src/VBox/Installer/win/NLS/en_US.wxl +++ b/src/VBox/Installer/win/NLS/en_US.wxl @@ -63,7 +63,6 @@ <String Id="VB_NetAdpDriver">[ProductName] virtual network adapter driver for Host-Only Networking.</String> <String Id="VB_NetLwfDriver">[ProductName] driver for NDIS6 Bridged Networking.</String> <String Id="VB_NetAdp6Driver">[ProductName] virtual network adapter driver for NDIS6 Host-Only Networking.</String> - <String Id="VB_Python">Python support for VirtualBox.</String> <!----> @@ -75,6 +74,7 @@ <String Id="Only64Bit">This application only runs on 64-bit Windows systems. Please install the 32-bit version of [ProductName]!</String> <String Id="SunFound">An old Sun VirtualBox installation has been found on this machine. Please uninstall this package first and then install [ProductName]!</String> <String Id="InnotekFound">An old innotek VirtualBox installation has been found on this machine. Please uninstall this package first and then install [ProductName]!</String> + <String Id="InvalidTargetDir">Invalid installation directory specified! Please use another installation directory to install [ProductName].</String> <!----> @@ -94,6 +94,12 @@ <!----> + <String Id="InvalidTargetDirDlg_Header">Invalid installation directory</String> + <String Id="InvalidTargetDirDlg_Desc1">The chosen installation directory is invalid, as it does not meet the security requirements.</String> + <String Id="InvalidTargetDirDlg_Desc2">Please choose another directory for installing [ProductName].</String> + + <!----> + <String Id="CheckSerialDlg_Header">Serial Number</String> <String Id="CheckSerialDlg_Body">Please enter your serial number in the fields below. You'll find it on the sticker inside the VirtualBox CD case.</String> <String Id="CheckSerialDlg_Footer">When done entering the serial number, press the "Check" button below.</String> diff --git a/src/VBox/Installer/win/NLS/fa_IR.wxl b/src/VBox/Installer/win/NLS/fa_IR.wxl index f6b0173a..1eeedf8a 100644 --- a/src/VBox/Installer/win/NLS/fa_IR.wxl +++ b/src/VBox/Installer/win/NLS/fa_IR.wxl @@ -58,8 +58,7 @@ <String Id="VB_NetAdpDriver">درایور آداپتور شبکه مجازی [ProductName] برای شبکه فقط-میزبان.</String> <String Id="VB_NetLwfDriver">[ProductName] driver for NDIS6 Bridged Networking.</String> <String Id="VB_NetAdp6Driver">[ProductName] virtual network adapter driver for NDIS6 Host-Only Networking.</String> - - <String Id="VB_Python">پشتیبانی از پایتون برای ویرچوال باکس.</String> + <String Id="VB_Python">پشتیبانی از پایتون برای ویرچوال باکس.</String> <!----> <String Id="NeedAdmin">برای حذف [ProductName] شما نیاز به اجازه مدیر دارید! این راه انداز حالا لغو میشود.</String> <String Id="NeedMSCRT">[ProductName] needs the Microsoft Visual C++ 2019 Redistributable Package being installed first. Please install and restart the installation of [ProductName].</String> @@ -68,6 +67,7 @@ <String Id="Only64Bit">این برنامه فقط روی ویندوز 64 بیتی اِجرا میشود. لطفا نسخه 32 بیتی [ProductName] را نصب کنید!</String> <String Id="SunFound">یک نصب قدیمی ویرچوال باکس روی این رایانه یافت شد. لطفا اول این بسته را حذف سپس [ProductName] را نصب کنید!</String> <String Id="InnotekFound">یک نسخه قدیمی نصب ویرچوال باکس در این ماشین یافت شد. لطفا اول این بسته را حذف و سپس [ProductName] را نصب کنید!</String> + <String Id="InvalidTargetDir">Invalid installation directory specified! Please use another installation directory to install [ProductName].</String> <!----> <String Id="CancelDlg_Question">آیا میخواهید نصب [ProductName] را لغو کنید؟</String> <!----> @@ -79,6 +79,10 @@ <String Id="LicenseAgreementDlg_Accept">&من ضوابط را در توافقنامه مجوز می پذیرم</String> <String Id="LicenseAgreementDlg_Decline">&من ضوابط را در توافقنامه مجوز نمی پذیرم</String> <!----> + <String Id="InvalidTargetDirDlg_Header">Invalid installation directory</String> + <String Id="InvalidTargetDirDlg_Desc1">The chosen installation directory is invalid, as it does not meet the security requirements.</String> + <String Id="InvalidTargetDirDlg_Desc2">Please choose another directory for installing [ProductName].</String> + <!----> <String Id="CheckSerialDlg_Header">شماره سریال</String> <String Id="CheckSerialDlg_Body">لطفا شماره سریال را در فیلد زیر وارد کنید.آن را روی برچسب روی جلد سی دی ویرچوال باکس می یابید.</String> <String Id="CheckSerialDlg_Footer">وقتی که وارد کردن شماره سریال انجام شد،دکمه "بررسی" را در زیر فشار دهید.</String> diff --git a/src/VBox/Installer/win/NLS/fr_FR.wxl b/src/VBox/Installer/win/NLS/fr_FR.wxl index 773786c5..2624925b 100644 --- a/src/VBox/Installer/win/NLS/fr_FR.wxl +++ b/src/VBox/Installer/win/NLS/fr_FR.wxl @@ -63,8 +63,7 @@ <String Id="VB_NetAdpDriver">Pilote de carte réseau virtuelle [ProductName] pour l'accès réseau privé hôte.</String> <String Id="VB_NetLwfDriver">[ProductName] driver for NDIS6 Bridged Networking.</String> <String Id="VB_NetAdp6Driver">[ProductName] virtual network adapter driver for NDIS6 Host-Only Networking.</String> - - <String Id="VB_Python">Python support for VirtualBox.</String> + <String Id="VB_Python">Python support for VirtualBox.</String> <!----> @@ -74,6 +73,7 @@ <String Id="Only32Bit">Cette application ne marche que sur des systèmes Windows 32-bit. Veuillez installer la version 64-bit de [ProductName]!</String> <String Id="Only64Bit">Cette application ne marche que sur des systèmes Windows 64-bit. Veuillez installer la version 32-bit de [ProductName]!</String> <String Id="InnotekFound">Vous avez une ancienne installation de innotek VirtualBox sur cette machine. Il vous faudra la désinstaller avant de pouvoir installer [ProductName].</String> + <String Id="InvalidTargetDir">Invalid installation directory specified! Please use another installation directory to install [ProductName].</String> <!----> @@ -93,6 +93,12 @@ <!----> + <String Id="InvalidTargetDirDlg_Header">Invalid installation directory</String> + <String Id="InvalidTargetDirDlg_Desc1">The chosen installation directory is invalid, as it does not meet the security requirements.</String> + <String Id="InvalidTargetDirDlg_Desc2">Please choose another directory for installing [ProductName].</String> + + <!----> + <String Id="CheckSerialDlg_Header">Numéro de série</String> <String Id="CheckSerialDlg_Body">Veulliez entrer votre numéro de série dans les champs ci-dessous. Vous le trouverez sur l'autocollant à l'intérieur du boîtier du CD de VirtualBox.</String> <String Id="CheckSerialDlg_Footer">Quand vous avez fini d'entrer le numéro de série, appuyez sur le bouton Vérifier ci-dessous.</String> diff --git a/src/VBox/Installer/win/NLS/it_IT.wxl b/src/VBox/Installer/win/NLS/it_IT.wxl index adead2a5..ef0b25d5 100644 --- a/src/VBox/Installer/win/NLS/it_IT.wxl +++ b/src/VBox/Installer/win/NLS/it_IT.wxl @@ -58,8 +58,7 @@ <String Id="VB_NetAdpDriver">Driver di [ProductName] per la scheda di rete virtuale per la rete solo host.</String> <String Id="VB_NetLwfDriver">Driver di [ProductName] per la rete con bridge NDIS6.</String> <String Id="VB_NetAdp6Driver">Driver di [ProductName] per la scheda di rete virtuale per la rete solo host NDIS6.</String> - - <String Id="VB_Python">Supporto Python per VirtualBox.</String> + <String Id="VB_Python">Supporto Python per VirtualBox.</String> <!----> <String Id="NeedAdmin">Devi avere diritti di amministrazione per (dis)installare [ProductName]! L'installazione sarà interrotta immediatamente.</String> <String Id="NeedMSCRT">[ProductName] needs the Microsoft Visual C++ 2019 Redistributable Package being installed first. Please install and restart the installation of [ProductName].</String> @@ -68,6 +67,7 @@ <String Id="Only64Bit">Questa applicazione può essere eseguita solo su sistemi Windows a 64 bit. Installa la versione a 32 bit di [ProductName]!</String> <String Id="SunFound">Una vecchia installazione di Sun VirtualBox è stata trovata su questa macchina. Disinstalla prima questo pacchetto e poi installa [ProductName]!</String> <String Id="InnotekFound">Una vecchia installazione di innotek VirtualBox è stata trovata su questa macchina. Disinstalla prima questo pacchetto e poi installa [ProductName]!</String> + <String Id="InvalidTargetDir">Invalid installation directory specified! Please use another installation directory to install [ProductName].</String> <!----> <String Id="CancelDlg_Question">Sei sicuro di voler annullare l'installazione di [ProductName]?</String> <!----> @@ -79,6 +79,10 @@ <String Id="LicenseAgreementDlg_Accept">&Accetto i termini dell'accordo di licenza</String> <String Id="LicenseAgreementDlg_Decline">&Non accetto i termini dell'accordo di licenza</String> <!----> + <String Id="InvalidTargetDirDlg_Header">Invalid installation directory</String> + <String Id="InvalidTargetDirDlg_Desc1">The chosen installation directory is invalid, as it does not meet the security requirements.</String> + <String Id="InvalidTargetDirDlg_Desc2">Please choose another directory for installing [ProductName].</String> + <!----> <String Id="CheckSerialDlg_Header">Numero di serie</String> <String Id="CheckSerialDlg_Body">Digita il numero di serie nel campo seguente. Troverai il numero sull'adesivo all'interno della custodia del CD di VirtualBox.</String> <String Id="CheckSerialDlg_Footer">Una volta digitato il numero di serie, premi il pulsante "Controlla" in basso.</String> diff --git a/src/VBox/Installer/win/NLS/ru_RU.wxl b/src/VBox/Installer/win/NLS/ru_RU.wxl index b3be4e45..3eac3530 100644 --- a/src/VBox/Installer/win/NLS/ru_RU.wxl +++ b/src/VBox/Installer/win/NLS/ru_RU.wxl @@ -63,7 +63,6 @@ <String Id="VB_NetAdpDriver">[ProductName] virtual network adapter driver for Host-Only Networking.</String> <String Id="VB_NetLwfDriver">[ProductName] driver for NDIS6 Bridged Networking.</String> <String Id="VB_NetAdp6Driver">[ProductName] virtual network adapter driver for NDIS6 Host-Only Networking.</String> - <String Id="VB_Python">Python support for VirtualBox.</String> <!----> @@ -75,6 +74,7 @@ <String Id="Only64Bit">This application only runs on 64-bit Windows systems. Please install the 32-bit version of [ProductName]!</String> <String Id="SunFound">An old Sun VirtualBox installation has been found on this machine. Please uninstall this package first and then install [ProductName]!</String> <String Id="InnotekFound">An old innotek VirtualBox installation has been found on this machine. Please uninstall this package first and then install [ProductName]!</String> + <String Id="InvalidTargetDir">Invalid installation directory specified! Please use another installation directory to install [ProductName].</String> <!----> @@ -94,6 +94,12 @@ <!----> + <String Id="InvalidTargetDirDlg_Header">Invalid installation directory</String> + <String Id="InvalidTargetDirDlg_Desc1">The chosen installation directory is invalid, as it does not meet the security requirements.</String> + <String Id="InvalidTargetDirDlg_Desc2">Please choose another directory for installing [ProductName].</String> + + <!----> + <String Id="CheckSerialDlg_Header">Serial Number</String> <String Id="CheckSerialDlg_Body">Please enter your serial number in the fields below. You'll find it on the sticker inside the VirtualBox CD case.</String> <String Id="CheckSerialDlg_Footer">When done entering the serial number, press the "Check" button below.</String> diff --git a/src/VBox/Installer/win/NLS/tr_TR.wxl b/src/VBox/Installer/win/NLS/tr_TR.wxl index 2604eff9..ff7a3b89 100644 --- a/src/VBox/Installer/win/NLS/tr_TR.wxl +++ b/src/VBox/Installer/win/NLS/tr_TR.wxl @@ -63,8 +63,7 @@ <String Id="VB_NetAdpDriver">Yalnızca-Anamakine Ağı Oluşturma için [ProductName] sanal ağ bağdaştırıcısı sürücüsü.</String> <String Id="VB_NetLwfDriver">NDIS6 Köprü Ağı Oluşturma için [ProductName] sürücüsü.</String> <String Id="VB_NetAdp6Driver">NDIS6 Yalnızca-Anamakine Ağı Oluşturma için [ProductName] sanal ağ bağdaştırıcısı sürücüsü.</String> - - <String Id="VB_Python">VirtualBox için Python desteği.</String> + <String Id="VB_Python">VirtualBox için Python desteği.</String> <!----> @@ -75,6 +74,7 @@ <String Id="Only64Bit">Bu uygulama yalnızca 64-bit Windows sistemlerinde çalışır. Lütfen [ProductName] 32-bit sürümünü yükleyin!</String> <String Id="SunFound">Bu makinede eski bir Sun VirtualBox kurulumu bulundu. Lütfen önce bu paketi kaldırın ve sonra [ProductName] yükleyin!</String> <String Id="InnotekFound">Bu makinede eski bir innotek VirtualBox kurulumu bulundu. Lütfen önce bu paketi kaldırın ve sonra [ProductName] yükleyin!</String> + <String Id="InvalidTargetDir">Invalid installation directory specified! Please use another installation directory to install [ProductName].</String> <!----> @@ -94,6 +94,12 @@ <!----> + <String Id="InvalidTargetDirDlg_Header">Invalid installation directory</String> + <String Id="InvalidTargetDirDlg_Desc1">The chosen installation directory is invalid, as it does not meet the security requirements.</String> + <String Id="InvalidTargetDirDlg_Desc2">Please choose another directory for installing [ProductName].</String> + + <!----> + <String Id="CheckSerialDlg_Header">Seri Numarası</String> <String Id="CheckSerialDlg_Body">Lütfen aşağıdaki alana seri numaranızı girin. VirtualBox CD kutusu içerisindeki etikette bulacaksınız.</String> <String Id="CheckSerialDlg_Footer">Seri numarasını girmeniz bittiğinde, aşağıdaki "Denetle" düğmesine basın".</String> diff --git a/src/VBox/Installer/win/NLS/zh_CN.wxl b/src/VBox/Installer/win/NLS/zh_CN.wxl index 7ea1c68c..2d57834a 100644 --- a/src/VBox/Installer/win/NLS/zh_CN.wxl +++ b/src/VBox/Installer/win/NLS/zh_CN.wxl @@ -63,7 +63,6 @@ <String Id="VB_NetAdpDriver">[ProductName] 虚拟网络界面卡针对“仅主机”网络。</String> <String Id="VB_NetLwfDriver">[ProductName] driver for NDIS6 Bridged Networking.</String> <String Id="VB_NetAdp6Driver">[ProductName] virtual network adapter driver for NDIS6 Host-Only Networking.</String> - <String Id="VB_Python">VirtualBox 的 Python 支持。</String> <!----> @@ -75,6 +74,7 @@ <String Id="Only64Bit">此应用程序只能运行在 64 位 Windows 系统。 请安装 [ProductName] 的 32 位版本!</String> <String Id="SunFound">在此计算机发现旧的 Sun VirtualBox 安装。 请先卸载此组件然后安装 [ProductName]!</String> <String Id="InnotekFound">在此计算机发现旧的 innotek VirtualBox 安装。 请先卸载此组件然后安装 [ProductName]!</String> +<String Id="InvalidTargetDir">Invalid installation directory specified! Please use another installation directory to install [ProductName].</String> <!----> @@ -94,6 +94,12 @@ <!----> +<String Id="InvalidTargetDirDlg_Header">Invalid installation directory</String> +<String Id="InvalidTargetDirDlg_Desc1">The chosen installation directory is invalid, as it does not meet the security requirements.</String> +<String Id="InvalidTargetDirDlg_Desc2">Please choose another directory for installing [ProductName].</String> + +<!----> + <String Id="CheckSerialDlg_Header">序号</String> <String Id="CheckSerialDlg_Body">请在以下字段输入你的序号。 你可以在 VirtualBox CD 盒内的贴纸找到。</String> <String Id="CheckSerialDlg_Footer">序号输入完成时,单击以下"检查"按钮。</String> diff --git a/src/VBox/Installer/win/NLS/zh_TW.wxl b/src/VBox/Installer/win/NLS/zh_TW.wxl index cc7da673..c30e8113 100644 --- a/src/VBox/Installer/win/NLS/zh_TW.wxl +++ b/src/VBox/Installer/win/NLS/zh_TW.wxl @@ -63,7 +63,6 @@ <String Id="VB_NetAdpDriver">[ProductName] 虛擬網路介面卡針對「僅限主機」網路。</String> <String Id="VB_NetLwfDriver">[ProductName] 驅動程式針對 NDIS6 橋接網路。</String> <String Id="VB_NetAdp6Driver">[ProductName] 虛擬網路介面卡針對 NDIS6 「僅限主機」網路。</String> - <String Id="VB_Python">VirtualBox 的 Python 支援。</String> <!----> @@ -75,6 +74,7 @@ <String Id="Only64Bit">此應用程式只能執行在 64 位元的 Windows 系統。 請安裝 [ProductName] 的 32 位元版本!</String> <String Id="SunFound">在此電腦發現舊的 Sun VirtualBox 安裝。 請先解除安裝此套件然後安裝 [ProductName]!</String> <String Id="InnotekFound">在此電腦發現舊的 innotek VirtualBox 安裝。 請先解除安裝此套件然後安裝 [ProductName]!</String> + <String Id="InvalidTargetDir">Invalid installation directory specified! Please use another installation directory to install [ProductName].</String> <!----> @@ -94,6 +94,12 @@ <!----> + <String Id="InvalidTargetDirDlg_Header">Invalid installation directory</String> + <String Id="InvalidTargetDirDlg_Desc1">The chosen installation directory is invalid, as it does not meet the security requirements.</String> + <String Id="InvalidTargetDirDlg_Desc2">Please choose another directory for installing [ProductName].</String> + + <!----> + <String Id="CheckSerialDlg_Header">序號</String> <String Id="CheckSerialDlg_Body">請在以下欄位輸入您的序號。 您可以在 VirtualBox CD 盒內的貼紙找到。</String> <String Id="CheckSerialDlg_Footer">序號輸入完成時,按一下以下「檢查」按鈕。</String> diff --git a/src/VBox/Installer/win/UserInterface.wxi b/src/VBox/Installer/win/UserInterface.wxi index f371cd55..c3bbab13 100644 --- a/src/VBox/Installer/win/UserInterface.wxi +++ b/src/VBox/Installer/win/UserInterface.wxi @@ -206,6 +206,43 @@ </Dialog> + <!-- Shows a dialog which tells the user that the chosen installation directory is invalid and therefore cannot be used. --> + <Dialog Id="VBoxInvalidTargetDirDlg" Width="370" Height="270" Title="[ProductName] !(loc.Setup)" NoMinimize="yes"> + + <!-- The wizard has a bitmap as background. The source is defined as a property below. --> + <Control Id="Bitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="234" TabSkip="no" Text="[DialogBitmap]" /> + + <!-- Title text drawn on the background --> + <Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes"> + <Text>{\DlgInvalidSerial}!(loc.InvalidTargetDirDlg_Header)</Text> + </Control> + + <!-- Text saying what we gonna do --> + <Control Id="Description" Type="Text" X="135" Y="70" Width="220" Height="130" Transparent="yes" NoPrefix="yes"> + <Text>!(loc.InvalidTargetDirDlg_Desc1)</Text> + </Control> + + <Control Id="Description2" Type="Text" X="135" Y="95" Width="220" Height="130" Transparent="yes" NoPrefix="yes"> + <Text>!(loc.InvalidTargetDirDlg_Desc2)</Text> + </Control> + + <!-- And a line for looking nice... --> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" /> + + <!-- Build number text drawn left bottom --> + <Control Id="Build" Type="Text" X="20" Y="247" Width="220" Height="10" Transparent="yes" NoPrefix="yes"> + <Text>[Version_text] $(var.Property_Version)</Text> + </Control> + + <Control Id="Back" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="!(loc.ButtonText_Back)"/> + + <!-- Canceling will bring up a confirmation dialog ('SpawnDialog' attribute) --> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="!(loc.ButtonText_Cancel)"> + <Publish Event="SpawnDialog" Value="VBoxCancelDlg">1</Publish> + </Control> + + </Dialog> + <!-- Dialog used to set another installation path. This is taken from the tutorial template on the web and can also be used for package selection etc. if necessary after some tweaking. --> <Dialog Id="VBoxCustomizeDlg" Width="370" Height="270" Title="[ProductName] !(loc.Setup)" NoMinimize="yes" TrackDiskSpace="yes"> @@ -220,7 +257,7 @@ <Control Id="Text" Type="Text" X="25" Y="55" Width="320" Height="20"> <Text>!(loc.CustomizeDlg_IconTree)</Text> </Control> - <Control Id="Tree" Type="SelectionTree" X="25" Y="85" Width="175" Height="95" Property="_BrowseProperty" + <Control Id="Tree" Type="SelectionTree" X="25" Y="85" Width="175" Height="95" Property="VBOX_TARGET_DIR" Sunken="yes" TabSkip="no" Text="Tree of selections" /> <Control Id="Browse" Type="PushButton" X="304" Y="200" Width="56" Height="17" Text="!(loc.ButtonText_Browse)"> <Publish Event="SelectionBrowse" Value="VBoxBrowseDlg">1</Publish> @@ -465,18 +502,12 @@ <!-- Dialog used to change the installation directory --> <Dialog Id="VBoxBrowseDlg" Width="370" Height="270" Title="[ProductName] !(loc.Setup)" NoMinimize="yes"> - <Control Id="PathEdit" Type="PathEdit" X="84" Y="202" Width="261" Height="18" Property="_BrowseProperty" Indirect="yes" /> - <Control Id="OK" Type="PushButton" X="304" Y="243" Width="56" Height="17" Default="yes" Text="!(loc.ButtonText_OK)"> - <Publish Event="SetTargetPath" Value="[_BrowseProperty]">1</Publish> - <Publish Event="EndDialog" Value="Return">1</Publish> - </Control> - <Control Id="Cancel" Type="PushButton" X="240" Y="243" Width="56" Height="17" Cancel="yes" Text="!(loc.ButtonText_Cancel)"> - <Publish Event="Reset" Value="0">1</Publish> - <Publish Event="EndDialog" Value="Return">1</Publish> - </Control> + <Control Id="PathEdit" Type="PathEdit" X="84" Y="202" Width="261" Height="18" Property="VBOX_TARGET_DIR" Indirect="yes" /> + <Control Id="OK" Type="PushButton" X="304" Y="243" Width="56" Height="17" Default="yes" Text="!(loc.ButtonText_OK)" /> + <Control Id="Cancel" Type="PushButton" X="240" Y="243" Width="56" Height="17" Cancel="yes" Text="!(loc.ButtonText_Cancel)"/> <Control Id="ComboLabel" Type="Text" X="25" Y="58" Width="44" Height="10" TabSkip="no" Text="!(loc.BrowseDlg_LookIn)" /> <Control Id="DirectoryCombo" Type="DirectoryCombo" X="70" Y="55" Width="220" Height="80" - Property="_BrowseProperty" Indirect="yes" Fixed="yes" Remote="yes"> + Property="VBOX_TARGET_DIR" Indirect="yes" Fixed="yes" Remote="yes"> <Subscribe Event="IgnoreChange" Attribute="IgnoreChange" /> </Control> <Control Id="Up" Type="PushButton" X="298" Y="55" Width="19" Height="19" ToolTip="!(loc.BrowseDlg_UpOneLevelTooltip)" Icon="yes" FixedSize="yes" IconSize="16" Text="[FolderUp]"> @@ -487,7 +518,7 @@ <Publish Event="DirectoryListNew" Value="0">1</Publish> </Control> <Control Id="DirectoryList" Type="DirectoryList" X="25" Y="83" Width="320" Height="110" - Property="_BrowseProperty" Sunken="yes" Indirect="yes" TabSkip="no" /> + Property="VBOX_TARGET_DIR" Sunken="yes" Indirect="yes" TabSkip="no" /> <Control Id="PathLabel" Type="Text" X="25" Y="205" Width="59" Height="10" TabSkip="no" Text="!(loc.BrowseDlg_FolderName)" /> <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="[BannerBitmap]" /> <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes"> @@ -1177,15 +1208,33 @@ <Publish Dialog="VBoxWrongSerialDlg" Control="Back" Event="NewDialog" Value="VBoxCheckSerialDlg">1</Publish> - <!-- Note: We have to set (1) or unset ({}) the properties first (see order #), as those will be needed for further routing. --> - <Publish Dialog="VBoxCustomizeDlg" Control="Next" Property="VBOX_SHOW_WARN_PYTHONAPI_DLG" Value="1" Order="1"><![CDATA[(&VBoxPython=3) AND (VBOX_PYTHON_DEPS_INSTALLED="0")]]></Publish> - <Publish Dialog="VBoxCustomizeDlg" Control="Next" Property="VBOX_SHOW_WARN_PYTHONAPI_DLG" Value="{}" Order="2"><![CDATA[(&VBoxPython<3)]]></Publish> - <Publish Dialog="VBoxCustomizeDlg" Control="Next" Property="VBOX_SHOW_WARN_DISCONNECTIFACES_DLG" Value="1" Order="3"><![CDATA[&VBoxNetworkFlt=3]]></Publish> - <Publish Dialog="VBoxCustomizeDlg" Control="Next" Property="VBOX_SHOW_WARN_DISCONNECTIFACES_DLG" Value="{}" Order="4"><![CDATA[&VBoxNetworkFlt<3]]></Publish> - <Publish Dialog="VBoxCustomizeDlg" Control="Next" Event="NewDialog" Value="VBoxWarnDisconNetIfacesDlg" Order="10"><![CDATA[VBOX_SHOW_WARN_DISCONNECTIFACES_DLG]]></Publish> - <Publish Dialog="VBoxCustomizeDlg" Control="Next" Event="NewDialog" Value="VBoxWarnPythonDlg" Order="11"><![CDATA[VBOX_SHOW_WARN_PYTHONAPI_DLG AND (NOT VBOX_SHOW_WARN_DISCONNECTIFACES_DLG)]]></Publish> - <Publish Dialog="VBoxCustomizeDlg" Control="Next" Event="NewDialog" Value="VBoxCustomize2Dlg" Order="12"><![CDATA[VBOX_SHOW_CUSTOMIZE2_DLG AND (NOT VBOX_SHOW_WARN_DISCONNECTIFACES_DLG) AND (NOT VBOX_SHOW_WARN_PYTHONAPI_DLG)]]></Publish> - <Publish Dialog="VBoxCustomizeDlg" Control="Next" Event="NewDialog" Value="VBoxVerifyReadyDlg" Order="13"><![CDATA[(NOT VBOX_SHOW_CUSTOMIZE2_DLG) AND (NOT VBOX_SHOW_WARN_DISCONNECTIFACES_DLG) AND (NOT VBOX_SHOW_WARN_PYTHONAPI_DLG)]]></Publish> + <Publish Dialog="VBoxBrowseDlg" Control="OK" Event="SetTargetPath" Value="[VBOX_TARGET_DIR]" Order="1">1</Publish> + <Publish Dialog="VBoxBrowseDlg" Control="OK" Event="EndDialog" Value="Return" Order="2">1</Publish> + <Publish Dialog="VBoxBrowseDlg" Control="Cancel" Event="Reset" Value="0" Order="1">1</Publish> + <Publish Dialog="VBoxBrowseDlg" Control="Cancel" Event="EndDialog" Value="Return" Order="2">1</Publish> + + <Publish Dialog="VBoxInvalidTargetDirDlg" Control="Back" Event="NewDialog" Value="VBoxCustomizeDlg">1</Publish> + + <!-- Note: We have to set (1) or unset ({}) the properties first (see order #), as those will be needed for further routing. + Note2: I'd love to make this easier to read/follow, but this is how Windows Installer XML works for processing all these events, sigh. --> + + <!-- Check if the chosen installation directory turned out to be invalid by calling our installation helper DLL + and performing a custom action. See @bugref{10616} --> + <Publish Dialog="VBoxCustomizeDlg" Control="Next" Event="DoAction" Value="ca_CheckTargetDirPre" Order="1">1</Publish> + <Publish Dialog="VBoxCustomizeDlg" Control="Next" Property="VBOX_SHOW_INVALID_TARGET_DLG" Value="1" Order="2"><![CDATA[VBox_Target_Dir_Is_Valid="0"]]></Publish> + <Publish Dialog="VBoxCustomizeDlg" Control="Next" Property="VBOX_SHOW_INVALID_TARGET_DLG" Value="{}" Order="3"><![CDATA[VBox_Target_Dir_Is_Valid="1"]]></Publish> + <Publish Dialog="VBoxCustomizeDlg" Control="Next" Property="VBOX_SHOW_WARN_PYTHONAPI_DLG" Value="1" Order="4"><![CDATA[(&VBoxPython=3) AND (VBOX_PYTHON_DEPS_INSTALLED="0")]]></Publish> + <Publish Dialog="VBoxCustomizeDlg" Control="Next" Property="VBOX_SHOW_WARN_PYTHONAPI_DLG" Value="{}" Order="5"><![CDATA[(&VBoxPython<3)]]></Publish> + <Publish Dialog="VBoxCustomizeDlg" Control="Next" Property="VBOX_SHOW_WARN_DISCONNECTIFACES_DLG" Value="1" Order="6"><![CDATA[&VBoxNetworkFlt=3]]></Publish> + <Publish Dialog="VBoxCustomizeDlg" Control="Next" Property="VBOX_SHOW_WARN_DISCONNECTIFACES_DLG" Value="{}" Order="7"><![CDATA[&VBoxNetworkFlt<3]]></Publish> + + <!-- Show an error dialog if the chosen installation directory was found to be invalid. See @bugref{10616} --> + <Publish Dialog="VBoxCustomizeDlg" Control="Next" Event="NewDialog" Value="VBoxInvalidTargetDirDlg" Order="10"><![CDATA[VBOX_SHOW_INVALID_TARGET_DLG]]></Publish> + <Publish Dialog="VBoxCustomizeDlg" Control="Next" Event="NewDialog" Value="VBoxWarnDisconNetIfacesDlg" Order="20"><![CDATA[VBOX_SHOW_WARN_DISCONNECTIFACES_DLG and (NOT VBOX_SHOW_INVALID_TARGET_DLG)]]></Publish> + <Publish Dialog="VBoxCustomizeDlg" Control="Next" Event="NewDialog" Value="VBoxWarnPythonDlg" Order="30"><![CDATA[VBOX_SHOW_WARN_PYTHONAPI_DLG AND (NOT VBOX_SHOW_WARN_DISCONNECTIFACES_DLG) AND (NOT VBOX_SHOW_INVALID_TARGET_DLG)]]></Publish> + <!-- Only allow going to the next stage if the chosen installation directory is valid. See @bugref{10616} --> + <Publish Dialog="VBoxCustomizeDlg" Control="Next" Event="NewDialog" Value="VBoxCustomize2Dlg" Order="40"><![CDATA[VBOX_SHOW_CUSTOMIZE2_DLG AND (NOT VBOX_SHOW_WARN_DISCONNECTIFACES_DLG) AND (NOT VBOX_SHOW_WARN_PYTHONAPI_DLG) AND (NOT VBOX_SHOW_INVALID_TARGET_DLG)]]></Publish> + <Publish Dialog="VBoxCustomizeDlg" Control="Next" Event="NewDialog" Value="VBoxVerifyReadyDlg" Order="50"><![CDATA[(NOT VBOX_SHOW_CUSTOMIZE2_DLG) AND (NOT VBOX_SHOW_WARN_DISCONNECTIFACES_DLG) AND (NOT VBOX_SHOW_WARN_PYTHONAPI_DLG)]]></Publish> <Publish Dialog="VBoxCustomizeDlg" Control="Back" Event="NewDialog" Value="VBoxCheckSerialDlg"><![CDATA[VBOX_SHOW_SERIAL_CHECK_DLG]]></Publish> <Publish Dialog="VBoxCustomizeDlg" Control="Back" Event="NewDialog" Value="VBoxLicenseAgreementDlg"><![CDATA[NOT VBOX_SHOW_SERIAL_CHECK_DLG]]></Publish> @@ -1211,6 +1260,7 @@ <?if $(env.VBOX_WITH_CRT_PACKING) = "no" ?> <Custom Action="ca_IsMSCRTInstalled" After="AppSearch" /> <?endif?> + <Custom Action="ca_CheckTargetDirPre" After="AppSearch"/> <!-- Required for launch conditions. See @bugref{10616} --> <Custom Action="ca_OriginalTargetDir" After="FileCost"><![CDATA[(NOT INSTALLDIR) AND (NOT EXISTINGINSTALLDIR)]]></Custom> <Custom Action="ca_DefaultTargetDir" After="FileCost"><![CDATA[NOT Installed AND (NOT INSTALLDIR) AND EXISTINGINSTALLDIR]]></Custom> <Custom Action="ca_IsWindows10" After="CostFinalize" /> diff --git a/src/VBox/Installer/win/VBoxMergeAppCA.wxi b/src/VBox/Installer/win/VBoxMergeAppCA.wxi index ddc29f5e..2a3eef7f 100644 --- a/src/VBox/Installer/win/VBoxMergeAppCA.wxi +++ b/src/VBox/Installer/win/VBoxMergeAppCA.wxi @@ -35,5 +35,11 @@ <CustomAction Id="ca_IsWindows10" BinaryKey="VBoxInstallHelper" DllEntry="IsWindows10" Execute="immediate" Return="ignore" Impersonate="no" /> + <!-- Makes sure we check if the chosen target directory is valid before allowing to install. See @bugref{10616} --> + <CustomAction Id="ca_CheckTargetDirPre" BinaryKey="VBoxInstallHelper" + DllEntry="CheckTargetDir" Execute="immediate" Return="ignore" Impersonate="no" /> + <!-- Makes sure that the target directory we installed into still is valid. Rollback if it isn't. See @bugref{10616} --> + <CustomAction Id="ca_CheckTargetDirPost" BinaryKey="VBoxInstallHelper" + DllEntry="CheckTargetDir" Execute="immediate" Return="check" Impersonate="no" /> </Include> diff --git a/src/VBox/Installer/win/VBoxMergeAppSeq.wxi b/src/VBox/Installer/win/VBoxMergeAppSeq.wxi index b6340cef..6b7c3a1f 100644 --- a/src/VBox/Installer/win/VBoxMergeAppSeq.wxi +++ b/src/VBox/Installer/win/VBoxMergeAppSeq.wxi @@ -30,6 +30,11 @@ <?if $(env.VBOX_WITH_CRT_PACKING) = "no" ?> <Custom Action="ca_IsMSCRTInstalled" After="AppSearch">1</Custom> <?endif?> + <!-- Required for lauch conditions. See @bugref{10616} --> + <Custom Action="ca_CheckTargetDirPre" After="AppSearch"/> + <!-- Check if the installation directory still fits our security requirements after we finalized installation. + See @bugref{10616} --> + <Custom Action="ca_CheckTargetDirPost" After="InstallFinalize"><![CDATA[NOT REMOVE]]></Custom> <Custom Action="ca_IsWindows10" After="FileCost">1</Custom> diff --git a/src/VBox/Installer/win/VirtualBox.wxs b/src/VBox/Installer/win/VirtualBox.wxs index 1e4911cc..beccd815 100644 --- a/src/VBox/Installer/win/VirtualBox.wxs +++ b/src/VBox/Installer/win/VirtualBox.wxs @@ -127,6 +127,11 @@ Installed OR (VBOX_MSCRT_INSTALLED) </Condition> <?endif ?> + <!-- Check if the current INSTALLDIR is valid or not, or if VBox already is installed. + Thight might be handed-in via command line (MSI properties) or through a customized merge module. See @bugref{10616} --> + <Condition Message="!(loc.InvalidTargetDir)"> + Installed OR (VBox_Target_Dir_Is_Valid="1") + </Condition> <!-- Detect old innotek installation --> <!-- Force a manual uninstall of an already installed innotek VirtualBox version first --> |