secur32: Eliminate broken clean-up "cheat".
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 #include <assert.h>
20 #include <stdarg.h>
21
22 #include "ntstatus.h"
23 #define WIN32_NO_STATUS
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winnls.h"
27 #include "winreg.h"
28 #include "winternl.h"
29 #include "shlwapi.h"
30 #include "sspi.h"
31 #include "secur32_priv.h"
32 #include "secext.h"
33 #include "ntsecapi.h"
34 #include "thunks.h"
35 #include "lmcons.h"
36
37 #include "wine/list.h"
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
41
42 /**
43  *  Type definitions
44  */
45
46 typedef struct _SecurePackageTable
47 {
48     DWORD numPackages;
49     DWORD numAllocated;
50     struct list table;
51 } SecurePackageTable;
52
53 typedef struct _SecureProviderTable
54 {
55     DWORD numProviders;
56     DWORD numAllocated;
57     struct list table;
58 } SecureProviderTable;
59
60 /**
61  *  Prototypes
62  */
63
64 /* Tries to load moduleName as a provider.  If successful, enumerates what
65  * packages it can and adds them to the package and provider tables.  Resizes
66  * tables as necessary.
67  */
68 static void _tryLoadProvider(PWSTR moduleName);
69
70 /* Initialization: read securityproviders value and attempt to open each dll
71  * there.  For each DLL, call _tryLoadProvider to see if it's really an SSP.
72  * Two undocumented functions, AddSecurityPackage(A/W) and
73  * DeleteSecurityPackage(A/W), seem suspiciously like they'd register or
74  * unregister a dll, but I'm not sure.
75  */
76 static void SECUR32_initializeProviders(void);
77
78 /* Frees all loaded packages and providers */
79 static void SECUR32_freeProviders(void);
80
81 /**
82  *  Globals
83  */
84
85 static CRITICAL_SECTION cs;
86 static CRITICAL_SECTION_DEBUG cs_debug =
87 {
88     0, 0, &cs,
89     { &cs_debug.ProcessLocksList, &cs_debug.ProcessLocksList },
90       0, 0, { (DWORD_PTR)(__FILE__ ": cs") }
91 };
92 static CRITICAL_SECTION cs = { &cs_debug, -1, 0, 0, 0, 0 };
93 static SecurePackageTable *packageTable = NULL;
94 static SecureProviderTable *providerTable = NULL;
95
96 static SecurityFunctionTableA securityFunctionTableA = {
97     SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
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     EncryptMessage, /* Reserved3 */
116     DecryptMessage, /* 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,
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     EncryptMessage, /* Reserved3 */
147     DecryptMessage, /* 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 static PWSTR SECUR32_strdupW(PCWSTR str)
175 {
176     PWSTR ret;
177
178     if (str)
179     {
180         ret = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(str) + 1) * sizeof(WCHAR));
181         if (ret)
182             lstrcpyW(ret, str);
183     }
184     else
185         ret = NULL;
186     return ret;
187 }
188
189 PWSTR SECUR32_AllocWideFromMultiByte(PCSTR str)
190 {
191     PWSTR ret;
192
193     if (str)
194     {
195         int charsNeeded = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
196
197         if (charsNeeded)
198         {
199             ret = HeapAlloc(GetProcessHeap(), 0, charsNeeded * sizeof(WCHAR));
200             if (ret)
201                 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, charsNeeded);
202         }
203         else
204             ret = NULL;
205     }
206     else
207         ret = NULL;
208     return ret;
209 }
210
211 PSTR SECUR32_AllocMultiByteFromWide(PCWSTR str)
212 {
213     PSTR ret;
214
215     if (str)
216     {
217         int charsNeeded = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0,
218          NULL, NULL);
219
220         if (charsNeeded)
221         {
222             ret = HeapAlloc(GetProcessHeap(), 0, charsNeeded);
223             if (ret)
224                 WideCharToMultiByte(CP_ACP, 0, str, -1, ret, charsNeeded,
225                  NULL, NULL);
226         }
227         else
228             ret = NULL;
229     }
230     else
231         ret = NULL;
232     return ret;
233 }
234
235 static void _makeFnTableA(PSecurityFunctionTableA fnTableA,
236  const SecurityFunctionTableA *inFnTableA,
237  const SecurityFunctionTableW *inFnTableW)
238 {
239     if (fnTableA)
240     {
241         if (inFnTableA)
242         {
243             /* The size of the version 1 table is based on platform sdk's
244              * sspi.h, though the sample ssp also provided with platform sdk
245              * implies only functions through QuerySecurityPackageInfoA are
246              * implemented (yikes)
247              */
248             size_t tableSize = inFnTableA->dwVersion == 1 ?
249              (const BYTE *)&inFnTableA->SetContextAttributesA -
250              (const BYTE *)inFnTableA : sizeof(SecurityFunctionTableA);
251
252             memcpy(fnTableA, inFnTableA, tableSize);
253             /* override this, since we can do it internally anyway */
254             fnTableA->QuerySecurityPackageInfoA =
255              QuerySecurityPackageInfoA;
256         }
257         else if (inFnTableW)
258         {
259             /* functions with thunks */
260             if (inFnTableW->AcquireCredentialsHandleW)
261                 fnTableA->AcquireCredentialsHandleA =
262                  thunk_AcquireCredentialsHandleA;
263             if (inFnTableW->InitializeSecurityContextW)
264                 fnTableA->InitializeSecurityContextA =
265                  thunk_InitializeSecurityContextA;
266             if (inFnTableW->ImportSecurityContextW)
267                 fnTableA->ImportSecurityContextA =
268                  thunk_ImportSecurityContextA;
269             if (inFnTableW->AddCredentialsW)
270                 fnTableA->AddCredentialsA =
271                  thunk_AddCredentialsA;
272             if (inFnTableW->QueryCredentialsAttributesW)
273                 fnTableA->QueryCredentialsAttributesA =
274                  thunk_QueryCredentialsAttributesA;
275             if (inFnTableW->QueryContextAttributesW)
276                 fnTableA->QueryContextAttributesA =
277                  thunk_QueryContextAttributesA;
278             if (inFnTableW->SetContextAttributesW)
279                 fnTableA->SetContextAttributesA =
280                  thunk_SetContextAttributesA;
281             /* this can't be thunked, there's no extra param to know which
282              * package to forward to */
283             fnTableA->EnumerateSecurityPackagesA = NULL;
284             /* functions with no thunks needed */
285             fnTableA->AcceptSecurityContext = inFnTableW->AcceptSecurityContext;
286             fnTableA->CompleteAuthToken = inFnTableW->CompleteAuthToken;
287             fnTableA->DeleteSecurityContext = inFnTableW->DeleteSecurityContext;
288             fnTableA->ImpersonateSecurityContext =
289              inFnTableW->ImpersonateSecurityContext;
290             fnTableA->RevertSecurityContext = inFnTableW->RevertSecurityContext;
291             fnTableA->MakeSignature = inFnTableW->MakeSignature;
292             fnTableA->VerifySignature = inFnTableW->VerifySignature;
293             fnTableA->FreeContextBuffer = inFnTableW->FreeContextBuffer;
294             fnTableA->QuerySecurityPackageInfoA =
295              QuerySecurityPackageInfoA;
296             fnTableA->ExportSecurityContext =
297              inFnTableW->ExportSecurityContext;
298             fnTableA->QuerySecurityContextToken =
299              inFnTableW->QuerySecurityContextToken;
300             fnTableA->EncryptMessage = inFnTableW->EncryptMessage;
301             fnTableA->DecryptMessage = inFnTableW->DecryptMessage;
302         }
303     }
304 }
305
306 static void _makeFnTableW(PSecurityFunctionTableW fnTableW,
307  const SecurityFunctionTableA *inFnTableA,
308  const SecurityFunctionTableW *inFnTableW)
309 {
310     if (fnTableW)
311     {
312         if (inFnTableW)
313         {
314             /* The size of the version 1 table is based on platform sdk's
315              * sspi.h, though the sample ssp also provided with platform sdk
316              * implies only functions through QuerySecurityPackageInfoA are
317              * implemented (yikes)
318              */
319             size_t tableSize = inFnTableW->dwVersion == 1 ?
320              (const BYTE *)&inFnTableW->SetContextAttributesW -
321              (const BYTE *)inFnTableW : sizeof(SecurityFunctionTableW);
322
323             memcpy(fnTableW, inFnTableW, tableSize);
324             /* override this, since we can do it internally anyway */
325             fnTableW->QuerySecurityPackageInfoW =
326              QuerySecurityPackageInfoW;
327         }
328         else if (inFnTableA)
329         {
330             /* functions with thunks */
331             if (inFnTableA->AcquireCredentialsHandleA)
332                 fnTableW->AcquireCredentialsHandleW =
333                  thunk_AcquireCredentialsHandleW;
334             if (inFnTableA->InitializeSecurityContextA)
335                 fnTableW->InitializeSecurityContextW =
336                  thunk_InitializeSecurityContextW;
337             if (inFnTableA->ImportSecurityContextA)
338                 fnTableW->ImportSecurityContextW =
339                  thunk_ImportSecurityContextW;
340             if (inFnTableA->AddCredentialsA)
341                 fnTableW->AddCredentialsW =
342                  thunk_AddCredentialsW;
343             if (inFnTableA->QueryCredentialsAttributesA)
344                 fnTableW->QueryCredentialsAttributesW =
345                  thunk_QueryCredentialsAttributesW;
346             if (inFnTableA->QueryContextAttributesA)
347                 fnTableW->QueryContextAttributesW =
348                  thunk_QueryContextAttributesW;
349             if (inFnTableA->SetContextAttributesA)
350                 fnTableW->SetContextAttributesW =
351                  thunk_SetContextAttributesW;
352             /* this can't be thunked, there's no extra param to know which
353              * package to forward to */
354             fnTableW->EnumerateSecurityPackagesW = NULL;
355             /* functions with no thunks needed */
356             fnTableW->AcceptSecurityContext = inFnTableA->AcceptSecurityContext;
357             fnTableW->CompleteAuthToken = inFnTableA->CompleteAuthToken;
358             fnTableW->DeleteSecurityContext = inFnTableA->DeleteSecurityContext;
359             fnTableW->ImpersonateSecurityContext =
360              inFnTableA->ImpersonateSecurityContext;
361             fnTableW->RevertSecurityContext = inFnTableA->RevertSecurityContext;
362             fnTableW->MakeSignature = inFnTableA->MakeSignature;
363             fnTableW->VerifySignature = inFnTableA->VerifySignature;
364             fnTableW->FreeContextBuffer = inFnTableA->FreeContextBuffer;
365             fnTableW->QuerySecurityPackageInfoW =
366              QuerySecurityPackageInfoW;
367             fnTableW->ExportSecurityContext =
368              inFnTableA->ExportSecurityContext;
369             fnTableW->QuerySecurityContextToken =
370              inFnTableA->QuerySecurityContextToken;
371             fnTableW->EncryptMessage = inFnTableA->EncryptMessage;
372             fnTableW->DecryptMessage = inFnTableA->DecryptMessage;
373         }
374     }
375 }
376
377 static void _copyPackageInfo(PSecPkgInfoW info, const SecPkgInfoA *inInfoA,
378  const SecPkgInfoW *inInfoW)
379 {
380     if (info && (inInfoA || inInfoW))
381     {
382         /* odd, I know, but up until Name and Comment the structures are
383          * identical
384          */
385         memcpy(info, inInfoW ? inInfoW : (const SecPkgInfoW *)inInfoA, sizeof(*info));
386         if (inInfoW)
387         {
388             info->Name = SECUR32_strdupW(inInfoW->Name);
389             info->Comment = SECUR32_strdupW(inInfoW->Comment);
390         }
391         else
392         {
393             info->Name = SECUR32_AllocWideFromMultiByte(inInfoA->Name);
394             info->Comment = SECUR32_AllocWideFromMultiByte(inInfoA->Comment);
395         }
396     }
397 }
398
399 SecureProvider *SECUR32_addProvider(const SecurityFunctionTableA *fnTableA,
400  const SecurityFunctionTableW *fnTableW, PCWSTR moduleName)
401 {
402     SecureProvider *ret;
403
404     EnterCriticalSection(&cs);
405
406     if (!providerTable)
407     {
408         providerTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SecureProviderTable));
409         if (!providerTable)
410         {
411             LeaveCriticalSection(&cs);
412             return NULL;
413         }
414
415         list_init(&providerTable->table);
416     }
417
418     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(SecureProvider));
419     if (!ret)
420     {
421         LeaveCriticalSection(&cs);
422         return NULL;
423     }
424
425     list_add_tail(&providerTable->table, &ret->entry);
426     ret->lib = NULL;
427
428     if (fnTableA || fnTableW)
429     {
430         ret->moduleName = moduleName ? SECUR32_strdupW(moduleName) : NULL;
431         _makeFnTableA(&ret->fnTableA, fnTableA, fnTableW);
432         _makeFnTableW(&ret->fnTableW, fnTableA, fnTableW);
433         ret->loaded = moduleName ? FALSE : TRUE;
434     }
435     else
436     {
437         ret->moduleName = SECUR32_strdupW(moduleName);
438         ret->loaded = FALSE;
439     }
440     
441     LeaveCriticalSection(&cs);
442     return ret;
443 }
444
445 void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd,
446  const SecPkgInfoA *infoA, const SecPkgInfoW *infoW)
447 {
448     ULONG i;
449
450     assert(provider);
451     assert(infoA || infoW);
452
453     EnterCriticalSection(&cs);
454
455     if (!packageTable)
456     {
457         packageTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackageTable));
458         if (!packageTable)
459         {
460             LeaveCriticalSection(&cs);
461             return;
462         }
463
464         packageTable->numPackages = 0;
465         list_init(&packageTable->table);
466     }
467         
468     for (i = 0; i < toAdd; i++)
469     {
470         SecurePackage *package = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackage));
471         if (!package)
472             continue;
473
474         list_add_tail(&packageTable->table, &package->entry);
475
476         package->provider = provider;
477         _copyPackageInfo(&package->infoW,
478             infoA ? &infoA[i] : NULL,
479             infoW ? &infoW[i] : NULL);
480     }
481     packageTable->numPackages += toAdd;
482
483     LeaveCriticalSection(&cs);
484 }
485
486 static void _tryLoadProvider(PWSTR moduleName)
487 {
488     HMODULE lib = LoadLibraryW(moduleName);
489
490     if (lib)
491     {
492         INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
493          (INIT_SECURITY_INTERFACE_W)GetProcAddress(lib,
494          SECURITY_ENTRYPOINT_ANSIW);
495         INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
496          (INIT_SECURITY_INTERFACE_A)GetProcAddress(lib,
497          SECURITY_ENTRYPOINT_ANSIA);
498
499         TRACE("loaded %s, InitSecurityInterfaceA is %p, InitSecurityInterfaceW is %p\n",
500          debugstr_w(moduleName), pInitSecurityInterfaceA,
501          pInitSecurityInterfaceW);
502         if (pInitSecurityInterfaceW || pInitSecurityInterfaceA)
503         {
504             PSecurityFunctionTableA fnTableA = NULL;
505             PSecurityFunctionTableW fnTableW = NULL;
506             ULONG toAdd = 0;
507             PSecPkgInfoA infoA = NULL;
508             PSecPkgInfoW infoW = NULL;
509             SECURITY_STATUS ret = SEC_E_OK;
510
511             if (pInitSecurityInterfaceA)
512                 fnTableA = pInitSecurityInterfaceA();
513             if (pInitSecurityInterfaceW)
514                 fnTableW = pInitSecurityInterfaceW();
515             if (fnTableW && fnTableW->EnumerateSecurityPackagesW)
516             {
517                 if (fnTableW != &securityFunctionTableW)
518                     ret = fnTableW->EnumerateSecurityPackagesW(&toAdd, &infoW);
519                 else
520                     TRACE("%s has built-in providers, skip adding\n", debugstr_w(moduleName));
521             }
522             else if (fnTableA && fnTableA->EnumerateSecurityPackagesA)
523             {
524                 if (fnTableA != &securityFunctionTableA)
525                     ret = fnTableA->EnumerateSecurityPackagesA(&toAdd, &infoA);
526                 else
527                     TRACE("%s has built-in providers, skip adding\n", debugstr_w(moduleName));
528             }
529             if (ret == SEC_E_OK && toAdd > 0 && (infoW || infoA))
530             {
531                 SecureProvider *provider = SECUR32_addProvider(NULL, NULL,
532                  moduleName);
533
534                 if (provider)
535                     SECUR32_addPackages(provider, toAdd, infoA, infoW);
536                 if (infoW)
537                     fnTableW->FreeContextBuffer(infoW);
538                 else
539                     fnTableA->FreeContextBuffer(infoA);
540             }
541         }
542         FreeLibrary(lib);
543     }
544     else
545         WARN("failed to load %s\n", debugstr_w(moduleName));
546 }
547
548 static const WCHAR securityProvidersKeyW[] = {
549  'S','Y','S','T','E','M','\\','C','u','r','r','e','n','t','C','o','n','t','r',
550  'o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','S','e','c','u','r',
551  'i','t','y','P','r','o','v','i','d','e','r','s','\0'
552  };
553 static const WCHAR securityProvidersW[] = {
554  'S','e','c','u','r','i','t','y','P','r','o','v','i','d','e','r','s',0
555  };
556  
557 static void SECUR32_initializeProviders(void)
558 {
559     HKEY key;
560     LSTATUS apiRet;
561
562     TRACE("\n");
563     /* First load built-in providers */
564     SECUR32_initSchannelSP();
565     SECUR32_initNTLMSP();
566     /* Load the Negotiate provider last so apps stumble over the working NTLM
567      * provider first. Attempting to fix bug #16905 while keeping the
568      * application reported on wine-users on 2006-09-12 working. */
569     SECUR32_initNegotiateSP();
570     /* Now load providers from registry */
571     apiRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, securityProvidersKeyW, 0,
572      KEY_READ, &key);
573     if (apiRet == ERROR_SUCCESS)
574     {
575         WCHAR securityPkgNames[MAX_PATH]; /* arbitrary len */
576         DWORD size = sizeof(securityPkgNames) / sizeof(WCHAR), type;
577
578         apiRet = RegQueryValueExW(key, securityProvidersW, NULL, &type,
579          (PBYTE)securityPkgNames, &size);
580         if (apiRet == ERROR_SUCCESS && type == REG_SZ)
581         {
582             WCHAR *ptr;
583
584             size = size / sizeof(WCHAR);
585             for (ptr = securityPkgNames;
586               ptr < 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(PCWSTR packageName)
607 {
608     SecurePackage *ret = NULL;
609     BOOL matched = FALSE;
610
611     if (packageTable && packageName)
612     {
613         LIST_FOR_EACH_ENTRY(ret, &packageTable->table, SecurePackage, entry)
614         {
615             matched = !lstrcmpiW(ret->infoW.Name, packageName);
616             if (matched)
617                 break;
618         }
619         
620         if (!matched)
621                 return NULL;
622
623         if (ret->provider && !ret->provider->loaded)
624         {
625             ret->provider->lib = LoadLibraryW(ret->provider->moduleName);
626             if (ret->provider->lib)
627             {
628                 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
629                  (INIT_SECURITY_INTERFACE_W)GetProcAddress(ret->provider->lib,
630                  SECURITY_ENTRYPOINT_ANSIW);
631                 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
632                  (INIT_SECURITY_INTERFACE_A)GetProcAddress(ret->provider->lib,
633                  SECURITY_ENTRYPOINT_ANSIA);
634                 PSecurityFunctionTableA fnTableA = NULL;
635                 PSecurityFunctionTableW fnTableW = NULL;
636
637                 if (pInitSecurityInterfaceA)
638                     fnTableA = pInitSecurityInterfaceA();
639                 if (pInitSecurityInterfaceW)
640                     fnTableW = pInitSecurityInterfaceW();
641                 /* don't update built-in SecurityFunctionTable */
642                 if (fnTableA != &securityFunctionTableA)
643                     _makeFnTableA(&ret->provider->fnTableA, fnTableA, fnTableW);
644                 if (fnTableW != &securityFunctionTableW)
645                     _makeFnTableW(&ret->provider->fnTableW, fnTableA, fnTableW);
646                 ret->provider->loaded = TRUE;
647             }
648             else
649                 ret = NULL;
650         }
651     }
652     return ret;
653 }
654
655 SecurePackage *SECUR32_findPackageA(PCSTR packageName)
656 {
657     SecurePackage *ret;
658
659     if (packageTable && packageName)
660     {
661         UNICODE_STRING package;
662
663         RtlCreateUnicodeStringFromAsciiz(&package, packageName);
664         ret = SECUR32_findPackageW(package.Buffer);
665         RtlFreeUnicodeString(&package);
666     }
667     else
668         ret = NULL;
669     return ret;
670 }
671
672 static void SECUR32_freeProviders(void)
673 {
674     TRACE("\n");
675     EnterCriticalSection(&cs);
676
677     SECUR32_deinitSchannelSP();
678
679     if (packageTable)
680     {
681         SecurePackage *package, *package_next;
682         LIST_FOR_EACH_ENTRY_SAFE(package, package_next, &packageTable->table,
683                                  SecurePackage, entry)
684         {
685             HeapFree(GetProcessHeap(), 0, package->infoW.Name);
686             HeapFree(GetProcessHeap(), 0, package->infoW.Comment);
687             HeapFree(GetProcessHeap(), 0, package);
688         }
689
690         HeapFree(GetProcessHeap(), 0, packageTable);
691         packageTable = NULL;
692     }
693
694     if (providerTable)
695     {
696         SecureProvider *provider, *provider_next;
697         LIST_FOR_EACH_ENTRY_SAFE(provider, provider_next, &providerTable->table,
698                                  SecureProvider, entry)
699         {
700             HeapFree(GetProcessHeap(), 0, provider->moduleName);
701             if (provider->lib)
702                 FreeLibrary(provider->lib);
703             HeapFree(GetProcessHeap(), 0, provider);
704         }
705
706         HeapFree(GetProcessHeap(), 0, providerTable);
707         providerTable = NULL;
708     }
709
710     LeaveCriticalSection(&cs);
711     DeleteCriticalSection(&cs);
712 }
713
714 /***********************************************************************
715  *              FreeContextBuffer (SECUR32.@)
716  *
717  * Doh--if pv was allocated by a crypto package, this may not be correct.
718  * The sample ssp seems to use LocalAlloc/LocalFee, but there doesn't seem to
719  * be any guarantee, nor is there an alloc function in secur32.
720  */
721 SECURITY_STATUS WINAPI FreeContextBuffer(PVOID pv)
722 {
723     HeapFree(GetProcessHeap(), 0, pv);
724
725     return SEC_E_OK;
726 }
727
728 /***********************************************************************
729  *              EnumerateSecurityPackagesW (SECUR32.@)
730  */
731 SECURITY_STATUS WINAPI EnumerateSecurityPackagesW(PULONG pcPackages,
732  PSecPkgInfoW *ppPackageInfo)
733 {
734     SECURITY_STATUS ret = SEC_E_OK;
735
736     TRACE("(%p, %p)\n", pcPackages, ppPackageInfo);
737
738     /* windows just crashes if pcPackages or ppPackageInfo is NULL, so will I */
739     *pcPackages = 0;
740     EnterCriticalSection(&cs);
741     if (packageTable)
742     {
743         SecurePackage *package;
744         size_t bytesNeeded;
745
746         bytesNeeded = packageTable->numPackages * sizeof(SecPkgInfoW);
747         LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
748         {
749             if (package->infoW.Name)
750                 bytesNeeded += (lstrlenW(package->infoW.Name) + 1) * sizeof(WCHAR);
751             if (package->infoW.Comment)
752                 bytesNeeded += (lstrlenW(package->infoW.Comment) + 1) * sizeof(WCHAR);
753         }
754         if (bytesNeeded)
755         {
756             *ppPackageInfo = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
757             if (*ppPackageInfo)
758             {
759                 ULONG i = 0;
760                 PWSTR nextString;
761
762                 *pcPackages = packageTable->numPackages;
763                 nextString = (PWSTR)((PBYTE)*ppPackageInfo +
764                  packageTable->numPackages * sizeof(SecPkgInfoW));
765                 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
766                 {
767                     PSecPkgInfoW pkgInfo = *ppPackageInfo + i++;
768
769                     *pkgInfo = package->infoW;
770                     if (package->infoW.Name)
771                     {
772                         TRACE("Name[%d] = %s\n", i - 1, debugstr_w(package->infoW.Name));
773                         pkgInfo->Name = nextString;
774                         lstrcpyW(nextString, package->infoW.Name);
775                         nextString += lstrlenW(nextString) + 1;
776                     }
777                     else
778                         pkgInfo->Name = NULL;
779                     if (package->infoW.Comment)
780                     {
781                         TRACE("Comment[%d] = %s\n", i - 1, debugstr_w(package->infoW.Comment));
782                         pkgInfo->Comment = nextString;
783                         lstrcpyW(nextString, package->infoW.Comment);
784                         nextString += lstrlenW(nextString) + 1;
785                     }
786                     else
787                         pkgInfo->Comment = NULL;
788                 }
789             }
790             else
791                 ret = SEC_E_INSUFFICIENT_MEMORY;
792         }
793     }
794     LeaveCriticalSection(&cs);
795     TRACE("<-- 0x%08x\n", ret);
796     return ret;
797 }
798
799 /* Converts info (which is assumed to be an array of cPackages SecPkgInfoW
800  * structures) into an array of SecPkgInfoA structures, which it returns.
801  */
802 static PSecPkgInfoA thunk_PSecPkgInfoWToA(ULONG cPackages,
803  const SecPkgInfoW *info)
804 {
805     PSecPkgInfoA ret;
806
807     if (info)
808     {
809         size_t bytesNeeded = cPackages * sizeof(SecPkgInfoA);
810         ULONG i;
811
812         for (i = 0; i < cPackages; i++)
813         {
814             if (info[i].Name)
815                 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Name,
816                  -1, NULL, 0, NULL, NULL);
817             if (info[i].Comment)
818                 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Comment,
819                  -1, NULL, 0, NULL, NULL);
820         }
821         ret = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
822         if (ret)
823         {
824             PSTR nextString;
825
826             nextString = (PSTR)((PBYTE)ret + cPackages * sizeof(SecPkgInfoA));
827             for (i = 0; i < cPackages; i++)
828             {
829                 PSecPkgInfoA pkgInfo = ret + i;
830                 int bytes;
831
832                 memcpy(pkgInfo, &info[i], sizeof(SecPkgInfoA));
833                 if (info[i].Name)
834                 {
835                     pkgInfo->Name = nextString;
836                     /* just repeat back to WideCharToMultiByte how many bytes
837                      * it requires, since we asked it earlier
838                      */
839                     bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
840                      NULL, 0, NULL, NULL);
841                     WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
842                      pkgInfo->Name, bytes, NULL, NULL);
843                     nextString += lstrlenA(nextString) + 1;
844                 }
845                 else
846                     pkgInfo->Name = NULL;
847                 if (info[i].Comment)
848                 {
849                     pkgInfo->Comment = nextString;
850                     /* just repeat back to WideCharToMultiByte how many bytes
851                      * it requires, since we asked it earlier
852                      */
853                     bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
854                      NULL, 0, NULL, NULL);
855                     WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
856                      pkgInfo->Comment, bytes, NULL, NULL);
857                     nextString += lstrlenA(nextString) + 1;
858                 }
859                 else
860                     pkgInfo->Comment = NULL;
861             }
862         }
863     }
864     else
865         ret = NULL;
866     return ret;
867 }
868
869 /***********************************************************************
870  *              EnumerateSecurityPackagesA (SECUR32.@)
871  */
872 SECURITY_STATUS WINAPI EnumerateSecurityPackagesA(PULONG pcPackages,
873  PSecPkgInfoA *ppPackageInfo)
874 {
875     SECURITY_STATUS ret;
876     PSecPkgInfoW info;
877
878     ret = EnumerateSecurityPackagesW(pcPackages, &info);
879     if (ret == SEC_E_OK && *pcPackages && info)
880     {
881         *ppPackageInfo = thunk_PSecPkgInfoWToA(*pcPackages, info);
882         if (*pcPackages && !*ppPackageInfo)
883         {
884             *pcPackages = 0;
885             ret = SEC_E_INSUFFICIENT_MEMORY;
886         }
887         FreeContextBuffer(info);
888     }
889     return ret;
890 }
891
892 /***********************************************************************
893  *              GetComputerObjectNameA (SECUR32.@)
894  *
895  * Get the local computer's name using the format specified.
896  *
897  * PARAMS
898  *  NameFormat   [I] The format for the name.
899  *  lpNameBuffer [O] Pointer to buffer to receive the name.
900  *  nSize        [I/O] Size in characters of buffer.
901  *
902  * RETURNS
903  *  TRUE  If the name was written to lpNameBuffer.
904  *  FALSE If the name couldn't be written.
905  *
906  * NOTES
907  *  If lpNameBuffer is NULL, then the size of the buffer needed to hold the
908  *  name will be returned in *nSize.
909  *
910  *  nSize returns the number of characters written when lpNameBuffer is not
911  *  NULL or the size of the buffer needed to hold the name when the buffer
912  *  is too short or lpNameBuffer is NULL.
913  * 
914  *  It the buffer is too short, ERROR_INSUFFICIENT_BUFFER error will be set.
915  */
916 BOOLEAN WINAPI GetComputerObjectNameA(
917   EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
918 {
919     BOOLEAN rc;
920     LPWSTR bufferW = NULL;
921     ULONG sizeW = *nSize;
922     TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
923     if (lpNameBuffer) {
924         bufferW = HeapAlloc(GetProcessHeap(), 0, sizeW * sizeof(WCHAR));
925         if (bufferW == NULL) {
926             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
927             return FALSE;
928         }
929     }
930     rc = GetComputerObjectNameW(NameFormat, bufferW, &sizeW);
931     if (rc && bufferW) {
932         ULONG len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
933         WideCharToMultiByte(CP_ACP, 0, bufferW, -1, lpNameBuffer, *nSize, NULL, NULL);
934         *nSize = len;
935     }
936     else
937         *nSize = sizeW;
938     HeapFree(GetProcessHeap(), 0, bufferW);
939     return rc;
940 }
941
942 /***********************************************************************
943  *              GetComputerObjectNameW (SECUR32.@)
944  */
945 BOOLEAN WINAPI GetComputerObjectNameW(
946   EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
947 {
948     LSA_HANDLE policyHandle;
949     LSA_OBJECT_ATTRIBUTES objectAttributes;
950     PPOLICY_DNS_DOMAIN_INFO domainInfo;
951     NTSTATUS ntStatus;
952     BOOLEAN status;
953     TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
954
955     if (NameFormat == NameUnknown)
956     {
957         SetLastError(ERROR_INVALID_PARAMETER);
958         return FALSE;
959     }
960
961     ZeroMemory(&objectAttributes, sizeof(objectAttributes));
962     objectAttributes.Length = sizeof(objectAttributes);
963
964     ntStatus = LsaOpenPolicy(NULL, &objectAttributes,
965                              POLICY_VIEW_LOCAL_INFORMATION,
966                              &policyHandle);
967     if (ntStatus != STATUS_SUCCESS)
968     {
969         SetLastError(LsaNtStatusToWinError(ntStatus));
970         WARN("LsaOpenPolicy failed with NT status %u\n", GetLastError());
971         return FALSE;
972     }
973
974     ntStatus = LsaQueryInformationPolicy(policyHandle,
975                                          PolicyDnsDomainInformation,
976                                          (PVOID *)&domainInfo);
977     if (ntStatus != STATUS_SUCCESS)
978     {
979         SetLastError(LsaNtStatusToWinError(ntStatus));
980         WARN("LsaQueryInformationPolicy failed with NT status %u\n",
981              GetLastError());
982         LsaClose(policyHandle);
983         return FALSE;
984     }
985
986     if (domainInfo->Sid)
987     {
988         switch (NameFormat)
989         {
990         case NameSamCompatible:
991             {
992                 WCHAR name[MAX_COMPUTERNAME_LENGTH + 1];
993                 DWORD size = sizeof(name)/sizeof(name[0]);
994                 if (GetComputerNameW(name, &size))
995                 {
996                     DWORD len = domainInfo->Name.Length + size + 3;
997                     if (lpNameBuffer)
998                     {
999                         if (*nSize < len)
1000                         {
1001                             *nSize = len;
1002                             SetLastError(ERROR_INSUFFICIENT_BUFFER);
1003                             status = FALSE;
1004                         }
1005                         else
1006                         {
1007                             WCHAR bs[] = { '\\', 0 };
1008                             WCHAR ds[] = { '$', 0 };
1009                             lstrcpyW(lpNameBuffer, domainInfo->Name.Buffer);
1010                             lstrcatW(lpNameBuffer, bs);
1011                             lstrcatW(lpNameBuffer, name);
1012                             lstrcatW(lpNameBuffer, ds);
1013                             status = TRUE;
1014                         }
1015                     }
1016                     else        /* just requesting length required */
1017                     {
1018                         *nSize = len;
1019                         status = TRUE;
1020                     }
1021                 }
1022                 else
1023                 {
1024                     SetLastError(ERROR_INTERNAL_ERROR);
1025                     status = FALSE;
1026                 }
1027             }
1028             break;
1029         case NameFullyQualifiedDN:
1030         case NameDisplay:
1031         case NameUniqueId:
1032         case NameCanonical:
1033         case NameUserPrincipal:
1034         case NameCanonicalEx:
1035         case NameServicePrincipal:
1036         case NameDnsDomain:
1037             FIXME("NameFormat %d not implemented\n", NameFormat);
1038             SetLastError(ERROR_CANT_ACCESS_DOMAIN_INFO);
1039             status = FALSE;
1040             break;
1041         default:
1042             SetLastError(ERROR_INVALID_PARAMETER);
1043             status = FALSE;
1044         }
1045     }
1046     else
1047     {
1048         SetLastError(ERROR_CANT_ACCESS_DOMAIN_INFO);
1049         status = FALSE;
1050     }
1051
1052     LsaFreeMemory(domainInfo);
1053     LsaClose(policyHandle);
1054
1055     return status;
1056 }
1057
1058 /***********************************************************************
1059  *              GetUserNameExA (SECUR32.@)
1060  */
1061 BOOLEAN WINAPI GetUserNameExA(
1062   EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
1063 {
1064     BOOLEAN rc;
1065     LPWSTR bufferW = NULL;
1066     ULONG sizeW = *nSize;
1067     TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
1068     if (lpNameBuffer) {
1069         bufferW = HeapAlloc(GetProcessHeap(), 0, sizeW * sizeof(WCHAR));
1070         if (bufferW == NULL) {
1071             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1072             return FALSE;
1073         }
1074     }
1075     rc = GetUserNameExW(NameFormat, bufferW, &sizeW);
1076     if (rc) {
1077         ULONG len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
1078         if (len <= *nSize)
1079         {
1080             WideCharToMultiByte(CP_ACP, 0, bufferW, -1, lpNameBuffer, *nSize, NULL, NULL);
1081             *nSize = len - 1;
1082         }
1083         else
1084         {
1085             *nSize = len;
1086             rc = FALSE;
1087             SetLastError(ERROR_MORE_DATA);
1088         }
1089     }
1090     else
1091         *nSize = sizeW;
1092     HeapFree(GetProcessHeap(), 0, bufferW);
1093     return rc;
1094 }
1095
1096 BOOLEAN WINAPI GetUserNameExW(
1097   EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
1098 {
1099     BOOLEAN status;
1100     WCHAR samname[UNLEN + 1 + MAX_COMPUTERNAME_LENGTH + 1];
1101     LPWSTR out;
1102     DWORD len;
1103     TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
1104
1105     switch (NameFormat)
1106     {
1107     case NameSamCompatible:
1108         {
1109             /* This assumes the current user is always a local account */
1110             len = MAX_COMPUTERNAME_LENGTH + 1;
1111             if (GetComputerNameW(samname, &len))
1112             {
1113                 out = samname + lstrlenW(samname);
1114                 *out++ = '\\';
1115                 len = UNLEN + 1;
1116                 if (GetUserNameW(out, &len))
1117                 {
1118                     status = (lstrlenW(samname) < *nSize);
1119                     if (status)
1120                     {
1121                         lstrcpyW(lpNameBuffer, samname);
1122                         *nSize = lstrlenW(samname);
1123                     }
1124                     else
1125                     {
1126                         SetLastError(ERROR_MORE_DATA);
1127                         *nSize = lstrlenW(samname) + 1;
1128                     }
1129                 }
1130                 else
1131                     status = FALSE;
1132             }
1133             else
1134                 status = FALSE;
1135         }
1136         break;
1137     case NameUnknown:
1138     case NameFullyQualifiedDN:
1139     case NameDisplay:
1140     case NameUniqueId:
1141     case NameCanonical:
1142     case NameUserPrincipal:
1143     case NameCanonicalEx:
1144     case NameServicePrincipal:
1145     case NameDnsDomain:
1146         SetLastError(ERROR_NONE_MAPPED);
1147         status = FALSE;
1148         break;
1149     default:
1150         SetLastError(ERROR_INVALID_PARAMETER);
1151         status = FALSE;
1152     }
1153
1154     return status;
1155 }
1156
1157 BOOLEAN WINAPI TranslateNameA(
1158   LPCSTR lpAccountName, EXTENDED_NAME_FORMAT AccountNameFormat,
1159   EXTENDED_NAME_FORMAT DesiredNameFormat, LPSTR lpTranslatedName,
1160   PULONG nSize)
1161 {
1162     FIXME("%p %d %d %p %p\n", lpAccountName, AccountNameFormat,
1163           DesiredNameFormat, lpTranslatedName, nSize);
1164     return FALSE;
1165 }
1166
1167 BOOLEAN WINAPI TranslateNameW(
1168   LPCWSTR lpAccountName, EXTENDED_NAME_FORMAT AccountNameFormat,
1169   EXTENDED_NAME_FORMAT DesiredNameFormat, LPWSTR lpTranslatedName,
1170   PULONG nSize)
1171 {
1172     FIXME("%p %d %d %p %p\n", lpAccountName, AccountNameFormat,
1173           DesiredNameFormat, lpTranslatedName, nSize);
1174     return FALSE;
1175 }
1176
1177 /***********************************************************************
1178  *              DllMain (SECUR32.0)
1179  */
1180 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1181 {
1182     if (fdwReason == DLL_PROCESS_ATTACH)
1183     {
1184         DisableThreadLibraryCalls(hinstDLL);
1185         SECUR32_initializeProviders();
1186     }
1187     else if (fdwReason == DLL_PROCESS_DETACH)
1188     {
1189         SECUR32_freeProviders();
1190     }
1191
1192     return TRUE;
1193 }