VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManageModifyNvram.cpp@ 93318

Last change on this file since 93318 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.8 KB
Line 
1/* $Id: VBoxManageModifyNvram.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * VBoxManage - The nvram control related commands.
4 */
5
6/*
7 * Copyright (C) 2021-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifndef VBOX_ONLY_DOCS
19
20
21/*********************************************************************************************************************************
22* Header Files *
23*********************************************************************************************************************************/
24#include <VBox/com/com.h>
25#include <VBox/com/array.h>
26#include <VBox/com/ErrorInfo.h>
27#include <VBox/com/errorprint.h>
28#include <VBox/com/VirtualBox.h>
29
30#include <iprt/errcore.h>
31#include <iprt/path.h>
32#include <iprt/param.h>
33#include <iprt/string.h>
34#include <iprt/ctype.h>
35#include <iprt/stream.h>
36#include <iprt/file.h>
37#include <iprt/getopt.h>
38#include <iprt/uuid.h>
39#include <VBox/log.h>
40
41#include "VBoxManage.h"
42using namespace com;
43
44DECLARE_TRANSLATION_CONTEXT(Nvram);
45
46// funcs
47///////////////////////////////////////////////////////////////////////////////
48
49
50/**
51 * Handles the 'modifynvram myvm inituefivarstore' sub-command.
52 * @returns Exit code.
53 * @param a The handler argument package.
54 * @param nvram Reference to the NVRAM store interface.
55 */
56static RTEXITCODE handleModifyNvramInitUefiVarStore(HandlerArg *a, ComPtr<INvramStore> &nvramStore)
57{
58 RT_NOREF(a);
59
60 CHECK_ERROR2I_RET(nvramStore, InitUefiVariableStore(0 /*aSize*/), RTEXITCODE_FAILURE);
61 return RTEXITCODE_SUCCESS;
62}
63
64
65/**
66 * Handles the 'modifynvram myvm enrollmssignatures' sub-command.
67 * @returns Exit code.
68 * @param a The handler argument package.
69 * @param nvram Reference to the NVRAM store interface.
70 */
71static RTEXITCODE handleModifyNvramEnrollMsSignatures(HandlerArg *a, ComPtr<INvramStore> &nvramStore)
72{
73 RT_NOREF(a);
74
75 ComPtr<IUefiVariableStore> uefiVarStore;
76 CHECK_ERROR2I_RET(nvramStore, COMGETTER(UefiVariableStore)(uefiVarStore.asOutParam()), RTEXITCODE_FAILURE);
77
78 CHECK_ERROR2I_RET(uefiVarStore, EnrollDefaultMsSignatures(), RTEXITCODE_FAILURE);
79 return RTEXITCODE_SUCCESS;
80}
81
82
83/**
84 * Handles the 'modifynvram myvm enrollpk' sub-command.
85 * @returns Exit code.
86 * @param a The handler argument package.
87 * @param nvram Reference to the NVRAM store interface.
88 */
89static RTEXITCODE handleModifyNvramEnrollPlatformKey(HandlerArg *a, ComPtr<INvramStore> &nvramStore)
90{
91 static const RTGETOPTDEF s_aOptions[] =
92 {
93 /* common options */
94 { "--platform-key", 'p', RTGETOPT_REQ_STRING },
95 { "--owner-uuid", 'f', RTGETOPT_REQ_STRING }
96 };
97
98 const char *pszPlatformKey = NULL;
99 const char *pszOwnerUuid = NULL;
100
101 RTGETOPTSTATE GetState;
102 int vrc = RTGetOptInit(&GetState, a->argc - 2, &a->argv[2], s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0);
103 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
104
105 int c;
106 RTGETOPTUNION ValueUnion;
107 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
108 {
109 switch (c)
110 {
111 case 'p':
112 pszPlatformKey = ValueUnion.psz;
113 break;
114 case 'f':
115 pszOwnerUuid = ValueUnion.psz;
116 break;
117 default:
118 return errorGetOpt(c, &ValueUnion);
119 }
120 }
121
122 if (!pszPlatformKey)
123 return errorSyntax(Nvram::tr("No platform key file path was given to \"enrollpk\""));
124 if (!pszOwnerUuid)
125 return errorSyntax(Nvram::tr("No owner UUID was given to \"enrollpk\""));
126
127 RTFILE hPkFile;
128 vrc = RTFileOpen(&hPkFile, pszPlatformKey, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
129 if (RT_SUCCESS(vrc))
130 {
131 uint64_t cbSize;
132 vrc = RTFileQuerySize(hPkFile, &cbSize);
133 if (RT_SUCCESS(vrc))
134 {
135 if (cbSize <= _32K)
136 {
137 SafeArray<BYTE> aPk((size_t)cbSize);
138 vrc = RTFileRead(hPkFile, aPk.raw(), (size_t)cbSize, NULL);
139 if (RT_SUCCESS(vrc))
140 {
141 RTFileClose(hPkFile);
142
143 ComPtr<IUefiVariableStore> uefiVarStore;
144 CHECK_ERROR2I_RET(nvramStore, COMGETTER(UefiVariableStore)(uefiVarStore.asOutParam()), RTEXITCODE_FAILURE);
145 CHECK_ERROR2I_RET(uefiVarStore, EnrollPlatformKey(ComSafeArrayAsInParam(aPk), Bstr(pszOwnerUuid).raw()), RTEXITCODE_FAILURE);
146 return RTEXITCODE_SUCCESS;
147 }
148 else
149 RTMsgError(Nvram::tr("Cannot read contents of file \"%s\": %Rrc"), pszPlatformKey, vrc);
150 }
151 else
152 RTMsgError(Nvram::tr("File \"%s\" is bigger than 32KByte"), pszPlatformKey);
153 }
154 else
155 RTMsgError(Nvram::tr("Cannot get size of file \"%s\": %Rrc"), pszPlatformKey, vrc);
156
157 RTFileClose(hPkFile);
158 }
159 else
160 RTMsgError(Nvram::tr("Cannot open file \"%s\": %Rrc"), pszPlatformKey, vrc);
161
162 return RTEXITCODE_FAILURE;
163}
164
165
166/**
167 * Handles the 'modifynvram myvm enrollorclpk' sub-command.
168 * @returns Exit code.
169 * @param a The handler argument package.
170 * @param nvram Reference to the NVRAM store interface.
171 */
172static RTEXITCODE handleModifyNvramEnrollOraclePlatformKey(HandlerArg *a, ComPtr<INvramStore> &nvramStore)
173{
174 RT_NOREF(a);
175
176 ComPtr<IUefiVariableStore> uefiVarStore;
177 CHECK_ERROR2I_RET(nvramStore, COMGETTER(UefiVariableStore)(uefiVarStore.asOutParam()), RTEXITCODE_FAILURE);
178
179 CHECK_ERROR2I_RET(uefiVarStore, EnrollOraclePlatformKey(), RTEXITCODE_FAILURE);
180 return RTEXITCODE_SUCCESS;
181}
182
183
184/**
185 * Handles the 'modifynvram myvm listvars' sub-command.
186 * @returns Exit code.
187 * @param a The handler argument package.
188 * @param nvram Reference to the NVRAM store interface.
189 */
190static RTEXITCODE handleModifyNvramListUefiVars(HandlerArg *a, ComPtr<INvramStore> &nvramStore)
191{
192 RT_NOREF(a);
193
194 ComPtr<IUefiVariableStore> uefiVarStore;
195 CHECK_ERROR2I_RET(nvramStore, COMGETTER(UefiVariableStore)(uefiVarStore.asOutParam()), RTEXITCODE_FAILURE);
196
197 com::SafeArray<BSTR> aNames;
198 com::SafeArray<BSTR> aOwnerGuids;
199 CHECK_ERROR2I_RET(uefiVarStore, QueryVariables(ComSafeArrayAsOutParam(aNames), ComSafeArrayAsOutParam(aOwnerGuids)), RTEXITCODE_FAILURE);
200 for (size_t i = 0; i < aNames.size(); i++)
201 {
202 Bstr strName = aNames[i];
203 Bstr strOwnerGuid = aOwnerGuids[i];
204
205 RTPrintf("%-32ls {%ls}\n", strName.raw(), strOwnerGuid.raw());
206 }
207
208 return RTEXITCODE_SUCCESS;
209}
210
211
212/**
213 * Handles the 'modifynvram myvm queryvar' sub-command.
214 * @returns Exit code.
215 * @param a The handler argument package.
216 * @param nvram Reference to the NVRAM store interface.
217 */
218static RTEXITCODE handleModifyNvramQueryUefiVar(HandlerArg *a, ComPtr<INvramStore> &nvramStore)
219{
220 static const RTGETOPTDEF s_aOptions[] =
221 {
222 /* common options */
223 { "--name", 'n', RTGETOPT_REQ_STRING },
224 { "--filename", 'f', RTGETOPT_REQ_STRING }
225 };
226
227 const char *pszVarName = NULL;
228 const char *pszVarDataFilename = NULL;
229
230 RTGETOPTSTATE GetState;
231 int vrc = RTGetOptInit(&GetState, a->argc - 2, &a->argv[2], s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0);
232 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
233
234 int c;
235 RTGETOPTUNION ValueUnion;
236 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
237 {
238 switch (c)
239 {
240 case 'n':
241 pszVarName = ValueUnion.psz;
242 break;
243 case 'f':
244 pszVarDataFilename = ValueUnion.psz;
245 break;
246 default:
247 return errorGetOpt(c, &ValueUnion);
248 }
249 }
250
251 if (!pszVarName)
252 return errorSyntax(Nvram::tr("No variable name was given to \"queryvar\""));
253
254 ComPtr<IUefiVariableStore> uefiVarStore;
255 CHECK_ERROR2I_RET(nvramStore, COMGETTER(UefiVariableStore)(uefiVarStore.asOutParam()), RTEXITCODE_FAILURE);
256
257 Bstr strOwnerGuid;
258 com::SafeArray<UefiVariableAttributes_T> aVarAttrs;
259 com::SafeArray<BYTE> aData;
260 CHECK_ERROR2I_RET(uefiVarStore, QueryVariableByName(Bstr(pszVarName).raw(), strOwnerGuid.asOutParam(),
261 ComSafeArrayAsOutParam(aVarAttrs), ComSafeArrayAsOutParam(aData)),
262 RTEXITCODE_FAILURE);
263
264 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
265 if (!pszVarDataFilename)
266 {
267 RTPrintf("%s {%ls}:\n"
268 "%.*Rhxd\n", pszVarName, strOwnerGuid.raw(), aData.size(), aData.raw());
269 }
270 else
271 {
272 /* Just write the data to the file. */
273 RTFILE hFile = NIL_RTFILE;
274 vrc = RTFileOpen(&hFile, pszVarDataFilename, RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
275 if (RT_SUCCESS(vrc))
276 {
277 vrc = RTFileWrite(hFile, aData.raw(), aData.size(), NULL /*pcbWritten*/);
278 if (RT_FAILURE(vrc))
279 rcExit = RTMsgErrorExitFailure(Nvram::tr("Error writing to '%s': %Rrc"), pszVarDataFilename, vrc);
280
281 RTFileClose(hFile);
282 }
283 else
284 rcExit = RTMsgErrorExitFailure(Nvram::tr("Error opening '%s': %Rrc"), pszVarDataFilename, vrc);
285 }
286
287 return rcExit;
288}
289
290
291/**
292 * Handles the 'modifynvram myvm deletevar' sub-command.
293 * @returns Exit code.
294 * @param a The handler argument package.
295 * @param nvram Reference to the NVRAM store interface.
296 */
297static RTEXITCODE handleModifyNvramDeleteUefiVar(HandlerArg *a, ComPtr<INvramStore> &nvramStore)
298{
299 static const RTGETOPTDEF s_aOptions[] =
300 {
301 /* common options */
302 { "--name", 'n', RTGETOPT_REQ_STRING },
303 { "--owner-uuid", 'f', RTGETOPT_REQ_STRING }
304 };
305
306 const char *pszVarName = NULL;
307 const char *pszOwnerUuid = NULL;
308
309 RTGETOPTSTATE GetState;
310 int vrc = RTGetOptInit(&GetState, a->argc - 2, &a->argv[2], s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0);
311 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
312
313 int c;
314 RTGETOPTUNION ValueUnion;
315 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
316 {
317 switch (c)
318 {
319 case 'n':
320 pszVarName = ValueUnion.psz;
321 break;
322 case 'f':
323 pszOwnerUuid = ValueUnion.psz;
324 break;
325 default:
326 return errorGetOpt(c, &ValueUnion);
327 }
328 }
329
330 if (!pszVarName)
331 return errorSyntax(Nvram::tr("No variable name was given to \"deletevar\""));
332 if (!pszOwnerUuid)
333 return errorSyntax(Nvram::tr("No owner UUID was given to \"deletevar\""));
334
335 ComPtr<IUefiVariableStore> uefiVarStore;
336 CHECK_ERROR2I_RET(nvramStore, COMGETTER(UefiVariableStore)(uefiVarStore.asOutParam()), RTEXITCODE_FAILURE);
337 CHECK_ERROR2I_RET(uefiVarStore, DeleteVariable(Bstr(pszVarName).raw(), Bstr(pszOwnerUuid).raw()), RTEXITCODE_FAILURE);
338
339 return RTEXITCODE_SUCCESS;
340}
341
342
343/**
344 * Handles the 'modifynvram myvm changevar' sub-command.
345 * @returns Exit code.
346 * @param a The handler argument package.
347 * @param nvram Reference to the NVRAM store interface.
348 */
349static RTEXITCODE handleModifyNvramChangeUefiVar(HandlerArg *a, ComPtr<INvramStore> &nvramStore)
350{
351 static const RTGETOPTDEF s_aOptions[] =
352 {
353 /* common options */
354 { "--name", 'n', RTGETOPT_REQ_STRING },
355 { "--filename", 'f', RTGETOPT_REQ_STRING }
356 };
357
358 const char *pszVarName = NULL;
359 const char *pszVarDataFilename = NULL;
360
361 RTGETOPTSTATE GetState;
362 int vrc = RTGetOptInit(&GetState, a->argc - 2, &a->argv[2], s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0);
363 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
364
365 int c;
366 RTGETOPTUNION ValueUnion;
367 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
368 {
369 switch (c)
370 {
371 case 'n':
372 pszVarName = ValueUnion.psz;
373 break;
374 case 'f':
375 pszVarDataFilename = ValueUnion.psz;
376 break;
377 default:
378 return errorGetOpt(c, &ValueUnion);
379 }
380 }
381
382 if (!pszVarName)
383 return errorSyntax(Nvram::tr("No variable name was given to \"changevar\""));
384 if (!pszVarDataFilename)
385 return errorSyntax(Nvram::tr("No variable data filename was given to \"changevar\""));
386
387 RTFILE hFile = NIL_RTFILE;
388 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
389 vrc = RTFileOpen(&hFile, pszVarDataFilename, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
390 if (RT_SUCCESS(vrc))
391 {
392 uint64_t cbFile = 0;
393 vrc = RTFileQuerySize(hFile, &cbFile);
394 if (RT_SUCCESS(vrc))
395 {
396 com::SafeArray<BYTE> aData;
397 aData.resize(cbFile);
398
399 vrc = RTFileRead(hFile, aData.raw(), aData.size(), NULL /*pcbRead*/);
400 RTFileClose(hFile);
401
402 if (RT_SUCCESS(vrc))
403 {
404 ComPtr<IUefiVariableStore> uefiVarStore;
405 CHECK_ERROR2I_RET(nvramStore, COMGETTER(UefiVariableStore)(uefiVarStore.asOutParam()), RTEXITCODE_FAILURE);
406 CHECK_ERROR2I_RET(uefiVarStore, ChangeVariable(Bstr(pszVarName).raw(), ComSafeArrayAsInParam(aData)), RTEXITCODE_FAILURE);
407 }
408 else
409 rcExit = RTMsgErrorExitFailure(Nvram::tr("Error reading from '%s': %Rrc"), pszVarDataFilename, vrc);
410 }
411 }
412 else
413 rcExit = RTMsgErrorExitFailure(Nvram::tr("Error opening '%s': %Rrc"), pszVarDataFilename, vrc);
414
415 return rcExit;
416}
417
418
419/**
420 * Handles the 'modifynvram' command.
421 * @returns Exit code.
422 * @param a The handler argument package.
423 */
424RTEXITCODE handleModifyNvram(HandlerArg *a)
425{
426 HRESULT rc = S_OK;
427 ComPtr<IMachine> machine;
428 ComPtr<INvramStore> nvramStore;
429
430 if (a->argc < 2)
431 return errorNoSubcommand();
432
433 /* try to find the given machine */
434 CHECK_ERROR_RET(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
435 machine.asOutParam()), RTEXITCODE_FAILURE);
436
437 /* open a session for the VM (new or shared) */
438 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Write), RTEXITCODE_FAILURE);
439
440 /* get the mutable session machine */
441 a->session->COMGETTER(Machine)(machine.asOutParam());
442 rc = machine->COMGETTER(NonVolatileStore)(nvramStore.asOutParam());
443 if (FAILED(rc)) goto leave;
444
445 if (!strcmp(a->argv[1], "inituefivarstore"))
446 {
447 setCurrentSubcommand(HELP_SCOPE_MODIFYNVRAM_INITUEFIVARSTORE);
448 rc = handleModifyNvramInitUefiVarStore(a, nvramStore) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
449 }
450 else if (!strcmp(a->argv[1], "enrollmssignatures"))
451 {
452 setCurrentSubcommand(HELP_SCOPE_MODIFYNVRAM_ENROLLMSSIGNATURES);
453 rc = handleModifyNvramEnrollMsSignatures(a, nvramStore) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
454 }
455 else if (!strcmp(a->argv[1], "enrollpk"))
456 {
457 setCurrentSubcommand(HELP_SCOPE_MODIFYNVRAM_ENROLLPK);
458 rc = handleModifyNvramEnrollPlatformKey(a, nvramStore) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
459 }
460 else if (!strcmp(a->argv[1], "enrollorclpk"))
461 {
462 setCurrentSubcommand(HELP_SCOPE_MODIFYNVRAM_ENROLLORCLPK);
463 rc = handleModifyNvramEnrollOraclePlatformKey(a, nvramStore) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
464 }
465 else if (!strcmp(a->argv[1], "listvars"))
466 {
467 setCurrentSubcommand(HELP_SCOPE_MODIFYNVRAM_LISTVARS);
468 rc = handleModifyNvramListUefiVars(a, nvramStore) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
469 }
470 else if (!strcmp(a->argv[1], "queryvar"))
471 {
472 setCurrentSubcommand(HELP_SCOPE_MODIFYNVRAM_QUERYVAR);
473 rc = handleModifyNvramQueryUefiVar(a, nvramStore) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
474 }
475 else if (!strcmp(a->argv[1], "deletevar"))
476 {
477 setCurrentSubcommand(HELP_SCOPE_MODIFYNVRAM_DELETEVAR);
478 rc = handleModifyNvramDeleteUefiVar(a, nvramStore) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
479 }
480 else if (!strcmp(a->argv[1], "changevar"))
481 {
482 setCurrentSubcommand(HELP_SCOPE_MODIFYNVRAM_CHANGEVAR);
483 rc = handleModifyNvramChangeUefiVar(a, nvramStore) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
484 }
485 else
486 return errorUnknownSubcommand(a->argv[0]);
487
488 /* commit changes */
489 if (SUCCEEDED(rc))
490 CHECK_ERROR(machine, SaveSettings());
491
492leave:
493 /* it's important to always close sessions */
494 a->session->UnlockMachine();
495
496 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
497}
498
499#endif /* !VBOX_ONLY_DOCS */
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