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