VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxCredProv/VBoxCredProv.cpp@ 36453

最後變更 在這個檔案從36453是 36453,由 vboxsync 提交於 14 年 前

VBoxCredProv: Implemented support for handling/ignoring remote (desktop) sessions.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 12.6 KB
 
1//
2// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
3// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
4// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
5// PARTICULAR PURPOSE.
6//
7// Copyright (c) 2006 Microsoft Corporation. All rights reserved.
8//
9// Modifications (c) 2009-2011 Oracle Corporation
10//
11
12#include <credentialprovider.h>
13
14#include <iprt/err.h>
15#include <VBox/VBoxGuestLib.h>
16
17#include "VBoxCredProv.h"
18#include "VBoxCredential.h"
19#include "guid.h"
20
21
22VBoxCredProv::VBoxCredProv(void) :
23 m_cRef(1),
24 m_pPoller(NULL),
25 m_pCred(NULL),
26 m_pCredProvEvents(NULL),
27 m_fGotCredentials(false),
28 m_fHandleRemoteSessions(false)
29{
30 LONG l = DllAddRef();
31
32 int rc = RTR3Init(); /* Never terminate the runtime! */
33 if (RT_FAILURE(rc))
34 LogRel(("VBoxCredProv: Could not init runtime! rc = %Rrc\n", rc));
35 rc = VbglR3Init();
36 if (RT_FAILURE(rc))
37 LogRel(("VBoxCredProv: Could not init guest library! rc = %Rrc\n", rc));
38
39 if (l == 1) /* First instance? */
40 LogRel(("VBoxCredProv: Loaded.\n"));
41 Log(("VBoxCredProv: DLL refcount (load) = %ld\n", l));
42}
43
44
45VBoxCredProv::~VBoxCredProv(void)
46{
47 Log(("VBoxCredProv::~VBoxCredProv\n"));
48
49 if (m_pCred != NULL)
50 {
51 m_pCred->Release();
52 m_pCred = NULL;
53 }
54
55 if (m_pPoller != NULL)
56 {
57 m_pPoller->Shutdown();
58 delete m_pPoller;
59 m_pPoller = NULL;
60 }
61
62 LONG lRefCount = DllGetRefCount();
63 if (lRefCount == 1) /* First (=last) instance unloaded? */
64 LogRel(("VBoxCredProv: Unloaded.\n"));
65 Log(("VBoxCredProv: DLL refcount (unload) = %ld\n", lRefCount));
66
67 VbglR3Term();
68 DllRelease();
69}
70
71
72/**
73 * Loads the global configuration from registry.
74 *
75 * @return DWORD Windows error code.
76 */
77DWORD VBoxCredProv::LoadConfiguration(void)
78{
79 HKEY hKey;
80 /** @todo Add some registry wrapper function(s) as soon as we got more values to retrieve. */
81 DWORD dwRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Oracle\\VirtualBox Guest Additions\\AutoLogon",
82 0L, KEY_QUERY_VALUE, &hKey);
83 if (dwRet == ERROR_SUCCESS)
84 {
85 DWORD dwValue;
86 DWORD dwType = REG_DWORD;
87 DWORD dwSize = sizeof(DWORD);
88
89 dwRet = RegQueryValueEx(hKey, L"HandleRemoteSessions", NULL, &dwType, (LPBYTE)&dwValue, &dwSize);
90 if ( dwRet == ERROR_SUCCESS
91 && dwType == REG_DWORD
92 && dwSize == sizeof(DWORD))
93 {
94 m_fHandleRemoteSessions = true;
95 }
96 RegCloseKey(hKey);
97 }
98 /* Do not report back an error here yet. */
99 return ERROR_SUCCESS;
100}
101
102
103/**
104 * Determines whether we should handle the current session or not.
105 *
106 * @return bool true if we should handle this session, false if not.
107 */
108bool VBoxCredProv::HandleCurrentSession(void)
109{
110 bool fHandle = false;
111 if (isRemoteSession())
112 {
113 if (m_fHandleRemoteSessions) /* Force remote session handling. */
114 fHandle = true;
115 }
116 else /* No remote session. */
117 fHandle = true;
118 return fHandle;
119}
120
121
122/*
123 * SetUsageScenario is the provider's cue that it's going to be asked for tiles
124 * in a subsequent call. This call happens after the user pressed CTRL+ALT+DEL
125 * and we need to handle the CPUS_LOGON event.
126 */
127HRESULT VBoxCredProv::SetUsageScenario(CREDENTIAL_PROVIDER_USAGE_SCENARIO cpUsageScenario,
128 DWORD dwFlags)
129{
130 UNREFERENCED_PARAMETER(dwFlags);
131 HRESULT hr;
132 DWORD dwErr;
133
134 m_cpUsageScenario = cpUsageScenario;
135
136 /* Decide which scenarios to support here. Returning E_NOTIMPL simply tells the caller
137 * that we're not designed for that scenario. */
138 switch (m_cpUsageScenario)
139 {
140 case CPUS_LOGON:
141 case CPUS_UNLOCK_WORKSTATION:
142
143 dwErr = LoadConfiguration();
144 if (dwErr != ERROR_SUCCESS)
145 LogRel(("VBoxCredProv: Error while loading configuration, error=%ld\n", dwErr));
146 /* Do not stop running on a misconfigured system. */
147
148 /*
149 * If we're told to not handle the current session just bail out and let the
150 * user know.
151 */
152 if (!HandleCurrentSession())
153 {
154 LogRel(("VBoxCredProv: Handling of remote desktop sessions is disabled.\n"));
155 break;
156 }
157
158 if (m_pPoller == NULL)
159 {
160 m_pPoller = new VBoxCredPoller();
161 Assert(m_pPoller);
162 if (false == m_pPoller->Initialize(this))
163 Log(("VBoxCredProv::SetUsageScenario: Could not initialize credentials poller thread!\n"));
164 }
165
166 if (m_pCred == NULL)
167 {
168 m_pCred = new VBoxCredential(this);
169
170 /* All stuff allocated? */
171 if (m_pCred != NULL)
172 {
173 hr = m_pCred->Initialize(m_cpUsageScenario,
174 s_rgCredProvFieldDescriptors,
175 s_rgFieldStatePairs);
176 }
177 else
178 {
179 hr = E_OUTOFMEMORY;
180 Log(("VBoxCredProv::SetUsageScenario: Out of memory!\n"));
181 }
182 }
183 else
184 {
185 /* All set up already! */
186 hr = S_OK;
187 }
188
189 /* If we did fail -> cleanup */
190 if (FAILED(hr))
191 {
192 if (m_pCred != NULL)
193 {
194 m_pCred->Release();
195 m_pCred = NULL;
196 }
197 }
198 break;
199
200 case CPUS_CHANGE_PASSWORD:
201 case CPUS_CREDUI:
202 case CPUS_PLAP:
203
204 hr = E_NOTIMPL;
205 break;
206
207 default:
208
209 hr = E_INVALIDARG;
210 break;
211 }
212
213 Log(("VBoxCredProv::SetUsageScenario returned 0x%08x (cpUS: %d, Flags: %ld)\n", hr, cpUsageScenario, dwFlags));
214 return hr;
215}
216
217
218/*
219 * SetSerialization takes the kind of buffer that you would normally return to LogonUI for
220 * an authentication attempt. It's the opposite of ICredentialProviderCredential::GetSerialization.
221 * GetSerialization is implement by a credential and serializes that credential. Instead,
222 * SetSerialization takes the serialization and uses it to create a credential.
223 *
224 * SetSerialization is called for two main scenarios. The first scenario is in the credUI case
225 * where it is prepopulating a tile with credentials that the user chose to store in the OS.
226 * The second situation is in a remote logon case where the remote client may wish to
227 * prepopulate a tile with a username, or in some cases, completely populate the tile and
228 * use it to logon without showing any UI.
229 */
230STDMETHODIMP VBoxCredProv::SetSerialization(const CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION *pcpCredentialSerialization)
231{
232 UNREFERENCED_PARAMETER(pcpCredentialSerialization);
233 return E_NOTIMPL;
234}
235
236
237/*
238 * Called by LogonUI to give you a callback. Providers often use the callback if they
239 * some event would cause them to need to change the set of tiles (visible UI elements)
240 * that they enumerated.
241 */
242HRESULT VBoxCredProv::Advise(ICredentialProviderEvents *pcpEvents,
243 UINT_PTR upAdviseContext)
244{
245 Log(("VBoxCredProv::Advise\n"));
246
247 if (m_pCredProvEvents != NULL)
248 m_pCredProvEvents->Release();
249
250 m_pCredProvEvents = pcpEvents;
251 Assert(m_pCredProvEvents);
252 m_pCredProvEvents->AddRef();
253
254 /*
255 * Save advice context for later use when binding to
256 * certain ICredentialProviderEvents events.
257 */
258 m_upAdviseContext = upAdviseContext;
259 return S_OK;
260}
261
262
263/* Called by LogonUI when the ICredentialProviderEvents callback is no longer valid. */
264HRESULT VBoxCredProv::UnAdvise()
265{
266 Log(("VBoxCredProv::UnAdvise\n"));
267 if (m_pCredProvEvents != NULL)
268 {
269 m_pCredProvEvents->Release();
270 m_pCredProvEvents = NULL;
271 }
272
273 return S_OK;
274}
275
276
277/*
278 * Called by LogonUI to determine the number of fields in your tiles. This
279 * does mean that all your tiles must have the same number of fields.
280 * This number must include both visible and invisible fields. If you want a tile
281 * to have different fields from the other tiles you enumerate for a given usage
282 * scenario you must include them all in this count and then hide/show them as desired
283 * using the field descriptors.
284 */
285HRESULT VBoxCredProv::GetFieldDescriptorCount(DWORD *pdwCount)
286{
287 Assert(pdwCount);
288 *pdwCount = SFI_NUM_FIELDS;
289
290 Log(("VBoxCredProv::GetFieldDescriptorCount: %ld\n", *pdwCount));
291 return S_OK;
292}
293
294
295/* Gets the field descriptor for a particular field. */
296HRESULT VBoxCredProv::GetFieldDescriptorAt(DWORD dwIndex,
297 CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR **ppcpFieldDescriptor)
298{
299 /* Verify dwIndex is a valid field */
300 HRESULT hr;
301 if ( dwIndex < SFI_NUM_FIELDS
302 && ppcpFieldDescriptor)
303 {
304 hr = FieldDescriptorCoAllocCopy(s_rgCredProvFieldDescriptors[dwIndex], ppcpFieldDescriptor);
305 }
306 else
307 {
308 hr = E_INVALIDARG;
309 }
310
311 Log(("VBoxCredProv::GetFieldDescriptorAt: hr=0x%08x, index=%ld, ppcpfd=%p\n",
312 hr, dwIndex, ppcpFieldDescriptor));
313 return hr;
314}
315
316
317/*
318 * Sets pdwCount to the number of tiles that we wish to show at this time.
319 * Sets pdwDefault to the index of the tile which should be used as the default.
320 *
321 * The default tile is the tile which will be shown in the zoomed view by default. If
322 * more than one provider specifies a default tile the behavior is the last used cred
323 * prov gets to specify the default tile to be displayed
324 *
325 * If *pbAutoLogonWithDefault is TRUE, LogonUI will immediately call GetSerialization
326 * on the credential you've specified as the default and will submit that credential
327 * for authentication without showing any further UI.
328 */
329HRESULT VBoxCredProv::GetCredentialCount(DWORD *pdwCount,
330 DWORD *pdwDefault,
331 BOOL *pbAutoLogonWithDefault)
332{
333 Assert(pdwCount);
334 Assert(pdwDefault);
335 Assert(pbAutoLogonWithDefault);
336
337 bool fGotCredentials = false;
338
339 /* Poller thread create/active? */
340 if ( m_pPoller
341 && m_pCred)
342 {
343 fGotCredentials = m_pPoller->QueryCredentials(m_pCred);
344 }
345
346 if (fGotCredentials)
347 {
348 *pdwCount = 1; /* This provider always has the same number of credentials (1). */
349 *pdwDefault = 0; /* The credential we provide is *always* at index 0! */
350 *pbAutoLogonWithDefault = TRUE; /* We always at least try to auto-login (if password is correct). */
351 }
352 else
353 {
354 *pdwCount = 0;
355 *pdwDefault = CREDENTIAL_PROVIDER_NO_DEFAULT;
356 *pbAutoLogonWithDefault = FALSE;
357 }
358
359 Log(("VBoxCredProv::GetCredentialCount: *pdwCount=%ld, *pdwDefault=%ld, *pbAutoLogonWithDefault=%s\n",
360 *pdwCount, *pdwDefault, *pbAutoLogonWithDefault ? "true" : "false"));
361 return S_OK;
362}
363
364
365/*
366 * Returns the credential at the index specified by dwIndex. This function is called by logonUI to enumerate
367 * the tiles.
368 */
369HRESULT VBoxCredProv::GetCredentialAt(DWORD dwIndex,
370 ICredentialProviderCredential **ppCredProvCredential)
371{
372 HRESULT hr;
373
374 Log(("VBoxCredProv::GetCredentialAt: Index=%ld, ppCredProvCredential=%p\n", dwIndex, ppCredProvCredential));
375
376 if (m_pCred == NULL)
377 {
378 Log(("VBoxCredProv::GetCredentialAt: No credentials available.\n"));
379 return E_INVALIDARG;
380 }
381
382 /* Validate parameters (we only have one credential). */
383 if( dwIndex == 0
384 && ppCredProvCredential)
385 {
386 hr = m_pCred->QueryInterface(IID_ICredentialProviderCredential,
387 reinterpret_cast<void**>(ppCredProvCredential));
388 }
389 else
390 {
391 Log(("VBoxCredProv::GetCredentialAt: More than one credential not supported!\n"));
392 hr = E_INVALIDARG;
393 }
394 return hr;
395}
396
397
398/* Do a credential re-enumeration if we got the event to do so. */
399void VBoxCredProv::OnCredentialsProvided()
400{
401 Log(("VBoxCredProv::OnCredentialsProvided\n"));
402
403 if (m_pCredProvEvents != NULL)
404 m_pCredProvEvents->CredentialsChanged(m_upAdviseContext);
405}
406
407
408/* Creates our provider. This happens *before* CTRL-ALT-DEL was pressed! */
409HRESULT VBoxCredProv_CreateInstance(REFIID riid, void** ppv)
410{
411 HRESULT hr;
412
413 VBoxCredProv* pProvider = new VBoxCredProv();
414 if (pProvider)
415 {
416 hr = pProvider->QueryInterface(riid, ppv);
417 pProvider->Release();
418 }
419 else
420 {
421 hr = E_OUTOFMEMORY;
422 }
423 return hr;
424}
425
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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