Index: /trunk/Config.kmk
===================================================================
--- /trunk/Config.kmk	(revision 33805)
+++ /trunk/Config.kmk	(revision 33806)
@@ -3008,4 +3008,13 @@
 
 #
+# Template for building set-uid-to-root helper programs.
+# These shall have not extra runpaths, esp. not origin ones.
+#
+TEMPLATE_VBoxR3SetUidToRoot = Set-uid-to-root helper program.
+TEMPLATE_VBoxR3SetUidToRoot_EXTENDS = VBOXR3HARDENEDEXE
+TEMPLATE_VBoxR3SetUidToRoot_LIBS = $(NO_SUCH_VARIABLE)
+
+
+#
 # Template for building R3 shared objects / DLLs with the 10.5 Mac OS X SDK.
 # Identical to VBOXR3EXE, except for the DYLIB, the classic_linker and SDK bits.
Index: /trunk/include/VBox/err.h
===================================================================
--- /trunk/include/VBox/err.h	(revision 33805)
+++ /trunk/include/VBox/err.h	(revision 33806)
@@ -1390,4 +1390,9 @@
 /** The file or directory is world writable (hardening). */
 #define VERR_SUPLIB_WORLD_WRITABLE                  (-3767)
+/** The argv[0] of an internal application does not match the executable image
+ * path (hardening). */
+#define VERR_SUPLIB_INVALID_ARGV0_INTERNAL          (-3768)
+/** The internal application does not reside in the correct place (hardening). */
+#define VERR_SUPLIB_INVALID_INTERNAL_APP_DIR        (-3769)
 /** @} */
 
Index: /trunk/include/VBox/sup.h
===================================================================
--- /trunk/include/VBox/sup.h	(revision 33805)
+++ /trunk/include/VBox/sup.h	(revision 33806)
@@ -971,6 +971,24 @@
  * @param   phFile          Where to store the handle to the opened file. This is optional, pass NULL
  *                          if the file should not be opened.
+ * @deprecated Write a new one.
  */
 SUPR3DECL(int) SUPR3HardenedVerifyFile(const char *pszFilename, const char *pszWhat, PRTFILE phFile);
+
+/**
+ * Verifies the integrity of a the current process, including the image
+ * location and that the invocation was absolute.
+ *
+ * This must currently be called after initializing the runtime.  The intended
+ * audience is set-uid-to-root applications, root services and similar.
+ *
+ * @returns VBox status code.  On failure
+ *          message.
+ * @param   pszArgv0        The first argument to main().
+ * @param   fInternal       Set this to @c true if this is an internal
+ *                          VirtualBox application.  Otherwise pass @c false.
+ * @param   pszErr          Where to return error message on failure.
+ * @param   cbErr           The size of the error buffer.
+ */
+SUPR3DECL(int) SUPR3HardenedVerifySelf(const char *pszArgv0, bool fInternal, char *pszErr, size_t cbErr);
 
 /**
Index: /trunk/include/iprt/process.h
===================================================================
--- /trunk/include/iprt/process.h	(revision 33805)
+++ /trunk/include/iprt/process.h	(revision 33806)
@@ -282,12 +282,19 @@
 
 /**
- * Gets the executable image name (full path) of the current process.
- *
- * @returns pszExecName on success. NULL on buffer overflow or other errors.
- *
- * @param   pszExecName     Where to store the name.
- * @param   cchExecName     The size of the buffer.
- */
-RTR3DECL(char *) RTProcGetExecutableName(char *pszExecName, size_t cchExecName);
+ * Gets the short process name.
+ *
+ * @returns Pointer to read-only name string.
+ */
+RTR3DECL(const char *) RTProcShortName(void);
+
+/**
+ * Gets the path to the executable image of the current process.
+ *
+ * @returns pszExecPath on success. NULL on buffer overflow or other errors.
+ *
+ * @param   pszExecPath     Where to store the path.
+ * @param   cbExecPath      The size of the buffer.
+ */
+RTR3DECL(char *) RTProcGetExecutablePath(char *pszExecPath, size_t cbExecPath);
 
 /**
Index: /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlExec.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlExec.cpp	(revision 33805)
+++ /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlExec.cpp	(revision 33806)
@@ -1049,5 +1049,5 @@
     /* Search the path of our executable. */
     char szVBoxService[RTPATH_MAX];
