imm32/tests: Test ImmTranslateMessage / ImeToAsciiEx calls.
[wine.git] / dlls / secur32 / secur32.c
blobd703757bae71e6f4caa1f562c92a6db492748dc2
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
20 #include <assert.h>
21 #include <stdarg.h>
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winnls.h"
28 #include "winreg.h"
29 #include "winternl.h"
30 #include "shlwapi.h"
31 #include "sspi.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 "secur32_priv.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 void _makeFnTableA(PSecurityFunctionTableA fnTableA,
176 const SecurityFunctionTableA *inFnTableA,
177 const SecurityFunctionTableW *inFnTableW)
179 if (fnTableA)
181 if (inFnTableA)
183 /* The size of the version 1 table is based on platform sdk's
184 * sspi.h, though the sample ssp also provided with platform sdk
185 * implies only functions through QuerySecurityPackageInfoA are
186 * implemented (yikes)
188 size_t tableSize = inFnTableA->dwVersion == 1 ?
189 offsetof(SecurityFunctionTableA, SetContextAttributesA) :
190 sizeof(SecurityFunctionTableA);
192 memcpy(fnTableA, inFnTableA, tableSize);
193 /* override this, since we can do it internally anyway */
194 fnTableA->QuerySecurityPackageInfoA =
195 QuerySecurityPackageInfoA;
197 else if (inFnTableW)
199 /* functions with thunks */
200 if (inFnTableW->AcquireCredentialsHandleW)
201 fnTableA->AcquireCredentialsHandleA =
202 thunk_AcquireCredentialsHandleA;
203 if (inFnTableW->InitializeSecurityContextW)
204 fnTableA->InitializeSecurityContextA =
205 thunk_InitializeSecurityContextA;
206 if (inFnTableW->ImportSecurityContextW)
207 fnTableA->ImportSecurityContextA =
208 thunk_ImportSecurityContextA;
209 if (inFnTableW->AddCredentialsW)
210 fnTableA->AddCredentialsA =
211 thunk_AddCredentialsA;
212 if (inFnTableW->QueryCredentialsAttributesW)
213 fnTableA->QueryCredentialsAttributesA =
214 thunk_QueryCredentialsAttributesA;
215 if (inFnTableW->QueryContextAttributesW)
216 fnTableA->QueryContextAttributesA =
217 thunk_QueryContextAttributesA;
218 if (inFnTableW->SetContextAttributesW)
219 fnTableA->SetContextAttributesA =
220 thunk_SetContextAttributesA;
221 /* this can't be thunked, there's no extra param to know which
222 * package to forward to */
223 fnTableA->EnumerateSecurityPackagesA = NULL;
224 /* functions with no thunks needed */
225 fnTableA->AcceptSecurityContext = inFnTableW->AcceptSecurityContext;
226 fnTableA->CompleteAuthToken = inFnTableW->CompleteAuthToken;
227 fnTableA->DeleteSecurityContext = inFnTableW->DeleteSecurityContext;
228 fnTableA->ImpersonateSecurityContext =
229 inFnTableW->ImpersonateSecurityContext;
230 fnTableA->RevertSecurityContext = inFnTableW->RevertSecurityContext;
231 fnTableA->MakeSignature = inFnTableW->MakeSignature;
232 fnTableA->VerifySignature = inFnTableW->VerifySignature;
233 fnTableA->FreeContextBuffer = inFnTableW->FreeContextBuffer;
234 fnTableA->QuerySecurityPackageInfoA =
235 QuerySecurityPackageInfoA;
236 fnTableA->ExportSecurityContext =
237 inFnTableW->ExportSecurityContext;
238 fnTableA->QuerySecurityContextToken =
239 inFnTableW->QuerySecurityContextToken;
240 fnTableA->EncryptMessage = inFnTableW->EncryptMessage;
241 fnTableA->DecryptMessage = inFnTableW->DecryptMessage;
246 static void _makeFnTableW(PSecurityFunctionTableW fnTableW,
247 const SecurityFunctionTableA *inFnTableA,
248 const SecurityFunctionTableW *inFnTableW)
250 if (fnTableW)
252 if (inFnTableW)
254 /* The size of the version 1 table is based on platform sdk's
255 * sspi.h, though the sample ssp also provided with platform sdk
256 * implies only functions through QuerySecurityPackageInfoA are
257 * implemented (yikes)
259 size_t tableSize = inFnTableW->dwVersion == 1 ?
260 offsetof(SecurityFunctionTableW, SetContextAttributesW) :
261 sizeof(SecurityFunctionTableW);
263 memcpy(fnTableW, inFnTableW, tableSize);
264 /* override this, since we can do it internally anyway */
265 fnTableW->QuerySecurityPackageInfoW =
266 QuerySecurityPackageInfoW;
268 else if (inFnTableA)
270 /* functions with thunks */
271 if (inFnTableA->AcquireCredentialsHandleA)
272 fnTableW->AcquireCredentialsHandleW =
273 thunk_AcquireCredentialsHandleW;
274 if (inFnTableA->InitializeSecurityContextA)
275 fnTableW->InitializeSecurityContextW =
276 thunk_InitializeSecurityContextW;
277 if (inFnTableA->ImportSecurityContextA)
278 fnTableW->ImportSecurityContextW =
279 thunk_ImportSecurityContextW;
280 if (inFnTableA->AddCredentialsA)
281 fnTableW->AddCredentialsW =
282 thunk_AddCredentialsW;
283 if (inFnTableA->QueryCredentialsAttributesA)
284 fnTableW->QueryCredentialsAttributesW =
285 thunk_QueryCredentialsAttributesW;
286 if (inFnTableA->QueryContextAttributesA)
287 fnTableW->QueryContextAttributesW =
288 thunk_QueryContextAttributesW;
289 if (inFnTableA->SetContextAttributesA)
290 fnTableW->SetContextAttributesW =
291 thunk_SetContextAttributesW;
292 /* this can't be thunked, there's no extra param to know which
293 * package to forward to */
294 fnTableW->EnumerateSecurityPackagesW = NULL;
295 /* functions with no thunks needed */
296 fnTableW->AcceptSecurityContext = inFnTableA->AcceptSecurityContext;
297 fnTableW->CompleteAuthToken = inFnTableA->CompleteAuthToken;
298 fnTableW->DeleteSecurityContext = inFnTableA->DeleteSecurityContext;
299 fnTableW->ImpersonateSecurityContext =
300 inFnTableA->ImpersonateSecurityContext;
301 fnTableW->RevertSecurityContext = inFnTableA->RevertSecurityContext;
302 fnTableW->MakeSignature = inFnTableA->MakeSignature;
303 fnTableW->VerifySignature = inFnTableA->VerifySignature;
304 fnTableW->FreeContextBuffer = inFnTableA->FreeContextBuffer;
305 fnTableW->QuerySecurityPackageInfoW =
306 QuerySecurityPackageInfoW;
307 fnTableW->ExportSecurityContext =
308 inFnTableA->ExportSecurityContext;
309 fnTableW->QuerySecurityContextToken =
310 inFnTableA->QuerySecurityContextToken;
311 fnTableW->EncryptMessage = inFnTableA->EncryptMessage;
312 fnTableW->DecryptMessage = inFnTableA->DecryptMessage;
317 static WCHAR *strdupAW( const char *str )
319 WCHAR *ret = NULL;
320 if (str)
322 int len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
323 if ((ret = malloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
325 return ret;
328 static void _copyPackageInfo(PSecPkgInfoW info, const SecPkgInfoA *inInfoA,
329 const SecPkgInfoW *inInfoW)
331 if (info && (inInfoA || inInfoW))
333 /* odd, I know, but up until Name and Comment the structures are
334 * identical
336 memcpy(info, inInfoW ? inInfoW : (const SecPkgInfoW *)inInfoA, sizeof(*info));
337 if (inInfoW)
339 info->Name = wcsdup(inInfoW->Name);
340 info->Comment = wcsdup(inInfoW->Comment);
342 else
344 info->Name = strdupAW(inInfoA->Name);
345 info->Comment = strdupAW(inInfoA->Comment);
350 SecureProvider *SECUR32_addProvider(const SecurityFunctionTableA *fnTableA,
351 const SecurityFunctionTableW *fnTableW, PCWSTR moduleName)
353 SecureProvider *ret;
355 EnterCriticalSection(&cs);
357 if (!providerTable)
359 if (!(providerTable = malloc(sizeof(*providerTable))))
361 LeaveCriticalSection(&cs);
362 return NULL;
365 list_init(&providerTable->table);
368 if (!(ret = malloc(sizeof(*ret))))
370 LeaveCriticalSection(&cs);
371 return NULL;
374 list_add_tail(&providerTable->table, &ret->entry);
375 ret->lib = NULL;
377 if (fnTableA || fnTableW)
379 ret->moduleName = wcsdup(moduleName);
380 _makeFnTableA(&ret->fnTableA, fnTableA, fnTableW);
381 _makeFnTableW(&ret->fnTableW, fnTableA, fnTableW);
382 ret->loaded = !moduleName;
384 else
386 ret->moduleName = wcsdup(moduleName);
387 ret->loaded = FALSE;
390 LeaveCriticalSection(&cs);
391 return ret;
394 void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd,
395 const SecPkgInfoA *infoA, const SecPkgInfoW *infoW)
397 ULONG i;
399 assert(provider);
400 assert(infoA || infoW);
402 EnterCriticalSection(&cs);
404 if (!packageTable)
406 if (!(packageTable = malloc(sizeof(*packageTable))))
408 LeaveCriticalSection(&cs);
409 return;
412 packageTable->numPackages = 0;
413 list_init(&packageTable->table);
416 for (i = 0; i < toAdd; i++)
418 SecurePackage *package;
420 if (!(package = malloc(sizeof(*package)))) continue;
422 list_add_tail(&packageTable->table, &package->entry);
424 package->provider = provider;
425 _copyPackageInfo(&package->infoW, infoA ? &infoA[i] : NULL, infoW ? &infoW[i] : NULL);
427 packageTable->numPackages += toAdd;
429 LeaveCriticalSection(&cs);
432 static void _tryLoadProvider(PWSTR moduleName)
434 HMODULE lib = LoadLibraryW(moduleName);
436 if (lib)
438 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
439 (INIT_SECURITY_INTERFACE_W)GetProcAddress(lib,
440 SECURITY_ENTRYPOINT_ANSIW);
441 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
442 (INIT_SECURITY_INTERFACE_A)GetProcAddress(lib,
443 SECURITY_ENTRYPOINT_ANSIA);
445 TRACE("loaded %s, InitSecurityInterfaceA is %p, InitSecurityInterfaceW is %p\n",
446 debugstr_w(moduleName), pInitSecurityInterfaceA,
447 pInitSecurityInterfaceW);
448 if (pInitSecurityInterfaceW || pInitSecurityInterfaceA)
450 PSecurityFunctionTableA fnTableA = NULL;
451 PSecurityFunctionTableW fnTableW = NULL;
452 ULONG toAdd = 0;
453 PSecPkgInfoA infoA = NULL;
454 PSecPkgInfoW infoW = NULL;
455 SECURITY_STATUS ret = SEC_E_OK;
457 if (pInitSecurityInterfaceA)
458 fnTableA = pInitSecurityInterfaceA();
459 if (pInitSecurityInterfaceW)
460 fnTableW = pInitSecurityInterfaceW();
461 if (fnTableW && fnTableW->EnumerateSecurityPackagesW)
463 if (fnTableW != &securityFunctionTableW)
464 ret = fnTableW->EnumerateSecurityPackagesW(&toAdd, &infoW);
465 else
466 TRACE("%s has built-in providers, skip adding\n", debugstr_w(moduleName));
468 else if (fnTableA && fnTableA->EnumerateSecurityPackagesA)
470 if (fnTableA != &securityFunctionTableA)
471 ret = fnTableA->EnumerateSecurityPackagesA(&toAdd, &infoA);
472 else
473 TRACE("%s has built-in providers, skip adding\n", debugstr_w(moduleName));
475 if (ret == SEC_E_OK && toAdd > 0 && (infoW || infoA))
477 SecureProvider *provider = SECUR32_addProvider(NULL, NULL,
478 moduleName);
480 if (provider)
481 SECUR32_addPackages(provider, toAdd, infoA, infoW);
482 if (infoW)
483 fnTableW->FreeContextBuffer(infoW);
484 else
485 fnTableA->FreeContextBuffer(infoA);
488 FreeLibrary(lib);
490 else
491 WARN("failed to load %s\n", debugstr_w(moduleName));
494 static void SECUR32_initializeProviders(void)
496 HKEY key;
497 LSTATUS apiRet;
499 TRACE("\n");
500 /* First load built-in providers */
501 SECUR32_initSchannelSP();
502 /* Load SSP/AP packages (Kerberos and others) */
503 load_auth_packages();
504 /* Load the Negotiate provider last so apps stumble over the working NTLM
505 * provider first. Attempting to fix bug #16905 while keeping the
506 * application reported on wine-users on 2006-09-12 working. */
507 SECUR32_initNegotiateSP();
508 /* Now load providers from registry */
509 apiRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\SecurityProviders", 0,
510 KEY_READ, &key);
511 if (apiRet == ERROR_SUCCESS)
513 WCHAR securityPkgNames[MAX_PATH]; /* arbitrary len */
514 DWORD size = sizeof(securityPkgNames), type;
516 apiRet = RegQueryValueExW(key, L"SecurityProviders", NULL, &type, (PBYTE)securityPkgNames, &size);
517 if (apiRet == ERROR_SUCCESS && type == REG_SZ)
519 WCHAR *ptr;
521 size = size / sizeof(WCHAR);
522 for (ptr = securityPkgNames;
523 ptr < securityPkgNames + size; )
525 WCHAR *comma;
527 for (comma = ptr; *comma && *comma != ','; comma++)
529 if (*comma == ',')
530 *comma = '\0';
531 for (; *ptr && iswspace(*ptr) && ptr < securityPkgNames + size;
532 ptr++)
534 if (*ptr)
535 _tryLoadProvider(ptr);
536 ptr += lstrlenW(ptr) + 1;
539 RegCloseKey(key);
543 SecurePackage *SECUR32_findPackageW(PCWSTR packageName)
545 SecurePackage *ret = NULL;
546 BOOL matched = FALSE;
548 if (packageTable && packageName)
550 LIST_FOR_EACH_ENTRY(ret, &packageTable->table, SecurePackage, entry)
552 matched = !lstrcmpiW(ret->infoW.Name, packageName);
553 if (matched) break;
555 if (!matched) return NULL;
557 if (ret->provider && !ret->provider->loaded)
559 ret->provider->lib = LoadLibraryW(ret->provider->moduleName);
560 if (ret->provider->lib)
562 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
563 (INIT_SECURITY_INTERFACE_W)GetProcAddress(ret->provider->lib,
564 SECURITY_ENTRYPOINT_ANSIW);
565 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
566 (INIT_SECURITY_INTERFACE_A)GetProcAddress(ret->provider->lib,
567 SECURITY_ENTRYPOINT_ANSIA);
568 PSecurityFunctionTableA fnTableA = NULL;
569 PSecurityFunctionTableW fnTableW = NULL;
571 if (pInitSecurityInterfaceA)
572 fnTableA = pInitSecurityInterfaceA();
573 if (pInitSecurityInterfaceW)
574 fnTableW = pInitSecurityInterfaceW();
575 /* don't update built-in SecurityFunctionTable */
576 if (fnTableA != &securityFunctionTableA)
577 _makeFnTableA(&ret->provider->fnTableA, fnTableA, fnTableW);
578 if (fnTableW != &securityFunctionTableW)
579 _makeFnTableW(&ret->provider->fnTableW, fnTableA, fnTableW);
580 ret->provider->loaded = TRUE;
582 else
583 ret = NULL;
586 return ret;
589 SecurePackage *SECUR32_findPackageA(PCSTR packageName)
591 SecurePackage *ret;
593 if (packageTable && packageName)
595 UNICODE_STRING package;
597 RtlCreateUnicodeStringFromAsciiz(&package, packageName);
598 ret = SECUR32_findPackageW(package.Buffer);
599 RtlFreeUnicodeString(&package);
601 else
602 ret = NULL;
603 return ret;
606 static void SECUR32_freeProviders(void)
608 TRACE("\n");
609 EnterCriticalSection(&cs);
611 SECUR32_deinitSchannelSP();
613 if (packageTable)
615 SecurePackage *package, *package_next;
616 LIST_FOR_EACH_ENTRY_SAFE(package, package_next, &packageTable->table,
617 SecurePackage, entry)
619 free(package->infoW.Name);
620 free(package->infoW.Comment);
621 free(package);
624 free(packageTable);
625 packageTable = NULL;
628 if (providerTable)
630 SecureProvider *provider, *provider_next;
631 LIST_FOR_EACH_ENTRY_SAFE(provider, provider_next, &providerTable->table, SecureProvider, entry)
633 free(provider->moduleName);
634 if (provider->lib) FreeLibrary(provider->lib);
635 free(provider);
638 free(providerTable);
639 providerTable = NULL;
642 LeaveCriticalSection(&cs);
643 DeleteCriticalSection(&cs);
646 /***********************************************************************
647 * FreeContextBuffer (SECUR32.@)
649 * Doh--if pv was allocated by a crypto package, this may not be correct.
650 * The sample ssp seems to use LocalAlloc/LocalFee, but there doesn't seem to
651 * be any guarantee, nor is there an alloc function in secur32.
653 SECURITY_STATUS WINAPI FreeContextBuffer( void *pv )
655 RtlFreeHeap( GetProcessHeap(), 0, pv );
656 return SEC_E_OK;
659 /***********************************************************************
660 * EnumerateSecurityPackagesW (SECUR32.@)
662 SECURITY_STATUS WINAPI EnumerateSecurityPackagesW(PULONG pcPackages,
663 PSecPkgInfoW *ppPackageInfo)
665 SECURITY_STATUS ret = SEC_E_OK;
667 TRACE("(%p, %p)\n", pcPackages, ppPackageInfo);
669 /* windows just crashes if pcPackages or ppPackageInfo is NULL, so will I */
670 *pcPackages = 0;
671 EnterCriticalSection(&cs);
672 if (packageTable)
674 SecurePackage *package;
675 size_t bytesNeeded;
677 bytesNeeded = packageTable->numPackages * sizeof(SecPkgInfoW);
678 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
680 if (package->infoW.Name)
681 bytesNeeded += (lstrlenW(package->infoW.Name) + 1) * sizeof(WCHAR);
682 if (package->infoW.Comment)
683 bytesNeeded += (lstrlenW(package->infoW.Comment) + 1) * sizeof(WCHAR);
685 if (bytesNeeded)
687 /* freed with FeeContextBuffer */
688 if ((*ppPackageInfo = RtlAllocateHeap(GetProcessHeap(), 0, bytesNeeded)))
690 ULONG i = 0;
691 PWSTR nextString;
693 *pcPackages = packageTable->numPackages;
694 nextString = (PWSTR)((PBYTE)*ppPackageInfo +
695 packageTable->numPackages * sizeof(SecPkgInfoW));
696 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
698 PSecPkgInfoW pkgInfo = *ppPackageInfo + i++;
700 *pkgInfo = package->infoW;
701 if (package->infoW.Name)
703 TRACE("Name[%ld] = %s\n", i - 1, debugstr_w(package->infoW.Name));
704 pkgInfo->Name = nextString;
705 lstrcpyW(nextString, package->infoW.Name);
706 nextString += lstrlenW(nextString) + 1;
708 else
709 pkgInfo->Name = NULL;
710 if (package->infoW.Comment)
712 TRACE("Comment[%ld] = %s\n", i - 1, debugstr_w(package->infoW.Comment));
713 pkgInfo->Comment = nextString;
714 lstrcpyW(nextString, package->infoW.Comment);
715 nextString += lstrlenW(nextString) + 1;
717 else
718 pkgInfo->Comment = NULL;
721 else
722 ret = SEC_E_INSUFFICIENT_MEMORY;
725 LeaveCriticalSection(&cs);
726 TRACE("<-- 0x%08lx\n", ret);
727 return ret;
730 /* Converts info (which is assumed to be an array of cPackages SecPkgInfoW
731 * structures) into an array of SecPkgInfoA structures, which it returns.
733 static PSecPkgInfoA thunk_PSecPkgInfoWToA(ULONG cPackages,
734 const SecPkgInfoW *info)
736 PSecPkgInfoA ret;
738 if (info)
740 size_t bytesNeeded = cPackages * sizeof(SecPkgInfoA);
741 ULONG i;
743 for (i = 0; i < cPackages; i++)
745 if (info[i].Name)
746 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Name,
747 -1, NULL, 0, NULL, NULL);
748 if (info[i].Comment)
749 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Comment,
750 -1, NULL, 0, NULL, NULL);
752 /* freed with FreeContextBuffer */
753 if ((ret = RtlAllocateHeap(GetProcessHeap(), 0, bytesNeeded)))
755 PSTR nextString;
757 nextString = (PSTR)((PBYTE)ret + cPackages * sizeof(SecPkgInfoA));
758 for (i = 0; i < cPackages; i++)
760 PSecPkgInfoA pkgInfo = ret + i;
761 int bytes;
763 memcpy(pkgInfo, &info[i], sizeof(SecPkgInfoA));
764 if (info[i].Name)
766 pkgInfo->Name = nextString;
767 /* just repeat back to WideCharToMultiByte how many bytes
768 * it requires, since we asked it earlier
770 bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
771 NULL, 0, NULL, NULL);
772 WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
773 pkgInfo->Name, bytes, NULL, NULL);
774 nextString += lstrlenA(nextString) + 1;
776 else
777 pkgInfo->Name = NULL;
778 if (info[i].Comment)
780 pkgInfo->Comment = nextString;
781 /* just repeat back to WideCharToMultiByte how many bytes
782 * it requires, since we asked it earlier
784 bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
785 NULL, 0, NULL, NULL);
786 WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
787 pkgInfo->Comment, bytes, NULL, NULL);
788 nextString += lstrlenA(nextString) + 1;
790 else
791 pkgInfo->Comment = NULL;
795 else
796 ret = NULL;
797 return ret;
800 /***********************************************************************
801 * EnumerateSecurityPackagesA (SECUR32.@)
803 SECURITY_STATUS WINAPI EnumerateSecurityPackagesA(PULONG pcPackages,
804 PSecPkgInfoA *ppPackageInfo)
806 SECURITY_STATUS ret;
807 PSecPkgInfoW info;
809 ret = EnumerateSecurityPackagesW(pcPackages, &info);
810 if (ret == SEC_E_OK && *pcPackages && info)
812 *ppPackageInfo = thunk_PSecPkgInfoWToA(*pcPackages, info);
813 if (*pcPackages && !*ppPackageInfo)
815 *pcPackages = 0;
816 ret = SEC_E_INSUFFICIENT_MEMORY;
818 FreeContextBuffer(info);
820 return ret;
823 /***********************************************************************
824 * GetComputerObjectNameA (SECUR32.@)
826 * Get the local computer's name using the format specified.
828 * PARAMS
829 * NameFormat [I] The format for the name.
830 * lpNameBuffer [O] Pointer to buffer to receive the name.
831 * nSize [I/O] Size in characters of buffer.
833 * RETURNS
834 * TRUE If the name was written to lpNameBuffer.
835 * FALSE If the name couldn't be written.
837 * NOTES
838 * If lpNameBuffer is NULL, then the size of the buffer needed to hold the
839 * name will be returned in *nSize.
841 * nSize returns the number of characters written when lpNameBuffer is not
842 * NULL or the size of the buffer needed to hold the name when the buffer
843 * is too short or lpNameBuffer is NULL.
845 * It the buffer is too short, ERROR_INSUFFICIENT_BUFFER error will be set.
847 BOOLEAN WINAPI GetComputerObjectNameA(
848 EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
850 BOOLEAN rc;
851 LPWSTR bufferW = NULL;
852 ULONG sizeW = *nSize;
854 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
856 if (lpNameBuffer) {
857 if (!(bufferW = malloc(sizeW * sizeof(WCHAR)))) {
858 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
859 return FALSE;
862 rc = GetComputerObjectNameW(NameFormat, bufferW, &sizeW);
863 if (rc && bufferW) {
864 ULONG len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
865 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, lpNameBuffer, *nSize, NULL, NULL);
866 *nSize = len;
868 else
869 *nSize = sizeW;
870 free(bufferW);
871 return rc;
874 /***********************************************************************
875 * GetComputerObjectNameW (SECUR32.@)
877 BOOLEAN WINAPI GetComputerObjectNameW(
878 EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
880 LSA_HANDLE policyHandle;
881 LSA_OBJECT_ATTRIBUTES objectAttributes;
882 PPOLICY_DNS_DOMAIN_INFO domainInfo;
883 NTSTATUS ntStatus;
884 BOOLEAN status;
886 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
888 if (NameFormat == NameUnknown)
890 SetLastError(ERROR_INVALID_PARAMETER);
891 return FALSE;
894 ZeroMemory(&objectAttributes, sizeof(objectAttributes));
895 objectAttributes.Length = sizeof(objectAttributes);
897 ntStatus = LsaOpenPolicy(NULL, &objectAttributes,
898 POLICY_VIEW_LOCAL_INFORMATION,
899 &policyHandle);
900 if (ntStatus != STATUS_SUCCESS)
902 SetLastError(LsaNtStatusToWinError(ntStatus));
903 WARN("LsaOpenPolicy failed with NT status %lu\n", GetLastError());
904 return FALSE;
907 ntStatus = LsaQueryInformationPolicy(policyHandle,
908 PolicyDnsDomainInformation,
909 (PVOID *)&domainInfo);
910 if (ntStatus != STATUS_SUCCESS)
912 SetLastError(LsaNtStatusToWinError(ntStatus));
913 WARN("LsaQueryInformationPolicy failed with NT status %lu\n",
914 GetLastError());
915 LsaClose(policyHandle);
916 return FALSE;
919 if (domainInfo->Sid)
921 switch (NameFormat)
923 case NameSamCompatible:
925 WCHAR name[MAX_COMPUTERNAME_LENGTH + 1];
926 DWORD size = ARRAY_SIZE(name);
927 if (GetComputerNameW(name, &size))
929 DWORD len = domainInfo->Name.Length + size + 3;
930 if (lpNameBuffer && *nSize >= len)
932 if (domainInfo->Name.Buffer)
934 lstrcpyW(lpNameBuffer, domainInfo->Name.Buffer);
935 lstrcatW(lpNameBuffer, L"\\");
937 else
938 *lpNameBuffer = 0;
939 lstrcatW(lpNameBuffer, name);
940 lstrcatW(lpNameBuffer, L"$");
941 status = TRUE;
943 else /* just requesting length required */
945 *nSize = len;
946 SetLastError(ERROR_INSUFFICIENT_BUFFER);
947 status = FALSE;
950 else
952 SetLastError(ERROR_INTERNAL_ERROR);
953 status = FALSE;
956 break;
957 case NameFullyQualifiedDN:
959 WCHAR name[MAX_COMPUTERNAME_LENGTH + 1];
960 DWORD len, size;
961 WCHAR *suffix;
963 size = ARRAY_SIZE(name);
964 if (!GetComputerNameW(name, &size))
966 status = FALSE;
967 break;
970 len = wcslen(L"CN=") + size + 1 + wcslen(L"CN=Computers") + 1 + wcslen(L"DC=");
971 if (domainInfo->DnsDomainName.Buffer)
973 suffix = wcsrchr(domainInfo->DnsDomainName.Buffer, '.');
974 if (suffix)
976 *suffix++ = 0;
977 len += 1 + wcslen(L"DC=") + wcslen(suffix);
979 len += wcslen(domainInfo->DnsDomainName.Buffer);
981 else
982 suffix = NULL;
984 if (lpNameBuffer && *nSize > len)
986 lstrcpyW(lpNameBuffer, L"CN=");
987 lstrcatW(lpNameBuffer, name);
988 lstrcatW(lpNameBuffer, L",");
989 lstrcatW(lpNameBuffer, L"CN=Computers");
990 if (domainInfo->DnsDomainName.Buffer)
992 lstrcatW(lpNameBuffer, L",");
993 lstrcatW(lpNameBuffer, L"DC=");
994 lstrcatW(lpNameBuffer, domainInfo->DnsDomainName.Buffer);
995 if (suffix)
997 lstrcatW(lpNameBuffer, L",");
998 lstrcatW(lpNameBuffer, L"DC=");
999 lstrcatW(lpNameBuffer, suffix);
1002 status = TRUE;
1004 else /* just requesting length required */
1006 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1007 status = FALSE;
1009 *nSize = len + 1;
1010 break;
1012 case NameDisplay:
1013 case NameUniqueId:
1014 case NameCanonical:
1015 case NameUserPrincipal:
1016 case NameCanonicalEx:
1017 case NameServicePrincipal:
1018 case NameDnsDomain:
1019 FIXME("NameFormat %d not implemented\n", NameFormat);
1020 SetLastError(ERROR_CANT_ACCESS_DOMAIN_INFO);
1021 status = FALSE;
1022 break;
1023 default:
1024 SetLastError(ERROR_INVALID_PARAMETER);
1025 status = FALSE;
1028 else
1030 SetLastError(ERROR_CANT_ACCESS_DOMAIN_INFO);
1031 status = FALSE;
1034 LsaFreeMemory(domainInfo);
1035 LsaClose(policyHandle);
1037 return status;
1040 SECURITY_STATUS WINAPI AddSecurityPackageA(LPSTR name, SECURITY_PACKAGE_OPTIONS *options)
1042 FIXME("(%s %p)\n", debugstr_a(name), options);
1043 return E_NOTIMPL;
1046 SECURITY_STATUS WINAPI AddSecurityPackageW(LPWSTR name, SECURITY_PACKAGE_OPTIONS *options)
1048 FIXME("(%s %p)\n", debugstr_w(name), options);
1049 return E_NOTIMPL;
1052 SECURITY_STATUS WINAPI DeleteSecurityPackageA(LPSTR name)
1054 FIXME("(%s)\n", debugstr_a(name));
1055 return E_NOTIMPL;
1058 SECURITY_STATUS WINAPI DeleteSecurityPackageW(LPWSTR name)
1060 FIXME("(%s)\n", debugstr_w(name));
1061 return E_NOTIMPL;
1064 /***********************************************************************
1065 * GetUserNameExA (SECUR32.@)
1067 BOOLEAN WINAPI GetUserNameExA(
1068 EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
1070 BOOLEAN rc;
1071 LPWSTR bufferW = NULL;
1072 ULONG sizeW = *nSize;
1073 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
1074 if (lpNameBuffer) {
1075 bufferW = malloc(sizeW * sizeof(WCHAR));
1076 if (bufferW == NULL) {
1077 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1078 return FALSE;
1081 rc = GetUserNameExW(NameFormat, bufferW, &sizeW);
1082 if (rc) {
1083 ULONG len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
1084 if (len <= *nSize)
1086 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, lpNameBuffer, *nSize, NULL, NULL);
1087 *nSize = len - 1;
1089 else
1091 *nSize = len;
1092 rc = FALSE;
1093 SetLastError(ERROR_MORE_DATA);
1096 else
1097 *nSize = sizeW;
1098 free(bufferW);
1099 return rc;
1102 BOOLEAN WINAPI GetUserNameExW(
1103 EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
1105 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
1107 switch (NameFormat)
1109 case NameSamCompatible:
1111 WCHAR samname[UNLEN + 1 + MAX_COMPUTERNAME_LENGTH + 1];
1112 LPWSTR out;
1113 DWORD len;
1115 /* This assumes the current user is always a local account */
1116 len = MAX_COMPUTERNAME_LENGTH + 1;
1117 if (GetComputerNameW(samname, &len))
1119 out = samname + lstrlenW(samname);
1120 *out++ = '\\';
1121 len = UNLEN + 1;
1122 if (GetUserNameW(out, &len))
1124 if (lstrlenW(samname) < *nSize)
1126 lstrcpyW(lpNameBuffer, samname);
1127 *nSize = lstrlenW(samname);
1128 return TRUE;
1131 SetLastError(ERROR_MORE_DATA);
1132 *nSize = lstrlenW(samname) + 1;
1135 return FALSE;
1138 case NameUnknown:
1139 case NameFullyQualifiedDN:
1140 case NameDisplay:
1141 case NameUniqueId:
1142 case NameCanonical:
1143 case NameUserPrincipal:
1144 case NameCanonicalEx:
1145 case NameServicePrincipal:
1146 case NameDnsDomain:
1147 SetLastError(ERROR_NONE_MAPPED);
1148 return FALSE;
1150 default:
1151 SetLastError(ERROR_INVALID_PARAMETER);
1152 return FALSE;
1156 BOOLEAN WINAPI TranslateNameA(
1157 LPCSTR lpAccountName, EXTENDED_NAME_FORMAT AccountNameFormat,
1158 EXTENDED_NAME_FORMAT DesiredNameFormat, LPSTR lpTranslatedName,
1159 PULONG nSize)
1161 FIXME("%p %d %d %p %p\n", lpAccountName, AccountNameFormat,
1162 DesiredNameFormat, lpTranslatedName, nSize);
1163 return FALSE;
1166 BOOLEAN WINAPI TranslateNameW(
1167 LPCWSTR lpAccountName, EXTENDED_NAME_FORMAT AccountNameFormat,
1168 EXTENDED_NAME_FORMAT DesiredNameFormat, LPWSTR lpTranslatedName,
1169 PULONG nSize)
1171 FIXME("%p %d %d %p %p\n", lpAccountName, AccountNameFormat,
1172 DesiredNameFormat, lpTranslatedName, nSize);
1173 return FALSE;
1176 /***********************************************************************
1177 * DllMain (SECUR32.0)
1179 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved)
1181 switch (reason)
1183 case DLL_PROCESS_ATTACH:
1184 DisableThreadLibraryCalls(hinstDLL);
1185 SECUR32_initializeProviders();
1186 break;
1187 case DLL_PROCESS_DETACH:
1188 if (reserved) break;
1189 SECUR32_freeProviders();
1192 return TRUE;