Begin stubs of built-in schannel provider.
[wine] / dlls / secur32 / secur32.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 #include <assert.h>
20 #include <stdarg.h>
21 #include "windef.h"
22 #include "winbase.h"
23 #include "winnls.h"
24 #include "winreg.h"
25 #include "winternl.h"
26 #include "shlwapi.h"
27 #include "sspi.h"
28 #include "secur32_priv.h"
29 #include "secext.h"
30 #include "thunks.h"
31
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
35
36 /**
37  *  Type definitions
38  */
39
40 typedef struct _SecurePackageTable
41 {
42     DWORD numPackages;
43     DWORD numAllocated;
44     SecurePackage table[1];
45 } SecurePackageTable;
46
47 typedef struct _SecureProviderTable
48 {
49     DWORD numProviders;
50     DWORD numAllocated;
51     SecureProvider table[1];
52 } SecureProviderTable;
53
54 /**
55  *  Prototypes
56  */
57
58 /* Makes sure table has space for at least howBig entries.  If table is NULL,
59  * returns a newly allocated table.  Otherwise returns the address of the
60  * modified table, which may not be the same was when called.
61  */
62 static SecurePackageTable *_resizePackageTable(SecurePackageTable *table,
63  DWORD howBig);
64
65 /* Makes sure table has space for at least howBig entries.  If table is NULL,
66  * returns a newly allocated table.  Otherwise returns the address of the
67  * modified table, which may not be the same was when called.
68  */
69 static SecureProviderTable *_resizeProviderTable(SecureProviderTable *table,
70  DWORD howBig);
71
72 /* Tries to load moduleName as a provider.  If successful, enumerates what
73  * packages it can and adds them to the package and provider tables.  Resizes
74  * tables as necessary.
75  */
76 static void _tryLoadProvider(PWSTR moduleName);
77
78 /* Initialization: read securityproviders value and attempt to open each dll
79  * there.  For each DLL, call _tryLoadProvider to see if it's really an SSP.
80  * Two undocumented functions, AddSecurityPackage(A/W) and
81  * DeleteSecurityPackage(A/W), seem suspiciously like they'd register or
82  * unregister a dll, but I'm not sure.
83  */
84 static void SECUR32_initializeProviders(void);
85
86 /* Frees all loaded packages and providers */
87 static void SECUR32_freeProviders(void);
88
89 /**
90  *  Globals
91  */
92
93 static CRITICAL_SECTION cs;
94 static SecurePackageTable *packageTable = NULL;
95 static SecureProviderTable *providerTable = NULL;
96
97 static SecurityFunctionTableA securityFunctionTableA = {
98     SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION_2,
99     EnumerateSecurityPackagesA,
100     QueryCredentialsAttributesA,
101     AcquireCredentialsHandleA,
102     FreeCredentialsHandle,
103     NULL, /* Reserved2 */
104     InitializeSecurityContextA,
105     AcceptSecurityContext,
106     CompleteAuthToken,
107     DeleteSecurityContext,
108     ApplyControlToken,
109     QueryContextAttributesA,
110     ImpersonateSecurityContext,
111     RevertSecurityContext,
112     MakeSignature,
113     VerifySignature,
114     FreeContextBuffer,
115     QuerySecurityPackageInfoA,
116     NULL, /* Reserved3 */
117     NULL, /* Reserved4 */
118     ExportSecurityContext,
119     ImportSecurityContextA,
120     AddCredentialsA,
121     NULL, /* Reserved8 */
122     QuerySecurityContextToken,
123     EncryptMessage,
124     DecryptMessage,
125     SetContextAttributesA
126 };
127
128 static SecurityFunctionTableW securityFunctionTableW = {
129     SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION_2,
130     EnumerateSecurityPackagesW,
131     QueryCredentialsAttributesW,
132     AcquireCredentialsHandleW,
133     FreeCredentialsHandle,
134     NULL, /* Reserved2 */
135     InitializeSecurityContextW,
136     AcceptSecurityContext,
137     CompleteAuthToken,
138     DeleteSecurityContext,
139     ApplyControlToken,
140     QueryContextAttributesW,
141     ImpersonateSecurityContext,
142     RevertSecurityContext,
143     MakeSignature,
144     VerifySignature,
145     FreeContextBuffer,
146     QuerySecurityPackageInfoW,
147     NULL, /* Reserved3 */
148     NULL, /* Reserved4 */
149     ExportSecurityContext,
150     ImportSecurityContextW,
151     AddCredentialsW,
152     NULL, /* Reserved8 */
153     QuerySecurityContextToken,
154     EncryptMessage,
155     DecryptMessage,
156     SetContextAttributesW
157 };
158
159 /***********************************************************************
160  *              InitSecurityInterfaceA (SECUR32.@)
161  */
162 PSecurityFunctionTableA WINAPI InitSecurityInterfaceA(void)
163 {
164     return &securityFunctionTableA;
165 }
166
167 /***********************************************************************
168  *              InitSecurityInterfaceW (SECUR32.@)
169  */
170 PSecurityFunctionTableW WINAPI InitSecurityInterfaceW(void)
171 {
172     return &securityFunctionTableW;
173 }
174
175 /* Allocates or resizes table to have space for at least howBig packages.
176  * Uses Heap functions, because needs to be able to reallocate.
177  */
178 static SecurePackageTable *_resizePackageTable(SecurePackageTable *table,
179  DWORD howBig)
180 {
181     SecurePackageTable *ret;
182
183     EnterCriticalSection(&cs);
184     if (table)
185     {
186         if (table->numAllocated < howBig)
187         {
188             ret = HeapReAlloc(GetProcessHeap(), 0, table,
189              sizeof(SecurePackageTable) + (howBig - 1) * sizeof(SecurePackage));
190             if (ret)
191             {
192                 ret->numAllocated = howBig;
193                 table = ret;
194             }
195         }
196         else
197             ret = table;
198     }
199     else
200     {
201         DWORD numAllocated = (howBig > 1 ? howBig : 1);
202
203         ret = HeapAlloc(GetProcessHeap(), 0,
204          sizeof(SecurePackageTable) +
205          (numAllocated - 1) * sizeof(SecurePackage));
206         if (ret)
207         {
208             ret->numAllocated = numAllocated;
209             ret->numPackages = 0;
210         }
211     }
212     LeaveCriticalSection(&cs);
213     return ret;
214 }
215
216 /* Allocates or resizes table to have space for at least howBig providers.
217  * Uses Heap functions, because needs to be able to reallocate.
218  */
219 static SecureProviderTable *_resizeProviderTable(SecureProviderTable *table,
220  DWORD howBig)
221 {
222     SecureProviderTable *ret;
223
224     EnterCriticalSection(&cs);
225     if (table)
226     {
227         if (table->numAllocated < howBig)
228         {
229             ret = HeapReAlloc(GetProcessHeap(), 0, table,
230              sizeof(SecureProviderTable) +
231              (howBig - 1) * sizeof(SecureProvider));
232             if (ret)
233             {
234                 ret->numAllocated = howBig;
235                 table = ret;
236             }
237         }
238         else
239             ret = table;
240     }
241     else
242     {
243         DWORD numAllocated = (howBig > 1 ? howBig : 1);
244
245         ret = HeapAlloc(GetProcessHeap(), 0,
246          sizeof(SecureProviderTable) +
247          (numAllocated - 1) * sizeof(SecureProvider));
248         if (ret)
249         {
250             ret->numAllocated = numAllocated;
251             ret->numProviders = 0;
252         }
253     }
254     LeaveCriticalSection(&cs);
255     return ret;
256 }
257
258 PWSTR SECUR32_strdupW(PCWSTR str)
259 {
260     PWSTR ret;
261
262     if (str)
263     {
264         ret = (PWSTR)SECUR32_ALLOC((lstrlenW(str) + 1) * sizeof(WCHAR));
265         if (ret)
266             lstrcpyW(ret, str);
267     }
268     else
269         ret = NULL;
270     return ret;
271 }
272
273 PWSTR SECUR32_AllocWideFromMultiByte(PCSTR str)
274 {
275     PWSTR ret;
276
277     if (str)
278     {
279         int charsNeeded = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
280
281         if (charsNeeded)
282         {
283             ret = (PWSTR)SECUR32_ALLOC(charsNeeded * sizeof(WCHAR));
284             if (ret)
285                 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, charsNeeded);
286         }
287         else
288             ret = NULL;
289     }
290     else
291         ret = NULL;
292     return ret;
293 }
294
295 PSTR SECUR32_AllocMultiByteFromWide(PCWSTR str)
296 {
297     PSTR ret;
298
299     if (str)
300     {
301         int charsNeeded = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0,
302          NULL, NULL);
303
304         if (charsNeeded)
305         {
306             ret = (PSTR)SECUR32_ALLOC(charsNeeded);
307             if (ret)
308                 WideCharToMultiByte(CP_ACP, 0, str, -1, ret, charsNeeded,
309                  NULL, NULL);
310         }
311         else
312             ret = NULL;
313     }
314     else
315         ret = NULL;
316     return ret;
317 }
318
319 static void _makeFnTableA(PSecurityFunctionTableA fnTableA,
320  const PSecurityFunctionTableA inFnTableA,
321  const PSecurityFunctionTableW inFnTableW)
322 {
323     if (fnTableA)
324     {
325         if (inFnTableA)
326         {
327             /* The size of the version 1 table is based on platform sdk's
328              * sspi.h, though the sample ssp also provided with platform sdk
329              * implies only functions through QuerySecurityPackageInfoA are
330              * implemented (yikes)
331              */
332             size_t tableSize = inFnTableA->dwVersion == 1 ?
333              (LPBYTE)&inFnTableA->SetContextAttributesA -
334              (LPBYTE)inFnTableA : sizeof(SecurityFunctionTableA);
335
336             memcpy(fnTableA, inFnTableA, tableSize);
337             /* override this, since we can do it internally anyway */
338             fnTableA->QuerySecurityPackageInfoA =
339              QuerySecurityPackageInfoA;
340         }
341         else if (inFnTableW)
342         {
343             /* functions with thunks */
344             if (inFnTableW->AcquireCredentialsHandleW)
345                 fnTableA->AcquireCredentialsHandleA =
346                  thunk_AcquireCredentialsHandleA;
347             if (inFnTableW->InitializeSecurityContextW)
348                 fnTableA->InitializeSecurityContextA =
349                  thunk_InitializeSecurityContextA;
350             if (inFnTableW->ImportSecurityContextW)
351                 fnTableA->ImportSecurityContextA =
352                  thunk_ImportSecurityContextA;
353             if (inFnTableW->AddCredentialsW)
354                 fnTableA->AddCredentialsA =
355                  thunk_AddCredentialsA;
356             if (inFnTableW->QueryCredentialsAttributesW)
357                 fnTableA->QueryCredentialsAttributesA =
358                  thunk_QueryCredentialsAttributesA;
359             if (inFnTableW->QueryContextAttributesW)
360                 fnTableA->QueryContextAttributesA =
361                  thunk_QueryContextAttributesA;
362             if (inFnTableW->SetContextAttributesW)
363                 fnTableA->SetContextAttributesA =
364                  thunk_SetContextAttributesA;
365             /* this can't be thunked, there's no extra param to know which
366              * package to forward to */
367             fnTableA->EnumerateSecurityPackagesA = NULL;
368             /* functions with no thunks needed */
369             fnTableA->AcceptSecurityContext = inFnTableW->AcceptSecurityContext;
370             fnTableA->CompleteAuthToken = inFnTableW->CompleteAuthToken;
371             fnTableA->DeleteSecurityContext = inFnTableW->DeleteSecurityContext;
372             fnTableA->ImpersonateSecurityContext =
373              inFnTableW->ImpersonateSecurityContext;
374             fnTableA->RevertSecurityContext = inFnTableW->RevertSecurityContext;
375             fnTableA->MakeSignature = inFnTableW->MakeSignature;
376             fnTableA->VerifySignature = inFnTableW->VerifySignature;
377             fnTableA->FreeContextBuffer = inFnTableW->FreeContextBuffer;
378             fnTableA->QuerySecurityPackageInfoA =
379              QuerySecurityPackageInfoA;
380             fnTableA->ExportSecurityContext =
381              inFnTableW->ExportSecurityContext;
382             fnTableA->QuerySecurityContextToken =
383              inFnTableW->QuerySecurityContextToken;
384             fnTableA->EncryptMessage = inFnTableW->EncryptMessage;
385             fnTableA->DecryptMessage = inFnTableW->DecryptMessage;
386         }
387     }
388 }
389
390 static void _makeFnTableW(PSecurityFunctionTableW fnTableW,
391  const PSecurityFunctionTableA inFnTableA,
392  const PSecurityFunctionTableW inFnTableW)
393 {
394     if (fnTableW)
395     {
396         if (inFnTableW)
397         {
398             /* The size of the version 1 table is based on platform sdk's
399              * sspi.h, though the sample ssp also provided with platform sdk
400              * implies only functions through QuerySecurityPackageInfoA are
401              * implemented (yikes)
402              */
403             size_t tableSize = inFnTableW->dwVersion == 1 ?
404              (LPBYTE)&inFnTableW->SetContextAttributesW -
405              (LPBYTE)inFnTableW : sizeof(SecurityFunctionTableW);
406
407             memcpy(fnTableW, inFnTableW, tableSize);
408             /* override this, since we can do it internally anyway */
409             fnTableW->QuerySecurityPackageInfoW =
410              QuerySecurityPackageInfoW;
411         }
412         else if (inFnTableA)
413         {
414             /* functions with thunks */
415             if (inFnTableA->AcquireCredentialsHandleA)
416                 fnTableW->AcquireCredentialsHandleW =
417                  thunk_AcquireCredentialsHandleW;
418             if (inFnTableA->InitializeSecurityContextA)
419                 fnTableW->InitializeSecurityContextW =
420                  thunk_InitializeSecurityContextW;
421             if (inFnTableA->ImportSecurityContextA)
422                 fnTableW->ImportSecurityContextW =
423                  thunk_ImportSecurityContextW;
424             if (inFnTableA->AddCredentialsA)
425                 fnTableW->AddCredentialsW =
426                  thunk_AddCredentialsW;
427             if (inFnTableA->QueryCredentialsAttributesA)
428                 fnTableW->QueryCredentialsAttributesW =
429                  thunk_QueryCredentialsAttributesW;
430             if (inFnTableA->QueryContextAttributesA)
431                 fnTableW->QueryContextAttributesW =
432                  thunk_QueryContextAttributesW;
433             if (inFnTableA->SetContextAttributesA)
434                 fnTableW->SetContextAttributesW =
435                  thunk_SetContextAttributesW;
436             /* this can't be thunked, there's no extra param to know which
437              * package to forward to */
438             fnTableW->EnumerateSecurityPackagesW = NULL;
439             /* functions with no thunks needed */
440             fnTableW->AcceptSecurityContext = inFnTableA->AcceptSecurityContext;
441             fnTableW->CompleteAuthToken = inFnTableA->CompleteAuthToken;
442             fnTableW->DeleteSecurityContext = inFnTableA->DeleteSecurityContext;
443             fnTableW->ImpersonateSecurityContext =
444              inFnTableA->ImpersonateSecurityContext;
445             fnTableW->RevertSecurityContext = inFnTableA->RevertSecurityContext;
446             fnTableW->MakeSignature = inFnTableA->MakeSignature;
447             fnTableW->VerifySignature = inFnTableA->VerifySignature;
448             fnTableW->FreeContextBuffer = inFnTableA->FreeContextBuffer;
449             fnTableW->QuerySecurityPackageInfoW =
450              QuerySecurityPackageInfoW;
451             fnTableW->ExportSecurityContext =
452              inFnTableA->ExportSecurityContext;
453             fnTableW->QuerySecurityContextToken =
454              inFnTableA->QuerySecurityContextToken;
455             fnTableW->EncryptMessage = inFnTableA->EncryptMessage;
456             fnTableW->DecryptMessage = inFnTableA->DecryptMessage;
457         }
458     }
459 }
460
461 static void _copyPackageInfo(PSecPkgInfoW info, const SecPkgInfoA *inInfoA,
462  const SecPkgInfoW *inInfoW)
463 {
464     if (info && (inInfoA || inInfoW))
465     {
466         /* odd, I know, but up until Name and Comment the structures are
467          * identical
468          */
469         memcpy(info, inInfoW ? inInfoW : (PSecPkgInfoW)inInfoA, sizeof(*info));
470         if (inInfoW)
471         {
472             info->Name = SECUR32_strdupW(inInfoW->Name);
473             info->Comment = SECUR32_strdupW(inInfoW->Comment);
474         }
475         else
476         {
477             info->Name = SECUR32_AllocWideFromMultiByte(inInfoA->Name);
478             info->Comment = SECUR32_AllocWideFromMultiByte(inInfoA->Comment);
479         }
480     }
481 }
482
483 SecureProvider *SECUR32_addProvider(PSecurityFunctionTableA fnTableA,
484  PSecurityFunctionTableW fnTableW, PWSTR moduleName)
485 {
486     SecureProvider *ret;
487
488     EnterCriticalSection(&cs);
489     providerTable = _resizeProviderTable(providerTable,
490      providerTable ? providerTable->numProviders + 1 : 1);
491     if (providerTable)
492     {
493         ret = &providerTable->table[providerTable->numProviders++];
494         ret->lib = NULL;
495         if (fnTableA || fnTableW)
496         {
497             _makeFnTableA(&ret->fnTableA, fnTableA, fnTableW);
498             _makeFnTableW(&ret->fnTableW, fnTableA, fnTableW);
499             ret->loaded = TRUE;
500         }
501         else
502         {
503             ret->moduleName = SECUR32_strdupW(moduleName);
504             ret->loaded = FALSE;
505         }
506     }
507     else
508         ret = NULL;
509     LeaveCriticalSection(&cs);
510     return ret;
511 }
512
513 void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd,
514  const SecPkgInfoA *infoA, const SecPkgInfoW *infoW)
515 {
516     assert(provider);
517     assert(infoA || infoW);
518
519     EnterCriticalSection(&cs);
520     packageTable = _resizePackageTable(packageTable,
521      packageTable ? packageTable->numPackages + toAdd : toAdd);
522     if (packageTable)
523     {
524         ULONG i;
525
526         for (i = 0; i < toAdd; i++)
527         {
528             SecurePackage *package =
529              &packageTable->table[packageTable->numPackages + i];
530
531             package->provider = provider;
532             _copyPackageInfo(&package->infoW,
533              infoA ? &infoA[i] : NULL,
534              infoW ? &infoW[i] : NULL);
535         }
536         packageTable->numPackages += toAdd;
537     }
538     LeaveCriticalSection(&cs);
539 }
540
541 static void _tryLoadProvider(PWSTR moduleName)
542 {
543     HMODULE lib = LoadLibraryW(moduleName);
544
545     if (lib)
546     {
547         INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
548          (INIT_SECURITY_INTERFACE_W)GetProcAddress(lib,
549          SECURITY_ENTRYPOINT_ANSIW);
550         INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
551          (INIT_SECURITY_INTERFACE_A)GetProcAddress(lib,
552          SECURITY_ENTRYPOINT_ANSIA);
553
554         TRACE("loaded %s, InitSecurityInterfaceA is %p, InitSecurityInterfaceW is %p\n",
555          debugstr_w(moduleName), pInitSecurityInterfaceA,
556          pInitSecurityInterfaceW);
557         if (pInitSecurityInterfaceW || pInitSecurityInterfaceA)
558         {
559             PSecurityFunctionTableA fnTableA = NULL;
560             PSecurityFunctionTableW fnTableW = NULL;
561             ULONG toAdd = 0;
562             PSecPkgInfoA infoA = NULL;
563             PSecPkgInfoW infoW = NULL;
564             SECURITY_STATUS ret = SEC_E_OK;
565
566             if (pInitSecurityInterfaceA)
567                 fnTableA = pInitSecurityInterfaceA();
568             if (pInitSecurityInterfaceW)
569                 fnTableW = pInitSecurityInterfaceW();
570             if (fnTableW && fnTableW->EnumerateSecurityPackagesW)
571                 ret = fnTableW->EnumerateSecurityPackagesW(&toAdd, &infoW);
572             else if (fnTableA && fnTableA->EnumerateSecurityPackagesA)
573                 ret = fnTableA->EnumerateSecurityPackagesA(&toAdd, &infoA);
574             if (ret == SEC_E_OK && toAdd > 0 && (infoW || infoA))
575             {
576                 SecureProvider *provider = SECUR32_addProvider(NULL, NULL,
577                  moduleName);
578
579                 if (provider)
580                     SECUR32_addPackages(provider, toAdd, infoA, infoW);
581                 if (infoW)
582                     fnTableW->FreeContextBuffer(infoW);
583                 else
584                     fnTableA->FreeContextBuffer(infoA);
585             }
586         }
587         FreeLibrary(lib);
588     }
589     else
590         WARN("failed to load %s\n", debugstr_w(moduleName));
591 }
592
593 static const WCHAR securityProvidersKeyW[] = {
594  'S','Y','S','T','E','M','\\','C','u','r','r','e','n','t','C','o','n','t','r',
595  'o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','S','e','c','u','r',
596  'i','t','y','P','r','o','v','i','d','e','r','s','\0'
597  };
598 static const WCHAR securityProvidersW[] = {
599  'S','e','c','u','r','i','t','y','P','r','o','v','i','d','e','r','s',0
600  };
601  
602 static void SECUR32_initializeProviders(void)
603 {
604     HKEY key;
605     long apiRet;
606
607     TRACE("\n");
608     InitializeCriticalSection(&cs);
609     /* First load built-in providers */
610     SECUR32_initSchannelSP();
611     /* Now load providers from registry */
612     apiRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, securityProvidersKeyW, 0,
613      KEY_READ, &key);
614     if (apiRet == ERROR_SUCCESS)
615     {
616         WCHAR securityPkgNames[MAX_PATH]; /* arbitrary len */
617         DWORD size = sizeof(securityPkgNames) / sizeof(WCHAR), type;
618
619         apiRet = RegQueryValueExW(key, securityProvidersW, NULL, &type,
620          (PBYTE)securityPkgNames, &size);
621         if (apiRet == ERROR_SUCCESS && type == REG_SZ)
622         {
623             WCHAR *ptr;
624
625             for (ptr = securityPkgNames;
626              ptr < (PWSTR)((PBYTE)securityPkgNames + size); )
627             {
628                 WCHAR *comma;
629
630                 for (comma = ptr; *comma && *comma != ','; comma++)
631                     ;
632                 if (*comma == ',')
633                     *comma = '\0';
634                 for (; *ptr && isspace(*ptr) && ptr < securityPkgNames + size;
635                  ptr++)
636                     ;
637                 if (*ptr)
638                     _tryLoadProvider(ptr);
639                 ptr += lstrlenW(ptr) + 1;
640             }
641         }
642         RegCloseKey(key);
643     }
644 }
645
646 SecurePackage *SECUR32_findPackageW(PWSTR packageName)
647 {
648     SecurePackage *ret = NULL;
649
650     if (packageTable && packageName)
651     {
652         DWORD i;
653
654         for (i = 0, ret = NULL; !ret && i < packageTable->numPackages; i++)
655             if (!lstrcmpiW(packageTable->table[i].infoW.Name, packageName))
656                 ret = &packageTable->table[i];
657         if (ret && ret->provider && !ret->provider->loaded)
658         {
659             ret->provider->lib = LoadLibraryW(ret->provider->moduleName);
660             if (ret->provider->lib)
661             {
662                 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
663                  (INIT_SECURITY_INTERFACE_W)GetProcAddress(ret->provider->lib,
664                  SECURITY_ENTRYPOINT_ANSIW);
665                 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
666                  (INIT_SECURITY_INTERFACE_A)GetProcAddress(ret->provider->lib,
667                  SECURITY_ENTRYPOINT_ANSIA);
668                 PSecurityFunctionTableA fnTableA = NULL;
669                 PSecurityFunctionTableW fnTableW = NULL;
670
671                 if (pInitSecurityInterfaceA)
672                     fnTableA = pInitSecurityInterfaceA();
673                 if (pInitSecurityInterfaceW)
674                     fnTableW = pInitSecurityInterfaceW();
675                 _makeFnTableA(&ret->provider->fnTableA, fnTableA, fnTableW);
676                 _makeFnTableW(&ret->provider->fnTableW, fnTableA, fnTableW);
677                 ret->provider->loaded = TRUE;
678             }
679             else
680                 ret = NULL;
681         }
682     }
683     return ret;
684 }
685
686 SecurePackage *SECUR32_findPackageA(PSTR packageName)
687 {
688     SecurePackage *ret;
689
690     if (packageTable && packageName)
691     {
692         UNICODE_STRING package;
693
694         RtlCreateUnicodeStringFromAsciiz(&package, packageName);
695         ret = SECUR32_findPackageW(package.Buffer);
696         RtlFreeUnicodeString(&package);
697     }
698     else
699         ret = NULL;
700     return ret;
701 }
702
703 static void SECUR32_freeProviders(void)
704 {
705     DWORD i;
706
707     TRACE("\n");
708     EnterCriticalSection(&cs);
709     if (packageTable)
710     {
711         for (i = 0; i < packageTable->numPackages; i++)
712         {
713             SECUR32_FREE(packageTable->table[i].infoW.Name);
714             SECUR32_FREE(packageTable->table[i].infoW.Comment);
715         }
716         HeapFree(GetProcessHeap(), 0, packageTable);
717         packageTable = NULL;
718     }
719     if (providerTable)
720     {
721         for (i = 0; i < providerTable->numProviders; i++)
722         {
723             if (providerTable->table[i].moduleName)
724                 SECUR32_FREE(providerTable->table[i].moduleName);
725             if (providerTable->table[i].lib)
726                 FreeLibrary(providerTable->table[i].lib);
727         }
728         HeapFree(GetProcessHeap(), 0, providerTable);
729         providerTable = NULL;
730     }
731     LeaveCriticalSection(&cs);
732     DeleteCriticalSection(&cs);
733 }
734
735 /***********************************************************************
736  *              FreeContextBuffer (SECUR32.@)
737  *
738  * Doh--if pv was allocated by a crypto package, this may not be correct.
739  * The sample ssp seems to use LocalAlloc/LocalFee, but there doesn't seem to
740  * be any guarantee, nor is there an alloc function in secur32.
741  */
742 SECURITY_STATUS WINAPI FreeContextBuffer(PVOID pv)
743 {
744     SECURITY_STATUS ret;
745
746     /* as it turns out, SECURITY_STATUSes are actually HRESULTS */
747     if (pv)
748     {
749         if (SECUR32_FREE(pv) == NULL)
750             ret = SEC_E_OK;
751         else
752             ret = HRESULT_FROM_WIN32(GetLastError());
753     }
754     else
755         ret = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
756     return ret;
757 }
758
759 /***********************************************************************
760  *              EnumerateSecurityPackagesW (SECUR32.@)
761  */
762 SECURITY_STATUS WINAPI EnumerateSecurityPackagesW(PULONG pcPackages,
763  PSecPkgInfoW *ppPackageInfo)
764 {
765     SECURITY_STATUS ret = SEC_E_OK;
766
767     /* windows just crashes if pcPackages or ppPackageInfo is NULL, so will I */
768     *pcPackages = 0;
769     EnterCriticalSection(&cs);
770     if (packageTable)
771     {
772         ULONG i;
773         size_t bytesNeeded;
774
775         bytesNeeded = packageTable->numPackages * sizeof(SecPkgInfoW);
776         for (i = 0; i < packageTable->numPackages; i++)
777         {
778             if (packageTable->table[i].infoW.Name)
779                 bytesNeeded +=
780                  (lstrlenW(packageTable->table[i].infoW.Name) + 1) *
781                  sizeof(WCHAR);
782             if (packageTable->table[i].infoW.Comment)
783                 bytesNeeded +=
784                  (lstrlenW(packageTable->table[i].infoW.Comment) + 1) *
785                  sizeof(WCHAR);
786         }
787         if (bytesNeeded)
788         {
789             *ppPackageInfo = (PSecPkgInfoW)SECUR32_ALLOC(bytesNeeded);
790             if (*ppPackageInfo)
791             {
792                 PWSTR nextString;
793
794                 *pcPackages = packageTable->numPackages;
795                 nextString = (PWSTR)((PBYTE)*ppPackageInfo +
796                  packageTable->numPackages * sizeof(SecPkgInfoW));
797                 for (i = 0; i < packageTable->numPackages; i++)
798                 {
799                     PSecPkgInfoW pkgInfo = *ppPackageInfo + i;
800
801                     memcpy(pkgInfo, &packageTable->table[i].infoW,
802                      sizeof(SecPkgInfoW));
803                     if (packageTable->table[i].infoW.Name)
804                     {
805                         pkgInfo->Name = nextString;
806                         lstrcpyW(nextString, packageTable->table[i].infoW.Name);
807                         nextString += lstrlenW(nextString) + 1;
808                     }
809                     else
810                         pkgInfo->Name = NULL;
811                     if (packageTable->table[i].infoW.Comment)
812                     {
813                         pkgInfo->Comment = nextString;
814                         lstrcpyW(nextString,
815                          packageTable->table[i].infoW.Comment);
816                         nextString += lstrlenW(nextString) + 1;
817                     }
818                     else
819                         pkgInfo->Comment = NULL;
820                 }
821             }
822             else
823                 ret = SEC_E_INSUFFICIENT_MEMORY;
824         }
825     }
826     LeaveCriticalSection(&cs);
827     return ret;
828 }
829
830 /* Converts info (which is assumed to be an array of cPackages SecPkgInfoW
831  * structures) into an array of SecPkgInfoA structures, which it returns.
832  */
833 static PSecPkgInfoA thunk_PSecPkgInfoWToA(ULONG cPackages,
834  const PSecPkgInfoW info)
835 {
836     PSecPkgInfoA ret;
837
838     if (info)
839     {
840         size_t bytesNeeded = cPackages * sizeof(SecPkgInfoA);
841         ULONG i;
842
843         for (i = 0; i < cPackages; i++)
844         {
845             if (info[i].Name)
846                 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Name,
847                  -1, NULL, 0, NULL, NULL);
848             if (info[i].Comment)
849                 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Comment,
850                  -1, NULL, 0, NULL, NULL);
851         }
852         ret = (PSecPkgInfoA)SECUR32_ALLOC(bytesNeeded);
853         if (ret)
854         {
855             PSTR nextString;
856
857             nextString = (PSTR)((PBYTE)ret + cPackages * sizeof(SecPkgInfoA));
858             for (i = 0; i < cPackages; i++)
859             {
860                 PSecPkgInfoA pkgInfo = ret + i;
861                 int bytes;
862
863                 memcpy(pkgInfo, &info[i], sizeof(SecPkgInfoA));
864                 if (info[i].Name)
865                 {
866                     pkgInfo->Name = nextString;
867                     /* just repeat back to WideCharToMultiByte how many bytes
868                      * it requires, since we asked it earlier
869                      */
870                     bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
871                      NULL, 0, NULL, NULL);
872                     WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
873                      pkgInfo->Name, bytes, NULL, NULL);
874                     nextString += lstrlenA(nextString) + 1;
875                 }
876                 else
877                     pkgInfo->Name = NULL;
878                 if (info[i].Comment)
879                 {
880                     pkgInfo->Comment = nextString;
881                     /* just repeat back to WideCharToMultiByte how many bytes
882                      * it requires, since we asked it earlier
883                      */
884                     bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
885                      NULL, 0, NULL, NULL);
886                     WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
887                      pkgInfo->Comment, bytes, NULL, NULL);
888                     nextString += lstrlenA(nextString) + 1;
889                 }
890                 else
891                     pkgInfo->Comment = NULL;
892             }
893         }
894     }
895     else
896         ret = NULL;
897     return ret;
898 }
899
900 /***********************************************************************
901  *              EnumerateSecurityPackagesA (SECUR32.@)
902  */
903 SECURITY_STATUS WINAPI EnumerateSecurityPackagesA(PULONG pcPackages,
904  PSecPkgInfoA *ppPackageInfo)
905 {
906     SECURITY_STATUS ret;
907     PSecPkgInfoW info;
908
909     ret = EnumerateSecurityPackagesW(pcPackages, &info);
910     if (ret == SEC_E_OK && *pcPackages && info)
911     {
912         *ppPackageInfo = thunk_PSecPkgInfoWToA(*pcPackages, info);
913         if (*pcPackages && !*ppPackageInfo)
914         {
915             *pcPackages = 0;
916             ret = SEC_E_INSUFFICIENT_MEMORY;
917         }
918         FreeContextBuffer(info);
919     }
920     return ret;
921 }
922
923 /***********************************************************************
924  *              GetComputerObjectNameA (SECUR32.@)
925  */
926 BOOLEAN WINAPI GetComputerObjectNameA(
927   EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
928 {
929     FIXME("%d %p %p\n", NameFormat, lpNameBuffer, nSize);
930     return FALSE;
931 }
932
933 /***********************************************************************
934  *              GetComputerObjectNameW (SECUR32.@)
935  */
936 BOOLEAN WINAPI GetComputerObjectNameW(
937   EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
938 {
939     FIXME("%d %p %p\n", NameFormat, lpNameBuffer, nSize);
940     return FALSE;
941 }
942
943 /***********************************************************************
944  *              DllMain (SECUR32.0)
945  */
946 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
947 {
948     if (fdwReason == DLL_PROCESS_ATTACH)
949     {
950         DisableThreadLibraryCalls(hinstDLL);
951         SECUR32_initializeProviders();
952     }
953     else if (fdwReason == DLL_PROCESS_DETACH)
954     {
955         SECUR32_freeProviders();
956     }
957
958     return TRUE;
959 }