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