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.

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