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