VirtualBox

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

Last change on this file since 104973 was 104745, checked in by vboxsync, 12 months ago

IPRT,Main: Reworked the newly introduced RTCrX509Certificate_Generate function. It's now called RTCrX509Certificate_GenerateSelfSignedRsa and takes a few more parameters. We still can't read the output it creates. Added a create-self-signed-rsa-cert command to RTSignTool for easy testing. bugref:10310

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.4 KB
Line 
1/* $Id: VRDEServerImpl.cpp 104745 2024-05-21 12:52:09Z 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 int vrc = mParent->i_calculateFullPath(strServerCertificate, strServerCertificate);
245 AssertRCReturn(vrc, vrc);
246
247 Utf8Str strServerPrivateKey("server_key_private.pem");
248 vrc = mParent->i_calculateFullPath(strServerPrivateKey, strServerPrivateKey);
249 AssertRCReturn(vrc, vrc);
250
251 vrc = RTCrX509Certificate_GenerateSelfSignedRsa(RTDIGESTTYPE_SHA1, 2048 /*cBits*/, 10 * 365 * RT_SEC_1DAY,
252 0 /*fKeyUsage*/, 0 /*fExtKeyUsage*/, NULL /*pvSubjectTodo*/,
253 strServerCertificate.c_str(), strServerPrivateKey.c_str(), NULL /*pErrInfo*/);
254 if (RT_SUCCESS(vrc))
255 {
256 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
257 mData.backup();
258
259/** @todo r=bird: These statements may trigger exceptions and leave
260 * dangling server_cert.pem & server_key_private.pem files around.
261 * Since we're not doing an active settings save here (problematic IIRC) there
262 * are probably hundreds more likely ways this could go belly up and leave those
263 * files behind.
264 *
265 * The problem is that the code relies on the _settings_ to decide whether they
266 * are there or not, and if no it creates them. If anything goes wrong before
267 * we can save settings, this function will fail to retify the situation because
268 * the file already exist and RTCrX509Certificate_GenerateSelfSignedRsa won't
269 * overwrite existing files.
270 *
271 * Klaus, some settings saving input required here!
272 */
273 mData->mapProperties["Security/Method"] = Utf8Str("TLS");
274 mData->mapProperties["Security/ServerCertificate"] = strServerCertificate;
275 mData->mapProperties["Security/ServerPrivateKey"] = strServerPrivateKey;
276
277 /* Done with the properties access. */
278 alock.release();
279 }
280 return vrc;
281}
282
283// IVRDEServer properties
284/////////////////////////////////////////////////////////////////////////////
285
286HRESULT VRDEServer::getEnabled(BOOL *aEnabled)
287{
288 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
289
290 *aEnabled = mData->fEnabled;
291
292 return S_OK;
293}
294
295HRESULT VRDEServer::setEnabled(BOOL aEnabled)
296{
297 /* the machine can also be in saved state for this property to change */
298 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
299 if (FAILED(adep.hrc())) return adep.hrc();
300
301 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
302
303 HRESULT hrc = S_OK;
304
305 if (mData->fEnabled != RT_BOOL(aEnabled))
306 {
307 mData.backup();
308 mData->fEnabled = RT_BOOL(aEnabled);
309
310 /* leave the lock before informing callbacks */
311 alock.release();
312
313 /*
314 * If TLS is not explicitly disabled and there is not an existing certificate
315 * then auto-generate a self-signed certificate for this VM.
316 */
317 Utf8Str strPath = mData->mapProperties["Security/ServerCertificate"];
318 if (aEnabled && strPath.isEmpty())
319 {
320 if (mData->mapProperties["Security/Method"] != "RDP")
321 {
322 int vrc = i_generateServerCertificate();
323 if (RT_FAILURE(vrc))
324 LogRel(("Failed to auto generate server key and certificate: (%Rrc)\n", vrc));
325 }
326 }
327
328 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
329 mParent->i_setModified(Machine::IsModified_VRDEServer);
330 mlock.release();
331
332 /* Avoid deadlock when i_onVRDEServerChange eventually calls SetExtraData. */
333 adep.release();
334
335 hrc = mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
336 if (FAILED(hrc))
337 {
338 /* Failed to enable/disable the server. Revert the internal state. */
339 adep.add();
340 if (SUCCEEDED(adep.hrc()))
341 {
342 alock.acquire();
343 mData->fEnabled = !RT_BOOL(aEnabled);
344 alock.release();
345 mlock.acquire();
346 mParent->i_setModified(Machine::IsModified_VRDEServer);
347 }
348 }
349 }
350
351 return hrc;
352}
353
354static int i_portParseNumber(uint16_t *pu16Port, const char *pszStart, const char *pszEnd)
355{
356 /* Gets a string of digits, converts to 16 bit port number.
357 * Note: pszStart <= pszEnd is expected, the string contains
358 * only digits and pszEnd points to the char after last
359 * digit.
360 */
361 size_t cch = (size_t)(pszEnd - pszStart);
362 if (cch > 0 && cch <= 5) /* Port is up to 5 decimal digits. */
363 {
364 unsigned uPort = 0;
365 while (pszStart != pszEnd)
366 {
367 uPort = uPort * 10 + (unsigned)(*pszStart - '0');
368 pszStart++;
369 }
370
371 if (uPort != 0 && uPort < 0x10000)
372 {
373 if (pu16Port)
374 *pu16Port = (uint16_t)uPort;
375 return VINF_SUCCESS;
376 }
377 }
378
379 return VERR_INVALID_PARAMETER;
380}
381
382static int i_vrdpServerVerifyPortsString(const com::Utf8Str &aPortRange)
383{
384 const char *pszPortRange = aPortRange.c_str();
385
386 if (!pszPortRange || *pszPortRange == 0) /* Reject empty string. */
387 return VERR_INVALID_PARAMETER;
388
389 /* The string should be like "1000-1010,1020,2000-2003" */
390 while (*pszPortRange)
391 {
392 const char *pszStart = pszPortRange;
393 const char *pszDash = NULL;
394 const char *pszEnd = pszStart;
395
396 while (*pszEnd && *pszEnd != ',')
397 {
398 if (*pszEnd == '-')
399 {
400 if (pszDash != NULL)
401 return VERR_INVALID_PARAMETER; /* More than one '-'. */
402
403 pszDash = pszEnd;
404 }
405 else if (!RT_C_IS_DIGIT(*pszEnd))
406 return VERR_INVALID_PARAMETER;
407
408 pszEnd++;
409 }
410
411 /* Update the next range pointer. */
412 pszPortRange = pszEnd;
413 if (*pszPortRange == ',')
414 {
415 pszPortRange++;
416 }
417
418 /* A probably valid range. Verify and parse it. */
419 int vrc;
420 if (pszDash)
421 {
422 vrc = i_portParseNumber(NULL, pszStart, pszDash);
423 if (RT_SUCCESS(vrc))
424 vrc = i_portParseNumber(NULL, pszDash + 1, pszEnd);
425 }
426 else
427 vrc = i_portParseNumber(NULL, pszStart, pszEnd);
428
429 if (RT_FAILURE(vrc))
430 return vrc;
431 }
432
433 return VINF_SUCCESS;
434}
435
436HRESULT VRDEServer::setVRDEProperty(const com::Utf8Str &aKey, const com::Utf8Str &aValue)
437{
438 LogFlowThisFunc(("\n"));
439
440 /* the machine can also be in saved state for this property to change */
441 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
442 if (FAILED(adep.hrc())) return adep.hrc();
443
444 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
445
446 /* Special processing for some "standard" properties. */
447 if (aKey == "TCP/Ports")
448 {
449 /* Verify the string. "0" means the default port. */
450 Utf8Str strPorts = aValue == "0"?
451 VRDP_DEFAULT_PORT_STR:
452 aValue;
453 int vrc = i_vrdpServerVerifyPortsString(strPorts);
454 if (RT_FAILURE(vrc))
455 return E_INVALIDARG;
456
457 if (strPorts != mData->mapProperties["TCP/Ports"])
458 {
459 /* Port value is not verified here because it is up to VRDP transport to
460 * use it. Specifying a wrong port number will cause a running server to
461 * stop. There is no fool proof here.
462 */
463 mData.backup();
464 mData->mapProperties["TCP/Ports"] = strPorts;
465
466 /* leave the lock before informing callbacks */
467 alock.release();
468
469 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
470 mParent->i_setModified(Machine::IsModified_VRDEServer);
471 mlock.release();
472
473 /* Avoid deadlock when i_onVRDEServerChange eventually calls SetExtraData. */
474 adep.release();
475
476 mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
477 }
478 }
479 else
480 {
481 /* Generic properties processing.
482 * Look up the old value first; if nothing's changed then do nothing.
483 */
484 Utf8Str strOldValue;
485
486 settings::StringsMap::const_iterator it = mData->mapProperties.find(aKey);
487 if (it != mData->mapProperties.end())
488 strOldValue = it->second;
489
490 if (strOldValue != aValue)
491 {
492 if (aValue.isEmpty())
493 mData->mapProperties.erase(aKey);
494 else
495 mData->mapProperties[aKey] = aValue;
496
497 /* leave the lock before informing callbacks */
498 alock.release();
499
500 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
501 mParent->i_setModified(Machine::IsModified_VRDEServer);
502 mlock.release();
503
504 /* Avoid deadlock when i_onVRDEServerChange eventually calls SetExtraData. */
505 adep.release();
506
507 mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
508 }
509 }
510
511 return S_OK;
512}
513
514HRESULT VRDEServer::getVRDEProperty(const com::Utf8Str &aKey, com::Utf8Str &aValue)
515{
516 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
517 settings::StringsMap::const_iterator it = mData->mapProperties.find(aKey);
518 if (it != mData->mapProperties.end())
519 aValue = it->second; // source is a Utf8Str
520 else if (aKey == "TCP/Ports")
521 aValue = VRDP_DEFAULT_PORT_STR;
522
523 return S_OK;
524}
525
526/*
527 * Work around clang being unhappy about PFNVRDESUPPORTEDPROPERTIES
528 * ("exception specifications are not allowed beyond a single level of
529 * indirection"). The original comment for 13.0 check said: "assuming
530 * this issue will be fixed eventually". Well, 13.0 is now out, and
531 * it was not.
532 */
533#define CLANG_EXCEPTION_SPEC_HACK (RT_CLANG_PREREQ(11, 0) /* && !RT_CLANG_PREREQ(13, 0) */)
534
535#if CLANG_EXCEPTION_SPEC_HACK
536static int loadVRDELibrary(const char *pszLibraryName, RTLDRMOD *phmod, void *ppfn)
537#else
538static int loadVRDELibrary(const char *pszLibraryName, RTLDRMOD *phmod, PFNVRDESUPPORTEDPROPERTIES *ppfn)
539#endif
540{
541 int vrc = VINF_SUCCESS;
542
543 RTLDRMOD hmod = NIL_RTLDRMOD;
544
545 RTERRINFOSTATIC ErrInfo;
546 RTErrInfoInitStatic(&ErrInfo);
547 if (RTPathHavePath(pszLibraryName))
548 vrc = SUPR3HardenedLdrLoadPlugIn(pszLibraryName, &hmod, &ErrInfo.Core);
549 else
550 vrc = SUPR3HardenedLdrLoadAppPriv(pszLibraryName, &hmod, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core);
551 if (RT_SUCCESS(vrc))
552 {
553 vrc = RTLdrGetSymbol(hmod, "VRDESupportedProperties", (void **)ppfn);
554
555 if (RT_FAILURE(vrc) && vrc != VERR_SYMBOL_NOT_FOUND)
556 LogRel(("VRDE: Error resolving symbol '%s', vrc %Rrc.\n", "VRDESupportedProperties", vrc));
557 }
558 else
559 {
560 if (RTErrInfoIsSet(&ErrInfo.Core))
561 LogRel(("VRDE: Error loading the library '%s': %s (%Rrc)\n", pszLibraryName, ErrInfo.Core.pszMsg, vrc));
562 else
563 LogRel(("VRDE: Error loading the library '%s' vrc = %Rrc.\n", pszLibraryName, vrc));
564
565 hmod = NIL_RTLDRMOD;
566 }
567
568 if (RT_SUCCESS(vrc))
569 *phmod = hmod;
570 else
571 {
572 if (hmod != NIL_RTLDRMOD)
573 {
574 RTLdrClose(hmod);
575 hmod = NIL_RTLDRMOD;
576 }
577 }
578
579 return vrc;
580}
581
582HRESULT VRDEServer::getVRDEProperties(std::vector<com::Utf8Str> &aProperties)
583{
584 size_t cProperties = 0;
585 aProperties.resize(0);
586 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
587 if (!mData->fEnabled)
588 {
589 return S_OK;
590 }
591 alock.release();
592
593 /*
594 * Check that a VRDE extension pack name is set and resolve it into a
595 * library path.
596 */
597 Bstr bstrExtPack;
598 HRESULT hrc = COMGETTER(VRDEExtPack)(bstrExtPack.asOutParam());
599 Log(("VRDEPROP: get extpack hrc 0x%08X, isEmpty %d\n", hrc, bstrExtPack.isEmpty()));
600 if (FAILED(hrc))
601 return hrc;
602 if (bstrExtPack.isEmpty())
603 return E_FAIL;
604
605 Utf8Str strExtPack(bstrExtPack);
606 Utf8Str strVrdeLibrary;
607 int vrc = VINF_SUCCESS;
608 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
609 strVrdeLibrary = "VBoxVRDP";
610 else
611 {
612#ifdef VBOX_WITH_EXTPACK
613 VirtualBox *pVirtualBox = mParent->i_getVirtualBox();
614 ExtPackManager *pExtPackMgr = pVirtualBox->i_getExtPackManager();
615 vrc = pExtPackMgr->i_getVrdeLibraryPathForExtPack(&strExtPack, &strVrdeLibrary);
616#else
617 vrc = VERR_FILE_NOT_FOUND;
618#endif
619 }
620 Log(("VRDEPROP: library get vrc %Rrc\n", vrc));
621
622 if (RT_SUCCESS(vrc))
623 {
624 /*
625 * Load the VRDE library and start the server, if it is enabled.
626 */
627 PFNVRDESUPPORTEDPROPERTIES pfn = NULL;
628 RTLDRMOD hmod = NIL_RTLDRMOD;
629#if CLANG_EXCEPTION_SPEC_HACK
630 vrc = loadVRDELibrary(strVrdeLibrary.c_str(), &hmod, (void **)&pfn);
631#else
632 vrc = loadVRDELibrary(strVrdeLibrary.c_str(), &hmod, &pfn);
633#endif
634 Log(("VRDEPROP: load library [%s] vrc %Rrc\n", strVrdeLibrary.c_str(), vrc));
635 if (RT_SUCCESS(vrc))
636 {
637 const char * const *papszNames = pfn();
638
639 if (papszNames)
640 {
641 size_t i;
642 for (i = 0; papszNames[i] != NULL; ++i)
643 {
644 cProperties++;
645 }
646 }
647 Log(("VRDEPROP: %d properties\n", cProperties));
648
649 if (cProperties > 0)
650 {
651 aProperties.resize(cProperties);
652 for (size_t i = 0; i < cProperties && papszNames[i] != NULL; ++i)
653 {
654 aProperties[i] = papszNames[i];
655 }
656 }
657
658 /* Do not forget to unload the library. */
659 RTLdrClose(hmod);
660 hmod = NIL_RTLDRMOD;
661 }
662 }
663
664 if (RT_FAILURE(vrc))
665 {
666 return E_FAIL;
667 }
668
669 return S_OK;
670}
671
672
673HRESULT VRDEServer::getAuthType(AuthType_T *aType)
674{
675 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
676
677 *aType = mData->authType;
678
679 return S_OK;
680}
681
682HRESULT VRDEServer::setAuthType(AuthType_T aType)
683{
684 /* the machine can also be in saved state for this property to change */
685 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
686 if (FAILED(adep.hrc())) return adep.hrc();
687
688 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
689
690 if (mData->authType != aType)
691 {
692 mData.backup();
693 mData->authType = aType;
694
695 /* leave the lock before informing callbacks */
696 alock.release();
697
698 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
699 mParent->i_setModified(Machine::IsModified_VRDEServer);
700 mlock.release();
701
702 mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
703 }
704
705 return S_OK;
706}
707
708HRESULT VRDEServer::getAuthTimeout(ULONG *aTimeout)
709{
710 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
711
712 *aTimeout = mData->ulAuthTimeout;
713
714 return S_OK;
715}
716
717
718HRESULT VRDEServer::setAuthTimeout(ULONG aTimeout)
719{
720 /* the machine can also be in saved state for this property to change */
721 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
722 if (FAILED(adep.hrc())) return adep.hrc();
723
724 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
725
726 if (aTimeout != mData->ulAuthTimeout)
727 {
728 mData.backup();
729 mData->ulAuthTimeout = aTimeout;
730
731 /* leave the lock before informing callbacks */
732 alock.release();
733
734 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
735 mParent->i_setModified(Machine::IsModified_VRDEServer);
736 mlock.release();
737
738 /* sunlover 20060131: This setter does not require the notification
739 * really */
740#if 0
741 mParent->onVRDEServerChange();
742#endif
743 }
744
745 return S_OK;
746}
747
748HRESULT VRDEServer::getAuthLibrary(com::Utf8Str &aLibrary)
749{
750 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
751 aLibrary = mData->strAuthLibrary;
752 alock.release();
753
754 if (aLibrary.isEmpty())
755 {
756 /* Get the global setting. */
757 ComPtr<ISystemProperties> systemProperties;
758 HRESULT hrc = mParent->i_getVirtualBox()->COMGETTER(SystemProperties)(systemProperties.asOutParam());
759 if (SUCCEEDED(hrc))
760 {
761 Bstr strlib;
762 hrc = systemProperties->COMGETTER(VRDEAuthLibrary)(strlib.asOutParam());
763 if (SUCCEEDED(hrc))
764 aLibrary = Utf8Str(strlib).c_str();
765 }
766
767 if (FAILED(hrc))
768 return setError(hrc, tr("failed to query the library setting\n"));
769 }
770
771 return S_OK;
772}
773
774
775HRESULT VRDEServer::setAuthLibrary(const com::Utf8Str &aLibrary)
776{
777 /* the machine can also be in saved state for this property to change */
778 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
779 if (FAILED(adep.hrc())) return adep.hrc();
780
781 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
782
783 if (mData->strAuthLibrary != aLibrary)
784 {
785 mData.backup();
786 mData->strAuthLibrary = aLibrary;
787
788 /* leave the lock before informing callbacks */
789 alock.release();
790
791 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
792 mParent->i_setModified(Machine::IsModified_VRDEServer);
793 mlock.release();
794
795 mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
796 }
797
798 return S_OK;
799}
800
801
802HRESULT VRDEServer::getAllowMultiConnection(BOOL *aAllowMultiConnection)
803{
804 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
805
806 *aAllowMultiConnection = mData->fAllowMultiConnection;
807
808 return S_OK;
809}
810
811
812HRESULT VRDEServer::setAllowMultiConnection(BOOL aAllowMultiConnection)
813{
814 /* the machine can also be in saved state for this property to change */
815 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
816 if (FAILED(adep.hrc())) return adep.hrc();
817
818 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
819
820 if (mData->fAllowMultiConnection != RT_BOOL(aAllowMultiConnection))
821 {
822 mData.backup();
823 mData->fAllowMultiConnection = RT_BOOL(aAllowMultiConnection);
824
825 /* leave the lock before informing callbacks */
826 alock.release();
827
828 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
829 mParent->i_setModified(Machine::IsModified_VRDEServer);
830 mlock.release();
831
832 mParent->i_onVRDEServerChange(/* aRestart */ TRUE); /// @todo does it need a restart?
833 }
834
835 return S_OK;
836}
837
838HRESULT VRDEServer::getReuseSingleConnection(BOOL *aReuseSingleConnection)
839{
840 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
841
842 *aReuseSingleConnection = mData->fReuseSingleConnection;
843
844 return S_OK;
845}
846
847
848HRESULT VRDEServer::setReuseSingleConnection(BOOL aReuseSingleConnection)
849{
850 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
851 if (FAILED(adep.hrc())) return adep.hrc();
852
853 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
854
855 if (mData->fReuseSingleConnection != RT_BOOL(aReuseSingleConnection))
856 {
857 mData.backup();
858 mData->fReuseSingleConnection = RT_BOOL(aReuseSingleConnection);
859
860 /* leave the lock before informing callbacks */
861 alock.release();
862
863 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
864 mParent->i_setModified(Machine::IsModified_VRDEServer);
865 mlock.release();
866
867 mParent->i_onVRDEServerChange(/* aRestart */ TRUE); /// @todo needs a restart?
868 }
869
870 return S_OK;
871}
872
873HRESULT VRDEServer::getVRDEExtPack(com::Utf8Str &aExtPack)
874{
875 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
876 Utf8Str strExtPack = mData->strVrdeExtPack;
877 alock.release();
878 HRESULT hrc = S_OK;
879
880 if (strExtPack.isNotEmpty())
881 {
882 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
883 hrc = S_OK;
884 else
885 {
886#ifdef VBOX_WITH_EXTPACK
887 ExtPackManager *pExtPackMgr = mParent->i_getVirtualBox()->i_getExtPackManager();
888 hrc = pExtPackMgr->i_checkVrdeExtPack(&strExtPack);
889#else
890 hrc = setError(E_FAIL, tr("Extension pack '%s' does not exist"), strExtPack.c_str());
891#endif
892 }
893 if (SUCCEEDED(hrc))
894 aExtPack = strExtPack;
895 }
896 else
897 {
898 /* Get the global setting. */
899 ComPtr<ISystemProperties> systemProperties;
900 hrc = mParent->i_getVirtualBox()->COMGETTER(SystemProperties)(systemProperties.asOutParam());
901 if (SUCCEEDED(hrc))
902 {
903 Bstr bstr;
904 hrc = systemProperties->COMGETTER(DefaultVRDEExtPack)(bstr.asOutParam());
905 if (SUCCEEDED(hrc))
906 aExtPack = bstr;
907 }
908 }
909 return hrc;
910}
911
912// public methods only for internal purposes
913/////////////////////////////////////////////////////////////////////////////
914HRESULT VRDEServer::setVRDEExtPack(const com::Utf8Str &aExtPack)
915{
916 HRESULT hrc = S_OK;
917 /* the machine can also be in saved state for this property to change */
918 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
919 hrc = adep.hrc();
920 if (SUCCEEDED(hrc))
921 {
922 /*
923 * If not empty, check the specific extension pack.
924 */
925 if (!aExtPack.isEmpty())
926 {
927 if (aExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
928 hrc = S_OK;
929 else
930 {
931#ifdef VBOX_WITH_EXTPACK
932 ExtPackManager *pExtPackMgr = mParent->i_getVirtualBox()->i_getExtPackManager();
933 hrc = pExtPackMgr->i_checkVrdeExtPack(&aExtPack);
934#else
935 hrc = setError(E_FAIL, tr("Extension pack '%s' does not exist"), aExtPack.c_str());
936#endif
937 }
938 }
939 if (SUCCEEDED(hrc))
940 {
941 /*
942 * Update the setting if there is an actual change, post an
943 * change event to trigger a VRDE server restart.
944 */
945 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
946 if (aExtPack != mData->strVrdeExtPack)
947 {
948 mData.backup();
949 mData->strVrdeExtPack = aExtPack;
950
951 /* leave the lock before informing callbacks */
952 alock.release();
953
954 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
955 mParent->i_setModified(Machine::IsModified_VRDEServer);
956 mlock.release();
957
958 mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
959 }
960 }
961 }
962
963 return hrc;
964}
965
966// public methods only for internal purposes
967/////////////////////////////////////////////////////////////////////////////
968
969/**
970 * @note Locks this object for writing.
971 */
972void VRDEServer::i_rollback()
973{
974 /* sanity */
975 AutoCaller autoCaller(this);
976 AssertComRCReturnVoid(autoCaller.hrc());
977
978 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
979
980 mData.rollback();
981}
982
983/**
984 * @note Locks this object for writing, together with the peer object (also
985 * for writing) if there is one.
986 */
987void VRDEServer::i_commit()
988{
989 /* sanity */
990 AutoCaller autoCaller(this);
991 AssertComRCReturnVoid(autoCaller.hrc());
992
993 /* sanity too */
994 AutoCaller peerCaller(mPeer);
995 AssertComRCReturnVoid(peerCaller.hrc());
996
997 /* lock both for writing since we modify both (mPeer is "master" so locked
998 * first) */
999 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
1000
1001 if (mData.isBackedUp())
1002 {
1003 mData.commit();
1004 if (mPeer)
1005 {
1006 /* attach new data to the peer and reshare it */
1007 mPeer->mData.attach(mData);
1008 }
1009 }
1010}
1011
1012/**
1013 * @note Locks this object for writing, together with the peer object
1014 * represented by @a aThat (locked for reading).
1015 */
1016void VRDEServer::i_copyFrom(VRDEServer *aThat)
1017{
1018 AssertReturnVoid(aThat != NULL);
1019
1020 /* sanity */
1021 AutoCaller autoCaller(this);
1022 AssertComRCReturnVoid(autoCaller.hrc());
1023
1024 /* sanity too */
1025 AutoCaller thatCaller(aThat);
1026 AssertComRCReturnVoid(thatCaller.hrc());
1027
1028 /* peer is not modified, lock it for reading (aThat is "master" so locked
1029 * first) */
1030 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
1031 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
1032
1033 /* this will back up current data */
1034 mData.assignCopy(aThat->mData);
1035}
1036/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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