VirtualBox

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

Last change on this file since 105130 was 105130, checked in by vboxsync, 5 months ago

Main: Fix build errors after r163757; bugref:10310

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