-    if (RTProcGetExecutableName(szVBoxService, sizeof(szVBoxService)))
+    if (RTProcGetExecutablePath(szVBoxService, sizeof(szVBoxService)))
     {
         char *pszExecResolved = NULL;
Index: /trunk/src/VBox/Additions/common/VBoxService/VBoxServicePageSharing.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxService/VBoxServicePageSharing.cpp	(revision 33805)
+++ /trunk/src/VBox/Additions/common/VBoxService/VBoxServicePageSharing.cpp	(revision 33806)
@@ -690,5 +690,5 @@
         {
             char szExeName[256];
-            char *pszExeName = RTProcGetExecutableName(szExeName, sizeof(szExeName));
+            char *pszExeName = RTProcGetExecutablePath(szExeName, sizeof(szExeName));
             if (pszExeName)
             {
Index: /trunk/src/VBox/HostDrivers/Support/SUPLib.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPLib.cpp	(revision 33805)
+++ /trunk/src/VBox/HostDrivers/Support/SUPLib.cpp	(revision 33806)
@@ -1438,4 +1438,76 @@
 
 
+SUPR3DECL(int) SUPR3HardenedVerifySelf(const char *pszArgv0, bool fInternal, char *pszErr, size_t cbErr)
+{
+    /*
+     * Quick input validation.
+     */
+    AssertPtr(pszArgv0);
+    AssertPtr(pszErr);
+    Assert(cbErr > 32);
+
+    /*
+     * Get the executable image path as we need it for all the tests here.
+     */
+    char szExecPath[RTPATH_MAX];
+    if (!RTProcGetExecutablePath(szExecPath, sizeof(szExecPath)))
+    {
+        RTStrPrintf(pszErr, cbErr, "RTProcGetExecutablePath failed");
+        return VERR_INTERNAL_ERROR_2;
+    }
+
+    int rc;
+    if (fInternal)
+    {
+        /*
+         * Internal applications must be launched directly without any PATH
+         * searching involved.
+         */
+        if (RTPathCompare(pszArgv0, szExecPath) != 0)
+        {
+            RTStrPrintf(pszErr, cbErr, "argv[0] does not match the executable image path: '%s' != '%s'", pszArgv0, szExecPath);
+            return VERR_SUPLIB_INVALID_ARGV0_INTERNAL;
+        }
+
+        /*
+         * Internal applications must reside in or under the
+         * RTPathAppPrivateArch directory.
+         */
+        char szAppPrivateArch[RTPATH_MAX];
+        rc = RTPathAppPrivateArch(szAppPrivateArch, sizeof(szAppPrivateArch));
+        if (RT_FAILURE(rc))
+        {
+            RTStrPrintf(pszErr, cbErr, "RTPathAppPrivateArch failed with rc=%Rrc", rc);
+            return VERR_SUPLIB_INVALID_ARGV0_INTERNAL;
+        }
+        size_t cchAppPrivateArch = strlen(szAppPrivateArch);
+        if (   cchAppPrivateArch >= strlen(szExecPath)
+            || !RTPATH_IS_SLASH(szExecPath[cchAppPrivateArch]))
+        {
+            RTStrPrintf(pszErr, cbErr, "Internal executable does reside under RTPathAppPrivateArch");
+            return VERR_SUPLIB_INVALID_INTERNAL_APP_DIR;
+        }
+        szExecPath[cchAppPrivateArch] = '\0';
+        if (RTPathCompare(szExecPath, szAppPrivateArch) != 0)
+        {
+            RTStrPrintf(pszErr, cbErr, "Internal executable does reside under RTPathAppPrivateArch");
+            return VERR_SUPLIB_INVALID_INTERNAL_APP_DIR;
+        }
+        szExecPath[cchAppPrivateArch] = RTPATH_SLASH;
+    }
+
+#ifdef VBOX_WITH_HARDENING
+    /*
+     * Verify that the image file and parent directories are sane.
+     */
+    rc = supR3HardenedVerifyFile(szPath, NULL, pszErr, cbErr);
+    if (RT_FAILURE(rc))
+        return rc;
+#endif
+
+    return VINF_SUCCESS;
+}
+
+
 SUPR3DECL(int) SUPR3HardenedVerifyDir(const char *pszDirPath, bool fRecursive, bool fCheckFiles, char *pszErr, size_t cbErr)
 {
Index: /trunk/src/VBox/HostServices/GuestControl/testcase/tstGuestControlSvc.cpp
===================================================================
--- /trunk/src/VBox/HostServices/GuestControl/testcase/tstGuestControlSvc.cpp	(revision 33805)
+++ /trunk/src/VBox/HostServices/GuestControl/testcase/tstGuestControlSvc.cpp	(revision 33806)
@@ -1127,6 +1127,6 @@
 
     /* Save image name for later use. */
-    if (!RTProcGetExecutableName(g_szImageName, sizeof(g_szImageName)))
-        return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTProcGetExecutableName failed\n");
+    if (!RTProcGetExecutablePath(g_szImageName, sizeof(g_szImageName)))
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTProcGetExecutablePath failed\n");
 
     VBOXHGCMSVCFNTABLE svcTable;
Index: /trunk/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa.c
===================================================================
--- /trunk/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa.c	(revision 33805)
+++ /trunk/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa.c	(revision 33806)
@@ -68,5 +68,5 @@
     /* VirtualBox is the only frontend which support 3D right now. */
     char pszName[256];
-    if (RTProcGetExecutableName(pszName, sizeof(pszName)))
+    if (RTProcGetExecutablePath(pszName, sizeof(pszName)))
         /* Check for VirtualBox and VirtualBoxVM */
         if (RTStrNICmp(RTPathFilename(pszName), "VirtualBox", 10) != 0)
Index: /trunk/src/VBox/Main/ConsoleImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/ConsoleImpl.cpp	(revision 33805)
+++ /trunk/src/VBox/Main/ConsoleImpl.cpp	(revision 33806)
@@ -5066,5 +5066,5 @@
         /* the package type is interesting for Linux distributions */
         char szExecName[RTPATH_MAX];
-        char *pszExecName = RTProcGetExecutableName(szExecName, sizeof(szExecName));
+        char *pszExecName = RTProcGetExecutablePath(szExecName, sizeof(szExecName));
         RTLogRelLogger(loggerRelease, 0, ~0U,
                        "Executable: %s\n"
Index: /trunk/src/VBox/Main/DHCPServerRunner.cpp
===================================================================
--- /trunk/src/VBox/Main/DHCPServerRunner.cpp	(revision 33805)
+++ /trunk/src/VBox/Main/DHCPServerRunner.cpp	(revision 33806)
@@ -83,5 +83,5 @@
     /* get the path to the executable */
     char exePathBuf[RTPATH_MAX];
-    const char *exePath = RTProcGetExecutableName(exePathBuf, RTPATH_MAX);
+    const char *exePath = RTProcGetExecutablePath(exePathBuf, RTPATH_MAX);
     char *substrSl = strrchr(exePathBuf, '/');
     char *substrBs = strrchr(exePathBuf, '\\');
Index: /trunk/src/VBox/Main/ExtPackManagerImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/ExtPackManagerImpl.cpp	(revision 33805)
+++ /trunk/src/VBox/Main/ExtPackManagerImpl.cpp	(revision 33806)
@@ -445,5 +445,5 @@
     if (RT_FAILURE(vrc))
     {
-        m->strWhyUnusable.printf(tr("%s"), szErr);
+        m->strWhyUnusable.printf(tr("%s (rc=%Rrc)"), szErr, vrc);
         return;
     }
@@ -842,11 +842,11 @@
     int rc = RTPathAppPrivateArch(szBaseDir, sizeof(szBaseDir));
     AssertLogRelRCReturn(rc, E_FAIL);
-    rc = RTPathAppend(szBaseDir, sizeof(szBaseDir), "ExtensionPacks");
+    rc = RTPathAppend(szBaseDir, sizeof(szBaseDir), VBOX_EXTPACK_INSTALL_DIR);
     AssertLogRelRCReturn(rc, E_FAIL);
 
     char szCertificatDir[RTPATH_MAX];
-    rc = RTPathAppPrivateArch(szCertificatDir, sizeof(szCertificatDir));
+    rc = RTPathAppPrivateNoArch(szCertificatDir, sizeof(szCertificatDir));
     AssertLogRelRCReturn(rc, E_FAIL);
-    rc = RTPathAppend(szBaseDir, sizeof(szCertificatDir), "Certificates");
+    rc = RTPathAppend(szBaseDir, sizeof(szCertificatDir), VBOX_EXTPACK_CERT_DIR);
     AssertLogRelRCReturn(rc, E_FAIL);
 
@@ -882,5 +882,6 @@
             if (   RTFS_IS_DIRECTORY(Entry.Info.Attr.fMode)
                 && strcmp(Entry.szName, ".")  != 0
-                && strcmp(Entry.szName, "..") != 0 )
+                && strcmp(Entry.szName, "..") != 0
+                && VBoxExtPackIsValidName(Entry.szName) )
             {
                 /*
@@ -1003,72 +1004,58 @@
                     /*
                      * Derive the name of the extension pack from the file
-                     * name.
-                     *
-                     * RESTRICTION: The name can only contain english alphabet
-                     *              charactes, decimal digits and space.
-                     *              Impose a max length of 64 chars.
+                     * name.  Certain restrictions are here placed on the
+                     * tarball name.
                      */
-                    char *pszName = RTStrDup(RTPathFilename(strTarball.c_str()));
-                    if (pszName)
+                    iprt::MiniString *pStrName = VBoxExtPackExtractNameFromTarballPath(strTarball.c_str());
+                    if (pStrName)
                     {
-                        char *pszEnd = pszName;
-                        while (RT_C_IS_ALNUM(*pszEnd) || *pszEnd == ' ')
-                            pszEnd++;
-                        if (   pszEnd == pszName
-                            || pszEnd - pszName <= 64)
+                        /*
+                         * Refresh the data we have on the extension pack as it
+                         * may be made stale by direct meddling or some other user.
+                         */
+                        ExtPack *pExtPack;
+                        hrc = refreshExtPack(pStrName->c_str(), false /*a_fUnsuableIsError*/, &pExtPack);
+                        if (SUCCEEDED(hrc) && !pExtPack)
                         {
-                            *pszEnd = '\0';
-
                             /*
-                             * Refresh the data we have on the extension pack
-                             * as it may be made stale by direct meddling or
-                             * some other user.
+                             * Run the set-uid-to-root binary that performs the actual
+                             * installation.  Then create an object for the packet (we
+                             * do this even on failure, to be on the safe side).
                              */
-                            ExtPack *pExtPack;
-                            hrc = refreshExtPack(pszName, false /*a_fUnsuableIsError*/, &pExtPack);
-                            if (SUCCEEDED(hrc) && !pExtPack)
+                            char szTarballFd[64];
+                            RTStrPrintf(szTarballFd, sizeof(szTarballFd), "0x%RX64",
+                                        (uint64_t)RTFileToNative(hFile));
+
+                            hrc = runSetUidToRootHelper("install",
+                                                        "--base-dir",        m->strBaseDir.c_str(),
+                                                        "--certificate-dir", m->strCertificatDirPath.c_str(),
+                                                        "--name",            pStrName->c_str(),
+                                                        "--tarball",         strTarball.c_str(),
+                                                        "--tarball-fd",      &szTarballFd[0],
+                                                        NULL);
+                            if (SUCCEEDED(hrc))
                             {
-                                /*
-                                 * Run the set-uid-to-root binary that performs the actual
-                                 * installation.  Then create an object for the packet (we
-                                 * do this even on failure, to be on the safe side).
-                                 */
-                                char szTarballFd[64];
-                                RTStrPrintf(szTarballFd, sizeof(szTarballFd), "0x%RX64",
-                                            (uint64_t)RTFileToNative(hFile));
-
-                                hrc = runSetUidToRootHelper("install",
-                                                            "--base-dir",        m->strBaseDir.c_str(),
-                                                            "--name",            pszName,
-                                                            "--certificate-dir", m->strCertificatDirPath.c_str(),
-                                                            "--tarball",         strTarball.c_str(),
-                                                            "--tarball-fd",      &szTarballFd[0],
-                                                            NULL);
+                                hrc = refreshExtPack(pStrName->c_str(), true /*a_fUnsuableIsError*/, &pExtPack);
                                 if (SUCCEEDED(hrc))
                                 {
-                                    hrc = refreshExtPack(pszName, true /*a_fUnsuableIsError*/, &pExtPack);
-                                    if (SUCCEEDED(hrc))
-                                    {
-                                        LogRel(("ExtPackManager: Successfully installed extension pack '%s'.\n", pszName));
-                                        pExtPack->callInstalledHook();
-                                    }
-                                }
-                                else
-                                {
-                                    ErrorInfoKeeper Eik;
-                                    refreshExtPack(pszName, false /*a_fUnsuableIsError*/, NULL);
+                                    LogRel(("ExtPackManager: Successfully installed extension pack '%s'.\n", pStrName->c_str()));
+                                    pExtPack->callInstalledHook();
                                 }
                             }
-                            else if (SUCCEEDED(hrc))
-                                hrc = setError(E_FAIL,
-                                               tr("Extension pack '%s' is already installed."
-                                                  " In case of a reinstallation, please uninstall it first"),
-                                               pszName);
+                            else
+                            {
+                                ErrorInfoKeeper Eik;
+                                refreshExtPack(pStrName->c_str(), false /*a_fUnsuableIsError*/, NULL);
+                            }
                         }
-                        else
-                            hrc = setError(E_FAIL, tr("Malformed '%s' file name"), strTarball.c_str());
+                        else if (SUCCEEDED(hrc))
+                            hrc = setError(E_FAIL,
+                                           tr("Extension pack '%s' is already installed."
+                                              " In case of a reinstallation, please uninstall it first"),
+                                           pStrName->c_str());
+                        delete pStrName;
                     }
                     else
-                        hrc = E_OUTOFMEMORY;
+                        hrc = setError(E_FAIL, tr("Malformed '%s' file name"), strTarball.c_str());
                 }
                 else if (RT_SUCCESS(vrc))
Index: /trunk/src/VBox/Main/ExtPackUtil.cpp
===================================================================
--- /trunk/src/VBox/Main/ExtPackUtil.cpp	(revision 33805)
+++ /trunk/src/VBox/Main/ExtPackUtil.cpp	(revision 33806)
@@ -15,5 +15,5 @@
 *   Header Files                                                               *
 *******************************************************************************/
-#include "ExtPackUtil.h"
+#include "include/ExtPackUtil.h"
 
 #include <iprt/ctype.h>
@@ -150,17 +150,72 @@
 
 /**
+ * Extract the extension pack name from the tarball path.
+ *
+ * @returns String containing the name on success, the caller must delete it.
+ *          NULL if no valid name was found or if we ran out of memory.
+ * @param   pszTarball          The path to the tarball.
+ */
+iprt::MiniString *VBoxExtPackExtractNameFromTarballPath(const char *pszTarball)
+{
+    /*
+     * Skip ahead to the filename part and count the number of characters
+     * that matches the criteria for a extension pack name.
+     */
+    const char *pszSrc = RTPathFilename(pszTarball);
+    if (!pszSrc)
+        return NULL;
+
+    size_t off = 0;
+    while (RT_C_IS_ALNUM(pszSrc[off]) || pszSrc[off] == ' ')
+        off++;
+
+    /*
+     * Check min and max name limits.
+     */
+    if (   off > VBOX_EXTPACK_NAME_MIN_LEN
+        || off < VBOX_EXTPACK_NAME_MIN_LEN)
+        return NULL;
+
+    /*
+     * Make a duplicate of the name and return it.
+     */
+    iprt::MiniString *pStrRet = new iprt::MiniString(off, pszSrc);
+    Assert(VBoxExtPackIsValidName(pStrRet->c_str()));
+    return pStrRet;
+}
+
+
+/**
  * Validates the extension pack name.
  *
  * @returns true if valid, false if not.
  * @param   pszName             The name to validate.
+ * @sa      VBoxExtPackExtractNameFromTarballPath
  */
 bool VBoxExtPackIsValidName(const char *pszName)
 {
-    /* This must match the code in the extension manager. */
-    if (!pszName || *pszName == '\0')
-        return false;
-    while (RT_C_IS_ALNUM(*pszName) || *pszName == ' ')
-        pszName++;
-    return *pszName == '\0';
+    if (!pszName)
+        return false;
+
+    /*
+     * Check the characters making up the name, only english alphabet
+     * characters, decimal digits and spaces are allowed.
+     */
+    size_t off = 0;
+    while (pszName[off])
+    {
+        if (!RT_C_IS_ALNUM(pszName[off]) && !pszName[off] == ' ')
+            return false;
+        off++;
+    }
+
+    /*
+     * Check min and max name limits.
+     */
+    if (   off > VBOX_EXTPACK_NAME_MIN_LEN
+        || off < VBOX_EXTPACK_NAME_MIN_LEN)
+        return false;
+
+    return true;
 }
 
Index: /trunk/src/VBox/Main/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Main/Makefile.kmk	(revision 33805)
+++ /trunk/src/VBox/Main/Makefile.kmk	(revision 33806)
@@ -730,9 +730,11 @@
 ifeq ($(LOGNAME),bird) # def VBOX_WITH_EXTPACK
  PROGRAMS += VBoxExtPackHelperApp
- VBoxExtPackHelperApp_TEMPLATE = VBoxR3Static
- VBoxExtPackHelperApp_SOURCES = VBoxExtPackHelperApp.cpp
- VBoxExtPackHelperApp_DEFS = IN_RT_R3
+ VBoxExtPackHelperApp_TEMPLATE = VBoxR3SetUidToRoot
+ VBoxExtPackHelperApp_SOURCES = \
+	VBoxExtPackHelperApp.cpp \
+	ExtPackUtil.cpp
  VBoxExtPackHelperApp_LIBS = \
-	$(VBOX_LIB_RUNTIME_STATIC)
+        $(LIB_RUNTIME)
+
 endif # VBOX_WITH_EXTPACK
 
Index: /trunk/src/VBox/Main/VBoxExtPackHelperApp.cpp
===================================================================
--- /trunk/src/VBox/Main/VBoxExtPackHelperApp.cpp	(revision 33805)
+++ /trunk/src/VBox/Main/VBoxExtPackHelperApp.cpp	(revision 33806)
@@ -19,13 +19,15 @@
 #include <iprt/buildconfig.h>
 //#include <iprt/ctype.h>
-//#include <iprt/dir.h>
+#include <iprt/dir.h>
 //#include <iprt/env.h>
-//#include <iprt/file.h>
+#include <iprt/file.h>
+#include <iprt/fs.h>
 #include <iprt/getopt.h>
 #include <iprt/initterm.h>
 #include <iprt/message.h>
-//#include <iprt/param.h>
+#include <iprt/param.h>
 #include <iprt/path.h>
 //#include <iprt/pipe.h>
+#include <iprt/process.h>
 #include <iprt/string.h>
 #include <iprt/stream.h>
@@ -33,4 +35,5 @@
 #include <VBox/log.h>
 #include <VBox/err.h>
+#include <VBox/sup.h>
 #include <VBox/version.h>
 
@@ -40,4 +43,282 @@
 {
     return true;
+}
+
+
+/**
+ * Handle the special standard options when these are specified after the
+ * command.
+ *
+ * @param   ch          The option character.
+ */
+static RTEXITCODE DoStandardOption(int ch)
+{
+    switch (ch)
+    {
+        case 'h':
+        {
+            RTMsgInfo(VBOX_PRODUCT " Extension Pack Helper App\n"
+                      "(C) " VBOX_C_YEAR " " VBOX_VENDOR "\n"
+                      "All rights reserved.\n"
+                      "\n"
+                      "This NOT intended for general use, please use VBoxManage instead\n"
+                      "or call the IExtPackManager API directly.\n"
+                      "\n"
+                      "Usage: %s <command> [options]\n"
+                      "Commands:\n"
+                      "    install --base-dir <dir> --certificate-dir <dir> --name <name> \\\n"
+                      "        --tarball <tarball> --tarball-fd <fd>\n"
+                      "    uninstall --base-dir <dir> --name <name>\n"
+                      , RTProcShortName());
+            return RTEXITCODE_SUCCESS;
+        }
+
+        case 'V':
+            RTPrintf("%sr%d\n", VBOX_VERSION_STRING, RTBldCfgRevision());
+            return RTEXITCODE_SUCCESS;
+
+        default:
+            AssertFailedReturn(RTEXITCODE_FAILURE);
+    }
+}
+
+
+/**
+ * Checks if the cerficiate directory is valid.
+ *
+ * @returns true if it is valid, false if it isn't.
+ * @param   pszCertDir          The certificate directory to validate.
+ */
+static bool IsValidCertificateDir(const char *pszCertDir)
+{
+    /*
+     * Just be darn strict for now.
+     */
+    char szCorrect[RTPATH_MAX];
+    int rc = RTPathAppPrivateNoArch(szCorrect, sizeof(szCorrect));
+    if (RT_FAILURE(rc))
+        return false;
+    rc = RTPathAppend(szCorrect, sizeof(szCorrect), VBOX_EXTPACK_CERT_DIR);
+    if (RT_FAILURE(rc))
+        return false;
+
+    return RTPathCompare(szCorrect, pszCertDir) == 0;
+}
+
+
+/**
+ * Checks if the base directory is valid.
+ *
+ * @returns true if it is valid, false if it isn't.
+ * @param   pszBaesDir          The base directory to validate.
+ */
+static bool IsValidBaseDir(const char *pszBaseDir)
+{
+    /*
+     * Just be darn strict for now.
+     */
+    char szCorrect[RTPATH_MAX];
+    int rc = RTPathAppPrivateArch(szCorrect, sizeof(szCorrect));
+    if (RT_FAILURE(rc))
+        return false;
+    rc = RTPathAppend(szCorrect, sizeof(szCorrect), VBOX_EXTPACK_INSTALL_DIR);
+    if (RT_FAILURE(rc))
+        return false;
+
+    return RTPathCompare(szCorrect, pszBaseDir) == 0;
+}
+
+/**
+ * Cleans up a temporary extension pack directory.
+ *
+ * This is used by 'uninstall', 'cleanup' and in the failure path of 'install'.
+ *
+ * @returns The program exit code.
+ * @param   pszDir          The directory to clean up.  The caller is
+ *                          responsible for making sure this is valid.
+ * @param   fTemporary      Whether this is a temporary install directory or
+ *                          not.
+ */
+static RTEXITCODE RemoveExtPackDir(const char *pszDir, bool fTemporary)
+{
+    /** @todo May have to undo 555 modes here later.  */
+    int rc = RTDirRemoveRecursive(pszDir, RTDIRRMREC_F_CONTENT_AND_DIR);
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExit(RTEXITCODE_FAILURE,
+                              "Failed to delete the %sextension pack directory: %Rrc ('%s')",
+                              fTemporary ? "temporary " : "", rc, pszDir);
+    return RTEXITCODE_SUCCESS;
+}
+
+
+/**
+ * Sets the permissions of the temporary extension pack directory just before
+ * renaming it.
+ *
+ * By default the temporary directory is only accessible by root, this function
+ * will make it world readable and browseable.
+ *
+ * @returns The program exit code.
+ * @param   pszDir              The temporary extension pack directory.
+ */
+static RTEXITCODE SetExtPackPermissions(const char *pszDir)
+{
+#if !defined(RT_OS_WINDOWS)
+     int rc = RTPathSetMode(pszDir, 0755);
+     if (RT_FAILURE(rc))
+         return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to set directory permissions: %Rrc ('%s')", rc, pszDir);
+#else
+        /** @todo  */
+#endif
+
+    return RTEXITCODE_SUCCESS;
+}
+
+/**
+ * Validates the extension pack.
+ *
+ * Operations performed:
+ *      - Manifest seal check.
+ *      - Manifest check.
+ *      - Recursive hardening check.
+ *      - XML validity check.
+ *      - Name check (against XML).
+ *
+ * @returns The program exit code.
+ * @param   pszDir              The directory where the extension pack has been
+ *                              unpacked.
+ * @param   pszName             The expected extension pack name.
+ * @param   pszTarball          The name of the tarball in case we have to
+ *                              complain about something.
+ */
+static RTEXITCODE ValidateExtPack(const char *pszDir, const char *pszTarball, const char *pszName)
+{
+    /** @todo  */
+    return RTEXITCODE_SUCCESS;
+}
+
+
+/**
+ * Unpacks the extension pack into the specified directory.
+ *
+ * This will apply ownership and permission changes to all the content, the
+ * exception is @a pszDirDst which will be handled by SetExtPackPermissions.
+ *
+ * @returns The program exit code.
+ * @param   hTarballFile        The tarball to unpack.
+ * @param   pszDirDst           Where to unpack it.
+ * @param   pszTarball          The name of the tarball in case we have to
+ *                              complain about something.
+ */
+static RTEXITCODE UnpackExtPack(RTFILE hTarballFile, const char *pszDirDst, const char *pszTarball)
+{
+    /** @todo  */
+    return RTEXITCODE_SUCCESS;
+}
+
+
+/**
+ * The 2nd part of the installation process.
+ *
+ * @returns The program exit code.
+ * @param   pszBaseDir          The base directory.
+ * @param   pszCertDir          The certificat directory.
+ * @param   pszTarball          The tarball name.
+ * @param   hTarballFile        The handle to open the @a pszTarball file.
+ * @param   hTarballFileOpt     The tarball file handle (optional).
+ * @param   pszName             The extension pack name.
+ */
+static RTEXITCODE DoInstall2(const char *pszBaseDir, const char *pszCertDir, const char *pszTarball,
+                             RTFILE hTarballFile, RTFILE hTarballFileOpt, const char *pszName)
+{
+    /*
+     * Do some basic validation of the tarball file.
+     */
+    RTFSOBJINFO ObjInfo;
+    int rc = RTFileQueryInfo(hTarballFile, &ObjInfo, RTFSOBJATTRADD_UNIX);
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTFileQueryInfo failed with %Rrc on '%s'", rc, pszTarball);
+    if (!RTFS_IS_FILE(ObjInfo.Attr.fMode))
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Not a regular file: %s", pszTarball);
+
+    if (hTarballFileOpt != NIL_RTFILE)
+    {
+        RTFSOBJINFO ObjInfo2;
+        rc = RTFileQueryInfo(hTarballFileOpt, &ObjInfo2, RTFSOBJATTRADD_UNIX);
+        if (RT_FAILURE(rc))
+            return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTFileQueryInfo failed with %Rrc on --tarball-fd", rc);
+        if (   ObjInfo.Attr.u.Unix.INodeIdDevice != ObjInfo2.Attr.u.Unix.INodeIdDevice
+            || ObjInfo.Attr.u.Unix.INodeId       != ObjInfo2.Attr.u.Unix.INodeId)
+            return RTMsgErrorExit(RTEXITCODE_FAILURE, "--tarball and --tarball-fd does not match");
+    }
+
+    /*
+     * Construct the paths to the two directories we'll be using.
+     */
+    char szFinalPath[RTPATH_MAX];
+    rc = RTPathJoin(szFinalPath, sizeof(szFinalPath), pszBaseDir, pszName);
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExit(RTEXITCODE_FAILURE,
+                              "Failed to construct the path to the final extension pack directory: %Rrc", rc);
+
+    char szTmpPath[RTPATH_MAX];
+    rc = RTPathJoin(szTmpPath, sizeof(szTmpPath) - 64, pszBaseDir, pszName);
+    if (RT_SUCCESS(rc))
+    {
+        size_t cchTmpPath = strlen(szTmpPath);
+        RTStrPrintf(&szTmpPath[cchTmpPath], sizeof(szTmpPath) - cchTmpPath, "-_-inst-%u", (uint32_t)RTProcSelf());
+    }
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExit(RTEXITCODE_FAILURE,
+                              "Failed to construct the path to the temporary extension pack directory: %Rrc", rc);
+
+    /*
+     * Check that they don't exist at this point in time.
+     */
+    rc = RTPathQueryInfoEx(szFinalPath, &ObjInfo, RTFSOBJATTRADD_NOTHING,  RTPATH_F_ON_LINK);
+    if (RT_SUCCESS(rc) && RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode))
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "The extension pack is already installed. You must uninstall the old one first.");
+    if (RT_SUCCESS(rc))
+        return RTMsgErrorExit(RTEXITCODE_FAILURE,
+                              "Found non-directory file system object where the extension pack would be installed ('%s')",
+                              szFinalPath);
+    if (rc != VERR_FILE_NOT_FOUND && rc != VERR_PATH_NOT_FOUND)
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Unexpected RTPathQueryInfoEx status code %Rrc for '%s'", rc, szFinalPath);
+
+    rc = RTPathQueryInfoEx(szTmpPath, &ObjInfo, RTFSOBJATTRADD_NOTHING,  RTPATH_F_ON_LINK);
+    if (rc != VERR_FILE_NOT_FOUND && rc != VERR_PATH_NOT_FOUND)
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Unexpected RTPathQueryInfoEx status code %Rrc for '%s'", rc, szFinalPath);
+
+    /*
+     * Create the temporary directory and prepare the extension pack within it.
+     * If all checks out correctly, rename it to the final directory.
+     */
+    rc = RTDirCreate(szTmpPath, 0700);
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create temporary directory: %Rrc ('%s')", rc, szTmpPath);
+
+    RTEXITCODE rcExit = UnpackExtPack(hTarballFile, szTmpPath, pszTarball);
+    if (rcExit == RTEXITCODE_SUCCESS)
+        rcExit = ValidateExtPack(szTmpPath, pszTarball, pszName);
+    if (rcExit == RTEXITCODE_SUCCESS)
+        rcExit = SetExtPackPermissions(szTmpPath);
+    if (rcExit == RTEXITCODE_SUCCESS)
+    {
+        rc = RTDirRename(szTmpPath, szFinalPath, RTPATHRENAME_FLAGS_NO_REPLACE);
+        if (RT_SUCCESS(rc))
+            RTMsgInfo("Successfully installed '%s' (%s)", pszName, pszTarball);
+        else
+            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,
+                                    "Failed to rename the temporary directory to the final one: %Rrc ('%s' -> '%s')",
+                                    rc, szTmpPath, szFinalPath);
+    }
+
+    /*
+     * Clean up the temporary directory on failure.
+     */
+    if (rcExit != RTEXITCODE_SUCCESS)
+        RemoveExtPackDir(szTmpPath, true /*fTemporary*/);
+
+    return rcExit;
 }
 
@@ -52,6 +333,111 @@
 static RTEXITCODE DoInstall(int argc, char **argv)
 {
-    return RTEXITCODE_FAILURE;
-}
+    /*
+     * Parse the parameters.
+     *
+     * Note! The --base-dir and --cert-dir are only for checking that the
+     *       caller and this help applications have the same idea of where
+     *       things are.  Likewise, the --name is for verifying assumptions
+     *       the caller made about the name.  The optional --tarball-fd option
+     *       is just for easing the paranoia on the user side.
+     */
+    static const RTGETOPTDEF s_aOptions[] =
+    {
+        { "--base-dir",     'b',   RTGETOPT_REQ_STRING },
+        { "--cert-dir",     'c',   RTGETOPT_REQ_STRING },
+        { "--name",         'n',   RTGETOPT_REQ_STRING },
+        { "--tarball",      't',   RTGETOPT_REQ_STRING },
+        { "--tarball-fd",   'f',   RTGETOPT_REQ_UINT64 }
+    };
+    RTGETOPTSTATE   GetState;
+    int rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0 /*fFlags*/);
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOptInit failed: %Rrc\n", rc);
+
+    const char     *pszBaseDir      = NULL;
+    const char     *pszCertDir      = NULL;
+    const char     *pszName         = NULL;
+    const char     *pszTarball      = NULL;
+    RTFILE          hTarballFileOpt = NIL_RTFILE;
+    RTGETOPTUNION   ValueUnion;
+    int             ch;
+    while ((ch = RTGetOpt(&GetState, &ValueUnion)))
+    {
+        switch (ch)
+        {
+            case 'b':
+                if (pszBaseDir)
+                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many --base-dir options");
+                pszBaseDir = ValueUnion.psz;
+                if (!IsValidBaseDir(pszBaseDir))
+                    return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid base directory: '%s'", pszBaseDir);
+                break;
+
+            case 'c':
+                if (pszCertDir)
+                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many --cert-dir options");
+                pszCertDir = ValueUnion.psz;
+                if (!IsValidCertificateDir(pszCertDir))
+                    return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid certificate directory: '%s'", pszCertDir);
+                break;
+
+            case 'n':
+                if (pszName)
+                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many --name options");
+                pszName = ValueUnion.psz;
+                if (!VBoxExtPackIsValidName(pszName))
+                    return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid extension pack name: '%s'", pszName);
+                break;
+
+            case 't':
+                if (pszTarball)
+                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many --tarball options");
+                pszTarball = ValueUnion.psz;
+                break;
+
+            case 'd':
+            {
+                if (hTarballFileOpt != NIL_RTFILE)
+                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many --tarball-fd options");
+                RTHCUINTPTR hNative = (RTHCUINTPTR)ValueUnion.u64;
+                if (hNative != ValueUnion.u64)
+                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The --tarball-fd value is out of range: %#RX64", ValueUnion.u64);
+                rc = RTFileFromNative(&hTarballFileOpt, hNative);
+                if (RT_FAILURE(rc))
+                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "RTFileFromNative failed on --target-fd value: %Rrc", rc);
+                break;
+            }
+
+            case 'h':
+            case 'V':
+                return DoStandardOption(ch);
+
+            default:
+                return RTGetOptPrintError(ch, &ValueUnion);
+        }
+        break;
+    }
+    if (!pszName)
+        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing --name option");
+    if (!pszBaseDir)
+        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing --base-dir option");
+    if (!pszCertDir)
+        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing --cert-dir option");
+    if (!pszTarball)
+        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing --tarball option");
+
+    /*
+     * Ok, down to business.
+     */
+    RTFILE hTarballFile;
+    rc = RTFileOpen(&hTarballFile, pszTarball, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to open the extension pack tarball: %Rrc ('%s')", rc, pszTarball);
+
+    RTEXITCODE rcExit = DoInstall2(pszBaseDir, pszCertDir, pszTarball, hTarballFile, hTarballFileOpt, pszName);
+    RTFileClose(hTarballFile);
+    return rcExit;
+}
+
 
 /**
@@ -64,73 +450,251 @@
 static RTEXITCODE DoUninstall(int argc, char **argv)
 {
-    return RTEXITCODE_FAILURE;
-}
-
-
-int main(int argc, char **argv)
-{
-    int rc = RTR3Init();
-    if (RT_FAILURE(rc))
-        return RTMsgInitFailure(rc);
-
-    RTEXITCODE rcExit = RTEXITCODE_FAILURE;
-    if (argc > 1)
-    {
-        /*
-         * Command string switch.
-         */
-        if (!strcmp(argv[1], "install"))
-            rcExit = DoInstall(argc, argv);
-        else if (!strcmp(argv[1], "uninstall"))
-            rcExit = DoUninstall(argc, argv);
-        else
+    /*
+     * Parse the parameters.
+     *
+     * Note! The --base-dir is only for checking that the caller and this help
+     *       applications have the same idea of where things are.
+     */
+    static const RTGETOPTDEF s_aOptions[] =
+    {
+        { "--base-dir",     'b',   RTGETOPT_REQ_STRING },
+        { "--name",         'n',   RTGETOPT_REQ_STRING }
+    };
+    RTGETOPTSTATE   GetState;
+    int rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0 /*fFlags*/);
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOptInit failed: %Rrc\n", rc);
+
+    const char     *pszBaseDir = NULL;
+    const char     *pszName    = NULL;
+    RTGETOPTUNION   ValueUnion;
+    int             ch;
+    while ((ch = RTGetOpt(&GetState, &ValueUnion)))
+    {
+        switch (ch)
         {
-            /*
-             * Didn't match a command, check for standard options.
-             */
-            RTGETOPTSTATE State;
-            rc = RTGetOptInit(&State, argc, argv, NULL, 0, 1, 0 /*fFlags*/);
+            case 'b':
+                if (pszBaseDir)
+                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many --base-dir options");
+                pszBaseDir = ValueUnion.psz;
+                if (!IsValidBaseDir(pszBaseDir))
+                    return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid base directory: '%s'", pszBaseDir);
+                break;
+
+            case 'n':
+                if (pszName)
+                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many --name options");
+                pszName = ValueUnion.psz;
+                if (!VBoxExtPackIsValidName(pszName))
+                    return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid extension pack name: '%s'", pszName);
+                break;
+
+            case 'h':
+            case 'V':
+                return DoStandardOption(ch);
+
+            default:
+                return RTGetOptPrintError(ch, &ValueUnion);
+        }
+        break;
+    }
+    if (!pszName)
+        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing --name option");
+    if (!pszBaseDir)
+        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing --base-dir option");
+
+    /*
+     * Ok, down to business.
+     */
+    /* Check that it exists. */
+    char szExtPackDir[RTPATH_MAX];
+    rc = RTPathJoin(szExtPackDir, sizeof(szExtPackDir), pszBaseDir, pszName);
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to construct extension pack path: %Rrc", rc);
+
+    if (!RTDirExists(szExtPackDir))
+    {
+        RTMsgInfo("Extension pack not installed. Nothing to do.");
+        return RTEXITCODE_SUCCESS;
+    }
+
+    /* Rename the extension pack directory before deleting it to prevent new
+       VM processes from picking it up. */
+    char szExtPackUnInstDir[RTPATH_MAX];
+    rc = RTPathJoin(szExtPackUnInstDir, sizeof(szExtPackUnInstDir), pszBaseDir, pszName);
+    if (RT_SUCCESS(rc))
+        rc = RTStrCat(szExtPackUnInstDir, sizeof(szExtPackUnInstDir), "-_-uninst");
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to construct temporary extension pack path: %Rrc", rc);
+
+    rc = RTDirRename(szExtPackDir, szExtPackUnInstDir, RTPATHRENAME_FLAGS_NO_REPLACE);
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to rename the extension pack directory: %Rrc", rc);
+
+    /* Recursively delete the directory content. */
+    RTEXITCODE rcExit = RemoveExtPackDir(szExtPackUnInstDir, false /*fTemporary*/);
+    if (rcExit == RTEXITCODE_SUCCESS)
+        RTMsgInfo("Successfully removed extension pack '%s'\n", pszName);
+
+    return rcExit;
+}
+
+/**
+ * Implements the 'cleanup' command.
+ *
+ * @returns The program exit code.
+ * @param   argc            The number of program arguments.
+ * @param   argv            The program arguments.
+ */
+static RTEXITCODE DoCleanup(int argc, char **argv)
+{
+    /*
+     * Parse the parameters.
+     *
+     * Note! The --base-dir is only for checking that the caller and this help
+     *       applications have the same idea of where things are.
+     */
+    static const RTGETOPTDEF s_aOptions[] =
+    {
+        { "--base-dir",     'b',   RTGETOPT_REQ_STRING },
+    };
+    RTGETOPTSTATE   GetState;
+    int rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0 /*fFlags*/);
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOptInit failed: %Rrc\n", rc);
+
+    const char     *pszBaseDir = NULL;
+    RTGETOPTUNION   ValueUnion;
+    int             ch;
+    while ((ch = RTGetOpt(&GetState, &ValueUnion)))
+    {
+        switch (ch)
+        {
+            case 'b':
+                if (pszBaseDir)
+                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many --base-dir options");
+                pszBaseDir = ValueUnion.psz;
+                if (!IsValidBaseDir(pszBaseDir))
+                    return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid base directory: '%s'", pszBaseDir);
+                break;
+
+            case 'h':
+            case 'V':
+                return DoStandardOption(ch);
+
+            default:
+                return RTGetOptPrintError(ch, &ValueUnion);
+        }
+        break;
+    }
+    if (!pszBaseDir)
+        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing --base-dir option");
+
+    /*
+     * Ok, down to business.
+     */
+    PRTDIR pDir;
+    rc = RTDirOpen(&pDir, pszBaseDir);
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed open the base directory: %Rrc ('%s')", rc, pszBaseDir);
+
+    uint32_t    cCleaned = 0;
+    RTEXITCODE  rcExit = RTEXITCODE_SUCCESS;
+    for (;;)
+    {
+        RTDIRENTRYEX Entry;
+        rc = RTDirReadEx(pDir, &Entry, NULL /*pcbDirEntry*/, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
+        if (RT_FAILURE(rc))
+        {
+            if (rc != VERR_NO_MORE_FILES)
+                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDirReadEx returns %Rrc", rc);
+            break;
+        }
+        if (   RTFS_IS_DIRECTORY(Entry.Info.Attr.fMode)
+            && strcmp(Entry.szName, ".")  != 0
+            && strcmp(Entry.szName, "..") != 0
+            && !VBoxExtPackIsValidName(Entry.szName) )
+        {
+            char szPath[RTPATH_MAX];
+            rc = RTPathJoin(szPath, sizeof(szPath), pszBaseDir, Entry.szName);
             if (RT_SUCCESS(rc))
             {
-                for (;;)
-                {
-                    RTGETOPTUNION ValueUnion;
-                    int ch = RTGetOpt(&State, &ValueUnion);
-                    switch (ch)
-                    {
-                        case 'h':
-                            RTMsgInfo(VBOX_PRODUCT " Extension Pack Helper App\n"
-                                      "(C) " VBOX_C_YEAR " " VBOX_VENDOR "\n"
-                                      "All rights reserved.\n"
-                                      "\n"
-                                      "This NOT intended for general use, please use VBoxManage instead\n"
-                                      "or call the IExtPackManager API directly.\n"
-                                      "\n"
-                                      "Usage: %s <command> [options]\n"
-                                      "Commands:\n"
-                                      "    install --base-dir <dir> --name <name> --tarball <tarball> --tarball-fd <fd>\n"
-                                      "    uninstall --base-dir <dir> --name <name>\n"
-                                      , RTPathFilename(argv[0]));
-                            rcExit = RTEXITCODE_SUCCESS;
-                            break;
-
-                        case 'V':
-                            RTPrintf("%sr%d\n", VBOX_VERSION_STRING, RTBldCfgRevision());
-                            rcExit = RTEXITCODE_SUCCESS;
-                            break;
-
-                        default:
-                            rcExit = RTGetOptPrintError(ch, &ValueUnion);
-                            break;
-                    }
-                }
+                RTEXITCODE rcExit2 = RemoveExtPackDir(szPath, true /*fTemporary*/);
+                if (rcExit2 == RTEXITCODE_SUCCESS)
+                    RTMsgInfo("Successfully removed '%s'.", Entry.szName);
+                else if (rcExit == RTEXITCODE_SUCCESS)
+                    rcExit = rcExit2;
             }
             else
-                RTMsgError("RTGetOptInit failed: %Rrc\n", rc);
+                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathJoin failed with %Rrc for '%s'", rc, Entry.szName);
+            cCleaned++;
         }
     }
-    else
-        RTMsgError("No command was specified\n");
+    RTDirClose(pDir);
+    if (!cCleaned)
+        RTMsgInfo("Nothing to clean.");
     return rcExit;
 }
 
+
+
+int main(int argc, char **argv)
+{
+    /*
+     * Initialize IPRT and check that we're correctly installed.
+     */
+    int rc = RTR3Init();
+    if (RT_FAILURE(rc))
+        return RTMsgInitFailure(rc);
+
+    char szErr[2048];
+    rc = SUPR3HardenedVerifySelf(argv[0], true /*fInternal*/, szErr, sizeof(szErr));
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s", szErr);
+
+    /*
+     * Parse the top level arguments until we find a command.
+     */
+    static const RTGETOPTDEF s_aOptions[] =
+    {
+#define CMD_INSTALL     1000
+        { "install",    CMD_INSTALL,    RTGETOPT_REQ_NOTHING },
+#define CMD_UNINSTALL   1001
+        { "uninstall",  CMD_UNINSTALL,  RTGETOPT_REQ_NOTHING },
+#define CMD_CLEANUP     1002
+        { "cleanup",    CMD_CLEANUP,    RTGETOPT_REQ_NOTHING },
+    };
+    RTGETOPTSTATE GetState;
+    rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0 /*fFlags*/);
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOptInit failed: %Rrc\n", rc);
+    for (;;)
+    {
+        RTGETOPTUNION ValueUnion;
+        int ch = RTGetOpt(&GetState, &ValueUnion);
+        switch (ch)
+        {
+            case 0:
+                return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No command specified");
+
+            case CMD_INSTALL:
+                return DoInstall(argc, argv);
+
+            case CMD_UNINSTALL:
+                return DoUninstall(argc, argv);
+
+            case CMD_CLEANUP:
+                return DoCleanup(argc, argv);
+
+            case 'h':
+            case 'V':
+                return DoStandardOption(ch);
+
+            default:
+                return RTGetOptPrintError(ch, &ValueUnion);
+        }
+        /* not currently reached */
+    }
+    /* not reached */
+}
+
Index: /trunk/src/VBox/Main/VirtualBoxImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/VirtualBoxImpl.cpp	(revision 33805)
+++ /trunk/src/VBox/Main/VirtualBoxImpl.cpp	(revision 33806)
@@ -2062,5 +2062,5 @@
         /* get the path to the executable */
         char exePathBuf[RTPATH_MAX];
