Add NTLM security provider dummy.
[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             ret->moduleName = NULL;
499             _makeFnTableA(&ret->fnTableA, fnTableA, fnTableW);
500             _makeFnTableW(&ret->fnTableW, fnTableA, fnTableW);
501             ret->loaded = TRUE;
502         }
503         else
504         {
505             ret->moduleName = SECUR32_strdupW(moduleName);
506             ret->loaded = FALSE;
507         }
508     }
509     else
510         ret = NULL;
511     LeaveCriticalSection(&cs);
512     return ret;
513 }
514
515 void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd,
516  const SecPkgInfoA *infoA, const SecPkgInfoW *infoW)
517 {
518     assert(provider);
519     assert(infoA || infoW);
520
521     EnterCriticalSection(&cs);
522     packageTable = _resizePackageTable(packageTable,
523      packageTable ? packageTable->numPackages + toAdd : toAdd);
524     if (packageTable)
525     {
526         ULONG i;
527
528         for (i = 0; i < toAdd; i++)
529         {
530             SecurePackage *package =
531              &packageTable->table[packageTable->numPackages + i];
532
533             package->provider = provider;
534             _copyPackageInfo(&package->infoW,
535              infoA ? &infoA[i] : NULL,
536              infoW ? &infoW[i] : NULL);
537         }
538         packageTable->numPackages += toAdd;
539     }
540     LeaveCriticalSection(&cs);
541 }
542
543 static void _tryLoadProvider(PWSTR moduleName)
544 {
545     HMODULE lib = LoadLibraryW(moduleName);
546
547     if (lib)
548     {
549         INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
550          (INIT_SECURITY_INTERFACE_W)GetProcAddress(lib,
551          SECURITY_ENTRYPOINT_ANSIW);
552         INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
553          (INIT_SECURITY_INTERFACE_A)GetProcAddress(lib,
554          SECURITY_ENTRYPOINT_ANSIA);
555
556         TRACE("loaded %s, InitSecurityInterfaceA is %p, InitSecurityInterfaceW is %p\n",
557          debugstr_w(moduleName), pInitSecurityInterfaceA,
558          pInitSecurityInterfaceW);
559         if (pInitSecurityInterfaceW || pInitSecurityInterfaceA)
560         {
561             PSecurityFunctionTableA fnTableA = NULL;
562             PSecurityFunctionTableW fnTableW = NULL;
563             ULONG toAdd = 0;
564             PSecPkgInfoA infoA = NULL;
565             PSecPkgInfoW infoW = NULL;
566             SECURITY_STATUS ret = SEC_E_OK;
567
568             if (pInitSecurityInterfaceA)
569                 fnTableA = pInitSecurityInterfaceA();
570             if (pInitSecurityInterfaceW)
571                 fnTableW = pInitSecurityInterfaceW();
572             if (fnTableW && fnTableW->EnumerateSecurityPackagesW)
573                 ret = fnTableW->EnumerateSecurityPackagesW(&toAdd, &infoW);
574             else if (fnTableA && fnTableA->EnumerateSecurityPackagesA)
575                 ret = fnTableA->EnumerateSecurityPackagesA(&toAdd, &infoA);
576             if (ret == SEC_E_OK && toAdd > 0 && (infoW || infoA))
577             {
578                 SecureProvider *provider = SECUR32_addProvider(NULL, NULL,
579                  moduleName);
580
581                 if (provider)
582                     SECUR32_addPackages(provider, toAdd, infoA, infoW);
583                 if (infoW)
584                     fnTableW->FreeContextBuffer(infoW);
585                 else
586                     fnTableA->FreeContextBuffer(infoA);
587             }
588         }
589         FreeLibrary(lib);
590     }
591     else
592         WARN("failed to load %s\n", debugstr_w(moduleName));
593 }
594
595 static const WCHAR securityProvidersKeyW[] = {
596  'S','Y','S','T','E','M','\\','C','u','r','r','e','n','t','C','o','n','t','r',
597  'o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','S','e','c','u','r',
598  'i','t','y','P','r','o','v','i','d','e','r','s','\0'
599  };
600 static const WCHAR securityProvidersW[] = {
601  'S','e','c','u','r','i','t','y','P','r','o','v','i','d','e','r','s',0
602  };
603  
604 static void SECUR32_initializeProviders(void)
605 {
606     HKEY key;
607     long apiRet;
608
609     TRACE("\n");
610     InitializeCriticalSection(&cs);
611     /* First load built-in providers */
612     SECUR32_initSchannelSP();
613     SECUR32_initNegotiateSP();
614     SECUR32_initNTLMSP();
615     /* Now load providers from registry */
616     apiRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, securityProvidersKeyW, 0,
617      KEY_READ, &key);
618     if (apiRet == ERROR_SUCCESS)
619     {
620         WCHAR securityPkgNames[MAX_PATH]; /* arbitrary len */
621         DWORD size = sizeof(securityPkgNames) / sizeof(WCHAR), type;
622
623         apiRet = RegQueryValueExW(key, securityProvidersW, NULL, &type,
624          (PBYTE)securityPkgNames, &size);
625         if (apiRet == ERROR_SUCCESS && type == REG_SZ)
626         {
627             WCHAR *ptr;
628
629             for (ptr = securityPkgNames;
630              ptr < (PWSTR)((PBYTE)securityPkgNames + size); )
631             {
632                 WCHAR *comma;
633
634                 for (comma = ptr; *comma && *comma != ','; comma++)
635                     ;
636                 if (*comma == ',')
637                     *comma = '\0';
638                 for (; *ptr && isspace(*ptr) && ptr < securityPkgNames + size;
639                  ptr++)
640                     ;
641                 if (*ptr)
642                     _tryLoadProvider(ptr);
643                 ptr += lstrlenW(ptr) + 1;
644             }
645         }
646         RegCloseKey(key);
647     }
648 }
649
650 SecurePackage *SECUR32_findPackageW(PWSTR packageName)
651 {
652     SecurePackage *ret = NULL;
653
654     if (packageTable && packageName)
655     {
656         DWORD i;
657
658         for (i = 0, ret = NULL; !ret && i < packageTable->numPackages; i++)
659             if (!lstrcmpiW(packageTable->table[i].infoW.Name, packageName))
660                 ret = &packageTable->table[i];
661         if (ret && ret->provider && !ret->provider->loaded)
662         {
663             ret->provider->lib = LoadLibraryW(ret->provider->moduleName);
664             if (ret->provider->lib)
665             {
666                 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
667                  (INIT_SECURITY_INTERFACE_W)GetProcAddress(ret->provider->lib,
668                  SECURITY_ENTRYPOINT_ANSIW);
669                 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
670                  (INIT_SECURITY_INTERFACE_A)GetProcAddress(ret->provider->lib,
671                  SECURITY_ENTRYPOINT_ANSIA);
672                 PSecurityFunctionTableA fnTableA = NULL;
673                 PSecurityFunctionTableW fnTableW = NULL;
674
675                 if (pInitSecurityInterfaceA)
676                     fnTableA = pInitSecurityInterfaceA();
677                 if (pInitSecurityInterfaceW)
678                     fnTableW = pInitSecurityInterfaceW();
679                 _makeFnTableA(&ret->provider->fnTableA, fnTableA, fnTableW);
680                 _makeFnTableW(&ret->provider->fnTableW, fnTableA, fnTableW);
681                 ret->provider->loaded = TRUE;
682             }
683             else
684                 ret = NULL;
685         }
686     }
687     return ret;
688 }
689
690 SecurePackage *SECUR32_findPackageA(PSTR packageName)
691 {
692     SecurePackage *ret;
693
694     if (packageTable && packageName)
695     {
696         UNICODE_STRING package;
697
698         RtlCreateUnicodeStringFromAsciiz(&package, packageName);
699         ret = SECUR32_findPackageW(package.Buffer);
700         RtlFreeUnicodeString(&package);
701     }
702     else
703         ret = NULL;
704     return ret;
705 }
706
707 static void SECUR32_freeProviders(void)
708 {
709     DWORD i;
710
711     TRACE("\n");
712     EnterCriticalSection(&cs);
713     if (packageTable)
714     {
715         for (i = 0; i < packageTable->numPackages; i++)
716         {
717             SECUR32_FREE(packageTable->table[i].infoW.Name);
718             SECUR32_FREE(packageTable->table[i].infoW.Comment);
719         }
720         HeapFree(GetProcessHeap(), 0, packageTable);
721         packageTable = NULL;
722     }
723     if (providerTable)
724     {
725         for (i = 0; i < providerTable->numProviders; i++)
726         {
727             if (providerTable->table[i].moduleName)
728                 SECUR32_FREE(providerTable->table[i].moduleName);
729             if (providerTable->table[i].lib)
730                 FreeLibrary(providerTable->table[i].lib);
731         }
732         HeapFree(GetProcessHeap(), 0, providerTable);
733         providerTable = NULL;
734     }
735     LeaveCriticalSection(&cs);
736     DeleteCriticalSection(&cs);
737 }
738
739 /***********************************************************************
740  *              FreeContextBuffer (SECUR32.@)
741  *
742  * Doh--if pv was allocated by a crypto package, this may not be correct.
743  * The sample ssp seems to use LocalAlloc/LocalFee, but there doesn't seem to
744  * be any guarantee, nor is there an alloc function in secur32.
745  */
746 SECURITY_STATUS WINAPI FreeContextBuffer(PVOID pv)
747 {
748     SECURITY_STATUS ret;
749
750     /* as it turns out, SECURITY_STATUSes are actually HRESULTS */
751     if (pv)
752     {
753         if (SECUR32_FREE(pv) == NULL)
754             ret = SEC_E_OK;
755         else
756             ret = HRESULT_FROM_WIN32(GetLastError());
757     }
758     else
759         ret = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
760     return ret;
761 }
762
763 /***********************************************************************
764  *              EnumerateSecurityPackagesW (SECUR32.@)
765  */
766 SECURITY_STATUS WINAPI EnumerateSecurityPackagesW(PULONG pcPackages,
767  PSecPkgInfoW *ppPackageInfo)
768 {
769     SECURITY_STATUS ret = SEC_E_OK;
770
771     /* windows just crashes if pcPackages or ppPackageInfo is NULL, so will I */
772     *pcPackages = 0;
773     EnterCriticalSection(&cs);
774     if (packageTable)
775     {
776         ULONG i;
777         size_t bytesNeeded;
778
779         bytesNeeded = packageTable->numPackages * sizeof(SecPkgInfoW);
780         for (i = 0; i < packageTable->numPackages; i++)
781         {
782             if (packageTable->table[i].infoW.Name)
783                 bytesNeeded +=
784                  (lstrlenW(packageTable->table[i].infoW.Name) + 1) *
785                  sizeof(WCHAR);
786             if (packageTable->table[i].infoW.Comment)
787                 bytesNeeded +=
788                  (lstrlenW(packageTable->table[i].infoW.Comment) + 1) *
789                  sizeof(WCHAR);
790         }
791         if (bytesNeeded)
792         {
793             *ppPackageInfo = (PSecPkgInfoW)SECUR32_ALLOC(bytesNeeded);
794             if (*ppPackageInfo)
795             {
796                 PWSTR nextString;
797
798                 *pcPackages = packageTable->numPackages;
799                 nextString = (PWSTR)((PBYTE)*ppPackageInfo +
800                  packageTable->numPackages * sizeof(SecPkgInfoW));
801                 for (i = 0; i < packageTable->numPackages; i++)
802                 {
803                     PSecPkgInfoW pkgInfo = *ppPackageInfo + i;
804
805                     memcpy(pkgInfo, &packageTable->table[i].infoW,
806                      sizeof(SecPkgInfoW));
807                     if (packageTable->table[i].infoW.Name)
808                     {
809                         pkgInfo->Name = nextString;
810                         lstrcpyW(nextString, packageTable->table[i].infoW.Name);
811                         nextString += lstrlenW(nextString) + 1;
812                     }
813                     else
814                         pkgInfo->Name = NULL;
815                     if (packageTable->table[i].infoW.Comment)
816                     {
817                         pkgInfo->Comment = nextString;
818                         lstrcpyW(nextString,
819                          packageTable->table[i].infoW.Comment);
820                         nextString += lstrlenW(nextString) + 1;
821                     }
822                     else
823                         pkgInfo->Comment = NULL;
824                 }
825             }
826             else
827                 ret = SEC_E_INSUFFICIENT_MEMORY;
828         }
829     }
830     LeaveCriticalSection(&cs);
831     return ret;
832 }
833
834 /* Converts info (which is assumed to be an array of cPackages SecPkgInfoW
835  * structures) into an array of SecPkgInfoA structures, which it returns.
836  */
837 static PSecPkgInfoA thunk_PSecPkgInfoWToA(ULONG cPackages,
838  const PSecPkgInfoW info)
839 {
840     PSecPkgInfoA ret;
841
842     if (info)
843     {
844         size_t bytesNeeded = cPackages * sizeof(SecPkgInfoA);
845         ULONG i;
846
847         for (i = 0; i < cPackages; i++)
848         {
849             if (info[i].Name)
850                 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Name,
851                  -1, NULL, 0, NULL, NULL);
852             if (info[i].Comment)
853                 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Comment,
854                  -1, NULL, 0, NULL, NULL);
855         }
856         ret = (PSecPkgInfoA)SECUR32_ALLOC(bytesNeeded);
857         if (ret)
858         {
859             PSTR nextString;
860
861             nextString = (PSTR)((PBYTE)ret + cPackages * sizeof(SecPkgInfoA));
862             for (i = 0; i < cPackages; i++)
863             {
864                 PSecPkgInfoA pkgInfo = ret + i;
865                 int bytes;
866
867                 memcpy(pkgInfo, &info[i], sizeof(SecPkgInfoA));
868                 if (info[i].Name)
869                 {
870                     pkgInfo->Name = nextString;
871                     /* just repeat back to WideCharToMultiByte how many bytes
872                      * it requires, since we asked it earlier
873                      */
874                     bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
875                      NULL, 0, NULL, NULL);
876                     WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
877                      pkgInfo->Name, bytes, NULL, NULL);
878                     nextString += lstrlenA(nextString) + 1;
879                 }
880                 else
881                     pkgInfo->Name = NULL;
882                 if (info[i].Comment)
883                 {
884                     pkgInfo->Comment = nextString;
885                     /* just repeat back to WideCharToMultiByte how many bytes
886                      * it requires, since we asked it earlier
887                      */
888                     bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
889                      NULL, 0, NULL, NULL);
890                     WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
891                      pkgInfo->Comment, bytes, NULL, NULL);
892                     nextString += lstrlenA(nextString) + 1;
893                 }
894                 else
895                     pkgInfo->Comment = NULL;
896             }
897         }
898     }
899     else
900         ret = NULL;
901     return ret;
902 }
903
904 /***********************************************************************
905  *              EnumerateSecurityPackagesA (SECUR32.@)
906  */
907 SECURITY_STATUS WINAPI EnumerateSecurityPackagesA(PULONG pcPackages,
908  PSecPkgInfoA *ppPackageInfo)
909 {
910     SECURITY_STATUS ret;
911     PSecPkgInfoW info;
912
913     ret = EnumerateSecurityPackagesW(pcPackages, &info);
914     if (ret == SEC_E_OK && *pcPackages && info)
915     {
916         *ppPackageInfo = thunk_PSecPkgInfoWToA(*pcPackages, info);
917         if (*pcPackages && !*ppPackageInfo)
918         {
919             *pcPackages = 0;
920             ret = SEC_E_INSUFFICIENT_MEMORY;
921         }
922         FreeContextBuffer(info);
923     }
924     return ret;
925 }
926
927 /***********************************************************************
928  *              GetComputerObjectNameA (SECUR32.@)
929  */
930 BOOLEAN WINAPI GetComputerObjectNameA(
931   EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
932 {
933     FIXME("%d %p %p\n", NameFormat, lpNameBuffer, nSize);
934     return FALSE;
935 }
936
937 /***********************************************************************
938  *              GetComputerObjectNameW (SECUR32.@)
939  */
940 BOOLEAN WINAPI GetComputerObjectNameW(
941   EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
942 {
943     FIXME("%d %p %p\n", NameFormat, lpNameBuffer, nSize);
944     return FALSE;
945 }
946
947 BOOLEAN WINAPI GetUserNameExA(
948   EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
949 {
950     FIXME("%d %p %p\n", NameFormat, lpNameBuffer, nSize);
951     return FALSE;
952 }
953
954 BOOLEAN WINAPI GetUserNameExW(
955   EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
956 {
957     FIXME("%d %p %p\n", NameFormat, lpNameBuffer, nSize);
958     return FALSE;
959 }
960
961 NTSTATUS WINAPI LsaCallAuthenticationPackage(
962   HANDLE LsaHandle, ULONG AuthenticationPackage, PVOID ProtocolSubmitBuffer,
963   ULONG SubmitBufferLength, PVOID* ProtocolReturnBuffer, PULONG ReturnBufferLength,
964   PNTSTATUS ProtocolStatus)
965 {
966     FIXME("%p %ld %p %ld %p %p %p\n", LsaHandle, AuthenticationPackage,
967           ProtocolSubmitBuffer, SubmitBufferLength, ProtocolReturnBuffer,
968           ReturnBufferLength, ProtocolStatus);
969     return 0;
970 }
971
972 NTSTATUS WINAPI LsaConnectUntrusted(PHANDLE LsaHandle)
973 {
974     FIXME("%p\n", LsaHandle);
975     return 0;
976 }
977
978 NTSTATUS WINAPI LsaDeregisterLogonProcess(HANDLE LsaHandle)
979 {
980     FIXME("%p\n", LsaHandle);
981     return 0;
982 }
983
984 BOOLEAN WINAPI TranslateNameA(
985   LPCSTR lpAccountName, EXTENDED_NAME_FORMAT AccountNameFormat,
986   EXTENDED_NAME_FORMAT DesiredNameFormat, LPSTR lpTranslatedName,
987   PULONG nSize)
988 {
989     FIXME("%p %d %d %p %p\n", lpAccountName, AccountNameFormat,
990           DesiredNameFormat, lpTranslatedName, nSize);
991     return FALSE;
992 }
993
994 BOOLEAN WINAPI TranslateNameW(
995   LPCWSTR lpAccountName, EXTENDED_NAME_FORMAT AccountNameFormat,
996   EXTENDED_NAME_FORMAT DesiredNameFormat, LPWSTR lpTranslatedName,
997   PULONG nSize)
998 {
999     FIXME("%p %d %d %p %p\n", lpAccountName, AccountNameFormat,
1000           DesiredNameFormat, lpTranslatedName, nSize);
1001     return FALSE;
1002 }
1003
1004 /***********************************************************************
1005  *              DllMain (SECUR32.0)
1006  */
1007 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1008 {
1009     if (fdwReason == DLL_PROCESS_ATTACH)
1010     {
1011         DisableThreadLibraryCalls(hinstDLL);
1012         SECUR32_initializeProviders();
1013     }
1014     else if (fdwReason == DLL_PROCESS_DETACH)
1015     {
1016         SECUR32_freeProviders();
1017     }
1018
1019     return TRUE;
1020 }