/**
 * Figure the type of a file/dir based on path and FS object info.
 *
 * @returns The type.
 * @param   pszPath             The path to the file/dir.
 * @param   pObjInfo            The object information, symlinks followed.
 */
static RTDBGSYMCACHEFILETYPE rtDbgSymCacheFigureType2(const char *pszPath, PCRTFSOBJINFO pObjInfo)
{
    const char *pszName = RTPathFilename(pszPath);
    const char *pszExt  = RTPathSuffix(pszName);
    if (pszExt)
        pszExt++;
    else
        pszExt = "";

    if (   RTFS_IS_DIRECTORY(pObjInfo->Attr.fMode)
            || (pObjInfo->Attr.fMode & RTFS_DOS_DIRECTORY)) /** @todo OS X samba reports reparse points in /Volumes/ that we cannot resolve. */
    {
        /* Skip directories shouldn't bother with. */
        if (   !RTStrICmp(pszName, ".Trashes")
                || !RTStrICmp(pszName, ".$RESCYCLE.BIN")
                || !RTStrICmp(pszName, "System.kext") /* Usually only plugins here, so skip it. */
           )
            return RTDBGSYMCACHEFILETYPE_IGNORE;

        /* Directories can also be bundles on the mac. */
        if (!RTStrICmp(pszExt, "dSYM"))
            return RTDBGSYMCACHEFILETYPE_DEBUG_BUNDLE;

        for (unsigned i = 0; i < RT_ELEMENTS(g_apszBundleSuffixes) - 1; i++)
            if (!RTStrICmp(pszExt, &g_apszBundleSuffixes[i][1]))
                return RTDBGSYMCACHEFILETYPE_IMAGE_BUNDLE;

        return RTDBGSYMCACHEFILETYPE_DIR;
    }

    if (!RTFS_IS_FILE(pObjInfo->Attr.fMode))
        return RTDBGSYMCACHEFILETYPE_INVALID;

    /* Select image vs debug info based on extension. */
    if (   !RTStrICmp(pszExt, "pdb")
            || !RTStrICmp(pszExt, "dbg")
            || !RTStrICmp(pszExt, "sym")
            || !RTStrICmp(pszExt, "dwo")
            || !RTStrICmp(pszExt, "dwp")
            || !RTStrICmp(pszExt, "debug")
            || !RTStrICmp(pszExt, "dsym")
            || !RTStrICmp(pszExt, "dwarf")
            || !RTStrICmp(pszExt, "map")
            || !RTStrICmp(pszExt, "cv"))
        return RTDBGSYMCACHEFILETYPE_DEBUG_FILE;

    /* Filter out a bunch of files which obviously shouldn't be images. */
    if (   !RTStrICmp(pszExt, "txt")
            || !RTStrICmp(pszExt, "html")
            || !RTStrICmp(pszExt, "htm")
            || !RTStrICmp(pszExt, "rtf")
            || !RTStrICmp(pszExt, "zip")
            || !RTStrICmp(pszExt, "doc")
            || !RTStrICmp(pszExt, "gz")
            || !RTStrICmp(pszExt, "bz2")
            || !RTStrICmp(pszExt, "xz")
            || !RTStrICmp(pszExt, "kmk")
            || !RTStrICmp(pszExt, "c")
            || !RTStrICmp(pszExt, "cpp")
            || !RTStrICmp(pszExt, "h")
            || !RTStrICmp(pszExt, "m")
            || !RTStrICmp(pszExt, "mm")
            || !RTStrICmp(pszExt, "asm")
            || !RTStrICmp(pszExt, "S")
            || !RTStrICmp(pszExt, "inc")
            || !RTStrICmp(pszExt, "sh")
       )
        return RTDBGSYMCACHEFILETYPE_IGNORE;
    if (   !RTStrICmp(pszName, "Makefile")
            || !RTStrICmp(pszName, "GNUmakefile")
            || !RTStrICmp(pszName, "createsymbolfiles")
            || !RTStrICmp(pszName, "kgmacros")
       )
        return RTDBGSYMCACHEFILETYPE_IGNORE;

    return RTDBGSYMCACHEFILETYPE_IMAGE_FILE;
}
Exemple #2
0
/**
 * Searches for a long option.
 *
 * @returns Pointer to a matching option.
 * @param   pszOption       The alleged long option.
 * @param   paOptions       Option array.
 * @param   cOptions        Number of items in the array.
 * @param   fFlags          Init flags.
 */
static PCRTGETOPTDEF rtGetOptSearchLong(const char *pszOption, PCRTGETOPTDEF paOptions, size_t cOptions, uint32_t fFlags)
{
    PCRTGETOPTDEF pOpt = paOptions;
    while (cOptions-- > 0)
    {
        if (pOpt->pszLong)
        {
            if ((pOpt->fFlags & RTGETOPT_REQ_MASK) != RTGETOPT_REQ_NOTHING)
            {
                /*
                 * A value is required with the argument. We're trying to be
                 * understanding here and will permit any of the following:
                 *      --long12:value,  --long12=value, --long12 value,
                 *      --long:value,    --long=value,   --long value,
                 *
                 * If the option is index, then all trailing chars must be
                 * digits.  For error reporting reasons we also match where
                 * there is no index.
                 */
                size_t cchLong = strlen(pOpt->pszLong);
                if (   !strncmp(pszOption, pOpt->pszLong, cchLong)
                    || (   pOpt->fFlags & RTGETOPT_FLAG_ICASE
                        && !RTStrNICmp(pszOption, pOpt->pszLong, cchLong)))
                {
                    if (pOpt->fFlags & RTGETOPT_FLAG_INDEX)
                        while (RT_C_IS_DIGIT(pszOption[cchLong]))
                            cchLong++;
                    if (   pszOption[cchLong] == '\0'
                        || pszOption[cchLong] == ':'
                        || pszOption[cchLong] == '=')
                        return pOpt;
                }
            }
            else if (pOpt->fFlags & RTGETOPT_FLAG_INDEX)
            {
                /*
                 * The option takes an index but no value.
                 * As above, we also match where there is no index.
                 */
                size_t cchLong = strlen(pOpt->pszLong);
                if (   !strncmp(pszOption, pOpt->pszLong, cchLong)
                    || (   pOpt->fFlags & RTGETOPT_FLAG_ICASE
                        && !RTStrNICmp(pszOption, pOpt->pszLong, cchLong)))
                {
                    while (RT_C_IS_DIGIT(pszOption[cchLong]))
                        cchLong++;
                    if (pszOption[cchLong] == '\0')
                        return pOpt;
                }
            }
            else if (   !strcmp(pszOption, pOpt->pszLong)
                     || (   pOpt->fFlags & RTGETOPT_FLAG_ICASE
                         && !RTStrICmp(pszOption, pOpt->pszLong)))
                return pOpt;
        }
        pOpt++;
    }

    if (!(fFlags & RTGETOPTINIT_FLAGS_NO_STD_OPTS))
        for (uint32_t i = 0; i < RT_ELEMENTS(g_aStdOptions); i++)
            if (   !strcmp(pszOption, g_aStdOptions[i].pszLong)
                || (   g_aStdOptions[i].fFlags & RTGETOPT_FLAG_ICASE
                    && !RTStrICmp(pszOption, g_aStdOptions[i].pszLong)))
                return &g_aStdOptions[i];

    return NULL;
}
Exemple #3
0
int main(int argc, char **argv)
{
    RTEXITCODE rcExit;

    /*
     * Init globals and such.
     */
    int rc = RTR3InitExe(argc, &argv, 0);
    if (RT_FAILURE(rc))
        return RTMsgInitFailure(rc);
    g_pszProgName = RTPathFilename(argv[0]);
#ifdef DEBUG
    rc = RTCritSectInit(&g_csLog);
    AssertRC(rc);
#endif

#ifdef VBOXSERVICE_TOOLBOX
    /*
     * Run toolbox code before all other stuff since these things are simpler
     * shell/file/text utility like programs that just happens to be inside
     * VBoxService and shouldn't be subject to /dev/vboxguest, pid-files and
     * global mutex restrictions.
     */
    if (VBoxServiceToolboxMain(argc, argv, &rcExit))
        return rcExit;
#endif

    bool fUserSession = false;
#ifdef VBOX_WITH_GUEST_CONTROL
    /*
     * Check if we're the specially spawned VBoxService.exe process that
     * handles a guest control session.
     */
    if (   argc >= 2
        && !RTStrICmp(argv[1], "guestsession"))
        fUserSession = true;
#endif

    /*
     * Connect to the kernel part before daemonizing so we can fail and
     * complain if there is some kind of problem.  We need to initialize the
     * guest lib *before* we do the pre-init just in case one of services needs
     * do to some initial stuff with it.
     */
    if (fUserSession)
        rc = VbglR3InitUser();
    else
        rc = VbglR3Init();

    if (RT_FAILURE(rc))
    {
        if (rc == VERR_ACCESS_DENIED)
            return RTMsgErrorExit(RTEXITCODE_FAILURE, "Insufficient privileges to start %s! Please start with Administrator/root privileges!\n",
                                  g_pszProgName);
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "VbglR3Init failed with rc=%Rrc\n", rc);
    }

#ifdef RT_OS_WINDOWS
    /*
     * Check if we're the specially spawned VBoxService.exe process that
     * handles page fusion.  This saves an extra executable.
     */
    if (   argc == 2
        && !RTStrICmp(argv[1], "pagefusion"))
        return VBoxServicePageSharingWorkerChild();
#endif

#ifdef VBOX_WITH_GUEST_CONTROL
    /*
     * Check if we're the specially spawned VBoxService.exe process that
     * handles a guest control session.
     */
    if (fUserSession)
        return VBoxServiceControlSessionForkInit(argc, argv);
#endif

    /*
     * Parse the arguments.
     *
     * Note! This code predates RTGetOpt, thus the manual parsing.
     */
    bool fDaemonize = true;
    bool fDaemonized = false;
    for (int i = 1; i < argc; i++)
    {
        const char *psz = argv[i];
        if (*psz != '-')
            return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown argument '%s'\n", psz);
        psz++;

        /* translate long argument to short */
        if (*psz == '-')
        {
            psz++;
            size_t cch = strlen(psz);
#define MATCHES(strconst)       (   cch == sizeof(strconst) - 1 \
                                 && !memcmp(psz, strconst, sizeof(strconst) - 1) )
            if (MATCHES("foreground"))
                psz = "f";
            else if (MATCHES("verbose"))
                psz = "v";
            else if (MATCHES("version"))
                psz = "V";
            else if (MATCHES("help"))
                psz = "h";
            else if (MATCHES("interval"))
                psz = "i";
#ifdef RT_OS_WINDOWS
            else if (MATCHES("register"))
                psz = "r";
            else if (MATCHES("unregister"))
                psz = "u";
#endif
            else if (MATCHES("logfile"))
                psz = "l";
            else if (MATCHES("daemonized"))
            {
                fDaemonized = true;
                continue;
            }
            else
            {
                bool fFound = false;

                if (cch > sizeof("enable-") && !memcmp(psz, RT_STR_TUPLE("enable-")))
                    for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
                        if ((fFound = !RTStrICmp(psz + sizeof("enable-") - 1, g_aServices[j].pDesc->pszName)))
                            g_aServices[j].fEnabled = true;

                if (cch > sizeof("disable-") && !memcmp(psz, RT_STR_TUPLE("disable-")))
                    for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
                        if ((fFound = !RTStrICmp(psz + sizeof("disable-") - 1, g_aServices[j].pDesc->pszName)))
                            g_aServices[j].fEnabled = false;

                if (cch > sizeof("only-") && !memcmp(psz, RT_STR_TUPLE("only-")))
                    for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
                    {
                        g_aServices[j].fEnabled = !RTStrICmp(psz + sizeof("only-") - 1, g_aServices[j].pDesc->pszName);
                        if (g_aServices[j].fEnabled)
                            fFound = true;
                    }

                if (!fFound)
                {
                    rcExit = vboxServiceLazyPreInit();
                    if (rcExit != RTEXITCODE_SUCCESS)
                        return rcExit;
                    for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
                    {
                        rc = g_aServices[j].pDesc->pfnOption(NULL, argc, argv, &i);
                        fFound = rc == VINF_SUCCESS;
                        if (fFound)
                            break;
                        if (rc != -1)
                            return rc;
                    }
                }
                if (!fFound)
                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown option '%s'\n", argv[i]);
                continue;
            }
#undef MATCHES
        }

        /* handle the string of short options. */
        do
        {
            switch (*psz)
            {
                case 'i':
                    rc = VBoxServiceArgUInt32(argc, argv, psz + 1, &i,
                                              &g_DefaultInterval, 1, (UINT32_MAX / 1000) - 1);
                    if (rc)
                        return rc;
                    psz = NULL;
                    break;

                case 'f':
                    fDaemonize = false;
                    break;

                case 'v':
                    g_cVerbosity++;
                    break;

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

                case 'h':
                case '?':
                    return vboxServiceUsage();

#ifdef RT_OS_WINDOWS
                case 'r':
                    return VBoxServiceWinInstall();

                case 'u':
                    return VBoxServiceWinUninstall();
#endif

                case 'l':
                {
                    rc = VBoxServiceArgString(argc, argv, psz + 1, &i,
                                              g_szLogFile, sizeof(g_szLogFile));
                    if (rc)
                        return rc;
                    psz = NULL;
                    break;
                }

                default:
                {
                    rcExit = vboxServiceLazyPreInit();
                    if (rcExit != RTEXITCODE_SUCCESS)
                        return rcExit;

                    bool fFound = false;
                    for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
                    {
                        rc = g_aServices[j].pDesc->pfnOption(&psz, argc, argv, &i);
                        fFound = rc == VINF_SUCCESS;
                        if (fFound)
                            break;
                        if (rc != -1)
                            return rc;
                    }
                    if (!fFound)
                        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown option '%c' (%s)\n", *psz, argv[i]);
                    break;
                }
            }
        } while (psz && *++psz);
    }

    /* Check that at least one service is enabled. */
    if (vboxServiceCountEnabledServices() == 0)
        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "At least one service must be enabled\n");

    rc = VBoxServiceLogCreate(strlen(g_szLogFile) ? g_szLogFile : NULL);
    if (RT_FAILURE(rc))
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create release log \"%s\", rc=%Rrc\n",
                              strlen(g_szLogFile) ? g_szLogFile : "<None>", rc);

    /* Call pre-init if we didn't do it already. */
    rcExit = vboxServiceLazyPreInit();
    if (rcExit != RTEXITCODE_SUCCESS)
        return rcExit;

