VirtualBox

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

Last change on this file since 98103 was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use