Esempio n. 1
0
/**
 * Adjust the profile environment after forking the child process and changing
 * the UID.
 *
 * @returns IRPT status code.
 * @param   hEnvToUse       The environment we're going to use with execve.
 * @param   fFlags          The process creation flags.
 * @param   hEnv            The environment passed in by the user.
 */
static int rtProcPosixAdjustProfileEnvFromChild(RTENV hEnvToUse, uint32_t fFlags, RTENV hEnv)
{
    int rc = VINF_SUCCESS;
#ifdef RT_OS_DARWIN
    if (   RT_SUCCESS(rc)
        && (!(fFlags & RTPROC_FLAGS_ENV_CHANGE_RECORD) || RTEnvExistEx(hEnv, "TMPDIR")) )
    {
        char szValue[_4K];
        size_t cbNeeded = confstr(_CS_DARWIN_USER_TEMP_DIR, szValue, sizeof(szValue));
        if (cbNeeded > 0 && cbNeeded < sizeof(szValue))
        {
            char *pszTmp;
            rc = RTStrCurrentCPToUtf8(&pszTmp, szValue);
            if (RT_SUCCESS(rc))
            {
                rc = RTEnvSetEx(hEnvToUse, "TMPDIR", pszTmp);
                RTStrFree(pszTmp);
            }
        }
        else
            rc = VERR_BUFFER_OVERFLOW;
    }
#endif
    return rc;
}
RTDECL(int) RTEnvPutEx(RTENV Env, const char *pszVarEqualValue)
{
    int rc;
    AssertPtrReturn(pszVarEqualValue, VERR_INVALID_POINTER);
    const char *pszEq = strchr(pszVarEqualValue, '=');
    if (!pszEq)
        rc = RTEnvUnsetEx(Env, pszVarEqualValue);
    else
    {
        /*
         * Make a copy of the variable name so we can terminate it
         * properly and then pass the request on to RTEnvSetEx.
         */
        const char *pszValue = pszEq + 1;

        size_t cchVar = pszEq - pszVarEqualValue;
        Assert(cchVar < 1024);
        char *pszVar = (char *)alloca(cchVar + 1);
        memcpy(pszVar, pszVarEqualValue, cchVar);
        pszVar[cchVar] = '\0';

        rc = RTEnvSetEx(Env, pszVar, pszValue);
    }
    return rc;
}
Esempio n. 3
0
/**
 * Create a very very basic environment for a user.
 *
 * @returns IPRT status code.
 * @param   phEnvToUse  Where to return the created environment.
 * @param   pszUser     The user name for the profile.
 */
