VirtualBox

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

最後變更 在這個檔案從104692是 104618,由 vboxsync 提交於 10 月 前

Fixed potential overwriting of certificates - bugref:10310

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

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