VirtualBox

source: vbox/trunk/src/VBox/Installer/win/InstallHelper/VBoxInstallHelper.cpp@ 104164

最後變更 在這個檔案從104164是 104164,由 vboxsync 提交於 12 月 前

Windows/Host Installer: Check permissions of target directory when installing. Added a new testcase for this [build fix]. bugref:10616

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 98.3 KB
 
1/* $Id: VBoxInstallHelper.cpp 104164 2024-04-04 17:14:12Z vboxsync $ */
2/** @file
3 * VBoxInstallHelper - Various helper routines for Windows host installer.
4 */
5
6/*
7 * Copyright (C) 2008-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.alldomusa.eu.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#if defined(VBOX_WITH_NETFLT) || defined(VBOX_WITH_NETADP)
33# include "VBox/VBoxNetCfg-win.h"
34# include "VBox/VBoxDrvCfg-win.h"
35#endif
36
37#define _WIN32_DCOM
38#include <iprt/win/windows.h>
39
40#include <aclapi.h>
41#include <msi.h>
42#include <msiquery.h>
43
44#include <shellapi.h>
45#define INITGUID
46#include <guiddef.h>
47#include <cfgmgr32.h>
48#include <devguid.h>
49#include <sddl.h> /* For ConvertSidToStringSidW. */
50
51#include <iprt/win/objbase.h>
52#include <iprt/win/setupapi.h>
53#include <iprt/win/shlobj.h>
54
55#include <VBox/version.h>
56
57#include <iprt/assert.h>
58#include <iprt/alloca.h>
59#include <iprt/dir.h>
60#include <iprt/err.h>
61#include <iprt/file.h>
62#include <iprt/mem.h>
63#include <iprt/path.h> /* RTPATH_MAX, RTPATH_IS_SLASH */
64#include <iprt/string.h> /* RT_ZERO */
65#include <iprt/stream.h>
66#include <iprt/thread.h>
67#include <iprt/utf16.h>
68
69#include "VBoxCommon.h"
70#ifndef VBOX_OSE
71# include "internal/VBoxSerial.h"
72#endif
73
74
75/*********************************************************************************************************************************
76* Defined Constants And Macros *
77*********************************************************************************************************************************/
78#ifdef DEBUG
79# define NonStandardAssert(_expr) Assert(_expr)
80#else
81# define NonStandardAssert(_expr) do{ }while(0)
82#endif
83
84#define MY_WTEXT_HLP(a_str) L##a_str
85#define MY_WTEXT(a_str) MY_WTEXT_HLP(a_str)
86
87
88/*********************************************************************************************************************************
89* Internal structures *
90*********************************************************************************************************************************/
91/**
92 * Structure for keeping a target's directory security context.
93 */
94typedef struct TGTDIRSECCTX
95{
96 /** Initialized status. */
97 bool fInitialized;
98 /** Handle of the target's parent directory.
99 *
100 * Kept open while the context is around and initialized. */
101 RTDIR hParentDir;
102 /** Absolute (resolved) path of the target directory. */
103 char szTargetDirAbs[RTPATH_MAX];
104 /** Access mask which is forbidden for an ACE of type ACCESS_ALLOWED_ACE_TYPE. */
105 uint32_t fAccessMaskForbidden;
106 /** Array of well-known SIDs which are forbidden. */
107 PSID *paWellKnownSidsForbidden;
108 /** Number of entries in \a paWellKnownSidsForbidden. */
109 size_t cWellKnownSidsForbidden;
110} TGTDIRSECCTX;
111/** Pointer to a target's directory security context. */
112typedef TGTDIRSECCTX *PTGTDIRSECCTX;
113
114
115/*********************************************************************************************************************************
116* Prototypes *
117*********************************************************************************************************************************/
118static void destroyTargetDirSecurityCtx(PTGTDIRSECCTX pCtx);
119
120
121/*********************************************************************************************************************************
122* Globals *
123*********************************************************************************************************************************/
124static uint32_t g_cRef = 0;
125/** Our target directory security context.
126 *
127 * Has to be global in order to keep it around as long as the DLL is being loaded. */
128static TGTDIRSECCTX g_TargetDirSecCtx = { 0 };
129
130
131/**
132 * DLL entry point.
133 */
134BOOL WINAPI DllMain(HANDLE hInst, ULONG uReason, LPVOID pReserved)
135{
136 RT_NOREF(hInst, uReason, pReserved);
137
138#ifdef DEBUG
139 WCHAR wszMsg[128];
140 RTUtf16Printf(wszMsg, RT_ELEMENTS(wszMsg), "DllMain: hInst=%#x, uReason=%u (PID %u), g_cRef=%RU32\n",
141 hInst, uReason, GetCurrentProcessId(), g_cRef);
142 OutputDebugStringW(wszMsg);
143#endif
144
145 switch (uReason)
146 {
147 case DLL_PROCESS_ATTACH:
148 {
149 g_cRef++;
150#if 0
151 /*
152 * This is a trick for allowing the debugger to be attached, don't know if
153 * there is an official way to do that, but this is a pretty efficient.
154 *
155 * Monitor the debug output in DbgView and be ready to start windbg when
156 * the message below appear. This will happen 3-4 times during install,
157 * and 2-3 times during uninstall.
158 *
159 * Note! The DIFxApp.DLL will automatically trigger breakpoints when a
160 * debugger is attached. Just continue on these.
161 */
162 RTUtf16Printf(wszMsg, RT_ELEMENTS(wszMsg), "Waiting for debugger to attach: windbg -g -G -p %u\n", GetCurrentProcessId());
163 for (unsigned i = 0; i < 128 && !IsDebuggerPresent(); i++)
164 {
165 OutputDebugStringW(wszMsg);
166 Sleep(1001);
167 }
168 Sleep(1002);
169 __debugbreak();
170#endif
171 break;
172 }
173
174 case DLL_PROCESS_DETACH:
175 {
176 g_cRef--;
177 break;
178 }
179
180 default:
181 break;
182 }
183
184 return TRUE;
185}
186
187/**
188 * Format a log message and print it to whatever is there (i.e. to the MSI log).
189 *
190 * UTF-16 strings are formatted using '%ls' (lowercase).
191 * ANSI strings are formatted using '%s' (uppercase).
192 *
193 * @returns VBox status code.
194 * @param hInstall MSI installer handle. Optional and can be NULL.
195 * @param pszFmt Format string.
196 * @param ... Variable arguments for format string.
197 */
198static int logStringF(MSIHANDLE hInstall, const char *pszFmt, ...)
199{
200 RTUTF16 wszVa[RTPATH_MAX + 256];
201 va_list va;
202 va_start(va, pszFmt);
203 ssize_t cwc = RTUtf16PrintfV(wszVa, RT_ELEMENTS(wszVa), pszFmt, va);
204 va_end(va);
205
206 RTUTF16 wszMsg[RTPATH_MAX + 256];
207 cwc = RTUtf16Printf(wszMsg, sizeof(wszMsg), "VBoxInstallHelper: %ls", wszVa);
208 if (cwc <= 0)
209 return VERR_BUFFER_OVERFLOW;
210
211#ifdef DEBUG
212 OutputDebugStringW(wszMsg);
213#endif
214#ifdef TESTCASE
215 RTPrintf("%ls\n", wszMsg);
216#endif
217 PMSIHANDLE hMSI = MsiCreateRecord(2 /* cParms */);
218 if (hMSI)
219 {
220 MsiRecordSetStringW(hMSI, 0, wszMsg);
221 MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_INFO), hMSI);
222 MsiCloseHandle(hMSI);
223 }
224
225 return cwc < RT_ELEMENTS(wszVa) ? VINF_SUCCESS : VERR_BUFFER_OVERFLOW;
226}
227
228UINT __stdcall IsSerialCheckNeeded(MSIHANDLE hModule)
229{
230#ifndef VBOX_OSE
231 /*BOOL fRet =*/ serialCheckNeeded(hModule);
232#else
233 RT_NOREF(hModule);
234#endif
235 return ERROR_SUCCESS;
236}
237
238UINT __stdcall CheckSerial(MSIHANDLE hModule)
239{
240#ifndef VBOX_OSE
241 /*BOOL bRet =*/ serialIsValid(hModule);
242#else
243 RT_NOREF(hModule);
244#endif
245 return ERROR_SUCCESS;
246}
247
248/**
249 * Initializes a target security context.
250 *
251 * @returns VBox status code.
252 * @param pCtx Target directory security context to initialize.
253 * @param hModule Windows installer module handle.
254 * @param pszPath Target directory path to use.
255 */
256static int initTargetDirSecurityCtx(PTGTDIRSECCTX pCtx, MSIHANDLE hModule, const char *pszPath)
257{
258 if (pCtx->fInitialized)
259 return VINF_SUCCESS;
260
261#ifdef DEBUG
262 logStringF(hModule, "initTargetDirSecurityCtx: pszPath=%s\n", pszPath);
263#endif
264
265 char szPathTemp[RTPATH_MAX];
266 int vrc = RTStrCopy(szPathTemp, sizeof(szPathTemp), pszPath);
267 if (RT_FAILURE(vrc))
268 return vrc;
269
270 /* Try to find a parent path which exists. */
271 char szPathParentAbs[RTPATH_MAX] = { 0 };
272 for (int i = 0; i < 256; i++) /* Failsafe counter. */
273 {
274 RTPathStripTrailingSlash(szPathTemp);
275 RTPathStripFilename(szPathTemp);
276 vrc = RTPathReal(szPathTemp, szPathParentAbs, sizeof(szPathParentAbs));
277 if (RT_SUCCESS(vrc))
278 break;
279 }
280
281 if (RT_FAILURE(vrc))
282 {
283 logStringF(hModule, "initTargetDirSecurityCtx: No existing / valid parent directory found (%Rrc), giving up\n", vrc);
284 return vrc;
285 }
286
287 RTDIR hParentDir;
288 vrc = RTDirOpen(&hParentDir, szPathParentAbs);
289 if (RT_FAILURE(vrc))
290 {
291 logStringF(hModule, "initTargetDirSecurityCtx: Locking parent directory '%s' failed with %Rrc\n", szPathParentAbs, vrc);
292 return vrc;
293 }
294
295#ifdef DEBUG
296 logStringF(hModule, "initTargetDirSecurityCtx: Locked parent directory '%s'\n", szPathParentAbs);
297#endif
298
299 char szPathTargetAbs[RTPATH_MAX];
300 vrc = RTPathReal(pszPath, szPathTargetAbs, sizeof(szPathTargetAbs));
301 if (RT_FAILURE(vrc))
302 vrc = RTStrCopy(szPathTargetAbs, sizeof(szPathTargetAbs), pszPath);
303 if (RT_FAILURE(vrc))
304 {
305 logStringF(hModule, "initTargetDirSecurityCtx: Failed to resolve absolute target path (%Rrc)\n", vrc);
306 return vrc;
307 }
308
309#ifdef DEBUG
310 logStringF(hModule, "initTargetDirSecurityCtx: szPathTargetAbs=%s, szPathParentAbs=%s\n", szPathTargetAbs, szPathParentAbs);
311#endif
312
313 /* Target directory validation. */
314 if ( !RTStrCmp(szPathTargetAbs, szPathParentAbs) /* Don't allow installation into root directories. */
315 || RTStrStr(szPathTargetAbs, ".."))
316 {
317 logStringF(hModule, "initTargetDirSecurityCtx: Directory '%s' invalid", szPathTargetAbs);
318 vrc = VERR_INVALID_NAME;
319 }
320
321 if (RT_SUCCESS(vrc))
322 {
323 RTFSOBJINFO fsObjInfo;
324 vrc = RTPathQueryInfo(szPathParentAbs, &fsObjInfo, RTFSOBJATTRADD_NOTHING);
325 if (RT_SUCCESS(vrc))
326 {
327 if (RTFS_IS_DIRECTORY(fsObjInfo.Attr.fMode)) /* No symlinks or other fun stuff. */
328 {
329 static WELL_KNOWN_SID_TYPE aForbiddenWellKnownSids[] =
330 {
331 WinNullSid,
332 WinWorldSid,
333 WinAuthenticatedUserSid,
334 WinBuiltinUsersSid,
335 WinBuiltinGuestsSid,
336 WinBuiltinPowerUsersSid
337 };
338
339 pCtx->paWellKnownSidsForbidden = (PSID *)RTMemAlloc(sizeof(PSID) * RT_ELEMENTS(aForbiddenWellKnownSids));
340 AssertPtrReturn(pCtx->paWellKnownSidsForbidden, VERR_NO_MEMORY);
341
342 size_t i = 0;
343 for(; i < RT_ELEMENTS(aForbiddenWellKnownSids); i++)
344 {
345 pCtx->paWellKnownSidsForbidden[i] = RTMemAlloc(SECURITY_MAX_SID_SIZE);
346 AssertPtrBreakStmt(pCtx->paWellKnownSidsForbidden, vrc = VERR_NO_MEMORY);
347 DWORD cbSid = SECURITY_MAX_SID_SIZE;
348 if (!CreateWellKnownSid(aForbiddenWellKnownSids[i], NULL, pCtx->paWellKnownSidsForbidden[i], &cbSid))
349 {
350 vrc = RTErrConvertFromWin32(GetLastError());
351 logStringF(hModule, "initTargetDirSecurityCtx: Creating SID (index %zu) failed with %Rrc\n", i, vrc);
352 break;
353 }
354 }
355
356 if (RT_SUCCESS(vrc))
357 {
358 vrc = RTStrCopy(pCtx->szTargetDirAbs, sizeof(pCtx->szTargetDirAbs), szPathTargetAbs);
359 if (RT_SUCCESS(vrc))
360 {
361 pCtx->fInitialized = true;
362 pCtx->hParentDir = hParentDir;
363 pCtx->cWellKnownSidsForbidden = i;
364 pCtx->fAccessMaskForbidden = FILE_WRITE_DATA
365 | FILE_APPEND_DATA
366 | FILE_WRITE_ATTRIBUTES
367 | FILE_WRITE_EA;
368
369 RTFILE fh;
370 RTFileOpen(&fh, "c:\\temp\\targetdir.ctx", RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE | RTFILE_O_WRITE);
371 RTFileClose(fh);
372
373 return VINF_SUCCESS;
374 }
375 }
376 }
377 else
378 vrc = VERR_INVALID_NAME;
379 }
380 }
381
382 RTDirClose(hParentDir);
383
384 while (pCtx->cWellKnownSidsForbidden--)
385 {
386 RTMemFree(pCtx->paWellKnownSidsForbidden[pCtx->cWellKnownSidsForbidden]);
387 pCtx->paWellKnownSidsForbidden[pCtx->cWellKnownSidsForbidden] = NULL;
388 }
389
390 logStringF(hModule, "initTargetDirSecurityCtx: Initialization failed failed with %Rrc\n", vrc);
391 return vrc;
392}
393
394/**
395 * Destroys a target security context.
396 *
397 * @returns VBox status code.
398 * @param pCtx Target directory security context to destroy.
399 */
400static void destroyTargetDirSecurityCtx(PTGTDIRSECCTX pCtx)
401{
402 if ( !pCtx
403 || !pCtx->fInitialized)
404 return;
405
406 if (pCtx->hParentDir != NIL_RTDIR)
407 {
408 RTDirClose(pCtx->hParentDir);
409 pCtx->hParentDir = NIL_RTDIR;
410 }
411 RT_ZERO(pCtx->szTargetDirAbs);
412
413 for (size_t i = 0; i < pCtx->cWellKnownSidsForbidden; i++)
414 RTMemFree(pCtx->paWellKnownSidsForbidden[i]);
415 pCtx->cWellKnownSidsForbidden = 0;
416
417 RTMemFree(pCtx->paWellKnownSidsForbidden);
418 pCtx->paWellKnownSidsForbidden = NULL;
419
420 RTFileDelete("c:\\temp\\targetdir.ctx");
421
422 logStringF(NULL, "destroyTargetDirSecurityCtx\n");
423}
424
425#ifdef DEBUG
426/**
427 * Returns a stingified version of an ACE type.
428 *
429 * @returns Stingified version of an ACE type.
430 * @param uType ACE type.
431 */
432inline const char *dbgAceTypeToString(uint8_t uType)
433{
434 switch (uType)
435 {
436 RT_CASE_RET_STR(ACCESS_ALLOWED_ACE_TYPE);
437 RT_CASE_RET_STR(ACCESS_DENIED_ACE_TYPE);
438 RT_CASE_RET_STR(SYSTEM_AUDIT_ACE_TYPE);
439 RT_CASE_RET_STR(SYSTEM_ALARM_ACE_TYPE);
440 default: break;
441 }
442
443 return "<Invalid>";
444}
445
446/**
447 * Returns an allocated string for a SID containing the user/domain name.
448 *
449 * @returns Allocated string (UTF-8). Must be free'd using RTStrFree().
450 * @param pSid SID to return allocated string for.
451 */
452inline char *dbgSidToNameA(const PSID pSid)
453{
454 char *pszName = NULL;
455 int vrc = VINF_SUCCESS;
456
457 LPWSTR pwszSid = NULL;
458 if (ConvertSidToStringSid(pSid, &pwszSid))
459 {
460 SID_NAME_USE SidNameUse;
461
462 WCHAR wszUser[MAX_PATH];
463 DWORD cbUser = sizeof(wszUser);
464 WCHAR wszDomain[MAX_PATH];
465 DWORD cbDomain = sizeof(wszDomain);
466 if (LookupAccountSid(NULL, pSid, wszUser, &cbUser, wszDomain, &cbDomain, &SidNameUse))
467 {
468 RTUTF16 wszName[RTPATH_MAX];
469 if (RTUtf16Printf(wszName, RT_ELEMENTS(wszName), "%ls%s%ls (%ls)",
470 wszUser, wszDomain[0] == L'\0' ? "" : "\\", wszDomain, pwszSid))
471 {
472 vrc = RTUtf16ToUtf8(wszName, &pszName);
473 }
474 else
475 vrc = VERR_NO_MEMORY;
476 }
477 else
478 vrc = RTStrAPrintf(&pszName, "<Lookup Error>");
479
480 LocalFree(pwszSid);
481 }
482 else
483 vrc = VERR_NOT_FOUND;
484
485 return RT_SUCCESS(vrc) ? pszName : "<Invalid>";
486}
487#endif /* DEBUG */
488
489/**
490 * Checks a single target path whether it's safe to use or not.
491 *
492 * We check if the given path is owned by "NT Service\TrustedInstaller" and therefore assume that it's safe to use.
493 *
494 * @returns VBox status code. On error the path should be considered unsafe.
495 * @retval VERR_INVALID_NAME if the given path is considered unsafe.
496 * @retval VINF_SUCCESS if the given path is found to be safe to use.
497 * @param hModule Windows installer module handle.
498 * @param pszPath Path to check.
499 */
500static int checkTargetDirOne(MSIHANDLE hModule, PTGTDIRSECCTX pCtx, const char *pszPath)
501{
502 logStringF(hModule, "checkTargetDirOne: Checking '%s' ...", pszPath);
503
504 PRTUTF16 pwszPath;
505 int vrc = RTStrToUtf16(pszPath, &pwszPath);
506 if (RT_FAILURE(vrc))
507 return vrc;
508
509 PACL pDacl = NULL;
510 PSECURITY_DESCRIPTOR pSecurityDescriptor = { 0 };
511 DWORD dwErr = GetNamedSecurityInfo(pwszPath, SE_FILE_OBJECT, GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
512 NULL, NULL, NULL, NULL, &pSecurityDescriptor);
513 if (dwErr == ERROR_SUCCESS)
514 {
515 BOOL fDaclPresent = FALSE;
516 BOOL fDaclDefaultedIgnored = FALSE;
517 if (GetSecurityDescriptorDacl(pSecurityDescriptor, &fDaclPresent,
518 &pDacl, &fDaclDefaultedIgnored))
519 {
520 if ( !fDaclPresent
521 || !pDacl)
522 {
523 /* Bail out early if the DACL isn't provided or is missing. */
524 vrc = VERR_INVALID_NAME;
525 }
526 else
527 {
528 ACL_SIZE_INFORMATION aclSizeInfo;
529 RT_ZERO(aclSizeInfo);
530 if (GetAclInformation(pDacl, &aclSizeInfo, sizeof(aclSizeInfo), AclSizeInformation))
531 {
532 for(DWORD idxACE = 0; idxACE < aclSizeInfo.AceCount; idxACE++)
533 {
534 ACE_HEADER *pAceHdr = NULL;
535 if (GetAce(pDacl, idxACE, (LPVOID *)&pAceHdr))
536 {
537#ifdef DEBUG
538 logStringF(hModule, "checkTargetDirOne: ACE type=%s, flags=%#x, size=%#x",
539 dbgAceTypeToString(pAceHdr->AceType), pAceHdr->AceFlags, pAceHdr->AceSize);
540#endif
541 /* Note: We print the ACEs in canonoical order. */
542 switch (pAceHdr->AceType)
543 {
544 case ACCESS_ALLOWED_ACE_TYPE: /* We're only interested in the ALLOW ACE. */
545 {
546 ACCESS_ALLOWED_ACE const *pAce = (ACCESS_ALLOWED_ACE *)pAceHdr;
547 PSID const pSid = (PSID)&pAce->SidStart;
548#ifdef DEBUG
549 char *pszSid = dbgSidToNameA(pSid);
550 logStringF(hModule, "checkTargetDirOne:\t%s fMask=%#x", pszSid, pAce->Mask);
551 RTStrFree(pszSid);
552#endif
553 /* We check the flags here first for performance reasons. */
554 if ((pAce->Mask & pCtx->fAccessMaskForbidden) == pCtx->fAccessMaskForbidden)
555 {
556 for (size_t idxSID = 0; idxSID < pCtx->cWellKnownSidsForbidden; idxSID++)
557 {
558 PSID const pSidForbidden = pCtx->paWellKnownSidsForbidden[idxSID];
559 bool const fForbidden = EqualSid(pSid, pSidForbidden);
560#ifdef DEBUG
561 char *pszName = dbgSidToNameA(pSidForbidden);
562 logStringF(hModule, "checkTargetDirOne:\t%s : %s",
563 fForbidden ? "** FORBIDDEN **" : "ALLOWED ", pszName);
564 RTStrFree(pszName);
565#endif /* DEBUG */
566 if (fForbidden)
567 {
568 vrc = VERR_INVALID_NAME;
569 break;
570 }
571 }
572 }
573
574 break;
575 }
576
577 case ACCESS_DENIED_ACE_TYPE: /* We're only interested in the ALLOW ACE. */
578 {
579 ACCESS_DENIED_ACE const *pAce = (ACCESS_DENIED_ACE *)pAceHdr;
580#ifdef DEBUG
581 LPWSTR pwszSid = NULL;
582 ConvertSidToStringSid((PSID)&pAce->SidStart, &pwszSid);
583
584 logStringF(hModule, "checkTargetDirOne:\t%ls fMask=%#x (generic %#x specific %#x)",
585 pwszSid ? pwszSid : L"<Allocation Error>", pAce->Mask);
586
587 LocalFree(pwszSid);
588#endif /* DEBUG */
589 /* Ignore everything else. */
590 break;
591 }
592 }
593 }
594 else
595 dwErr = GetLastError();
596
597 /* No point in checking further if we failed somewhere above. */
598 if (RT_FAILURE(vrc))
599 break;
600
601 } /* for ACE */
602 }
603 else
604 dwErr = GetLastError();
605 }
606 }
607 else
608 dwErr = GetLastError();
609
610 LocalFree(pSecurityDescriptor);
611 }
612 else
613 dwErr = GetLastError();
614
615 if (RT_SUCCESS(vrc))
616 vrc = RTErrConvertFromWin32(dwErr);
617
618#ifdef DEBUG
619 logStringF(hModule, "checkTargetDirOne: Returning %Rrc", vrc);
620#endif
621
622 if ( RT_FAILURE(vrc)
623 && vrc != VERR_INVALID_NAME)
624 logStringF(hModule, "checkTargetDirOne: Failed with %Rrc (%#x)", vrc, dwErr);
625
626 return vrc;
627}
628
629/**
630 * Checks whether the path in the public property INSTALLDIR has the correct ACL permissions and returns whether
631 * it's valid or not.
632 *
633 * Called from the MSI installer as a custom action.
634 *
635 * @returns Success status (acccording to MSI custom actions).
636 * @retval ERROR_SUCCESS if checking the target directory turned out to be valid.
637 * @retval ERROR_NO_NET_OR_BAD_PATH is the target directory is invalid.
638 * @param hModule Windows installer module handle.
639 *
640 * @note Sets private property VBox_Target_Dir_Is_Valid to "1" (true) if the given target path is valid,
641 * or "0" (false) if it is not. An empty target directory is considered to be valid (i.e. INSTALLDIR not set yet).
642 *
643 * @sa @bugref{10616}
644 */
645UINT __stdcall CheckTargetDir(MSIHANDLE hModule)
646{
647 char *pszTargetDir;
648
649 int vrc = VBoxGetMsiPropUtf8(hModule, "INSTALLDIR", &pszTargetDir);
650 if (RT_SUCCESS(vrc))
651 {
652 logStringF(hModule, "CheckTargetDir: Checking target directory '%s' ...", pszTargetDir);
653
654 if (!RTStrNLen(pszTargetDir, RTPATH_MAX))
655 {
656 logStringF(hModule, "CheckTargetDir: No INSTALLDIR set (yet), skipping ...");
657 VBoxSetMsiProp(hModule, L"VBox_Target_Dir_Is_Valid", L"1");
658 }
659 else
660 {
661 union
662 {
663 RTPATHPARSED Parsed;
664 uint8_t ab[RTPATH_MAX];
665 } u;
666
667 vrc = RTPathParse(pszTargetDir, &u.Parsed, sizeof(u), RTPATH_STR_F_STYLE_DOS);
668 if (RT_SUCCESS(vrc))
669 {
670 if (u.Parsed.fProps & RTPATH_PROP_DOTDOT_REFS)
671 vrc = VERR_INVALID_PARAMETER;
672 if (RT_SUCCESS(vrc))
673 {
674 vrc = initTargetDirSecurityCtx(&g_TargetDirSecCtx, hModule, pszTargetDir);
675 if (RT_SUCCESS(vrc))
676 {
677 uint16_t idxComp = u.Parsed.cComps;
678 char szPathToCheck[RTPATH_MAX];
679 while (idxComp > 1) /* We traverse backwards from INSTALLDIR and leave out the root (e.g. C:\"). */
680 {
681 u.Parsed.cComps = idxComp;
682 vrc = RTPathParsedReassemble(pszTargetDir, &u.Parsed, RTPATH_STR_F_STYLE_DOS,
683 szPathToCheck, sizeof(szPathToCheck));
684 if (RT_FAILURE(vrc))
685 break;
686 if (RTDirExists(szPathToCheck))
687 {
688 vrc = checkTargetDirOne(hModule, &g_TargetDirSecCtx, szPathToCheck);
689 if (RT_FAILURE(vrc))
690 break;
691 }
692 else
693 logStringF(hModule, "CheckTargetDir: Path '%s' does not exist (yet)", szPathToCheck);
694 idxComp--;
695 }
696
697 destroyTargetDirSecurityCtx(&g_TargetDirSecCtx);
698 }
699 else
700 logStringF(hModule, "CheckTargetDir: initTargetDirSecurityCtx failed with %Rrc\n", vrc);
701
702 if (RT_SUCCESS(vrc))
703 VBoxSetMsiProp(hModule, L"VBox_Target_Dir_Is_Valid", L"1");
704 }
705 }
706 else
707 logStringF(hModule, "CheckTargetDir: Parsing path failed with %Rrc", vrc);
708 }
709
710 RTStrFree(pszTargetDir);
711 }
712
713 if (RT_FAILURE(vrc)) /* On failure (or when in doubt), mark the installation directory as invalid. */
714 {
715 logStringF(hModule, "CheckTargetDir: Checking failed with %Rrc", vrc);
716 VBoxSetMsiProp(hModule, L"VBox_Target_Dir_Is_Valid", L"0");
717 }
718
719 /* Return back outcome to the MSI engine. */
720 return RT_SUCCESS(vrc) ? ERROR_SUCCESS : ERROR_NO_NET_OR_BAD_PATH;
721}
722
723/**
724 * Runs an executable on the OS.
725 *
726 * @returns Windows error code.
727 * @param hModule Windows installer module handle.
728 * @param pwszImage The executable to run.
729 * @param pwszArgs The arguments (command line w/o executable).
730 */
731static UINT procRun(MSIHANDLE hModule, const wchar_t *pwszImage, wchar_t const *pwszArgs)
732{
733 /*
734 * Construct a full command line.
735 */
736 size_t const cwcImage = RTUtf16Len(pwszImage);
737 size_t const cwcArgs = RTUtf16Len(pwszArgs);
738
739 wchar_t *pwszCmdLine = (wchar_t *)alloca((1 + cwcImage + 1 + 1 + cwcArgs + 1) * sizeof(wchar_t));
740 pwszCmdLine[0] = '"';
741 memcpy(&pwszCmdLine[1], pwszImage, cwcImage * sizeof(wchar_t));
742 pwszCmdLine[1 + cwcImage] = '"';
743 pwszCmdLine[1 + cwcImage + 1] = ' ';
744 memcpy(&pwszCmdLine[1 + cwcImage + 1 + 1], pwszArgs, (cwcArgs + 1) * sizeof(wchar_t));
745
746 /*
747 * Construct startup info.
748 */
749 STARTUPINFOW StartupInfo;
750 RT_ZERO(StartupInfo);
751 StartupInfo.cb = sizeof(StartupInfo);
752 StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
753 StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
754 StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
755 StartupInfo.dwFlags = STARTF_USESTDHANDLES;
756#ifndef DEBUG
757 StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
758 StartupInfo.wShowWindow = SW_HIDE;
759#endif
760
761 /*
762 * Start it.
763 */
764 UINT rcWin;
765 PROCESS_INFORMATION ChildInfo = { NULL, NULL, 0, 0 };
766 if (CreateProcessW(pwszImage, pwszCmdLine, NULL /*pProcessAttribs*/, NULL /*pThreadAttribs*/, TRUE /*fInheritHandles*/,
767 0 /*fFlags*/, NULL /*pwszEnv*/, NULL /*pwszCwd*/, &StartupInfo, &ChildInfo))
768 {
769 logStringF(hModule, "procRun: Info: Started process %u: %ls", ChildInfo.dwProcessId, pwszCmdLine);
770 CloseHandle(ChildInfo.hThread);
771 DWORD const dwWait = WaitForSingleObject(ChildInfo.hProcess, RT_MS_30SEC);
772 DWORD dwExitCode = 0xf00dface;
773 if (GetExitCodeProcess(ChildInfo.hProcess, &dwExitCode))
774 {
775 if (dwExitCode == 0)
776 {
777 logStringF(hModule, "procRun: Info: Process '%ls' terminated exit code zero", pwszCmdLine);
778 rcWin = ERROR_SUCCESS;
779 }
780 else
781 {
782 logStringF(hModule, "procRun: Process '%ls' terminated with non-zero exit code: %u (%#x)",
783 pwszCmdLine, dwExitCode, dwExitCode);
784 rcWin = ERROR_GEN_FAILURE;
785 }
786 }
787 else
788 {
789 rcWin = GetLastError();
790 logStringF(hModule, "procRun: Process '%ls' is probably still running: rcWin=%u dwWait=%u (%#x)",
791 pwszCmdLine, rcWin, dwWait, dwWait);
792 }
793 }
794 else
795 {
796 rcWin = GetLastError();
797 logStringF(hModule, "procRun: Creating process '%ls' failed: rcWin=%u\n", pwszCmdLine, rcWin);
798 }
799 return rcWin;
800}
801
802/**
803 * Tries to retrieve the Python installation path on the system, extended version.
804 *
805 * @returns Windows error code.
806 * @param hModule Windows installer module handle.
807 * @param hKeyRoot Registry root key to use, e.g. HKEY_LOCAL_MACHINE.
808 * @param pwszPythonPath Buffer to return the path for python.exe in.
809 * @param cwcPythonPath Buffer size in UTF-16 units.
810 * @param fReturnExe Return the path to python.exe if true, otherwise
811 * just the python install directory.
812 */
813static UINT getPythonPathEx(MSIHANDLE hModule, HKEY hKeyRoot, wchar_t *pwszPythonPath, size_t cwcPythonPath, bool fReturnExe)
814{
815 *pwszPythonPath = '\0';
816
817 /*
818 * Enumerate the subkeys of python core installation key.
819 *
820 * Note: The loop ASSUMES that later found versions are higher, e.g. newer
821 * Python versions. For now we always go by the newest version.
822 */
823 HKEY hKeyPythonCore = NULL;
824 LSTATUS dwErr = RegOpenKeyExW(hKeyRoot, L"SOFTWARE\\Python\\PythonCore", 0, KEY_READ, &hKeyPythonCore);
825 if (dwErr != ERROR_SUCCESS)
826 return dwErr;
827
828 UINT rcWinRet = ERROR_PATH_NOT_FOUND;
829 for (DWORD i = 0; i < 16384; ++i)
830 {
831 static wchar_t const s_wszInstallPath[] = L"\\InstallPath";
832 static wchar_t const s_wszPythonExe[] = L"python.exe";
833
834 /* Get key name: */
835 wchar_t wszBuf[RTPATH_MAX + RT_MAX(RT_ELEMENTS(s_wszInstallPath), RT_ELEMENTS(s_wszPythonExe)) + 2];
836 DWORD cwcKeyNm = RTPATH_MAX;
837 DWORD dwKeyType = REG_SZ;
838 dwErr = RegEnumKeyExW(hKeyPythonCore, i, wszBuf, &cwcKeyNm, NULL, NULL, NULL, NULL);
839 if (dwErr == ERROR_NO_MORE_ITEMS)
840 break;
841 if (dwErr != ERROR_SUCCESS)
842 continue;
843 if (dwKeyType != REG_SZ)
844 continue;
845 if (cwcKeyNm == 0)
846 continue;
847 NonStandardAssert(cwcKeyNm <= sizeof(wszBuf));
848
849 /* Try Open the InstallPath subkey: */
850 memcpy(&wszBuf[cwcKeyNm], s_wszInstallPath, sizeof(s_wszInstallPath));
851
852 HKEY hKeyInstallPath = NULL;
853 dwErr = RegOpenKeyExW(hKeyPythonCore, wszBuf, 0, KEY_READ, &hKeyInstallPath);
854 if (dwErr != ERROR_SUCCESS)
855 continue;
856
857 /* Query the value. We double buffer this so we don't overwrite an okay
858 return value with this. Use the smaller of cwcPythonPath and wszValue
859 so RegQueryValueExW can do all the buffer overflow checking for us.
860 For paranoid reasons, we reserve a space for a terminator as well as
861 a slash. (ASSUMES reasonably sized output buffer.) */
862 NonStandardAssert(cwcPythonPath > RT_ELEMENTS(s_wszPythonExe) + 16);
863 DWORD cbValue = (DWORD)RT_MIN( cwcPythonPath * sizeof(wchar_t)
864 - (fReturnExe ? sizeof(s_wszInstallPath) - sizeof(wchar_t) * 2 : sizeof(wchar_t) * 2),
865 RTPATH_MAX * sizeof(wchar_t));
866 DWORD dwValueType = REG_SZ;
867 dwErr = RegQueryValueExW(hKeyInstallPath, L"", NULL, &dwValueType, (LPBYTE)wszBuf, &cbValue);
868 RegCloseKey(hKeyInstallPath);
869 if ( dwErr == ERROR_SUCCESS
870 && dwValueType == REG_SZ
871 && cbValue >= sizeof(L"C:\\") - sizeof(L""))
872 {
873 /* Find length in wchar_t unit w/o terminator: */
874 DWORD cwc = cbValue / sizeof(wchar_t);
875 while (cwc > 0 && wszBuf[cwc - 1] == '\0')
876 cwc--;
877 wszBuf[cwc] = '\0';
878 if (cwc > 2)
879 {
880 /* Check if the path leads to a directory with a python.exe file in it. */
881 if (!RTPATH_IS_SLASH(wszBuf[cwc - 1]))
882 wszBuf[cwc++] = '\\';
883 memcpy(&wszBuf[cwc], s_wszPythonExe, sizeof(s_wszPythonExe));
884 DWORD const fAttribs = GetFileAttributesW(wszBuf);
885 if (fAttribs != INVALID_FILE_ATTRIBUTES)
886 {
887 if (!(fAttribs & FILE_ATTRIBUTE_DIRECTORY))
888 {
889 /* Okay, we found something that can be returned. */
890 if (fReturnExe)
891 cwc += RT_ELEMENTS(s_wszPythonExe) - 1;
892 wszBuf[cwc] = '\0';
893 logStringF(hModule, "getPythonPath: Found: \"%ls\"", wszBuf);
894
895 NonStandardAssert(cwcPythonPath > cwc);
896 memcpy(pwszPythonPath, wszBuf, cwc * sizeof(wchar_t));
897 pwszPythonPath[cwc] = '\0';
898 rcWinRet = ERROR_SUCCESS;
899 }
900 else
901 logStringF(hModule, "getPythonPath: Warning: Skipping \"%ls\": is a directory (%#x)", wszBuf, fAttribs);
902 }
903 else
904 logStringF(hModule, "getPythonPath: Warning: Skipping \"%ls\": Does not exist (%u)", wszBuf, GetLastError());
905 }
906 }
907 }
908
909 RegCloseKey(hKeyPythonCore);
910 if (rcWinRet != ERROR_SUCCESS)
911 logStringF(hModule, "getPythonPath: Unable to find python");
912 return rcWinRet;
913}
914
915/**
916 * Retrieves the absolute path of the Python installation.
917 *
918 * @returns Windows error code.
919 * @param hModule Windows installer module handle.
920 * @param pwszPythonPath Buffer to return the path for python.exe in.
921 * @param cwcPythonPath Buffer size in UTF-16 units.
922 * @param fReturnExe Return the path to python.exe if true, otherwise
923 * just the python install directory.
924 */
925static UINT getPythonPath(MSIHANDLE hModule, wchar_t *pwszPythonPath, size_t cwcPythonPath, bool fReturnExe = false)
926{
927 UINT rcWin = getPythonPathEx(hModule, HKEY_LOCAL_MACHINE, pwszPythonPath, cwcPythonPath, fReturnExe);
928 if (rcWin != ERROR_SUCCESS)
929 rcWin = getPythonPathEx(hModule, HKEY_CURRENT_USER, pwszPythonPath, cwcPythonPath, fReturnExe);
930 return rcWin;
931}
932
933/**
934 * Retrieves the absolute path of the Python executable.
935 *
936 * @returns Windows error code.
937 * @param hModule Windows installer module handle.
938 * @param pwszPythonExe Buffer to return the path for python.exe in.
939 * @param cwcPythonExe Buffer size in UTF-16 units.
940 */
941static UINT getPythonExe(MSIHANDLE hModule, wchar_t *pwszPythonExe, size_t cwcPythonExe)
942{
943 return getPythonPath(hModule, pwszPythonExe, cwcPythonExe, true /*fReturnExe*/);
944}
945
946/**
947 * Checks if all dependencies for running the VBox Python API bindings are met.
948 *
949 * @returns VBox status code, or error if depedencies are not met.
950 * @param hModule Windows installer module handle.
951 * @param pwszPythonExe Path to Python interpreter image (.exe).
952 */
953static int checkPythonDependencies(MSIHANDLE hModule, const wchar_t *pwszPythonExe)
954{
955 /*
956 * Check if importing the win32api module works.
957 * This is a prerequisite for setting up the VBox API.
958 */
959 logStringF(hModule, "checkPythonDependencies: Checking for win32api extensions ...");
960
961 UINT rcWin = procRun(hModule, pwszPythonExe, L"-c \"import win32api\"");
962 if (rcWin == ERROR_SUCCESS)
963 logStringF(hModule, "checkPythonDependencies: win32api found\n");
964 else
965 logStringF(hModule, "checkPythonDependencies: Importing win32api failed with %u (%#x)\n", rcWin, rcWin);
966
967 return rcWin;
968}
969
970/**
971 * Checks for a valid Python installation on the system.
972 *
973 * Called from the MSI installer as custom action.
974 *
975 * @returns Always ERROR_SUCCESS.
976 * Sets public property VBOX_PYTHON_INSTALLED to "0" (false) or "1" (success).
977 * Sets public property VBOX_PYTHON_PATH to the Python installation path (if found).
978 *
979 * @param hModule Windows installer module handle.
980 */
981UINT __stdcall IsPythonInstalled(MSIHANDLE hModule)
982{
983 wchar_t wszPythonPath[RTPATH_MAX];
984 UINT rcWin = getPythonPath(hModule, wszPythonPath, RTPATH_MAX);
985 if (rcWin == ERROR_SUCCESS)
986 {
987 logStringF(hModule, "IsPythonInstalled: Python installation found at \"%ls\"", wszPythonPath);
988 VBoxSetMsiProp(hModule, L"VBOX_PYTHON_PATH", wszPythonPath);
989 VBoxSetMsiProp(hModule, L"VBOX_PYTHON_INSTALLED", L"1");
990 }
991 else
992 {
993 logStringF(hModule, "IsPythonInstalled: Error: No suitable Python installation found (%u), skipping installation.", rcWin);
994 logStringF(hModule, "IsPythonInstalled: Python seems not to be installed; please download + install the Python Core package.");
995 VBoxSetMsiProp(hModule, L"VBOX_PYTHON_INSTALLED", L"0");
996 }
997
998 return ERROR_SUCCESS; /* Never return failure. */
999}
1000
1001/**
1002 * Checks if all dependencies for running the VBox Python API bindings are met.
1003 *
1004 * Called from the MSI installer as custom action.
1005 *
1006 * @returns Always ERROR_SUCCESS.
1007 * Sets public property VBOX_PYTHON_DEPS_INSTALLED to "0" (false) or "1" (success).
1008 *
1009 * @param hModule Windows installer module handle.
1010 */
1011UINT __stdcall ArePythonAPIDepsInstalled(MSIHANDLE hModule)
1012{
1013 wchar_t wszPythonExe[RTPATH_MAX];
1014 UINT dwErr = getPythonExe(hModule, wszPythonExe, RTPATH_MAX);
1015 if (dwErr == ERROR_SUCCESS)
1016 {
1017 dwErr = checkPythonDependencies(hModule, wszPythonExe);
1018 if (dwErr == ERROR_SUCCESS)
1019 logStringF(hModule, "ArePythonAPIDepsInstalled: Dependencies look good.");
1020 }
1021
1022 if (dwErr != ERROR_SUCCESS)
1023 logStringF(hModule, "ArePythonAPIDepsInstalled: Failed with dwErr=%u", dwErr);
1024
1025 VBoxSetMsiProp(hModule, L"VBOX_PYTHON_DEPS_INSTALLED", dwErr == ERROR_SUCCESS ? L"1" : L"0");
1026 return ERROR_SUCCESS; /* Never return failure. */
1027}
1028
1029/**
1030 * Checks if all required MS CRTs (Visual Studio Redistributable Package) are installed on the system.
1031 *
1032 * Called from the MSI installer as custom action.
1033 *
1034 * @returns Always ERROR_SUCCESS.
1035 * Sets public property VBOX_MSCRT_INSTALLED to "" (false, to use "NOT" in WiX) or "1" (success).
1036 *
1037 * Also exposes public properties VBOX_MSCRT_VER_MIN + VBOX_MSCRT_VER_MAJ strings
1038 * with the most recent MSCRT version detected.
1039 *
1040 * @param hModule Windows installer module handle.
1041 *
1042 * @sa https://docs.microsoft.com/en-us/cpp/windows/redistributing-visual-cpp-files?view=msvc-170
1043 */
1044UINT __stdcall IsMSCRTInstalled(MSIHANDLE hModule)
1045{
1046 HKEY hKeyVS = NULL;
1047 LSTATUS lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1048 L"SOFTWARE\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\X64",
1049 0, KEY_READ, &hKeyVS);
1050 if (lrc == ERROR_SUCCESS)
1051 {
1052 DWORD dwVal = 0;
1053 DWORD cbVal = sizeof(dwVal);
1054 DWORD dwValueType = REG_DWORD; /** @todo r=bird: output only parameter, optional, so pointless. */
1055 lrc = RegQueryValueExW(hKeyVS, L"Installed", NULL, &dwValueType, (LPBYTE)&dwVal, &cbVal);
1056 if (lrc == ERROR_SUCCESS)
1057 {
1058 if (dwVal >= 1)
1059 {
1060 DWORD dwMaj = 0; /** @todo r=bird: It's purdent to initialize values if you don't bother to check the type and size! */
1061 lrc = RegQueryValueExW(hKeyVS, L"Major", NULL, &dwValueType, (LPBYTE)&dwMaj, &cbVal);
1062 if (lrc == ERROR_SUCCESS)
1063 {
1064 VBoxSetMsiPropDWORD(hModule, L"VBOX_MSCRT_VER_MAJ", dwMaj);
1065
1066 DWORD dwMin = 0;
1067 lrc = RegQueryValueExW(hKeyVS, L"Minor", NULL, &dwValueType, (LPBYTE)&dwMin, &cbVal);
1068 if (lrc == ERROR_SUCCESS)
1069 {
1070 VBoxSetMsiPropDWORD(hModule, L"VBOX_MSCRT_VER_MIN", dwMin);
1071
1072 logStringF(hModule, "IsMSCRTInstalled: Found v%u.%u\n", dwMaj, dwMin);
1073
1074 /* Check for at least 2019. */
1075 if (dwMaj > 14 || (dwMaj == 14 && dwMin >= 20))
1076 VBoxSetMsiProp(hModule, L"VBOX_MSCRT_INSTALLED", L"1");
1077 }
1078 else
1079 logStringF(hModule, "IsMSCRTInstalled: Found, but 'Minor' key not present (lrc=%d)", lrc);
1080 }
1081 else
1082 logStringF(hModule, "IsMSCRTInstalled: Found, but 'Major' key not present (lrc=%d)", lrc);
1083 }
1084 else
1085 {
1086 logStringF(hModule, "IsMSCRTInstalled: Found, but not marked as installed");
1087 lrc = ERROR_NOT_INSTALLED;
1088 }
1089 }
1090 else
1091 logStringF(hModule, "IsMSCRTInstalled: Found, but 'Installed' key not present (lrc=%d)", lrc);
1092 }
1093
1094 if (lrc != ERROR_SUCCESS)
1095 logStringF(hModule, "IsMSCRTInstalled: Failed with lrc=%ld", lrc);
1096
1097 return ERROR_SUCCESS; /* Never return failure. */
1098}
1099
1100/**
1101 * Checks if the running OS is (at least) Windows 10 (e.g. >= build 10000).
1102 *
1103 * Called from the MSI installer as custom action.
1104 *
1105 * @returns Always ERROR_SUCCESS.
1106 * Sets public property VBOX_IS_WINDOWS_10 to "" (empty / false) or "1" (success).
1107 *
1108 * @param hModule Windows installer module handle.
1109 */
1110UINT __stdcall IsWindows10(MSIHANDLE hModule)
1111{
1112 /*
1113 * Note: We cannot use RtlGetVersion() / GetVersionExW() here, as the Windows Installer service
1114 * all shims this, unfortunately. So we have to go another route by querying the major version
1115 * number from the registry.
1116 */
1117 HKEY hKeyCurVer = NULL;
1118 LSTATUS lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &hKeyCurVer);
1119 if (lrc == ERROR_SUCCESS)
1120 {
1121 DWORD dwVal = 0;
1122 DWORD cbVal = sizeof(dwVal);
1123 DWORD dwValueType = REG_DWORD; /** @todo r=bird: Again, the type is an optional output parameter. pointless to init or pass it unless you check. */
1124 lrc = RegQueryValueExW(hKeyCurVer, L"CurrentMajorVersionNumber", NULL, &dwValueType, (LPBYTE)&dwVal, &cbVal);
1125 if (lrc == ERROR_SUCCESS)
1126 {
1127 logStringF(hModule, "IsWindows10/CurrentMajorVersionNumber: %u", dwVal);
1128
1129 VBoxSetMsiProp(hModule, L"VBOX_IS_WINDOWS_10", dwVal >= 10 ? L"1" : L"");
1130 }
1131 else
1132 logStringF(hModule, "IsWindows10/RegOpenKeyExW: Error reading CurrentMajorVersionNumber (%ld)", lrc);
1133
1134 RegCloseKey(hKeyCurVer);
1135 }
1136 else
1137 logStringF(hModule, "IsWindows10/RegOpenKeyExW: Error opening CurrentVersion key (%ld)", lrc);
1138
1139 return ERROR_SUCCESS; /* Never return failure. */
1140}
1141
1142/**
1143 * Installs and compiles the VBox Python bindings.
1144 *
1145 * Called from the MSI installer as custom action.
1146 *
1147 * @returns Always ERROR_SUCCESS.
1148 * Sets public property VBOX_API_INSTALLED to "0" (false) or "1" (success).
1149 *
1150 * @param hModule Windows installer module handle.
1151 */
1152UINT __stdcall InstallPythonAPI(MSIHANDLE hModule)
1153{
1154 logStringF(hModule, "InstallPythonAPI: Checking for installed Python environment(s) ...");
1155
1156 /** @todo r=bird: Can't we get the VBOX_PYTHON_PATH property here? */
1157 wchar_t wszPythonExe[RTPATH_MAX];
1158 UINT rcWin = getPythonExe(hModule, wszPythonExe, RTPATH_MAX);
1159 if (rcWin != ERROR_SUCCESS)
1160 {
1161 VBoxSetMsiProp(hModule, L"VBOX_API_INSTALLED", L"0");
1162 return ERROR_SUCCESS;
1163 }
1164
1165 /*
1166 * Set up the VBox API.
1167 */
1168 /* Get the VBox API setup string. */
1169 WCHAR wszVBoxPythonInstallerPath[RTPATH_MAX];
1170 rcWin = VBoxGetMsiProp(hModule, L"CustomActionData", wszVBoxPythonInstallerPath, RT_ELEMENTS(wszVBoxPythonInstallerPath));
1171 if (rcWin == ERROR_SUCCESS)
1172 {
1173 /* Make sure our current working directory is the VBox installation path. */
1174 if (SetCurrentDirectoryW(wszVBoxPythonInstallerPath))
1175 {
1176 /* Set required environment variables. */
1177 /** @todo r=andy: That can't be right!
1178 *
1179 * r=bird: The variable probably isn't used because VBOX_MSI_INSTALL_PATH is
1180 * set by VBoxMergeApp.wxi. */
1181 if (SetEnvironmentVariableW(L"VBOX_INSTALL_PATH", wszVBoxPythonInstallerPath))
1182 {
1183 logStringF(hModule, "InstallPythonAPI: Invoking vboxapisetup.py in \"%ls\" ...", wszVBoxPythonInstallerPath);
1184
1185 rcWin = procRun(hModule, wszPythonExe, L"vboxapisetup.py install");
1186 if (rcWin == ERROR_SUCCESS)
1187 {
1188 logStringF(hModule, "InstallPythonAPI: Installation of vboxapisetup.py successful");
1189
1190 /*
1191 * Do some sanity checking if the VBox API works.
1192 */
1193 logStringF(hModule, "InstallPythonAPI: Validating VBox API ...");
1194
1195 rcWin = procRun(hModule, wszPythonExe, L"-c \"from vboxapi import VirtualBoxManager\"");
1196 if (rcWin == ERROR_SUCCESS)
1197 {
1198 logStringF(hModule, "InstallPythonAPI: VBox API looks good.");
1199 VBoxSetMsiProp(hModule, L"VBOX_API_INSTALLED", L"1");
1200 return ERROR_SUCCESS;
1201 }
1202
1203 /* failed */
1204 logStringF(hModule, "InstallPythonAPI: Validating VBox API failed with %u (%#x)", rcWin, rcWin);
1205 }
1206 else
1207 logStringF(hModule, "InstallPythonAPI: Calling vboxapisetup.py failed with %u (%#x)", rcWin, rcWin);
1208 }
1209 else
1210 logStringF(hModule, "InstallPythonAPI: Could set environment variable VBOX_INSTALL_PATH: LastError=%u",
1211 GetLastError());
1212 }
1213 else
1214 logStringF(hModule, "InstallPythonAPI: Could set working directory to \"%ls\": LastError=%u",
1215 wszVBoxPythonInstallerPath, GetLastError());
1216 }
1217 else
1218 logStringF(hModule, "InstallPythonAPI: Unable to retrieve VBox installation directory: rcWin=%u (%#x)", rcWin, rcWin);
1219
1220 VBoxSetMsiProp(hModule, L"VBOX_API_INSTALLED", L"0");
1221 logStringF(hModule, "InstallPythonAPI: Installation failed");
1222 return ERROR_SUCCESS; /* Do not fail here. */
1223}
1224
1225static LONG installBrandingValue(MSIHANDLE hModule,
1226 const WCHAR *pwszFileName,
1227 const WCHAR *pwszSection,
1228 const WCHAR *pwszValue)
1229{
1230 LONG rc;
1231 WCHAR wszValue[MAX_PATH];
1232 if (GetPrivateProfileStringW(pwszSection, pwszValue, NULL, wszValue, sizeof(wszValue), pwszFileName) > 0)
1233 {
1234 WCHAR wszKey[MAX_PATH + 64];
1235 if (RTUtf16ICmpAscii(pwszSection, "General") != 0)
1236 RTUtf16Printf(wszKey, RT_ELEMENTS(wszKey), "SOFTWARE\\%s\\VirtualBox\\Branding\\%ls", VBOX_VENDOR_SHORT, pwszSection);
1237 else
1238 RTUtf16Printf(wszKey, RT_ELEMENTS(wszKey), "SOFTWARE\\%s\\VirtualBox\\Branding", VBOX_VENDOR_SHORT);
1239
1240 HKEY hkBranding = NULL;
1241 rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszKey, 0, KEY_WRITE, &hkBranding);
1242 if (rc == ERROR_SUCCESS)
1243 {
1244 rc = RegSetValueExW(hkBranding,
1245 pwszValue,
1246 NULL,
1247 REG_SZ,
1248 (BYTE *)wszValue,
1249 (DWORD)RTUtf16Len(wszValue));
1250 if (rc != ERROR_SUCCESS)
1251 logStringF(hModule, "InstallBranding: Could not write value %s! Error %d", pwszValue, rc);
1252 RegCloseKey(hkBranding);
1253 }
1254 }
1255 else
1256 rc = ERROR_NOT_FOUND;
1257 return rc;
1258}
1259
1260/**
1261 * @note Both paths strings must have an extra terminator.
1262 */
1263static UINT CopyDir(MSIHANDLE hModule, const WCHAR *pwszzDstDir, const WCHAR *pwszzSrcDir)
1264{
1265 NonStandardAssert(pwszzDstDir[RTUtf16Len(pwszzDstDir) + 1] == '\0');
1266 NonStandardAssert(pwszzSrcDir[RTUtf16Len(pwszzSrcDir) + 1] == '\0');
1267
1268 SHFILEOPSTRUCTW s = {0};
1269 s.hwnd = NULL;
1270 s.wFunc = FO_COPY;
1271 s.pTo = pwszzDstDir;
1272 s.pFrom = pwszzSrcDir;
1273 s.fFlags = FOF_SILENT
1274 | FOF_NOCONFIRMATION
1275 | FOF_NOCONFIRMMKDIR
1276 | FOF_NOERRORUI;
1277
1278 logStringF(hModule, "CopyDir: pwszzDstDir=%ls, pwszzSrcDir=%ls", pwszzDstDir, pwszzSrcDir);
1279 int r = SHFileOperationW(&s);
1280 if (r == 0)
1281 return ERROR_SUCCESS;
1282 logStringF(hModule, "CopyDir: Copy operation returned status %#x", r);
1283 return ERROR_GEN_FAILURE;
1284}
1285
1286/**
1287 * @note The directory string must have two zero terminators!
1288 */
1289static UINT RemoveDir(MSIHANDLE hModule, const WCHAR *pwszzDstDir)
1290{
1291 NonStandardAssert(pwszzDstDir[RTUtf16Len(pwszzDstDir) + 1] == '\0');
1292
1293 SHFILEOPSTRUCTW s = {0};
1294 s.hwnd = NULL;
1295 s.wFunc = FO_DELETE;
1296 s.pFrom = pwszzDstDir;
1297 s.fFlags = FOF_SILENT
1298 | FOF_NOCONFIRMATION
1299 | FOF_NOCONFIRMMKDIR
1300 | FOF_NOERRORUI;
1301
1302 logStringF(hModule, "RemoveDir: pwszzDstDir=%ls", pwszzDstDir);
1303 int r = SHFileOperationW(&s);
1304 if (r == 0)
1305 return ERROR_SUCCESS;
1306 logStringF(hModule, "RemoveDir: Remove operation returned status %#x", r);
1307 return ERROR_GEN_FAILURE;
1308}
1309
1310/**
1311 * @note Both paths strings must have an extra terminator.
1312 */
1313static UINT RenameDir(MSIHANDLE hModule, const WCHAR *pwszzDstDir, const WCHAR *pwszzSrcDir)
1314{
1315 NonStandardAssert(pwszzDstDir[RTUtf16Len(pwszzDstDir) + 1] == '\0');
1316 NonStandardAssert(pwszzSrcDir[RTUtf16Len(pwszzSrcDir) + 1] == '\0');
1317
1318 SHFILEOPSTRUCTW s = {0};
1319 s.hwnd = NULL;
1320 s.wFunc = FO_RENAME;
1321 s.pTo = pwszzDstDir;
1322 s.pFrom = pwszzSrcDir;
1323 s.fFlags = FOF_SILENT
1324 | FOF_NOCONFIRMATION
1325 | FOF_NOCONFIRMMKDIR
1326 | FOF_NOERRORUI;
1327
1328 logStringF(hModule, "RenameDir: pwszzDstDir=%ls, pwszzSrcDir=%ls", pwszzDstDir, pwszzSrcDir);
1329 int r = SHFileOperationW(&s);
1330 if (r == 0)
1331 return ERROR_SUCCESS;
1332 logStringF(hModule, "RenameDir: Rename operation returned status %#x", r);
1333 return ERROR_GEN_FAILURE;
1334}
1335
1336/** RTPathAppend-like function. */
1337static UINT AppendToPath(wchar_t *pwszPath, size_t cwcPath, const wchar_t *pwszAppend, bool fDoubleTerm = false)
1338{
1339 size_t cwcCurPath = RTUtf16Len(pwszPath);
1340 size_t cwcSlash = cwcCurPath > 1 && RTPATH_IS_SLASH(pwszPath[cwcCurPath - 1]) ? 0 : 1;
1341 while (RTPATH_IS_SLASH(*pwszAppend))
1342 pwszAppend++;
1343 size_t cwcAppend = RTUtf16Len(pwszAppend);
1344 if (cwcCurPath + cwcCurPath + cwcAppend + fDoubleTerm < cwcPath)
1345 {
1346 if (cwcSlash)
1347 pwszPath[cwcCurPath++] = '\\';
1348 memcpy(&pwszPath[cwcCurPath], pwszAppend, (cwcAppend + 1) * sizeof(wchar_t));
1349 if (fDoubleTerm)
1350 pwszPath[cwcCurPath + cwcAppend + 1] = '\0';
1351 return ERROR_SUCCESS;
1352 }
1353 return ERROR_BUFFER_OVERFLOW;
1354}
1355
1356/** RTPathJoin-like function. */
1357static UINT JoinPaths(wchar_t *pwszPath, size_t cwcPath, wchar_t *pwszPath1, const wchar_t *pwszAppend, bool fDoubleTerm = false)
1358{
1359 size_t cwcCurPath = RTUtf16Len(pwszPath1);
1360 if (cwcCurPath < cwcPath)
1361 {
1362 memcpy(pwszPath, pwszPath1, (cwcCurPath + 1) * sizeof(wchar_t));
1363 return AppendToPath(pwszPath, cwcPath, pwszAppend, fDoubleTerm);
1364 }
1365 return ERROR_BUFFER_OVERFLOW;
1366}
1367
1368UINT __stdcall UninstallBranding(MSIHANDLE hModule)
1369{
1370 logStringF(hModule, "UninstallBranding: Handling branding file ...");
1371
1372 WCHAR wszPath[RTPATH_MAX];
1373 UINT rc = VBoxGetMsiProp(hModule, L"CustomActionData", wszPath, RT_ELEMENTS(wszPath));
1374 if (rc == ERROR_SUCCESS)
1375 {
1376 size_t const cwcPath = RTUtf16Len(wszPath);
1377 rc = AppendToPath(wszPath, RTPATH_MAX, L"custom", true /*fDoubleTerm*/);
1378 if (rc == ERROR_SUCCESS)
1379 rc = RemoveDir(hModule, wszPath);
1380
1381 /* Check for .custom directory from a failed install and remove it. */
1382 wszPath[cwcPath] = '\0';
1383 rc = AppendToPath(wszPath, RTPATH_MAX, L".custom", true /*fDoubleTerm*/);
1384 if (rc == ERROR_SUCCESS)
1385 rc = RemoveDir(hModule, wszPath);
1386 }
1387
1388 logStringF(hModule, "UninstallBranding: Handling done. (rc=%u (ignored))", rc);
1389 return ERROR_SUCCESS; /* Do not fail here. */
1390}
1391
1392UINT __stdcall InstallBranding(MSIHANDLE hModule)
1393{
1394 logStringF(hModule, "InstallBranding: Handling branding file ...");
1395
1396 /*
1397 * Get the paths.
1398 */
1399 wchar_t wszSrcPath[RTPATH_MAX];
1400 UINT rc = VBoxGetMsiProp(hModule, L"SOURCEDIR", wszSrcPath, RT_ELEMENTS(wszSrcPath));
1401 if (rc == ERROR_SUCCESS)
1402 {
1403 wchar_t wszDstPath[RTPATH_MAX];
1404 rc = VBoxGetMsiProp(hModule, L"CustomActionData", wszDstPath, RT_ELEMENTS(wszDstPath) - 1);
1405 if (rc == ERROR_SUCCESS)
1406 {
1407 /*
1408 * First we copy the src\.custom dir to the target.
1409 */
1410 rc = AppendToPath(wszSrcPath, RT_ELEMENTS(wszSrcPath) - 1, L".custom", true /*fDoubleTerm*/);
1411 if (rc == ERROR_SUCCESS)
1412 {
1413 rc = CopyDir(hModule, wszDstPath, wszSrcPath);
1414 if (rc == ERROR_SUCCESS)
1415 {
1416 /*
1417 * The rename the '.custom' directory we now got in the target area to 'custom'.
1418 */
1419 rc = JoinPaths(wszSrcPath, RT_ELEMENTS(wszSrcPath), wszDstPath, L".custom", true /*fDoubleTerm*/);
1420 if (rc == ERROR_SUCCESS)
1421 {
1422 rc = AppendToPath(wszDstPath, RT_ELEMENTS(wszDstPath), L"custom", true /*fDoubleTerm*/);
1423 if (rc == ERROR_SUCCESS)
1424 rc = RenameDir(hModule, wszDstPath, wszSrcPath);
1425 }
1426 }
1427 }
1428 }
1429 }
1430
1431 logStringF(hModule, "InstallBranding: Handling done. (rc=%u (ignored))", rc);
1432 return ERROR_SUCCESS; /* Do not fail here. */
1433}
1434
1435#if defined(VBOX_WITH_NETFLT) || defined(VBOX_WITH_NETADP)
1436
1437/** @todo should use some real VBox app name */
1438#define VBOX_NETCFG_APP_NAME L"VirtualBox Installer"
1439#define VBOX_NETCFG_MAX_RETRIES 10
1440#define NETFLT_PT_INF_REL_PATH L"VBoxNetFlt.inf"
1441#define NETFLT_MP_INF_REL_PATH L"VBoxNetFltM.inf"
1442#define NETFLT_ID L"sun_VBoxNetFlt" /** @todo Needs to be changed (?). */
1443#define NETADP_ID L"sun_VBoxNetAdp" /** @todo Needs to be changed (?). */
1444
1445#define NETLWF_INF_NAME L"VBoxNetLwf.inf"
1446
1447static MSIHANDLE g_hCurrentModule = NULL;
1448
1449static UINT _uninstallNetFlt(MSIHANDLE hModule);
1450static UINT _uninstallNetLwf(MSIHANDLE hModule);
1451
1452static VOID vboxDrvLoggerCallback(VBOXDRVCFG_LOG_SEVERITY_T enmSeverity, char *pszMsg, void *pvContext)
1453{
1454 RT_NOREF1(pvContext);
1455 switch (enmSeverity)
1456 {
1457 case VBOXDRVCFG_LOG_SEVERITY_FLOW:
1458 case VBOXDRVCFG_LOG_SEVERITY_REGULAR:
1459 break;
1460 case VBOXDRVCFG_LOG_SEVERITY_REL:
1461 if (g_hCurrentModule)
1462 logStringF(g_hCurrentModule, "%s", pszMsg);
1463 break;
1464 default:
1465 break;
1466 }
1467}
1468
1469static DECLCALLBACK(void) netCfgLoggerCallback(const char *pszString)
1470{
1471 if (g_hCurrentModule)
1472 logStringF(g_hCurrentModule, "%s", pszString);
1473}
1474
1475static VOID netCfgLoggerDisable()
1476{
1477 if (g_hCurrentModule)
1478 {
1479 VBoxNetCfgWinSetLogging(NULL);
1480 g_hCurrentModule = NULL;
1481 }
1482}
1483
1484static VOID netCfgLoggerEnable(MSIHANDLE hModule)
1485{
1486 NonStandardAssert(hModule);
1487
1488 if (g_hCurrentModule)
1489 netCfgLoggerDisable();
1490
1491 g_hCurrentModule = hModule;
1492
1493 VBoxNetCfgWinSetLogging(netCfgLoggerCallback);
1494 /* uncomment next line if you want to add logging information from VBoxDrvCfg.cpp */
1495// VBoxDrvCfgLoggerSet(vboxDrvLoggerCallback, NULL);
1496}
1497
1498static UINT errorConvertFromHResult(MSIHANDLE hModule, HRESULT hr)
1499{
1500 UINT uRet;
1501 switch (hr)
1502 {
1503 case S_OK:
1504 uRet = ERROR_SUCCESS;
1505 break;
1506
1507 case NETCFG_S_REBOOT:
1508 {
1509 logStringF(hModule, "Reboot required, setting REBOOT property to \"force\"");
1510 HRESULT hr2 = MsiSetPropertyW(hModule, L"REBOOT", L"Force");
1511 if (hr2 != ERROR_SUCCESS)
1512 logStringF(hModule, "Failed to set REBOOT property, error = %#x", hr2);
1513 uRet = ERROR_SUCCESS; /* Never fail here. */
1514 break;
1515 }
1516
1517 default:
1518 logStringF(hModule, "Converting unhandled HRESULT (%#x) to ERROR_GEN_FAILURE", hr);
1519 uRet = ERROR_GEN_FAILURE;
1520 }
1521 return uRet;
1522}
1523
1524static MSIHANDLE createNetCfgLockedMsgRecord(MSIHANDLE hModule)
1525{
1526 MSIHANDLE hRecord = MsiCreateRecord(2);
1527 if (hRecord)
1528 {
1529 UINT uErr = MsiRecordSetInteger(hRecord, 1, 25001);
1530 if (uErr != ERROR_SUCCESS)
1531 {
1532 logStringF(hModule, "createNetCfgLockedMsgRecord: MsiRecordSetInteger failed, error = %#x", uErr);
1533 MsiCloseHandle(hRecord);
1534 hRecord = NULL;
1535 }
1536 }
1537 else
1538 logStringF(hModule, "createNetCfgLockedMsgRecord: Failed to create a record");
1539
1540 return hRecord;
1541}
1542
1543static UINT doNetCfgInit(MSIHANDLE hModule, INetCfg **ppnc, BOOL bWrite)
1544{
1545 MSIHANDLE hMsg = NULL;
1546 UINT uErr = ERROR_GEN_FAILURE;
1547 int MsgResult;
1548 int cRetries = 0;
1549
1550 do
1551 {
1552 LPWSTR lpszLockedBy;
1553 HRESULT hr = VBoxNetCfgWinQueryINetCfg(ppnc, bWrite, VBOX_NETCFG_APP_NAME, 10000, &lpszLockedBy);
1554 if (hr != NETCFG_E_NO_WRITE_LOCK)
1555 {
1556 if (FAILED(hr))
1557 logStringF(hModule, "doNetCfgInit: VBoxNetCfgWinQueryINetCfg failed, error = %#x", hr);
1558 uErr = errorConvertFromHResult(hModule, hr);
1559 break;
1560 }
1561
1562 /* hr == NETCFG_E_NO_WRITE_LOCK */
1563
1564 if (!lpszLockedBy)
1565 {
1566 logStringF(hModule, "doNetCfgInit: lpszLockedBy == NULL, breaking");
1567 break;
1568 }
1569
1570 /* on vista the 6to4svc.dll periodically maintains the lock for some reason,
1571 * if this is the case, increase the wait period by retrying multiple times
1572 * NOTE: we could alternatively increase the wait timeout,
1573 * however it seems unneeded for most cases, e.g. in case some network connection property
1574 * dialog is opened, it would be better to post a notification to the user as soon as possible
1575 * rather than waiting for a longer period of time before displaying it */
1576 if ( cRetries < VBOX_NETCFG_MAX_RETRIES
1577 && RTUtf16ICmpAscii(lpszLockedBy, "6to4svc.dll") == 0)
1578 {
1579 cRetries++;
1580 logStringF(hModule, "doNetCfgInit: lpszLockedBy is 6to4svc.dll, retrying %d out of %d", cRetries, VBOX_NETCFG_MAX_RETRIES);
1581 MsgResult = IDRETRY;
1582 }
1583 else
1584 {
1585 if (!hMsg)
1586 {
1587 hMsg = createNetCfgLockedMsgRecord(hModule);
1588 if (!hMsg)
1589 {
1590 logStringF(hModule, "doNetCfgInit: Failed to create a message record, breaking");
1591 CoTaskMemFree(lpszLockedBy);
1592 break;
1593 }
1594 }
1595
1596 UINT rTmp = MsiRecordSetStringW(hMsg, 2, lpszLockedBy);
1597 NonStandardAssert(rTmp == ERROR_SUCCESS);
1598 if (rTmp != ERROR_SUCCESS)
1599 {
1600 logStringF(hModule, "doNetCfgInit: MsiRecordSetStringW failed, error = #%x", rTmp);
1601 CoTaskMemFree(lpszLockedBy);
1602 break;
1603 }
1604
1605 MsgResult = MsiProcessMessage(hModule, (INSTALLMESSAGE)(INSTALLMESSAGE_USER | MB_RETRYCANCEL), hMsg);
1606 NonStandardAssert(MsgResult == IDRETRY || MsgResult == IDCANCEL);
1607 logStringF(hModule, "doNetCfgInit: MsiProcessMessage returned (%#x)", MsgResult);
1608 }
1609 CoTaskMemFree(lpszLockedBy);
1610 } while(MsgResult == IDRETRY);
1611
1612 if (hMsg)
1613 MsiCloseHandle(hMsg);
1614
1615 return uErr;
1616}
1617#endif /* defined(VBOX_WITH_NETFLT) || defined(VBOX_WITH_NETADP) */
1618
1619#ifdef VBOX_WITH_NETFLT
1620static UINT vboxNetFltQueryInfArray(MSIHANDLE hModule, OUT LPWSTR pwszPtInf, DWORD cwcPtInf,
1621 OUT LPWSTR pwszMpInf, DWORD cwcMpInf)
1622{
1623 DWORD cwcEffBuf = cwcPtInf - RT_MAX(sizeof(NETFLT_PT_INF_REL_PATH), sizeof(NETFLT_MP_INF_REL_PATH)) / sizeof(WCHAR);
1624 UINT uErr = MsiGetPropertyW(hModule, L"CustomActionData", pwszPtInf, &cwcEffBuf);
1625 if ( uErr == ERROR_SUCCESS
1626 && cwcEffBuf > 0)
1627 {
1628 int vrc = RTUtf16Copy(pwszMpInf, cwcMpInf, pwszPtInf);
1629 AssertRCReturn(vrc, ERROR_BUFFER_OVERFLOW);
1630
1631 vrc = RTUtf16Cat(pwszPtInf, cwcPtInf, NETFLT_PT_INF_REL_PATH);
1632 AssertRCReturn(vrc, ERROR_BUFFER_OVERFLOW);
1633 logStringF(hModule, "vboxNetFltQueryInfArray: INF 1: %ls", pwszPtInf);
1634
1635 vrc = RTUtf16Cat(pwszMpInf, cwcMpInf, NETFLT_MP_INF_REL_PATH);
1636 AssertRCReturn(vrc, ERROR_BUFFER_OVERFLOW);
1637 logStringF(hModule, "vboxNetFltQueryInfArray: INF 2: %ls", pwszMpInf);
1638 }
1639 else if (uErr != ERROR_SUCCESS)
1640 logStringF(hModule, "vboxNetFltQueryInfArray: MsiGetPropertyW failed, error = %#x", uErr);
1641 else
1642 {
1643 logStringF(hModule, "vboxNetFltQueryInfArray: Empty installation directory");
1644 uErr = ERROR_GEN_FAILURE;
1645 }
1646
1647 return uErr;
1648}
1649
1650static UINT _uninstallNetFlt(MSIHANDLE hModule)
1651{
1652 INetCfg *pNetCfg;
1653 UINT uErr;
1654
1655 netCfgLoggerEnable(hModule);
1656
1657 BOOL bOldIntMode = SetupSetNonInteractiveMode(FALSE);
1658
1659 __try
1660 {
1661 logStringF(hModule, "Uninstalling NetFlt");
1662
1663 uErr = doNetCfgInit(hModule, &pNetCfg, TRUE);
1664 if (uErr == ERROR_SUCCESS)
1665 {
1666 HRESULT hr = VBoxNetCfgWinNetFltUninstall(pNetCfg);
1667 if (hr != S_OK)
1668 logStringF(hModule, "UninstallNetFlt: VBoxNetCfgWinUninstallComponent failed, error = %#x", hr);
1669
1670 uErr = errorConvertFromHResult(hModule, hr);
1671
1672 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
1673
1674 logStringF(hModule, "Uninstalling NetFlt done, error = %#x", uErr);
1675 }
1676 else
1677 logStringF(hModule, "UninstallNetFlt: doNetCfgInit failed, error = %#x", uErr);
1678 }
1679 __finally
1680 {
1681 if (bOldIntMode)
1682 {
1683 /* The prev mode != FALSE, i.e. non-interactive. */
1684 SetupSetNonInteractiveMode(bOldIntMode);
1685 }
1686 netCfgLoggerDisable();
1687 }
1688
1689 /* Never fail the uninstall even if we did not succeed. */
1690 return ERROR_SUCCESS;
1691}
1692#endif /* VBOX_WITH_NETFLT */
1693
1694UINT __stdcall UninstallNetFlt(MSIHANDLE hModule)
1695{
1696#ifdef VBOX_WITH_NETFLT
1697 _uninstallNetLwf(hModule);
1698 return _uninstallNetFlt(hModule);
1699#else
1700 RT_NOREF(hModule);
1701 return ERROR_SUCCESS;
1702#endif
1703}
1704
1705#ifdef VBOX_WITH_NETFLT
1706static UINT _installNetFlt(MSIHANDLE hModule)
1707{
1708 UINT uErr;
1709 INetCfg *pNetCfg;
1710
1711 netCfgLoggerEnable(hModule);
1712
1713 BOOL bOldIntMode = SetupSetNonInteractiveMode(FALSE);
1714
1715 __try
1716 {
1717
1718 logStringF(hModule, "InstallNetFlt: Installing NetFlt");
1719
1720 uErr = doNetCfgInit(hModule, &pNetCfg, TRUE);
1721 if (uErr == ERROR_SUCCESS)
1722 {
1723 WCHAR wszPtInf[MAX_PATH];
1724 WCHAR wszMpInf[MAX_PATH];
1725 uErr = vboxNetFltQueryInfArray(hModule, wszPtInf, RT_ELEMENTS(wszPtInf), wszMpInf, RT_ELEMENTS(wszMpInf));
1726 if (uErr == ERROR_SUCCESS)
1727 {
1728 LPCWSTR const apwszInfs[] = { wszPtInf, wszMpInf };
1729 HRESULT hr = VBoxNetCfgWinNetFltInstall(pNetCfg, &apwszInfs[0], RT_ELEMENTS(apwszInfs));
1730 if (FAILED(hr))
1731 logStringF(hModule, "InstallNetFlt: VBoxNetCfgWinNetFltInstall failed, error = %#x", hr);
1732
1733 uErr = errorConvertFromHResult(hModule, hr);
1734 }
1735 else
1736 logStringF(hModule, "InstallNetFlt: vboxNetFltQueryInfArray failed, error = %#x", uErr);
1737
1738 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
1739
1740 logStringF(hModule, "InstallNetFlt: Done");
1741 }
1742 else
1743 logStringF(hModule, "InstallNetFlt: doNetCfgInit failed, error = %#x", uErr);
1744 }
1745 __finally
1746 {
1747 if (bOldIntMode)
1748 {
1749 /* The prev mode != FALSE, i.e. non-interactive. */
1750 SetupSetNonInteractiveMode(bOldIntMode);
1751 }
1752 netCfgLoggerDisable();
1753 }
1754
1755 /* Never fail the install even if we did not succeed. */
1756 return ERROR_SUCCESS;
1757}
1758#endif /* VBOX_WITH_NETFLT */
1759
1760UINT __stdcall InstallNetFlt(MSIHANDLE hModule)
1761{
1762#ifdef VBOX_WITH_NETFLT
1763 _uninstallNetLwf(hModule);
1764 return _installNetFlt(hModule);
1765#else
1766 RT_NOREF(hModule);
1767 return ERROR_SUCCESS;
1768#endif
1769}
1770
1771#ifdef VBOX_WITH_NETFLT
1772static UINT _uninstallNetLwf(MSIHANDLE hModule)
1773{
1774 INetCfg *pNetCfg;
1775 UINT uErr;
1776
1777 netCfgLoggerEnable(hModule);
1778
1779 BOOL bOldIntMode = SetupSetNonInteractiveMode(FALSE);
1780
1781 __try
1782 {
1783 logStringF(hModule, "Uninstalling NetLwf");
1784
1785 uErr = doNetCfgInit(hModule, &pNetCfg, TRUE);
1786 if (uErr == ERROR_SUCCESS)
1787 {
1788 HRESULT hr = VBoxNetCfgWinNetLwfUninstall(pNetCfg);
1789 if (hr != S_OK)
1790 logStringF(hModule, "UninstallNetLwf: VBoxNetCfgWinUninstallComponent failed, error = %#x", hr);
1791
1792 uErr = errorConvertFromHResult(hModule, hr);
1793
1794 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
1795
1796 logStringF(hModule, "Uninstalling NetLwf done, error = %#x", uErr);
1797 }
1798 else
1799 logStringF(hModule, "UninstallNetLwf: doNetCfgInit failed, error = %#x", uErr);
1800 }
1801 __finally
1802 {
1803 if (bOldIntMode)
1804 {
1805 /* The prev mode != FALSE, i.e. non-interactive. */
1806 SetupSetNonInteractiveMode(bOldIntMode);
1807 }
1808 netCfgLoggerDisable();
1809 }
1810
1811 /* Never fail the uninstall even if we did not succeed. */
1812 return ERROR_SUCCESS;
1813}
1814#endif /* VBOX_WITH_NETFLT */
1815
1816UINT __stdcall UninstallNetLwf(MSIHANDLE hModule)
1817{
1818#ifdef VBOX_WITH_NETFLT
1819 _uninstallNetFlt(hModule);
1820 return _uninstallNetLwf(hModule);
1821#else
1822 RT_NOREF(hModule);
1823 return ERROR_SUCCESS;
1824#endif
1825}
1826
1827#ifdef VBOX_WITH_NETFLT
1828static UINT _installNetLwf(MSIHANDLE hModule)
1829{
1830 UINT uErr;
1831 INetCfg *pNetCfg;
1832
1833 netCfgLoggerEnable(hModule);
1834
1835 BOOL bOldIntMode = SetupSetNonInteractiveMode(FALSE);
1836
1837 __try
1838 {
1839
1840 logStringF(hModule, "InstallNetLwf: Installing NetLwf");
1841
1842 uErr = doNetCfgInit(hModule, &pNetCfg, TRUE);
1843 if (uErr == ERROR_SUCCESS)
1844 {
1845 WCHAR wszInf[MAX_PATH];
1846 DWORD cwcInf = RT_ELEMENTS(wszInf) - sizeof(NETLWF_INF_NAME) - 1;
1847 uErr = MsiGetPropertyW(hModule, L"CustomActionData", wszInf, &cwcInf);
1848 if (uErr == ERROR_SUCCESS)
1849 {
1850 if (cwcInf)
1851 {
1852 if (wszInf[cwcInf - 1] != L'\\')
1853 {
1854 wszInf[cwcInf++] = L'\\';
1855 wszInf[cwcInf] = L'\0';
1856 }
1857
1858 int vrc = RTUtf16Cat(wszInf, RT_ELEMENTS(wszInf), NETLWF_INF_NAME);
1859 AssertRC(vrc);
1860
1861 HRESULT hr = VBoxNetCfgWinNetLwfInstall(pNetCfg, wszInf);
1862 if (FAILED(hr))
1863 logStringF(hModule, "InstallNetLwf: VBoxNetCfgWinNetLwfInstall failed, error = %#x", hr);
1864
1865 uErr = errorConvertFromHResult(hModule, hr);
1866 }
1867 else
1868 {
1869 logStringF(hModule, "vboxNetFltQueryInfArray: Empty installation directory");
1870 uErr = ERROR_GEN_FAILURE;
1871 }
1872 }
1873 else
1874 logStringF(hModule, "vboxNetFltQueryInfArray: MsiGetPropertyW failed, error = %#x", uErr);
1875
1876 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
1877
1878 logStringF(hModule, "InstallNetLwf: Done");
1879 }
1880 else
1881 logStringF(hModule, "InstallNetLwf: doNetCfgInit failed, error = %#x", uErr);
1882 }
1883 __finally
1884 {
1885 if (bOldIntMode)
1886 {
1887 /* The prev mode != FALSE, i.e. non-interactive. */
1888 SetupSetNonInteractiveMode(bOldIntMode);
1889 }
1890 netCfgLoggerDisable();
1891 }
1892
1893 /* Never fail the install even if we did not succeed. */
1894 return ERROR_SUCCESS;
1895}
1896#endif /* VBOX_WITH_NETFLT */
1897
1898UINT __stdcall InstallNetLwf(MSIHANDLE hModule)
1899{
1900#ifdef VBOX_WITH_NETFLT
1901 _uninstallNetFlt(hModule);
1902 return _installNetLwf(hModule);
1903#else
1904 RT_NOREF(hModule);
1905 return ERROR_SUCCESS;
1906#endif
1907}
1908
1909
1910#if 0 /** @todo r=andy Remove this? */
1911static BOOL RenameHostOnlyConnectionsCallback(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pContext)
1912{
1913 WCHAR DevName[256];
1914 DWORD winEr;
1915
1916 if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, pDev,
1917 SPDRP_FRIENDLYNAME , /* IN DWORD Property,*/
1918 NULL, /*OUT PDWORD PropertyRegDataType, OPTIONAL*/
1919 (PBYTE)DevName, /*OUT PBYTE PropertyBuffer,*/
1920 sizeof(DevName), /* IN DWORD PropertyBufferSize,*/
1921 NULL /*OUT PDWORD RequiredSize OPTIONAL*/
1922 ))
1923 {
1924 HKEY hKey = SetupDiOpenDevRegKey(hDevInfo, pDev,
1925 DICS_FLAG_GLOBAL, /* IN DWORD Scope,*/
1926 0, /*IN DWORD HwProfile, */
1927 DIREG_DRV, /* IN DWORD KeyType, */
1928 KEY_READ /*IN REGSAM samDesired*/
1929 );
1930 NonStandardAssert(hKey != INVALID_HANDLE_VALUE);
1931 if (hKey != INVALID_HANDLE_VALUE)
1932 {
1933 WCHAR guid[50];
1934 DWORD cbGuid=sizeof(guid);
1935 winEr = RegQueryValueExW(hKey,
1936 L"NetCfgInstanceId", /*__in_opt LPCTSTR lpValueName,*/
1937 NULL, /*__reserved LPDWORD lpReserved,*/
1938 NULL, /*__out_opt LPDWORD lpType,*/
1939 (LPBYTE)guid, /*__out_opt LPBYTE lpData,*/
1940 &cbGuid /*guid__inout_opt LPDWORD lpcbData*/
1941 );
1942 NonStandardAssert(winEr == ERROR_SUCCESS);
1943 if (winEr == ERROR_SUCCESS)
1944 {
1945 WCHAR ConnectoinName[128];
1946 ULONG cbName = sizeof(ConnectoinName);
1947
1948 HRESULT hr = VBoxNetCfgWinGenHostonlyConnectionName(DevName, ConnectoinName, &cbName);
1949 NonStandardAssert(hr == S_OK);
1950 if (SUCCEEDED(hr))
1951 {
1952 hr = VBoxNetCfgWinRenameConnection(guid, ConnectoinName);
1953 NonStandardAssert(hr == S_OK);
1954 }
1955 }
1956 }
1957 RegCloseKey(hKey);
1958 }
1959 else
1960 {
1961 NonStandardAssert(0);
1962 }
1963
1964 return TRUE;
1965}
1966#endif /* 0 */
1967
1968#ifdef VBOX_WITH_NETADP
1969static UINT _createHostOnlyInterface(MSIHANDLE hModule, LPCWSTR pwszId, LPCWSTR pwszInfName)
1970{
1971 netCfgLoggerEnable(hModule);
1972
1973 BOOL fSetupModeInteractive = SetupSetNonInteractiveMode(FALSE);
1974
1975 logStringF(hModule, "CreateHostOnlyInterface: Creating host-only interface");
1976
1977 HRESULT hr = E_FAIL;
1978 GUID guid;
1979 WCHAR wszMpInf[MAX_PATH];
1980 DWORD cwcMpInf = RT_ELEMENTS(wszMpInf) - (DWORD)RTUtf16Len(pwszInfName) - 1 - 1;
1981 LPCWSTR pwszInfPath = NULL;
1982 bool fIsFile = false;
1983 UINT uErr = MsiGetPropertyW(hModule, L"CustomActionData", wszMpInf, &cwcMpInf);
1984 if (uErr == ERROR_SUCCESS)
1985 {
1986 if (cwcMpInf)
1987 {
1988 logStringF(hModule, "CreateHostOnlyInterface: NetAdpDir property = %ls", wszMpInf);
1989 if (wszMpInf[cwcMpInf - 1] != L'\\')
1990 {
1991 wszMpInf[cwcMpInf++] = L'\\';
1992 wszMpInf[cwcMpInf] = L'\0';
1993 }
1994
1995 int vrc = RTUtf16Cat(wszMpInf, RT_ELEMENTS(wszMpInf), pwszInfName);
1996 AssertRC(vrc);
1997
1998 pwszInfPath = wszMpInf;
1999 fIsFile = true;
2000
2001 logStringF(hModule, "CreateHostOnlyInterface: Resulting INF path = %ls", pwszInfPath);
2002 }
2003 else
2004 logStringF(hModule, "CreateHostOnlyInterface: VBox installation path is empty");
2005 }
2006 else
2007 logStringF(hModule, "CreateHostOnlyInterface: Unable to retrieve VBox installation path, error = %#x", uErr);
2008
2009 /* Make sure the inf file is installed. */
2010 if (pwszInfPath != NULL && fIsFile)
2011 {
2012 logStringF(hModule, "CreateHostOnlyInterface: Calling VBoxDrvCfgInfInstall(%ls)", pwszInfPath);
2013 hr = VBoxDrvCfgInfInstall(pwszInfPath);
2014 logStringF(hModule, "CreateHostOnlyInterface: VBoxDrvCfgInfInstall returns %#x", hr);
2015 if (FAILED(hr))
2016 logStringF(hModule, "CreateHostOnlyInterface: Failed to install INF file, error = %#x", hr);
2017 }
2018
2019 if (SUCCEEDED(hr))
2020 {
2021 //first, try to update Host Only Network Interface
2022 BOOL fRebootRequired = FALSE;
2023 hr = VBoxNetCfgWinUpdateHostOnlyNetworkInterface(pwszInfPath, &fRebootRequired, pwszId);
2024 if (SUCCEEDED(hr))
2025 {
2026 if (fRebootRequired)
2027 {
2028 logStringF(hModule, "CreateHostOnlyInterface: Reboot required for update, setting REBOOT property to force");
2029 HRESULT hr2 = MsiSetPropertyW(hModule, L"REBOOT", L"Force");
2030 if (hr2 != ERROR_SUCCESS)
2031 logStringF(hModule, "CreateHostOnlyInterface: Failed to set REBOOT property for update, error = %#x", hr2);
2032 }
2033 }
2034 else
2035 {
2036 //in fail case call CreateHostOnlyInterface
2037 logStringF(hModule, "CreateHostOnlyInterface: VBoxNetCfgWinUpdateHostOnlyNetworkInterface failed, hr = %#x", hr);
2038 logStringF(hModule, "CreateHostOnlyInterface: calling VBoxNetCfgWinCreateHostOnlyNetworkInterface");
2039# ifdef VBOXNETCFG_DELAYEDRENAME
2040 BSTR devId;
2041 hr = VBoxNetCfgWinCreateHostOnlyNetworkInterface(pwszInfPath, fIsFile, NULL, &guid, &devId, NULL);
2042# else /* !VBOXNETCFG_DELAYEDRENAME */
2043 hr = VBoxNetCfgWinCreateHostOnlyNetworkInterface(pwszInfPath, fIsFile, NULL, &guid, NULL, NULL);
2044# endif /* !VBOXNETCFG_DELAYEDRENAME */
2045 logStringF(hModule, "CreateHostOnlyInterface: VBoxNetCfgWinCreateHostOnlyNetworkInterface returns %#x", hr);
2046 if (SUCCEEDED(hr))
2047 {
2048 ULONG ip = inet_addr("192.168.56.1");
2049 ULONG mask = inet_addr("255.255.255.0");
2050 logStringF(hModule, "CreateHostOnlyInterface: calling VBoxNetCfgWinEnableStaticIpConfig");
2051 hr = VBoxNetCfgWinEnableStaticIpConfig(&guid, ip, mask);
2052 logStringF(hModule, "CreateHostOnlyInterface: VBoxNetCfgWinEnableStaticIpConfig returns %#x", hr);
2053 if (FAILED(hr))
2054 logStringF(hModule, "CreateHostOnlyInterface: VBoxNetCfgWinEnableStaticIpConfig failed, error = %#x", hr);
2055# ifdef VBOXNETCFG_DELAYEDRENAME
2056 hr = VBoxNetCfgWinRenameHostOnlyConnection(&guid, devId, NULL);
2057 if (FAILED(hr))
2058 logStringF(hModule, "CreateHostOnlyInterface: VBoxNetCfgWinRenameHostOnlyConnection failed, error = %#x", hr);
2059 SysFreeString(devId);
2060# endif /* VBOXNETCFG_DELAYEDRENAME */
2061 }
2062 else
2063 logStringF(hModule, "CreateHostOnlyInterface: VBoxNetCfgWinCreateHostOnlyNetworkInterface failed, error = %#x", hr);
2064 }
2065 }
2066
2067 if (SUCCEEDED(hr))
2068 logStringF(hModule, "CreateHostOnlyInterface: Creating host-only interface done");
2069
2070 /* Restore original setup mode. */
2071 logStringF(hModule, "CreateHostOnlyInterface: Almost done...");
2072 if (fSetupModeInteractive)
2073 SetupSetNonInteractiveMode(fSetupModeInteractive);
2074
2075 netCfgLoggerDisable();
2076
2077 logStringF(hModule, "CreateHostOnlyInterface: Returns success (ignoring all failures)");
2078 /* Never fail the install even if we did not succeed. */
2079 return ERROR_SUCCESS;
2080}
2081#endif /* VBOX_WITH_NETADP */
2082
2083UINT __stdcall CreateHostOnlyInterface(MSIHANDLE hModule)
2084{
2085#ifdef VBOX_WITH_NETADP
2086 return _createHostOnlyInterface(hModule, NETADP_ID, L"VBoxNetAdp.inf");
2087#else
2088 RT_NOREF(hModule);
2089 return ERROR_SUCCESS;
2090#endif
2091}
2092
2093UINT __stdcall Ndis6CreateHostOnlyInterface(MSIHANDLE hModule)
2094{
2095#ifdef VBOX_WITH_NETADP
2096# if 0 /* Trick for allowing the debugger to be attached. */
2097 for (unsigned i = 0; i < 128 && !IsDebuggerPresent(); i++)
2098 {
2099 logStringF(hModule, "Waiting for debugger to attach: windbg -p %u", GetCurrentProcessId());
2100 Sleep(1001);
2101 }
2102 Sleep(1002);
2103 __debugbreak();
2104# endif
2105 return _createHostOnlyInterface(hModule, NETADP_ID, L"VBoxNetAdp6.inf");
2106#else /* !VBOX_WITH_NETADP */
2107 RT_NOREF(hModule);
2108 return ERROR_SUCCESS;
2109#endif
2110}
2111
2112#ifdef VBOX_WITH_NETADP
2113static UINT _removeHostOnlyInterfaces(MSIHANDLE hModule, LPCWSTR pwszId)
2114{
2115 netCfgLoggerEnable(hModule);
2116
2117 logStringF(hModule, "RemoveHostOnlyInterfaces: Removing all host-only interfaces");
2118
2119 BOOL fSetupModeInteractive = SetupSetNonInteractiveMode(FALSE);
2120
2121 HRESULT hr = VBoxNetCfgWinRemoveAllNetDevicesOfId(pwszId);
2122 if (SUCCEEDED(hr))
2123 {
2124 hr = VBoxDrvCfgInfUninstallAllSetupDi(&GUID_DEVCLASS_NET, L"Net", pwszId, SUOI_FORCEDELETE/* could be SUOI_FORCEDELETE */);
2125 if (FAILED(hr))
2126 logStringF(hModule, "RemoveHostOnlyInterfaces: NetAdp uninstalled successfully, but failed to remove INF files");
2127 else
2128 logStringF(hModule, "RemoveHostOnlyInterfaces: NetAdp uninstalled successfully");
2129 }
2130 else
2131 logStringF(hModule, "RemoveHostOnlyInterfaces: NetAdp uninstall failed, hr = %#x", hr);
2132
2133 /* Restore original setup mode. */
2134 if (fSetupModeInteractive)
2135 SetupSetNonInteractiveMode(fSetupModeInteractive);
2136
2137 netCfgLoggerDisable();
2138
2139 /* Never fail the uninstall even if we did not succeed. */
2140 return ERROR_SUCCESS;
2141}
2142#endif /* VBOX_WITH_NETADP */
2143
2144UINT __stdcall RemoveHostOnlyInterfaces(MSIHANDLE hModule)
2145{
2146#ifdef VBOX_WITH_NETADP
2147 return _removeHostOnlyInterfaces(hModule, NETADP_ID);
2148#else
2149 RT_NOREF(hModule);
2150 return ERROR_SUCCESS;
2151#endif
2152}
2153
2154#ifdef VBOX_WITH_NETADP
2155static UINT _stopHostOnlyInterfaces(MSIHANDLE hModule, LPCWSTR pwszId)
2156{
2157 netCfgLoggerEnable(hModule);
2158
2159 logStringF(hModule, "StopHostOnlyInterfaces: Stopping all host-only interfaces");
2160
2161 BOOL fSetupModeInteractive = SetupSetNonInteractiveMode(FALSE);
2162
2163 HRESULT hr = VBoxNetCfgWinPropChangeAllNetDevicesOfId(pwszId, VBOXNECTFGWINPROPCHANGE_TYPE_DISABLE);
2164 if (SUCCEEDED(hr))
2165 logStringF(hModule, "StopHostOnlyInterfaces: Disabling host interfaces was successful, hr = %#x", hr);
2166 else
2167 logStringF(hModule, "StopHostOnlyInterfaces: Disabling host interfaces failed, hr = %#x", hr);
2168
2169 /* Restore original setup mode. */
2170 if (fSetupModeInteractive)
2171 SetupSetNonInteractiveMode(fSetupModeInteractive);
2172
2173 netCfgLoggerDisable();
2174
2175 /* Never fail the uninstall even if we did not succeed. */
2176 return ERROR_SUCCESS;
2177}
2178#endif /* VBOX_WITH_NETADP */
2179
2180UINT __stdcall StopHostOnlyInterfaces(MSIHANDLE hModule)
2181{
2182#ifdef VBOX_WITH_NETADP
2183 return _stopHostOnlyInterfaces(hModule, NETADP_ID);
2184#else
2185 RT_NOREF(hModule);
2186 return ERROR_SUCCESS;
2187#endif
2188}
2189
2190#ifdef VBOX_WITH_NETADP
2191static UINT _updateHostOnlyInterfaces(MSIHANDLE hModule, LPCWSTR pwszInfName, LPCWSTR pwszId)
2192{
2193 netCfgLoggerEnable(hModule);
2194
2195 logStringF(hModule, "UpdateHostOnlyInterfaces: Updating all host-only interfaces");
2196
2197 BOOL fSetupModeInteractive = SetupSetNonInteractiveMode(FALSE);
2198
2199 WCHAR wszMpInf[MAX_PATH];
2200 DWORD cwcMpInf = RT_ELEMENTS(wszMpInf) - (DWORD)RTUtf16Len(pwszInfName) - 1 - 1;
2201 LPCWSTR pwszInfPath = NULL;
2202 bool fIsFile = false;
2203 UINT uErr = MsiGetPropertyW(hModule, L"CustomActionData", wszMpInf, &cwcMpInf);
2204 if (uErr == ERROR_SUCCESS)
2205 {
2206 if (cwcMpInf)
2207 {
2208 logStringF(hModule, "UpdateHostOnlyInterfaces: NetAdpDir property = %ls", wszMpInf);
2209 if (wszMpInf[cwcMpInf - 1] != L'\\')
2210 {
2211 wszMpInf[cwcMpInf++] = L'\\';
2212 wszMpInf[cwcMpInf] = L'\0';
2213 }
2214
2215 int vrc = RTUtf16Cat(wszMpInf, RT_ELEMENTS(wszMpInf), pwszInfName);
2216 AssertRC(vrc);
2217 pwszInfPath = wszMpInf;
2218 fIsFile = true;
2219
2220 logStringF(hModule, "UpdateHostOnlyInterfaces: Resulting INF path = %ls", pwszInfPath);
2221
2222 DWORD attrFile = GetFileAttributesW(pwszInfPath);
2223 if (attrFile == INVALID_FILE_ATTRIBUTES)
2224 {
2225 DWORD dwErr = GetLastError();
2226 logStringF(hModule, "UpdateHostOnlyInterfaces: File \"%ls\" not found, dwErr=%ld", pwszInfPath, dwErr);
2227 }
2228 else
2229 {
2230 logStringF(hModule, "UpdateHostOnlyInterfaces: File \"%ls\" exists", pwszInfPath);
2231
2232 BOOL fRebootRequired = FALSE;
2233 HRESULT hr = VBoxNetCfgWinUpdateHostOnlyNetworkInterface(pwszInfPath, &fRebootRequired, pwszId);
2234 if (SUCCEEDED(hr))
2235 {
2236 if (fRebootRequired)
2237 {
2238 logStringF(hModule, "UpdateHostOnlyInterfaces: Reboot required, setting REBOOT property to force");
2239 HRESULT hr2 = MsiSetPropertyW(hModule, L"REBOOT", L"Force");
2240 if (hr2 != ERROR_SUCCESS)
2241 logStringF(hModule, "UpdateHostOnlyInterfaces: Failed to set REBOOT property, error = %#x", hr2);
2242 }
2243 }
2244 else
2245 logStringF(hModule, "UpdateHostOnlyInterfaces: VBoxNetCfgWinUpdateHostOnlyNetworkInterface failed, hr = %#x", hr);
2246 }
2247 }
2248 else
2249 logStringF(hModule, "UpdateHostOnlyInterfaces: VBox installation path is empty");
2250 }
2251 else
2252 logStringF(hModule, "UpdateHostOnlyInterfaces: Unable to retrieve VBox installation path, error = %#x", uErr);
2253
2254 /* Restore original setup mode. */
2255 if (fSetupModeInteractive)
2256 SetupSetNonInteractiveMode(fSetupModeInteractive);
2257
2258 netCfgLoggerDisable();
2259
2260 /* Never fail the update even if we did not succeed. */
2261 return ERROR_SUCCESS;
2262}
2263#endif /* VBOX_WITH_NETADP */
2264
2265UINT __stdcall UpdateHostOnlyInterfaces(MSIHANDLE hModule)
2266{
2267#ifdef VBOX_WITH_NETADP
2268 return _updateHostOnlyInterfaces(hModule, L"VBoxNetAdp.inf", NETADP_ID);
2269#else
2270 RT_NOREF(hModule);
2271 return ERROR_SUCCESS;
2272#endif
2273}
2274
2275UINT __stdcall Ndis6UpdateHostOnlyInterfaces(MSIHANDLE hModule)
2276{
2277#ifdef VBOX_WITH_NETADP
2278 return _updateHostOnlyInterfaces(hModule, L"VBoxNetAdp6.inf", NETADP_ID);
2279#else
2280 RT_NOREF(hModule);
2281 return ERROR_SUCCESS;
2282#endif
2283}
2284
2285#ifdef VBOX_WITH_NETADP
2286static UINT _uninstallNetAdp(MSIHANDLE hModule, LPCWSTR pwszId)
2287{
2288 INetCfg *pNetCfg;
2289 UINT uErr;
2290
2291 netCfgLoggerEnable(hModule);
2292
2293 BOOL bOldIntMode = SetupSetNonInteractiveMode(FALSE);
2294
2295 __try
2296 {
2297 logStringF(hModule, "Uninstalling NetAdp");
2298
2299 uErr = doNetCfgInit(hModule, &pNetCfg, TRUE);
2300 if (uErr == ERROR_SUCCESS)
2301 {
2302 HRESULT hr = VBoxNetCfgWinNetAdpUninstall(pNetCfg, pwszId);
2303 if (hr != S_OK)
2304 logStringF(hModule, "UninstallNetAdp: VBoxNetCfgWinUninstallComponent failed, error = %#x", hr);
2305
2306 uErr = errorConvertFromHResult(hModule, hr);
2307
2308 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
2309
2310 logStringF(hModule, "Uninstalling NetAdp done, error = %#x", uErr);
2311 }
2312 else
2313 logStringF(hModule, "UninstallNetAdp: doNetCfgInit failed, error = %#x", uErr);
2314 }
2315 __finally
2316 {
2317 if (bOldIntMode)
2318 {
2319 /* The prev mode != FALSE, i.e. non-interactive. */
2320 SetupSetNonInteractiveMode(bOldIntMode);
2321 }
2322 netCfgLoggerDisable();
2323 }
2324
2325 /* Never fail the uninstall even if we did not succeed. */
2326 return ERROR_SUCCESS;
2327}
2328#endif /* VBOX_WITH_NETADP */
2329
2330UINT __stdcall UninstallNetAdp(MSIHANDLE hModule)
2331{
2332#ifdef VBOX_WITH_NETADP
2333 return _uninstallNetAdp(hModule, NETADP_ID);
2334#else
2335 RT_NOREF(hModule);
2336 return ERROR_SUCCESS;
2337#endif
2338}
2339
2340static bool isTAPDevice(const WCHAR *pwszGUID)
2341{
2342 HKEY hNetcard;
2343 bool bIsTapDevice = false;
2344 LONG lStatus = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2345 L"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",
2346 0, KEY_READ, &hNetcard);
2347 if (lStatus != ERROR_SUCCESS)
2348 return false;
2349
2350 int i = 0;
2351 for (;;)
2352 {
2353 WCHAR wszEnumName[256];
2354 WCHAR wszNetCfgInstanceId[256];
2355 DWORD dwKeyType;
2356 HKEY hNetCardGUID;
2357
2358 DWORD dwLen = sizeof(wszEnumName);
2359 lStatus = RegEnumKeyExW(hNetcard, i, wszEnumName, &dwLen, NULL, NULL, NULL, NULL);
2360 if (lStatus != ERROR_SUCCESS)
2361 break;
2362
2363 lStatus = RegOpenKeyExW(hNetcard, wszEnumName, 0, KEY_READ, &hNetCardGUID);
2364 if (lStatus == ERROR_SUCCESS)
2365 {
2366 dwLen = sizeof(wszNetCfgInstanceId);
2367 lStatus = RegQueryValueExW(hNetCardGUID, L"NetCfgInstanceId", NULL, &dwKeyType, (LPBYTE)wszNetCfgInstanceId, &dwLen);
2368 if ( lStatus == ERROR_SUCCESS
2369 && dwKeyType == REG_SZ)
2370 {
2371 WCHAR wszNetProductName[256];
2372 WCHAR wszNetProviderName[256];
2373
2374 wszNetProductName[0] = 0;
2375 dwLen = sizeof(wszNetProductName);
2376 lStatus = RegQueryValueExW(hNetCardGUID, L"ProductName", NULL, &dwKeyType, (LPBYTE)wszNetProductName, &dwLen);
2377
2378 wszNetProviderName[0] = 0;
2379 dwLen = sizeof(wszNetProviderName);
2380 lStatus = RegQueryValueExW(hNetCardGUID, L"ProviderName", NULL, &dwKeyType, (LPBYTE)wszNetProviderName, &dwLen);
2381
2382 if ( !RTUtf16Cmp(wszNetCfgInstanceId, pwszGUID)
2383 && !RTUtf16Cmp(wszNetProductName, L"VirtualBox TAP Adapter")
2384 && ( (!RTUtf16Cmp(wszNetProviderName, L"innotek GmbH")) /* Legacy stuff. */
2385 || (!RTUtf16Cmp(wszNetProviderName, L"Sun Microsystems, Inc.")) /* Legacy stuff. */
2386 || (!RTUtf16Cmp(wszNetProviderName, MY_WTEXT(VBOX_VENDOR))) /* Reflects current vendor string. */
2387 )
2388 )
2389 {
2390 bIsTapDevice = true;
2391 RegCloseKey(hNetCardGUID);
2392 break;
2393 }
2394 }
2395 RegCloseKey(hNetCardGUID);
2396 }
2397 ++i;
2398 }
2399
2400 RegCloseKey(hNetcard);
2401 return bIsTapDevice;
2402}
2403
2404/** @todo r=andy BUGBUG WTF! Why do we a) set the rc to 0 (success), and b) need this macro at all!?
2405 *
2406 * @todo r=bird: Because it's returning a bool, not int? The return code is
2407 * ignored anyway, both internally in removeNetworkInterface and in it's caller.
2408 * There is similar code in VBoxNetCfg.cpp, which is probably where it was copied from. */
2409#define SetErrBreak(args) \
2410 if (1) { \
2411 rc = 0; \
2412 logStringF args; \
2413 break; \
2414 } else do {} while (0)
2415
2416int removeNetworkInterface(MSIHANDLE hModule, const WCHAR *pwszGUID)
2417{
2418 int rc = 1;
2419 do /* break-loop */
2420 {
2421 WCHAR wszPnPInstanceId[512] = {0};
2422
2423 /* We have to find the device instance ID through a registry search */
2424
2425 HKEY hkeyNetwork = 0;
2426 HKEY hkeyConnection = 0;
2427
2428 do /* break-loop */
2429 {
2430 WCHAR wszRegLocation[256];
2431 RTUtf16Printf(wszRegLocation, RT_ELEMENTS(wszRegLocation),
2432 "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%ls", pwszGUID);
2433 LONG lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRegLocation, 0, KEY_READ, &hkeyNetwork);
2434 if (lrc != ERROR_SUCCESS || !hkeyNetwork)
2435 SetErrBreak((hModule, "VBox HostInterfaces: Host interface network was not found in registry (%ls)! (lrc=%d) [1]",
2436 wszRegLocation, lrc));
2437
2438 lrc = RegOpenKeyExW(hkeyNetwork, L"Connection", 0, KEY_READ, &hkeyConnection);
2439 if (lrc != ERROR_SUCCESS || !hkeyConnection)
2440 SetErrBreak((hModule, "VBox HostInterfaces: Host interface network was not found in registry (%ls)! (lrc=%d) [2]",
2441 wszRegLocation, lrc));
2442
2443 DWORD len = sizeof(wszPnPInstanceId);
2444 DWORD dwKeyType;
2445 lrc = RegQueryValueExW(hkeyConnection, L"PnPInstanceID", NULL, &dwKeyType, (LPBYTE)&wszPnPInstanceId[0], &len);
2446 if (lrc != ERROR_SUCCESS || dwKeyType != REG_SZ)
2447 SetErrBreak((hModule, "VBox HostInterfaces: Host interface network was not found in registry (%ls)! (lrc=%d) [3]",
2448 wszRegLocation, lrc));
2449 }
2450 while (0);
2451
2452 if (hkeyConnection)
2453 RegCloseKey(hkeyConnection);
2454 if (hkeyNetwork)
2455 RegCloseKey(hkeyNetwork);
2456
2457 /*
2458 * Now we are going to enumerate all network devices and
2459 * wait until we encounter the right device instance ID
2460 */
2461
2462 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2463 BOOL fResult;
2464
2465 do /* break-loop */
2466 {
2467 /* initialize the structure size */
2468 SP_DEVINFO_DATA DeviceInfoData = { sizeof(DeviceInfoData) };
2469
2470 /* copy the net class GUID */
2471 GUID netGuid;
2472 memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof (GUID_DEVCLASS_NET));
2473
2474 /* return a device info set contains all installed devices of the Net class */
2475 hDeviceInfo = SetupDiGetClassDevs(&netGuid, NULL, NULL, DIGCF_PRESENT);
2476 if (hDeviceInfo == INVALID_HANDLE_VALUE)
2477 {
2478 logStringF(hModule, "VBox HostInterfaces: SetupDiGetClassDevs failed (0x%08X)!", GetLastError());
2479 SetErrBreak((hModule, "VBox HostInterfaces: Uninstallation failed!"));
2480 }
2481
2482 /* enumerate the driver info list */
2483 BOOL fFoundDevice = FALSE;
2484 for (DWORD index = 0;; index++)
2485 {
2486 fResult = SetupDiEnumDeviceInfo(hDeviceInfo, index, &DeviceInfoData);
2487 if (!fResult)
2488 {
2489 if (GetLastError() == ERROR_NO_MORE_ITEMS)
2490 break;
2491 continue;
2492 }
2493
2494 /* try to get the hardware ID registry property */
2495 WCHAR *pwszDeviceHwid;
2496 DWORD size = 0;
2497 fResult = SetupDiGetDeviceRegistryProperty(hDeviceInfo,
2498 &DeviceInfoData,
2499 SPDRP_HARDWAREID,
2500 NULL,
2501 NULL,
2502 0,
2503 &size);
2504 if (!fResult)
2505 {
2506 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2507 continue;
2508
2509 pwszDeviceHwid = (WCHAR *)RTMemAllocZ(size);
2510 if (!pwszDeviceHwid)
2511 continue;
2512
2513 fResult = SetupDiGetDeviceRegistryProperty(hDeviceInfo,
2514 &DeviceInfoData,
2515 SPDRP_HARDWAREID,
2516 NULL,
2517 (PBYTE)pwszDeviceHwid,
2518 size,
2519 &size);
2520 if (!fResult)
2521 {
2522 RTMemFree(pwszDeviceHwid);
2523 continue;
2524 }
2525 }
2526 else
2527 {
2528 /* something is wrong. This shouldn't have worked with a NULL buffer */
2529 continue;
2530 }
2531
2532 for (WCHAR *t = pwszDeviceHwid;
2533 *t && t < &pwszDeviceHwid[size / sizeof(WCHAR)];
2534 t += RTUtf16Len(t) + 1)
2535 {
2536 if (RTUtf16ICmpAscii(t, "vboxtap") == 0)
2537 {
2538 /* get the device instance ID */
2539 WCHAR wszDevID[MAX_DEVICE_ID_LEN];
2540 if (CM_Get_Device_IDW(DeviceInfoData.DevInst, wszDevID, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS)
2541 {
2542 /* compare to what we determined before */
2543 if (RTUtf16Cmp(wszDevID, wszPnPInstanceId) == 0)
2544 {
2545 fFoundDevice = TRUE;
2546 break;
2547 }
2548 }
2549 }
2550 }
2551
2552 RTMemFree(pwszDeviceHwid);
2553
2554 if (fFoundDevice)
2555 break;
2556 }
2557
2558 if (fFoundDevice)
2559 {
2560 fResult = SetupDiSetSelectedDevice(hDeviceInfo, &DeviceInfoData);
2561 if (!fResult)
2562 {
2563 logStringF(hModule, "VBox HostInterfaces: SetupDiSetSelectedDevice failed (0x%08X)!", GetLastError());
2564 SetErrBreak((hModule, "VBox HostInterfaces: Uninstallation failed!"));
2565 }
2566
2567 fResult = SetupDiCallClassInstaller(DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
2568 if (!fResult)
2569 {
2570 logStringF(hModule, "VBox HostInterfaces: SetupDiCallClassInstaller (DIF_REMOVE) failed (0x%08X)!", GetLastError());
2571 SetErrBreak((hModule, "VBox HostInterfaces: Uninstallation failed!"));
2572 }
2573 }
2574 else
2575 SetErrBreak((hModule, "VBox HostInterfaces: Host interface network device not found!"));
2576 } while (0);
2577
2578 /* clean up the device info set */
2579 if (hDeviceInfo != INVALID_HANDLE_VALUE)
2580 SetupDiDestroyDeviceInfoList(hDeviceInfo);
2581 } while (0);
2582 return rc;
2583}
2584
2585UINT __stdcall UninstallTAPInstances(MSIHANDLE hModule)
2586{
2587 static const wchar_t s_wszNetworkKey[] = L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}";
2588 HKEY hCtrlNet;
2589
2590 LSTATUS lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, s_wszNetworkKey, 0, KEY_READ, &hCtrlNet);
2591 if (lrc == ERROR_SUCCESS)
2592 {
2593 logStringF(hModule, "VBox HostInterfaces: Enumerating interfaces ...");
2594 for (int i = 0; ; ++i)
2595 {
2596 WCHAR wszNetworkGUID[256] = { 0 };
2597 DWORD dwLen = (DWORD)sizeof(wszNetworkGUID);
2598 lrc = RegEnumKeyExW(hCtrlNet, i, wszNetworkGUID, &dwLen, NULL, NULL, NULL, NULL);
2599 if (lrc != ERROR_SUCCESS)
2600 {
2601 switch (lrc)
2602 {
2603 case ERROR_NO_MORE_ITEMS:
2604 logStringF(hModule, "VBox HostInterfaces: No interfaces found.");
2605 break;
2606 default:
2607 logStringF(hModule, "VBox HostInterfaces: Enumeration failed: %ld", lrc);
2608 break;
2609 }
2610 break;
2611 }
2612
2613 if (isTAPDevice(wszNetworkGUID))
2614 {
2615 logStringF(hModule, "VBox HostInterfaces: Removing interface \"%ls\" ...", wszNetworkGUID);
2616 removeNetworkInterface(hModule, wszNetworkGUID);
2617 lrc = RegDeleteKeyW(hCtrlNet, wszNetworkGUID);
2618 }
2619 }
2620 RegCloseKey(hCtrlNet);
2621 logStringF(hModule, "VBox HostInterfaces: Removing interfaces done.");
2622 }
2623 return ERROR_SUCCESS;
2624}
2625
2626
2627/**
2628 * This is used to remove the old VBoxDrv service before installation.
2629 *
2630 * The current service name is VBoxSup but the INF file won't remove the old
2631 * one, so we do it manually to try prevent trouble as the device nodes are the
2632 * same and we would fail starting VBoxSup.sys if VBoxDrv.sys is still loading.
2633 *
2634 * Status code is ignored for now as a reboot should fix most potential trouble
2635 * here (and I don't want to break stuff too badly).
2636 *
2637 * @sa @bugref{10162}
2638 */
2639UINT __stdcall UninstallVBoxDrv(MSIHANDLE hModule)
2640{
2641 /*
2642 * Try open the service.
2643 */
2644 SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_CHANGE_CONFIG | SERVICE_STOP | SERVICE_QUERY_STATUS);
2645 if (hSMgr)
2646 {
2647 SC_HANDLE hService = OpenServiceW(hSMgr, L"VBoxDrv", DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS);
2648 if (hService)
2649 {
2650 /*
2651 * Try stop it before we delete it.
2652 */
2653 SERVICE_STATUS Status = { 0, 0, 0, 0, 0, 0, 0 };
2654 QueryServiceStatus(hService, &Status);
2655 if (Status.dwCurrentState == SERVICE_STOPPED)
2656 logStringF(hModule, "VBoxDrv: The service old service was already stopped");
2657 else
2658 {
2659 logStringF(hModule, "VBoxDrv: Stopping the service (state %u)", Status.dwCurrentState);
2660 if (ControlService(hService, SERVICE_CONTROL_STOP, &Status))
2661 {
2662 /* waiting for it to stop: */
2663 int iWait = 100;
2664 while (Status.dwCurrentState == SERVICE_STOP_PENDING && iWait-- > 0)
2665 {
2666 Sleep(100);
2667 QueryServiceStatus(hService, &Status);
2668 }
2669
2670 if (Status.dwCurrentState == SERVICE_STOPPED)
2671 logStringF(hModule, "VBoxDrv: Stopped service");
2672 else
2673 logStringF(hModule, "VBoxDrv: Failed to stop the service, status: %u", Status.dwCurrentState);
2674 }
2675 else
2676 {
2677 DWORD const dwErr = GetLastError();
2678 if ( Status.dwCurrentState == SERVICE_STOP_PENDING
2679 && dwErr == ERROR_SERVICE_CANNOT_ACCEPT_CTRL)
2680 logStringF(hModule, "VBoxDrv: Failed to stop the service: stop pending, not accepting control messages");
2681 else
2682 logStringF(hModule, "VBoxDrv: Failed to stop the service: dwErr=%u status=%u", dwErr, Status.dwCurrentState);
2683 }
2684 }
2685
2686 /*
2687 * Delete the service, or at least mark it for deletion.
2688 */
2689 if (DeleteService(hService))
2690 logStringF(hModule, "VBoxDrv: Successfully delete service");
2691 else
2692 logStringF(hModule, "VBoxDrv: Failed to delete the service: %u", GetLastError());
2693
2694 CloseServiceHandle(hService);
2695 }
2696 else
2697 {
2698 DWORD const dwErr = GetLastError();
2699 if (dwErr == ERROR_SERVICE_DOES_NOT_EXIST)
2700 logStringF(hModule, "VBoxDrv: Nothing to do, the old service does not exist");
2701 else
2702 logStringF(hModule, "VBoxDrv: Failed to open the service: %u", dwErr);
2703 }
2704
2705 CloseServiceHandle(hSMgr);
2706 }
2707 else
2708 logStringF(hModule, "VBoxDrv: Failed to open service manager (%u).", GetLastError());
2709
2710 return ERROR_SUCCESS;
2711}
2712
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette