static int rtCrStoreAddCertsFromNative(RTCRSTORE hStore, DWORD fStore, PCRTUTF16 pwszStoreName,
                                       PFNCERTOPENSTORE pfnOpenStore, PFNCERTCLOSESTORE pfnCloseStore,
                                       PFNCERTENUMCERTIFICATESINSTORE pfnEnumCerts, int rc, PRTERRINFO pErrInfo)
{
    DWORD fOpenStore = CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG;
    HCERTSTORE hNativeStore = pfnOpenStore(CERT_STORE_PROV_SYSTEM_W, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
                                           NULL /* hCryptProv = default */, fStore | fOpenStore, pwszStoreName);
    if (hStore)
    {
        PCCERT_CONTEXT pCurCtx = NULL;
        while ((pCurCtx = pfnEnumCerts(hNativeStore, pCurCtx)) != NULL)
        {
            if (pCurCtx->dwCertEncodingType & X509_ASN_ENCODING)
            {
                RTERRINFOSTATIC StaticErrInfo;
                RTASN1CURSORPRIMARY PrimaryCursor;
                RTAsn1CursorInitPrimary(&PrimaryCursor, pCurCtx->pbCertEncoded, pCurCtx->cbCertEncoded,
                                        RTErrInfoInitStatic(&StaticErrInfo),
                                        &g_RTAsn1DefaultAllocator, RTASN1CURSOR_FLAGS_DER, "CurCtx");
                RTCRX509CERTIFICATE MyCert;
                int rc2 = RTCrX509Certificate_DecodeAsn1(&PrimaryCursor.Cursor, 0, &MyCert, "Cert");
                if (RT_SUCCESS(rc2))
                {
                    rc2 = RTCrStoreCertAddEncoded(hStore, RTCRCERTCTX_F_ENC_X509_DER | RTCRCERTCTX_F_ADD_IF_NOT_FOUND,
                                                  pCurCtx->pbCertEncoded, pCurCtx->cbCertEncoded,
                                                  RTErrInfoInitStatic(&StaticErrInfo));
                    RTCrX509Certificate_Delete(&MyCert);
                }
                if (RT_FAILURE(rc2))
                {
                    if (RTErrInfoIsSet(&StaticErrInfo.Core))
                        RTErrInfoAddF(pErrInfo, -rc2, "  %s", StaticErrInfo.Core.pszMsg);
                    else
                        RTErrInfoAddF(pErrInfo, -rc2, "  %Rrc adding cert", rc2);
                    rc = -rc2;
                }
            }
        }
        pfnCloseStore(hNativeStore, CERT_CLOSE_STORE_CHECK_FLAG);
    }
    else
    {
        DWORD uLastErr = GetLastError();
        if (uLastErr != ERROR_FILE_NOT_FOUND)
            rc = RTErrInfoAddF(pErrInfo, -RTErrConvertFromWin32(uLastErr),
                               " CertOpenStore(%#x,'%ls') failed: %u", fStore, pwszStoreName);
    }
    return rc;
}
/**
 * Recursively changes the file mode.
 *
 * @returns exit code
 * @param   pOpts               The mkdir option.
 * @param   pszPath             The path to start changing the mode of.
 */
static int rtCmdChModRecursive(RTCMDCHMODOPTS const *pOpts, const char *pszPath)
{
    /*
     * Check if it's a directory first.  If not, join the non-recursive code.
     */
    int             rc;
    uint32_t        offError;
    RTFSOBJINFO     ObjInfo;
    RTERRINFOSTATIC ErrInfo;
    bool const      fUseChainApi = pOpts->fAlwaysUseChainApi || RTVfsChainIsSpec(pszPath);
    if (!fUseChainApi)
    {
        rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
        if (RT_FAILURE(rc))
            return RTMsgErrorExitFailure("RTPathQueryInfoEx failed on '%s': %Rrc", pszPath, rc);
    }
    else
    {
        rc = RTVfsChainQueryInfo(pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK,
                                 &offError, RTErrInfoInitStatic(&ErrInfo));
        if (RT_FAILURE(rc))
            return RTVfsChainMsgErrorExitFailure("RTVfsChainQueryInfo", pszPath, rc, offError, &ErrInfo.Core);
    }

    if (!RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode))
    {
        /*
         * Don't bother redoing the above work if its not necessary.
         */
        RTFMODE fNewMode = rtCmdMkModCalcNewMode(pOpts, ObjInfo.Attr.fMode);
        if (fNewMode != ObjInfo.Attr.fMode)
            return rtCmdChModOne(pOpts, pszPath);
        if (pOpts->enmNoiseLevel >= kRTCmdChModNoise_Verbose)
            RTPrintf("%s\n", pszPath);
        return RTEXITCODE_SUCCESS;
    }

    /*
     * For recursion we always use the VFS layer.
     */
    RTVFSDIR hVfsDir;
    if (!fUseChainApi)
    {
        rc = RTVfsDirOpenNormal(pszPath, 0 /** @todo write attrib flag*/, &hVfsDir);
        if (RT_FAILURE(rc))
            return RTMsgErrorExitFailure("RTVfsDirOpenNormal failed on '%s': %Rrc", pszPath, rc);
    }
    else
    {
        rc = RTVfsChainOpenDir(pszPath, 0 /** @todo write attrib flag*/, &hVfsDir, &offError, RTErrInfoInitStatic(&ErrInfo));
        if (RT_FAILURE(rc))
            return RTVfsChainMsgErrorExitFailure("RTVfsChainQueryInfo", pszPath, rc, offError, &ErrInfo.Core);
    }

    RTMsgError("Recursion is not yet implemented\n");
    RTVfsDirRelease(hVfsDir);
    rc = VERR_NOT_IMPLEMENTED;

    return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
}
Example #3
0
/**
 * Loads the modules.
 *
 * @returns RTEXITCODE_SUCCESS on success.
 */
static RTEXITCODE LoadModules(void)
{
    for (uint32_t i = 0; i < RT_ELEMENTS(g_aModules); i++)
    {
        if (g_aModules[i].fPreload)
        {
            char            szPath[RTPATH_MAX];
            int rc = RTPathAppPrivateArch(szPath, sizeof(szPath));
            if (RT_SUCCESS(rc))
                rc = RTPathAppend(szPath, sizeof(szPath), g_aModules[i].pszName);
            if (RT_FAILURE(rc))
                return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAppPrivateArch or RTPathAppend returned %Rrc", rc);

            void           *pvImageBase;
            RTERRINFOSTATIC ErrInfo;
            RTErrInfoInitStatic(&ErrInfo);
            rc = SUPR3LoadModule(szPath, g_aModules[i].pszName, &g_aModules[i].pvImageBase, &ErrInfo.Core);
            if (RT_FAILURE(rc))
                return RTMsgErrorExit(RTEXITCODE_FAILURE, "SUPR3LoadModule failed for %s (%s): %s (rc=%Rrc)",
                                      g_aModules[i].pszName, szPath, ErrInfo.Core.pszMsg, rc);
            if (g_cVerbose >= 1)
                RTMsgInfo("Loaded '%s' ('%s') at %p\n", szPath, g_aModules[i].pszName, g_aModules[i].pvImageBase);
        }
    }

    RTStrmFlush(g_pStdOut);
    return RTEXITCODE_SUCCESS;
}
/**
 * Changes the file mode of one file system object.
 *
 * @returns exit code
 * @param   pOpts               The chmod options.
 * @param   pszPath             The path to the file system object to change the
 *                              file mode of.
 */
static RTEXITCODE rtCmdChModOne(RTCMDCHMODOPTS const *pOpts, const char *pszPath)
{
    int         rc;
    RTFSOBJINFO ObjInfo;
    bool        fChanges = false;
    if (!pOpts->fAlwaysUseChainApi && !RTVfsChainIsSpec(pszPath) )
    {
        rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
        if (RT_SUCCESS(rc))
        {
            RTFMODE fNewMode = rtCmdMkModCalcNewMode(pOpts, ObjInfo.Attr.fMode);
            fChanges = fNewMode != ObjInfo.Attr.fMode;
            if (fChanges)
            {
                rc = RTPathSetMode(pszPath, fNewMode);
                if (RT_FAILURE(rc))
                    RTMsgError("RTPathSetMode failed on '%s' with fNewMode=%#x: %Rrc", pszPath, fNewMode, rc);
            }
        }
        else
            RTMsgError("RTPathQueryInfoEx failed on '%s': %Rrc", pszPath, rc);
    }
    else
    {
        RTVFSOBJ        hVfsObj;
        uint32_t        offError;
        RTERRINFOSTATIC ErrInfo;
        rc = RTVfsChainOpenObj(pszPath, RTFILE_O_ACCESS_ATTR_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
                               RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_CREATE_NOTHING | RTPATH_F_FOLLOW_LINK,
                               &hVfsObj, &offError, RTErrInfoInitStatic(&ErrInfo));
        if (RT_SUCCESS(rc))
        {
            rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING);
            if (RT_SUCCESS(rc))
            {
                RTFMODE fNewMode = rtCmdMkModCalcNewMode(pOpts, ObjInfo.Attr.fMode);
                fChanges = fNewMode != ObjInfo.Attr.fMode;
                if (fChanges)
                {
                    rc = RTVfsObjSetMode(hVfsObj, fNewMode, RTCHMOD_SET_ALL_MASK);
                    if (RT_FAILURE(rc))
                        RTMsgError("RTVfsObjSetMode failed on '%s' with fNewMode=%#x: %Rrc", pszPath, fNewMode, rc);
                }
            }
            else
                RTVfsChainMsgError("RTVfsObjQueryInfo", pszPath, rc, offError, &ErrInfo.Core);
            RTVfsObjRelease(hVfsObj);
        }
        else
            RTVfsChainMsgError("RTVfsChainOpenObject", pszPath, rc, offError, &ErrInfo.Core);
    }

    if (RT_SUCCESS(rc))
    {
        if (pOpts->enmNoiseLevel >= (fChanges ? kRTCmdChModNoise_Changes : kRTCmdChModNoise_Verbose))
            RTPrintf("%s\n", pszPath);
        return RTEXITCODE_SUCCESS;
    }
    return RTEXITCODE_FAILURE;
}
/**
 * Opens the input file.
 *
 * @returns Command exit, error messages written using RTMsg*.
 *
 * @param   pszFile             The input filename.
 * @param   pOpts               The options, szOutput will be filled in by this
 *                              function on success.
 * @param   phVfsIos            Where to return the input stream handle.
 */
static RTEXITCODE gzipOpenInput(const char *pszFile, PRTGZIPCMDOPTS pOpts, PRTVFSIOSTREAM phVfsIos)
{
    int rc;

    pOpts->pszInput = pszFile;
    if (!strcmp(pszFile, "-"))
    {
        if (   !pOpts->fForce
            && pOpts->fDecompress
            && gzipIsStdHandleATty(RTHANDLESTD_OUTPUT))
            return RTMsgErrorExit(RTEXITCODE_SYNTAX,
                                  "Yeah, right. I'm not reading any compressed data from the terminal without --force.\n");

        rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_INPUT,
                                      RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
                                      true /*fLeaveOpen*/,
                                      phVfsIos);
        if (RT_FAILURE(rc))
            return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening standard input: %Rrc", rc);
    }
    else
    {
        uint32_t        offError = 0;
        RTERRINFOSTATIC ErrInfo;
        rc = RTVfsChainOpenIoStream(pszFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE,
                                    phVfsIos, &offError, RTErrInfoInitStatic(&ErrInfo));
        if (RT_FAILURE(rc))
            return RTVfsChainMsgErrorExitFailure("RTVfsChainOpenIoStream", pszFile, rc, offError, &ErrInfo.Core);
    }

    return RTEXITCODE_SUCCESS;

}
int main(int argc, char **argv)
{
    /*
     * Init IPRT.
     */
    int rc = RTR3InitExe(argc, &argv, 0);
    if (RT_FAILURE(rc))
        return RTMsgInitFailure(rc);

    /*
     * Locate a native DTrace command binary.
     */
    bool fIsNativeDTrace = false;
    char szDTraceCmd[RTPATH_MAX];
    szDTraceCmd[0] = '\0';

#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) || defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
    /*
     * 1. Try native first on platforms where it's applicable.
     */
    static const char * const s_apszNativeDTrace[] =
    {
        "/usr/sbin/dtrace",
        "/sbin/dtrace",
        "/usr/bin/dtrace",
        "/bin/dtrace",
        "/usr/local/sbin/dtrace",
        "/usr/local/bin/dtrace"
    };
    if (!RTEnvExist("VBOX_DTRACE_NO_NATIVE"))
        for (uint32_t i = 0; i < RT_ELEMENTS(s_apszNativeDTrace); i++)
            if (RTFileExists(s_apszNativeDTrace[i]))
            {
                fIsNativeDTrace = true;
                strcpy(szDTraceCmd, s_apszNativeDTrace[i]);
# ifdef RT_OS_LINUX
                /** @todo Warn if the dtrace modules haven't been loaded or vboxdrv isn't
                 *        compiled against them. */
# endif
                break;
            }
    if (szDTraceCmd[0] == '\0')
#endif
    {
        /*
         * 2. VBoxDTrace extension pack installed?
         *
         * Note! We cannot use the COM API here because this program is usually
         *       run thru sudo or directly as root, even if the target
         *       VirtualBox process is running as regular user.  This is due to
         *       the privileges required to run dtrace scripts on a host.
         */
        rc = RTPathAppPrivateArch(szDTraceCmd, sizeof(szDTraceCmd));
        if (RT_SUCCESS(rc))
            rc = RTPathAppend(szDTraceCmd, sizeof(szDTraceCmd),
                              VBOX_EXTPACK_INSTALL_DIR RTPATH_SLASH_STR VBOX_EXTPACK_VBOXDTRACE_MANGLED_NAME);
        if (RT_SUCCESS(rc))
            rc = RTPathAppend(szDTraceCmd, sizeof(szDTraceCmd), RTBldCfgTargetDotArch());
        if (RT_SUCCESS(rc))
            rc = RTPathAppend(szDTraceCmd, sizeof(szDTraceCmd), "VBoxDTraceCmd");
        if (RT_SUCCESS(rc))
            rc = RTStrCat(szDTraceCmd, sizeof(szDTraceCmd), RTLdrGetSuff());
        if (RT_FAILURE(rc))
            return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing extension pack path: %Rrc", rc);
        if (!RTFileExists(szDTraceCmd))
            return RTMsgErrorExit(RTEXITCODE_FAILURE,
                                  "Unable to find a DTrace implementation. VBoxDTrace Extension Pack installed?");
        fIsNativeDTrace = false;
    }


    /*
     * Construct a new command line that includes our libary.
     */
    char szDTraceLibDir[RTPATH_MAX];
    rc = RTPathAppPrivateNoArch(szDTraceLibDir, sizeof(szDTraceLibDir));
    if (RT_SUCCESS(rc))
        rc = RTPathAppend(szDTraceLibDir, sizeof(szDTraceLibDir), "dtrace" RTPATH_SLASH_STR "lib");
    if (RT_SUCCESS(rc))
        rc = RTPathAppend(szDTraceLibDir, sizeof(szDTraceLibDir), RTBldCfgTargetArch());
    if (RT_FAILURE(rc))
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing dtrace library path for VBox: %Rrc", rc);

    char **papszArgs = (char **)RTMemAlloc((argc + 3) * sizeof(char *));
    if (!papszArgs)
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "No memory for argument list.");

    int cArgs    = 1;
    papszArgs[0] = fIsNativeDTrace ? szDTraceCmd : argv[0];
    if (argc > 1)
    {
        papszArgs[cArgs++] = (char *)"-L";
        papszArgs[cArgs++] = szDTraceLibDir;
    }
    for (int i = 1; i < argc; i++)
        papszArgs[cArgs++] = argv[i];
    papszArgs[cArgs] = NULL;
    Assert(cArgs <= argc + 3);


    /*
     * The native DTrace we execute as a sub-process and wait for.
     */
    RTEXITCODE rcExit;
    if (fIsNativeDTrace)
    {
        RTPROCESS hProc;
        rc = RTProcCreate(szDTraceCmd, papszArgs, RTENV_DEFAULT, 0, &hProc);
        if (RT_SUCCESS(rc))
        {
            RTPROCSTATUS Status;
            rc = RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &Status);
            if (RT_SUCCESS(rc))
            {
                if (Status.enmReason == RTPROCEXITREASON_NORMAL)
                    rcExit = (RTEXITCODE)Status.iStatus;
                else
                    rcExit = RTEXITCODE_FAILURE;
            }
            else
                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error waiting for child process: %Rrc", rc);
        }
        else
            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error executing '%s': %Rrc", szDTraceCmd, rc);
    }
    /*
     * While the VBoxDTrace we load and call the main function of.
     */
    else
    {
        RTERRINFOSTATIC ErrInfo;
        RTLDRMOD hMod;
        rc = SUPR3HardenedLdrLoadPlugIn(szDTraceCmd, &hMod, RTErrInfoInitStatic(&ErrInfo));
        if (RT_SUCCESS(rc))
        {
            PFNVBOXDTRACEMAIN pfnVBoxDTraceMain;
            rc = RTLdrGetSymbol(hMod, "VBoxDTraceMain", (void **)&pfnVBoxDTraceMain);
            if (RT_SUCCESS(rc))
                rcExit = (RTEXITCODE)pfnVBoxDTraceMain(cArgs, papszArgs);
            else
                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error locating 'VBoxDTraceMain' in '%s': %Rrc", szDTraceCmd, rc);
        }
        else
            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error loading '%s': %Rrc (%s)", szDTraceCmd, rc, ErrInfo.szMsg);
    }
    return rcExit;
}
static RTEXITCODE RTCmdChMod(unsigned cArgs,  char **papszArgs)
{
    /*
     * Parse the command line.
     */
    static const RTGETOPTDEF s_aOptions[] =
    {
        /* operations */
        { "--recursive",                'R', RTGETOPT_REQ_NOTHING },
        { "--preserve-root",            'x', RTGETOPT_REQ_NOTHING },
        { "--no-preserve-root",         'X', RTGETOPT_REQ_NOTHING },
        { "--changes",                  'c', RTGETOPT_REQ_NOTHING },
        { "--quiet",                    'f', RTGETOPT_REQ_NOTHING },
        { "--silent",                   'f', RTGETOPT_REQ_NOTHING },
        { "--verbose",                  'v', RTGETOPT_REQ_NOTHING },
        { "--reference",                'Z', RTGETOPT_REQ_NOTHING },
        { "--always-use-vfs-chain-api", 'A', RTGETOPT_REQ_NOTHING },

    };

    RTGETOPTSTATE GetState;
    int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1,
                          RTGETOPTINIT_FLAGS_OPTS_FIRST);
    if (RT_FAILURE(rc))
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOpt failed: %Rrc", rc);

    RTCMDCHMODOPTS Opts;
    Opts.enmNoiseLevel      = kRTCmdChModNoise_Default;
    Opts.fPreserveRoot      = false;
    Opts.fRecursive         = false;
    Opts.fAlwaysUseChainApi = false;
    Opts.fModeClear         = 0;
    Opts.fModeSet           = 0;

    RTGETOPTUNION ValueUnion;
    while (   (rc = RTGetOpt(&GetState, &ValueUnion)) != 0
           && rc != VINF_GETOPT_NOT_OPTION)
    {
        switch (rc)
        {
            case 'R':
                Opts.fRecursive = true;
                break;

            case 'x':
                Opts.fPreserveRoot = true;
                break;
            case 'X':
                Opts.fPreserveRoot = false;
                break;

            case 'f':
                Opts.enmNoiseLevel = kRTCmdChModNoise_Quiet;
                break;
            case 'c':
                Opts.enmNoiseLevel = kRTCmdChModNoise_Changes;
                break;
            case 'v':
                Opts.enmNoiseLevel = kRTCmdChModNoise_Verbose;
                break;

            case 'Z':
            {
                RTFSOBJINFO     ObjInfo;
                RTERRINFOSTATIC ErrInfo;
                uint32_t        offError;
                rc = RTVfsChainQueryInfo(ValueUnion.psz, &ObjInfo,RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK,
                                         &offError, RTErrInfoInitStatic(&ErrInfo));
                if (RT_FAILURE(rc))
                    return RTVfsChainMsgErrorExitFailure("RTVfsChainQueryInfo", ValueUnion.psz, rc, offError, &ErrInfo.Core);
                Opts.fModeClear = RTCHMOD_SET_ALL_MASK;
                Opts.fModeSet   = ObjInfo.Attr.fMode & RTCHMOD_SET_ALL_MASK;
                break;
            }

            case 'A':
                Opts.fAlwaysUseChainApi = true;
                break;

            case 'h':
                RTPrintf("Usage: %s [options] <mode> <file> [..]\n"
                         "\n"
                         "Options:\n"
                         "  -f, --silent, --quiet\n"
                         "  -c, --changes\n"
                         "  -v, --verbose\n"
                         "      Noise level selection.\n"
                         "  -R, --recursive\n"
                         "      Recurse into directories.\n"
                         "  --preserve-root, --no-preserve-root\n"
                         "      Whether to allow recursion from the root (default: yes).\n"
                         "  --reference <file>\n"
                         "      Take mode mask to use from <file> instead of <mode>.\n"
                         "\n"
                         "The <mode> part isn't fully implemented, so only numerical octal notation\n"
                         "works.  Prefix the number(s) with 0x to use hexadecimal.  There are two forms\n"
                         "of the numerical notation: <SET> and <SET>:<CLEAR>\n"
                         , papszArgs[0]);
                return RTEXITCODE_SUCCESS;

            case 'V':
                RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
                return RTEXITCODE_SUCCESS;

            default:

                return RTGetOptPrintError(rc, &ValueUnion);
        }
    }

    /*
     * The MODE.
     */
    if (   Opts.fModeClear == 0
        && Opts.fModeSet   == 0)
    {
        if (rc != VINF_GETOPT_NOT_OPTION)
            return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No mode change specified.\n");

        char *pszNext;
        if (   ValueUnion.psz[0] == '0'
            && (ValueUnion.psz[1] == 'x' || ValueUnion.psz[1] == 'X'))
            rc = RTStrToUInt32Ex(ValueUnion.psz, &pszNext, 16, &Opts.fModeSet);
        else
            rc = RTStrToUInt32Ex(ValueUnion.psz, &pszNext, 8, &Opts.fModeSet);
        if (   rc != VINF_SUCCESS
            && (rc != VWRN_TRAILING_CHARS || *pszNext != ':'))
            return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unable to parse mode mask: %s\n", ValueUnion.psz);
        Opts.fModeSet &= RTCHMOD_SET_ALL_MASK;

        if (rc == VINF_SUCCESS)
            Opts.fModeClear = RTCHMOD_SET_ALL_MASK;
        else
        {
            pszNext++;
            if (   pszNext[0] == '0'
                && (pszNext[1] == 'x' || pszNext[1] == 'X'))
                rc = RTStrToUInt32Ex(pszNext, &pszNext, 16, &Opts.fModeClear);
            else
                rc = RTStrToUInt32Ex(pszNext, &pszNext, 8, &Opts.fModeClear);
            if (rc != VINF_SUCCESS)
                return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unable to parse mode mask: %s\n", ValueUnion.psz);
            Opts.fModeClear &= RTCHMOD_SET_ALL_MASK;
        }

        rc = RTGetOpt(&GetState, &ValueUnion);
    }

    /*
     * No files means error.
     */
    if (rc != VINF_GETOPT_NOT_OPTION)
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "No directories specified.\n");

    /*
     * Work thru the specified dirs.
     */
    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
    while (rc == VINF_GETOPT_NOT_OPTION)
    {
        if (Opts.fRecursive)
            rc = rtCmdChModRecursive(&Opts, ValueUnion.psz);
        else
            rc = rtCmdChModOne(&Opts, ValueUnion.psz);
        if (RT_FAILURE(rc))
            rcExit = RTEXITCODE_FAILURE;

        /* next */
        rc = RTGetOpt(&GetState, &ValueUnion);
    }
    if (rc != 0)
        rcExit = RTGetOptPrintError(rc, &ValueUnion);

    return rcExit;
}
int main(int argc, char **argv)
{
    /*
     * Init.
     */
    int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB);
    if (RT_FAILURE(rc))
        return RTMsgInitFailure(rc);

    /*
     * Process arguments.
     */
    static const RTGETOPTDEF s_aOptions[] =
    {
        { "--keep",             'k', RTGETOPT_REQ_NOTHING },
        { "--no-keep",          'n', RTGETOPT_REQ_NOTHING },
    };

    bool fKeepLoaded = false;

    int ch;
    RTGETOPTUNION ValueUnion;
    RTGETOPTSTATE GetState;
    RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
    while ((ch = RTGetOpt(&GetState, &ValueUnion)))
    {
        switch (ch)
        {
            case VINF_GETOPT_NOT_OPTION:
            {
                void           *pvImageBase;
                RTERRINFOSTATIC ErrInfo;
                RTErrInfoInitStatic(&ErrInfo);
                rc = SUPR3LoadModule(ValueUnion.psz, RTPathFilename(ValueUnion.psz), &pvImageBase, &ErrInfo.Core);
                if (RT_FAILURE(rc))
                {
                    RTMsgError("%Rrc when attempting to load '%s': %s\n", rc, ValueUnion.psz, ErrInfo.Core.pszMsg);
                    return 1;
                }
                RTPrintf("Loaded '%s' at %p\n", ValueUnion.psz, pvImageBase);

                if (!fKeepLoaded)
                {
                    rc = SUPR3FreeModule(pvImageBase);
                    if (RT_FAILURE(rc))
                    {
                        RTMsgError("%Rrc when attempting to load '%s'\n", rc, ValueUnion.psz);
                        return 1;
                    }
                }
                break;
            }

            case 'k':
                fKeepLoaded = true;
                break;

            case 'n':
                fKeepLoaded = false;
                break;

            case 'h':
                RTPrintf("%s [mod1 [mod2...]]\n", argv[0]);
                return 1;

            case 'V':
                RTPrintf("$Revision$\n");
                return 0;

            default:
                return RTGetOptPrintError(ch, &ValueUnion);
        }
    }

    return 0;
}
/**
 * Create one directory and any missing parent directories.
 *
 * @returns exit code
 * @param   pOpts               The mkdir option.
 * @param   pszDir              The path to the new directory.
 */
static int rtCmdRmDirOneWithParents(RTCMDRMDIROPTS const *pOpts, const char *pszDir)
{
    /* We need a copy we can work with here. */
    char *pszCopy = RTStrDup(pszDir);
    if (!pszCopy)
        return RTMsgErrorExitFailure("Out of string memory!");

    int rc;
    if (!pOpts->fAlwaysUseChainApi && !RTVfsChainIsSpec(pszDir) )
    {
        size_t cchCopy = strlen(pszCopy);
        do
        {
            rc = RTDirRemove(pszCopy);
            if (RT_SUCCESS(rc))
            {
                if (pOpts->fVerbose)
                    RTPrintf("%s\n", pszCopy);
            }
            else if ((rc == VERR_PATH_NOT_FOUND || rc == VERR_FILE_NOT_FOUND) && pOpts->fIgnoreNonExisting)
                rc = VINF_SUCCESS;
            else
            {
                if ((rc == VERR_DIR_NOT_EMPTY || rc == VERR_SHARING_VIOLATION) && pOpts->fIgnoreNotEmpty)
                    rc = VINF_SUCCESS;
                else
                    RTMsgError("Failed to remove directory '%s': %Rrc", pszCopy, rc);
                break;
            }

            /* Strip off a component. */
            while (cchCopy > 0 && RTPATH_IS_SLASH(pszCopy[cchCopy - 1]))
                cchCopy--;
            while (cchCopy > 0 && !RTPATH_IS_SLASH(pszCopy[cchCopy - 1]))
                cchCopy--;
            while (cchCopy > 0 && RTPATH_IS_SLASH(pszCopy[cchCopy - 1]))
                cchCopy--;
            pszCopy[cchCopy] = '\0';
        } while (cchCopy > 0);
    }
    else
    {
        /*
         * Strip the final path element from the pszDir spec.
         */
        char       *pszFinalPath;
        char       *pszSpec;
        uint32_t    offError;
        rc = RTVfsChainSplitOffFinalPath(pszCopy, &pszSpec, &pszFinalPath, &offError);
        if (RT_SUCCESS(rc))
        {
            /*
             * Open the root director/whatever.
             */
            RTERRINFOSTATIC ErrInfo;
            RTVFSDIR hVfsBaseDir;
            if (pszSpec)
            {
                rc = RTVfsChainOpenDir(pszSpec, 0 /*fOpen*/, &hVfsBaseDir, &offError, RTErrInfoInitStatic(&ErrInfo));
                if (RT_FAILURE(rc))
                    RTVfsChainMsgError("RTVfsChainOpenDir", pszSpec, rc, offError, &ErrInfo.Core);
                else if (!pszFinalPath)
                    pszFinalPath = RTStrEnd(pszSpec, RTSTR_MAX);
            }
            else if (!RTPathStartsWithRoot(pszFinalPath))
            {
                rc = RTVfsDirOpenNormal(".", 0 /*fOpen*/, &hVfsBaseDir);
                if (RT_FAILURE(rc))
                    RTMsgError("Failed to open '.' (for %s): %Rrc", rc, pszFinalPath);
            }
            else
            {
                char *pszRoot = pszFinalPath;
                pszFinalPath = RTPathSkipRootSpec(pszFinalPath);
                char const chSaved = *pszFinalPath;
                *pszFinalPath = '\0';
                rc = RTVfsDirOpenNormal(pszRoot, 0 /*fOpen*/, &hVfsBaseDir);
                *pszFinalPath = chSaved;
                if (RT_FAILURE(rc))
                    RTMsgError("Failed to open root dir for '%s': %Rrc", rc, pszRoot);
            }

            /*
             * Walk the path component by component, starting at the end.
             */
            if (RT_SUCCESS(rc))
            {
                size_t cchFinalPath = strlen(pszFinalPath);
                while (RT_SUCCESS(rc) && cchFinalPath > 0)
                {
                    rc = RTVfsDirRemoveDir(hVfsBaseDir, pszFinalPath, 0 /*fFlags*/);
                    if (RT_SUCCESS(rc))
                    {
                        if (pOpts->fVerbose)
                            RTPrintf("%s\n", pszCopy);
                    }
                    else if ((rc == VERR_PATH_NOT_FOUND || rc == VERR_FILE_NOT_FOUND) && pOpts->fIgnoreNonExisting)
                        rc = VINF_SUCCESS;
                    else
                    {
                        if ((rc == VERR_DIR_NOT_EMPTY || rc == VERR_SHARING_VIOLATION) && pOpts->fIgnoreNotEmpty)
                            rc = VINF_SUCCESS;
                        else if (pszSpec)
                            RTMsgError("Failed to remove directory '%s:%s': %Rrc", pszSpec, pszFinalPath, rc);
                        else
                            RTMsgError("Failed to remove directory '%s': %Rrc", pszFinalPath, rc);
                        break;
                    }

                    /* Strip off a component. */
                    while (cchFinalPath > 0 && RTPATH_IS_SLASH(pszFinalPath[cchFinalPath - 1]))
                        cchFinalPath--;
                    while (cchFinalPath > 0 && !RTPATH_IS_SLASH(pszFinalPath[cchFinalPath - 1]))
                        cchFinalPath--;
                    while (cchFinalPath > 0 && RTPATH_IS_SLASH(pszFinalPath[cchFinalPath - 1]))
                        cchFinalPath--;
                    pszFinalPath[cchFinalPath] = '\0';
                }

                RTVfsDirRelease(hVfsBaseDir);
            }
        }
        else
            RTVfsChainMsgError("RTVfsChainOpenParentDir", pszCopy, rc, offError, NULL);
    }
    RTStrFree(pszCopy);
    return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
}
/**
 * Removes one directory.
 *
 * @returns exit code
 * @param   pOpts               The mkdir option.
 * @param   pszDir              The path to the new directory.
 */
static RTEXITCODE rtCmdRmDirOne(RTCMDRMDIROPTS const *pOpts, const char *pszDir)
{
    int rc;
    if (!pOpts->fAlwaysUseChainApi && !RTVfsChainIsSpec(pszDir) )
        rc = RTDirRemove(pszDir);
    else
    {
        RTVFSDIR        hVfsDir;
        const char     *pszChild;
        uint32_t        offError;
        RTERRINFOSTATIC ErrInfo;
        rc = RTVfsChainOpenParentDir(pszDir, 0 /*fOpen*/, &hVfsDir, &pszChild, &offError, RTErrInfoInitStatic(&ErrInfo));
        if (RT_SUCCESS(rc))
        {
            rc = RTVfsDirRemoveDir(hVfsDir, pszChild, 0 /*fFlags*/);
            RTVfsDirRelease(hVfsDir);
        }
        else
            return RTVfsChainMsgErrorExitFailure("RTVfsChainOpenParentDir", pszDir, rc, offError, &ErrInfo.Core);
    }
    if (RT_SUCCESS(rc))
    {
        if (pOpts->fVerbose)
            RTPrintf("%s\n", pszDir);
        return RTEXITCODE_SUCCESS;
    }
    if ((rc == VERR_DIR_NOT_EMPTY || rc == VERR_SHARING_VIOLATION) && pOpts->fIgnoreNotEmpty)
        return RTEXITCODE_SUCCESS; /** @todo be verbose about this? */
    if ((rc == VERR_PATH_NOT_FOUND || rc == VERR_FILE_NOT_FOUND) && pOpts->fIgnoreNonExisting)
        return RTEXITCODE_SUCCESS; /** @todo be verbose about this? */
    return RTMsgErrorExitFailure("Failed to remove '%s': %Rrc", pszDir, rc);
}
static RTEXITCODE HandleExtractExeSignerCert(int cArgs, char **papszArgs)
{
    /*
     * Parse arguments.
     */
    static const RTGETOPTDEF s_aOptions[] =
    {
        { "--ber",    'b', RTGETOPT_REQ_NOTHING },
        { "--cer",    'c', RTGETOPT_REQ_NOTHING },
        { "--der",    'd', RTGETOPT_REQ_NOTHING },
        { "--exe",    'e', RTGETOPT_REQ_STRING },
        { "--output", 'o', RTGETOPT_REQ_STRING },
    };

    const char *pszExe = NULL;
    const char *pszOut = NULL;
    RTLDRARCH   enmLdrArch   = RTLDRARCH_WHATEVER;
    uint32_t    fCursorFlags = RTASN1CURSOR_FLAGS_DER;

    RTGETOPTSTATE GetState;
    int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
    AssertRCReturn(rc, RTEXITCODE_FAILURE);
    RTGETOPTUNION ValueUnion;
    int ch;
    while ((ch = RTGetOpt(&GetState, &ValueUnion)))
    {
        switch (ch)
        {
            case 'e':   pszExe = ValueUnion.psz; break;
            case 'o':   pszOut = ValueUnion.psz; break;
            case 'b':   fCursorFlags = 0; break;
            case 'c':   fCursorFlags = RTASN1CURSOR_FLAGS_CER; break;
            case 'd':   fCursorFlags = RTASN1CURSOR_FLAGS_DER; break;
            case 'V':   return HandleVersion(cArgs, papszArgs);
            case 'h':   return HelpExtractExeSignerCert(g_pStdOut, RTSIGNTOOLHELP_FULL);

            case VINF_GETOPT_NOT_OPTION:
                if (!pszExe)
                    pszExe = ValueUnion.psz;
                else if (!pszOut)
                    pszOut = ValueUnion.psz;
                else
                    return RTMsgErrorExit(RTEXITCODE_FAILURE, "Too many file arguments: %s", ValueUnion.psz);
                break;

            default:
                return RTGetOptPrintError(ch, &ValueUnion);
        }
    }
    if (!pszExe)
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "No executable given.");
    if (!pszOut)
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "No output file given.");
    if (RTPathExists(pszOut))
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "The output file '%s' exists.", pszOut);

    /*
     * Do it.
     */

    /* Open the executable image and query the PKCS7 info. */
    RTLDRMOD hLdrMod;
    rc = RTLdrOpen(pszExe, RTLDR_O_FOR_VALIDATION, enmLdrArch, &hLdrMod);
    if (RT_FAILURE(rc))
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening executable image '%s': %Rrc", pszExe, rc);

    RTEXITCODE rcExit = RTEXITCODE_FAILURE;
