VirtualBox

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

Last change on this file was 106839, checked in by vboxsync, 4 weeks ago

Windows driver installation: Made it a bit smarter wrt model / PnP ID detection within files. bugref:10762

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

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