VirtualBox

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

最後變更 在這個檔案從108422是 108149,由 vboxsync 提交於 5 週 前

Main/src-server: removed VRDE server certificate generation from getVRDEProperty() ticketref:22259 bugref:10310

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