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.

1167 lines
29 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // ezlogon.c
  8. //
  9. // SYNOPSIS
  10. //
  11. // Defines the IAS wrapper around LsaLogonUser
  12. //
  13. // MODIFICATION HISTORY
  14. //
  15. // 08/15/1998 Original version.
  16. // 09/09/1998 Fix AV when logon domain doesn't match user domain.
  17. // 10/02/1998 NULL out handle when LsaLogonUser fails.
  18. // 10/11/1998 Use SubStatus for STATUS_ACCOUNT_RESTRICTION.
  19. // 10/22/1998 PIAS_LOGON_HOURS is now a mandatory parameter.
  20. // 01/28/1999 Remove LogonDomainName check.
  21. // 04/19/1999 Add IASPurgeTicketCache.
  22. //
  23. ///////////////////////////////////////////////////////////////////////////////
  24. #include <nt.h>
  25. #include <ntrtl.h>
  26. #include <nturtl.h>
  27. #include <windows.h>
  28. #include <lm.h>
  29. #include <sha.h>
  30. #include <ntsam.h>
  31. #include <ntsamp.h>
  32. #include <dsgetdc.h>
  33. #include <ntlsa.h>
  34. #include <kerberos.h>
  35. #include <windows.h>
  36. #include <ezlogon.h>
  37. #include <malloc.h>
  38. //#include <iaslsa.h>
  39. //#define NT_RESPONSE_LENGTH 24
  40. //#define LM_RESPONSE_LENGTH 24
  41. //////////
  42. // Handle to the IAS Logon Process.
  43. //////////
  44. LSA_HANDLE theLogonProcess;
  45. //////////
  46. // The MSV1_0 authentication package.
  47. //////////
  48. ULONG theMSV1_0_Package;
  49. CONST CHAR LOGON_PROCESS_NAME[] = "CHAP";
  50. CONST CHAR TOKEN_SOURCE_NAME[TOKEN_SOURCE_LENGTH] = "CHAP";
  51. // Number of milliseconds in a week.
  52. #define MSEC_PER_WEEK (1000 * 60 * 60 * 24 * 7)
  53. //////////
  54. // Misc. global variables used for logons.
  55. //////////
  56. LSA_HANDLE theLogonProcess; // The handle for the logon process.
  57. ULONG theMSV1_0_Package; // The MSV1_0 authentication package.
  58. ULONG theKerberosPackage; // The Kerberos authentication package.
  59. STRING theOriginName; // The origin of the logon requests.
  60. TOKEN_SOURCE theSourceContext; // The source context of the logon requests.
  61. //////////
  62. // Domain names.
  63. //////////
  64. WCHAR theAccountDomain [DNLEN + 1]; // Local account domain.
  65. WCHAR theRegistryDomain[DNLEN + 1]; // Registry override for default domain.
  66. //////////
  67. // SID's
  68. //////////
  69. PSID theAccountDomainSid;
  70. PSID theBuiltinDomainSid;
  71. //////////
  72. // UNC name of the local computer.
  73. //////////
  74. WCHAR theLocalServer[CNLEN + 3];
  75. SECURITY_QUALITY_OF_SERVICE QOS =
  76. {
  77. sizeof(SECURITY_QUALITY_OF_SERVICE), // Length
  78. SecurityImpersonation, // ImpersonationLevel
  79. SECURITY_DYNAMIC_TRACKING, // ContextTrackingMode
  80. FALSE // EffectiveOnly
  81. };
  82. OBJECT_ATTRIBUTES theObjectAttributes =
  83. {
  84. sizeof(OBJECT_ATTRIBUTES), // Length
  85. NULL, // RootDirectory
  86. NULL, // ObjectName
  87. 0, // Attributes
  88. NULL, // SecurityDescriptor
  89. &QOS // SecurityQualityOfService
  90. };
  91. /////////////////////////////////////////////////////////////////////////////// //
  92. // FUNCTION
  93. //
  94. // IASLogonInitialize
  95. //
  96. // DESCRIPTION
  97. //
  98. // Registers the logon process.
  99. //
  100. ///////////////////////////////////////////////////////////////////////////////
  101. DWORD
  102. WINAPI
  103. IASLogonInitialize( VOID )
  104. {
  105. DWORD status;
  106. BOOLEAN wasEnabled;
  107. LSA_STRING processName, packageName;
  108. PPOLICY_ACCOUNT_DOMAIN_INFO padi;
  109. LSA_OPERATIONAL_MODE opMode;
  110. DWORD cbData = 0;
  111. LSA_HANDLE hLsa;
  112. //////////
  113. // Enable SE_TCB_PRIVILEGE.
  114. //////////
  115. status = RtlAdjustPrivilege(
  116. SE_TCB_PRIVILEGE,
  117. TRUE,
  118. FALSE,
  119. &wasEnabled
  120. );
  121. if (!NT_SUCCESS(status)) { goto exit; }
  122. //////////
  123. // Register as a logon process.
  124. //////////
  125. RtlInitString(
  126. &processName,
  127. LOGON_PROCESS_NAME
  128. );
  129. status = LsaRegisterLogonProcess(
  130. &processName,
  131. &theLogonProcess,
  132. &opMode
  133. );
  134. if (!NT_SUCCESS(status)) { goto exit; }
  135. //////////
  136. // Lookup the MSV1_0 authentication package.
  137. //////////
  138. RtlInitString(
  139. &packageName,
  140. MSV1_0_PACKAGE_NAME
  141. );
  142. status = LsaLookupAuthenticationPackage(
  143. theLogonProcess,
  144. &packageName,
  145. &theMSV1_0_Package
  146. );
  147. if (!NT_SUCCESS(status)) { goto deregister; }
  148. //////////
  149. // Lookup the Kerberos authentication package.
  150. //////////
  151. RtlInitString(
  152. &packageName,
  153. MICROSOFT_KERBEROS_NAME_A
  154. );
  155. status = LsaLookupAuthenticationPackage(
  156. theLogonProcess,
  157. &packageName,
  158. &theKerberosPackage
  159. );
  160. if (!NT_SUCCESS(status)) { goto deregister; }
  161. //////////
  162. // Initialize the source context.
  163. //////////
  164. memcpy(theSourceContext.SourceName,
  165. TOKEN_SOURCE_NAME,
  166. TOKEN_SOURCE_LENGTH);
  167. status = NtAllocateLocallyUniqueId(
  168. &theSourceContext.SourceIdentifier
  169. );
  170. if (!NT_SUCCESS(status)) { goto deregister; }
  171. /////////
  172. /// Initialize the account domain and local domain
  173. ////////
  174. wcscpy(theLocalServer, L"\\\\");
  175. cbData = CNLEN + 1;
  176. if (!GetComputerNameW(theLocalServer + 2, &cbData))
  177. { return GetLastError(); }
  178. //////////
  179. // Open a handle to the LSA.
  180. //////////
  181. status = LsaOpenPolicy(
  182. NULL,
  183. &theObjectAttributes,
  184. POLICY_VIEW_LOCAL_INFORMATION,
  185. &hLsa
  186. );
  187. if (!NT_SUCCESS(status)) { goto deregister; }
  188. //////////
  189. // Get the account domain information.
  190. //////////
  191. status = LsaQueryInformationPolicy(
  192. hLsa,
  193. PolicyAccountDomainInformation,
  194. (PVOID*)&padi
  195. );
  196. LsaClose(hLsa);
  197. if (!NT_SUCCESS(status)) { goto deregister; }
  198. // Save the domain name.
  199. wcsncpy(theAccountDomain, padi->DomainName.Buffer, DNLEN);
  200. _wcsupr(theAccountDomain);
  201. return NO_ERROR;
  202. deregister:
  203. LsaDeregisterLogonProcess(theLogonProcess);
  204. theLogonProcess = NULL;
  205. //setup the logon domain for the machine
  206. exit:
  207. return RtlNtStatusToDosError(status);
  208. }
  209. /////////////////////////////////////////////////////////////////////////////// //
  210. // FUNCTION
  211. //
  212. // IASLogonShutdown
  213. //
  214. // DESCRIPTION
  215. //
  216. // Deregisters the logon process.
  217. //
  218. ///////////////////////////////////////////////////////////////////////////////
  219. VOID
  220. WINAPI
  221. IASLogonShutdown( VOID )
  222. {
  223. LsaDeregisterLogonProcess(theLogonProcess);
  224. theLogonProcess = NULL;
  225. }
  226. /////////////////////////////////////////////////////////////////////////////// //
  227. // FUNCTION
  228. //
  229. // IASInitAuthInfo
  230. //
  231. // DESCRIPTION
  232. //
  233. // Initializes the fields common to all MSV1_0_LM20* structs.
  234. //
  235. ///////////////////////////////////////////////////////////////////////////////
  236. VOID
  237. WINAPI
  238. IASInitAuthInfo(
  239. IN PVOID AuthInfo,
  240. IN DWORD FixedLength,
  241. IN PCWSTR UserName,
  242. IN PCWSTR Domain,
  243. OUT PBYTE* Data
  244. )
  245. {
  246. PMSV1_0_LM20_LOGON logon;
  247. // Zero out the fixed data.
  248. memset(AuthInfo, 0, FixedLength);
  249. // Set Data to point just past the fixed struct.
  250. *Data = FixedLength + (PBYTE)AuthInfo;
  251. // This cast is safe since all LM20 structs have the same initial fields.
  252. logon = (PMSV1_0_LM20_LOGON)AuthInfo;
  253. // We always do Network logons.
  254. logon->MessageType = MsV1_0NetworkLogon;
  255. // Copy in the strings common to all logons.
  256. IASInitUnicodeString(logon->LogonDomainName, *Data, Domain);
  257. IASInitUnicodeString(logon->UserName, *Data, UserName);
  258. IASInitUnicodeString(logon->Workstation, *Data, L"");
  259. }
  260. /////////////////////////////////////////////////////////////////////////////// //
  261. // FUNCTION
  262. //
  263. // IASLogonUser
  264. //
  265. // DESCRIPTION
  266. //
  267. // Wrapper around LsaLogonUser.
  268. //
  269. ///////////////////////////////////////////////////////////////////////////////
  270. DWORD
  271. WINAPI
  272. IASLogonUser(
  273. IN PVOID AuthInfo,
  274. IN ULONG AuthInfoLength,
  275. OUT PMSV1_0_LM20_LOGON_PROFILE *Profile,
  276. OUT PHANDLE Token
  277. )
  278. {
  279. NTSTATUS status, SubStatus;
  280. PMSV1_0_LM20_LOGON_PROFILE ProfileBuffer;
  281. ULONG ProfileBufferLength;
  282. LUID LogonId;
  283. QUOTA_LIMITS Quotas;
  284. // Make sure the OUT arguments are NULL.
  285. *Token = NULL;
  286. ProfileBuffer = NULL;
  287. status = LsaLogonUser(
  288. theLogonProcess,
  289. &theOriginName,
  290. Network,
  291. theMSV1_0_Package,
  292. AuthInfo,
  293. AuthInfoLength,
  294. NULL,
  295. &theSourceContext,
  296. &ProfileBuffer,
  297. &ProfileBufferLength,
  298. &LogonId,
  299. Token,
  300. &Quotas,
  301. &SubStatus
  302. );
  303. if (!NT_SUCCESS(status))
  304. {
  305. // For account restrictions, we can get a more descriptive error
  306. // from the SubStatus.
  307. if (status == STATUS_ACCOUNT_RESTRICTION && !NT_SUCCESS(SubStatus))
  308. {
  309. status = SubStatus;
  310. }
  311. // Sometimes LsaLogonUser returns an invalid handle value on failure.
  312. *Token = NULL;
  313. }
  314. if (Profile)
  315. {
  316. // Return the profile if requested ...
  317. *Profile = ProfileBuffer;
  318. }
  319. else if (ProfileBuffer)
  320. {
  321. // ... otherwise free it.
  322. LsaFreeReturnBuffer(ProfileBuffer);
  323. }
  324. return RtlNtStatusToDosError(status);
  325. }
  326. //
  327. // All MSCHAP Related stuff goes here
  328. //
  329. ///////////////////////////////////////////////////////////////////////////////
  330. //
  331. // Various constants used for MS-CHAP v2
  332. //
  333. ///////////////////////////////////////////////////////////////////////////////
  334. UCHAR AuthMagic1[39] =
  335. {
  336. 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
  337. 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
  338. 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
  339. 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
  340. };
  341. UCHAR AuthMagic2[41] =
  342. {
  343. 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
  344. 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
  345. 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
  346. 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
  347. 0x6E
  348. };
  349. UCHAR SHSpad1[40] =
  350. {
  351. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  352. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  353. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  354. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  355. };
  356. UCHAR SHSpad2[40] =
  357. {
  358. 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
  359. 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
  360. 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
  361. 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2
  362. };
  363. UCHAR KeyMagic1[27] =
  364. {
  365. 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
  366. 0x68, 0x65, 0x20, 0x4D, 0x50, 0x50, 0x45, 0x20, 0x4D,
  367. 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4B, 0x65, 0x79
  368. };
  369. UCHAR KeyMagic2[84] =
  370. {
  371. 0x4F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6C, 0x69,
  372. 0x65, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2C, 0x20,
  373. 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
  374. 0x65, 0x20, 0x73, 0x65, 0x6E, 0x64, 0x20, 0x6B, 0x65, 0x79,
  375. 0x3B, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
  376. 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
  377. 0x2C, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
  378. 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
  379. 0x6B, 0x65, 0x79, 0x2E
  380. };
  381. UCHAR KeyMagic3[84] =
  382. {
  383. 0x4F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6C, 0x69,
  384. 0x65, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2C, 0x20,
  385. 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
  386. 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
  387. 0x6B, 0x65, 0x79, 0x3B, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68,
  388. 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
  389. 0x69, 0x64, 0x65, 0x2C, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
  390. 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6E, 0x64, 0x20,
  391. 0x6B, 0x65, 0x79, 0x2E
  392. };
  393. ///////////////////////////////////////////////////////////////////////////////
  394. //
  395. // FUNCTION
  396. //
  397. // IASLogonMSCHAP
  398. //
  399. // DESCRIPTION
  400. //
  401. // Performs MS-CHAP authentication against the NT SAM database.
  402. //
  403. ///////////////////////////////////////////////////////////////////////////////
  404. DWORD
  405. WINAPI
  406. IASLogonMSCHAP(
  407. PCWSTR UserName,
  408. PCWSTR Domain,
  409. PBYTE Challenge,
  410. PBYTE NtResponse,
  411. PBYTE LmResponse,
  412. PIAS_MSCHAP_PROFILE Profile,
  413. PHANDLE Token
  414. )
  415. {
  416. DWORD status;
  417. ULONG authLength;
  418. PMSV1_0_LM20_LOGON authInfo;
  419. PBYTE data;
  420. PMSV1_0_LM20_LOGON_PROFILE logonProfile;
  421. DWORD len;
  422. // Calculate the length of the authentication info.
  423. authLength = sizeof(MSV1_0_LM20_LOGON) +
  424. (wcslen(Domain) + wcslen(UserName)) * sizeof(WCHAR) +
  425. (LmResponse ? LM_RESPONSE_LENGTH : 0) +
  426. (NtResponse ? NT_RESPONSE_LENGTH : 0);
  427. __try
  428. {
  429. // Allocate a buffer on the stack.
  430. authInfo = (PMSV1_0_LM20_LOGON)_alloca(authLength);
  431. } __except(GetExceptionCode() == STATUS_STACK_OVERFLOW)
  432. {
  433. _resetstkoflw();
  434. }
  435. // Initialize the struct.
  436. IASInitAuthInfo(
  437. authInfo,
  438. sizeof(MSV1_0_LM20_LOGON),
  439. UserName,
  440. Domain,
  441. &data
  442. );
  443. /////////
  444. // Fill in the challenges and responses.
  445. /////////
  446. IASInitFixedArray(
  447. authInfo->ChallengeToClient,
  448. Challenge
  449. );
  450. if (NtResponse)
  451. {
  452. IASInitOctetString(
  453. authInfo->CaseSensitiveChallengeResponse,
  454. data,
  455. NtResponse,
  456. NT_RESPONSE_LENGTH
  457. );
  458. }
  459. else
  460. {
  461. memset(
  462. &authInfo->CaseSensitiveChallengeResponse,
  463. 0,
  464. sizeof(authInfo->CaseSensitiveChallengeResponse)
  465. );
  466. }
  467. if (LmResponse)
  468. {
  469. IASInitOctetString(
  470. authInfo->CaseInsensitiveChallengeResponse,
  471. data,
  472. LmResponse,
  473. LM_RESPONSE_LENGTH
  474. );
  475. }
  476. else
  477. {
  478. memset(
  479. &authInfo->CaseInsensitiveChallengeResponse,
  480. 0,
  481. sizeof(authInfo->CaseInsensitiveChallengeResponse)
  482. );
  483. }
  484. // Set the parameters.
  485. authInfo->ParameterControl = DEFAULT_PARAMETER_CONTROL;
  486. status = IASLogonUser(
  487. authInfo,
  488. authLength,
  489. &logonProfile,
  490. Token
  491. );
  492. if (status == NO_ERROR)
  493. {
  494. Profile->KickOffTime.QuadPart = logonProfile->KickOffTime.QuadPart;
  495. // NOTE Workaround for LSA IA64 WINBUG # 126930 6/13/2000 IA64:
  496. // LsaLogonUser succeeds but returns NULL LogonDomainName.
  497. if (logonProfile->LogonDomainName.Buffer)
  498. {
  499. wcsncpy(Profile->LogonDomainName,
  500. logonProfile->LogonDomainName.Buffer,
  501. DNLEN);
  502. }
  503. else
  504. {
  505. memset(Profile->LogonDomainName, 0, sizeof(Profile->LogonDomainName));
  506. }
  507. IASInitFixedArray(
  508. Profile->LanmanSessionKey,
  509. logonProfile->LanmanSessionKey
  510. );
  511. IASInitFixedArray(
  512. Profile->UserSessionKey,
  513. logonProfile->UserSessionKey
  514. );
  515. LsaFreeReturnBuffer(logonProfile);
  516. }
  517. return status;
  518. }
  519. ///////////////////////////////////////////////////////////////////////////////
  520. //
  521. // FUNCTION
  522. //
  523. // IASLogonMSCHAPv2
  524. //
  525. // DESCRIPTION
  526. //
  527. // Performs MS-CHAP v2 authentication.
  528. //
  529. ///////////////////////////////////////////////////////////////////////////////
  530. DWORD
  531. WINAPI
  532. IASLogonMSCHAPv2(
  533. IN PCWSTR UserName,
  534. IN PCWSTR Domain,
  535. IN PCSTR HashUserName,
  536. IN PBYTE Challenge,
  537. IN DWORD ChallengeLength,
  538. IN PBYTE Response,
  539. IN PBYTE PeerChallenge,
  540. OUT PIAS_MSCHAP_V2_PROFILE Profile,
  541. OUT PHANDLE Token
  542. )
  543. {
  544. A_SHA_CTX context;
  545. BYTE digest[A_SHA_DIGEST_LEN], masterKey[A_SHA_DIGEST_LEN];
  546. BYTE computedChallenge[MSV1_0_CHALLENGE_LENGTH];
  547. IAS_MSCHAP_PROFILE v1profile;
  548. DWORD status;
  549. /////////
  550. // Compute the v2 challenge.
  551. /////////
  552. A_SHAInit(&context);
  553. A_SHAUpdate(&context, PeerChallenge, 16);
  554. A_SHAUpdate(&context, Challenge, ChallengeLength);
  555. A_SHAUpdate(&context, (PBYTE)HashUserName, strlen(HashUserName));
  556. A_SHAFinal(&context, digest);
  557. memcpy(computedChallenge, digest, sizeof(computedChallenge));
  558. /////////
  559. // Authenticate the user.
  560. /////////
  561. status = IASLogonMSCHAP(
  562. UserName,
  563. Domain,
  564. computedChallenge,
  565. Response,
  566. NULL,
  567. &v1profile,
  568. Token
  569. );
  570. if (status != NO_ERROR) { return status; }
  571. /////////
  572. // Generate authenticator response.
  573. /////////
  574. A_SHAInit(&context);
  575. A_SHAUpdate(&context, v1profile.UserSessionKey, 16);
  576. A_SHAUpdate(&context, Response, NT_RESPONSE_LENGTH);
  577. A_SHAUpdate(&context, AuthMagic1, sizeof(AuthMagic1));
  578. A_SHAFinal(&context, digest);
  579. A_SHAInit(&context);
  580. A_SHAUpdate(&context, digest, sizeof(digest));
  581. A_SHAUpdate(&context, computedChallenge, sizeof(computedChallenge));
  582. A_SHAUpdate(&context, AuthMagic2, sizeof(AuthMagic2));
  583. A_SHAFinal(&context, digest);
  584. memcpy(Profile->AuthResponse, digest, _AUTHENTICATOR_RESPONSE_LENGTH);
  585. /////////
  586. // Generate master key.
  587. /////////
  588. A_SHAInit(&context);
  589. A_SHAUpdate(&context, v1profile.UserSessionKey, 16);
  590. A_SHAUpdate(&context, Response, NT_RESPONSE_LENGTH);
  591. A_SHAUpdate(&context, KeyMagic1, sizeof(KeyMagic1));
  592. A_SHAFinal(&context, masterKey);
  593. /////////
  594. // Generate receive key.
  595. /////////
  596. A_SHAInit(&context);
  597. A_SHAUpdate(&context, masterKey, 16);
  598. A_SHAUpdate(&context, SHSpad1, sizeof(SHSpad1));
  599. A_SHAUpdate(&context, KeyMagic2, sizeof(KeyMagic2));
  600. A_SHAUpdate(&context, SHSpad2, sizeof(SHSpad2));
  601. A_SHAFinal(&context, digest);
  602. memcpy(Profile->RecvSessionKey, digest, MSV1_0_USER_SESSION_KEY_LENGTH);
  603. /////////
  604. // Generate send key.
  605. /////////
  606. A_SHAInit(&context);
  607. A_SHAUpdate(&context, masterKey, 16);
  608. A_SHAUpdate(&context, SHSpad1, sizeof(SHSpad1));
  609. A_SHAUpdate(&context, KeyMagic3, sizeof(KeyMagic3));
  610. A_SHAUpdate(&context, SHSpad2, sizeof(SHSpad2));
  611. A_SHAFinal(&context, digest);
  612. memcpy(Profile->SendSessionKey, digest, MSV1_0_USER_SESSION_KEY_LENGTH);
  613. /////////
  614. // Copy the logon domain.
  615. /////////
  616. memcpy(
  617. Profile->LogonDomainName,
  618. v1profile.LogonDomainName,
  619. sizeof(Profile->LogonDomainName)
  620. );
  621. return NO_ERROR;
  622. }
  623. DWORD
  624. WINAPI
  625. IASGetSendRecvSessionKeys( PBYTE pbUserSessionKey,
  626. DWORD dwUserSessionKeyLen,
  627. PBYTE pbResponse,
  628. DWORD dwResponseLen,
  629. OUT PBYTE pbSendKey,
  630. OUT PBYTE pbRecvKey
  631. )
  632. {
  633. DWORD dwRetCode = NO_ERROR;
  634. A_SHA_CTX context;
  635. BYTE digest[A_SHA_DIGEST_LEN], masterKey[A_SHA_DIGEST_LEN];
  636. /////////
  637. // Generate master key.
  638. /////////
  639. A_SHAInit(&context);
  640. A_SHAUpdate(&context, pbUserSessionKey, dwUserSessionKeyLen);
  641. A_SHAUpdate(&context, pbResponse, dwResponseLen);
  642. A_SHAUpdate(&context, KeyMagic1, sizeof(KeyMagic1));
  643. A_SHAFinal(&context, masterKey);
  644. /////////
  645. // Generate receive key.
  646. /////////
  647. A_SHAInit(&context);
  648. A_SHAUpdate(&context, masterKey, 16);
  649. A_SHAUpdate(&context, SHSpad1, sizeof(SHSpad1));
  650. A_SHAUpdate(&context, KeyMagic2, sizeof(KeyMagic2));
  651. A_SHAUpdate(&context, SHSpad2, sizeof(SHSpad2));
  652. A_SHAFinal(&context, digest);
  653. memcpy(pbRecvKey, digest, MSV1_0_USER_SESSION_KEY_LENGTH);
  654. /////////
  655. // Generate send key.
  656. /////////
  657. A_SHAInit(&context);
  658. A_SHAUpdate(&context, masterKey, 16);
  659. A_SHAUpdate(&context, SHSpad1, sizeof(SHSpad1));
  660. A_SHAUpdate(&context, KeyMagic3, sizeof(KeyMagic3));
  661. A_SHAUpdate(&context, SHSpad2, sizeof(SHSpad2));
  662. A_SHAFinal(&context, digest);
  663. memcpy(pbSendKey, digest, MSV1_0_USER_SESSION_KEY_LENGTH);
  664. return dwRetCode;
  665. }
  666. #if 0
  667. /////////////////////////////////////////////////////////////////////////////// //
  668. // FUNCTION
  669. //
  670. // IASCheckAccountRestrictions
  671. //
  672. // DESCRIPTION
  673. //
  674. // Checks whether an account can be used for logon.
  675. //
  676. ///////////////////////////////////////////////////////////////////////////////
  677. DWORD
  678. WINAPI
  679. IASCheckAccountRestrictions(
  680. IN PLARGE_INTEGER AccountExpires,
  681. IN PIAS_LOGON_HOURS LogonHours,
  682. OUT PLARGE_INTEGER SessionTimeout
  683. )
  684. {
  685. LARGE_INTEGER now;
  686. TIME_ZONE_INFORMATION tzi;
  687. SYSTEMTIME st;
  688. DWORD unit;
  689. LARGE_INTEGER KickoffTime;
  690. LARGE_INTEGER LogoffTime;
  691. ULONG LogoffUnitsIntoWeek;
  692. USHORT i;
  693. ULONG LogoffMsIntoWeek;
  694. ULONG MillisecondsPerUnit;
  695. ULONG DeltaMs;
  696. ULONG CurrentUnitsIntoWeek;
  697. LARGE_INTEGER Delta100Ns;
  698. _ASSERT(SessionTimeout != NULL);
  699. SessionTimeout->QuadPart = MAXLONGLONG;
  700. KickoffTime.QuadPart = MAXLONGLONG;
  701. LogoffTime.QuadPart = MAXLONGLONG;
  702. GetSystemTimeAsFileTime((LPFILETIME)&now);
  703. // An expiration time of zero means 'never'.
  704. if ((AccountExpires->QuadPart != 0) &&
  705. (AccountExpires->QuadPart < now.QuadPart))
  706. {
  707. return ERROR_ACCOUNT_EXPIRED;
  708. }
  709. // If LogonHours is empty, then we're done.
  710. if (LogonHours->UnitsPerWeek == 0)
  711. {
  712. return NO_ERROR;
  713. }
  714. // The LogonHours array does not account for bias.
  715. switch (GetTimeZoneInformation(&tzi))
  716. {
  717. case TIME_ZONE_ID_UNKNOWN:
  718. case TIME_ZONE_ID_STANDARD:
  719. // Bias is in minutes.
  720. now.QuadPart -= 60 * 10000000 * (LONGLONG)tzi.StandardBias;
  721. break;
  722. case TIME_ZONE_ID_DAYLIGHT:
  723. // Bias is in minutes.
  724. now.QuadPart -= 60 * 10000000 * (LONGLONG)tzi.DaylightBias;
  725. break;
  726. default:
  727. return ERROR_INVALID_LOGON_HOURS;
  728. }
  729. FileTimeToSystemTime(
  730. (LPFILETIME)&now,
  731. &st
  732. );
  733. // Number of milliseconds into the week.
  734. unit = st.wMilliseconds +
  735. st.wSecond * 1000 +
  736. st.wMinute * 1000 * 60 +
  737. st.wHour * 1000 * 60 * 60 +
  738. st.wDayOfWeek * 1000 * 60 * 60 * 24;
  739. // Convert this to 'units'.
  740. unit /= (MSEC_PER_WEEK / (DWORD)LogonHours->UnitsPerWeek);
  741. // Test the appropriate bit.
  742. if ((LogonHours->LogonHours[unit / 8 ] & (1 << (unit % 8))) == 0)
  743. {
  744. return ERROR_INVALID_LOGON_HOURS;
  745. }
  746. else
  747. {
  748. //
  749. // Determine the next time that the user is NOT supposed to be logged
  750. // in, and return that as LogoffTime.
  751. //
  752. i = 0;
  753. LogoffUnitsIntoWeek = unit;
  754. do
  755. {
  756. ++i;
  757. LogoffUnitsIntoWeek = ( LogoffUnitsIntoWeek + 1 )
  758. % LogonHours->UnitsPerWeek;
  759. }
  760. while ( ( i <= LogonHours->UnitsPerWeek) &&
  761. ( LogonHours->LogonHours[ LogoffUnitsIntoWeek / 8 ] &
  762. ( 0x01 << ( LogoffUnitsIntoWeek % 8 ) ) ) );
  763. if ( i > LogonHours->UnitsPerWeek )
  764. {
  765. //
  766. // All times are allowed, so there's no logoff
  767. // time. Return forever for both LogoffTime and
  768. // KickoffTime.
  769. //
  770. LogoffTime.QuadPart = MAXLONGLONG;
  771. KickoffTime.QuadPart = MAXLONGLONG;
  772. }
  773. else
  774. {
  775. //
  776. // LogoffUnitsIntoWeek points at which time unit the
  777. // user is to log off. Calculate actual time from
  778. // the unit, and return it.
  779. //
  780. // CurrentTimeFields already holds the current
  781. // time for some time during this week; just adjust
  782. // to the logoff time during this week and convert
  783. // to time format.
  784. //
  785. MillisecondsPerUnit = MSEC_PER_WEEK / LogonHours->UnitsPerWeek;
  786. LogoffMsIntoWeek = MillisecondsPerUnit * LogoffUnitsIntoWeek;
  787. if ( LogoffMsIntoWeek < unit )
  788. {
  789. DeltaMs = MSEC_PER_WEEK - ( unit - LogoffMsIntoWeek );
  790. }
  791. else
  792. {
  793. DeltaMs = LogoffMsIntoWeek - unit;
  794. }
  795. Delta100Ns.QuadPart = (LONGLONG) DeltaMs * 10000;
  796. LogoffTime.QuadPart = min(now.QuadPart +
  797. Delta100Ns.QuadPart,
  798. LogoffTime.QuadPart);
  799. }
  800. // Get the minimum of the three values
  801. KickoffTime.QuadPart = min(LogoffTime.QuadPart, KickoffTime.QuadPart);
  802. KickoffTime.QuadPart = min(KickoffTime.QuadPart, AccountExpires->QuadPart);
  803. // store the result
  804. SessionTimeout->QuadPart = KickoffTime.QuadPart;
  805. }
  806. return NO_ERROR;
  807. }
  808. /////////////////////////////////////////////////////////////////////////////// //
  809. // FUNCTION
  810. //
  811. // IASPurgeTicketCache
  812. //
  813. // DESCRIPTION
  814. //
  815. // Purges the Kerberos ticket cache.
  816. //
  817. ///////////////////////////////////////////////////////////////////////////////
  818. DWORD
  819. WINAPI
  820. IASPurgeTicketCache( VOID )
  821. {
  822. KERB_PURGE_TKT_CACHE_REQUEST request;
  823. NTSTATUS status, subStatus;
  824. PVOID response;
  825. ULONG responseLength;
  826. memset(&request, 0, sizeof(request));
  827. request.MessageType = KerbPurgeTicketCacheMessage;
  828. response = NULL;
  829. responseLength = 0;
  830. subStatus = 0;
  831. status = LsaCallAuthenticationPackage(
  832. theLogonProcess,
  833. theKerberosPackage,
  834. &request,
  835. sizeof(request),
  836. &response,
  837. &responseLength,
  838. &subStatus
  839. );
  840. if (NT_SUCCESS(status))
  841. {
  842. LsaFreeReturnBuffer(response);
  843. }
  844. return RtlNtStatusToDosError(status);
  845. }
  846. #endif
  847. ///////////////////////////////////////////////////////////////////////////////
  848. //
  849. // FUNCTION
  850. //
  851. // IASGetDcName
  852. //
  853. // DESCRIPTION
  854. //
  855. // Wrapper around DsGetDcNameW. Tries to do the right thing with regard
  856. // to NETBIOS and DNS names.
  857. //
  858. ///////////////////////////////////////////////////////////////////////////////
  859. DWORD
  860. WINAPI
  861. IASGetDcName(
  862. IN LPCWSTR DomainName,
  863. IN ULONG Flags,
  864. OUT PDOMAIN_CONTROLLER_INFOW *DomainControllerInfo
  865. )
  866. {
  867. DWORD status;
  868. PDOMAIN_CONTROLLER_INFOW dci;
  869. if (!(Flags & DS_IS_DNS_NAME)) { Flags |= DS_IS_FLAT_NAME; }
  870. status = DsGetDcNameW(
  871. NULL,
  872. DomainName,
  873. NULL,
  874. NULL,
  875. Flags,
  876. DomainControllerInfo
  877. );
  878. if (status == NO_ERROR &&
  879. !(Flags & DS_IS_DNS_NAME) &&
  880. ((*DomainControllerInfo)->Flags & DS_DS_FLAG))
  881. {
  882. // It's an NT5 DC, so we need the DNS name of the server.
  883. Flags |= DS_RETURN_DNS_NAME;
  884. // We always want a cache hit here.
  885. Flags &= ~(ULONG)DS_FORCE_REDISCOVERY;
  886. if (!DsGetDcNameW(
  887. NULL,
  888. DomainName,
  889. NULL,
  890. NULL,
  891. Flags,
  892. &dci
  893. ))
  894. {
  895. NetApiBufferFree(*DomainControllerInfo);
  896. *DomainControllerInfo = dci;
  897. }
  898. }
  899. return status;
  900. }
  901. ///////////////////////////////////////////////////////////////////////////////
  902. //
  903. // FUNCTION
  904. //
  905. // IASChangePassword2
  906. //
  907. // DESCRIPTION
  908. //
  909. // Performs V2 password change.
  910. //
  911. ///////////////////////////////////////////////////////////////////////////////
  912. DWORD
  913. WINAPI
  914. IASChangePassword2(
  915. IN PCWSTR UserName,
  916. IN PCWSTR Domain,
  917. IN PBYTE OldNtHash,
  918. IN PBYTE OldLmHash,
  919. IN PBYTE NtEncPassword,
  920. IN PBYTE LmEncPassword,
  921. IN BOOL LmPresent
  922. )
  923. {
  924. DWORD status;
  925. PDOMAIN_CONTROLLER_INFOW dci;
  926. UNICODE_STRING uniServerName, uniUserName;
  927. //////////
  928. // Get the name of the DC to connect to.
  929. //////////
  930. if (_wcsicmp(Domain, theAccountDomain) == 0)
  931. {
  932. //////////
  933. // Local domain, so use theLocalServer.
  934. //////////
  935. dci = NULL;
  936. RtlInitUnicodeString(
  937. &uniServerName,
  938. theLocalServer
  939. );
  940. }
  941. else
  942. {
  943. //////////
  944. // Remote domain, so use IASGetDcName.
  945. //////////
  946. status = IASGetDcName(
  947. Domain,
  948. DS_WRITABLE_REQUIRED,
  949. &dci
  950. );
  951. if (status != NO_ERROR) { goto exit; }
  952. RtlInitUnicodeString(
  953. &uniServerName,
  954. dci->DomainControllerName
  955. );
  956. }
  957. RtlInitUnicodeString(
  958. &uniUserName,
  959. UserName
  960. );
  961. status = SamiChangePasswordUser2(
  962. &uniServerName,
  963. &uniUserName,
  964. (PSAMPR_ENCRYPTED_USER_PASSWORD)NtEncPassword,
  965. (PENCRYPTED_NT_OWF_PASSWORD)OldNtHash,
  966. (BOOLEAN)LmPresent,
  967. (PSAMPR_ENCRYPTED_USER_PASSWORD)LmEncPassword,
  968. (PENCRYPTED_LM_OWF_PASSWORD)OldLmHash
  969. );
  970. status = RtlNtStatusToDosError(status);
  971. if (dci)
  972. {
  973. NetApiBufferFree(dci);
  974. }
  975. exit:
  976. return status;
  977. }
  978. ///////////////////////////////////////////////////////////////////////////////
  979. //
  980. // FUNCTION
  981. //
  982. // IASChangePassword3
  983. //
  984. // DESCRIPTION
  985. //
  986. // Performs MS-CHAP v2 change password.
  987. //
  988. ///////////////////////////////////////////////////////////////////////////////
  989. DWORD
  990. WINAPI
  991. IASChangePassword3(
  992. IN PCWSTR UserName,
  993. IN PCWSTR Domain,
  994. IN PBYTE EncHash,
  995. IN PBYTE EncPassword
  996. )
  997. {
  998. return IASChangePassword2(
  999. UserName,
  1000. Domain,
  1001. EncHash,
  1002. NULL,
  1003. EncPassword,
  1004. NULL,
  1005. FALSE
  1006. );
  1007. }