comctl32: Update Catalan translation.
[wine/multimedia.git] / dlls / secur32 / secur32.c
blob05221d46ece9efba9364606f25f60fc939b14904
1 /* Copyright (C) 2004 Juan Lang
3 * This file implements loading of SSP DLLs.
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.
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.
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
19 #include <assert.h>
20 #include <stdarg.h>
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"
37 #include "wine/list.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
42 /**
43 * Type definitions
46 typedef struct _SecurePackageTable
48 DWORD numPackages;
49 DWORD numAllocated;
50 struct list table;
51 } SecurePackageTable;
53 typedef struct _SecureProviderTable
55 DWORD numProviders;
56 DWORD numAllocated;
57 struct list table;
58 } SecureProviderTable;
60 /**
61 * Prototypes
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.
68 static void _tryLoadProvider(PWSTR moduleName);
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.
76 static void SECUR32_initializeProviders(void);
78 /* Frees all loaded packages and providers */
79 static void SECUR32_freeProviders(void);
81 /**
82 * Globals
85 static CRITICAL_SECTION cs;
86 static CRITICAL_SECTION_DEBUG cs_debug =
88 0, 0, &cs,
89 { &cs_debug.ProcessLocksList, &cs_debug.ProcessLocksList },
90 0, 0, { (DWORD_PTR)(__FILE__ ": cs") }
92 static CRITICAL_SECTION cs = { &cs_debug, -1, 0, 0, 0, 0 };
93 static SecurePackageTable *packageTable = NULL;
94 static SecureProviderTable *providerTable = NULL;
96 static SecurityFunctionTableA securityFunctionTableA = {
97 SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
98 EnumerateSecurityPackagesA,
99 QueryCredentialsAttributesA,
100 AcquireCredentialsHandleA,
101 FreeCredentialsHandle,
102 NULL, /* Reserved2 */
103 InitializeSecurityContextA,
104 AcceptSecurityContext,
105 CompleteAuthToken,
106 DeleteSecurityContext,
107 ApplyControlToken,
108 QueryContextAttributesA,
109 ImpersonateSecurityContext,
110 RevertSecurityContext,
111 MakeSignature,
112 VerifySignature,
113 FreeContextBuffer,
114 QuerySecurityPackageInfoA,
115 EncryptMessage, /* Reserved3 */
116 DecryptMessage, /* Reserved4 */
117 ExportSecurityContext,
118 ImportSecurityContextA,
119 AddCredentialsA,
120 NULL, /* Reserved8 */
121 QuerySecurityContextToken,
122 EncryptMessage,
123 DecryptMessage,
124 SetContextAttributesA
127 static SecurityFunctionTableW securityFunctionTableW = {
128 SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
129 EnumerateSecurityPackagesW,
130 QueryCredentialsAttributesW,
131 AcquireCredentialsHandleW,
132 FreeCredentialsHandle,
133 NULL, /* Reserved2 */
134 InitializeSecurityContextW,
135 AcceptSecurityContext,
136 CompleteAuthToken,
137 DeleteSecurityContext,
138 ApplyControlToken,
139 QueryContextAttributesW,
140 ImpersonateSecurityContext,
141 RevertSecurityContext,
142 MakeSignature,
143 VerifySignature,
144 FreeContextBuffer,
145 QuerySecurityPackageInfoW,
146 EncryptMessage, /* Reserved3 */
147 DecryptMessage, /* Reserved4 */
148 ExportSecurityContext,
149 ImportSecurityContextW,
150 AddCredentialsW,
151 NULL, /* Reserved8 */
152 QuerySecurityContextToken,
153 EncryptMessage,
154 DecryptMessage,
155 SetContextAttributesW
158 /***********************************************************************
159 * InitSecurityInterfaceA (SECUR32.@)
161 PSecurityFunctionTableA WINAPI InitSecurityInterfaceA(void)
163 return &securityFunctionTableA;
166 /***********************************************************************
167 * InitSecurityInterfaceW (SECUR32.@)
169 PSecurityFunctionTableW WINAPI InitSecurityInterfaceW(void)
171 return &securityFunctionTableW;
174 static PWSTR SECUR32_strdupW(PCWSTR str)
176 PWSTR ret;
178 if (str)
180 ret = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(str) + 1) * sizeof(WCHAR));
181 if (ret)
182 lstrcpyW(ret, str);
184 else
185 ret = NULL;
186 return ret;
189 PWSTR SECUR32_AllocWideFromMultiByte(PCSTR str)
191 PWSTR ret;
193 if (str)
195 int charsNeeded = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
197 if (charsNeeded)
199 ret = HeapAlloc(GetProcessHeap(), 0, charsNeeded * sizeof(WCHAR));
200 if (ret)
201 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, charsNeeded);
203 else
204 ret = NULL;
206 else
207 ret = NULL;
208 return ret;
211 PSTR SECUR32_AllocMultiByteFromWide(PCWSTR str)
213 PSTR ret;
215 if (str)
217 int charsNeeded = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0,
218 NULL, NULL);
220 if (charsNeeded)
222 ret = HeapAlloc(GetProcessHeap(), 0, charsNeeded);
223 if (ret)
224 WideCharToMultiByte(CP_ACP, 0, str, -1, ret, charsNeeded,
225 NULL, NULL);
227 else
228 ret = NULL;
230 else
231 ret = NULL;
232 return ret;
235 static void _makeFnTableA(PSecurityFunctionTableA fnTableA,
236 const SecurityFunctionTableA *inFnTableA,
237 const SecurityFunctionTableW *inFnTableW)
239 if (fnTableA)
241 if (inFnTableA)
243 /* The size of the version 1 table is based on platform sdk's
244 * sspi.h, though the sample ssp also provided with platform sdk
245 * implies only functions through QuerySecurityPackageInfoA are
246 * implemented (yikes)
248 size_t tableSize = inFnTableA->dwVersion == 1 ?
249 (const BYTE *)&inFnTableA->SetContextAttributesA -
250 (const BYTE *)inFnTableA : sizeof(SecurityFunctionTableA);
252 memcpy(fnTableA, inFnTableA, tableSize);
253 /* override this, since we can do it internally anyway */
254 fnTableA->QuerySecurityPackageInfoA =
255 QuerySecurityPackageInfoA;
257 else if (inFnTableW)
259 /* functions with thunks */
260 if (inFnTableW->AcquireCredentialsHandleW)
261 fnTableA->AcquireCredentialsHandleA =
262 thunk_AcquireCredentialsHandleA;
263 if (inFnTableW->InitializeSecurityContextW)
264 fnTableA->InitializeSecurityContextA =
265 thunk_InitializeSecurityContextA;
266 if (inFnTableW->ImportSecurityContextW)
267 fnTableA->ImportSecurityContextA =
268 thunk_ImportSecurityContextA;
269 if (inFnTableW->AddCredentialsW)
270 fnTableA->AddCredentialsA =
271 thunk_AddCredentialsA;
272 if (inFnTableW->QueryCredentialsAttributesW)
273 fnTableA->QueryCredentialsAttributesA =
274 thunk_QueryCredentialsAttributesA;
275 if (inFnTableW->QueryContextAttributesW)
276 fnTableA->QueryContextAttributesA =
277 thunk_QueryContextAttributesA;
278 if (inFnTableW->SetContextAttributesW)
279 fnTableA->SetContextAttributesA =
280 thunk_SetContextAttributesA;
281 /* this can't be thunked, there's no extra param to know which
282 * package to forward to */
283 fnTableA->EnumerateSecurityPackagesA = NULL;
284 /* functions with no thunks needed */
285 fnTableA->AcceptSecurityContext = inFnTableW->AcceptSecurityContext;
286 fnTableA->CompleteAuthToken = inFnTableW->CompleteAuthToken;
287 fnTableA->DeleteSecurityContext = inFnTableW->DeleteSecurityContext;
288 fnTableA->ImpersonateSecurityContext =
289 inFnTableW->ImpersonateSecurityContext;
290 fnTableA->RevertSecurityContext = inFnTableW->RevertSecurityContext;
291 fnTableA->MakeSignature = inFnTableW->MakeSignature;
292 fnTableA->VerifySignature = inFnTableW->VerifySignature;
293 fnTableA->FreeContextBuffer = inFnTableW->FreeContextBuffer;
294 fnTableA->QuerySecurityPackageInfoA =
295 QuerySecurityPackageInfoA;
296 fnTableA->ExportSecurityContext =
297 inFnTableW->ExportSecurityContext;
298 fnTableA->QuerySecurityContextToken =
299 inFnTableW->QuerySecurityContextToken;
300 fnTableA->EncryptMessage = inFnTableW->EncryptMessage;
301 fnTableA->DecryptMessage = inFnTableW->DecryptMessage;
306 static void _makeFnTableW(PSecurityFunctionTableW fnTableW,
307 const SecurityFunctionTableA *inFnTableA,
308 const SecurityFunctionTableW *inFnTableW)
310 if (fnTableW)
312 if (inFnTableW)
314 /* The size of the version 1 table is based on platform sdk's
315 * sspi.h, though the sample ssp also provided with platform sdk
316 * implies only functions through QuerySecurityPackageInfoA are
317 * implemented (yikes)
319 size_t tableSize = inFnTableW->dwVersion == 1 ?
320 (const BYTE *)&inFnTableW->SetContextAttributesW -
321 (const BYTE *)inFnTableW : sizeof(SecurityFunctionTableW);
323 memcpy(fnTableW, inFnTableW, tableSize);
324 /* override this, since we can do it internally anyway */
325 fnTableW->QuerySecurityPackageInfoW =
326 QuerySecurityPackageInfoW;
328 else if (inFnTableA)
330 /* functions with thunks */
331 if (inFnTableA->AcquireCredentialsHandleA)
332 fnTableW->AcquireCredentialsHandleW =
333 thunk_AcquireCredentialsHandleW;
334 if (inFnTableA->InitializeSecurityContextA)
335 fnTableW->InitializeSecurityContextW =
336 thunk_InitializeSecurityContextW;
337 if (inFnTableA->ImportSecurityContextA)
338 fnTableW->ImportSecurityContextW =
339 thunk_ImportSecurityContextW;
340 if (inFnTableA->AddCredentialsA)
341 fnTableW->AddCredentialsW =
342 thunk_AddCredentialsW;
343 if (inFnTableA->QueryCredentialsAttributesA)
344 fnTableW->QueryCredentialsAttributesW =
345 thunk_QueryCredentialsAttributesW;
346 if (inFnTableA->QueryContextAttributesA)
347 fnTableW->QueryContextAttributesW =
348 thunk_QueryContextAttributesW;
349 if (inFnTableA->SetContextAttributesA)
350 fnTableW->SetContextAttributesW =
351 thunk_SetContextAttributesW;
352 /* this can't be thunked, there's no extra param to know which
353 * package to forward to */
354 fnTableW->EnumerateSecurityPackagesW = NULL;
355 /* functions with no thunks needed */
356 fnTableW->AcceptSecurityContext = inFnTableA->AcceptSecurityContext;
357 fnTableW->CompleteAuthToken = inFnTableA->CompleteAuthToken;
358 fnTableW->DeleteSecurityContext = inFnTableA->DeleteSecurityContext;
359 fnTableW->ImpersonateSecurityContext =
360 inFnTableA->ImpersonateSecurityContext;
361 fnTableW->RevertSecurityContext = inFnTableA->RevertSecurityContext;
362 fnTableW->MakeSignature = inFnTableA->MakeSignature;
363 fnTableW->VerifySignature = inFnTableA->VerifySignature;
364 fnTableW->FreeContextBuffer = inFnTableA->FreeContextBuffer;
365 fnTableW->QuerySecurityPackageInfoW =
366 QuerySecurityPackageInfoW;
367 fnTableW->ExportSecurityContext =
368 inFnTableA->ExportSecurityContext;
369 fnTableW->QuerySecurityContextToken =
370 inFnTableA->QuerySecurityContextToken;
371 fnTableW->EncryptMessage = inFnTableA->EncryptMessage;
372 fnTableW->DecryptMessage = inFnTableA->DecryptMessage;
377 static void _copyPackageInfo(PSecPkgInfoW info, const SecPkgInfoA *inInfoA,
378 const SecPkgInfoW *inInfoW)
380 if (info && (inInfoA || inInfoW))
382 /* odd, I know, but up until Name and Comment the structures are
383 * identical
385 memcpy(info, inInfoW ? inInfoW : (const SecPkgInfoW *)inInfoA, sizeof(*info));
386 if (inInfoW)
388 info->Name = SECUR32_strdupW(inInfoW->Name);
389 info->Comment = SECUR32_strdupW(inInfoW->Comment);
391 else
393 info->Name = SECUR32_AllocWideFromMultiByte(inInfoA->Name);
394 info->Comment = SECUR32_AllocWideFromMultiByte(inInfoA->Comment);
399 SecureProvider *SECUR32_addProvider(const SecurityFunctionTableA *fnTableA,
400 const SecurityFunctionTableW *fnTableW, PCWSTR moduleName)
402 SecureProvider *ret;
404 EnterCriticalSection(&cs);
406 if (!providerTable)
408 providerTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SecureProviderTable));
409 if (!providerTable)
411 LeaveCriticalSection(&cs);
412 return NULL;
415 list_init(&providerTable->table);
418 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(SecureProvider));
419 if (!ret)
421 LeaveCriticalSection(&cs);
422 return NULL;
425 list_add_tail(&providerTable->table, &ret->entry);
426 ret->lib = NULL;
428 if (fnTableA || fnTableW)
430 ret->moduleName = moduleName ? SECUR32_strdupW(moduleName) : NULL;
431 _makeFnTableA(&ret->fnTableA, fnTableA, fnTableW);
432 _makeFnTableW(&ret->fnTableW, fnTableA, fnTableW);
433 ret->loaded = moduleName ? FALSE : TRUE;
435 else
437 ret->moduleName = SECUR32_strdupW(moduleName);
438 ret->loaded = FALSE;
441 LeaveCriticalSection(&cs);
442 return ret;
445 void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd,
446 const SecPkgInfoA *infoA, const SecPkgInfoW *infoW)
448 ULONG i;
450 assert(provider);
451 assert(infoA || infoW);
453 EnterCriticalSection(&cs);
455 if (!packageTable)
457 packageTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackageTable));
458 if (!packageTable)
460 LeaveCriticalSection(&cs);
461 return;
464 packageTable->numPackages = 0;
465 list_init(&packageTable->table);
468 for (i = 0; i < toAdd; i++)
470 SecurePackage *package = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackage));
471 if (!package)
472 continue;
474 list_add_tail(&packageTable->table, &package->entry);
476 package->provider = provider;
477 _copyPackageInfo(&package->infoW,
478 infoA ? &infoA[i] : NULL,
479 infoW ? &infoW[i] : NULL);
481 packageTable->numPackages += toAdd;
483 LeaveCriticalSection(&cs);
486 static void _tryLoadProvider(PWSTR moduleName)
488 HMODULE lib = LoadLibraryW(moduleName);
490 if (lib)
492 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
493 (INIT_SECURITY_INTERFACE_W)GetProcAddress(lib,
494 SECURITY_ENTRYPOINT_ANSIW);
495 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
496 (INIT_SECURITY_INTERFACE_A)GetProcAddress(lib,
497 SECURITY_ENTRYPOINT_ANSIA);
499 TRACE("loaded %s, InitSecurityInterfaceA is %p, InitSecurityInterfaceW is %p\n",
500 debugstr_w(moduleName), pInitSecurityInterfaceA,
501 pInitSecurityInterfaceW);
502 if (pInitSecurityInterfaceW || pInitSecurityInterfaceA)
504 PSecurityFunctionTableA fnTableA = NULL;
505 PSecurityFunctionTableW fnTableW = NULL;
506 ULONG toAdd = 0;
507 PSecPkgInfoA infoA = NULL;
508 PSecPkgInfoW infoW = NULL;
509 SECURITY_STATUS ret = SEC_E_OK;
511 if (pInitSecurityInterfaceA)
512 fnTableA = pInitSecurityInterfaceA();
513 if (pInitSecurityInterfaceW)
514 fnTableW = pInitSecurityInterfaceW();
515 if (fnTableW && fnTableW->EnumerateSecurityPackagesW)
517 if (fnTableW != &securityFunctionTableW)
518 ret = fnTableW->EnumerateSecurityPackagesW(&toAdd, &infoW);
519 else
520 TRACE("%s has built-in providers, skip adding\n", debugstr_w(moduleName));
522 else if (fnTableA && fnTableA->EnumerateSecurityPackagesA)
524 if (fnTableA != &securityFunctionTableA)
525 ret = fnTableA->EnumerateSecurityPackagesA(&toAdd, &infoA);
526 else
527 TRACE("%s has built-in providers, skip adding\n", debugstr_w(moduleName));
529 if (ret == SEC_E_OK && toAdd > 0 && (infoW || infoA))
531 SecureProvider *provider = SECUR32_addProvider(NULL, NULL,
532 moduleName);
534 if (provider)
535 SECUR32_addPackages(provider, toAdd, infoA, infoW);
536 if (infoW)
537 fnTableW->FreeContextBuffer(infoW);
538 else
539 fnTableA->FreeContextBuffer(infoA);
542 FreeLibrary(lib);
544 else
545 WARN("failed to load %s\n", debugstr_w(moduleName));
548 static const WCHAR securityProvidersKeyW[] = {
549 'S','Y','S','T','E','M','\\','C','u','r','r','e','n','t','C','o','n','t','r',
550 'o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','S','e','c','u','r',
551 'i','t','y','P','r','o','v','i','d','e','r','s','\0'
553 static const WCHAR securityProvidersW[] = {
554 'S','e','c','u','r','i','t','y','P','r','o','v','i','d','e','r','s',0
557 static void SECUR32_initializeProviders(void)
559 HKEY key;
560 LSTATUS apiRet;
562 TRACE("\n");
563 /* First load built-in providers */
564 SECUR32_initSchannelSP();
565 SECUR32_initNTLMSP();
566 /* Load the Negotiate provider last so apps stumble over the working NTLM
567 * provider first. Attempting to fix bug #16905 while keeping the
568 * application reported on wine-users on 2006-09-12 working. */
569 SECUR32_initNegotiateSP();
570 /* Now load providers from registry */
571 apiRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, securityProvidersKeyW, 0,
572 KEY_READ, &key);
573 if (apiRet == ERROR_SUCCESS)
575 WCHAR securityPkgNames[MAX_PATH]; /* arbitrary len */
576 DWORD size = sizeof(securityPkgNames) / sizeof(WCHAR), type;
578 apiRet = RegQueryValueExW(key, securityProvidersW, NULL, &type,
579 (PBYTE)securityPkgNames, &size);
580 if (apiRet == ERROR_SUCCESS && type == REG_SZ)
582 WCHAR *ptr;
584 size = size / sizeof(WCHAR);
585 for (ptr = securityPkgNames;
586 ptr < securityPkgNames + size; )
588 WCHAR *comma;
590 for (comma = ptr; *comma && *comma != ','; comma++)
592 if (*comma == ',')
593 *comma = '\0';
594 for (; *ptr && isspace(*ptr) && ptr < securityPkgNames + size;
595 ptr++)
597 if (*ptr)
598 _tryLoadProvider(ptr);
599 ptr += lstrlenW(ptr) + 1;
602 RegCloseKey(key);
606 SecurePackage *SECUR32_findPackageW(PCWSTR packageName)
608 SecurePackage *ret = NULL;
609 BOOL matched = FALSE;
611 if (packageTable && packageName)
613 LIST_FOR_EACH_ENTRY(ret, &packageTable->table, SecurePackage, entry)
615 matched = !lstrcmpiW(ret->infoW.Name, packageName);
616 if (matched)
617 break;
620 if (!matched)
621 return NULL;
623 if (ret->provider && !ret->provider->loaded)
625 ret->provider->lib = LoadLibraryW(ret->provider->moduleName);
626 if (ret->provider->lib)
628 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
629 (INIT_SECURITY_INTERFACE_W)GetProcAddress(ret->provider->lib,
630 SECURITY_ENTRYPOINT_ANSIW);
631 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
632 (INIT_SECURITY_INTERFACE_A)GetProcAddress(ret->provider->lib,
633 SECURITY_ENTRYPOINT_ANSIA);
634 PSecurityFunctionTableA fnTableA = NULL;
635 PSecurityFunctionTableW fnTableW = NULL;
637 if (pInitSecurityInterfaceA)
638 fnTableA = pInitSecurityInterfaceA();
639 if (pInitSecurityInterfaceW)
640 fnTableW = pInitSecurityInterfaceW();
641 /* don't update built-in SecurityFunctionTable */
642 if (fnTableA != &securityFunctionTableA)
643 _makeFnTableA(&ret->provider->fnTableA, fnTableA, fnTableW);
644 if (fnTableW != &securityFunctionTableW)
645 _makeFnTableW(&ret->provider->fnTableW, fnTableA, fnTableW);
646 ret->provider->loaded = TRUE;
648 else
649 ret = NULL;
652 return ret;
655 SecurePackage *SECUR32_findPackageA(PCSTR packageName)
657 SecurePackage *ret;
659 if (packageTable && packageName)
661 UNICODE_STRING package;
663 RtlCreateUnicodeStringFromAsciiz(&package, packageName);
664 ret = SECUR32_findPackageW(package.Buffer);
665 RtlFreeUnicodeString(&package);
667 else
668 ret = NULL;
669 return ret;
672 static void SECUR32_freeProviders(void)
674 TRACE("\n");
675 EnterCriticalSection(&cs);
677 SECUR32_deinitSchannelSP();
679 if (packageTable)
681 SecurePackage *package, *package_next;
682 LIST_FOR_EACH_ENTRY_SAFE(package, package_next, &packageTable->table,
683 SecurePackage, entry)
685 HeapFree(GetProcessHeap(), 0, package->infoW.Name);
686 HeapFree(GetProcessHeap(), 0, package->infoW.Comment);
687 HeapFree(GetProcessHeap(), 0, package);
690 HeapFree(GetProcessHeap(), 0, packageTable);
691 packageTable = NULL;
694 if (providerTable)
696 SecureProvider *provider, *provider_next;
697 LIST_FOR_EACH_ENTRY_SAFE(provider, provider_next, &providerTable->table,
698 SecureProvider, entry)
700 HeapFree(GetProcessHeap(), 0, provider->moduleName);
701 if (provider->lib)
702 FreeLibrary(provider->lib);
703 HeapFree(GetProcessHeap(), 0, provider);
706 HeapFree(GetProcessHeap(), 0, providerTable);
707 providerTable = NULL;
710 LeaveCriticalSection(&cs);
711 DeleteCriticalSection(&cs);
714 /***********************************************************************
715 * FreeContextBuffer (SECUR32.@)
717 * Doh--if pv was allocated by a crypto package, this may not be correct.
718 * The sample ssp seems to use LocalAlloc/LocalFee, but there doesn't seem to
719 * be any guarantee, nor is there an alloc function in secur32.
721 SECURITY_STATUS WINAPI FreeContextBuffer(PVOID pv)
723 HeapFree(GetProcessHeap(), 0, pv);
725 return SEC_E_OK;
728 /***********************************************************************
729 * EnumerateSecurityPackagesW (SECUR32.@)
731 SECURITY_STATUS WINAPI EnumerateSecurityPackagesW(PULONG pcPackages,
732 PSecPkgInfoW *ppPackageInfo)
734 SECURITY_STATUS ret = SEC_E_OK;
736 TRACE("(%p, %p)\n", pcPackages, ppPackageInfo);
738 /* windows just crashes if pcPackages or ppPackageInfo is NULL, so will I */
739 *pcPackages = 0;
740 EnterCriticalSection(&cs);
741 if (packageTable)
743 SecurePackage *package;
744 size_t bytesNeeded;
746 bytesNeeded = packageTable->numPackages * sizeof(SecPkgInfoW);
747 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
749 if (package->infoW.Name)
750 bytesNeeded += (lstrlenW(package->infoW.Name) + 1) * sizeof(WCHAR);
751 if (package->infoW.Comment)
752 bytesNeeded += (lstrlenW(package->infoW.Comment) + 1) * sizeof(WCHAR);
754 if (bytesNeeded)
756 *ppPackageInfo = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
757 if (*ppPackageInfo)
759 ULONG i = 0;
760 PWSTR nextString;
762 *pcPackages = packageTable->numPackages;
763 nextString = (PWSTR)((PBYTE)*ppPackageInfo +
764 packageTable->numPackages * sizeof(SecPkgInfoW));
765 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
767 PSecPkgInfoW pkgInfo = *ppPackageInfo + i++;
769 *pkgInfo = package->infoW;
770 if (package->infoW.Name)
772 TRACE("Name[%d] = %s\n", i - 1, debugstr_w(package->infoW.Name));
773 pkgInfo->Name = nextString;
774 lstrcpyW(nextString, package->infoW.Name);
775 nextString += lstrlenW(nextString) + 1;
777 else
778 pkgInfo->Name = NULL;
779 if (package->infoW.Comment)
781 TRACE("Comment[%d] = %s\n", i - 1, debugstr_w(package->infoW.Comment));
782 pkgInfo->Comment = nextString;
783 lstrcpyW(nextString, package->infoW.Comment);
784 nextString += lstrlenW(nextString) + 1;
786 else
787 pkgInfo->Comment = NULL;
790 else
791 ret = SEC_E_INSUFFICIENT_MEMORY;
794 LeaveCriticalSection(&cs);
795 TRACE("<-- 0x%08x\n", ret);
796 return ret;
799 /* Converts info (which is assumed to be an array of cPackages SecPkgInfoW
800 * structures) into an array of SecPkgInfoA structures, which it returns.
802 static PSecPkgInfoA thunk_PSecPkgInfoWToA(ULONG cPackages,
803 const SecPkgInfoW *info)
805 PSecPkgInfoA ret;
807 if (info)
809 size_t bytesNeeded = cPackages * sizeof(SecPkgInfoA);
810 ULONG i;
812 for (i = 0; i < cPackages; i++)
814 if (info[i].Name)
815 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Name,
816 -1, NULL, 0, NULL, NULL);
817 if (info[i].Comment)
818 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Comment,
819 -1, NULL, 0, NULL, NULL);
821 ret = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
822 if (ret)
824 PSTR nextString;
826 nextString = (PSTR)((PBYTE)ret + cPackages * sizeof(SecPkgInfoA));
827 for (i = 0; i < cPackages; i++)
829 PSecPkgInfoA pkgInfo = ret + i;
830 int bytes;
832 memcpy(pkgInfo, &info[i], sizeof(SecPkgInfoA));
833 if (info[i].Name)
835 pkgInfo->Name = nextString;
836 /* just repeat back to WideCharToMultiByte how many bytes
837 * it requires, since we asked it earlier
839 bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
840 NULL, 0, NULL, NULL);
841 WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
842 pkgInfo->Name, bytes, NULL, NULL);
843 nextString += lstrlenA(nextString) + 1;
845 else
846 pkgInfo->Name = NULL;
847 if (info[i].Comment)
849 pkgInfo->Comment = nextString;
850 /* just repeat back to WideCharToMultiByte how many bytes
851 * it requires, since we asked it earlier
853 bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
854 NULL, 0, NULL, NULL);
855 WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
856 pkgInfo->Comment, bytes, NULL, NULL);
857 nextString += lstrlenA(nextString) + 1;
859 else
860 pkgInfo->Comment = NULL;
864 else
865 ret = NULL;
866 return ret;
869 /***********************************************************************
870 * EnumerateSecurityPackagesA (SECUR32.@)
872 SECURITY_STATUS WINAPI EnumerateSecurityPackagesA(PULONG pcPackages,
873 PSecPkgInfoA *ppPackageInfo)
875 SECURITY_STATUS ret;
876 PSecPkgInfoW info;
878 ret = EnumerateSecurityPackagesW(pcPackages, &info);
879 if (ret == SEC_E_OK && *pcPackages && info)
881 *ppPackageInfo = thunk_PSecPkgInfoWToA(*pcPackages, info);
882 if (*pcPackages && !*ppPackageInfo)
884 *pcPackages = 0;
885 ret = SEC_E_INSUFFICIENT_MEMORY;
887 FreeContextBuffer(info);
889 return ret;
892 /***********************************************************************
893 * GetComputerObjectNameA (SECUR32.@)
895 * Get the local computer's name using the format specified.
897 * PARAMS
898 * NameFormat [I] The format for the name.
899 * lpNameBuffer [O] Pointer to buffer to receive the name.
900 * nSize [I/O] Size in characters of buffer.
902 * RETURNS
903 * TRUE If the name was written to lpNameBuffer.
904 * FALSE If the name couldn't be written.
906 * NOTES
907 * If lpNameBuffer is NULL, then the size of the buffer needed to hold the
908 * name will be returned in *nSize.
910 * nSize returns the number of characters written when lpNameBuffer is not
911 * NULL or the size of the buffer needed to hold the name when the buffer
912 * is too short or lpNameBuffer is NULL.
914 * It the buffer is too short, ERROR_INSUFFICIENT_BUFFER error will be set.
916 BOOLEAN WINAPI GetComputerObjectNameA(
917 EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
919 BOOLEAN rc;
920 LPWSTR bufferW = NULL;
921 ULONG sizeW = *nSize;
922 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
923 if (lpNameBuffer) {
924 bufferW = HeapAlloc(GetProcessHeap(), 0, sizeW * sizeof(WCHAR));
925 if (bufferW == NULL) {
926 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
927 return FALSE;
930 rc = GetComputerObjectNameW(NameFormat, bufferW, &sizeW);
931 if (rc && bufferW) {
932 ULONG len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
933 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, lpNameBuffer, *nSize, NULL, NULL);
934 *nSize = len;
936 else
937 *nSize = sizeW;
938 HeapFree(GetProcessHeap(), 0, bufferW);
939 return rc;
942 /***********************************************************************
943 * GetComputerObjectNameW (SECUR32.@)
945 BOOLEAN WINAPI GetComputerObjectNameW(
946 EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
948 LSA_HANDLE policyHandle;
949 LSA_OBJECT_ATTRIBUTES objectAttributes;
950 PPOLICY_DNS_DOMAIN_INFO domainInfo;
951 NTSTATUS ntStatus;
952 BOOLEAN status;
953 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
955 if (NameFormat == NameUnknown)
957 SetLastError(ERROR_INVALID_PARAMETER);
958 return FALSE;
961 ZeroMemory(&objectAttributes, sizeof(objectAttributes));
962 objectAttributes.Length = sizeof(objectAttributes);
964 ntStatus = LsaOpenPolicy(NULL, &objectAttributes,
965 POLICY_VIEW_LOCAL_INFORMATION,
966 &policyHandle);
967 if (ntStatus != STATUS_SUCCESS)
969 SetLastError(LsaNtStatusToWinError(ntStatus));
970 WARN("LsaOpenPolicy failed with NT status %u\n", GetLastError());
971 return FALSE;
974 ntStatus = LsaQueryInformationPolicy(policyHandle,
975 PolicyDnsDomainInformation,
976 (PVOID *)&domainInfo);
977 if (ntStatus != STATUS_SUCCESS)
979 SetLastError(LsaNtStatusToWinError(ntStatus));
980 WARN("LsaQueryInformationPolicy failed with NT status %u\n",
981 GetLastError());
982 LsaClose(policyHandle);
983 return FALSE;
986 if (domainInfo->Sid)
988 switch (NameFormat)
990 case NameSamCompatible:
992 WCHAR name[MAX_COMPUTERNAME_LENGTH + 1];
993 DWORD size = sizeof(name)/sizeof(name[0]);
994 if (GetComputerNameW(name, &size))
996 DWORD len = domainInfo->Name.Length + size + 3;
997 if (lpNameBuffer)
999 if (*nSize < len)
1001 *nSize = len;
1002 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1003 status = FALSE;
1005 else
1007 WCHAR bs[] = { '\\', 0 };
1008 WCHAR ds[] = { '$', 0 };
1009 lstrcpyW(lpNameBuffer, domainInfo->Name.Buffer);
1010 lstrcatW(lpNameBuffer, bs);
1011 lstrcatW(lpNameBuffer, name);
1012 lstrcatW(lpNameBuffer, ds);
1013 status = TRUE;
1016 else /* just requesting length required */
1018 *nSize = len;
1019 status = TRUE;
1022 else
1024 SetLastError(ERROR_INTERNAL_ERROR);
1025 status = FALSE;
1028 break;
1029 case NameFullyQualifiedDN:
1030 case NameDisplay:
1031 case NameUniqueId:
1032 case NameCanonical:
1033 case NameUserPrincipal:
1034 case NameCanonicalEx:
1035 case NameServicePrincipal:
1036 case NameDnsDomain:
1037 FIXME("NameFormat %d not implemented\n", NameFormat);
1038 SetLastError(ERROR_CANT_ACCESS_DOMAIN_INFO);
1039 status = FALSE;
1040 break;
1041 default:
1042 SetLastError(ERROR_INVALID_PARAMETER);
1043 status = FALSE;
1046 else
1048 SetLastError(ERROR_CANT_ACCESS_DOMAIN_INFO);
1049 status = FALSE;
1052 LsaFreeMemory(domainInfo);
1053 LsaClose(policyHandle);
1055 return status;
1058 /***********************************************************************
1059 * GetUserNameExA (SECUR32.@)
1061 BOOLEAN WINAPI GetUserNameExA(
1062 EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
1064 BOOLEAN rc;
1065 LPWSTR bufferW = NULL;
1066 ULONG sizeW = *nSize;
1067 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
1068 if (lpNameBuffer) {
1069 bufferW = HeapAlloc(GetProcessHeap(), 0, sizeW * sizeof(WCHAR));
1070 if (bufferW == NULL) {
1071 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1072 return FALSE;
1075 rc = GetUserNameExW(NameFormat, bufferW, &sizeW);
1076 if (rc) {
1077 ULONG len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
1078 if (len <= *nSize)
1080 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, lpNameBuffer, *nSize, NULL, NULL);
1081 *nSize = len - 1;
1083 else
1085 *nSize = len;
1086 rc = FALSE;
1087 SetLastError(ERROR_MORE_DATA);
1090 else
1091 *nSize = sizeW;
1092 HeapFree(GetProcessHeap(), 0, bufferW);
1093 return rc;
1096 BOOLEAN WINAPI GetUserNameExW(
1097 EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
1099 BOOLEAN status;
1100 WCHAR samname[UNLEN + 1 + MAX_COMPUTERNAME_LENGTH + 1];
1101 LPWSTR out;
1102 DWORD len;
1103 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
1105 switch (NameFormat)
1107 case NameSamCompatible:
1109 /* This assumes the current user is always a local account */
1110 len = MAX_COMPUTERNAME_LENGTH + 1;
1111 if (GetComputerNameW(samname, &len))
1113 out = samname + lstrlenW(samname);
1114 *out++ = '\\';
1115 len = UNLEN + 1;
1116 if (GetUserNameW(out, &len))
1118 status = (lstrlenW(samname) < *nSize);
1119 if (status)
1121 lstrcpyW(lpNameBuffer, samname);
1122 *nSize = lstrlenW(samname);
1124 else
1126 SetLastError(ERROR_MORE_DATA);
1127 *nSize = lstrlenW(samname) + 1;
1130 else
1131 status = FALSE;
1133 else
1134 status = FALSE;
1136 break;
1137 case NameUnknown:
1138 case NameFullyQualifiedDN:
1139 case NameDisplay:
1140 case NameUniqueId:
1141 case NameCanonical:
1142 case NameUserPrincipal:
1143 case NameCanonicalEx:
1144 case NameServicePrincipal:
1145 case NameDnsDomain:
1146 SetLastError(ERROR_NONE_MAPPED);
1147 status = FALSE;
1148 break;
1149 default:
1150 SetLastError(ERROR_INVALID_PARAMETER);
1151 status = FALSE;
1154 return status;
1157 BOOLEAN WINAPI TranslateNameA(
1158 LPCSTR lpAccountName, EXTENDED_NAME_FORMAT AccountNameFormat,
1159 EXTENDED_NAME_FORMAT DesiredNameFormat, LPSTR lpTranslatedName,
1160 PULONG nSize)
1162 FIXME("%p %d %d %p %p\n", lpAccountName, AccountNameFormat,
1163 DesiredNameFormat, lpTranslatedName, nSize);
1164 return FALSE;
1167 BOOLEAN WINAPI TranslateNameW(
1168 LPCWSTR lpAccountName, EXTENDED_NAME_FORMAT AccountNameFormat,
1169 EXTENDED_NAME_FORMAT DesiredNameFormat, LPWSTR lpTranslatedName,
1170 PULONG nSize)
1172 FIXME("%p %d %d %p %p\n", lpAccountName, AccountNameFormat,
1173 DesiredNameFormat, lpTranslatedName, nSize);
1174 return FALSE;
1177 /***********************************************************************
1178 * DllMain (SECUR32.0)
1180 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1182 if (fdwReason == DLL_PROCESS_ATTACH)
1184 DisableThreadLibraryCalls(hinstDLL);
1185 SECUR32_initializeProviders();
1187 else if (fdwReason == DLL_PROCESS_DETACH)
1189 SECUR32_freeProviders();
1192 return TRUE;