#ifdef RT_OS_WINDOWS
    /*
     * Make sure only one instance of VBoxService runs at a time.  Create a
     * global mutex for that.
     *
     * Note! The \\Global\ namespace was introduced with Win2K, thus the
     *       version check.
     * Note! If the mutex exists CreateMutex will open it and set last error to
     *       ERROR_ALREADY_EXISTS.
     */
    OSVERSIONINFOEX OSInfoEx;
    RT_ZERO(OSInfoEx);
    OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

    SetLastError(NO_ERROR);
    HANDLE hMutexAppRunning;
    if (    GetVersionEx((LPOSVERSIONINFO)&OSInfoEx)
        &&  OSInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT
        &&  OSInfoEx.dwMajorVersion >= 5 /* NT 5.0 a.k.a W2K */)
        hMutexAppRunning = CreateMutex(NULL, FALSE, "Global\\" VBOXSERVICE_NAME);
    else
        hMutexAppRunning = CreateMutex(NULL, FALSE, VBOXSERVICE_NAME);
    if (hMutexAppRunning == NULL)
    {
        DWORD dwErr = GetLastError();
        if (   dwErr == ERROR_ALREADY_EXISTS
            || dwErr == ERROR_ACCESS_DENIED)
        {
            VBoxServiceError("%s is already running! Terminating.\n", g_pszProgName);
            return RTEXITCODE_FAILURE;
        }

        VBoxServiceError("CreateMutex failed with last error %u! Terminating.\n", GetLastError());
        return RTEXITCODE_FAILURE;
    }

#else  /* !RT_OS_WINDOWS */
    /** @todo Add PID file creation here? */
#endif /* !RT_OS_WINDOWS */

    VBoxServiceVerbose(0, "%s r%s started. Verbose level = %d\n",
                       RTBldCfgVersion(), RTBldCfgRevisionStr(), g_cVerbosity);

    /*
     * Daemonize if requested.
     */
    if (fDaemonize && !fDaemonized)
    {
#ifdef RT_OS_WINDOWS
        VBoxServiceVerbose(2, "Starting service dispatcher ...\n");
        rcExit = VBoxServiceWinEnterCtrlDispatcher();
#else
        VBoxServiceVerbose(1, "Daemonizing...\n");
        rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */,
                             false /* fRespawn */, NULL /* pcRespawn */);
        if (RT_FAILURE(rc))
            return VBoxServiceError("Daemon failed: %Rrc\n", rc);
        /* in-child */
#endif
    }
#ifdef RT_OS_WINDOWS
    else
#endif
    {
        /*
         * Windows: We're running the service as a console application now. Start the
         *          services, enter the main thread's run loop and stop them again
         *          when it returns.
         *
         * POSIX:   This is used for both daemons and console runs. Start all services
         *          and return immediately.
         */
#ifdef RT_OS_WINDOWS
# ifndef RT_OS_NT4
        /* Install console control handler. */
        if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)VBoxServiceConsoleControlHandler, TRUE /* Add handler */))
        {
            VBoxServiceError("Unable to add console control handler, error=%ld\n", GetLastError());
            /* Just skip this error, not critical. */
        }
# endif /* !RT_OS_NT4 */
#endif /* RT_OS_WINDOWS */
        rc = VBoxServiceStartServices();
        rcExit = RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
        if (RT_SUCCESS(rc))
            VBoxServiceMainWait();
#ifdef RT_OS_WINDOWS
# ifndef RT_OS_NT4
        /* Uninstall console control handler. */
        if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)NULL, FALSE /* Remove handler */))
        {
            VBoxServiceError("Unable to remove console control handler, error=%ld\n", GetLastError());
            /* Just skip this error, not critical. */
        }
# endif /* !RT_OS_NT4 */
#else /* !RT_OS_WINDOWS */
        /* On Windows - since we're running as a console application - we already stopped all services
         * through the console control handler. So only do the stopping of services here on other platforms
         * where the break/shutdown/whatever signal was just received. */
        VBoxServiceStopServices();
#endif /* RT_OS_WINDOWS */
    }
    VBoxServiceReportStatus(VBoxGuestFacilityStatus_Terminated);

#ifdef RT_OS_WINDOWS
    /*
     * Cleanup mutex.
     */
    CloseHandle(hMutexAppRunning);
#endif

    VBoxServiceVerbose(0, "Ended.\n");

#ifdef DEBUG
    RTCritSectDelete(&g_csLog);
    //RTMemTrackerDumpAllToStdOut();
#endif

    VBoxServiceLogDestroy();

    return rcExit;
}
/**
 * Value string -> Value union.
 *
 * @returns IPRT status code.
 * @param   fFlags              The value flags.
 * @param   pszValue            The value string.
 * @param   pValueUnion         Where to return the processed value.
 */
