VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/VRDEServerImpl.cpp@ 104570

Last change on this file since 104570 was 104570, checked in by vboxsync, 7 months ago

Make TLS default and auto-generate a certificate - bugref:10310

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.4 KB
Line 
1/* $Id: VRDEServerImpl.cpp 104570 2024-05-10 04:58:46Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#define LOG_GROUP LOG_GROUP_MAIN_VRDESERVER
29#include "VRDEServerImpl.h"
30#include "MachineImpl.h"
31#include "VirtualBoxImpl.h"
32#ifdef VBOX_WITH_EXTPACK
33# include "ExtPackManagerImpl.h"
34#endif
35
36#include <iprt/cpp/utils.h>
37#include <iprt/ctype.h>
38#include <iprt/ldr.h>
39#include <iprt/path.h>
40#include <iprt/crypto/x509.h>
41
42#include <VBox/err.h>
43#include <VBox/sup.h>
44#include <VBox/com/array.h>
45
46#include <VBox/RemoteDesktop/VRDE.h>
47
48#include "AutoStateDep.h"
49#include "AutoCaller.h"
50#include "Global.h"
51#include "LoggingNew.h"
52
53// defines
54/////////////////////////////////////////////////////////////////////////////
55#define VRDP_DEFAULT_PORT_STR "3389"
56
57// constructor / destructor
58/////////////////////////////////////////////////////////////////////////////
59
60VRDEServer::VRDEServer()
61 : mParent(NULL)
62{
63}
64
65VRDEServer::~VRDEServer()
66{
67}
68
69HRESULT VRDEServer::FinalConstruct()
70{
71 return BaseFinalConstruct();
72}
73
74void VRDEServer::FinalRelease()
75{
76 uninit();
77 BaseFinalRelease();
78}
79
80// public initializer/uninitializer for internal purposes only
81/////////////////////////////////////////////////////////////////////////////
82
83/**
84 * Initializes the VRDP server object.
85 *
86 * @param aParent Handle of the parent object.
87 */
88HRESULT VRDEServer::init(Machine *aParent)
89{
90 LogFlowThisFunc(("aParent=%p\n", aParent));
91
92 ComAssertRet(aParent, E_INVALIDARG);
93
94 /* Enclose the state transition NotReady->InInit->Ready */
95 AutoInitSpan autoInitSpan(this);
96 AssertReturn(autoInitSpan.isOk(), E_FAIL);
97
98 unconst(mParent) = aParent;
99 /* mPeer is left null */
100
101 mData.allocate();
102
103 mData->fEnabled = false;
104
105 /* Confirm a successful initialization */
106 autoInitSpan.setSucceeded();
107
108 return S_OK;
109}
110
111/**
112 * Initializes the object given another object
113 * (a kind of copy constructor). This object shares data with
114 * the object passed as an argument.
115 *
116 * @note This object must be destroyed before the original object
117 * it shares data with is destroyed.
118 *
119 * @note Locks @a aThat object for reading.
120 */
121HRESULT VRDEServer::init(Machine *aParent, VRDEServer *aThat)
122{
123 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
124
125 ComAssertRet(aParent && aThat, E_INVALIDARG);
126
127 /* Enclose the state transition NotReady->InInit->Ready */
128 AutoInitSpan autoInitSpan(this);
129 AssertReturn(autoInitSpan.isOk(), E_FAIL);
130
131 unconst(mParent) = aParent;
132 unconst(mPeer) = aThat;
133
134 AutoCaller thatCaller(aThat);
135 AssertComRCReturnRC(thatCaller.hrc());
136
137 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
138 mData.share(aThat->mData);
139
140 /* Confirm a successful initialization */
141 autoInitSpan.setSucceeded();
142
143 return S_OK;
144}
145
146/**
147 * Initializes the guest object given another guest object
148 * (a kind of copy constructor). This object makes a private copy of data
149 * of the original object passed as an argument.
150 *
151 * @note Locks @a aThat object for reading.
152 */
153HRESULT VRDEServer::initCopy(Machine *aParent, VRDEServer *aThat)
154{
155 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
156
157 ComAssertRet(aParent && aThat, E_INVALIDARG);
158
159 /* Enclose the state transition NotReady->InInit->Ready */
160 AutoInitSpan autoInitSpan(this);
161 AssertReturn(autoInitSpan.isOk(), E_FAIL);
162
163 unconst(mParent) = aParent;
164 /* mPeer is left null */
165
166 AutoCaller thatCaller(aThat);
167 AssertComRCReturnRC(thatCaller.hrc());
168
169 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
170 mData.attachCopy(aThat->mData);
171
172 /* Confirm a successful initialization */
173 autoInitSpan.setSucceeded();
174
175 return S_OK;
176}
177
178/**
179 * Uninitializes the instance and sets the ready flag to FALSE.
180 * Called either from FinalRelease() or by the parent when it gets destroyed.
181 */
182void VRDEServer::uninit()
183{
184 LogFlowThisFunc(("\n"));
185
186 /* Enclose the state transition Ready->InUninit->NotReady */
187 AutoUninitSpan autoUninitSpan(this);
188 if (autoUninitSpan.uninitDone())
189 return;
190
191 mData.free();
192
193 unconst(mPeer) = NULL;
194 unconst(mParent) = NULL;
195}
196
197/**
198 * Loads settings from the given machine node.
199 * May be called once right after this object creation.
200 *
201 * @param data Configuration settings.
202 *
203 * @note Locks this object for writing.
204 */
205HRESULT VRDEServer::i_loadSettings(const settings::VRDESettings &data)
206{
207 using namespace settings;
208
209 AutoCaller autoCaller(this);
210 AssertComRCReturnRC(autoCaller.hrc());
211
212 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
213 mData.assignCopy(&data);
214
215 return S_OK;
216}
217
218/**
219 * Saves settings to the given machine node.
220 *
221 * @param data Configuration settings.
222 *
223 * @note Locks this object for reading.
224 */
225HRESULT VRDEServer::i_saveSettings(settings::VRDESettings &data)
226{
227 AutoCaller autoCaller(this);
228 AssertComRCReturnRC(autoCaller.hrc());
229
230 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
231 data = *mData.data();
232
233 return S_OK;
234}
235
236/**
237 * Auto-generates a self-signed certificate for the VM.
238 *
239 * @note Locks this object for writing.
240*/
241int VRDEServer::i_generateServerCertificate()
242{
243 Utf8Str strServerCertificate = "server_cert.pem";
244 Utf8Str strServerPrivateKey = "server_key_private.pem";
245 mParent->i_calculateFullPath(strServerCertificate, strServerCertificate);
246 mParent->i_calculateFullPath(strServerPrivateKey, strServerPrivateKey);
247 const char *pszServerCertificate = strServerCertificate.c_str();
248 const char *pszServerPrivateKey = strServerPrivateKey.c_str();
249
250 int vrc = RTCrX509Certificate_Generate(pszServerCertificate, pszServerPrivateKey);
251
252 if (RT_SUCCESS(vrc))
253 {
254 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
255 mData.backup();
256
257 mData->mapProperties["Security/Method"] = Utf8Str("TLS");
258 mData->mapProperties["Security/ServerCertificate"] = strServerCertificate;
259 mData->mapProperties["Security/ServerPrivateKey"] = strServerPrivateKey;
260
261 /* Done with the properties access. */
262 alock.release();
263 }
264 return vrc;
265}
266
267// IVRDEServer properties
268/////////////////////////////////////////////////////////////////////////////
269
270HRESULT VRDEServer::getEnabled(BOOL *aEnabled)
271{
272 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
273
274 *aEnabled = mData->fEnabled;
275
276 return S_OK;
277}
278
279HRESULT VRDEServer::setEnabled(BOOL aEnabled)
280{
281 /* the machine can also be in saved state for this property to change */
282 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
283 if (FAILED(adep.hrc())) return adep.hrc();
284
285 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
286
287 HRESULT hrc = S_OK;
288
289 if (mData->fEnabled != RT_BOOL(aEnabled))
290 {
291 mData.backup();
292 mData->fEnabled = RT_BOOL(aEnabled);
293
294 /* leave the lock before informing callbacks */
295 alock.release();
296
297 /*
298 * If TLS is not explicitely disabled then auto-generate
299 * a self-signed certificate for this VM.
300 */
301 if (mData->mapProperties["Security/Method"] != "RDP")
302 {
303 int vrc = i_generateServerCertificate();
304 if (RT_FAILURE(vrc))
305 {
306 LogRel(("Failed to auto generate server key and certificate: (%Rrc)\n", vrc));
307 }
308 }
309
310 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
311 mParent->i_setModified(Machine::IsModified_VRDEServer);
312 mlock.release();
313
314 /* Avoid deadlock when i_onVRDEServerChange eventually calls SetExtraData. */
315 adep.release();
316
317 hrc = mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
318 if (FAILED(hrc))
319 {
320 /* Failed to enable/disable the server. Revert the internal state. */
321 adep.add();
322 if (SUCCEEDED(adep.hrc()))
323 {
324 alock.acquire();
325 mData->fEnabled = !RT_BOOL(aEnabled);
326 alock.release();
327 mlock.acquire();
328 mParent->i_setModified(Machine::IsModified_VRDEServer);
329 }
330 }
331 }
332
333 return hrc;
334}
335
336static int i_portParseNumber(uint16_t *pu16Port, const char *pszStart, const char *pszEnd)
337{
338 /* Gets a string of digits, converts to 16 bit port number.
339 * Note: pszStart <= pszEnd is expected, the string contains
340 * only digits and pszEnd points to the char after last
341 * digit.
342 */
343 size_t cch = (size_t)(pszEnd - pszStart);
344 if (cch > 0 && cch <= 5) /* Port is up to 5 decimal digits. */
345 {
346 unsigned uPort = 0;
347 while (pszStart != pszEnd)
348 {
349 uPort = uPort * 10 + (unsigned)(*pszStart - '0');
350 pszStart++;
351 }
352
353 if (uPort != 0 && uPort < 0x10000)
354 {
355 if (pu16Port)
356 *pu16Port = (uint16_t)uPort;
357 return VINF_SUCCESS;
358 }
359 }
360
361 return VERR_INVALID_PARAMETER;
362}
363
364static int i_vrdpServerVerifyPortsString(const com::Utf8Str &aPortRange)
365{
366 const char *pszPortRange = aPortRange.c_str();
367
368 if (!pszPortRange || *pszPortRange == 0) /* Reject empty string. */
369 return VERR_INVALID_PARAMETER;
370
371 /* The string should be like "1000-1010,1020,2000-2003" */
372 while (*pszPortRange)
373 {
374 const char *pszStart = pszPortRange;
375 const char *pszDash = NULL;
376 const char *pszEnd = pszStart;
377
378 while (*pszEnd && *pszEnd != ',')
379 {
380 if (*pszEnd == '-')
381 {
382 if (pszDash != NULL)
383 return VERR_INVALID_PARAMETER; /* More than one '-'. */
384
385 pszDash = pszEnd;
386 }
387 else if (!RT_C_IS_DIGIT(*pszEnd))
388 return VERR_INVALID_PARAMETER;
389
390 pszEnd++;
391 }
392
393 /* Update the next range pointer. */
394 pszPortRange = pszEnd;
395 if (*pszPortRange == ',')
396 {
397 pszPortRange++;
398 }
399
400 /* A probably valid range. Verify and parse it. */
401 int vrc;
402 if (pszDash)
403 {
404 vrc = i_portParseNumber(NULL, pszStart, pszDash);
405 if (RT_SUCCESS(vrc))
406 vrc = i_portParseNumber(NULL, pszDash + 1, pszEnd);
407 }
408 else
409 vrc = i_portParseNumber(NULL, pszStart, pszEnd);
410
411 if (RT_FAILURE(vrc))
412 return vrc;
413 }
414
415 return VINF_SUCCESS;
416}
417
418HRESULT VRDEServer::setVRDEProperty(const com::Utf8Str &aKey, const com::Utf8Str &aValue)
419{
420 LogFlowThisFunc(("\n"));
421
422 /* the machine can also be in saved state for this property to change */
423 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
424 if (FAILED(adep.hrc())) return adep.hrc();
425
426 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
427
428 /* Special processing for some "standard" properties. */
429 if (aKey == "TCP/Ports")
430 {
431 /* Verify the string. "0" means the default port. */
432 Utf8Str strPorts = aValue == "0"?
433 VRDP_DEFAULT_PORT_STR:
434 aValue;
435 int vrc = i_vrdpServerVerifyPortsString(strPorts);
436 if (RT_FAILURE(vrc))
437 return E_INVALIDARG;
438
439 if (strPorts != mData->mapProperties["TCP/Ports"])
440 {
441 /* Port value is not verified here because it is up to VRDP transport to
442 * use it. Specifying a wrong port number will cause a running server to
443 * stop. There is no fool proof here.
444 */
445 mData.backup();
446 mData->mapProperties["TCP/Ports"] = strPorts;
447
448 /* leave the lock before informing callbacks */
449 alock.release();
450
451 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
452 mParent->i_setModified(Machine::IsModified_VRDEServer);
453 mlock.release();
454
455 /* Avoid deadlock when i_onVRDEServerChange eventually calls SetExtraData. */
456 adep.release();
457
458 mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
459 }
460 }
461 else
462 {
463 /* Generic properties processing.
464 * Look up the old value first; if nothing's changed then do nothing.
465 */
466 Utf8Str strOldValue;
467
468 settings::StringsMap::const_iterator it = mData->mapProperties.find(aKey);
469 if (it != mData->mapProperties.end())
470 strOldValue = it->second;
471
472 if (strOldValue != aValue)
473 {
474 if (aValue.isEmpty())
475 mData->mapProperties.erase(aKey);
476 else
477 mData->mapProperties[aKey] = aValue;
478
479 /* leave the lock before informing callbacks */
480 alock.release();
481
482 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
483 mParent->i_setModified(Machine::IsModified_VRDEServer);
484 mlock.release();
485
486 /* Avoid deadlock when i_onVRDEServerChange eventually calls SetExtraData. */
487 adep.release();
488
489 mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
490 }
491 }
492
493 return S_OK;
494}
495
496HRESULT VRDEServer::getVRDEProperty(const com::Utf8Str &aKey, com::Utf8Str &aValue)
497{
498 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
499 settings::StringsMap::const_iterator it = mData->mapProperties.find(aKey);
500 if (it != mData->mapProperties.end())
501 aValue = it->second; // source is a Utf8Str
502 else if (aKey == "TCP/Ports")
503 aValue = VRDP_DEFAULT_PORT_STR;
504
505 return S_OK;
506}
507
508/*
509 * Work around clang being unhappy about PFNVRDESUPPORTEDPROPERTIES
510 * ("exception specifications are not allowed beyond a single level of
511 * indirection"). The original comment for 13.0 check said: "assuming
512 * this issue will be fixed eventually". Well, 13.0 is now out, and
513 * it was not.
514 */
515#define CLANG_EXCEPTION_SPEC_HACK (RT_CLANG_PREREQ(11, 0) /* && !RT_CLANG_PREREQ(13, 0) */)
516
517#if CLANG_EXCEPTION_SPEC_HACK
518static int loadVRDELibrary(const char *pszLibraryName, RTLDRMOD *phmod, void *ppfn)
519#else
520static int loadVRDELibrary(const char *pszLibraryName, RTLDRMOD *phmod, PFNVRDESUPPORTEDPROPERTIES *ppfn)
521#endif
522{
523 int vrc = VINF_SUCCESS;
524
525 RTLDRMOD hmod = NIL_RTLDRMOD;
526
527 RTERRINFOSTATIC ErrInfo;
528 RTErrInfoInitStatic(&ErrInfo);
529 if (RTPathHavePath(pszLibraryName))
530 vrc = SUPR3HardenedLdrLoadPlugIn(pszLibraryName, &hmod, &ErrInfo.Core);
531 else
532 vrc = SUPR3HardenedLdrLoadAppPriv(pszLibraryName, &hmod, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core);
533 if (RT_SUCCESS(vrc))
534 {
535 vrc = RTLdrGetSymbol(hmod, "VRDESupportedProperties", (void **)ppfn);
536
537 if (RT_FAILURE(vrc) && vrc != VERR_SYMBOL_NOT_FOUND)
538 LogRel(("VRDE: Error resolving symbol '%s', vrc %Rrc.\n", "VRDESupportedProperties", vrc));
539 }
540 else
541 {
542 if (RTErrInfoIsSet(&ErrInfo.Core))
543 LogRel(("VRDE: Error loading the library '%s': %s (%Rrc)\n", pszLibraryName, ErrInfo.Core.pszMsg, vrc));
544 else
545 LogRel(("VRDE: Error loading the library '%s' vrc = %Rrc.\n", pszLibraryName, vrc));
546
547 hmod = NIL_RTLDRMOD;
548 }
549
550 if (RT_SUCCESS(vrc))
551 *phmod = hmod;
552 else
553 {
554 if (hmod != NIL_RTLDRMOD)
555 {
556 RTLdrClose(hmod);
557 hmod = NIL_RTLDRMOD;
558 }
559 }
560
561 return vrc;
562}
563
564HRESULT VRDEServer::getVRDEProperties(std::vector<com::Utf8Str> &aProperties)
565{
566 size_t cProperties = 0;
567 aProperties.resize(0);
568 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
569 if (!mData->fEnabled)
570 {
571 return S_OK;
572 }
573 alock.release();
574
575 /*
576 * Check that a VRDE extension pack name is set and resolve it into a
577 * library path.
578 */
579 Bstr bstrExtPack;
580 HRESULT hrc = COMGETTER(VRDEExtPack)(bstrExtPack.asOutParam());
581 Log(("VRDEPROP: get extpack hrc 0x%08X, isEmpty %d\n", hrc, bstrExtPack.isEmpty()));
582 if (FAILED(hrc))
583 return hrc;
584 if (bstrExtPack.isEmpty())
585 return E_FAIL;
586
587 Utf8Str strExtPack(bstrExtPack);
588 Utf8Str strVrdeLibrary;
589 int vrc = VINF_SUCCESS;
590 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
591 strVrdeLibrary = "VBoxVRDP";
592 else
593 {
594#ifdef VBOX_WITH_EXTPACK
595 VirtualBox *pVirtualBox = mParent->i_getVirtualBox();
596 ExtPackManager *pExtPackMgr = pVirtualBox->i_getExtPackManager();
597 vrc = pExtPackMgr->i_getVrdeLibraryPathForExtPack(&strExtPack, &strVrdeLibrary);
598#else
599 vrc = VERR_FILE_NOT_FOUND;
600#endif
601 }
602 Log(("VRDEPROP: library get vrc %Rrc\n", vrc));
603
604 if (RT_SUCCESS(vrc))
605 {
606 /*
607 * Load the VRDE library and start the server, if it is enabled.
608 */
609 PFNVRDESUPPORTEDPROPERTIES pfn = NULL;
610 RTLDRMOD hmod = NIL_RTLDRMOD;
611#if CLANG_EXCEPTION_SPEC_HACK
612 vrc = loadVRDELibrary(strVrdeLibrary.c_str(), &hmod, (void **)&pfn);
613#else
614 vrc = loadVRDELibrary(strVrdeLibrary.c_str(), &hmod, &pfn);
615#endif
616 Log(("VRDEPROP: load library [%s] vrc %Rrc\n", strVrdeLibrary.c_str(), vrc));
617 if (RT_SUCCESS(vrc))
618 {
619 const char * const *papszNames = pfn();
620
621 if (papszNames)
622 {
623 size_t i;
624 for (i = 0; papszNames[i] != NULL; ++i)
625 {
626 cProperties++;
627 }
628 }
629 Log(("VRDEPROP: %d properties\n", cProperties));
630
631 if (cProperties > 0)
632 {
633 aProperties.resize(cProperties);
634 for (size_t i = 0; i < cProperties && papszNames[i] != NULL; ++i)
635 {
636 aProperties[i] = papszNames[i];
637 }
638 }
639
640 /* Do not forget to unload the library. */
641 RTLdrClose(hmod);
642 hmod = NIL_RTLDRMOD;
643 }
644 }
645
646 if (RT_FAILURE(vrc))
647 {
648 return E_FAIL;
649 }
650
651 return S_OK;
652}
653
654
655HRESULT VRDEServer::getAuthType(AuthType_T *aType)
656{
657 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
658
659 *aType = mData->authType;
660
661 return S_OK;
662}
663
664HRESULT VRDEServer::setAuthType(AuthType_T aType)
665{
666 /* the machine can also be in saved state for this property to change */
667 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
668 if (FAILED(adep.hrc())) return adep.hrc();
669
670 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
671
672 if (mData->authType != aType)
673 {
674 mData.backup();
675 mData->authType = aType;
676
677 /* leave the lock before informing callbacks */
678 alock.release();
679
680 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
681 mParent->i_setModified(Machine::IsModified_VRDEServer);
682 mlock.release();
683
684 mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
685 }
686
687 return S_OK;
688}
689
690HRESULT VRDEServer::getAuthTimeout(ULONG *aTimeout)
691{
692 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
693
694 *aTimeout = mData->ulAuthTimeout;
695
696 return S_OK;
697}
698
699
700HRESULT VRDEServer::setAuthTimeout(ULONG aTimeout)
701{
702 /* the machine can also be in saved state for this property to change */
703 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
704 if (FAILED(adep.hrc())) return adep.hrc();
705
706 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
707
708 if (aTimeout != mData->ulAuthTimeout)
709 {
710 mData.backup();
711 mData->ulAuthTimeout = aTimeout;
712
713 /* leave the lock before informing callbacks */
714 alock.release();
715
716 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
717 mParent->i_setModified(Machine::IsModified_VRDEServer);
718 mlock.release();
719
720 /* sunlover 20060131: This setter does not require the notification
721 * really */
722#if 0
723 mParent->onVRDEServerChange();
724#endif
725 }
726
727 return S_OK;
728}
729
730HRESULT VRDEServer::getAuthLibrary(com::Utf8Str &aLibrary)
731{
732 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
733 aLibrary = mData->strAuthLibrary;
734 alock.release();
735
736 if (aLibrary.isEmpty())
737 {
738 /* Get the global setting. */
739 ComPtr<ISystemProperties> systemProperties;
740 HRESULT hrc = mParent->i_getVirtualBox()->COMGETTER(SystemProperties)(systemProperties.asOutParam());
741 if (SUCCEEDED(hrc))
742 {
743 Bstr strlib;
744 hrc = systemProperties->COMGETTER(VRDEAuthLibrary)(strlib.asOutParam());
745 if (SUCCEEDED(hrc))
746 aLibrary = Utf8Str(strlib).c_str();
747 }
748
749 if (FAILED(hrc))
750 return setError(hrc, tr("failed to query the library setting\n"));
751 }
752
753 return S_OK;
754}
755
756
757HRESULT VRDEServer::setAuthLibrary(const com::Utf8Str &aLibrary)
758{
759 /* the machine can also be in saved state for this property to change */
760 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
761 if (FAILED(adep.hrc())) return adep.hrc();
762
763 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
764
765 if (mData->strAuthLibrary != aLibrary)
766 {
767 mData.backup();
768 mData->strAuthLibrary = aLibrary;
769
770 /* leave the lock before informing callbacks */
771 alock.release();
772
773 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
774 mParent->i_setModified(Machine::IsModified_VRDEServer);
775 mlock.release();
776
777 mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
778 }
779
780 return S_OK;
781}
782
783
784HRESULT VRDEServer::getAllowMultiConnection(BOOL *aAllowMultiConnection)
785{
786 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
787
788 *aAllowMultiConnection = mData->fAllowMultiConnection;
789
790 return S_OK;
791}
792
793
794HRESULT VRDEServer::setAllowMultiConnection(BOOL aAllowMultiConnection)
795{
796 /* the machine can also be in saved state for this property to change */
797 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
798 if (FAILED(adep.hrc())) return adep.hrc();
799
800 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
801
802 if (mData->fAllowMultiConnection != RT_BOOL(aAllowMultiConnection))
803 {
804 mData.backup();
805 mData->fAllowMultiConnection = RT_BOOL(aAllowMultiConnection);
806
807 /* leave the lock before informing callbacks */
808 alock.release();
809
810 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
811 mParent->i_setModified(Machine::IsModified_VRDEServer);
812 mlock.release();
813
814 mParent->i_onVRDEServerChange(/* aRestart */ TRUE); /// @todo does it need a restart?
815 }
816
817 return S_OK;
818}
819
820HRESULT VRDEServer::getReuseSingleConnection(BOOL *aReuseSingleConnection)
821{
822 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
823
824 *aReuseSingleConnection = mData->fReuseSingleConnection;
825
826 return S_OK;
827}
828
829
830HRESULT VRDEServer::setReuseSingleConnection(BOOL aReuseSingleConnection)
831{
832 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
833 if (FAILED(adep.hrc())) return adep.hrc();
834
835 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
836
837 if (mData->fReuseSingleConnection != RT_BOOL(aReuseSingleConnection))
838 {
839 mData.backup();
840 mData->fReuseSingleConnection = RT_BOOL(aReuseSingleConnection);
841
842 /* leave the lock before informing callbacks */
843 alock.release();
844
845 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
846 mParent->i_setModified(Machine::IsModified_VRDEServer);
847 mlock.release();
848
849 mParent->i_onVRDEServerChange(/* aRestart */ TRUE); /// @todo needs a restart?
850 }
851
852 return S_OK;
853}
854
855HRESULT VRDEServer::getVRDEExtPack(com::Utf8Str &aExtPack)
856{
857 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
858 Utf8Str strExtPack = mData->strVrdeExtPack;
859 alock.release();
860 HRESULT hrc = S_OK;
861
862 if (strExtPack.isNotEmpty())
863 {
864 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
865 hrc = S_OK;
866 else
867 {
868#ifdef VBOX_WITH_EXTPACK
869 ExtPackManager *pExtPackMgr = mParent->i_getVirtualBox()->i_getExtPackManager();
870 hrc = pExtPackMgr->i_checkVrdeExtPack(&strExtPack);
871#else
872 hrc = setError(E_FAIL, tr("Extension pack '%s' does not exist"), strExtPack.c_str());
873#endif
874 }
875 if (SUCCEEDED(hrc))
876 aExtPack = strExtPack;
877 }
878 else
879 {
880 /* Get the global setting. */
881 ComPtr<ISystemProperties> systemProperties;
882 hrc = mParent->i_getVirtualBox()->COMGETTER(SystemProperties)(systemProperties.asOutParam());
883 if (SUCCEEDED(hrc))
884 {
885 Bstr bstr;
886 hrc = systemProperties->COMGETTER(DefaultVRDEExtPack)(bstr.asOutParam());
887 if (SUCCEEDED(hrc))
888 aExtPack = bstr;
889 }
890 }
891 return hrc;
892}
893
894// public methods only for internal purposes
895/////////////////////////////////////////////////////////////////////////////
896HRESULT VRDEServer::setVRDEExtPack(const com::Utf8Str &aExtPack)
897{
898 HRESULT hrc = S_OK;
899 /* the machine can also be in saved state for this property to change */
900 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
901 hrc = adep.hrc();
902 if (SUCCEEDED(hrc))
903 {
904 /*
905 * If not empty, check the specific extension pack.
906 */
907 if (!aExtPack.isEmpty())
908 {
909 if (aExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
910 hrc = S_OK;
911 else
912 {
913#ifdef VBOX_WITH_EXTPACK
914 ExtPackManager *pExtPackMgr = mParent->i_getVirtualBox()->i_getExtPackManager();
915 hrc = pExtPackMgr->i_checkVrdeExtPack(&aExtPack);
916#else
917 hrc = setError(E_FAIL, tr("Extension pack '%s' does not exist"), aExtPack.c_str());
918#endif
919 }
920 }
921 if (SUCCEEDED(hrc))
922 {
923 /*
924 * Update the setting if there is an actual change, post an
925 * change event to trigger a VRDE server restart.
926 */
927 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
928 if (aExtPack != mData->strVrdeExtPack)
929 {
930 mData.backup();
931 mData->strVrdeExtPack = aExtPack;
932
933 /* leave the lock before informing callbacks */
934 alock.release();
935
936 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
937 mParent->i_setModified(Machine::IsModified_VRDEServer);
938 mlock.release();
939
940 mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
941 }
942 }
943 }
944
945 return hrc;
946}
947
948// public methods only for internal purposes
949/////////////////////////////////////////////////////////////////////////////
950
951/**
952 * @note Locks this object for writing.
953 */
954void VRDEServer::i_rollback()
955{
956 /* sanity */
957 AutoCaller autoCaller(this);
958 AssertComRCReturnVoid(autoCaller.hrc());
959
960 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
961
962 mData.rollback();
963}
964
965/**
966 * @note Locks this object for writing, together with the peer object (also
967 * for writing) if there is one.
968 */
969void VRDEServer::i_commit()
970{
971 /* sanity */
972 AutoCaller autoCaller(this);
973 AssertComRCReturnVoid(autoCaller.hrc());
974
975 /* sanity too */
976 AutoCaller peerCaller(mPeer);
977 AssertComRCReturnVoid(peerCaller.hrc());
978
979 /* lock both for writing since we modify both (mPeer is "master" so locked
980 * first) */
981 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
982
983 if (mData.isBackedUp())
984 {
985 mData.commit();
986 if (mPeer)
987 {
988 /* attach new data to the peer and reshare it */
989 mPeer->mData.attach(mData);
990 }
991 }
992}
993
994/**
995 * @note Locks this object for writing, together with the peer object
996 * represented by @a aThat (locked for reading).
997 */
998void VRDEServer::i_copyFrom(VRDEServer *aThat)
999{
1000 AssertReturnVoid(aThat != NULL);
1001
1002 /* sanity */
1003 AutoCaller autoCaller(this);
1004 AssertComRCReturnVoid(autoCaller.hrc());
1005
1006 /* sanity too */
1007 AutoCaller thatCaller(aThat);
1008 AssertComRCReturnVoid(thatCaller.hrc());
1009
1010 /* peer is not modified, lock it for reading (aThat is "master" so locked
1011 * first) */
1012 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
1013 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
1014
1015 /* this will back up current data */
1016 mData.assignCopy(aThat->mData);
1017}
1018/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette