VirtualBox

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

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

VBoxCredProv: Added support for unlocking workstations.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.3 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// Helper functions for copying parameters and packaging the buffer
10// for GetSerialization.
11//
12// Modifications (c) 2009-2010 Oracle Corporation
13//
14
15#include "helpers.h"
16#include <intsafe.h>
17
18#include <VBox/log.h>
19
20//
21// Copies the field descriptor pointed to by rcpfd into a buffer allocated
22// using CoTaskMemAlloc. Returns that buffer in ppcpfd.
23//
24HRESULT FieldDescriptorCoAllocCopy(
25 const CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR& rcpfd,
26 CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR** ppcpfd
27 )
28{
29 HRESULT hr;
30 DWORD cbStruct = sizeof(CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR);
31
32 CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR* pcpfd =
33 (CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR*)CoTaskMemAlloc(cbStruct);
34
35 if (pcpfd)
36 {
37 pcpfd->dwFieldID = rcpfd.dwFieldID;
38 pcpfd->cpft = rcpfd.cpft;
39
40 if (rcpfd.pszLabel)
41 {
42 hr = SHStrDupW(rcpfd.pszLabel, &pcpfd->pszLabel);
43 }
44 else
45 {
46 pcpfd->pszLabel = NULL;
47 hr = S_OK;
48 }
49 }
50 else
51 {
52 hr = E_OUTOFMEMORY;
53 }
54 if (SUCCEEDED(hr))
55 {
56 *ppcpfd = pcpfd;
57 }
58 else
59 {
60 CoTaskMemFree(pcpfd);
61 *ppcpfd = NULL;
62 }
63
64
65 return hr;
66}
67
68//
69// Copies rcpfd into the buffer pointed to by pcpfd. The caller is responsible for
70// allocating pcpfd. This function uses CoTaskMemAlloc to allocate memory for
71// pcpfd->pszLabel.
72//
73HRESULT FieldDescriptorCopy(
74 const CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR& rcpfd,
75 CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR* pcpfd
76 )
77{
78 HRESULT hr;
79 CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR cpfd;
80
81 cpfd.dwFieldID = rcpfd.dwFieldID;
82 cpfd.cpft = rcpfd.cpft;
83
84 if (rcpfd.pszLabel)
85 {
86 hr = SHStrDupW(rcpfd.pszLabel, &cpfd.pszLabel);
87 }
88 else
89 {
90 cpfd.pszLabel = NULL;
91 hr = S_OK;
92 }
93
94 if (SUCCEEDED(hr))
95 {
96 *pcpfd = cpfd;
97 }
98
99 return hr;
100}
101
102//
103// This function copies the length of pwz and the pointer pwz into the UNICODE_STRING structure
104// This function is intended for serializing a credential in GetSerialization only.
105// Note that this function just makes a copy of the string pointer. It DOES NOT ALLOCATE storage!
106// Be very, very sure that this is what you want, because it probably isn't outside of the
107// exact GetSerialization call where the sample uses it.
108//
109HRESULT UnicodeStringInitWithString(
110 PWSTR pwz,
111 UNICODE_STRING* pus
112 )
113{
114 HRESULT hr;
115 if (pwz)
116 {
117 size_t lenString;
118 hr = StringCchLengthW(pwz, USHORT_MAX, &(lenString));
119 if (SUCCEEDED(hr))
120 {
121 USHORT usCharCount;
122 hr = SizeTToUShort(lenString, &usCharCount);
123 if (SUCCEEDED(hr))
124 {
125 USHORT usSize;
126 hr = SizeTToUShort(sizeof(WCHAR), &usSize);
127 if (SUCCEEDED(hr))
128 {
129 hr = UShortMult(usCharCount, usSize, &(pus->Length)); // Explicitly NOT including NULL terminator
130 if (SUCCEEDED(hr))
131 {
132 pus->MaximumLength = pus->Length;
133 pus->Buffer = pwz;
134 hr = S_OK;
135 }
136 else
137 {
138 hr = HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
139 }
140 }
141 }
142 }
143 }
144 else
145 {
146 hr = E_INVALIDARG;
147 }
148 return hr;
149}
150
151//
152// The following function is intended to be used ONLY with the Kerb*Pack functions. It does
153// no bounds-checking because its callers have precise requirements and are written to respect
154// its limitations.
155// You can read more about the UNICODE_STRING type at:
156// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/unicode_string.asp
157//
158static void _UnicodeStringPackedUnicodeStringCopy(
159 const UNICODE_STRING& rus,
160 PWSTR pwzBuffer,
161 UNICODE_STRING* pus
162 )
163{
164 pus->Length = rus.Length;
165 pus->MaximumLength = rus.Length;
166 pus->Buffer = pwzBuffer;
167
168 CopyMemory(pus->Buffer, rus.Buffer, pus->Length);
169}
170
171//
172// WinLogon and LSA consume "packed" KERB_INTERACTIVE_UNLOCK_LOGONs. In these, the PWSTR members of each
173// UNICODE_STRING are not actually pointers but byte offsets into the overall buffer represented
174// by the packed KERB_INTERACTIVE_UNLOCK_LOGON. For example:
175//
176// rkiulIn.Logon.LogonDomainName.Length = 14 -> Length is in bytes, not characters
177// rkiulIn.Logon.LogonDomainName.Buffer = sizeof(KERB_INTERACTIVE_UNLOCK_LOGON) -> LogonDomainName begins immediately
178// after the KERB_... struct in the buffer
179// rkiulIn.Logon.UserName.Length = 10
180// rkiulIn.Logon.UserName.Buffer = sizeof(KERB_INTERACTIVE_UNLOCK_LOGON) + 14 -> UNICODE_STRINGS are NOT null-terminated
181//
182// rkiulIn.Logon.Password.Length = 16
183// rkiulIn.Logon.Password.Buffer = sizeof(KERB_INTERACTIVE_UNLOCK_LOGON) + 14 + 10
184//
185// There's more information on this at:
186// http://msdn.microsoft.com/msdnmag/issues/05/06/SecurityBriefs/#void
187//
188HRESULT KerbInteractiveUnlockLogonPack(
189 const KERB_INTERACTIVE_UNLOCK_LOGON& rkiulIn,
190 BYTE** prgb,
191 DWORD* pcb
192 )
193{
194 HRESULT hr;
195
196 const KERB_INTERACTIVE_LOGON* pkilIn = &rkiulIn.Logon;
197
198 // alloc space for struct plus extra for the three strings
199 DWORD cb = sizeof(rkiulIn) +
200 pkilIn->LogonDomainName.Length +
201 pkilIn->UserName.Length +
202 pkilIn->Password.Length;
203
204 KERB_INTERACTIVE_UNLOCK_LOGON* pkiulOut = (KERB_INTERACTIVE_UNLOCK_LOGON*)CoTaskMemAlloc(cb);
205
206 if (pkiulOut)
207 {
208 ZeroMemory(&pkiulOut->LogonId, sizeof(LUID));
209
210 //
211 // point pbBuffer at the beginning of the extra space
212 //
213 BYTE* pbBuffer = (BYTE*)pkiulOut + sizeof(*pkiulOut);
214
215 //
216 // set up the Logon structure within the KERB_INTERACTIVE_UNLOCK_LOGON
217 //
218 KERB_INTERACTIVE_LOGON* pkilOut = &pkiulOut->Logon;
219
220 pkilOut->MessageType = pkilIn->MessageType;
221
222 //
223 // copy each string,
224 // fix up appropriate buffer pointer to be offset,
225 // advance buffer pointer over copied characters in extra space
226 //
227 _UnicodeStringPackedUnicodeStringCopy(pkilIn->LogonDomainName, (PWSTR)pbBuffer, &pkilOut->LogonDomainName);
228 pkilOut->LogonDomainName.Buffer = (PWSTR)(pbBuffer - (BYTE*)pkiulOut);
229 pbBuffer += pkilOut->LogonDomainName.Length;
230
231 _UnicodeStringPackedUnicodeStringCopy(pkilIn->UserName, (PWSTR)pbBuffer, &pkilOut->UserName);
232 pkilOut->UserName.Buffer = (PWSTR)(pbBuffer - (BYTE*)pkiulOut);
233 pbBuffer += pkilOut->UserName.Length;
234
235 _UnicodeStringPackedUnicodeStringCopy(pkilIn->Password, (PWSTR)pbBuffer, &pkilOut->Password);
236 pkilOut->Password.Buffer = (PWSTR)(pbBuffer - (BYTE*)pkiulOut);
237
238 *prgb = (BYTE*)pkiulOut;
239 *pcb = cb;
240
241 hr = S_OK;
242 }
243 else
244 {
245 hr = E_OUTOFMEMORY;
246 }
247
248 return hr;
249}
250
251//
252// Unpack a KERB_INTERACTIVE_UNLOCK_LOGON *in place*. That is, reset the Buffers from being offsets to
253// being real pointers. This means, of course, that passing the resultant struct across any sort of
254// memory space boundary is not going to work -- repack it if necessary!
255//
256void KerbInteractiveUnlockLogonUnpackInPlace(
257 __inout_bcount(cb) KERB_INTERACTIVE_UNLOCK_LOGON* pkiul
258 )
259{
260 KERB_INTERACTIVE_LOGON* pkil = &pkiul->Logon;
261
262 pkil->LogonDomainName.Buffer = pkil->LogonDomainName.Buffer
263 ? (PWSTR)((BYTE*)pkiul + (ULONG_PTR)pkil->LogonDomainName.Buffer)
264 : NULL;
265
266 pkil->UserName.Buffer = pkil->UserName.Buffer
267 ? (PWSTR)((BYTE*)pkiul + (ULONG_PTR)pkil->UserName.Buffer)
268 : NULL;
269
270 pkil->Password.Buffer = pkil->Password.Buffer
271 ? (PWSTR)((BYTE*)pkiul + (ULONG_PTR)pkil->Password.Buffer)
272 : NULL;
273}
274
275//
276// This function packs the string pszSourceString in pszDestinationString
277// for use with LSA functions including LsaLookupAuthenticationPackage.
278//
279HRESULT LsaInitString(PSTRING pszDestinationString, PCSTR pszSourceString)
280{
281 size_t cchLength;
282 HRESULT hr = StringCchLengthA(pszSourceString, USHORT_MAX, &cchLength);
283 if (SUCCEEDED(hr))
284 {
285 USHORT usLength;
286 hr = SizeTToUShort(cchLength, &usLength);
287
288 if (SUCCEEDED(hr))
289 {
290 pszDestinationString->Buffer = (PCHAR)pszSourceString;
291 pszDestinationString->Length = usLength;
292 pszDestinationString->MaximumLength = pszDestinationString->Length+1;
293 hr = S_OK;
294 }
295 }
296 return hr;
297}
298
299//
300// Retrieves the 'negotiate' AuthPackage from the LSA. In this case, Kerberos
301// For more information on auth packages see this msdn page:
302// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/msv1_0_lm20_logon.asp
303//
304HRESULT RetrieveNegotiateAuthPackage(ULONG * pulAuthPackage)
305{
306 HRESULT hr;
307 HANDLE hLsa;
308
309 NTSTATUS status = LsaConnectUntrusted(&hLsa);
310 if (SUCCEEDED(HRESULT_FROM_NT(status)))
311 {
312
313 ULONG ulAuthPackage;
314 LSA_STRING lsaszKerberosName;
315 LsaInitString(&lsaszKerberosName, NEGOSSP_NAME_A);
316
317 status = LsaLookupAuthenticationPackage(hLsa, &lsaszKerberosName, &ulAuthPackage);
318 if (SUCCEEDED(HRESULT_FROM_NT(status)))
319 {
320 *pulAuthPackage = ulAuthPackage;
321 hr = S_OK;
322 }
323 else
324 {
325 hr = HRESULT_FROM_NT(status);
326 }
327 LsaDeregisterLogonProcess(hLsa);
328 }
329 else
330 {
331 hr= HRESULT_FROM_NT(status);
332 }
333
334 return hr;
335}
336
337/* Re-defined function for *not* having a log handle (= log file created).
338 For some reason this does not work in this early stage (yet). */
339PRTLOGGER RTLogDefaultInit(void)
340{
341 return NULL;
342}
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