VirtualBox

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

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