fa454ae613df408fa1290512a95f3ea2bb75ff93
[reactos.git] / reactos / dll / win32 / secur32 / sspi.c
1 /* Copyright (C) 2004 Juan Lang
2 *
3 * This file implements loading of SSP DLLs.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include "precomp.h"
21
22 #include <assert.h>
23 #include <lsass/lsass.h>
24
25 #include <wine/debug.h>
26 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
27
28 #define UNLEN 256
29
30 typedef struct _SecurePackageTable
31 {
32 DWORD numPackages;
33 DWORD numAllocated;
34 struct list table;
35 } SecurePackageTable;
36
37 typedef struct _SecureProviderTable
38 {
39 DWORD numProviders;
40 DWORD numAllocated;
41 struct list table;
42 } SecureProviderTable;
43
44 static void SECUR32_initializeProviders(void);
45
46 static CRITICAL_SECTION cs;
47 static CRITICAL_SECTION_DEBUG cs_debug =
48 {
49 0, 0, &cs,
50 { &cs_debug.ProcessLocksList, &cs_debug.ProcessLocksList },
51 0, 0, { (DWORD_PTR)(__FILE__ ": cs") }
52 };
53 static CRITICAL_SECTION cs = { &cs_debug, -1, 0, 0, 0, 0 };
54 static SecurePackageTable *packageTable = NULL;
55 static SecureProviderTable *providerTable = NULL;
56
57 static SecurityFunctionTableA securityFunctionTableA = {
58 SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
59 EnumerateSecurityPackagesA,
60 QueryCredentialsAttributesA,
61 AcquireCredentialsHandleA,
62 FreeCredentialsHandle,
63 NULL, /* Reserved2 */
64 InitializeSecurityContextA,
65 AcceptSecurityContext,
66 CompleteAuthToken,
67 DeleteSecurityContext,
68 ApplyControlToken,
69 QueryContextAttributesA,
70 ImpersonateSecurityContext,
71 RevertSecurityContext,
72 MakeSignature,
73 VerifySignature,
74 FreeContextBuffer,
75 QuerySecurityPackageInfoA,
76 EncryptMessage, /* Reserved3 */
77 DecryptMessage, /* Reserved4 */
78 ExportSecurityContext,
79 ImportSecurityContextA,
80 AddCredentialsA,
81 NULL, /* Reserved8 */
82 QuerySecurityContextToken,
83 EncryptMessage,
84 DecryptMessage,
85 NULL
86 };
87
88 static SecurityFunctionTableW securityFunctionTableW = {
89 SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
90 EnumerateSecurityPackagesW,
91 QueryCredentialsAttributesW,
92 AcquireCredentialsHandleW,
93 FreeCredentialsHandle,
94 NULL, /* Reserved2 */
95 InitializeSecurityContextW,
96 AcceptSecurityContext,
97 CompleteAuthToken,
98 DeleteSecurityContext,
99 ApplyControlToken,
100 QueryContextAttributesW,
101 ImpersonateSecurityContext,
102 RevertSecurityContext,
103 MakeSignature,
104 VerifySignature,
105 FreeContextBuffer,
106 QuerySecurityPackageInfoW,
107 EncryptMessage, /* Reserved3 */
108 DecryptMessage, /* Reserved4 */
109 ExportSecurityContext,
110 ImportSecurityContextW,
111 AddCredentialsW,
112 NULL, /* Reserved8 */
113 QuerySecurityContextToken,
114 EncryptMessage,
115 DecryptMessage,
116 NULL
117 };
118
119 /***********************************************************************
120 * InitSecurityInterfaceA (SECUR32.@)
121 */
122 PSecurityFunctionTableA WINAPI InitSecurityInterfaceA(void)
123 {
124 TRACE("InitSecurityInterfaceA() called\n");
125 return &securityFunctionTableA;
126 }
127
128 /***********************************************************************
129 * InitSecurityInterfaceW (SECUR32.@)
130 */
131 PSecurityFunctionTableW WINAPI InitSecurityInterfaceW(void)
132 {
133 TRACE("InitSecurityInterfaceW() called\n");
134 return &securityFunctionTableW;
135 }
136
137 static PWSTR SECUR32_strdupW(PCWSTR str)
138 {
139 PWSTR ret;
140
141 if (str)
142 {
143 ret = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(str) + 1) * sizeof(WCHAR));
144 if (ret)
145 lstrcpyW(ret, str);
146 }
147 else
148 ret = NULL;
149 return ret;
150 }
151
152 PWSTR SECUR32_AllocWideFromMultiByte(PCSTR str)
153 {
154 PWSTR ret;
155
156 if (str)
157 {
158 int charsNeeded = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
159
160 if (charsNeeded)
161 {
162 ret = HeapAlloc(GetProcessHeap(), 0, charsNeeded * sizeof(WCHAR));
163 if (ret)
164 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, charsNeeded);
165 }
166 else
167 ret = NULL;
168 }
169 else
170 ret = NULL;
171 return ret;
172 }
173
174 PSTR SECUR32_AllocMultiByteFromWide(PCWSTR str)
175 {
176 PSTR ret;
177
178 if (str)
179 {
180 int charsNeeded = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0,
181 NULL, NULL);
182
183 if (charsNeeded)
184 {
185 ret = HeapAlloc(GetProcessHeap(), 0, charsNeeded);
186 if (ret)
187 WideCharToMultiByte(CP_ACP, 0, str, -1, ret, charsNeeded,
188 NULL, NULL);
189 }
190 else
191 ret = NULL;
192 }
193 else
194 ret = NULL;
195 return ret;
196 }
197
198 static void _makeFnTableA(PSecurityFunctionTableA fnTableA,
199 const SecurityFunctionTableA *inFnTableA,
200 const SecurityFunctionTableW *inFnTableW)
201 {
202 if (fnTableA)
203 {
204 if (inFnTableA)
205 {
206 /* The size of the version 1 table is based on platform sdk's
207 * sspi.h, though the sample ssp also provided with platform sdk
208 * implies only functions through QuerySecurityPackageInfoA are
209 * implemented (yikes)
210 */
211 size_t tableSize = inFnTableA->dwVersion == 1 ?
212 (const BYTE *)&inFnTableA->SetContextAttributesA -
213 (const BYTE *)inFnTableA : sizeof(SecurityFunctionTableA);
214
215 memcpy(fnTableA, inFnTableA, tableSize);
216 /* override this, since we can do it internally anyway */
217 fnTableA->QuerySecurityPackageInfoA =
218 QuerySecurityPackageInfoA;
219 }
220 else if (inFnTableW)
221 {
222 /* functions with thunks */
223 if (inFnTableW->AcquireCredentialsHandleW)
224 fnTableA->AcquireCredentialsHandleA =
225 thunk_AcquireCredentialsHandleA;
226 if (inFnTableW->InitializeSecurityContextW)
227 fnTableA->InitializeSecurityContextA =
228 thunk_InitializeSecurityContextA;
229 if (inFnTableW->ImportSecurityContextW)
230 fnTableA->ImportSecurityContextA =
231 thunk_ImportSecurityContextA;
232 if (inFnTableW->AddCredentialsW)
233 fnTableA->AddCredentialsA =
234 thunk_AddCredentialsA;
235 if (inFnTableW->QueryCredentialsAttributesW)
236 fnTableA->QueryCredentialsAttributesA =
237 thunk_QueryCredentialsAttributesA;
238 if (inFnTableW->QueryContextAttributesW)
239 fnTableA->QueryContextAttributesA =
240 thunk_QueryContextAttributesA;
241 if (inFnTableW->SetContextAttributesW)
242 fnTableA->SetContextAttributesA =
243 thunk_SetContextAttributesA;
244 /* this can't be thunked, there's no extra param to know which
245 * package to forward to */
246 fnTableA->EnumerateSecurityPackagesA = NULL;
247 /* functions with no thunks needed */
248 fnTableA->AcceptSecurityContext = inFnTableW->AcceptSecurityContext;
249 fnTableA->CompleteAuthToken = inFnTableW->CompleteAuthToken;
250 fnTableA->DeleteSecurityContext = inFnTableW->DeleteSecurityContext;
251 fnTableA->ImpersonateSecurityContext =
252 inFnTableW->ImpersonateSecurityContext;
253 fnTableA->RevertSecurityContext = inFnTableW->RevertSecurityContext;
254 fnTableA->MakeSignature = inFnTableW->MakeSignature;
255 fnTableA->VerifySignature = inFnTableW->VerifySignature;
256 fnTableA->FreeContextBuffer = inFnTableW->FreeContextBuffer;
257 fnTableA->QuerySecurityPackageInfoA =
258 QuerySecurityPackageInfoA;
259 fnTableA->ExportSecurityContext =
260 inFnTableW->ExportSecurityContext;
261 fnTableA->QuerySecurityContextToken =
262 inFnTableW->QuerySecurityContextToken;
263 fnTableA->EncryptMessage = inFnTableW->EncryptMessage;
264 fnTableA->DecryptMessage = inFnTableW->DecryptMessage;
265 }
266 }
267 }
268
269 static void _makeFnTableW(PSecurityFunctionTableW fnTableW,
270 const SecurityFunctionTableA *inFnTableA,
271 const SecurityFunctionTableW *inFnTableW)
272 {
273 if (fnTableW)
274 {
275 if (inFnTableW)
276 {
277 /* The size of the version 1 table is based on platform sdk's
278 * sspi.h, though the sample ssp also provided with platform sdk
279 * implies only functions through QuerySecurityPackageInfoA are
280 * implemented (yikes)
281 */
282 size_t tableSize = inFnTableW->dwVersion == 1 ?
283 (const BYTE *)&inFnTableW->SetContextAttributesW -
284 (const BYTE *)inFnTableW : sizeof(SecurityFunctionTableW);
285
286 memcpy(fnTableW, inFnTableW, tableSize);
287 /* override this, since we can do it internally anyway */
288 fnTableW->QuerySecurityPackageInfoW =
289 QuerySecurityPackageInfoW;
290 }
291 else if (inFnTableA)
292 {
293 /* functions with thunks */
294 if (inFnTableA->AcquireCredentialsHandleA)
295 fnTableW->AcquireCredentialsHandleW =
296 thunk_AcquireCredentialsHandleW;
297 if (inFnTableA->InitializeSecurityContextA)
298 fnTableW->InitializeSecurityContextW =
299 thunk_InitializeSecurityContextW;
300 if (inFnTableA->ImportSecurityContextA)
301 fnTableW->ImportSecurityContextW =
302 thunk_ImportSecurityContextW;
303 if (inFnTableA->AddCredentialsA)
304 fnTableW->AddCredentialsW =
305 thunk_AddCredentialsW;
306 if (inFnTableA->QueryCredentialsAttributesA)
307 fnTableW->QueryCredentialsAttributesW =
308 thunk_QueryCredentialsAttributesW;
309 if (inFnTableA->QueryContextAttributesA)
310 fnTableW->QueryContextAttributesW =
311 thunk_QueryContextAttributesW;
312 if (inFnTableA->SetContextAttributesA)
313 fnTableW->SetContextAttributesW =
314 thunk_SetContextAttributesW;
315 /* this can't be thunked, there's no extra param to know which
316 * package to forward to */
317 fnTableW->EnumerateSecurityPackagesW = NULL;
318 /* functions with no thunks needed */
319 fnTableW->AcceptSecurityContext = inFnTableA->AcceptSecurityContext;
320 fnTableW->CompleteAuthToken = inFnTableA->CompleteAuthToken;
321 fnTableW->DeleteSecurityContext = inFnTableA->DeleteSecurityContext;
322 fnTableW->ImpersonateSecurityContext =
323 inFnTableA->ImpersonateSecurityContext;
324 fnTableW->RevertSecurityContext = inFnTableA->RevertSecurityContext;
325 fnTableW->MakeSignature = inFnTableA->MakeSignature;
326 fnTableW->VerifySignature = inFnTableA->VerifySignature;
327 fnTableW->FreeContextBuffer = inFnTableA->FreeContextBuffer;
328 fnTableW->QuerySecurityPackageInfoW =
329 QuerySecurityPackageInfoW;
330 fnTableW->ExportSecurityContext =
331 inFnTableA->ExportSecurityContext;
332 fnTableW->QuerySecurityContextToken =
333 inFnTableA->QuerySecurityContextToken;
334 fnTableW->EncryptMessage = inFnTableA->EncryptMessage;
335 fnTableW->DecryptMessage = inFnTableA->DecryptMessage;
336 }
337 }
338 }
339
340 static void _copyPackageInfo(PSecPkgInfoW info, const SecPkgInfoA *inInfoA,
341 const SecPkgInfoW *inInfoW)
342 {
343 if (info && (inInfoA || inInfoW))
344 {
345 /* odd, I know, but up until Name and Comment the structures are
346 * identical
347 */
348 memcpy(info, inInfoW ? inInfoW : (const SecPkgInfoW *)inInfoA, sizeof(*info));
349 if (inInfoW)
350 {
351 info->Name = SECUR32_strdupW(inInfoW->Name);
352 info->Comment = SECUR32_strdupW(inInfoW->Comment);
353 }
354 else
355 {
356 info->Name = SECUR32_AllocWideFromMultiByte(inInfoA->Name);
357 info->Comment = SECUR32_AllocWideFromMultiByte(inInfoA->Comment);
358 }
359 }
360 }
361
362 static
363 SecureProvider *SECUR32_addProvider(const SecurityFunctionTableA *fnTableA,
364 const SecurityFunctionTableW *fnTableW, PCWSTR moduleName)
365 {
366 SecureProvider *ret;
367
368 EnterCriticalSection(&cs);
369
370 if (!providerTable)
371 {
372 providerTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SecureProviderTable));
373 if (!providerTable)
374 {
375 LeaveCriticalSection(&cs);
376 return NULL;
377 }
378
379 list_init(&providerTable->table);
380 }
381
382 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(SecureProvider));
383 if (!ret)
384 {
385 LeaveCriticalSection(&cs);
386 return NULL;
387 }
388
389 list_add_tail(&providerTable->table, &ret->entry);
390 ret->lib = NULL;
391
392 if (fnTableA || fnTableW)
393 {
394 ret->moduleName = moduleName ? SECUR32_strdupW(moduleName) : NULL;
395 _makeFnTableA(&ret->fnTableA, fnTableA, fnTableW);
396 _makeFnTableW(&ret->fnTableW, fnTableA, fnTableW);
397 ret->loaded = !moduleName;
398 }
399 else
400 {
401 ret->moduleName = SECUR32_strdupW(moduleName);
402 ret->loaded = FALSE;
403 }
404
405 LeaveCriticalSection(&cs);
406 return ret;
407 }
408
409 static
410 void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd,
411 const SecPkgInfoA *infoA, const SecPkgInfoW *infoW)
412 {
413 ULONG i;
414
415 assert(provider);
416 assert(infoA || infoW);
417
418 EnterCriticalSection(&cs);
419
420 if (!packageTable)
421 {
422 packageTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackageTable));
423 if (!packageTable)
424 {
425 LeaveCriticalSection(&cs);
426 return;
427 }
428
429 packageTable->numPackages = 0;
430 list_init(&packageTable->table);
431 }
432
433 for (i = 0; i < toAdd; i++)
434 {
435 SecurePackage *package = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackage));
436 if (!package)
437 continue;
438
439 list_add_tail(&packageTable->table, &package->entry);
440
441 package->provider = provider;
442 _copyPackageInfo(&package->infoW,
443 infoA ? &infoA[i] : NULL,
444 infoW ? &infoW[i] : NULL);
445 }
446 packageTable->numPackages += toAdd;
447
448 LeaveCriticalSection(&cs);
449 }
450
451 static void _tryLoadProvider(PWSTR moduleName)
452 {
453 HMODULE lib = LoadLibraryW(moduleName);
454
455 if (lib)
456 {
457 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
458 (INIT_SECURITY_INTERFACE_W)GetProcAddress(lib,
459 SECURITY_ENTRYPOINT_ANSIW);
460 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
461 (INIT_SECURITY_INTERFACE_A)GetProcAddress(lib,
462 SECURITY_ENTRYPOINT_ANSIA);
463
464 TRACE("loaded %s, InitSecurityInterfaceA is %p, InitSecurityInterfaceW is %p\n",
465 debugstr_w(moduleName), pInitSecurityInterfaceA,
466 pInitSecurityInterfaceW);
467 if (pInitSecurityInterfaceW || pInitSecurityInterfaceA)
468 {
469 PSecurityFunctionTableA fnTableA = NULL;
470 PSecurityFunctionTableW fnTableW = NULL;
471 ULONG toAdd = 0;
472 PSecPkgInfoA infoA = NULL;
473 PSecPkgInfoW infoW = NULL;
474 SECURITY_STATUS ret = SEC_E_OK;
475
476 if (pInitSecurityInterfaceA)
477 fnTableA = pInitSecurityInterfaceA();
478 if (pInitSecurityInterfaceW)
479 fnTableW = pInitSecurityInterfaceW();
480 if (fnTableW && fnTableW->EnumerateSecurityPackagesW)
481 {
482 if (fnTableW != &securityFunctionTableW)
483 ret = fnTableW->EnumerateSecurityPackagesW(&toAdd, &infoW);
484 else
485 TRACE("%s has built-in providers, skip adding\n", debugstr_w(moduleName));
486 }
487 else if (fnTableA && fnTableA->EnumerateSecurityPackagesA)
488 {
489 if (fnTableA != &securityFunctionTableA)
490 ret = fnTableA->EnumerateSecurityPackagesA(&toAdd, &infoA);
491 else
492 TRACE("%s has built-in providers, skip adding\n", debugstr_w(moduleName));
493 }
494 if (ret == SEC_E_OK && toAdd > 0 && (infoW || infoA))
495 {
496 SecureProvider *provider = SECUR32_addProvider(NULL, NULL,
497 moduleName);
498
499 if (provider)
500 SECUR32_addPackages(provider, toAdd, infoA, infoW);
501 if (infoW)
502 fnTableW->FreeContextBuffer(infoW);
503 else
504 fnTableA->FreeContextBuffer(infoA);
505 }
506 }
507 FreeLibrary(lib);
508 }
509 else
510 WARN("failed to load %s\n", debugstr_w(moduleName));
511 }
512
513 static const WCHAR securityProvidersKeyW[] = {
514 'S','Y','S','T','E','M','\\','C','u','r','r','e','n','t','C','o','n','t','r',
515 'o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','S','e','c','u','r',
516 'i','t','y','P','r','o','v','i','d','e','r','s','\0'
517 };
518 static const WCHAR securityProvidersW[] = {
519 'S','e','c','u','r','i','t','y','P','r','o','v','i','d','e','r','s',0
520 };
521
522 /* FIXME: we're missing SECUR32_freeProviders, so all of this gets leaked */
523 static void SECUR32_initializeProviders(void)
524 {
525 HKEY key;
526 LSTATUS apiRet;
527
528 /* Now load providers from registry */
529 apiRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, securityProvidersKeyW, 0,
530 KEY_READ, &key);
531 if (apiRet == ERROR_SUCCESS)
532 {
533 WCHAR securityPkgNames[MAX_PATH]; /* arbitrary len */
534 DWORD size = sizeof(securityPkgNames) / sizeof(WCHAR), type;
535
536 apiRet = RegQueryValueExW(key, securityProvidersW, NULL, &type,
537 (PBYTE)securityPkgNames, &size);
538 if (apiRet == ERROR_SUCCESS && type == REG_SZ)
539 {
540 WCHAR *ptr;
541
542 size = size / sizeof(WCHAR);
543 for (ptr = securityPkgNames;
544 ptr < securityPkgNames + size; )
545 {
546 WCHAR *comma;
547
548 for (comma = ptr; *comma && *comma != ','; comma++)
549 ;
550 if (*comma == ',')
551 *comma = '\0';
552 for (; *ptr && isspace(*ptr) && ptr < securityPkgNames + size;
553 ptr++)
554 ;
555 if (*ptr)
556 _tryLoadProvider(ptr);
557 ptr += lstrlenW(ptr) + 1;
558 }
559 }
560 RegCloseKey(key);
561 }
562 }
563
564 SecurePackage *SECUR32_findPackageW(PCWSTR packageName)
565 {
566 SecurePackage *ret = NULL;
567 BOOL matched = FALSE;
568
569 #ifdef __REACTOS__
570 if (!packageTable)
571 SECUR32_initializeProviders();
572 #endif
573
574 if (packageTable && packageName)
575 {
576 LIST_FOR_EACH_ENTRY(ret, &packageTable->table, SecurePackage, entry)
577 {
578 matched = !lstrcmpiW(ret->infoW.Name, packageName);
579 if (matched)
580 break;
581 }
582
583 if (!matched)
584 return NULL;
585
586 if (ret->provider && !ret->provider->loaded)
587 {
588 ret->provider->lib = LoadLibraryW(ret->provider->moduleName);
589 if (ret->provider->lib)
590 {
591 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
592 (INIT_SECURITY_INTERFACE_W)GetProcAddress(ret->provider->lib,
593 SECURITY_ENTRYPOINT_ANSIW);
594 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
595 (INIT_SECURITY_INTERFACE_A)GetProcAddress(ret->provider->lib,
596 SECURITY_ENTRYPOINT_ANSIA);
597 PSecurityFunctionTableA fnTableA = NULL;
598 PSecurityFunctionTableW fnTableW = NULL;
599
600 if (pInitSecurityInterfaceA)
601 fnTableA = pInitSecurityInterfaceA();
602 if (pInitSecurityInterfaceW)
603 fnTableW = pInitSecurityInterfaceW();
604 /* don't update built-in SecurityFunctionTable */
605 if (fnTableA != &securityFunctionTableA)
606 _makeFnTableA(&ret->provider->fnTableA, fnTableA, fnTableW);
607 if (fnTableW != &securityFunctionTableW)
608 _makeFnTableW(&ret->provider->fnTableW, fnTableA, fnTableW);
609 ret->provider->loaded = TRUE;
610 }
611 else
612 ret = NULL;
613 }
614 }
615 return ret;
616 }
617
618 SecurePackage *SECUR32_findPackageA(PCSTR packageName)
619 {
620 SecurePackage *ret;
621
622 if (packageName)
623 {
624 UNICODE_STRING package;
625
626 RtlCreateUnicodeStringFromAsciiz(&package, packageName);
627 ret = SECUR32_findPackageW(package.Buffer);
628 RtlFreeUnicodeString(&package);
629 }
630 else
631 ret = NULL;
632 return ret;
633 }
634
635 /***********************************************************************
636 * FreeContextBuffer (SECUR32.@)
637 *
638 * Doh--if pv was allocated by a crypto package, this may not be correct.
639 * The sample ssp seems to use LocalAlloc/LocalFee, but there doesn't seem to
640 * be any guarantee, nor is there an alloc function in secur32.
641 */
642 SECURITY_STATUS WINAPI FreeContextBuffer(PVOID pv)
643 {
644 HeapFree(GetProcessHeap(), 0, pv);
645
646 return SEC_E_OK;
647 }
648
649 /***********************************************************************
650 * EnumerateSecurityPackagesW (SECUR32.@)
651 */
652 SECURITY_STATUS WINAPI EnumerateSecurityPackagesW(PULONG pcPackages,
653 PSecPkgInfoW *ppPackageInfo)
654 {
655 SECURITY_STATUS ret = SEC_E_OK;
656
657 TRACE("(%p, %p)\n", pcPackages, ppPackageInfo);
658
659 #ifdef __REACTOS__
660 if (!packageTable)
661 SECUR32_initializeProviders();
662 #endif
663
664 /* windows just crashes if pcPackages or ppPackageInfo is NULL, so will I */
665 *pcPackages = 0;
666 EnterCriticalSection(&cs);
667 if (packageTable)
668 {
669 SecurePackage *package;
670 size_t bytesNeeded;
671
672 bytesNeeded = packageTable->numPackages * sizeof(SecPkgInfoW);
673 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
674 {
675 if (package->infoW.Name)
676 bytesNeeded += (lstrlenW(package->infoW.Name) + 1) * sizeof(WCHAR);
677 if (package->infoW.Comment)
678 bytesNeeded += (lstrlenW(package->infoW.Comment) + 1) * sizeof(WCHAR);
679 }
680 if (bytesNeeded)
681 {
682 *ppPackageInfo = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
683 if (*ppPackageInfo)
684 {
685 ULONG i = 0;
686 PWSTR nextString;
687
688 *pcPackages = packageTable->numPackages;
689 nextString = (PWSTR)((PBYTE)*ppPackageInfo +
690 packageTable->numPackages * sizeof(SecPkgInfoW));
691 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
692 {
693 PSecPkgInfoW pkgInfo = *ppPackageInfo + i++;
694
695 *pkgInfo = package->infoW;
696 if (package->infoW.Name)
697 {
698 TRACE("Name[%d] = %s\n", i - 1, debugstr_w(package->infoW.Name));
699 pkgInfo->Name = nextString;
700 lstrcpyW(nextString, package->infoW.Name);
701 nextString += lstrlenW(nextString) + 1;
702 }
703 else
704 pkgInfo->Name = NULL;
705 if (package->infoW.Comment)
706 {
707 TRACE("Comment[%d] = %s\n", i - 1, debugstr_w(package->infoW.Comment));
708 pkgInfo->Comment = nextString;
709 lstrcpyW(nextString, package->infoW.Comment);
710 nextString += lstrlenW(nextString) + 1;
711 }
712 else
713 pkgInfo->Comment = NULL;
714 }
715 }
716 else
717 ret = SEC_E_INSUFFICIENT_MEMORY;
718 }
719 }
720 LeaveCriticalSection(&cs);
721 TRACE("<-- 0x%08x\n", ret);
722 return ret;
723 }
724
725 /* Converts info (which is assumed to be an array of cPackages SecPkgInfoW
726 * structures) into an array of SecPkgInfoA structures, which it returns.
727 */
728 static PSecPkgInfoA thunk_PSecPkgInfoWToA(ULONG cPackages,
729 const SecPkgInfoW *info)
730 {
731 PSecPkgInfoA ret;
732
733 if (info)
734 {
735 size_t bytesNeeded = cPackages * sizeof(SecPkgInfoA);
736 ULONG i;
737
738 for (i = 0; i < cPackages; i++)
739 {
740 if (info[i].Name)
741 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Name,
742 -1, NULL, 0, NULL, NULL);
743 if (info[i].Comment)
744 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Comment,
745 -1, NULL, 0, NULL, NULL);
746 }
747 ret = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
748 if (ret)
749 {
750 PSTR nextString;
751
752 nextString = (PSTR)((PBYTE)ret + cPackages * sizeof(SecPkgInfoA));
753 for (i = 0; i < cPackages; i++)
754 {
755 PSecPkgInfoA pkgInfo = ret + i;
756 int bytes;
757
758 memcpy(pkgInfo, &info[i], sizeof(SecPkgInfoA));
759 if (info[i].Name)
760 {
761 pkgInfo->Name = nextString;
762 /* just repeat back to WideCharToMultiByte how many bytes
763 * it requires, since we asked it earlier
764 */
765 bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
766 NULL, 0, NULL, NULL);
767 WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
768 pkgInfo->Name, bytes, NULL, NULL);
769 nextString += lstrlenA(nextString) + 1;
770 }
771 else
772 pkgInfo->Name = NULL;
773 if (info[i].Comment)
774 {
775 pkgInfo->Comment = nextString;
776 /* just repeat back to WideCharToMultiByte how many bytes
777 * it requires, since we asked it earlier
778 */
779 bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
780 NULL, 0, NULL, NULL);
781 WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
782 pkgInfo->Comment, bytes, NULL, NULL);
783 nextString += lstrlenA(nextString) + 1;
784 }
785 else
786 pkgInfo->Comment = NULL;
787 }
788 }
789 }
790 else
791 ret = NULL;
792 return ret;
793 }
794
795 /***********************************************************************
796 * EnumerateSecurityPackagesA (SECUR32.@)
797 */
798 SECURITY_STATUS WINAPI EnumerateSecurityPackagesA(PULONG pcPackages,
799 PSecPkgInfoA *ppPackageInfo)
800 {
801 SECURITY_STATUS ret;
802 PSecPkgInfoW info;
803
804 ret = EnumerateSecurityPackagesW(pcPackages, &info);
805 if (ret == SEC_E_OK && *pcPackages && info)
806 {
807 *ppPackageInfo = thunk_PSecPkgInfoWToA(*pcPackages, info);
808 if (*pcPackages && !*ppPackageInfo)
809 {
810 *pcPackages = 0;
811 ret = SEC_E_INSUFFICIENT_MEMORY;
812 }
813 FreeContextBuffer(info);
814 }
815 return ret;
816 }
817
818 /***********************************************************************
819 * GetComputerObjectNameA (SECUR32.@)
820 *
821 * Get the local computer's name using the format specified.
822 *
823 * PARAMS
824 * NameFormat [I] The format for the name.
825 * lpNameBuffer [O] Pointer to buffer to receive the name.
826 * nSize [I/O] Size in characters of buffer.
827 *
828 * RETURNS
829 * TRUE If the name was written to lpNameBuffer.
830 * FALSE If the name couldn't be written.
831 *
832 * NOTES
833 * If lpNameBuffer is NULL, then the size of the buffer needed to hold the
834 * name will be returned in *nSize.
835 *
836 * nSize returns the number of characters written when lpNameBuffer is not
837 * NULL or the size of the buffer needed to hold the name when the buffer
838 * is too short or lpNameBuffer is NULL.
839 *
840 * It the buffer is too short, ERROR_INSUFFICIENT_BUFFER error will be set.
841 */
842 BOOLEAN WINAPI GetComputerObjectNameA(
843 EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
844 {
845 BOOLEAN rc;
846 LPWSTR bufferW = NULL;
847 ULONG sizeW = *nSize;
848 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
849 if (lpNameBuffer) {
850 bufferW = HeapAlloc(GetProcessHeap(), 0, sizeW * sizeof(WCHAR));
851 if (bufferW == NULL) {
852 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
853 return FALSE;
854 }
855 }
856 rc = GetComputerObjectNameW(NameFormat, bufferW, &sizeW);
857 if (rc && bufferW) {
858 ULONG len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
859 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, lpNameBuffer, *nSize, NULL, NULL);
860 *nSize = len;
861 }
862 else
863 *nSize = sizeW;
864 HeapFree(GetProcessHeap(), 0, bufferW);
865 return rc;
866 }
867
868 /***********************************************************************
869 * GetComputerObjectNameW (SECUR32.@)
870 */
871 BOOLEAN WINAPI GetComputerObjectNameW(
872 EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
873 {
874 LSA_HANDLE policyHandle;
875 LSA_OBJECT_ATTRIBUTES objectAttributes;
876 PPOLICY_DNS_DOMAIN_INFO domainInfo;
877 NTSTATUS ntStatus;
878 BOOLEAN status;
879 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
880
881 if (NameFormat == NameUnknown)
882 {
883 SetLastError(ERROR_INVALID_PARAMETER);
884 return FALSE;
885 }
886
887 ZeroMemory(&objectAttributes, sizeof(objectAttributes));
888 objectAttributes.Length = sizeof(objectAttributes);
889
890 ntStatus = LsaOpenPolicy(NULL, &objectAttributes,
891 POLICY_VIEW_LOCAL_INFORMATION,
892 &policyHandle);
893 if (ntStatus != STATUS_SUCCESS)
894 {
895 SetLastError(LsaNtStatusToWinError(ntStatus));
896 WARN("LsaOpenPolicy failed with NT status %u\n", GetLastError());
897 return FALSE;
898 }
899
900 ntStatus = LsaQueryInformationPolicy(policyHandle,
901 PolicyDnsDomainInformation,
902 (PVOID *)&domainInfo);
903 if (ntStatus != STATUS_SUCCESS)
904 {
905 SetLastError(LsaNtStatusToWinError(ntStatus));
906 WARN("LsaQueryInformationPolicy failed with NT status %u\n",
907 GetLastError());
908 LsaClose(policyHandle);
909 return FALSE;
910 }
911
912 if (domainInfo->Sid)
913 {
914 switch (NameFormat)
915 {
916 case NameSamCompatible:
917 {
918 WCHAR name[MAX_COMPUTERNAME_LENGTH + 1];
919 DWORD size = sizeof(name)/sizeof(name[0]);
920 if (GetComputerNameW(name, &size))
921 {
922 DWORD len = domainInfo->Name.Length + size + 3;
923 if (lpNameBuffer)
924 {
925 if (*nSize < len)
926 {
927 *nSize = len;
928 SetLastError(ERROR_INSUFFICIENT_BUFFER);
929 status = FALSE;
930 }
931 else
932 {
933 WCHAR bs[] = { '\\', 0 };
934 WCHAR ds[] = { '$', 0 };
935 lstrcpyW(lpNameBuffer, domainInfo->Name.Buffer);
936 lstrcatW(lpNameBuffer, bs);
937 lstrcatW(lpNameBuffer, name);
938 lstrcatW(lpNameBuffer, ds);
939 status = TRUE;
940 }
941 }
942 else /* just requesting length required */
943 {
944 *nSize = len;
945 status = TRUE;
946 }
947 }
948 else
949 {
950 SetLastError(ERROR_INTERNAL_ERROR);
951 status = FALSE;
952 }
953 }
954 break;
955 case NameFullyQualifiedDN:
956 case NameDisplay:
957 case NameUniqueId:
958 case NameCanonical:
959 case NameUserPrincipal:
960 case NameCanonicalEx:
961 case NameServicePrincipal:
962 case NameDnsDomain:
963 FIXME("NameFormat %d not implemented\n", NameFormat);
964 SetLastError(ERROR_CANT_ACCESS_DOMAIN_INFO);
965 status = FALSE;
966 break;
967 default:
968 SetLastError(ERROR_INVALID_PARAMETER);
969 status = FALSE;
970 }
971 }
972 else
973 {
974 SetLastError(ERROR_CANT_ACCESS_DOMAIN_INFO);
975 status = FALSE;
976 }
977
978 LsaFreeMemory(domainInfo);
979 LsaClose(policyHandle);
980
981 return status;
982 }
983
984 /***********************************************************************
985 * GetUserNameExA (SECUR32.@)
986 */
987 BOOLEAN WINAPI GetUserNameExA(
988 EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
989 {
990 BOOLEAN rc;
991 LPWSTR bufferW = NULL;
992 ULONG sizeW = *nSize;
993 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
994 if (lpNameBuffer) {
995 bufferW = HeapAlloc(GetProcessHeap(), 0, sizeW * sizeof(WCHAR));
996 if (bufferW == NULL) {
997 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
998 return FALSE;
999 }
1000 }
1001 rc = GetUserNameExW(NameFormat, bufferW, &sizeW);
1002 if (rc) {
1003 ULONG len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
1004 if (len <= *nSize)
1005 {
1006 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, lpNameBuffer, *nSize, NULL, NULL);
1007 *nSize = len - 1;
1008 }
1009 else
1010 {
1011 *nSize = len;
1012 rc = FALSE;
1013 SetLastError(ERROR_MORE_DATA);
1014 }
1015 }
1016 else
1017 *nSize = sizeW;
1018 HeapFree(GetProcessHeap(), 0, bufferW);
1019 return rc;
1020 }
1021
1022 BOOLEAN WINAPI GetUserNameExW(
1023 EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
1024 {
1025 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
1026
1027 switch (NameFormat)
1028 {
1029 case NameSamCompatible:
1030 {
1031 WCHAR samname[UNLEN + 1 + MAX_COMPUTERNAME_LENGTH + 1];
1032 LPWSTR out;
1033 DWORD len;
1034
1035 /* This assumes the current user is always a local account */
1036 len = MAX_COMPUTERNAME_LENGTH + 1;
1037 if (GetComputerNameW(samname, &len))
1038 {
1039 out = samname + lstrlenW(samname);
1040 *out++ = '\\';
1041 len = UNLEN + 1;
1042 if (GetUserNameW(out, &len))
1043 {
1044 if (lstrlenW(samname) < *nSize)
1045 {
1046 lstrcpyW(lpNameBuffer, samname);
1047 *nSize = lstrlenW(samname);
1048 return TRUE;
1049 }
1050
1051 SetLastError(ERROR_MORE_DATA);
1052 *nSize = lstrlenW(samname) + 1;
1053 }
1054 }
1055 return FALSE;
1056 }
1057
1058 case NameUnknown:
1059 case NameFullyQualifiedDN:
1060 case NameDisplay:
1061 case NameUniqueId:
1062 case NameCanonical:
1063 case NameUserPrincipal:
1064 case NameCanonicalEx:
1065 case NameServicePrincipal:
1066 case NameDnsDomain:
1067 SetLastError(ERROR_NONE_MAPPED);
1068 return FALSE;
1069
1070 default:
1071 SetLastError(ERROR_INVALID_PARAMETER);
1072 return FALSE;
1073 }
1074 }
1075
1076 BOOLEAN WINAPI TranslateNameA(
1077 LPCSTR lpAccountName, EXTENDED_NAME_FORMAT AccountNameFormat,
1078 EXTENDED_NAME_FORMAT DesiredNameFormat, LPSTR lpTranslatedName,
1079 PULONG nSize)
1080 {
1081 FIXME("%p %d %d %p %p\n", lpAccountName, AccountNameFormat,
1082 DesiredNameFormat, lpTranslatedName, nSize);
1083 return FALSE;
1084 }
1085
1086 BOOLEAN WINAPI TranslateNameW(
1087 LPCWSTR lpAccountName, EXTENDED_NAME_FORMAT AccountNameFormat,
1088 EXTENDED_NAME_FORMAT DesiredNameFormat, LPWSTR lpTranslatedName,
1089 PULONG nSize)
1090 {
1091 FIXME("%p %d %d %p %p\n", lpAccountName, AccountNameFormat,
1092 DesiredNameFormat, lpTranslatedName, nSize);
1093 return FALSE;
1094 }