Rewrote the collapsing of . and .. in RtlGetFullPathName_U for better
[wine.git] / dlls / secur32 / secur32.c
blob2b5145882b9d431e163e4fa70da665e031d1d696
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include <stdarg.h>
20 #include "windef.h"
21 #include "winbase.h"
22 #include "winnls.h"
23 #include "winreg.h"
24 #include "winternl.h"
25 #include "shlwapi.h"
26 #include "sspi.h"
27 #include "secur32_priv.h"
28 #include "thunks.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
34 /**
35 * Type definitions
38 typedef struct _SecurePackageTable
40 DWORD numPackages;
41 DWORD numAllocated;
42 SecurePackage table[1];
43 } SecurePackageTable;
45 typedef struct _SecureProviderTable
47 DWORD numProviders;
48 DWORD numAllocated;
49 SecureProvider table[1];
50 } SecureProviderTable;
52 /**
53 * Prototypes
56 /* Makes sure table has space for at least howBig entries. If table is NULL,
57 * returns a newly allocated table. Otherwise returns the address of the
58 * modified table, which may not be the same was when called.
60 static SecurePackageTable *_resizePackageTable(SecurePackageTable *table,
61 DWORD howBig);
63 /* Makes sure table has space for at least howBig entries. If table is NULL,
64 * returns a newly allocated table. Otherwise returns the address of the
65 * modified table, which may not be the same was when called.
67 static SecureProviderTable *_resizeProviderTable(SecureProviderTable *table,
68 DWORD howBig);
70 /* Tries to load moduleName as a provider. If successful, enumerates what
71 * packages it can and adds them to the package and provider tables. Resizes
72 * tables as necessary.
74 static void _tryLoadProvider(PWSTR moduleName);
76 /* Initialization: read securityproviders value and attempt to open each dll
77 * there. For each DLL, call _tryLoadProvider to see if it's really an SSP.
78 * Two undocumented functions, AddSecurityPackage(A/W) and
79 * DeleteSecurityPackage(A/W), seem suspiciously like they'd register or
80 * unregister a dll, but I'm not sure.
82 static void SECUR32_initializeProviders(void);
84 /* Frees all loaded packages and providers */
85 static void SECUR32_freeProviders(void);
87 /**
88 * Globals
91 static CRITICAL_SECTION cs;
92 static SecurePackageTable *packageTable = NULL;
93 static SecureProviderTable *providerTable = NULL;
95 static SecurityFunctionTableA securityFunctionTableA = {
96 SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION_2,
97 EnumerateSecurityPackagesA,
98 QueryCredentialsAttributesA,
99 AcquireCredentialsHandleA,
100 FreeCredentialsHandle,
101 NULL, /* Reserved2 */
102 InitializeSecurityContextA,
103 AcceptSecurityContext,
104 CompleteAuthToken,
105 DeleteSecurityContext,
106 ApplyControlToken,
107 QueryContextAttributesA,
108 ImpersonateSecurityContext,
109 RevertSecurityContext,
110 MakeSignature,
111 VerifySignature,
112 FreeContextBuffer,
113 QuerySecurityPackageInfoA,
114 NULL, /* Reserved3 */
115 NULL, /* Reserved4 */
116 ExportSecurityContext,
117 ImportSecurityContextA,
118 AddCredentialsA,
119 NULL, /* Reserved8 */
120 QuerySecurityContextToken,
121 EncryptMessage,
122 DecryptMessage,
123 SetContextAttributesA
126 static SecurityFunctionTableW securityFunctionTableW = {
127 SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION_2,
128 EnumerateSecurityPackagesW,
129 QueryCredentialsAttributesW,
130 AcquireCredentialsHandleW,
131 FreeCredentialsHandle,
132 NULL, /* Reserved2 */
133 InitializeSecurityContextW,
134 AcceptSecurityContext,
135 CompleteAuthToken,
136 DeleteSecurityContext,
137 ApplyControlToken,
138 QueryContextAttributesW,
139 ImpersonateSecurityContext,
140 RevertSecurityContext,
141 MakeSignature,
142 VerifySignature,
143 FreeContextBuffer,
144 QuerySecurityPackageInfoW,
145 NULL, /* Reserved3 */
146 NULL, /* Reserved4 */
147 ExportSecurityContext,
148 ImportSecurityContextW,
149 AddCredentialsW,
150 NULL, /* Reserved8 */
151 QuerySecurityContextToken,
152 EncryptMessage,
153 DecryptMessage,
154 SetContextAttributesW
157 PSecurityFunctionTableA SEC_ENTRY InitSecurityInterfaceA(void)
159 return &securityFunctionTableA;
162 PSecurityFunctionTableW SEC_ENTRY InitSecurityInterfaceW(void)
164 return &securityFunctionTableW;
167 /* Allocates or resizes table to have space for at least howBig packages.
168 * Uses Heap functions, because needs to be able to reallocate.
170 static SecurePackageTable *_resizePackageTable(SecurePackageTable *table,
171 DWORD howBig)
173 SecurePackageTable *ret;
175 EnterCriticalSection(&cs);
176 if (table)
178 if (table->numAllocated < howBig)
180 ret = (SecurePackageTable *)HeapReAlloc(GetProcessHeap(), 0, table,
181 sizeof(SecurePackageTable) + (howBig - 1) * sizeof(SecurePackage));
182 if (ret)
184 ret->numAllocated = howBig;
185 table = ret;
188 else
189 ret = table;
191 else
193 DWORD numAllocated = (howBig > 1 ? howBig : 1);
195 ret = (SecurePackageTable *)HeapAlloc(GetProcessHeap(), 0,
196 sizeof(SecurePackageTable) +
197 (numAllocated - 1) * sizeof(SecurePackage));
198 if (ret)
200 ret->numAllocated = numAllocated;
201 ret->numPackages = 0;
204 LeaveCriticalSection(&cs);
205 return ret;
208 /* Allocates or resizes table to have space for at least howBig providers.
209 * Uses Heap functions, because needs to be able to reallocate.
211 static SecureProviderTable *_resizeProviderTable(SecureProviderTable *table,
212 DWORD howBig)
214 SecureProviderTable *ret;
216 EnterCriticalSection(&cs);
217 if (table)
219 if (table->numAllocated < howBig)
221 ret = (SecureProviderTable *)HeapReAlloc(GetProcessHeap(), 0, table,
222 sizeof(SecureProviderTable) +
223 (howBig - 1) * sizeof(SecureProvider));
224 if (ret)
226 ret->numAllocated = howBig;
227 table = ret;
230 else
231 ret = table;
233 else
235 DWORD numAllocated = (howBig > 1 ? howBig : 1);
237 ret = (SecureProviderTable *)HeapAlloc(GetProcessHeap(), 0,
238 sizeof(SecureProviderTable) +
239 (numAllocated - 1) * sizeof(SecureProvider));
240 if (ret)
242 ret->numAllocated = numAllocated;
243 ret->numProviders = 0;
246 LeaveCriticalSection(&cs);
247 return ret;
250 PWSTR SECUR32_strdupW(PCWSTR str)
252 PWSTR ret;
254 if (str)
256 ret = (PWSTR)SECUR32_ALLOC((lstrlenW(str) + 1) * sizeof(WCHAR));
257 if (ret)
258 lstrcpyW(ret, str);
260 else
261 ret = NULL;
262 return ret;
265 PWSTR SECUR32_AllocWideFromMultiByte(PCSTR str)
267 PWSTR ret;
269 if (str)
271 int charsNeeded = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
273 if (charsNeeded)
275 ret = (PWSTR)SECUR32_ALLOC(charsNeeded * sizeof(WCHAR));
276 if (ret)
277 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, charsNeeded);
279 else
280 ret = NULL;
282 else
283 ret = NULL;
284 return ret;
287 PSTR SECUR32_AllocMultiByteFromWide(PCWSTR str)
289 PSTR ret;
291 if (str)
293 int charsNeeded = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0,
294 NULL, NULL);
296 if (charsNeeded)
298 ret = (PSTR)SECUR32_ALLOC(charsNeeded);
299 if (ret)
300 WideCharToMultiByte(CP_ACP, 0, str, -1, ret, charsNeeded,
301 NULL, NULL);
303 else
304 ret = NULL;
306 else
307 ret = NULL;
308 return ret;
311 static void _makeFnTableA(PSecurityFunctionTableA fnTableA,
312 const PSecurityFunctionTableA inFnTableA,
313 const PSecurityFunctionTableW inFnTableW)
315 if (fnTableA)
317 if (inFnTableA)
319 /* The size of the version 1 table is based on platform sdk's
320 * sspi.h, though the sample ssp also provided with platform sdk
321 * implies only functions through QuerySecurityPackageInfoA are
322 * implemented (yikes)
324 size_t tableSize = inFnTableA->dwVersion == 1 ?
325 (LPBYTE)&inFnTableA->SetContextAttributesA -
326 (LPBYTE)inFnTableA : sizeof(SecurityFunctionTableA);
328 memcpy(fnTableA, inFnTableA, tableSize);
329 /* override this, since we can do it internally anyway */
330 fnTableA->QuerySecurityPackageInfoA =
331 QuerySecurityPackageInfoA;
333 else if (inFnTableW)
335 /* functions with thunks */
336 if (inFnTableW->AcquireCredentialsHandleW)
337 fnTableA->AcquireCredentialsHandleA =
338 thunk_AcquireCredentialsHandleA;
339 if (inFnTableW->InitializeSecurityContextW)
340 fnTableA->InitializeSecurityContextA =
341 thunk_InitializeSecurityContextA;
342 if (inFnTableW->ImportSecurityContextW)
343 fnTableA->ImportSecurityContextA =
344 thunk_ImportSecurityContextA;
345 if (inFnTableW->AddCredentialsW)
346 fnTableA->AddCredentialsA =
347 thunk_AddCredentialsA;
348 if (inFnTableW->QueryCredentialsAttributesW)
349 fnTableA->QueryCredentialsAttributesA =
350 thunk_QueryCredentialsAttributesA;
351 if (inFnTableW->QueryContextAttributesW)
352 fnTableA->QueryContextAttributesA =
353 thunk_QueryContextAttributesA;
354 if (inFnTableW->SetContextAttributesW)
355 fnTableA->SetContextAttributesA =
356 thunk_SetContextAttributesA;
357 /* this can't be thunked, there's no extra param to know which
358 * package to forward to */
359 fnTableA->EnumerateSecurityPackagesA = NULL;
360 /* functions with no thunks needed */
361 fnTableA->AcceptSecurityContext = inFnTableW->AcceptSecurityContext;
362 fnTableA->CompleteAuthToken = inFnTableW->CompleteAuthToken;
363 fnTableA->DeleteSecurityContext = inFnTableW->DeleteSecurityContext;
364 fnTableA->ImpersonateSecurityContext =
365 inFnTableW->ImpersonateSecurityContext;
366 fnTableA->RevertSecurityContext = inFnTableW->RevertSecurityContext;
367 fnTableA->MakeSignature = inFnTableW->MakeSignature;
368 fnTableA->VerifySignature = inFnTableW->VerifySignature;
369 fnTableA->FreeContextBuffer = inFnTableW->FreeContextBuffer;
370 fnTableA->QuerySecurityPackageInfoA =
371 QuerySecurityPackageInfoA;
372 fnTableA->ExportSecurityContext =
373 inFnTableW->ExportSecurityContext;
374 fnTableA->QuerySecurityContextToken =
375 inFnTableW->QuerySecurityContextToken;
376 fnTableA->EncryptMessage = inFnTableW->EncryptMessage;
377 fnTableA->DecryptMessage = inFnTableW->DecryptMessage;
382 static void _makeFnTableW(PSecurityFunctionTableW fnTableW,
383 const PSecurityFunctionTableA inFnTableA,
384 const PSecurityFunctionTableW inFnTableW)
386 if (fnTableW)
388 if (inFnTableW)
390 /* The size of the version 1 table is based on platform sdk's
391 * sspi.h, though the sample ssp also provided with platform sdk
392 * implies only functions through QuerySecurityPackageInfoA are
393 * implemented (yikes)
395 size_t tableSize = inFnTableW->dwVersion == 1 ?
396 (LPBYTE)&inFnTableW->SetContextAttributesW -
397 (LPBYTE)inFnTableW : sizeof(SecurityFunctionTableW);
399 memcpy(fnTableW, inFnTableW, tableSize);
400 /* override this, since we can do it internally anyway */
401 fnTableW->QuerySecurityPackageInfoW =
402 QuerySecurityPackageInfoW;
404 else if (inFnTableA)
406 /* functions with thunks */
407 if (inFnTableA->AcquireCredentialsHandleA)
408 fnTableW->AcquireCredentialsHandleW =
409 thunk_AcquireCredentialsHandleW;
410 if (inFnTableA->InitializeSecurityContextA)
411 fnTableW->InitializeSecurityContextW =
412 thunk_InitializeSecurityContextW;
413 if (inFnTableA->ImportSecurityContextA)
414 fnTableW->ImportSecurityContextW =
415 thunk_ImportSecurityContextW;
416 if (inFnTableA->AddCredentialsA)
417 fnTableW->AddCredentialsW =
418 thunk_AddCredentialsW;
419 if (inFnTableA->QueryCredentialsAttributesA)
420 fnTableW->QueryCredentialsAttributesW =
421 thunk_QueryCredentialsAttributesW;
422 if (inFnTableA->QueryContextAttributesA)
423 fnTableW->QueryContextAttributesW =
424 thunk_QueryContextAttributesW;
425 if (inFnTableA->SetContextAttributesA)
426 fnTableW->SetContextAttributesW =
427 thunk_SetContextAttributesW;
428 /* this can't be thunked, there's no extra param to know which
429 * package to forward to */
430 fnTableW->EnumerateSecurityPackagesW = NULL;
431 /* functions with no thunks needed */
432 fnTableW->AcceptSecurityContext = inFnTableA->AcceptSecurityContext;
433 fnTableW->CompleteAuthToken = inFnTableA->CompleteAuthToken;
434 fnTableW->DeleteSecurityContext = inFnTableA->DeleteSecurityContext;
435 fnTableW->ImpersonateSecurityContext =
436 inFnTableA->ImpersonateSecurityContext;
437 fnTableW->RevertSecurityContext = inFnTableA->RevertSecurityContext;
438 fnTableW->MakeSignature = inFnTableA->MakeSignature;
439 fnTableW->VerifySignature = inFnTableA->VerifySignature;
440 fnTableW->FreeContextBuffer = inFnTableA->FreeContextBuffer;
441 fnTableW->QuerySecurityPackageInfoW =
442 QuerySecurityPackageInfoW;
443 fnTableW->ExportSecurityContext =
444 inFnTableA->ExportSecurityContext;
445 fnTableW->QuerySecurityContextToken =
446 inFnTableA->QuerySecurityContextToken;
447 fnTableW->EncryptMessage = inFnTableA->EncryptMessage;
448 fnTableW->DecryptMessage = inFnTableA->DecryptMessage;
453 static void _copyPackageInfo(PSecPkgInfoW info, PSecPkgInfoA inInfoA,
454 PSecPkgInfoW inInfoW)
456 if (info && (inInfoA || inInfoW))
458 /* odd, I know, but up until Name and Comment the structures are
459 * identical
461 memcpy(info, inInfoW ? inInfoW : (PSecPkgInfoW)inInfoA, sizeof(*info));
462 if (inInfoW)
464 info->Name = SECUR32_strdupW(inInfoW->Name);
465 info->Comment = SECUR32_strdupW(inInfoW->Comment);
467 else
469 info->Name = SECUR32_AllocWideFromMultiByte(inInfoA->Name);
470 info->Comment = SECUR32_AllocWideFromMultiByte(inInfoA->Comment);
475 static void _tryLoadProvider(PWSTR moduleName)
477 HMODULE lib = LoadLibraryW(moduleName);
479 if (lib)
481 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
482 (INIT_SECURITY_INTERFACE_W)GetProcAddress(lib,
483 SECURITY_ENTRYPOINT_ANSIW);
484 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
485 (INIT_SECURITY_INTERFACE_A)GetProcAddress(lib,
486 SECURITY_ENTRYPOINT_ANSIA);
488 TRACE("loaded %s, InitSecurityInterfaceA is %p, InitSecurityInterfaceW is %p\n",
489 debugstr_w(moduleName), pInitSecurityInterfaceA,
490 pInitSecurityInterfaceW);
491 if (pInitSecurityInterfaceW || pInitSecurityInterfaceA)
493 PSecurityFunctionTableA fnTableA = NULL;
494 PSecurityFunctionTableW fnTableW = NULL;
495 ULONG toAdd = 0;
496 PSecPkgInfoA infoA = NULL;
497 PSecPkgInfoW infoW = NULL;
498 SECURITY_STATUS ret = SEC_E_OK;
500 if (pInitSecurityInterfaceA)
501 fnTableA = pInitSecurityInterfaceA();
502 if (pInitSecurityInterfaceW)
503 fnTableW = pInitSecurityInterfaceW();
504 if (fnTableW && fnTableW->EnumerateSecurityPackagesW)
505 ret = fnTableW->EnumerateSecurityPackagesW(&toAdd, &infoW);
506 else if (fnTableA && fnTableA->EnumerateSecurityPackagesA)
507 ret = fnTableA->EnumerateSecurityPackagesA(&toAdd, &infoA);
508 if (ret == SEC_E_OK && toAdd > 0 && (infoW || infoA))
510 providerTable = _resizeProviderTable(providerTable,
511 providerTable ? providerTable->numProviders + 1 : 1);
512 packageTable = _resizePackageTable(packageTable,
513 packageTable ? packageTable->numPackages + toAdd : toAdd);
514 if (providerTable && packageTable)
516 ULONG i;
517 SecureProvider *provider =
518 &providerTable->table[providerTable->numProviders];
520 EnterCriticalSection(&cs);
521 provider->moduleName = SECUR32_strdupW(moduleName);
522 provider->lib = NULL;
523 for (i = 0; i < toAdd; i++)
525 SecurePackage *package =
526 &packageTable->table[packageTable->numPackages + i];
528 package->provider = provider;
529 _copyPackageInfo(&package->infoW,
530 infoA ? &infoA[i] : NULL,
531 infoW ? &infoW[i] : NULL);
533 packageTable->numPackages += toAdd;
534 providerTable->numProviders++;
535 LeaveCriticalSection(&cs);
537 if (infoW)
538 fnTableW->FreeContextBuffer(infoW);
539 else
540 fnTableA->FreeContextBuffer(infoA);
543 FreeLibrary(lib);
545 else
546 WARN("failed to load %s\n", debugstr_w(moduleName));
549 static WCHAR securityProvidersKeyW[] = {
550 'S','Y','S','T','E','M','\\','C','u','r','r','e','n','t','C','o','n','t','r',
551 'o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','S','e','c','u','r',
552 'i','t','y','P','r','o','v','i','d','e','r','s','\0'
554 static const WCHAR securityProvidersW[] = {
555 'S','e','c','u','r','i','t','y','P','r','o','v','i','d','e','r','s',0
558 static void SECUR32_initializeProviders(void)
560 HKEY key;
561 long apiRet;
563 TRACE("\n");
564 InitializeCriticalSection(&cs);
565 apiRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, securityProvidersKeyW, 0,
566 KEY_READ, &key);
567 if (apiRet == ERROR_SUCCESS)
569 WCHAR securityPkgNames[MAX_PATH]; /* arbitrary len */
570 DWORD size = sizeof(securityPkgNames) / sizeof(WCHAR), type;
572 apiRet = RegQueryValueExW(key, securityProvidersW, NULL, &type,
573 (PBYTE)securityPkgNames, &size);
574 if (apiRet == ERROR_SUCCESS && type == REG_SZ)
576 WCHAR *ptr;
578 for (ptr = securityPkgNames;
579 ptr < (PWSTR)((PBYTE)securityPkgNames + size); )
581 WCHAR *comma;
583 for (comma = ptr; *comma && *comma != ','; comma++)
585 if (*comma == ',')
586 *comma = '\0';
587 for (; *ptr && isspace(*ptr) && ptr < securityPkgNames + size;
588 ptr++)
590 if (*ptr)
591 _tryLoadProvider(ptr);
592 ptr += lstrlenW(ptr) + 1;
595 RegCloseKey(key);
599 SecurePackage *SECUR32_findPackageW(PWSTR packageName)
601 SecurePackage *ret;
603 if (packageTable && packageName)
605 DWORD i;
607 for (i = 0, ret = NULL; !ret && i < packageTable->numPackages; i++)
608 if (!lstrcmpiW(packageTable->table[i].infoW.Name, packageName))
609 ret = &packageTable->table[i];
610 if (ret && ret->provider && !ret->provider->lib)
612 ret->provider->lib = LoadLibraryW(ret->provider->moduleName);
613 if (ret->provider->lib)
615 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
616 (INIT_SECURITY_INTERFACE_W)GetProcAddress(ret->provider->lib,
617 SECURITY_ENTRYPOINT_ANSIW);
618 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
619 (INIT_SECURITY_INTERFACE_A)GetProcAddress(ret->provider->lib,
620 SECURITY_ENTRYPOINT_ANSIA);
621 PSecurityFunctionTableA fnTableA = NULL;
622 PSecurityFunctionTableW fnTableW = NULL;
624 if (pInitSecurityInterfaceA)
625 fnTableA = pInitSecurityInterfaceA();
626 if (pInitSecurityInterfaceW)
627 fnTableW = pInitSecurityInterfaceW();
628 _makeFnTableA(&ret->provider->fnTableA, fnTableA, fnTableW);
629 _makeFnTableW(&ret->provider->fnTableW, fnTableA, fnTableW);
631 else
632 ret = NULL;
635 else
636 ret = NULL;
637 return ret;
640 SecurePackage *SECUR32_findPackageA(PSTR packageName)
642 SecurePackage *ret;
644 if (packageTable && packageName)
646 UNICODE_STRING package;
648 RtlCreateUnicodeStringFromAsciiz(&package, packageName);
649 ret = SECUR32_findPackageW(package.Buffer);
650 RtlFreeUnicodeString(&package);
652 else
653 ret = NULL;
654 return ret;
657 static void SECUR32_freeProviders(void)
659 DWORD i;
661 TRACE("\n");
662 EnterCriticalSection(&cs);
663 if (packageTable)
665 for (i = 0; i < packageTable->numPackages; i++)
667 SECUR32_FREE(packageTable->table[i].infoW.Name);
668 SECUR32_FREE(packageTable->table[i].infoW.Comment);
670 HeapFree(GetProcessHeap(), 0, packageTable);
671 packageTable = NULL;
673 if (providerTable)
675 for (i = 0; i < providerTable->numProviders; i++)
677 if (providerTable->table[i].moduleName)
678 SECUR32_FREE(providerTable->table[i].moduleName);
679 if (providerTable->table[i].lib)
680 FreeLibrary(providerTable->table[i].lib);
682 HeapFree(GetProcessHeap(), 0, providerTable);
683 providerTable = NULL;
685 LeaveCriticalSection(&cs);
686 DeleteCriticalSection(&cs);
689 /* Doh--if pv was allocated by a crypto package, this may not be correct.
690 * The sample ssp seems to use LocalAlloc/LocalFee, but there doesn't seem to
691 * be any guarantee, nor is there an alloc function in secur32.
693 SECURITY_STATUS SEC_ENTRY FreeContextBuffer(PVOID pv)
695 SECURITY_STATUS ret;
697 /* as it turns out, SECURITY_STATUSes are actually HRESULTS */
698 if (pv)
700 if (SECUR32_FREE(pv) == NULL)
701 ret = SEC_E_OK;
702 else
703 ret = HRESULT_FROM_WIN32(GetLastError());
705 else
706 ret = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
707 return ret;
710 SECURITY_STATUS SEC_ENTRY EnumerateSecurityPackagesW(PULONG pcPackages,
711 PSecPkgInfoW *ppPackageInfo)
713 SECURITY_STATUS ret = SEC_E_OK;
715 /* windows just crashes if pcPackages or ppPackageInfo is NULL, so will I */
716 *pcPackages = 0;
717 EnterCriticalSection(&cs);
718 if (packageTable)
720 ULONG i;
721 size_t bytesNeeded;
723 bytesNeeded = packageTable->numPackages * sizeof(SecPkgInfoW);
724 for (i = 0; i < packageTable->numPackages; i++)
726 if (packageTable->table[i].infoW.Name)
727 bytesNeeded +=
728 (lstrlenW(packageTable->table[i].infoW.Name) + 1) *
729 sizeof(WCHAR);
730 if (packageTable->table[i].infoW.Comment)
731 bytesNeeded +=
732 (lstrlenW(packageTable->table[i].infoW.Comment) + 1) *
733 sizeof(WCHAR);
735 if (bytesNeeded)
737 *ppPackageInfo = (PSecPkgInfoW)SECUR32_ALLOC(bytesNeeded);
738 if (*ppPackageInfo)
740 PWSTR nextString;
742 *pcPackages = packageTable->numPackages;
743 nextString = (PWSTR)((PBYTE)*ppPackageInfo +
744 packageTable->numPackages * sizeof(SecPkgInfoW));
745 for (i = 0; i < packageTable->numPackages; i++)
747 PSecPkgInfoW pkgInfo = *ppPackageInfo + i;
749 memcpy(pkgInfo, &packageTable->table[i].infoW,
750 sizeof(SecPkgInfoW));
751 if (packageTable->table[i].infoW.Name)
753 pkgInfo->Name = nextString;
754 lstrcpyW(nextString, packageTable->table[i].infoW.Name);
755 nextString += lstrlenW(nextString) + 1;
757 else
758 pkgInfo->Name = NULL;
759 if (packageTable->table[i].infoW.Comment)
761 pkgInfo->Comment = nextString;
762 lstrcpyW(nextString,
763 packageTable->table[i].infoW.Comment);
764 nextString += lstrlenW(nextString) + 1;
766 else
767 pkgInfo->Comment = NULL;
770 else
771 ret = SEC_E_INSUFFICIENT_MEMORY;
774 LeaveCriticalSection(&cs);
775 return ret;
778 /* Converts info (which is assumed to be an array of cPackages SecPkgInfoW
779 * structures) into an array of SecPkgInfoA structures, which it returns.
781 static PSecPkgInfoA thunk_PSecPkgInfoWToA(ULONG cPackages,
782 const PSecPkgInfoW info)
784 PSecPkgInfoA ret;
786 if (info)
788 size_t bytesNeeded = cPackages * sizeof(SecPkgInfoA);
789 ULONG i;
791 for (i = 0; i < cPackages; i++)
793 if (info[i].Name)
794 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Name,
795 -1, NULL, 0, NULL, NULL);
796 if (info[i].Comment)
797 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Comment,
798 -1, NULL, 0, NULL, NULL);
800 ret = (PSecPkgInfoA)SECUR32_ALLOC(bytesNeeded);
801 if (ret)
803 PSTR nextString;
805 nextString = (PSTR)((PBYTE)ret + cPackages * sizeof(SecPkgInfoA));
806 for (i = 0; i < cPackages; i++)
808 PSecPkgInfoA pkgInfo = ret + i;
809 int bytes;
811 memcpy(pkgInfo, &info[i], sizeof(SecPkgInfoA));
812 if (info[i].Name)
814 pkgInfo->Name = nextString;
815 /* just repeat back to WideCharToMultiByte how many bytes
816 * it requires, since we asked it earlier
818 bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
819 NULL, 0, NULL, NULL);
820 WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
821 pkgInfo->Name, bytes, NULL, NULL);
822 nextString += lstrlenA(nextString) + 1;
824 else
825 pkgInfo->Name = NULL;
826 if (info[i].Comment)
828 pkgInfo->Comment = nextString;
829 /* just repeat back to WideCharToMultiByte how many bytes
830 * it requires, since we asked it earlier
832 bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
833 NULL, 0, NULL, NULL);
834 WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
835 pkgInfo->Comment, bytes, NULL, NULL);
836 nextString += lstrlenA(nextString) + 1;
838 else
839 pkgInfo->Comment = NULL;
843 else
844 ret = NULL;
845 return ret;
848 SECURITY_STATUS SEC_ENTRY EnumerateSecurityPackagesA(PULONG pcPackages,
849 PSecPkgInfoA *ppPackageInfo)
851 SECURITY_STATUS ret;
852 PSecPkgInfoW info;
854 ret = EnumerateSecurityPackagesW(pcPackages, &info);
855 if (ret == SEC_E_OK && *pcPackages && info)
857 *ppPackageInfo = thunk_PSecPkgInfoWToA(*pcPackages, info);
858 if (*pcPackages && !*ppPackageInfo)
860 *pcPackages = 0;
861 ret = SEC_E_INSUFFICIENT_MEMORY;
863 FreeContextBuffer(info);
865 return ret;
868 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
870 if (fdwReason == DLL_PROCESS_ATTACH)
872 DisableThreadLibraryCalls(hinstDLL);
873 SECUR32_initializeProviders();
875 else if (fdwReason == DLL_PROCESS_DETACH)
877 SECUR32_freeProviders();
880 return TRUE;