Source code of Windows XP (NT5)
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.

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