mf/samplegrabber: Handle paused state.
[wine.git] / dlls / secur32 / secur32.c
blob08bac24686ae3fc4d53f3f25afe948096af86aff
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 HINSTANCE hsecur32;
45 /**
46 * Type definitions
49 typedef struct _SecurePackageTable
51 DWORD numPackages;
52 DWORD numAllocated;
53 struct list table;
54 } SecurePackageTable;
56 typedef struct _SecureProviderTable
58 DWORD numProviders;
59 DWORD numAllocated;
60 struct list table;
61 } SecureProviderTable;
63 /**
64 * Prototypes
67 /* Tries to load moduleName as a provider. If successful, enumerates what
68 * packages it can and adds them to the package and provider tables. Resizes
69 * tables as necessary.
71 static void _tryLoadProvider(PWSTR moduleName);
73 /* Initialization: read securityproviders value and attempt to open each dll
74 * there. For each DLL, call _tryLoadProvider to see if it's really an SSP.
75 * Two undocumented functions, AddSecurityPackage(A/W) and
76 * DeleteSecurityPackage(A/W), seem suspiciously like they'd register or
77 * unregister a dll, but I'm not sure.
79 static void SECUR32_initializeProviders(void);
81 /* Frees all loaded packages and providers */
82 static void SECUR32_freeProviders(void);
84 /**
85 * Globals
88 static CRITICAL_SECTION cs;
89 static CRITICAL_SECTION_DEBUG cs_debug =
91 0, 0, &cs,
92 { &cs_debug.ProcessLocksList, &cs_debug.ProcessLocksList },
93 0, 0, { (DWORD_PTR)(__FILE__ ": cs") }
95 static CRITICAL_SECTION cs = { &cs_debug, -1, 0, 0, 0, 0 };
96 static SecurePackageTable *packageTable = NULL;
97 static SecureProviderTable *providerTable = NULL;
99 static SecurityFunctionTableA securityFunctionTableA = {
100 SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
101 EnumerateSecurityPackagesA,
102 QueryCredentialsAttributesA,
103 AcquireCredentialsHandleA,
104 FreeCredentialsHandle,
105 NULL, /* Reserved2 */
106 InitializeSecurityContextA,
107 AcceptSecurityContext,
108 CompleteAuthToken,
109 DeleteSecurityContext,
110 ApplyControlToken,
111 QueryContextAttributesA,
112 ImpersonateSecurityContext,
113 RevertSecurityContext,
114 MakeSignature,
115 VerifySignature,
116 FreeContextBuffer,
117 QuerySecurityPackageInfoA,
118 EncryptMessage, /* Reserved3 */
119 DecryptMessage, /* Reserved4 */
120 ExportSecurityContext,
121 ImportSecurityContextA,
122 AddCredentialsA,
123 NULL, /* Reserved8 */
124 QuerySecurityContextToken,
125 EncryptMessage,
126 DecryptMessage,
127 SetContextAttributesA
130 static SecurityFunctionTableW securityFunctionTableW = {
131 SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
132 EnumerateSecurityPackagesW,
133 QueryCredentialsAttributesW,
134 AcquireCredentialsHandleW,
135 FreeCredentialsHandle,
136 NULL, /* Reserved2 */
137 InitializeSecurityContextW,
138 AcceptSecurityContext,
139 CompleteAuthToken,
140 DeleteSecurityContext,
141 ApplyControlToken,
142 QueryContextAttributesW,
143 ImpersonateSecurityContext,
144 RevertSecurityContext,
145 MakeSignature,
146 VerifySignature,
147 FreeContextBuffer,
148 QuerySecurityPackageInfoW,
149 EncryptMessage, /* Reserved3 */
150 DecryptMessage, /* Reserved4 */
151 ExportSecurityContext,
152 ImportSecurityContextW,
153 AddCredentialsW,
154 NULL, /* Reserved8 */
155 QuerySecurityContextToken,
156 EncryptMessage,
157 DecryptMessage,
158 SetContextAttributesW
161 /***********************************************************************
162 * InitSecurityInterfaceA (SECUR32.@)
164 PSecurityFunctionTableA WINAPI InitSecurityInterfaceA(void)
166 return &securityFunctionTableA;
169 /***********************************************************************
170 * InitSecurityInterfaceW (SECUR32.@)
172 PSecurityFunctionTableW WINAPI InitSecurityInterfaceW(void)
174 return &securityFunctionTableW;
177 static WCHAR *strdupW( const WCHAR *str )
179 WCHAR *ret = NULL;
180 if (str && (ret = malloc( (wcslen(str) + 1) * sizeof(WCHAR) ))) wcscpy( ret, str );
181 return ret;
184 static void _makeFnTableA(PSecurityFunctionTableA fnTableA,
185 const SecurityFunctionTableA *inFnTableA,
186 const SecurityFunctionTableW *inFnTableW)
188 if (fnTableA)
190 if (inFnTableA)
192 /* The size of the version 1 table is based on platform sdk's
193 * sspi.h, though the sample ssp also provided with platform sdk
194 * implies only functions through QuerySecurityPackageInfoA are
195 * implemented (yikes)
197 size_t tableSize = inFnTableA->dwVersion == 1 ?
198 offsetof(SecurityFunctionTableA, SetContextAttributesA) :
199 sizeof(SecurityFunctionTableA);
201 memcpy(fnTableA, inFnTableA, tableSize);
202 /* override this, since we can do it internally anyway */
203 fnTableA->QuerySecurityPackageInfoA =
204 QuerySecurityPackageInfoA;
206 else if (inFnTableW)
208 /* functions with thunks */
209 if (inFnTableW->AcquireCredentialsHandleW)
210 fnTableA->AcquireCredentialsHandleA =
211 thunk_AcquireCredentialsHandleA;
212 if (inFnTableW->InitializeSecurityContextW)
213 fnTableA->InitializeSecurityContextA =
214 thunk_InitializeSecurityContextA;
215 if (inFnTableW->ImportSecurityContextW)
216 fnTableA->ImportSecurityContextA =
217 thunk_ImportSecurityContextA;
218 if (inFnTableW->AddCredentialsW)
219 fnTableA->AddCredentialsA =
220 thunk_AddCredentialsA;
221 if (inFnTableW->QueryCredentialsAttributesW)
222 fnTableA->QueryCredentialsAttributesA =
223 thunk_QueryCredentialsAttributesA;
224 if (inFnTableW->QueryContextAttributesW)
225 fnTableA->QueryContextAttributesA =
226 thunk_QueryContextAttributesA;
227 if (inFnTableW->SetContextAttributesW)
228 fnTableA->SetContextAttributesA =
229 thunk_SetContextAttributesA;
230 /* this can't be thunked, there's no extra param to know which
231 * package to forward to */
232 fnTableA->EnumerateSecurityPackagesA = NULL;
233 /* functions with no thunks needed */
234 fnTableA->AcceptSecurityContext = inFnTableW->AcceptSecurityContext;
235 fnTableA->CompleteAuthToken = inFnTableW->CompleteAuthToken;
236 fnTableA->DeleteSecurityContext = inFnTableW->DeleteSecurityContext;
237 fnTableA->ImpersonateSecurityContext =
238 inFnTableW->ImpersonateSecurityContext;
239 fnTableA->RevertSecurityContext = inFnTableW->RevertSecurityContext;
240 fnTableA->MakeSignature = inFnTableW->MakeSignature;
241 fnTableA->VerifySignature = inFnTableW->VerifySignature;
242 fnTableA->FreeContextBuffer = inFnTableW->FreeContextBuffer;
243 fnTableA->QuerySecurityPackageInfoA =
244 QuerySecurityPackageInfoA;
245 fnTableA->ExportSecurityContext =
246 inFnTableW->ExportSecurityContext;
247 fnTableA->QuerySecurityContextToken =
248 inFnTableW->QuerySecurityContextToken;
249 fnTableA->EncryptMessage = inFnTableW->EncryptMessage;
250 fnTableA->DecryptMessage = inFnTableW->DecryptMessage;
255 static void _makeFnTableW(PSecurityFunctionTableW fnTableW,
256 const SecurityFunctionTableA *inFnTableA,
257 const SecurityFunctionTableW *inFnTableW)
259 if (fnTableW)
261 if (inFnTableW)
263 /* The size of the version 1 table is based on platform sdk's
264 * sspi.h, though the sample ssp also provided with platform sdk
265 * implies only functions through QuerySecurityPackageInfoA are
266 * implemented (yikes)
268 size_t tableSize = inFnTableW->dwVersion == 1 ?
269 offsetof(SecurityFunctionTableW, SetContextAttributesW) :
270 sizeof(SecurityFunctionTableW);
272 memcpy(fnTableW, inFnTableW, tableSize);
273 /* override this, since we can do it internally anyway */
274 fnTableW->QuerySecurityPackageInfoW =
275 QuerySecurityPackageInfoW;
277 else if (inFnTableA)
279 /* functions with thunks */
280 if (inFnTableA->AcquireCredentialsHandleA)
281 fnTableW->AcquireCredentialsHandleW =
282 thunk_AcquireCredentialsHandleW;
283 if (inFnTableA->InitializeSecurityContextA)
284 fnTableW->InitializeSecurityContextW =
285 thunk_InitializeSecurityContextW;
286 if (inFnTableA->ImportSecurityContextA)
287 fnTableW->ImportSecurityContextW =
288 thunk_ImportSecurityContextW;
289 if (inFnTableA->AddCredentialsA)
290 fnTableW->AddCredentialsW =
291 thunk_AddCredentialsW;
292 if (inFnTableA->QueryCredentialsAttributesA)
293 fnTableW->QueryCredentialsAttributesW =
294 thunk_QueryCredentialsAttributesW;
295 if (inFnTableA->QueryContextAttributesA)
296 fnTableW->QueryContextAttributesW =
297 thunk_QueryContextAttributesW;
298 if (inFnTableA->SetContextAttributesA)
299 fnTableW->SetContextAttributesW =
300 thunk_SetContextAttributesW;
301 /* this can't be thunked, there's no extra param to know which
302 * package to forward to */
303 fnTableW->EnumerateSecurityPackagesW = NULL;
304 /* functions with no thunks needed */
305 fnTableW->AcceptSecurityContext = inFnTableA->AcceptSecurityContext;
306 fnTableW->CompleteAuthToken = inFnTableA->CompleteAuthToken;
307 fnTableW->DeleteSecurityContext = inFnTableA->DeleteSecurityContext;
308 fnTableW->ImpersonateSecurityContext =
309 inFnTableA->ImpersonateSecurityContext;
310 fnTableW->RevertSecurityContext = inFnTableA->RevertSecurityContext;
311 fnTableW->MakeSignature = inFnTableA->MakeSignature;
312 fnTableW->VerifySignature = inFnTableA->VerifySignature;
313 fnTableW->FreeContextBuffer = inFnTableA->FreeContextBuffer;
314 fnTableW->QuerySecurityPackageInfoW =
315 QuerySecurityPackageInfoW;
316 fnTableW->ExportSecurityContext =
317 inFnTableA->ExportSecurityContext;
318 fnTableW->QuerySecurityContextToken =
319 inFnTableA->QuerySecurityContextToken;
320 fnTableW->EncryptMessage = inFnTableA->EncryptMessage;
321 fnTableW->DecryptMessage = inFnTableA->DecryptMessage;
326 static WCHAR *strdupAW( const char *str )
328 WCHAR *ret = NULL;
329 if (str)
331 int len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
332 if ((ret = malloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
334 return ret;
337 static void _copyPackageInfo(PSecPkgInfoW info, const SecPkgInfoA *inInfoA,
338 const SecPkgInfoW *inInfoW)
340 if (info && (inInfoA || inInfoW))
342 /* odd, I know, but up until Name and Comment the structures are
343 * identical
345 memcpy(info, inInfoW ? inInfoW : (const SecPkgInfoW *)inInfoA, sizeof(*info));
346 if (inInfoW)
348 info->Name = strdupW(inInfoW->Name);
349 info->Comment = strdupW(inInfoW->Comment);
351 else
353 info->Name = strdupAW(inInfoA->Name);
354 info->Comment = strdupAW(inInfoA->Comment);
359 SecureProvider *SECUR32_addProvider(const SecurityFunctionTableA *fnTableA,
360 const SecurityFunctionTableW *fnTableW, PCWSTR moduleName)
362 SecureProvider *ret;
364 EnterCriticalSection(&cs);
366 if (!providerTable)
368 if (!(providerTable = malloc(sizeof(*ret))))
370 LeaveCriticalSection(&cs);
371 return NULL;
374 list_init(&providerTable->table);
377 if (!(ret = malloc(sizeof(*ret))))
379 LeaveCriticalSection(&cs);
380 return NULL;
383 list_add_tail(&providerTable->table, &ret->entry);
384 ret->lib = NULL;
386 if (fnTableA || fnTableW)
388 ret->moduleName = moduleName ? strdupW(moduleName) : NULL;
389 _makeFnTableA(&ret->fnTableA, fnTableA, fnTableW);
390 _makeFnTableW(&ret->fnTableW, fnTableA, fnTableW);
391 ret->loaded = !moduleName;
393 else
395 ret->moduleName = strdupW(moduleName);
396 ret->loaded = FALSE;
399 LeaveCriticalSection(&cs);
400 return ret;
403 void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd,
404 const SecPkgInfoA *infoA, const SecPkgInfoW *infoW)
406 ULONG i;
408 assert(provider);
409 assert(infoA || infoW);
411 EnterCriticalSection(&cs);
413 if (!packageTable)
415 if (!(packageTable = malloc(sizeof(*packageTable))))
417 LeaveCriticalSection(&cs);
418 return;
421 packageTable->numPackages = 0;
422 list_init(&packageTable->table);
425 for (i = 0; i < toAdd; i++)
427 SecurePackage *package;
429 if (!(package = malloc(sizeof(*package)))) continue;
431 list_add_tail(&packageTable->table, &package->entry);
433 package->provider = provider;
434 _copyPackageInfo(&package->infoW, infoA ? &infoA[i] : NULL, infoW ? &infoW[i] : NULL);
436 packageTable->numPackages += toAdd;
438 LeaveCriticalSection(&cs);
441 static void _tryLoadProvider(PWSTR moduleName)
443 HMODULE lib = LoadLibraryW(moduleName);
445 if (lib)
447 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
448 (INIT_SECURITY_INTERFACE_W)GetProcAddress(lib,
449 SECURITY_ENTRYPOINT_ANSIW);
450 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
451 (INIT_SECURITY_INTERFACE_A)GetProcAddress(lib,
452 SECURITY_ENTRYPOINT_ANSIA);
454 TRACE("loaded %s, InitSecurityInterfaceA is %p, InitSecurityInterfaceW is %p\n",
455 debugstr_w(moduleName), pInitSecurityInterfaceA,
456 pInitSecurityInterfaceW);
457 if (pInitSecurityInterfaceW || pInitSecurityInterfaceA)
459 PSecurityFunctionTableA fnTableA = NULL;
460 PSecurityFunctionTableW fnTableW = NULL;
461 ULONG toAdd = 0;
462 PSecPkgInfoA infoA = NULL;
463 PSecPkgInfoW infoW = NULL;
464 SECURITY_STATUS ret = SEC_E_OK;
466 if (pInitSecurityInterfaceA)
467 fnTableA = pInitSecurityInterfaceA();
468 if (pInitSecurityInterfaceW)
469 fnTableW = pInitSecurityInterfaceW();
470 if (fnTableW && fnTableW->EnumerateSecurityPackagesW)
472 if (fnTableW != &securityFunctionTableW)
473 ret = fnTableW->EnumerateSecurityPackagesW(&toAdd, &infoW);
474 else
475 TRACE("%s has built-in providers, skip adding\n", debugstr_w(moduleName));
477 else if (fnTableA && fnTableA->EnumerateSecurityPackagesA)
479 if (fnTableA != &securityFunctionTableA)
480 ret = fnTableA->EnumerateSecurityPackagesA(&toAdd, &infoA);
481 else
482 TRACE("%s has built-in providers, skip adding\n", debugstr_w(moduleName));
484 if (ret == SEC_E_OK && toAdd > 0 && (infoW || infoA))
486 SecureProvider *provider = SECUR32_addProvider(NULL, NULL,
487 moduleName);
489 if (provider)
490 SECUR32_addPackages(provider, toAdd, infoA, infoW);
491 if (infoW)
492 fnTableW->FreeContextBuffer(infoW);
493 else
494 fnTableA->FreeContextBuffer(infoA);
497 FreeLibrary(lib);
499 else
500 WARN("failed to load %s\n", debugstr_w(moduleName));
503 static void SECUR32_initializeProviders(void)
505 HKEY key;
506 LSTATUS apiRet;
508 TRACE("\n");
509 /* First load built-in providers */
510 SECUR32_initSchannelSP();
511 /* Load SSP/AP packages (Kerberos and others) */
512 load_auth_packages();
513 /* Load the Negotiate provider last so apps stumble over the working NTLM
514 * provider first. Attempting to fix bug #16905 while keeping the
515 * application reported on wine-users on 2006-09-12 working. */
516 SECUR32_initNegotiateSP();
517 /* Now load providers from registry */
518 apiRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\SecurityProviders", 0,
519 KEY_READ, &key);
520 if (apiRet == ERROR_SUCCESS)
522 WCHAR securityPkgNames[MAX_PATH]; /* arbitrary len */
523 DWORD size = sizeof(securityPkgNames), type;
525 apiRet = RegQueryValueExW(key, L"SecurityProviders", NULL, &type, (PBYTE)securityPkgNames, &size);
526 if (apiRet == ERROR_SUCCESS && type == REG_SZ)
528 WCHAR *ptr;
530 size = size / sizeof(WCHAR);
531 for (ptr = securityPkgNames;
532 ptr < securityPkgNames + size; )
534 WCHAR *comma;
536 for (comma = ptr; *comma && *comma != ','; comma++)
538 if (*comma == ',')
539 *comma = '\0';
540 for (; *ptr && iswspace(*ptr) && ptr < securityPkgNames + size;
541 ptr++)
543 if (*ptr)
544 _tryLoadProvider(ptr);
545 ptr += lstrlenW(ptr) + 1;
548 RegCloseKey(key);
552 SecurePackage *SECUR32_findPackageW(PCWSTR packageName)
554 SecurePackage *ret = NULL;
555 BOOL matched = FALSE;
557 if (packageTable && packageName)
559 LIST_FOR_EACH_ENTRY(ret, &packageTable->table, SecurePackage, entry)
561 matched = !lstrcmpiW(ret->infoW.Name, packageName);
562 if (matched) break;
564 if (!matched) return NULL;
566 if (ret->provider && !ret->provider->loaded)
568 ret->provider->lib = LoadLibraryW(ret->provider->moduleName);
569 if (ret->provider->lib)
571 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
572 (INIT_SECURITY_INTERFACE_W)GetProcAddress(ret->provider->lib,
573 SECURITY_ENTRYPOINT_ANSIW);
574 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
575 (INIT_SECURITY_INTERFACE_A)GetProcAddress(ret->provider->lib,
576 SECURITY_ENTRYPOINT_ANSIA);
577 PSecurityFunctionTableA fnTableA = NULL;
578 PSecurityFunctionTableW fnTableW = NULL;
580 if (pInitSecurityInterfaceA)
581 fnTableA = pInitSecurityInterfaceA();
582 if (pInitSecurityInterfaceW)
583 fnTableW = pInitSecurityInterfaceW();
584 /* don't update built-in SecurityFunctionTable */
585 if (fnTableA != &securityFunctionTableA)
586 _makeFnTableA(&ret->provider->fnTableA, fnTableA, fnTableW);
587 if (fnTableW != &securityFunctionTableW)
588 _makeFnTableW(&ret->provider->fnTableW, fnTableA, fnTableW);
589 ret->provider->loaded = TRUE;
591 else
592 ret = NULL;
595 return ret;
598 SecurePackage *SECUR32_findPackageA(PCSTR packageName)
600 SecurePackage *ret;
602 if (packageTable && packageName)
604 UNICODE_STRING package;
606 RtlCreateUnicodeStringFromAsciiz(&package, packageName);
607 ret = SECUR32_findPackageW(package.Buffer);
608 RtlFreeUnicodeString(&package);
610 else
611 ret = NULL;
612 return ret;
615 static void SECUR32_freeProviders(void)
617 TRACE("\n");
618 EnterCriticalSection(&cs);
620 SECUR32_deinitSchannelSP();
622 if (packageTable)
624 SecurePackage *package, *package_next;
625 LIST_FOR_EACH_ENTRY_SAFE(package, package_next, &packageTable->table,
626 SecurePackage, entry)
628 free(package->infoW.Name);
629 free(package->infoW.Comment);
630 free(package);
633 free(packageTable);
634 packageTable = NULL;
637 if (providerTable)
639 SecureProvider *provider, *provider_next;
640 LIST_FOR_EACH_ENTRY_SAFE(provider, provider_next, &providerTable->table, SecureProvider, entry)
642 free(provider->moduleName);
643 if (provider->lib) FreeLibrary(provider->lib);
644 free(provider);
647 free(providerTable);
648 providerTable = NULL;
651 LeaveCriticalSection(&cs);
652 DeleteCriticalSection(&cs);
655 /***********************************************************************
656 * FreeContextBuffer (SECUR32.@)
658 * Doh--if pv was allocated by a crypto package, this may not be correct.
659 * The sample ssp seems to use LocalAlloc/LocalFee, but there doesn't seem to
660 * be any guarantee, nor is there an alloc function in secur32.
662 SECURITY_STATUS WINAPI FreeContextBuffer( void *pv )
664 RtlFreeHeap( GetProcessHeap(), 0, pv );
665 return SEC_E_OK;
668 /***********************************************************************
669 * EnumerateSecurityPackagesW (SECUR32.@)
671 SECURITY_STATUS WINAPI EnumerateSecurityPackagesW(PULONG pcPackages,
672 PSecPkgInfoW *ppPackageInfo)
674 SECURITY_STATUS ret = SEC_E_OK;
676 TRACE("(%p, %p)\n", pcPackages, ppPackageInfo);
678 /* windows just crashes if pcPackages or ppPackageInfo is NULL, so will I */
679 *pcPackages = 0;
680 EnterCriticalSection(&cs);
681 if (packageTable)
683 SecurePackage *package;
684 size_t bytesNeeded;
686 bytesNeeded = packageTable->numPackages * sizeof(SecPkgInfoW);
687 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
689 if (package->infoW.Name)
690 bytesNeeded += (lstrlenW(package->infoW.Name) + 1) * sizeof(WCHAR);
691 if (package->infoW.Comment)
692 bytesNeeded += (lstrlenW(package->infoW.Comment) + 1) * sizeof(WCHAR);
694 if (bytesNeeded)
696 /* freed with FeeContextBuffer */
697 if ((*ppPackageInfo = RtlAllocateHeap(GetProcessHeap(), 0, bytesNeeded)))
699 ULONG i = 0;
700 PWSTR nextString;
702 *pcPackages = packageTable->numPackages;
703 nextString = (PWSTR)((PBYTE)*ppPackageInfo +
704 packageTable->numPackages * sizeof(SecPkgInfoW));
705 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
707 PSecPkgInfoW pkgInfo = *ppPackageInfo + i++;
709 *pkgInfo = package->infoW;
710 if (package->infoW.Name)
712 TRACE("Name[%d] = %s\n", i - 1, debugstr_w(package->infoW.Name));
713 pkgInfo->Name = nextString;
714 lstrcpyW(nextString, package->infoW.Name);
715 nextString += lstrlenW(nextString) + 1;
717 else
718 pkgInfo->Name = NULL;
719 if (package->infoW.Comment)
721 TRACE("Comment[%d] = %s\n", i - 1, debugstr_w(package->infoW.Comment));
722 pkgInfo->Comment = nextString;
723 lstrcpyW(nextString, package->infoW.Comment);
724 nextString += lstrlenW(nextString) + 1;
726 else
727 pkgInfo->Comment = NULL;
730 else
731 ret = SEC_E_INSUFFICIENT_MEMORY;
734 LeaveCriticalSection(&cs);
735 TRACE("<-- 0x%08x\n", ret);
736 return ret;
739 /* Converts info (which is assumed to be an array of cPackages SecPkgInfoW
740 * structures) into an array of SecPkgInfoA structures, which it returns.
742 static PSecPkgInfoA thunk_PSecPkgInfoWToA(ULONG cPackages,
743 const SecPkgInfoW *info)
745 PSecPkgInfoA ret;
747 if (info)
749 size_t bytesNeeded = cPackages * sizeof(SecPkgInfoA);
750 ULONG i;
752 for (i = 0; i < cPackages; i++)
754 if (info[i].Name)
755 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Name,
756 -1, NULL, 0, NULL, NULL);
757 if (info[i].Comment)
758 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Comment,
759 -1, NULL, 0, NULL, NULL);
761 /* freed with FreeContextBuffer */
762 if ((ret = RtlAllocateHeap(GetProcessHeap(), 0, bytesNeeded)))
764 PSTR nextString;
766 nextString = (PSTR)((PBYTE)ret + cPackages * sizeof(SecPkgInfoA));
767 for (i = 0; i < cPackages; i++)
769 PSecPkgInfoA pkgInfo = ret + i;
770 int bytes;
772 memcpy(pkgInfo, &info[i], sizeof(SecPkgInfoA));
773 if (info[i].Name)
775 pkgInfo->Name = nextString;
776 /* just repeat back to WideCharToMultiByte how many bytes
777 * it requires, since we asked it earlier
779 bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
780 NULL, 0, NULL, NULL);
781 WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
782 pkgInfo->Name, bytes, NULL, NULL);
783 nextString += lstrlenA(nextString) + 1;
785 else
786 pkgInfo->Name = NULL;
787 if (info[i].Comment)
789 pkgInfo->Comment = nextString;
790 /* just repeat back to WideCharToMultiByte how many bytes
791 * it requires, since we asked it earlier
793 bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
794 NULL, 0, NULL, NULL);
795 WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
796 pkgInfo->Comment, bytes, NULL, NULL);
797 nextString += lstrlenA(nextString) + 1;
799 else
800 pkgInfo->Comment = NULL;
804 else
805 ret = NULL;
806 return ret;
809 /***********************************************************************
810 * EnumerateSecurityPackagesA (SECUR32.@)
812 SECURITY_STATUS WINAPI EnumerateSecurityPackagesA(PULONG pcPackages,
813 PSecPkgInfoA *ppPackageInfo)
815 SECURITY_STATUS ret;
816 PSecPkgInfoW info;
818 ret = EnumerateSecurityPackagesW(pcPackages, &info);
819 if (ret == SEC_E_OK && *pcPackages && info)
821 *ppPackageInfo = thunk_PSecPkgInfoWToA(*pcPackages, info);
822 if (*pcPackages && !*ppPackageInfo)
824 *pcPackages = 0;
825 ret = SEC_E_INSUFFICIENT_MEMORY;
827 FreeContextBuffer(info);
829 return ret;
832 /***********************************************************************
833 * GetComputerObjectNameA (SECUR32.@)
835 * Get the local computer's name using the format specified.
837 * PARAMS
838 * NameFormat [I] The format for the name.
839 * lpNameBuffer [O] Pointer to buffer to receive the name.
840 * nSize [I/O] Size in characters of buffer.
842 * RETURNS
843 * TRUE If the name was written to lpNameBuffer.
844 * FALSE If the name couldn't be written.
846 * NOTES
847 * If lpNameBuffer is NULL, then the size of the buffer needed to hold the
848 * name will be returned in *nSize.
850 * nSize returns the number of characters written when lpNameBuffer is not
851 * NULL or the size of the buffer needed to hold the name when the buffer
852 * is too short or lpNameBuffer is NULL.
854 * It the buffer is too short, ERROR_INSUFFICIENT_BUFFER error will be set.
856 BOOLEAN WINAPI GetComputerObjectNameA(
857 EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
859 BOOLEAN rc;
860 LPWSTR bufferW = NULL;
861 ULONG sizeW = *nSize;
863 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
865 if (lpNameBuffer) {
866 if (!(bufferW = malloc(sizeW * sizeof(WCHAR)))) {
867 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
868 return FALSE;
871 rc = GetComputerObjectNameW(NameFormat, bufferW, &sizeW);
872 if (rc && bufferW) {
873 ULONG len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
874 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, lpNameBuffer, *nSize, NULL, NULL);
875 *nSize = len;
877 else
878 *nSize = sizeW;
879 free(bufferW);
880 return rc;
883 /***********************************************************************
884 * GetComputerObjectNameW (SECUR32.@)
886 BOOLEAN WINAPI GetComputerObjectNameW(
887 EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
889 LSA_HANDLE policyHandle;
890 LSA_OBJECT_ATTRIBUTES objectAttributes;
891 PPOLICY_DNS_DOMAIN_INFO domainInfo;
892 NTSTATUS ntStatus;
893 BOOLEAN status;
895 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
897 if (NameFormat == NameUnknown)
899 SetLastError(ERROR_INVALID_PARAMETER);
900 return FALSE;
903 ZeroMemory(&objectAttributes, sizeof(objectAttributes));
904 objectAttributes.Length = sizeof(objectAttributes);
906 ntStatus = LsaOpenPolicy(NULL, &objectAttributes,
907 POLICY_VIEW_LOCAL_INFORMATION,
908 &policyHandle);
909 if (ntStatus != STATUS_SUCCESS)
911 SetLastError(LsaNtStatusToWinError(ntStatus));
912 WARN("LsaOpenPolicy failed with NT status %u\n", GetLastError());
913 return FALSE;
916 ntStatus = LsaQueryInformationPolicy(policyHandle,
917 PolicyDnsDomainInformation,
918 (PVOID *)&domainInfo);
919 if (ntStatus != STATUS_SUCCESS)
921 SetLastError(LsaNtStatusToWinError(ntStatus));
922 WARN("LsaQueryInformationPolicy failed with NT status %u\n",
923 GetLastError());
924 LsaClose(policyHandle);
925 return FALSE;
928 if (domainInfo->Sid)
930 switch (NameFormat)
932 case NameSamCompatible:
934 WCHAR name[MAX_COMPUTERNAME_LENGTH + 1];
935 DWORD size = ARRAY_SIZE(name);
936 if (GetComputerNameW(name, &size))
938 DWORD len = domainInfo->Name.Length + size + 3;
939 if (lpNameBuffer && *nSize >= len)
941 if (domainInfo->Name.Buffer)
943 lstrcpyW(lpNameBuffer, domainInfo->Name.Buffer);
944 lstrcatW(lpNameBuffer, L"\\");
946 else
947 *lpNameBuffer = 0;
948 lstrcatW(lpNameBuffer, name);
949 lstrcatW(lpNameBuffer, L"$");
950 status = TRUE;
952 else /* just requesting length required */
954 *nSize = len;
955 SetLastError(ERROR_INSUFFICIENT_BUFFER);
956 status = FALSE;
959 else
961 SetLastError(ERROR_INTERNAL_ERROR);
962 status = FALSE;
965 break;
966 case NameFullyQualifiedDN:
968 WCHAR name[MAX_COMPUTERNAME_LENGTH + 1];
969 DWORD len, size;
970 WCHAR *suffix;
972 size = ARRAY_SIZE(name);
973 if (!GetComputerNameW(name, &size))
975 status = FALSE;
976 break;
979 len = wcslen(L"CN=") + size + 1 + wcslen(L"CN=Computers") + 1 + wcslen(L"DC=");
980 if (domainInfo->DnsDomainName.Buffer)
982 suffix = wcsrchr(domainInfo->DnsDomainName.Buffer, '.');
983 if (suffix)
985 *suffix++ = 0;
986 len += 1 + wcslen(L"DC=") + wcslen(suffix);
988 len += wcslen(domainInfo->DnsDomainName.Buffer);
990 else
991 suffix = NULL;
993 if (lpNameBuffer && *nSize > len)
995 lstrcpyW(lpNameBuffer, L"CN=");
996 lstrcatW(lpNameBuffer, name);
997 lstrcatW(lpNameBuffer, L",");
998 lstrcatW(lpNameBuffer, L"CN=Computers");
999 if (domainInfo->DnsDomainName.Buffer)
1001 lstrcatW(lpNameBuffer, L",");
1002 lstrcatW(lpNameBuffer, L"DC=");
1003 lstrcatW(lpNameBuffer, domainInfo->DnsDomainName.Buffer);
1004 if (suffix)
1006 lstrcatW(lpNameBuffer, L",");
1007 lstrcatW(lpNameBuffer, L"DC=");
1008 lstrcatW(lpNameBuffer, suffix);
1011 status = TRUE;
1013 else /* just requesting length required */
1015 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1016 status = FALSE;
1018 *nSize = len + 1;
1019 break;
1021 case NameDisplay:
1022 case NameUniqueId:
1023 case NameCanonical:
1024 case NameUserPrincipal:
1025 case NameCanonicalEx:
1026 case NameServicePrincipal:
1027 case NameDnsDomain:
1028 FIXME("NameFormat %d not implemented\n", NameFormat);
1029 SetLastError(ERROR_CANT_ACCESS_DOMAIN_INFO);
1030 status = FALSE;
1031 break;
1032 default:
1033 SetLastError(ERROR_INVALID_PARAMETER);
1034 status = FALSE;
1037 else
1039 SetLastError(ERROR_CANT_ACCESS_DOMAIN_INFO);
1040 status = FALSE;
1043 LsaFreeMemory(domainInfo);
1044 LsaClose(policyHandle);
1046 return status;
1049 SECURITY_STATUS WINAPI AddSecurityPackageA(LPSTR name, SECURITY_PACKAGE_OPTIONS *options)
1051 FIXME("(%s %p)\n", debugstr_a(name), options);
1052 return E_NOTIMPL;
1055 SECURITY_STATUS WINAPI AddSecurityPackageW(LPWSTR name, SECURITY_PACKAGE_OPTIONS *options)
1057 FIXME("(%s %p)\n", debugstr_w(name), options);
1058 return E_NOTIMPL;
1061 /***********************************************************************
1062 * GetUserNameExA (SECUR32.@)
1064 BOOLEAN WINAPI GetUserNameExA(
1065 EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
1067 BOOLEAN rc;
1068 LPWSTR bufferW = NULL;
1069 ULONG sizeW = *nSize;
1070 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
1071 if (lpNameBuffer) {
1072 bufferW = malloc(sizeW * sizeof(WCHAR));
1073 if (bufferW == NULL) {
1074 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1075 return FALSE;
1078 rc = GetUserNameExW(NameFormat, bufferW, &sizeW);
1079 if (rc) {
1080 ULONG len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
1081 if (len <= *nSize)
1083 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, lpNameBuffer, *nSize, NULL, NULL);
1084 *nSize = len - 1;
1086 else
1088 *nSize = len;
1089 rc = FALSE;
1090 SetLastError(ERROR_MORE_DATA);
1093 else
1094 *nSize = sizeW;
1095 free(bufferW);
1096 return rc;
1099 BOOLEAN WINAPI GetUserNameExW(
1100 EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
1102 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
1104 switch (NameFormat)
1106 case NameSamCompatible:
1108 WCHAR samname[UNLEN + 1 + MAX_COMPUTERNAME_LENGTH + 1];
1109 LPWSTR out;
1110 DWORD len;
1112 /* This assumes the current user is always a local account */
1113 len = MAX_COMPUTERNAME_LENGTH + 1;
1114 if (GetComputerNameW(samname, &len))
1116 out = samname + lstrlenW(samname);
1117 *out++ = '\\';
1118 len = UNLEN + 1;
1119 if (GetUserNameW(out, &len))
1121 if (lstrlenW(samname) < *nSize)
1123 lstrcpyW(lpNameBuffer, samname);
1124 *nSize = lstrlenW(samname);
1125 return TRUE;
1128 SetLastError(ERROR_MORE_DATA);
1129 *nSize = lstrlenW(samname) + 1;
1132 return FALSE;
1135 case NameUnknown:
1136 case NameFullyQualifiedDN:
1137 case NameDisplay:
1138 case NameUniqueId:
1139 case NameCanonical:
1140 case NameUserPrincipal:
1141 case NameCanonicalEx:
1142 case NameServicePrincipal:
1143 case NameDnsDomain:
1144 SetLastError(ERROR_NONE_MAPPED);
1145 return FALSE;
1147 default:
1148 SetLastError(ERROR_INVALID_PARAMETER);
1149 return FALSE;
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 reason, LPVOID reserved)
1178 switch (reason)
1180 case DLL_PROCESS_ATTACH:
1181 hsecur32 = hinstDLL;
1182 DisableThreadLibraryCalls(hinstDLL);
1183 SECUR32_initializeProviders();
1184 break;
1185 case DLL_PROCESS_DETACH:
1186 if (reserved) break;
1187 SECUR32_freeProviders();
1190 return TRUE;