-        char *exePath = RTProcGetExecutableName(exePathBuf, RTPATH_MAX);
+        char *exePath = RTProcGetExecutablePath(exePathBuf, RTPATH_MAX);
         if (!exePath)
         {
Index: /trunk/src/VBox/Main/generic/OpenGLTestApp.cpp
===================================================================
--- /trunk/src/VBox/Main/generic/OpenGLTestApp.cpp	(revision 33805)
+++ /trunk/src/VBox/Main/generic/OpenGLTestApp.cpp	(revision 33806)
@@ -166,5 +166,5 @@
         /* the package type is interesting for Linux distributions */
         char szExecName[RTPATH_MAX];
-        char *pszExecName = RTProcGetExecutableName(szExecName, sizeof(szExecName));
+        char *pszExecName = RTProcGetExecutablePath(szExecName, sizeof(szExecName));
         RTLogRelLogger(loggerRelease, 0, ~0U,
                        "Executable: %s\n"
Index: /trunk/src/VBox/Main/include/ExtPackUtil.h
===================================================================
--- /trunk/src/VBox/Main/include/ExtPackUtil.h	(revision 33805)
+++ /trunk/src/VBox/Main/include/ExtPackUtil.h	(revision 33806)
@@ -24,4 +24,16 @@
  * The suffix of a extension pack tarball. */
 #define VBOX_EXTPACK_SUFFIX             ".vbox-extpack"
+
+/** The minimum length (strlen) of a extension pack name. */
+#define VBOX_EXTPACK_NAME_MIN_LEN       6
+/** The max length (strlen) of a extension pack name. */
+#define VBOX_EXTPACK_NAME_MAX_LEN       64
+
+/** The architecture-dependent application data subdirectory where the
+ * extension packs are installed.  Relative to RTPathAppPrivateArch. */
+#define VBOX_EXTPACK_INSTALL_DIR        "ExtensionPacks"
+/** The architecture-independent application data subdirectory where the
+ * certificates are installed.  Relative to RTPathAppPrivateNoArch. */
+#define VBOX_EXTPACK_CERT_DIR           "Certificates"
 
 
@@ -52,4 +64,5 @@
 
 iprt::MiniString *VBoxExtPackLoadDesc(const char *a_pszDir, PVBOXEXTPACKDESC a_pExtPackDesc, PRTFSOBJINFO a_pObjInfo);
+iprt::MiniString *VBoxExtPackExtractNameFromTarballPath(const char *pszTarball);
 bool    VBoxExtPackIsValidName(const char *pszName);
 bool    VBoxExtPackIsValidVersionString(const char *pszName);
Index: /trunk/src/VBox/Runtime/VBox/RTAssertShouldPanic-vbox.cpp
===================================================================
--- /trunk/src/VBox/Runtime/VBox/RTAssertShouldPanic-vbox.cpp	(revision 33805)
+++ /trunk/src/VBox/Runtime/VBox/RTAssertShouldPanic-vbox.cpp	(revision 33806)
@@ -116,5 +116,5 @@
         {
             char *pszExecName = &szCmd[cch];
-            if (!RTProcGetExecutableName(pszExecName, sizeof(szCmd) - cch))
+            if (!RTProcGetExecutablePath(pszExecName, sizeof(szCmd) - cch))
                 *pszExecName = '\0';
         }
Index: /trunk/src/VBox/Runtime/VBox/log-vbox.cpp
===================================================================
--- /trunk/src/VBox/Runtime/VBox/log-vbox.cpp	(revision 33805)
+++ /trunk/src/VBox/Runtime/VBox/log-vbox.cpp	(revision 33806)
@@ -297,5 +297,5 @@
 # ifndef IN_GUEST
     char szExecName[RTPATH_MAX];
-    if (!RTProcGetExecutableName(szExecName, sizeof(szExecName)))
+    if (!RTProcGetExecutablePath(szExecName, sizeof(szExecName)))
         strcpy(szExecName, "VBox");
     RTTIMESPEC TimeSpec;
Index: /trunk/src/VBox/Runtime/generic/RTProcDaemonize-generic.cpp
===================================================================
--- /trunk/src/VBox/Runtime/generic/RTProcDaemonize-generic.cpp	(revision 33805)
+++ /trunk/src/VBox/Runtime/generic/RTProcDaemonize-generic.cpp	(revision 33806)
@@ -49,5 +49,5 @@
      */
     char szExecPath[RTPATH_MAX];
-    AssertReturn(RTProcGetExecutableName(szExecPath, sizeof(szExecPath)) == szExecPath, VERR_WRONG_ORDER);
+    AssertReturn(RTProcGetExecutablePath(szExecPath, sizeof(szExecPath)) == szExecPath, VERR_WRONG_ORDER);
 
     /*
Index: /trunk/src/VBox/Runtime/r3/init.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/init.cpp	(revision 33805)
+++ /trunk/src/VBox/Runtime/r3/init.cpp	(revision 33806)
@@ -80,5 +80,5 @@
 
 /** The process path.
- * This is used by RTPathExecDir and RTProcGetExecutableName and set by rtProcInitName. */
+ * This is used by RTPathExecDir and RTProcGetExecutablePath and set by rtProcInitName. */
 char        g_szrtProcExePath[RTPATH_MAX];
 /** The length of g_szrtProcExePath. */
Index: /trunk/src/VBox/Runtime/r3/process.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/process.cpp	(revision 33805)
+++ /trunk/src/VBox/Runtime/r3/process.cpp	(revision 33806)
@@ -92,5 +92,5 @@
 
 
-RTR3DECL(char *) RTProcGetExecutableName(char *pszExecName, size_t cchExecName)
+RTR3DECL(char *) RTProcGetExecutablePath(char *pszExecPath, size_t cbExecPath)
 {
     if (RT_UNLIKELY(g_szrtProcExePath[0] == '\0'))
@@ -101,13 +101,19 @@
      */
     size_t cch = g_cchrtProcExePath;
-    if (cch < cchExecName)
+    if (cch < cbExecPath)
     {
-        memcpy(pszExecName, g_szrtProcExePath, cch);
-        pszExecName[cch] = '\0';
-        return pszExecName;
+        memcpy(pszExecPath, g_szrtProcExePath, cch);
+        pszExecPath[cch] = '\0';
+        return pszExecPath;
     }
 
-    AssertMsgFailed(("Buffer too small (%zu <= %zu)\n", cchExecName, cch));
+    AssertMsgFailed(("Buffer too small (%zu <= %zu)\n", cbExecPath, cch));
     return NULL;
 }
 
+
+RTR3DECL(const char *) RTProcShortName(void)
+{
+    return &g_szrtProcExePath[g_offrtProcName];
+}
+
Index: /trunk/src/VBox/Runtime/r3/solaris/coredumper-solaris.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/solaris/coredumper-solaris.cpp	(revision 33805)
+++ /trunk/src/VBox/Runtime/r3/solaris/coredumper-solaris.cpp	(revision 33806)
@@ -1956,5 +1956,5 @@
     pVBoxProc->CoreContent    = CC_CONTENT_DEFAULT;
 
-    RTProcGetExecutableName(pVBoxProc->szExecPath, sizeof(pVBoxProc->szExecPath));  /* this gets full path not just name */
+    RTProcGetExecutablePath(pVBoxProc->szExecPath, sizeof(pVBoxProc->szExecPath));  /* this gets full path not just name */
     pVBoxProc->pszExecName = RTPathFilename(pVBoxProc->szExecPath);
 
Index: /trunk/src/VBox/Runtime/testcase/tstRTDigest.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTDigest.cpp	(revision 33805)
+++ /trunk/src/VBox/Runtime/testcase/tstRTDigest.cpp	(revision 33806)
@@ -48,5 +48,5 @@
 {
     char szName[RTPATH_MAX];
-    if (!RTProcGetExecutableName(szName, sizeof(szName)))
+    if (!RTProcGetExecutablePath(szName, sizeof(szName)))
         strcpy(szName, "tstRTDigest");
 
Index: /trunk/src/VBox/Runtime/testcase/tstRTPath.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTPath.cpp	(revision 33805)
+++ /trunk/src/VBox/Runtime/testcase/tstRTPath.cpp	(revision 33806)
@@ -53,5 +53,5 @@
 
     /*
-     * RTPathExecDir, RTPathUserHome and RTProcGetExecutableName.
+     * RTPathExecDir, RTPathUserHome and RTProcGetExecutablePath.
      */
     RTTestSub(hTest, "RTPathExecDir");
@@ -60,9 +60,9 @@
         RTTestIPrintf(RTTESTLVL_INFO, "ExecDir={%s}\n", szPath);
 
-    RTTestSub(hTest, "RTProcGetExecutableName");
-    if (RTProcGetExecutableName(szPath, sizeof(szPath)) == szPath)
+    RTTestSub(hTest, "RTProcGetExecutablePath");
+    if (RTProcGetExecutablePath(szPath, sizeof(szPath)) == szPath)
         RTTestIPrintf(RTTESTLVL_INFO, "ExecutableName={%s}\n", szPath);
     else
-        RTTestIFailed("RTProcGetExecutableName -> NULL");
+        RTTestIFailed("RTProcGetExecutablePath -> NULL");
 
     RTTestSub(hTest, "RTPathUserHome");
Index: /trunk/src/VBox/Runtime/testcase/tstRTPipe.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTPipe.cpp	(revision 33805)
+++ /trunk/src/VBox/Runtime/testcase/tstRTPipe.cpp	(revision 33806)
@@ -94,5 +94,5 @@
 
     char    szPathSelf[RTPATH_MAX];
-    RTTESTI_CHECK_RETV(RTProcGetExecutableName(szPathSelf, sizeof(szPathSelf)) == szPathSelf);
+    RTTESTI_CHECK_RETV(RTProcGetExecutablePath(szPathSelf, sizeof(szPathSelf)) == szPathSelf);
 
     RTPIPE  hPipeR;
@@ -157,5 +157,5 @@
 
     char    szPathSelf[RTPATH_MAX];
-    RTTESTI_CHECK_RETV(RTProcGetExecutableName(szPathSelf, sizeof(szPathSelf)) == szPathSelf);
+    RTTESTI_CHECK_RETV(RTProcGetExecutablePath(szPathSelf, sizeof(szPathSelf)) == szPathSelf);
 
     RTPIPE  hPipeR;
Index: /trunk/src/VBox/Runtime/testcase/tstRTProcCreateEx.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTProcCreateEx.cpp	(revision 33805)
+++ /trunk/src/VBox/Runtime/testcase/tstRTProcCreateEx.cpp	(revision 33806)
@@ -436,5 +436,5 @@
     RTTestBanner(hTest);
 
-    if (!RTProcGetExecutableName(g_szExecName, sizeof(g_szExecName)))
+    if (!RTProcGetExecutablePath(g_szExecName, sizeof(g_szExecName)))
         RTStrCopy(g_szExecName, sizeof(g_szExecName), argv[0]);
 
Index: /trunk/src/VBox/Runtime/testcase/tstRTProcIsRunningByName.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTProcIsRunningByName.cpp	(revision 33805)
+++ /trunk/src/VBox/Runtime/testcase/tstRTProcIsRunningByName.cpp	(revision 33806)
@@ -72,5 +72,5 @@
      * Test 3: Check for our own process, filename only.
      */
-    if (RTProcGetExecutableName(szExecPath, RTPATH_MAX))
+    if (RTProcGetExecutablePath(szExecPath, RTPATH_MAX))
     {
         /* Strip any path components */
@@ -105,5 +105,5 @@
     else
     {
-        RTPrintf("tstRTProcIsRunningByName: FAILURE - RTProcGetExecutableName failed!\n");
+        RTPrintf("tstRTProcIsRunningByName: FAILURE - RTProcGetExecutablePath failed!\n");
         cErrors++;
     }
Index: /trunk/src/VBox/Runtime/testcase/tstRTSymlink.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTSymlink.cpp	(revision 33805)
+++ /trunk/src/VBox/Runtime/testcase/tstRTSymlink.cpp	(revision 33806)
@@ -129,5 +129,5 @@
 
     char szExecFile[RTPATH_MAX];
-    RTTESTI_CHECK_RETV(RTProcGetExecutableName(szExecFile, sizeof(szExecFile)) != NULL);
+    RTTESTI_CHECK_RETV(RTProcGetExecutablePath(szExecFile, sizeof(szExecFile)) != NULL);
     size_t cchExecFile = strlen(szExecFile);
     RTTESTI_CHECK(RTFileExists(szExecFile));
