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 | //
|
---|
24 | HRESULT 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 | //
|
---|
73 | HRESULT 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 | //
|
---|
109 | HRESULT 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 | //
|
---|
158 | static 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_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_LOGON. For example:
|
---|
175 | //
|
---|
176 | // kil.LogonDomainName.Length = 14 -> Length is in bytes, not characters
|
---|
177 | // kil.LogonDomainName.Buffer = sizeof(KERB_INTERACTIVE_LOGON) -> LogonDomainName begins immediately
|
---|
178 | // after the KERB_... struct in the buffer
|
---|
179 | // kil.UserName.Length = 10
|
---|
180 | // kil.UserName.Buffer = sizeof(KERB_INTERACTIVE_LOGON) + 14 -> UNICODE_STRINGS are NOT null-terminated
|
---|
181 | //
|
---|
182 | // kil.Password.Length = 16
|
---|
183 | // kil.Password.Buffer = sizeof(KERB_INTERACTIVE_LOGON) + 14 + 10
|
---|
184 | //
|
---|
185 | // There's more information on this at:
|
---|
186 | // http://msdn.microsoft.com/msdnmag/issues/05/06/SecurityBriefs/#void
|
---|
187 | //
|
---|
188 |
|
---|
189 | HRESULT KerbInteractiveLogonPack(
|
---|
190 | const KERB_INTERACTIVE_LOGON& rkil,
|
---|
191 | BYTE** prgb,
|
---|
192 | DWORD* pcb
|
---|
193 | )
|
---|
194 | {
|
---|
195 | HRESULT hr;
|
---|
196 |
|
---|
197 | // alloc space for struct plus extra for the three strings
|
---|
198 | DWORD cb = sizeof(rkil) +
|
---|
199 | rkil.LogonDomainName.Length +
|
---|
200 | rkil.UserName.Length +
|
---|
201 | rkil.Password.Length;
|
---|
202 |
|
---|
203 | KERB_INTERACTIVE_LOGON* pkil = (KERB_INTERACTIVE_LOGON*)CoTaskMemAlloc(cb);
|
---|
204 |
|
---|
205 | if (pkil)
|
---|
206 | {
|
---|
207 | pkil->MessageType = rkil.MessageType;
|
---|
208 |
|
---|
209 | //
|
---|
210 | // point pbBuffer at the beginning of the extra space
|
---|
211 | //
|
---|
212 | BYTE* pbBuffer = (BYTE*)pkil + sizeof(KERB_INTERACTIVE_LOGON);
|
---|
213 |
|
---|
214 | //
|
---|
215 | // copy each string,
|
---|
216 | // fix up appropriate buffer pointer to be offset,
|
---|
217 | // advance buffer pointer over copied characters in extra space
|
---|
218 | //
|
---|
219 | _UnicodeStringPackedUnicodeStringCopy(rkil.LogonDomainName, (PWSTR)pbBuffer, &pkil->LogonDomainName);
|
---|
220 | pkil->LogonDomainName.Buffer = (PWSTR)(pbBuffer - (BYTE*)pkil);
|
---|
221 | pbBuffer += pkil->LogonDomainName.Length;
|
---|
222 |
|
---|
223 | _UnicodeStringPackedUnicodeStringCopy(rkil.UserName, (PWSTR)pbBuffer, &pkil->UserName);
|
---|
224 | pkil->UserName.Buffer = (PWSTR)(pbBuffer - (BYTE*)pkil);
|
---|
225 | pbBuffer += pkil->UserName.Length;
|
---|
226 |
|
---|
227 | _UnicodeStringPackedUnicodeStringCopy(rkil.Password, (PWSTR)pbBuffer, &pkil->Password);
|
---|
228 | pkil->Password.Buffer = (PWSTR)(pbBuffer - (BYTE*)pkil);
|
---|
229 |
|
---|
230 | *prgb = (BYTE*)pkil;
|
---|
231 | *pcb = cb;
|
---|
232 |
|
---|
233 | hr = S_OK;
|
---|
234 | }
|
---|
235 | else
|
---|
236 | {
|
---|
237 | hr = E_OUTOFMEMORY;
|
---|
238 | }
|
---|
239 |
|
---|
240 | return hr;
|
---|
241 | }
|
---|
242 |
|
---|
243 | //
|
---|
244 | // Unpack a KERB_INTERACTIVE_UNLOCK_LOGON *in place*. That is, reset the Buffers from being offsets to
|
---|
245 | // being real pointers. This means, of course, that passing the resultant struct across any sort of
|
---|
246 | // memory space boundary is not going to work -- repack it if necessary!
|
---|
247 | //
|
---|
248 | //
|
---|
249 | // Unpack a KERB_INTERACTIVE_UNLOCK_LOGON *in place*. That is, reset the Buffers from being offsets to
|
---|
250 | // being real pointers. This means, of course, that passing the resultant struct across any sort of
|
---|
251 | // memory space boundary is not going to work -- repack it if necessary!
|
---|
252 | //
|
---|
253 | void KerbInteractiveLogonUnpackInPlace(
|
---|
254 | __inout_bcount(cb) KERB_INTERACTIVE_UNLOCK_LOGON* pkiul
|
---|
255 | )
|
---|
256 | {
|
---|
257 | KERB_INTERACTIVE_LOGON* pkil = &pkiul->Logon;
|
---|
258 |
|
---|
259 | pkil->LogonDomainName.Buffer = pkil->LogonDomainName.Buffer
|
---|
260 | ? (PWSTR)((BYTE*)pkiul + (ULONG_PTR)pkil->LogonDomainName.Buffer)
|
---|
261 | : NULL;
|
---|
262 |
|
---|
263 | pkil->UserName.Buffer = pkil->UserName.Buffer
|
---|
264 | ? (PWSTR)((BYTE*)pkiul + (ULONG_PTR)pkil->UserName.Buffer)
|
---|
265 | : NULL;
|
---|
266 |
|
---|
267 | pkil->Password.Buffer = pkil->Password.Buffer
|
---|
268 | ? (PWSTR)((BYTE*)pkiul + (ULONG_PTR)pkil->Password.Buffer)
|
---|
269 | : NULL;
|
---|
270 | }
|
---|
271 |
|
---|
272 | //
|
---|
273 | // This function packs the string pszSourceString in pszDestinationString
|
---|
274 | // for use with LSA functions including LsaLookupAuthenticationPackage.
|
---|
275 | //
|
---|
276 | HRESULT LsaInitString(PSTRING pszDestinationString, PCSTR pszSourceString)
|
---|
277 | {
|
---|
278 | size_t cchLength;
|
---|
279 | HRESULT hr = StringCchLengthA(pszSourceString, USHORT_MAX, &cchLength);
|
---|
280 | if (SUCCEEDED(hr))
|
---|
281 | {
|
---|
282 | USHORT usLength;
|
---|
283 | hr = SizeTToUShort(cchLength, &usLength);
|
---|
284 |
|
---|
285 | if (SUCCEEDED(hr))
|
---|
286 | {
|
---|
287 | pszDestinationString->Buffer = (PCHAR)pszSourceString;
|
---|
288 | pszDestinationString->Length = usLength;
|
---|
289 | pszDestinationString->MaximumLength = pszDestinationString->Length+1;
|
---|
290 | hr = S_OK;
|
---|
291 | }
|
---|
292 | }
|
---|
293 | return hr;
|
---|
294 | }
|
---|
295 |
|
---|
296 | //
|
---|
297 | // Retrieves the 'negotiate' AuthPackage from the LSA. In this case, Kerberos
|
---|
298 | // For more information on auth packages see this msdn page:
|
---|
299 | // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/msv1_0_lm20_logon.asp
|
---|
300 | //
|
---|
301 | HRESULT RetrieveNegotiateAuthPackage(ULONG * pulAuthPackage)
|
---|
302 | {
|
---|
303 | HRESULT hr;
|
---|
304 | HANDLE hLsa;
|
---|
305 |
|
---|
306 | NTSTATUS status = LsaConnectUntrusted(&hLsa);
|
---|
307 | if (SUCCEEDED(HRESULT_FROM_NT(status)))
|
---|
308 | {
|
---|
309 |
|
---|
310 | ULONG ulAuthPackage;
|
---|
311 | LSA_STRING lsaszKerberosName;
|
---|
312 | LsaInitString(&lsaszKerberosName, NEGOSSP_NAME_A);
|
---|
313 |
|
---|
314 | status = LsaLookupAuthenticationPackage(hLsa, &lsaszKerberosName, &ulAuthPackage);
|
---|
315 | if (SUCCEEDED(HRESULT_FROM_NT(status)))
|
---|
316 | {
|
---|
317 | *pulAuthPackage = ulAuthPackage;
|
---|
318 | hr = S_OK;
|
---|
319 | }
|
---|
320 | else
|
---|
321 | {
|
---|
322 | hr = HRESULT_FROM_NT(status);
|
---|
323 | }
|
---|
324 | LsaDeregisterLogonProcess(hLsa);
|
---|
325 | }
|
---|
326 | else
|
---|
327 | {
|
---|
328 | hr= HRESULT_FROM_NT(status);
|
---|
329 | }
|
---|
330 |
|
---|
331 | return hr;
|
---|
332 | }
|
---|
333 |
|
---|
334 | /* Re-defined function for *not* having a log handle (= log file created).
|
---|
335 | For some reason this does not work in this early stage (yet). */
|
---|
336 | PRTLOGGER RTLogDefaultInit(void)
|
---|
337 | {
|
---|
338 | return NULL;
|
---|
339 | }
|
---|