VirtualBox

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

Last change on this file since 36454 was 36454, checked in by vboxsync, 14 years ago

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

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.7 KB
Line 
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 hr = S_OK; /* Just report back that everything is fine to prevent winlogon from stopping. */
156 break;
157 }
158
159 if (m_pPoller == NULL)
160 {
161 m_pPoller = new VBoxCredPoller();
162 Assert(m_pPoller);
163 if (false == m_pPoller->Initialize(this))
164 Log(("VBoxCredProv::SetUsageScenario: Could not initialize credentials poller thread!\n"));
165 }
166
167 if (m_pCred == NULL)
168 {
169 m_pCred = new VBoxCredential(this);
170
171 /* All stuff allocated? */
172 if (m_pCred != NULL)
173 {
174 hr = m_pCred->Initialize(m_cpUsageScenario,
175 s_rgCredProvFieldDescriptors,
176 s_rgFieldStatePairs);
177 }
178 else
179 {
180 hr = E_OUTOFMEMORY;
181 Log(("VBoxCredProv::SetUsageScenario: Out of memory!\n"));
182 }
183 }
184 else
185 {
186 /* All set up already! */
187 hr = S_OK;
188 }
189
190 /* If we did fail -> cleanup */
191 if (FAILED(hr))
192 {
193 if (m_pCred != NULL)
194 {
195 m_pCred->Release();
196 m_pCred = NULL;
197 }
198 }
199 break;
200
201 case CPUS_CHANGE_PASSWORD:
202 case CPUS_CREDUI:
203 case CPUS_PLAP:
204
205 hr = E_NOTIMPL;
206 break;
207
208 default:
209
210 hr = E_INVALIDARG;
211 break;
212 }
213
214 Log(("VBoxCredProv::SetUsageScenario returned 0x%08x (cpUS: %d, Flags: %ld)\n", hr, cpUsageScenario, dwFlags));
215 return hr;
216}
217
218
219/*
220 * SetSerialization takes the kind of buffer that you would normally return to LogonUI for
221 * an authentication attempt. It's the opposite of ICredentialProviderCredential::GetSerialization.
222 * GetSerialization is implement by a credential and serializes that credential. Instead,
223 * SetSerialization takes the serialization and uses it to create a credential.
224 *
225 * SetSerialization is called for two main scenarios. The first scenario is in the credUI case
226 * where it is prepopulating a tile with credentials that the user chose to store in the OS.
227 * The second situation is in a remote logon case where the remote client may wish to
228 * prepopulate a tile with a username, or in some cases, completely populate the tile and
229 * use it to logon without showing any UI.
230 */
231STDMETHODIMP VBoxCredProv::SetSerialization(const CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION *pcpCredentialSerialization)
232{
233 UNREFERENCED_PARAMETER(pcpCredentialSerialization);
234 return E_NOTIMPL;
235}
236
237
238/*
239 * Called by LogonUI to give you a callback. Providers often use the callback if they
240 * some event would cause them to need to change the set of tiles (visible UI elements)
241 * that they enumerated.
242 */
243HRESULT VBoxCredProv::Advise(ICredentialProviderEvents *pcpEvents,
244 UINT_PTR upAdviseContext)
245{
246 Log(("VBoxCredProv::Advise\n"));
247
248 if (m_pCredProvEvents != NULL)
249 m_pCredProvEvents->Release();
250
251 m_pCredProvEvents = pcpEvents;
252 Assert(m_pCredProvEvents);
253 m_pCredProvEvents->AddRef();
254
255 /*
256 * Save advice context for later use when binding to
257 * certain ICredentialProviderEvents events.
258 */
259 m_upAdviseContext = upAdviseContext;
260 return S_OK;
261}
262
263
264/* Called by LogonUI when the ICredentialProviderEvents callback is no longer valid. */
265HRESULT VBoxCredProv::UnAdvise()
266{
267 Log(("VBoxCredProv::UnAdvise\n"));
268 if (m_pCredProvEvents != NULL)
269 {
270 m_pCredProvEvents->Release();
271 m_pCredProvEvents = NULL;
272 }
273
274 return S_OK;
275}
276
277
278/*
279 * Called by LogonUI to determine the number of fields in your tiles. This
280 * does mean that all your tiles must have the same number of fields.
281 * This number must include both visible and invisible fields. If you want a tile
282 * to have different fields from the other tiles you enumerate for a given usage
283 * scenario you must include them all in this count and then hide/show them as desired
284 * using the field descriptors.
285 */
286HRESULT VBoxCredProv::GetFieldDescriptorCount(DWORD *pdwCount)
287{
288 Assert(pdwCount);
289 *pdwCount = SFI_NUM_FIELDS;
290
291 Log(("VBoxCredProv::GetFieldDescriptorCount: %ld\n", *pdwCount));
292 return S_OK;
293}
294
295
296/* Gets the field descriptor for a particular field. */
297HRESULT VBoxCredProv::GetFieldDescriptorAt(DWORD dwIndex,
298 CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR **ppcpFieldDescriptor)
299{
300 /* Verify dwIndex is a valid field */
301 HRESULT hr;
302 if ( dwIndex < SFI_NUM_FIELDS
303 && ppcpFieldDescriptor)
304 {
305 hr = FieldDescriptorCoAllocCopy(s_rgCredProvFieldDescriptors[dwIndex], ppcpFieldDescriptor);
306 }
307 else
308 {
309 hr = E_INVALIDARG;
310 }
311
312 Log(("VBoxCredProv::GetFieldDescriptorAt: hr=0x%08x, index=%ld, ppcpfd=%p\n",
313 hr, dwIndex, ppcpFieldDescriptor));
314 return hr;
315}
316
317
318/*
319 * Sets pdwCount to the number of tiles that we wish to show at this time.
320 * Sets pdwDefault to the index of the tile which should be used as the default.
321 *
322 * The default tile is the tile which will be shown in the zoomed view by default. If
323 * more than one provider specifies a default tile the behavior is the last used cred
324 * prov gets to specify the default tile to be displayed
325 *
326 * If *pbAutoLogonWithDefault is TRUE, LogonUI will immediately call GetSerialization
327 * on the credential you've specified as the default and will submit that credential
328 * for authentication without showing any further UI.
329 */
330HRESULT VBoxCredProv::GetCredentialCount(DWORD *pdwCount,
331 DWORD *pdwDefault,
332 BOOL *pbAutoLogonWithDefault)
333{
334 Assert(pdwCount);
335 Assert(pdwDefault);
336 Assert(pbAutoLogonWithDefault);
337
338 bool fGotCredentials = false;
339
340 /* Poller thread create/active? */
341 if ( m_pPoller
342 && m_pCred)
343 {
344 fGotCredentials = m_pPoller->QueryCredentials(m_pCred);
345 }
346
347 if (fGotCredentials)
348 {
349 *pdwCount = 1; /* This provider always has the same number of credentials (1). */
350 *pdwDefault = 0; /* The credential we provide is *always* at index 0! */
351 *pbAutoLogonWithDefault = TRUE; /* We always at least try to auto-login (if password is correct). */
352 }
353 else
354 {
355 *pdwCount = 0;
356 *pdwDefault = CREDENTIAL_PROVIDER_NO_DEFAULT;
357 *pbAutoLogonWithDefault = FALSE;
358 }
359
360 Log(("VBoxCredProv::GetCredentialCount: *pdwCount=%ld, *pdwDefault=%ld, *pbAutoLogonWithDefault=%s\n",
361 *pdwCount, *pdwDefault, *pbAutoLogonWithDefault ? "true" : "false"));
362 return S_OK;
363}
364
365
366/*
367 * Returns the credential at the index specified by dwIndex. This function is called by logonUI to enumerate
368 * the tiles.
369 */
370HRESULT VBoxCredProv::GetCredentialAt(DWORD dwIndex,
371 ICredentialProviderCredential **ppCredProvCredential)
372{
373 HRESULT hr;
374
375 Log(("VBoxCredProv::GetCredentialAt: Index=%ld, ppCredProvCredential=%p\n", dwIndex, ppCredProvCredential));
376
377 if (m_pCred == NULL)
378 {
379 Log(("VBoxCredProv::GetCredentialAt: No credentials available.\n"));
380 return E_INVALIDARG;
381 }
382
383 /* Validate parameters (we only have one credential). */
384 if( dwIndex == 0
385 && ppCredProvCredential)
386 {
387 hr = m_pCred->QueryInterface(IID_ICredentialProviderCredential,
388 reinterpret_cast<void**>(ppCredProvCredential));
389 }
390 else
391 {
392 Log(("VBoxCredProv::GetCredentialAt: More than one credential not supported!\n"));
393 hr = E_INVALIDARG;
394 }
395 return hr;
396}
397
398
399/* Do a credential re-enumeration if we got the event to do so. */
400void VBoxCredProv::OnCredentialsProvided()
401{
402 Log(("VBoxCredProv::OnCredentialsProvided\n"));
403
404 if (m_pCredProvEvents != NULL)
405 m_pCredProvEvents->CredentialsChanged(m_upAdviseContext);
406}
407
408
409/* Creates our provider. This happens *before* CTRL-ALT-DEL was pressed! */
410HRESULT VBoxCredProv_CreateInstance(REFIID riid, void** ppv)
411{
412 HRESULT hr;
413
414 VBoxCredProv* pProvider = new VBoxCredProv();
415 if (pProvider)
416 {
417 hr = pProvider->QueryInterface(riid, ppv);
418 pProvider->Release();
419 }
420 else
421 {
422 hr = E_OUTOFMEMORY;
423 }
424 return hr;
425}
426
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