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