Esempio n. 1
0
int main()
{
    RTR3Init();
    printf("tstLog: Requires manual inspection of the log output!\n");
    RTLogPrintf("%%Rrc %d: %Rrc\n", VERR_INVALID_PARAMETER, VERR_INVALID_PARAMETER);
    RTLogPrintf("%%Rrs %d: %Rrs\n", VERR_INVALID_PARAMETER, VERR_INVALID_PARAMETER);
    RTLogPrintf("%%Rrf %d: %Rrf\n", VERR_INVALID_PARAMETER, VERR_INVALID_PARAMETER);
    RTLogPrintf("%%Rra %d: %Rra\n", VERR_INVALID_PARAMETER, VERR_INVALID_PARAMETER);

    static uint8_t au8Hex[256];
    for (unsigned iHex = 0; iHex < sizeof(au8Hex); iHex++)
        au8Hex[iHex] = (uint8_t)iHex;
    RTLogPrintf("%%Rhxs   : %Rhxs\n", &au8Hex[0]);
    RTLogPrintf("%%.32Rhxs: %.32Rhxs\n", &au8Hex[0]);

    RTLogPrintf("%%Rhxd   :\n%Rhxd\n", &au8Hex[0]);
    RTLogPrintf("%%.64Rhxd:\n%.64Rhxd\n", &au8Hex[0]);
    RTLogPrintf("%%.*Rhxd:\n%.*Rhxd\n", 64, &au8Hex[0]);
    RTLogPrintf("%%32.256Rhxd : \n%32.256Rhxd\n", &au8Hex[0]);
    RTLogPrintf("%%32.*Rhxd : \n%32.*Rhxd\n", 256, &au8Hex[0]);
    RTLogPrintf("%%7.32Rhxd : \n%7.32Rhxd\n", &au8Hex[0]);
    RTLogPrintf("%%7.*Rhxd : \n%7.*Rhxd\n", 32, &au8Hex[0]);
    RTLogPrintf("%%*.*Rhxd : \n%*.*Rhxd\n", 7, 32, &au8Hex[0]);

    RTLogPrintf("%%RGp: %RGp\n", (RTGCPHYS)0x87654321);
    RTLogPrintf("%%RGv: %RGv\n", (RTGCPTR)0x87654321);
    RTLogPrintf("%%RHp: %RHp\n", (RTGCPHYS)0x87654321);
    RTLogPrintf("%%RHv: %RHv\n", (RTGCPTR)0x87654321);

    RTLogPrintf("%%RI8 : %RI8\n", (uint8_t)808);
    RTLogPrintf("%%RI16: %RI16\n", (uint16_t)16016);
    RTLogPrintf("%%RI32: %RI32\n", _1G);
    RTLogPrintf("%%RI64: %RI64\n", _1E);

    RTLogPrintf("%%RU8 : %RU8\n", (uint8_t)808);
    RTLogPrintf("%%RU16: %RU16\n", (uint16_t)16016);
    RTLogPrintf("%%RU32: %RU32\n", _2G32);
    RTLogPrintf("%%RU64: %RU64\n", _2E);

    RTLogPrintf("%%RX8 : %RX8 %#RX8\n",   (uint8_t)808, (uint8_t)808);
    RTLogPrintf("%%RX16: %RX16 %#RX16\n", (uint16_t)16016, (uint16_t)16016);
    RTLogPrintf("%%RX32: %RX32 %#RX32\n", _2G32, _2G32);
    RTLogPrintf("%%RX64: %RX64 %#RX64\n", _2E, _2E);

    RTLogFlush(NULL);

    return 0;
}
Esempio n. 2
0
RTDECL(void) RTAssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
{
    /*
     * Fill in the globals.
     */
    ASMAtomicUoWritePtr(&g_pszRTAssertExpr, pszExpr);
    ASMAtomicUoWritePtr(&g_pszRTAssertFile, pszFile);
    ASMAtomicUoWritePtr(&g_pszRTAssertFunction, pszFunction);
    ASMAtomicUoWriteU32(&g_u32RTAssertLine, uLine);
    RTStrPrintf(g_szRTAssertMsg1, sizeof(g_szRTAssertMsg1),
                "\n!!Assertion Failed!!\n"
                "Expression: %s\n"
                "Location  : %s(%d) %s\n",
                pszExpr, pszFile, uLine, pszFunction);

    /*
     * If not quiet, make noise.
     */
    if (!RTAssertAreQuiet())
    {
        RTERRVARS SavedErrVars;
        RTErrVarsSave(&SavedErrVars);

#ifdef IN_RING0
# ifdef IN_GUEST_R0
        RTLogBackdoorPrintf("\n!!Assertion Failed!!\n"
                            "Expression: %s\n"
                            "Location  : %s(%d) %s\n",
                            pszExpr, pszFile, uLine, pszFunction);
# endif
        /** @todo fully integrate this with the logger... play safe a bit for now.  */
        rtR0AssertNativeMsg1(pszExpr, uLine, pszFile, pszFunction);

#else  /* !IN_RING0 */
# if !defined(IN_RING3) && !defined(LOG_NO_COM)
#  if 0 /* Enable this iff you have a COM port and really want this debug info. */
        RTLogComPrintf("\n!!Assertion Failed!!\n"
                       "Expression: %s\n"
                       "Location  : %s(%d) %s\n",
                       pszExpr, pszFile, uLine, pszFunction);
#  endif
# endif

        PRTLOGGER pLog = RTLogRelGetDefaultInstance();
        if (pLog)
        {
            RTLogRelPrintf("\n!!Assertion Failed!!\n"
                           "Expression: %s\n"
                           "Location  : %s(%d) %s\n",
                           pszExpr, pszFile, uLine, pszFunction);
# ifndef IN_RC /* flushing is done automatically in RC */
            RTLogFlush(pLog);
# endif
        }

# ifndef LOG_ENABLED
        if (!pLog)
# endif
        {
            pLog = RTLogDefaultInstance();
            if (pLog)
            {
                RTLogPrintf("\n!!Assertion Failed!!\n"
                            "Expression: %s\n"
                            "Location  : %s(%d) %s\n",
                            pszExpr, pszFile, uLine, pszFunction);
# ifndef IN_RC /* flushing is done automatically in RC */
                RTLogFlush(pLog);
# endif
            }
        }

# ifdef IN_RING3
        /* print to stderr, helps user and gdb debugging. */
        fprintf(stderr,
                "\n!!Assertion Failed!!\n"
                "Expression: %s\n"
                "Location  : %s(%d) %s\n",
                VALID_PTR(pszExpr) ? pszExpr : "<none>",
                VALID_PTR(pszFile) ? pszFile : "<none>",
                uLine,
                VALID_PTR(pszFunction) ? pszFunction : "");
        fflush(stderr);
# endif
#endif /* !IN_RING0 */

        RTErrVarsRestore(&SavedErrVars);
    }
}
/**
 * Internal free.
 */
RTDECL(void) rtR3MemFree(const char *pszOp, RTMEMTYPE enmType, void *pv, void *pvCaller, RT_SRC_POS_DECL)
{
    /*
     * Simple case.
     */
    if (!pv)
        return;

    /*
     * Check watch points.
     */
    for (unsigned i = 0; i < RT_ELEMENTS(gapvRTMemFreeWatch); i++)
        if (gapvRTMemFreeWatch[i] == pv)
            RTAssertDoPanic();

#ifdef RTALLOC_EFENCE_TRACE
    /*
     * Find the block.
     */
    PRTMEMBLOCK pBlock = rtmemBlockRemove(pv);
    if (pBlock)
    {
        if (gfRTMemFreeLog)
            RTLogPrintf("RTMem %s: pv=%p pvCaller=%p cbUnaligned=%#x\n", pszOp, pv, pvCaller, pBlock->cbUnaligned);

# ifdef RTALLOC_EFENCE_NOMAN_FILLER
        /*
         * Check whether the no man's land is untouched.
         */
#  ifdef RTALLOC_EFENCE_IN_FRONT
        void *pvWrong = ASMMemIsAll8((char *)pv + pBlock->cbUnaligned,
                                     RT_ALIGN_Z(pBlock->cbAligned, PAGE_SIZE) - pBlock->cbUnaligned,
                                     RTALLOC_EFENCE_NOMAN_FILLER);
#  else
        /* Alignment must match allocation alignment in rtMemAlloc(). */
        void  *pvWrong   = ASMMemIsAll8((char *)pv + pBlock->cbUnaligned,
                                        pBlock->cbAligned - pBlock->cbUnaligned,
                                        RTALLOC_EFENCE_NOMAN_FILLER);
        if (pvWrong)
            RTAssertDoPanic();
        pvWrong = ASMMemIsAll8((void *)((uintptr_t)pv & ~PAGE_OFFSET_MASK),
                               RT_ALIGN_Z(pBlock->cbAligned, PAGE_SIZE) - pBlock->cbAligned,
                               RTALLOC_EFENCE_NOMAN_FILLER);
#  endif
        if (pvWrong)
            RTAssertDoPanic();
# endif

# ifdef RTALLOC_EFENCE_FREE_FILL
        /*
         * Fill the user part of the block.
         */
        memset(pv, RTALLOC_EFENCE_FREE_FILL, pBlock->cbUnaligned);
# endif

# if defined(RTALLOC_EFENCE_FREE_DELAYED) && RTALLOC_EFENCE_FREE_DELAYED > 0
        /*
         * We're doing delayed freeing.
         * That means we'll expand the E-fence to cover the entire block.
         */
        int rc = RTMemProtect(pv, pBlock->cbAligned, RTMEM_PROT_NONE);
        if (RT_SUCCESS(rc))
        {
            /*
             * Insert it into the free list and process pending frees.
             */
            rtmemBlockDelayInsert(pBlock);
            while ((pBlock = rtmemBlockDelayRemove()) != NULL)
            {
                pv = pBlock->Core.Key;
#  ifdef RTALLOC_EFENCE_IN_FRONT
                void  *pvBlock = (char *)pv - RTALLOC_EFENCE_SIZE;
#  else
                void  *pvBlock = (void *)((uintptr_t)pv & ~PAGE_OFFSET_MASK);
#  endif
                size_t cbBlock = RT_ALIGN_Z(pBlock->cbAligned, PAGE_SIZE) + RTALLOC_EFENCE_SIZE;
                rc = RTMemProtect(pvBlock, cbBlock, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
                if (RT_SUCCESS(rc))
                    RTMemPageFree(pvBlock, RT_ALIGN_Z(pBlock->cbAligned, PAGE_SIZE) + RTALLOC_EFENCE_SIZE);
                else
                    rtmemComplain(pszOp, "RTMemProtect(%p, %#x, RTMEM_PROT_READ | RTMEM_PROT_WRITE) -> %d\n", pvBlock, cbBlock, rc);
                rtmemBlockFree(pBlock);
            }
        }
        else
            rtmemComplain(pszOp, "Failed to expand the efence of pv=%p cb=%d, rc=%d.\n", pv, pBlock, rc);

# else /* !RTALLOC_EFENCE_FREE_DELAYED */

        /*
         * Turn of the E-fence and free it.
         */
#  ifdef RTALLOC_EFENCE_IN_FRONT
        void *pvBlock = (char *)pv - RTALLOC_EFENCE_SIZE;
        void *pvEFence = pvBlock;
#  else
        void *pvBlock = (void *)((uintptr_t)pv & ~PAGE_OFFSET_MASK);
        void *pvEFence = (char *)pv + pBlock->cb;
#  endif
        int rc = RTMemProtect(pvEFence, RTALLOC_EFENCE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
        if (RT_SUCCESS(rc))
            RTMemPageFree(pvBlock, RT_ALIGN_Z(pBlock->cbAligned, PAGE_SIZE) + RTALLOC_EFENCE_SIZE);
        else
            rtmemComplain(pszOp, "RTMemProtect(%p, %#x, RTMEM_PROT_READ | RTMEM_PROT_WRITE) -> %d\n", pvEFence, RTALLOC_EFENCE_SIZE, rc);
        rtmemBlockFree(pBlock);

# endif /* !RTALLOC_EFENCE_FREE_DELAYED */
    }
    else
        rtmemComplain(pszOp, "pv=%p not found! Incorrect free!\n", pv);

#else /* !RTALLOC_EFENCE_TRACE */

    /*
     * We have no size tracking, so we're not doing any freeing because
     * we cannot if the E-fence is after the block.
     * Let's just expand the E-fence to the first page of the user bit
     * since we know that it's around.
     */
    int rc = RTMemProtect((void *)((uintptr_t)pv & ~PAGE_OFFSET_MASK), PAGE_SIZE, RTMEM_PROT_NONE);
    if (RT_FAILURE(rc))
        rtmemComplain(pszOp, "RTMemProtect(%p, PAGE_SIZE, RTMEM_PROT_NONE) -> %d\n", (void *)((uintptr_t)pv & ~PAGE_OFFSET_MASK), rc);
#endif /* !RTALLOC_EFENCE_TRACE */
}
Esempio n. 4
0
static DECLCALLBACK(int) doit(PVM pVM)
{
    RTPrintf(TESTCASE ": testing...\n");
    SetupSelectors(pVM);

    /*
     * Loading the module and resolve the entry point.
     */
    int rc = PDMR3LdrLoadRC(pVM, NULL, "tstMicroRC.gc");
    if (RT_FAILURE(rc))
    {
        RTPrintf(TESTCASE ": Failed to load tstMicroRC.gc, rc=%Rra\n", rc);
        return rc;
    }
    RTRCPTR RCPtrEntry;
    rc = PDMR3LdrGetSymbolRC(pVM, "tstMicroRC.gc", "tstMicroRC", &RCPtrEntry);
    if (RT_FAILURE(rc))
    {
        RTPrintf(TESTCASE ": Failed to resolve the 'tstMicroRC' entry point in tstMicroRC.gc, rc=%Rra\n", rc);
        return rc;
    }
    RTRCPTR RCPtrStart;
    rc = PDMR3LdrGetSymbolRC(pVM, "tstMicroRC.gc", "tstMicroRCAsmStart", &RCPtrStart);
    if (RT_FAILURE(rc))
    {
        RTPrintf(TESTCASE ": Failed to resolve the 'tstMicroRCAsmStart' entry point in tstMicroRC.gc, rc=%Rra\n", rc);
        return rc;
    }
    RTRCPTR RCPtrEnd;
    rc = PDMR3LdrGetSymbolRC(pVM, "tstMicroRC.gc", "tstMicroRCAsmEnd", &RCPtrEnd);
    if (RT_FAILURE(rc))
    {
        RTPrintf(TESTCASE ": Failed to resolve the 'tstMicroRCAsmEnd' entry point in tstMicroRC.gc, rc=%Rra\n", rc);
        return rc;
    }

    /*
     * Allocate and initialize the instance data.
     */
    PTSTMICRO pTst;
    rc = MMHyperAlloc(pVM, RT_ALIGN_Z(sizeof(*pTst), PAGE_SIZE), PAGE_SIZE, MM_TAG_VM, (void **)&pTst);
    if (RT_FAILURE(rc))
    {
        RTPrintf(TESTCASE ": Failed to resolve allocate instance memory (%d bytes), rc=%Rra\n", sizeof(*pTst), rc);
        return rc;
    }
    pTst->RCPtr = MMHyperR3ToRC(pVM, pTst);
    pTst->RCPtrStack = MMHyperR3ToRC(pVM, &pTst->au8Stack[sizeof(pTst->au8Stack) - 32]);

    /* the page must be writable from user mode */
    rc = PGMMapModifyPage(pVM, pTst->RCPtr, sizeof(*pTst), X86_PTE_US | X86_PTE_RW, ~(uint64_t)(X86_PTE_US | X86_PTE_RW));
    if (RT_FAILURE(rc))
    {
        RTPrintf(TESTCASE ": PGMMapModifyPage -> rc=%Rra\n", rc);
        return rc;
    }

    /* all the code must be executable from R3. */
    rc = PGMMapModifyPage(pVM, RCPtrStart, RCPtrEnd - RCPtrStart + PAGE_SIZE, X86_PTE_US, ~(uint64_t)X86_PTE_US);
    if (RT_FAILURE(rc))
    {
        RTPrintf(TESTCASE ": PGMMapModifyPage -> rc=%Rra\n", rc);
        return rc;
    }
    DBGFR3PagingDumpEx(pVM->pUVM, 0 /*idCpu*/, DBGFPGDMP_FLAGS_CURRENT_CR3 | DBGFPGDMP_FLAGS_CURRENT_MODE
                       | DBGFPGDMP_FLAGS_SHADOW | DBGFPGDMP_FLAGS_HEADER | DBGFPGDMP_FLAGS_PRINT_CR3,
                       0 /*cr3*/, 0 /*u64FirstAddr*/, UINT64_MAX /*u64LastAddr*/, 99 /*cMaxDepth*/, NULL);

#if 0
    /*
     * Disassemble the assembly...
     */
    RTGCPTR GCPtr = RCPtrStart;
    while (GCPtr < RCPtrEnd)
    {
        size_t  cb = 0;
        char    sz[256];
        int rc = DBGFR3DisasInstrEx(pVM, CPUMGetHyperCS(pVM), GCPtr, 0, sz, sizeof(sz), &cb);
        if (RT_SUCCESS(rc))
            RTLogPrintf("%s\n", sz);
        else
        {
            RTLogPrintf("%RGv rc=%Rrc\n", GCPtr, rc);
            cb = 1;
        }
        GCPtr += cb;
    }
#endif

#ifdef VBOX_WITH_RAW_MODE
    /*
     * Do the profiling.
     */
    /* execute the instruction profiling tests */
    PrintHeaderInstr();
    int i;
    for (i = TSTMICROTEST_OVERHEAD; i < TSTMICROTEST_TRAP_FIRST; i++)
    {
        TSTMICROTEST enmTest = (TSTMICROTEST)i;
        uint64_t    cMin = ~0;
        uint64_t    cMax = 0;
        uint64_t    cTotal = 0;
        unsigned    cSamples = 0;
        rc = VINF_SUCCESS;
        for (int c = 0; c < 100; c++)
        {
            int rc2 = VMMR3CallRC(pVM, RCPtrEntry, 2, pTst->RCPtr, enmTest);
            if (RT_SUCCESS(rc2))
            {
                uint64_t u64 = pTst->aResults[enmTest].cTotalTicks;
                if (cMin > u64)
                    cMin = u64;
                if (cMax < u64)
                    cMax = u64;
                cTotal += u64;
                cSamples++;
            }
            else if (RT_SUCCESS(rc))
                rc = rc2;
        }
        uint64_t cAvg = cTotal / (cSamples ? cSamples : 1);
        pTst->aResults[enmTest].cTotalTicks = cAvg;
        PrintResultInstr(pTst, enmTest, rc, cMin, cAvg, cMax);
        /* store the overhead */
        if (enmTest == TSTMICROTEST_OVERHEAD)
            pTst->u64Overhead = cMin;
    }
#endif


#ifdef VBOX_WITH_RAW_MODE
    /* execute the trap/cycle profiling tests. */
    RTPrintf("\n");
    PrintHeaderTraps();
    /* don't disable rdtsc in R1/R2/R3! */
    CPUMR3SetCR4Feature(pVM, 0, ~X86_CR4_TSD);
    for (i = TSTMICROTEST_TRAP_FIRST; i < TSTMICROTEST_MAX; i++)
    {
        TSTMICROTEST enmTest = (TSTMICROTEST)i;
        rc = VMMR3CallRC(pVM, RCPtrEntry, 2, pTst->RCPtr, enmTest);
        PrintResultTrap(pTst, enmTest, rc);
    }
#endif

    RTPrintf(TESTCASE ": done!\n");
    return VINF_SUCCESS;
}
/**
 * Check the credentials and return the gid/uid of user.
 *
 * @param    pszUser     username
 * @param    pszPasswd   password
 * @param    gid         where to store the GID of the user
 * @param    uid         where to store the UID of the user
 * @returns IPRT status code
 */
static int rtCheckCredentials(const char *pszUser, const char *pszPasswd, gid_t *pGid, uid_t *pUid)
{
#if defined(RT_OS_DARWIN)
    RTLogPrintf("rtCheckCredentials\n");

    /*
     * Resolve user to UID and GID.
     */
    char            szBuf[_4K];
    struct passwd   Pw;
    struct passwd  *pPw;
    if (getpwnam_r(pszUser, &Pw, szBuf, sizeof(szBuf), &pPw) != 0)
        return VERR_AUTHENTICATION_FAILURE;
    if (!pPw)
        return VERR_AUTHENTICATION_FAILURE;

    *pUid = pPw->pw_uid;
    *pGid = pPw->pw_gid;

    /*
     * Use PAM for the authentication.
     * Note! libpam.2.dylib was introduced with 10.6.x (OpenPAM).
     */
    void *hModPam = dlopen("libpam.dylib", RTLD_LAZY | RTLD_GLOBAL);
    if (hModPam)
    {
        int (*pfnPamStart)(const char *, const char *, struct pam_conv *, pam_handle_t **);
        int (*pfnPamAuthenticate)(pam_handle_t *, int);
        int (*pfnPamAcctMgmt)(pam_handle_t *, int);
        int (*pfnPamSetItem)(pam_handle_t *, int, const void *);
        int (*pfnPamEnd)(pam_handle_t *, int);
        *(void **)&pfnPamStart        = dlsym(hModPam, "pam_start");
        *(void **)&pfnPamAuthenticate = dlsym(hModPam, "pam_authenticate");
        *(void **)&pfnPamAcctMgmt     = dlsym(hModPam, "pam_acct_mgmt");
        *(void **)&pfnPamSetItem      = dlsym(hModPam, "pam_set_item");
        *(void **)&pfnPamEnd          = dlsym(hModPam, "pam_end");
        ASMCompilerBarrier();
        if (   pfnPamStart
            && pfnPamAuthenticate
            && pfnPamAcctMgmt
            && pfnPamSetItem
            && pfnPamEnd)
        {
#define pam_start           pfnPamStart
#define pam_authenticate    pfnPamAuthenticate
#define pam_acct_mgmt       pfnPamAcctMgmt
#define pam_set_item        pfnPamSetItem
#define pam_end             pfnPamEnd

            /* Do the PAM stuff.
               Note! Abusing 'login' here for now... */
            pam_handle_t   *hPam        = NULL;
            RTPROCPAMARGS   PamConvArgs = { pszUser, pszPasswd };
            struct pam_conv PamConversation;
            RT_ZERO(PamConversation);
            PamConversation.appdata_ptr = &PamConvArgs;
            PamConversation.conv        = rtPamConv;
            int rc = pam_start("login", pszUser, &PamConversation, &hPam);
            if (rc == PAM_SUCCESS)
            {
                rc = pam_set_item(hPam, PAM_RUSER, pszUser);
                if (rc == PAM_SUCCESS)
                    rc = pam_authenticate(hPam, 0);
                if (rc == PAM_SUCCESS)
                {
                    rc = pam_acct_mgmt(hPam, 0);
                    if (   rc == PAM_SUCCESS
                        || rc == PAM_AUTHINFO_UNAVAIL /*??*/)
                    {
                        pam_end(hPam, PAM_SUCCESS);
                        dlclose(hModPam);
                        return VINF_SUCCESS;
                    }
                    Log(("rtCheckCredentials: pam_acct_mgmt -> %d\n", rc));
                }
                else
                    Log(("rtCheckCredentials: pam_authenticate -> %d\n", rc));
                pam_end(hPam, rc);
            }
            else
                Log(("rtCheckCredentials: pam_start -> %d\n", rc));
        }
        else
            Log(("rtCheckCredentials: failed to resolve symbols: %p %p %p %p %p\n",
                 pfnPamStart, pfnPamAuthenticate, pfnPamAcctMgmt, pfnPamSetItem, pfnPamEnd));
        dlclose(hModPam);
    }
    else
        Log(("rtCheckCredentials: Loading libpam.dylib failed\n"));
    return VERR_AUTHENTICATION_FAILURE;

#elif defined(RT_OS_LINUX)
    struct passwd *pw;

    pw = getpwnam(pszUser);
    if (!pw)
        return VERR_AUTHENTICATION_FAILURE;

    if (!pszPasswd)
        pszPasswd = "";

    struct spwd *spwd;
    /* works only if /etc/shadow is accessible */
    spwd = getspnam(pszUser);
    if (spwd)
        pw->pw_passwd = spwd->sp_pwdp;

    /* Default fCorrect=true if no password specified. In that case, pw->pw_passwd
     * must be NULL (no password set for this user). Fail if a password is specified
     * but the user does not have one assigned. */
    int fCorrect = !pszPasswd || !*pszPasswd;
    if (pw->pw_passwd && *pw->pw_passwd)
    {
        struct crypt_data *data = (struct crypt_data*)RTMemTmpAllocZ(sizeof(*data));
        /* be reentrant */
        char *pszEncPasswd = crypt_r(pszPasswd, pw->pw_passwd, data);
        fCorrect = pszEncPasswd && !strcmp(pszEncPasswd, pw->pw_passwd);
        RTMemTmpFree(data);
    }
    if (!fCorrect)
        return VERR_AUTHENTICATION_FAILURE;

    *pGid = pw->pw_gid;
    *pUid = pw->pw_uid;
    return VINF_SUCCESS;

#elif defined(RT_OS_SOLARIS)
    struct passwd *ppw, pw;
    char szBuf[1024];

    if (getpwnam_r(pszUser, &pw, szBuf, sizeof(szBuf), &ppw) != 0 || ppw == NULL)
        return VERR_AUTHENTICATION_FAILURE;

    if (!pszPasswd)
        pszPasswd = "";

    struct spwd spwd;
    char szPwdBuf[1024];
    /* works only if /etc/shadow is accessible */
    if (getspnam_r(pszUser, &spwd, szPwdBuf, sizeof(szPwdBuf)) != NULL)
        ppw->pw_passwd = spwd.sp_pwdp;

    char *pszEncPasswd = crypt(pszPasswd, ppw->pw_passwd);
    if (strcmp(pszEncPasswd, ppw->pw_passwd))
        return VERR_AUTHENTICATION_FAILURE;

    *pGid = ppw->pw_gid;
    *pUid = ppw->pw_uid;
    return VINF_SUCCESS;

#else
    NOREF(pszUser); NOREF(pszPasswd); NOREF(pGid); NOREF(pUid);
    return VERR_AUTHENTICATION_FAILURE;
#endif
}