VirtualBox

source: vbox/trunk/src/VBox/GuestHost/installation/VBoxWinDrvInst.cpp@ 107973

Last change on this file since 107973 was 107973, checked in by vboxsync, 3 months ago

Windows driver installation: Fixed the ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED error, added documentation and give a clue to users why this might have failed. See source for details. bugref:10762

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 93.9 KB
Line 
1/* $Id: VBoxWinDrvInst.cpp 107973 2025-01-29 09:30:26Z vboxsync $ */
2/** @file
3 * VBoxWinDrvInst - Windows driver installation handling.
4 */
5
6/*
7 * Copyright (C) 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#include <iprt/win/windows.h>
33#include <iprt/win/setupapi.h>
34#include <newdev.h> /* For INSTALLFLAG_XXX. */
35#include <cfgmgr32.h> /* For MAX_DEVICE_ID_LEN. */
36#ifdef RT_ARCH_X86
37# include <wintrust.h>
38# include <softpub.h>
39#endif
40
41#include <iprt/assert.h>
42#include <iprt/buildconfig.h>
43#include <iprt/cdefs.h>
44#include <iprt/dir.h>
45#include <iprt/ldr.h>
46#include <iprt/list.h>
47#include <iprt/mem.h>
48#include <iprt/once.h>
49#include <iprt/path.h>
50#include <iprt/stream.h>
51#include <iprt/string.h>
52#include <iprt/system.h>
53#include <iprt/utf16.h>
54
55#include <package-generated.h>
56#include "product-generated.h"
57
58#include <VBox/err.h> /* For VERR_PLATFORM_ARCH_NOT_SUPPORTED.*/
59#include <VBox/version.h>
60
61#include <VBox/GuestHost/VBoxWinDrvDefs.h>
62#include <VBox/GuestHost/VBoxWinDrvInst.h>
63#include <VBox/GuestHost/VBoxWinDrvStore.h>
64
65#include "VBoxWinDrvCommon.h"
66#include "VBoxWinDrvInstInternal.h"
67
68
69/*********************************************************************************************************************************
70* Defines *
71*********************************************************************************************************************************/
72
73/* Defines from newdev.h (WINVER >= _WIN32_WINNT_VISTA). */
74#define DIIRFLAG_INF_ALREADY_COPIED 0x00000001
75#define DIIRFLAG_FORCE_INF 0x00000002
76#define DIIRFLAG_HW_USING_THE_INF 0x00000004
77#define DIIRFLAG_HOTPATCH 0x00000008
78#define DIIRFLAG_NOBACKUP 0x00000010
79
80
81/* SetupUninstallOEMInf Flags values. */
82#define SUOI_FORCEDELETE 0x00000001
83
84
85/*********************************************************************************************************************************
86* Defined Constants And Macros *
87*********************************************************************************************************************************/
88/** The magic value for RTFTPSERVERINTERNAL::u32Magic. */
89#define VBOXWINDRVINST_MAGIC UINT32_C(0x20171201)
90
91/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
92#define VBOXWINDRVINST_VALID_RETURN_RC(hDrvInst, a_rc) \
93 do { \
94 AssertPtrReturn((hDrvInst), (a_rc)); \
95 AssertReturn((hDrvInst)->u32Magic == VBOXWINDRVINST_MAGIC, (a_rc)); \
96 } while (0)
97
98/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
99#define VBOXWINDRVINST_VALID_RETURN(hDrvInst) VBOXWINDRVINST_VALID_RETURN_RC((hDrvInst), VERR_INVALID_HANDLE)
100
101/** Validates a handle and returns (void) if not valid. */
102#define VBOXWINDRVINST_VALID_RETURN_VOID(hDrvInst) \
103 do { \
104 AssertPtrReturnVoid(hDrvInst); \
105 AssertReturnVoid((hDrvInst)->u32Magic == VBOXWINDRVINST_MAGIC); \
106 } while (0)
107
108
109/*********************************************************************************************************************************
110* Structures and Typedefs *
111*********************************************************************************************************************************/
112/* newdev.dll: */
113typedef BOOL(WINAPI* PFNDIINSTALLDRIVERW) (HWND hwndParent, LPCWSTR InfPath, DWORD Flags, PBOOL NeedReboot);
114typedef BOOL(WINAPI* PFNDIUNINSTALLDRIVERW) (HWND hwndParent, LPCWSTR InfPath, DWORD Flags, PBOOL NeedReboot);
115typedef BOOL(WINAPI* PFNUPDATEDRIVERFORPLUGANDPLAYDEVICESW) (HWND hwndParent, LPCWSTR HardwareId, LPCWSTR FullInfPath, DWORD InstallFlags, PBOOL bRebootRequired);
116/* setupapi.dll: */
117typedef VOID(WINAPI* PFNINSTALLHINFSECTIONW) (HWND Window, HINSTANCE ModuleHandle, PCWSTR CommandLine, INT ShowCommand);
118typedef BOOL(WINAPI* PFNSETUPCOPYOEMINFW) (PCWSTR SourceInfFileName, PCWSTR OEMSourceMediaLocation, DWORD OEMSourceMediaType, DWORD CopyStyle, PWSTR DestinationInfFileName, DWORD DestinationInfFileNameSize, PDWORD RequiredSize, PWSTR DestinationInfFileNameComponent);
119typedef HINF(WINAPI* PFNSETUPOPENINFFILEW) (PCWSTR FileName, PCWSTR InfClass, DWORD InfStyle, PUINT ErrorLine);
120typedef VOID(WINAPI* PFNSETUPCLOSEINFFILE) (HINF InfHandle);
121typedef BOOL(WINAPI* PFNSETUPDIGETINFCLASSW) (PCWSTR, LPGUID, PWSTR, DWORD, PDWORD);
122typedef BOOL(WINAPI* PFNSETUPUNINSTALLOEMINFW) (PCWSTR InfFileName, DWORD Flags, PVOID Reserved);
123typedef BOOL(WINAPI *PFNSETUPSETNONINTERACTIVEMODE) (BOOL NonInteractiveFlag);
124
125/** Function pointer for a general try INF section callback. */
126typedef int (*PFNVBOXWINDRVINST_TRYINFSECTION_CALLBACK)(HINF hInf, PCRTUTF16 pwszSection, void *pvCtx);
127
128
129/*********************************************************************************************************************************
130* Global Variables *
131*********************************************************************************************************************************/
132/** Init once structure for run-as-user functions we need. */
133DECL_HIDDEN_DATA(RTONCE) g_vboxWinDrvInstResolveOnce = RTONCE_INITIALIZER;
134
135/* newdev.dll: */
136DECL_HIDDEN_DATA(PFNDIINSTALLDRIVERW) g_pfnDiInstallDriverW = NULL; /* For Vista+ .*/
137DECL_HIDDEN_DATA(PFNDIUNINSTALLDRIVERW) g_pfnDiUninstallDriverW = NULL; /* Since Win 10 version 1703. */
138DECL_HIDDEN_DATA(PFNUPDATEDRIVERFORPLUGANDPLAYDEVICESW) g_pfnUpdateDriverForPlugAndPlayDevicesW = NULL; /* For < Vista .*/
139/* setupapi.dll: */
140DECL_HIDDEN_DATA(PFNINSTALLHINFSECTIONW) g_pfnInstallHinfSectionW = NULL; /* For W2K+. */
141DECL_HIDDEN_DATA(PFNSETUPCOPYOEMINFW) g_pfnSetupCopyOEMInfW = NULL; /* For W2K+. */
142DECL_HIDDEN_DATA(PFNSETUPOPENINFFILEW) g_pfnSetupOpenInfFileW = NULL; /* For W2K+. */
143DECL_HIDDEN_DATA(PFNSETUPCLOSEINFFILE) g_pfnSetupCloseInfFile = NULL; /* For W2K+. */
144DECL_HIDDEN_DATA(PFNSETUPDIGETINFCLASSW) g_pfnSetupDiGetINFClassW = NULL; /* For W2K+. */
145DECL_HIDDEN_DATA(PFNSETUPUNINSTALLOEMINFW) g_pfnSetupUninstallOEMInfW = NULL; /* For XP+. */
146DECL_HIDDEN_DATA(PFNSETUPSETNONINTERACTIVEMODE) g_pfnSetupSetNonInteractiveMode = NULL; /* For W2K+. */
147
148/**
149 * Structure for keeping the internal Windows driver context.
150 */
151typedef struct VBOXWINDRVINSTINTERNAL
152{
153 /** Magic value. */
154 uint32_t u32Magic;
155 /** Callback function for logging output. Optional and can be NULL. */
156 PFNVBOXWINDRIVERLOGMSG pfnLog;
157 /** User-supplied pointer for \a pfnLog. Optional and can be NULL. */
158 void *pvUser;
159 /** Currently set verbosity level. */
160 unsigned uVerbosity;
161 /** Number of (logged) warnings. */
162 unsigned cWarnings;
163 /** Number of (logged) errors. */
164 unsigned cErrors;
165 /** Whether a reboot is needed in order to perform the current (un)installation. */
166 bool fReboot;
167 /** OS version to use. Detected on creation. RTSYSTEM_NT_VERSION_GET_XXX style.
168 * Can be overwritten via VBoxWinDrvInstSetOsVersion(). */
169 uint64_t uOsVer;
170 /** Parameters for (un)installation. */
171 VBOXWINDRVINSTPARMS Parms;
172 /** Driver store entry to use. */
173 PVBOXWINDRVSTORE pStore;
174} VBOXWINDRVINSTINTERNAL;
175/** Pointer to an internal Windows driver installation context. */
176typedef VBOXWINDRVINSTINTERNAL *PVBOXWINDRVINSTINTERNAL;
177
178/**
179 * Structure for holding a single DLL import symbol.
180 *
181 * Ordinal currently ignored.
182 */
183typedef struct VBOXWINDRVINSTIMPORTSYMBOL
184{
185 /** Symbol name. */
186 const char *pszSymbol;
187 /** Function pointer. */
188 void **pfnFunc;
189} VBOXWINDRVINSTIMPORTSYMBOL;
190
191
192/*********************************************************************************************************************************
193* Prototypes *
194*********************************************************************************************************************************/
195static int vboxWinDrvParmsDetermine(PVBOXWINDRVINSTINTERNAL pCtx, PVBOXWINDRVINSTPARMS pParms, bool fForce);
196
197
198/*********************************************************************************************************************************
199* Import tables *
200*********************************************************************************************************************************/
201
202/* setupapi.dll: */
203static VBOXWINDRVINSTIMPORTSYMBOL s_aSetupApiImports[] =
204{
205 { "InstallHinfSectionW", (void **)&g_pfnInstallHinfSectionW },
206 { "SetupCopyOEMInfW", (void **)&g_pfnSetupCopyOEMInfW },
207 { "SetupUninstallOEMInfW", (void **)&g_pfnSetupUninstallOEMInfW },
208 { "SetupOpenInfFileW", (void **)&g_pfnSetupOpenInfFileW },
209 { "SetupCloseInfFile", (void **)&g_pfnSetupCloseInfFile },
210 { "SetupDiGetINFClassW", (void **)&g_pfnSetupDiGetINFClassW },
211 { "SetupSetNonInteractiveMode", (void **)&g_pfnSetupSetNonInteractiveMode }
212};
213
214/* newdev.dll: */
215static VBOXWINDRVINSTIMPORTSYMBOL s_aNewDevImports[] =
216{
217 /* Only for Vista / 2008 Server and up. */
218 { "DiInstallDriverW", (void **)&g_pfnDiInstallDriverW },
219 { "DiUninstallDriverW", (void **)&g_pfnDiUninstallDriverW },
220 /* Anything older (must support Windows 2000). */
221 { "UpdateDriverForPlugAndPlayDevicesW", (void **)&g_pfnUpdateDriverForPlugAndPlayDevicesW }
222};
223
224
225/*********************************************************************************************************************************
226* Implementation *
227*********************************************************************************************************************************/
228
229/**
230 * Logs message, va_list version.
231 *
232 * @returns VBox status code.
233 * @param pCtx Windows driver installer context.
234 * @param enmType Log type to use.
235 * @param pszFormat Format string to log.
236 * @param args va_list to use.
237 */
238DECLINLINE(void) vboxWinDrvInstLogExV(PVBOXWINDRVINSTINTERNAL pCtx,
239 VBOXWINDRIVERLOGTYPE enmType, const char *pszFormat, va_list args)
240{
241 if (!pCtx->pfnLog)
242 return;
243
244 char *psz = NULL;
245 RTStrAPrintfV(&psz, pszFormat, args);
246 AssertPtrReturnVoid(psz);
247
248 pCtx->pfnLog(enmType, psz, pCtx->pvUser);
249 RTStrFree(psz);
250}
251
252/**
253 * Logs message, extended version.
254 *
255 * @returns VBox status code.
256 * @param pCtx Windows driver installer context.
257 * @param enmType Log type to use.
258 * @param pszFormat Format string to log.
259 */
260DECLINLINE(void) vboxWinDrvInstLogEx(PVBOXWINDRVINSTINTERNAL pCtx,
261 VBOXWINDRIVERLOGTYPE enmType, const char *pszFormat, ...)
262{
263 va_list args;
264 va_start(args, pszFormat);
265 vboxWinDrvInstLogExV(pCtx, enmType, pszFormat, args);
266 va_end(args);
267}
268
269/**
270 * Logs an error message, extended version.
271 *
272 * @returns VBox status code.
273 * @param pCtx Windows driver installer context.
274 * @param fIgnore Whether to ignore the error in the error count or not.
275 * @param pszFormat Format string to log.
276 * @param args va_list for \a pszFormat.
277 */
278DECLINLINE(void) vboxWinDrvInstLogErrorExV(PVBOXWINDRVINSTINTERNAL pCtx, bool fIgnore, const char *pszFormat, va_list args)
279{
280 vboxWinDrvInstLogExV(pCtx, VBOXWINDRIVERLOGTYPE_ERROR, pszFormat, args);
281 if (!fIgnore)
282 pCtx->cErrors++;
283}
284
285#ifdef RT_ARCH_X86
286/**
287 * Logs an error message but ignores (skips) the error count.
288 *
289 * @returns VBox status code.
290 * @param pCtx Windows driver installer context.
291 * @param pszFormat Format string to log.
292 * @param ... Variable arguments for \a pszFormat.
293 */
294DECLINLINE(void) vboxWinDrvInstLogErrorIgn(PVBOXWINDRVINSTINTERNAL pCtx, const char *pszFormat, ...)
295{
296 va_list args;
297 va_start(args, pszFormat);
298 vboxWinDrvInstLogErrorExV(pCtx, true /* fIgnore */, pszFormat, args);
299 va_end(args);
300}
301
302/**
303 * Logs an error message, ignores (skips) the error count and returns the given rc for convenience.
304 *
305 * @returns VBox status code, given by \a rc.
306 * @param pCtx Windows driver installer context.
307 * @param rc rc to return.
308 * @param pszFormat Format string to log.
309 * @param ... Variable arguments for \a pszFormat.
310 */
311DECLINLINE(int) vboxWinDrvInstLogErrorRetIgn(PVBOXWINDRVINSTINTERNAL pCtx, int rc, const char *pszFormat, ...)
312{
313 va_list args;
314 va_start(args, pszFormat);
315 vboxWinDrvInstLogErrorExV(pCtx, true /* fIgnore */, pszFormat, args);
316 va_end(args);
317
318 return rc;
319}
320#endif /* RT_ARCH_X86 */
321
322/**
323 * Logs an error message.
324 *
325 * @returns VBox status code.
326 * @param pCtx Windows driver installer context.
327 * @param pszFormat Format string to log.
328 */
329DECLINLINE(void) vboxWinDrvInstLogError(PVBOXWINDRVINSTINTERNAL pCtx, const char *pszFormat, ...)
330{
331 va_list args;
332 va_start(args, pszFormat);
333 vboxWinDrvInstLogErrorExV(pCtx, false /* fIgnore */, pszFormat, args);
334 va_end(args);
335}
336
337/**
338 * Logs a warning message.
339 *
340 * @returns VBox status code.
341 * @param pCtx Windows driver installer context.
342 * @param pszFormat Format string to log.
343 */
344DECLINLINE(void) vboxWinDrvInstLogWarn(PVBOXWINDRVINSTINTERNAL pCtx, const char *pszFormat, ...)
345{
346 va_list args;
347 va_start(args, pszFormat);
348 vboxWinDrvInstLogExV(pCtx, VBOXWINDRIVERLOGTYPE_WARN, pszFormat, args);
349 va_end(args);
350
351 pCtx->cWarnings++;
352}
353
354/**
355 * Logs an information message.
356 *
357 * @returns VBox status code.
358 * @param pCtx Windows driver installer context.
359 * @param pszFormat Format string to log.
360 */
361DECLINLINE(void) vboxWinDrvInstLogInfo(PVBOXWINDRVINSTINTERNAL pCtx, const char *pszFormat, ...)
362{
363 va_list args;
364 va_start(args, pszFormat);
365 vboxWinDrvInstLogExV(pCtx, VBOXWINDRIVERLOGTYPE_INFO, pszFormat, args);
366 va_end(args);
367}
368
369/**
370 * Logs a verbose message.
371 *
372 * @returns VBox status code.
373 * @param pCtx Windows driver installer context.
374 * @param uVerbosity Verbosity level to use for logging.
375 * @param pszFormat Format string to log.
376 */
377DECLINLINE(void) vboxWinDrvInstLogVerbose(PVBOXWINDRVINSTINTERNAL pCtx, unsigned uVerbosity, const char *pszFormat, ...)
378{
379 if (uVerbosity <= pCtx->uVerbosity)
380 {
381 va_list args;
382 va_start(args, pszFormat);
383 vboxWinDrvInstLogExV(pCtx, VBOXWINDRIVERLOGTYPE_VERBOSE, pszFormat, args);
384 va_end(args);
385 }
386}
387
388/**
389 * Logs (and indicates) that a reboot is needed.
390 *
391 * @returns VBox status code.
392 * @param pCtx Windows driver installer context.
393 * @param pszFormat Format string to log.
394 */
395DECLINLINE(void) vboxWinDrvInstLogRebootNeeded(PVBOXWINDRVINSTINTERNAL pCtx, const char *pszFormat, ...)
396{
397 va_list args;
398 va_start(args, pszFormat);
399 vboxWinDrvInstLogExV(pCtx, VBOXWINDRIVERLOGTYPE_REBOOT_NEEDED, pszFormat, args);
400 va_end(args);
401}
402
403/**
404 * Logs the last Windows error given via GetLastError().
405 *
406 * @returns Last Windows error translated into VBox status code.
407 * @retval VERR_INSTALLATION_FAILED if a translation to a VBox status code wasn't possible.
408 * @param pCtx Windows driver installer context.
409 * @param pszFormat Format string to log.
410 */
411DECLINLINE(int) vboxWinDrvInstLogLastError(PVBOXWINDRVINSTINTERNAL pCtx, const char *pszFormat, ...)
412{
413 DWORD const dwErr = GetLastError();
414
415 va_list args;
416 va_start(args, pszFormat);
417
418 char *psz = NULL;
419 RTStrAPrintfV(&psz, pszFormat, args);
420 AssertPtrReturn(psz, VERR_NO_MEMORY);
421
422 int rc = VERR_INSTALLATION_FAILED;
423
424#ifdef DEBUG_andy
425 bool const fAssertMayPanic = RTAssertMayPanic();
426 RTAssertSetMayPanic(false);
427#endif
428
429 /* Try resolving Setup API errors first (we don't handle those in IPRT). */
430 const char *pszErr = VBoxWinDrvSetupApiErrToStr(dwErr);
431 if (!pszErr) /* Also ask for special winerr.h codes we don't handle in IPRT. */
432 pszErr = VBoxWinDrvWinErrToStr(dwErr);
433 if (!pszErr)
434 rc = RTErrConvertFromWin32(dwErr);
435
436#ifdef DEBUG_andy
437 RTAssertSetMayPanic(fAssertMayPanic);
438#endif
439
440 if (pszErr)
441 vboxWinDrvInstLogError(pCtx, "%s: %s (%ld / %#x)", psz, pszErr, dwErr, dwErr);
442 else
443 vboxWinDrvInstLogError(pCtx, "%s: %Rrc (%ld / %#x)", psz, rc, dwErr, dwErr);
444
445 RTStrFree(psz);
446
447 va_end(args);
448
449 return rc;
450}
451
452/**
453 * Resolves a single symbol of a module (DLL).
454 *
455 * @returns VBox status code.
456 * @param pCtx Windows driver installer context.
457 * @param hMod Module handle to use.
458 * @param pszSymbol Name of symbol to resolve.
459 * @param pfnFunc Where to return the function pointer for resolved symbol on success.
460 */
461DECLINLINE(int) vboxWinDrvInstInstModResolveSym(PVBOXWINDRVINSTINTERNAL pCtx, RTLDRMOD hMod, const char *pszSymbol,
462 void **pfnFunc)
463{
464 int rc = RTLdrGetSymbol(hMod, pszSymbol, pfnFunc);
465 if (RT_FAILURE(rc))
466 {
467 vboxWinDrvInstLogVerbose(pCtx, 1, "Warning: Symbol \"%s\" not found (%Rrc)", pszSymbol, rc);
468 *pfnFunc = NULL;
469 }
470
471 return rc;
472}
473
474/**
475 * Resolves symbols of a specific module (DLL).
476 *
477 * @returns VBox status code.
478 * @param pCtx Windows driver installer context.
479 * @param pszFilename Path of module to resolve symbols for.
480 * @param pSymbols Table of symbols to resolve.
481 * @param cSymbols Number of symbols within \a pSymbols to resolve.
482 */
483static DECLCALLBACK(int) vboxWinDrvInstResolveMod(PVBOXWINDRVINSTINTERNAL pCtx,
484 const char *pszFilename, VBOXWINDRVINSTIMPORTSYMBOL *pSymbols, size_t cSymbols)
485{
486 vboxWinDrvInstLogVerbose(pCtx, 1, "Resolving symbols for module \"%s\" ...", pszFilename);
487
488 RTLDRMOD hMod;
489 int rc = RTLdrLoadSystem(pszFilename, true /*fNoUnload*/, &hMod);
490 if (RT_SUCCESS(rc))
491 {
492 for (size_t i = 0; i < cSymbols; i++)
493 {
494 void *pfnFunc;
495 rc = vboxWinDrvInstInstModResolveSym(pCtx, hMod, pSymbols[i].pszSymbol, &pfnFunc);
496 if (RT_SUCCESS(rc))
497 *pSymbols[i].pfnFunc = pfnFunc;
498 }
499
500 RTLdrClose(hMod);
501 }
502 else
503 vboxWinDrvInstLogError(pCtx, "Unabled to load module \"%s\" (%Rrc)", pszFilename, rc);
504
505 return rc;
506}
507
508/**
509 * Initialize the import APIs for run-as-user and special environment support.
510 *
511 * @returns VBox status code.
512 * @param pvUser Pointer to VBOXWINDRVINSTINTERNAL.
513 */
514static DECLCALLBACK(int) vboxWinDrvInstResolveOnce(void *pvUser)
515{
516 PVBOXWINDRVINSTINTERNAL pCtx = (PVBOXWINDRVINSTINTERNAL)pvUser;
517
518 /*
519 * Note: Any use of Difx[app|api].dll imports is forbidden (and also marked as being deprecated since Windows 10)!
520 */
521
522 /* rc ignored, keep going */ vboxWinDrvInstResolveMod(pCtx, "setupapi.dll",
523 s_aSetupApiImports, RT_ELEMENTS(s_aSetupApiImports));
524 /* rc ignored, keep going */ vboxWinDrvInstResolveMod(pCtx, "newdev.dll",
525 s_aNewDevImports, RT_ELEMENTS(s_aNewDevImports));
526
527 return VINF_SUCCESS;
528}
529
530/**
531 * Initializes a driver installation parameters structure.
532 *
533 * @param pParms Installation parameters structure to initialize.
534 */
535static void vboxWinDrvInstParmsInit(PVBOXWINDRVINSTPARMS pParms)
536{
537 RT_BZERO(pParms, sizeof(VBOXWINDRVINSTPARMS));
538}
539
540/**
541 * Destroys a driver installation parameters structure.
542 *
543 * @param pParms Installation parameters structure to destroy.
544 */
545static void vboxWinDrvInstParmsDestroy(PVBOXWINDRVINSTPARMS pParms)
546{
547 switch (pParms->enmMode)
548 {
549 case VBOXWINDRVINSTMODE_INSTALL:
550 case VBOXWINDRVINSTMODE_UNINSTALL:
551 {
552 RTUtf16Free(pParms->u.UnInstall.pwszModel);
553 pParms->u.UnInstall.pwszModel = NULL;
554 RTUtf16Free(pParms->u.UnInstall.pwszPnpId);
555 pParms->u.UnInstall.pwszPnpId = NULL;
556 RTUtf16Free(pParms->u.UnInstall.pwszSection);
557 pParms->u.UnInstall.pwszSection = NULL;
558 break;
559 }
560
561 case VBOXWINDRVINSTMODE_INSTALL_INFSECTION:
562 case VBOXWINDRVINSTMODE_UNINSTALL_INFSECTION:
563 {
564 RTUtf16Free(pParms->u.ExecuteInf.pwszSection);
565 pParms->u.ExecuteInf.pwszSection = NULL;
566 break;
567 }
568
569 case VBOXWINDRVINSTMODE_INVALID:
570 break;
571
572 default:
573 AssertFailed();
574 break;
575 }
576
577 RTUtf16Free(pParms->pwszInfFile);
578 pParms->pwszInfFile = NULL;
579}
580
581/**
582 * Structure for keeping callback data for vboxDrvInstExecuteInfFileCallback().
583 */
584typedef struct VBOXDRVINSTINFCALLBACKCTX
585{
586 /** Pointer to driver installer instance. */
587 PVBOXWINDRVINSTINTERNAL pThis;
588 /** Weak pointer to INF section being handled. */
589 PCRTUTF16 pwszSection;
590 /** User-supplied context pointer. */
591 void *pvSetupContext;
592} VBOXDRVINSTINFCALLBACKCTX;
593/** Pointer to structure for keeping callback data for vboxDrvInstExecuteInfFileCallback(). */
594typedef VBOXDRVINSTINFCALLBACKCTX *PVBOXDRVINSTINFCALLBACKCTX;
595
596/** Callback for SetupInstallFromInfSectionW(). */
597RT_C_DECLS_BEGIN /** @todo r=andy Not sure if we have something else to use. */
598static UINT WINAPI vboxDrvInstExecuteInfFileCallback(PVOID pvCtx,
599 UINT uNotification,
600 UINT_PTR Param1,
601 UINT_PTR Param2)
602{
603 RT_NOREF(Param2);
604
605 PVBOXDRVINSTINFCALLBACKCTX pCtx = (PVBOXDRVINSTINFCALLBACKCTX)pvCtx;
606
607 vboxWinDrvInstLogVerbose(pCtx->pThis, 4, "Got installation notification %#x", uNotification);
608
609 switch (uNotification)
610 {
611 case SPFILENOTIFY_NEEDMEDIA:
612 {
613 PSOURCE_MEDIA_W pSourceMedia = (PSOURCE_MEDIA_W)Param1;
614 vboxWinDrvInstLogInfo(pCtx->pThis, "Requesting installation media \"%ls\\%ls\"...",
615 pSourceMedia->SourcePath, pSourceMedia->SourceFile);
616 break;
617 }
618
619 case SPFILENOTIFY_STARTCOPY:
620 case SPFILENOTIFY_ENDCOPY:
621 {
622 PFILEPATHS_W pFilePaths = (PFILEPATHS_W)Param1;
623 vboxWinDrvInstLogInfo(pCtx->pThis, "%s copying \"%ls\" -> \"%ls\"",
624 uNotification == SPFILENOTIFY_STARTCOPY
625 ? "Started" : "Finished", pFilePaths->Source, pFilePaths->Target);
626 break;
627 }
628
629 case SPFILENOTIFY_RENAMEERROR:
630 case SPFILENOTIFY_DELETEERROR:
631 case SPFILENOTIFY_COPYERROR:
632 {
633 PFILEPATHS_W pFilePaths = (PFILEPATHS_W)Param1;
634 vboxWinDrvInstLogError(pCtx->pThis, "Rename/Delete/Copy error \"%ls\" -> \"%s\" (%#x)",
635 pFilePaths->Source, pFilePaths->Target, pFilePaths->Win32Error);
636 break;
637 }
638
639 case SPFILENOTIFY_TARGETNEWER:
640 vboxWinDrvInstLogInfo(pCtx->pThis, "A newer version of the specified file exists on the target");
641 break;
642
643 case SPFILENOTIFY_TARGETEXISTS:
644 vboxWinDrvInstLogInfo(pCtx->pThis, "A copy of the specified file already exists on the target");
645 break;
646
647 default:
648 break;
649 }
650
651 return SetupDefaultQueueCallbackW(pCtx->pvSetupContext, uNotification, Param1, Param2);;
652}
653RT_C_DECLS_END
654
655/**
656 * Generic function to for probing a list of well-known sections for [un]installation.
657 *
658 * Due to the nature of INF files this function tries different combinations of decorations (e.g. SectionName[.NTAMD64|.X86])
659 * and invokes the given callback for the first found section.
660 *
661 * @returns VBox status code.
662 * @param pCtx Windows driver installer context.
663 * @param hInf Handle of INF file.
664 * @param pwszSection Section to invoke for [un]installation.
665 * If NULL, the "DefaultInstall" / "DefaultUninstall" section will be tried.
666 * @param pfnCallback Callback to invoke for each found section.
667 */
668static int vboxWinDrvTryInfSectionEx(PVBOXWINDRVINSTINTERNAL pCtx, HINF hInf, PCRTUTF16 pwszSection,
669 PFNVBOXWINDRVINST_TRYINFSECTION_CALLBACK pfnCallback)
670{
671 if (pwszSection)
672 vboxWinDrvInstLogVerbose(pCtx, 1, "Trying section \"%ls\"", pwszSection);
673
674 /* Sorted by most likely-ness. */
675 PCRTUTF16 apwszTryInstallSections[] =
676 {
677 /* The more specific (using decorations), the better. Try these first. Might be NULL. */
678 pwszSection,
679 /* The Default[Un]Install sections apply to primitive (and legacy) drivers. */
680 pCtx->Parms.enmMode == VBOXWINDRVINSTMODE_INSTALL
681 ? L"DefaultInstall" : L"DefaultUninstall"
682 };
683
684 PCRTUTF16 apwszTryInstallDecorations[] =
685 {
686 /* No decoration. Try that first. */
687 L"",
688 /* Native architecture. */
689 L"" VBOXWINDRVINF_DOT_NT_NATIVE_ARCH_STR
690 };
691
692 int rc = VERR_NOT_FOUND;
693
694 for (size_t i = 0; i < RT_ELEMENTS(apwszTryInstallSections); i++)
695 {
696 PCRTUTF16 const pwszTrySection = apwszTryInstallSections[i];
697 if (!pwszTrySection)
698 continue;
699
700 for (size_t d = 0; d < RT_ELEMENTS(apwszTryInstallDecorations); d++)
701 {
702 RTUTF16 wszTrySection[64];
703 rc = RTUtf16Copy(wszTrySection, sizeof(wszTrySection), pwszTrySection);
704 AssertRCBreak(rc);
705 rc = RTUtf16Cat(wszTrySection, sizeof(wszTrySection), apwszTryInstallDecorations[d]);
706 AssertRCBreak(rc);
707
708 rc = pfnCallback(hInf, wszTrySection, pCtx /* pvCtx */);
709 if (RT_SUCCESS(rc))
710 break;
711
712 if (rc == VERR_FILE_NOT_FOUND) /* File gone already. */
713 {
714 rc = VINF_SUCCESS;
715 break;
716 }
717
718 if (rc != VERR_NOT_FOUND)
719 vboxWinDrvInstLogError(pCtx, "Trying INF section failed with %Rrc", rc);
720 }
721
722 if (RT_SUCCESS(rc)) /* Bail out if callback above succeeded. */
723 break;
724 }
725
726 if (rc == VERR_NOT_FOUND)
727 {
728 vboxWinDrvInstLogWarn(pCtx, "No matching sections to try found -- buggy driver?");
729 rc = VINF_SUCCESS;
730 }
731
732 return rc;
733}
734
735/**
736 * Generic function to for probing a list of well-known sections for [un]installation.
737 *
738 * Due to the nature of INF files this function tries different combinations of decorations (e.g. SectionName[.NTAMD64|.X86])
739 * and invokes the given callback for the first found section.
740 *
741 * @returns VBox status code.
742 * @param pCtx Windows driver installer context.
743 * @param pwszInfPathAbs Absolute path of INF file to use for [un]installation.
744 * @param pwszSection Section to invoke for [un]installation.
745 * If NULL, the "DefaultInstall" / "DefaultUninstall" section will be tried.
746 * @param pfnCallback Callback to invoke for each found section.
747 */
748static int vboxWinDrvTryInfSection(PVBOXWINDRVINSTINTERNAL pCtx, PCRTUTF16 pwszInfPathAbs, PCRTUTF16 pwszSection,
749 PFNVBOXWINDRVINST_TRYINFSECTION_CALLBACK pfnCallback)
750{
751 HINF hInf;
752 int rc = VBoxWinDrvInfOpen(pwszInfPathAbs, &hInf);
753 if (RT_FAILURE(rc))
754 {
755 vboxWinDrvInstLogError(pCtx, "Unable to open INF file: %Rrc\n", rc);
756 return rc;
757 }
758 vboxWinDrvInstLogVerbose(pCtx, 1, "INF file \"%ls\" opened", pwszInfPathAbs);
759
760 rc = vboxWinDrvTryInfSectionEx(pCtx, hInf, pwszSection, pfnCallback);
761
762 VBoxWinDrvInfClose(hInf);
763 vboxWinDrvInstLogVerbose(pCtx, 1, "INF file \"%ls\" closed", pwszInfPathAbs);
764
765 return rc;
766}
767
768/**
769 * Uninstalls a section of a given INF file.
770 *
771 * @returns VBox status code.
772 * @retval VERR_NOT_FOUND if the given section has not been found.
773 * @param pCtx Windows driver installer context.
774 * @param hInf Handle of INF file.
775 * @param pwszSection Section within INF file to uninstall.
776 * Can have a platform decoration (e.g. "Foobar.NTx86").
777 */
778static int vboxWinDrvUninstallInfSectionEx(PVBOXWINDRVINSTINTERNAL pCtx, HINF hInf, PCRTUTF16 pwszSection)
779{
780 AssertPtrReturn(pwszSection, VERR_INVALID_POINTER);
781
782 int rc = VINF_SUCCESS;
783
784 vboxWinDrvInstLogInfo(pCtx, "Uninstalling INF section \"%ls\" ...", pwszSection);
785
786 /*
787 * Uninstall services (if any).
788 */
789 RTUTF16 wszSection[64];
790 ssize_t const cwchSection = RTUtf16Printf(wszSection, RT_ELEMENTS(wszSection),
791 "%ls%s", pwszSection, ".Services");
792 if (cwchSection > 0)
793 {
794 /* We always want to be the first service tag in the group order list (if any). */
795 DWORD fFlags = SPSVCINST_TAGTOFRONT;
796 BOOL fRc = SetupInstallServicesFromInfSectionW(hInf, wszSection, fFlags);
797 if (!fRc)
798 {
799 DWORD const dwErr = GetLastError();
800 if (dwErr == ERROR_SECTION_NOT_FOUND)
801 {
802 vboxWinDrvInstLogVerbose(pCtx, 1, "INF section \"%ls\" not found", wszSection);
803 rc = VERR_NOT_FOUND;
804 }
805 else
806 {
807 rc = vboxWinDrvInstLogLastError(pCtx, "Could not uninstall INF services section \"%ls\"", wszSection);
808 if (rc == VERR_FILE_NOT_FOUND)
809 {
810 /* Hint: Getting VERR_FILE_NOT_FOUND here might mean that an old service entry still is dangling around.
811 * 'sc query <service name> won't show this, however.
812 * Use 'sc delete <service name>' to delete the leftover. */
813 vboxWinDrvInstLogError(pCtx,
814 "Hint: An old service (SCM) entry might be dangling around.\n"
815 "Try removing it via 'sc delete <service name>' and try again.");
816 }
817 }
818 }
819 else
820 vboxWinDrvInstLogInfo(pCtx, "Uninstalling INF services section \"%ls\" successful", wszSection);
821
822 }
823 else
824 {
825 vboxWinDrvInstLogError(pCtx, "Unable to build uninstallation section string");
826 rc = VERR_BUFFER_OVERFLOW;
827 }
828
829 return rc;
830}
831
832/**
833 * Installs a section of a given INF file.
834 *
835 * @returns VBox status code.
836 * @retval VERR_NOT_FOUND if the given section has not been found.
837 * @param pCtx Windows driver installer context.
838 * @param hInf Handle of INF file.
839 * @param pwszSection Section within INF file to install.
840 * Can have a platform decoration (e.g. "Foobar.NTx86").
841 */
842static int vboxWinDrvInstallInfSectionEx(PVBOXWINDRVINSTINTERNAL pCtx, HINF hInf, PCRTUTF16 pwszSection)
843{
844 AssertPtrReturn(pwszSection, VERR_INVALID_POINTER);
845
846 int rc = VINF_SUCCESS;
847
848 vboxWinDrvInstLogInfo(pCtx, "Installing INF section \"%ls\" ...", pwszSection);
849
850 VBOXDRVINSTINFCALLBACKCTX CallbackCtx;
851 RT_ZERO(CallbackCtx);
852 CallbackCtx.pThis = pCtx;
853 CallbackCtx.pwszSection = pwszSection;
854 CallbackCtx.pvSetupContext = SetupInitDefaultQueueCallback(NULL);
855
856 BOOL fRc = SetupInstallFromInfSectionW(NULL, // hWndOwner
857 hInf,
858 pwszSection,
859 SPINST_ALL, // Flags
860 NULL, // RelativeKeyRoot
861 NULL, // SourceRootPath
862 SP_COPY_NOSKIP
863 | SP_COPY_IN_USE_NEEDS_REBOOT,
864 vboxDrvInstExecuteInfFileCallback,
865 &CallbackCtx,
866 NULL, // DeviceInfoSet
867 NULL); // DeviceInfoData
868 if (fRc)
869 {
870 vboxWinDrvInstLogInfo(pCtx, "Installing INF section \"%ls\" successful", pwszSection);
871 }
872 else
873 {
874 DWORD const dwErr = GetLastError();
875 /* Seems like newer Windows OSes (seen on Win10) don't like undecorated sections with SetupInstallFromInfSectionW().
876 * So ignore this and continue. */
877 if (dwErr == ERROR_BADKEY)
878 {
879 vboxWinDrvInstLogVerbose(pCtx, 1, "Installing INF section \"%ls\" failed with %#x (%d), ignoring",
880 pwszSection, dwErr, dwErr);
881 }
882 else
883 rc = vboxWinDrvInstLogLastError(pCtx, "Installing INF section \"%ls\" failed", pwszSection);
884 }
885
886 /*
887 * Try install services.
888 */
889 RTUTF16 wszSection[64];
890 ssize_t const cwchSection = RTUtf16Printf(wszSection, RT_ELEMENTS(wszSection),
891 "%ls%ls%s", pwszSection, VBOXWINDRVINF_DECORATION_SEP_UTF16_STR, "Services");
892 if (cwchSection > 0)
893 {
894 /* We always want to be the first service tag in the group order list (if any). */
895 DWORD const fFlags = SPSVCINST_TAGTOFRONT;
896 fRc = SetupInstallServicesFromInfSectionW(hInf, wszSection, fFlags);
897 if (!fRc)
898 {
899 DWORD const dwErr = GetLastError();
900 if (dwErr == ERROR_SECTION_NOT_FOUND)
901 {
902 vboxWinDrvInstLogVerbose(pCtx, 1, "INF section \"%ls\" not found, skipping", wszSection);
903 rc = VERR_NOT_FOUND;
904 }
905 else if (dwErr == ERROR_SERVICE_MARKED_FOR_DELETE)
906 vboxWinDrvInstLogWarn(pCtx, "Service in INF section \"%ls\" already marked for deletion, skipping", wszSection);
907 else if (dwErr == ERROR_SERVICE_CANNOT_ACCEPT_CTRL)
908 vboxWinDrvInstLogWarn(pCtx, "Service in INF section \"%ls\" does not accept any control commands (probably in starting/stopping state), skipping", wszSection);
909 else
910 {
911 rc = vboxWinDrvInstLogLastError(pCtx, "Could not install INF services section \"%ls\"", wszSection);
912 if (rc == VERR_FILE_NOT_FOUND)
913 {
914 /* Hint: Getting VERR_FILE_NOT_FOUND here might mean that an old service entry still is dangling around.
915 * 'sc query <service name> won't show this, however.
916 * Use 'sc delete <service name>' to delete the leftover. */
917 vboxWinDrvInstLogError(pCtx, "An old service (SCM) entry might be dangling around.");
918 vboxWinDrvInstLogInfo (pCtx, "Try removing it via 'sc delete <service name>' and try again.");
919 }
920 }
921 }
922 else
923 vboxWinDrvInstLogInfo(pCtx, "Installing INF services section \"%ls\" successful", wszSection);
924
925 }
926 else
927 {
928 vboxWinDrvInstLogError(pCtx, "Unable to build section string");
929 rc = VERR_BUFFER_OVERFLOW;
930 }
931
932 if (CallbackCtx.pvSetupContext)
933 {
934 SetupTermDefaultQueueCallback(CallbackCtx.pvSetupContext);
935 CallbackCtx.pvSetupContext = NULL;
936 }
937
938 return rc;
939}
940
941/**
942 * Installs a section of a given INF file.
943 *
944 * Only supported for the VBOXWINDRVINSTMODE_INSTALL_INFSECTION + VBOXWINDRVINSTMODE_UNINSTALL_INFSECTION modes.
945 *
946 * @returns VBox status code.
947 * @retval VERR_NOT_FOUND if the given section has not been found.
948 * @param pCtx Windows driver installer context.
949 * @param pParms Windows driver installation parameters to use.
950 */
951static int vboxWinDrvInstallInfSection(PVBOXWINDRVINSTINTERNAL pCtx, PVBOXWINDRVINSTPARMS pParms)
952{
953 AssertReturn( pParms->enmMode == VBOXWINDRVINSTMODE_INSTALL_INFSECTION
954 || pParms->enmMode == VBOXWINDRVINSTMODE_UNINSTALL_INFSECTION, VERR_INVALID_PARAMETER);
955
956 HINF hInf;
957 int rc = VBoxWinDrvInfOpen(pParms->pwszInfFile, &hInf);
958 if (RT_FAILURE(rc))
959 {
960 vboxWinDrvInstLogError(pCtx, "Unable to open INF file: %Rrc\n", rc);
961 return rc;
962 }
963
964 vboxWinDrvInstLogVerbose(pCtx, 1, "INF file \"%ls\" opened", pParms->pwszInfFile);
965
966 rc = vboxWinDrvInstallInfSectionEx(pCtx, hInf, pParms->u.ExecuteInf.pwszSection);
967
968 VBoxWinDrvInfClose(hInf);
969 vboxWinDrvInstLogVerbose(pCtx, 1, "INF file \"%ls\" closed", pParms->pwszInfFile);
970
971 return rc;
972}
973
974/**
975 * Callback implementation for invoking a section for installation.
976 *
977 * @returns VBox status code.
978 * @param hInf Handle of INF file to use.
979 * @param pwszSection Section to invoke.
980 * @param pvCtx User-supplied pointer. Usually PVBOXWINDRVINSTINTERNAL.
981 */
982DECLCALLBACK(int) vboxWinDrvInstallTryInfSectionCallback(HINF hInf, PCRTUTF16 pwszSection, void *pvCtx)
983{
984 PVBOXWINDRVINSTINTERNAL pCtx = (PVBOXWINDRVINSTINTERNAL)pvCtx;
985
986 return vboxWinDrvInstallInfSectionEx(pCtx, hInf, pwszSection);
987}
988
989#ifdef RT_ARCH_X86
990/** Static pointer to the internal driver installer handle, used by vboxWinDrvInterceptedWinVerifyTrust(). */
991static PVBOXWINDRVINSTINTERNAL s_vboxWinDrvInterceptedWinVerifyTrustCtx = NULL;
992
993/**
994 * Interceptor WinVerifyTrust function for SetupApi.dll on Windows 2000, XP,
995 * W2K3 and XP64.
996 *
997 * This crudely modifies the driver verification request from a WHQL/logo driver
998 * check to a simple Authenticode check.
999 *
1000 * s_vboxWinDrvInterceptedWinVerifyTrustCtx must be set.
1001 */
1002static LONG WINAPI vboxWinDrvInterceptedWinVerifyTrust(HWND hwnd, GUID *pActionId, void *pvData)
1003{
1004 AssertPtrReturn(s_vboxWinDrvInterceptedWinVerifyTrustCtx, TRUST_E_SYSTEM_ERROR);
1005
1006 /*
1007 * Resolve the real WinVerifyTrust function.
1008 */
1009 static decltype(WinVerifyTrust) * volatile s_pfnRealWinVerifyTrust = NULL;
1010 decltype(WinVerifyTrust) *pfnRealWinVerifyTrust = s_pfnRealWinVerifyTrust;
1011 if (!pfnRealWinVerifyTrust)
1012 {
1013 HMODULE hmod = GetModuleHandleW(L"WINTRUST.DLL");
1014 if (!hmod)
1015 hmod = LoadLibraryW(L"WINTRUST.DLL");
1016 if (!hmod)
1017 {
1018 vboxWinDrvInstLogErrorIgn(s_vboxWinDrvInterceptedWinVerifyTrustCtx, "InterceptedWinVerifyTrust: Failed to load wintrust.dll");
1019 return TRUST_E_SYSTEM_ERROR;
1020 }
1021 pfnRealWinVerifyTrust = (decltype(WinVerifyTrust) *)GetProcAddress(hmod, "WinVerifyTrust");
1022 if (!pfnRealWinVerifyTrust)
1023 {
1024 vboxWinDrvInstLogErrorIgn(s_vboxWinDrvInterceptedWinVerifyTrustCtx, "InterceptedWinVerifyTrust: Failed to locate WinVerifyTrust in wintrust.dll");
1025 return TRUST_E_SYSTEM_ERROR;
1026 }
1027 s_pfnRealWinVerifyTrust = pfnRealWinVerifyTrust;
1028 }
1029
1030 /*
1031 * Modify the ID if appropriate.
1032 */
1033 static const GUID s_GuidDriverActionVerify = DRIVER_ACTION_VERIFY;
1034 static const GUID s_GuidActionGenericChainVerify = WINTRUST_ACTION_GENERIC_CHAIN_VERIFY;
1035 static const GUID s_GuidActionGenericVerify2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
1036 if (pActionId)
1037 {
1038 if (memcmp(pActionId, &s_GuidDriverActionVerify, sizeof(*pActionId)) == 0)
1039 {
1040 /** @todo don't apply to obvious NT components... */
1041 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, "DRIVER_ACTION_VERIFY: Changing it to WINTRUST_ACTION_GENERIC_VERIFY_V2");
1042 pActionId = (GUID *)&s_GuidActionGenericVerify2;
1043 }
1044 else if (memcmp(pActionId, &s_GuidActionGenericChainVerify, sizeof(*pActionId)) == 0)
1045 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, "WINTRUST_ACTION_GENERIC_CHAIN_VERIFY");
1046 else if (memcmp(pActionId, &s_GuidActionGenericVerify2, sizeof(*pActionId)) == 0)
1047 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, "WINTRUST_ACTION_GENERIC_VERIFY_V2");
1048 else
1049 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, "WINTRUST_ACTION_UNKNOWN");
1050 }
1051
1052 /*
1053 * Log the data.
1054 */
1055 if (pvData)
1056 {
1057 WINTRUST_DATA *pData = (WINTRUST_DATA *)pvData;
1058 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " cbStruct = %ld", pData->cbStruct);
1059# ifdef DEBUG
1060 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " dwUIChoice = %ld", pData->dwUIChoice);
1061 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " fdwRevocationChecks = %ld", pData->fdwRevocationChecks);
1062 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " dwStateAction = %ld", pData->dwStateAction);
1063 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " hWVTStateData = %p", (uintptr_t)pData->hWVTStateData);
1064# endif
1065 if (pData->cbStruct >= 7*sizeof(uint32_t))
1066 {
1067 switch (pData->dwUnionChoice)
1068 {
1069 case WTD_CHOICE_FILE:
1070 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pFile = %p", (uintptr_t)pData->pFile);
1071 if (RT_VALID_PTR(pData->pFile))
1072 {
1073 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pFile->cbStruct = %ld", pData->pFile->cbStruct);
1074# ifndef DEBUG
1075 if (pData->pFile->hFile)
1076# endif
1077 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pFile->hFile = %p", (uintptr_t)pData->pFile->hFile);
1078 if (RT_VALID_PTR(pData->pFile->pcwszFilePath))
1079 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pFile->pcwszFilePath = %ls", pData->pFile->pcwszFilePath);
1080# ifdef DEBUG
1081 else
1082 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pFile->pcwszFilePath = %ls", (uintptr_t)pData->pFile->pcwszFilePath);
1083 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pFile->pgKnownSubject = %p", (uintptr_t)pData->pFile->pgKnownSubject);
1084# endif
1085 }
1086 break;
1087
1088 case WTD_CHOICE_CATALOG:
1089 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pCatalog = %p", (uintptr_t)pData->pCatalog);
1090 if (RT_VALID_PTR(pData->pCatalog))
1091 {
1092 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pCat->cbStruct = %ld", pData->pCatalog->cbStruct);
1093# ifdef DEBUG
1094 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pCat->dwCatalogVersion = %ld", pData->pCatalog->dwCatalogVersion);
1095# endif
1096 if (RT_VALID_PTR(pData->pCatalog->pcwszCatalogFilePath))
1097 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, "pCat->pcwszCatalogFilePath = %ls", pData->pCatalog->pcwszCatalogFilePath);
1098# ifdef DEBUG
1099 else
1100 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, "pCat->pcwszCatalogFilePath = %ls", (uintptr_t)pData->pCatalog->pcwszCatalogFilePath);
1101# endif
1102 if (RT_VALID_PTR(pData->pCatalog->pcwszMemberTag))
1103 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pCat->pcwszMemberTag = %ls", pData->pCatalog->pcwszMemberTag);
1104# ifdef DEBUG
1105 else
1106 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pCat->pcwszMemberTag = %ls", (uintptr_t)pData->pCatalog->pcwszMemberTag);
1107# endif
1108 if (RT_VALID_PTR(pData->pCatalog->pcwszMemberFilePath))
1109 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pCat->pcwszMemberFilePath = %ls", pData->pCatalog->pcwszMemberFilePath);
1110# ifdef DEBUG
1111 else
1112 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pCat->pcwszMemberFilePath = %ls", (uintptr_t)pData->pCatalog->pcwszMemberFilePath);
1113# else
1114 if (pData->pCatalog->hMemberFile)
1115# endif
1116 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pCat->hMemberFile = %p", (uintptr_t)pData->pCatalog->hMemberFile);
1117# ifdef DEBUG
1118 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, "pCat->pbCalculatedFileHash = %p", (uintptr_t)pData->pCatalog->pbCalculatedFileHash);
1119 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, "pCat->cbCalculatedFileHash = %ld", pData->pCatalog->cbCalculatedFileHash);
1120 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pCat->pcCatalogContext = %p", (uintptr_t)pData->pCatalog->pcCatalogContext);
1121# endif
1122 }
1123 break;
1124
1125 case WTD_CHOICE_BLOB:
1126 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pBlob = %p\n", (uintptr_t)pData->pBlob);
1127 break;
1128
1129 case WTD_CHOICE_SIGNER:
1130 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pSgnr = %p", (uintptr_t)pData->pSgnr);
1131 break;
1132
1133 case WTD_CHOICE_CERT:
1134 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pCert = %p", (uintptr_t)pData->pCert);
1135 break;
1136
1137 default:
1138 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " dwUnionChoice = %ld", pData->dwUnionChoice);
1139 break;
1140 }
1141 }
1142 }
1143
1144 /*
1145 * Make the call.
1146 */
1147 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, "Calling WinVerifyTrust ...");
1148 LONG iRet = pfnRealWinVerifyTrust(hwnd, pActionId, pvData);
1149 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, "WinVerifyTrust returns %ld", iRet);
1150
1151 return iRet;
1152}
1153
1154/**
1155 * Installs an WinVerifyTrust interceptor in setupapi.dll on Windows 2000, XP,
1156 * W2K3 and XP64.
1157 *
1158 * This is a very crude hack to lower the WHQL check to just require a valid
1159 * Authenticode signature by intercepting the verification call.
1160 *
1161 * @returns VBox status code.
1162 * @param pCtx Windows driver installer context.
1163 */
1164static int vboxWinDrvInstallWinVerifyTrustInterceptorInSetupApi(PVBOXWINDRVINSTINTERNAL pCtx)
1165{
1166 /* Check the version: */
1167 OSVERSIONINFOW VerInfo = { sizeof(VerInfo) };
1168 GetVersionExW(&VerInfo);
1169 if (VerInfo.dwMajorVersion != 5)
1170 {
1171 vboxWinDrvInstLogVerbose(pCtx, 1, "OS not supported to intercept WinVerifyTrust, skipping");
1172 return VERR_NOT_SUPPORTED;
1173 }
1174
1175# define PRINT_ERROR_AND_RETURN(a_Msg, ...) \
1176 return vboxWinDrvInstLogErrorRetIgn(pCtx, VERR_NOT_SUPPORTED, a_Msg, __VA_ARGS__);
1177
1178 /* The the target module: */
1179 HMODULE const hModSetupApi = GetModuleHandleW(L"SETUPAPI.DLL");
1180 if (!hModSetupApi)
1181 {
1182 DWORD const dwLastErr = GetLastError();
1183 PRINT_ERROR_AND_RETURN("Failed to locate SETUPAPI.DLL in the process: %ld / %#x", dwLastErr, dwLastErr);
1184 }
1185
1186 /*
1187 * Find the delayed import table (at least that's how it's done in the RTM).
1188 */
1189 IMAGE_DOS_HEADER const *pDosHdr = (IMAGE_DOS_HEADER const *)hModSetupApi;
1190 IMAGE_NT_HEADERS const *pNtHdrs = (IMAGE_NT_HEADERS const *)( (uintptr_t)hModSetupApi
1191 + ( pDosHdr->e_magic == IMAGE_DOS_SIGNATURE
1192 ? pDosHdr->e_lfanew : 0));
1193
1194 if (pNtHdrs->Signature != IMAGE_NT_SIGNATURE)
1195 PRINT_ERROR_AND_RETURN("Failed to parse SETUPAPI.DLL for WinVerifyTrust interception: #1");
1196 if (pNtHdrs->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
1197 PRINT_ERROR_AND_RETURN("Failed to parse SETUPAPI.DLL for WinVerifyTrust interception: #2");
1198 if (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT)
1199 PRINT_ERROR_AND_RETURN("Failed to parse SETUPAPI.DLL for WinVerifyTrust interception: #3");
1200
1201 uint32_t const cbDir = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size;
1202 if (cbDir < sizeof(IMAGE_DELAYLOAD_DESCRIPTOR))
1203 PRINT_ERROR_AND_RETURN("Failed to parse SETUPAPI.DLL for WinVerifyTrust interception: #4");
1204 uint32_t const cbImages = pNtHdrs->OptionalHeader.SizeOfImage;
1205 if (cbDir >= cbImages)
1206 PRINT_ERROR_AND_RETURN("Failed to parse SETUPAPI.DLL for WinVerifyTrust interception: #5");
1207 uint32_t const offDir = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress;
1208 if (offDir > cbImages - cbDir)
1209 PRINT_ERROR_AND_RETURN("Failed to parse SETUPAPI.DLL for WinVerifyTrust interception: #6");
1210
1211 /*
1212 * Scan the entries looking for wintrust.dll.
1213 */
1214 IMAGE_DELAYLOAD_DESCRIPTOR const * const paEntries = (IMAGE_DELAYLOAD_DESCRIPTOR const *)((uintptr_t)hModSetupApi + offDir);
1215 uint32_t const cEntries = cbDir / sizeof(paEntries[0]);
1216 for (uint32_t iImp = 0; iImp < cEntries; iImp++)
1217 {
1218 const char * const pchRva2Ptr = paEntries[iImp].Attributes.RvaBased ? (const char *)hModSetupApi : (const char *)0;
1219 const char * const pszDllName = &pchRva2Ptr[paEntries[iImp].DllNameRVA];
1220 if (RTStrICmpAscii(pszDllName, "WINTRUST.DLL") == 0)
1221 {
1222 /*
1223 * Scan the symbol names.
1224 */
1225 //uint32_t const cbHdrs = pNtHdrs->OptionalHeader.SizeOfHeaders;
1226 uint32_t * const pauNameRvas = (uint32_t *)&pchRva2Ptr[paEntries[iImp].ImportNameTableRVA];
1227 uintptr_t * const paIat = (uintptr_t *)&pchRva2Ptr[paEntries[iImp].ImportAddressTableRVA];
1228 for (uint32_t iSym = 0; pauNameRvas[iSym] != NULL; iSym++)
1229 {
1230 IMAGE_IMPORT_BY_NAME const * const pName = (IMAGE_IMPORT_BY_NAME const *)&pchRva2Ptr[pauNameRvas[iSym]];
1231 if (RTStrCmp(pName->Name, "WinVerifyTrust") == 0)
1232 {
1233 vboxWinDrvInstLogVerbose(pCtx, 1, "Intercepting WinVerifyTrust for SETUPAPI.DLL (old: %p)", paIat[iSym]);
1234 paIat[iSym] = (uintptr_t)vboxWinDrvInterceptedWinVerifyTrust;
1235 return 0;
1236 }
1237 }
1238 PRINT_ERROR_AND_RETURN("Failed to parse SETUPAPI.DLL for WinVerifyTrust interception: #9");
1239 }
1240 }
1241 PRINT_ERROR_AND_RETURN("Failed to parse SETUPAPI.DLL for WinVerifyTrust interception: #10");
1242
1243# undef PRINT_ERROR_AND_RETURN
1244}
1245#endif /* RT_ARCH_X86 */
1246
1247/**
1248 * Performs the actual driver installation.
1249 *
1250 * @returns VBox status code.
1251 * @param pCtx Windows driver installer context.
1252 * @param pParms Windows driver installation parameters to use.
1253 */
1254static int vboxWinDrvInstallPerform(PVBOXWINDRVINSTINTERNAL pCtx, PVBOXWINDRVINSTPARMS pParms)
1255{
1256 int rc = vboxWinDrvParmsDetermine(pCtx, pParms, false /* fForce */);
1257 if (RT_FAILURE(rc))
1258 return rc;
1259
1260 switch (pParms->enmMode)
1261 {
1262 case VBOXWINDRVINSTMODE_INSTALL:
1263 {
1264 BOOL fRc = FALSE;
1265 BOOL fReboot = FALSE;
1266
1267#ifdef RT_ARCH_X86
1268 s_vboxWinDrvInterceptedWinVerifyTrustCtx = pCtx; /* Hand over the driver installer context. */
1269 vboxWinDrvInstallWinVerifyTrustInterceptorInSetupApi(pCtx);
1270#endif
1271 /*
1272 * Pre-install driver.
1273 */
1274 DWORD dwInstallFlags = 0;
1275 if (pCtx->uOsVer >= RTSYSTEM_MAKE_NT_VERSION(6, 0, 0)) /* for Vista / 2008 Server and up. */
1276 {
1277 if (pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_FORCE)
1278 dwInstallFlags |= DIIRFLAG_FORCE_INF;
1279
1280 vboxWinDrvInstLogVerbose(pCtx, 1, "Using g_pfnDiInstallDriverW(), dwInstallFlags=%#x", dwInstallFlags);
1281
1282 if (!(pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_DRYRUN))
1283 fRc = g_pfnDiInstallDriverW(NULL /* hWndParent */, pParms->pwszInfFile, dwInstallFlags, &fReboot);
1284 else
1285 fRc = TRUE;
1286 if (!fRc)
1287 {
1288 DWORD const dwErr = GetLastError();
1289
1290 /*
1291 * Work around an error code wich only appears on old(er) Windows Server editions (e.g. 2012 R2 or 2016)
1292 * where SetupAPI tells "unable to mark devices that match new inf", which ultimately results in
1293 * ERROR_LINE_NOT_FOUND. This probably is because of primitive drivers which don't have a PnP ID set in
1294 * the INF file.
1295 *
1296 * pnputil.exe also gives the same error in the SetupAPI log when handling the very same INF file.
1297 *
1298 * So skip this error and pretend everything is fine. */
1299 if (dwErr == ERROR_LINE_NOT_FOUND)
1300 fRc = true;
1301
1302 /*
1303 * Work around an error which occurs on Windows Vista, where DiInstallDriverW() can't handle
1304 * primitive drivers (i.e. [Manufacturer] section is missing). So try installing the detected
1305 * INF section in the next block below.
1306 */
1307 if (dwErr == ERROR_WRONG_INF_TYPE)
1308 fRc = true;
1309
1310 /* For anything else we want to get notified that something isn't working. */
1311 if (!fRc)
1312 {
1313 switch (dwErr)
1314 {
1315 case ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED:
1316 {
1317 /* For silent installs give a clue why this might have failed. */
1318 if (pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_SILENT)
1319 vboxWinDrvInstLogWarn(pCtx, "Silent installation was selected, but required certificates "
1320 "were not pre-installed into the Windows drvier store, so "
1321 "the installation will be rejected automatically");
1322 RT_FALL_THROUGH();
1323 }
1324
1325 default:
1326 rc = vboxWinDrvInstLogLastError(pCtx, "DiInstallDriverW() failed");
1327 break;
1328 }
1329 }
1330 }
1331
1332 if (fRc)
1333 rc = vboxWinDrvTryInfSection(pCtx,
1334 pParms->pwszInfFile, pParms->u.UnInstall.pwszSection,
1335 vboxWinDrvInstallTryInfSectionCallback);
1336 }
1337 else /* For Windows 2000 and below. */
1338 {
1339 if (pParms->u.UnInstall.pwszPnpId)
1340 {
1341 if (pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_SILENT)
1342 {
1343 /* Using INSTALLFLAG_NONINTERACTIVE will trigger an invalid parameter error on Windows 2000. */
1344 if (pCtx->uOsVer >= RTSYSTEM_MAKE_NT_VERSION(5, 1, 0))
1345 dwInstallFlags |= INSTALLFLAG_NONINTERACTIVE;
1346 else
1347 vboxWinDrvInstLogWarn(pCtx, "This version of Windows does not support silent installs");
1348 }
1349
1350 if (pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_FORCE)
1351 dwInstallFlags |= INSTALLFLAG_FORCE;
1352
1353 vboxWinDrvInstLogVerbose(pCtx, 4, "Using g_pfnUpdateDriverForPlugAndPlayDevicesW(), pwszPnpId=%ls, pwszInfFile=%ls, dwInstallFlags=%#x",
1354 pParms->u.UnInstall.pwszPnpId, pParms->pwszInfFile, dwInstallFlags);
1355
1356 if (!(pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_DRYRUN))
1357 fRc = g_pfnUpdateDriverForPlugAndPlayDevicesW(NULL /* hWndParent */,
1358 pParms->u.UnInstall.pwszPnpId,
1359 pParms->pwszInfFile, dwInstallFlags, &fReboot);
1360 else
1361 fRc = TRUE;
1362
1363 if (!fRc)
1364 {
1365 DWORD const dwErr = GetLastError();
1366 switch (dwErr)
1367 {
1368 case ERROR_NO_SUCH_DEVINST:
1369 {
1370 vboxWinDrvInstLogInfo(pCtx, "Device (\"%ls\") not found (yet), pre-installing driver ...",
1371 pParms->u.UnInstall.pwszPnpId);
1372 break;
1373 }
1374
1375 case ERROR_NO_DRIVER_SELECTED:
1376 {
1377 vboxWinDrvInstLogWarn(pCtx, "Not able to select a driver from the given INF, using given model");
1378 break;
1379 }
1380
1381 case ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED:
1382 {
1383 /* For silent installs give a clue why this might have failed. */
1384 if (pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_SILENT)
1385 vboxWinDrvInstLogWarn(pCtx, "Silent installation was selected, but required certificates "
1386 "were not pre-installed into the Windows drvier store, so "
1387 "the installation will be rejected automatically");
1388 RT_FALL_THROUGH();
1389 }
1390
1391 default:
1392 rc = vboxWinDrvInstLogLastError(pCtx, "Installation(UpdateDriverForPlugAndPlayDevicesW) failed");
1393 break;
1394 }
1395 }
1396 }
1397
1398 if (RT_FAILURE(rc))
1399 break;
1400
1401 /*
1402 * Pre-install driver.
1403 */
1404 RTUTF16 wszInfFileAbs[RTPATH_MAX] = { 0 };
1405 LPWSTR pwszInfFile = NULL;
1406 if ( GetFullPathNameW(pParms->pwszInfFile, RT_ELEMENTS(wszInfFileAbs), wszInfFileAbs, &pwszInfFile)
1407 && pwszInfFile)
1408 {
1409 RTUTF16 wszSrcPathAbs[RTPATH_MAX] = { 0 };
1410 rc = RTUtf16CopyEx(wszSrcPathAbs, RT_ELEMENTS(wszSrcPathAbs), wszInfFileAbs,
1411 RTUtf16Len(wszInfFileAbs) - RTUtf16Len(pwszInfFile));
1412 if (RT_SUCCESS(rc))
1413 {
1414 RTUTF16 wszDstPathAbs[RTPATH_MAX] = { 0 };
1415 if (!(pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_DRYRUN))
1416 fRc = g_pfnSetupCopyOEMInfW(wszInfFileAbs, wszSrcPathAbs, SPOST_PATH, 0,
1417 wszDstPathAbs, RT_ELEMENTS(wszDstPathAbs), NULL, NULL);
1418 else
1419 fRc = TRUE;
1420
1421 vboxWinDrvInstLogVerbose(pCtx, 1, " INF file: %ls", wszInfFileAbs);
1422 vboxWinDrvInstLogVerbose(pCtx, 1, "Source path: %ls", wszSrcPathAbs);
1423 vboxWinDrvInstLogVerbose(pCtx, 1, " Dest path: %ls", wszDstPathAbs);
1424
1425 if (fRc)
1426 vboxWinDrvInstLogInfo(pCtx, "Copying OEM INF successful");
1427 else
1428 rc = vboxWinDrvInstLogLastError(pCtx, "Installation(SetupCopyOEMInfW) failed");
1429 }
1430 }
1431 else
1432 rc = vboxWinDrvInstLogLastError(pCtx, "GetFullPathNameW() failed");
1433
1434 if (RT_SUCCESS(rc))
1435 rc = vboxWinDrvTryInfSection(pCtx,
1436 pParms->pwszInfFile, pParms->u.UnInstall.pwszSection,
1437 vboxWinDrvInstallTryInfSectionCallback);
1438 }
1439
1440 if (RT_FAILURE(rc))
1441 break;
1442
1443 pCtx->fReboot = RT_BOOL(fReboot);
1444 break;
1445 }
1446
1447 case VBOXWINDRVINSTMODE_INSTALL_INFSECTION:
1448 {
1449 rc = vboxWinDrvInstallInfSection(pCtx, pParms);
1450 break;
1451 }
1452
1453 default:
1454 break;
1455 }
1456
1457 return rc;
1458}
1459
1460/**
1461 * Returns whether the given (in)installation parameters are valid or not.
1462 *
1463 * @returns \c true if valid, \c false if not.
1464 * @param pCtx Windows driver installer context.
1465 * @param pParms Windows driver (un)installation parameters to validate.
1466 */
1467static bool vboxWinDrvParmsAreValid(PVBOXWINDRVINSTINTERNAL pCtx, PVBOXWINDRVINSTPARMS pParms)
1468{
1469 if (pParms->u.UnInstall.pwszPnpId)
1470 {
1471 size_t const cchPnpId = RTUtf16Len(pParms->u.UnInstall.pwszPnpId);
1472 if ( !cchPnpId
1473 || cchPnpId > MAX_DEVICE_ID_LEN)
1474 {
1475 vboxWinDrvInstLogVerbose(pCtx, 1, "PnP ID not specified explicitly or invalid");
1476 return false;
1477 }
1478 }
1479
1480 return true;
1481}
1482
1483/**
1484 * Determines (un)installation parameters from a given set of parameters, logged.
1485 *
1486 * @returns VBox status code.
1487 * @retval VERR_INVALID_PARAMETER if no valid parameters could be determined.
1488 * @param pCtx Windows driver installer context.
1489 * @param pParms Windows driver installation parameters to determine for.
1490 * @param fForce Whether to overwrite already set parameters or not.
1491 *
1492 * @note Only can deal with the first model / PnP ID found for now.
1493 */
1494static int vboxWinDrvParmsDetermine(PVBOXWINDRVINSTINTERNAL pCtx, PVBOXWINDRVINSTPARMS pParms, bool fForce)
1495{
1496 int rc;
1497
1498 /* INF file given? */
1499 if (pParms->pwszInfFile)
1500 {
1501 HINF hInf;
1502 rc = VBoxWinDrvInfOpen(pParms->pwszInfFile, &hInf);
1503 if (RT_SUCCESS(rc))
1504 {
1505 /* Get the INF type first. */
1506 PRTUTF16 pwszMainSection;
1507 VBOXWINDRVINFTYPE enmType = VBoxWinDrvInfGetTypeEx(hInf, &pwszMainSection);
1508 if (enmType != VBOXWINDRVINFTYPE_INVALID)
1509 {
1510 vboxWinDrvInstLogVerbose(pCtx, 1, "INF type is: %s",
1511 enmType == VBOXWINDRVINFTYPE_NORMAL
1512 ? "Normal" : "Primitive");
1513 /*
1514 * Determine model.
1515 */
1516 if ( !pParms->u.UnInstall.pwszModel
1517 || fForce)
1518 {
1519 vboxWinDrvInstLogVerbose(pCtx, 1, "Determining model ...");
1520 if (fForce)
1521 {
1522 RTUtf16Free(pParms->u.UnInstall.pwszModel);
1523 pParms->u.UnInstall.pwszModel = NULL;
1524 }
1525 rc = VBoxWinDrvInfQueryFirstModel(hInf, pwszMainSection, &pParms->u.UnInstall.pwszModel);
1526 if (RT_SUCCESS(rc))
1527 {
1528 RTUtf16Free(pParms->u.UnInstall.pwszSection);
1529 pParms->u.UnInstall.pwszSection = NULL;
1530
1531 /* Now that we have determined the model, try if there is a section in the INF file for this model. */
1532 rc = VBoxWinDrvInfQueryInstallSection(hInf, pParms->u.UnInstall.pwszModel,
1533 &pParms->u.UnInstall.pwszSection);
1534 if (RT_FAILURE(rc))
1535 {
1536 switch (enmType)
1537 {
1538 case VBOXWINDRVINFTYPE_NORMAL:
1539 {
1540 vboxWinDrvInstLogError(pCtx, "No section to install found, can't continue");
1541 break;
1542 }
1543
1544 case VBOXWINDRVINFTYPE_PRIMITIVE:
1545 {
1546 /* If for the given model there is no install section, set the section to main section
1547 * we got when we determined the INF type.
1548 *
1549 * This will be mostly the case for primitive drivers. */
1550 if (rc == VERR_NOT_FOUND)
1551 {
1552 pParms->u.UnInstall.pwszSection = RTUtf16Dup(pwszMainSection);
1553 if (pParms->u.UnInstall.pwszSection)
1554 {
1555 rc = VINF_SUCCESS;
1556 }
1557 else
1558 rc = VERR_NO_MEMORY;
1559 }
1560 break;
1561 }
1562
1563 default:
1564 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
1565 break;
1566 }
1567 }
1568 }
1569 else
1570 {
1571 switch (rc)
1572 {
1573 case VERR_PLATFORM_ARCH_NOT_SUPPORTED:
1574 {
1575 vboxWinDrvInstLogError(pCtx, "Model found, but platform is not supported");
1576 break;
1577 }
1578
1579 case VERR_NOT_FOUND:
1580 {
1581 vboxWinDrvInstLogError(pCtx, "No model found to install found -- buggy driver?");
1582 break;
1583 }
1584
1585 default:
1586 break;
1587 }
1588 }
1589 }
1590
1591 /*
1592 * Determine PnP ID.
1593 *
1594 * Only available in non-primitive drivers.
1595 */
1596 if ( enmType == VBOXWINDRVINFTYPE_NORMAL
1597 && ( !pParms->u.UnInstall.pwszPnpId
1598 || fForce))
1599 {
1600 if (pParms->u.UnInstall.pwszModel)
1601 {
1602 vboxWinDrvInstLogVerbose(pCtx, 1, "Determining PnP ID ...");
1603 if (fForce)
1604 {
1605 RTUtf16Free(pParms->u.UnInstall.pwszPnpId);
1606 pParms->u.UnInstall.pwszPnpId = NULL;
1607 }
1608 /* ignore rc */ VBoxWinDrvInfQueryFirstPnPId(hInf,
1609 pParms->u.UnInstall.pwszModel, &pParms->u.UnInstall.pwszPnpId);
1610 }
1611 else
1612 vboxWinDrvInstLogVerbose(pCtx, 1, "No first model found/set, skipping determining PnP ID");
1613 }
1614
1615 RTUtf16Free(pwszMainSection);
1616 }
1617 else
1618 {
1619 vboxWinDrvInstLogError(pCtx, "INF file is invalid");
1620 rc = VERR_INVALID_PARAMETER;
1621 }
1622
1623 VBoxWinDrvInfClose(hInf);
1624 }
1625 }
1626 /* No INF file given but either the model or the PnP ID? */
1627 else if ( pParms->u.UnInstall.pwszModel
1628 || pParms->u.UnInstall.pwszPnpId)
1629 {
1630 /* Nothing to do for us here. */
1631 rc = VINF_SUCCESS;
1632 }
1633 else
1634 {
1635 vboxWinDrvInstLogError(pCtx, "Neither INF file nor model/PnP ID given; can't continue");
1636 rc = VERR_INVALID_PARAMETER;
1637 }
1638
1639 if (RT_SUCCESS(rc))
1640 {
1641 vboxWinDrvInstLogVerbose(pCtx, 1, "Determined parameters:");
1642 vboxWinDrvInstLogVerbose(pCtx, 1, "\tINF File: %ls",
1643 pParms->pwszInfFile ? pParms->pwszInfFile : L"<None>");
1644 vboxWinDrvInstLogVerbose(pCtx, 1, "\t Model: %ls",
1645 pParms->u.UnInstall.pwszModel ? pParms->u.UnInstall.pwszModel : L"<None>");
1646 vboxWinDrvInstLogVerbose(pCtx, 1, "\t PnP ID: %ls",
1647 pParms->u.UnInstall.pwszPnpId ? pParms->u.UnInstall.pwszPnpId : L"<None>");
1648 vboxWinDrvInstLogVerbose(pCtx, 1, "\t Section: %ls",
1649 pParms->u.UnInstall.pwszSection ? pParms->u.UnInstall.pwszSection : L"<None>");
1650 }
1651
1652 return rc;
1653}
1654
1655/**
1656 * Queries OEM INF files from the driver store.
1657 *
1658 * @returns VBox status code.
1659 * @param pCtx Windows driver installer context.
1660 * @param pParms Windows driver installation parameters to use.
1661 * @param ppList Where to return the list of found Windows driver store entries on success.
1662 * Needs to be destroyed with VBoxWinDrvStoreListFree().
1663 */
1664static int vboxWinDrvQueryFromDriverStore(PVBOXWINDRVINSTINTERNAL pCtx, PVBOXWINDRVINSTPARMS pParms,
1665 PVBOXWINDRVSTORELIST *ppList)
1666{
1667 int rc = vboxWinDrvParmsDetermine(pCtx, pParms, false /* fForce */);
1668 if (RT_SUCCESS(rc))
1669 {
1670 PVBOXWINDRVSTORELIST pList = NULL;
1671 char *pszNeedle = NULL;
1672
1673 if (pParms->u.UnInstall.pwszPnpId)
1674 {
1675 rc = RTUtf16ToUtf8(pParms->u.UnInstall.pwszPnpId, &pszNeedle);
1676 if (RT_SUCCESS(rc))
1677 rc = VBoxWinDrvStoreQueryByPnpId(pCtx->pStore, pszNeedle, &pList);
1678 }
1679 else if (pParms->u.UnInstall.pwszModel)
1680 {
1681 rc = RTUtf16ToUtf8(pParms->u.UnInstall.pwszModel, &pszNeedle);
1682 if (RT_SUCCESS(rc))
1683 rc = VBoxWinDrvStoreQueryByModelName(pCtx->pStore, pszNeedle, &pList);
1684 }
1685 else if (pParms->pwszInfFile)
1686 {
1687 rc = VERR_NOT_IMPLEMENTED;
1688 }
1689
1690 RTStrFree(pszNeedle);
1691 pszNeedle = NULL;
1692
1693 if (RT_SUCCESS(rc))
1694 {
1695 *ppList = pList;
1696 }
1697 else
1698 VBoxWinDrvStoreListFree(pList);
1699 }
1700
1701 return rc;
1702}
1703
1704/**
1705 * Callback implementation for invoking a section for uninstallation.
1706 *
1707 * @returns VBox status code.
1708 * @param hInf Handle to INF file.
1709 * @param pwszSection Section to invoke.
1710 * @param pvCtx User-supplied pointer. Usually PVBOXWINDRVINSTINTERNAL.
1711 */
1712DECLCALLBACK(int) vboxWinDrvUninstallTryInfSectionCallback(HINF hInf, PCRTUTF16 pwszSection, void *pvCtx)
1713{
1714 PVBOXWINDRVINSTINTERNAL pCtx = (PVBOXWINDRVINSTINTERNAL)pvCtx;
1715
1716 return vboxWinDrvUninstallInfSectionEx(pCtx, hInf, pwszSection);
1717}
1718
1719/**
1720 * Removes OEM INF files from the driver store.
1721 *
1722 * @returns VBox status code.
1723 * @param pCtx Windows driver installer context.
1724 * @param pParms Windows driver uninstallation parameters to use.
1725 * @param pList Driver store list with OEM INF entries to remove.
1726 */
1727static int vboxWinDrvUninstallFromDriverStore(PVBOXWINDRVINSTINTERNAL pCtx,
1728 PVBOXWINDRVINSTPARMS pParms, PVBOXWINDRVSTORELIST pList)
1729{
1730
1731 int rc = VINF_SUCCESS;
1732
1733 const char *pszDrvStorePath = VBoxWinDrvStoreBackendGetLocation(pCtx->pStore);
1734
1735 vboxWinDrvInstLogInfo(pCtx, "Uninstalling %zu matching entr%s", pList->cEntries, pList->cEntries == 1 ? "y" : "ies");
1736 PVBOXWINDRVSTOREENTRY pCur;
1737 RTListForEach(&pList->List, pCur, VBOXWINDRVSTOREENTRY, Node)
1738 {
1739 bool fRc = FALSE;
1740
1741 /*
1742 * Running the uninstalling section(s) first before removing the driver from the driver store below.
1743 */
1744 RTUTF16 wszInfPathAbs[RTPATH_MAX];
1745 ssize_t const cwchInfPathAbs = RTUtf16Printf(wszInfPathAbs, RT_ELEMENTS(wszInfPathAbs),
1746 "%s\\%ls", pszDrvStorePath, pCur->wszInfFile);
1747 AssertBreakStmt(cwchInfPathAbs > 0, rc = VERR_BUFFER_OVERFLOW);
1748
1749 vboxWinDrvInstLogInfo(pCtx, "Uninstalling %ls (%ls)", pCur->wszModel, wszInfPathAbs);
1750
1751 /* Only calltry calling the "DefaultUninstall" section here, as there aren't any other section(s)
1752 * to handle for uninstalling a driver via INF files. */
1753 /* rc ignored, keep going */ vboxWinDrvTryInfSection(pCtx, wszInfPathAbs, NULL /* DefaultUninstall */,
1754 vboxWinDrvUninstallTryInfSectionCallback);
1755
1756 /*
1757 * Remove the driver from the driver store.
1758 */
1759 if (g_pfnDiUninstallDriverW)
1760 {
1761 vboxWinDrvInstLogVerbose(pCtx, 1, "Using DiUninstallDriverW()");
1762
1763 BOOL fReboot = FALSE;
1764 if (!(pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_DRYRUN))
1765 {
1766 /* Takes the fully qualified path of the INF file to uninstall. */
1767 fRc = g_pfnDiUninstallDriverW(NULL /* hWndParent */, wszInfPathAbs, 0 /* Flags */, &fReboot);
1768 }
1769 else
1770 fRc = TRUE;
1771 if (fRc)
1772 pCtx->fReboot = RT_BOOL(fReboot);
1773 else
1774 {
1775 /* Not fatal, try next block. */
1776 DWORD const dwErr = GetLastError();
1777 vboxWinDrvInstLogVerbose(pCtx, 1, "DiUninstallDriverW() failed with %#x (%d)", dwErr, dwErr);
1778 }
1779 }
1780
1781 /* Not (yet) successful? Try harder using an older API. */
1782 if ( !fRc
1783 && g_pfnSetupUninstallOEMInfW)
1784 {
1785 vboxWinDrvInstLogVerbose(pCtx, 1, "Using SetupUninstallOEMInfW()");
1786
1787 if (!(pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_DRYRUN))
1788 {
1789 DWORD dwUninstallFlags = 0;
1790 if (pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_FORCE)
1791 dwUninstallFlags |= SUOI_FORCEDELETE;
1792
1793 /* Takes the oemXXX.inf file (without a path), as found in the Windows INF directory. */
1794 fRc = g_pfnSetupUninstallOEMInfW(pCur->wszInfFile, dwUninstallFlags, NULL /* pReserved */);
1795 }
1796 }
1797
1798 int rc2 = VINF_SUCCESS;
1799
1800 if (fRc)
1801 vboxWinDrvInstLogInfo(pCtx, "Uninstalling OEM INF \"%ls\" successful", wszInfPathAbs);
1802 else
1803 {
1804 DWORD const dwErr = GetLastError();
1805 if (dwErr == ERROR_INF_IN_USE_BY_DEVICES)
1806 vboxWinDrvInstLogError(pCtx, "Unable to uninstall OEM INF \"%ls\": Driver still in use by device", wszInfPathAbs);
1807 else
1808 rc2 = vboxWinDrvInstLogLastError(pCtx, "Uninstalling OEM INF \"%ls\" failed", wszInfPathAbs);
1809 }
1810
1811 /* If anything failed above, try removing stuff ourselves as good as we can. */
1812 if (RT_FAILURE(rc2))
1813 /* rc ignored, keep going */ vboxWinDrvTryInfSection(pCtx, wszInfPathAbs, pCur->wszModel,
1814 vboxWinDrvUninstallTryInfSectionCallback);
1815
1816 if (RT_SUCCESS(rc)) /* Keep first error if already set. */
1817 rc = rc2;
1818
1819 /* Keep going. */
1820 }
1821
1822 return rc;
1823}
1824
1825/**
1826 * Performs the actual driver uninstallation.
1827 *
1828 * @returns VBox status code.
1829 * @param pCtx Windows driver installer context.
1830 * @param pParms Windows driver installation parameters to use.
1831 */
1832static int vboxWinDrvUninstallPerform(PVBOXWINDRVINSTINTERNAL pCtx, PVBOXWINDRVINSTPARMS pParms)
1833{
1834 int rc;
1835 switch (pParms->enmMode)
1836 {
1837 case VBOXWINDRVINSTMODE_UNINSTALL:
1838 {
1839 PVBOXWINDRVSTORELIST pList = NULL;
1840 rc = vboxWinDrvQueryFromDriverStore(pCtx, pParms, &pList);
1841 if (RT_SUCCESS(rc))
1842 {
1843 rc = vboxWinDrvUninstallFromDriverStore(pCtx, pParms, pList);
1844
1845 VBoxWinDrvStoreListFree(pList);
1846 pList = NULL;
1847 }
1848 break;
1849 }
1850
1851 case VBOXWINDRVINSTMODE_UNINSTALL_INFSECTION:
1852 {
1853 rc = vboxWinDrvInstallInfSection(pCtx, pParms);
1854 break;
1855 }
1856
1857 default:
1858 rc = VINF_SUCCESS;
1859 break;
1860 }
1861
1862 return rc;
1863}
1864
1865/**
1866 * Main function to perform the actual driver [un]installation.
1867 *
1868 * @returns VBox status code.
1869 * @param pCtx Windows driver installer context.
1870 * @param pParms Windows driver installation parameters to use.
1871 */
1872static int vboxWinDrvInstMain(PVBOXWINDRVINSTINTERNAL pCtx, PVBOXWINDRVINSTPARMS pParms)
1873{
1874 /* Note: Other parameters might be optional, depending on the mode. */
1875 AssertReturn(!(pParms->fFlags & ~VBOX_WIN_DRIVERINSTALL_F_VALID_MASK), VERR_INVALID_PARAMETER);
1876
1877 bool const fInstall = pParms->enmMode == VBOXWINDRVINSTMODE_INSTALL
1878 || pParms->enmMode == VBOXWINDRVINSTMODE_INSTALL_INFSECTION;
1879
1880 if (pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_DRYRUN)
1881 vboxWinDrvInstLogWarn(pCtx, "Dry-run mode active -- no installation performed!");
1882
1883 const char * const pszLogAction = fInstall ? "Installing" : "Uninstalling";
1884 if (pParms->pwszInfFile)
1885 vboxWinDrvInstLogInfo(pCtx, "%s driver \"%ls\" ... ", pszLogAction, pParms->pwszInfFile);
1886 else if (pParms->u.UnInstall.pwszModel)
1887 vboxWinDrvInstLogInfo(pCtx, "%s driver model \"%ls\" ... ", pszLogAction, pParms->u.UnInstall.pwszModel);
1888 else if (pParms->u.UnInstall.pwszPnpId)
1889 vboxWinDrvInstLogInfo(pCtx, "%s PnP ID \"%ls\" ... ", pszLogAction, pParms->u.UnInstall.pwszPnpId);
1890
1891 if ( pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_SILENT
1892 && g_pfnSetupSetNonInteractiveMode)
1893 {
1894 vboxWinDrvInstLogInfo(pCtx, "Setting non-interactive mode ...");
1895 if (!(pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_DRYRUN))
1896 g_pfnSetupSetNonInteractiveMode(TRUE /* fEnable */);
1897 }
1898
1899 if (!vboxWinDrvParmsAreValid(pCtx, pParms))
1900 {
1901 vboxWinDrvInstLogError(pCtx, "%s parameters are invalid, can't continue", fInstall ? "Installation" : "Uninstallation");
1902 return VERR_INVALID_PARAMETER;
1903 }
1904
1905 int rc;
1906 if (fInstall)
1907 rc = vboxWinDrvInstallPerform(pCtx, pParms);
1908 else
1909 rc = vboxWinDrvUninstallPerform(pCtx, pParms);
1910
1911 if (RT_SUCCESS(rc))
1912 {
1913 vboxWinDrvInstLogInfo(pCtx, "Driver was %sinstalled successfully", fInstall ? "" : "un");
1914 if (pCtx->fReboot)
1915 {
1916 vboxWinDrvInstLogRebootNeeded(pCtx, "A reboot is needed in order to complete the driver %sinstallation.",
1917 fInstall ? "" : "un");
1918 rc = VINF_REBOOT_NEEDED;
1919 }
1920 }
1921
1922 /* Note: Call vboxWinDrvInstLogEx() to not increase the error/warn count here. */
1923 if (pCtx->cErrors)
1924 vboxWinDrvInstLogEx(pCtx, VBOXWINDRIVERLOGTYPE_ERROR, "%sstalling driver(s) failed with %u errors, %u warnings (rc=%Rrc)",
1925 fInstall ? "In" : "Unin", pCtx->cErrors, pCtx->cWarnings, rc);
1926 else if (pCtx->cWarnings)
1927 vboxWinDrvInstLogEx(pCtx, VBOXWINDRIVERLOGTYPE_WARN, "%sstalling driver(s) succeeded with %u warnings",
1928 fInstall ? "In" : "Unin", pCtx->cWarnings);
1929
1930 return rc;
1931}
1932
1933/**
1934 * Creates a Windows driver installer instance, extended version.
1935 *
1936 * @returns VBox status code.
1937 * @param phDrvInst where to return the created driver installer handle on success.
1938 * @param uVerbosity Sets the initial verbosity level.
1939 * @param pfnLog Log callback function to set.
1940 * @param pvUser User-supplied pointer to set. Optional and might be NULL.
1941 */
1942int VBoxWinDrvInstCreateEx(PVBOXWINDRVINST phDrvInst, unsigned uVerbosity, PFNVBOXWINDRIVERLOGMSG pfnLog, void *pvUser)
1943{
1944 int rc;
1945
1946 PVBOXWINDRVINSTINTERNAL pCtx = (PVBOXWINDRVINSTINTERNAL)RTMemAllocZ(sizeof(VBOXWINDRVINSTINTERNAL));
1947 if (pCtx)
1948 {
1949 pCtx->u32Magic = VBOXWINDRVINST_MAGIC;
1950 pCtx->uVerbosity = uVerbosity;
1951 pCtx->pfnLog = pfnLog;
1952 pCtx->pvUser = pvUser;
1953
1954 pCtx->uOsVer = RTSystemGetNtVersion(); /* Might be overwritten later via VBoxWinDrvInstSetOsVersion(). */
1955
1956 vboxWinDrvInstLogInfo(pCtx, VBOX_PRODUCT " Version " VBOX_VERSION_STRING " - r%s", RTBldCfgRevisionStr());
1957 vboxWinDrvInstLogInfo(pCtx, "Detected Windows version %d.%d.%d (%s)", RTSYSTEM_NT_VERSION_GET_MAJOR(pCtx->uOsVer),
1958 RTSYSTEM_NT_VERSION_GET_MINOR(pCtx->uOsVer),
1959 RTSYSTEM_NT_VERSION_GET_BUILD(pCtx->uOsVer),
1960 RTBldCfgTargetArch());
1961
1962 rc = RTOnce(&g_vboxWinDrvInstResolveOnce, vboxWinDrvInstResolveOnce, pCtx);
1963 if (RT_SUCCESS(rc))
1964 {
1965 rc = VBoxWinDrvStoreCreate(&pCtx->pStore);
1966 if (RT_SUCCESS(rc))
1967 {
1968 *phDrvInst = (VBOXWINDRVINST)pCtx;
1969 return VINF_SUCCESS;
1970 }
1971 else
1972 vboxWinDrvInstLogError(pCtx, "Creating driver store failed with %Rrc", rc);
1973 }
1974 }
1975 else
1976 rc = VERR_NO_MEMORY;
1977
1978 VBoxWinDrvStoreDestroy(pCtx->pStore);
1979 VBoxWinDrvInstDestroy(pCtx);
1980 return rc;
1981}
1982
1983/**
1984 * Creates a Windows driver installer instance.
1985 *
1986 * @returns VBox status code.
1987 * @param phDrvInst where to return the created driver installer handle on success.
1988 */
1989int VBoxWinDrvInstCreate(PVBOXWINDRVINST phDrvInst)
1990{
1991 return VBoxWinDrvInstCreateEx(phDrvInst, 0 /* uVerbosity */, NULL /* pfnLog */, NULL /* pvUser */);
1992}
1993
1994/**
1995 * Destroys a Windows driver installer instance.
1996 *
1997 * @returns VBox status code.
1998 * @param hDrvInst Windows driver installer handle to destroy.
1999 * The handle will be invalid after calling this function.
2000 */
2001int VBoxWinDrvInstDestroy(VBOXWINDRVINST hDrvInst)
2002{
2003 if (hDrvInst == NIL_VBOXWINDRVINST)
2004 return VINF_SUCCESS;
2005
2006 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2007 VBOXWINDRVINST_VALID_RETURN(pCtx);
2008
2009 vboxWinDrvInstParmsDestroy(&pCtx->Parms);
2010
2011 VBoxWinDrvStoreDestroy(pCtx->pStore);
2012 pCtx->pStore = NULL;
2013
2014 RTMemFree(pCtx);
2015
2016 return VINF_SUCCESS;
2017}
2018
2019/**
2020 * Returns the number of (logged) warnings so far.
2021 *
2022 * @returns Number of (logged) warnings so far.
2023 * @param hDrvInst Windows driver installer handle.
2024 */
2025unsigned VBoxWinDrvInstGetWarnings(VBOXWINDRVINST hDrvInst)
2026{
2027 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2028 VBOXWINDRVINST_VALID_RETURN_RC(pCtx, UINT8_MAX);
2029
2030 return pCtx->cWarnings;
2031}
2032
2033/**
2034 * Returns the number of (logged) errors so far.
2035 *
2036 * @returns Number of (logged) errors so far..
2037 * @param hDrvInst Windows driver installer handle.
2038 */
2039unsigned VBoxWinDrvInstGetErrors(VBOXWINDRVINST hDrvInst)
2040{
2041 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2042 VBOXWINDRVINST_VALID_RETURN_RC(pCtx, UINT8_MAX);
2043
2044 return pCtx->cErrors;
2045}
2046
2047/**
2048 * Sets (overwrites) the current OS version used for the (un)installation code.
2049 *
2050 * @param hDrvInst Windows driver installer handle.
2051 * @param uOsVer OS version to set. RTSYSTEM_MAKE_NT_VERSION style.
2052 */
2053void VBoxWinDrvInstSetOsVersion(VBOXWINDRVINST hDrvInst, uint64_t uOsVer)
2054{
2055 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2056 VBOXWINDRVINST_VALID_RETURN_VOID(pCtx);
2057
2058 pCtx->uOsVer = uOsVer;
2059
2060 vboxWinDrvInstLogInfo(pCtx, "Set OS version to: %u.%u\n", RTSYSTEM_NT_VERSION_GET_MAJOR(pCtx->uOsVer),
2061 RTSYSTEM_NT_VERSION_GET_MINOR(pCtx->uOsVer));
2062}
2063
2064/**
2065 * Sets the verbosity of a Windows driver installer instance.
2066 *
2067 * @returns The old verbosity level.
2068 * @param hDrvInst Windows driver installer handle to set verbosity for.
2069 * @param uVerbosity Verbosity level to set.
2070 */
2071unsigned VBoxWinDrvInstSetVerbosity(VBOXWINDRVINST hDrvInst, unsigned uVerbosity)
2072{
2073 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2074 VBOXWINDRVINST_VALID_RETURN_RC(pCtx, UINT8_MAX);
2075
2076 unsigned const uOldVerbosity = hDrvInst->uVerbosity;
2077 hDrvInst->uVerbosity = uVerbosity;
2078 return uOldVerbosity;
2079}
2080
2081/**
2082 * Sets the log callback of a Windows driver installer instance.
2083 *
2084 * @returns VBox status code.
2085 * @param hDrvInst Windows driver installer handle to set log callback for.
2086 * @param pfnLog Log callback function to set.
2087 * @param pvUser User-supplied pointer to set. Optional and might be NULL.
2088 */
2089void VBoxWinDrvInstSetLogCallback(VBOXWINDRVINST hDrvInst, PFNVBOXWINDRIVERLOGMSG pfnLog, void *pvUser)
2090{
2091 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2092 VBOXWINDRVINST_VALID_RETURN_VOID(pCtx);
2093
2094 pCtx->pfnLog = pfnLog;
2095 pCtx->pvUser = pvUser;
2096}
2097
2098/**
2099 * Installs a driver, extended version.
2100 *
2101 * @returns VBox status code.
2102 * @param hDrvInst Windows driver installer handle to use.
2103 * @param pszInfFile INF file to use.
2104 * @param pszModel Model name to use. Optional and can be NULL.
2105 * @param pszPnpId PnP ID to use. NT-style wildcards supported. Optional and can be NULL.
2106 * @param fFlags Installation flags (of type VBOX_WIN_DRIVERINSTALL_F_XXX) to use.
2107 */
2108int VBoxWinDrvInstInstallEx(VBOXWINDRVINST hDrvInst,
2109 const char *pszInfFile, const char *pszModel, const char *pszPnpId, uint32_t fFlags)
2110{
2111 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2112 VBOXWINDRVINST_VALID_RETURN(pCtx);
2113
2114 AssertPtrReturn(pszInfFile, VERR_INVALID_PARAMETER);
2115
2116 vboxWinDrvInstParmsInit(&pCtx->Parms);
2117
2118 /* Resolve the INF file's absolute path, as as Setup API functions tend to need this. */
2119 char szInfPathAbs[RTPATH_MAX];
2120 int rc = RTPathReal(pszInfFile, szInfPathAbs, sizeof(szInfPathAbs));
2121 if (RT_SUCCESS(rc))
2122 {
2123 rc = RTStrToUtf16(szInfPathAbs, &pCtx->Parms.pwszInfFile);
2124 if (RT_FAILURE(rc))
2125 vboxWinDrvInstLogError(pCtx, "Failed to build path for INF file \"%s\", rc=%Rrc", pszInfFile, rc);
2126 }
2127 else
2128 vboxWinDrvInstLogError(pCtx, "Determining real path for INF file \"%s\" failed, rc=%Rrc", pszInfFile, rc);
2129
2130 if (RT_SUCCESS(rc) && pszModel) /* Model is optional. */
2131 rc = RTStrToUtf16(pszModel, &pCtx->Parms.u.UnInstall.pwszModel);
2132 if (RT_SUCCESS(rc) && pszPnpId) /* Ditto. */
2133 rc = RTStrToUtf16(pszPnpId, &pCtx->Parms.u.UnInstall.pwszPnpId);
2134
2135 if (RT_SUCCESS(rc))
2136 {
2137 pCtx->Parms.enmMode = VBOXWINDRVINSTMODE_INSTALL;
2138 pCtx->Parms.fFlags = fFlags;
2139
2140 rc = vboxWinDrvInstMain(pCtx, &pCtx->Parms);
2141 }
2142
2143 if (!(fFlags & VBOX_WIN_DRIVERINSTALL_F_NO_DESTROY))
2144 vboxWinDrvInstParmsDestroy(&pCtx->Parms);
2145
2146 if (RT_FAILURE(rc))
2147 vboxWinDrvInstLogError(pCtx, "Driver installation failed with %Rrc", rc);
2148
2149 return rc;
2150}
2151
2152/**
2153 * Installs a driver.
2154 *
2155 * @returns VBox status code.
2156 * @param hDrvInst Windows driver installer handle to use.
2157 * @param pszInfFile INF file to use.
2158 * @param fFlags Installation flags (of type VBOX_WIN_DRIVERINSTALL_F_XXX) to use.
2159 *
2160 * @note This function tries determining the model / PnP ID from the given INF file.
2161 * To control the behavior exactly, use VBoxWinDrvInstInstallEx().
2162 */
2163int VBoxWinDrvInstInstall(VBOXWINDRVINST hDrvInst, const char *pszInfFile, uint32_t fFlags)
2164{
2165 return VBoxWinDrvInstInstallEx(hDrvInst, pszInfFile, NULL /* pszModel */, NULL /* pszPnpId */, fFlags);
2166}
2167
2168/**
2169 * Uninstalls a driver.
2170 *
2171 * @returns VBox status code.
2172 * @param hDrvInst Windows driver installer handle to use.
2173 * @param pszInfFile INF file within driver store to uninstall.
2174 * Optional and can be NULL.
2175 * @param pszModel Model to uninstall (e.g. "VBoxUSB.AMD64"). NT-style wildcards supported.
2176 * Optional and can be NULL.
2177 * @param pszPnpId PnP ID to use (e.g. "USB\\VID_80EE&PID_CAFE"). NT-style wildcards supported.
2178 * Optional and can be NULL.
2179 * @param fFlags Installation flags (of type VBOX_WIN_DRIVERINSTALL_F_XXX) to use.
2180 */
2181int VBoxWinDrvInstUninstall(VBOXWINDRVINST hDrvInst, const char *pszInfFile, const char *pszModel, const char *pszPnpId,
2182 uint32_t fFlags)
2183{
2184 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2185 VBOXWINDRVINST_VALID_RETURN(pCtx);
2186
2187 int rc = VINF_SUCCESS;
2188
2189 vboxWinDrvInstParmsInit(&pCtx->Parms);
2190
2191 /* If given, get the sole INF file name (without path), to make it searchable within the driver store.
2192 * Note: This only will work with "oemXXX.inf" files for the (legcy) driver store. */
2193 if (pszInfFile && *pszInfFile)
2194 {
2195 char *pszInfFileName = RTPathFilename(pszInfFile);
2196 if (pszInfFileName)
2197 rc = RTStrToUtf16(pszInfFileName, &pCtx->Parms.pwszInfFile);
2198 else
2199 rc = VERR_FILE_NOT_FOUND;
2200 }
2201
2202 if (RT_SUCCESS(rc) && pszModel && *pszModel)
2203 rc = RTStrToUtf16(pszModel, &pCtx->Parms.u.UnInstall.pwszModel);
2204 if (RT_SUCCESS(rc) && pszPnpId && *pszPnpId)
2205 rc = RTStrToUtf16(pszPnpId, &pCtx->Parms.u.UnInstall.pwszPnpId);
2206
2207 pCtx->Parms.enmMode = VBOXWINDRVINSTMODE_UNINSTALL;
2208 pCtx->Parms.fFlags = fFlags;
2209
2210 if (RT_SUCCESS(rc))
2211 rc = vboxWinDrvInstMain(pCtx, &pCtx->Parms);
2212
2213 if (!(fFlags & VBOX_WIN_DRIVERINSTALL_F_NO_DESTROY))
2214 vboxWinDrvInstParmsDestroy(&pCtx->Parms);
2215
2216 if (RT_FAILURE(rc))
2217 vboxWinDrvInstLogError(pCtx, "Driver uninstallation failed with %Rrc", rc);
2218
2219 return rc;
2220}
2221
2222/**
2223 * Worker function for executing a section of an INF file.
2224 *
2225 * @returns VBox status code.
2226 * @param hDrvInst Windows driver installer handle to use.
2227 * @param fInstall Whether to execute the section to install or uninstall.
2228 * @param pszInfFile INF file to use.
2229 * @param pszSection Section within the INF file to execute.
2230 * @param fFlags Installation flags to use.
2231 */
2232int VBoxWinDrvInstExecuteInfWorker(VBOXWINDRVINST hDrvInst,
2233 bool fInstall, const char *pszInfFile, const char *pszSection, uint32_t fFlags)
2234{
2235 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2236 VBOXWINDRVINST_VALID_RETURN(pCtx);
2237
2238 AssertPtrReturn(pszInfFile, VERR_INVALID_POINTER);
2239
2240 vboxWinDrvInstParmsInit(&pCtx->Parms);
2241
2242 int rc = RTStrToUtf16(pszInfFile, &pCtx->Parms.pwszInfFile);
2243 if (RT_SUCCESS(rc) && pszSection) /* pszSection is optional. */
2244 rc = RTStrToUtf16(pszSection, &pCtx->Parms.u.ExecuteInf.pwszSection);
2245 AssertRCReturn(rc, rc);
2246
2247 pCtx->Parms.enmMode = fInstall ? VBOXWINDRVINSTMODE_INSTALL_INFSECTION : VBOXWINDRVINSTMODE_UNINSTALL_INFSECTION;
2248 pCtx->Parms.fFlags = fFlags;
2249
2250 rc = vboxWinDrvInstMain(pCtx, &pCtx->Parms);
2251
2252 if (!(fFlags & VBOX_WIN_DRIVERINSTALL_F_NO_DESTROY))
2253 vboxWinDrvInstParmsDestroy(&pCtx->Parms);
2254
2255 return rc;
2256}
2257
2258/**
2259 * Executes a section of an INF file for installation.
2260 *
2261 * @returns VBox status code.
2262 * @param hDrvInst Windows driver installer handle to use.
2263 * @param pszInfFile INF file to use.
2264 * @param pszSection Section within the INF file to execute.
2265 * @param fFlags Installation flags to use.
2266 */
2267int VBoxWinDrvInstInstallExecuteInf(VBOXWINDRVINST hDrvInst, const char *pszInfFile, const char *pszSection, uint32_t fFlags)
2268{
2269 return VBoxWinDrvInstExecuteInfWorker(hDrvInst, true /* fInstall */, pszInfFile, pszSection, fFlags);
2270}
2271
2272/**
2273 * Executes a section of an INF file for uninstallation.
2274 *
2275 * @returns VBox status code.
2276 * @param hDrvInst Windows driver installer handle to use.
2277 * @param pszInfFile INF file to use.
2278 * @param pszSection Section within the INF file to execute.
2279 * @param fFlags Installation flags to use.
2280 */
2281int VBoxWinDrvInstUninstallExecuteInf(VBOXWINDRVINST hDrvInst, const char *pszInfFile, const char *pszSection, uint32_t fFlags)
2282{
2283 return VBoxWinDrvInstExecuteInfWorker(hDrvInst, false /* fInstall */, pszInfFile, pszSection, fFlags);
2284}
2285
2286#ifdef TESTCASE
2287/**
2288 * Returns the internal parameters of an (un)installation.
2289 *
2290 * @returns Internal parameters of an (un)installation.
2291 * @param hDrvInst Windows driver installer handle to use.
2292 */
2293PVBOXWINDRVINSTPARMS VBoxWinDrvInstTestGetParms(VBOXWINDRVINST hDrvInst)
2294{
2295 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2296 VBOXWINDRVINST_VALID_RETURN_RC((hDrvInst), NULL);
2297
2298 return &pCtx->Parms;
2299}
2300
2301/**
2302 * Detroys internal parameters of an (un)installation.
2303 *
2304 * @param pParms Internal parameters of an (un)installation to destroy.
2305 */
2306void VBoxWinDrvInstTestParmsDestroy(PVBOXWINDRVINSTPARMS pParms)
2307{
2308 vboxWinDrvInstParmsDestroy(pParms);
2309}
2310#endif /* TESTCASE */
2311
Note: See TracBrowser for help on using the repository browser.

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