ddraw/tests: Remove p8_primary_test.
[wine.git] / dlls / secur32 / secur32.c
blob1605c7fad8ae71e0d5e8db109ed253dc4757da58
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"
39 #include "wine/unicode.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
43 /**
44 * Type definitions
47 typedef struct _SecurePackageTable
49 DWORD numPackages;
50 DWORD numAllocated;
51 struct list table;
52 } SecurePackageTable;
54 typedef struct _SecureProviderTable
56 DWORD numProviders;
57 DWORD numAllocated;
58 struct list table;
59 } SecureProviderTable;
61 /**
62 * Prototypes
65 /* Tries to load moduleName as a provider. If successful, enumerates what
66 * packages it can and adds them to the package and provider tables. Resizes
67 * tables as necessary.
69 static void _tryLoadProvider(PWSTR moduleName);
71 /* Initialization: read securityproviders value and attempt to open each dll
72 * there. For each DLL, call _tryLoadProvider to see if it's really an SSP.
73 * Two undocumented functions, AddSecurityPackage(A/W) and
74 * DeleteSecurityPackage(A/W), seem suspiciously like they'd register or
75 * unregister a dll, but I'm not sure.
77 static void SECUR32_initializeProviders(void);
79 /* Frees all loaded packages and providers */
80 static void SECUR32_freeProviders(void);
82 /**
83 * Globals
86 static CRITICAL_SECTION cs;
87 static CRITICAL_SECTION_DEBUG cs_debug =
89 0, 0, &cs,
90 { &cs_debug.ProcessLocksList, &cs_debug.ProcessLocksList },
91 0, 0, { (DWORD_PTR)(__FILE__ ": cs") }
93 static CRITICAL_SECTION cs = { &cs_debug, -1, 0, 0, 0, 0 };
94 static SecurePackageTable *packageTable = NULL;
95 static SecureProviderTable *providerTable = NULL;
97 static SecurityFunctionTableA securityFunctionTableA = {
98 SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
99 EnumerateSecurityPackagesA,
100 QueryCredentialsAttributesA,
101 AcquireCredentialsHandleA,
102 FreeCredentialsHandle,
103 NULL, /* Reserved2 */
104 InitializeSecurityContextA,
105 AcceptSecurityContext,
106 CompleteAuthToken,
107 DeleteSecurityContext,
108 ApplyControlToken,
109 QueryContextAttributesA,
110 ImpersonateSecurityContext,
111 RevertSecurityContext,
112 MakeSignature,
113 VerifySignature,
114 FreeContextBuffer,
115 QuerySecurityPackageInfoA,
116 EncryptMessage, /* Reserved3 */
117 DecryptMessage, /* Reserved4 */
118 ExportSecurityContext,
119 ImportSecurityContextA,
120 AddCredentialsA,
121 NULL, /* Reserved8 */
122 QuerySecurityContextToken,
123 EncryptMessage,
124 DecryptMessage,
125 SetContextAttributesA
128 static SecurityFunctionTableW securityFunctionTableW = {
129 SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
130 EnumerateSecurityPackagesW,
131 QueryCredentialsAttributesW,
132 AcquireCredentialsHandleW,
133 FreeCredentialsHandle,
134 NULL, /* Reserved2 */
135 InitializeSecurityContextW,
136 AcceptSecurityContext,
137 CompleteAuthToken,
138 DeleteSecurityContext,
139 ApplyControlToken,
140 QueryContextAttributesW,
141 ImpersonateSecurityContext,
142 RevertSecurityContext,
143 MakeSignature,
144 VerifySignature,
145 FreeContextBuffer,
146 QuerySecurityPackageInfoW,
147 EncryptMessage, /* Reserved3 */
148 DecryptMessage, /* Reserved4 */
149 ExportSecurityContext,
150 ImportSecurityContextW,
151 AddCredentialsW,
152 NULL, /* Reserved8 */
153 QuerySecurityContextToken,
154 EncryptMessage,
155 DecryptMessage,
156 SetContextAttributesW
159 /***********************************************************************
160 * InitSecurityInterfaceA (SECUR32.@)
162 PSecurityFunctionTableA WINAPI InitSecurityInterfaceA(void)
164 return &securityFunctionTableA;
167 /***********************************************************************
168 * InitSecurityInterfaceW (SECUR32.@)
170 PSecurityFunctionTableW WINAPI InitSecurityInterfaceW(void)
172 return &securityFunctionTableW;
175 static PWSTR SECUR32_strdupW(PCWSTR str)
177 PWSTR ret;
179 if (str)
181 ret = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(str) + 1) * sizeof(WCHAR));
182 if (ret)
183 lstrcpyW(ret, str);
185 else
186 ret = NULL;
187 return ret;
190 PWSTR SECUR32_AllocWideFromMultiByte(PCSTR str)
192 PWSTR ret;
194 if (str)
196 int charsNeeded = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
198 if (charsNeeded)
200 ret = HeapAlloc(GetProcessHeap(), 0, charsNeeded * sizeof(WCHAR));
201 if (ret)
202 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, charsNeeded);
204 else
205 ret = NULL;
207 else
208 ret = NULL;
209 return ret;
212 PSTR SECUR32_AllocMultiByteFromWide(PCWSTR str)
214 PSTR ret;
216 if (str)
218 int charsNeeded = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0,
219 NULL, NULL);
221 if (charsNeeded)
223 ret = HeapAlloc(GetProcessHeap(), 0, charsNeeded);
224 if (ret)
225 WideCharToMultiByte(CP_ACP, 0, str, -1, ret, charsNeeded,
226 NULL, NULL);
228 else
229 ret = NULL;
231 else
232 ret = NULL;
233 return ret;
236 static void _makeFnTableA(PSecurityFunctionTableA fnTableA,
237 const SecurityFunctionTableA *inFnTableA,
238 const SecurityFunctionTableW *inFnTableW)
240 if (fnTableA)
242 if (inFnTableA)
244 /* The size of the version 1 table is based on platform sdk's
245 * sspi.h, though the sample ssp also provided with platform sdk
246 * implies only functions through QuerySecurityPackageInfoA are
247 * implemented (yikes)
249 size_t tableSize = inFnTableA->dwVersion == 1 ?
250 (const BYTE *)&inFnTableA->SetContextAttributesA -
251 (const BYTE *)inFnTableA : sizeof(SecurityFunctionTableA);
253 memcpy(fnTableA, inFnTableA, tableSize);
254 /* override this, since we can do it internally anyway */
255 fnTableA->QuerySecurityPackageInfoA =
256 QuerySecurityPackageInfoA;
258 else if (inFnTableW)
260 /* functions with thunks */
261 if (inFnTableW->AcquireCredentialsHandleW)
262 fnTableA->AcquireCredentialsHandleA =
263 thunk_AcquireCredentialsHandleA;
264 if (inFnTableW->InitializeSecurityContextW)
265 fnTableA->InitializeSecurityContextA =
266 thunk_InitializeSecurityContextA;
267 if (inFnTableW->ImportSecurityContextW)
268 fnTableA->ImportSecurityContextA =
269 thunk_ImportSecurityContextA;
270 if (inFnTableW->AddCredentialsW)
271 fnTableA->AddCredentialsA =
272 thunk_AddCredentialsA;
273 if (inFnTableW->QueryCredentialsAttributesW)
274 fnTableA->QueryCredentialsAttributesA =
275 thunk_QueryCredentialsAttributesA;
276 if (inFnTableW->QueryContextAttributesW)
277 fnTableA->QueryContextAttributesA =
278 thunk_QueryContextAttributesA;
279 if (inFnTableW->SetContextAttributesW)
280 fnTableA->SetContextAttributesA =
281 thunk_SetContextAttributesA;
282 /* this can't be thunked, there's no extra param to know which
283 * package to forward to */
284 fnTableA->EnumerateSecurityPackagesA = NULL;
285 /* functions with no thunks needed */
286 fnTableA->AcceptSecurityContext = inFnTableW->AcceptSecurityContext;
287 fnTableA->CompleteAuthToken = inFnTableW->CompleteAuthToken;
288 fnTableA->DeleteSecurityContext = inFnTableW->DeleteSecurityContext;
289 fnTableA->ImpersonateSecurityContext =
290 inFnTableW->ImpersonateSecurityContext;
291 fnTableA->RevertSecurityContext = inFnTableW->RevertSecurityContext;
292 fnTableA->MakeSignature = inFnTableW->MakeSignature;
293 fnTableA->VerifySignature = inFnTableW->VerifySignature;
294 fnTableA->FreeContextBuffer = inFnTableW->FreeContextBuffer;
295 fnTableA->QuerySecurityPackageInfoA =
296 QuerySecurityPackageInfoA;
297 fnTableA->ExportSecurityContext =
298 inFnTableW->ExportSecurityContext;
299 fnTableA->QuerySecurityContextToken =
300 inFnTableW->QuerySecurityContextToken;
301 fnTableA->EncryptMessage = inFnTableW->EncryptMessage;
302 fnTableA->DecryptMessage = inFnTableW->DecryptMessage;
307 static void _makeFnTableW(PSecurityFunctionTableW fnTableW,
308 const SecurityFunctionTableA *inFnTableA,
309 const SecurityFunctionTableW *inFnTableW)
311 if (fnTableW)
313 if (inFnTableW)
315 /* The size of the version 1 table is based on platform sdk's
316 * sspi.h, though the sample ssp also provided with platform sdk
317 * implies only functions through QuerySecurityPackageInfoA are
318 * implemented (yikes)
320 size_t tableSize = inFnTableW->dwVersion == 1 ?
321 (const BYTE *)&inFnTableW->SetContextAttributesW -
322 (const BYTE *)inFnTableW : sizeof(SecurityFunctionTableW);
324 memcpy(fnTableW, inFnTableW, tableSize);
325 /* override this, since we can do it internally anyway */
326 fnTableW->QuerySecurityPackageInfoW =
327 QuerySecurityPackageInfoW;
329 else if (inFnTableA)
331 /* functions with thunks */
332 if (inFnTableA->AcquireCredentialsHandleA)
333 fnTableW->AcquireCredentialsHandleW =
334 thunk_AcquireCredentialsHandleW;
335 if (inFnTableA->InitializeSecurityContextA)
336 fnTableW->InitializeSecurityContextW =
337 thunk_InitializeSecurityContextW;
338 if (inFnTableA->ImportSecurityContextA)
339 fnTableW->ImportSecurityContextW =
340 thunk_ImportSecurityContextW;
341 if (inFnTableA->AddCredentialsA)
342 fnTableW->AddCredentialsW =
343 thunk_AddCredentialsW;
344 if (inFnTableA->QueryCredentialsAttributesA)
345 fnTableW->QueryCredentialsAttributesW =
346 thunk_QueryCredentialsAttributesW;
347 if (inFnTableA->QueryContextAttributesA)
348 fnTableW->QueryContextAttributesW =
349 thunk_QueryContextAttributesW;
350 if (inFnTableA->SetContextAttributesA)
351 fnTableW->SetContextAttributesW =
352 thunk_SetContextAttributesW;
353 /* this can't be thunked, there's no extra param to know which
354 * package to forward to */
355 fnTableW->EnumerateSecurityPackagesW = NULL;
356 /* functions with no thunks needed */
357 fnTableW->AcceptSecurityContext = inFnTableA->AcceptSecurityContext;
358 fnTableW->CompleteAuthToken = inFnTableA->CompleteAuthToken;
359 fnTableW->DeleteSecurityContext = inFnTableA->DeleteSecurityContext;
360 fnTableW->ImpersonateSecurityContext =
361 inFnTableA->ImpersonateSecurityContext;
362 fnTableW->RevertSecurityContext = inFnTableA->RevertSecurityContext;
363 fnTableW->MakeSignature = inFnTableA->MakeSignature;
364 fnTableW->VerifySignature = inFnTableA->VerifySignature;
365 fnTableW->FreeContextBuffer = inFnTableA->FreeContextBuffer;
366 fnTableW->QuerySecurityPackageInfoW =
367 QuerySecurityPackageInfoW;
368 fnTableW->ExportSecurityContext =
369 inFnTableA->ExportSecurityContext;
370 fnTableW->QuerySecurityContextToken =
371 inFnTableA->QuerySecurityContextToken;
372 fnTableW->EncryptMessage = inFnTableA->EncryptMessage;
373 fnTableW->DecryptMessage = inFnTableA->DecryptMessage;
378 static void _copyPackageInfo(PSecPkgInfoW info, const SecPkgInfoA *inInfoA,
379 const SecPkgInfoW *inInfoW)
381 if (info && (inInfoA || inInfoW))
383 /* odd, I know, but up until Name and Comment the structures are
384 * identical
386 memcpy(info, inInfoW ? inInfoW : (const SecPkgInfoW *)inInfoA, sizeof(*info));
387 if (inInfoW)
389 info->Name = SECUR32_strdupW(inInfoW->Name);
390 info->Comment = SECUR32_strdupW(inInfoW->Comment);
392 else
394 info->Name = SECUR32_AllocWideFromMultiByte(inInfoA->Name);
395 info->Comment = SECUR32_AllocWideFromMultiByte(inInfoA->Comment);
400 SecureProvider *SECUR32_addProvider(const SecurityFunctionTableA *fnTableA,
401 const SecurityFunctionTableW *fnTableW, PCWSTR moduleName)
403 SecureProvider *ret;
405 EnterCriticalSection(&cs);
407 if (!providerTable)
409 providerTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SecureProviderTable));
410 if (!providerTable)
412 LeaveCriticalSection(&cs);
413 return NULL;
416 list_init(&providerTable->table);
419 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(SecureProvider));
420 if (!ret)
422 LeaveCriticalSection(&cs);
423 return NULL;
426 list_add_tail(&providerTable->table, &ret->entry);
427 ret->lib = NULL;
429 if (fnTableA || fnTableW)
431 ret->moduleName = moduleName ? SECUR32_strdupW(moduleName) : NULL;
432 _makeFnTableA(&ret->fnTableA, fnTableA, fnTableW);
433 _makeFnTableW(&ret->fnTableW, fnTableA, fnTableW);
434 ret->loaded = !moduleName;
436 else
438 ret->moduleName = SECUR32_strdupW(moduleName);
439 ret->loaded = FALSE;
442 LeaveCriticalSection(&cs);
443 return ret;
446 void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd,
447 const SecPkgInfoA *infoA, const SecPkgInfoW *infoW)
449 ULONG i;
451 assert(provider);
452 assert(infoA || infoW);
454 EnterCriticalSection(&cs);
456 if (!packageTable)
458 packageTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackageTable));
459 if (!packageTable)
461 LeaveCriticalSection(&cs);
462 return;
465 packageTable->numPackages = 0;
466 list_init(&packageTable->table);
469 for (i = 0; i < toAdd; i++)
471 SecurePackage *package = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackage));
472 if (!package)
473 continue;
475 list_add_tail(&packageTable->table, &package->entry);
477 package->provider = provider;
478 _copyPackageInfo(&package->infoW,
479 infoA ? &infoA[i] : NULL,
480 infoW ? &infoW[i] : NULL);
482 packageTable->numPackages += toAdd;
484 LeaveCriticalSection(&cs);
487 static void _tryLoadProvider(PWSTR moduleName)
489 HMODULE lib = LoadLibraryW(moduleName);
491 if (lib)
493 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
494 (INIT_SECURITY_INTERFACE_W)GetProcAddress(lib,
495 SECURITY_ENTRYPOINT_ANSIW);
496 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
497 (INIT_SECURITY_INTERFACE_A)GetProcAddress(lib,
498 SECURITY_ENTRYPOINT_ANSIA);
500 TRACE("loaded %s, InitSecurityInterfaceA is %p, InitSecurityInterfaceW is %p\n",
501 debugstr_w(moduleName), pInitSecurityInterfaceA,
502 pInitSecurityInterfaceW);
503 if (pInitSecurityInterfaceW || pInitSecurityInterfaceA)
505 PSecurityFunctionTableA fnTableA = NULL;
506 PSecurityFunctionTableW fnTableW = NULL;
507 ULONG toAdd = 0;
508 PSecPkgInfoA infoA = NULL;
509 PSecPkgInfoW infoW = NULL;
510 SECURITY_STATUS ret = SEC_E_OK;
512 if (pInitSecurityInterfaceA)
513 fnTableA = pInitSecurityInterfaceA();
514 if (pInitSecurityInterfaceW)
515 fnTableW = pInitSecurityInterfaceW();
516 if (fnTableW && fnTableW->EnumerateSecurityPackagesW)
518 if (fnTableW != &securityFunctionTableW)
519 ret = fnTableW->EnumerateSecurityPackagesW(&toAdd, &infoW);
520 else
521 TRACE("%s has built-in providers, skip adding\n", debugstr_w(moduleName));
523 else if (fnTableA && fnTableA->EnumerateSecurityPackagesA)
525 if (fnTableA != &securityFunctionTableA)
526 ret = fnTableA->EnumerateSecurityPackagesA(&toAdd, &infoA);
527 else
528 TRACE("%s has built-in providers, skip adding\n", debugstr_w(moduleName));
530 if (ret == SEC_E_OK && toAdd > 0 && (infoW || infoA))
532 SecureProvider *provider = SECUR32_addProvider(NULL, NULL,
533 moduleName);
535 if (provider)
536 SECUR32_addPackages(provider, toAdd, infoA, infoW);
537 if (infoW)
538 fnTableW->FreeContextBuffer(infoW);
539 else
540 fnTableA->FreeContextBuffer(infoA);
543 FreeLibrary(lib);
545 else
546 WARN("failed to load %s\n", debugstr_w(moduleName));
549 static const WCHAR securityProvidersKeyW[] = {
550 'S','Y','S','T','E','M','\\','C','u','r','r','e','n','t','C','o','n','t','r',
551 'o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','S','e','c','u','r',
552 'i','t','y','P','r','o','v','i','d','e','r','s','\0'
554 static const WCHAR securityProvidersW[] = {
555 'S','e','c','u','r','i','t','y','P','r','o','v','i','d','e','r','s',0
558 static void SECUR32_initializeProviders(void)
560 HKEY key;
561 LSTATUS apiRet;
563 TRACE("\n");
564 /* First load built-in providers */
565 SECUR32_initSchannelSP();
566 SECUR32_initNTLMSP();
567 /* Load the Negotiate provider last so apps stumble over the working NTLM
568 * provider first. Attempting to fix bug #16905 while keeping the
569 * application reported on wine-users on 2006-09-12 working. */
570 SECUR32_initNegotiateSP();
571 /* Now load providers from registry */
572 apiRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, securityProvidersKeyW, 0,
573 KEY_READ, &key);
574 if (apiRet == ERROR_SUCCESS)
576 WCHAR securityPkgNames[MAX_PATH]; /* arbitrary len */
577 DWORD size = sizeof(securityPkgNames) / sizeof(WCHAR), type;
579 apiRet = RegQueryValueExW(key, securityProvidersW, NULL, &type,
580 (PBYTE)securityPkgNames, &size);
581 if (apiRet == ERROR_SUCCESS && type == REG_SZ)
583 WCHAR *ptr;
585 size = size / sizeof(WCHAR);
586 for (ptr = securityPkgNames;
587 ptr < securityPkgNames + size; )
589 WCHAR *comma;
591 for (comma = ptr; *comma && *comma != ','; comma++)
593 if (*comma == ',')
594 *comma = '\0';
595 for (; *ptr && isspace(*ptr) && ptr < securityPkgNames + size;
596 ptr++)
598 if (*ptr)
599 _tryLoadProvider(ptr);
600 ptr += lstrlenW(ptr) + 1;
603 RegCloseKey(key);
607 SecurePackage *SECUR32_findPackageW(PCWSTR packageName)
609 SecurePackage *ret = NULL;
610 BOOL matched = FALSE;
612 if (packageTable && packageName)
614 LIST_FOR_EACH_ENTRY(ret, &packageTable->table, SecurePackage, entry)
616 matched = !lstrcmpiW(ret->infoW.Name, packageName);
617 if (matched)
618 break;
621 if (!matched)
622 return NULL;
624 if (ret->provider && !ret->provider->loaded)
626 ret->provider->lib = LoadLibraryW(ret->provider->moduleName);
627 if (ret->provider->lib)
629 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
630 (INIT_SECURITY_INTERFACE_W)GetProcAddress(ret->provider->lib,
631 SECURITY_ENTRYPOINT_ANSIW);
632 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
633 (INIT_SECURITY_INTERFACE_A)GetProcAddress(ret->provider->lib,
634 SECURITY_ENTRYPOINT_ANSIA);
635 PSecurityFunctionTableA fnTableA = NULL;
636 PSecurityFunctionTableW fnTableW = NULL;
638 if (pInitSecurityInterfaceA)
639 fnTableA = pInitSecurityInterfaceA();
640 if (pInitSecurityInterfaceW)
641 fnTableW = pInitSecurityInterfaceW();
642 /* don't update built-in SecurityFunctionTable */
643 if (fnTableA != &securityFunctionTableA)
644 _makeFnTableA(&ret->provider->fnTableA, fnTableA, fnTableW);
645 if (fnTableW != &securityFunctionTableW)
646 _makeFnTableW(&ret->provider->fnTableW, fnTableA, fnTableW);
647 ret->provider->loaded = TRUE;
649 else
650 ret = NULL;
653 return ret;
656 SecurePackage *SECUR32_findPackageA(PCSTR packageName)
658 SecurePackage *ret;
660 if (packageTable && packageName)
662 UNICODE_STRING package;
664 RtlCreateUnicodeStringFromAsciiz(&package, packageName);
665 ret = SECUR32_findPackageW(package.Buffer);
666 RtlFreeUnicodeString(&package);
668 else
669 ret = NULL;
670 return ret;
673 static void SECUR32_freeProviders(void)
675 TRACE("\n");
676 EnterCriticalSection(&cs);
678 SECUR32_deinitSchannelSP();
680 if (packageTable)
682 SecurePackage *package, *package_next;
683 LIST_FOR_EACH_ENTRY_SAFE(package, package_next, &packageTable->table,
684 SecurePackage, entry)
686 HeapFree(GetProcessHeap(), 0, package->infoW.Name);
687 HeapFree(GetProcessHeap(), 0, package->infoW.Comment);
688 HeapFree(GetProcessHeap(), 0, package);
691 HeapFree(GetProcessHeap(), 0, packageTable);
692 packageTable = NULL;
695 if (providerTable)
697 SecureProvider *provider, *provider_next;
698 LIST_FOR_EACH_ENTRY_SAFE(provider, provider_next, &providerTable->table,
699 SecureProvider, entry)
701 HeapFree(GetProcessHeap(), 0, provider->moduleName);
702 if (provider->lib)
703 FreeLibrary(provider->lib);
704 HeapFree(GetProcessHeap(), 0, provider);
707 HeapFree(GetProcessHeap(), 0, providerTable);
708 providerTable = NULL;
711 LeaveCriticalSection(&cs);
712 DeleteCriticalSection(&cs);
715 /***********************************************************************
716 * FreeContextBuffer (SECUR32.@)
718 * Doh--if pv was allocated by a crypto package, this may not be correct.
719 * The sample ssp seems to use LocalAlloc/LocalFee, but there doesn't seem to
720 * be any guarantee, nor is there an alloc function in secur32.
722 SECURITY_STATUS WINAPI FreeContextBuffer(PVOID pv)
724 HeapFree(GetProcessHeap(), 0, pv);
726 return SEC_E_OK;
729 /***********************************************************************
730 * EnumerateSecurityPackagesW (SECUR32.@)
732 SECURITY_STATUS WINAPI EnumerateSecurityPackagesW(PULONG pcPackages,
733 PSecPkgInfoW *ppPackageInfo)
735 SECURITY_STATUS ret = SEC_E_OK;
737 TRACE("(%p, %p)\n", pcPackages, ppPackageInfo);
739 /* windows just crashes if pcPackages or ppPackageInfo is NULL, so will I */
740 *pcPackages = 0;
741 EnterCriticalSection(&cs);
742 if (packageTable)
744 SecurePackage *package;
745 size_t bytesNeeded;
747 bytesNeeded = packageTable->numPackages * sizeof(SecPkgInfoW);
748 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
750 if (package->infoW.Name)
751 bytesNeeded += (lstrlenW(package->infoW.Name) + 1) * sizeof(WCHAR);
752 if (package->infoW.Comment)
753 bytesNeeded += (lstrlenW(package->infoW.Comment) + 1) * sizeof(WCHAR);
755 if (bytesNeeded)
757 *ppPackageInfo = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
758 if (*ppPackageInfo)
760 ULONG i = 0;
761 PWSTR nextString;
763 *pcPackages = packageTable->numPackages;
764 nextString = (PWSTR)((PBYTE)*ppPackageInfo +
765 packageTable->numPackages * sizeof(SecPkgInfoW));
766 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
768 PSecPkgInfoW pkgInfo = *ppPackageInfo + i++;
770 *pkgInfo = package->infoW;
771 if (package->infoW.Name)
773 TRACE("Name[%d] = %s\n", i - 1, debugstr_w(package->infoW.Name));
774 pkgInfo->Name = nextString;
775 lstrcpyW(nextString, package->infoW.Name);
776 nextString += lstrlenW(nextString) + 1;
778 else
779 pkgInfo->Name = NULL;
780 if (package->infoW.Comment)
782 TRACE("Comment[%d] = %s\n", i - 1, debugstr_w(package->infoW.Comment));
783 pkgInfo->Comment = nextString;
784 lstrcpyW(nextString, package->infoW.Comment);
785 nextString += lstrlenW(nextString) + 1;
787 else
788 pkgInfo->Comment = NULL;
791 else
792 ret = SEC_E_INSUFFICIENT_MEMORY;
795 LeaveCriticalSection(&cs);
796 TRACE("<-- 0x%08x\n", ret);
797 return ret;
800 /* Converts info (which is assumed to be an array of cPackages SecPkgInfoW
801 * structures) into an array of SecPkgInfoA structures, which it returns.
803 static PSecPkgInfoA thunk_PSecPkgInfoWToA(ULONG cPackages,
804 const SecPkgInfoW *info)
806 PSecPkgInfoA ret;
808 if (info)
810 size_t bytesNeeded = cPackages * sizeof(SecPkgInfoA);
811 ULONG i;
813 for (i = 0; i < cPackages; i++)
815 if (info[i].Name)
816 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Name,
817 -1, NULL, 0, NULL, NULL);
818 if (info[i].Comment)
819 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Comment,
820 -1, NULL, 0, NULL, NULL);
822 ret = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
823 if (ret)
825 PSTR nextString;
827 nextString = (PSTR)((PBYTE)ret + cPackages * sizeof(SecPkgInfoA));
828 for (i = 0; i < cPackages; i++)
830 PSecPkgInfoA pkgInfo = ret + i;
831 int bytes;
833 memcpy(pkgInfo, &info[i], sizeof(SecPkgInfoA));
834 if (info[i].Name)
836 pkgInfo->Name = nextString;
837 /* just repeat back to WideCharToMultiByte how many bytes
838 * it requires, since we asked it earlier
840 bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
841 NULL, 0, NULL, NULL);
842 WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
843 pkgInfo->Name, bytes, NULL, NULL);
844 nextString += lstrlenA(nextString) + 1;
846 else
847 pkgInfo->Name = NULL;
848 if (info[i].Comment)
850 pkgInfo->Comment = nextString;
851 /* just repeat back to WideCharToMultiByte how many bytes
852 * it requires, since we asked it earlier
854 bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
855 NULL, 0, NULL, NULL);
856 WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
857 pkgInfo->Comment, bytes, NULL, NULL);
858 nextString += lstrlenA(nextString) + 1;
860 else
861 pkgInfo->Comment = NULL;
865 else
866 ret = NULL;
867 return ret;
870 /***********************************************************************
871 * EnumerateSecurityPackagesA (SECUR32.@)
873 SECURITY_STATUS WINAPI EnumerateSecurityPackagesA(PULONG pcPackages,
874 PSecPkgInfoA *ppPackageInfo)
876 SECURITY_STATUS ret;
877 PSecPkgInfoW info;
879 ret = EnumerateSecurityPackagesW(pcPackages, &info);
880 if (ret == SEC_E_OK && *pcPackages && info)
882 *ppPackageInfo = thunk_PSecPkgInfoWToA(*pcPackages, info);
883 if (*pcPackages && !*ppPackageInfo)
885 *pcPackages = 0;
886 ret = SEC_E_INSUFFICIENT_MEMORY;
888 FreeContextBuffer(info);
890 return ret;
893 /***********************************************************************
894 * GetComputerObjectNameA (SECUR32.@)
896 * Get the local computer's name using the format specified.
898 * PARAMS
899 * NameFormat [I] The format for the name.
900 * lpNameBuffer [O] Pointer to buffer to receive the name.
901 * nSize [I/O] Size in characters of buffer.
903 * RETURNS
904 * TRUE If the name was written to lpNameBuffer.
905 * FALSE If the name couldn't be written.
907 * NOTES
908 * If lpNameBuffer is NULL, then the size of the buffer needed to hold the
909 * name will be returned in *nSize.
911 * nSize returns the number of characters written when lpNameBuffer is not
912 * NULL or the size of the buffer needed to hold the name when the buffer
913 * is too short or lpNameBuffer is NULL.
915 * It the buffer is too short, ERROR_INSUFFICIENT_BUFFER error will be set.
917 BOOLEAN WINAPI GetComputerObjectNameA(
918 EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
920 BOOLEAN rc;
921 LPWSTR bufferW = NULL;
922 ULONG sizeW = *nSize;
923 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
924 if (lpNameBuffer) {
925 bufferW = HeapAlloc(GetProcessHeap(), 0, sizeW * sizeof(WCHAR));
926 if (bufferW == NULL) {
927 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
928 return FALSE;
931 rc = GetComputerObjectNameW(NameFormat, bufferW, &sizeW);
932 if (rc && bufferW) {
933 ULONG len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
934 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, lpNameBuffer, *nSize, NULL, NULL);
935 *nSize = len;
937 else
938 *nSize = sizeW;
939 HeapFree(GetProcessHeap(), 0, bufferW);
940 return rc;
943 /***********************************************************************
944 * GetComputerObjectNameW (SECUR32.@)
946 BOOLEAN WINAPI GetComputerObjectNameW(
947 EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
949 LSA_HANDLE policyHandle;
950 LSA_OBJECT_ATTRIBUTES objectAttributes;
951 PPOLICY_DNS_DOMAIN_INFO domainInfo;
952 NTSTATUS ntStatus;
953 BOOLEAN status;
954 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
956 if (NameFormat == NameUnknown)
958 SetLastError(ERROR_INVALID_PARAMETER);
959 return FALSE;
962 ZeroMemory(&objectAttributes, sizeof(objectAttributes));
963 objectAttributes.Length = sizeof(objectAttributes);
965 ntStatus = LsaOpenPolicy(NULL, &objectAttributes,
966 POLICY_VIEW_LOCAL_INFORMATION,
967 &policyHandle);
968 if (ntStatus != STATUS_SUCCESS)
970 SetLastError(LsaNtStatusToWinError(ntStatus));
971 WARN("LsaOpenPolicy failed with NT status %u\n", GetLastError());
972 return FALSE;
975 ntStatus = LsaQueryInformationPolicy(policyHandle,
976 PolicyDnsDomainInformation,
977 (PVOID *)&domainInfo);
978 if (ntStatus != STATUS_SUCCESS)
980 SetLastError(LsaNtStatusToWinError(ntStatus));
981 WARN("LsaQueryInformationPolicy failed with NT status %u\n",
982 GetLastError());
983 LsaClose(policyHandle);
984 return FALSE;
987 if (domainInfo->Sid)
989 switch (NameFormat)
991 case NameSamCompatible:
993 WCHAR name[MAX_COMPUTERNAME_LENGTH + 1];
994 DWORD size = sizeof(name)/sizeof(name[0]);
995 if (GetComputerNameW(name, &size))
997 DWORD len = domainInfo->Name.Length + size + 3;
998 if (lpNameBuffer)
1000 if (*nSize < len)
1002 *nSize = len;
1003 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1004 status = FALSE;
1006 else
1008 WCHAR bs[] = { '\\', 0 };
1009 WCHAR ds[] = { '$', 0 };
1010 lstrcpyW(lpNameBuffer, domainInfo->Name.Buffer);
1011 lstrcatW(lpNameBuffer, bs);
1012 lstrcatW(lpNameBuffer, name);
1013 lstrcatW(lpNameBuffer, ds);
1014 status = TRUE;
1017 else /* just requesting length required */
1019 *nSize = len;
1020 status = TRUE;
1023 else
1025 SetLastError(ERROR_INTERNAL_ERROR);
1026 status = FALSE;
1029 break;
1030 case NameFullyQualifiedDN:
1031 case NameDisplay:
1032 case NameUniqueId:
1033 case NameCanonical:
1034 case NameUserPrincipal:
1035 case NameCanonicalEx:
1036 case NameServicePrincipal:
1037 case NameDnsDomain:
1038 FIXME("NameFormat %d not implemented\n", NameFormat);
1039 SetLastError(ERROR_CANT_ACCESS_DOMAIN_INFO);
1040 status = FALSE;
1041 break;
1042 default:
1043 SetLastError(ERROR_INVALID_PARAMETER);
1044 status = FALSE;
1047 else
1049 SetLastError(ERROR_CANT_ACCESS_DOMAIN_INFO);
1050 status = FALSE;
1053 LsaFreeMemory(domainInfo);
1054 LsaClose(policyHandle);
1056 return status;
1059 /***********************************************************************
1060 * GetUserNameExA (SECUR32.@)
1062 BOOLEAN WINAPI GetUserNameExA(
1063 EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
1065 BOOLEAN rc;
1066 LPWSTR bufferW = NULL;
1067 ULONG sizeW = *nSize;
1068 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
1069 if (lpNameBuffer) {
1070 bufferW = HeapAlloc(GetProcessHeap(), 0, sizeW * sizeof(WCHAR));
1071 if (bufferW == NULL) {
1072 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1073 return FALSE;
1076 rc = GetUserNameExW(NameFormat, bufferW, &sizeW);
1077 if (rc) {
1078 ULONG len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
1079 if (len <= *nSize)
1081 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, lpNameBuffer, *nSize, NULL, NULL);
1082 *nSize = len - 1;
1084 else
1086 *nSize = len;
1087 rc = FALSE;
1088 SetLastError(ERROR_MORE_DATA);
1091 else
1092 *nSize = sizeW;
1093 HeapFree(GetProcessHeap(), 0, bufferW);
1094 return rc;
1097 BOOLEAN WINAPI GetUserNameExW(
1098 EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
1100 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
1102 switch (NameFormat)
1104 case NameSamCompatible:
1106 WCHAR samname[UNLEN + 1 + MAX_COMPUTERNAME_LENGTH + 1];
1107 LPWSTR out;
1108 DWORD len;
1110 /* This assumes the current user is always a local account */
1111 len = MAX_COMPUTERNAME_LENGTH + 1;
1112 if (GetComputerNameW(samname, &len))
1114 out = samname + lstrlenW(samname);
1115 *out++ = '\\';
1116 len = UNLEN + 1;
1117 if (GetUserNameW(out, &len))
1119 if (lstrlenW(samname) < *nSize)
1121 lstrcpyW(lpNameBuffer, samname);
1122 *nSize = lstrlenW(samname);
1123 return TRUE;
1126 SetLastError(ERROR_MORE_DATA);
1127 *nSize = lstrlenW(samname) + 1;
1130 return FALSE;
1133 case NameUnknown:
1134 case NameFullyQualifiedDN:
1135 case NameDisplay:
1136 case NameUniqueId:
1137 case NameCanonical:
1138 case NameUserPrincipal:
1139 case NameCanonicalEx:
1140 case NameServicePrincipal:
1141 case NameDnsDomain:
1142 SetLastError(ERROR_NONE_MAPPED);
1143 return FALSE;
1145 default:
1146 SetLastError(ERROR_INVALID_PARAMETER);
1147 return FALSE;
1151 BOOLEAN WINAPI TranslateNameA(
1152 LPCSTR lpAccountName, EXTENDED_NAME_FORMAT AccountNameFormat,
1153 EXTENDED_NAME_FORMAT DesiredNameFormat, LPSTR lpTranslatedName,
1154 PULONG nSize)
1156 FIXME("%p %d %d %p %p\n", lpAccountName, AccountNameFormat,
1157 DesiredNameFormat, lpTranslatedName, nSize);
1158 return FALSE;
1161 BOOLEAN WINAPI TranslateNameW(
1162 LPCWSTR lpAccountName, EXTENDED_NAME_FORMAT AccountNameFormat,
1163 EXTENDED_NAME_FORMAT DesiredNameFormat, LPWSTR lpTranslatedName,
1164 PULONG nSize)
1166 FIXME("%p %d %d %p %p\n", lpAccountName, AccountNameFormat,
1167 DesiredNameFormat, lpTranslatedName, nSize);
1168 return FALSE;
1171 /***********************************************************************
1172 * SspiEncodeAuthIdentityAsStrings (SECUR32.0)
1174 SECURITY_STATUS SEC_ENTRY SspiEncodeAuthIdentityAsStrings(
1175 PSEC_WINNT_AUTH_IDENTITY_OPAQUE opaque_id, PCWSTR *username,
1176 PCWSTR *domainname, PCWSTR *creds )
1178 SEC_WINNT_AUTH_IDENTITY_W *id = (SEC_WINNT_AUTH_IDENTITY_W *)opaque_id;
1180 FIXME("%p %p %p %p\n", opaque_id, username, domainname, creds);
1182 *username = SECUR32_strdupW( id->User );
1183 *domainname = SECUR32_strdupW( id->Domain );
1184 *creds = SECUR32_strdupW( id->Password );
1186 return SEC_E_OK;
1189 /***********************************************************************
1190 * SspiEncodeStringsAsAuthIdentity (SECUR32.0)
1192 SECURITY_STATUS SEC_ENTRY SspiEncodeStringsAsAuthIdentity(
1193 PCWSTR username, PCWSTR domainname, PCWSTR creds,
1194 PSEC_WINNT_AUTH_IDENTITY_OPAQUE *opaque_id )
1196 SEC_WINNT_AUTH_IDENTITY_W *id;
1197 DWORD len_username = 0, len_domainname = 0, len_password = 0, size;
1198 WCHAR *ptr;
1200 FIXME( "%s %s %s %p\n", debugstr_w(username), debugstr_w(domainname),
1201 debugstr_w(creds), opaque_id );
1203 if (!username && !domainname && !creds) return SEC_E_INVALID_TOKEN;
1205 if (username) len_username = strlenW( username );
1206 if (domainname) len_domainname = strlenW( domainname );
1207 if (creds) len_password = strlenW( creds );
1209 size = sizeof(*id);
1210 if (username) size += (len_username + 1) * sizeof(WCHAR);
1211 if (domainname) size += (len_domainname + 1) * sizeof(WCHAR);
1212 if (creds) size += (len_password + 1) * sizeof(WCHAR);
1213 if (!(id = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ))) return ERROR_OUTOFMEMORY;
1214 ptr = (WCHAR *)(id + 1);
1216 if (username)
1218 memcpy( ptr, username, (len_username + 1) * sizeof(WCHAR) );
1219 id->User = ptr;
1220 id->UserLength = len_username;
1221 ptr += len_username + 1;
1223 if (domainname)
1225 memcpy( ptr, domainname, (len_domainname + 1) * sizeof(WCHAR) );
1226 id->Domain = ptr;
1227 id->DomainLength = len_domainname;
1228 ptr += len_domainname + 1;
1230 if (creds)
1232 memcpy( ptr, creds, (len_password + 1) * sizeof(WCHAR) );
1233 id->Password = ptr;
1234 id->PasswordLength = len_password;
1237 *opaque_id = id;
1238 return SEC_E_OK;
1241 /***********************************************************************
1242 * SspiFreeAuthIdentity (SECUR32.0)
1244 void SEC_ENTRY SspiFreeAuthIdentity( PSEC_WINNT_AUTH_IDENTITY_OPAQUE opaque_id )
1247 TRACE( "%p\n", opaque_id );
1248 HeapFree( GetProcessHeap(), 0, opaque_id );
1251 /***********************************************************************
1252 * SspiLocalFree (SECUR32.0)
1254 void SEC_ENTRY SspiLocalFree( void *ptr )
1256 TRACE( "%p\n", ptr );
1257 HeapFree( GetProcessHeap(), 0, ptr );
1260 /***********************************************************************
1261 * SspiZeroAuthIdentity (SECUR32.0)
1263 void SEC_ENTRY SspiZeroAuthIdentity( PSEC_WINNT_AUTH_IDENTITY_OPAQUE opaque_id )
1265 SEC_WINNT_AUTH_IDENTITY_W *id = (SEC_WINNT_AUTH_IDENTITY_W *)opaque_id;
1267 TRACE( "%p\n", opaque_id );
1269 if (!id) return;
1270 if (id->User) memset( id->User, 0, id->UserLength * sizeof(WCHAR) );
1271 if (id->Domain) memset( id->Domain, 0, id->DomainLength * sizeof(WCHAR) );
1272 if (id->Password) memset( id->Password, 0, id->PasswordLength * sizeof(WCHAR) );
1273 memset( id, 0, sizeof(*id) );
1276 /***********************************************************************
1277 * DllMain (SECUR32.0)
1279 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved)
1281 switch (reason)
1283 case DLL_PROCESS_ATTACH:
1284 DisableThreadLibraryCalls(hinstDLL);
1285 SECUR32_initializeProviders();
1286 break;
1287 case DLL_PROCESS_DETACH:
1288 if (reserved) break;
1289 SECUR32_freeProviders();
1292 return TRUE;