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