#ifdef DEBUG
    size_t     cbBuf = 64;
#else
    size_t     cbBuf = _512K;
#endif
    void      *pvBuf = RTMemAlloc(cbBuf);
    size_t     cbRet = 0;
    rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_PKCS7_SIGNED_DATA, NULL /*pvBits*/, pvBuf, cbBuf, &cbRet);
    if (rc == VERR_BUFFER_OVERFLOW && cbRet < _4M && cbRet > 0)
    {
        RTMemFree(pvBuf);
        cbBuf = cbRet;
        pvBuf = RTMemAlloc(cbBuf);
        rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_PKCS7_SIGNED_DATA, NULL /*pvBits*/, pvBuf, cbBuf, &cbRet);
    }
    if (RT_SUCCESS(rc))
    {
        static RTERRINFOSTATIC s_StaticErrInfo;
        RTErrInfoInitStatic(&s_StaticErrInfo);

        /*
         * Decode the output.
         */
        RTASN1CURSORPRIMARY PrimaryCursor;
        RTAsn1CursorInitPrimary(&PrimaryCursor, pvBuf, (uint32_t)cbRet, &s_StaticErrInfo.Core,
                                &g_RTAsn1DefaultAllocator, fCursorFlags, "exe");
        RTCRPKCS7CONTENTINFO Pkcs7Ci;
        rc = RTCrPkcs7ContentInfo_DecodeAsn1(&PrimaryCursor.Cursor, 0, &Pkcs7Ci, "pkcs7");
        if (RT_SUCCESS(rc))
        {
            if (RTCrPkcs7ContentInfo_IsSignedData(&Pkcs7Ci))
            {
                PCRTCRPKCS7SIGNEDDATA pSd = Pkcs7Ci.u.pSignedData;
                if (pSd->SignerInfos.cItems == 1)
                {
                    PCRTCRPKCS7ISSUERANDSERIALNUMBER pISN = &pSd->SignerInfos.paItems[0].IssuerAndSerialNumber;
                    PCRTCRX509CERTIFICATE pCert;
                    pCert = RTCrPkcs7SetOfCerts_FindX509ByIssuerAndSerialNumber(&pSd->Certificates,
                                                                                &pISN->Name, &pISN->SerialNumber);
                    if (pCert)
                    {
                        /*
                         * Write it out.
                         */
                        RTFILE hFile;
                        rc = RTFileOpen(&hFile, pszOut, RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE);
                        if (RT_SUCCESS(rc))
                        {
                            uint32_t cbCert = pCert->SeqCore.Asn1Core.cbHdr + pCert->SeqCore.Asn1Core.cb;
                            rc = RTFileWrite(hFile, pCert->SeqCore.Asn1Core.uData.pu8 - pCert->SeqCore.Asn1Core.cbHdr,
                                             cbCert, NULL);
                            if (RT_SUCCESS(rc))
                            {
                                rc = RTFileClose(hFile);
                                if (RT_SUCCESS(rc))
                                {
                                    hFile  = NIL_RTFILE;
                                    rcExit = RTEXITCODE_SUCCESS;
                                    RTMsgInfo("Successfully wrote %u bytes to '%s'", cbCert, pszOut);
                                }
                                else
                                    RTMsgError("RTFileClose failed: %Rrc", rc);
                            }
                            else
                                RTMsgError("RTFileWrite failed: %Rrc", rc);
                            RTFileClose(hFile);
                        }
                        else
                            RTMsgError("Error opening '%s': %Rrc", pszOut, rc);
                    }
                    else
                        RTMsgError("Certificate not found.");
                }
                else
                    RTMsgError("SignerInfo count: %u", pSd->SignerInfos.cItems);
            }
            else
                RTMsgError("No PKCS7 content: ContentType=%s", Pkcs7Ci.ContentType.szObjId);
            RTAsn1VtDelete(&Pkcs7Ci.SeqCore.Asn1Core);
        }
        else
            RTMsgError("RTPkcs7ContentInfoDecodeAsn1 failed: %Rrc - %s", rc, s_StaticErrInfo.szMsg);
    }
    else
        RTMsgError("RTLDRPROP_PKCS7_SIGNED_DATA failed on '%s': %Rrc", pszExe, rc);
    RTMemFree(pvBuf);
    rc = RTLdrClose(hLdrMod);
    if (RT_FAILURE(rc))
        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTLdrClose failed: %Rrc\n", rc);
    return rcExit;
}