msxml4/tests: Copy namespaces as attributes tests.
[wine.git] / dlls / secur32 / secur32.c
blobf757ea6d34f21a488ecb0ea5f5c35625a58c529e
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 /* Now load providers from registry */
505 apiRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\SecurityProviders", 0,
506 KEY_READ, &key);
507 if (apiRet == ERROR_SUCCESS)
509 WCHAR securityPkgNames[MAX_PATH]; /* arbitrary len */
510 DWORD size = sizeof(securityPkgNames), type;
512 apiRet = RegQueryValueExW(key, L"SecurityProviders", NULL, &type, (PBYTE)securityPkgNames, &size);
513 if (apiRet == ERROR_SUCCESS && type == REG_SZ)
515 WCHAR *ptr;
517 size = size / sizeof(WCHAR);
518 for (ptr = securityPkgNames;
519 ptr < securityPkgNames + size; )
521 WCHAR *comma;
523 for (comma = ptr; *comma && *comma != ','; comma++)
525 if (*comma == ',')
526 *comma = '\0';
527 for (; *ptr && iswspace(*ptr) && ptr < securityPkgNames + size;
528 ptr++)
530 if (*ptr)
531 _tryLoadProvider(ptr);
532 ptr += lstrlenW(ptr) + 1;
535 RegCloseKey(key);
539 SecurePackage *SECUR32_findPackageW(PCWSTR packageName)
541 SecurePackage *ret = NULL;
542 BOOL matched = FALSE;
544 if (packageTable && packageName)
546 LIST_FOR_EACH_ENTRY(ret, &packageTable->table, SecurePackage, entry)
548 matched = !lstrcmpiW(ret->infoW.Name, packageName);
549 if (matched) break;
551 if (!matched) return NULL;
553 if (ret->provider && !ret->provider->loaded)
555 ret->provider->lib = LoadLibraryW(ret->provider->moduleName);
556 if (ret->provider->lib)
558 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
559 (INIT_SECURITY_INTERFACE_W)GetProcAddress(ret->provider->lib,
560 SECURITY_ENTRYPOINT_ANSIW);
561 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
562 (INIT_SECURITY_INTERFACE_A)GetProcAddress(ret->provider->lib,
563 SECURITY_ENTRYPOINT_ANSIA);
564 PSecurityFunctionTableA fnTableA = NULL;
565 PSecurityFunctionTableW fnTableW = NULL;
567 if (pInitSecurityInterfaceA)
568 fnTableA = pInitSecurityInterfaceA();
569 if (pInitSecurityInterfaceW)
570 fnTableW = pInitSecurityInterfaceW();
571 /* don't update built-in SecurityFunctionTable */
572 if (fnTableA != &securityFunctionTableA)
573 _makeFnTableA(&ret->provider->fnTableA, fnTableA, fnTableW);
574 if (fnTableW != &securityFunctionTableW)
575 _makeFnTableW(&ret->provider->fnTableW, fnTableA, fnTableW);
576 ret->provider->loaded = TRUE;
578 else
579 ret = NULL;
582 return ret;
585 SecurePackage *SECUR32_findPackageA(PCSTR packageName)
587 SecurePackage *ret;
589 if (packageTable && packageName)
591 UNICODE_STRING package;
593 RtlCreateUnicodeStringFromAsciiz(&package, packageName);
594 ret = SECUR32_findPackageW(package.Buffer);
595 RtlFreeUnicodeString(&package);
597 else
598 ret = NULL;
599 return ret;
602 static void SECUR32_freeProviders(void)
604 TRACE("\n");
605 EnterCriticalSection(&cs);
607 SECUR32_deinitSchannelSP();
609 if (packageTable)
611 SecurePackage *package, *package_next;
612 LIST_FOR_EACH_ENTRY_SAFE(package, package_next, &packageTable->table,
613 SecurePackage, entry)
615 free(package->infoW.Name);
616 free(package->infoW.Comment);
617 free(package);
620 free(packageTable);
621 packageTable = NULL;
624 if (providerTable)
626 SecureProvider *provider, *provider_next;
627 LIST_FOR_EACH_ENTRY_SAFE(provider, provider_next, &providerTable->table, SecureProvider, entry)
629 free(provider->moduleName);
630 if (provider->lib) FreeLibrary(provider->lib);
631 free(provider);
634 free(providerTable);
635 providerTable = NULL;
638 LeaveCriticalSection(&cs);
639 DeleteCriticalSection(&cs);
642 /***********************************************************************
643 * FreeContextBuffer (SECUR32.@)
645 * Doh--if pv was allocated by a crypto package, this may not be correct.
646 * The sample ssp seems to use LocalAlloc/LocalFee, but there doesn't seem to
647 * be any guarantee, nor is there an alloc function in secur32.
649 SECURITY_STATUS WINAPI FreeContextBuffer( void *pv )
651 RtlFreeHeap( GetProcessHeap(), 0, pv );
652 return SEC_E_OK;
655 /***********************************************************************
656 * EnumerateSecurityPackagesW (SECUR32.@)
658 SECURITY_STATUS WINAPI EnumerateSecurityPackagesW(PULONG pcPackages,
659 PSecPkgInfoW *ppPackageInfo)
661 SECURITY_STATUS ret = SEC_E_OK;
663 TRACE("(%p, %p)\n", pcPackages, ppPackageInfo);
665 /* windows just crashes if pcPackages or ppPackageInfo is NULL, so will I */
666 *pcPackages = 0;
667 EnterCriticalSection(&cs);
668 if (packageTable)
670 SecurePackage *package;
671 size_t bytesNeeded;
673 bytesNeeded = packageTable->numPackages * sizeof(SecPkgInfoW);
674 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
676 if (package->infoW.Name)
677 bytesNeeded += (lstrlenW(package->infoW.Name) + 1) * sizeof(WCHAR);
678 if (package->infoW.Comment)
679 bytesNeeded += (lstrlenW(package->infoW.Comment) + 1) * sizeof(WCHAR);
681 if (bytesNeeded)
683 /* freed with FeeContextBuffer */
684 if ((*ppPackageInfo = RtlAllocateHeap(GetProcessHeap(), 0, bytesNeeded)))
686 ULONG i = 0;
687 PWSTR nextString;
689 *pcPackages = packageTable->numPackages;
690 nextString = (PWSTR)((PBYTE)*ppPackageInfo +
691 packageTable->numPackages * sizeof(SecPkgInfoW));
692 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
694 PSecPkgInfoW pkgInfo = *ppPackageInfo + i++;
696 *pkgInfo = package->infoW;
697 if (package->infoW.Name)
699 TRACE("Name[%ld] = %s\n", i - 1, debugstr_w(package->infoW.Name));
700 pkgInfo->Name = nextString;
701 lstrcpyW(nextString, package->infoW.Name);
702 nextString += lstrlenW(nextString) + 1;
704 else
705 pkgInfo->Name = NULL;
706 if (package->infoW.Comment)
708 TRACE("Comment[%ld] = %s\n", i - 1, debugstr_w(package->infoW.Comment));
709 pkgInfo->Comment = nextString;
710 lstrcpyW(nextString, package->infoW.Comment);
711 nextString += lstrlenW(nextString) + 1;
713 else
714 pkgInfo->Comment = NULL;
717 else
718 ret = SEC_E_INSUFFICIENT_MEMORY;
721 LeaveCriticalSection(&cs);
722 TRACE("<-- 0x%08lx\n", ret);
723 return ret;
726 /* Converts info (which is assumed to be an array of cPackages SecPkgInfoW
727 * structures) into an array of SecPkgInfoA structures, which it returns.
729 static PSecPkgInfoA thunk_PSecPkgInfoWToA(ULONG cPackages,
730 const SecPkgInfoW *info)
732 PSecPkgInfoA ret;
734 if (info)
736 size_t bytesNeeded = cPackages * sizeof(SecPkgInfoA);
737 ULONG i;
739 for (i = 0; i < cPackages; i++)
741 if (info[i].Name)
742 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Name,
743 -1, NULL, 0, NULL, NULL);
744 if (info[i].Comment)
745 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Comment,
746 -1, NULL, 0, NULL, NULL);
748 /* freed with FreeContextBuffer */
749 if ((ret = RtlAllocateHeap(GetProcessHeap(), 0, bytesNeeded)))
751 PSTR nextString;
753 nextString = (PSTR)((PBYTE)ret + cPackages * sizeof(SecPkgInfoA));
754 for (i = 0; i < cPackages; i++)
756 PSecPkgInfoA pkgInfo = ret + i;
757 int bytes;
759 memcpy(pkgInfo, &info[i], sizeof(SecPkgInfoA));
760 if (info[i].Name)
762 pkgInfo->Name = nextString;
763 /* just repeat back to WideCharToMultiByte how many bytes
764 * it requires, since we asked it earlier
766 bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
767 NULL, 0, NULL, NULL);
768 WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
769 pkgInfo->Name, bytes, NULL, NULL);
770 nextString += lstrlenA(nextString) + 1;
772 else
773 pkgInfo->Name = NULL;
774 if (info[i].Comment)
776 pkgInfo->Comment = nextString;
777 /* just repeat back to WideCharToMultiByte how many bytes
778 * it requires, since we asked it earlier
780 bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
781 NULL, 0, NULL, NULL);
782 WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
783 pkgInfo->Comment, bytes, NULL, NULL);
784 nextString += lstrlenA(nextString) + 1;
786 else
787 pkgInfo->Comment = NULL;
791 else
792 ret = NULL;
793 return ret;
796 /***********************************************************************
797 * EnumerateSecurityPackagesA (SECUR32.@)
799 SECURITY_STATUS WINAPI EnumerateSecurityPackagesA(PULONG pcPackages,
800 PSecPkgInfoA *ppPackageInfo)
802 SECURITY_STATUS ret;
803 PSecPkgInfoW info;
805 ret = EnumerateSecurityPackagesW(pcPackages, &info);
806 if (ret == SEC_E_OK && *pcPackages && info)
808 *ppPackageInfo = thunk_PSecPkgInfoWToA(*pcPackages, info);
809 if (*pcPackages && !*ppPackageInfo)
811 *pcPackages = 0;
812 ret = SEC_E_INSUFFICIENT_MEMORY;
814 FreeContextBuffer(info);
816 return ret;
820 static const char *debugstr_NameFormat( EXTENDED_NAME_FORMAT format )
822 static const char * const names[] =
824 "NameUnknown",
825 "NameFullyQualifiedDN",
826 "NameSamCompatible",
827 "NameDisplay",
828 NULL,
829 NULL,
830 "NameUniqueId",
831 "NameCanonical",
832 "NameUserPrincipal",
833 "NameCanonicalEx",
834 "NameServicePrincipal",
835 NULL,
836 "NameDnsDomain",
837 "NameGivenName",
838 "NameSurname"
841 if (format < ARRAY_SIZE(names) && names[format]) return names[format];
842 return wine_dbg_sprintf( "%u", format );
846 /***********************************************************************
847 * GetComputerObjectNameA (SECUR32.@)
849 * Get the local computer's name using the format specified.
851 * PARAMS
852 * NameFormat [I] The format for the name.
853 * lpNameBuffer [O] Pointer to buffer to receive the name.
854 * nSize [I/O] Size in characters of buffer.
856 * RETURNS
857 * TRUE If the name was written to lpNameBuffer.
858 * FALSE If the name couldn't be written.
860 * NOTES
861 * If lpNameBuffer is NULL, then the size of the buffer needed to hold the
862 * name will be returned in *nSize.
864 * nSize returns the number of characters written when lpNameBuffer is not
865 * NULL or the size of the buffer needed to hold the name when the buffer
866 * is too short or lpNameBuffer is NULL.
868 * It the buffer is too short, ERROR_INSUFFICIENT_BUFFER error will be set.
870 BOOLEAN WINAPI GetComputerObjectNameA(
871 EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
873 BOOLEAN rc;
874 LPWSTR bufferW = NULL;
875 ULONG sizeW = *nSize;
877 TRACE("(%s %p %p)\n", debugstr_NameFormat(NameFormat), lpNameBuffer, nSize);
879 if (lpNameBuffer) {
880 if (!(bufferW = malloc(sizeW * sizeof(WCHAR)))) {
881 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
882 return FALSE;
885 rc = GetComputerObjectNameW(NameFormat, bufferW, &sizeW);
886 if (rc && bufferW) {
887 ULONG len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
888 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, lpNameBuffer, *nSize, NULL, NULL);
889 *nSize = len;
891 else
892 *nSize = sizeW;
893 free(bufferW);
894 return rc;
897 /***********************************************************************
898 * GetComputerObjectNameW (SECUR32.@)
900 BOOLEAN WINAPI GetComputerObjectNameW(
901 EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
903 LSA_HANDLE policyHandle;
904 LSA_OBJECT_ATTRIBUTES objectAttributes;
905 PPOLICY_DNS_DOMAIN_INFO domainInfo;
906 NTSTATUS ntStatus;
907 BOOLEAN status;
909 TRACE("(%s %p %p)\n", debugstr_NameFormat(NameFormat), lpNameBuffer, nSize);
911 if (NameFormat == NameUnknown)
913 SetLastError(ERROR_INVALID_PARAMETER);
914 return FALSE;
917 ZeroMemory(&objectAttributes, sizeof(objectAttributes));
918 objectAttributes.Length = sizeof(objectAttributes);
920 ntStatus = LsaOpenPolicy(NULL, &objectAttributes,
921 POLICY_VIEW_LOCAL_INFORMATION,
922 &policyHandle);
923 if (ntStatus != STATUS_SUCCESS)
925 SetLastError(LsaNtStatusToWinError(ntStatus));
926 WARN("LsaOpenPolicy failed with NT status %lu\n", GetLastError());
927 return FALSE;
930 ntStatus = LsaQueryInformationPolicy(policyHandle,
931 PolicyDnsDomainInformation,
932 (PVOID *)&domainInfo);
933 if (ntStatus != STATUS_SUCCESS)
935 SetLastError(LsaNtStatusToWinError(ntStatus));
936 WARN("LsaQueryInformationPolicy failed with NT status %lu\n",
937 GetLastError());
938 LsaClose(policyHandle);
939 return FALSE;
942 if (domainInfo->Sid)
944 switch (NameFormat)
946 case NameSamCompatible:
948 WCHAR name[MAX_COMPUTERNAME_LENGTH + 1];
949 DWORD size = ARRAY_SIZE(name);
950 if (GetComputerNameW(name, &size))
952 DWORD len = domainInfo->Name.Length + size + 3;
953 if (lpNameBuffer && *nSize >= len)
955 if (domainInfo->Name.Buffer)
957 lstrcpyW(lpNameBuffer, domainInfo->Name.Buffer);
958 lstrcatW(lpNameBuffer, L"\\");
960 else
961 *lpNameBuffer = 0;
962 lstrcatW(lpNameBuffer, name);
963 lstrcatW(lpNameBuffer, L"$");
964 status = TRUE;
966 else /* just requesting length required */
968 *nSize = len;
969 SetLastError(ERROR_INSUFFICIENT_BUFFER);
970 status = FALSE;
973 else
975 SetLastError(ERROR_INTERNAL_ERROR);
976 status = FALSE;
979 break;
980 case NameFullyQualifiedDN:
982 WCHAR name[MAX_COMPUTERNAME_LENGTH + 1];
983 DWORD len, size;
984 WCHAR *suffix;
986 size = ARRAY_SIZE(name);
987 if (!GetComputerNameW(name, &size))
989 status = FALSE;
990 break;
993 len = wcslen(L"CN=") + size + 1 + wcslen(L"CN=Computers") + 1 + wcslen(L"DC=");
994 if (domainInfo->DnsDomainName.Buffer)
996 suffix = wcsrchr(domainInfo->DnsDomainName.Buffer, '.');
997 if (suffix)
999 *suffix++ = 0;
1000 len += 1 + wcslen(L"DC=") + wcslen(suffix);
1002 len += wcslen(domainInfo->DnsDomainName.Buffer);
1004 else
1005 suffix = NULL;
1007 if (lpNameBuffer && *nSize > len)
1009 lstrcpyW(lpNameBuffer, L"CN=");
1010 lstrcatW(lpNameBuffer, name);
1011 lstrcatW(lpNameBuffer, L",");
1012 lstrcatW(lpNameBuffer, L"CN=Computers");
1013 if (domainInfo->DnsDomainName.Buffer)
1015 lstrcatW(lpNameBuffer, L",");
1016 lstrcatW(lpNameBuffer, L"DC=");
1017 lstrcatW(lpNameBuffer, domainInfo->DnsDomainName.Buffer);
1018 if (suffix)
1020 lstrcatW(lpNameBuffer, L",");
1021 lstrcatW(lpNameBuffer, L"DC=");
1022 lstrcatW(lpNameBuffer, suffix);
1025 status = TRUE;
1027 else /* just requesting length required */
1029 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1030 status = FALSE;
1032 *nSize = len + 1;
1033 break;
1035 case NameDisplay:
1036 case NameUniqueId:
1037 case NameCanonical:
1038 case NameUserPrincipal:
1039 case NameCanonicalEx:
1040 case NameServicePrincipal:
1041 case NameDnsDomain:
1042 FIXME("NameFormat %d not implemented\n", NameFormat);
1043 SetLastError(ERROR_CANT_ACCESS_DOMAIN_INFO);
1044 status = FALSE;
1045 break;
1046 default:
1047 SetLastError(ERROR_INVALID_PARAMETER);
1048 status = FALSE;
1051 else
1053 SetLastError(ERROR_CANT_ACCESS_DOMAIN_INFO);
1054 status = FALSE;
1057 LsaFreeMemory(domainInfo);
1058 LsaClose(policyHandle);
1060 return status;
1063 SECURITY_STATUS WINAPI AddSecurityPackageA(LPSTR name, SECURITY_PACKAGE_OPTIONS *options)
1065 FIXME("(%s %p)\n", debugstr_a(name), options);
1066 return E_NOTIMPL;
1069 SECURITY_STATUS WINAPI AddSecurityPackageW(LPWSTR name, SECURITY_PACKAGE_OPTIONS *options)
1071 FIXME("(%s %p)\n", debugstr_w(name), options);
1072 return E_NOTIMPL;
1075 SECURITY_STATUS WINAPI DeleteSecurityPackageA(LPSTR name)
1077 FIXME("(%s)\n", debugstr_a(name));
1078 return E_NOTIMPL;
1081 SECURITY_STATUS WINAPI DeleteSecurityPackageW(LPWSTR name)
1083 FIXME("(%s)\n", debugstr_w(name));
1084 return E_NOTIMPL;
1087 /***********************************************************************
1088 * GetUserNameExA (SECUR32.@)
1090 BOOLEAN WINAPI GetUserNameExA(
1091 EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
1093 BOOLEAN rc;
1094 LPWSTR bufferW = NULL;
1095 ULONG sizeW = *nSize;
1096 TRACE("(%s %p %p)\n", debugstr_NameFormat(NameFormat), lpNameBuffer, nSize);
1097 if (lpNameBuffer) {
1098 bufferW = malloc(sizeW * sizeof(WCHAR));
1099 if (bufferW == NULL) {
1100 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1101 return FALSE;
1104 rc = GetUserNameExW(NameFormat, bufferW, &sizeW);
1105 if (rc) {
1106 ULONG len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
1107 if (len <= *nSize)
1109 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, lpNameBuffer, *nSize, NULL, NULL);
1110 *nSize = len - 1;
1112 else
1114 *nSize = len;
1115 rc = FALSE;
1116 SetLastError(ERROR_MORE_DATA);
1119 else
1120 *nSize = sizeW;
1121 free(bufferW);
1122 return rc;
1125 BOOLEAN WINAPI GetUserNameExW(
1126 EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
1128 TRACE("(%s %p %p)\n", debugstr_NameFormat(NameFormat), lpNameBuffer, nSize);
1130 switch (NameFormat)
1132 case NameSamCompatible:
1134 WCHAR samname[UNLEN + 1 + MAX_COMPUTERNAME_LENGTH + 1];
1135 LPWSTR out;
1136 DWORD len;
1138 /* This assumes the current user is always a local account */
1139 len = MAX_COMPUTERNAME_LENGTH + 1;
1140 if (GetComputerNameW(samname, &len))
1142 out = samname + lstrlenW(samname);
1143 *out++ = '\\';
1144 len = UNLEN + 1;
1145 if (GetUserNameW(out, &len))
1147 if (lstrlenW(samname) < *nSize)
1149 lstrcpyW(lpNameBuffer, samname);
1150 *nSize = lstrlenW(samname);
1151 return TRUE;
1154 SetLastError(ERROR_MORE_DATA);
1155 *nSize = lstrlenW(samname) + 1;
1158 return FALSE;
1161 case NameUnknown:
1162 case NameFullyQualifiedDN:
1163 case NameDisplay:
1164 case NameUniqueId:
1165 case NameCanonical:
1166 case NameUserPrincipal:
1167 case NameCanonicalEx:
1168 case NameServicePrincipal:
1169 case NameDnsDomain:
1170 FIXME("NameFormat %d not implemented\n", NameFormat);
1171 SetLastError(ERROR_NONE_MAPPED);
1172 return FALSE;
1174 default:
1175 SetLastError(ERROR_INVALID_PARAMETER);
1176 return FALSE;
1180 BOOLEAN WINAPI TranslateNameA(
1181 LPCSTR lpAccountName, EXTENDED_NAME_FORMAT AccountNameFormat,
1182 EXTENDED_NAME_FORMAT DesiredNameFormat, LPSTR lpTranslatedName,
1183 PULONG nSize)
1185 FIXME("%p %s %s %p %p\n", lpAccountName, debugstr_NameFormat(AccountNameFormat),
1186 debugstr_NameFormat(DesiredNameFormat), lpTranslatedName, nSize);
1187 return FALSE;
1190 BOOLEAN WINAPI TranslateNameW(
1191 LPCWSTR lpAccountName, EXTENDED_NAME_FORMAT AccountNameFormat,
1192 EXTENDED_NAME_FORMAT DesiredNameFormat, LPWSTR lpTranslatedName,
1193 PULONG nSize)
1195 FIXME("%p %s %s %p %p\n", lpAccountName, debugstr_NameFormat(AccountNameFormat),
1196 debugstr_NameFormat(DesiredNameFormat), lpTranslatedName, nSize);
1197 return FALSE;
1200 /***********************************************************************
1201 * DllMain (SECUR32.0)
1203 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved)
1205 switch (reason)
1207 case DLL_PROCESS_ATTACH:
1208 DisableThreadLibraryCalls(hinstDLL);
1209 SECUR32_initializeProviders();
1210 break;
1211 case DLL_PROCESS_DETACH:
1212 if (reserved) break;
1213 SECUR32_freeProviders();
1216 return TRUE;