[SECUR32]
[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
24 #include <wine/debug.h>
25 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
26
27 typedef struct _SecurePackageTable
28 {
29 DWORD numPackages;
30 DWORD numAllocated;
31 struct list table;
32 } SecurePackageTable;
33
34 typedef struct _SecureProviderTable
35 {
36 DWORD numProviders;
37 DWORD numAllocated;
38 struct list table;
39 } SecureProviderTable;
40
41 static void SECUR32_initializeProviders(void);
42
43 static CRITICAL_SECTION cs;
44 static CRITICAL_SECTION_DEBUG cs_debug =
45 {
46 0, 0, &cs,
47 { &cs_debug.ProcessLocksList, &cs_debug.ProcessLocksList },
48 0, 0, { (DWORD_PTR)(__FILE__ ": cs") }
49 };
50 static CRITICAL_SECTION cs = { &cs_debug, -1, 0, 0, 0, 0 };
51 static SecurePackageTable *packageTable = NULL;
52 static SecureProviderTable *providerTable = NULL;
53
54 static SecurityFunctionTableA securityFunctionTableA =
55 {
56 SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
57 EnumerateSecurityPackagesA,
58 QueryCredentialsAttributesA,
59 AcquireCredentialsHandleA,
60 FreeCredentialsHandle,
61 NULL, /* Reserved2 */
62 InitializeSecurityContextA,
63 AcceptSecurityContext,
64 CompleteAuthToken,
65 DeleteSecurityContext,
66 ApplyControlToken,
67 QueryContextAttributesA,
68 ImpersonateSecurityContext,
69 RevertSecurityContext,
70 MakeSignature,
71 VerifySignature,
72 FreeContextBuffer,
73 QuerySecurityPackageInfoA,
74 EncryptMessage, /* Reserved3 */
75 DecryptMessage, /* Reserved4 */
76 ExportSecurityContext,
77 ImportSecurityContextA,
78 AddCredentialsA,
79 NULL, /* Reserved8 */
80 QuerySecurityContextToken,
81 EncryptMessage,
82 DecryptMessage,
83 NULL
84 };
85
86 static SecurityFunctionTableW securityFunctionTableW =
87 {
88 SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
89 EnumerateSecurityPackagesW,
90 QueryCredentialsAttributesW,
91 AcquireCredentialsHandleW,
92 FreeCredentialsHandle,
93 NULL, /* Reserved2 */
94 InitializeSecurityContextW,
95 AcceptSecurityContext,
96 CompleteAuthToken,
97 DeleteSecurityContext,
98 ApplyControlToken,
99 QueryContextAttributesW,
100 ImpersonateSecurityContext,
101 RevertSecurityContext,
102 MakeSignature,
103 VerifySignature,
104 FreeContextBuffer,
105 QuerySecurityPackageInfoW,
106 EncryptMessage, /* Reserved3 */
107 DecryptMessage, /* Reserved4 */
108 ExportSecurityContext,
109 ImportSecurityContextW,
110 AddCredentialsW,
111 NULL, /* Reserved8 */
112 QuerySecurityContextToken,
113 EncryptMessage,
114 DecryptMessage,
115 NULL
116 };
117
118 /***********************************************************************
119 * EnumerateSecurityPackagesW (SECUR32.@)
120 */
121 SECURITY_STATUS WINAPI EnumerateSecurityPackagesW(PULONG pcPackages,
122 PSecPkgInfoW *ppPackageInfo)
123 {
124 SECURITY_STATUS ret = SEC_E_OK;
125
126 TRACE("(%p, %p)\n", pcPackages, ppPackageInfo);
127
128 #ifdef __REACTOS__
129 if (!packageTable)
130 SECUR32_initializeProviders();
131 #endif
132
133 /* windows just crashes if pcPackages or ppPackageInfo is NULL, so will I */
134 *pcPackages = 0;
135 EnterCriticalSection(&cs);
136 if (packageTable)
137 {
138 SecurePackage *package;
139 size_t bytesNeeded;
140
141 bytesNeeded = packageTable->numPackages * sizeof(SecPkgInfoW);
142 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
143 {
144 if (package->infoW.Name)
145 bytesNeeded += (lstrlenW(package->infoW.Name) + 1) * sizeof(WCHAR);
146 if (package->infoW.Comment)
147 bytesNeeded += (lstrlenW(package->infoW.Comment) + 1) * sizeof(WCHAR);
148 }
149 if (bytesNeeded)
150 {
151 *ppPackageInfo = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
152 if (*ppPackageInfo)
153 {
154 ULONG i = 0;
155 PWSTR nextString;
156
157 *pcPackages = packageTable->numPackages;
158 nextString = (PWSTR)((PBYTE)*ppPackageInfo +
159 packageTable->numPackages * sizeof(SecPkgInfoW));
160 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
161 {
162 PSecPkgInfoW pkgInfo = *ppPackageInfo + i++;
163
164 *pkgInfo = package->infoW;
165 if (package->infoW.Name)
166 {
167 TRACE("Name[%d] = %S\n", i - 1, package->infoW.Name);
168 pkgInfo->Name = nextString;
169 lstrcpyW(nextString, package->infoW.Name);
170 nextString += lstrlenW(nextString) + 1;
171 }
172 else
173 pkgInfo->Name = NULL;
174 if (package->infoW.Comment)
175 {
176 TRACE("Comment[%d] = %S\n", i - 1, package->infoW.Comment);
177 pkgInfo->Comment = nextString;
178 lstrcpyW(nextString, package->infoW.Comment);
179 nextString += lstrlenW(nextString) + 1;
180 }
181 else
182 pkgInfo->Comment = NULL;
183 }
184 }
185 else
186 ret = SEC_E_INSUFFICIENT_MEMORY;
187 }
188 }
189 LeaveCriticalSection(&cs);
190 TRACE("<-- 0x%08x\n", ret);
191 return ret;
192 }
193
194 /* Converts info (which is assumed to be an array of cPackages SecPkgInfoW
195 * structures) into an array of SecPkgInfoA structures, which it returns.
196 */
197 static PSecPkgInfoA thunk_PSecPkgInfoWToA(ULONG cPackages,
198 const SecPkgInfoW *info)
199 {
200 PSecPkgInfoA ret;
201
202 if (info)
203 {
204 size_t bytesNeeded = cPackages * sizeof(SecPkgInfoA);
205 ULONG i;
206
207 for (i = 0; i < cPackages; i++)
208 {
209 if (info[i].Name)
210 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Name,
211 -1, NULL, 0, NULL, NULL);
212 if (info[i].Comment)
213 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Comment,
214 -1, NULL, 0, NULL, NULL);
215 }
216 ret = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
217 if (ret)
218 {
219 PSTR nextString;
220
221 nextString = (PSTR)((PBYTE)ret + cPackages * sizeof(SecPkgInfoA));
222 for (i = 0; i < cPackages; i++)
223 {
224 PSecPkgInfoA pkgInfo = ret + i;
225 int bytes;
226
227 memcpy(pkgInfo, &info[i], sizeof(SecPkgInfoA));
228 if (info[i].Name)
229 {
230 pkgInfo->Name = nextString;
231 /* just repeat back to WideCharToMultiByte how many bytes
232 * it requires, since we asked it earlier
233 */
234 bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
235 NULL, 0, NULL, NULL);
236 WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
237 pkgInfo->Name, bytes, NULL, NULL);
238 nextString += lstrlenA(nextString) + 1;
239 }
240 else
241 pkgInfo->Name = NULL;
242 if (info[i].Comment)
243 {
244 pkgInfo->Comment = nextString;
245 /* just repeat back to WideCharToMultiByte how many bytes
246 * it requires, since we asked it earlier
247 */
248 bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
249 NULL, 0, NULL, NULL);
250 WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
251 pkgInfo->Comment, bytes, NULL, NULL);
252 nextString += lstrlenA(nextString) + 1;
253 }
254 else
255 pkgInfo->Comment = NULL;
256 }
257 }
258 }
259 else
260 ret = NULL;
261 return ret;
262 }
263
264 /***********************************************************************
265 * EnumerateSecurityPackagesA (SECUR32.@)
266 */
267 SECURITY_STATUS WINAPI EnumerateSecurityPackagesA(PULONG pcPackages,
268 PSecPkgInfoA *ppPackageInfo)
269 {
270 SECURITY_STATUS ret;
271 PSecPkgInfoW info;
272
273 ret = EnumerateSecurityPackagesW(pcPackages, &info);
274 if (ret == SEC_E_OK && *pcPackages && info)
275 {
276 *ppPackageInfo = thunk_PSecPkgInfoWToA(*pcPackages, info);
277 if (*pcPackages && !*ppPackageInfo)
278 {
279 *pcPackages = 0;
280 ret = SEC_E_INSUFFICIENT_MEMORY;
281 }
282 FreeContextBuffer(info);
283 }
284 return ret;
285 }
286
287 SECURITY_STATUS
288 WINAPI
289 FreeContextBuffer (
290 PVOID pvoid
291 )
292 {
293 HeapFree(GetProcessHeap(), 0, pvoid);
294 return SEC_E_OK;
295 }
296
297 PSecurityFunctionTableW
298 WINAPI
299 InitSecurityInterfaceW(VOID)
300 {
301 TRACE("InitSecurityInterfaceW() called\n");
302 return &securityFunctionTableW;
303 }
304
305 PSecurityFunctionTableA
306 WINAPI
307 InitSecurityInterfaceA(VOID)
308 {
309 TRACE("InitSecurityInterfaceA() called\n");
310 return &securityFunctionTableA;
311 }
312
313 BOOLEAN
314 WINAPI
315 TranslateNameA(
316 LPCSTR lpAccountName,
317 EXTENDED_NAME_FORMAT AccountNameFormat,
318 EXTENDED_NAME_FORMAT DesiredNameFormat,
319 LPSTR lpTranslatedName,
320 PULONG nSize
321 )
322 {
323 UNIMPLEMENTED;
324 return FALSE;
325 }
326
327 BOOLEAN
328 WINAPI
329 TranslateNameW(
330 LPCWSTR lpAccountName,
331 EXTENDED_NAME_FORMAT AccountNameFormat,
332 EXTENDED_NAME_FORMAT DesiredNameFormat,
333 LPWSTR lpTranslatedName,
334 PULONG nSize
335 )
336 {
337 UNIMPLEMENTED;
338 return FALSE;
339 }
340
341 /*** PRIVATE FUNCTIONS ***************************************************************************/
342
343 static PWSTR SECUR32_strdupW(PCWSTR str)
344 {
345 PWSTR ret;
346
347 if (str)
348 {
349 ret = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(str) + 1) * sizeof(WCHAR));
350 if (ret)
351 lstrcpyW(ret, str);
352 }
353 else
354 ret = NULL;
355 return ret;
356 }
357
358 PWSTR SECUR32_AllocWideFromMultiByte(PCSTR str)
359 {
360 PWSTR ret;
361
362 if (str)
363 {
364 int charsNeeded = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
365
366 if (charsNeeded)
367 {
368 ret = HeapAlloc(GetProcessHeap(), 0, charsNeeded * sizeof(WCHAR));
369 if (ret)
370 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, charsNeeded);
371 }
372 else
373 ret = NULL;
374 }
375 else
376 ret = NULL;
377 return ret;
378 }
379
380 PSTR SECUR32_AllocMultiByteFromWide(PCWSTR str)
381 {
382 PSTR ret;
383
384 if (str)
385 {
386 int charsNeeded = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0,
387 NULL, NULL);
388
389 if (charsNeeded)
390 {
391 ret = HeapAlloc(GetProcessHeap(), 0, charsNeeded);
392 if (ret)
393 WideCharToMultiByte(CP_ACP, 0, str, -1, ret, charsNeeded,
394 NULL, NULL);
395 }
396 else
397 ret = NULL;
398 }
399 else
400 ret = NULL;
401 return ret;
402 }
403
404 static void _makeFnTableA(PSecurityFunctionTableA fnTableA,
405 const SecurityFunctionTableA *inFnTableA,
406 const SecurityFunctionTableW *inFnTableW)
407 {
408 if (fnTableA)
409 {
410 if (inFnTableA)
411 {
412 /* The size of the version 1 table is based on platform sdk's
413 * sspi.h, though the sample ssp also provided with platform sdk
414 * implies only functions through QuerySecurityPackageInfoA are
415 * implemented (yikes)
416 */
417 size_t tableSize = inFnTableA->dwVersion == 1 ?
418 (const BYTE *)&inFnTableA->SetContextAttributesA -
419 (const BYTE *)inFnTableA : sizeof(SecurityFunctionTableA);
420
421 memcpy(fnTableA, inFnTableA, tableSize);
422 /* override this, since we can do it internally anyway */
423 fnTableA->QuerySecurityPackageInfoA =
424 QuerySecurityPackageInfoA;
425 }
426 else if (inFnTableW)
427 {
428 /* functions with thunks */
429 if (inFnTableW->AcquireCredentialsHandleW)
430 fnTableA->AcquireCredentialsHandleA =
431 thunk_AcquireCredentialsHandleA;
432 if (inFnTableW->InitializeSecurityContextW)
433 fnTableA->InitializeSecurityContextA =
434 thunk_InitializeSecurityContextA;
435 if (inFnTableW->ImportSecurityContextW)
436 fnTableA->ImportSecurityContextA =
437 thunk_ImportSecurityContextA;
438 if (inFnTableW->AddCredentialsW)
439 fnTableA->AddCredentialsA =
440 thunk_AddCredentialsA;
441 if (inFnTableW->QueryCredentialsAttributesW)
442 fnTableA->QueryCredentialsAttributesA =
443 thunk_QueryCredentialsAttributesA;
444 if (inFnTableW->QueryContextAttributesW)
445 fnTableA->QueryContextAttributesA =
446 thunk_QueryContextAttributesA;
447 if (inFnTableW->SetContextAttributesW)
448 fnTableA->SetContextAttributesA =
449 thunk_SetContextAttributesA;
450 /* this can't be thunked, there's no extra param to know which
451 * package to forward to */
452 fnTableA->EnumerateSecurityPackagesA = NULL;
453 /* functions with no thunks needed */
454 fnTableA->AcceptSecurityContext = inFnTableW->AcceptSecurityContext;
455 fnTableA->CompleteAuthToken = inFnTableW->CompleteAuthToken;
456 fnTableA->DeleteSecurityContext = inFnTableW->DeleteSecurityContext;
457 fnTableA->ImpersonateSecurityContext =
458 inFnTableW->ImpersonateSecurityContext;
459 fnTableA->RevertSecurityContext = inFnTableW->RevertSecurityContext;
460 fnTableA->MakeSignature = inFnTableW->MakeSignature;
461 fnTableA->VerifySignature = inFnTableW->VerifySignature;
462 fnTableA->FreeContextBuffer = inFnTableW->FreeContextBuffer;
463 fnTableA->QuerySecurityPackageInfoA =
464 QuerySecurityPackageInfoA;
465 fnTableA->ExportSecurityContext =
466 inFnTableW->ExportSecurityContext;
467 fnTableA->QuerySecurityContextToken =
468 inFnTableW->QuerySecurityContextToken;
469 fnTableA->EncryptMessage = inFnTableW->EncryptMessage;
470 fnTableA->DecryptMessage = inFnTableW->DecryptMessage;
471 }
472 }
473 }
474
475 static void _makeFnTableW(PSecurityFunctionTableW fnTableW,
476 const SecurityFunctionTableA *inFnTableA,
477 const SecurityFunctionTableW *inFnTableW)
478 {
479 if (fnTableW)
480 {
481 if (inFnTableW)
482 {
483 /* The size of the version 1 table is based on platform sdk's
484 * sspi.h, though the sample ssp also provided with platform sdk
485 * implies only functions through QuerySecurityPackageInfoA are
486 * implemented (yikes)
487 */
488 size_t tableSize = inFnTableW->dwVersion == 1 ?
489 (const BYTE *)&inFnTableW->SetContextAttributesW -
490 (const BYTE *)inFnTableW : sizeof(SecurityFunctionTableW);
491
492 memcpy(fnTableW, inFnTableW, tableSize);
493 /* override this, since we can do it internally anyway */
494 fnTableW->QuerySecurityPackageInfoW =
495 QuerySecurityPackageInfoW;
496 }
497 else if (inFnTableA)
498 {
499 /* functions with thunks */
500 if (inFnTableA->AcquireCredentialsHandleA)
501 fnTableW->AcquireCredentialsHandleW =
502 thunk_AcquireCredentialsHandleW;
503 if (inFnTableA->InitializeSecurityContextA)
504 fnTableW->InitializeSecurityContextW =
505 thunk_InitializeSecurityContextW;
506 if (inFnTableA->ImportSecurityContextA)
507 fnTableW->ImportSecurityContextW =
508 thunk_ImportSecurityContextW;
509 if (inFnTableA->AddCredentialsA)
510 fnTableW->AddCredentialsW =
511 thunk_AddCredentialsW;
512 if (inFnTableA->QueryCredentialsAttributesA)
513 fnTableW->QueryCredentialsAttributesW =
514 thunk_QueryCredentialsAttributesW;
515 if (inFnTableA->QueryContextAttributesA)
516 fnTableW->QueryContextAttributesW =
517 thunk_QueryContextAttributesW;
518 if (inFnTableA->SetContextAttributesA)
519 fnTableW->SetContextAttributesW =
520 thunk_SetContextAttributesW;
521 /* this can't be thunked, there's no extra param to know which
522 * package to forward to */
523 fnTableW->EnumerateSecurityPackagesW = NULL;
524 /* functions with no thunks needed */
525 fnTableW->AcceptSecurityContext = inFnTableA->AcceptSecurityContext;
526 fnTableW->CompleteAuthToken = inFnTableA->CompleteAuthToken;
527 fnTableW->DeleteSecurityContext = inFnTableA->DeleteSecurityContext;
528 fnTableW->ImpersonateSecurityContext =
529 inFnTableA->ImpersonateSecurityContext;
530 fnTableW->RevertSecurityContext = inFnTableA->RevertSecurityContext;
531 fnTableW->MakeSignature = inFnTableA->MakeSignature;
532 fnTableW->VerifySignature = inFnTableA->VerifySignature;
533 fnTableW->FreeContextBuffer = inFnTableA->FreeContextBuffer;
534 fnTableW->QuerySecurityPackageInfoW =
535 QuerySecurityPackageInfoW;
536 fnTableW->ExportSecurityContext =
537 inFnTableA->ExportSecurityContext;
538 fnTableW->QuerySecurityContextToken =
539 inFnTableA->QuerySecurityContextToken;
540 fnTableW->EncryptMessage = inFnTableA->EncryptMessage;
541 fnTableW->DecryptMessage = inFnTableA->DecryptMessage;
542 }
543 }
544 }
545
546 static void _copyPackageInfo(PSecPkgInfoW info, const SecPkgInfoA *inInfoA,
547 const SecPkgInfoW *inInfoW)
548 {
549 if (info && (inInfoA || inInfoW))
550 {
551 /* odd, I know, but up until Name and Comment the structures are
552 * identical
553 */
554 memcpy(info, inInfoW ? inInfoW : (const SecPkgInfoW *)inInfoA, sizeof(*info));
555 if (inInfoW)
556 {
557 info->Name = SECUR32_strdupW(inInfoW->Name);
558 info->Comment = SECUR32_strdupW(inInfoW->Comment);
559 }
560 else
561 {
562 info->Name = SECUR32_AllocWideFromMultiByte(inInfoA->Name);
563 info->Comment = SECUR32_AllocWideFromMultiByte(inInfoA->Comment);
564 }
565 }
566 }
567
568 static
569 SecureProvider *SECUR32_addProvider(const SecurityFunctionTableA *fnTableA,
570 const SecurityFunctionTableW *fnTableW, PCWSTR moduleName)
571 {
572 SecureProvider *ret;
573
574 EnterCriticalSection(&cs);
575
576 if (!providerTable)
577 {
578 providerTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SecureProviderTable));
579 if (!providerTable)
580 {
581 LeaveCriticalSection(&cs);
582 return NULL;
583 }
584
585 list_init(&providerTable->table);
586 }
587
588 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(SecureProvider));
589 if (!ret)
590 {
591 LeaveCriticalSection(&cs);
592 return NULL;
593 }
594
595 list_add_tail(&providerTable->table, &ret->entry);
596 ret->lib = NULL;
597
598 if (fnTableA || fnTableW)
599 {
600 ret->moduleName = moduleName ? SECUR32_strdupW(moduleName) : NULL;
601 _makeFnTableA(&ret->fnTableA, fnTableA, fnTableW);
602 _makeFnTableW(&ret->fnTableW, fnTableA, fnTableW);
603 ret->loaded = !moduleName;
604 }
605 else
606 {
607 ret->moduleName = SECUR32_strdupW(moduleName);
608 ret->loaded = FALSE;
609 }
610
611 LeaveCriticalSection(&cs);
612 return ret;
613 }
614
615 static
616 void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd,
617 const SecPkgInfoA *infoA, const SecPkgInfoW *infoW)
618 {
619 ULONG i;
620
621 assert(provider);
622 assert(infoA || infoW);
623
624 EnterCriticalSection(&cs);
625
626 if (!packageTable)
627 {
628 packageTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackageTable));
629 if (!packageTable)
630 {
631 LeaveCriticalSection(&cs);
632 return;
633 }
634
635 packageTable->numPackages = 0;
636 list_init(&packageTable->table);
637 }
638
639 for (i = 0; i < toAdd; i++)
640 {
641 SecurePackage *package = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackage));
642 if (!package)
643 continue;
644
645 list_add_tail(&packageTable->table, &package->entry);
646
647 package->provider = provider;
648 _copyPackageInfo(&package->infoW,
649 infoA ? &infoA[i] : NULL,
650 infoW ? &infoW[i] : NULL);
651 }
652 packageTable->numPackages += toAdd;
653
654 LeaveCriticalSection(&cs);
655 }
656
657 static void _tryLoadProvider(PWSTR moduleName)
658 {
659 HMODULE lib = LoadLibraryW(moduleName);
660
661 if (lib)
662 {
663 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
664 (INIT_SECURITY_INTERFACE_W)GetProcAddress(lib,
665 SECURITY_ENTRYPOINT_ANSIW);
666 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
667 (INIT_SECURITY_INTERFACE_A)GetProcAddress(lib,
668 SECURITY_ENTRYPOINT_ANSIA);
669
670 TRACE("loaded %S, InitSecurityInterfaceA is %p, InitSecurityInterfaceW is %p\n",
671 moduleName, pInitSecurityInterfaceA,
672 pInitSecurityInterfaceW);
673 if (pInitSecurityInterfaceW || pInitSecurityInterfaceA)
674 {
675 PSecurityFunctionTableA fnTableA = NULL;
676 PSecurityFunctionTableW fnTableW = NULL;
677 ULONG toAdd = 0;
678 PSecPkgInfoA infoA = NULL;
679 PSecPkgInfoW infoW = NULL;
680 SECURITY_STATUS ret = SEC_E_OK;
681
682 if (pInitSecurityInterfaceA)
683 fnTableA = pInitSecurityInterfaceA();
684 if (pInitSecurityInterfaceW)
685 fnTableW = pInitSecurityInterfaceW();
686 if (fnTableW && fnTableW->EnumerateSecurityPackagesW)
687 {
688 if (fnTableW != &securityFunctionTableW)
689 ret = fnTableW->EnumerateSecurityPackagesW(&toAdd, &infoW);
690 else
691 TRACE("%S has built-in providers, skip adding\n", moduleName);
692 }
693 else if (fnTableA && fnTableA->EnumerateSecurityPackagesA)
694 {
695 if (fnTableA != &securityFunctionTableA)
696 ret = fnTableA->EnumerateSecurityPackagesA(&toAdd, &infoA);
697 else
698 TRACE("%S has built-in providers, skip adding\n", moduleName);
699 }
700 if (ret == SEC_E_OK && toAdd > 0 && (infoW || infoA))
701 {
702 SecureProvider *provider = SECUR32_addProvider(NULL, NULL,
703 moduleName);
704
705 if (provider)
706 SECUR32_addPackages(provider, toAdd, infoA, infoW);
707 if (infoW)
708 fnTableW->FreeContextBuffer(infoW);
709 else
710 fnTableA->FreeContextBuffer(infoA);
711 }
712 }
713 FreeLibrary(lib);
714 }
715 else
716 WARN("failed to load %S\n", moduleName);
717 }
718
719 static const WCHAR securityProvidersKeyW[] = {
720 'S','Y','S','T','E','M','\\','C','u','r','r','e','n','t','C','o','n','t','r',
721 'o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','S','e','c','u','r',
722 'i','t','y','P','r','o','v','i','d','e','r','s','\0'
723 };
724 static const WCHAR securityProvidersW[] = {
725 'S','e','c','u','r','i','t','y','P','r','o','v','i','d','e','r','s',0
726 };
727
728 /* FIXME: we're missing SECUR32_freeProviders, so all of this gets leaked */
729 static void SECUR32_initializeProviders(void)
730 {
731 HKEY key;
732 LSTATUS apiRet;
733
734 /* Now load providers from registry */
735 apiRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, securityProvidersKeyW, 0,
736 KEY_READ, &key);
737 if (apiRet == ERROR_SUCCESS)
738 {
739 WCHAR securityPkgNames[MAX_PATH]; /* arbitrary len */
740 DWORD size = sizeof(securityPkgNames) / sizeof(WCHAR), type;
741
742 apiRet = RegQueryValueExW(key, securityProvidersW, NULL, &type,
743 (PBYTE)securityPkgNames, &size);
744 if (apiRet == ERROR_SUCCESS && type == REG_SZ)
745 {
746 WCHAR *ptr;
747
748 size = size / sizeof(WCHAR);
749 for (ptr = securityPkgNames;
750 ptr < securityPkgNames + size; )
751 {
752 WCHAR *comma;
753
754 for (comma = ptr; *comma && *comma != ','; comma++)
755 ;
756 if (*comma == ',')
757 *comma = '\0';
758 for (; *ptr && isspace(*ptr) && ptr < securityPkgNames + size;
759 ptr++)
760 ;
761 if (*ptr)
762 _tryLoadProvider(ptr);
763 ptr += lstrlenW(ptr) + 1;
764 }
765 }
766 RegCloseKey(key);
767 }
768 }
769
770 SecurePackage *SECUR32_findPackageW(PCWSTR packageName)
771 {
772 SecurePackage *ret = NULL;
773 BOOL matched = FALSE;
774
775 #ifdef __REACTOS__
776 if (!packageTable)
777 SECUR32_initializeProviders();
778 #endif
779
780 if (packageTable && packageName)
781 {
782 LIST_FOR_EACH_ENTRY(ret, &packageTable->table, SecurePackage, entry)
783 {
784 matched = !lstrcmpiW(ret->infoW.Name, packageName);
785 if (matched)
786 break;
787 }
788
789 if (!matched)
790 return NULL;
791
792 if (ret->provider && !ret->provider->loaded)
793 {
794 ret->provider->lib = LoadLibraryW(ret->provider->moduleName);
795 if (ret->provider->lib)
796 {
797 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
798 (INIT_SECURITY_INTERFACE_W) GetProcAddress(ret->provider->lib,
799 SECURITY_ENTRYPOINT_ANSIW);
800 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
801 (INIT_SECURITY_INTERFACE_A) GetProcAddress(ret->provider->lib,
802 SECURITY_ENTRYPOINT_ANSIA);
803 PSecurityFunctionTableA fnTableA = NULL;
804 PSecurityFunctionTableW fnTableW = NULL;
805
806 if (pInitSecurityInterfaceA)
807 fnTableA = pInitSecurityInterfaceA();
808 if (pInitSecurityInterfaceW)
809 fnTableW = pInitSecurityInterfaceW();
810 /* don't update built-in SecurityFunctionTable */
811 if (fnTableA != &securityFunctionTableA)
812 _makeFnTableA(&ret->provider->fnTableA, fnTableA, fnTableW);
813 if (fnTableW != &securityFunctionTableW)
814 _makeFnTableW(&ret->provider->fnTableW, fnTableA, fnTableW);
815 ret->provider->loaded = TRUE;
816 }
817 else
818 ret = NULL;
819 }
820 }
821 return ret;
822 }
823
824 SecurePackage *SECUR32_findPackageA(PCSTR packageName)
825 {
826 SecurePackage *ret;
827
828 if (packageName)
829 {
830 UNICODE_STRING package;
831
832 RtlCreateUnicodeStringFromAsciiz(&package, packageName);
833 ret = SECUR32_findPackageW(package.Buffer);
834 RtlFreeUnicodeString(&package);
835 }
836 else
837 ret = NULL;
838 return ret;
839 }