VBoxExtPackHelperApp.cpp revision 939e2ecb812c6402abcc63e7d615c5444acfd02e
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/* $Id$ */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/** @file
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * VirtualBox Main - Extension Pack Helper Application, usually set-uid-to-root.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/*
f8e804dad2cc0262b6384e97c12be107cf7e19e0vboxsync * Copyright (C) 2010-2011 Oracle Corporation
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * available from http://www.virtualbox.org. This file is free software;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * you can redistribute it and/or modify it under the terms of the GNU
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * General Public License (GPL) as published by the Free Software
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/*******************************************************************************
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync* Header Files *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync*******************************************************************************/
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include "../include/ExtPackUtil.h"
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <iprt/buildconfig.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <iprt/dir.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <iprt/env.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <iprt/file.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <iprt/fs.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <iprt/getopt.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <iprt/initterm.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <iprt/manifest.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <iprt/message.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <iprt/param.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <iprt/path.h>
628ddfbd43ad5365d69fddda4007598242956577vboxsync#include <iprt/process.h>
628ddfbd43ad5365d69fddda4007598242956577vboxsync#include <iprt/string.h>
628ddfbd43ad5365d69fddda4007598242956577vboxsync#include <iprt/stream.h>
628ddfbd43ad5365d69fddda4007598242956577vboxsync#include <iprt/vfs.h>
628ddfbd43ad5365d69fddda4007598242956577vboxsync#include <iprt/zip.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <iprt/cpp/ministring.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <VBox/log.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <VBox/err.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <VBox/sup.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <VBox/version.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#ifdef RT_OS_WINDOWS
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync# define _WIN32_WINNT 0x0501
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync# include <Objbase.h> /* CoInitializeEx */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync# include <Windows.h> /* ShellExecuteEx, ++ */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync# ifdef DEBUG
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync# include <Sddl.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync# endif
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#endif
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#ifdef RT_OS_DARWIN
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync# include <Security/Authorization.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync# include <Security/AuthorizationTags.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync# include <CoreFoundation/CoreFoundation.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#endif
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#if !defined(RT_OS_OS2)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync# include <stdio.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync# include <errno.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync# if !defined(RT_OS_WINDOWS)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync# include <sys/types.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync# include <unistd.h> /* geteuid */
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync# endif
ae5379e3e7573369566d4628ef6c597da693cc55vboxsync#endif
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync
ae5379e3e7573369566d4628ef6c597da693cc55vboxsync/*******************************************************************************
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync* Defined Constants And Macros *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync*******************************************************************************/
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/** Enable elevation on Windows and Darwin. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#if !defined(RT_OS_OS2) || defined(DOXYGEN_RUNNING)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync# define WITH_ELEVATION
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync#endif
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync/** @name Command and option names
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @{ */
400d70dc1edb0f6d2a9d3a860b1b43f0b2cdfb39vboxsync#define CMD_INSTALL 1000
b6247ebeef75e5ab689ba845ad8cae8746607bb3vboxsync#define CMD_UNINSTALL 1001
400d70dc1edb0f6d2a9d3a860b1b43f0b2cdfb39vboxsync#define CMD_CLEANUP 1002
400d70dc1edb0f6d2a9d3a860b1b43f0b2cdfb39vboxsync#ifdef WITH_ELEVATION
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync# define OPT_ELEVATED 1090
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync# define OPT_STDOUT 1091
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync# define OPT_STDERR 1092
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#endif
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#define OPT_DISP_INFO_HACK 1093
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/** @} */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
54d3b0107d9bf326fe6e0de92e012c791dbb1587vboxsync/*******************************************************************************
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync* Global Variables *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync*******************************************************************************/
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#ifdef RT_OS_WINDOWS
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic HINSTANCE g_hInstance;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#endif
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#ifdef IN_RT_R3
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/* Override RTAssertShouldPanic to prevent gdb process creation. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncRTDECL(bool) RTAssertShouldPanic(void)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync{
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return true;
ce5210fe822f74de78c3dddc74f32a2cabcee5fdvboxsync}
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#endif
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
ce5210fe822f74de78c3dddc74f32a2cabcee5fdvboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/**
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync * Handle the special standard options when these are specified after the
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync * command.
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync *
77cce7691847be5aef145f31ba3f9d66fc2cf594vboxsync * @param ch The option character.
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync */
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsyncstatic RTEXITCODE DoStandardOption(int ch)
54d3b0107d9bf326fe6e0de92e012c791dbb1587vboxsync{
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync switch (ch)
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync {
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync case 'h':
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTMsgInfo(VBOX_PRODUCT " Extension Pack Helper App\n"
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync "(C) " VBOX_C_YEAR " " VBOX_VENDOR "\n"
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync "All rights reserved.\n"
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync "\n"
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync "This NOT intended for general use, please use VBoxManage instead\n"
9e293277b378073ce86910209a246b744b4caa2cvboxsync "or call the IExtPackManager API directly.\n"
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync "\n"
9e293277b378073ce86910209a246b744b4caa2cvboxsync "Usage: %s <command> [options]\n"
9e293277b378073ce86910209a246b744b4caa2cvboxsync "Commands:\n"
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync " install --base-dir <dir> --cert-dir <dir> --name <name> \\\n"
9e293277b378073ce86910209a246b744b4caa2cvboxsync " --tarball <tarball> --tarball-fd <fd>\n"
aabfd650b7e36e2c25a6d48b2a2bfd95fe93b65avboxsync " uninstall --base-dir <dir> --name <name>\n"
aabfd650b7e36e2c25a6d48b2a2bfd95fe93b65avboxsync " cleanup --base-dir <dir>\n"
aabfd650b7e36e2c25a6d48b2a2bfd95fe93b65avboxsync , RTProcShortName());
9e293277b378073ce86910209a246b744b4caa2cvboxsync return RTEXITCODE_SUCCESS;
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync }
bdd15592ca3578b623ff588055a561f58b7e5586vboxsync
bdd15592ca3578b623ff588055a561f58b7e5586vboxsync case 'V':
bdd15592ca3578b623ff588055a561f58b7e5586vboxsync RTPrintf("%sr%d\n", VBOX_VERSION_STRING, RTBldCfgRevision());
9e293277b378073ce86910209a246b744b4caa2cvboxsync return RTEXITCODE_SUCCESS;
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync default:
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync AssertFailedReturn(RTEXITCODE_FAILURE);
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync }
f350b7cf96f1e2f3b0cfd34cfe8726c754f43584vboxsync}
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync
f350b7cf96f1e2f3b0cfd34cfe8726c754f43584vboxsync
f350b7cf96f1e2f3b0cfd34cfe8726c754f43584vboxsync/**
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Checks if the cerficiate directory is valid.
f350b7cf96f1e2f3b0cfd34cfe8726c754f43584vboxsync *
f350b7cf96f1e2f3b0cfd34cfe8726c754f43584vboxsync * @returns true if it is valid, false if it isn't.
f350b7cf96f1e2f3b0cfd34cfe8726c754f43584vboxsync * @param pszCertDir The certificate directory to validate.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic bool IsValidCertificateDir(const char *pszCertDir)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync{
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Just be darn strict for now.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
f350b7cf96f1e2f3b0cfd34cfe8726c754f43584vboxsync char szCorrect[RTPATH_MAX];
551d9b8ee3568ad3e11b65ce6ef2867c36375f37vboxsync int rc = RTPathAppPrivateNoArch(szCorrect, sizeof(szCorrect));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync return false;
b8908d384db2324f04a2f68a13e67ea32ebf609avboxsync rc = RTPathAppend(szCorrect, sizeof(szCorrect), VBOX_EXTPACK_CERT_DIR);
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return false;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync return RTPathCompare(szCorrect, pszCertDir) == 0;
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync}
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/**
8e0c2ca3abd721979958f95b9af73b60665478c8vboxsync * Checks if the base directory is valid.
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync *
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync * @returns true if it is valid, false if it isn't.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pszBaesDir The base directory to validate.
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic bool IsValidBaseDir(const char *pszBaseDir)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync{
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Just be darn strict for now.
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync */
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync char szCorrect[RTPATH_MAX];
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync int rc = RTPathAppPrivateArchTop(szCorrect, sizeof(szCorrect));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return false;
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync rc = RTPathAppend(szCorrect, sizeof(szCorrect), VBOX_EXTPACK_INSTALL_DIR);
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return false;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTPathCompare(szCorrect, pszBaseDir) == 0;
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync}
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/**
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync * Cleans up a temporary extension pack directory.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *
39592d8ff3243f6116c4e99be391bcf30a4ad187vboxsync * This is used by 'uninstall', 'cleanup' and in the failure path of 'install'.
39592d8ff3243f6116c4e99be391bcf30a4ad187vboxsync *
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync * @returns The program exit code.
3ca89d9d8c4fc158ba28bdf82c9cc3697625ce12vboxsync * @param pszDir The directory to clean up. The caller is
39592d8ff3243f6116c4e99be391bcf30a4ad187vboxsync * responsible for making sure this is valid.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param fTemporary Whether this is a temporary install directory or
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * not.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic RTEXITCODE RemoveExtPackDir(const char *pszDir, bool fTemporary)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync{
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** @todo May have to undo 555 modes here later. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync int rc = RTDirRemoveRecursive(pszDir, RTDIRRMREC_F_CONTENT_AND_DIR);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync "Failed to delete the %sextension pack directory: %Rrc ('%s')",
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync fTemporary ? "temporary " : "", rc, pszDir);
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync return RTEXITCODE_SUCCESS;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync}
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/**
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Common uninstall worker used by both uninstall and install --replace.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns success or failure, message displayed on failure.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pszExtPackDir The extension pack directory name.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic RTEXITCODE CommonUninstallWorker(const char *pszExtPackDir)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync{
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* Rename the extension pack directory before deleting it to prevent new
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync VM processes from picking it up. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync char szExtPackUnInstDir[RTPATH_MAX];
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync int rc = RTStrCopy(szExtPackUnInstDir, sizeof(szExtPackUnInstDir), pszExtPackDir);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_SUCCESS(rc))
c77e7bff89c7639353778366984d51ff165ea0e3vboxsync rc = RTStrCat(szExtPackUnInstDir, sizeof(szExtPackUnInstDir), "-_-uninst");
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to construct temporary extension pack path: %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTDirRename(pszExtPackDir, szExtPackUnInstDir, RTPATHRENAME_FLAGS_NO_REPLACE);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to rename the extension pack directory: %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* Recursively delete the directory content. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RemoveExtPackDir(szExtPackUnInstDir, false /*fTemporary*/);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync}
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/**
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Wrapper around VBoxExtPackOpenTarFss.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns success or failure, message displayed on failure.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param hTarballFile The handle to the tarball file.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param phTarFss Where to return the filesystem stream handle.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic RTEXITCODE OpenTarFss(RTFILE hTarballFile, PRTVFSFSSTREAM phTarFss)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync{
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync char szError[8192];
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync int rc = VBoxExtPackOpenTarFss(hTarballFile, szError, sizeof(szError), phTarFss);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Assert(szError[0]);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s", szError);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Assert(!szError[0]);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTEXITCODE_SUCCESS;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync}
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/**
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Sets the permissions of the temporary extension pack directory just before
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * renaming it.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * By default the temporary directory is only accessible by root, this function
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * will make it world readable and browseable.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns The program exit code.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pszDir The temporary extension pack directory.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic RTEXITCODE SetExtPackPermissions(const char *pszDir)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync{
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTMsgInfo("Setting permissions...");
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#if !defined(RT_OS_WINDOWS)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync int rc = RTPathSetMode(pszDir, 0755);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to set directory permissions: %Rrc ('%s')", rc, pszDir);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#else
f5eadb22976c1f9813300e4042b8255cfaef7e19vboxsync /** @todo */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#endif
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTEXITCODE_SUCCESS;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync}
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/**
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Wrapper around VBoxExtPackValidateMember.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns Program exit code, failure with message.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pszName The name of the directory.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param enmType The object type.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param hVfsObj The VFS object.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic RTEXITCODE ValidateMemberOfExtPack(const char *pszName, RTVFSOBJTYPE enmType, RTVFSOBJ hVfsObj)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync{
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync char szError[8192];
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync int rc = VBoxExtPackValidateMember(pszName, enmType, hVfsObj, szError, sizeof(szError));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Assert(szError[0]);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s", szError);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Assert(!szError[0]);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTEXITCODE_SUCCESS;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync}
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/**
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Validates the extension pack tarball prior to unpacking.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Operations performed:
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * - Hardening checks.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns The program exit code.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pszDir The directory where the extension pack has been
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * unpacked.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pszExtPackName The expected extension pack name.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pszTarball The name of the tarball in case we have to
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * complain about something.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic RTEXITCODE ValidateUnpackedExtPack(const char *pszDir, const char *pszTarball, const char *pszExtPackName)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync{
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTMsgInfo("Validating unpacked extension pack...");
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTERRINFOSTATIC ErrInfo;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTErrInfoInitStatic(&ErrInfo);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync int rc = SUPR3HardenedVerifyDir(pszDir, true /*fRecursive*/, true /*fCheckFiles*/, &ErrInfo.Core);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Hardening check failed with %Rrc: %s", rc, ErrInfo.Core.pszMsg);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTEXITCODE_SUCCESS;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync}
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/**
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Unpacks a directory from an extension pack tarball.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns Program exit code, failure with message.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pszDstDirName The name of the unpacked directory.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param hVfsObj The source object for the directory.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic RTEXITCODE UnpackExtPackDir(const char *pszDstDirName, RTVFSOBJ hVfsObj)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync{
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Get the mode mask before creating the directory.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTFSOBJINFO ObjInfo;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync int rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszDstDirName, rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync ObjInfo.Attr.fMode &= ~(RTFS_UNIX_IWOTH | RTFS_UNIX_IWGRP);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTDirCreate(pszDstDirName, ObjInfo.Attr.fMode, 0);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create directory '%s': %Rrc", pszDstDirName, rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#ifndef RT_OS_WINDOWS
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Because of umask, we have to apply the mode again.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTPathSetMode(pszDstDirName, ObjInfo.Attr.fMode);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to set directory permissions on '%s': %Rrc", pszDstDirName, rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#else
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** @todo Ownership tricks on windows? */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#endif
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTEXITCODE_SUCCESS;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync}
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/**
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Unpacks a file from an extension pack tarball.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns Program exit code, failure with message.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pszName The name in the tarball.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pszDstFilename The name of the unpacked file.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param hVfsIosSrc The source stream for the file.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param hUnpackManifest The manifest to add the file digest to.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic RTEXITCODE UnpackExtPackFile(const char *pszName, const char *pszDstFilename,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTVFSIOSTREAM hVfsIosSrc, RTMANIFEST hUnpackManifest)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync{
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Query the object info, we'll need it for buffer sizing as well as
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * setting the file mode.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTFSOBJINFO ObjInfo;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync int rc = RTVfsIoStrmQueryInfo(hVfsIosSrc, &ObjInfo, RTFSOBJATTRADD_NOTHING);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsIoStrmQueryInfo failed with %Rrc on '%s'", rc, pszDstFilename);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Create the file.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync uint32_t fFlags = RTFILE_O_WRITE | RTFILE_O_DENY_ALL | RTFILE_O_CREATE | (0600 << RTFILE_O_CREATE_MODE_SHIFT);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTFILE hFile;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTFileOpen(&hFile, pszDstFilename, fFlags);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create '%s': %Rrc", pszDstFilename, rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Create a I/O stream for the destination file, stack a manifest entry
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * creator on top of it.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTVFSIOSTREAM hVfsIosDst2;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTVfsIoStrmFromRTFile(hFile, fFlags, true /*fLeaveOpen*/, &hVfsIosDst2);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_SUCCESS(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTVFSIOSTREAM hVfsIosDst;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTManifestEntryAddPassthruIoStream(hUnpackManifest, hVfsIosDst2, pszName,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTMANIFEST_ATTR_SIZE | RTMANIFEST_ATTR_SHA256,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync false /*fReadOrWrite*/, &hVfsIosDst);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTVfsIoStrmRelease(hVfsIosDst2);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_SUCCESS(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Pump the data thru.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTVfsUtilPumpIoStreams(hVfsIosSrc, hVfsIosDst, (uint32_t)RT_MIN(ObjInfo.cbObject, _1G));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_SUCCESS(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTManifestPtIosAddEntryNow(hVfsIosDst);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_SUCCESS(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTVfsIoStrmRelease(hVfsIosDst);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync hVfsIosDst = NIL_RTVFSIOSTREAM;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Set the mode mask.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync ObjInfo.Attr.fMode &= ~(RTFS_UNIX_IWOTH | RTFS_UNIX_IWGRP);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTFileSetMode(hFile, ObjInfo.Attr.fMode);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** @todo Windows needs to do more here, I think. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_SUCCESS(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTFileClose(hFile);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTEXITCODE_SUCCESS;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTMsgError("Failed to set the mode of '%s' to %RTfmode: %Rrc", pszDstFilename, ObjInfo.Attr.fMode, rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync else
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTMsgError("RTManifestPtIosAddEntryNow failed for '%s': %Rrc", pszDstFilename, rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync else
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTMsgError("RTVfsUtilPumpIoStreams failed for '%s': %Rrc", pszDstFilename, rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTVfsIoStrmRelease(hVfsIosDst);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync else
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTMsgError("RTManifestEntryAddPassthruIoStream failed: %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync else
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTMsgError("RTVfsIoStrmFromRTFile failed: %Rrc", rc);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync RTFileClose(hFile);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTEXITCODE_FAILURE;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync}
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
f5eadb22976c1f9813300e4042b8255cfaef7e19vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/**
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Unpacks the extension pack into the specified directory.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * This will apply ownership and permission changes to all the content, the
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * exception is @a pszDirDst which will be handled by SetExtPackPermissions.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns The program exit code.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param hTarballFile The tarball to unpack.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pszDirDst Where to unpack it.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param hValidManifest The manifest we've validated.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pszTarball The name of the tarball in case we have to
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * complain about something.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic RTEXITCODE UnpackExtPack(RTFILE hTarballFile, const char *pszDirDst, RTMANIFEST hValidManifest,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync const char *pszTarball)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync{
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTMsgInfo("Unpacking extension pack into '%s'...", pszDirDst);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Set up the destination path.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync char szDstPath[RTPATH_MAX];
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync int rc = RTPathAbs(pszDirDst, szDstPath, sizeof(szDstPath) - VBOX_EXTPACK_MAX_MEMBER_NAME_LENGTH - 2);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAbs('%s',,) failed: %Rrc", pszDirDst, rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync size_t offDstPath = RTPathStripTrailingSlash(szDstPath);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync szDstPath[offDstPath++] = '/';
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync szDstPath[offDstPath] = '\0';
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Open the tar.gz filesystem stream and set up an manifest in-memory file.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTVFSFSSTREAM hTarFss;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTEXITCODE rcExit = OpenTarFss(hTarballFile, &hTarFss);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (rcExit != RTEXITCODE_SUCCESS)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return rcExit;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTMANIFEST hUnpackManifest;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTManifestCreate(0 /*fFlags*/, &hUnpackManifest);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_SUCCESS(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Process the tarball (would be nice to move this to a function).
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync for (;;)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Get the next stream object.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync char *pszName;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTVFSOBJ hVfsObj;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTVFSOBJTYPE enmType;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTVfsFsStrmNext(hTarFss, &pszName, &enmType, &hVfsObj);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (rc != VERR_EOF)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsFsStrmNext failed: %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync break;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync const char *pszAdjName = pszName[0] == '.' && pszName[1] == '/' ? &pszName[2] : pszName;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Check the type & name validity then unpack it.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rcExit = ValidateMemberOfExtPack(pszName, enmType, hVfsObj);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (rcExit == RTEXITCODE_SUCCESS)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync szDstPath[offDstPath] = '\0';
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTStrCopy(&szDstPath[offDstPath], sizeof(szDstPath) - offDstPath, pszAdjName);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_SUCCESS(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if ( enmType == RTVFSOBJTYPE_FILE
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync || enmType == RTVFSOBJTYPE_IO_STREAM)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rcExit = UnpackExtPackFile(pszAdjName, szDstPath, hVfsIos, hUnpackManifest);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTVfsIoStrmRelease(hVfsIos);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync else if (*pszAdjName && strcmp(pszAdjName, "."))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rcExit = UnpackExtPackDir(szDstPath, hVfsObj);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync else
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Name is too long: '%s' (%Rrc)", pszAdjName, rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Clean up and break out on failure.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTVfsObjRelease(hVfsObj);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTStrFree(pszName);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (rcExit != RTEXITCODE_SUCCESS)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync break;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Check that what we just extracted matches the already verified
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * manifest.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (rcExit == RTEXITCODE_SUCCESS)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync char szError[RTPATH_MAX];
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTManifestEqualsEx(hUnpackManifest, hValidManifest, NULL /*papszIgnoreEntries*/, NULL /*papszIgnoreAttr*/,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync 0 /*fFlags*/, szError, sizeof(szError));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_SUCCESS(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTEXITCODE_SUCCESS;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync else if (rc == VERR_NOT_EQUAL && szError[0])
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Manifest mismatch: %s", szError);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync else
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTManifestEqualsEx failed: %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#if 0
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTVFSIOSTREAM hVfsIosStdOut = NIL_RTVFSIOSTREAM;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, RTFILE_O_WRITE, true, &hVfsIosStdOut);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTVfsIoStrmWrite(hVfsIosStdOut, "Unpack:\n", sizeof("Unpack:\n") - 1, true, NULL);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTManifestWriteStandard(hUnpackManifest, hVfsIosStdOut);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTVfsIoStrmWrite(hVfsIosStdOut, "Valid:\n", sizeof("Valid:\n") - 1, true, NULL);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTManifestWriteStandard(hValidManifest, hVfsIosStdOut);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#endif
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTManifestRelease(hUnpackManifest);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTVfsFsStrmRelease(hTarFss);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return rcExit;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync}
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/**
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Wrapper around VBoxExtPackValidateTarball.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns The program exit code.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param hTarballFile The handle to open the @a pszTarball file.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pszExtPackName The name of the extension pack name.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pszTarball The name of the tarball in case we have to
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * complain about something.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param phValidManifest Where to return the handle to fully validated
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * the manifest for the extension pack. This
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * includes all files.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic RTEXITCODE ValidateExtPackTarball(RTFILE hTarballFile, const char *pszExtPackName, const char *pszTarball,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync PRTMANIFEST phValidManifest)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync{
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *phValidManifest = NIL_RTMANIFEST;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTMsgInfo("Validating extension pack '%s' ('%s')...", pszTarball, pszExtPackName);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync char szError[8192];
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync int rc = VBoxExtPackValidateTarball(hTarballFile, pszExtPackName, pszTarball,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync szError, sizeof(szError), phValidManifest, NULL /*phXmlFile*/);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Assert(szError[0]);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s", szError);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Assert(!szError[0]);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTEXITCODE_SUCCESS;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync}
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/**
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * The 2nd part of the installation process.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns The program exit code.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pszBaseDir The base directory.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pszCertDir The certificat directory.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pszTarball The tarball name.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param hTarballFile The handle to open the @a pszTarball file.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param hTarballFileOpt The tarball file handle (optional).
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * @param pszName The extension pack name.
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * @param pszMangledName The mangled extension pack name.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param fReplace Whether to replace any existing ext pack.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic RTEXITCODE DoInstall2(const char *pszBaseDir, const char *pszCertDir, const char *pszTarball,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTFILE hTarballFile, RTFILE hTarballFileOpt,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync const char *pszName, const char *pszMangledName, bool fReplace)
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync{
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Do some basic validation of the tarball file.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTFSOBJINFO ObjInfo;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync int rc = RTFileQueryInfo(hTarballFile, &ObjInfo, RTFSOBJATTRADD_UNIX);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTFileQueryInfo failed with %Rrc on '%s'", rc, pszTarball);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (!RTFS_IS_FILE(ObjInfo.Attr.fMode))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Not a regular file: %s", pszTarball);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (hTarballFileOpt != NIL_RTFILE)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTFSOBJINFO ObjInfo2;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTFileQueryInfo(hTarballFileOpt, &ObjInfo2, RTFSOBJATTRADD_UNIX);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTFileQueryInfo failed with %Rrc on --tarball-fd", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if ( ObjInfo.Attr.u.Unix.INodeIdDevice != ObjInfo2.Attr.u.Unix.INodeIdDevice
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync || ObjInfo.Attr.u.Unix.INodeId != ObjInfo2.Attr.u.Unix.INodeId)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "--tarball and --tarball-fd does not match");
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Construct the paths to the two directories we'll be using.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync char szFinalPath[RTPATH_MAX];
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTPathJoin(szFinalPath, sizeof(szFinalPath), pszBaseDir, pszMangledName);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync "Failed to construct the path to the final extension pack directory: %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync char szTmpPath[RTPATH_MAX];
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTPathJoin(szTmpPath, sizeof(szTmpPath) - 64, pszBaseDir, pszMangledName);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_SUCCESS(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync size_t cchTmpPath = strlen(szTmpPath);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTStrPrintf(&szTmpPath[cchTmpPath], sizeof(szTmpPath) - cchTmpPath, "-_-inst-%u", (uint32_t)RTProcSelf());
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync "Failed to construct the path to the temporary extension pack directory: %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Check that they don't exist at this point in time, unless fReplace=true.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTPathQueryInfoEx(szFinalPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_SUCCESS(rc) && RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (!fReplace)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync "The extension pack is already installed. You must uninstall the old one first.");
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync else if (RT_SUCCESS(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync "Found non-directory file system object where the extension pack would be installed ('%s')",
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync szFinalPath);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync else if (rc != VERR_FILE_NOT_FOUND && rc != VERR_PATH_NOT_FOUND)
c77e7bff89c7639353778366984d51ff165ea0e3vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Unexpected RTPathQueryInfoEx status code %Rrc for '%s'", rc, szFinalPath);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTPathQueryInfoEx(szTmpPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (rc != VERR_FILE_NOT_FOUND && rc != VERR_PATH_NOT_FOUND)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Unexpected RTPathQueryInfoEx status code %Rrc for '%s'", rc, szFinalPath);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Create the temporary directory and prepare the extension pack within it.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * If all checks out correctly, rename it to the final directory.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTDirCreate(pszBaseDir, 0755, 0);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#ifndef RT_OS_WINDOWS
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Because of umask, we have to apply the mode again.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTPathSetMode(pszBaseDir, 0755);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to set directory permissions on '%s': %Rrc", pszBaseDir, rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#else
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** @todo Ownership tricks on windows? */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#endif
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTDirCreate(szTmpPath, 0700, 0);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create temporary directory: %Rrc ('%s')", rc, szTmpPath);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTMANIFEST hValidManifest = NIL_RTMANIFEST;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTEXITCODE rcExit = ValidateExtPackTarball(hTarballFile, pszName, pszTarball, &hValidManifest);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (rcExit == RTEXITCODE_SUCCESS)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rcExit = UnpackExtPack(hTarballFile, szTmpPath, hValidManifest, pszTarball);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (rcExit == RTEXITCODE_SUCCESS)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rcExit = ValidateUnpackedExtPack(szTmpPath, pszTarball, pszName);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (rcExit == RTEXITCODE_SUCCESS)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rcExit = SetExtPackPermissions(szTmpPath);
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync RTManifestRelease(hValidManifest);
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (rcExit == RTEXITCODE_SUCCESS)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTDirRename(szTmpPath, szFinalPath, RTPATHRENAME_FLAGS_NO_REPLACE);
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync if ( RT_FAILURE(rc)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync && fReplace
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync && RTDirExists(szFinalPath))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* Automatic uninstall if --replace was given. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rcExit = CommonUninstallWorker(szFinalPath);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (rcExit == RTEXITCODE_SUCCESS)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTDirRename(szTmpPath, szFinalPath, RTPATHRENAME_FLAGS_NO_REPLACE);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_SUCCESS(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTMsgInfo("Successfully installed '%s' (%s)", pszName, pszTarball);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync else if (rcExit == RTEXITCODE_SUCCESS)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync "Failed to rename the temporary directory to the final one: %Rrc ('%s' -> '%s')",
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc, szTmpPath, szFinalPath);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Clean up the temporary directory on failure.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (rcExit != RTEXITCODE_SUCCESS)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RemoveExtPackDir(szTmpPath, true /*fTemporary*/);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return rcExit;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync}
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/**
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Implements the 'install' command.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns The program exit code.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param argc The number of program arguments.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param argv The program arguments.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync */
37e7010b28a4667800196960b59cd63b5434b7d7vboxsyncstatic RTEXITCODE DoInstall(int argc, char **argv)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync{
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync /*
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * Parse the parameters.
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync *
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * Note! The --base-dir and --cert-dir are only for checking that the
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * caller and this help applications have the same idea of where
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * things are. Likewise, the --name is for verifying assumptions
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync * the caller made about the name. The optional --tarball-fd option
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * is just for easing the paranoia on the user side.
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync */
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync static const RTGETOPTDEF s_aOptions[] =
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync {
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync { "--base-dir", 'b', RTGETOPT_REQ_STRING },
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync { "--cert-dir", 'c', RTGETOPT_REQ_STRING },
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync { "--name", 'n', RTGETOPT_REQ_STRING },
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync { "--tarball", 't', RTGETOPT_REQ_STRING },
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync { "--tarball-fd", 'd', RTGETOPT_REQ_UINT64 },
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync { "--replace", 'r', RTGETOPT_REQ_NOTHING }
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync };
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync RTGETOPTSTATE GetState;
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync int rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0 /*fFlags*/);
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync if (RT_FAILURE(rc))
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOptInit failed: %Rrc\n", rc);
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync const char *pszBaseDir = NULL;
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync const char *pszCertDir = NULL;
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync const char *pszName = NULL;
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync const char *pszTarball = NULL;
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync RTFILE hTarballFileOpt = NIL_RTFILE;
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync bool fReplace = false;
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync RTGETOPTUNION ValueUnion;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync int ch;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync while ((ch = RTGetOpt(&GetState, &ValueUnion)))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync switch (ch)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync case 'b':
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (pszBaseDir)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many --base-dir options");
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync pszBaseDir = ValueUnion.psz;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (!IsValidBaseDir(pszBaseDir))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid base directory: '%s'", pszBaseDir);
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync break;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync case 'c':
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (pszCertDir)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many --cert-dir options");
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync pszCertDir = ValueUnion.psz;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (!IsValidCertificateDir(pszCertDir))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid certificate directory: '%s'", pszCertDir);
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync break;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync case 'n':
f7f5cd7b1e530eb5636da51c974b48ae0c1775b3vboxsync if (pszName)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many --name options");
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync pszName = ValueUnion.psz;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (!VBoxExtPackIsValidName(pszName))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid extension pack name: '%s'", pszName);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync break;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync case 't':
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (pszTarball)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many --tarball options");
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync pszTarball = ValueUnion.psz;
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync break;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync case 'd':
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (hTarballFileOpt != NIL_RTFILE)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many --tarball-fd options");
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync RTHCUINTPTR hNative = (RTHCUINTPTR)ValueUnion.u64;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync if (hNative != ValueUnion.u64)
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The --tarball-fd value is out of range: %#RX64", ValueUnion.u64);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync rc = RTFileFromNative(&hTarballFileOpt, hNative);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync if (RT_FAILURE(rc))
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "RTFileFromNative failed on --target-fd value: %Rrc", rc);
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync break;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync }
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync case 'r':
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync fReplace = true;
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync break;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync case 'h':
f7f5cd7b1e530eb5636da51c974b48ae0c1775b3vboxsync case 'V':
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync return DoStandardOption(ch);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync default:
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTGetOptPrintError(ch, &ValueUnion);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync }
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync }
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (!pszName)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing --name option");
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (!pszBaseDir)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing --base-dir option");
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (!pszCertDir)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing --cert-dir option");
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (!pszTarball)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing --tarball option");
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync /*
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * Ok, down to business.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync */
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync RTCString *pstrMangledName = VBoxExtPackMangleName(pszName);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (!pstrMangledName)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to mangle name ('%s)", pszName);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync RTEXITCODE rcExit;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync RTFILE hTarballFile;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync rc = RTFileOpen(&hTarballFile, pszTarball, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (RT_SUCCESS(rc))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync rcExit = DoInstall2(pszBaseDir, pszCertDir, pszTarball, hTarballFile, hTarballFileOpt,
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync pszName, pstrMangledName->c_str(), fReplace);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync RTFileClose(hTarballFile);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync }
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync else
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to open the extension pack tarball: %Rrc ('%s')", rc, pszTarball);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync delete pstrMangledName;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync return rcExit;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync}
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync/**
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * Implements the 'uninstall' command.
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync *
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync * @returns The program exit code.
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync * @param argc The number of program arguments.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * @param argv The program arguments.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync */
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsyncstatic RTEXITCODE DoUninstall(int argc, char **argv)
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync{
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync /*
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync * Parse the parameters.
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync *
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * Note! The --base-dir is only for checking that the caller and this help
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * applications have the same idea of where things are.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync */
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync static const RTGETOPTDEF s_aOptions[] =
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync { "--base-dir", 'b', RTGETOPT_REQ_STRING },
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync { "--name", 'n', RTGETOPT_REQ_STRING }
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync };
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync RTGETOPTSTATE GetState;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync int rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0 /*fFlags*/);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync if (RT_FAILURE(rc))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOptInit failed: %Rrc\n", rc);
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync const char *pszBaseDir = NULL;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync const char *pszName = NULL;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync RTGETOPTUNION ValueUnion;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync int ch;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync while ((ch = RTGetOpt(&GetState, &ValueUnion)))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync switch (ch)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync case 'b':
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (pszBaseDir)
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many --base-dir options");
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync pszBaseDir = ValueUnion.psz;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (!IsValidBaseDir(pszBaseDir))
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid base directory: '%s'", pszBaseDir);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync break;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync case 'n':
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync if (pszName)
d6c4b5eecea7735227dc41255d4e742543ddc86fvboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many --name options");
d6c4b5eecea7735227dc41255d4e742543ddc86fvboxsync pszName = ValueUnion.psz;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (!VBoxExtPackIsValidName(pszName))
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid extension pack name: '%s'", pszName);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync break;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync case 'h':
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync case 'V':
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return DoStandardOption(ch);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync default:
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync return RTGetOptPrintError(ch, &ValueUnion);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync }
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync }
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (!pszName)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing --name option");
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync if (!pszBaseDir)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing --base-dir option");
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync /*
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * Mangle the name so we can construct the directory names.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync */
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync RTCString *pstrMangledName = VBoxExtPackMangleName(pszName);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (!pstrMangledName)
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to mangle name ('%s)", pszName);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync RTCString strMangledName(*pstrMangledName);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync delete pstrMangledName;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync /*
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * Ok, down to business.
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync */
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync /* Check that it exists. */
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync char szExtPackDir[RTPATH_MAX];
79fe674227c3f2b82ab22a6b7d340283b610fb83vboxsync rc = RTPathJoin(szExtPackDir, sizeof(szExtPackDir), pszBaseDir, strMangledName.c_str());
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync if (RT_FAILURE(rc))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to construct extension pack path: %Rrc", rc);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync if (!RTDirExists(szExtPackDir))
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync RTMsgInfo("Extension pack not installed. Nothing to do.");
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTEXITCODE_SUCCESS;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync }
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync RTEXITCODE rcExit = CommonUninstallWorker(szExtPackDir);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (rcExit == RTEXITCODE_SUCCESS)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync RTMsgInfo("Successfully removed extension pack '%s'\n", pszName);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return rcExit;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync}
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync/**
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * Implements the 'cleanup' command.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync *
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * @returns The program exit code.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * @param argc The number of program arguments.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * @param argv The program arguments.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync */
37e7010b28a4667800196960b59cd63b5434b7d7vboxsyncstatic RTEXITCODE DoCleanup(int argc, char **argv)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync{
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync /*
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * Parse the parameters.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync *
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * Note! The --base-dir is only for checking that the caller and this help
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * applications have the same idea of where things are.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync */
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync static const RTGETOPTDEF s_aOptions[] =
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync { "--base-dir", 'b', RTGETOPT_REQ_STRING },
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync };
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync RTGETOPTSTATE GetState;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync int rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0 /*fFlags*/);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (RT_FAILURE(rc))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOptInit failed: %Rrc\n", rc);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync const char *pszBaseDir = NULL;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync RTGETOPTUNION ValueUnion;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync int ch;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync while ((ch = RTGetOpt(&GetState, &ValueUnion)))
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync switch (ch)
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync case 'b':
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (pszBaseDir)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many --base-dir options");
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync pszBaseDir = ValueUnion.psz;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (!IsValidBaseDir(pszBaseDir))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid base directory: '%s'", pszBaseDir);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync break;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync case 'h':
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync case 'V':
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return DoStandardOption(ch);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync default:
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTGetOptPrintError(ch, &ValueUnion);
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync }
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync }
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (!pszBaseDir)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing --base-dir option");
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync /*
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync * Ok, down to business.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync */
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync PRTDIR pDir;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync rc = RTDirOpen(&pDir, pszBaseDir);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (RT_FAILURE(rc))
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed open the base directory: %Rrc ('%s')", rc, pszBaseDir);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync uint32_t cCleaned = 0;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync for (;;)
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync {
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync RTDIRENTRYEX Entry;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync rc = RTDirReadEx(pDir, &Entry, NULL /*pcbDirEntry*/, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (RT_FAILURE(rc))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (rc != VERR_NO_MORE_FILES)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDirReadEx returns %Rrc", rc);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync break;
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync }
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync /*
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync * Only directories which conform with our temporary install/uninstall
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * naming scheme are candidates for cleaning.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync */
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if ( RTFS_IS_DIRECTORY(Entry.Info.Attr.fMode)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync && strcmp(Entry.szName, ".") != 0
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync && strcmp(Entry.szName, "..") != 0)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync bool fCandidate = false;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync char *pszMarker = strstr(Entry.szName, "-_-");
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if ( pszMarker
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync && ( !strcmp(pszMarker, "-_-uninst")
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync || !strncmp(pszMarker, "-_-inst", sizeof("-_-inst") - 1)))
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync fCandidate = VBoxExtPackIsValidMangledName(Entry.szName, pszMarker - &Entry.szName[0]);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (fCandidate)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync /*
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * Recursive delete, safe.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync */
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync char szPath[RTPATH_MAX];
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync rc = RTPathJoin(szPath, sizeof(szPath), pszBaseDir, Entry.szName);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (RT_SUCCESS(rc))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync RTEXITCODE rcExit2 = RemoveExtPackDir(szPath, true /*fTemporary*/);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (rcExit2 == RTEXITCODE_SUCCESS)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync RTMsgInfo("Successfully removed '%s'.", Entry.szName);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync else if (rcExit == RTEXITCODE_SUCCESS)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync rcExit = rcExit2;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync }
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync else
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathJoin failed with %Rrc for '%s'", rc, Entry.szName);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync cCleaned++;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync }
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync }
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync }
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync RTDirClose(pDir);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (!cCleaned)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync RTMsgInfo("Nothing to clean.");
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync return rcExit;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync}
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync#ifdef WITH_ELEVATION
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_DARWIN)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync/**
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * Looks in standard locations for a suitable exec tool.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync *
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * @returns true if found, false if not.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * @param pszPath Where to store the path to the tool on
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * successs.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * @param cbPath The size of the buffer @a pszPath points to.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * @param pszName The name of the tool we're looking for.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync */
37e7010b28a4667800196960b59cd63b5434b7d7vboxsyncstatic bool FindExecTool(char *pszPath, size_t cbPath, const char *pszName)
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync{
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync static const char * const s_apszPaths[] =
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync "/bin",
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync "/usr/bin",
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync "/usr/local/bin",
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync "/sbin",
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync "/usr/sbin",
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync "/usr/local/sbin",
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync#ifdef RT_OS_SOLARIS
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync "/usr/sfw/bin",
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync "/usr/gnu/bin",
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync "/usr/xpg4/bin",
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync "/usr/xpg6/bin",
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync "/usr/openwin/bin",
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync "/usr/ucb"
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync#endif
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync };
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync for (unsigned i = 0; i < RT_ELEMENTS(s_apszPaths); i++)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync int rc = RTPathJoin(pszPath, cbPath, s_apszPaths[i], pszName);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (RT_SUCCESS(rc))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync RTFSOBJINFO ObjInfo;
980eeb78f6811c935c7ebbe33de92f757ec3bc78vboxsync rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX, RTPATH_F_FOLLOW_LINK);
980eeb78f6811c935c7ebbe33de92f757ec3bc78vboxsync if (RT_SUCCESS(rc))
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync {
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync if (!(ObjInfo.Attr.fMode & RTFS_UNIX_IWOTH))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return true;
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync }
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync }
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync }
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync return false;
f5eadb22976c1f9813300e4042b8255cfaef7e19vboxsync}
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync#endif
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync/**
f5eadb22976c1f9813300e4042b8255cfaef7e19vboxsync * Copies the content of a file to a stream.
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync *
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync * @param hSrc The source file.
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync * @param pDst The destination stream.
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync * @param fComplain Whether to complain about errors (i.e. is this
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * stderr, if not keep the trap shut because it
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * may be missing when running under VBoxSVC.)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync */
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsyncstatic void CopyFileToStdXxx(RTFILE hSrc, PRTSTREAM pDst, bool fComplain)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync{
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync int rc;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync for (;;)
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync {
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync char abBuf[0x1000];
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync size_t cbRead;
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync rc = RTFileRead(hSrc, abBuf, sizeof(abBuf), &cbRead);
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync if (RT_FAILURE(rc))
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync {
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync RTMsgError("RTFileRead failed: %Rrc", rc);
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync break;
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync }
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync if (!cbRead)
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync break;
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync rc = RTStrmWrite(pDst, abBuf, cbRead);
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync if (RT_FAILURE(rc))
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync {
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync if (fComplain)
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync RTMsgError("RTStrmWrite failed: %Rrc", rc);
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync break;
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync }
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync }
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync rc = RTStrmFlush(pDst);
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync if (RT_FAILURE(rc) && fComplain)
f65d92209d8ab9f6093c0e2a90e7d5b73a2254fevboxsync RTMsgError("RTStrmFlush failed: %Rrc", rc);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync}
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync/**
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * Relaunches ourselves as a elevated process using platform specific facilities.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync *
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * @returns Program exit code.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * @param pszExecPath The executable path.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * @param papszArgs The arguments.
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync * @param cSuArgs The number of argument entries reserved for the
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * 'su' like programs at the start of papszArgs.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * @param cMyArgs The number of arguments following @a cSuArgs.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * @param iCmd The command that is being executed. (For
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * selecting messages.)
980eeb78f6811c935c7ebbe33de92f757ec3bc78vboxsync * @param pszDisplayInfoHack Display information hack. Platform specific++.
980eeb78f6811c935c7ebbe33de92f757ec3bc78vboxsync */
f7f5cd7b1e530eb5636da51c974b48ae0c1775b3vboxsyncstatic RTEXITCODE RelaunchElevatedNative(const char *pszExecPath, const char **papszArgs, int cSuArgs, int cMyArgs,
40577689fbf5c30d288d6c006f34329acdcdd97avboxsync int iCmd, const char *pszDisplayInfoHack)
980eeb78f6811c935c7ebbe33de92f757ec3bc78vboxsync{
980eeb78f6811c935c7ebbe33de92f757ec3bc78vboxsync RTEXITCODE rcExit = RTEXITCODE_FAILURE;
980eeb78f6811c935c7ebbe33de92f757ec3bc78vboxsync#ifdef RT_OS_WINDOWS
980eeb78f6811c935c7ebbe33de92f757ec3bc78vboxsync NOREF(iCmd);
980eeb78f6811c935c7ebbe33de92f757ec3bc78vboxsync
980eeb78f6811c935c7ebbe33de92f757ec3bc78vboxsync MSG Msg;
f7f5cd7b1e530eb5636da51c974b48ae0c1775b3vboxsync PeekMessage(&Msg, NULL, 0, 0, PM_NOREMOVE);
f7f5cd7b1e530eb5636da51c974b48ae0c1775b3vboxsync CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
f7f5cd7b1e530eb5636da51c974b48ae0c1775b3vboxsync
f7f5cd7b1e530eb5636da51c974b48ae0c1775b3vboxsync SHELLEXECUTEINFOW Info;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
f7f5cd7b1e530eb5636da51c974b48ae0c1775b3vboxsync Info.cbSize = sizeof(Info);
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync Info.fMask = SEE_MASK_NOCLOSEPROCESS;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync Info.hwnd = NULL;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync Info.lpVerb = L"runas";
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync int rc = RTStrToUtf16(pszExecPath, (PRTUTF16 *)&Info.lpFile);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (RT_SUCCESS(rc))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync char *pszCmdLine;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync rc = RTGetOptArgvToString(&pszCmdLine, &papszArgs[cSuArgs + 1], RTGETOPTARGV_CNV_QUOTE_MS_CRT);
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync if (RT_SUCCESS(rc))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync rc = RTStrToUtf16(pszCmdLine, (PRTUTF16 *)&Info.lpParameters);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (RT_SUCCESS(rc))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync Info.lpDirectory = NULL;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync Info.nShow = SW_SHOWMAXIMIZED;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync Info.hInstApp = NULL;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync Info.lpIDList = NULL;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync Info.lpClass = NULL;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync Info.hkeyClass = NULL;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync Info.dwHotKey = 0;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync Info.hMonitor = NULL;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync Info.hProcess = INVALID_HANDLE_VALUE;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync /* Apply display hacks. */
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (pszDisplayInfoHack)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync const char *pszArg = strstr(pszDisplayInfoHack, "hwnd=");
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (pszArg)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync uint64_t u64Hwnd;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync rc = RTStrToUInt64Ex(pszArg + sizeof("hwnd=") - 1, NULL, 0, &u64Hwnd);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (RT_SUCCESS(rc))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync HWND hwnd = (HWND)(uintptr_t)u64Hwnd;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync Info.hwnd = hwnd;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync Info.hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync }
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync }
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync }
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync if (Info.hMonitor == NULL)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync POINT Pt = {0,0};
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync Info.hMonitor = MonitorFromPoint(Pt, MONITOR_DEFAULTTOPRIMARY);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync }
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync if (Info.hMonitor != NULL)
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync Info.fMask |= SEE_MASK_HMONITOR;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync if (ShellExecuteExW(&Info))
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync {
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync if (Info.hProcess != INVALID_HANDLE_VALUE)
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync {
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync /*
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync * Wait for the process, make sure the deal with messages.
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync */
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync for (;;)
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync DWORD dwRc = MsgWaitForMultipleObjects(1, &Info.hProcess, FALSE, 5000/*ms*/, QS_ALLEVENTS);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (dwRc == WAIT_OBJECT_0)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync break;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if ( dwRc != WAIT_TIMEOUT
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync && dwRc != WAIT_OBJECT_0 + 1)
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync {
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync RTMsgError("MsgWaitForMultipleObjects returned: %#x (%d), err=%u", dwRc, dwRc, GetLastError());
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync break;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync }
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync MSG Msg;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync {
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync TranslateMessage(&Msg);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync DispatchMessageW(&Msg);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync }
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync }
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync DWORD dwExitCode;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync if (GetExitCodeProcess(Info.hProcess, &dwExitCode))
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (dwExitCode >= 0 && dwExitCode < 128)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync rcExit = (RTEXITCODE)dwExitCode;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync else
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync rcExit = RTEXITCODE_FAILURE;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync }
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync CloseHandle(Info.hProcess);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync }
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync else
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync RTMsgError("ShellExecuteExW return INVALID_HANDLE_VALUE as Info.hProcess");
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync }
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync else
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync RTMsgError("ShellExecuteExW failed: %u (%#x)", GetLastError(), GetLastError());
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync RTUtf16Free((PRTUTF16)Info.lpParameters);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync }
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync RTStrFree(pszCmdLine);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync }
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync RTUtf16Free((PRTUTF16)Info.lpFile);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync }
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync else
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync RTMsgError("RTStrToUtf16 failed: %Rc", rc);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync#elif defined(RT_OS_DARWIN)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync char szIconName[RTPATH_MAX];
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync int rc = RTPathAppPrivateArch(szIconName, sizeof(szIconName));
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync if (RT_SUCCESS(rc))
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync rc = RTPathAppend(szIconName, sizeof(szIconName), "../Resources/virtualbox.png");
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync if (RT_FAILURE(rc))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to construct icon path: %Rrc", rc);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync AuthorizationRef AuthRef;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync OSStatus orc = AuthorizationCreate(NULL, 0, kAuthorizationFlagDefaults, &AuthRef);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync if (orc == errAuthorizationSuccess)
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync {
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync /*
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync * Preautorize the privileged execution of ourselves.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync */
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync AuthorizationItem AuthItem = { kAuthorizationRightExecute, 0, NULL, 0 };
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync AuthorizationRights AuthRights = { 1, &AuthItem };
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync NOREF(iCmd);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync static char s_szPrompt[] = "VirtualBox needs further rights to make changes to your installation.\n\n";
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync AuthorizationItem aAuthEnvItems[] =
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync {
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync { kAuthorizationEnvironmentPrompt, strlen(s_szPrompt), s_szPrompt, 0 },
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync { kAuthorizationEnvironmentIcon, strlen(szIconName), szIconName, 0 }
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync };
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync AuthorizationEnvironment AuthEnv = { RT_ELEMENTS(aAuthEnvItems), aAuthEnvItems };
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync orc = AuthorizationCopyRights(AuthRef, &AuthRights, &AuthEnv,
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync kAuthorizationFlagPreAuthorize | kAuthorizationFlagInteractionAllowed
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync | kAuthorizationFlagExtendRights,
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync NULL);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync if (orc == errAuthorizationSuccess)
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync {
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync /*
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * Execute with extra permissions
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync */
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync FILE *pSocketStrm;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync orc = AuthorizationExecuteWithPrivileges(AuthRef, pszExecPath, kAuthorizationFlagDefaults,
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync (char * const *)&papszArgs[cSuArgs + 3],
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync &pSocketStrm);
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (orc == errAuthorizationSuccess)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync /*
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * Read the output of the tool, the read will fail when it quits.
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync */
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync for (;;)
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync char achBuf[1024];
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync size_t cbRead = fread(achBuf, 1, sizeof(achBuf), pSocketStrm);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync if (!cbRead)
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync break;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync fwrite(achBuf, 1, cbRead, stdout);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync }
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync rcExit = RTEXITCODE_SUCCESS;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync fclose(pSocketStrm);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync }
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync else
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync RTMsgError("AuthorizationExecuteWithPrivileges failed: %d", orc);
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync }
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync else if (orc == errAuthorizationCanceled)
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync RTMsgError("Authorization canceled by the user");
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync else
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync RTMsgError("AuthorizationCopyRights failed: %d", orc);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync AuthorizationFree(AuthRef, kAuthorizationFlagDefaults);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync }
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync else
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync RTMsgError("AuthorizationCreate failed: %d", orc);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync#else
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync /*
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync * Several of the alternatives below will require a command line.
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync */
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync char *pszCmdLine;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync int rc = RTGetOptArgvToString(&pszCmdLine, &papszArgs[cSuArgs], RTGETOPTARGV_CNV_QUOTE_BOURNE_SH);
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync if (RT_FAILURE(rc))
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOptArgvToString failed: %Rrc");
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync /*
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync * Look for various standard stuff for executing a program as root.
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync *
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync * N.B. When adding new arguments, please make 100% sure RelaunchElevated
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * allocates enough array entries.
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync *
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * TODO: Feel free to contribute code for using PolicyKit directly.
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync */
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync bool fHaveDisplayVar = RTEnvExist("DISPLAY");
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync int iSuArg = cSuArgs;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync char szExecTool[260];
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync char szXterm[260];
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync /*
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * kdesudo is available on KDE3/KDE4
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync */
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync if (fHaveDisplayVar && FindExecTool(szExecTool, sizeof(szExecTool), "kdesudo"))
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync iSuArg = cSuArgs - 4;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync papszArgs[cSuArgs - 4] = szExecTool;
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync papszArgs[cSuArgs - 3] = "--comment";
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync papszArgs[cSuArgs - 2] = iCmd == CMD_INSTALL
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync ? "VirtualBox extension pack installer"
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync : iCmd == CMD_UNINSTALL
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync ? "VirtualBox extension pack uninstaller"
33619506f3e6045180309528f76b39cc36760431vboxsync : "VirtualBox extension pack maintainer";
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync papszArgs[cSuArgs - 1] = "--";
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync }
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync /*
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * gksu is our favorite as it is very well integrated.
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync */
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync else if (fHaveDisplayVar && FindExecTool(szExecTool, sizeof(szExecTool), "gksu"))
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync#if 0 /* older gksu does not grok --description nor '--' and multiple args. */
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync iSuArg = cSuArgs - 4;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync papszArgs[cSuArgs - 4] = szExecTool;
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync papszArgs[cSuArgs - 3] = "--description";
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync papszArgs[cSuArgs - 2] = iCmd == CMD_INSTALL
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync ? "VirtualBox extension pack installer"
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync : iCmd == CMD_UNINSTALL
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync ? "VirtualBox extension pack uninstaller"
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync : "VirtualBox extension pack maintainer";
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync papszArgs[cSuArgs - 1] = "--";
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync#elif defined(RT_OS_SOLARIS) /* Force it not to use pfexec as it won't wait then. */
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync iSuArg = cSuArgs - 4;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync papszArgs[cSuArgs - 4] = szExecTool;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync papszArgs[cSuArgs - 3] = "-au";
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync papszArgs[cSuArgs - 2] = "root";
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync papszArgs[cSuArgs - 1] = pszCmdLine;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync papszArgs[cSuArgs] = NULL;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync#else
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync iSuArg = cSuArgs - 2;
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync papszArgs[cSuArgs - 2] = szExecTool;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync papszArgs[cSuArgs - 1] = pszCmdLine;
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync papszArgs[cSuArgs] = NULL;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync#endif
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync }
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync /*
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync * pkexec may work for ssh console sessions as well if the right agents
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * are installed. However it is very generic and does not allow for any
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync * custom messages. Thus it comes after gksu.
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync */
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync else if (FindExecTool(szExecTool, sizeof(szExecTool), "pkexec"))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync iSuArg = cSuArgs - 1;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync papszArgs[cSuArgs - 1] = szExecTool;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync }
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync /*
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync * The ultimate fallback is running 'su -' within an xterm. We use the
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync * title of the xterm to tell what is going on.
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync */
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync else if ( fHaveDisplayVar
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync && FindExecTool(szExecTool, sizeof(szExecTool), "su")
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync && FindExecTool(szXterm, sizeof(szXterm), "xterm"))
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync {
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync iSuArg = cSuArgs - 9;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync papszArgs[cSuArgs - 9] = szXterm;
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync papszArgs[cSuArgs - 8] = "-T";
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync papszArgs[cSuArgs - 7] = iCmd == CMD_INSTALL
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync ? "VirtualBox extension pack installer - su"
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync : iCmd == CMD_UNINSTALL
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync ? "VirtualBox extension pack uninstaller - su"
33619506f3e6045180309528f76b39cc36760431vboxsync : "VirtualBox extension pack maintainer - su";
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync papszArgs[cSuArgs - 6] = "-e";
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync papszArgs[cSuArgs - 5] = szExecTool;
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync papszArgs[cSuArgs - 4] = "-";
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync papszArgs[cSuArgs - 3] = "root";
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync papszArgs[cSuArgs - 2] = "-c";
37e7010b28a4667800196960b59cd63b5434b7d7vboxsync papszArgs[cSuArgs - 1] = pszCmdLine;
3ee1fadbf124a56daa99470bee91759440ef5da9vboxsync papszArgs[cSuArgs] = NULL;
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync }
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync else if (fHaveDisplayVar)
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync RTMsgError("Unable to locate 'pkexec', 'gksu' or 'su+xterm'. Try perform the operation using VBoxManage running as root");
9fbcdff887bd2d679720a8a50f5601df57b32b1bvboxsync else
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTMsgError("Unable to locate 'pkexec'. Try perform the operation using VBoxManage running as root");
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (iSuArg != cSuArgs)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync AssertRelease(iSuArg >= 0);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Argument list constructed, execute it and wait for the exec
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * program to complete.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTPROCESS hProcess;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTProcCreateEx(papszArgs[iSuArg], &papszArgs[iSuArg], RTENV_DEFAULT, 0 /*fFlags*/,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync NULL /*phStdIn*/, NULL /*phStdOut*/, NULL /*phStdErr*/, NULL /*pszAsUser*/, NULL /*pszPassword*/,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync &hProcess);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_SUCCESS(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTPROCSTATUS Status;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTProcWait(hProcess, RTPROCWAIT_FLAGS_BLOCK, &Status);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_SUCCESS(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (Status.enmReason == RTPROCEXITREASON_NORMAL)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rcExit = (RTEXITCODE)Status.iStatus;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync else
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rcExit = RTEXITCODE_FAILURE;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync else
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTMsgError("Error while waiting for '%s': %Rrc", papszArgs[iSuArg], rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync else
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTMsgError("Failed to execute '%s': %Rrc", papszArgs[iSuArg], rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTStrFree(pszCmdLine);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#endif
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return rcExit;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync}
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/**
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Relaunches ourselves as a elevated process using platform specific facilities.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns Program exit code.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param argc The number of arguments.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param argv The arguments.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param iCmd The command that is being executed.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pszDisplayInfoHack Display information hack. Platform specific++.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic RTEXITCODE RelaunchElevated(int argc, char **argv, int iCmd, const char *pszDisplayInfoHack)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync{
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * We need the executable name later, so get it now when it's easy to quit.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync char szExecPath[RTPATH_MAX];
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (!RTProcGetExecutablePath(szExecPath,sizeof(szExecPath)))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTProcGetExecutablePath failed");
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /*
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Create a couple of temporary files for stderr and stdout.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync char szTempDir[RTPATH_MAX - sizeof("/stderr")];
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync int rc = RTPathTemp(szTempDir, sizeof(szTempDir));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathTemp failed: %Rrc", rc);
rc = RTPathAppend(szTempDir, sizeof(szTempDir), "VBoxExtPackHelper-XXXXXX");
if (RT_FAILURE(rc))
return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAppend failed: %Rrc", rc);
rc = RTDirCreateTemp(szTempDir);
if (RT_FAILURE(rc))
return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDirCreateTemp failed: %Rrc", rc);
RTEXITCODE rcExit = RTEXITCODE_FAILURE;
char szStdOut[RTPATH_MAX];
char szStdErr[RTPATH_MAX];
rc = RTPathJoin(szStdOut, sizeof(szStdOut), szTempDir, "stdout");
if (RT_SUCCESS(rc))
rc = RTPathJoin(szStdErr, sizeof(szStdErr), szTempDir, "stderr");
if (RT_SUCCESS(rc))
{
RTFILE hStdOut;
rc = RTFileOpen(&hStdOut, szStdOut, RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_NONE
| (0600 << RTFILE_O_CREATE_MODE_SHIFT));
if (RT_SUCCESS(rc))
{
RTFILE hStdErr;
rc = RTFileOpen(&hStdErr, szStdErr, RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_NONE
| (0600 << RTFILE_O_CREATE_MODE_SHIFT));
if (RT_SUCCESS(rc))
{
/*
* Insert the --elevated and stdout/err names into the argument
* list. Note that darwin skips the --stdout bit, so don't
* change the order here.
*/
int const cSuArgs = 12;
int cArgs = argc + 5 + 1;
char const **papszArgs = (char const **)RTMemTmpAllocZ((cSuArgs + cArgs + 1) * sizeof(const char *));
if (papszArgs)
{
int iDst = cSuArgs;
papszArgs[iDst++] = argv[0];
papszArgs[iDst++] = "--stdout";
papszArgs[iDst++] = szStdOut;
papszArgs[iDst++] = "--stderr";
papszArgs[iDst++] = szStdErr;
papszArgs[iDst++] = "--elevated";
for (int iSrc = 1; iSrc <= argc; iSrc++)
papszArgs[iDst++] = argv[iSrc];
/*
* Do the platform specific process execution (waiting included).
*/
rcExit = RelaunchElevatedNative(szExecPath, papszArgs, cSuArgs, cArgs, iCmd, pszDisplayInfoHack);
/*
* Copy the standard files to our standard handles.
*/
CopyFileToStdXxx(hStdErr, g_pStdErr, true /*fComplain*/);
CopyFileToStdXxx(hStdOut, g_pStdOut, false);
RTMemTmpFree(papszArgs);
}
RTFileClose(hStdErr);
RTFileDelete(szStdErr);
}
RTFileClose(hStdOut);
RTFileDelete(szStdOut);
}
}
RTDirRemove(szTempDir);
return rcExit;
}
/**
* Checks if the process is elevated or not.
*
* @returns RTEXITCODE_SUCCESS if preconditions are fine,
* otherwise error message + RTEXITCODE_FAILURE.
* @param pfElevated Where to store the elevation indicator.
*/
static RTEXITCODE ElevationCheck(bool *pfElevated)
{
*pfElevated = false;
# if defined(RT_OS_WINDOWS)
/** @todo This should probably check if UAC is diabled and if we are
* Administrator first. Also needs to check for Vista+ first, probably.
*/
DWORD cb;
RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
HANDLE hToken;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
return RTMsgErrorExit(RTEXITCODE_FAILURE, "OpenProcessToken failed: %u (%#x)", GetLastError(), GetLastError());
/*
* Check if we're member of the Administrators group. If we aren't, there
* is no way to elevate ourselves to system admin.
* N.B. CheckTokenMembership does not do the job here (due to attributes?).
*/
BOOL fIsAdmin = FALSE;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
PSID pAdminGrpSid;
if (AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pAdminGrpSid))
{
# ifdef DEBUG
char *pszAdminGrpSid = NULL;
ConvertSidToStringSid(pAdminGrpSid, &pszAdminGrpSid);
# endif
if ( !GetTokenInformation(hToken, TokenGroups, NULL, 0, &cb)
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
PTOKEN_GROUPS pTokenGroups = (PTOKEN_GROUPS)RTMemAllocZ(cb);
if (GetTokenInformation(hToken, TokenGroups, pTokenGroups, cb, &cb))
{
for (DWORD iGrp = 0; iGrp < pTokenGroups->GroupCount; iGrp++)
{
# ifdef DEBUG
char *pszGrpSid = NULL;
ConvertSidToStringSid(pTokenGroups->Groups[iGrp].Sid, &pszGrpSid);
# endif
if (EqualSid(pAdminGrpSid, pTokenGroups->Groups[iGrp].Sid))
{
/* That it's listed is enough I think, ignore attributes. */
fIsAdmin = TRUE;
break;
}
}
}
else
rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "GetTokenInformation(TokenGroups,cb) failed: %u (%#x)", GetLastError(), GetLastError());
RTMemFree(pTokenGroups);
}
else
rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "GetTokenInformation(TokenGroups,0) failed: %u (%#x)", GetLastError(), GetLastError());
FreeSid(pAdminGrpSid);
}
else
rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "AllocateAndInitializeSid failed: %u (%#x)", GetLastError(), GetLastError());
if (fIsAdmin)
{
/*
* Check the integrity level (Vista / UAC).
*/
# define MY_SECURITY_MANDATORY_HIGH_RID 0x00003000L
# define MY_TokenIntegrityLevel ((TOKEN_INFORMATION_CLASS)25)
if ( !GetTokenInformation(hToken, MY_TokenIntegrityLevel, NULL, 0, &cb)
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
PSID_AND_ATTRIBUTES pSidAndAttr = (PSID_AND_ATTRIBUTES)RTMemAlloc(cb);
if (GetTokenInformation(hToken, MY_TokenIntegrityLevel, pSidAndAttr, cb, &cb))
{
DWORD dwIntegrityLevel = *GetSidSubAuthority(pSidAndAttr->Sid, *GetSidSubAuthorityCount(pSidAndAttr->Sid) - 1U);
if (dwIntegrityLevel >= MY_SECURITY_MANDATORY_HIGH_RID)
*pfElevated = true;
}
else
rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "GetTokenInformation failed: %u (%#x)", GetLastError(), GetLastError());
RTMemFree(pSidAndAttr);
}
else if ( GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == ERROR_NOT_SUPPORTED)
*pfElevated = true; /* Older Windows version. */
else
rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "GetTokenInformation failed: %u (%#x)", GetLastError(), GetLastError());
}
else
rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Membership in the Administrators group is required to perform this action");
CloseHandle(hToken);
return rcExit;
# else
/*
* On Unixy systems, we check if the executable and the current user is
* the same. This heuristic works fine for both hardened and development
* builds.
*/
char szExecPath[RTPATH_MAX];
if (RTProcGetExecutablePath(szExecPath, sizeof(szExecPath)) == NULL)
return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTProcGetExecutablePath failed");
RTFSOBJINFO ObjInfo;
int rc = RTPathQueryInfoEx(szExecPath, &ObjInfo, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
if (RT_FAILURE(rc))
return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathQueryInfoEx failed");
*pfElevated = ObjInfo.Attr.u.Unix.uid == geteuid()
|| ObjInfo.Attr.u.Unix.uid == getuid();
return RTEXITCODE_SUCCESS;
# endif
}
#endif /* WITH_ELEVATION */
int main(int argc, char **argv)
{
/*
* Initialize IPRT and check that we're correctly installed.
*/
int rc = RTR3InitExe(argc, &argv, 0);
if (RT_FAILURE(rc))
return RTMsgInitFailure(rc);
RTERRINFOSTATIC ErrInfo;
RTErrInfoInitStatic(&ErrInfo);
rc = SUPR3HardenedVerifySelf(argv[0], true /*fInternal*/, &ErrInfo.Core);
if (RT_FAILURE(rc))
return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s", ErrInfo.Core.pszMsg);
/*
* Elevation check.
*/
const char *pszDisplayInfoHack = NULL;
RTEXITCODE rcExit;
#ifdef WITH_ELEVATION
bool fElevated;
rcExit = ElevationCheck(&fElevated);
if (rcExit != RTEXITCODE_SUCCESS)
return rcExit;
#endif
/*
* Parse the top level arguments until we find a command.
*/
static const RTGETOPTDEF s_aOptions[] =
{
{ "install", CMD_INSTALL, RTGETOPT_REQ_NOTHING },
{ "uninstall", CMD_UNINSTALL, RTGETOPT_REQ_NOTHING },
{ "cleanup", CMD_CLEANUP, RTGETOPT_REQ_NOTHING },
#ifdef WITH_ELEVATION
{ "--elevated", OPT_ELEVATED, RTGETOPT_REQ_NOTHING },
{ "--stdout", OPT_STDOUT, RTGETOPT_REQ_STRING },
{ "--stderr", OPT_STDERR, RTGETOPT_REQ_STRING },
#endif
{ "--display-info-hack", OPT_DISP_INFO_HACK, RTGETOPT_REQ_STRING },
};
RTGETOPTSTATE GetState;
rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0 /*fFlags*/);
if (RT_FAILURE(rc))
return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOptInit failed: %Rrc\n", rc);
for (;;)
{
RTGETOPTUNION ValueUnion;
int ch = RTGetOpt(&GetState, &ValueUnion);
switch (ch)
{
case 0:
return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No command specified");
case CMD_INSTALL:
case CMD_UNINSTALL:
case CMD_CLEANUP:
{
#ifdef WITH_ELEVATION
if (!fElevated)
return RelaunchElevated(argc, argv, ch, pszDisplayInfoHack);
#endif
int cCmdargs = argc - GetState.iNext;
char **papszCmdArgs = argv + GetState.iNext;
switch (ch)
{
case CMD_INSTALL:
rcExit = DoInstall( cCmdargs, papszCmdArgs);
break;
case CMD_UNINSTALL:
rcExit = DoUninstall(cCmdargs, papszCmdArgs);
break;
case CMD_CLEANUP:
rcExit = DoCleanup( cCmdargs, papszCmdArgs);
break;
default:
AssertReleaseFailedReturn(RTEXITCODE_FAILURE);
}
/*
* Standard error should end with rcExit=RTEXITCODE_SUCCESS on
* success since the exit code may otherwise get lost in the
* process elevation fun.
*/
RTStrmFlush(g_pStdOut);
RTStrmFlush(g_pStdErr);
switch (rcExit)
{
case RTEXITCODE_SUCCESS:
RTStrmPrintf(g_pStdErr, "rcExit=RTEXITCODE_SUCCESS\n");
break;
default:
RTStrmPrintf(g_pStdErr, "rcExit=%d\n", rcExit);
break;
}
RTStrmFlush(g_pStdErr);
RTStrmFlush(g_pStdOut);
return rcExit;
}
#ifdef WITH_ELEVATION
case OPT_ELEVATED:
fElevated = true;
break;
case OPT_STDERR:
case OPT_STDOUT:
{
FILE *pFile = freopen(ValueUnion.psz, "r+", ch == OPT_STDOUT ? stdout : stderr);
if (!pFile)
{
rc = RTErrConvertFromErrno(errno);
return RTMsgErrorExit(RTEXITCODE_FAILURE, "freopen on '%s': %Rrc", ValueUnion.psz, rc);
}
break;
}
#endif
case OPT_DISP_INFO_HACK:
if (pszDisplayInfoHack)
return RTMsgErrorExit(RTEXITCODE_SYNTAX, "--display-info-hack shall only occur once");
pszDisplayInfoHack = ValueUnion.psz;
break;
case 'h':
case 'V':
return DoStandardOption(ch);
default:
return RTGetOptPrintError(ch, &ValueUnion);
}
/* not currently reached */
}
/* not reached */
}
#ifdef RT_OS_WINDOWS
extern "C" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
g_hInstance = hInstance;
NOREF(hPrevInstance); NOREF(nShowCmd); NOREF(lpCmdLine);
int rc = RTR3InitExeNoArguments(0);
if (RT_FAILURE(rc))
return RTMsgInitFailure(rc);
LPWSTR pwszCmdLine = GetCommandLineW();
if (!pwszCmdLine)
return RTMsgErrorExit(RTEXITCODE_FAILURE, "GetCommandLineW failed");
char *pszCmdLine;
rc = RTUtf16ToUtf8(pwszCmdLine, &pszCmdLine); /* leaked */
if (RT_FAILURE(rc))
return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to convert the command line: %Rrc", rc);
int cArgs;
char **papszArgs;
rc = RTGetOptArgvFromString(&papszArgs, &cArgs, pszCmdLine, NULL);
if (RT_SUCCESS(rc))
{
rc = main(cArgs, papszArgs);
RTGetOptArgvFree(papszArgs);
}
else
rc = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOptArgvFromString failed: %Rrc", rc);
RTStrFree(pszCmdLine);
return rc;
}
#endif