1 /* Copyright (C) 2004 Juan Lang
2 *
3 * This file implements loading of SSP DLLs.
4 *
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.
9 *
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.
14 *
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
18 */
19
20 #include "precomp.h"
21
22 #include <assert.h>
23 #include <lsass/lsass.h>
24
25 #include <wine/debug.h>
26 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
27
28 #define UNLEN 256
29
30 typedef struct _SecurePackageTable
31 {
32 DWORD numPackages;
33 DWORD numAllocated;
34 struct list table;
35 } SecurePackageTable;
36
37 typedef struct _SecureProviderTable
38 {
39 DWORD numProviders;
40 DWORD numAllocated;
41 struct list table;
42 } SecureProviderTable;
43
44 static void SECUR32_initializeProviders(void);
45 /* static */ void SECUR32_freeProviders(void);
46
47 static CRITICAL_SECTION cs;
48 static CRITICAL_SECTION_DEBUG cs_debug =
49 {
50 0, 0, &cs,
51 { &cs_debug.ProcessLocksList, &cs_debug.ProcessLocksList },
52 0, 0, { (DWORD_PTR)(__FILE__ ": cs") }
53 };
54 static CRITICAL_SECTION cs = { &cs_debug, -1, 0, 0, 0, 0 };
55 static SecurePackageTable *packageTable = NULL;
56 static SecureProviderTable *providerTable = NULL;
57
58 static SecurityFunctionTableA securityFunctionTableA = {
59 SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
60 EnumerateSecurityPackagesA,
61 QueryCredentialsAttributesA,
62 AcquireCredentialsHandleA,
63 FreeCredentialsHandle,
64 NULL, /* Reserved2 */
65 InitializeSecurityContextA,
66 AcceptSecurityContext,
67 CompleteAuthToken,
68 DeleteSecurityContext,
69 ApplyControlToken,
70 QueryContextAttributesA,
71 ImpersonateSecurityContext,
72 RevertSecurityContext,
73 MakeSignature,
74 VerifySignature,
75 FreeContextBuffer,
76 QuerySecurityPackageInfoA,
77 EncryptMessage, /* Reserved3 */
78 DecryptMessage, /* Reserved4 */
79 ExportSecurityContext,
80 ImportSecurityContextA,
81 AddCredentialsA,
82 NULL, /* Reserved8 */
83 QuerySecurityContextToken,
84 EncryptMessage,
85 DecryptMessage,
86 NULL
87 };
88
89 static SecurityFunctionTableW securityFunctionTableW = {
90 SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
91 EnumerateSecurityPackagesW,
92 QueryCredentialsAttributesW,
93 AcquireCredentialsHandleW,
94 FreeCredentialsHandle,
95 NULL, /* Reserved2 */
96 InitializeSecurityContextW,
97 AcceptSecurityContext,
98 CompleteAuthToken,
99 DeleteSecurityContext,
100 ApplyControlToken,
101 QueryContextAttributesW,
102 ImpersonateSecurityContext,
103 RevertSecurityContext,
104 MakeSignature,
105 VerifySignature,
106 FreeContextBuffer,
107 QuerySecurityPackageInfoW,
108 EncryptMessage, /* Reserved3 */
109 DecryptMessage, /* Reserved4 */
110 ExportSecurityContext,
111 ImportSecurityContextW,
112 AddCredentialsW,
113 NULL, /* Reserved8 */
114 QuerySecurityContextToken,
115 EncryptMessage,
116 DecryptMessage,
117 NULL
118 };
119
120 /***********************************************************************
121 * InitSecurityInterfaceA (SECUR32.@)
122 */
InitSecurityInterfaceA(void)123 PSecurityFunctionTableA WINAPI InitSecurityInterfaceA(void)
124 {
125 TRACE("InitSecurityInterfaceA() called\n");
126 return &securityFunctionTableA;
127 }
128
129 /***********************************************************************
130 * InitSecurityInterfaceW (SECUR32.@)
131 */
InitSecurityInterfaceW(void)132 PSecurityFunctionTableW WINAPI InitSecurityInterfaceW(void)
133 {
134 TRACE("InitSecurityInterfaceW() called\n");
135 return &securityFunctionTableW;
136 }
137
SECUR32_strdupW(PCWSTR str)138 static PWSTR SECUR32_strdupW(PCWSTR str)
139 {
140 PWSTR ret;
141
142 if (str)
143 {
144 ret = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(str) + 1) * sizeof(WCHAR));
145 if (ret)
146 lstrcpyW(ret, str);
147 }
148 else
149 ret = NULL;
150 return ret;
151 }
152
SECUR32_AllocWideFromMultiByte(PCSTR str)153 PWSTR SECUR32_AllocWideFromMultiByte(PCSTR str)
154 {
155 PWSTR ret;
156
157 if (str)
158 {
159 int charsNeeded = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
160
161 if (charsNeeded)
162 {
163 ret = HeapAlloc(GetProcessHeap(), 0, charsNeeded * sizeof(WCHAR));
164 if (ret)
165 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, charsNeeded);
166 }
167 else
168 ret = NULL;
169 }
170 else
171 ret = NULL;
172 return ret;
173 }
174
SECUR32_AllocMultiByteFromWide(PCWSTR str)175 PSTR SECUR32_AllocMultiByteFromWide(PCWSTR str)
176 {
177 PSTR ret;
178
179 if (str)
180 {
181 int charsNeeded = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0,
182 NULL, NULL);
183
184 if (charsNeeded)
185 {
186 ret = HeapAlloc(GetProcessHeap(), 0, charsNeeded);
187 if (ret)
188 WideCharToMultiByte(CP_ACP, 0, str, -1, ret, charsNeeded,
189 NULL, NULL);
190 }
191 else
192 ret = NULL;
193 }
194 else
195 ret = NULL;
196 return ret;
197 }
198
_makeFnTableA(PSecurityFunctionTableA fnTableA,const SecurityFunctionTableA * inFnTableA,const SecurityFunctionTableW * inFnTableW)199 static void _makeFnTableA(PSecurityFunctionTableA fnTableA,
200 const SecurityFunctionTableA *inFnTableA,
201 const SecurityFunctionTableW *inFnTableW)
202 {
203 if (fnTableA)
204 {
205 if (inFnTableA)
206 {
207 /* The size of the version 1 table is based on platform sdk's
208 * sspi.h, though the sample ssp also provided with platform sdk
209 * implies only functions through QuerySecurityPackageInfoA are
210 * implemented (yikes)
211 */
212 size_t tableSize = inFnTableA->dwVersion == 1 ?
213 (const BYTE *)&inFnTableA->SetContextAttributesA -
214 (const BYTE *)inFnTableA : sizeof(SecurityFunctionTableA);
215
216 memcpy(fnTableA, inFnTableA, tableSize);
217 /* override this, since we can do it internally anyway */
218 fnTableA->QuerySecurityPackageInfoA =
219 QuerySecurityPackageInfoA;
220 }
221 else if (inFnTableW)
222 {
223 /* functions with thunks */
224 if (inFnTableW->AcquireCredentialsHandleW)
225 fnTableA->AcquireCredentialsHandleA =
226 thunk_AcquireCredentialsHandleA;
227 if (inFnTableW->InitializeSecurityContextW)
228 fnTableA->InitializeSecurityContextA =
229 thunk_InitializeSecurityContextA;
230 if (inFnTableW->ImportSecurityContextW)
231 fnTableA->ImportSecurityContextA =
232 thunk_ImportSecurityContextA;
233 if (inFnTableW->AddCredentialsW)
234 fnTableA->AddCredentialsA =
235 thunk_AddCredentialsA;
236 if (inFnTableW->QueryCredentialsAttributesW)
237 fnTableA->QueryCredentialsAttributesA =
238 thunk_QueryCredentialsAttributesA;
239 if (inFnTableW->QueryContextAttributesW)
240 fnTableA->QueryContextAttributesA =
241 thunk_QueryContextAttributesA;
242 if (inFnTableW->SetContextAttributesW)
243 fnTableA->SetContextAttributesA =
244 thunk_SetContextAttributesA;
245 /* this can't be thunked, there's no extra param to know which
246 * package to forward to */
247 fnTableA->EnumerateSecurityPackagesA = NULL;
248 /* functions with no thunks needed */
249 fnTableA->AcceptSecurityContext = inFnTableW->AcceptSecurityContext;
250 fnTableA->CompleteAuthToken = inFnTableW->CompleteAuthToken;
251 fnTableA->DeleteSecurityContext = inFnTableW->DeleteSecurityContext;
252 fnTableA->ImpersonateSecurityContext =
253 inFnTableW->ImpersonateSecurityContext;
254 fnTableA->RevertSecurityContext = inFnTableW->RevertSecurityContext;
255 fnTableA->MakeSignature = inFnTableW->MakeSignature;
256 fnTableA->VerifySignature = inFnTableW->VerifySignature;
257 fnTableA->FreeContextBuffer = inFnTableW->FreeContextBuffer;
258 fnTableA->QuerySecurityPackageInfoA =
259 QuerySecurityPackageInfoA;
260 fnTableA->ExportSecurityContext =
261 inFnTableW->ExportSecurityContext;
262 fnTableA->QuerySecurityContextToken =
263 inFnTableW->QuerySecurityContextToken;
264 fnTableA->EncryptMessage = inFnTableW->EncryptMessage;
265 fnTableA->DecryptMessage = inFnTableW->DecryptMessage;
266 }
267 }
268 }
269
_makeFnTableW(PSecurityFunctionTableW fnTableW,const SecurityFunctionTableA * inFnTableA,const SecurityFunctionTableW * inFnTableW)270 static void _makeFnTableW(PSecurityFunctionTableW fnTableW,
271 const SecurityFunctionTableA *inFnTableA,
272 const SecurityFunctionTableW *inFnTableW)
273 {
274 if (fnTableW)
275 {
276 if (inFnTableW)
277 {
278 /* The size of the version 1 table is based on platform sdk's
279 * sspi.h, though the sample ssp also provided with platform sdk
280 * implies only functions through QuerySecurityPackageInfoA are
281 * implemented (yikes)
282 */
283 size_t tableSize = inFnTableW->dwVersion == 1 ?
284 (const BYTE *)&inFnTableW->SetContextAttributesW -
285 (const BYTE *)inFnTableW : sizeof(SecurityFunctionTableW);
286
287 memcpy(fnTableW, inFnTableW, tableSize);
288 /* override this, since we can do it internally anyway */
289 fnTableW->QuerySecurityPackageInfoW =
290 QuerySecurityPackageInfoW;
291 }
292 else if (inFnTableA)
293 {
294 /* functions with thunks */
295 if (inFnTableA->AcquireCredentialsHandleA)
296 fnTableW->AcquireCredentialsHandleW =
297 thunk_AcquireCredentialsHandleW;
298 if (inFnTableA->InitializeSecurityContextA)
299 fnTableW->InitializeSecurityContextW =
300 thunk_InitializeSecurityContextW;
301 if (inFnTableA->ImportSecurityContextA)
302 fnTableW->ImportSecurityContextW =
303 thunk_ImportSecurityContextW;
304 if (inFnTableA->AddCredentialsA)
305 fnTableW->AddCredentialsW =
306 thunk_AddCredentialsW;
307 if (inFnTableA->QueryCredentialsAttributesA)
308 fnTableW->QueryCredentialsAttributesW =
309 thunk_QueryCredentialsAttributesW;
310 if (inFnTableA->QueryContextAttributesA)
311 fnTableW->QueryContextAttributesW =
312 thunk_QueryContextAttributesW;
313 if (inFnTableA->SetContextAttributesA)
314 fnTableW->SetContextAttributesW =
315 thunk_SetContextAttributesW;
316 /* this can't be thunked, there's no extra param to know which
317 * package to forward to */
318 fnTableW->EnumerateSecurityPackagesW = NULL;
319 /* functions with no thunks needed */
320 fnTableW->AcceptSecurityContext = inFnTableA->AcceptSecurityContext;
321 fnTableW->CompleteAuthToken = inFnTableA->CompleteAuthToken;
322 fnTableW->DeleteSecurityContext = inFnTableA->DeleteSecurityContext;
323 fnTableW->ImpersonateSecurityContext =
324 inFnTableA->ImpersonateSecurityContext;
325 fnTableW->RevertSecurityContext = inFnTableA->RevertSecurityContext;
326 fnTableW->MakeSignature = inFnTableA->MakeSignature;
327 fnTableW->VerifySignature = inFnTableA->VerifySignature;
328 fnTableW->FreeContextBuffer = inFnTableA->FreeContextBuffer;
329 fnTableW->QuerySecurityPackageInfoW =
330 QuerySecurityPackageInfoW;
331 fnTableW->ExportSecurityContext =
332 inFnTableA->ExportSecurityContext;
333 fnTableW->QuerySecurityContextToken =
334 inFnTableA->QuerySecurityContextToken;
335 fnTableW->EncryptMessage = inFnTableA->EncryptMessage;
336 fnTableW->DecryptMessage = inFnTableA->DecryptMessage;
337 }
338 }
339 }
340
_copyPackageInfo(PSecPkgInfoW info,const SecPkgInfoA * inInfoA,const SecPkgInfoW * inInfoW)341 static void _copyPackageInfo(PSecPkgInfoW info, const SecPkgInfoA *inInfoA,
342 const SecPkgInfoW *inInfoW)
343 {
344 if (info && (inInfoA || inInfoW))
345 {
346 /* odd, I know, but up until Name and Comment the structures are
347 * identical
348 */
349 memcpy(info, inInfoW ? inInfoW : (const SecPkgInfoW *)inInfoA, sizeof(*info));
350 if (inInfoW)
351 {
352 info->Name = SECUR32_strdupW(inInfoW->Name);
353 info->Comment = SECUR32_strdupW(inInfoW->Comment);
354 }
355 else
356 {
357 info->Name = SECUR32_AllocWideFromMultiByte(inInfoA->Name);
358 info->Comment = SECUR32_AllocWideFromMultiByte(inInfoA->Comment);
359 }
360 }
361 }
362
363 // static
SECUR32_addProvider(const SecurityFunctionTableA * fnTableA,const SecurityFunctionTableW * fnTableW,PCWSTR moduleName)364 SecureProvider *SECUR32_addProvider(const SecurityFunctionTableA *fnTableA,
365 const SecurityFunctionTableW *fnTableW, PCWSTR moduleName)
366 {
367 SecureProvider *ret;
368
369 EnterCriticalSection(&cs);
370
371 if (!providerTable)
372 {
373 providerTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SecureProviderTable));
374 if (!providerTable)
375 {
376 LeaveCriticalSection(&cs);
377 return NULL;
378 }
379
380 list_init(&providerTable->table);
381 }
382
383 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(SecureProvider));
384 if (!ret)
385 {
386 LeaveCriticalSection(&cs);
387 return NULL;
388 }
389
390 list_add_tail(&providerTable->table, &ret->entry);
391 ret->lib = NULL;
392
393 if (fnTableA || fnTableW)
394 {
395 ret->moduleName = moduleName ? SECUR32_strdupW(moduleName) : NULL;
396 _makeFnTableA(&ret->fnTableA, fnTableA, fnTableW);
397 _makeFnTableW(&ret->fnTableW, fnTableA, fnTableW);
398 ret->loaded = !moduleName;
399 }
400 else
401 {
402 ret->moduleName = SECUR32_strdupW(moduleName);
403 ret->loaded = FALSE;
404 }
405
406 LeaveCriticalSection(&cs);
407 return ret;
408 }
409
410 // static
SECUR32_addPackages(SecureProvider * provider,ULONG toAdd,const SecPkgInfoA * infoA,const SecPkgInfoW * infoW)411 void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd,
412 const SecPkgInfoA *infoA, const SecPkgInfoW *infoW)
413 {
414 ULONG i;
415
416 assert(provider);
417 assert(infoA || infoW);
418
419 EnterCriticalSection(&cs);
420
421 if (!packageTable)
422 {
423 packageTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackageTable));
424 if (!packageTable)
425 {
426 LeaveCriticalSection(&cs);
427 return;
428 }
429
430 packageTable->numPackages = 0;
431 list_init(&packageTable->table);
432 }
433
434 for (i = 0; i < toAdd; i++)
435 {
436 SecurePackage *package = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackage));
437 if (!package)
438 continue;
439
440 list_add_tail(&packageTable->table, &package->entry);
441
442 package->provider = provider;
443 _copyPackageInfo(&package->infoW,
444 infoA ? &infoA[i] : NULL,
445 infoW ? &infoW[i] : NULL);
446 }
447 packageTable->numPackages += toAdd;
448
449 LeaveCriticalSection(&cs);
450 }
451
_tryLoadProvider(PWSTR moduleName)452 static void _tryLoadProvider(PWSTR moduleName)
453 {
454 HMODULE lib = LoadLibraryW(moduleName);
455
456 if (lib)
457 {
458 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
459 (INIT_SECURITY_INTERFACE_W)GetProcAddress(lib,
460 SECURITY_ENTRYPOINT_ANSIW);
461 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
462 (INIT_SECURITY_INTERFACE_A)GetProcAddress(lib,
463 SECURITY_ENTRYPOINT_ANSIA);
464
465 TRACE("loaded %s, InitSecurityInterfaceA is %p, InitSecurityInterfaceW is %p\n",
466 debugstr_w(moduleName), pInitSecurityInterfaceA,
467 pInitSecurityInterfaceW);
468 if (pInitSecurityInterfaceW || pInitSecurityInterfaceA)
469 {
470 PSecurityFunctionTableA fnTableA = NULL;
471 PSecurityFunctionTableW fnTableW = NULL;
472 ULONG toAdd = 0;
473 PSecPkgInfoA infoA = NULL;
474 PSecPkgInfoW infoW = NULL;
475 SECURITY_STATUS ret = SEC_E_OK;
476
477 if (pInitSecurityInterfaceA)
478 fnTableA = pInitSecurityInterfaceA();
479 if (pInitSecurityInterfaceW)
480 fnTableW = pInitSecurityInterfaceW();
481 if (fnTableW && fnTableW->EnumerateSecurityPackagesW)
482 {
483 if (fnTableW != &securityFunctionTableW)
484 ret = fnTableW->EnumerateSecurityPackagesW(&toAdd, &infoW);
485 else
486 TRACE("%s has built-in providers, skip adding\n", debugstr_w(moduleName));
487 }
488 else if (fnTableA && fnTableA->EnumerateSecurityPackagesA)
489 {
490 if (fnTableA != &securityFunctionTableA)
491 ret = fnTableA->EnumerateSecurityPackagesA(&toAdd, &infoA);
492 else
493 TRACE("%s has built-in providers, skip adding\n", debugstr_w(moduleName));
494 }
495 if (ret == SEC_E_OK && toAdd > 0 && (infoW || infoA))
496 {
497 SecureProvider *provider = SECUR32_addProvider(NULL, NULL,
498 moduleName);
499
500 if (provider)
501 SECUR32_addPackages(provider, toAdd, infoA, infoW);
502 if (infoW)
503 fnTableW->FreeContextBuffer(infoW);
504 else
505 fnTableA->FreeContextBuffer(infoA);
506 }
507 }
508 FreeLibrary(lib);
509 }
510 else
511 WARN("failed to load %s\n", debugstr_w(moduleName));
512 }
513
514 static const WCHAR securityProvidersKeyW[] = {
515 'S','Y','S','T','E','M','\\','C','u','r','r','e','n','t','C','o','n','t','r',
516 'o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','S','e','c','u','r',
517 'i','t','y','P','r','o','v','i','d','e','r','s','\0'
518 };
519 static const WCHAR securityProvidersW[] = {
520 'S','e','c','u','r','i','t','y','P','r','o','v','i','d','e','r','s',0
521 };
522
SECUR32_initializeProviders(void)523 static void SECUR32_initializeProviders(void)
524 {
525 HKEY key;
526 LSTATUS apiRet;
527
528 /* Now load providers from registry */
529 apiRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, securityProvidersKeyW, 0,
530 KEY_READ, &key);
531 if (apiRet == ERROR_SUCCESS)
532 {
533 WCHAR securityPkgNames[MAX_PATH]; /* arbitrary len */
534 DWORD size = sizeof(securityPkgNames), type;
535
536 apiRet = RegQueryValueExW(key, securityProvidersW, NULL, &type,
537 (PBYTE)securityPkgNames, &size);
538 if (apiRet == ERROR_SUCCESS && type == REG_SZ)
539 {
540 WCHAR *ptr;
541
542 size = size / sizeof(WCHAR);
543 for (ptr = securityPkgNames;
544 ptr < securityPkgNames + size; )
545 {
546 WCHAR *comma;
547
548 for (comma = ptr; *comma && *comma != ','; comma++)
549 ;
550 if (*comma == ',')
551 *comma = '\0';
552 for (; *ptr && isspace(*ptr) && ptr < securityPkgNames + size;
553 ptr++)
554 ;
555 if (*ptr)
556 _tryLoadProvider(ptr);
557 ptr += lstrlenW(ptr) + 1;
558 }
559 }
560 RegCloseKey(key);
561 }
562
563 /* Now load the built-in providers (in Wine, this is done before the registry loading) */
564 #ifdef __REACTOS__
565 /// FIXME: Interim Wine code until we get Samuel's rewrite!
566 /* First load built-in providers */
567 SECUR32_initNTLMSP();
568 SECUR32_initKerberosSP();
569 /* Load the Negotiate provider last so apps stumble over the working NTLM
570 * provider first. Attempting to fix bug #16905 while keeping the
571 * application reported on wine-users on 2006-09-12 working. */
572 SECUR32_initNegotiateSP();
573 #endif
574
575 }
576
SECUR32_findPackageW(PCWSTR packageName)577 SecurePackage *SECUR32_findPackageW(PCWSTR packageName)
578 {
579 SecurePackage *ret = NULL;
580 BOOL matched = FALSE;
581
582 #ifdef __REACTOS__
583 if (!packageTable)
584 SECUR32_initializeProviders();
585 #endif
586
587 if (packageTable && packageName)
588 {
589 LIST_FOR_EACH_ENTRY(ret, &packageTable->table, SecurePackage, entry)
590 {
591 matched = !lstrcmpiW(ret->infoW.Name, packageName);
592 if (matched)
593 break;
594 }
595
596 if (!matched)
597 return NULL;
598
599 if (ret->provider && !ret->provider->loaded)
600 {
601 ret->provider->lib = LoadLibraryW(ret->provider->moduleName);
602 if (ret->provider->lib)
603 {
604 INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
605 (INIT_SECURITY_INTERFACE_W)GetProcAddress(ret->provider->lib,
606 SECURITY_ENTRYPOINT_ANSIW);
607 INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
608 (INIT_SECURITY_INTERFACE_A)GetProcAddress(ret->provider->lib,
609 SECURITY_ENTRYPOINT_ANSIA);
610 PSecurityFunctionTableA fnTableA = NULL;
611 PSecurityFunctionTableW fnTableW = NULL;
612
613 if (pInitSecurityInterfaceA)
614 fnTableA = pInitSecurityInterfaceA();
615 if (pInitSecurityInterfaceW)
616 fnTableW = pInitSecurityInterfaceW();
617 /* don't update built-in SecurityFunctionTable */
618 if (fnTableA != &securityFunctionTableA)
619 _makeFnTableA(&ret->provider->fnTableA, fnTableA, fnTableW);
620 if (fnTableW != &securityFunctionTableW)
621 _makeFnTableW(&ret->provider->fnTableW, fnTableA, fnTableW);
622 ret->provider->loaded = TRUE;
623 }
624 else
625 ret = NULL;
626 }
627 }
628 return ret;
629 }
630
SECUR32_findPackageA(PCSTR packageName)631 SecurePackage *SECUR32_findPackageA(PCSTR packageName)
632 {
633 SecurePackage *ret;
634
635 if (packageName)
636 {
637 UNICODE_STRING package;
638
639 RtlCreateUnicodeStringFromAsciiz(&package, packageName);
640 ret = SECUR32_findPackageW(package.Buffer);
641 RtlFreeUnicodeString(&package);
642 }
643 else
644 ret = NULL;
645 return ret;
646 }
647
SECUR32_freeProviders(void)648 /* static */ void SECUR32_freeProviders(void)
649 {
650 TRACE("\n");
651 EnterCriticalSection(&cs);
652
653 #ifndef __REACTOS__
654 SECUR32_deinitSchannelSP();
655 #endif
656
657 if (packageTable)
658 {
659 SecurePackage *package, *package_next;
660 LIST_FOR_EACH_ENTRY_SAFE(package, package_next, &packageTable->table,
661 SecurePackage, entry)
662 {
663 HeapFree(GetProcessHeap(), 0, package->infoW.Name);
664 HeapFree(GetProcessHeap(), 0, package->infoW.Comment);
665 HeapFree(GetProcessHeap(), 0, package);
666 }
667
668 HeapFree(GetProcessHeap(), 0, packageTable);
669 packageTable = NULL;
670 }
671
672 if (providerTable)
673 {
674 SecureProvider *provider, *provider_next;
675 LIST_FOR_EACH_ENTRY_SAFE(provider, provider_next, &providerTable->table,
676 SecureProvider, entry)
677 {
678 HeapFree(GetProcessHeap(), 0, provider->moduleName);
679 if (provider->lib)
680 FreeLibrary(provider->lib);
681 HeapFree(GetProcessHeap(), 0, provider);
682 }
683
684 HeapFree(GetProcessHeap(), 0, providerTable);
685 providerTable = NULL;
686 }
687
688 LeaveCriticalSection(&cs);
689 DeleteCriticalSection(&cs);
690 }
691
692 /***********************************************************************
693 * FreeContextBuffer (SECUR32.@)
694 *
695 * Doh--if pv was allocated by a crypto package, this may not be correct.
696 * The sample ssp seems to use LocalAlloc/LocalFee, but there doesn't seem to
697 * be any guarantee, nor is there an alloc function in secur32.
698 */
FreeContextBuffer(PVOID pv)699 SECURITY_STATUS WINAPI FreeContextBuffer(PVOID pv)
700 {
701 HeapFree(GetProcessHeap(), 0, pv);
702
703 return SEC_E_OK;
704 }
705
706 /***********************************************************************
707 * EnumerateSecurityPackagesW (SECUR32.@)
708 */
EnumerateSecurityPackagesW(PULONG pcPackages,PSecPkgInfoW * ppPackageInfo)709 SECURITY_STATUS WINAPI EnumerateSecurityPackagesW(PULONG pcPackages,
710 PSecPkgInfoW *ppPackageInfo)
711 {
712 SECURITY_STATUS ret = SEC_E_OK;
713
714 TRACE("(%p, %p)\n", pcPackages, ppPackageInfo);
715
716 #ifdef __REACTOS__
717 if (!packageTable)
718 SECUR32_initializeProviders();
719 #endif
720
721 /* windows just crashes if pcPackages or ppPackageInfo is NULL, so will I */
722 *pcPackages = 0;
723 EnterCriticalSection(&cs);
724 if (packageTable)
725 {
726 SecurePackage *package;
727 size_t bytesNeeded;
728
729 bytesNeeded = packageTable->numPackages * sizeof(SecPkgInfoW);
730 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
731 {
732 if (package->infoW.Name)
733 bytesNeeded += (lstrlenW(package->infoW.Name) + 1) * sizeof(WCHAR);
734 if (package->infoW.Comment)
735 bytesNeeded += (lstrlenW(package->infoW.Comment) + 1) * sizeof(WCHAR);
736 }
737 if (bytesNeeded)
738 {
739 *ppPackageInfo = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
740 if (*ppPackageInfo)
741 {
742 ULONG i = 0;
743 PWSTR nextString;
744
745 *pcPackages = packageTable->numPackages;
746 nextString = (PWSTR)((PBYTE)*ppPackageInfo +
747 packageTable->numPackages * sizeof(SecPkgInfoW));
748 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
749 {
750 PSecPkgInfoW pkgInfo = *ppPackageInfo + i++;
751
752 *pkgInfo = package->infoW;
753 if (package->infoW.Name)
754 {
755 TRACE("Name[%d] = %s\n", i - 1, debugstr_w(package->infoW.Name));
756 pkgInfo->Name = nextString;
757 lstrcpyW(nextString, package->infoW.Name);
758 nextString += lstrlenW(nextString) + 1;
759 }
760 else
761 pkgInfo->Name = NULL;
762 if (package->infoW.Comment)
763 {
764 TRACE("Comment[%d] = %s\n", i - 1, debugstr_w(package->infoW.Comment));
765 pkgInfo->Comment = nextString;
766 lstrcpyW(nextString, package->infoW.Comment);
767 nextString += lstrlenW(nextString) + 1;
768 }
769 else
770 pkgInfo->Comment = NULL;
771 }
772 }
773 else
774 ret = SEC_E_INSUFFICIENT_MEMORY;
775 }
776 }
777 LeaveCriticalSection(&cs);
778 TRACE("<-- 0x%08x\n", ret);
779 return ret;
780 }
781
782 /* Converts info (which is assumed to be an array of cPackages SecPkgInfoW
783 * structures) into an array of SecPkgInfoA structures, which it returns.
784 */
thunk_PSecPkgInfoWToA(ULONG cPackages,const SecPkgInfoW * info)785 static PSecPkgInfoA thunk_PSecPkgInfoWToA(ULONG cPackages,
786 const SecPkgInfoW *info)
787 {
788 PSecPkgInfoA ret;
789
790 if (info)
791 {
792 size_t bytesNeeded = cPackages * sizeof(SecPkgInfoA);
793 ULONG i;
794
795 for (i = 0; i < cPackages; i++)
796 {
797 if (info[i].Name)
798 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Name,
799 -1, NULL, 0, NULL, NULL);
800 if (info[i].Comment)
801 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Comment,
802 -1, NULL, 0, NULL, NULL);
803 }
804 ret = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
805 if (ret)
806 {
807 PSTR nextString;
808
809 nextString = (PSTR)((PBYTE)ret + cPackages * sizeof(SecPkgInfoA));
810 for (i = 0; i < cPackages; i++)
811 {
812 PSecPkgInfoA pkgInfo = ret + i;
813 int bytes;
814
815 memcpy(pkgInfo, &info[i], sizeof(SecPkgInfoA));
816 if (info[i].Name)
817 {
818 pkgInfo->Name = nextString;
819 /* just repeat back to WideCharToMultiByte how many bytes
820 * it requires, since we asked it earlier
821 */
822 bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
823 NULL, 0, NULL, NULL);
824 WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
825 pkgInfo->Name, bytes, NULL, NULL);
826 nextString += lstrlenA(nextString) + 1;
827 }
828 else
829 pkgInfo->Name = NULL;
830 if (info[i].Comment)
831 {
832 pkgInfo->Comment = nextString;
833 /* just repeat back to WideCharToMultiByte how many bytes
834 * it requires, since we asked it earlier
835 */
836 bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
837 NULL, 0, NULL, NULL);
838 WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
839 pkgInfo->Comment, bytes, NULL, NULL);
840 nextString += lstrlenA(nextString) + 1;
841 }
842 else
843 pkgInfo->Comment = NULL;
844 }
845 }
846 }
847 else
848 ret = NULL;
849 return ret;
850 }
851
852 /***********************************************************************
853 * EnumerateSecurityPackagesA (SECUR32.@)
854 */
EnumerateSecurityPackagesA(PULONG pcPackages,PSecPkgInfoA * ppPackageInfo)855 SECURITY_STATUS WINAPI EnumerateSecurityPackagesA(PULONG pcPackages,
856 PSecPkgInfoA *ppPackageInfo)
857 {
858 SECURITY_STATUS ret;
859 PSecPkgInfoW info;
860
861 ret = EnumerateSecurityPackagesW(pcPackages, &info);
862 if (ret == SEC_E_OK && *pcPackages && info)
863 {
864 *ppPackageInfo = thunk_PSecPkgInfoWToA(*pcPackages, info);
865 if (*pcPackages && !*ppPackageInfo)
866 {
867 *pcPackages = 0;
868 ret = SEC_E_INSUFFICIENT_MEMORY;
869 }
870 FreeContextBuffer(info);
871 }
872 return ret;
873 }
874
875 /***********************************************************************
876 * GetComputerObjectNameA (SECUR32.@)
877 *
878 * Get the local computer's name using the format specified.
879 *
880 * PARAMS
881 * NameFormat [I] The format for the name.
882 * lpNameBuffer [O] Pointer to buffer to receive the name.
883 * nSize [I/O] Size in characters of buffer.
884 *
885 * RETURNS
886 * TRUE If the name was written to lpNameBuffer.
887 * FALSE If the name couldn't be written.
888 *
889 * NOTES
890 * If lpNameBuffer is NULL, then the size of the buffer needed to hold the
891 * name will be returned in *nSize.
892 *
893 * nSize returns the number of characters written when lpNameBuffer is not
894 * NULL or the size of the buffer needed to hold the name when the buffer
895 * is too short or lpNameBuffer is NULL.
896 *
897 * It the buffer is too short, ERROR_INSUFFICIENT_BUFFER error will be set.
898 */
GetComputerObjectNameA(EXTENDED_NAME_FORMAT NameFormat,LPSTR lpNameBuffer,PULONG nSize)899 BOOLEAN WINAPI GetComputerObjectNameA(
900 EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
901 {
902 BOOLEAN rc;
903 LPWSTR bufferW = NULL;
904 ULONG sizeW = *nSize;
905 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
906 if (lpNameBuffer) {
907 bufferW = HeapAlloc(GetProcessHeap(), 0, sizeW * sizeof(WCHAR));
908 if (bufferW == NULL) {
909 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
910 return FALSE;
911 }
912 }
913 rc = GetComputerObjectNameW(NameFormat, bufferW, &sizeW);
914 if (rc && bufferW) {
915 ULONG len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
916 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, lpNameBuffer, *nSize, NULL, NULL);
917 *nSize = len;
918 }
919 else
920 *nSize = sizeW;
921 HeapFree(GetProcessHeap(), 0, bufferW);
922 return rc;
923 }
924
925 /***********************************************************************
926 * GetComputerObjectNameW (SECUR32.@)
927 */
GetComputerObjectNameW(EXTENDED_NAME_FORMAT NameFormat,LPWSTR lpNameBuffer,PULONG nSize)928 BOOLEAN WINAPI GetComputerObjectNameW(
929 EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
930 {
931 LSA_HANDLE policyHandle;
932 LSA_OBJECT_ATTRIBUTES objectAttributes;
933 PPOLICY_DNS_DOMAIN_INFO domainInfo;
934 NTSTATUS ntStatus;
935 BOOLEAN status;
936 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
937
938 if (NameFormat == NameUnknown)
939 {
940 SetLastError(ERROR_INVALID_PARAMETER);
941 return FALSE;
942 }
943
944 ZeroMemory(&objectAttributes, sizeof(objectAttributes));
945 objectAttributes.Length = sizeof(objectAttributes);
946
947 ntStatus = LsaOpenPolicy(NULL, &objectAttributes,
948 POLICY_VIEW_LOCAL_INFORMATION,
949 &policyHandle);
950 if (ntStatus != STATUS_SUCCESS)
951 {
952 SetLastError(LsaNtStatusToWinError(ntStatus));
953 WARN("LsaOpenPolicy failed with NT status %u\n", GetLastError());
954 return FALSE;
955 }
956
957 ntStatus = LsaQueryInformationPolicy(policyHandle,
958 PolicyDnsDomainInformation,
959 (PVOID *)&domainInfo);
960 if (ntStatus != STATUS_SUCCESS)
961 {
962 SetLastError(LsaNtStatusToWinError(ntStatus));
963 WARN("LsaQueryInformationPolicy failed with NT status %u\n",
964 GetLastError());
965 LsaClose(policyHandle);
966 return FALSE;
967 }
968
969 if (domainInfo->Sid)
970 {
971 switch (NameFormat)
972 {
973 case NameSamCompatible:
974 {
975 WCHAR name[MAX_COMPUTERNAME_LENGTH + 1];
976 DWORD size = sizeof(name)/sizeof(name[0]);
977 if (GetComputerNameW(name, &size))
978 {
979 DWORD len = domainInfo->Name.Length + size + 3;
980 if (lpNameBuffer)
981 {
982 if (*nSize < len)
983 {
984 *nSize = len;
985 SetLastError(ERROR_INSUFFICIENT_BUFFER);
986 status = FALSE;
987 }
988 else
989 {
990 WCHAR bs[] = { '\\', 0 };
991 WCHAR ds[] = { '$', 0 };
992 lstrcpyW(lpNameBuffer, domainInfo->Name.Buffer);
993 lstrcatW(lpNameBuffer, bs);
994 lstrcatW(lpNameBuffer, name);
995 lstrcatW(lpNameBuffer, ds);
996 status = TRUE;
997 }
998 }
999 else /* just requesting length required */
1000 {
1001 *nSize = len;
1002 status = TRUE;
1003 }
1004 }
1005 else
1006 {
1007 SetLastError(ERROR_INTERNAL_ERROR);
1008 status = FALSE;
1009 }
1010 }
1011 break;
1012 case NameFullyQualifiedDN:
1013 case NameDisplay:
1014 case NameUniqueId:
1015 case NameCanonical:
1016 case NameUserPrincipal:
1017 case NameCanonicalEx:
1018 case NameServicePrincipal:
1019 case NameDnsDomain:
1020 FIXME("NameFormat %d not implemented\n", NameFormat);
1021 SetLastError(ERROR_CANT_ACCESS_DOMAIN_INFO);
1022 status = FALSE;
1023 break;
1024 default:
1025 SetLastError(ERROR_INVALID_PARAMETER);
1026 status = FALSE;
1027 }
1028 }
1029 else
1030 {
1031 SetLastError(ERROR_CANT_ACCESS_DOMAIN_INFO);
1032 status = FALSE;
1033 }
1034
1035 LsaFreeMemory(domainInfo);
1036 LsaClose(policyHandle);
1037
1038 return status;
1039 }
1040
1041 /***********************************************************************
1042 * GetUserNameExA (SECUR32.@)
1043 */
GetUserNameExA(EXTENDED_NAME_FORMAT NameFormat,LPSTR lpNameBuffer,PULONG nSize)1044 BOOLEAN WINAPI GetUserNameExA(
1045 EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
1046 {
1047 BOOLEAN rc;
1048 LPWSTR bufferW = NULL;
1049 ULONG sizeW = *nSize;
1050 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
1051 if (lpNameBuffer) {
1052 bufferW = HeapAlloc(GetProcessHeap(), 0, sizeW * sizeof(WCHAR));
1053 if (bufferW == NULL) {
1054 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1055 return FALSE;
1056 }
1057 }
1058 rc = GetUserNameExW(NameFormat, bufferW, &sizeW);
1059 if (rc) {
1060 ULONG len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
1061 if (len <= *nSize)
1062 {
1063 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, lpNameBuffer, *nSize, NULL, NULL);
1064 *nSize = len - 1;
1065 }
1066 else
1067 {
1068 *nSize = len;
1069 rc = FALSE;
1070 SetLastError(ERROR_MORE_DATA);
1071 }
1072 }
1073 else
1074 *nSize = sizeW;
1075 HeapFree(GetProcessHeap(), 0, bufferW);
1076 return rc;
1077 }
1078
GetUserNameExW(EXTENDED_NAME_FORMAT NameFormat,LPWSTR lpNameBuffer,PULONG nSize)1079 BOOLEAN WINAPI GetUserNameExW(
1080 EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
1081 {
1082 TRACE("(%d %p %p)\n", NameFormat, lpNameBuffer, nSize);
1083
1084 switch (NameFormat)
1085 {
1086 case NameSamCompatible:
1087 {
1088 WCHAR samname[UNLEN + 1 + MAX_COMPUTERNAME_LENGTH + 1];
1089 LPWSTR out;
1090 DWORD len;
1091
1092 /* This assumes the current user is always a local account */
1093 len = MAX_COMPUTERNAME_LENGTH + 1;
1094 if (GetComputerNameW(samname, &len))
1095 {
1096 out = samname + lstrlenW(samname);
1097 *out++ = '\\';
1098 len = UNLEN + 1;
1099 if (GetUserNameW(out, &len))
1100 {
1101 if (lstrlenW(samname) < *nSize)
1102 {
1103 lstrcpyW(lpNameBuffer, samname);
1104 *nSize = lstrlenW(samname);
1105 return TRUE;
1106 }
1107
1108 SetLastError(ERROR_MORE_DATA);
1109 *nSize = lstrlenW(samname) + 1;
1110 }
1111 }
1112 return FALSE;
1113 }
1114
1115 case NameUnknown:
1116 case NameFullyQualifiedDN:
1117 case NameDisplay:
1118 case NameUniqueId:
1119 case NameCanonical:
1120 case NameUserPrincipal:
1121 case NameCanonicalEx:
1122 case NameServicePrincipal:
1123 case NameDnsDomain:
1124 SetLastError(ERROR_NONE_MAPPED);
1125 return FALSE;
1126
1127 default:
1128 SetLastError(ERROR_INVALID_PARAMETER);
1129 return FALSE;
1130 }
1131 }
1132
TranslateNameA(LPCSTR lpAccountName,EXTENDED_NAME_FORMAT AccountNameFormat,EXTENDED_NAME_FORMAT DesiredNameFormat,LPSTR lpTranslatedName,PULONG nSize)1133 BOOLEAN WINAPI TranslateNameA(
1134 LPCSTR lpAccountName, EXTENDED_NAME_FORMAT AccountNameFormat,
1135 EXTENDED_NAME_FORMAT DesiredNameFormat, LPSTR lpTranslatedName,
1136 PULONG nSize)
1137 {
1138 FIXME("%p %d %d %p %p\n", lpAccountName, AccountNameFormat,
1139 DesiredNameFormat, lpTranslatedName, nSize);
1140 return FALSE;
1141 }
1142
TranslateNameW(LPCWSTR lpAccountName,EXTENDED_NAME_FORMAT AccountNameFormat,EXTENDED_NAME_FORMAT DesiredNameFormat,LPWSTR lpTranslatedName,PULONG nSize)1143 BOOLEAN WINAPI TranslateNameW(
1144 LPCWSTR lpAccountName, EXTENDED_NAME_FORMAT AccountNameFormat,
1145 EXTENDED_NAME_FORMAT DesiredNameFormat, LPWSTR lpTranslatedName,
1146 PULONG nSize)
1147 {
1148 FIXME("%p %d %d %p %p\n", lpAccountName, AccountNameFormat,
1149 DesiredNameFormat, lpTranslatedName, nSize);
1150 return FALSE;
1151 }
1152