oleaut32/tests: Replace realloc() with HeapReAlloc().
[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     /* Do not load Negotiate yet. This breaks for some user on the wine-users
561      * mailing list as of 2006-09-12. Without Negotiate, applications should
562      * fall back to NTLM and that should work.*/
563 #if 0
564     SECUR32_initNegotiateSP();
565 #endif
566     SECUR32_initNTLMSP();
567     /* Now load providers from registry */
568     apiRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, securityProvidersKeyW, 0,
569      KEY_READ, &key);
570     if (apiRet == ERROR_SUCCESS)
571     {
572         WCHAR securityPkgNames[MAX_PATH]; /* arbitrary len */
573         DWORD size = sizeof(securityPkgNames) / sizeof(WCHAR), type;
574
575         apiRet = RegQueryValueExW(key, securityProvidersW, NULL, &type,
576          (PBYTE)securityPkgNames, &size);
577         if (apiRet == ERROR_SUCCESS && type == REG_SZ)
578         {
579             WCHAR *ptr;
580
581             size = size / sizeof(WCHAR);
582             for (ptr = securityPkgNames;
583               ptr < securityPkgNames + size; )
584             {
585                 WCHAR *comma;
586
587                 for (comma = ptr; *comma && *comma != ','; comma++)
588                     ;
589                 if (*comma == ',')
590                     *comma = '\0';
591                 for (; *ptr && isspace(*ptr) && ptr < securityPkgNames + size;
592                  ptr++)
593                     ;
594                 if (*ptr)
595                     _tryLoadProvider(ptr);
596                 ptr += lstrlenW(ptr) + 1;
597             }
598         }
599         RegCloseKey(key);
600     }
601 }
602
603 SecurePackage *SECUR32_findPackageW(PCWSTR packageName)
604 {
605     SecurePackage *ret = NULL;
606     BOOL matched = FALSE;
607
608     if (packageTable && packageName)
609     {
610         LIST_FOR_EACH_ENTRY(ret, &packageTable->table, SecurePackage, entry)
611         {
612             matched = !lstrcmpiW(ret->infoW.Name, packageName);
613             if (matched)
614                 break;
615         }
616         
617         if (!matched)
618                 return NULL;
619
620         if (ret->provider && !ret->provider->loaded)
621         {
622             ret->provider->lib = LoadLibraryW(ret->provider->moduleName);
623             if (ret->provider->lib)
624             {
625                 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
626                  (INIT_SECURITY_INTERFACE_W)GetProcAddress(ret->provider->lib,
627                  SECURITY_ENTRYPOINT_ANSIW);
628                 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
629                  (INIT_SECURITY_INTERFACE_A)GetProcAddress(ret->provider->lib,
630                  SECURITY_ENTRYPOINT_ANSIA);
631                 PSecurityFunctionTableA fnTableA = NULL;
632                 PSecurityFunctionTableW fnTableW = NULL;
633
634                 if (pInitSecurityInterfaceA)
635                     fnTableA = pInitSecurityInterfaceA();
636                 if (pInitSecurityInterfaceW)
637                     fnTableW = pInitSecurityInterfaceW();
638                 /* don't update built-in SecurityFunctionTable */
639                 if (fnTableA != &securityFunctionTableA)
640                     _makeFnTableA(&ret->provider->fnTableA, fnTableA, fnTableW);
641                 if (fnTableW != &securityFunctionTableW)
642                     _makeFnTableW(&ret->provider->fnTableW, fnTableA, fnTableW);
643                 ret->provider->loaded = TRUE;
644             }
645             else
646                 ret = NULL;
647         }
648     }
649     return ret;
650 }
651
652 SecurePackage *SECUR32_findPackageA(PCSTR packageName)
653 {
654     SecurePackage *ret;
655
656     if (packageTable && packageName)
657     {
658         UNICODE_STRING package;
659
660         RtlCreateUnicodeStringFromAsciiz(&package, packageName);
661         ret = SECUR32_findPackageW(package.Buffer);
662         RtlFreeUnicodeString(&package);
663     }
664     else
665         ret = NULL;
666     return ret;
667 }
668
669 static void SECUR32_freeProviders(void)
670 {
671     SecurePackage *package;
672     SecureProvider *provider;
673
674     TRACE("\n");
675     EnterCriticalSection(&cs);
676
677     SECUR32_deinitSchannelSP();
678
679     if (packageTable)
680     {
681         LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
682         {
683             HeapFree(GetProcessHeap(), 0, package->infoW.Name);
684             HeapFree(GetProcessHeap(), 0, package->infoW.Comment);
685         }
686
687         HeapFree(GetProcessHeap(), 0, packageTable);
688         packageTable = NULL;
689     }
690
691     if (providerTable)
692     {
693         LIST_FOR_EACH_ENTRY(provider, &providerTable->table, SecureProvider, entry)
694         {
695             HeapFree(GetProcessHeap(), 0, provider->moduleName);
696             if (provider->lib)
697                 FreeLibrary(provider->lib);
698         }
699
700         HeapFree(GetProcessHeap(), 0, providerTable);
701         providerTable = NULL;
702     }
703
704     LeaveCriticalSection(&cs);
705     cs.DebugInfo->Spare[0] = 0;
706     DeleteCriticalSection(&cs);
707 }
708
709 /***********************************************************************
710  *              FreeContextBuffer (SECUR32.@)
711  *
712  * Doh--if pv was allocated by a crypto package, this may not be correct.
713  * The sample ssp seems to use LocalAlloc/LocalFee, but there doesn't seem to
714  * be any guarantee, nor is there an alloc function in secur32.
715  */
716 SECURITY_STATUS WINAPI FreeContextBuffer(PVOID pv)
717 {
718     HeapFree(GetProcessHeap(), 0, pv);
719
720     return SEC_E_OK;
721 }
722
723 /***********************************************************************
724  *              EnumerateSecurityPackagesW (SECUR32.@)
725  */
726 SECURITY_STATUS WINAPI EnumerateSecurityPackagesW(PULONG pcPackages,
727  PSecPkgInfoW *ppPackageInfo)
728 {
729     SECURITY_STATUS ret = SEC_E_OK;
730
731     TRACE("(%p, %p)\n", pcPackages, ppPackageInfo);
732
733     /* windows just crashes if pcPackages or ppPackageInfo is NULL, so will I */
734     *pcPackages = 0;
735     EnterCriticalSection(&cs);
736     if (packageTable)
737     {
738         SecurePackage *package;
739         size_t bytesNeeded;
740
741         bytesNeeded = packageTable->numPackages * sizeof(SecPkgInfoW);
742         LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
743         {
744             if (package->infoW.Name)
745                 bytesNeeded += (lstrlenW(package->infoW.Name) + 1) * sizeof(WCHAR);
746             if (package->infoW.Comment)
747                 bytesNeeded += (lstrlenW(package->infoW.Comment) + 1) * sizeof(WCHAR);
748         }
749         if (bytesNeeded)
750         {
751             *ppPackageInfo = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
752             if (*ppPackageInfo)
753             {
754                 ULONG i = 0;
755                 PWSTR nextString;
756
757                 *pcPackages = packageTable->numPackages;
758                 nextString = (PWSTR)((PBYTE)*ppPackageInfo +
759                  packageTable->numPackages * sizeof(SecPkgInfoW));
760                 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
761                 {
762                     PSecPkgInfoW pkgInfo = *ppPackageInfo + i++;
763
764                     *pkgInfo = package->infoW;
765                     if (package->infoW.Name)
766                     {
767                         TRACE("Name[%d] = %s\n", i - 1, debugstr_w(package->infoW.Name));
768                         pkgInfo->Name = nextString;
769                         lstrcpyW(nextString, package->infoW.Name);
770                         nextString += lstrlenW(nextString) + 1;
771                     }
772                     else
773                         pkgInfo->Name = NULL;
774                     if (package->infoW.Comment)
775                     {
776                         TRACE("Comment[%d] = %s\n", i - 1, debugstr_w(package->infoW.Comment));
777                         pkgInfo->Comment = nextString;
778                         lstrcpyW(nextString, package->infoW.Comment);
779                         nextString += lstrlenW(nextString) + 1;
780                     }
781                     else
782                         pkgInfo->Comment = NULL;
783                 }
784             }
785             else
786                 ret = SEC_E_INSUFFICIENT_MEMORY;
787         }
788     }
789     LeaveCriticalSection(&cs);
790     TRACE("<-- 0x%08x\n", ret);
791     return ret;
792 }
793
794 /* Converts info (which is assumed to be an array of cPackages SecPkgInfoW
795  * structures) into an array of SecPkgInfoA structures, which it returns.
796  */
797 static PSecPkgInfoA thunk_PSecPkgInfoWToA(ULONG cPackages,
798  const SecPkgInfoW *info)
799 {
800     PSecPkgInfoA ret;
801
802     if (info)
803     {
804         size_t bytesNeeded = cPackages * sizeof(SecPkgInfoA);
805         ULONG i;
806
807         for (i = 0; i < cPackages; i++)
808         {
809             if (info[i].Name)
810                 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Name,
811                  -1, NULL, 0, NULL, NULL);
812             if (info[i].Comment)
813                 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Comment,
814                  -1, NULL, 0, NULL, NULL);
815         }
816         ret = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
817         if (ret)
818         {
819             PSTR nextString;
820
821             nextString = (PSTR)((PBYTE)ret + cPackages * sizeof(SecPkgInfoA));
822             for (i = 0; i < cPackages; i++)
823             {
824                 PSecPkgInfoA pkgInfo = ret + i;
825                 int bytes;
826
827                 memcpy(pkgInfo, &info[i], sizeof(SecPkgInfoA));
828                 if (info[i].Name)
829                 {
830                     pkgInfo->Name = nextString;
831                     /* just repeat back to WideCharToMultiByte how many bytes
832                      * it requires, since we asked it earlier
833                      */
834                     bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
835                      NULL, 0, NULL, NULL);
836                     WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
837                      pkgInfo->Name, bytes, NULL, NULL);
838                     nextString += lstrlenA(nextString) + 1;
839                 }
840                 else
841                     pkgInfo->Name = NULL;
842                 if (info[i].Comment)
843                 {
844                     pkgInfo->Comment = nextString;
845                     /* just repeat back to WideCharToMultiByte how many bytes
846                      * it requires, since we asked it earlier
847                      */
848                     bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
849                      NULL, 0, NULL, NULL);
850                     WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
851                      pkgInfo->Comment, bytes, NULL, NULL);
852                     nextString += lstrlenA(nextString) + 1;
853                 }
854                 else
855                     pkgInfo->Comment = NULL;
856             }
857         }
858     }
859     else
860         ret = NULL;
861     return ret;
862 }
863
864 /***********************************************************************
865  *              EnumerateSecurityPackagesA (SECUR32.@)
866  */
867 SECURITY_STATUS WINAPI EnumerateSecurityPackagesA(PULONG pcPackages,
868  PSecPkgInfoA *ppPackageInfo)
869 {
870     SECURITY_STATUS ret;
871     PSecPkgInfoW info;
872
873     ret = EnumerateSecurityPackagesW(pcPackages, &info);
874     if (ret == SEC_E_OK && *pcPackages && info)
875     {
876         *ppPackageInfo = thunk_PSecPkgInfoWToA(*pcPackages, info);
877         if (*pcPackages && !*ppPackageInfo)
878         {
879             *pcPackages = 0;
880             ret = SEC_E_INSUFFICIENT_MEMORY;
881         }
882         FreeContextBuffer(info);
883     }
884     return ret;
885 }
886
887 /***********************************************************************
888  *              GetComputerObjectNameA (SECUR32.@)
889  *
890  * Get the local computer's name using the format specified.
891  *
892  * PARAMS
893  *  NameFormat   [I] The format for the name.
894  *  lpNameBuffer [O] Pointer to buffer to receive the name.
895  *  nSize        [I/O] Size in characters of buffer.
896  *
897  * RETURNS
898  *  TRUE  If the name was written to lpNameBuffer.
899  *  FALSE If the name couldn't be written.
900  *
901  * NOTES
902  *  If lpNameBuffer is NULL, then the size of the buffer needed to hold the
903  *  name will be returned in *nSize.
904  *
905  *  nSize returns the number of characters written when lpNameBuffer is not
906  *  NULL or the size of the buffer needed to hold the name when the buffer
907  *  is too short or lpNameBuffer is NULL.
908  * 
909  *  It the buffer is too short, ERROR_INSUFFICIENT_BUFFER error will be set.
910  */
911 BOOLEAN WINAPI GetComputerObjectNameA(
912   EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
913 {
914     BOOLEAN rc;
915     LPWSTR bufferW = NULL;
916     ULONG sizeW = *nSize;
917     TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
918     if (lpNameBuffer) {
919         bufferW = HeapAlloc(GetProcessHeap(), 0, sizeW * sizeof(WCHAR));
920         if (bufferW == NULL) {
921             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
922             return FALSE;
923         }
924     }
925     rc = GetComputerObjectNameW(NameFormat, bufferW, &sizeW);
926     if (rc && bufferW) {
927         ULONG len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
928         WideCharToMultiByte(CP_ACP, 0, bufferW, -1, lpNameBuffer, *nSize, NULL, NULL);
929         *nSize = len;
930     }
931     else
932         *nSize = sizeW;
933     HeapFree(GetProcessHeap(), 0, bufferW);
934     return rc;
935 }
936
937 /***********************************************************************
938  *              GetComputerObjectNameW (SECUR32.@)
939  */
940 BOOLEAN WINAPI GetComputerObjectNameW(
941   EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
942 {
943     LSA_HANDLE policyHandle;
944     LSA_OBJECT_ATTRIBUTES objectAttributes;
945     PPOLICY_DNS_DOMAIN_INFO domainInfo;
946     NTSTATUS ntStatus;
947     BOOLEAN status;
948     TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
949
950     if (NameFormat == NameUnknown)
951     {
952         SetLastError(ERROR_INVALID_PARAMETER);
953         return FALSE;
954     }
955
956     ZeroMemory(&objectAttributes, sizeof(objectAttributes));
957     objectAttributes.Length = sizeof(objectAttributes);
958
959     ntStatus = LsaOpenPolicy(NULL, &objectAttributes,
960                              POLICY_VIEW_LOCAL_INFORMATION,
961                              &policyHandle);
962     if (ntStatus != STATUS_SUCCESS)
963     {
964         SetLastError(LsaNtStatusToWinError(ntStatus));
965         WARN("LsaOpenPolicy failed with NT status %u\n", GetLastError());
966         return FALSE;
967     }
968
969     ntStatus = LsaQueryInformationPolicy(policyHandle,
970                                          PolicyDnsDomainInformation,
971                                          (PVOID *)&domainInfo);
972     if (ntStatus != STATUS_SUCCESS)
973     {
974         SetLastError(LsaNtStatusToWinError(ntStatus));
975         WARN("LsaQueryInformationPolicy failed with NT status %u\n",
976              GetLastError());
977         LsaClose(policyHandle);
978         return FALSE;
979     }
980
981     if (domainInfo->Sid)
982     {
983         switch (NameFormat)
984         {
985         case NameSamCompatible:
986             {
987                 WCHAR name[MAX_COMPUTERNAME_LENGTH + 1];
988                 DWORD size = sizeof(name)/sizeof(name[0]);
989                 if (GetComputerNameW(name, &size))
990                 {
991                     DWORD len = domainInfo->Name.Length + size + 3;
992                     if (lpNameBuffer)
993                     {
994                         if (*nSize < len)
995                         {
996                             *nSize = len;
997                             SetLastError(ERROR_INSUFFICIENT_BUFFER);
998                             status = FALSE;
999                         }
1000                         else
1001                         {
1002                             WCHAR bs[] = { '\\', 0 };
1003                             WCHAR ds[] = { '$', 0 };
1004                             lstrcpyW(lpNameBuffer, domainInfo->Name.Buffer);
1005                             lstrcatW(lpNameBuffer, bs);
1006                             lstrcatW(lpNameBuffer, name);
1007                             lstrcatW(lpNameBuffer, ds);
1008                             status = TRUE;
1009                         }
1010                     }
1011                     else        /* just requesting length required */
1012                     {
1013                         *nSize = len;
1014                         status = TRUE;
1015                     }
1016                 }
1017                 else
1018                 {
1019                     SetLastError(ERROR_INTERNAL_ERROR);
1020                     status = FALSE;
1021                 }
1022             }
1023             break;
1024         case NameFullyQualifiedDN:
1025         case NameDisplay:
1026         case NameUniqueId:
1027         case NameCanonical:
1028         case NameUserPrincipal:
1029         case NameCanonicalEx:
1030         case NameServicePrincipal:
1031         case NameDnsDomain:
1032             FIXME("NameFormat %d not implemented\n", NameFormat);
1033             SetLastError(ERROR_CANT_ACCESS_DOMAIN_INFO);
1034             status = FALSE;
1035             break;
1036         default:
1037             SetLastError(ERROR_INVALID_PARAMETER);
1038             status = FALSE;
1039         }
1040     }
1041     else
1042     {
1043         SetLastError(ERROR_CANT_ACCESS_DOMAIN_INFO);
1044         status = FALSE;
1045     }
1046
1047     LsaFreeMemory(domainInfo);
1048     LsaClose(policyHandle);
1049
1050     return status;
1051 }
1052
1053 /***********************************************************************
1054  *              GetUserNameExA (SECUR32.@)
1055  */
1056 BOOLEAN WINAPI GetUserNameExA(
1057   EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
1058 {
1059     BOOLEAN rc;
1060     LPWSTR bufferW = NULL;
1061     ULONG sizeW = *nSize;
1062     TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
1063     if (lpNameBuffer) {
1064         bufferW = HeapAlloc(GetProcessHeap(), 0, sizeW * sizeof(WCHAR));
1065         if (bufferW == NULL) {
1066             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1067             return FALSE;
1068         }
1069     }
1070     rc = GetUserNameExW(NameFormat, bufferW, &sizeW);
1071     if (rc) {
1072         ULONG len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
1073         if (len <= *nSize)
1074         {
1075             WideCharToMultiByte(CP_ACP, 0, bufferW, -1, lpNameBuffer, *nSize, NULL, NULL);
1076             *nSize = len - 1;
1077         }
1078         else
1079         {
1080             *nSize = len;
1081             rc = FALSE;
1082             SetLastError(ERROR_MORE_DATA);
1083         }
1084     }
1085     else
1086         *nSize = sizeW;
1087     HeapFree(GetProcessHeap(), 0, bufferW);
1088     return rc;
1089 }
1090
1091 BOOLEAN WINAPI GetUserNameExW(
1092   EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
1093 {
1094     BOOLEAN status;
1095     WCHAR samname[UNLEN + 1 + MAX_COMPUTERNAME_LENGTH + 1];
1096     LPWSTR out;
1097     DWORD len;
1098     TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
1099
1100     switch (NameFormat)
1101     {
1102     case NameSamCompatible:
1103         {
1104             /* This assumes the current user is always a local account */
1105             len = MAX_COMPUTERNAME_LENGTH + 1;
1106             if (GetComputerNameW(samname, &len))
1107             {
1108                 out = samname + lstrlenW(samname);
1109                 *out++ = '\\';
1110                 len = UNLEN + 1;
1111                 if (GetUserNameW(out, &len))
1112                 {
1113                     status = (lstrlenW(samname) < *nSize);
1114                     if (status)
1115                     {
1116                         lstrcpyW(lpNameBuffer, samname);
1117                         *nSize = lstrlenW(samname);
1118                     }
1119                     else
1120                     {
1121                         SetLastError(ERROR_MORE_DATA);
1122                         *nSize = lstrlenW(samname) + 1;
1123                     }
1124                 }
1125                 else
1126                     status = FALSE;
1127             }
1128             else
1129                 status = FALSE;
1130         }
1131         break;
1132     case NameUnknown:
1133     case NameFullyQualifiedDN:
1134     case NameDisplay:
1135     case NameUniqueId:
1136     case NameCanonical:
1137     case NameUserPrincipal:
1138     case NameCanonicalEx:
1139     case NameServicePrincipal:
1140     case NameDnsDomain:
1141         SetLastError(ERROR_NONE_MAPPED);
1142         status = FALSE;
1143         break;
1144     default:
1145         SetLastError(ERROR_INVALID_PARAMETER);
1146         status = FALSE;
1147     }
1148
1149     return status;
1150 }
1151
1152 BOOLEAN WINAPI TranslateNameA(
1153   LPCSTR lpAccountName, EXTENDED_NAME_FORMAT AccountNameFormat,
1154   EXTENDED_NAME_FORMAT DesiredNameFormat, LPSTR lpTranslatedName,
1155   PULONG nSize)
1156 {
1157     FIXME("%p %d %d %p %p\n", lpAccountName, AccountNameFormat,
1158           DesiredNameFormat, lpTranslatedName, nSize);
1159     return FALSE;
1160 }
1161
1162 BOOLEAN WINAPI TranslateNameW(
1163   LPCWSTR lpAccountName, EXTENDED_NAME_FORMAT AccountNameFormat,
1164   EXTENDED_NAME_FORMAT DesiredNameFormat, LPWSTR lpTranslatedName,
1165   PULONG nSize)
1166 {
1167     FIXME("%p %d %d %p %p\n", lpAccountName, AccountNameFormat,
1168           DesiredNameFormat, lpTranslatedName, nSize);
1169     return FALSE;
1170 }
1171
1172 /***********************************************************************
1173  *              DllMain (SECUR32.0)
1174  */
1175 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1176 {
1177     if (fdwReason == DLL_PROCESS_ATTACH)
1178     {
1179         DisableThreadLibraryCalls(hinstDLL);
1180         SECUR32_initializeProviders();
1181     }
1182     else if (fdwReason == DLL_PROCESS_DETACH)
1183     {
1184         SECUR32_freeProviders();
1185     }
1186
1187     return TRUE;
1188 }