VBoxServiceControlSession.cpp revision 4171ffb38eb8720b2ae9a8d13e95103ab26cfd12
7f21d92108ecca490de4b14e2a0a747b2a966beavboxsync * VBoxServiceControlSession - Guest session handling. Also handles
7f21d92108ecca490de4b14e2a0a747b2a966beavboxsync * the forked session processes.
7f21d92108ecca490de4b14e2a0a747b2a966beavboxsync * Copyright (C) 2013 Oracle Corporation
7f21d92108ecca490de4b14e2a0a747b2a966beavboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
7f21d92108ecca490de4b14e2a0a747b2a966beavboxsync * available from http://www.virtualbox.org. This file is free software;
7f21d92108ecca490de4b14e2a0a747b2a966beavboxsync * you can redistribute it and/or modify it under the terms of the GNU
7f21d92108ecca490de4b14e2a0a747b2a966beavboxsync * General Public License (GPL) as published by the Free Software
7f21d92108ecca490de4b14e2a0a747b2a966beavboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
7f21d92108ecca490de4b14e2a0a747b2a966beavboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
7f21d92108ecca490de4b14e2a0a747b2a966beavboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
7f21d92108ecca490de4b14e2a0a747b2a966beavboxsync/*******************************************************************************
7f21d92108ecca490de4b14e2a0a747b2a966beavboxsync* Header Files *
7f21d92108ecca490de4b14e2a0a747b2a966beavboxsync*******************************************************************************/
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncusing namespace guestControl;
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync/*******************************************************************************
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync* Externals *
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync*******************************************************************************/
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncextern int VBoxServiceLogCreate(const char *pszLogFile);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncextern void VBoxServiceLogDestroy(void);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync/*******************************************************************************
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync* Internal Functions *
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync*******************************************************************************/
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic int gstcntlSessionFileDestroy(PVBOXSERVICECTRLFILE pFile);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic int gstcntlSessionFileAdd(PVBOXSERVICECTRLSESSION pSession, PVBOXSERVICECTRLFILE pFile);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic PVBOXSERVICECTRLFILE gstcntlSessionFileGetLocked(const PVBOXSERVICECTRLSESSION pSession, uint32_t uHandle);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic DECLCALLBACK(int) gstcntlSessionThread(RTTHREAD ThreadSelf, void *pvUser);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync/* Host -> Guest handlers. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic int gstcntlSessionHandleDirRemove(PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic int gstcntlSessionHandleFileOpen(PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic int gstcntlSessionHandleFileClose(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic int gstcntlSessionHandleFileRead(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic int gstcntlSessionHandleFileWrite(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx, void *pvScratchBuf, size_t cbScratchBuf);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic int gstcntlSessionHandleFileSeek(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic int gstcntlSessionHandleFileTell(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic int gstcntlSessionHandlePathRename(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic int gstcntlSessionHandleProcExec(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic int gstcntlSessionHandleProcInput(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx, void *pvScratchBuf, size_t cbScratchBuf);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic int gstcntlSessionHandleProcOutput(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic int gstcntlSessionHandleProcTerminate(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic int gstcntlSessionHandleProcWaitFor(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync/** Generic option indices for session fork arguments. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync VBOXSERVICESESSIONOPT_FIRST = 1000, /* For initialization. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic int gstcntlSessionFileDestroy(PVBOXSERVICECTRLFILE pFile)
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /* Remove file entry in any case. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /* Destroy this object. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync/** @todo No locking done yet! */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic PVBOXSERVICECTRLFILE gstcntlSessionFileGetLocked(const PVBOXSERVICECTRLSESSION pSession,
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /** @todo Use a map later! */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync RTListForEach(&pSession->lstFiles, pFileCur, VBOXSERVICECTRLFILE, Node)
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic int gstcntlSessionHandleDirRemove(PVBOXSERVICECTRLSESSION pSession,
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /* Directory to remove. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /* Flags of type DIRREMOVE_FLAG_. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync bool fRecursive = false;
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /* Note: DIRREMOVE_FLAG_RECURSIVE must be set explicitly.
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync * Play safe here. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /* Setting direct value is intentional. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /* Setting direct value is intentional. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync VBoxServiceVerbose(4, "[Dir %s]: Removing with uFlags=0x%x, fRecursive=%RTbool\n",
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /** @todo Add own recursive function (or a new IPRT function w/ callback?) to
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync * provide guest-to-host progress reporting. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /* Report back in any case. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync VBoxServiceError("[Dir %s]: Failed to report removing status, rc=%Rrc\n",
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync VBoxServiceVerbose(4, "Removing directory \"%s\" returned rc=%Rrc\n",
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic int gstcntlSessionHandleFileOpen(PVBOXSERVICECTRLSESSION pSession,
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /* File to open. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /* Open mode. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /* Disposition. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /* Sharing. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /* Creation mode. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /* Offset. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync VBoxServiceVerbose(4, "[File %s]: szAccess=%s, szDisposition=%s, szSharing=%s, uOffset=%RU64, rc=%Rrc\n",
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync szFile, szAccess, szDisposition, szSharing, uOffset, rc);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync PVBOXSERVICECTRLFILE pFile = (PVBOXSERVICECTRLFILE)RTMemAllocZ(sizeof(VBOXSERVICECTRLFILE));
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync && !RTStrPrintf(pFile->szName, sizeof(pFile->szName), "%s", szFile))
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync VBoxServiceVerbose(4, "[File %s]: Opening flags=0x%x, rc=%Rrc\n",
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync rc = RTFileOpen(&pFile->hFile, pFile->szName, fFlags);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /* Seeking is optional. However, the whole operation
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync * will fail if we don't succeed seeking to the wanted position. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync rc = RTFileSeek(pFile->hFile, (int64_t)uOffset, RTFILE_SEEK_BEGIN, NULL /* Current offset */);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync VBoxServiceError("[File %s]: Seeking to offset %RU64 failed; rc=%Rrc\n",
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync VBoxServiceError("[File %s]: Opening failed; rc=%Rrc\n",
7f21d92108ecca490de4b14e2a0a747b2a966beavboxsync uHandle = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pHostCtx->uContextID);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /* rc = */ RTListAppend(&pSession->lstFiles, &pFile->Node);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync VBoxServiceVerbose(3, "[File %s]: Opened (ID=%RU32)\n",
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /* Report back in any case. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync int rc2 = VbglR3GuestCtrlFileCbOpen(pHostCtx, rc, uHandle);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync VBoxServiceError("[File %s]: Failed to report file open status, rc=%Rrc\n",
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync VBoxServiceVerbose(4, "Opening file \"%s\" (open mode=\"%s\", disposition=\"%s\", creation mode=0x%x returned rc=%Rrc\n",
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync szFile, szAccess, szDisposition, uCreationMode, rc);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic int gstcntlSessionHandleFileClose(const PVBOXSERVICECTRLSESSION pSession,
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync int rc = VbglR3GuestCtrlFileGetClose(pHostCtx, &uHandle /* File handle to close */);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync pFile = gstcntlSessionFileGetLocked(pSession, uHandle);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /* Report back in any case. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync int rc2 = VbglR3GuestCtrlFileCbClose(pHostCtx, rc);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync VBoxServiceError("Failed to report file close status, rc=%Rrc\n", rc2);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync VBoxServiceVerbose(4, "Closing file \"%s\" (handle=%RU32) returned rc=%Rrc\n",
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync pFile ? pFile->szName : "<Not found>", uHandle, rc);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsyncstatic int gstcntlSessionHandleFileRead(const PVBOXSERVICECTRLSESSION pSession,
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync int rc = VbglR3GuestCtrlFileGetRead(pHostCtx, &uHandle, &cbToRead);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync pFile = gstcntlSessionFileGetLocked(pSession, uHandle);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync rc = RTFileRead(pFile->hFile, pvDataRead, cbToRead, &cbRead);
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync /* Report back in any case. */
8810985701f1c6beb8f74c235c216e18b67192b0vboxsync int rc2 = VbglR3GuestCtrlFileCbRead(pHostCtx, rc, pvDataRead, (uint32_t)cbRead);
&& pvDataRead)
#ifdef DEBUG
return rc;
if (pFile)
if (cbToRead)
if (!pvDataRead)
&& pvDataRead)
#ifdef DEBUG
return rc;
&cbToWrite);
if (pFile)
#ifdef DEBUG
VBoxServiceVerbose(4, "[File %s]: Writing pvScratchBuf=%p, cbToWrite=%RU32, cbWritten=%zu, rc=%Rrc\n",
#ifdef DEBUG
return rc;
if (pFile)
#ifdef DEBUG
VBoxServiceVerbose(4, "[File %s]: Writing iOffset=%RI64, pvScratchBuf=%p, cbToWrite=%RU32, cbWritten=%zu, rc=%Rrc\n",
#ifdef DEBUG
return rc;
if (pFile)
unsigned uSeekMethodIPRT;
switch (uSeekMethod)
case GUEST_FILE_SEEKTYPE_END:
#ifdef DEBUG
#ifdef DEBUG
return rc;
if (pFile)
#ifdef DEBUG
#ifdef DEBUG
return rc;
&uFlags);
#ifdef DEBUG
return rc;
VBoxServiceVerbose(3, "Request to start process szCmd=%s, uFlags=0x%x, szArgs=%s, szEnv=%s, uTimeout=%RU32\n",
if (fStartAllowed)
return rc;
VBoxServiceError("Too much process input received, rejecting: uPID=%RU32, cbSize=%RU32, cbScratchBuf=%RU32\n",
bool fPendingClose = false;
fPendingClose = true;
#ifdef DEBUG
if (pProcess)
#ifdef DEBUG
return rc;
#ifdef DEBUG_andy
if (pProcess)
#ifdef DEBUG_andy
return rc;
if (pProcess)
#ifdef DEBUG_andy
return rc;
if (pProcess)
return rc;
volatile bool *pfShutdown)
switch (uMsg)
case HOST_SESSION_CLOSE:
case HOST_DIR_REMOVE:
case HOST_EXEC_CMD:
case HOST_EXEC_SET_INPUT:
case HOST_EXEC_GET_OUTPUT:
case HOST_EXEC_TERMINATE:
case HOST_EXEC_WAIT_FOR:
case HOST_FILE_OPEN:
case HOST_FILE_CLOSE:
case HOST_FILE_READ:
case HOST_FILE_READ_AT:
case HOST_FILE_WRITE:
case HOST_FILE_WRITE_AT:
case HOST_FILE_SEEK:
case HOST_FILE_TELL:
case HOST_PATH_RENAME:
return rc;
return rc;
bool fProcessAlive = true;
int rcWait;
fProcessAlive = false;
if (!u64TimeoutStart)
VBoxServiceVerbose(3, "Guest session ID=%RU32 thread was asked to terminate, waiting for session process to exit (%RU32ms timeout) ...\n",
if (!fProcessAlive)
VBoxServiceVerbose(2, "Guest session ID=%RU32 process terminated with rc=%Rrc, reason=%ld, status=%d\n",
if (fProcessAlive)
case RTPROCEXITREASON_NORMAL:
case RTPROCEXITREASON_ABEND:
case RTPROCEXITREASON_SIGNAL:
VBoxServiceVerbose(3, "Guest session ID=%RU32 thread ended with sessionStatus=%RU32, sessionRc=%Rrc\n",
return rc;
bool fSessionFilter = true;
fSessionFilter = false;
VBGLR3GUESTCTRLCMDCTX ctx = { uClientID, VBOX_GUESTCTRL_CONTEXTID_MAKE_SESSION(pSession->StartupInfo.uSessionID) };
if (!pvScratchBuf)
bool fShutdown = false;
#ifdef DEBUG
VBoxServiceVerbose(4, "Message requires %RU32 parameters, but only 2 supplied -- retrying request (no error!)...\n", cParms);
VBoxServiceVerbose(3, "Getting host message failed with %Rrc\n", rc); /* VERR_GEN_IO_FAILURE seems to be normal if ran into timeout. */
if (fShutdown)
if (pvScratchBuf)
if (uClientID)
PVBOXSERVICECTRLPROCESS GstCntlSessionRetainProcess(PVBOXSERVICECTRLSESSION pSession, uint32_t uPID)
return pProcess;
cProcesses++;
while (pProcess)
if (fLast)
#ifdef DEBUG
while (pProcess)
if (fLast)
while (pFile)
if (fLast)
return rc;
return rc;
return rc;
return VINF_SUCCESS;
return VINF_SUCCESS;
bool *pbAllowed)
bool fLimitReached = false;
if (iProcsLeft < 0)
fLimitReached = true;
return rc;
#ifdef DEBUG
return VERR_ALREADY_EXISTS;
if (pSessionThread)
sizeof(VBOXSERVICECTRLSESSIONSTARTUPINFO));
if (fAnonymous)
VBoxServiceVerbose(3, "New anonymous guest session ID=%RU32 created, uFlags=%x, using protocol %RU32\n",
VBoxServiceVerbose(3, "Forking new guest session ID=%RU32, szUser=%s, szPassword=%s, szDomain=%s, uFlags=%x, using protocol %RU32\n",
#ifdef DEBUG
if (pszExeName)
if (!fAnonymous)
if (!RTStrPrintf(szParmUserName, sizeof(szParmUserName), "--user=%s", pSessionThread->StartupInfo.szUser))
if (RT_SUCCESS(rc) && !RTStrPrintf(szParmSessionProto, sizeof(szParmSessionProto), "--session-proto=%RU32",
#ifdef DEBUG
#ifdef DEBUG
if (!fAnonymous)
if (pszLogFile)
char *pszLogNewSuffix;
#ifndef DEBUG
if (pszLogSuff)
#ifdef DEBUG
iOptIdx = 0;
return rc;
pThread));
return VERR_NOT_FOUND;
int rcThread;
return rc;
return rc;
while (pSessionThread)
if (fLast)
return rc;
#ifdef DEBUG
#ifdef DEBUG
int ch;
switch (ch)
#ifdef DEBUG
#ifdef DEBUG
g_cVerbosity++;
case VINF_GETOPT_NOT_OPTION:
return rcExit;