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