static int rtProcPosixCreateProfileEnv(PRTENV phEnvToUse, const char *pszUser)
{
    struct passwd   Pwd;
    struct passwd  *pPwd = NULL;
    char            achBuf[_4K];
    int             rc;
    errno = 0;
    if (pszUser)
        rc = getpwnam_r(pszUser, &Pwd, achBuf, sizeof(achBuf), &pPwd);
    else
        rc = getpwuid_r(getuid(), &Pwd, achBuf, sizeof(achBuf), &pPwd);
    if (rc == 0 && pPwd)
    {
        char *pszDir;
        rc = RTStrCurrentCPToUtf8(&pszDir, pPwd->pw_dir);
        if (RT_SUCCESS(rc))
        {
            char *pszShell;
            rc = RTStrCurrentCPToUtf8(&pszShell, pPwd->pw_shell);
            if (RT_SUCCESS(rc))
            {
                char *pszUserFree = NULL;
                if (!pszUser)
                {
                    rc = RTStrCurrentCPToUtf8(&pszUserFree, pPwd->pw_name);
                    if (RT_SUCCESS(rc))
                        pszUser = pszUserFree;
                }
                if (RT_SUCCESS(rc))
                {
                    rc = RTEnvCreate(phEnvToUse);
                    if (RT_SUCCESS(rc))
                    {
                        RTENV hEnvToUse = *phEnvToUse;

                        rc = RTEnvSetEx(hEnvToUse, "HOME", pszDir);
                        if (RT_SUCCESS(rc))
                            rc = RTEnvSetEx(hEnvToUse, "SHELL", pszShell);
                        if (RT_SUCCESS(rc))
                            rc = RTEnvSetEx(hEnvToUse, "USER", pszUser);
                        if (RT_SUCCESS(rc))
                            rc = RTEnvSetEx(hEnvToUse, "LOGNAME", pszUser);

                        if (RT_SUCCESS(rc))
                            rc = RTEnvSetEx(hEnvToUse, "PATH", pPwd->pw_uid == 0 ? _PATH_STDPATH : _PATH_DEFPATH);

                        if (RT_SUCCESS(rc))
                        {
                            RTStrPrintf(achBuf, sizeof(achBuf), "%s/%s", _PATH_MAILDIR, pszUser);
                            rc = RTEnvSetEx(hEnvToUse, "MAIL", achBuf);
                        }

#ifdef RT_OS_DARWIN
                        if (RT_SUCCESS(rc) && !pszUserFree)
                        {
                            size_t cbNeeded = confstr(_CS_DARWIN_USER_TEMP_DIR, achBuf, sizeof(achBuf));
                            if (cbNeeded > 0 && cbNeeded < sizeof(achBuf))
                            {
                                char *pszTmp;
                                rc = RTStrCurrentCPToUtf8(&pszTmp, achBuf);
                                if (RT_SUCCESS(rc))
                                {
                                    rc = RTEnvSetEx(hEnvToUse, "TMPDIR", pszTmp);
                                    RTStrFree(pszTmp);
                                }
                            }
                            else
                                rc = VERR_BUFFER_OVERFLOW;
                        }
#endif

                        /** @todo load /etc/environment, /etc/profile.env and ~/.pam_environment? */

                        if (RT_FAILURE(rc))
                            RTEnvDestroy(hEnvToUse);
                    }
                    RTStrFree(pszUserFree);
                }
                RTStrFree(pszShell);
            }
            RTStrFree(pszDir);
        }
    }
    else
        rc = errno ? RTErrConvertFromErrno(errno) : VERR_ACCESS_DENIED;
    return rc;
}
Esempio n. 4
0
/**
 * Initializes the COM runtime.
 *
 * This method must be called on each thread of the client application that
 * wants to access COM facilities. The initialization must be performed before
 * calling any other COM method or attempting to instantiate COM objects.
 *
 * On platforms using XPCOM, this method uses the following scheme to search for
 * XPCOM runtime:
 *
 * 1. If the VBOX_APP_HOME environment variable is set, the path it specifies
 *    is used to search XPCOM libraries and components. If this method fails to
 *    initialize XPCOM runtime using this path, it will immediately return a
 *    failure and will NOT check for other paths as described below.
 *
 * 2. If VBOX_APP_HOME is not set, this methods tries the following paths in the
 *    given order:
 *
 *    a) Compiled-in application data directory (as returned by
 *       RTPathAppPrivateArch())
 *    b) "/usr/lib/virtualbox" (Linux only)
 *    c) "/opt/VirtualBox" (Linux only)
 *
 *    The first path for which the initialization succeeds will be used.
 *
 * On MS COM platforms, the COM runtime is provided by the system and does not
 * need to be searched for.
 *
 * Once the COM subsystem is no longer necessary on a given thread, Shutdown()
 * must be called to free resources allocated for it. Note that a thread may
 * call Initialize() several times but for each of tese calls there must be a
 * corresponding Shutdown() call.
 *
 * @return S_OK on success and a COM result code in case of failure.
 */
