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