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.

2089 lines
55 KiB

  1. //+--------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1996
  6. //
  7. // File: ntlm.cxx
  8. //
  9. // Contents: main entrypoints for the ntlm security package
  10. // SpLsaModeInitialize
  11. // SpInitialize
  12. // SpShutdown
  13. // SpGetInfo
  14. //
  15. // Helper functions:
  16. // NtLmSetPolicyInfo
  17. // NtLmPolicyChangeCallback
  18. // NtLmRegisterForPolicyChange
  19. // NtLmUnregisterForPolicyChange
  20. //
  21. // History: ChandanS 26-Jul-1996 Stolen from kerberos\client2\kerberos.cxx
  22. // ChandanS 16-Apr-1998 No reboot on domain name change
  23. // JClark 28-Jun-2000 Added WMI Trace Logging Support
  24. //
  25. //---------------------------------------------------------------------
  26. // Variables with the EXTERN storage class are declared here
  27. #define NTLM_GLOBAL
  28. #define DEBUG_ALLOCATE
  29. #include <global.h>
  30. #include <wow64t.h>
  31. #include "trace.h"
  32. extern "C"
  33. {
  34. NTSTATUS
  35. LsaApInitializePackage(
  36. IN ULONG AuthenticationPackageId,
  37. IN PLSA_DISPATCH_TABLE LsaDispatchTable,
  38. IN PSTRING Database OPTIONAL,
  39. IN PSTRING Confidentiality OPTIONAL,
  40. OUT PSTRING *AuthenticationPackageName
  41. );
  42. }
  43. BOOLEAN NtLmCredentialInitialized;
  44. BOOLEAN NtLmContextInitialized;
  45. BOOLEAN NtLmRNGInitialized;
  46. LIST_ENTRY NtLmProcessOptionsList;
  47. RTL_RESOURCE NtLmProcessOptionsLock;
  48. //+--------------------------------------------------------------------
  49. //
  50. // Function: SpLsaModeInitialize
  51. //
  52. // Synopsis: This function is called by the LSA when this DLL is loaded.
  53. // It returns security package function tables for all
  54. // security packages in the DLL.
  55. //
  56. // Arguments: LsaVersion - Version number of the LSA
  57. // PackageVersion - Returns version number of the package
  58. // Tables - Returns array of function tables for the package
  59. // TableCount - Returns number of entries in array of
  60. // function tables.
  61. //
  62. // Returns: PackageVersion (as above)
  63. // Tables (as above)
  64. // TableCount (as above)
  65. //
  66. // Notes:
  67. //
  68. //---------------------------------------------------------------------
  69. NTSTATUS NTAPI
  70. SpLsaModeInitialize(
  71. IN ULONG LsaVersion,
  72. OUT PULONG PackageVersion,
  73. OUT PSECPKG_FUNCTION_TABLE * Tables,
  74. OUT PULONG TableCount
  75. )
  76. {
  77. #if DBG
  78. // SspGlobalDbflag = SSP_CRITICAL| SSP_API| SSP_API_MORE |SSP_INIT| SSP_MISC | SSP_NO_LOCAL;
  79. SspGlobalDbflag = SSP_CRITICAL ;
  80. InitializeCriticalSection(&SspGlobalLogFileCritSect);
  81. #endif
  82. SspPrint((SSP_API, "Entering SpLsaModeInitialize\n"));
  83. SECURITY_STATUS Status = SEC_E_OK;
  84. if (LsaVersion != SECPKG_INTERFACE_VERSION)
  85. {
  86. SspPrint((SSP_CRITICAL, "Invalid LSA version: %d\n", LsaVersion));
  87. Status = STATUS_INVALID_PARAMETER;
  88. goto CleanUp;
  89. }
  90. NtLmFunctionTable.InitializePackage = NULL;
  91. NtLmFunctionTable.LogonUser = NULL;
  92. NtLmFunctionTable.CallPackage = LsaApCallPackage;
  93. NtLmFunctionTable.LogonTerminated = LsaApLogonTerminated;
  94. NtLmFunctionTable.CallPackageUntrusted = LsaApCallPackageUntrusted;
  95. NtLmFunctionTable.LogonUserEx = NULL;
  96. NtLmFunctionTable.LogonUserEx2 = LsaApLogonUserEx2;
  97. NtLmFunctionTable.Initialize = SpInitialize;
  98. NtLmFunctionTable.Shutdown = SpShutdown;
  99. NtLmFunctionTable.GetInfo = SpGetInfo;
  100. NtLmFunctionTable.AcceptCredentials = SpAcceptCredentials;
  101. NtLmFunctionTable.AcquireCredentialsHandle = SpAcquireCredentialsHandle;
  102. NtLmFunctionTable.FreeCredentialsHandle = SpFreeCredentialsHandle;
  103. NtLmFunctionTable.SaveCredentials = SpSaveCredentials;
  104. NtLmFunctionTable.GetCredentials = SpGetCredentials;
  105. NtLmFunctionTable.DeleteCredentials = SpDeleteCredentials;
  106. NtLmFunctionTable.InitLsaModeContext = SpInitLsaModeContext;
  107. NtLmFunctionTable.AcceptLsaModeContext = SpAcceptLsaModeContext;
  108. NtLmFunctionTable.DeleteContext = SpDeleteContext;
  109. NtLmFunctionTable.ApplyControlToken = SpApplyControlToken;
  110. NtLmFunctionTable.GetUserInfo = SpGetUserInfo;
  111. NtLmFunctionTable.QueryCredentialsAttributes = SpQueryCredentialsAttributes ;
  112. NtLmFunctionTable.GetExtendedInformation = SpGetExtendedInformation ;
  113. NtLmFunctionTable.SetExtendedInformation = SpSetExtendedInformation ;
  114. NtLmFunctionTable.CallPackagePassthrough = LsaApCallPackagePassthrough;
  115. #if 0
  116. NtLmFunctionTable.QueryContextAttributes = SpQueryLsaModeContextAttributes;
  117. NtLmFunctionTable.SetContextAttributes = SpSetContextAttributes;
  118. *PackageVersion = SECPKG_INTERFACE_VERSION_2;
  119. #else
  120. *PackageVersion = SECPKG_INTERFACE_VERSION;
  121. #endif
  122. *Tables = &NtLmFunctionTable;
  123. *TableCount = 1;
  124. //
  125. // Get the Event Trace logging on board
  126. //
  127. NtlmInitializeTrace();
  128. SafeAllocaInitialize(SAFEALLOCA_USE_DEFAULT,
  129. SAFEALLOCA_USE_DEFAULT,
  130. NtLmAllocate,
  131. NtLmFree);
  132. CleanUp:
  133. SspPrint((SSP_API, "Leaving SpLsaModeInitialize\n"));
  134. return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  135. }
  136. //+-------------------------------------------------------------------------
  137. //
  138. // Function: NtLmSetPolicyInfo
  139. //
  140. // Synopsis: Function to be called when policy changes
  141. //
  142. // Effects:
  143. //
  144. // Arguments:
  145. //
  146. // Requires:
  147. //
  148. // Returns:
  149. //
  150. // Notes:
  151. // if fInit is TRUE, this is called by the init routine in ntlm
  152. //
  153. //
  154. //+-------------------------------------------------------------------------
  155. NTSTATUS
  156. NtLmSetPolicyInfo(
  157. IN PUNICODE_STRING DnsComputerName,
  158. IN PUNICODE_STRING ComputerName,
  159. IN PUNICODE_STRING DnsDomainName,
  160. IN PUNICODE_STRING DomainName,
  161. IN PSID DomainSid,
  162. IN POLICY_NOTIFICATION_INFORMATION_CLASS ChangedInfoClass,
  163. IN BOOLEAN fInit
  164. )
  165. {
  166. NTSTATUS Status = STATUS_SUCCESS;
  167. // Buffers to delete on cleanup
  168. STRING ComputerNameAnsiString;
  169. STRING DomainNameAnsiString;
  170. UNICODE_STRING DnsTreeName = {0};
  171. ComputerNameAnsiString.Buffer = NULL;
  172. DomainNameAnsiString.Buffer = NULL;
  173. //
  174. // grab the treename. don't do this during Init, because the SAM
  175. // isn't initialized yet.
  176. //
  177. if(!fInit)
  178. {
  179. Status = SsprQueryTreeName( &DnsTreeName );
  180. }
  181. RtlAcquireResourceExclusive(&NtLmGlobalCritSect, TRUE);
  182. if(!fInit && NT_SUCCESS( Status ))
  183. {
  184. if( NtLmGlobalUnicodeDnsTreeName.Buffer != NULL )
  185. {
  186. NtLmFree( NtLmGlobalUnicodeDnsTreeName.Buffer );
  187. }
  188. RtlCopyMemory(&NtLmGlobalUnicodeDnsTreeName, &DnsTreeName, sizeof(DnsTreeName));
  189. }
  190. //
  191. // Do this only if this is package init
  192. //
  193. if (fInit)
  194. {
  195. if (ComputerName && ComputerName->Buffer != NULL)
  196. {
  197. ULONG cLength = ComputerName->Length / sizeof(WCHAR);
  198. if ((ComputerName->Length + sizeof(WCHAR)) > sizeof(NtLmGlobalUnicodeComputerName))
  199. {
  200. // Bad ComputerName
  201. Status = STATUS_INVALID_COMPUTER_NAME;
  202. SspPrint((SSP_CRITICAL, "NtLmSetPolicyInfo, Bad computer name length is %d\n", cLength));
  203. goto CleanUp;
  204. }
  205. wcsncpy(NtLmGlobalUnicodeComputerName,
  206. ComputerName->Buffer,
  207. cLength);
  208. NtLmGlobalUnicodeComputerName[cLength] = UNICODE_NULL;
  209. // make NtlmGlobalUnicodeComputerNameString a string form
  210. RtlInitUnicodeString( &NtLmGlobalUnicodeComputerNameString,
  211. NtLmGlobalUnicodeComputerName );
  212. // Save old buffers for deleting
  213. ComputerNameAnsiString = NtLmGlobalOemComputerNameString;
  214. Status = RtlUpcaseUnicodeStringToOemString(
  215. &NtLmGlobalOemComputerNameString,
  216. &NtLmGlobalUnicodeComputerNameString,
  217. TRUE );
  218. if ( !NT_SUCCESS(Status) ) {
  219. Status = STATUS_SUCCESS;
  220. //SspPrint((SSP_CRITICAL, "NtLmSetPolicyInfo, Error from RtlUpcaseUnicodeStringToOemString is %d\n", Status));
  221. ComputerNameAnsiString.Buffer = NULL;
  222. // goto CleanUp;
  223. }
  224. }
  225. }
  226. //
  227. // Initialize various forms of the primary domain name of the local system
  228. // Do this only if this is package init or it's DnsDomain info
  229. //
  230. if (fInit || (ChangedInfoClass == PolicyNotifyDnsDomainInformation))
  231. {
  232. if (DnsComputerName && DnsComputerName->Buffer != NULL ) {
  233. ULONG cLength = DnsComputerName->Length / sizeof(WCHAR);
  234. if((DnsComputerName->Length + sizeof(WCHAR)) > sizeof(NtLmGlobalUnicodeDnsComputerName))
  235. {
  236. // Bad ComputerName
  237. Status = STATUS_INVALID_COMPUTER_NAME;
  238. SspPrint((SSP_CRITICAL, "NtLmSetPolicyInfo, Bad computer name length is %d\n", cLength));
  239. goto CleanUp;
  240. }
  241. wcsncpy(NtLmGlobalUnicodeDnsComputerName,
  242. DnsComputerName->Buffer,
  243. cLength);
  244. NtLmGlobalUnicodeDnsComputerName[cLength] = UNICODE_NULL;
  245. // make NtlmGlobalUnicodeDnsComputerNameString a string form
  246. RtlInitUnicodeString( &NtLmGlobalUnicodeDnsComputerNameString,
  247. NtLmGlobalUnicodeDnsComputerName );
  248. }
  249. if (DnsDomainName && DnsDomainName->Buffer != NULL ) {
  250. ULONG cLength = DnsDomainName->Length / sizeof(WCHAR);
  251. if((DnsDomainName->Length + sizeof(WCHAR)) > sizeof(NtLmGlobalUnicodeDnsDomainName))
  252. {
  253. // Bad ComputerName
  254. Status = STATUS_INVALID_COMPUTER_NAME;
  255. SspPrint((SSP_CRITICAL, "NtLmSetPolicyInfo, Bad domain name length is %d\n", cLength));
  256. goto CleanUp;
  257. }
  258. wcsncpy(NtLmGlobalUnicodeDnsDomainName,
  259. DnsDomainName->Buffer,
  260. cLength);
  261. NtLmGlobalUnicodeDnsDomainName[cLength] = UNICODE_NULL;
  262. // make NtlmGlobalUnicodeDnsDomainNameString a string form
  263. RtlInitUnicodeString( &NtLmGlobalUnicodeDnsDomainNameString,
  264. NtLmGlobalUnicodeDnsDomainName );
  265. }
  266. if (DomainName && DomainName->Buffer != NULL)
  267. {
  268. ULONG cLength = DomainName->Length / sizeof(WCHAR);
  269. if ((DomainName->Length + sizeof(WCHAR)) > sizeof(NtLmGlobalUnicodePrimaryDomainName))
  270. {
  271. Status = STATUS_NAME_TOO_LONG;
  272. SspPrint((SSP_CRITICAL, "NtLmSetPolicyInfo, Bad domain name length is %d\n", cLength));
  273. goto CleanUp;
  274. }
  275. wcsncpy(NtLmGlobalUnicodePrimaryDomainName,
  276. DomainName->Buffer,
  277. cLength);
  278. NtLmGlobalUnicodePrimaryDomainName[cLength] = UNICODE_NULL;
  279. // make NtlmGlobalUnicodePrimaryDomainNameString a string form
  280. RtlInitUnicodeString( &NtLmGlobalUnicodePrimaryDomainNameString,
  281. NtLmGlobalUnicodePrimaryDomainName );
  282. // Save old buffers for deleting
  283. DomainNameAnsiString = NtLmGlobalOemPrimaryDomainNameString;
  284. Status = RtlUpcaseUnicodeStringToOemString(
  285. &NtLmGlobalOemPrimaryDomainNameString,
  286. &NtLmGlobalUnicodePrimaryDomainNameString,
  287. TRUE );
  288. if ( !NT_SUCCESS(Status) ) {
  289. // SspPrint((SSP_CRITICAL, "NtLmSetPolicyInfo, Error from RtlUpcaseUnicodeStringToOemString is %d\n", Status));
  290. DomainNameAnsiString.Buffer = NULL;
  291. // goto CleanUp;
  292. Status = STATUS_SUCCESS;
  293. }
  294. }
  295. }
  296. //
  297. // If this is a standalone windows NT workstation,
  298. // use the computer name as the Target name.
  299. //
  300. if ( DomainSid != NULL)
  301. {
  302. NtLmGlobalUnicodeTargetName = NtLmGlobalUnicodePrimaryDomainNameString;
  303. NtLmGlobalOemTargetName = NtLmGlobalOemPrimaryDomainNameString;
  304. NtLmGlobalTargetFlags = NTLMSSP_TARGET_TYPE_DOMAIN;
  305. NtLmGlobalDomainJoined = TRUE;
  306. }
  307. else
  308. {
  309. NtLmGlobalUnicodeTargetName = NtLmGlobalUnicodeComputerNameString;
  310. NtLmGlobalOemTargetName = NtLmGlobalOemComputerNameString;
  311. NtLmGlobalTargetFlags = NTLMSSP_TARGET_TYPE_SERVER;
  312. NtLmGlobalDomainJoined = FALSE;
  313. }
  314. //
  315. // update the GlobalNtlm3 targetinfo.
  316. //
  317. Status = SsprUpdateTargetInfo();
  318. CleanUp:
  319. RtlReleaseResource(&NtLmGlobalCritSect);
  320. if (ComputerNameAnsiString.Buffer)
  321. {
  322. RtlFreeOemString(&ComputerNameAnsiString);
  323. }
  324. if (DomainNameAnsiString.Buffer)
  325. {
  326. RtlFreeOemString(&DomainNameAnsiString);
  327. }
  328. return Status;
  329. }
  330. NET_API_STATUS
  331. NtLmFlushLogonCache (
  332. VOID
  333. )
  334. /*++
  335. Routine Description:
  336. This function flushes the logon cache. This is done on unjoin.
  337. If the cache were not flushed, a user could logon to cached credentials after the unjoin.
  338. That is especially bad since Winlogon now tries a cached logon to improve boot times.
  339. Return Value:
  340. NERR_Success -- Success
  341. --*/
  342. {
  343. NET_API_STATUS NetStatus;
  344. HKEY hKey = NULL;
  345. #define NETSETUPP_LOGON_CACHE_PATH L"SECURITY\\Cache"
  346. #define NETSETUPP_LOGON_CACHE_VALUE L"NL$Control"
  347. //
  348. // Open the key containing the cache
  349. //
  350. NetStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  351. NETSETUPP_LOGON_CACHE_PATH,
  352. 0,
  353. KEY_SET_VALUE,
  354. &hKey );
  355. if ( NetStatus == ERROR_SUCCESS ) {
  356. //
  357. // Delete the value describing the size of the cache
  358. // This ensures the values cannot be used
  359. //
  360. RegDeleteValue( hKey, NETSETUPP_LOGON_CACHE_VALUE );
  361. RegCloseKey( hKey );
  362. }
  363. return NetStatus;
  364. }
  365. //+-------------------------------------------------------------------------
  366. //
  367. // Function: NtLmPolicyChangeCallback
  368. //
  369. // Synopsis: Function to be called when domain policy changes
  370. //
  371. // Effects:
  372. //
  373. // Arguments:
  374. //
  375. // Requires:
  376. //
  377. // Returns:
  378. //
  379. // Notes:
  380. //
  381. //
  382. //--------------------------------------------------------------------------
  383. VOID NTAPI
  384. NtLmPolicyChangeCallback(
  385. IN POLICY_NOTIFICATION_INFORMATION_CLASS ChangedInfoClass
  386. )
  387. {
  388. NTSTATUS Status = STATUS_SUCCESS;
  389. PLSAPR_POLICY_INFORMATION Policy = NULL;
  390. switch (ChangedInfoClass)
  391. {
  392. case PolicyNotifyDnsDomainInformation:
  393. {
  394. WCHAR UnicodeDnsComputerName[DNS_MAX_NAME_LENGTH + 1];
  395. UNICODE_STRING UnicodeDnsComputerNameString;
  396. ULONG DnsComputerNameLength = sizeof(UnicodeDnsComputerName) / sizeof(WCHAR);
  397. //
  398. // Get the new domain information
  399. //
  400. Status = I_LsaIQueryInformationPolicyTrusted(
  401. PolicyDnsDomainInformation,
  402. &Policy
  403. );
  404. if (!NT_SUCCESS(Status))
  405. {
  406. SspPrint((SSP_CRITICAL, "NtLmPolicyChangeCallback, Error from I_LsaIQueryInformationPolicyTrusted is %d\n", Status));
  407. goto Cleanup;
  408. }
  409. //
  410. // get the new DNS computer name
  411. //
  412. if ( !GetComputerNameExW( ComputerNameDnsFullyQualified,
  413. UnicodeDnsComputerName,
  414. &DnsComputerNameLength ) )
  415. {
  416. UnicodeDnsComputerName[ 0 ] = L'\0';
  417. }
  418. RtlInitUnicodeString( &UnicodeDnsComputerNameString,
  419. UnicodeDnsComputerName);
  420. Status = NtLmSetPolicyInfo(
  421. &UnicodeDnsComputerNameString,
  422. NULL,
  423. (PUNICODE_STRING) &Policy->PolicyDnsDomainInfo.DnsDomainName,
  424. (PUNICODE_STRING) &Policy->PolicyDnsDomainInfo.Name,
  425. (PSID) Policy->PolicyDnsDomainInfo.Sid,
  426. ChangedInfoClass,
  427. FALSE);
  428. if (!NT_SUCCESS(Status))
  429. {
  430. SspPrint((SSP_CRITICAL, "NtLmPolicyChangeCallback, Error from NtLmSetDomainName is %d\n", Status));
  431. goto Cleanup;
  432. }
  433. {
  434. BOOLEAN FlushLogonCache = FALSE;
  435. if( NtLmSecPkg.DomainSid == NULL &&
  436. Policy->PolicyDnsDomainInfo.Sid != NULL
  437. )
  438. {
  439. FlushLogonCache = TRUE;
  440. }
  441. if( NtLmSecPkg.DomainSid != NULL &&
  442. Policy->PolicyDnsDomainInfo.Sid == NULL
  443. )
  444. {
  445. FlushLogonCache = TRUE;
  446. }
  447. if( NtLmSecPkg.DomainSid != NULL &&
  448. Policy->PolicyDnsDomainInfo.Sid != NULL
  449. )
  450. {
  451. if(!RtlEqualSid( NtLmSecPkg.DomainSid, Policy->PolicyDnsDomainInfo.Sid ))
  452. {
  453. FlushLogonCache = TRUE;
  454. }
  455. }
  456. if( FlushLogonCache )
  457. {
  458. //
  459. // flush the logon cache...
  460. //
  461. NtLmFlushLogonCache();
  462. }
  463. }
  464. }
  465. break;
  466. default:
  467. break;
  468. }
  469. Cleanup:
  470. if (Policy != NULL)
  471. {
  472. switch (ChangedInfoClass)
  473. {
  474. case PolicyNotifyDnsDomainInformation:
  475. {
  476. I_LsaIFree_LSAPR_POLICY_INFORMATION(
  477. PolicyDnsDomainInformation,
  478. Policy
  479. );
  480. }
  481. break;
  482. default:
  483. break;
  484. }
  485. }
  486. return;
  487. }
  488. //+-------------------------------------------------------------------------
  489. //
  490. // Function: NtLmRegisterForPolicyChange
  491. //
  492. // Synopsis: Register with the LSA to be notified of policy changes
  493. //
  494. // Effects:
  495. //
  496. // Arguments:
  497. //
  498. // Requires:
  499. //
  500. // Returns:
  501. //
  502. // Notes:
  503. //
  504. //
  505. //--------------------------------------------------------------------------
  506. NTSTATUS
  507. NtLmRegisterForPolicyChange(
  508. IN POLICY_NOTIFICATION_INFORMATION_CLASS ChangedInfoClass
  509. )
  510. {
  511. NTSTATUS Status = STATUS_SUCCESS;
  512. Status = I_LsaIRegisterPolicyChangeNotificationCallback(
  513. NtLmPolicyChangeCallback,
  514. ChangedInfoClass
  515. );
  516. if (!NT_SUCCESS(Status))
  517. {
  518. SspPrint((SSP_CRITICAL, "NtLmRegisterForPolicyChange, Error from I_LsaIRegisterPolicyChangeNotificationCallback is %d\n", Status));
  519. }
  520. SspPrint((SSP_MISC, "I_LsaIRegisterPolicyChangeNotificationCallback called with %d\n", ChangedInfoClass));
  521. return(Status);
  522. }
  523. //+-------------------------------------------------------------------------
  524. //
  525. // Function: NtLmUnregisterForPolicyChange
  526. //
  527. // Synopsis: Unregister for policy change notification
  528. //
  529. // Effects:
  530. //
  531. // Arguments:
  532. //
  533. // Requires:
  534. //
  535. // Returns:
  536. //
  537. // Notes:
  538. //
  539. //
  540. //--------------------------------------------------------------------------
  541. VOID
  542. NtLmUnregisterForPolicyChange(
  543. IN POLICY_NOTIFICATION_INFORMATION_CLASS ChangedInfoClass
  544. )
  545. {
  546. (VOID) I_LsaIUnregisterPolicyChangeNotificationCallback(
  547. NtLmPolicyChangeCallback,
  548. ChangedInfoClass
  549. );
  550. }
  551. //+--------------------------------------------------------------------
  552. //
  553. // Function: SpInitialize
  554. //
  555. // Synopsis: Initializes the Security package
  556. //
  557. // Arguments: PackageId - Contains ID for this package assigned by LSA
  558. // Parameters - Contains machine-specific information
  559. // FunctionTable - Contains table of LSA helper routines
  560. //
  561. // Returns: None
  562. //
  563. // Notes: Everything that was done in LsaApInitializePackage
  564. // should be done here. Lsa assures us that only
  565. // one thread is executing this at a time. Don't
  566. // have to worry about concurrency problems.
  567. // Most of the stuff was taken from SspCommonInitialize()
  568. // from svcdlls\ntlmssp\common\initcomn.c
  569. //
  570. //---------------------------------------------------------------------
  571. NTSTATUS NTAPI
  572. SpInitialize(
  573. IN ULONG_PTR PackageId,
  574. IN PSECPKG_PARAMETERS Parameters,
  575. IN PLSA_SECPKG_FUNCTION_TABLE FunctionTable
  576. )
  577. {
  578. SspPrint((SSP_API, "Entering SpInitialize\n"));
  579. SECURITY_STATUS Status = SEC_E_OK;
  580. WCHAR UnicodeComputerName[CNLEN + 1];
  581. UNICODE_STRING UnicodeComputerNameString;
  582. ULONG ComputerNameLength =
  583. (sizeof(UnicodeComputerName)/sizeof(WCHAR));
  584. WCHAR UnicodeDnsComputerName[DNS_MAX_NAME_LENGTH + 1];
  585. UNICODE_STRING UnicodeDnsComputerNameString;
  586. ULONG DnsComputerNameLength = sizeof(UnicodeDnsComputerName) / sizeof(WCHAR);
  587. //
  588. // Init the global crit section
  589. //
  590. RtlInitializeResource(&NtLmGlobalCritSect);
  591. RtlInitializeResource(&NtLmProcessOptionsLock);
  592. InitializeListHead( &NtLmProcessOptionsList );
  593. //
  594. // All the following are global
  595. //
  596. NtLmState = NtLmLsaMode;
  597. NtLmPackageId = PackageId;
  598. // We really need this to be a day less than maxtime so when callers
  599. // of sspi convert to utc, they won't get time in the past.
  600. NtLmGlobalForever.HighPart = 0x7FFFFF36;
  601. NtLmGlobalForever.LowPart = 0xD5969FFF;
  602. //
  603. // Following are local
  604. //
  605. NtLmCredentialInitialized = FALSE;
  606. NtLmContextInitialized = FALSE;
  607. NtLmRNGInitialized = FALSE;
  608. //
  609. // Save away the Lsa functions
  610. //
  611. LsaFunctions = FunctionTable;
  612. //
  613. // Save the Parameters info
  614. //
  615. NtLmSecPkg.MachineState = Parameters->MachineState;
  616. NtLmSecPkg.SetupMode = Parameters->SetupMode;
  617. //
  618. // allocate a locally unique ID rereferencing the machine logon.
  619. //
  620. Status = NtAllocateLocallyUniqueId( &NtLmGlobalLuidMachineLogon );
  621. if (!NT_SUCCESS (Status))
  622. {
  623. SspPrint((SSP_CRITICAL, "SpInitialize, Error from NtAllocateLocallyUniqueId is %d\n", Status));
  624. goto CleanUp;
  625. }
  626. //
  627. // create a logon session for the machine logon.
  628. //
  629. Status = LsaFunctions->CreateLogonSession( &NtLmGlobalLuidMachineLogon );
  630. if( !NT_SUCCESS(Status) ) {
  631. SspPrint((SSP_CRITICAL, "SpInitialize, Error from CreateLogonSession is %d\n", Status));
  632. goto CleanUp;
  633. }
  634. Status = NtLmDuplicateUnicodeString(
  635. &NtLmSecPkg.DomainName,
  636. &Parameters->DomainName);
  637. if (!NT_SUCCESS (Status))
  638. {
  639. SspPrint((SSP_CRITICAL, "SpInitialize, Error from NtLmDuplicateUnicodeString is %d\n", Status));
  640. goto CleanUp;
  641. }
  642. Status = NtLmDuplicateUnicodeString(
  643. &NtLmSecPkg.DnsDomainName,
  644. &Parameters->DnsDomainName);
  645. if (!NT_SUCCESS (Status))
  646. {
  647. SspPrint((SSP_CRITICAL, "SpInitialize, Error from NtLmDuplicateUnicodeString is %d\n", Status));
  648. goto CleanUp;
  649. }
  650. if (Parameters->DomainSid != NULL) {
  651. Status = NtLmDuplicateSid( &NtLmSecPkg.DomainSid,
  652. Parameters->DomainSid );
  653. if (!NT_SUCCESS (Status))
  654. {
  655. SspPrint((SSP_CRITICAL, "SpInitialize, Error from NtLmDuplicateSid is %d\n", Status));
  656. goto CleanUp;
  657. }
  658. }
  659. //
  660. // Determine if this machine is running NT Workstation or NT Server
  661. //
  662. if (!RtlGetNtProductType (&NtLmGlobalNtProductType))
  663. {
  664. SspPrint((SSP_API_MORE, "RtlGetNtProductType defaults to NtProductWinNt\n"));
  665. }
  666. //
  667. // Determine if we are running Personal SKU
  668. //
  669. {
  670. OSVERSIONINFOEXW osvi;
  671. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
  672. if(GetVersionExW((OSVERSIONINFOW*)&osvi))
  673. {
  674. NtLmGlobalPersonalSKU = ( osvi.wProductType == VER_NT_WORKSTATION && (osvi.wSuiteMask & VER_SUITE_PERSONAL));
  675. } else {
  676. SspPrint((SSP_API_MORE, "GetVersionEx defaults to non-personal\n"));
  677. }
  678. }
  679. Status = I_LsaIOpenPolicyTrusted(&NtLmGlobalPolicyHandle);
  680. if ( !NT_SUCCESS(Status) ) {
  681. SspPrint((SSP_CRITICAL, "SpInitialize, Error from I_LsaIOpenPolicyTrusted is %d\n", Status));
  682. goto CleanUp;
  683. }
  684. if ( !GetComputerNameW( UnicodeComputerName,
  685. &ComputerNameLength ) ) {
  686. Status = STATUS_INVALID_COMPUTER_NAME;
  687. SspPrint((SSP_CRITICAL, "SpInitialize, Error from GetComputerNameW is %d\n", Status));
  688. goto CleanUp;
  689. }
  690. if ( !GetComputerNameExW( ComputerNameDnsFullyQualified,
  691. UnicodeDnsComputerName,
  692. &DnsComputerNameLength ) )
  693. {
  694. //
  695. // per CliffV, failure is legal.
  696. //
  697. UnicodeDnsComputerName[ 0 ] = L'\0';
  698. }
  699. {
  700. SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
  701. (VOID)AllocateAndInitializeSid(
  702. &siaNtAuthority,
  703. 1,
  704. SECURITY_ANONYMOUS_LOGON_RID,
  705. 0, 0, 0, 0, 0, 0, 0,
  706. &NtLmGlobalAnonymousSid
  707. );
  708. }
  709. //
  710. // pickup a copy of the Local System access token.
  711. //
  712. {
  713. HANDLE hProcessToken;
  714. NTSTATUS StatusToken;
  715. StatusToken = NtOpenProcessToken(
  716. NtCurrentProcess(),
  717. TOKEN_QUERY | TOKEN_DUPLICATE,
  718. &hProcessToken
  719. );
  720. if( NT_SUCCESS( StatusToken ) ) {
  721. TOKEN_STATISTICS LocalTokenStatistics;
  722. DWORD TokenStatisticsSize = sizeof(LocalTokenStatistics);
  723. LUID LogonIdSystem = SYSTEM_LUID;
  724. Status = NtQueryInformationToken(
  725. hProcessToken,
  726. TokenStatistics,
  727. &LocalTokenStatistics,
  728. TokenStatisticsSize,
  729. &TokenStatisticsSize
  730. );
  731. if( NT_SUCCESS( Status ) ) {
  732. //
  733. // see if it's SYSTEM.
  734. //
  735. if(RtlEqualLuid(
  736. &LogonIdSystem,
  737. &(LocalTokenStatistics.AuthenticationId)
  738. )) {
  739. Status = SspDuplicateToken(
  740. hProcessToken,
  741. SecurityImpersonation,
  742. &NtLmGlobalAccessTokenSystem
  743. );
  744. }
  745. }
  746. NtClose( hProcessToken );
  747. }
  748. }
  749. if (!NT_SUCCESS (Status))
  750. {
  751. SspPrint((SSP_CRITICAL, "SpInitialize, could not acquire SYSTEM token %d\n", Status));
  752. goto CleanUp;
  753. }
  754. //
  755. // Init the Credential stuff
  756. //
  757. Status = SspCredentialInitialize();
  758. if (!NT_SUCCESS (Status))
  759. {
  760. SspPrint((SSP_CRITICAL, "SpInitialize, Error from SspCredentialInitializeis %d\n", Status));
  761. goto CleanUp;
  762. }
  763. NtLmCredentialInitialized = TRUE;
  764. //
  765. // Init the Context stuff
  766. //
  767. Status = SspContextInitialize();
  768. if (!NT_SUCCESS (Status))
  769. {
  770. SspPrint((SSP_CRITICAL, "SpInitialize, Error from SspContextInitializeis %d\n", Status));
  771. goto CleanUp;
  772. }
  773. NtLmContextInitialized = TRUE;
  774. //
  775. // Get the locale and check if it is FRANCE, which doesn't allow
  776. // encryption
  777. //
  778. NtLmGlobalEncryptionEnabled = IsEncryptionPermitted();
  779. //
  780. // Init the random number generator stuff
  781. //
  782. if( !NtLmInitializeRNG() ) {
  783. SspPrint((SSP_CRITICAL, "SpInitialize, Error from NtLmInitializeRNG\n"));
  784. Status = STATUS_UNSUCCESSFUL;
  785. goto CleanUp;
  786. }
  787. NtLmRNGInitialized = TRUE;
  788. NtLmCheckLmCompatibility();
  789. if( NtLmSecPkg.DomainSid != NULL )
  790. {
  791. NtLmGlobalDomainJoined = TRUE;
  792. }
  793. NtLmQueryMappedDomains();
  794. //
  795. // Set all the globals relating to computer name, domain name, sid etc.
  796. // This routine is also used by the callback for notifications from the lsa
  797. //
  798. RtlInitUnicodeString( &UnicodeComputerNameString,
  799. UnicodeComputerName);
  800. RtlInitUnicodeString( &UnicodeDnsComputerNameString,
  801. UnicodeDnsComputerName);
  802. Status = NtLmSetPolicyInfo( &UnicodeDnsComputerNameString,
  803. &UnicodeComputerNameString,
  804. &NtLmSecPkg.DnsDomainName,
  805. &NtLmSecPkg.DomainName,
  806. NtLmSecPkg.DomainSid,
  807. PolicyNotifyAuditEventsInformation, // Ignored
  808. TRUE ); // yes, package init
  809. if (!NT_SUCCESS (Status))
  810. {
  811. SspPrint((SSP_CRITICAL, "SpInitialize, Error from NtLmSetDomainInfo %d\n", Status));
  812. goto CleanUp;
  813. }
  814. // Do the Init stuff for the MSV authentication package
  815. // Passing FunctionTable as a (PLSA_DISPATCH_TABLE).
  816. // Well, the first 11 entries are the same. Cheating a
  817. // bit.
  818. Status = LsaApInitializePackage(
  819. (ULONG) PackageId,
  820. (PLSA_DISPATCH_TABLE)FunctionTable,
  821. NULL,
  822. NULL,
  823. NULL);
  824. if (!NT_SUCCESS (Status))
  825. {
  826. SspPrint((SSP_CRITICAL, "SpInitialize, Error from LsaApInitializePackage is %d\n", Status));
  827. goto CleanUp;
  828. }
  829. Status = NtLmRegisterForPolicyChange(PolicyNotifyDnsDomainInformation);
  830. if (!NT_SUCCESS (Status))
  831. {
  832. SspPrint((SSP_CRITICAL, "SpInitialize, Error from NtLmRegisterForPolicyChange is %d\n", Status));
  833. goto CleanUp;
  834. }
  835. CleanUp:
  836. if (!NT_SUCCESS (Status))
  837. {
  838. SpShutdown();
  839. }
  840. SspPrint((SSP_API, "Leaving SpInitialize\n"));
  841. return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  842. }
  843. //+--------------------------------------------------------------------
  844. //
  845. // Function: SpShutdown
  846. //
  847. // Synopsis: Exported function to shutdown the Security package.
  848. //
  849. // Effects: Forces the freeing of all credentials, contexts
  850. // and frees all global data
  851. //
  852. // Arguments: none
  853. //
  854. // Returns:
  855. //
  856. // Notes: SEC_E_OK in all cases
  857. // Most of the stuff was taken from SspCommonShutdown()
  858. // from svcdlls\ntlmssp\common\initcomn.c
  859. //
  860. //
  861. //---------------------------------------------------------------------
  862. NTSTATUS NTAPI
  863. SpShutdown(
  864. VOID
  865. )
  866. {
  867. SspPrint((SSP_API, "Entering SpShutdown\n"));
  868. //
  869. // comment out LSA mode cleanup code, per NTBUG 400026,
  870. // which can result in access violations during shutdown when
  871. // calls into package are still occuring during shutdown.
  872. //
  873. #if 0
  874. if (NtLmContextInitialized)
  875. {
  876. SspContextTerminate();
  877. NtLmContextInitialized = FALSE;
  878. }
  879. if (NtLmCredentialInitialized)
  880. {
  881. SspCredentialTerminate();
  882. NtLmCredentialInitialized = FALSE;
  883. }
  884. if (NtLmGlobalOemComputerNameString.Buffer != NULL)
  885. {
  886. RtlFreeOemString(&NtLmGlobalOemComputerNameString);
  887. NtLmGlobalOemComputerNameString.Buffer = NULL;
  888. }
  889. if (NtLmGlobalOemPrimaryDomainNameString.Buffer != NULL)
  890. {
  891. RtlFreeOemString(&NtLmGlobalOemPrimaryDomainNameString);
  892. NtLmGlobalOemPrimaryDomainNameString.Buffer = NULL;
  893. }
  894. if (NtLmGlobalNtLm3TargetInfo.Buffer != NULL)
  895. {
  896. NtLmFree (NtLmGlobalNtLm3TargetInfo.Buffer);
  897. NtLmGlobalNtLm3TargetInfo.Buffer = NULL;
  898. }
  899. if ( NtLmSecPkg.DomainName.Buffer != NULL )
  900. {
  901. NtLmFree (NtLmSecPkg.DomainName.Buffer);
  902. }
  903. if ( NtLmSecPkg.DnsDomainName.Buffer != NULL )
  904. {
  905. NtLmFree (NtLmSecPkg.DnsDomainName.Buffer);
  906. }
  907. if ( NtLmSecPkg.DomainSid != NULL )
  908. {
  909. NtLmFree (NtLmSecPkg.DomainSid);
  910. }
  911. if (NtLmGlobalLocalSystemSid != NULL)
  912. {
  913. FreeSid( NtLmGlobalLocalSystemSid);
  914. NtLmGlobalLocalSystemSid = NULL;
  915. }
  916. if (NtLmGlobalAliasAdminsSid != NULL)
  917. {
  918. FreeSid( NtLmGlobalAliasAdminsSid);
  919. NtLmGlobalAliasAdminsSid = NULL;
  920. }
  921. if (NtLmGlobalProcessUserSid != NULL)
  922. {
  923. NtLmFree( NtLmGlobalProcessUserSid );
  924. NtLmGlobalProcessUserSid = NULL;
  925. }
  926. if( NtLmGlobalAnonymousSid )
  927. {
  928. FreeSid( NtLmGlobalAnonymousSid );
  929. NtLmGlobalAnonymousSid = NULL;
  930. }
  931. if (NtLmRNGInitialized)
  932. {
  933. NtLmCleanupRNG();
  934. NtLmRNGInitialized = FALSE;
  935. }
  936. NtLmFreeMappedDomains();
  937. NtLmUnregisterForPolicyChange(PolicyNotifyDnsDomainInformation);
  938. if (NtLmGlobalAccessTokenSystem != NULL) {
  939. NtClose( NtLmGlobalAccessTokenSystem );
  940. NtLmGlobalAccessTokenSystem = NULL;
  941. }
  942. RtlDeleteResource(&NtLmGlobalCritSect);
  943. if (NtLmGlobalPolicyHandle != NULL) {
  944. (VOID) I_LsarClose( &NtLmGlobalPolicyHandle );
  945. }
  946. SspPrint((SSP_API, "Leaving SpShutdown\n"));
  947. #if DBG
  948. DeleteCriticalSection(&SspGlobalLogFileCritSect);
  949. #endif
  950. #endif // NTBUG 400026
  951. return(SEC_E_OK);
  952. }
  953. //+--------------------------------------------------------------------
  954. //
  955. // Function: SpGetInfo
  956. //
  957. // Synopsis: Returns information about the package
  958. //
  959. // Effects: returns pointers to global data
  960. //
  961. // Arguments: PackageInfo - Receives security package information
  962. //
  963. // Returns: SEC_E_OK in all cases
  964. //
  965. // Notes: Pointers to constants ok. Lsa will copy the data
  966. // before sending it to someone else
  967. //
  968. //---------------------------------------------------------------------
  969. NTSTATUS NTAPI
  970. SpGetInfo(
  971. OUT PSecPkgInfo PackageInfo
  972. )
  973. {
  974. SspPrint((SSP_API, "Entering SpGetInfo\n"));
  975. PackageInfo->fCapabilities = NTLMSP_CAPS;
  976. PackageInfo->wVersion = SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION;
  977. PackageInfo->wRPCID = RPC_C_AUTHN_WINNT;
  978. PackageInfo->cbMaxToken = NTLMSP_MAX_TOKEN_SIZE;
  979. PackageInfo->Name = NTLMSP_NAME;
  980. PackageInfo->Comment = NTLMSP_COMMENT;
  981. SspPrint((SSP_API, "Leaving SpGetInfo\n"));
  982. return(SEC_E_OK);
  983. }
  984. NTSTATUS
  985. NTAPI
  986. SpGetExtendedInformation(
  987. IN SECPKG_EXTENDED_INFORMATION_CLASS Class,
  988. OUT PSECPKG_EXTENDED_INFORMATION * ppInformation
  989. )
  990. {
  991. NTSTATUS Status = STATUS_SUCCESS;
  992. PSECPKG_EXTENDED_INFORMATION Information = NULL;
  993. ULONG Size ;
  994. switch ( Class )
  995. {
  996. case SecpkgContextThunks:
  997. Information = (PSECPKG_EXTENDED_INFORMATION)
  998. NtLmAllocate(sizeof(SECPKG_EXTENDED_INFORMATION) + sizeof(DWORD));
  999. if (Information == NULL)
  1000. {
  1001. Status = STATUS_INSUFFICIENT_RESOURCES;
  1002. goto Cleanup;
  1003. }
  1004. Information->Class = SecpkgContextThunks;
  1005. Information->Info.ContextThunks.InfoLevelCount = 1;
  1006. Information->Info.ContextThunks.Levels[0] = SECPKG_ATTR_CREDENTIAL_NAME;
  1007. *ppInformation = Information;
  1008. Information = NULL;
  1009. break;
  1010. case SecpkgWowClientDll:
  1011. //
  1012. // This indicates that we're smart enough to handle wow client processes
  1013. //
  1014. Information = (PSECPKG_EXTENDED_INFORMATION)
  1015. NtLmAllocate( sizeof( SECPKG_EXTENDED_INFORMATION ) +
  1016. (MAX_PATH * sizeof(WCHAR) ) );
  1017. if ( Information == NULL )
  1018. {
  1019. Status = STATUS_INSUFFICIENT_RESOURCES ;
  1020. goto Cleanup ;
  1021. }
  1022. Information->Class = SecpkgWowClientDll ;
  1023. Information->Info.WowClientDll.WowClientDllPath.Buffer = (PWSTR) (Information + 1);
  1024. Size = ExpandEnvironmentStrings(
  1025. L"%SystemRoot%\\" WOW64_SYSTEM_DIRECTORY_U L"\\msv1_0.DLL",
  1026. Information->Info.WowClientDll.WowClientDllPath.Buffer,
  1027. MAX_PATH );
  1028. Information->Info.WowClientDll.WowClientDllPath.Length = (USHORT) (Size * sizeof(WCHAR));
  1029. Information->Info.WowClientDll.WowClientDllPath.MaximumLength = (USHORT) ((Size + 1) * sizeof(WCHAR) );
  1030. *ppInformation = Information ;
  1031. Information = NULL ;
  1032. break;
  1033. default:
  1034. Status = SEC_E_UNSUPPORTED_FUNCTION ;
  1035. }
  1036. Cleanup:
  1037. if ( Information != NULL )
  1038. {
  1039. NtLmFree( Information );
  1040. }
  1041. return Status ;
  1042. }
  1043. NTSTATUS
  1044. NTAPI
  1045. SpSetExtendedInformation(
  1046. IN SECPKG_EXTENDED_INFORMATION_CLASS Class,
  1047. IN PSECPKG_EXTENDED_INFORMATION Info
  1048. )
  1049. {
  1050. NTSTATUS Status ;
  1051. switch ( Class )
  1052. {
  1053. case SecpkgMutualAuthLevel:
  1054. NtLmGlobalMutualAuthLevel = Info->Info.MutualAuthLevel.MutualAuthLevel ;
  1055. Status = SEC_E_OK ;
  1056. break;
  1057. default:
  1058. Status = SEC_E_UNSUPPORTED_FUNCTION ;
  1059. break;
  1060. }
  1061. return Status ;
  1062. }
  1063. VOID
  1064. NtLmCheckLmCompatibility(
  1065. )
  1066. /*++
  1067. Routine Description:
  1068. This routine checks to see if we should support the LM challenge
  1069. response protocol by looking in the registry under
  1070. system\currentcontrolset\Control\Lsa\LmCompatibilityLevel. The level
  1071. indicates whether to send the LM reponse by default and whether to
  1072. ever send the LM response
  1073. Arguments:
  1074. none.
  1075. Return Value:
  1076. None
  1077. --*/
  1078. {
  1079. NTSTATUS NtStatus;
  1080. UNICODE_STRING KeyName;
  1081. OBJECT_ATTRIBUTES ObjectAttributes;
  1082. HANDLE KeyHandle;
  1083. //
  1084. // initialize defaults
  1085. // Assume that LM is supported.
  1086. //
  1087. NtLmGlobalLmProtocolSupported = 0;
  1088. NtLmGlobalRequireNtlm2 = FALSE;
  1089. NtLmGlobalDatagramUse128BitEncryption = FALSE;
  1090. NtLmGlobalDatagramUse56BitEncryption = FALSE;
  1091. //
  1092. // Open the Lsa key in the registry
  1093. //
  1094. RtlInitUnicodeString(
  1095. &KeyName,
  1096. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Lsa"
  1097. );
  1098. InitializeObjectAttributes(
  1099. &ObjectAttributes,
  1100. &KeyName,
  1101. OBJ_CASE_INSENSITIVE,
  1102. 0,
  1103. NULL
  1104. );
  1105. NtStatus = NtOpenKey(
  1106. &KeyHandle,
  1107. KEY_READ,
  1108. &ObjectAttributes
  1109. );
  1110. if (!NT_SUCCESS(NtStatus)) {
  1111. return;
  1112. }
  1113. //
  1114. // save away registry key so we can use it for notification events.
  1115. //
  1116. NtLmGlobalLsaKey = (HKEY)KeyHandle;
  1117. // now open the MSV1_0 subkey...
  1118. RtlInitUnicodeString(
  1119. &KeyName,
  1120. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Lsa\\Msv1_0"
  1121. );
  1122. InitializeObjectAttributes(
  1123. &ObjectAttributes,
  1124. &KeyName,
  1125. OBJ_CASE_INSENSITIVE,
  1126. 0,
  1127. NULL
  1128. );
  1129. NtStatus = NtOpenKey(
  1130. &KeyHandle,
  1131. KEY_READ,
  1132. &ObjectAttributes
  1133. );
  1134. if (!NT_SUCCESS(NtStatus)) {
  1135. return;
  1136. }
  1137. //
  1138. // save away registry key so we can use it for notification events.
  1139. //
  1140. NtLmGlobalLsaMsv1_0Key = (HKEY)KeyHandle;
  1141. }
  1142. ULONG
  1143. NtLmValidMinimumSecurityFlagsMask(
  1144. IN ULONG MinimumSecurity
  1145. )
  1146. /*++
  1147. This routine takes a NtLmMinimumClientSec or NtLmMinimumServerSec registry
  1148. value and masks off the bits that are not relevant for enforcing the
  1149. supported options.
  1150. --*/
  1151. {
  1152. return (MinimumSecurity & (
  1153. NTLMSSP_NEGOTIATE_UNICODE |
  1154. NTLMSSP_NEGOTIATE_SIGN |
  1155. NTLMSSP_NEGOTIATE_SEAL |
  1156. NTLMSSP_NEGOTIATE_NTLM2 |
  1157. NTLMSSP_NEGOTIATE_128 |
  1158. NTLMSSP_NEGOTIATE_KEY_EXCH |
  1159. NTLMSSP_NEGOTIATE_56
  1160. ));
  1161. }
  1162. VOID
  1163. NTAPI
  1164. NtLmQueryDynamicGlobals(
  1165. PVOID pvContext,
  1166. BOOLEAN f
  1167. )
  1168. {
  1169. SspPrint((SSP_API, "Entering NtLmQueryDynamicGlobals\n"));
  1170. HKEY KeyHandle; // open registry key to Lsa\MSV1_0
  1171. LONG RegStatus;
  1172. DWORD RegValueType;
  1173. DWORD RegValue;
  1174. DWORD RegValueSize;
  1175. KeyHandle = NtLmGlobalLsaKey;
  1176. if( KeyHandle != NULL )
  1177. {
  1178. //
  1179. // lm compatibility level.
  1180. //
  1181. RegValueSize = sizeof( RegValue );
  1182. RegStatus = RegQueryValueExW(
  1183. KeyHandle,
  1184. L"LmCompatibilityLevel",
  1185. NULL,
  1186. &RegValueType,
  1187. (PUCHAR)&RegValue,
  1188. &RegValueSize
  1189. );
  1190. if ( RegStatus == ERROR_SUCCESS ) {
  1191. //
  1192. // Check that the data is the correct size and type - a ULONG.
  1193. //
  1194. if ((RegValueSize >= sizeof(ULONG)) &&
  1195. (RegValueType == REG_DWORD)) {
  1196. NtLmGlobalLmProtocolSupported = (ULONG)RegValue;
  1197. }
  1198. } else if( RegStatus == ERROR_FILE_NOT_FOUND ) {
  1199. //
  1200. // value was deleted - resort to default.
  1201. //
  1202. NtLmGlobalLmProtocolSupported = 0;
  1203. }
  1204. //
  1205. // handle ForceGuest
  1206. //
  1207. if( NtLmGlobalNtProductType != NtProductLanManNt )
  1208. {
  1209. RegValueSize = sizeof( RegValue );
  1210. if( NtLmGlobalPersonalSKU )
  1211. {
  1212. //
  1213. // personal product always has ForceGuest turned on.
  1214. //
  1215. RegValueSize = sizeof(ULONG);
  1216. RegValueType = REG_DWORD;
  1217. RegValue = 1;
  1218. RegStatus = ERROR_SUCCESS;
  1219. } else {
  1220. if( NtLmGlobalDomainJoined )
  1221. {
  1222. //
  1223. // joined product always has ForceGuest turned off.
  1224. //
  1225. RegValueSize = sizeof(ULONG);
  1226. RegValueType = REG_DWORD;
  1227. RegValue = 0;
  1228. RegStatus = ERROR_SUCCESS;
  1229. } else {
  1230. RegStatus = RegQueryValueExW(
  1231. KeyHandle,
  1232. L"ForceGuest",
  1233. NULL,
  1234. &RegValueType,
  1235. (PUCHAR)&RegValue,
  1236. &RegValueSize
  1237. );
  1238. }
  1239. }
  1240. } else {
  1241. //
  1242. // insure ForceGuest is disabled for domain controllers.
  1243. //
  1244. RegStatus = ERROR_FILE_NOT_FOUND;
  1245. }
  1246. if ( RegStatus == ERROR_SUCCESS ) {
  1247. //
  1248. // Check that the data is the correct size and type - a ULONG.
  1249. //
  1250. if ( (RegValueSize >= sizeof(ULONG)) &&
  1251. (RegValueType == REG_DWORD) )
  1252. {
  1253. if( RegValue == 1 )
  1254. {
  1255. NtLmGlobalForceGuest = TRUE;
  1256. } else {
  1257. NtLmGlobalForceGuest = FALSE;
  1258. }
  1259. }
  1260. } else if( RegStatus == ERROR_FILE_NOT_FOUND ) {
  1261. //
  1262. // value was deleted - resort to default.
  1263. //
  1264. NtLmGlobalForceGuest = FALSE;
  1265. }
  1266. //
  1267. // handle LimitBlankPasswordUse
  1268. //
  1269. if( NtLmGlobalNtProductType != NtProductLanManNt )
  1270. {
  1271. RegValueSize = sizeof( RegValue );
  1272. RegStatus = RegQueryValueExW(
  1273. KeyHandle,
  1274. L"LimitBlankPasswordUse",
  1275. NULL,
  1276. &RegValueType,
  1277. (PUCHAR)&RegValue,
  1278. &RegValueSize
  1279. );
  1280. } else {
  1281. //
  1282. // domain controllers always allow blank.
  1283. //
  1284. NtLmGlobalAllowBlankPassword = TRUE;
  1285. RegStatus = ERROR_INVALID_PARAMETER;
  1286. }
  1287. if ( RegStatus == ERROR_SUCCESS ) {
  1288. //
  1289. // Check that the data is the correct size and type - a ULONG.
  1290. //
  1291. if ( (RegValueSize >= sizeof(ULONG)) &&
  1292. (RegValueType == REG_DWORD) )
  1293. {
  1294. if( RegValue == 0 )
  1295. {
  1296. NtLmGlobalAllowBlankPassword = TRUE;
  1297. } else {
  1298. NtLmGlobalAllowBlankPassword = FALSE;
  1299. }
  1300. }
  1301. } else if( RegStatus == ERROR_FILE_NOT_FOUND ) {
  1302. //
  1303. // value was deleted - resort to default.
  1304. //
  1305. NtLmGlobalAllowBlankPassword = FALSE;
  1306. }
  1307. }
  1308. KeyHandle = NtLmGlobalLsaMsv1_0Key;
  1309. if( KeyHandle != NULL )
  1310. {
  1311. //
  1312. // get minimum client security flag.
  1313. //
  1314. RegValueSize = sizeof( RegValue );
  1315. RegStatus = RegQueryValueExW(
  1316. KeyHandle,
  1317. L"NtlmMinClientSec",
  1318. NULL,
  1319. &RegValueType,
  1320. (PUCHAR)&RegValue,
  1321. &RegValueSize
  1322. );
  1323. if ( RegStatus == ERROR_SUCCESS ) {
  1324. //
  1325. // Check that the data is the correct size and type - a ULONG.
  1326. //
  1327. if ((RegValueSize >= sizeof(ULONG)) &&
  1328. (RegValueType == REG_DWORD)) {
  1329. NtLmGlobalMinimumClientSecurity =
  1330. NtLmValidMinimumSecurityFlagsMask( (ULONG)RegValue );
  1331. }
  1332. } else if( RegStatus == ERROR_FILE_NOT_FOUND ) {
  1333. //
  1334. // value was deleted - resort to default.
  1335. //
  1336. NtLmGlobalMinimumClientSecurity = 0 ;
  1337. }
  1338. //
  1339. // get minimum server security flags.
  1340. //
  1341. RegValueSize = sizeof( RegValueSize );
  1342. RegStatus = RegQueryValueExW(
  1343. KeyHandle,
  1344. L"NtlmMinServerSec",
  1345. NULL,
  1346. &RegValueType,
  1347. (PUCHAR)&RegValue,
  1348. &RegValueSize
  1349. );
  1350. if ( RegStatus == ERROR_SUCCESS ) {
  1351. //
  1352. // Check that the data is the correct size and type - a ULONG.
  1353. //
  1354. if ((RegValueSize >= sizeof(ULONG)) &&
  1355. (RegValueType == REG_DWORD)) {
  1356. NtLmGlobalMinimumServerSecurity =
  1357. NtLmValidMinimumSecurityFlagsMask( (ULONG)RegValue );
  1358. }
  1359. } else if( RegStatus == ERROR_FILE_NOT_FOUND ) {
  1360. //
  1361. // value was deleted - resort to default.
  1362. //
  1363. NtLmGlobalMinimumServerSecurity = 0;
  1364. }
  1365. //
  1366. // All datagram related flags need to be set.
  1367. //
  1368. if (NtLmGlobalMinimumClientSecurity & NTLMSSP_NEGOTIATE_NTLM2)
  1369. {
  1370. NtLmGlobalRequireNtlm2 = TRUE;
  1371. }
  1372. if ((NtLmGlobalMinimumClientSecurity & NTLMSSP_NEGOTIATE_128) &&
  1373. (NtLmSecPkg.MachineState & SECPKG_STATE_STRONG_ENCRYPTION_PERMITTED))
  1374. {
  1375. NtLmGlobalDatagramUse128BitEncryption = TRUE;
  1376. } else if (NtLmGlobalMinimumClientSecurity & NTLMSSP_NEGOTIATE_56) {
  1377. NtLmGlobalDatagramUse56BitEncryption = TRUE;
  1378. }
  1379. #if DBG
  1380. //
  1381. // get the debugging flag
  1382. //
  1383. RegValueSize = sizeof( RegValueSize );
  1384. RegStatus = RegQueryValueExW(
  1385. KeyHandle,
  1386. L"DBFlag",
  1387. NULL,
  1388. &RegValueType,
  1389. (PUCHAR)&RegValue,
  1390. &RegValueSize
  1391. );
  1392. if ( RegStatus == ERROR_SUCCESS ) {
  1393. //
  1394. // Check that the data is the correct size and type - a ULONG.
  1395. //
  1396. if ((RegValueSize >= sizeof(ULONG)) &&
  1397. (RegValueType == REG_DWORD)) {
  1398. SspGlobalDbflag = (ULONG)RegValue;
  1399. }
  1400. }
  1401. #endif
  1402. }
  1403. //
  1404. // (re)register the wait events.
  1405. //
  1406. if( NtLmGlobalRegChangeNotifyEvent )
  1407. {
  1408. if( NtLmGlobalLsaKey )
  1409. {
  1410. RegNotifyChangeKeyValue(
  1411. NtLmGlobalLsaKey,
  1412. FALSE,
  1413. REG_NOTIFY_CHANGE_LAST_SET,
  1414. NtLmGlobalRegChangeNotifyEvent,
  1415. TRUE
  1416. );
  1417. }
  1418. #if DBG
  1419. if( NtLmGlobalLsaMsv1_0Key )
  1420. {
  1421. RegNotifyChangeKeyValue(
  1422. NtLmGlobalLsaMsv1_0Key,
  1423. FALSE,
  1424. REG_NOTIFY_CHANGE_LAST_SET,
  1425. NtLmGlobalRegChangeNotifyEvent,
  1426. TRUE
  1427. );
  1428. }
  1429. #endif
  1430. }
  1431. SspPrint((SSP_API, "Leaving NtLmQueryDynamicGlobals\n"));
  1432. return;
  1433. }
  1434. VOID
  1435. NtLmQueryMappedDomains(
  1436. VOID
  1437. )
  1438. {
  1439. HKEY KeyHandle; // open registry key to Lsa\MSV1_0
  1440. LONG RegStatus;
  1441. DWORD RegValueType;
  1442. WCHAR RegDomainName[DNS_MAX_NAME_LENGTH+1];
  1443. DWORD RegDomainSize;
  1444. //
  1445. // register the workitem that waits for the RegChangeNotifyEvent
  1446. // to be signalled. This supports dynamic refresh of configuration
  1447. // parameters.
  1448. //
  1449. NtLmGlobalRegChangeNotifyEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  1450. //
  1451. // query the globals once prior to registering the wait
  1452. // if a registry change occurs, the globals will be re-read by the worker
  1453. // thread.
  1454. //
  1455. NtLmQueryDynamicGlobals( NULL, FALSE );
  1456. NtLmGlobalRegWaitObject = RegisterWaitForSingleObjectEx(
  1457. NtLmGlobalRegChangeNotifyEvent,
  1458. NtLmQueryDynamicGlobals,
  1459. NULL,
  1460. INFINITE,
  1461. 0 // dwFlags
  1462. );
  1463. KeyHandle = NtLmGlobalLsaMsv1_0Key;
  1464. if( KeyHandle == NULL )
  1465. return;
  1466. //
  1467. // we only support loading the following globals once during initialization;
  1468. // they are not re-read until next reboot.
  1469. //
  1470. //
  1471. // Check the registry for a domain name to map
  1472. //
  1473. RegDomainSize = sizeof( RegDomainName );
  1474. RegStatus = RegQueryValueExW(
  1475. KeyHandle,
  1476. L"MappedDomain",
  1477. NULL,
  1478. &RegValueType,
  1479. (PUCHAR) RegDomainName,
  1480. &RegDomainSize
  1481. );
  1482. if (RegStatus == ERROR_SUCCESS && RegDomainSize <= 0xFFFF) {
  1483. NtLmLocklessGlobalMappedDomainString.Length = (USHORT)(RegDomainSize - sizeof(WCHAR));
  1484. NtLmLocklessGlobalMappedDomainString.MaximumLength = (USHORT)RegDomainSize;
  1485. NtLmLocklessGlobalMappedDomainString.Buffer = (PWSTR)NtLmAllocate( RegDomainSize );
  1486. if( NtLmLocklessGlobalMappedDomainString.Buffer != NULL )
  1487. CopyMemory( NtLmLocklessGlobalMappedDomainString.Buffer,
  1488. RegDomainName,
  1489. RegDomainSize );
  1490. } else {
  1491. RtlInitUnicodeString(
  1492. &NtLmLocklessGlobalMappedDomainString,
  1493. NULL
  1494. );
  1495. }
  1496. //
  1497. // Check the registry for a domain name to use
  1498. //
  1499. RegDomainSize = sizeof( RegDomainName );
  1500. RegStatus = RegQueryValueExW(
  1501. KeyHandle,
  1502. L"PreferredDomain",
  1503. NULL,
  1504. &RegValueType,
  1505. (PUCHAR) RegDomainName,
  1506. &RegDomainSize
  1507. );
  1508. if (RegStatus == ERROR_SUCCESS && RegDomainSize <= 0xFFFF) {
  1509. NtLmLocklessGlobalPreferredDomainString.Length = (USHORT)(RegDomainSize - sizeof(WCHAR));
  1510. NtLmLocklessGlobalPreferredDomainString.MaximumLength = (USHORT)RegDomainSize;
  1511. NtLmLocklessGlobalPreferredDomainString.Buffer = (PWSTR)NtLmAllocate( RegDomainSize );
  1512. if( NtLmLocklessGlobalPreferredDomainString.Buffer != NULL )
  1513. CopyMemory( NtLmLocklessGlobalPreferredDomainString.Buffer,
  1514. RegDomainName,
  1515. RegDomainSize );
  1516. } else {
  1517. RtlInitUnicodeString(
  1518. &NtLmLocklessGlobalPreferredDomainString,
  1519. NULL
  1520. );
  1521. }
  1522. return;
  1523. }
  1524. VOID
  1525. NtLmFreeMappedDomains(
  1526. VOID
  1527. )
  1528. {
  1529. if( NtLmGlobalRegWaitObject )
  1530. UnregisterWait( NtLmGlobalRegWaitObject );
  1531. if( NtLmGlobalRegChangeNotifyEvent )
  1532. CloseHandle( NtLmGlobalRegChangeNotifyEvent );
  1533. if( NtLmLocklessGlobalMappedDomainString.Buffer ) {
  1534. NtLmFree( NtLmLocklessGlobalMappedDomainString.Buffer );
  1535. NtLmLocklessGlobalMappedDomainString.Buffer = NULL;
  1536. }
  1537. if( NtLmLocklessGlobalPreferredDomainString.Buffer ) {
  1538. NtLmFree( NtLmLocklessGlobalPreferredDomainString.Buffer );
  1539. NtLmLocklessGlobalPreferredDomainString.Buffer = NULL;
  1540. }
  1541. }
  1542. ULONG
  1543. NtLmCheckProcessOption(
  1544. IN ULONG OptionRequest
  1545. )
  1546. {
  1547. SECPKG_CALL_INFO CallInfo;
  1548. ULONG OptionMask = 0;
  1549. PLIST_ENTRY ListHead;
  1550. PLIST_ENTRY ListEntry;
  1551. if(!LsaFunctions->GetCallInfo(&CallInfo))
  1552. {
  1553. goto Cleanup;
  1554. }
  1555. RtlAcquireResourceShared( &NtLmProcessOptionsLock, TRUE );
  1556. ListHead = &NtLmProcessOptionsList;
  1557. //
  1558. // Now walk the list looking for a match.
  1559. //
  1560. for ( ListEntry = ListHead->Flink;
  1561. ListEntry != ListHead;
  1562. ListEntry = ListEntry->Flink )
  1563. {
  1564. PSSP_PROCESSOPTIONS ProcessOptions;
  1565. ProcessOptions = CONTAINING_RECORD( ListEntry, SSP_PROCESSOPTIONS, Next );
  1566. if( ProcessOptions->ClientProcessID == CallInfo.ProcessId )
  1567. {
  1568. OptionMask = ProcessOptions->ProcessOptions;
  1569. break;
  1570. }
  1571. }
  1572. RtlReleaseResource( &NtLmProcessOptionsLock );
  1573. Cleanup:
  1574. return OptionMask;
  1575. }
  1576. BOOLEAN
  1577. NtLmSetProcessOption(
  1578. IN ULONG OptionRequest,
  1579. IN BOOLEAN DisableOption
  1580. )
  1581. {
  1582. SECPKG_CALL_INFO CallInfo;
  1583. PSSP_PROCESSOPTIONS pProcessOption = NULL;
  1584. PLIST_ENTRY ListHead;
  1585. PLIST_ENTRY ListEntry;
  1586. BOOLEAN fExisting = FALSE;
  1587. BOOLEAN fSuccess = FALSE;
  1588. if(!LsaFunctions->GetCallInfo(&CallInfo))
  1589. {
  1590. goto Cleanup;
  1591. }
  1592. pProcessOption = (PSSP_PROCESSOPTIONS)NtLmAllocate( sizeof(*pProcessOption) );
  1593. if( pProcessOption == NULL )
  1594. {
  1595. goto Cleanup;
  1596. }
  1597. pProcessOption->ClientProcessID = CallInfo.ProcessId;
  1598. pProcessOption->ProcessOptions = OptionRequest;
  1599. RtlAcquireResourceExclusive( &NtLmProcessOptionsLock, TRUE );
  1600. ListHead = &NtLmProcessOptionsList;
  1601. //
  1602. // Now walk the list looking for a match.
  1603. //
  1604. for ( ListEntry = ListHead->Flink;
  1605. ListEntry != ListHead;
  1606. ListEntry = ListEntry->Flink )
  1607. {
  1608. PSSP_PROCESSOPTIONS ProcessOptions;
  1609. ProcessOptions = CONTAINING_RECORD( ListEntry, SSP_PROCESSOPTIONS, Next );
  1610. if( ProcessOptions->ClientProcessID == CallInfo.ProcessId )
  1611. {
  1612. if( DisableOption )
  1613. {
  1614. ProcessOptions->ProcessOptions &= ~OptionRequest;
  1615. } else {
  1616. ProcessOptions->ProcessOptions |= OptionRequest;
  1617. }
  1618. fExisting = TRUE;
  1619. break;
  1620. }
  1621. }
  1622. if( !fExisting && !DisableOption )
  1623. {
  1624. InsertHeadList( &NtLmProcessOptionsList, &pProcessOption->Next );
  1625. pProcessOption = NULL;
  1626. }
  1627. RtlReleaseResource( &NtLmProcessOptionsLock );
  1628. fSuccess = TRUE;
  1629. Cleanup:
  1630. if( pProcessOption != NULL )
  1631. {
  1632. NtLmFree( pProcessOption );
  1633. }
  1634. return fSuccess;
  1635. }