static int rtGetOptProcessValue(uint32_t fFlags, const char *pszValue, PRTGETOPTUNION pValueUnion)
{
    /*
     * Transform into a option value as requested.
     * If decimal conversion fails, we'll check for "0x<xdigit>" and
     * try a 16 based conversion. We will not interpret any of the
     * generic ints as octals.
     */
    uint32_t const fSwitchValue =  fFlags & (  RTGETOPT_REQ_MASK
                                             | RTGETOPT_FLAG_HEX
                                             | RTGETOPT_FLAG_DEC
                                             | RTGETOPT_FLAG_OCT);
    switch (fSwitchValue)
    {
        case RTGETOPT_REQ_STRING:
            pValueUnion->psz = pszValue;
            break;

        case RTGETOPT_REQ_BOOL:
            if (   !RTStrICmp(pszValue, "true")
                || !RTStrICmp(pszValue, "t")
                || !RTStrICmp(pszValue, "yes")
                || !RTStrICmp(pszValue, "y")
                || !RTStrICmp(pszValue, "enabled")
                || !RTStrICmp(pszValue, "enable")
                || !RTStrICmp(pszValue, "en")
                || !RTStrICmp(pszValue, "e")
                || !RTStrICmp(pszValue, "on")
                || !RTStrCmp(pszValue, "1")
                )
                pValueUnion->f = true;
            else if (   !RTStrICmp(pszValue, "false")
                     || !RTStrICmp(pszValue, "f")
                     || !RTStrICmp(pszValue, "no")
                     || !RTStrICmp(pszValue, "n")
                     || !RTStrICmp(pszValue, "disabled")
                     || !RTStrICmp(pszValue, "disable")
                     || !RTStrICmp(pszValue, "dis")
                     || !RTStrICmp(pszValue, "d")
                     || !RTStrICmp(pszValue, "off")
                     || !RTStrCmp(pszValue, "0")
                     )
                pValueUnion->f = false;
            else
            {
                pValueUnion->psz = pszValue;
                return VERR_GETOPT_UNKNOWN_OPTION;
            }
            break;

        case RTGETOPT_REQ_BOOL_ONOFF:
            if (!RTStrICmp(pszValue, "on"))
                pValueUnion->f = true;
            else if (!RTStrICmp(pszValue, "off"))
                pValueUnion->f = false;
            else
            {
                pValueUnion->psz = pszValue;
                return VERR_GETOPT_UNKNOWN_OPTION;
            }
            break;

#define MY_INT_CASE(req, type, memb, convfn) \
            case req: \
            { \
                type Value; \
                if (    convfn(pszValue, 10, &Value) != VINF_SUCCESS \
                    &&  (   pszValue[0] != '0' \
                         || (pszValue[1] != 'x' && pszValue[1] != 'X') \
                         || !RT_C_IS_XDIGIT(pszValue[2]) \
                         || convfn(pszValue, 16, &Value) != VINF_SUCCESS ) ) \
                    return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \
                pValueUnion->memb = Value; \
                break; \
            }
#define MY_BASE_INT_CASE(req, type, memb, convfn, base) \
            case req: \
            { \
                type Value; \
                if (convfn(pszValue, base, &Value) != VINF_SUCCESS) \
                    return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \
                pValueUnion->memb = Value; \
                break; \
            }

        MY_INT_CASE(RTGETOPT_REQ_INT8,   int8_t,   i8,  RTStrToInt8Full)
        MY_INT_CASE(RTGETOPT_REQ_INT16,  int16_t,  i16, RTStrToInt16Full)
        MY_INT_CASE(RTGETOPT_REQ_INT32,  int32_t,  i32, RTStrToInt32Full)
        MY_INT_CASE(RTGETOPT_REQ_INT64,  int64_t,  i64, RTStrToInt64Full)
        MY_INT_CASE(RTGETOPT_REQ_UINT8,  uint8_t,  u8,  RTStrToUInt8Full)
        MY_INT_CASE(RTGETOPT_REQ_UINT16, uint16_t, u16, RTStrToUInt16Full)
        MY_INT_CASE(RTGETOPT_REQ_UINT32, uint32_t, u32, RTStrToUInt32Full)
        MY_INT_CASE(RTGETOPT_REQ_UINT64, uint64_t, u64, RTStrToUInt64Full)

        MY_BASE_INT_CASE(RTGETOPT_REQ_INT8   | RTGETOPT_FLAG_HEX, int8_t,   i8,  RTStrToInt8Full,   16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT16  | RTGETOPT_FLAG_HEX, int16_t,  i16, RTStrToInt16Full,  16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT32  | RTGETOPT_FLAG_HEX, int32_t,  i32, RTStrToInt32Full,  16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT64  | RTGETOPT_FLAG_HEX, int64_t,  i64, RTStrToInt64Full,  16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8  | RTGETOPT_FLAG_HEX, uint8_t,  u8,  RTStrToUInt8Full,  16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_HEX, uint16_t, u16, RTStrToUInt16Full, 16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX, uint32_t, u32, RTStrToUInt32Full, 16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX, uint64_t, u64, RTStrToUInt64Full, 16)

        MY_BASE_INT_CASE(RTGETOPT_REQ_INT8   | RTGETOPT_FLAG_DEC, int8_t,   i8,  RTStrToInt8Full,   10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT16  | RTGETOPT_FLAG_DEC, int16_t,  i16, RTStrToInt16Full,  10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT32  | RTGETOPT_FLAG_DEC, int32_t,  i32, RTStrToInt32Full,  10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT64  | RTGETOPT_FLAG_DEC, int64_t,  i64, RTStrToInt64Full,  10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8  | RTGETOPT_FLAG_DEC, uint8_t,  u8,  RTStrToUInt8Full,  10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_DEC, uint16_t, u16, RTStrToUInt16Full, 10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_DEC, uint32_t, u32, RTStrToUInt32Full, 10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_DEC, uint64_t, u64, RTStrToUInt64Full, 10)

        MY_BASE_INT_CASE(RTGETOPT_REQ_INT8   | RTGETOPT_FLAG_OCT, int8_t,   i8,  RTStrToInt8Full,   8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT16  | RTGETOPT_FLAG_OCT, int16_t,  i16, RTStrToInt16Full,  8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT32  | RTGETOPT_FLAG_OCT, int32_t,  i32, RTStrToInt32Full,  8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT64  | RTGETOPT_FLAG_OCT, int64_t,  i64, RTStrToInt64Full,  8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8  | RTGETOPT_FLAG_OCT, uint8_t,  u8,  RTStrToUInt8Full,  8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_OCT, uint16_t, u16, RTStrToUInt16Full, 8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT, uint32_t, u32, RTStrToUInt32Full, 8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_OCT, uint64_t, u64, RTStrToUInt64Full, 8)

#undef MY_INT_CASE
#undef MY_BASE_INT_CASE

        case RTGETOPT_REQ_IPV4ADDR:
        {
            RTNETADDRIPV4 Addr;
            if (rtgetoptConvertIPv4Addr(pszValue, &Addr) != VINF_SUCCESS)
                return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
            pValueUnion->IPv4Addr = Addr;
            break;
        }

        case RTGETOPT_REQ_IPV4CIDR:
        {
            RTNETADDRIPV4 network;
            RTNETADDRIPV4 netmask;
            if (RT_FAILURE(RTCidrStrToIPv4(pszValue, &network, &netmask)))
              return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
            pValueUnion->CidrIPv4.IPv4Network.u = network.u;
            pValueUnion->CidrIPv4.IPv4Netmask.u = netmask.u;
            break;
        }

        case RTGETOPT_REQ_MACADDR:
        {
            RTMAC Addr;
            if (rtgetoptConvertMacAddr(pszValue, &Addr) != VINF_SUCCESS)
                return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
            pValueUnion->MacAddr = Addr;
            break;
        }

        case RTGETOPT_REQ_UUID:
        {
            RTUUID Uuid;
            if (RTUuidFromStr(&Uuid, pszValue) != VINF_SUCCESS)
                return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
            pValueUnion->Uuid = Uuid;
            break;
        }

#define MY_INT_PAIR_CASE(a_fReqValue, a_fReqValueOptional, a_Type, a_MemberPrefix, a_fnConv, a_ConvBase, a_DefaultValue) \
            case a_fReqValue: \
            case a_fReqValueOptional: \
            { \
                /* First value: */ \
                a_Type Value1; \
                char *pszNext = NULL; \
                unsigned uBase =   pszValue[0] == '0' \
                                && (pszValue[1] == 'x' || pszValue[1] == 'X') \
                                && RT_C_IS_XDIGIT(pszValue[2]) \
                              ? 16 : a_ConvBase; \
                int rc = a_fnConv(pszValue, &pszNext, uBase, &Value1); \
                if (rc == VINF_SUCCESS || rc == VWRN_TRAILING_CHARS || rc == VWRN_TRAILING_SPACES) \
                { \
                    /* The second value, could be optional: */ \
                    a_Type Value2 = a_DefaultValue; \
                    pszValue = pszNext;\
                    if (pszValue) \
                    { \
                        while (RT_C_IS_BLANK(*pszValue)) \
                            pszValue++; \
                        if (*pszValue == ':' || *pszValue == '/' || *pszValue == '|') \
                            do pszValue++; \
                            while (RT_C_IS_BLANK(*pszValue)); \
                        if (pszValue != pszNext) \
                        { \
                            uBase =    pszValue[0] == '0' \
                                    && (pszValue[1] == 'x' || pszValue[1] == 'X') \
                                    && RT_C_IS_XDIGIT(pszValue[2]) \
                                  ? 16 : a_ConvBase; \
                            rc = a_fnConv(pszValue, &pszNext, uBase, &Value2); \
                            if (rc == VINF_SUCCESS) \
                            { /* likely */ } \
                            else \
                               { RTAssertMsg2("z rc=%Rrc: '%s' '%s' uBase=%d\n", rc, pszValue, pszNext, uBase); return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; } \
                        } \
                        else if (fSwitchValue != (a_fReqValueOptional)) \
                        { RTAssertMsg2("x\n"); return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; } \
                    } \
                    else if (fSwitchValue != (a_fReqValueOptional)) \
                        { RTAssertMsg2("y\n"); return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; } \
                    pValueUnion->a_MemberPrefix##Second = Value2; \
                    pValueUnion->a_MemberPrefix##First  = Value1; \
                    break; \
                } \
                return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \
            }

        MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT32_PAIR,                      RTGETOPT_REQ_UINT32_OPTIONAL_PAIR,
                         uint32_t, PairU32.u, RTStrToUInt32Ex, 10, UINT32_MAX)
        MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT32_PAIR | RTGETOPT_FLAG_DEC,  RTGETOPT_REQ_UINT32_OPTIONAL_PAIR | RTGETOPT_FLAG_DEC,
                         uint32_t, PairU32.u, RTStrToUInt32Ex, 10, UINT32_MAX)
        MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT32_PAIR | RTGETOPT_FLAG_HEX,  RTGETOPT_REQ_UINT32_OPTIONAL_PAIR | RTGETOPT_FLAG_HEX,
                         uint32_t, PairU32.u, RTStrToUInt32Ex, 16, UINT32_MAX)
        MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT32_PAIR | RTGETOPT_FLAG_OCT,  RTGETOPT_REQ_UINT32_OPTIONAL_PAIR | RTGETOPT_FLAG_OCT,
                         uint32_t, PairU32.u, RTStrToUInt32Ex,  8, UINT32_MAX)

        MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT64_PAIR,                      RTGETOPT_REQ_UINT64_OPTIONAL_PAIR,
                         uint64_t, PairU64.u, RTStrToUInt64Ex, 10, UINT64_MAX)
        MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT64_PAIR | RTGETOPT_FLAG_DEC,  RTGETOPT_REQ_UINT64_OPTIONAL_PAIR | RTGETOPT_FLAG_DEC,
                         uint64_t, PairU64.u, RTStrToUInt64Ex, 10, UINT64_MAX)
        MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT64_PAIR | RTGETOPT_FLAG_HEX,  RTGETOPT_REQ_UINT64_OPTIONAL_PAIR | RTGETOPT_FLAG_HEX,
                         uint64_t, PairU64.u, RTStrToUInt64Ex, 16, UINT64_MAX)
        MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT64_PAIR | RTGETOPT_FLAG_OCT,  RTGETOPT_REQ_UINT64_OPTIONAL_PAIR | RTGETOPT_FLAG_OCT,
                         uint64_t, PairU64.u, RTStrToUInt64Ex,  8, UINT64_MAX)

        default:
            AssertMsgFailed(("f=%#x\n", fFlags));
            return VERR_INTERNAL_ERROR;
    }

    return VINF_SUCCESS;
}
Exemple #5
0
int main(int argc, char **argv)
{
     RTR3InitExe(argc, &argv, 0);

     RTDIGESTTYPE enmDigestType  = RTDIGESTTYPE_INVALID;
     const char  *pszDigestType  = "NotSpecified";

     enum
     {
         kMethod_Full,
         kMethod_Block,
         kMethod_File,
         kMethod_CVAS
     } enmMethod = kMethod_Block;

     uint64_t   offStart    = 0;
     uint64_t   cbMax       = UINT64_MAX;
     bool       fTestcase   = false;

     static const RTGETOPTDEF s_aOptions[] =
     {
         { "--type",   't', RTGETOPT_REQ_STRING },
         { "--method", 'm', RTGETOPT_REQ_STRING },
         { "--help",   'h', RTGETOPT_REQ_NOTHING },
         { "--length", 'l', RTGETOPT_REQ_UINT64 },
         { "--offset", 'o', RTGETOPT_REQ_UINT64 },
         { "--testcase", 'x', RTGETOPT_REQ_NOTHING },
     };

     int ch;
     RTGETOPTUNION ValueUnion;
     RTGETOPTSTATE GetState;
     RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
     while ((ch = RTGetOpt(&GetState, &ValueUnion)))
     {
         switch (ch)
         {
             case 't':
                 if (!RTStrICmp(ValueUnion.psz, "crc32"))
                 {
                     pszDigestType  = "CRC32";
                     enmDigestType  = RTDIGESTTYPE_CRC32;
                 }
                 else if (!RTStrICmp(ValueUnion.psz, "crc64"))
                 {
                     pszDigestType = "CRC64";
                     enmDigestType = RTDIGESTTYPE_CRC64;
                 }
                 else if (!RTStrICmp(ValueUnion.psz, "md2"))
                 {
                     pszDigestType = "MD2";
                     enmDigestType = RTDIGESTTYPE_MD2;
                 }
                 else if (!RTStrICmp(ValueUnion.psz, "md5"))
                 {
                     pszDigestType = "MD5";
                     enmDigestType = RTDIGESTTYPE_MD5;
                 }
                 else if (!RTStrICmp(ValueUnion.psz, "sha1"))
                 {
                     pszDigestType = "SHA-1";
                     enmDigestType = RTDIGESTTYPE_SHA1;
                 }
                 else if (!RTStrICmp(ValueUnion.psz, "sha224"))
                 {
                     pszDigestType = "SHA-224";
                     enmDigestType = RTDIGESTTYPE_SHA224;
                 }
                 else if (!RTStrICmp(ValueUnion.psz, "sha256"))
                 {
                     pszDigestType = "SHA-256";
                     enmDigestType = RTDIGESTTYPE_SHA256;
                 }
                 else if (!RTStrICmp(ValueUnion.psz, "sha384"))
                 {
                     pszDigestType = "SHA-384";
                     enmDigestType = RTDIGESTTYPE_SHA384;
                 }
                 else if (!RTStrICmp(ValueUnion.psz, "sha512"))
                 {
                     pszDigestType = "SHA-512";
                     enmDigestType = RTDIGESTTYPE_SHA512;
                 }
                 else if (!RTStrICmp(ValueUnion.psz, "sha512/224"))
                 {
                     pszDigestType = "SHA-512/224";
                     enmDigestType = RTDIGESTTYPE_SHA512T224;
                 }
                 else if (!RTStrICmp(ValueUnion.psz, "sha512/256"))
                 {
                     pszDigestType = "SHA-512/256";
                     enmDigestType = RTDIGESTTYPE_SHA512T256;
                 }
                 else
                 {
                     Error("Invalid digest type: %s\n", ValueUnion.psz);
                     return 1;
                 }
                 break;

             case 'm':
                 if (!RTStrICmp(ValueUnion.psz, "full"))
                     enmMethod = kMethod_Full;
                 else if (!RTStrICmp(ValueUnion.psz, "block"))
                     enmMethod = kMethod_Block;
                 else if (!RTStrICmp(ValueUnion.psz, "file"))
                     enmMethod = kMethod_File;
                 else if (!RTStrICmp(ValueUnion.psz, "cvas"))
                     enmMethod = kMethod_CVAS;
                 else
                 {
                     Error("Invalid digest method: %s\n", ValueUnion.psz);
                     return 1;
                 }
                 break;

             case 'l':
                 cbMax = ValueUnion.u64;
                 break;

             case 'o':
                 offStart = ValueUnion.u64;
                 break;

             case 'x':
                 fTestcase = true;
                 break;

             case 'h':
                 RTPrintf("usage: tstRTDigest -t <digest-type> [-o <offset>] [-l <length>] [-x] file [file2 [..]]\n");
                 return 1;

             case VINF_GETOPT_NOT_OPTION:
             {
                 if (enmDigestType == RTDIGESTTYPE_INVALID)
                     return Error("No digest type was specified\n");

                 switch (enmMethod)
                 {
                     case kMethod_Full:
                         return Error("Full file method is not implemented\n");

                     case kMethod_File:
                         if (offStart != 0 || cbMax != UINT64_MAX)
                             return Error("The -l and -o options do not work with the 'file' method.");
                         switch (enmDigestType)
                         {
                             case RTDIGESTTYPE_SHA1:
                             {
                                 char *pszDigest;
                                 int rc = RTSha1DigestFromFile(ValueUnion.psz, &pszDigest, NULL, NULL);
                                 if (RT_FAILURE(rc))
                                     return Error("RTSha1Digest(%s,) -> %Rrc\n", ValueUnion.psz, rc);
                                 RTPrintf("%s  %s\n", pszDigest, ValueUnion.psz);
                                 RTStrFree(pszDigest);
                                 break;
                             }

                             case RTDIGESTTYPE_SHA256:
                             {
                                 char *pszDigest;
                                 int rc = RTSha256DigestFromFile(ValueUnion.psz, &pszDigest, NULL, NULL);
                                 if (RT_FAILURE(rc))
                                     return Error("RTSha256Digest(%s,) -> %Rrc\n", ValueUnion.psz, rc);
                                 RTPrintf("%s  %s\n", pszDigest, ValueUnion.psz);
                                 RTStrFree(pszDigest);
                                 break;
                             }
                             default:
                                 return Error("The file method isn't implemented for this digest\n");
                         }
                         break;

                     case kMethod_Block:
                     {
                         RTFILE hFile;
                         int rc = RTFileOpen(&hFile, ValueUnion.psz, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
                         if (RT_FAILURE(rc))
                             return Error("RTFileOpen(,%s,) -> %Rrc\n", ValueUnion.psz, rc);
                         if (offStart != 0)
                         {
                             rc = RTFileSeek(hFile, offStart, RTFILE_SEEK_BEGIN, NULL);
                             if (RT_FAILURE(rc))
                                 return Error("RTFileSeek(%s,%ull) -> %Rrc\n", ValueUnion.psz, offStart, rc);
                         }

                         uint64_t cbMaxLeft = cbMax;
                         size_t  cbRead;
                         uint8_t abBuf[_64K];
                         char   *pszDigest = (char *)&abBuf[0];
                         switch (enmDigestType)
                         {
                             case RTDIGESTTYPE_CRC32:
                             {
                                 uint32_t uCRC32 = RTCrc32Start();
                                 for (;;)
                                 {
                                     rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
                                     if (RT_FAILURE(rc) || !cbRead)
                                         break;
                                     uCRC32 = RTCrc32Process(uCRC32, abBuf, cbRead);
                                 }
                                 uCRC32 = RTCrc32Finish(uCRC32);
                                 RTStrPrintf(pszDigest, sizeof(abBuf), "%08RX32", uCRC32);
                                 break;
                             }

                             case RTDIGESTTYPE_CRC64:
                             {
                                 uint64_t uCRC64 = RTCrc64Start();
                                 for (;;)
                                 {
                                     rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
                                     if (RT_FAILURE(rc) || !cbRead)
                                         break;
                                     uCRC64 = RTCrc64Process(uCRC64, abBuf, cbRead);
                                 }
                                 uCRC64 = RTCrc64Finish(uCRC64);
                                 RTStrPrintf(pszDigest, sizeof(abBuf), "%016RX64", uCRC64);
                                 break;
                             }

                             case RTDIGESTTYPE_MD2:
                             {
                                 RTMD2CONTEXT Ctx;
                                 RTMd2Init(&Ctx);
                                 for (;;)
                                 {
                                     rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
                                     if (RT_FAILURE(rc) || !cbRead)
                                         break;
                                     RTMd2Update(&Ctx, abBuf, cbRead);
                                 }
                                 uint8_t abDigest[RTMD2_HASH_SIZE];
                                 RTMd2Final(&Ctx, abDigest);
                                 RTMd2ToString(abDigest, pszDigest, sizeof(abBuf));
                                 break;
                             }

                             case RTDIGESTTYPE_MD5:
                             {
                                 RTMD5CONTEXT Ctx;
                                 RTMd5Init(&Ctx);
                                 for (;;)
                                 {
                                     rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
                                     if (RT_FAILURE(rc) || !cbRead)
                                         break;
                                     RTMd5Update(&Ctx, abBuf, cbRead);
                                 }
                                 uint8_t abDigest[RTMD5HASHSIZE];
                                 RTMd5Final(abDigest, &Ctx);
                                 RTMd5ToString(abDigest, pszDigest, sizeof(abBuf));
                                 break;
                             }

                             case RTDIGESTTYPE_SHA1:
                             {
                                 RTSHA1CONTEXT Ctx;
                                 RTSha1Init(&Ctx);
                                 for (;;)
                                 {
                                     rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
                                     if (RT_FAILURE(rc) || !cbRead)
                                         break;
                                     RTSha1Update(&Ctx, abBuf, cbRead);
                                 }
                                 uint8_t abDigest[RTSHA1_HASH_SIZE];
                                 RTSha1Final(&Ctx, abDigest);
                                 RTSha1ToString(abDigest, pszDigest, sizeof(abBuf));
                                 break;
                             }

                             case RTDIGESTTYPE_SHA256:
                             {
                                 RTSHA256CONTEXT Ctx;
                                 RTSha256Init(&Ctx);
                                 for (;;)
                                 {
                                     rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
                                     if (RT_FAILURE(rc) || !cbRead)
                                         break;
                                     RTSha256Update(&Ctx, abBuf, cbRead);
                                 }
                                 uint8_t abDigest[RTSHA256_HASH_SIZE];
                                 RTSha256Final(&Ctx, abDigest);
                                 RTSha256ToString(abDigest, pszDigest, sizeof(abBuf));
                                 break;
                             }

                             case RTDIGESTTYPE_SHA512:
                             {
                                 RTSHA512CONTEXT Ctx;
                                 RTSha512Init(&Ctx);
                                 for (;;)
                                 {
                                     rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
                                     if (RT_FAILURE(rc) || !cbRead)
                                         break;
                                     RTSha512Update(&Ctx, abBuf, cbRead);
                                 }
                                 uint8_t abDigest[RTSHA512_HASH_SIZE];
                                 RTSha512Final(&Ctx, abDigest);
                                 RTSha512ToString(abDigest, pszDigest, sizeof(abBuf));
                                 break;
                             }

                             default:
                                 return Error("Internal error #1\n");
                         }
                         RTFileClose(hFile);
                         if (RT_FAILURE(rc) && rc != VERR_EOF)
                         {
                             RTPrintf("Partial: %s  %s\n", pszDigest, ValueUnion.psz);
                             return Error("RTFileRead(%s) -> %Rrc\n", ValueUnion.psz, rc);
                         }

                         if (!fTestcase)
                             RTPrintf("%s  %s\n", pszDigest, ValueUnion.psz);
                         else if (offStart)
                             RTPrintf("        { &g_abRandom72KB[%#4llx], %5llu, \"%s\", \"%s %llu bytes @%llu\" },\n",
                                      offStart, cbMax - cbMaxLeft, pszDigest, pszDigestType, offStart, cbMax - cbMaxLeft);
                         else
                             RTPrintf("        { &g_abRandom72KB[0],     %5llu, \"%s\", \"%s %llu bytes\" },\n",
                                      cbMax - cbMaxLeft, pszDigest, pszDigestType, cbMax - cbMaxLeft);
                         break;
                     }


                     /*
                      * Process a SHS response file:
                      *     http://csrc.nist.gov/groups/STM/cavp/index.html#03
                      */
                     case kMethod_CVAS:
                     {
                         RTCRDIGEST hDigest;
                         int rc = RTCrDigestCreateByType(&hDigest, enmDigestType);
                         if (RT_FAILURE(rc))
                             return Error("Failed to create digest calculator for %s: %Rrc", pszDigestType, rc);

                         uint32_t const cbDigest = RTCrDigestGetHashSize(hDigest);
                         if (!cbDigest || cbDigest >= _1K)
                             return Error("Unexpected hash size: %#x\n", cbDigest);

                         PRTSTREAM pFile;
                         rc = RTStrmOpen(ValueUnion.psz, "r", &pFile);
                         if (RT_FAILURE(rc))
                             return Error("Failed to open CVAS file '%s': %Rrc", ValueUnion.psz, rc);

                         /*
                          * Parse the input file.
                          * ASSUME order: Len, Msg, MD.
                          */
                         static char    s_szLine[_256K];
                         char          *psz;
                         uint32_t       cPassed = 0;
                         uint32_t       cErrors = 0;
                         uint32_t       iLine   = 1;
                         for (;;)
                         {
                             psz = MyGetNextSignificantLine(pFile, s_szLine, sizeof(s_szLine), &iLine, &rc);
                             if (!psz)
                                 break;

                             /* Skip [L = 20] stuff. */
                             if (*psz == '[')
                                 continue;

                             /* Message length. */
                             uint64_t cMessageBits;
                             if (RTStrNICmp(psz, RT_STR_TUPLE("Len =")))
                                 return Error("%s(%d): Expected 'Len =' found '%.10s...'", ValueUnion.psz, iLine, psz);
                             psz = RTStrStripL(psz + 5);
                             rc = RTStrToUInt64Full(psz, 0, &cMessageBits);
                             if (rc != VINF_SUCCESS)
                                 return Error("%s(%d): Error parsing length '%s': %Rrc\n", ValueUnion.psz, iLine, psz, rc);

                             /* The message text. */
                             psz = MyGetNextSignificantLine(pFile, s_szLine, sizeof(s_szLine), &iLine, &rc);
                             if (!psz)
                                 return Error("%s(%d): Expected message text not EOF.", ValueUnion.psz, iLine);
                             if (RTStrNICmp(psz, RT_STR_TUPLE("Msg =")))
                                 return Error("%s(%d): Expected 'Msg =' found '%.10s...'", ValueUnion.psz, iLine, psz);
                             psz = RTStrStripL(psz + 5);

                             size_t const   cbMessage = (cMessageBits + 7) / 8;
                             static uint8_t s_abMessage[sizeof(s_szLine) / 2];
                             if (cbMessage > 0)
                             {
                                 rc = RTStrConvertHexBytes(psz, s_abMessage, cbMessage, 0 /*fFlags*/);
                                 if (rc != VINF_SUCCESS)
                                     return Error("%s(%d): Error parsing message '%.10s...': %Rrc\n",
                                                  ValueUnion.psz, iLine, psz, rc);
                             }

                             /* The message digest. */
                             psz = MyGetNextSignificantLine(pFile, s_szLine, sizeof(s_szLine), &iLine, &rc);
                             if (!psz)
                                 return Error("%s(%d): Expected message digest not EOF.", ValueUnion.psz, iLine);
                             if (RTStrNICmp(psz, RT_STR_TUPLE("MD =")))
                                 return Error("%s(%d): Expected 'MD =' found '%.10s...'", ValueUnion.psz, iLine, psz);
                             psz = RTStrStripL(psz + 4);

                             static uint8_t s_abExpectedDigest[_1K];
                             rc = RTStrConvertHexBytes(psz, s_abExpectedDigest, cbDigest, 0 /*fFlags*/);
                             if (rc != VINF_SUCCESS)
                                 return Error("%s(%d): Error parsing message digest '%.10s...': %Rrc\n",
                                              ValueUnion.psz, iLine, psz, rc);

                             /*
                              * Do the testing.
                              */
                             rc = RTCrDigestReset(hDigest);
                             if (rc != VINF_SUCCESS)
                                 return Error("RTCrDigestReset failed: %Rrc", rc);

                             rc = RTCrDigestUpdate(hDigest, s_abMessage, cbMessage);
                             if (rc != VINF_SUCCESS)
                                 return Error("RTCrDigestUpdate failed: %Rrc", rc);

                             static uint8_t s_abActualDigest[_1K];
                             rc = RTCrDigestFinal(hDigest, s_abActualDigest, cbDigest);
                             if (rc != VINF_SUCCESS)
                                 return Error("RTCrDigestFinal failed: %Rrc", rc);

                             if (memcmp(s_abActualDigest, s_abExpectedDigest, cbDigest) == 0)
                                 cPassed++;
                             else
                             {
                                 Error("%s(%d): Message digest mismatch. Expected %.*RThxs, got %.*RThxs.",
                                       ValueUnion.psz, iLine, cbDigest, s_abExpectedDigest, cbDigest, s_abActualDigest);
                                 cErrors++;
                             }
                         }

                         RTStrmClose(pFile);
                         if (cErrors > 0)
                             return Error("Failed: %u error%s (%u passed)", cErrors, cErrors == 1 ? "" : "s", cPassed);
                         RTPrintf("Passed %u test%s.\n", cPassed, cPassed == 1 ? "" : "s");
                         if (RT_FAILURE(rc))
                             return Error("Failed: %Rrc", rc);
                         break;
                     }

                     default:
                         return Error("Internal error #2\n");
                 }
                 break;
             }

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

     return 0;
}
Exemple #6
0
DECLINLINE(int) tftpSessionOptionParse(PTFTPSESSION pTftpSession, PCTFTPIPHDR pcTftpIpHeader)
{
    int rc = VINF_SUCCESS;
    char *pszTftpRRQRaw;
    size_t idxTftpRRQRaw = 0;
    int cbTftpRRQRaw = 0;
    int fWithArg = 0;
    int idxOptionArg = 0;
    AssertPtrReturn(pTftpSession, VERR_INVALID_PARAMETER);
    AssertPtrReturn(pcTftpIpHeader, VERR_INVALID_PARAMETER);
    AssertReturn(RT_N2H_U16(pcTftpIpHeader->u16TftpOpType) == TFTP_RRQ, VERR_INVALID_PARAMETER);
    LogFlowFunc(("pTftpSession:%p, pcTftpIpHeader:%p\n", pTftpSession, pcTftpIpHeader));
    pszTftpRRQRaw = (char *)&pcTftpIpHeader->Core;
    cbTftpRRQRaw = RT_H2N_U16(pcTftpIpHeader->UdpHdr.uh_ulen) + sizeof(struct ip) - RT_OFFSETOF(TFTPIPHDR, Core);
    while(cbTftpRRQRaw)
    {
        idxTftpRRQRaw = RTStrNLen(pszTftpRRQRaw, 512 - idxTftpRRQRaw) + 1;
        if (RTStrNLen((char *)pTftpSession->pszFilename, TFTP_FILENAME_MAX) == 0)
        {
            rc = RTStrCopy((char *)pTftpSession->pszFilename, TFTP_FILENAME_MAX, pszTftpRRQRaw);
            if (RT_FAILURE(rc))
            {
                LogFlowFuncLeaveRC(rc);
                AssertRCReturn(rc,rc);
            }
        }
        else if (pTftpSession->enmTftpFmt == TFTPFMT_NONE)
        {
            int idxFmt = 0;
            rc = tftpFindTransferFormatIdxbyName(&idxFmt, pszTftpRRQRaw);
            if (RT_FAILURE(rc))
            {
                LogFlowFuncLeaveRC(VERR_INTERNAL_ERROR);
                return VERR_INTERNAL_ERROR;
            }
            AssertReturn(   g_TftpTransferFmtDesc[idxFmt].enmType != TFTPFMT_NONE
                         && g_TftpTransferFmtDesc[idxFmt].enmType != TFTPFMT_NOT_FMT, VERR_INTERNAL_ERROR);
            pTftpSession->enmTftpFmt = g_TftpTransferFmtDesc[idxFmt].enmType;
        }
        else if (fWithArg)
        {
            if (!RTStrICmp("blksize", g_TftpDesc[idxOptionArg].pszName))
            {
                rc = tftpSessionParseAndMarkOption(pszTftpRRQRaw, &pTftpSession->OptionBlkSize);
                if (pTftpSession->OptionBlkSize.u64Value > UINT16_MAX)
                    rc = VERR_INVALID_PARAMETER;
            }

            if (   RT_SUCCESS(rc)
                && !RTStrICmp("tsize", g_TftpDesc[idxOptionArg].pszName))
                rc = tftpSessionParseAndMarkOption(pszTftpRRQRaw, &pTftpSession->OptionTSize);

            /* @todo: we don't use timeout, but its value in the range 0-255 */
            if (   RT_SUCCESS(rc)
                && !RTStrICmp("timeout", g_TftpDesc[idxOptionArg].pszName))
                rc = tftpSessionParseAndMarkOption(pszTftpRRQRaw, &pTftpSession->OptionTimeout);

            /* @todo: unknown option detection */
            if (RT_FAILURE(rc))
            {
                LogFlowFuncLeaveRC(rc);
                AssertRCReturn(rc,rc);
            }
            fWithArg = 0;
            idxOptionArg = 0;
        }
        else
        {
            rc = tftpFindOptionIdxbyName(&idxOptionArg, pszTftpRRQRaw);
            if (RT_SUCCESS(rc))
                fWithArg = 1;
            else
            {
                LogFlowFuncLeaveRC(rc);
                AssertRCReturn(rc,rc);
            }
        }
        pszTftpRRQRaw += idxTftpRRQRaw;
        cbTftpRRQRaw -= idxTftpRRQRaw;
    }

    LogFlowFuncLeaveRC(rc);
    return rc;
}
HRESULT HostDnsServiceWin::updateInfo()
{
    HostDnsInformation info;

    LONG lrc;
    int rc;

    std::string strDomain;
    std::string strSearchList;  /* NB: comma separated, no spaces */


    /*
     * We ignore "DhcpDomain" key here since it's not stable.  If
     * there are two active interfaces that use DHCP (in particular
     * when host uses OpenVPN) then DHCP ACKs will take turns updating
     * that key.  Instead we call GetAdaptersAddresses() below (which
     * is what ipconfig.exe seems to do).
     */
    for (DWORD regIndex = 0; /**/; ++regIndex) {
        char keyName[256];
        DWORD cbKeyName = sizeof(keyName);
        DWORD keyType = 0;
        char keyData[1024];
        DWORD cbKeyData = sizeof(keyData);

        lrc = RegEnumValueA(m->hKeyTcpipParameters, regIndex,
                            keyName, &cbKeyName, 0,
                            &keyType, (LPBYTE)keyData, &cbKeyData);

        if (lrc == ERROR_NO_MORE_ITEMS)
            break;

        if (lrc == ERROR_MORE_DATA) /* buffer too small; handle? */
            continue;

        if (lrc != ERROR_SUCCESS)
        {
            LogRel2(("HostDnsServiceWin: RegEnumValue error %d\n", (int)lrc));
            return E_FAIL;
        }

        if (keyType != REG_SZ)
            continue;

        if (cbKeyData > 0 && keyData[cbKeyData - 1] == '\0')
            --cbKeyData;     /* don't count trailing NUL if present */

        if (RTStrICmp("Domain", keyName) == 0)
        {
            strDomain.assign(keyData, cbKeyData);
            LogRel2(("HostDnsServiceWin: Domain=\"%s\"\n", strDomain.c_str()));
        }
        else if (RTStrICmp("DhcpDomain", keyName) == 0)
        {
            std::string strDhcpDomain(keyData, cbKeyData);
            LogRel2(("HostDnsServiceWin: DhcpDomain=\"%s\"\n", strDhcpDomain.c_str()));
        }
        else if (RTStrICmp("SearchList", keyName) == 0)
        {
            strSearchList.assign(keyData, cbKeyData);
            LogRel2(("HostDnsServiceWin: SearchList=\"%s\"\n", strSearchList.c_str()));
        }
    }

    /* statically configured domain name */
    if (!strDomain.empty())
    {
        info.domain = strDomain;
        info.searchList.push_back(strDomain);
    }

    /* statically configured search list */
    if (!strSearchList.empty())
    {
        vappend(info.searchList, strSearchList, ',');
    }


    /*
     * When name servers are configured statically it seems that the
     * value of Tcpip\Parameters\NameServer is NOT set, inly interface
     * specific NameServer value is (which triggers notification for
     * us to pick up the change).  Fortunately, DnsApi seems to do the
     * right thing there.
     */
    DNS_STATUS status;
    PIP4_ARRAY pIp4Array = NULL;

    // NB: must be set on input it seems, despite docs' claim to the contrary.
    DWORD cbBuffer = sizeof(&pIp4Array);

    status = DnsQueryConfig(DnsConfigDnsServerList,
                            DNS_CONFIG_FLAG_ALLOC, NULL, NULL,
                            &pIp4Array, &cbBuffer);

    if (status == NO_ERROR && pIp4Array != NULL)
    {
        for (DWORD i = 0; i < pIp4Array->AddrCount; ++i)
        {
            char szAddrStr[16] = "";
            RTStrPrintf(szAddrStr, sizeof(szAddrStr), "%RTnaipv4", pIp4Array->AddrArray[i]);

            LogRel2(("HostDnsServiceWin: server %d: %s\n", i+1,  szAddrStr));
            info.servers.push_back(szAddrStr);
        }

        LocalFree(pIp4Array);
    }


    /**
     * DnsQueryConfig(DnsConfigSearchList, ...) is not implemented.
     * Call GetAdaptersAddresses() that orders the returned list
     * appropriately and collect IP_ADAPTER_ADDRESSES::DnsSuffix.
     */
    do {
        PIP_ADAPTER_ADDRESSES pAddrBuf = NULL;
        ULONG cbAddrBuf = 8 * 1024;
        bool fReallocated = false;
        ULONG err;

        pAddrBuf = (PIP_ADAPTER_ADDRESSES) malloc(cbAddrBuf);
        if (pAddrBuf == NULL)
        {
            LogRel2(("HostDnsServiceWin: failed to allocate %zu bytes"
                     " of GetAdaptersAddresses buffer\n",
                     (size_t)cbAddrBuf));
            break;
        }

        while (pAddrBuf != NULL)
        {
            ULONG cbAddrBufProvided = cbAddrBuf;

            err = GetAdaptersAddresses(AF_UNSPEC,
                                       GAA_FLAG_SKIP_ANYCAST
                                       | GAA_FLAG_SKIP_MULTICAST,
                                       NULL,
                                       pAddrBuf, &cbAddrBuf);
            if (err == NO_ERROR)
            {
                break;
            }
            else if (err == ERROR_BUFFER_OVERFLOW)
            {
                LogRel2(("HostDnsServiceWin: provided GetAdaptersAddresses with %zu"
                         " but asked again for %zu bytes\n",
                         (size_t)cbAddrBufProvided, (size_t)cbAddrBuf));

                if (RT_UNLIKELY(fReallocated)) /* what? again?! */
                {
                    LogRel2(("HostDnsServiceWin: ... not going to realloc again\n"));
                    free(pAddrBuf);
                    pAddrBuf = NULL;
                    break;
                }

                PIP_ADAPTER_ADDRESSES pNewBuf = (PIP_ADAPTER_ADDRESSES) realloc(pAddrBuf, cbAddrBuf);
                if (pNewBuf == NULL)
                {
                    LogRel2(("HostDnsServiceWin: failed to reallocate %zu bytes\n", (size_t)cbAddrBuf));
                    free(pAddrBuf);
                    pAddrBuf = NULL;
                    break;
                }

                /* try again */
                pAddrBuf = pNewBuf; /* cbAddrBuf already updated */
                fReallocated = true;
            }
            else
            {
                LogRel2(("HostDnsServiceWin: GetAdaptersAddresses error %d\n", err));
                free(pAddrBuf);
                pAddrBuf = NULL;
                break;
            }
        }

        if (pAddrBuf == NULL)
            break;

        for (PIP_ADAPTER_ADDRESSES pAdp = pAddrBuf; pAdp != NULL; pAdp = pAdp->Next)
        {
            LogRel2(("HostDnsServiceWin: %ls (status %u) ...\n",
                     pAdp->FriendlyName ? pAdp->FriendlyName : L"(null)",
                     pAdp->OperStatus));

            if (pAdp->OperStatus != IfOperStatusUp)
                continue;

            if (pAdp->DnsSuffix == NULL || *pAdp->DnsSuffix == L'\0')
                continue;

            char *pszDnsSuffix = NULL;
            rc = RTUtf16ToUtf8Ex(pAdp->DnsSuffix, RTSTR_MAX,
                                 &pszDnsSuffix, 0, /* allocate */
                                 NULL);
            if (RT_FAILURE(rc))
            {
                LogRel2(("HostDnsServiceWin: failed to convert DNS suffix \"%ls\": %Rrc\n",
                         pAdp->DnsSuffix, rc));
                continue;
            }

            AssertContinue(pszDnsSuffix != NULL);
            AssertContinue(*pszDnsSuffix != '\0');
            LogRel2(("HostDnsServiceWin: ... suffix = \"%s\"\n", pszDnsSuffix));

            vappend(info.searchList, pszDnsSuffix);
            RTStrFree(pszDnsSuffix);
        }

        free(pAddrBuf);
    } while (0);


    if (info.domain.empty() && !info.searchList.empty())
        info.domain = info.searchList[0];

    if (info.searchList.size() == 1)
        info.searchList.clear();

    HostDnsMonitor::setInfo(info);

    return S_OK;
}
Exemple #8
0
int main(int argc, char **argv)
{
    int rc = RTR3InitExe(argc, &argv, 0);
    if (RT_FAILURE(rc))
        return RTMsgInitFailure(rc);

    /*
     * Parse arguments.
     */
    static RTGETOPTDEF const s_aOptions[] =
    {
        { "--manifest",     'm', RTGETOPT_REQ_STRING  },
        { "--java",         'j', RTGETOPT_REQ_NOTHING },
        { "--chdir",        'C', RTGETOPT_REQ_STRING  },
        { "--attribute",    'a', RTGETOPT_REQ_STRING  },
        { "--verify",       'v', RTGETOPT_REQ_NOTHING },
    };

    bool            fVerify     = false;
    bool            fStdFormat  = true;
    const char     *pszManifest = NULL;
    const char     *pszChDir    = NULL;
    uint32_t        fAttr       = RTMANIFEST_ATTR_UNKNOWN;

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

    RTGETOPTUNION ValueUnion;
    while (   (rc = RTGetOpt(&GetState, &ValueUnion)) != 0
           &&  rc != VINF_GETOPT_NOT_OPTION)
    {
        switch (rc)
        {
            case 'a':
            {
                static struct
                {
                    const char *pszAttr;
                    uint32_t    fAttr;
                } s_aAttributes[] =
                {
                    { "size",   RTMANIFEST_ATTR_SIZE    },
                    { "md5",    RTMANIFEST_ATTR_MD5     },
                    { "sha1",   RTMANIFEST_ATTR_SHA1    },
                    { "sha256", RTMANIFEST_ATTR_SHA256  },
                    { "sha512", RTMANIFEST_ATTR_SHA512  }
                };
                uint32_t fThisAttr = RTMANIFEST_ATTR_UNKNOWN;
                for (unsigned i = 0; i < RT_ELEMENTS(s_aAttributes); i++)
                    if (!RTStrICmp(s_aAttributes[i].pszAttr, ValueUnion.psz))
                    {
                        fThisAttr = s_aAttributes[i].fAttr;
                        break;
                    }
                if (fThisAttr == RTMANIFEST_ATTR_UNKNOWN)
                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown attribute type '%s'", ValueUnion.psz);

                if (fAttr == RTMANIFEST_ATTR_UNKNOWN)
                    fAttr = fThisAttr;
                else
                    fAttr |= fThisAttr;
                break;
            }

            case 'j':
                fStdFormat = false;
                break;

            case 'm':
                if (pszManifest)
                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Only one manifest can be specified");
                pszManifest = ValueUnion.psz;
                break;

            case 'v':
                fVerify = true;
                break;

            case 'C':
                if (pszChDir)
                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Only one directory change can be specified");
                pszChDir = ValueUnion.psz;
                break;

            case 'h':
                RTPrintf("Usage: %s [--manifest <file>] [--chdir <dir>] [--attribute <attrib-name> [..]] <files>\n"
                         "   or  %s --verify [--manifest <file>] [--chdir <dir>]\n"
                         "\n"
                         "attrib-name: size, md5, sha1, sha256 or sha512\n"
                         , RTProcShortName(), RTProcShortName());
                return RTEXITCODE_SUCCESS;

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

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

    /*
     * Take action.
     */
    RTEXITCODE rcExit;
    if (!fVerify)
    {
        if (rc != VINF_GETOPT_NOT_OPTION)
            RTMsgWarning("No files specified, the manifest will be empty.");
        if (fAttr == RTMANIFEST_ATTR_UNKNOWN)
            fAttr = RTMANIFEST_ATTR_SIZE | RTMANIFEST_ATTR_MD5
                  | RTMANIFEST_ATTR_SHA1 | RTMANIFEST_ATTR_SHA256 | RTMANIFEST_ATTR_SHA512;
        rcExit = rtManifestDoCreate(pszManifest, fStdFormat, pszChDir, fAttr, &GetState, &ValueUnion, rc);
    }
    else
    {
        if (rc == VINF_GETOPT_NOT_OPTION)
            return RTMsgErrorExit(RTEXITCODE_SYNTAX,
                                  "No files should be specified when verifying a manifest (--verfiy), "
                                  "only a manifest via the --manifest option");
        if (fAttr != RTMANIFEST_ATTR_UNKNOWN)
            return RTMsgErrorExit(RTEXITCODE_SYNTAX,
                                  "The --attribute (-a) option does not combine with --verify (-v)");


        rcExit = rtManifestDoVerify(pszManifest, fStdFormat, pszChDir);
    }

    return rcExit;
}
Exemple #9
0
RTR3DECL(int) RTManifestVerifyFilesBuf(void *pvBuf, size_t cbSize, PRTMANIFESTTEST paTests, size_t cTests, size_t *piFailed)
{
    /* Validate input */
    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
    AssertReturn(cbSize > 0, VERR_INVALID_PARAMETER);
    AssertPtrReturn(paTests, VERR_INVALID_POINTER);
    AssertReturn(cTests > 0, VERR_INVALID_PARAMETER);
    AssertPtrNullReturn(piFailed, VERR_INVALID_POINTER);

    int rc = VINF_SUCCESS;

    PRTMANIFESTFILEENTRY paFiles = (PRTMANIFESTFILEENTRY)RTMemTmpAllocZ(sizeof(RTMANIFESTFILEENTRY) * cTests);
    if (!paFiles)
        return VERR_NO_MEMORY;

    /* Fill our compare list */
    for (size_t i = 0; i < cTests; ++i)
        paFiles[i].pTestPattern = &paTests[i];

    char *pcBuf = (char*)pvBuf;
    size_t cbRead = 0;
    /* Parse the manifest file line by line */
    for (;;)
    {
        if (cbRead >= cbSize)
            break;

        size_t cch = rtManifestIndexOfCharInBuf(pcBuf, cbSize - cbRead, '\n') + 1;

        /* Skip empty lines (UNIX/DOS format) */
        if (   (   cch == 1
                && pcBuf[0] == '\n')
            || (   cch == 2
                && pcBuf[0] == '\r'
                && pcBuf[1] == '\n'))
        {
            pcBuf += cch;
            cbRead += cch;
            continue;
        }

        /** @todo r=bird:
         *  -# Better deal with this EOF line platform dependency
         *  -# The SHA1 and SHA256 tests should probably include a blank space check.
         *  -# If there is a specific order to the elements in the string, it would be
         *     good if the delimiter searching checked for it.
         *  -# Deal with filenames containing delimiter characters.
         */

        /* Check for the digest algorithm */
        if (   cch < 4
            || (   !(   pcBuf[0] == 'S'
                     && pcBuf[1] == 'H'
                     && pcBuf[2] == 'A'
                     && pcBuf[3] == '1')
                &&
                   !(   pcBuf[0] == 'S'
                     && pcBuf[1] == 'H'
                     && pcBuf[2] == 'A'
                     && pcBuf[3] == '2'
                     && pcBuf[4] == '5'
                     && pcBuf[5] == '6')
               )
            )
        {
            /* Digest unsupported */
            rc = VERR_MANIFEST_UNSUPPORTED_DIGEST_TYPE;
            break;
        }

        /* Try to find the filename */
        char *pszNameStart = rtManifestPosOfCharInBuf(pcBuf, cch, '(');
        if (!pszNameStart)
        {
            rc = VERR_MANIFEST_WRONG_FILE_FORMAT;
            break;
        }
        char *pszNameEnd = rtManifestPosOfCharInBuf(pcBuf, cch, ')');
        if (!pszNameEnd)
        {
            rc = VERR_MANIFEST_WRONG_FILE_FORMAT;
            break;
        }

        /* Copy the filename part */
        size_t cchName = pszNameEnd - pszNameStart - 1;
        char *pszName = (char *)RTMemTmpAlloc(cchName + 1);
        if (!pszName)
        {
            rc = VERR_NO_MEMORY;
            break;
        }
        memcpy(pszName, pszNameStart + 1, cchName);
        pszName[cchName] = '\0';

        /* Try to find the digest sum */
        char *pszDigestStart = rtManifestPosOfCharInBuf(pcBuf, cch, '=') + 1;
        if (!pszDigestStart)
        {
            RTMemTmpFree(pszName);
            rc = VERR_MANIFEST_WRONG_FILE_FORMAT;
            break;
        }
        char *pszDigestEnd = rtManifestPosOfCharInBuf(pcBuf, cch, '\r');
        if (!pszDigestEnd)
            pszDigestEnd = rtManifestPosOfCharInBuf(pcBuf, cch, '\n');
        if (!pszDigestEnd)
        {
            RTMemTmpFree(pszName);
            rc = VERR_MANIFEST_WRONG_FILE_FORMAT;
            break;
        }
        /* Copy the digest part */
        size_t cchDigest = pszDigestEnd - pszDigestStart - 1;
        char *pszDigest = (char *)RTMemTmpAlloc(cchDigest + 1);
        if (!pszDigest)
        {
            RTMemTmpFree(pszName);
            rc = VERR_NO_MEMORY;
            break;
        }
        memcpy(pszDigest, pszDigestStart + 1, cchDigest);
        pszDigest[cchDigest] = '\0';

        /* Check our file list against the extracted data */
        bool fFound = false;
        for (size_t i = 0; i < cTests; ++i)
        {
            /** @todo r=bird: Using RTStrStr here looks bogus. */
            if (RTStrStr(paFiles[i].pTestPattern->pszTestFile, RTStrStrip(pszName)) != NULL)
            {
                /* Add the data of the manifest file to the file list */
                paFiles[i].pszManifestFile = RTStrDup(RTStrStrip(pszName));
                paFiles[i].pszManifestDigest = RTStrDup(RTStrStrip(pszDigest));
                fFound = true;
                break;
            }
        }
        RTMemTmpFree(pszName);
        RTMemTmpFree(pszDigest);
        if (!fFound)
        {
            /* There have to be an entry in the file list */
            rc = VERR_MANIFEST_FILE_MISMATCH;
            break;
        }

        pcBuf += cch;
        cbRead += cch;
    }

    if (   rc == VINF_SUCCESS
        || rc == VERR_EOF)
    {
        rc = VINF_SUCCESS;
        for (size_t i = 0; i < cTests; ++i)
        {
            /* If there is an entry in the file list, which hasn't an
             * equivalent in the manifest file, its an error. */
            if (   !paFiles[i].pszManifestFile
                || !paFiles[i].pszManifestDigest)
            {
                rc = VERR_MANIFEST_FILE_MISMATCH;
                break;
            }

            /* Do the manifest SHA digest match against the actual digest? */
            if (RTStrICmp(paFiles[i].pszManifestDigest, paFiles[i].pTestPattern->pszTestDigest))
            {
                if (piFailed)
                    *piFailed = i;
                rc = VERR_MANIFEST_DIGEST_MISMATCH;
                break;
            }
        }
    }

    /* Cleanup */
    for (size_t i = 0; i < cTests; ++i)
    {
        if (paFiles[i].pszManifestFile)
            RTStrFree(paFiles[i].pszManifestFile);
        if (paFiles[i].pszManifestDigest)
            RTStrFree(paFiles[i].pszManifestDigest);
    }
    RTMemTmpFree(paFiles);

    RTPrintf("rc = %Rrc\n", rc);
    return rc;
}
Exemple #10
0
int main(int argc, char **argv)
{
     RTR3InitExe(argc, &argv, 0);

     enum
     {
         kDigestType_NotSpecified,
         kDigestType_CRC32,
         kDigestType_CRC64,
         kDigestType_MD5,
         kDigestType_SHA1,
         kDigestType_SHA256,
         kDigestType_SHA512
     } enmDigestType = kDigestType_NotSpecified;

     enum
     {
         kMethod_Full,
         kMethod_Block,
         kMethod_File
     } enmMethod = kMethod_Block;

     static const RTGETOPTDEF s_aOptions[] =
     {
         { "--type",   't', RTGETOPT_REQ_STRING },
         { "--method", 'm', RTGETOPT_REQ_STRING },
         { "--help",   'h', RTGETOPT_REQ_NOTHING },
     };

     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 't':
                 if (!RTStrICmp(ValueUnion.psz, "crc32"))
                     enmDigestType = kDigestType_CRC32;
                 else if (!RTStrICmp(ValueUnion.psz, "crc64"))
                     enmDigestType = kDigestType_CRC64;
                 else if (!RTStrICmp(ValueUnion.psz, "md5"))
                     enmDigestType = kDigestType_MD5;
                 else if (!RTStrICmp(ValueUnion.psz, "sha1"))
                     enmDigestType = kDigestType_SHA1;
                 else if (!RTStrICmp(ValueUnion.psz, "sha256"))
                     enmDigestType = kDigestType_SHA256;
                 else if (!RTStrICmp(ValueUnion.psz, "sha512"))
                     enmDigestType = kDigestType_SHA512;
                 else
                 {
                     Error("Invalid digest type: %s\n", ValueUnion.psz);
                     return 1;
                 }
                 break;

             case 'm':
                 if (!RTStrICmp(ValueUnion.psz, "full"))
                     enmMethod = kMethod_Full;
                 else if (!RTStrICmp(ValueUnion.psz, "block"))
                     enmMethod = kMethod_Block;
                 else if (!RTStrICmp(ValueUnion.psz, "file"))
                     enmMethod = kMethod_File;
                 else
                 {
                     Error("Invalid digest method: %s\n", ValueUnion.psz);
                     return 1;
                 }
                 break;

             case 'h':
                 RTPrintf("syntax: tstRTDigest -t <digest-type> file [file2 [..]]\n");
                 return 1;

             case VINF_GETOPT_NOT_OPTION:
             {
                 if (enmDigestType == kDigestType_NotSpecified)
                     return Error("No digest type was specified\n");

                 switch (enmMethod)
                 {
                     case kMethod_Full:
                         return Error("Full file method is not implemented\n");

                     case kMethod_File:
                         switch (enmDigestType)
                         {
                             case kDigestType_SHA1:
                             {
                                 char *pszDigest;
                                 int rc = RTSha1DigestFromFile(ValueUnion.psz, &pszDigest, NULL, NULL);
                                 if (RT_FAILURE(rc))
                                     return Error("RTSha1Digest(%s,) -> %Rrc\n", ValueUnion.psz, rc);
                                 RTPrintf("%s  %s\n", pszDigest, ValueUnion.psz);
                                 RTStrFree(pszDigest);
                                 break;
                             }

                             default:
                                 return Error("The file method isn't implemented for this digest\n");
                         }
                         break;

                     case kMethod_Block:
                     {
                         RTFILE hFile;
                         int rc = RTFileOpen(&hFile, ValueUnion.psz, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
                         if (RT_FAILURE(rc))
                             return Error("RTFileOpen(,%s,) -> %Rrc\n", ValueUnion.psz, rc);

                         size_t  cbRead;
                         uint8_t abBuf[_64K];
                         char   *pszDigest = (char *)&abBuf[0];
                         switch (enmDigestType)
                         {
                             case kDigestType_CRC32:
                             {
                                 uint32_t uCRC32 = RTCrc32Start();
                                 for (;;)
                                 {
                                     rc = RTFileRead(hFile, abBuf, sizeof(abBuf), &cbRead);
                                     if (RT_FAILURE(rc) || !cbRead)
                                         break;
                                     uCRC32 = RTCrc32Process(uCRC32, abBuf, cbRead);
                                 }
                                 uCRC32 = RTCrc32Finish(uCRC32);
                                 RTStrPrintf(pszDigest, sizeof(abBuf), "%08RX32", uCRC32);
                                 break;
                             }

                             case kDigestType_CRC64:
                             {
                                 uint64_t uCRC64 = RTCrc64Start();
                                 for (;;)
                                 {
                                     rc = RTFileRead(hFile, abBuf, sizeof(abBuf), &cbRead);
                                     if (RT_FAILURE(rc) || !cbRead)
                                         break;
                                     uCRC64 = RTCrc64Process(uCRC64, abBuf, cbRead);
                                 }
                                 uCRC64 = RTCrc64Finish(uCRC64);
                                 RTStrPrintf(pszDigest, sizeof(abBuf), "%016RX64", uCRC64);
                                 break;
                             }

                             case kDigestType_MD5:
                             {
                                 RTMD5CONTEXT Ctx;
                                 RTMd5Init(&Ctx);
                                 for (;;)
                                 {
                                     rc = RTFileRead(hFile, abBuf, sizeof(abBuf), &cbRead);
                                     if (RT_FAILURE(rc) || !cbRead)
                                         break;
                                     RTMd5Update(&Ctx, abBuf, cbRead);
                                 }
                                 uint8_t abDigest[RTMD5HASHSIZE];
                                 RTMd5Final(abDigest, &Ctx);
                                 RTMd5ToString(abDigest, pszDigest, sizeof(abBuf));
                                 break;
                             }

                             case kDigestType_SHA1:
                             {
                                 RTSHA1CONTEXT Ctx;
                                 RTSha1Init(&Ctx);
                                 for (;;)
                                 {
                                     rc = RTFileRead(hFile, abBuf, sizeof(abBuf), &cbRead);
                                     if (RT_FAILURE(rc) || !cbRead)
                                         break;
                                     RTSha1Update(&Ctx, abBuf, cbRead);
                                 }
                                 uint8_t abDigest[RTSHA1_HASH_SIZE];
                                 RTSha1Final(&Ctx, abDigest);
                                 RTSha1ToString(abDigest, pszDigest, sizeof(abBuf));
                                 break;
                             }

                             case kDigestType_SHA256:
                             {
                                 RTSHA256CONTEXT Ctx;
                                 RTSha256Init(&Ctx);
                                 for (;;)
                                 {
                                     rc = RTFileRead(hFile, abBuf, sizeof(abBuf), &cbRead);
                                     if (RT_FAILURE(rc) || !cbRead)
                                         break;
                                     RTSha256Update(&Ctx, abBuf, cbRead);
                                 }
                                 uint8_t abDigest[RTSHA256_HASH_SIZE];
                                 RTSha256Final(&Ctx, abDigest);
                                 RTSha256ToString(abDigest, pszDigest, sizeof(abBuf));
                                 break;
                             }

                             case kDigestType_SHA512:
                             {
                                 RTSHA512CONTEXT Ctx;
                                 RTSha512Init(&Ctx);
                                 for (;;)
                                 {
                                     rc = RTFileRead(hFile, abBuf, sizeof(abBuf), &cbRead);
                                     if (RT_FAILURE(rc) || !cbRead)
                                         break;
                                     RTSha512Update(&Ctx, abBuf, cbRead);
                                 }
                                 uint8_t abDigest[RTSHA512_HASH_SIZE];
                                 RTSha512Final(&Ctx, abDigest);
                                 RTSha512ToString(abDigest, pszDigest, sizeof(abBuf));
                                 break;
                             }

                             default:
                                 return Error("Internal error #1\n");
                         }
                         RTFileClose(hFile);
                         if (RT_FAILURE(rc) && rc != VERR_EOF)
                         {
                             RTPrintf("Partial: %s  %s\n", pszDigest, ValueUnion.psz);
                             return Error("RTFileRead(%s) -> %Rrc\n", ValueUnion.psz, rc);
                         }
                         RTPrintf("%s  %s\n", pszDigest, ValueUnion.psz);
                         break;
                     }

                     default:
                         return Error("Internal error #2\n");
                 }
                 break;
             }

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

     return 0;
}
static int VBoxServiceAutoMountSharedFolder(const char *pszShareName, const char *pszMountPoint,
                                            vbsf_mount_opts *pOpts)
{
    AssertPtr(pOpts);

    int rc = VINF_SUCCESS;
    char szAlreadyMountedTo[RTPATH_MAX];
    /* If a Shared Folder already is mounted but not to our desired mount point,
     * do an unmount first! */
    if (   VBoxServiceAutoMountShareIsMounted(pszShareName, szAlreadyMountedTo, sizeof(szAlreadyMountedTo))
        && RTStrICmp(pszMountPoint, szAlreadyMountedTo))
    {
        VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder \"%s\" already mounted to \"%s\", unmounting ...\n",
                           pszShareName, szAlreadyMountedTo);
        rc = VBoxServiceAutoMountUnmount(szAlreadyMountedTo);
        if (RT_FAILURE(rc))
            VBoxServiceError("VBoxServiceAutoMountWorker: Failed to unmount \"%s\", %s (%d)!\n",
                             szAlreadyMountedTo, strerror(errno), errno);
    }

    if (RT_SUCCESS(rc))
        rc = VBoxServiceAutoMountPrepareMountPoint(pszMountPoint, pszShareName, pOpts);
    if (RT_SUCCESS(rc))
    {
#ifdef RT_OS_SOLARIS
        char achOptBuf[MAX_MNTOPT_STR] = { '\0', };
        int flags = 0;
        if (pOpts->ronly)
            flags |= MS_RDONLY;
        RTStrPrintf(achOptBuf, sizeof(achOptBuf), "uid=%d,gid=%d", pOpts->uid, pOpts->gid);
        int r = mount(pszShareName,
                      pszMountPoint,
                      flags | MS_OPTIONSTR,
                      "vboxfs",
                      NULL,                     /* char *dataptr */
                      0,                        /* int datalen */
                      achOptBuf,
                      sizeof(achOptBuf));
        if (r == 0)
        {
            VBoxServiceVerbose(0, "VBoxServiceAutoMountWorker: Shared folder \"%s\" was mounted to \"%s\"\n", pszShareName, pszMountPoint);
        }
        else
        {
            if (errno != EBUSY) /* Share is already mounted? Then skip error msg. */
                VBoxServiceError("VBoxServiceAutoMountWorker: Could not mount shared folder \"%s\" to \"%s\", error = %s\n",
                                 pszShareName, pszMountPoint, strerror(errno));
        }
#else /* !RT_OS_SOLARIS */
        unsigned long flags = MS_NODEV;

        const char *szOptions = { "rw" };
        struct vbsf_mount_info_new mntinf;

        mntinf.nullchar     = '\0';
        mntinf.signature[0] = VBSF_MOUNT_SIGNATURE_BYTE_0;
        mntinf.signature[1] = VBSF_MOUNT_SIGNATURE_BYTE_1;
        mntinf.signature[2] = VBSF_MOUNT_SIGNATURE_BYTE_2;
        mntinf.length       = sizeof(mntinf);

        mntinf.uid   = pOpts->uid;
        mntinf.gid   = pOpts->gid;
        mntinf.ttl   = pOpts->ttl;
        mntinf.dmode = pOpts->dmode;
        mntinf.fmode = pOpts->fmode;
        mntinf.dmask = pOpts->dmask;
        mntinf.fmask = pOpts->fmask;

        strcpy(mntinf.name, pszShareName);
        strcpy(mntinf.nls_name, "\0");

        int r = mount(NULL,
                      pszMountPoint,
                      "vboxsf",
                      flags,
                      &mntinf);
        if (r == 0)
        {
            VBoxServiceVerbose(0, "VBoxServiceAutoMountWorker: Shared folder \"%s\" was mounted to \"%s\"\n", pszShareName, pszMountPoint);

            r = vbsfmount_complete(pszShareName, pszMountPoint, flags, pOpts);
            switch (r)
            {
                case 0: /* Success. */
                    errno = 0; /* Clear all errors/warnings. */
                    break;

                case 1:
                    VBoxServiceError("VBoxServiceAutoMountWorker: Could not update mount table (failed to create memstream): %s\n", strerror(errno));
                    break;

                case 2:
                    VBoxServiceError("VBoxServiceAutoMountWorker: Could not open mount table for update: %s\n", strerror(errno));
                    break;

                case 3:
                    /* VBoxServiceError("VBoxServiceAutoMountWorker: Could not add an entry to the mount table: %s\n", strerror(errno)); */
                    errno = 0;
                    break;

                default:
                    VBoxServiceError("VBoxServiceAutoMountWorker: Unknown error while completing mount operation: %d\n", r);
                    break;
            }
        }
        else /* r == -1, we got some error in errno.  */
        {
            if (errno == EPROTO)
            {
                VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Messed up share name, re-trying ...\n");

                /* Sometimes the mount utility messes up the share name.  Try to
                 * un-mangle it again. */
                char szCWD[4096];
                size_t cchCWD;
                if (!getcwd(szCWD, sizeof(szCWD)))
                    VBoxServiceError("VBoxServiceAutoMountWorker: Failed to get the current working directory\n");
                cchCWD = strlen(szCWD);
                if (!strncmp(pszMountPoint, szCWD, cchCWD))
                {
                    while (pszMountPoint[cchCWD] == '/')
                        ++cchCWD;
                    /* We checked before that we have enough space */
                    strcpy(mntinf.name, pszMountPoint + cchCWD);
                }
                r = mount(NULL, pszMountPoint, "vboxsf", flags, &mntinf);
            }
            if (errno == EPROTO)
            {
                VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Re-trying with old mounting structure ...\n");

                /* New mount tool with old vboxsf module? Try again using the old
                 * vbsf_mount_info_old structure. */
                struct vbsf_mount_info_old mntinf_old;
                memcpy(&mntinf_old.name, &mntinf.name, MAX_HOST_NAME);
                memcpy(&mntinf_old.nls_name, mntinf.nls_name, MAX_NLS_NAME);
                mntinf_old.uid = mntinf.uid;
                mntinf_old.gid = mntinf.gid;
                mntinf_old.ttl = mntinf.ttl;
                r = mount(NULL, pszMountPoint, "vboxsf", flags, &mntinf_old);
            }
            if (r == -1) /* Was there some error from one of the tries above? */
            {
                switch (errno)
                {
                    /* If we get EINVAL here, the system already has mounted the Shared Folder to another
                     * mount point. */
                    case EINVAL:
                        VBoxServiceVerbose(0, "VBoxServiceAutoMountWorker: Shared folder \"%s\" already is mounted!\n", pszShareName);
                        /* Ignore this error! */
                        break;
                    case EBUSY:
                        /* Ignore these errors! */
                        break;

                    default:
                        VBoxServiceError("VBoxServiceAutoMountWorker: Could not mount shared folder \"%s\" to \"%s\": %s (%d)\n",
                                         pszShareName, pszMountPoint, strerror(errno), errno);
                        rc = RTErrConvertFromErrno(errno);
                        break;
                }
            }
        }
#endif /* !RT_OS_SOLARIS */
    }
    VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Mounting returned with rc=%Rrc\n", rc);
    return rc;
}
/**
 * Corrects the casing of the final component
 *
 * @returns
 * @param   pClient             .
 * @param   pszFullPath         .
 * @param   pszStartComponent   .
 */
static int vbsfCorrectCasing(SHFLCLIENTDATA *pClient, char *pszFullPath, char *pszStartComponent)
{
    Log2(("vbsfCorrectCasing: %s %s\n", pszFullPath, pszStartComponent));

    AssertReturn((uintptr_t)pszFullPath < (uintptr_t)pszStartComponent - 1U, VERR_INTERNAL_ERROR_2);
    AssertReturn(pszStartComponent[-1] == RTPATH_DELIMITER, VERR_INTERNAL_ERROR_5);

    /*
     * Allocate a buffer that can hold really long file name entries as well as
     * the initial search pattern.
     */
    size_t cchComponent = strlen(pszStartComponent);
    size_t cchParentDir = pszStartComponent - pszFullPath;
    size_t cchFullPath  = cchParentDir + cchComponent;
    Assert(strlen(pszFullPath) == cchFullPath);

    size_t cbDirEntry   = 4096;
    if (cchFullPath + 4 > cbDirEntry - RT_OFFSETOF(RTDIRENTRYEX, szName))
        cbDirEntry = RT_OFFSETOF(RTDIRENTRYEX, szName) + cchFullPath + 4;

    PRTDIRENTRYEX pDirEntry = (PRTDIRENTRYEX)RTMemAlloc(cbDirEntry);
    if (pDirEntry == NULL)
        return VERR_NO_MEMORY;

    /*
     * Construct the search criteria in the szName member of pDirEntry.
     */
    /** @todo This is quite inefficient, especially for directories with many
     *        files.  If any of the typically case sensitive host systems start
     *        supporting opendir wildcard filters, it would make sense to build
     *        one here with '?' for case foldable charaters. */
    /** @todo Use RTDirOpen here and drop the whole uncessary path copying? */
    int rc = RTPathJoinEx(pDirEntry->szName, cbDirEntry - RT_OFFSETOF(RTDIRENTRYEX, szName),
                          pszFullPath, cchParentDir,
                          RT_STR_TUPLE("*"));
    AssertRC(rc);
    if (RT_SUCCESS(rc))
    {
        PRTDIR hSearch = NULL;
        rc = RTDirOpenFiltered(&hSearch, pDirEntry->szName, RTDIRFILTER_WINNT, 0);
        if (RT_SUCCESS(rc))
        {
            for (;;)
            {
                size_t cbDirEntrySize = cbDirEntry;

                rc = RTDirReadEx(hSearch, pDirEntry, &cbDirEntrySize, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient));
                if (rc == VERR_NO_MORE_FILES)
                    break;

                if (   rc != VINF_SUCCESS
                    && rc != VWRN_NO_DIRENT_INFO)
                {
                    AssertFailed();
                    if (   rc == VERR_NO_TRANSLATION
                        || rc == VERR_INVALID_UTF8_ENCODING)
                        continue;
                    break;
                }

                Log2(("vbsfCorrectCasing: found %s\n", &pDirEntry->szName[0]));
                if (    pDirEntry->cbName == cchComponent
                    &&  !RTStrICmp(pszStartComponent, &pDirEntry->szName[0]))
                {
                    Log(("Found original name %s (%s)\n", &pDirEntry->szName[0], pszStartComponent));
                    strcpy(pszStartComponent, &pDirEntry->szName[0]);
                    rc = VINF_SUCCESS;
                    break;
                }
            }

            RTDirClose(hSearch);
        }
    }

    if (RT_FAILURE(rc))
        Log(("vbsfCorrectCasing %s failed with %Rrc\n", pszStartComponent, rc));

    RTMemFree(pDirEntry);

    return rc;
}
DECLEXPORT(int) pam_sm_authenticate(pam_handle_t *hPAM, int iFlags, int argc, const char **argv)
{
    RT_NOREF1(iFlags);

    /* Parse arguments. */
    for (int i = 0; i < argc; i++)
    {
        if (!RTStrICmp(argv[i], "debug"))
            g_verbosity = 1;
        else
            pam_vbox_error(hPAM, "pam_vbox_authenticate: unknown command line argument \"%s\"\n", argv[i]);
    }
    pam_vbox_log(hPAM, "pam_vbox_authenticate called\n");

    int rc = pam_vbox_init(hPAM);
    if (RT_FAILURE(rc))
        return PAM_SUCCESS; /* Jump out as early as we can to not mess around. */

    bool fFallback = true;

#ifdef VBOX_WITH_GUEST_PROPS
    uint32_t uClientId;
    rc = VbglR3GuestPropConnect(&uClientId);
    if (RT_SUCCESS(rc))
    {
        char szVal[256];
        rc = pam_vbox_read_prop(hPAM, uClientId,
                                "/VirtualBox/GuestAdd/PAM/CredsWait",
                                true /* Read-only on guest */,
                                szVal, sizeof(szVal));
        if (RT_SUCCESS(rc))
        {
            /* All calls which are checked against rc2 are not critical, e.g. it does
             * not matter if they succeed or not. */
            uint32_t uTimeoutMS = RT_INDEFINITE_WAIT; /* Wait infinite by default. */
            int rc2 = pam_vbox_read_prop(hPAM, uClientId,
                                         "/VirtualBox/GuestAdd/PAM/CredsWaitTimeout",
                                         true /* Read-only on guest */,
                                         szVal, sizeof(szVal));
            if (RT_SUCCESS(rc2))
            {
                uTimeoutMS = RTStrToUInt32(szVal);
                if (!uTimeoutMS)
                {
                    pam_vbox_error(hPAM, "pam_vbox_authenticate: invalid waiting timeout value specified, defaulting to infinite timeout\n");
                    uTimeoutMS = RT_INDEFINITE_WAIT;
                }
                else
                    uTimeoutMS = uTimeoutMS * 1000; /* Make ms out of s. */
            }

            rc2 = pam_vbox_read_prop(hPAM, uClientId,
                                     "/VirtualBox/GuestAdd/PAM/CredsMsgWaiting",
                                     true /* Read-only on guest */,
                                     szVal, sizeof(szVal));
            const char *pszWaitMsg = NULL;
            if (RT_SUCCESS(rc2))
                pszWaitMsg = szVal;

            rc2 = vbox_set_msg(hPAM, 0 /* Info message */,
                               pszWaitMsg ? pszWaitMsg : "Waiting for credentials ...");
            if (RT_FAILURE(rc2)) /* Not critical. */
                pam_vbox_error(hPAM, "pam_vbox_authenticate: error setting waiting information message, rc=%Rrc\n", rc2);

            if (RT_SUCCESS(rc))
            {
                /* Before we actuall wait for credentials just make sure we didn't already get credentials
                 * set so that we can skip waiting for them ... */
                rc = pam_vbox_check_creds(hPAM);
                if (rc == VERR_NOT_FOUND)
                {
                    rc = pam_vbox_wait_for_creds(hPAM, uClientId, uTimeoutMS);
                    if (rc == VERR_TIMEOUT)
                    {
                        pam_vbox_log(hPAM, "pam_vbox_authenticate: no credentials given within time\n");

                        rc2 = pam_vbox_read_prop(hPAM, uClientId,
                                                 "/VirtualBox/GuestAdd/PAM/CredsMsgWaitTimeout",
                                                 true /* Read-only on guest */,
                                                 szVal, sizeof(szVal));
                        if (RT_SUCCESS(rc2))
                        {
                            rc2 = vbox_set_msg(hPAM, 0 /* Info message */, szVal);
                            AssertRC(rc2);
                        }
                    }
                    else if (rc == VERR_CANCELLED)
                    {
                        pam_vbox_log(hPAM, "pam_vbox_authenticate: waiting aborted\n");

                        rc2 = pam_vbox_read_prop(hPAM, uClientId,
                                                 "/VirtualBox/GuestAdd/PAM/CredsMsgWaitAbort",
                                                 true /* Read-only on guest */,
                                                 szVal, sizeof(szVal));
                        if (RT_SUCCESS(rc2))
                        {
                            rc2 = vbox_set_msg(hPAM, 0 /* Info message */, szVal);
                            AssertRC(rc2);
                        }
                    }
                }

                /* If we got here we don't need the fallback, so just deactivate it. */
                fFallback = false;
            }
        }

        VbglR3GuestPropDisconnect(uClientId);
    }
#endif /* VBOX_WITH_GUEST_PROPS */

    if (fFallback)
    {
        pam_vbox_log(hPAM, "pam_vbox_authenticate: falling back to old method\n");

        /* If anything went wrong in the code above we just do a credentials
         * check like it was before: Try retrieving the stuff and authenticating. */
        int rc2 = pam_vbox_check_creds(hPAM);
        if (RT_SUCCESS(rc))
            rc = rc2;
    }

    pam_vbox_shutdown(hPAM);

    pam_vbox_log(hPAM, "pam_vbox_authenticate: overall result rc=%Rrc\n", rc);

    /* Never report an error here because if no credentials from the host are available or something
     * went wrong we then let do the authentication by the next module in the stack. */

    /* We report success here because this is all we can do right now -- we passed the credentials
     * to the next PAM module in the block above which then might do a shadow (like pam_unix/pam_unix2)
     * password verification to "really" authenticate the user. */
    return PAM_SUCCESS;
}
Exemple #14
0
/**
 * Value string -> Value union.
 *
 * @returns IPRT status code.
 * @param   fFlags              The value flags.
 * @param   pszValue            The value string.
 * @param   pValueUnion         Where to return the processed value.
 */
static int rtGetOptProcessValue(uint32_t fFlags, const char *pszValue, PRTGETOPTUNION pValueUnion)
{
    /*
     * Transform into a option value as requested.
     * If decimal conversion fails, we'll check for "0x<xdigit>" and
     * try a 16 based conversion. We will not interpret any of the
     * generic ints as octals.
     */
    switch (fFlags & (  RTGETOPT_REQ_MASK
                      | RTGETOPT_FLAG_HEX
                      | RTGETOPT_FLAG_DEC
                      | RTGETOPT_FLAG_OCT))
    {
        case RTGETOPT_REQ_STRING:
            pValueUnion->psz = pszValue;
            break;

        case RTGETOPT_REQ_BOOL:
            if (   !RTStrICmp(pszValue, "true")
                || !RTStrICmp(pszValue, "t")
                || !RTStrICmp(pszValue, "yes")
                || !RTStrICmp(pszValue, "y")
                || !RTStrICmp(pszValue, "enabled")
                || !RTStrICmp(pszValue, "enable")
                || !RTStrICmp(pszValue, "en")
                || !RTStrICmp(pszValue, "e")
                || !RTStrICmp(pszValue, "on")
                || !RTStrCmp(pszValue, "1")
                )
                pValueUnion->f = true;
            else if (   !RTStrICmp(pszValue, "false")
                     || !RTStrICmp(pszValue, "f")
                     || !RTStrICmp(pszValue, "no")
                     || !RTStrICmp(pszValue, "n")
                     || !RTStrICmp(pszValue, "disabled")
                     || !RTStrICmp(pszValue, "disable")
                     || !RTStrICmp(pszValue, "dis")
                     || !RTStrICmp(pszValue, "d")
                     || !RTStrICmp(pszValue, "off")
                     || !RTStrCmp(pszValue, "0")
                     )
                pValueUnion->f = false;
            else
            {
                pValueUnion->psz = pszValue;
                return VERR_GETOPT_UNKNOWN_OPTION;
            }
            break;

        case RTGETOPT_REQ_BOOL_ONOFF:
            if (!RTStrICmp(pszValue, "on"))
                pValueUnion->f = true;
            else if (!RTStrICmp(pszValue, "off"))
                pValueUnion->f = false;
            else
            {
                pValueUnion->psz = pszValue;
                return VERR_GETOPT_UNKNOWN_OPTION;
            }
            break;

#define MY_INT_CASE(req, type, memb, convfn) \
            case req: \
            { \
                type Value; \
                if (    convfn(pszValue, 10, &Value) != VINF_SUCCESS \
                    &&  (   pszValue[0] != '0' \
                         || (pszValue[1] != 'x' && pszValue[1] != 'X') \
                         || !RT_C_IS_XDIGIT(pszValue[2]) \
                         || convfn(pszValue, 16, &Value) != VINF_SUCCESS ) ) \
                    return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \
                pValueUnion->memb = Value; \
                break; \
            }
#define MY_BASE_INT_CASE(req, type, memb, convfn, base) \
            case req: \
            { \
                type Value; \
                if (convfn(pszValue, base, &Value) != VINF_SUCCESS) \
                    return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \
                pValueUnion->memb = Value; \
                break; \
            }

        MY_INT_CASE(RTGETOPT_REQ_INT8,   int8_t,   i8,  RTStrToInt8Full)
        MY_INT_CASE(RTGETOPT_REQ_INT16,  int16_t,  i16, RTStrToInt16Full)
        MY_INT_CASE(RTGETOPT_REQ_INT32,  int32_t,  i32, RTStrToInt32Full)
        MY_INT_CASE(RTGETOPT_REQ_INT64,  int64_t,  i64, RTStrToInt64Full)
        MY_INT_CASE(RTGETOPT_REQ_UINT8,  uint8_t,  u8,  RTStrToUInt8Full)
        MY_INT_CASE(RTGETOPT_REQ_UINT16, uint16_t, u16, RTStrToUInt16Full)
        MY_INT_CASE(RTGETOPT_REQ_UINT32, uint32_t, u32, RTStrToUInt32Full)
        MY_INT_CASE(RTGETOPT_REQ_UINT64, uint64_t, u64, RTStrToUInt64Full)

        MY_BASE_INT_CASE(RTGETOPT_REQ_INT8   | RTGETOPT_FLAG_HEX, int8_t,   i8,  RTStrToInt8Full,   16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT16  | RTGETOPT_FLAG_HEX, int16_t,  i16, RTStrToInt16Full,  16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT32  | RTGETOPT_FLAG_HEX, int32_t,  i32, RTStrToInt32Full,  16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT64  | RTGETOPT_FLAG_HEX, int64_t,  i64, RTStrToInt64Full,  16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8  | RTGETOPT_FLAG_HEX, uint8_t,  u8,  RTStrToUInt8Full,  16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_HEX, uint16_t, u16, RTStrToUInt16Full, 16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX, uint32_t, u32, RTStrToUInt32Full, 16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX, uint64_t, u64, RTStrToUInt64Full, 16)

        MY_BASE_INT_CASE(RTGETOPT_REQ_INT8   | RTGETOPT_FLAG_DEC, int8_t,   i8,  RTStrToInt8Full,   10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT16  | RTGETOPT_FLAG_DEC, int16_t,  i16, RTStrToInt16Full,  10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT32  | RTGETOPT_FLAG_DEC, int32_t,  i32, RTStrToInt32Full,  10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT64  | RTGETOPT_FLAG_DEC, int64_t,  i64, RTStrToInt64Full,  10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8  | RTGETOPT_FLAG_DEC, uint8_t,  u8,  RTStrToUInt8Full,  10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_DEC, uint16_t, u16, RTStrToUInt16Full, 10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_DEC, uint32_t, u32, RTStrToUInt32Full, 10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_DEC, uint64_t, u64, RTStrToUInt64Full, 10)

        MY_BASE_INT_CASE(RTGETOPT_REQ_INT8   | RTGETOPT_FLAG_OCT, int8_t,   i8,  RTStrToInt8Full,   8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT16  | RTGETOPT_FLAG_OCT, int16_t,  i16, RTStrToInt16Full,  8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT32  | RTGETOPT_FLAG_OCT, int32_t,  i32, RTStrToInt32Full,  8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT64  | RTGETOPT_FLAG_OCT, int64_t,  i64, RTStrToInt64Full,  8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8  | RTGETOPT_FLAG_OCT, uint8_t,  u8,  RTStrToUInt8Full,  8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_OCT, uint16_t, u16, RTStrToUInt16Full, 8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT, uint32_t, u32, RTStrToUInt32Full, 8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_OCT, uint64_t, u64, RTStrToUInt64Full, 8)

#undef MY_INT_CASE
#undef MY_BASE_INT_CASE

        case RTGETOPT_REQ_IPV4ADDR:
        {
            RTNETADDRIPV4 Addr;
            if (rtgetoptConvertIPv4Addr(pszValue, &Addr) != VINF_SUCCESS)
                return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
            pValueUnion->IPv4Addr = Addr;
            break;
        }

        case RTGETOPT_REQ_IPV4CIDR:
        {
            RTNETADDRIPV4 network;
            RTNETADDRIPV4 netmask;
            if (RT_FAILURE(RTCidrStrToIPv4(pszValue, &network, &netmask)))
              return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
            pValueUnion->CidrIPv4.IPv4Network.u = network.u;
            pValueUnion->CidrIPv4.IPv4Netmask.u = netmask.u;
            break;
        }

        case RTGETOPT_REQ_MACADDR:
        {
            RTMAC Addr;
            if (rtgetoptConvertMacAddr(pszValue, &Addr) != VINF_SUCCESS)
                return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
            pValueUnion->MacAddr = Addr;
            break;
        }

        case RTGETOPT_REQ_UUID:
        {
            RTUUID Uuid;
            if (RTUuidFromStr(&Uuid, pszValue) != VINF_SUCCESS)
                return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
            pValueUnion->Uuid = Uuid;
            break;
        }

        default:
            AssertMsgFailed(("f=%#x\n", fFlags));
            return VERR_INTERNAL_ERROR;
    }

    return VINF_SUCCESS;
}
/**
 * Checks if a testcase is include or should be skipped.
 *
 * @param pszTestcase   The testcase (filename).
 *
 * @return  true if the testcase is included.
 *          false if the testcase should be skipped.
 */
static bool IsTestcaseIncluded(const char *pszTestcase)
{
    /* exclude special modules based on extension. */
    const char *pszExt = RTPathExt(pszTestcase);
    if (   !RTStrICmp(pszExt, ".r0")
        || !RTStrICmp(pszExt, ".gc")
        || !RTStrICmp(pszExt, ".sys")
        || !RTStrICmp(pszExt, ".ko")
        || !RTStrICmp(pszExt, ".o")
        || !RTStrICmp(pszExt, ".obj")
        || !RTStrICmp(pszExt, ".lib")
        || !RTStrICmp(pszExt, ".a")
        || !RTStrICmp(pszExt, ".so")
        || !RTStrICmp(pszExt, ".dll")
        || !RTStrICmp(pszExt, ".dylib")
        || !RTStrICmp(pszExt, ".tmp")
        || !RTStrICmp(pszExt, ".log")
       )
        return false;

    /* check by name */
    char *pszDup = RTStrDup(pszTestcase);
    if (pszDup)
    {
        RTPathStripExt(pszDup);
        for (unsigned i = 0; i < RT_ELEMENTS(g_apszExclude); i++)
        {
            if (!strcmp(g_apszExclude[i], pszDup))
            {
                RTStrFree(pszDup);
                return false;
            }
        }
        RTStrFree(pszDup);
        return true;
    }

    RTPrintf("tstRunTestcases: Out of memory!\n");
    return false;
}
Exemple #16
0
/** @copydoc VDIMAGEBACKEND::pfnProbe */
static DECLCALLBACK(int) rawProbe(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
                                  PVDINTERFACE pVDIfsImage, VDTYPE *penmType)
{
    RT_NOREF1(pVDIfsDisk);
    LogFlowFunc(("pszFilename=\"%s\" pVDIfsDisk=%#p pVDIfsImage=%#p\n", pszFilename, pVDIfsDisk, pVDIfsImage));
    PVDIOSTORAGE pStorage = NULL;
    PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage);

    AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
    AssertReturn((VALID_PTR(pszFilename) && *pszFilename), VERR_INVALID_PARAMETER);

    /*
     * Open the file and read the footer.
     */
    int rc = vdIfIoIntFileOpen(pIfIo, pszFilename,
                               VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
                                       false /* fCreate */),
                               &pStorage);
    if (RT_SUCCESS(rc))
    {
        uint64_t cbFile;
        const char *pszSuffix = RTPathSuffix(pszFilename);
        rc = vdIfIoIntFileGetSize(pIfIo, pStorage, &cbFile);

        /* Try to guess the image type based on the extension. */
        if (   RT_SUCCESS(rc)
                && pszSuffix)
        {
            if (   !RTStrICmp(pszSuffix, ".iso")
                    || !RTStrICmp(pszSuffix, ".cdr")) /* DVD images. */
            {
                /* Note that there are ISO images smaller than 1 MB; it is impossible to distinguish
                 * between raw floppy and CD images based on their size (and cannot be reliably done
                 * based on contents, either).
                 */
                if (cbFile % 2048)
                    rc = VERR_VD_RAW_SIZE_MODULO_2048;
                else if (cbFile <= 32768)
                    rc = VERR_VD_RAW_SIZE_OPTICAL_TOO_SMALL;
                else
                {
                    *penmType = VDTYPE_DVD;
                    rc = VINF_SUCCESS;
                }
            }
            else if (   !RTStrICmp(pszSuffix, ".img")
                        || !RTStrICmp(pszSuffix, ".ima")
                        || !RTStrICmp(pszSuffix, ".dsk")
                        || !RTStrICmp(pszSuffix, ".flp")
                        || !RTStrICmp(pszSuffix, ".vfd")) /* Floppy images */
            {
                if (cbFile % 512)
                    rc = VERR_VD_RAW_SIZE_MODULO_512;
                else if (cbFile > RAW_MAX_FLOPPY_IMG_SIZE)
                    rc = VERR_VD_RAW_SIZE_FLOPPY_TOO_BIG;
                else
                {
                    *penmType = VDTYPE_FLOPPY;
                    rc = VINF_SUCCESS;
                }
            }
            else
                rc = VERR_VD_RAW_INVALID_HEADER;
        }
        else
            rc = VERR_VD_RAW_INVALID_HEADER;
    }

    if (pStorage)
        vdIfIoIntFileClose(pIfIo, pStorage);

    LogFlowFunc(("returns %Rrc\n", rc));
    return rc;
}
Exemple #17
0
/**
 * Handles the getregisters sub-command.
 *
 * @returns Suitable exit code.
 * @param   pArgs               The handler arguments.
 * @param   pDebugger           Pointer to the debugger interface.
 */
static RTEXITCODE handleDebugVM_GetRegisters(HandlerArg *pArgs, IMachineDebugger *pDebugger)
{
    /*
     * We take a list of register names (case insensitive).  If 'all' is
     * encountered we'll dump all registers.
     */
    ULONG                       idCpu = 0;
    unsigned                    cRegisters = 0;

    RTGETOPTSTATE               GetState;
    RTGETOPTUNION               ValueUnion;
    static const RTGETOPTDEF    s_aOptions[] =
    {
        { "--cpu", 'c', RTGETOPT_REQ_UINT32 },
    };
    int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
    AssertRCReturn(rc, RTEXITCODE_FAILURE);

    while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
    {
        switch (rc)
        {
            case 'c':
                idCpu = ValueUnion.u32;
                break;

            case VINF_GETOPT_NOT_OPTION:
                if (!RTStrICmp(ValueUnion.psz, "all"))
                {
                    com::SafeArray<BSTR> aBstrNames;
                    com::SafeArray<BSTR> aBstrValues;
                    CHECK_ERROR2I_RET(pDebugger, GetRegisters(idCpu, ComSafeArrayAsOutParam(aBstrNames),
                                                              ComSafeArrayAsOutParam(aBstrValues)),
                                      RTEXITCODE_FAILURE);
                    Assert(aBstrNames.size() == aBstrValues.size());

                    size_t cchMaxName  = 8;
                    for (size_t i = 0; i < aBstrNames.size(); i++)
                    {
                        size_t cchName = RTUtf16Len(aBstrNames[i]);
                        if (cchName > cchMaxName)
                            cchMaxName = cchName;
                    }

                    for (size_t i = 0; i < aBstrNames.size(); i++)
                        RTPrintf("%-*ls = %ls\n", cchMaxName, aBstrNames[i], aBstrValues[i]);
                }
                else
                {
                    com::Bstr bstrName = ValueUnion.psz;
                    com::Bstr bstrValue;
                    CHECK_ERROR2I_RET(pDebugger, GetRegister(idCpu, bstrName.raw(), bstrValue.asOutParam()), RTEXITCODE_FAILURE);
                    RTPrintf("%s = %ls\n", ValueUnion.psz, bstrValue.raw());
                }
                cRegisters++;
                break;

            default:
                return errorGetOpt(rc, &ValueUnion);
        }
    }

    if (!cRegisters)
        return errorSyntax("The getregisters sub-command takes at least one register name");
    return RTEXITCODE_SUCCESS;
}