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