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 */ 123 PSecurityFunctionTableA WINAPI InitSecurityInterfaceA(void) 124 { 125 TRACE("InitSecurityInterfaceA() called\n"); 126 return &securityFunctionTableA; 127 } 128 129 /*********************************************************************** 130 * InitSecurityInterfaceW (SECUR32.@) 131 */ 132 PSecurityFunctionTableW WINAPI InitSecurityInterfaceW(void) 133 { 134 TRACE("InitSecurityInterfaceW() called\n"); 135 return &securityFunctionTableW; 136 } 137 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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