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.

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