Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

785 lines
20 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1991 - 1992
  6. //
  7. // File: SPInit.cxx
  8. //
  9. // Contents: Initialization code for SPMgr/LSA
  10. //
  11. // Functions: LoadPackages -- Loads all the packages
  12. // InitThreadData -- Creates TLS values
  13. // InitSystemLogon -- Initializes the System logon
  14. // LsapEnableCreateTokenPrivilege -- Enables the privilege
  15. // InitLocatorAndOle -- Initializes Locator cache, Ole
  16. // InitKDCData -- Initializes knowledge about KDC
  17. //
  18. //
  19. // History: 08 Sep 92, RichardW Created from spmgr.c, etc.
  20. // 26 Mar 93, MikeSw Converted from C->C++
  21. //
  22. //------------------------------------------------------------------------
  23. //
  24. // precompiled headers
  25. //
  26. #include <lsapch.hxx>
  27. extern "C"
  28. {
  29. #include "spinit.h"
  30. #include <lmcons.h>
  31. #include <crypt.h>
  32. #include <logonmsv.h>
  33. #include <ssi.h>
  34. #include <lsads.h>
  35. }
  36. //+-------------------------------------------------------------------------
  37. //
  38. // Function: LoadPackages
  39. //
  40. // Synopsis: Loads all the specified security packages
  41. //
  42. // Effects: Packages loaded, global structures updated
  43. //
  44. // Arguments: comma-separated list of package names (DLL names)
  45. //
  46. // Requires:
  47. //
  48. // Returns: SUCCESS, or some failures
  49. //
  50. // Notes: This is run during SPM Init, while the process is still
  51. // single threaded, and not handling any calls.
  52. //
  53. //--------------------------------------------------------------------------
  54. extern "C"
  55. NTSTATUS
  56. LoadPackages( PWSTR * ppszPackages,
  57. PWSTR * ppszOldPkgs,
  58. PWSTR pszPreferred)
  59. {
  60. PWSTR pszPackage;
  61. NTSTATUS scRet;
  62. SECURITY_STRING sStr;
  63. SECPKG_PARAMETERS Parameters;
  64. ULONG iPackage = 0;
  65. ULONG iOldPkg = 0;
  66. ULONG LoadCount = 0;
  67. ULONG NewCount = 0;
  68. ULONG PreferredPackage = 0;
  69. PLSAPR_POLICY_DNS_DOMAIN_INFO DnsDomainInfo = NULL;
  70. PLSAP_SECURITY_PACKAGE Package;
  71. SECPKG_EVENT_PACKAGE_CHANGE Event;
  72. NT_PRODUCT_TYPE ProductType ;
  73. if (!SpmpInitializePackageControl())
  74. {
  75. return( STATUS_INSUFFICIENT_RESOURCES );
  76. }
  77. //
  78. // Build up the initialization message, to give the packages a better idea
  79. // of what is going on, and reduce their later calls for the same info.
  80. //
  81. Parameters.MachineState = SECPKG_STATE_ENCRYPTION_PERMITTED;
  82. Parameters.MachineState |= SECPKG_STATE_STRONG_ENCRYPTION_PERMITTED;
  83. Parameters.SetupMode = SetupPhase;
  84. scRet = LsaIQueryInformationPolicyTrusted(
  85. PolicyDnsDomainInformation,
  86. (PLSAPR_POLICY_INFORMATION *) &DnsDomainInfo
  87. );
  88. if (!NT_SUCCESS(scRet))
  89. {
  90. DebugLog((DEB_ERROR,"Failed to get primary domain info: 0x%x\n",scRet));
  91. return(scRet);
  92. }
  93. Parameters.DomainName = * (PUNICODE_STRING) &DnsDomainInfo->Name;
  94. Parameters.DnsDomainName = * (PUNICODE_STRING) &DnsDomainInfo->DnsDomainName;
  95. Parameters.DomainSid = (PSID) DnsDomainInfo->Sid;
  96. Parameters.DomainGuid = (GUID) DnsDomainInfo->DomainGuid;
  97. if ( RtlGetNtProductType( &ProductType ) )
  98. {
  99. if ( ProductType == NtProductLanManNt )
  100. {
  101. Parameters.MachineState |= SECPKG_STATE_DOMAIN_CONTROLLER ;
  102. }
  103. else
  104. {
  105. if (Parameters.DomainSid != NULL)
  106. {
  107. Parameters.MachineState |= SECPKG_STATE_WORKSTATION;
  108. }
  109. else
  110. {
  111. Parameters.MachineState |= SECPKG_STATE_STANDALONE;
  112. }
  113. }
  114. }
  115. else
  116. {
  117. Parameters.MachineState |= SECPKG_STATE_STANDALONE;
  118. }
  119. LoadCount = 0;
  120. NewCount = 0;
  121. DebugLog((DEB_TRACE_INIT, "Init Parameters = %d, %s\n",
  122. Parameters.MachineState,
  123. (Parameters.SetupMode ? "Setup" : "Normal") ));
  124. //
  125. // Add the built in Negotiate package first. It will hook all subsequent
  126. // package loads and unloads, so that it can keep a table running of all
  127. // the packages and their negotiate options.
  128. //
  129. if ( SpmpLoadBuiltin( 0, &NegTable, &Parameters ) )
  130. {
  131. LoadCount ++ ;
  132. }
  133. //
  134. // Set the preferred package to be the first non-negotiate package
  135. //
  136. PreferredPackage = LoadCount;
  137. //
  138. // Now load the new DLLs:
  139. //
  140. while (pszPackage = ppszPackages[iPackage])
  141. {
  142. if (SpmpLoadDll( pszPackage, &Parameters ))
  143. {
  144. LoadCount++;
  145. NewCount++;
  146. }
  147. iPackage++;
  148. }
  149. //
  150. // Now, load old style packages, or just the MSV package for now.
  151. //
  152. while (pszPackage = ppszOldPkgs[iOldPkg])
  153. {
  154. if (SpmpLoadAuthPkgDll( pszPackage ))
  155. {
  156. LoadCount++;
  157. }
  158. iOldPkg++;
  159. }
  160. //
  161. // Select the preferred package.
  162. //
  163. if ( pszPreferred == NULL )
  164. {
  165. Package = SpmpLocatePackage( PreferredPackage );
  166. }
  167. else
  168. {
  169. RtlInitUnicodeString( &sStr, pszPreferred );
  170. Package = SpmpLookupPackage( &sStr );
  171. }
  172. //
  173. // If there are no new packages, do not enabled a preferred
  174. // package. It will mess up the negotiate package
  175. //
  176. if ( NewCount == 0 )
  177. {
  178. Package = NULL ;
  179. }
  180. if ( Package )
  181. {
  182. Package->fPackage |= SP_PREFERRED ;
  183. Event.PackageId = Package->dwPackageID;
  184. Event.PackageName = Package->Name;
  185. Event.ChangeType = SECPKG_PACKAGE_CHANGE_SELECT ;
  186. LsapEventNotify(
  187. NOTIFY_CLASS_PACKAGE_CHANGE,
  188. 0,
  189. sizeof( Event ),
  190. &Event );
  191. }
  192. //
  193. // All the strings are actually offsets from the zeroth string
  194. //
  195. if (ppszPackages[0] != NULL)
  196. {
  197. LsapFreeLsaHeap(ppszPackages[0]);
  198. }
  199. //
  200. // Finally, free the array:
  201. //
  202. LsapFreeLsaHeap(ppszPackages);
  203. //
  204. // Get rid of the old package array, as well:
  205. //
  206. if (ppszOldPkgs[0] != NULL)
  207. {
  208. LsapFreeLsaHeap(ppszOldPkgs[0]);
  209. }
  210. LsapFreeLsaHeap(ppszOldPkgs);
  211. #if DBG
  212. SpmpLoadBuiltinAuthPkg( &DbgTable );
  213. #endif
  214. //
  215. // Free the primary domain info
  216. //
  217. LsaIFree_LSAPR_POLICY_INFORMATION(
  218. PolicyDnsDomainInformation,
  219. (PLSAPR_POLICY_INFORMATION) DnsDomainInfo
  220. );
  221. //
  222. // If at least the primary loaded, then return OK. If not that,
  223. // then return an error:
  224. //
  225. if ( LoadCount )
  226. {
  227. return(S_OK);
  228. }
  229. else
  230. {
  231. return(SEC_E_CANNOT_INSTALL);
  232. }
  233. }
  234. //+-------------------------------------------------------------------------
  235. //
  236. // Function: InitThreadData
  237. //
  238. // Synopsis: Initializes Tls* data slots
  239. //
  240. // Effects:
  241. //
  242. // Arguments:
  243. //
  244. // Requires:
  245. //
  246. // Returns:
  247. //
  248. // Notes:
  249. //
  250. //--------------------------------------------------------------------------
  251. extern "C"
  252. void
  253. InitThreadData(void)
  254. {
  255. dwSession = TlsAlloc();
  256. dwExceptionInfo = TlsAlloc();
  257. dwCallInfo = TlsAlloc();
  258. dwThreadPackage = TlsAlloc();
  259. LsapDsThreadState = TlsAlloc();
  260. dwThreadHeap = TlsAlloc();
  261. #ifdef DBG
  262. //
  263. // See dbp.h for the number of locks parameter
  264. //
  265. SafeLockInit( 12, TRUE );
  266. #endif
  267. }
  268. #ifdef LSAP_VERIFY_PACKAGE_ID
  269. BOOL RefSetCurrentPackageId(ULONG_PTR dwPackageId)
  270. {
  271. ULONG_PTR dwCurId;
  272. char szTmp[32];
  273. WCHAR szw[64];
  274. dwCurId = (ULONG_PTR) TlsGetValue(dwThreadPackage);
  275. _snprintf(szTmp, sizeof( szTmp ), "%ld (%ld)", dwPackageId, dwCurId);
  276. // wsprintf(szw, L"*** %x ==> %d\n", GetCurrentThreadId(), dwPackageId);
  277. // OutputDebugString(szw);
  278. if (dwCurId == SPMGR_ID)
  279. {
  280. DsysAssertMsg(dwPackageId != SPMGR_ID, szTmp);
  281. }
  282. return TlsSetValue(dwThreadPackage, (PVOID)dwPackageId);
  283. }
  284. #endif // LSAP_VERIFY_PACKAGE_ID
  285. //+-------------------------------------------------------------------------
  286. //
  287. // Function: InitSystemLogon
  288. //
  289. // Synopsis: Creates system logon credentials
  290. //
  291. // Effects: Creates credentials for NTLM and Kerberos for the Machine
  292. // in the system logon.
  293. //
  294. // Arguments:
  295. //
  296. // Requires:
  297. //
  298. // Returns:
  299. //
  300. // Notes:
  301. //
  302. //--------------------------------------------------------------------------
  303. extern "C"
  304. void
  305. InitSystemLogon(void)
  306. {
  307. UNICODE_STRING ComputerPrincipalName;
  308. PLSAP_SECURITY_PACKAGE pAuxPackage;
  309. PSession pSession = GetCurrentSession();
  310. UNICODE_STRING SecretName;
  311. ULONG_PTR iPackage;
  312. NTSTATUS scRet;
  313. SECPKG_PRIMARY_CRED PrimaryCred;
  314. PLSAPR_POLICY_INFORMATION PolicyInfo = NULL;
  315. PLSAPR_POLICY_INFORMATION DnsPolicyInfo = NULL;
  316. PLSAPR_CR_CIPHER_VALUE CrWkstaPassword = NULL;
  317. PLSAPR_CR_CIPHER_VALUE CrWkstaOldPassword = NULL;
  318. SID SystemSid = {SID_REVISION, 1,
  319. SECURITY_NT_AUTHORITY,
  320. SECURITY_LOCAL_SYSTEM_RID};
  321. LSAPR_HANDLE SecretHandle = NULL;
  322. UNICODE_STRING DomainCopy ;
  323. UNICODE_STRING MachineCopy ;
  324. PSID SidCopy ;
  325. RtlZeroMemory(
  326. &PrimaryCred,
  327. sizeof(PrimaryCred)
  328. );
  329. ComputerPrincipalName.Buffer = NULL;
  330. //
  331. // Build the computer principal name, which is the computer name followed
  332. // by a '$'
  333. //
  334. ComputerPrincipalName.Length = MachineName.Length + sizeof(WCHAR);
  335. ComputerPrincipalName.MaximumLength = MachineName.Length + 2 * sizeof(WCHAR);
  336. SafeAllocaAllocate(ComputerPrincipalName.Buffer, ComputerPrincipalName.MaximumLength);
  337. if (ComputerPrincipalName.Buffer == NULL)
  338. {
  339. goto Cleanup;
  340. }
  341. RtlCopyMemory(
  342. ComputerPrincipalName.Buffer,
  343. MachineName.Buffer,
  344. MachineName.Length
  345. );
  346. ComputerPrincipalName.Buffer[MachineName.Length/sizeof(WCHAR)] =
  347. SSI_ACCOUNT_NAME_POSTFIX_CHAR;
  348. ComputerPrincipalName.Buffer[1+MachineName.Length/sizeof(WCHAR)] =
  349. L'\0';
  350. PrimaryCred.LogonId = SystemLogonId;
  351. PrimaryCred.UserSid = &SystemSid;
  352. PrimaryCred.DownlevelName.Buffer = wcsrchr(ComputerPrincipalName.Buffer,L'\\');
  353. if (PrimaryCred.DownlevelName.Buffer == NULL)
  354. {
  355. PrimaryCred.DownlevelName = ComputerPrincipalName;
  356. }
  357. else
  358. {
  359. PrimaryCred.DownlevelName.Buffer++;
  360. RtlInitUnicodeString(
  361. &PrimaryCred.DownlevelName,
  362. PrimaryCred.DownlevelName.Buffer
  363. );
  364. }
  365. //
  366. // Get the machine account password, if there is one
  367. //
  368. RtlInitUnicodeString(
  369. &SecretName,
  370. SSI_SECRET_NAME
  371. );
  372. scRet = LsarOpenSecret(
  373. LsapPolicyHandle,
  374. (PLSAPR_UNICODE_STRING) &SecretName,
  375. SECRET_ALL_ACCESS,
  376. &SecretHandle
  377. );
  378. if (NT_SUCCESS(scRet))
  379. {
  380. scRet = LsarQuerySecret(
  381. SecretHandle,
  382. &CrWkstaPassword,
  383. NULL, // we don't want current val set time
  384. &CrWkstaOldPassword,
  385. NULL // ditto for old val
  386. );
  387. }
  388. //
  389. // We don't want to fail to boot if we don't have a password, so continue
  390. // after an error
  391. //
  392. if (NT_SUCCESS(scRet) && (CrWkstaPassword != NULL))
  393. {
  394. PrimaryCred.Password.Buffer = (LPWSTR) CrWkstaPassword->Buffer;
  395. PrimaryCred.Password.Length = (USHORT) CrWkstaPassword->Length;
  396. PrimaryCred.Password.MaximumLength = (USHORT) CrWkstaPassword->MaximumLength;
  397. PrimaryCred.Flags = PRIMARY_CRED_CLEAR_PASSWORD;
  398. if (CrWkstaOldPassword != NULL)
  399. {
  400. PrimaryCred.OldPassword.Buffer = (LPWSTR) CrWkstaOldPassword->Buffer;
  401. PrimaryCred.OldPassword.Length = (USHORT) CrWkstaOldPassword->Length;
  402. PrimaryCred.OldPassword.MaximumLength = (USHORT) CrWkstaOldPassword->MaximumLength;
  403. }
  404. }
  405. scRet = LsaIQueryInformationPolicyTrusted(
  406. PolicyDnsDomainInformation,
  407. &DnsPolicyInfo
  408. );
  409. if(!NT_SUCCESS(scRet))
  410. {
  411. scRet = LsaIQueryInformationPolicyTrusted(
  412. PolicyPrimaryDomainInformation,
  413. &PolicyInfo
  414. );
  415. if (NT_SUCCESS(scRet))
  416. {
  417. PrimaryCred.DomainName = *(PUNICODE_STRING) &PolicyInfo->PolicyPrimaryDomainInfo.Name;
  418. }
  419. } else {
  420. PrimaryCred.DomainName = *(PUNICODE_STRING) &DnsPolicyInfo->PolicyDnsDomainInfo.Name;
  421. PrimaryCred.DnsDomainName = *(PUNICODE_STRING) &DnsPolicyInfo->PolicyDnsDomainInfo.DnsDomainName;
  422. }
  423. //
  424. // Update the logon session with the "real" name:
  425. //
  426. scRet = LsapDuplicateString(
  427. &DomainCopy,
  428. &PrimaryCred.DomainName );
  429. if ( NT_SUCCESS( scRet ) )
  430. {
  431. scRet = LsapDuplicateString(
  432. &MachineCopy,
  433. &PrimaryCred.DownlevelName );
  434. if ( NT_SUCCESS( scRet ) )
  435. {
  436. scRet = LsapDuplicateSid(
  437. &SidCopy,
  438. PrimaryCred.UserSid );
  439. if ( NT_SUCCESS( scRet ) )
  440. {
  441. LsapSetLogonSessionAccountInfo(
  442. &SystemLogonId,
  443. &MachineCopy,
  444. &DomainCopy,
  445. NULL,
  446. &SidCopy,
  447. (SECURITY_LOGON_TYPE) 0,
  448. &PrimaryCred
  449. );
  450. //
  451. // If successful, LsapSetLogonSessionAccountInfo will have taken
  452. // ownership of UserSid
  453. //
  454. if ( SidCopy != NULL ) {
  455. LsapFreeLsaHeap( SidCopy );
  456. }
  457. }
  458. }
  459. }
  460. DebugLog((DEB_TRACE_INIT, "Establishing credentials for machine %ws\n", MachineName.Buffer));
  461. pAuxPackage = SpmpIteratePackagesByRequest( NULL, SP_ORDINAL_ACCEPTCREDS );
  462. while (pAuxPackage)
  463. {
  464. iPackage = pAuxPackage->dwPackageID;
  465. DebugLog((DEB_TRACE_INIT, "Whacking package %ws with %x:%x = %ws\n",
  466. pAuxPackage->Name.Buffer,
  467. SystemLogonId.HighPart, SystemLogonId.LowPart,
  468. MachineName.Buffer));
  469. SetCurrentPackageId(iPackage);
  470. __try
  471. {
  472. scRet = pAuxPackage->FunctionTable.AcceptCredentials(
  473. Interactive,
  474. &ComputerPrincipalName,
  475. &PrimaryCred,
  476. NULL // no supplemental credentials
  477. );
  478. }
  479. __except (EXCEPTION_EXECUTE_HANDLER)
  480. {
  481. scRet = (NTSTATUS) GetExceptionCode();
  482. scRet = SPException(scRet, iPackage);
  483. }
  484. // Note: if an exception occurs, we don't fail the logon, we just
  485. // do the magic on the package that blew. If the package blows,
  486. // the other packages may succeed, and so the user may not be able
  487. // to use that provider.
  488. pAuxPackage = SpmpIteratePackagesByRequest( pAuxPackage,
  489. SP_ORDINAL_ACCEPTCREDS );
  490. }
  491. Cleanup:
  492. //
  493. // Finally, set this thread back to being a SPM thread:
  494. //
  495. SetCurrentPackageId( SPMGR_ID );
  496. if (CrWkstaPassword != NULL)
  497. {
  498. LsaIFree_LSAPR_CR_CIPHER_VALUE(
  499. CrWkstaPassword
  500. );
  501. }
  502. if (CrWkstaOldPassword != NULL)
  503. {
  504. LsaIFree_LSAPR_CR_CIPHER_VALUE(
  505. CrWkstaOldPassword
  506. );
  507. }
  508. if (SecretHandle != NULL)
  509. {
  510. LsarClose(&SecretHandle);
  511. }
  512. if (PolicyInfo != NULL)
  513. {
  514. LsaIFree_LSAPR_POLICY_INFORMATION(
  515. PolicyPrimaryDomainInformation,
  516. PolicyInfo
  517. );
  518. }
  519. if (DnsPolicyInfo != NULL)
  520. {
  521. LsaIFree_LSAPR_POLICY_INFORMATION(
  522. PolicyDnsDomainInformation,
  523. DnsPolicyInfo
  524. );
  525. }
  526. SafeAllocaFree(ComputerPrincipalName.Buffer);
  527. }
  528. HANDLE
  529. SpmpOpenEvent( IN PWSTR EventName )
  530. {
  531. NTSTATUS NtStatus;
  532. HANDLE InstallationEvent;
  533. OBJECT_ATTRIBUTES EventAttributes;
  534. UNICODE_STRING UnicodeEventName;
  535. //
  536. // If the following event exists, it is an indication that
  537. // installation is in progress and that further security
  538. // initialization should be delayed until the event is
  539. // signalled. This is expected to be a NOTIFICATION event.
  540. //
  541. RtlInitUnicodeString( &UnicodeEventName, EventName);
  542. InitializeObjectAttributes( &EventAttributes, &UnicodeEventName, 0, 0, NULL );
  543. NtStatus = NtOpenEvent(
  544. &InstallationEvent,
  545. SYNCHRONIZE,
  546. &EventAttributes
  547. );
  548. if (NT_SUCCESS(NtStatus))
  549. {
  550. return(InstallationEvent);
  551. }
  552. else
  553. {
  554. return(NULL);
  555. }
  556. }
  557. HANDLE
  558. SpmpOpenSetupEvent( VOID )
  559. {
  560. return( SpmpOpenEvent(L"\\INSTALLATION_SECURITY_HOLD"));
  561. }
  562. extern "C"
  563. BOOLEAN
  564. SpmpIsSetupPass( VOID )
  565. {
  566. HANDLE hEvent;
  567. if (hEvent = SpmpOpenSetupEvent())
  568. {
  569. NtClose(hEvent);
  570. return(TRUE);
  571. }
  572. return(FALSE);
  573. }
  574. extern "C"
  575. BOOLEAN
  576. SpmpIsMiniSetupPass( VOID )
  577. {
  578. DWORD rc;
  579. DWORD d = 0;
  580. DWORD Type;
  581. HKEY hKey;
  582. //
  583. // See if this is a "mini" setup, in which case we
  584. // don't need to generate the domain SID.
  585. //
  586. rc = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  587. L"System\\Setup",
  588. 0,
  589. KEY_READ,
  590. &hKey );
  591. if( rc == ERROR_SUCCESS ) {
  592. //
  593. // Just get the size (ALPHA workaround). All
  594. // we care about is if the key exists...
  595. //
  596. rc = RegQueryValueExW( hKey,
  597. L"MiniSetupInProgress",
  598. NULL,
  599. &Type,
  600. (LPBYTE)NULL,
  601. &d );
  602. RegCloseKey( hKey );
  603. if( rc == ERROR_SUCCESS ) {
  604. return( TRUE );
  605. }
  606. }
  607. return( FALSE );
  608. }
  609. NTSTATUS
  610. LsapInstallationPause( VOID )
  611. /*++
  612. Routine Description:
  613. This function checks to see if the system is in an
  614. installation state. If so, it suspends further initialization
  615. until the installation state is complete.
  616. Installation state is signified by the existance of a well known
  617. event.
  618. Arguments:
  619. None.
  620. Return Value:
  621. STATUS_SUCCESS - Proceed with initialization.
  622. Other status values are unexpected.
  623. --*/
  624. {
  625. HANDLE InstallationEvent;
  626. NTSTATUS NtStatus;
  627. NTSTATUS TmpStatus;
  628. InstallationEvent = SpmpOpenSetupEvent();
  629. if ( InstallationEvent ) {
  630. //
  631. // The event exists - installation created it and will signal it
  632. // when it is ok to proceed with security initialization.
  633. // Installation code is responsible for deleting the event after
  634. // signalling it.
  635. //
  636. NtStatus = NtWaitForSingleObject( InstallationEvent, TRUE, 0 );
  637. TmpStatus = NtClose( InstallationEvent );
  638. ASSERT(NT_SUCCESS(TmpStatus));
  639. //
  640. // Now, strobe the state changed event, to indicate to the
  641. // rest of the threads that life has changed
  642. //
  643. SpmSetEvent(hStateChangeEvent);
  644. } else {
  645. NtStatus = STATUS_SUCCESS; // Indicate everything is as expected
  646. }
  647. return(NtStatus);
  648. }