[9360] | 1 | /* $Id: GuestCtrlImpl.cpp 47627 2013-08-09 08:31:24Z vboxsync $ */
|
---|
[1] | 2 | /** @file
|
---|
[35170] | 3 | * VirtualBox COM class implementation: Guest
|
---|
[1] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[45415] | 7 | * Copyright (C) 2006-2013 Oracle Corporation
|
---|
[1] | 8 | *
|
---|
| 9 | * This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
| 10 | * available from http://www.virtualbox.org. This file is free software;
|
---|
| 11 | * you can redistribute it and/or modify it under the terms of the GNU
|
---|
[5999] | 12 | * General Public License (GPL) as published by the Free Software
|
---|
| 13 | * Foundation, in version 2 as it comes in the "COPYING" file of the
|
---|
| 14 | * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
|
---|
| 15 | * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
|
---|
[1] | 16 | */
|
---|
| 17 |
|
---|
| 18 | #include "GuestImpl.h"
|
---|
[42354] | 19 | #include "GuestSessionImpl.h"
|
---|
[38085] | 20 | #include "GuestCtrlImplPrivate.h"
|
---|
[9360] | 21 |
|
---|
| 22 | #include "Global.h"
|
---|
[1] | 23 | #include "ConsoleImpl.h"
|
---|
[28132] | 24 | #include "ProgressImpl.h"
|
---|
[45415] | 25 | #include "VBoxEvents.h"
|
---|
[1] | 26 | #include "VMMDev.h"
|
---|
| 27 |
|
---|
[25860] | 28 | #include "AutoCaller.h"
|
---|
[1] | 29 |
|
---|
[21219] | 30 | #include <VBox/VMMDev.h>
|
---|
[27741] | 31 | #ifdef VBOX_WITH_GUEST_CONTROL
|
---|
| 32 | # include <VBox/com/array.h>
|
---|
[34831] | 33 | # include <VBox/com/ErrorInfo.h>
|
---|
[27741] | 34 | #endif
|
---|
[25346] | 35 | #include <iprt/cpp/utils.h>
|
---|
[33301] | 36 | #include <iprt/file.h>
|
---|
[27767] | 37 | #include <iprt/getopt.h>
|
---|
[33492] | 38 | #include <iprt/isofs.h>
|
---|
[32866] | 39 | #include <iprt/list.h>
|
---|
| 40 | #include <iprt/path.h>
|
---|
[35346] | 41 | #include <VBox/vmm/pgm.h>
|
---|
[1] | 42 |
|
---|
[33494] | 43 | #include <memory>
|
---|
| 44 |
|
---|
[42897] | 45 | #ifdef LOG_GROUP
|
---|
| 46 | #undef LOG_GROUP
|
---|
| 47 | #endif
|
---|
| 48 | #define LOG_GROUP LOG_GROUP_GUEST_CONTROL
|
---|
| 49 | #include <VBox/log.h>
|
---|
| 50 |
|
---|
| 51 |
|
---|
[1] | 52 | // public methods only for internal purposes
|
---|
| 53 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 54 |
|
---|
[28288] | 55 | #ifdef VBOX_WITH_GUEST_CONTROL
|
---|
[1] | 56 | /**
|
---|
[28286] | 57 | * Static callback function for receiving updates on guest control commands
|
---|
| 58 | * from the guest. Acts as a dispatcher for the actual class instance.
|
---|
[28233] | 59 | *
|
---|
| 60 | * @returns VBox status code.
|
---|
| 61 | *
|
---|
| 62 | * @todo
|
---|
| 63 | *
|
---|
| 64 | */
|
---|
[42864] | 65 | /* static */
|
---|
[37589] | 66 | DECLCALLBACK(int) Guest::notifyCtrlDispatcher(void *pvExtension,
|
---|
| 67 | uint32_t u32Function,
|
---|
[44863] | 68 | void *pvData,
|
---|
| 69 | uint32_t cbData)
|
---|
[28206] | 70 | {
|
---|
| 71 | using namespace guestControl;
|
---|
| 72 |
|
---|
| 73 | /*
|
---|
| 74 | * No locking, as this is purely a notification which does not make any
|
---|
| 75 | * changes to the object state.
|
---|
| 76 | */
|
---|
[42214] | 77 | LogFlowFunc(("pvExtension=%p, u32Function=%RU32, pvParms=%p, cbParms=%RU32\n",
|
---|
[44863] | 78 | pvExtension, u32Function, pvData, cbData));
|
---|
[28286] | 79 | ComObjPtr<Guest> pGuest = reinterpret_cast<Guest *>(pvExtension);
|
---|
[42214] | 80 | Assert(!pGuest.isNull());
|
---|
[28206] | 81 |
|
---|
[42214] | 82 | /*
|
---|
| 83 | * For guest control 2.0 using the legacy commands we need to do the following here:
|
---|
| 84 | * - Get the callback header to access the context ID
|
---|
| 85 | * - Get the context ID of the callback
|
---|
| 86 | * - Extract the session ID out of the context ID
|
---|
| 87 | * - Dispatch the whole stuff to the appropriate session (if still exists)
|
---|
| 88 | */
|
---|
[44863] | 89 | if (cbData != sizeof(VBOXGUESTCTRLHOSTCALLBACK))
|
---|
| 90 | return VERR_NOT_SUPPORTED;
|
---|
| 91 | PVBOXGUESTCTRLHOSTCALLBACK pSvcCb = (PVBOXGUESTCTRLHOSTCALLBACK)pvData;
|
---|
| 92 | AssertPtr(pSvcCb);
|
---|
[42214] | 93 |
|
---|
[44863] | 94 | if (!pSvcCb->mParms) /* At least context ID must be present. */
|
---|
| 95 | return VERR_INVALID_PARAMETER;
|
---|
[42214] | 96 |
|
---|
[44863] | 97 | uint32_t uContextID;
|
---|
| 98 | int rc = pSvcCb->mpaParms[0].getUInt32(&uContextID);
|
---|
| 99 | AssertMsgRC(rc, ("Unable to extract callback context ID, pvData=%p\n", pSvcCb));
|
---|
| 100 | if (RT_FAILURE(rc))
|
---|
| 101 | return rc;
|
---|
[42272] | 102 | #ifdef DEBUG
|
---|
[42897] | 103 | LogFlowFunc(("CID=%RU32, uSession=%RU32, uObject=%RU32, uCount=%RU32\n",
|
---|
[44863] | 104 | uContextID,
|
---|
| 105 | VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uContextID),
|
---|
| 106 | VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(uContextID),
|
---|
| 107 | VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID)));
|
---|
[42272] | 108 | #endif
|
---|
[42214] | 109 |
|
---|
[44863] | 110 | VBOXGUESTCTRLHOSTCBCTX ctxCb = { u32Function, uContextID };
|
---|
| 111 | rc = pGuest->dispatchToSession(&ctxCb, pSvcCb);
|
---|
[47627] | 112 |
|
---|
| 113 | LogFlowFunc(("Returning rc=%Rrc\n", rc));
|
---|
[28286] | 114 | return rc;
|
---|
| 115 | }
|
---|
[38290] | 116 | #endif /* VBOX_WITH_GUEST_CONTROL */
|
---|
[35455] | 117 |
|
---|
[47469] | 118 | STDMETHODIMP Guest::UpdateGuestAdditions(IN_BSTR aSource, ComSafeArrayIn(IN_BSTR, aArguments),
|
---|
[46526] | 119 | ComSafeArrayIn(AdditionsUpdateFlag_T, aFlags), IProgress **aProgress)
|
---|
[33492] | 120 | {
|
---|
| 121 | #ifndef VBOX_WITH_GUEST_CONTROL
|
---|
| 122 | ReturnComNotImplemented();
|
---|
| 123 | #else /* VBOX_WITH_GUEST_CONTROL */
|
---|
| 124 | CheckComArgStrNotEmptyOrNull(aSource);
|
---|
| 125 | CheckComArgOutPointerValid(aProgress);
|
---|
| 126 |
|
---|
| 127 | AutoCaller autoCaller(this);
|
---|
| 128 | if (FAILED(autoCaller.rc())) return autoCaller.rc();
|
---|
| 129 |
|
---|
[34398] | 130 | /* Validate flags. */
|
---|
[42693] | 131 | uint32_t fFlags = AdditionsUpdateFlag_None;
|
---|
[34398] | 132 | if (aFlags)
|
---|
| 133 | {
|
---|
[42693] | 134 | com::SafeArray<CopyFileFlag_T> flags(ComSafeArrayInArg(aFlags));
|
---|
| 135 | for (size_t i = 0; i < flags.size(); i++)
|
---|
| 136 | fFlags |= flags[i];
|
---|
| 137 | }
|
---|
| 138 |
|
---|
| 139 | if (fFlags)
|
---|
| 140 | {
|
---|
| 141 | if (!(fFlags & AdditionsUpdateFlag_WaitForUpdateStartOnly))
|
---|
[34398] | 142 | return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
|
---|
| 143 | }
|
---|
| 144 |
|
---|
[46524] | 145 | int rc = VINF_SUCCESS;
|
---|
| 146 |
|
---|
| 147 | ProcessArguments aArgs;
|
---|
| 148 | if (aArguments)
|
---|
| 149 | {
|
---|
| 150 | try
|
---|
| 151 | {
|
---|
| 152 | com::SafeArray<IN_BSTR> arguments(ComSafeArrayInArg(aArguments));
|
---|
| 153 | for (size_t i = 0; i < arguments.size(); i++)
|
---|
| 154 | aArgs.push_back(Utf8Str(arguments[i]));
|
---|
| 155 | }
|
---|
| 156 | catch(std::bad_alloc &)
|
---|
| 157 | {
|
---|
| 158 | rc = VERR_NO_MEMORY;
|
---|
| 159 | }
|
---|
| 160 | }
|
---|
| 161 |
|
---|
[42693] | 162 | HRESULT hr = S_OK;
|
---|
[42864] | 163 |
|
---|
[44935] | 164 | /*
|
---|
| 165 | * Create an anonymous session. This is required to run the Guest Additions
|
---|
| 166 | * update process with administrative rights.
|
---|
| 167 | */
|
---|
| 168 | GuestSessionStartupInfo startupInfo;
|
---|
| 169 | startupInfo.mName = "Updating Guest Additions";
|
---|
| 170 |
|
---|
| 171 | GuestCredentials guestCreds;
|
---|
| 172 | RT_ZERO(guestCreds);
|
---|
| 173 |
|
---|
[42693] | 174 | ComObjPtr<GuestSession> pSession;
|
---|
[46524] | 175 | if (RT_SUCCESS(rc))
|
---|
| 176 | rc = sessionCreate(startupInfo, guestCreds, pSession);
|
---|
[42693] | 177 | if (RT_FAILURE(rc))
|
---|
| 178 | {
|
---|
| 179 | switch (rc)
|
---|
| 180 | {
|
---|
| 181 | case VERR_MAX_PROCS_REACHED:
|
---|
[45415] | 182 | hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest sessions (%ld) reached"),
|
---|
[42693] | 183 | VBOX_GUESTCTRL_MAX_SESSIONS);
|
---|
| 184 | break;
|
---|
[33492] | 185 |
|
---|
[42693] | 186 | /** @todo Add more errors here. */
|
---|
| 187 |
|
---|
| 188 | default:
|
---|
| 189 | hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest session: %Rrc"), rc);
|
---|
| 190 | break;
|
---|
| 191 | }
|
---|
| 192 | }
|
---|
| 193 | else
|
---|
| 194 | {
|
---|
[42702] | 195 | Assert(!pSession.isNull());
|
---|
[44935] | 196 | int guestRc;
|
---|
[47469] | 197 | rc = pSession->startSessionInternal(&guestRc);
|
---|
[42693] | 198 | if (RT_FAILURE(rc))
|
---|
| 199 | {
|
---|
[44935] | 200 | /** @todo Handle guestRc! */
|
---|
| 201 |
|
---|
| 202 | hr = setError(VBOX_E_IPRT_ERROR, tr("Could not open guest session: %Rrc"), rc);
|
---|
[42693] | 203 | }
|
---|
| 204 | else
|
---|
| 205 | {
|
---|
[43170] | 206 | try
|
---|
[42693] | 207 | {
|
---|
[43170] | 208 | ComObjPtr<Progress> pProgress;
|
---|
| 209 | SessionTaskUpdateAdditions *pTask = new SessionTaskUpdateAdditions(pSession /* GuestSession */,
|
---|
[46524] | 210 | Utf8Str(aSource), aArgs, fFlags);
|
---|
[43170] | 211 | rc = pSession->startTaskAsync(tr("Updating Guest Additions"), pTask, pProgress);
|
---|
| 212 | if (RT_SUCCESS(rc))
|
---|
| 213 | {
|
---|
| 214 | /* Return progress to the caller. */
|
---|
| 215 | hr = pProgress.queryInterfaceTo(aProgress);
|
---|
| 216 | }
|
---|
| 217 | else
|
---|
| 218 | hr = setError(VBOX_E_IPRT_ERROR,
|
---|
| 219 | tr("Starting task for updating Guest Additions on the guest failed: %Rrc"), rc);
|
---|
[42693] | 220 | }
|
---|
[43170] | 221 | catch(std::bad_alloc &)
|
---|
| 222 | {
|
---|
| 223 | hr = E_OUTOFMEMORY;
|
---|
| 224 | }
|
---|
[42693] | 225 | }
|
---|
| 226 | }
|
---|
[42695] | 227 | return hr;
|
---|
[33492] | 228 | #endif /* VBOX_WITH_GUEST_CONTROL */
|
---|
| 229 | }
|
---|
[37375] | 230 |
|
---|
[42105] | 231 | // private methods
|
---|
| 232 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 233 |
|
---|
[44863] | 234 | int Guest::dispatchToSession(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
|
---|
[42214] | 235 | {
|
---|
[44863] | 236 | LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb));
|
---|
[42272] | 237 |
|
---|
[44863] | 238 | AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER);
|
---|
| 239 | AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
|
---|
| 240 |
|
---|
[44935] | 241 | LogFlowFunc(("uFunction=%RU32, uContextID=%RU32, uProtocol=%RU32\n",
|
---|
| 242 | pCtxCb->uFunction, pCtxCb->uContextID, pCtxCb->uProtocol));
|
---|
| 243 |
|
---|
[42214] | 244 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 245 |
|
---|
[44863] | 246 | uint32_t uSessionID = VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(pCtxCb->uContextID);
|
---|
[42436] | 247 | #ifdef DEBUG
|
---|
[44863] | 248 | LogFlowFunc(("uSessionID=%RU32 (%zu total)\n",
|
---|
[42436] | 249 | uSessionID, mData.mGuestSessions.size()));
|
---|
| 250 | #endif
|
---|
[42214] | 251 | GuestSessions::const_iterator itSession
|
---|
[42436] | 252 | = mData.mGuestSessions.find(uSessionID);
|
---|
[44863] | 253 |
|
---|
| 254 | int rc;
|
---|
[42214] | 255 | if (itSession != mData.mGuestSessions.end())
|
---|
| 256 | {
|
---|
| 257 | ComObjPtr<GuestSession> pSession(itSession->second);
|
---|
| 258 | Assert(!pSession.isNull());
|
---|
| 259 |
|
---|
| 260 | alock.release();
|
---|
[44863] | 261 |
|
---|
| 262 | bool fDispatch = true;
|
---|
| 263 | #ifdef DEBUG
|
---|
| 264 | /*
|
---|
| 265 | * Pre-check: If we got a status message with an error and VERR_TOO_MUCH_DATA
|
---|
| 266 | * it means that that guest could not handle the entire message
|
---|
| 267 | * because of its exceeding size. This should not happen on daily
|
---|
| 268 | * use but testcases might try this. It then makes no sense to dispatch
|
---|
| 269 | * this further because we don't have a valid context ID.
|
---|
| 270 | */
|
---|
| 271 | if ( pCtxCb->uFunction == GUEST_EXEC_STATUS
|
---|
| 272 | && pSvcCb->mParms >= 5)
|
---|
| 273 | {
|
---|
| 274 | CALLBACKDATA_PROC_STATUS dataCb;
|
---|
| 275 | /* pSvcCb->mpaParms[0] always contains the context ID. */
|
---|
| 276 | pSvcCb->mpaParms[1].getUInt32(&dataCb.uPID);
|
---|
| 277 | pSvcCb->mpaParms[2].getUInt32(&dataCb.uStatus);
|
---|
| 278 | pSvcCb->mpaParms[3].getUInt32(&dataCb.uFlags);
|
---|
| 279 | pSvcCb->mpaParms[4].getPointer(&dataCb.pvData, &dataCb.cbData);
|
---|
| 280 |
|
---|
| 281 | if ( (dataCb.uStatus == PROC_STS_ERROR)
|
---|
| 282 | && (dataCb.uFlags == VERR_TOO_MUCH_DATA))
|
---|
| 283 | {
|
---|
| 284 | LogFlowFunc(("Requested command with too much data, skipping dispatching ...\n"));
|
---|
| 285 |
|
---|
| 286 | Assert(dataCb.uPID == 0);
|
---|
| 287 | fDispatch = false;
|
---|
| 288 | }
|
---|
| 289 | }
|
---|
| 290 | #endif
|
---|
| 291 | if (fDispatch)
|
---|
| 292 | {
|
---|
| 293 | switch (pCtxCb->uFunction)
|
---|
| 294 | {
|
---|
| 295 | case GUEST_DISCONNECTED:
|
---|
[44935] | 296 | rc = pSession->dispatchToThis(pCtxCb, pSvcCb);
|
---|
| 297 | break;
|
---|
[44863] | 298 |
|
---|
| 299 | case GUEST_SESSION_NOTIFY:
|
---|
| 300 | rc = pSession->dispatchToThis(pCtxCb, pSvcCb);
|
---|
| 301 | break;
|
---|
| 302 |
|
---|
| 303 | case GUEST_EXEC_STATUS:
|
---|
| 304 | case GUEST_EXEC_OUTPUT:
|
---|
| 305 | case GUEST_EXEC_INPUT_STATUS:
|
---|
| 306 | case GUEST_EXEC_IO_NOTIFY:
|
---|
| 307 | rc = pSession->dispatchToProcess(pCtxCb, pSvcCb);
|
---|
| 308 | break;
|
---|
| 309 |
|
---|
| 310 | case GUEST_FILE_NOTIFY:
|
---|
| 311 | rc = pSession->dispatchToFile(pCtxCb, pSvcCb);
|
---|
| 312 | break;
|
---|
| 313 |
|
---|
| 314 | default:
|
---|
| 315 | rc = VERR_NOT_SUPPORTED;
|
---|
| 316 | break;
|
---|
| 317 | }
|
---|
| 318 | }
|
---|
| 319 | else
|
---|
| 320 | rc = VERR_NOT_FOUND;
|
---|
[42214] | 321 | }
|
---|
[42272] | 322 | else
|
---|
| 323 | rc = VERR_NOT_FOUND;
|
---|
| 324 |
|
---|
[47627] | 325 | LogFlowThisFunc(("Returning rc=%Rrc\n", rc));
|
---|
[42272] | 326 | return rc;
|
---|
[42214] | 327 | }
|
---|
| 328 |
|
---|
[42897] | 329 | int Guest::sessionRemove(GuestSession *pSession)
|
---|
[42084] | 330 | {
|
---|
[42897] | 331 | LogFlowThisFuncEnter();
|
---|
| 332 |
|
---|
[42105] | 333 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 334 |
|
---|
[42897] | 335 | int rc = VERR_NOT_FOUND;
|
---|
| 336 |
|
---|
| 337 | LogFlowFunc(("Closing session (ID=%RU32) ...\n", pSession->getId()));
|
---|
| 338 |
|
---|
[45415] | 339 | GuestSessions::iterator itSessions = mData.mGuestSessions.begin();
|
---|
| 340 | while (itSessions != mData.mGuestSessions.end())
|
---|
[42105] | 341 | {
|
---|
[42160] | 342 | if (pSession == itSessions->second)
|
---|
[42105] | 343 | {
|
---|
[47627] | 344 | /* Make sure to consume the pointer before the one of the
|
---|
| 345 | * iterator gets released. */
|
---|
| 346 | ComObjPtr<GuestSession> pCurSession = pSession;
|
---|
[47469] | 347 |
|
---|
[42897] | 348 | LogFlowFunc(("Removing session (pSession=%p, ID=%RU32) (now total %ld sessions)\n",
|
---|
[47627] | 349 | pSession, pSession->getId(), mData.mGuestSessions.size() - 1));
|
---|
[42897] | 350 |
|
---|
[47469] | 351 | itSessions->second->Release();
|
---|
| 352 |
|
---|
[45415] | 353 | mData.mGuestSessions.erase(itSessions);
|
---|
[42897] | 354 |
|
---|
[47627] | 355 | alock.release(); /* Release lock before firing off event. */
|
---|
| 356 |
|
---|
| 357 | fireGuestSessionRegisteredEvent(mEventSource, pCurSession,
|
---|
[45415] | 358 | false /* Unregistered */);
|
---|
[42897] | 359 | rc = VINF_SUCCESS;
|
---|
| 360 | break;
|
---|
[42105] | 361 | }
|
---|
[45415] | 362 |
|
---|
| 363 | itSessions++;
|
---|
[42105] | 364 | }
|
---|
| 365 |
|
---|
[47627] | 366 | LogFlowThisFunc(("Returning rc=%Rrc\n", rc));
|
---|
[42897] | 367 | return rc;
|
---|
[42105] | 368 | }
|
---|
| 369 |
|
---|
[44935] | 370 | int Guest::sessionCreate(const GuestSessionStartupInfo &ssInfo,
|
---|
| 371 | const GuestCredentials &guestCreds, ComObjPtr<GuestSession> &pGuestSession)
|
---|
[42160] | 372 | {
|
---|
| 373 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 374 |
|
---|
| 375 | int rc = VERR_MAX_PROCS_REACHED;
|
---|
[42272] | 376 | if (mData.mGuestSessions.size() >= VBOX_GUESTCTRL_MAX_SESSIONS)
|
---|
| 377 | return rc;
|
---|
| 378 |
|
---|
[42160] | 379 | try
|
---|
| 380 | {
|
---|
| 381 | /* Create a new session ID and assign it. */
|
---|
| 382 | uint32_t uNewSessionID = 0;
|
---|
| 383 | uint32_t uTries = 0;
|
---|
| 384 |
|
---|
| 385 | for (;;)
|
---|
| 386 | {
|
---|
[42272] | 387 | /* Is the context ID already used? */
|
---|
| 388 | if (!sessionExists(uNewSessionID))
|
---|
[42160] | 389 | {
|
---|
| 390 | rc = VINF_SUCCESS;
|
---|
| 391 | break;
|
---|
| 392 | }
|
---|
[42272] | 393 | uNewSessionID++;
|
---|
[42634] | 394 | if (uNewSessionID >= VBOX_GUESTCTRL_MAX_SESSIONS)
|
---|
| 395 | uNewSessionID = 0;
|
---|
[42160] | 396 |
|
---|
[44935] | 397 | if (++uTries == VBOX_GUESTCTRL_MAX_SESSIONS)
|
---|
[42160] | 398 | break; /* Don't try too hard. */
|
---|
| 399 | }
|
---|
| 400 | if (RT_FAILURE(rc)) throw rc;
|
---|
| 401 |
|
---|
| 402 | /* Create the session object. */
|
---|
| 403 | HRESULT hr = pGuestSession.createObject();
|
---|
| 404 | if (FAILED(hr)) throw VERR_COM_UNEXPECTED;
|
---|
| 405 |
|
---|
[44935] | 406 | /** @todo Use an overloaded copy operator. Later. */
|
---|
| 407 | GuestSessionStartupInfo startupInfo;
|
---|
| 408 | startupInfo.mID = uNewSessionID; /* Assign new session ID. */
|
---|
| 409 | startupInfo.mName = ssInfo.mName;
|
---|
| 410 | startupInfo.mOpenFlags = ssInfo.mOpenFlags;
|
---|
| 411 | startupInfo.mOpenTimeoutMS = ssInfo.mOpenTimeoutMS;
|
---|
| 412 |
|
---|
| 413 | GuestCredentials guestCredentials;
|
---|
| 414 | if (!guestCreds.mUser.isEmpty())
|
---|
| 415 | {
|
---|
| 416 | /** @todo Use an overloaded copy operator. Later. */
|
---|
| 417 | guestCredentials.mUser = guestCreds.mUser;
|
---|
| 418 | guestCredentials.mPassword = guestCreds.mPassword;
|
---|
| 419 | guestCredentials.mDomain = guestCreds.mDomain;
|
---|
| 420 | }
|
---|
| 421 | else
|
---|
| 422 | {
|
---|
| 423 | /* Internal (annonymous) session. */
|
---|
| 424 | startupInfo.mIsInternal = true;
|
---|
| 425 | }
|
---|
| 426 |
|
---|
| 427 | rc = pGuestSession->init(this, startupInfo, guestCredentials);
|
---|
[44863] | 428 | if (RT_FAILURE(rc)) throw rc;
|
---|
[42160] | 429 |
|
---|
[44863] | 430 | /*
|
---|
| 431 | * Add session object to our session map. This is necessary
|
---|
| 432 | * before calling openSession because the guest calls back
|
---|
[45415] | 433 | * with the creation result of this session.
|
---|
[44863] | 434 | */
|
---|
[42194] | 435 | mData.mGuestSessions[uNewSessionID] = pGuestSession;
|
---|
[42436] | 436 |
|
---|
[47627] | 437 | alock.release(); /* Release lock before firing off event. */
|
---|
| 438 |
|
---|
[45415] | 439 | fireGuestSessionRegisteredEvent(mEventSource, pGuestSession,
|
---|
| 440 | true /* Registered */);
|
---|
[42160] | 441 | }
|
---|
| 442 | catch (int rc2)
|
---|
| 443 | {
|
---|
| 444 | rc = rc2;
|
---|
| 445 | }
|
---|
| 446 |
|
---|
[47627] | 447 | LogFlowThisFunc(("Returning rc=%Rrc\n", rc));
|
---|
[42160] | 448 | return rc;
|
---|
| 449 | }
|
---|
| 450 |
|
---|
| 451 | inline bool Guest::sessionExists(uint32_t uSessionID)
|
---|
| 452 | {
|
---|
| 453 | GuestSessions::const_iterator itSessions = mData.mGuestSessions.find(uSessionID);
|
---|
| 454 | return (itSessions == mData.mGuestSessions.end()) ? false : true;
|
---|
| 455 | }
|
---|
| 456 |
|
---|
[42105] | 457 | // implementation of public methods
|
---|
| 458 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 459 |
|
---|
[47627] | 460 | STDMETHODIMP Guest::CreateSession(IN_BSTR aUser, IN_BSTR aPassword, IN_BSTR aDomain,
|
---|
| 461 | IN_BSTR aSessionName, IGuestSession **aGuestSession)
|
---|
[42105] | 462 | {
|
---|
[42084] | 463 | #ifndef VBOX_WITH_GUEST_CONTROL
|
---|
| 464 | ReturnComNotImplemented();
|
---|
| 465 | #else /* VBOX_WITH_GUEST_CONTROL */
|
---|
| 466 |
|
---|
[42214] | 467 | LogFlowFuncEnter();
|
---|
| 468 |
|
---|
[44935] | 469 | /* Do not allow anonymous sessions (with system rights) with public API. */
|
---|
[42084] | 470 | if (RT_UNLIKELY((aUser) == NULL || *(aUser) == '\0'))
|
---|
| 471 | return setError(E_INVALIDARG, tr("No user name specified"));
|
---|
[47469] | 472 | if (RT_UNLIKELY((aPassword) == NULL || *(aPassword) == '\0'))
|
---|
| 473 | return setError(E_INVALIDARG, tr("No password specified"));
|
---|
[42105] | 474 | CheckComArgOutPointerValid(aGuestSession);
|
---|
[42214] | 475 | /* Rest is optional. */
|
---|
[42084] | 476 |
|
---|
| 477 | AutoCaller autoCaller(this);
|
---|
| 478 | if (FAILED(autoCaller.rc())) return autoCaller.rc();
|
---|
| 479 |
|
---|
[44935] | 480 | GuestSessionStartupInfo startupInfo;
|
---|
| 481 | startupInfo.mName = aSessionName;
|
---|
[42214] | 482 |
|
---|
[44935] | 483 | GuestCredentials guestCreds;
|
---|
| 484 | guestCreds.mUser = aUser;
|
---|
| 485 | guestCreds.mPassword = aPassword;
|
---|
| 486 | guestCreds.mDomain = aDomain;
|
---|
| 487 |
|
---|
[42354] | 488 | ComObjPtr<GuestSession> pSession;
|
---|
[44935] | 489 | int rc = sessionCreate(startupInfo, guestCreds, pSession);
|
---|
[42354] | 490 | if (RT_SUCCESS(rc))
|
---|
| 491 | {
|
---|
| 492 | /* Return guest session to the caller. */
|
---|
| 493 | HRESULT hr2 = pSession.queryInterfaceTo(aGuestSession);
|
---|
| 494 | if (FAILED(hr2))
|
---|
| 495 | rc = VERR_COM_OBJECT_NOT_FOUND;
|
---|
| 496 | }
|
---|
[42214] | 497 |
|
---|
[44935] | 498 | if (RT_SUCCESS(rc))
|
---|
| 499 | {
|
---|
[45415] | 500 | /* Start (fork) the session asynchronously
|
---|
| 501 | * on the guest. */
|
---|
| 502 | rc = pSession->startSessionAsync();
|
---|
[44935] | 503 | }
|
---|
| 504 |
|
---|
| 505 | HRESULT hr = S_OK;
|
---|
| 506 |
|
---|
[42354] | 507 | if (RT_FAILURE(rc))
|
---|
| 508 | {
|
---|
| 509 | switch (rc)
|
---|
| 510 | {
|
---|
| 511 | case VERR_MAX_PROCS_REACHED:
|
---|
[45415] | 512 | hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest sessions (%ld) reached"),
|
---|
[42436] | 513 | VBOX_GUESTCTRL_MAX_SESSIONS);
|
---|
[42354] | 514 | break;
|
---|
| 515 |
|
---|
| 516 | /** @todo Add more errors here. */
|
---|
| 517 |
|
---|
[44935] | 518 | default:
|
---|
| 519 | hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest session: %Rrc"), rc);
|
---|
[42354] | 520 | break;
|
---|
| 521 | }
|
---|
| 522 | }
|
---|
| 523 |
|
---|
[47627] | 524 | LogFlowThisFunc(("Returning rc=%Rhrc\n", hr));
|
---|
[42214] | 525 | return hr;
|
---|
[42084] | 526 | #endif /* VBOX_WITH_GUEST_CONTROL */
|
---|
| 527 | }
|
---|
| 528 |
|
---|
[42411] | 529 | STDMETHODIMP Guest::FindSession(IN_BSTR aSessionName, ComSafeArrayOut(IGuestSession *, aSessions))
|
---|
| 530 | {
|
---|
[42546] | 531 | #ifndef VBOX_WITH_GUEST_CONTROL
|
---|
[42411] | 532 | ReturnComNotImplemented();
|
---|
[42546] | 533 | #else /* VBOX_WITH_GUEST_CONTROL */
|
---|
| 534 |
|
---|
| 535 | CheckComArgOutSafeArrayPointerValid(aSessions);
|
---|
| 536 |
|
---|
| 537 | LogFlowFuncEnter();
|
---|
| 538 |
|
---|
| 539 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 540 |
|
---|
| 541 | Utf8Str strName(aSessionName);
|
---|
| 542 | std::list < ComObjPtr<GuestSession> > listSessions;
|
---|
| 543 |
|
---|
| 544 | GuestSessions::const_iterator itSessions = mData.mGuestSessions.begin();
|
---|
| 545 | while (itSessions != mData.mGuestSessions.end())
|
---|
| 546 | {
|
---|
[42566] | 547 | if (strName.contains(itSessions->second->getName())) /** @todo Use a (simple) pattern match (IPRT?). */
|
---|
[42546] | 548 | listSessions.push_back(itSessions->second);
|
---|
| 549 | itSessions++;
|
---|
| 550 | }
|
---|
| 551 |
|
---|
| 552 | LogFlowFunc(("Sessions with \"%ls\" = %RU32\n",
|
---|
| 553 | aSessionName, listSessions.size()));
|
---|
| 554 |
|
---|
| 555 | if (listSessions.size())
|
---|
| 556 | {
|
---|
| 557 | SafeIfaceArray<IGuestSession> sessionIfacs(listSessions);
|
---|
| 558 | sessionIfacs.detachTo(ComSafeArrayOutArg(aSessions));
|
---|
| 559 |
|
---|
| 560 | return S_OK;
|
---|
| 561 | }
|
---|
| 562 |
|
---|
| 563 | return setErrorNoLog(VBOX_E_OBJECT_NOT_FOUND,
|
---|
| 564 | tr("Could not find sessions with name '%ls'"),
|
---|
| 565 | aSessionName);
|
---|
| 566 | #endif /* VBOX_WITH_GUEST_CONTROL */
|
---|
[42411] | 567 | }
|
---|
| 568 |
|
---|