README: Update for 1.2.
[wine/hacks.git] / dlls / secur32 / secur32.c
blobae1326c616771117e20e0435c548d73b1c9df65a
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 SecurePackageTable *packageTable = NULL;
87 static SecureProviderTable *providerTable = NULL;
89 static SecurityFunctionTableA securityFunctionTableA = {
90 SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
91 EnumerateSecurityPackagesA,
92 QueryCredentialsAttributesA,
93 AcquireCredentialsHandleA,
94 FreeCredentialsHandle,
95 NULL, /* Reserved2 */
96 InitializeSecurityContextA,
97 AcceptSecurityContext,
98 CompleteAuthToken,
99 DeleteSecurityContext,
100 ApplyControlToken,
101 QueryContextAttributesA,
102 ImpersonateSecurityContext,
103 RevertSecurityContext,
104 MakeSignature,
105 VerifySignature,
106 FreeContextBuffer,
107 QuerySecurityPackageInfoA,
108 EncryptMessage, /* Reserved3 */
109 DecryptMessage, /* Reserved4 */
110 ExportSecurityContext,
111 ImportSecurityContextA,
112 AddCredentialsA,
113 NULL, /* Reserved8 */
114 QuerySecurityContextToken,
115 EncryptMessage,
116 DecryptMessage,
117 SetContextAttributesA
120 static SecurityFunctionTableW securityFunctionTableW = {
121 SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
122 EnumerateSecurityPackagesW,
123 QueryCredentialsAttributesW,
124 AcquireCredentialsHandleW,
125 FreeCredentialsHandle,
126 NULL, /* Reserved2 */
127 InitializeSecurityContextW,
128 AcceptSecurityContext,
129 CompleteAuthToken,
130 DeleteSecurityContext,
131 ApplyControlToken,
132 QueryContextAttributesW,
133 ImpersonateSecurityContext,
134 RevertSecurityContext,
135 MakeSignature,
136 VerifySignature,
137 FreeContextBuffer,
138 QuerySecurityPackageInfoW,
139 EncryptMessage, /* Reserved3 */
140 DecryptMessage, /* Reserved4 */
141 ExportSecurityContext,
142 ImportSecurityContextW,
143 AddCredentialsW,
144 NULL, /* Reserved8 */
145 QuerySecurityContextToken,
146 EncryptMessage,
147 DecryptMessage,
148 SetContextAttributesW
151 /***********************************************************************
152 * InitSecurityInterfaceA (SECUR32.@)
154 PSecurityFunctionTableA WINAPI InitSecurityInterfaceA(void)
156 return &securityFunctionTableA;
159 /***********************************************************************
160 * InitSecurityInterfaceW (SECUR32.@)
162 PSecurityFunctionTableW WINAPI InitSecurityInterfaceW(void)
164 return &securityFunctionTableW;
167 static PWSTR SECUR32_strdupW(PCWSTR str)
169 PWSTR ret;
171 if (str)
173 ret = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(str) + 1) * sizeof(WCHAR));
174 if (ret)
175 lstrcpyW(ret, str);
177 else
178 ret = NULL;
179 return ret;
182 PWSTR SECUR32_AllocWideFromMultiByte(PCSTR str)
184 PWSTR ret;
186 if (str)
188 int charsNeeded = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
190 if (charsNeeded)
192 ret = HeapAlloc(GetProcessHeap(), 0, charsNeeded * sizeof(WCHAR));
193 if (ret)
194 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, charsNeeded);
196 else
197 ret = NULL;
199 else
200 ret = NULL;
201 return ret;
204 PSTR SECUR32_AllocMultiByteFromWide(PCWSTR str)
206 PSTR ret;
208 if (str)
210 int charsNeeded = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0,
211 NULL, NULL);
213 if (charsNeeded)
215 ret = HeapAlloc(GetProcessHeap(), 0, charsNeeded);
216 if (ret)
217 WideCharToMultiByte(CP_ACP, 0, str, -1, ret, charsNeeded,
218 NULL, NULL);
220 else
221 ret = NULL;
223 else
224 ret = NULL;
225 return ret;
228 static void _makeFnTableA(PSecurityFunctionTableA fnTableA,
229 const SecurityFunctionTableA *inFnTableA,
230 const SecurityFunctionTableW *inFnTableW)
232 if (fnTableA)
234 if (inFnTableA)
236 /* The size of the version 1 table is based on platform sdk's
237 * sspi.h, though the sample ssp also provided with platform sdk
238 * implies only functions through QuerySecurityPackageInfoA are
239 * implemented (yikes)
241 size_t tableSize = inFnTableA->dwVersion == 1 ?
242 (const BYTE *)&inFnTableA->SetContextAttributesA -
243 (const BYTE *)inFnTableA : sizeof(SecurityFunctionTableA);
245 memcpy(fnTableA, inFnTableA, tableSize);
246 /* override this, since we can do it internally anyway */
247 fnTableA->QuerySecurityPackageInfoA =
248 QuerySecurityPackageInfoA;
250 else if (inFnTableW)
252 /* functions with thunks */
253 if (inFnTableW->AcquireCredentialsHandleW)
254 fnTableA->AcquireCredentialsHandleA =
255 thunk_AcquireCredentialsHandleA;
256 if (inFnTableW->InitializeSecurityContextW)
257 fnTableA->InitializeSecurityContextA =
258 thunk_InitializeSecurityContextA;
259 if (inFnTableW->ImportSecurityContextW)
260 fnTableA->ImportSecurityContextA =
261 thunk_ImportSecurityContextA;
262 if (inFnTableW->AddCredentialsW)
263 fnTableA->AddCredentialsA =
264 thunk_AddCredentialsA;
265 if (inFnTableW->QueryCredentialsAttributesW)
266 fnTableA->QueryCredentialsAttributesA =
267 thunk_QueryCredentialsAttributesA;
268 if (inFnTableW->QueryContextAttributesW)
269 fnTableA->QueryContextAttributesA =
270 thunk_QueryContextAttributesA;
271 if (inFnTableW->SetContextAttributesW)
272 fnTableA->SetContextAttributesA =
273 thunk_SetContextAttributesA;
274 /* this can't be thunked, there's no extra param to know which
275 * package to forward to */
276 fnTableA->EnumerateSecurityPackagesA = NULL;
277 /* functions with no thunks needed */
278 fnTableA->AcceptSecurityContext = inFnTableW->AcceptSecurityContext;
279 fnTableA->CompleteAuthToken = inFnTableW->CompleteAuthToken;
280 fnTableA->DeleteSecurityContext = inFnTableW->DeleteSecurityContext;
281 fnTableA->ImpersonateSecurityContext =
282 inFnTableW->ImpersonateSecurityContext;
283 fnTableA->RevertSecurityContext = inFnTableW->RevertSecurityContext;
284 fnTableA->MakeSignature = inFnTableW->MakeSignature;
285 fnTableA->VerifySignature = inFnTableW->VerifySignature;
286 fnTableA->FreeContextBuffer = inFnTableW->FreeContextBuffer;
287 fnTableA->QuerySecurityPackageInfoA =
288 QuerySecurityPackageInfoA;
289 fnTableA->ExportSecurityContext =
290 inFnTableW->ExportSecurityContext;
291 fnTableA->QuerySecurityContextToken =
292 inFnTableW->QuerySecurityContextToken;
293 fnTableA->EncryptMessage = inFnTableW->EncryptMessage;
294 fnTableA->DecryptMessage = inFnTableW->DecryptMessage;
299 static void _makeFnTableW(PSecurityFunctionTableW fnTableW,
300 const SecurityFunctionTableA *inFnTableA,
301 const SecurityFunctionTableW *inFnTableW)
303 if (fnTableW)
305 if (inFnTableW)
307 /* The size of the version 1 table is based on platform sdk's
308 * sspi.h, though the sample ssp also provided with platform sdk
309 * implies only functions through QuerySecurityPackageInfoA are
310 * implemented (yikes)
312 size_t tableSize = inFnTableW->dwVersion == 1 ?
313 (const BYTE *)&inFnTableW->SetContextAttributesW -
314 (const BYTE *)inFnTableW : sizeof(SecurityFunctionTableW);
316 memcpy(fnTableW, inFnTableW, tableSize);
317 /* override this, since we can do it internally anyway */
318 fnTableW->QuerySecurityPackageInfoW =
319 QuerySecurityPackageInfoW;
321 else if (inFnTableA)
323 /* functions with thunks */
324 if (inFnTableA->AcquireCredentialsHandleA)
325 fnTableW->AcquireCredentialsHandleW =
326 thunk_AcquireCredentialsHandleW;
327 if (inFnTableA->InitializeSecurityContextA)
328 fnTableW->InitializeSecurityContextW =
329 thunk_InitializeSecurityContextW;
330 if (inFnTableA->ImportSecurityContextA)
331 fnTableW->ImportSecurityContextW =
332 thunk_ImportSecurityContextW;
333 if (inFnTableA->AddCredentialsA)
334 fnTableW->AddCredentialsW =
335 thunk_AddCredentialsW;
336 if (inFnTableA->QueryCredentialsAttributesA)
337 fnTableW->QueryCredentialsAttributesW =
338 thunk_QueryCredentialsAttributesW;
339 if (inFnTableA->QueryContextAttributesA)
340 fnTableW->QueryContextAttributesW =
341 thunk_QueryContextAttributesW;
342 if (inFnTableA->SetContextAttributesA)
343 fnTableW->SetContextAttributesW =
344 thunk_SetContextAttributesW;
345 /* this can't be thunked, there's no extra param to know which
346 * package to forward to */
347 fnTableW->EnumerateSecurityPackagesW = NULL;
348 /* functions with no thunks needed */
349 fnTableW->AcceptSecurityContext = inFnTableA->AcceptSecurityContext;
350 fnTableW->CompleteAuthToken = inFnTableA->CompleteAuthToken;
351 fnTableW->DeleteSecurityContext = inFnTableA->DeleteSecurityContext;
352 fnTableW->ImpersonateSecurityContext =
353 inFnTableA->ImpersonateSecurityContext;
354 fnTableW->RevertSecurityContext = inFnTableA->RevertSecurityContext;
355 fnTableW->MakeSignature = inFnTableA->MakeSignature;
356 fnTableW->VerifySignature = inFnTableA->VerifySignature;
357 fnTableW->FreeContextBuffer = inFnTableA->FreeContextBuffer;
358 fnTableW->QuerySecurityPackageInfoW =
359 QuerySecurityPackageInfoW;
360 fnTableW->ExportSecurityContext =
361 inFnTableA->ExportSecurityContext;
362 fnTableW->QuerySecurityContextToken =
363 inFnTableA->QuerySecurityContextToken;
364 fnTableW->EncryptMessage = inFnTableA->EncryptMessage;
365 fnTableW->DecryptMessage = inFnTableA->DecryptMessage;
370 static void _copyPackageInfo(PSecPkgInfoW info, const SecPkgInfoA *inInfoA,
371 const SecPkgInfoW *inInfoW)
373 if (info && (inInfoA || inInfoW))
375 /* odd, I know, but up until Name and Comment the structures are
376 * identical
378 memcpy(info, inInfoW ? inInfoW : (const SecPkgInfoW *)inInfoA, sizeof(*info));
379 if (inInfoW)
381 info->Name = SECUR32_strdupW(inInfoW->Name);
382 info->Comment = SECUR32_strdupW(inInfoW->Comment);
384 else
386 info->Name = SECUR32_AllocWideFromMultiByte(inInfoA->Name);
387 info->Comment = SECUR32_AllocWideFromMultiByte(inInfoA->Comment);
392 SecureProvider *SECUR32_addProvider(const SecurityFunctionTableA *fnTableA,
393 const SecurityFunctionTableW *fnTableW, PCWSTR moduleName)
395 SecureProvider *ret;
397 EnterCriticalSection(&cs);
399 if (!providerTable)
401 providerTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SecureProviderTable));
402 if (!providerTable)
404 LeaveCriticalSection(&cs);
405 return NULL;
408 list_init(&providerTable->table);
411 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(SecureProvider));
412 if (!ret)
414 LeaveCriticalSection(&cs);
415 return NULL;
418 list_add_tail(&providerTable->table, &ret->entry);
419 ret->lib = NULL;
421 if (fnTableA || fnTableW)
423 ret->moduleName = moduleName ? SECUR32_strdupW(moduleName) : NULL;
424 _makeFnTableA(&ret->fnTableA, fnTableA, fnTableW);
425 _makeFnTableW(&ret->fnTableW, fnTableA, fnTableW);
426 ret->loaded = moduleName ? FALSE : TRUE;
428 else
430 ret->moduleName = SECUR32_strdupW(moduleName);
431 ret->loaded = FALSE;
434 LeaveCriticalSection(&cs);
435 return ret;
438 void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd,
439 const SecPkgInfoA *infoA, const SecPkgInfoW *infoW)
441 ULONG i;
443 assert(provider);
444 assert(infoA || infoW);
446 EnterCriticalSection(&cs);
448 if (!packageTable)
450 packageTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackageTable));
451 if (!packageTable)
453 LeaveCriticalSection(&cs);
454 return;
457 packageTable->numPackages = 0;
458 list_init(&packageTable->table);
461 for (i = 0; i < toAdd; i++)
463 SecurePackage *package = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackage));
464 if (!package)
465 continue;
467 list_add_tail(&packageTable->table, &package->entry);
469 package->provider = provider;
470 _copyPackageInfo(&package->infoW,
471 infoA ? &infoA[i] : NULL,
472 infoW ? &infoW[i] : NULL);
474 packageTable->numPackages += toAdd;
476 LeaveCriticalSection(&cs);
479 static void _tryLoadProvider(PWSTR moduleName)
481 HMODULE lib = LoadLibraryW(moduleName);
483 if (lib)
485 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
486 (INIT_SECURITY_INTERFACE_W)GetProcAddress(lib,
487 SECURITY_ENTRYPOINT_ANSIW);
488 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
489 (INIT_SECURITY_INTERFACE_A)GetProcAddress(lib,
490 SECURITY_ENTRYPOINT_ANSIA);
492 TRACE("loaded %s, InitSecurityInterfaceA is %p, InitSecurityInterfaceW is %p\n",
493 debugstr_w(moduleName), pInitSecurityInterfaceA,
494 pInitSecurityInterfaceW);
495 if (pInitSecurityInterfaceW || pInitSecurityInterfaceA)
497 PSecurityFunctionTableA fnTableA = NULL;
498 PSecurityFunctionTableW fnTableW = NULL;
499 ULONG toAdd = 0;
500 PSecPkgInfoA infoA = NULL;
501 PSecPkgInfoW infoW = NULL;
502 SECURITY_STATUS ret = SEC_E_OK;
504 if (pInitSecurityInterfaceA)
505 fnTableA = pInitSecurityInterfaceA();
506 if (pInitSecurityInterfaceW)
507 fnTableW = pInitSecurityInterfaceW();
508 if (fnTableW && fnTableW->EnumerateSecurityPackagesW)
510 if (fnTableW != &securityFunctionTableW)
511 ret = fnTableW->EnumerateSecurityPackagesW(&toAdd, &infoW);
512 else
513 TRACE("%s has built-in providers, skip adding\n", debugstr_w(moduleName));
515 else if (fnTableA && fnTableA->EnumerateSecurityPackagesA)
517 if (fnTableA != &securityFunctionTableA)
518 ret = fnTableA->EnumerateSecurityPackagesA(&toAdd, &infoA);
519 else
520 TRACE("%s has built-in providers, skip adding\n", debugstr_w(moduleName));
522 if (ret == SEC_E_OK && toAdd > 0 && (infoW || infoA))
524 SecureProvider *provider = SECUR32_addProvider(NULL, NULL,
525 moduleName);
527 if (provider)
528 SECUR32_addPackages(provider, toAdd, infoA, infoW);
529 if (infoW)
530 fnTableW->FreeContextBuffer(infoW);
531 else
532 fnTableA->FreeContextBuffer(infoA);
535 FreeLibrary(lib);
537 else
538 WARN("failed to load %s\n", debugstr_w(moduleName));
541 static const WCHAR securityProvidersKeyW[] = {
542 'S','Y','S','T','E','M','\\','C','u','r','r','e','n','t','C','o','n','t','r',
543 'o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','S','e','c','u','r',
544 'i','t','y','P','r','o','v','i','d','e','r','s','\0'
546 static const WCHAR securityProvidersW[] = {
547 'S','e','c','u','r','i','t','y','P','r','o','v','i','d','e','r','s',0
550 static void SECUR32_initializeProviders(void)
552 HKEY key;
553 LSTATUS apiRet;
555 TRACE("\n");
556 InitializeCriticalSection(&cs);
557 cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs");
558 /* First load built-in providers */
559 SECUR32_initSchannelSP();
560 SECUR32_initNTLMSP();
561 /* Load the Negotiate provider last so apps stumble over the working NTLM
562 * provider first. Attempting to fix bug #16905 while keeping the
563 * application reported on wine-users on 2006-09-12 working. */
564 SECUR32_initNegotiateSP();
565 /* Now load providers from registry */
566 apiRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, securityProvidersKeyW, 0,
567 KEY_READ, &key);
568 if (apiRet == ERROR_SUCCESS)
570 WCHAR securityPkgNames[MAX_PATH]; /* arbitrary len */
571 DWORD size = sizeof(securityPkgNames) / sizeof(WCHAR), type;
573 apiRet = RegQueryValueExW(key, securityProvidersW, NULL, &type,
574 (PBYTE)securityPkgNames, &size);
575 if (apiRet == ERROR_SUCCESS && type == REG_SZ)
577 WCHAR *ptr;
579 size = size / sizeof(WCHAR);
580 for (ptr = securityPkgNames;
581 ptr < securityPkgNames + size; )
583 WCHAR *comma;
585 for (comma = ptr; *comma && *comma != ','; comma++)
587 if (*comma == ',')
588 *comma = '\0';
589 for (; *ptr && isspace(*ptr) && ptr < securityPkgNames + size;
590 ptr++)
592 if (*ptr)
593 _tryLoadProvider(ptr);
594 ptr += lstrlenW(ptr) + 1;
597 RegCloseKey(key);
601 SecurePackage *SECUR32_findPackageW(PCWSTR packageName)
603 SecurePackage *ret = NULL;
604 BOOL matched = FALSE;
606 if (packageTable && packageName)
608 LIST_FOR_EACH_ENTRY(ret, &packageTable->table, SecurePackage, entry)
610 matched = !lstrcmpiW(ret->infoW.Name, packageName);
611 if (matched)
612 break;
615 if (!matched)
616 return NULL;
618 if (ret->provider && !ret->provider->loaded)
620 ret->provider->lib = LoadLibraryW(ret->provider->moduleName);
621 if (ret->provider->lib)
623 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
624 (INIT_SECURITY_INTERFACE_W)GetProcAddress(ret->provider->lib,
625 SECURITY_ENTRYPOINT_ANSIW);
626 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
627 (INIT_SECURITY_INTERFACE_A)GetProcAddress(ret->provider->lib,
628 SECURITY_ENTRYPOINT_ANSIA);
629 PSecurityFunctionTableA fnTableA = NULL;
630 PSecurityFunctionTableW fnTableW = NULL;
632 if (pInitSecurityInterfaceA)
633 fnTableA = pInitSecurityInterfaceA();
634 if (pInitSecurityInterfaceW)
635 fnTableW = pInitSecurityInterfaceW();
636 /* don't update built-in SecurityFunctionTable */
637 if (fnTableA != &securityFunctionTableA)
638 _makeFnTableA(&ret->provider->fnTableA, fnTableA, fnTableW);
639 if (fnTableW != &securityFunctionTableW)
640 _makeFnTableW(&ret->provider->fnTableW, fnTableA, fnTableW);
641 ret->provider->loaded = TRUE;
643 else
644 ret = NULL;
647 return ret;
650 SecurePackage *SECUR32_findPackageA(PCSTR packageName)
652 SecurePackage *ret;
654 if (packageTable && packageName)
656 UNICODE_STRING package;
658 RtlCreateUnicodeStringFromAsciiz(&package, packageName);
659 ret = SECUR32_findPackageW(package.Buffer);
660 RtlFreeUnicodeString(&package);
662 else
663 ret = NULL;
664 return ret;
667 static void SECUR32_freeProviders(void)
669 TRACE("\n");
670 EnterCriticalSection(&cs);
672 SECUR32_deinitSchannelSP();
674 if (packageTable)
676 SecurePackage *package, *package_next;
677 LIST_FOR_EACH_ENTRY_SAFE(package, package_next, &packageTable->table,
678 SecurePackage, entry)
680 HeapFree(GetProcessHeap(), 0, package->infoW.Name);
681 HeapFree(GetProcessHeap(), 0, package->infoW.Comment);
682 HeapFree(GetProcessHeap(), 0, package);
685 HeapFree(GetProcessHeap(), 0, packageTable);
686 packageTable = NULL;
689 if (providerTable)
691 SecureProvider *provider, *provider_next;
692 LIST_FOR_EACH_ENTRY_SAFE(provider, provider_next, &providerTable->table,
693 SecureProvider, entry)
695 HeapFree(GetProcessHeap(), 0, provider->moduleName);
696 if (provider->lib)
697 FreeLibrary(provider->lib);
698 HeapFree(GetProcessHeap(), 0, provider);
701 HeapFree(GetProcessHeap(), 0, providerTable);
702 providerTable = NULL;
705 LeaveCriticalSection(&cs);
706 cs.DebugInfo->Spare[0] = 0;
707 DeleteCriticalSection(&cs);
710 /***********************************************************************
711 * FreeContextBuffer (SECUR32.@)
713 * Doh--if pv was allocated by a crypto package, this may not be correct.
714 * The sample ssp seems to use LocalAlloc/LocalFee, but there doesn't seem to
715 * be any guarantee, nor is there an alloc function in secur32.
717 SECURITY_STATUS WINAPI FreeContextBuffer(PVOID pv)
719 HeapFree(GetProcessHeap(), 0, pv);
721 return SEC_E_OK;
724 /***********************************************************************
725 * EnumerateSecurityPackagesW (SECUR32.@)
727 SECURITY_STATUS WINAPI EnumerateSecurityPackagesW(PULONG pcPackages,
728 PSecPkgInfoW *ppPackageInfo)
730 SECURITY_STATUS ret = SEC_E_OK;
732 TRACE("(%p, %p)\n", pcPackages, ppPackageInfo);
734 /* windows just crashes if pcPackages or ppPackageInfo is NULL, so will I */
735 *pcPackages = 0;
736 EnterCriticalSection(&cs);
737 if (packageTable)
739 SecurePackage *package;
740 size_t bytesNeeded;
742 bytesNeeded = packageTable->numPackages * sizeof(SecPkgInfoW);
743 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
745 if (package->infoW.Name)
746 bytesNeeded += (lstrlenW(package->infoW.Name) + 1) * sizeof(WCHAR);
747 if (package->infoW.Comment)
748 bytesNeeded += (lstrlenW(package->infoW.Comment) + 1) * sizeof(WCHAR);
750 if (bytesNeeded)
752 *ppPackageInfo = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
753 if (*ppPackageInfo)
755 ULONG i = 0;
756 PWSTR nextString;
758 *pcPackages = packageTable->numPackages;
759 nextString = (PWSTR)((PBYTE)*ppPackageInfo +
760 packageTable->numPackages * sizeof(SecPkgInfoW));
761 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
763 PSecPkgInfoW pkgInfo = *ppPackageInfo + i++;
765 *pkgInfo = package->infoW;
766 if (package->infoW.Name)
768 TRACE("Name[%d] = %s\n", i - 1, debugstr_w(package->infoW.Name));
769 pkgInfo->Name = nextString;
770 lstrcpyW(nextString, package->infoW.Name);
771 nextString += lstrlenW(nextString) + 1;
773 else
774 pkgInfo->Name = NULL;
775 if (package->infoW.Comment)
777 TRACE("Comment[%d] = %s\n", i - 1, debugstr_w(package->infoW.Comment));
778 pkgInfo->Comment = nextString;
779 lstrcpyW(nextString, package->infoW.Comment);
780 nextString += lstrlenW(nextString) + 1;
782 else
783 pkgInfo->Comment = NULL;
786 else
787 ret = SEC_E_INSUFFICIENT_MEMORY;
790 LeaveCriticalSection(&cs);
791 TRACE("<-- 0x%08x\n", ret);
792 return ret;
795 /* Converts info (which is assumed to be an array of cPackages SecPkgInfoW
796 * structures) into an array of SecPkgInfoA structures, which it returns.
798 static PSecPkgInfoA thunk_PSecPkgInfoWToA(ULONG cPackages,
799 const SecPkgInfoW *info)
801 PSecPkgInfoA ret;
803 if (info)
805 size_t bytesNeeded = cPackages * sizeof(SecPkgInfoA);
806 ULONG i;
808 for (i = 0; i < cPackages; i++)
810 if (info[i].Name)
811 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Name,
812 -1, NULL, 0, NULL, NULL);
813 if (info[i].Comment)
814 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Comment,
815 -1, NULL, 0, NULL, NULL);
817 ret = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
818 if (ret)
820 PSTR nextString;
822 nextString = (PSTR)((PBYTE)ret + cPackages * sizeof(SecPkgInfoA));
823 for (i = 0; i < cPackages; i++)
825 PSecPkgInfoA pkgInfo = ret + i;
826 int bytes;
828 memcpy(pkgInfo, &info[i], sizeof(SecPkgInfoA));
829 if (info[i].Name)
831 pkgInfo->Name = nextString;
832 /* just repeat back to WideCharToMultiByte how many bytes
833 * it requires, since we asked it earlier
835 bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
836 NULL, 0, NULL, NULL);
837 WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
838 pkgInfo->Name, bytes, NULL, NULL);
839 nextString += lstrlenA(nextString) + 1;
841 else
842 pkgInfo->Name = NULL;
843 if (info[i].Comment)
845 pkgInfo->Comment = nextString;
846 /* just repeat back to WideCharToMultiByte how many bytes
847 * it requires, since we asked it earlier
849 bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
850 NULL, 0, NULL, NULL);
851 WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
852 pkgInfo->Comment, bytes, NULL, NULL);
853 nextString += lstrlenA(nextString) + 1;
855 else
856 pkgInfo->Comment = NULL;
860 else
861 ret = NULL;
862 return ret;
865 /***********************************************************************
866 * EnumerateSecurityPackagesA (SECUR32.@)
868 SECURITY_STATUS WINAPI EnumerateSecurityPackagesA(PULONG pcPackages,
869 PSecPkgInfoA *ppPackageInfo)
871 SECURITY_STATUS ret;
872 PSecPkgInfoW info;
874 ret = EnumerateSecurityPackagesW(pcPackages, &info);
875 if (ret == SEC_E_OK && *pcPackages && info)
877 *ppPackageInfo = thunk_PSecPkgInfoWToA(*pcPackages, info);
878 if (*pcPackages && !*ppPackageInfo)
880 *pcPackages = 0;
881 ret = SEC_E_INSUFFICIENT_MEMORY;
883 FreeContextBuffer(info);
885 return ret;
888 /***********************************************************************
889 * GetComputerObjectNameA (SECUR32.@)
891 * Get the local computer's name using the format specified.
893 * PARAMS
894 * NameFormat [I] The format for the name.
895 * lpNameBuffer [O] Pointer to buffer to receive the name.
896 * nSize [I/O] Size in characters of buffer.
898 * RETURNS
899 * TRUE If the name was written to lpNameBuffer.
900 * FALSE If the name couldn't be written.
902 * NOTES
903 * If lpNameBuffer is NULL, then the size of the buffer needed to hold the
904 * name will be returned in *nSize.
906 * nSize returns the number of characters written when lpNameBuffer is not
907 * NULL or the size of the buffer needed to hold the name when the buffer
908 * is too short or lpNameBuffer is NULL.
910 * It the buffer is too short, ERROR_INSUFFICIENT_BUFFER error will be set.
912 BOOLEAN WINAPI GetComputerObjectNameA(
913 EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
915 BOOLEAN rc;
916 LPWSTR bufferW = NULL;
917 ULONG sizeW = *nSize;
918 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
919 if (lpNameBuffer) {
920 bufferW = HeapAlloc(GetProcessHeap(), 0, sizeW * sizeof(WCHAR));
921 if (bufferW == NULL) {
922 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
923 return FALSE;
926 rc = GetComputerObjectNameW(NameFormat, bufferW, &sizeW);
927 if (rc && bufferW) {
928 ULONG len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
929 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, lpNameBuffer, *nSize, NULL, NULL);
930 *nSize = len;
932 else
933 *nSize = sizeW;
934 HeapFree(GetProcessHeap(), 0, bufferW);
935 return rc;
938 /***********************************************************************
939 * GetComputerObjectNameW (SECUR32.@)
941 BOOLEAN WINAPI GetComputerObjectNameW(
942 EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
944 LSA_HANDLE policyHandle;
945 LSA_OBJECT_ATTRIBUTES objectAttributes;
946 PPOLICY_DNS_DOMAIN_INFO domainInfo;
947 NTSTATUS ntStatus;
948 BOOLEAN status;
949 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
951 if (NameFormat == NameUnknown)
953 SetLastError(ERROR_INVALID_PARAMETER);
954 return FALSE;
957 ZeroMemory(&objectAttributes, sizeof(objectAttributes));
958 objectAttributes.Length = sizeof(objectAttributes);
960 ntStatus = LsaOpenPolicy(NULL, &objectAttributes,
961 POLICY_VIEW_LOCAL_INFORMATION,
962 &policyHandle);
963 if (ntStatus != STATUS_SUCCESS)
965 SetLastError(LsaNtStatusToWinError(ntStatus));
966 WARN("LsaOpenPolicy failed with NT status %u\n", GetLastError());
967 return FALSE;
970 ntStatus = LsaQueryInformationPolicy(policyHandle,
971 PolicyDnsDomainInformation,
972 (PVOID *)&domainInfo);
973 if (ntStatus != STATUS_SUCCESS)
975 SetLastError(LsaNtStatusToWinError(ntStatus));
976 WARN("LsaQueryInformationPolicy failed with NT status %u\n",
977 GetLastError());
978 LsaClose(policyHandle);
979 return FALSE;
982 if (domainInfo->Sid)
984 switch (NameFormat)
986 case NameSamCompatible:
988 WCHAR name[MAX_COMPUTERNAME_LENGTH + 1];
989 DWORD size = sizeof(name)/sizeof(name[0]);
990 if (GetComputerNameW(name, &size))
992 DWORD len = domainInfo->Name.Length + size + 3;
993 if (lpNameBuffer)
995 if (*nSize < len)
997 *nSize = len;
998 SetLastError(ERROR_INSUFFICIENT_BUFFER);
999 status = FALSE;
1001 else
1003 WCHAR bs[] = { '\\', 0 };
1004 WCHAR ds[] = { '$', 0 };
1005 lstrcpyW(lpNameBuffer, domainInfo->Name.Buffer);
1006 lstrcatW(lpNameBuffer, bs);
1007 lstrcatW(lpNameBuffer, name);
1008 lstrcatW(lpNameBuffer, ds);
1009 status = TRUE;
1012 else /* just requesting length required */
1014 *nSize = len;
1015 status = TRUE;
1018 else
1020 SetLastError(ERROR_INTERNAL_ERROR);
1021 status = FALSE;
1024 break;
1025 case NameFullyQualifiedDN:
1026 case NameDisplay:
1027 case NameUniqueId:
1028 case NameCanonical:
1029 case NameUserPrincipal:
1030 case NameCanonicalEx:
1031 case NameServicePrincipal:
1032 case NameDnsDomain:
1033 FIXME("NameFormat %d not implemented\n", NameFormat);
1034 SetLastError(ERROR_CANT_ACCESS_DOMAIN_INFO);
1035 status = FALSE;
1036 break;
1037 default:
1038 SetLastError(ERROR_INVALID_PARAMETER);
1039 status = FALSE;
1042 else
1044 SetLastError(ERROR_CANT_ACCESS_DOMAIN_INFO);
1045 status = FALSE;
1048 LsaFreeMemory(domainInfo);
1049 LsaClose(policyHandle);
1051 return status;
1054 /***********************************************************************
1055 * GetUserNameExA (SECUR32.@)
1057 BOOLEAN WINAPI GetUserNameExA(
1058 EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
1060 BOOLEAN rc;
1061 LPWSTR bufferW = NULL;
1062 ULONG sizeW = *nSize;
1063 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
1064 if (lpNameBuffer) {
1065 bufferW = HeapAlloc(GetProcessHeap(), 0, sizeW * sizeof(WCHAR));
1066 if (bufferW == NULL) {
1067 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1068 return FALSE;
1071 rc = GetUserNameExW(NameFormat, bufferW, &sizeW);
1072 if (rc) {
1073 ULONG len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
1074 if (len <= *nSize)
1076 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, lpNameBuffer, *nSize, NULL, NULL);
1077 *nSize = len - 1;
1079 else
1081 *nSize = len;
1082 rc = FALSE;
1083 SetLastError(ERROR_MORE_DATA);
1086 else
1087 *nSize = sizeW;
1088 HeapFree(GetProcessHeap(), 0, bufferW);
1089 return rc;
1092 BOOLEAN WINAPI GetUserNameExW(
1093 EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
1095 BOOLEAN status;
1096 WCHAR samname[UNLEN + 1 + MAX_COMPUTERNAME_LENGTH + 1];
1097 LPWSTR out;
1098 DWORD len;
1099 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
1101 switch (NameFormat)
1103 case NameSamCompatible:
1105 /* This assumes the current user is always a local account */
1106 len = MAX_COMPUTERNAME_LENGTH + 1;
1107 if (GetComputerNameW(samname, &len))
1109 out = samname + lstrlenW(samname);
1110 *out++ = '\\';
1111 len = UNLEN + 1;
1112 if (GetUserNameW(out, &len))
1114 status = (lstrlenW(samname) < *nSize);
1115 if (status)
1117 lstrcpyW(lpNameBuffer, samname);
1118 *nSize = lstrlenW(samname);
1120 else
1122 SetLastError(ERROR_MORE_DATA);
1123 *nSize = lstrlenW(samname) + 1;
1126 else
1127 status = FALSE;
1129 else
1130 status = FALSE;
1132 break;
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 status = FALSE;
1144 break;
1145 default:
1146 SetLastError(ERROR_INVALID_PARAMETER);
1147 status = FALSE;
1150 return status;
1153 BOOLEAN WINAPI TranslateNameA(
1154 LPCSTR lpAccountName, EXTENDED_NAME_FORMAT AccountNameFormat,
1155 EXTENDED_NAME_FORMAT DesiredNameFormat, LPSTR lpTranslatedName,
1156 PULONG nSize)
1158 FIXME("%p %d %d %p %p\n", lpAccountName, AccountNameFormat,
1159 DesiredNameFormat, lpTranslatedName, nSize);
1160 return FALSE;
1163 BOOLEAN WINAPI TranslateNameW(
1164 LPCWSTR lpAccountName, EXTENDED_NAME_FORMAT AccountNameFormat,
1165 EXTENDED_NAME_FORMAT DesiredNameFormat, LPWSTR lpTranslatedName,
1166 PULONG nSize)
1168 FIXME("%p %d %d %p %p\n", lpAccountName, AccountNameFormat,
1169 DesiredNameFormat, lpTranslatedName, nSize);
1170 return FALSE;
1173 /***********************************************************************
1174 * DllMain (SECUR32.0)
1176 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1178 if (fdwReason == DLL_PROCESS_ATTACH)
1180 DisableThreadLibraryCalls(hinstDLL);
1181 SECUR32_initializeProviders();
1183 else if (fdwReason == DLL_PROCESS_DETACH)
1185 SECUR32_freeProviders();
1188 return TRUE;