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-2010 Oracle Corporation
|
---|
10 | //
|
---|
11 |
|
---|
12 | #ifndef WIN32_NO_STATUS
|
---|
13 | #include <ntstatus.h>
|
---|
14 | #define WIN32_NO_STATUS
|
---|
15 | #endif
|
---|
16 |
|
---|
17 | #include <iprt/string.h>
|
---|
18 |
|
---|
19 | #include "VBoxCredential.h"
|
---|
20 | #include "guid.h"
|
---|
21 |
|
---|
22 |
|
---|
23 | VBoxCredential::VBoxCredential() : m_cRef(1),
|
---|
24 | m_pCredProvCredentialEvents(NULL)
|
---|
25 | {
|
---|
26 | Log(("VBoxCredential::VBoxCredential\n"));
|
---|
27 |
|
---|
28 | DllAddRef();
|
---|
29 |
|
---|
30 | ZeroMemory(m_rgCredProvFieldDescriptors, sizeof(m_rgCredProvFieldDescriptors));
|
---|
31 | ZeroMemory(m_rgFieldStatePairs, sizeof(m_rgFieldStatePairs));
|
---|
32 | ZeroMemory(m_rgFieldStrings, sizeof(m_rgFieldStrings));
|
---|
33 | }
|
---|
34 |
|
---|
35 |
|
---|
36 | VBoxCredential::~VBoxCredential()
|
---|
37 | {
|
---|
38 | Log(("VBoxCredential::~VBoxCredential\n"));
|
---|
39 |
|
---|
40 | Reset();
|
---|
41 |
|
---|
42 | for (int i = 0; i < ARRAYSIZE(m_rgFieldStrings); i++)
|
---|
43 | {
|
---|
44 | CoTaskMemFree(m_rgFieldStrings[i]);
|
---|
45 | CoTaskMemFree(m_rgCredProvFieldDescriptors[i].pszLabel);
|
---|
46 | }
|
---|
47 |
|
---|
48 | DllRelease();
|
---|
49 | }
|
---|
50 |
|
---|
51 |
|
---|
52 | void VBoxCredential::Reset(void)
|
---|
53 | {
|
---|
54 | if (m_rgFieldStrings[SFI_PASSWORD])
|
---|
55 | {
|
---|
56 | // CoTaskMemFree (below) deals with NULL, but StringCchLength does not.
|
---|
57 | size_t lenPassword;
|
---|
58 | HRESULT hr = StringCchLengthW(m_rgFieldStrings[SFI_PASSWORD], 128, &(lenPassword));
|
---|
59 | if (SUCCEEDED(hr))
|
---|
60 | {
|
---|
61 | SecureZeroMemory(m_rgFieldStrings[SFI_PASSWORD], lenPassword * sizeof(*m_rgFieldStrings[SFI_PASSWORD]));
|
---|
62 | }
|
---|
63 | else
|
---|
64 | {
|
---|
65 | // TODO: Determine how to handle count error here.
|
---|
66 | }
|
---|
67 | }
|
---|
68 |
|
---|
69 | /** @todo securely clear other fields (user name, domain, ...) as well. */
|
---|
70 | }
|
---|
71 |
|
---|
72 |
|
---|
73 | int VBoxCredential::Update(const char *pszUser,
|
---|
74 | const char *pszPw,
|
---|
75 | const char *pszDomain)
|
---|
76 | {
|
---|
77 | /* Convert credentials to unicode. */
|
---|
78 | PWSTR *ppwszStored;
|
---|
79 |
|
---|
80 | ppwszStored = &m_rgFieldStrings[SFI_USERNAME];
|
---|
81 | CoTaskMemFree(*ppwszStored);
|
---|
82 | SHStrDupA(pszUser, ppwszStored);
|
---|
83 |
|
---|
84 | ppwszStored = &m_rgFieldStrings[SFI_PASSWORD];
|
---|
85 | CoTaskMemFree(*ppwszStored);
|
---|
86 | SHStrDupA(pszPw, ppwszStored);
|
---|
87 |
|
---|
88 | ppwszStored = &m_rgFieldStrings[SFI_DOMAINNAME];
|
---|
89 | CoTaskMemFree(*ppwszStored);
|
---|
90 | SHStrDupA(pszDomain, ppwszStored);
|
---|
91 |
|
---|
92 | Log(("VBoxCredential::Update: user=%ls, pw=%ls, domain=%ls\n",
|
---|
93 | m_rgFieldStrings[SFI_USERNAME] ? m_rgFieldStrings[SFI_USERNAME] : L"<empty>",
|
---|
94 | m_rgFieldStrings[SFI_PASSWORD] ? m_rgFieldStrings[SFI_PASSWORD] : L"<empty>",
|
---|
95 | m_rgFieldStrings[SFI_DOMAINNAME] ? m_rgFieldStrings[SFI_DOMAINNAME] : L"<empty>"));
|
---|
96 | return S_OK;
|
---|
97 | }
|
---|
98 |
|
---|
99 |
|
---|
100 | // Initializes one credential with the field information passed in.
|
---|
101 | // Set the value of the SFI_USERNAME field to pwzUsername.
|
---|
102 | // Optionally takes a password for the SetSerialization case.
|
---|
103 | HRESULT VBoxCredential::Initialize(CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus,
|
---|
104 | const CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR* rgcpfd,
|
---|
105 | const FIELD_STATE_PAIR* rgfsp)
|
---|
106 | {
|
---|
107 | Log(("VBoxCredential::Initialize: cpus=%ld, rgcpfd=%p, rgfsp=%p\n", cpus, rgcpfd, rgfsp));
|
---|
108 |
|
---|
109 | HRESULT hr = S_OK;
|
---|
110 |
|
---|
111 | m_cpUS = cpus;
|
---|
112 |
|
---|
113 | /* Copy the field descriptors for each field. This is useful if you want to vary the
|
---|
114 | * field descriptors based on what Usage scenario the credential was created for. */
|
---|
115 | for (DWORD i = 0; SUCCEEDED(hr) && i < ARRAYSIZE(m_rgCredProvFieldDescriptors); i++)
|
---|
116 | {
|
---|
117 | m_rgFieldStatePairs[i] = rgfsp[i];
|
---|
118 | hr = FieldDescriptorCopy(rgcpfd[i], &m_rgCredProvFieldDescriptors[i]);
|
---|
119 | }
|
---|
120 |
|
---|
121 | /* Fill in the default value to make winlogon happy. */
|
---|
122 | hr = SHStrDupW(L"Submit", &m_rgFieldStrings[SFI_SUBMIT_BUTTON]);
|
---|
123 |
|
---|
124 | return S_OK;
|
---|
125 | }
|
---|
126 |
|
---|
127 |
|
---|
128 | /* LogonUI calls this in order to give us a callback in case we need to notify it of anything.
|
---|
129 | * Store this callback pointer for later use. */
|
---|
130 | HRESULT VBoxCredential::Advise(ICredentialProviderCredentialEvents* pcpce)
|
---|
131 | {
|
---|
132 | Log(("VBoxCredential::Advise\n"));
|
---|
133 |
|
---|
134 | if (m_pCredProvCredentialEvents != NULL)
|
---|
135 | m_pCredProvCredentialEvents->Release();
|
---|
136 | m_pCredProvCredentialEvents = pcpce;
|
---|
137 | m_pCredProvCredentialEvents->AddRef();
|
---|
138 | return S_OK;
|
---|
139 | }
|
---|
140 |
|
---|
141 |
|
---|
142 | /* LogonUI calls this to tell us to release the callback. */
|
---|
143 | HRESULT VBoxCredential::UnAdvise()
|
---|
144 | {
|
---|
145 | Log(("VBoxCredential::UnAdvise\n"));
|
---|
146 |
|
---|
147 | Reset();
|
---|
148 |
|
---|
149 | if (m_pCredProvCredentialEvents)
|
---|
150 | m_pCredProvCredentialEvents->Release();
|
---|
151 | m_pCredProvCredentialEvents = NULL;
|
---|
152 | return S_OK;
|
---|
153 | }
|
---|
154 |
|
---|
155 |
|
---|
156 | // LogonUI calls this function when our tile is selected (zoomed).
|
---|
157 | // If you simply want fields to show/hide based on the selected state,
|
---|
158 | // there's no need to do anything here - you can set that up in the
|
---|
159 | // field definitions. But if you want to do something
|
---|
160 | // more complicated, like change the contents of a field when the tile is
|
---|
161 | // selected, you would do it here.
|
---|
162 | HRESULT VBoxCredential::SetSelected(BOOL* pbAutoLogon)
|
---|
163 | {
|
---|
164 | Log(("VBoxCredential::SetSelected\n"));
|
---|
165 |
|
---|
166 | /* Don't do auto logon here because it would retry too often with
|
---|
167 | * every credential field (user name, password, domain, ...) which makes
|
---|
168 | * winlogon wait before new login attempts can be made.
|
---|
169 | */
|
---|
170 | *pbAutoLogon = FALSE;
|
---|
171 | return S_OK;
|
---|
172 | }
|
---|
173 |
|
---|
174 |
|
---|
175 | // Similarly to SetSelected, LogonUI calls this when your tile was selected
|
---|
176 | // and now no longer is. The most common thing to do here (which we do below)
|
---|
177 | // is to clear out the password field.
|
---|
178 | HRESULT VBoxCredential::SetDeselected()
|
---|
179 | {
|
---|
180 | Log(("VBoxCredential::SetDeselected\n"));
|
---|
181 |
|
---|
182 | HRESULT hr = S_OK;
|
---|
183 | if (m_rgFieldStrings[SFI_PASSWORD])
|
---|
184 | {
|
---|
185 | // CoTaskMemFree (below) deals with NULL, but StringCchLength does not.
|
---|
186 | size_t lenPassword;
|
---|
187 | hr = StringCchLengthW(m_rgFieldStrings[SFI_PASSWORD], 128, &(lenPassword));
|
---|
188 | if (SUCCEEDED(hr))
|
---|
189 | {
|
---|
190 | SecureZeroMemory(m_rgFieldStrings[SFI_PASSWORD], lenPassword * sizeof(*m_rgFieldStrings[SFI_PASSWORD]));
|
---|
191 |
|
---|
192 | CoTaskMemFree(m_rgFieldStrings[SFI_PASSWORD]);
|
---|
193 | hr = SHStrDupW(L"", &m_rgFieldStrings[SFI_PASSWORD]);
|
---|
194 | }
|
---|
195 |
|
---|
196 | if (SUCCEEDED(hr) && m_pCredProvCredentialEvents)
|
---|
197 | {
|
---|
198 | m_pCredProvCredentialEvents->SetFieldString(this, SFI_PASSWORD, m_rgFieldStrings[SFI_PASSWORD]);
|
---|
199 | }
|
---|
200 | }
|
---|
201 |
|
---|
202 | return hr;
|
---|
203 | }
|
---|
204 |
|
---|
205 |
|
---|
206 | // Gets info for a particular field of a tile. Called by logonUI to get information to
|
---|
207 | // display the tile.
|
---|
208 | HRESULT VBoxCredential::GetFieldState(DWORD dwFieldID,
|
---|
209 | CREDENTIAL_PROVIDER_FIELD_STATE* pcpfs,
|
---|
210 | CREDENTIAL_PROVIDER_FIELD_INTERACTIVE_STATE* pcpfis)
|
---|
211 | {
|
---|
212 | Log(("VBoxCredential::GetFieldState: dwFieldID=%ld, pcpfs=%p, pcpfis=%p\n", dwFieldID, pcpfs, pcpfis));
|
---|
213 |
|
---|
214 | HRESULT hr;
|
---|
215 |
|
---|
216 | if ( (dwFieldID < ARRAYSIZE(m_rgFieldStatePairs))
|
---|
217 | && pcpfs
|
---|
218 | && pcpfis)
|
---|
219 | {
|
---|
220 | *pcpfs = m_rgFieldStatePairs[dwFieldID].cpfs;
|
---|
221 | *pcpfis = m_rgFieldStatePairs[dwFieldID].cpfis;
|
---|
222 |
|
---|
223 | hr = S_OK;
|
---|
224 | }
|
---|
225 | else
|
---|
226 | {
|
---|
227 | hr = E_INVALIDARG;
|
---|
228 | }
|
---|
229 | return hr;
|
---|
230 | }
|
---|
231 |
|
---|
232 |
|
---|
233 | // Sets ppwsz to the string value of the field at the index dwFieldID.
|
---|
234 | HRESULT VBoxCredential::GetStringValue(DWORD dwFieldID,
|
---|
235 | PWSTR* ppwsz)
|
---|
236 | {
|
---|
237 | Log(("VBoxCredential::GetStringValue: dwFieldID=%ld, pwz=%p\n", dwFieldID, ppwsz));
|
---|
238 |
|
---|
239 | HRESULT hr;
|
---|
240 |
|
---|
241 | // Check to make sure dwFieldID is a legitimate index.
|
---|
242 | if (dwFieldID < ARRAYSIZE(m_rgCredProvFieldDescriptors) && ppwsz)
|
---|
243 | {
|
---|
244 | // Make a copy of the string and return that. The caller
|
---|
245 | // is responsible for freeing it.
|
---|
246 | hr = SHStrDupW(m_rgFieldStrings[dwFieldID], ppwsz);
|
---|
247 | if (SUCCEEDED(hr))
|
---|
248 | Log(("VBoxCredential::GetStringValue: dwFieldID=%ld, pwz=%ls\n", dwFieldID, *ppwsz));
|
---|
249 | }
|
---|
250 | else
|
---|
251 | {
|
---|
252 | hr = E_INVALIDARG;
|
---|
253 | }
|
---|
254 |
|
---|
255 | return hr;
|
---|
256 | }
|
---|
257 |
|
---|
258 |
|
---|
259 | // Sets pdwAdjacentTo to the index of the field the submit button should be
|
---|
260 | // adjacent to. We recommend that the submit button is placed next to the last
|
---|
261 | // field which the user is required to enter information in. Optional fields
|
---|
262 | // should be below the submit button.
|
---|
263 | HRESULT VBoxCredential::GetSubmitButtonValue(DWORD dwFieldID,
|
---|
264 | DWORD* pdwAdjacentTo)
|
---|
265 | {
|
---|
266 | Log(("VBoxCredential::GetSubmitButtonValue: dwFieldID=%ld\n", dwFieldID));
|
---|
267 |
|
---|
268 | HRESULT hr;
|
---|
269 |
|
---|
270 | // Validate parameters.
|
---|
271 | if ((SFI_SUBMIT_BUTTON == dwFieldID) && pdwAdjacentTo)
|
---|
272 | {
|
---|
273 | // pdwAdjacentTo is a pointer to the fieldID you want the submit button to appear next to.
|
---|
274 | *pdwAdjacentTo = SFI_PASSWORD;
|
---|
275 | Log(("VBoxCredential::GetSubmitButtonValue: dwFieldID=%ld, *pdwAdjacentTo=%ld\n", dwFieldID, *pdwAdjacentTo));
|
---|
276 | hr = S_OK;
|
---|
277 | }
|
---|
278 | else
|
---|
279 | {
|
---|
280 | hr = E_INVALIDARG;
|
---|
281 | }
|
---|
282 | return hr;
|
---|
283 | }
|
---|
284 |
|
---|
285 |
|
---|
286 | // Sets the value of a field which can accept a string as a value.
|
---|
287 | // This is called on each keystroke when a user types into an edit field.
|
---|
288 | HRESULT VBoxCredential::SetStringValue(DWORD dwFieldID,
|
---|
289 | PCWSTR pwz)
|
---|
290 | {
|
---|
291 | Log(("VBoxCredential::SetStringValue: dwFieldID=%ld, pwz=%ls\n", dwFieldID, pwz));
|
---|
292 |
|
---|
293 | HRESULT hr;
|
---|
294 |
|
---|
295 | // Validate parameters.
|
---|
296 | if ( dwFieldID < ARRAYSIZE(m_rgCredProvFieldDescriptors)
|
---|
297 | && (CPFT_EDIT_TEXT == m_rgCredProvFieldDescriptors[dwFieldID].cpft ||
|
---|
298 | CPFT_PASSWORD_TEXT == m_rgCredProvFieldDescriptors[dwFieldID].cpft))
|
---|
299 | {
|
---|
300 | PWSTR* ppwszStored = &m_rgFieldStrings[dwFieldID];
|
---|
301 | CoTaskMemFree(*ppwszStored);
|
---|
302 | hr = SHStrDupW(pwz, ppwszStored);
|
---|
303 | }
|
---|
304 | else
|
---|
305 | {
|
---|
306 | hr = E_INVALIDARG;
|
---|
307 | }
|
---|
308 | return hr;
|
---|
309 | }
|
---|
310 |
|
---|
311 |
|
---|
312 | // The following methods are for logonUI to get the values of various UI elements and then communicate
|
---|
313 | // to the credential about what the user did in that field. However, these methods are not implemented
|
---|
314 | // because our tile doesn't contain these types of UI elements
|
---|
315 |
|
---|
316 | /* Gets the image to show in the user tile */
|
---|
317 | HRESULT VBoxCredential::GetBitmapValue(DWORD dwFieldID,
|
---|
318 | HBITMAP* phbmp)
|
---|
319 | {
|
---|
320 | UNREFERENCED_PARAMETER(dwFieldID);
|
---|
321 | UNREFERENCED_PARAMETER(phbmp);
|
---|
322 |
|
---|
323 | /* We don't do own bitmaps */
|
---|
324 | return E_NOTIMPL;
|
---|
325 | }
|
---|
326 |
|
---|
327 |
|
---|
328 | HRESULT VBoxCredential::GetCheckboxValue(DWORD dwFieldID,
|
---|
329 | BOOL* pbChecked,
|
---|
330 | PWSTR* ppwszLabel)
|
---|
331 | {
|
---|
332 | UNREFERENCED_PARAMETER(dwFieldID);
|
---|
333 | UNREFERENCED_PARAMETER(pbChecked);
|
---|
334 | UNREFERENCED_PARAMETER(ppwszLabel);
|
---|
335 | return E_NOTIMPL;
|
---|
336 | }
|
---|
337 |
|
---|
338 |
|
---|
339 | HRESULT VBoxCredential::GetComboBoxValueCount(DWORD dwFieldID,
|
---|
340 | DWORD* pcItems,
|
---|
341 | DWORD* pdwSelectedItem)
|
---|
342 | {
|
---|
343 | UNREFERENCED_PARAMETER(dwFieldID);
|
---|
344 | UNREFERENCED_PARAMETER(pcItems);
|
---|
345 | UNREFERENCED_PARAMETER(pdwSelectedItem);
|
---|
346 | return E_NOTIMPL;
|
---|
347 | }
|
---|
348 |
|
---|
349 |
|
---|
350 | HRESULT VBoxCredential::GetComboBoxValueAt(DWORD dwFieldID,
|
---|
351 | DWORD dwItem,
|
---|
352 | PWSTR* ppwszItem)
|
---|
353 | {
|
---|
354 | UNREFERENCED_PARAMETER(dwFieldID);
|
---|
355 | UNREFERENCED_PARAMETER(dwItem);
|
---|
356 | UNREFERENCED_PARAMETER(ppwszItem);
|
---|
357 | return E_NOTIMPL;
|
---|
358 | }
|
---|
359 |
|
---|
360 |
|
---|
361 | HRESULT VBoxCredential::SetCheckboxValue(DWORD dwFieldID,
|
---|
362 | BOOL bChecked)
|
---|
363 | {
|
---|
364 | UNREFERENCED_PARAMETER(dwFieldID);
|
---|
365 | UNREFERENCED_PARAMETER(bChecked);
|
---|
366 | return E_NOTIMPL;
|
---|
367 | }
|
---|
368 |
|
---|
369 |
|
---|
370 | HRESULT VBoxCredential::SetComboBoxSelectedValue(DWORD dwFieldId,
|
---|
371 | DWORD dwSelectedItem)
|
---|
372 | {
|
---|
373 | UNREFERENCED_PARAMETER(dwFieldId);
|
---|
374 | UNREFERENCED_PARAMETER(dwSelectedItem);
|
---|
375 | return E_NOTIMPL;
|
---|
376 | }
|
---|
377 |
|
---|
378 |
|
---|
379 | HRESULT VBoxCredential::CommandLinkClicked(DWORD dwFieldID)
|
---|
380 | {
|
---|
381 | UNREFERENCED_PARAMETER(dwFieldID);
|
---|
382 | return E_NOTIMPL;
|
---|
383 | }
|
---|
384 |
|
---|
385 |
|
---|
386 | // Collect the username and password into a serialized credential for the correct usage scenario
|
---|
387 | // (logon/unlock is what's demonstrated in this sample). LogonUI then passes these credentials
|
---|
388 | // back to the system to log on.
|
---|
389 | HRESULT VBoxCredential::GetSerialization(CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE* pcpgsr,
|
---|
390 | CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs,
|
---|
391 | PWSTR* ppwszOptionalStatusText,
|
---|
392 | CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon)
|
---|
393 | {
|
---|
394 | Log(("VBoxCredential::GetSerialization: pcpgsr=%p, pcpcs=%p, ppwszOptionalStatusText=%p, pcpsiOptionalStatusIcon=%p\n",
|
---|
395 | pcpgsr, pcpcs, ppwszOptionalStatusText, pcpsiOptionalStatusIcon));
|
---|
396 |
|
---|
397 | UNREFERENCED_PARAMETER(ppwszOptionalStatusText);
|
---|
398 | UNREFERENCED_PARAMETER(pcpsiOptionalStatusIcon);
|
---|
399 |
|
---|
400 | KERB_INTERACTIVE_LOGON kil;
|
---|
401 | ZeroMemory(&kil, sizeof(kil));
|
---|
402 |
|
---|
403 | HRESULT hr;
|
---|
404 |
|
---|
405 | WCHAR wsz[MAX_COMPUTERNAME_LENGTH+1];
|
---|
406 | DWORD cch = ARRAYSIZE(wsz);
|
---|
407 | if (GetComputerNameW(wsz, &cch))
|
---|
408 | {
|
---|
409 | /* Is a domain name missing? Then use the name of the local computer. */
|
---|
410 | if (NULL == m_rgFieldStrings [SFI_DOMAINNAME])
|
---|
411 | hr = UnicodeStringInitWithString(wsz, &kil.LogonDomainName);
|
---|
412 | else
|
---|
413 | hr = UnicodeStringInitWithString(
|
---|
414 | m_rgFieldStrings [SFI_DOMAINNAME], &kil.LogonDomainName);
|
---|
415 |
|
---|
416 | /* Fill in the username and password. */
|
---|
417 | if (SUCCEEDED(hr))
|
---|
418 | {
|
---|
419 | hr = UnicodeStringInitWithString(m_rgFieldStrings[SFI_USERNAME], &kil.UserName);
|
---|
420 |
|
---|
421 | if (SUCCEEDED(hr))
|
---|
422 | {
|
---|
423 | hr = UnicodeStringInitWithString(m_rgFieldStrings[SFI_PASSWORD], &kil.Password);
|
---|
424 |
|
---|
425 | if (SUCCEEDED(hr))
|
---|
426 | {
|
---|
427 | // Allocate copies of, and package, the strings in a binary blob
|
---|
428 | kil.MessageType = KerbInteractiveLogon;
|
---|
429 | hr = KerbInteractiveLogonPack(kil, &pcpcs->rgbSerialization, &pcpcs->cbSerialization);
|
---|
430 |
|
---|
431 | if (SUCCEEDED(hr))
|
---|
432 | {
|
---|
433 | ULONG ulAuthPackage;
|
---|
434 | hr = RetrieveNegotiateAuthPackage(&ulAuthPackage);
|
---|
435 | if (SUCCEEDED(hr))
|
---|
436 | {
|
---|
437 | pcpcs->ulAuthenticationPackage = ulAuthPackage;
|
---|
438 | pcpcs->clsidCredentialProvider = CLSID_VBoxCredProvider;
|
---|
439 |
|
---|
440 | // At this point the credential has created the serialized credential used for logon
|
---|
441 | // By setting this to CPGSR_RETURN_CREDENTIAL_FINISHED we are letting logonUI know
|
---|
442 | // that we have all the information we need and it should attempt to submit the
|
---|
443 | // serialized credential.
|
---|
444 | *pcpgsr = CPGSR_RETURN_CREDENTIAL_FINISHED;
|
---|
445 | }
|
---|
446 | }
|
---|
447 | }
|
---|
448 | }
|
---|
449 | }
|
---|
450 | }
|
---|
451 | else
|
---|
452 | {
|
---|
453 | DWORD dwErr = GetLastError();
|
---|
454 | hr = HRESULT_FROM_WIN32(dwErr);
|
---|
455 | }
|
---|
456 |
|
---|
457 | Log(("VBoxCredential::GetSerialization: Returned 0x%08x\n", hr));
|
---|
458 | return hr;
|
---|
459 | }
|
---|
460 |
|
---|
461 |
|
---|
462 | struct REPORT_RESULT_STATUS_INFO
|
---|
463 | {
|
---|
464 | NTSTATUS ntsStatus;
|
---|
465 | NTSTATUS ntsSubstatus;
|
---|
466 | PWSTR pwzMessage;
|
---|
467 | CREDENTIAL_PROVIDER_STATUS_ICON cpsi;
|
---|
468 | };
|
---|
469 |
|
---|
470 | static const REPORT_RESULT_STATUS_INFO s_rgLogonStatusInfo[] =
|
---|
471 | {
|
---|
472 | { STATUS_LOGON_FAILURE, STATUS_SUCCESS, L"Incorrect password or username.", CPSI_ERROR, },
|
---|
473 | { STATUS_ACCOUNT_RESTRICTION, STATUS_ACCOUNT_DISABLED, L"The account is disabled.", CPSI_WARNING },
|
---|
474 | };
|
---|
475 |
|
---|
476 |
|
---|
477 | // ReportResult is completely optional. Its purpose is to allow a credential to customize the string
|
---|
478 | // and the icon displayed in the case of a logon failure. For example, we have chosen to
|
---|
479 | // customize the error shown in the case of bad username/password and in the case of the account
|
---|
480 | // being disabled.
|
---|
481 | HRESULT VBoxCredential::ReportResult(NTSTATUS ntsStatus,
|
---|
482 | NTSTATUS ntsSubstatus,
|
---|
483 | PWSTR* ppwszOptionalStatusText,
|
---|
484 | CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon)
|
---|
485 | {
|
---|
486 | *ppwszOptionalStatusText = NULL;
|
---|
487 | *pcpsiOptionalStatusIcon = CPSI_NONE;
|
---|
488 |
|
---|
489 | DWORD dwStatusInfo = (DWORD)-1;
|
---|
490 |
|
---|
491 | // Look for a match on status and substatus.
|
---|
492 | for (DWORD i = 0; i < ARRAYSIZE(s_rgLogonStatusInfo); i++)
|
---|
493 | {
|
---|
494 | if (s_rgLogonStatusInfo[i].ntsStatus == ntsStatus && s_rgLogonStatusInfo[i].ntsSubstatus == ntsSubstatus)
|
---|
495 | {
|
---|
496 | dwStatusInfo = i;
|
---|
497 | break;
|
---|
498 | }
|
---|
499 | }
|
---|
500 |
|
---|
501 | if ((DWORD)-1 != dwStatusInfo)
|
---|
502 | {
|
---|
503 | if (SUCCEEDED(SHStrDupW(s_rgLogonStatusInfo[dwStatusInfo].pwzMessage, ppwszOptionalStatusText)))
|
---|
504 | {
|
---|
505 | *pcpsiOptionalStatusIcon = s_rgLogonStatusInfo[dwStatusInfo].cpsi;
|
---|
506 | }
|
---|
507 | }
|
---|
508 |
|
---|
509 | /* Try to lookup a text message for error code */
|
---|
510 | LPVOID lpMessageBuffer = NULL;
|
---|
511 | HMODULE hMod = LoadLibrary(L"NTDLL.DLL");
|
---|
512 | if (hMod)
|
---|
513 | {
|
---|
514 | FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER
|
---|
515 | | FORMAT_MESSAGE_FROM_SYSTEM
|
---|
516 | | FORMAT_MESSAGE_FROM_HMODULE,
|
---|
517 | hMod,
|
---|
518 | ntsStatus,
|
---|
519 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
---|
520 | (LPTSTR) &lpMessageBuffer,
|
---|
521 | 0,
|
---|
522 | NULL);
|
---|
523 | }
|
---|
524 |
|
---|
525 | Log(("VBoxCredential::ReportResult: ntsStatus=%ld, ntsSubstatus=%ld, ppwszOptionalStatusText=%p, pcpsiOptionalStatusIcon=%p, dwStatusInfo=%ld, Message=%ls\n",
|
---|
526 | ntsStatus, ntsSubstatus, ppwszOptionalStatusText, pcpsiOptionalStatusIcon, dwStatusInfo, lpMessageBuffer ? lpMessageBuffer : L"none"));
|
---|
527 |
|
---|
528 | if (lpMessageBuffer)
|
---|
529 | LocalFree(lpMessageBuffer);
|
---|
530 | FreeLibrary(hMod);
|
---|
531 |
|
---|
532 | // Since NULL is a valid value for *ppwszOptionalStatusText and *pcpsiOptionalStatusIcon
|
---|
533 | // this function can't fail.
|
---|
534 | return S_OK;
|
---|
535 | }
|
---|