HRESULT Initialize(bool fGui)
{
    HRESULT rc = E_FAIL;

#if !defined(VBOX_WITH_XPCOM)

    /*
     * We initialize COM in GUI thread in STA, to be compliant with QT and
     * OLE requirments (for example to allow D&D), while other threads
     * initialized in regular MTA. To allow fast proxyless access from
     * GUI thread to COM objects, we explicitly provide our COM objects
     * with free threaded marshaller.
     * !!!!! Please think twice before touching this code !!!!!
     */
    DWORD flags = fGui ?
                  COINIT_APARTMENTTHREADED
                | COINIT_SPEED_OVER_MEMORY
                :
                  COINIT_MULTITHREADED
                | COINIT_DISABLE_OLE1DDE
                | COINIT_SPEED_OVER_MEMORY;

    rc = CoInitializeEx(NULL, flags);

    /* the overall result must be either S_OK or S_FALSE (S_FALSE means
     * "already initialized using the same apartment model") */
    AssertMsg(rc == S_OK || rc == S_FALSE, ("rc=%08X\n", rc));

    /* To be flow compatible with the XPCOM case, we return here if this isn't
     * the main thread or if it isn't its first initialization call.
     * Note! CoInitializeEx and CoUninitialize does it's own reference
     *       counting, so this exercise is entirely for the EventQueue init. */
    bool fRc;
    RTTHREAD hSelf = RTThreadSelf();
    if (hSelf != NIL_RTTHREAD)
        ASMAtomicCmpXchgHandle(&gCOMMainThread, hSelf, NIL_RTTHREAD, fRc);
    else
        fRc = false;

    if (fGui)
        Assert(RTThreadIsMain(hSelf));

    if (!fRc)
    {
        if (   gCOMMainThread == hSelf
            && SUCCEEDED(rc))
            gCOMMainInitCount++;

        AssertComRC(rc);
        return rc;
    }
    Assert(RTThreadIsMain(hSelf));

    /* this is the first main thread initialization */
    Assert(gCOMMainInitCount == 0);
    if (SUCCEEDED(rc))
        gCOMMainInitCount = 1;

#else /* !defined (VBOX_WITH_XPCOM) */

    /* Unused here */
    NOREF(fGui);

    if (ASMAtomicXchgBool(&gIsXPCOMInitialized, true) == true)
    {
        /* XPCOM is already initialized on the main thread, no special
         * initialization is necessary on additional threads. Just increase
         * the init counter if it's a main thread again (to correctly support
         * nested calls to Initialize()/Shutdown() for compatibility with
         * Win32). */

        nsCOMPtr<nsIEventQueue> eventQ;
        rc = NS_GetMainEventQ(getter_AddRefs(eventQ));

        if (NS_SUCCEEDED(rc))
        {
            PRBool isOnMainThread = PR_FALSE;
            rc = eventQ->IsOnCurrentThread(&isOnMainThread);
            if (NS_SUCCEEDED(rc) && isOnMainThread)
                ++gXPCOMInitCount;
        }

        AssertComRC(rc);
        return rc;
    }
    Assert(RTThreadIsMain(RTThreadSelf()));

    /* this is the first initialization */
    gXPCOMInitCount = 1;
    bool const fInitEventQueues = true;

    /* prepare paths for registry files */
    char szCompReg[RTPATH_MAX];
    char szXptiDat[RTPATH_MAX];

    int vrc = GetVBoxUserHomeDirectory(szCompReg, sizeof(szCompReg));
    AssertRCReturn(vrc, NS_ERROR_FAILURE);
    strcpy(szXptiDat, szCompReg);

    vrc = RTPathAppend(szCompReg, sizeof(szCompReg), "compreg.dat");
    AssertRCReturn(vrc, NS_ERROR_FAILURE);
    vrc = RTPathAppend(szXptiDat, sizeof(szXptiDat), "xpti.dat");
    AssertRCReturn(vrc, NS_ERROR_FAILURE);

    LogFlowFunc(("component registry  : \"%s\"\n", szCompReg));
    LogFlowFunc(("XPTI data file      : \"%s\"\n", szXptiDat));

#if defined (XPCOM_GLUE)
    XPCOMGlueStartup(nsnull);
#endif

    static const char *kAppPathsToProbe[] =
    {
        NULL, /* 0: will use VBOX_APP_HOME */
        NULL, /* 1: will try RTPathAppPrivateArch() */
#ifdef RT_OS_LINUX
        "/usr/lib/virtualbox",
        "/opt/VirtualBox",
#elif RT_OS_SOLARIS
        "/opt/VirtualBox/amd64",
        "/opt/VirtualBox/i386",
#elif RT_OS_DARWIN
        "/Application/VirtualBox.app/Contents/MacOS",
#endif
    };

    /* Find out the directory where VirtualBox binaries are located */
    for (size_t i = 0; i < RT_ELEMENTS(kAppPathsToProbe); ++ i)
    {
        char szAppHomeDir[RTPATH_MAX];

        if (i == 0)
        {
            /* Use VBOX_APP_HOME if present */
            vrc = RTEnvGetEx(RTENV_DEFAULT, "VBOX_APP_HOME", szAppHomeDir, sizeof(szAppHomeDir), NULL);
            if (vrc == VERR_ENV_VAR_NOT_FOUND)
                continue;
            AssertRC(vrc);
        }
        else if (i == 1)
        {
            /* Use RTPathAppPrivateArch() first */
            vrc = RTPathAppPrivateArch(szAppHomeDir, sizeof(szAppHomeDir));
            AssertRC(vrc);
        }
        else
        {
            /* Iterate over all other paths */
            szAppHomeDir[RTPATH_MAX - 1] = '\0';
            strncpy(szAppHomeDir, kAppPathsToProbe[i], RTPATH_MAX - 1);
            vrc = VINF_SUCCESS;
        }
        if (RT_FAILURE(vrc))
        {
            rc = NS_ERROR_FAILURE;
            continue;
        }

        char szCompDir[RTPATH_MAX];
        vrc = RTPathAppend(strcpy(szCompDir, szAppHomeDir), sizeof(szCompDir), "components");
        if (RT_FAILURE(vrc))
        {
            rc = NS_ERROR_FAILURE;
            continue;
        }
        LogFlowFunc(("component directory : \"%s\"\n", szCompDir));

        nsCOMPtr<DirectoryServiceProvider> dsProv;
        dsProv = new DirectoryServiceProvider();
        if (dsProv)
            rc = dsProv->init(szCompReg, szXptiDat, szCompDir, szAppHomeDir);
        else
            rc = NS_ERROR_OUT_OF_MEMORY;
        if (NS_FAILED(rc))
            break;

        /* Setup the application path for NS_InitXPCOM2. Note that we properly
         * answer the NS_XPCOM_CURRENT_PROCESS_DIR query in our directory
         * service provider but it seems to be activated after the directory
         * service is used for the first time (see the source NS_InitXPCOM2). So
         * use the same value here to be on the safe side. */
        nsCOMPtr <nsIFile> appDir;
        {
            char *appDirCP = NULL;
            vrc = RTStrUtf8ToCurrentCP(&appDirCP, szAppHomeDir);
            if (RT_SUCCESS(vrc))
            {
                nsCOMPtr<nsILocalFile> file;
                rc = NS_NewNativeLocalFile(nsEmbedCString(appDirCP),
                                           PR_FALSE, getter_AddRefs(file));
                if (NS_SUCCEEDED(rc))
                    appDir = do_QueryInterface(file, &rc);

                RTStrFree(appDirCP);
            }
            else
                rc = NS_ERROR_FAILURE;
        }
        if (NS_FAILED(rc))
            break;

        /* Set VBOX_XPCOM_HOME to the same app path to make XPCOM sources that
         * still use it instead of the directory service happy */
        vrc = RTEnvSetEx(RTENV_DEFAULT, "VBOX_XPCOM_HOME", szAppHomeDir);
        AssertRC(vrc);

        /* Finally, initialize XPCOM */
        {
            nsCOMPtr<nsIServiceManager> serviceManager;
            rc = NS_InitXPCOM2(getter_AddRefs(serviceManager), appDir, dsProv);
            if (NS_SUCCEEDED(rc))
            {
                nsCOMPtr<nsIComponentRegistrar> registrar =
                    do_QueryInterface(serviceManager, &rc);
                if (NS_SUCCEEDED(rc))
                {
                    rc = registrar->AutoRegister(nsnull);
                    if (NS_SUCCEEDED(rc))
                    {
                        /* We succeeded, stop probing paths */
                        LogFlowFunc(("Succeeded.\n"));
                        break;
                    }
                }
            }
        }

        /* clean up before the new try */
        rc = NS_ShutdownXPCOM(nsnull);

        if (i == 0)
        {
            /* We failed with VBOX_APP_HOME, don't probe other paths */
            break;
        }
    }

#endif /* !defined (VBOX_WITH_XPCOM) */

    // for both COM and XPCOM, we only get here if this is the main thread;
    // only then initialize the autolock system (AutoLock.cpp)
    Assert(RTThreadIsMain(RTThreadSelf()));
    util::InitAutoLockSystem();

    AssertComRC(rc);

    /*
     * Init the main event queue (ASSUMES it cannot fail).
     */
    if (SUCCEEDED(rc))
        EventQueue::init();

    return rc;
}
static void tstRTCreateProcEx6(const char *pszAsUser, const char *pszPassword)
{
    RTTestISub("Profile environment");

    const char *apszArgs[5] =
    {
        g_szExecName,
        "--testcase-child-6",
        "inherit",
        pszAsUser,
        NULL
    };

    RTTESTI_CHECK_RC_RETV(RTEnvSetEx(RTENV_DEFAULT, "testcase-child-6", "true"), VINF_SUCCESS);

    /* Use the process environment first. */
    RTPROCESS hProc;
    RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/,
                                         NULL, NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
    RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
    RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);

    if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
        RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);

    /* Use the process environment first with a little change. */
    apszArgs[2] = "change-record";
    RTENV hEnvChange;
    RTTESTI_CHECK_RC_RETV(RTEnvCreateChangeRecord(&hEnvChange), VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTEnvSetEx(hEnvChange, "testcase-child-6", "changed"), VINF_SUCCESS);
    int rc;
    RTTESTI_CHECK_RC(rc = RTProcCreateEx(g_szExecName, apszArgs, hEnvChange, RTPROC_FLAGS_ENV_CHANGE_RECORD,
                                         NULL, NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
    if (RT_SUCCESS(rc))
    {
        ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
        ProcStatus.iStatus   = -1;
        RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);

        if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
            RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
    }


    /* Use profile environment this time. */
    apszArgs[2] = "noinherit";
    RTTESTI_CHECK_RC(rc = RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, RTPROC_FLAGS_PROFILE,
                                         NULL, NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
    if (RT_SUCCESS(rc))
    {
        ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
        ProcStatus.iStatus   = -1;
        RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);

        if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
            RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
    }

    /* Use profile environment this time. */
    apszArgs[2] = "noinherit-change-record";
    RTTESTI_CHECK_RC(rc = RTProcCreateEx(g_szExecName, apszArgs, hEnvChange,
                                         RTPROC_FLAGS_PROFILE | RTPROC_FLAGS_ENV_CHANGE_RECORD,
                                         NULL, NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
    if (RT_SUCCESS(rc))
    {
        ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
        ProcStatus.iStatus   = -1;
        RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);

        if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
            RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
    }


    RTTESTI_CHECK_RC(RTEnvDestroy(hEnvChange), VINF_SUCCESS);

    /*
     * Restore the environment and check that the PROFILE flag didn't mess with
     * the process environment.  (Note! The bug may be elsewhere as well.)
     */
    RTTESTI_CHECK_RC(RTEnvUnsetEx(RTENV_DEFAULT, "testcase-child-6"), VINF_SUCCESS);

    RTENV hEnvCur;
    RTTESTI_CHECK_RC_RETV(RTEnvClone(&hEnvCur, RTENV_DEFAULT), VINF_SUCCESS);
    uint32_t cCurrent = RTEnvCountEx(hEnvCur);
    uint32_t cInitial = RTEnvCountEx(g_hEnvInitial);
    RTTESTI_CHECK_MSG(cCurrent == cInitial, ("cCurrent=%u cInitial=%u\n", cCurrent, cInitial));
    uint32_t    cVars1;
    RTENV       hEnv1,    hEnv2;
    const char *pszEnv1, *pszEnv2;
    if (cCurrent >= cInitial)
    {
        hEnv1   = hEnvCur;
        pszEnv1 = "current";
        cVars1  = cCurrent;
        hEnv2   = g_hEnvInitial;
        pszEnv2 = "initial";
    }
    else
    {
        hEnv2   = hEnvCur;
        pszEnv2 = "current";
        hEnv1   = g_hEnvInitial;
        pszEnv1 = "initial";
        cVars1  = cInitial;
    }
    for (uint32_t i = 0; i < cVars1; i++)
    {
        char szValue1[_16K];
        char szVarNm[_1K];
        rc = RTEnvGetByIndexEx(hEnv1, i, szVarNm, sizeof(szVarNm), szValue1, sizeof(szValue1));
        if (RT_SUCCESS(rc))
        {
            char szValue2[_16K];
            rc = RTEnvGetEx(hEnv2, szVarNm, szValue2, sizeof(szValue2), NULL);
            if (RT_SUCCESS(rc))
            {
                if (strcmp(szValue1, szValue2) != 0)
                {
                    RTTestIFailed("Variable '%s' differs", szVarNm);
                    RTTestIFailureDetails("%s: '%s'\n"
                                          "%s: '%s'\n",
                                          pszEnv1, szValue1,
                                          pszEnv2, szValue2);
                }
            }
            else
                RTTestIFailed("RTEnvGetEx(%s,%s,,) failed: %Rrc", pszEnv2, szVarNm, rc);

        }
        else
            RTTestIFailed("RTEnvGetByIndexEx(%s,%u,,,,) failed: %Rrc", pszEnv1, i, rc);
    }
}