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