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.

2231 lines
61 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1996
  6. //
  7. // File: kerbpass.cxx
  8. //
  9. // Contents: Code for changing the Kerberos password on a KDC
  10. //
  11. //
  12. // History: 17-October-1998 MikeSw Created
  13. //
  14. //------------------------------------------------------------------------
  15. #include <kerb.hxx>
  16. #include <kerbp.h>
  17. #include <kerbpass.h>
  18. #ifdef RETAIL_LOG_SUPPORT
  19. static TCHAR THIS_FILE[] = TEXT(__FILE__);
  20. #endif
  21. #define FILENO FILENO_KERBPASS
  22. #ifndef WIN32_CHICAGO
  23. //+-------------------------------------------------------------------------
  24. //
  25. // Function: KerbUpdateLogonSessionPasswords
  26. //
  27. // Synopsis: If the caller of this API is changing the password
  28. // of its own account, update the passwords.
  29. //
  30. // Effects:
  31. //
  32. // Arguments:
  33. //
  34. // Requires:
  35. //
  36. // Returns:
  37. //
  38. // Notes:
  39. //
  40. //
  41. //--------------------------------------------------------------------------
  42. NTSTATUS
  43. KerbUpdateLogonSessionPasswords(
  44. IN PKERB_LOGON_SESSION TempLogonSession,
  45. IN PUNICODE_STRING NewPassword
  46. )
  47. {
  48. NTSTATUS Status;
  49. SECPKG_CLIENT_INFO ClientInfo;
  50. PKERB_LOGON_SESSION LogonSession = NULL;
  51. BOOLEAN LockHeld = FALSE;
  52. //
  53. // Get the logon session for the caller so we can compare the name of
  54. // the account of the changed password to the name of the account of the
  55. // caller.
  56. //
  57. Status = LsaFunctions->GetClientInfo(&ClientInfo);
  58. if (!NT_SUCCESS(Status))
  59. {
  60. goto Cleanup;
  61. }
  62. LogonSession = KerbReferenceLogonSession(
  63. &ClientInfo.LogonId,
  64. FALSE // don't remove
  65. );
  66. if (LogonSession == NULL)
  67. {
  68. Status = STATUS_NO_SUCH_LOGON_SESSION;
  69. goto Cleanup;
  70. }
  71. //
  72. // Now compare the names
  73. //
  74. DsysAssert( !LockHeld );
  75. KerbWriteLockLogonSessions(
  76. LogonSession
  77. );
  78. KerbReadLockLogonSessions(
  79. TempLogonSession
  80. );
  81. LockHeld = TRUE;
  82. if (RtlEqualUnicodeString(
  83. &LogonSession->PrimaryCredentials.UserName,
  84. &TempLogonSession->PrimaryCredentials.UserName,
  85. TRUE) && // case insensitive
  86. RtlEqualUnicodeString(
  87. &LogonSession->PrimaryCredentials.DomainName,
  88. &TempLogonSession->PrimaryCredentials.DomainName,
  89. TRUE)) // case insensitive
  90. {
  91. Status = KerbChangeCredentialsPassword(
  92. &LogonSession->PrimaryCredentials,
  93. NewPassword,
  94. NULL, // no etype info
  95. UserAccount,
  96. PRIMARY_CRED_CLEAR_PASSWORD
  97. );
  98. if (NT_SUCCESS(Status))
  99. {
  100. SECPKG_PRIMARY_CRED PrimaryCredentials = {0};
  101. PrimaryCredentials.LogonId = ClientInfo.LogonId;
  102. PrimaryCredentials.Password = *NewPassword;
  103. PrimaryCredentials.Flags = PRIMARY_CRED_UPDATE | PRIMARY_CRED_CLEAR_PASSWORD;
  104. //
  105. // Update all the other packages
  106. //
  107. KerbUnlockLogonSessions(TempLogonSession);
  108. KerbUnlockLogonSessions(LogonSession);
  109. LockHeld = FALSE;
  110. (VOID) LsaFunctions->UpdateCredentials(
  111. &PrimaryCredentials,
  112. NULL // no supplemental credentials
  113. );
  114. }
  115. }
  116. Cleanup:
  117. if (LockHeld)
  118. {
  119. KerbUnlockLogonSessions(TempLogonSession);
  120. KerbUnlockLogonSessions(LogonSession);
  121. }
  122. return(Status);
  123. }
  124. #endif // WIN32_CHICAGO
  125. #ifndef WIN32_CHICAGO
  126. //+-------------------------------------------------------------------------
  127. //
  128. // Function: KerbGetKpasswdTicket
  129. //
  130. // Synopsis: Gets a ticket for the kpasswd/changepw service in the
  131. // realm of the logon session.
  132. //
  133. // Effects:
  134. //
  135. // Arguments:
  136. //
  137. // Requires:
  138. //
  139. // Returns:
  140. //
  141. // Notes:
  142. //
  143. //
  144. //--------------------------------------------------------------------------
  145. NTSTATUS
  146. KerbGetKpasswdTicket(
  147. IN PKERB_LOGON_SESSION LogonSession,
  148. OUT PKERB_TICKET_CACHE_ENTRY * KpasswdTicket,
  149. OUT PUNICODE_STRING ClientRealm,
  150. OUT PKERB_INTERNAL_NAME * ClientName
  151. )
  152. {
  153. NTSTATUS Status = STATUS_SUCCESS;
  154. PKERB_INTERNAL_NAME KpasswdName = NULL;
  155. UNICODE_STRING CorrectRealm = {0};
  156. ULONG RetryCount = KERB_CLIENT_REFERRAL_MAX;
  157. BOOLEAN MitLogon;
  158. RtlInitUnicodeString(
  159. ClientRealm,
  160. NULL
  161. );
  162. //
  163. // Build the service name for the ticket
  164. //
  165. Status = KerbBuildKpasswdName(
  166. &KpasswdName
  167. );
  168. if (!NT_SUCCESS(Status))
  169. {
  170. goto Cleanup;
  171. }
  172. //
  173. // We don't know exactly what realm to change the password on. If the
  174. // client presesnted a UPN, we may need to chase that down first.
  175. // This is similar code to KerbGetTicketGrantingTicket.
  176. //
  177. //
  178. // We start off assuming that the domain name is the domain name
  179. // supplied by the client.
  180. //
  181. KerbReadLockLogonSessions( LogonSession );
  182. Status = KerbGetClientNameAndRealm(
  183. &LogonSession->LogonId,
  184. &LogonSession->PrimaryCredentials,
  185. FALSE,
  186. NULL,
  187. &MitLogon,
  188. FALSE, // default to wksta realm for UPN
  189. ClientName,
  190. ClientRealm
  191. );
  192. KerbUnlockLogonSessions( LogonSession );
  193. if (!NT_SUCCESS(Status))
  194. {
  195. goto Cleanup;
  196. }
  197. GetTicketRestart:
  198. //
  199. // Try to get the ticket now.
  200. //
  201. Status = KerbGetAuthenticationTicket(
  202. LogonSession,
  203. NULL, // credential
  204. NULL,
  205. TRUE,
  206. KpasswdName,
  207. ClientRealm,
  208. *ClientName,
  209. KERB_GET_AUTH_TICKET_NO_CANONICALIZE, // no name canonicalization
  210. 0, // no cache flags
  211. KpasswdTicket,
  212. NULL, // no credential key,
  213. &CorrectRealm
  214. );
  215. //
  216. // If it failed but gave us another realm to try, go there
  217. //
  218. if (!NT_SUCCESS(Status) && (CorrectRealm.Length != 0))
  219. {
  220. if (--RetryCount != 0)
  221. {
  222. KerbFreeString(ClientRealm);
  223. *ClientRealm = CorrectRealm;
  224. CorrectRealm.Buffer = NULL;
  225. goto GetTicketRestart;
  226. }
  227. }
  228. Cleanup:
  229. KerbFreeKdcName( &KpasswdName );
  230. KerbFreeString(&CorrectRealm);
  231. return(Status);
  232. }
  233. //+-------------------------------------------------------------------------
  234. //
  235. // Function: KerbBuildKerbPriv
  236. //
  237. // Synopsis: Builds a kerb-priv message with none of the optional
  238. // fields.
  239. //
  240. // Effects:
  241. //
  242. // Arguments:
  243. //
  244. // Requires:
  245. //
  246. // Returns:
  247. //
  248. // Notes:
  249. //
  250. //
  251. //--------------------------------------------------------------------------
  252. NTSTATUS
  253. KerbBuildKerbPriv(
  254. IN PBYTE Data,
  255. IN ULONG DataSize,
  256. IN PKERB_ENCRYPTION_KEY Key,
  257. IN OPTIONAL PULONG Nonce,
  258. OUT PKERB_MESSAGE_BUFFER PrivMessage
  259. )
  260. {
  261. KERBERR KerbErr = KDC_ERR_NONE;
  262. NTSTATUS Status = STATUS_SUCCESS;
  263. KERB_PRIV_MESSAGE Priv = {0};
  264. KERB_ENCRYPTED_PRIV PrivBody = {0};
  265. KERB_MESSAGE_BUFFER PackedBody = {0};
  266. PKERB_HOST_ADDRESSES Addresses = NULL;
  267. PKERB_HOST_ADDRESSES OurAddress = NULL;
  268. Status = KerbBuildHostAddresses(
  269. TRUE,
  270. TRUE,
  271. &Addresses
  272. );
  273. if (!NT_SUCCESS(Status))
  274. {
  275. goto Cleanup;
  276. }
  277. //
  278. // Look for the first IP address in the list
  279. //
  280. OurAddress = Addresses;
  281. while (OurAddress != NULL)
  282. {
  283. if (OurAddress->value.address_type == KERB_ADDRTYPE_INET)
  284. {
  285. break;
  286. }
  287. OurAddress = OurAddress->next;
  288. }
  289. if (OurAddress == NULL)
  290. {
  291. DebugLog((DEB_ERROR,"No IP addresses. %ws, line %d\n",THIS_FILE, __LINE__));
  292. Status = STATUS_NO_IP_ADDRESSES;
  293. goto Cleanup;
  294. }
  295. //
  296. // Get the client address
  297. //
  298. PrivBody.user_data.length = (int) DataSize;
  299. PrivBody.user_data.value = Data;
  300. PrivBody.sender_address.addr_type = OurAddress->value.address_type;
  301. PrivBody.sender_address.address.length = OurAddress->value.address.length;
  302. PrivBody.sender_address.address.value = OurAddress->value.address.value;
  303. if (ARGUMENT_PRESENT(Nonce))
  304. {
  305. PrivBody.KERB_ENCRYPTED_PRIV_sequence_number = (int) *Nonce;
  306. PrivBody.bit_mask |= KERB_ENCRYPTED_PRIV_sequence_number_present;
  307. }
  308. //
  309. // Now pack the priv_body
  310. //
  311. KerbErr = KerbPackData(
  312. &PrivBody,
  313. KERB_ENCRYPTED_PRIV_PDU,
  314. &PackedBody.BufferSize,
  315. &PackedBody.Buffer
  316. );
  317. if (!KERB_SUCCESS(KerbErr))
  318. {
  319. Status = KerbMapKerbError(KerbErr);
  320. goto Cleanup;
  321. }
  322. //
  323. // Now encrypt the body
  324. //
  325. KerbErr = KerbAllocateEncryptionBufferWrapper(
  326. Key->keytype,
  327. PackedBody.BufferSize,
  328. &Priv.encrypted_part.cipher_text.length,
  329. &Priv.encrypted_part.cipher_text.value
  330. );
  331. if (!KERB_SUCCESS(KerbErr))
  332. {
  333. Status = KerbMapKerbError(KerbErr);
  334. goto Cleanup;
  335. }
  336. KerbErr = KerbEncryptDataEx(
  337. &Priv.encrypted_part,
  338. PackedBody.BufferSize,
  339. PackedBody.Buffer,
  340. KERB_NO_KEY_VERSION,
  341. KERB_PRIV_SALT,
  342. Key
  343. );
  344. if (!KERB_SUCCESS(KerbErr))
  345. {
  346. Status = KerbMapKerbError(KerbErr);
  347. goto Cleanup;
  348. }
  349. //
  350. // Finally, pack the outer priv message.
  351. //
  352. Priv.version = KERBEROS_VERSION;
  353. Priv.message_type = KRB_PRIV;
  354. KerbErr = KerbPackData(
  355. &Priv,
  356. KERB_PRIV_MESSAGE_PDU,
  357. &PrivMessage->BufferSize,
  358. &PrivMessage->Buffer
  359. );
  360. if (!KERB_SUCCESS(KerbErr))
  361. {
  362. Status = KerbMapKerbError(KerbErr);
  363. goto Cleanup;
  364. }
  365. Cleanup:
  366. KerbFreeHostAddresses(Addresses);
  367. if (Priv.encrypted_part.cipher_text.value != NULL)
  368. {
  369. MIDL_user_free(Priv.encrypted_part.cipher_text.value);
  370. }
  371. if (PackedBody.Buffer != NULL)
  372. {
  373. MIDL_user_free(PackedBody.Buffer);
  374. }
  375. return(Status);
  376. }
  377. //+-------------------------------------------------------------------------
  378. //
  379. // Function: KerbBuildKpasswdRequest
  380. //
  381. // Synopsis: Builds a kpasswd request - build the AP REQ, KERB_PRIV,
  382. // and then combines them in the request.
  383. //
  384. // Effects:
  385. //
  386. // Arguments:
  387. //
  388. // Requires:
  389. //
  390. // Returns:
  391. //
  392. // Notes:
  393. //
  394. //
  395. //--------------------------------------------------------------------------
  396. NTSTATUS
  397. KerbBuildKpasswdRequest(
  398. IN PKERB_TICKET_CACHE_ENTRY KpasswdTicket,
  399. IN PUNICODE_STRING ClientRealm,
  400. IN PUNICODE_STRING NewPassword,
  401. OUT PKERB_MESSAGE_BUFFER RequestMessage,
  402. OUT PKERB_ENCRYPTION_KEY SessionKey,
  403. OUT PULONG Nonce
  404. )
  405. {
  406. NTSTATUS Status = STATUS_SUCCESS;
  407. KERB_MESSAGE_BUFFER ApRequest = {0};
  408. KERB_MESSAGE_BUFFER PrivMessage = {0};
  409. PKERB_KPASSWD_REQ KpasswdRequest;
  410. KERBERR KerbErr = KDC_ERR_NONE;
  411. STRING AnsiPassword = {0};
  412. RtlZeroMemory(
  413. SessionKey,
  414. sizeof(KERB_ENCRYPTION_KEY)
  415. );
  416. *Nonce = KerbAllocateNonce();
  417. //
  418. // Make a sub-session key for the AP request and for encrypting
  419. // the KERB_PRIV message.
  420. //
  421. KerbErr = KerbMakeKey(
  422. KpasswdTicket->SessionKey.keytype,
  423. SessionKey
  424. );
  425. if (!KERB_SUCCESS(KerbErr))
  426. {
  427. Status = KerbMapKerbError(KerbErr);
  428. goto Cleanup;
  429. }
  430. //
  431. // Build the AP request first
  432. //
  433. KerbReadLockTicketCache();
  434. KerbErr = KerbCreateApRequest(
  435. KpasswdTicket->ClientName,
  436. &KpasswdTicket->ClientDomainName,
  437. &KpasswdTicket->SessionKey,
  438. SessionKey,
  439. *Nonce,
  440. NULL, // authenticatortime on AP request - mutual auth???
  441. &KpasswdTicket->Ticket,
  442. 0, // no ap options
  443. NULL, // no checksum
  444. &KpasswdTicket->TimeSkew,
  445. FALSE, // not a KDC request
  446. &ApRequest.BufferSize,
  447. &ApRequest.Buffer
  448. );
  449. KerbUnlockTicketCache();
  450. if (!KERB_SUCCESS(KerbErr))
  451. {
  452. DebugLog((DEB_ERROR,"Failed to create AP request for kpasswd: 0x%x, %ws line %d\n",
  453. KerbErr, THIS_FILE, __LINE__ ));
  454. Status = KerbMapKerbError(KerbErr);
  455. goto Cleanup;
  456. }
  457. //
  458. // convert the password to UTF-8
  459. //
  460. KerbErr = KerbUnicodeStringToKerbString(
  461. &AnsiPassword,
  462. NewPassword
  463. );
  464. if (!KERB_SUCCESS(KerbErr))
  465. {
  466. Status = KerbMapKerbError(KerbErr);
  467. goto Cleanup;
  468. }
  469. //
  470. // Build the kerb_priv message
  471. //
  472. Status = KerbBuildKerbPriv(
  473. (PUCHAR) AnsiPassword.Buffer,
  474. AnsiPassword.Length,
  475. SessionKey,
  476. Nonce,
  477. &PrivMessage
  478. );
  479. if (!NT_SUCCESS(Status))
  480. {
  481. DebugLog((DEB_ERROR, "Failed to build Kerb-priv: 0x%x. %ws, line %d\n",
  482. Status, THIS_FILE, __LINE__));
  483. goto Cleanup;
  484. }
  485. //
  486. // Now build the request itself.
  487. //
  488. RequestMessage->BufferSize = PrivMessage.BufferSize + ApRequest.BufferSize +
  489. FIELD_OFFSET(KERB_KPASSWD_REQ,Data);
  490. RequestMessage->Buffer = (PBYTE) MIDL_user_allocate(RequestMessage->BufferSize);
  491. if (RequestMessage->Buffer == NULL)
  492. {
  493. Status = STATUS_INSUFFICIENT_RESOURCES;
  494. goto Cleanup;
  495. }
  496. KpasswdRequest = (PKERB_KPASSWD_REQ) RequestMessage->Buffer;
  497. SET_SHORT(KpasswdRequest->MessageLength, (USHORT) RequestMessage->BufferSize);
  498. SET_SHORT(KpasswdRequest->Version, KERB_KPASSWD_VERSION);
  499. SET_SHORT(KpasswdRequest->ApReqLength, (USHORT) ApRequest.BufferSize);
  500. RtlCopyMemory(
  501. KpasswdRequest->Data,
  502. ApRequest.Buffer,
  503. ApRequest.BufferSize
  504. );
  505. RtlCopyMemory(
  506. (PBYTE) KpasswdRequest->Data + ApRequest.BufferSize,
  507. PrivMessage.Buffer,
  508. PrivMessage.BufferSize
  509. );
  510. Cleanup:
  511. if (PrivMessage.Buffer != NULL)
  512. {
  513. MIDL_user_free(PrivMessage.Buffer);
  514. }
  515. if (ApRequest.Buffer != NULL)
  516. {
  517. MIDL_user_free(ApRequest.Buffer);
  518. }
  519. RtlEraseUnicodeString((PUNICODE_STRING) &AnsiPassword);
  520. KerbFreeString((PUNICODE_STRING) &AnsiPassword);
  521. return(Status);
  522. }
  523. //+-------------------------------------------------------------------------
  524. //
  525. // Function: KerbBuildSetPasswordRequest
  526. //
  527. // Synopsis: Builds a kpasswd request to set a password - build the
  528. // AP REQ, KERB_PRIV,
  529. // and then combines them in the request.
  530. //
  531. // Effects:
  532. //
  533. // Arguments:
  534. //
  535. // Requires:
  536. //
  537. // Returns:
  538. //
  539. // Notes:
  540. //
  541. //
  542. //--------------------------------------------------------------------------
  543. NTSTATUS
  544. KerbBuildSetPasswordRequest(
  545. IN PKERB_TICKET_CACHE_ENTRY KpasswdTicket,
  546. IN PKERB_INTERNAL_NAME ClientName,
  547. IN PUNICODE_STRING ClientRealm,
  548. IN PUNICODE_STRING NewPassword,
  549. OUT PKERB_MESSAGE_BUFFER RequestMessage,
  550. OUT PKERB_ENCRYPTION_KEY SessionKey,
  551. OUT PULONG Nonce
  552. )
  553. {
  554. NTSTATUS Status = STATUS_SUCCESS;
  555. KERB_MESSAGE_BUFFER ApRequest = {0};
  556. KERB_MESSAGE_BUFFER PrivMessage = {0};
  557. KERB_MESSAGE_BUFFER EncodedData = {0};
  558. PKERB_KPASSWD_REQ KpasswdRequest;
  559. KERBERR KerbErr = KDC_ERR_NONE;
  560. STRING AnsiPassword = {0};
  561. KERB_CHANGE_PASSWORD_DATA ChangeData = {0};
  562. RtlZeroMemory(
  563. SessionKey,
  564. sizeof(KERB_ENCRYPTION_KEY)
  565. );
  566. *Nonce = KerbAllocateNonce();
  567. //
  568. // Build the encoded data
  569. //
  570. //
  571. // convert the password to UTF-8
  572. //
  573. KerbErr = KerbUnicodeStringToKerbString(
  574. &AnsiPassword,
  575. NewPassword
  576. );
  577. if (!KERB_SUCCESS(KerbErr))
  578. {
  579. Status = KerbMapKerbError(KerbErr);
  580. goto Cleanup;
  581. }
  582. ChangeData.new_password.value = (PUCHAR) AnsiPassword.Buffer;
  583. ChangeData.new_password.length = AnsiPassword.Length;
  584. //
  585. // Convert the names
  586. //
  587. KerbErr = KerbConvertUnicodeStringToRealm(
  588. &ChangeData.target_realm,
  589. ClientRealm
  590. );
  591. if (!KERB_SUCCESS(KerbErr))
  592. {
  593. Status = KerbMapKerbError(KerbErr);
  594. goto Cleanup;
  595. }
  596. KerbErr = KerbConvertKdcNameToPrincipalName(
  597. &ChangeData.target_name,
  598. ClientName
  599. );
  600. if (!KERB_SUCCESS(KerbErr))
  601. {
  602. Status = KerbMapKerbError(KerbErr);
  603. goto Cleanup;
  604. }
  605. ChangeData.bit_mask = target_name_present | target_realm_present;
  606. //
  607. // Asn.1 encode the data for sending
  608. //
  609. KerbErr = KerbPackData(
  610. &ChangeData,
  611. KERB_CHANGE_PASSWORD_DATA_PDU,
  612. &EncodedData.BufferSize,
  613. &EncodedData.Buffer
  614. );
  615. if (!KERB_SUCCESS(KerbErr))
  616. {
  617. DebugLog((DEB_ERROR,"Failed to pack kerb change password data: 0x%xx, file %ws, line %d\n",
  618. KerbErr,
  619. THIS_FILE,
  620. __LINE__
  621. ));
  622. Status = KerbMapKerbError(KerbErr);
  623. goto Cleanup;
  624. }
  625. //
  626. // Make a sub-session key for the AP request and for encrypting
  627. // the KERB_PRIV message.
  628. //
  629. KerbErr = KerbMakeKey(
  630. KpasswdTicket->SessionKey.keytype,
  631. SessionKey
  632. );
  633. if (!KERB_SUCCESS(KerbErr))
  634. {
  635. Status = KerbMapKerbError(KerbErr);
  636. goto Cleanup;
  637. }
  638. //
  639. // Build the AP request first
  640. //
  641. KerbReadLockTicketCache();
  642. KerbErr = KerbCreateApRequest(
  643. KpasswdTicket->ClientName,
  644. &KpasswdTicket->ClientDomainName,
  645. &KpasswdTicket->SessionKey,
  646. SessionKey,
  647. *Nonce,
  648. NULL, // authenticatortime on AP request - mutual auth???
  649. &KpasswdTicket->Ticket,
  650. 0, // no ap options
  651. NULL, // no checksum
  652. &KpasswdTicket->TimeSkew,
  653. FALSE, // not a KDC request
  654. &ApRequest.BufferSize,
  655. &ApRequest.Buffer
  656. );
  657. KerbUnlockTicketCache();
  658. if (!KERB_SUCCESS(KerbErr))
  659. {
  660. DebugLog((DEB_ERROR,"Failed to create AP request for kpasswd: 0x%x, %ws line %d\n",
  661. KerbErr, THIS_FILE, __LINE__ ));
  662. Status = KerbMapKerbError(KerbErr);
  663. goto Cleanup;
  664. }
  665. //
  666. // Build the kerb_priv message
  667. //
  668. Status = KerbBuildKerbPriv(
  669. EncodedData.Buffer,
  670. EncodedData.BufferSize,
  671. SessionKey,
  672. Nonce,
  673. &PrivMessage
  674. );
  675. if (!NT_SUCCESS(Status))
  676. {
  677. DebugLog((DEB_ERROR, "Failed to build Kerb-priv: 0x%x. %ws, line %d\n",
  678. Status, THIS_FILE, __LINE__));
  679. goto Cleanup;
  680. }
  681. //
  682. // Now build the request itself.
  683. //
  684. RequestMessage->BufferSize = PrivMessage.BufferSize + ApRequest.BufferSize +
  685. FIELD_OFFSET(KERB_KPASSWD_REQ,Data);
  686. RequestMessage->Buffer = (PBYTE) MIDL_user_allocate(RequestMessage->BufferSize);
  687. if (RequestMessage->Buffer == NULL)
  688. {
  689. Status = STATUS_INSUFFICIENT_RESOURCES;
  690. goto Cleanup;
  691. }
  692. KpasswdRequest = (PKERB_KPASSWD_REQ) RequestMessage->Buffer;
  693. SET_SHORT(KpasswdRequest->MessageLength, (USHORT) RequestMessage->BufferSize);
  694. //
  695. // Use the special version for setting passwords
  696. //
  697. SET_SHORT(KpasswdRequest->Version, KERB_KPASSWD_SET_VERSION);
  698. SET_SHORT(KpasswdRequest->ApReqLength, (USHORT) ApRequest.BufferSize);
  699. RtlCopyMemory(
  700. KpasswdRequest->Data,
  701. ApRequest.Buffer,
  702. ApRequest.BufferSize
  703. );
  704. RtlCopyMemory(
  705. (PBYTE) KpasswdRequest->Data + ApRequest.BufferSize,
  706. PrivMessage.Buffer,
  707. PrivMessage.BufferSize
  708. );
  709. Cleanup:
  710. if (PrivMessage.Buffer != NULL)
  711. {
  712. MIDL_user_free(PrivMessage.Buffer);
  713. }
  714. if (ApRequest.Buffer != NULL)
  715. {
  716. MIDL_user_free(ApRequest.Buffer);
  717. }
  718. if (EncodedData.Buffer != NULL)
  719. {
  720. MIDL_user_free(EncodedData.Buffer);
  721. }
  722. RtlEraseUnicodeString((PUNICODE_STRING) &AnsiPassword);
  723. KerbFreeString((PUNICODE_STRING) &AnsiPassword);
  724. KerbFreeRealm(&ChangeData.target_realm);
  725. KerbFreePrincipalName(
  726. &ChangeData.target_name
  727. );
  728. return(Status);
  729. }
  730. //+-------------------------------------------------------------------------
  731. //
  732. // Function: KerbVerifyPrivMessage
  733. //
  734. // Synopsis: Verifies that a priv message is correct and returns the
  735. // user data from the message.
  736. //
  737. // Effects:
  738. //
  739. // Arguments:
  740. //
  741. // Requires:
  742. //
  743. // Returns:
  744. //
  745. // Notes:
  746. //
  747. //
  748. //--------------------------------------------------------------------------
  749. NTSTATUS
  750. KerbVerifyPrivMessage(
  751. IN PKERB_PRIV_MESSAGE PrivMessage,
  752. IN PKERB_ENCRYPTION_KEY SessionKey,
  753. OUT PKERB_MESSAGE_BUFFER PrivData
  754. )
  755. {
  756. KERBERR KerbErr = KDC_ERR_NONE;
  757. NTSTATUS Status = STATUS_SUCCESS;
  758. PKERB_ENCRYPTED_PRIV PrivBody = NULL;
  759. //
  760. // Now decrypt the KERB_PRIV message
  761. //
  762. if (PrivMessage->version != KERBEROS_VERSION)
  763. {
  764. DebugLog((DEB_ERROR,"Bad version in kpasswd priv message: %d, %ws, line %d\n",
  765. PrivMessage->version, THIS_FILE, __LINE__ ));
  766. Status = STATUS_INVALID_PARAMETER;
  767. goto Cleanup;
  768. }
  769. if (PrivMessage->message_type != KRB_PRIV)
  770. {
  771. DebugLog((DEB_ERROR,"Bad message type in kpasswd priv message: %d, %ws, line %d\n",
  772. PrivMessage->message_type, THIS_FILE, __LINE__ ));
  773. Status = STATUS_INVALID_PARAMETER;
  774. goto Cleanup;
  775. }
  776. KerbErr = KerbDecryptDataEx(
  777. &PrivMessage->encrypted_part,
  778. SessionKey,
  779. KERB_PRIV_SALT,
  780. (PULONG) &PrivMessage->encrypted_part.cipher_text.length,
  781. PrivMessage->encrypted_part.cipher_text.value
  782. );
  783. if (!KERB_SUCCESS(KerbErr))
  784. {
  785. DebugLog((DEB_ERROR,"Failed to decrypt priv message from kpasswd: 0x%x, %ws, line %d\n",
  786. KerbErr, THIS_FILE, __LINE__));
  787. Status = KerbMapKerbError(KerbErr);
  788. goto Cleanup;
  789. }
  790. //
  791. // Now decode the kerb priv body
  792. //
  793. KerbErr = KerbUnpackData(
  794. PrivMessage->encrypted_part.cipher_text.value,
  795. (ULONG) PrivMessage->encrypted_part.cipher_text.length,
  796. KERB_ENCRYPTED_PRIV_PDU,
  797. (PVOID *) &PrivBody
  798. );
  799. if (!KERB_SUCCESS(KerbErr))
  800. {
  801. DebugLog((DEB_ERROR,"Failed to unpack priv body from kpasswd: 0x%x, %ws, line %d\n",
  802. KerbErr, THIS_FILE, __LINE__));
  803. Status = KerbMapKerbError(KerbErr);
  804. goto Cleanup;
  805. }
  806. //
  807. // There is nothing in the body we want to verify (although other clients
  808. // verify the sender's address).
  809. //
  810. if (PrivBody->user_data.length != 0)
  811. {
  812. PrivData->BufferSize = PrivBody->user_data.length;
  813. PrivData->Buffer = (PBYTE) MIDL_user_allocate(PrivData->BufferSize);
  814. if (PrivData->Buffer == NULL)
  815. {
  816. Status = STATUS_INSUFFICIENT_RESOURCES;
  817. goto Cleanup;
  818. }
  819. RtlCopyMemory(
  820. PrivData->Buffer,
  821. PrivBody->user_data.value,
  822. PrivBody->user_data.length
  823. );
  824. }
  825. Cleanup:
  826. if (PrivBody != NULL)
  827. {
  828. KerbFreeData(
  829. KERB_ENCRYPTED_PRIV_PDU,
  830. PrivBody
  831. );
  832. }
  833. return(Status);
  834. }
  835. //+-------------------------------------------------------------------------
  836. //
  837. // Function: KerbHandleKpasswdReply
  838. //
  839. // Synopsis: Unpacks the reply from the kpasswd service and converts
  840. // the error to an NT status code
  841. //
  842. // Effects:
  843. //
  844. // Arguments:
  845. //
  846. // Requires:
  847. //
  848. // Returns:
  849. //
  850. // Notes:
  851. //
  852. //
  853. //--------------------------------------------------------------------------
  854. NTSTATUS
  855. KerbHandleKpasswdReply(
  856. IN PKERB_TICKET_CACHE_ENTRY KpasswdTicket,
  857. IN PKERB_ENCRYPTION_KEY SessionKey,
  858. IN PKERB_MESSAGE_BUFFER ReplyMessage
  859. )
  860. {
  861. NTSTATUS Status = STATUS_SUCCESS;
  862. KERBERR KerbErr = KDC_ERR_NONE;
  863. PKERB_KPASSWD_REP KpasswdReply;
  864. PKERB_ERROR ErrorMessage = NULL;
  865. PKERB_AP_REPLY ApReply = NULL;
  866. PKERB_ENCRYPTED_AP_REPLY ApReplyBody = NULL;
  867. PKERB_PRIV_MESSAGE PrivMessage = NULL;
  868. KERB_MESSAGE_BUFFER PrivData = {0};
  869. USHORT ResultCode = 0;
  870. //
  871. // First check to see if this is a reply
  872. //
  873. if (ReplyMessage->BufferSize > sizeof(KERB_KPASSWD_REP))
  874. {
  875. USHORT Version;
  876. USHORT Length;
  877. KpasswdReply = (PKERB_KPASSWD_REP) ReplyMessage->Buffer;
  878. GET_SHORT(Version, KpasswdReply->Version );
  879. GET_SHORT(Length, KpasswdReply->MessageLength);
  880. //
  881. // Verify these values are correct
  882. //
  883. if ((Version != KERB_KPASSWD_VERSION) ||
  884. (Length != (USHORT) ReplyMessage->BufferSize))
  885. {
  886. //
  887. // It must be a kerb_error message, so unpack it.
  888. //
  889. KerbErr = KerbUnpackKerbError(
  890. ReplyMessage->Buffer,
  891. ReplyMessage->BufferSize,
  892. &ErrorMessage
  893. );
  894. if (!KERB_SUCCESS(KerbErr))
  895. {
  896. Status = KerbMapKerbError(KerbErr);
  897. goto Cleanup;
  898. }
  899. }
  900. else
  901. {
  902. USHORT ApRepLength;
  903. ULONG PrivLength;
  904. //
  905. // It is a well formed kpasswd reply, so unpack that
  906. //
  907. GET_SHORT(ApRepLength, KpasswdReply->ApRepLength);
  908. if (ApRepLength > ReplyMessage->BufferSize - FIELD_OFFSET(KERB_KPASSWD_REP,Data))
  909. {
  910. DebugLog((DEB_ERROR,"ApReq length in kpasswd rep is wrong: %d vs %d, %ws, line %d\n",
  911. ApRepLength,
  912. FIELD_OFFSET(KERB_KPASSWD_REP,Data), THIS_FILE, __LINE__
  913. ));
  914. Status = STATUS_INVALID_PARAMETER;
  915. goto Cleanup;
  916. }
  917. //
  918. // Now unpack the AP reply
  919. //
  920. Status = KerbUnpackApReply(
  921. KpasswdReply->Data,
  922. ApRepLength,
  923. &ApReply
  924. );
  925. if (!KERB_SUCCESS(KerbErr))
  926. {
  927. Status = KerbMapKerbError(KerbErr);
  928. goto Cleanup;
  929. }
  930. //
  931. // Now try to unpack the remainder as KERB_PRIV. If that fails,
  932. // try it as a KERB_ERROR
  933. //
  934. PrivLength = ReplyMessage->BufferSize - (ApRepLength + FIELD_OFFSET(KERB_KPASSWD_REP,Data));
  935. KerbErr = KerbUnpackData(
  936. (PBYTE) KpasswdReply->Data + ApRepLength,
  937. PrivLength,
  938. KERB_PRIV_MESSAGE_PDU,
  939. (PVOID *) &PrivMessage
  940. );
  941. //
  942. // If that didn't work, try it as a kerb error message
  943. //
  944. if (!KERB_SUCCESS(KerbErr))
  945. {
  946. KerbErr = KerbUnpackKerbError(
  947. (PBYTE) KpasswdReply->Data + ApRepLength,
  948. PrivLength,
  949. &ErrorMessage
  950. );
  951. if (!KERB_SUCCESS(KerbErr))
  952. {
  953. DebugLog((DEB_ERROR,"Failed to unpack data from kpasswd rep: 0x%x, %ws line %d\n",
  954. KerbErr, THIS_FILE, __LINE__ ));
  955. Status = KerbMapKerbError(KerbErr);
  956. goto Cleanup;
  957. }
  958. }
  959. }
  960. }
  961. //
  962. // If we have an AP reply, verify it
  963. //
  964. if (ApReply != NULL)
  965. {
  966. KerbReadLockTicketCache();
  967. KerbErr = KerbDecryptDataEx(
  968. &ApReply->encrypted_part,
  969. &KpasswdTicket->SessionKey,
  970. KERB_AP_REP_SALT,
  971. (PULONG) &ApReply->encrypted_part.cipher_text.length,
  972. ApReply->encrypted_part.cipher_text.value
  973. );
  974. KerbUnlockTicketCache();
  975. if (!KERB_SUCCESS(KerbErr))
  976. {
  977. DebugLog((DEB_ERROR, "Failed to decrypt AP reply: 0x%x. %ws, line %d\n",KerbErr, THIS_FILE, __LINE__));
  978. if (KerbErr == KRB_ERR_GENERIC)
  979. {
  980. Status = STATUS_INSUFFICIENT_RESOURCES;
  981. }
  982. else
  983. {
  984. Status = STATUS_LOGON_FAILURE;
  985. }
  986. goto Cleanup;
  987. }
  988. //
  989. // Decode the contents now
  990. //
  991. if (!KERB_SUCCESS(KerbUnpackApReplyBody(
  992. ApReply->encrypted_part.cipher_text.value,
  993. ApReply->encrypted_part.cipher_text.length,
  994. &ApReplyBody)))
  995. {
  996. DebugLog((DEB_ERROR, "Failed to unpack AP reply body. %ws, line %d\n", THIS_FILE, __LINE__));
  997. Status = STATUS_INSUFFICIENT_RESOURCES;
  998. goto Cleanup;
  999. }
  1000. }
  1001. //
  1002. // If we got a priv-message, verify it
  1003. //
  1004. if (PrivMessage != NULL)
  1005. {
  1006. Status = KerbVerifyPrivMessage(
  1007. PrivMessage,
  1008. SessionKey,
  1009. &PrivData
  1010. );
  1011. if (!NT_SUCCESS(Status))
  1012. {
  1013. DebugLog((DEB_ERROR,"Failed to verify priv message while changing password: 0x%x. %ws, line %d\n",
  1014. Status, THIS_FILE, __LINE__));
  1015. goto Cleanup;
  1016. }
  1017. if (PrivData.BufferSize >= sizeof(USHORT))
  1018. {
  1019. GET_SHORT(ResultCode, PrivData.Buffer);
  1020. }
  1021. }
  1022. else
  1023. {
  1024. //
  1025. // Process the error message
  1026. //
  1027. if (ErrorMessage == NULL)
  1028. {
  1029. Status = STATUS_INSUFFICIENT_RESOURCES;
  1030. goto Cleanup;
  1031. }
  1032. // TBD: Extended errors, client side
  1033. KerbReportKerbError(
  1034. NULL,
  1035. NULL,
  1036. NULL,
  1037. NULL,
  1038. KLIN(FILENO, __LINE__),
  1039. ErrorMessage,
  1040. ErrorMessage->error_code,
  1041. NULL,
  1042. FALSE
  1043. );
  1044. Status = KerbMapKerbError(ErrorMessage->error_code);
  1045. if ((ErrorMessage->bit_mask & error_data_present) != 0)
  1046. {
  1047. if (ErrorMessage->error_data.length >= sizeof(USHORT))
  1048. {
  1049. GET_SHORT(ResultCode, ErrorMessage->error_data.value);
  1050. }
  1051. }
  1052. }
  1053. //
  1054. // Convert the result code & status into a real status
  1055. //
  1056. if (NT_SUCCESS(Status) || (Status == STATUS_INSUFFICIENT_RESOURCES))
  1057. {
  1058. switch(ResultCode) {
  1059. case KERB_KPASSWD_SUCCESS:
  1060. Status = STATUS_SUCCESS;
  1061. break;
  1062. case KERB_KPASSWD_MALFORMED:
  1063. Status = STATUS_INVALID_PARAMETER;
  1064. break;
  1065. case KERB_KPASSWD_ERROR:
  1066. Status = STATUS_UNSUCCESSFUL;
  1067. break;
  1068. case KERB_KPASSWD_AUTHENTICATION:
  1069. Status = STATUS_MUTUAL_AUTHENTICATION_FAILED;
  1070. break;
  1071. case KERB_KPASSWD_POLICY:
  1072. Status = STATUS_PASSWORD_RESTRICTION;
  1073. break;
  1074. case KERB_KPASSWD_AUTHORIZATION:
  1075. Status = STATUS_ACCESS_DENIED;
  1076. break;
  1077. default:
  1078. Status = STATUS_UNSUCCESSFUL;
  1079. }
  1080. }
  1081. Cleanup:
  1082. if (ErrorMessage != NULL)
  1083. {
  1084. KerbFreeKerbError(ErrorMessage);
  1085. }
  1086. if (ApReplyBody != NULL)
  1087. {
  1088. KerbFreeApReplyBody(ApReplyBody);
  1089. }
  1090. if (ApReply != NULL)
  1091. {
  1092. KerbFreeApReply(ApReply);
  1093. }
  1094. if (PrivData.Buffer != NULL)
  1095. {
  1096. MIDL_user_free(PrivData.Buffer);
  1097. }
  1098. if (PrivMessage != NULL)
  1099. {
  1100. KerbFreeData(
  1101. KERB_PRIV_MESSAGE_PDU,
  1102. PrivMessage
  1103. );
  1104. }
  1105. return(Status);
  1106. }
  1107. //+-------------------------------------------------------------------------
  1108. //
  1109. // Function: KerbChangePassword
  1110. //
  1111. // Synopsis: Uses the kerberos change password protocol to change
  1112. // a password. It is called through the LsaCallAuthenticationPackage
  1113. // interface
  1114. //
  1115. // Effects:
  1116. //
  1117. // Arguments:
  1118. //
  1119. // Requires:
  1120. //
  1121. // Returns:
  1122. //
  1123. // Notes:
  1124. //
  1125. //
  1126. //--------------------------------------------------------------------------
  1127. NTSTATUS NTAPI
  1128. KerbChangePassword(
  1129. IN PLSA_CLIENT_REQUEST ClientRequest,
  1130. IN PVOID ProtocolSubmitBuffer,
  1131. IN PVOID ClientBufferBase,
  1132. IN ULONG SubmitBufferSize,
  1133. OUT PVOID *ProtocolReturnBuffer,
  1134. OUT PULONG ReturnBufferSize,
  1135. OUT PNTSTATUS ProtocolStatus
  1136. )
  1137. {
  1138. PKERB_CHANGEPASSWORD_REQUEST ChangePasswordRequest = NULL;
  1139. NTSTATUS Status = STATUS_SUCCESS;
  1140. PSECURITY_SEED_AND_LENGTH SeedAndLength;
  1141. UCHAR Seed;
  1142. LUID DummyLogonId = {0};
  1143. PKERB_LOGON_SESSION LogonSession = NULL;
  1144. PKERB_TICKET_CACHE_ENTRY KpasswdTicket = NULL;
  1145. PKERB_INTERNAL_NAME ClientName = NULL;
  1146. UNICODE_STRING ValidatedAccountName;
  1147. UNICODE_STRING ValidatedDomainName;
  1148. LPWSTR ValidatedOldPasswordBuffer;
  1149. LPWSTR ValidatedNewPasswordBuffer;
  1150. UNICODE_STRING RealmName = {0};
  1151. KERB_MESSAGE_BUFFER KpasswdRequest = {0};
  1152. KERB_MESSAGE_BUFFER KpasswdReply = {0};
  1153. KERB_ENCRYPTION_KEY SessionKey = {0};
  1154. ULONG Nonce = 0;
  1155. BOOLEAN PasswordBufferValidated = FALSE;
  1156. BOOLEAN CalledPDC = FALSE;
  1157. ULONG StructureSize = sizeof(KERB_CHANGEPASSWORD_REQUEST);
  1158. KERB_CHANGEPASS_INFO ChangePassTraceInfo;
  1159. if( KerbEventTraceFlag ) // Event Trace: KerbChangePasswordStart {No Data}
  1160. {
  1161. ChangePassTraceInfo.EventTrace.Guid = KerbChangePassGuid;
  1162. ChangePassTraceInfo.EventTrace.Class.Type = EVENT_TRACE_TYPE_START;
  1163. ChangePassTraceInfo.EventTrace.Flags = WNODE_FLAG_TRACED_GUID;
  1164. ChangePassTraceInfo.EventTrace.Size = sizeof(EVENT_TRACE_HEADER);
  1165. TraceEvent( KerbTraceLoggerHandle, (PEVENT_TRACE_HEADER)&ChangePassTraceInfo );
  1166. }
  1167. *ReturnBufferSize = 0;
  1168. *ProtocolReturnBuffer = NULL;
  1169. *ProtocolStatus = STATUS_PENDING;
  1170. #if _WIN64
  1171. SECPKG_CALL_INFO CallInfo;
  1172. if(!LsaFunctions->GetCallInfo(&CallInfo))
  1173. {
  1174. Status = STATUS_INTERNAL_ERROR;
  1175. goto Cleanup;
  1176. }
  1177. if (CallInfo.Attributes & SECPKG_CALL_WOWCLIENT)
  1178. {
  1179. StructureSize = sizeof(KERB_CHANGEPASSWORD_REQUEST_WOW64);
  1180. }
  1181. #endif // _WIN64
  1182. //
  1183. // Sanity checks.
  1184. //
  1185. if ( SubmitBufferSize < StructureSize )
  1186. {
  1187. Status = STATUS_INVALID_PARAMETER;
  1188. goto Cleanup;
  1189. }
  1190. ChangePasswordRequest = (PKERB_CHANGEPASSWORD_REQUEST) ProtocolSubmitBuffer;
  1191. ASSERT( ChangePasswordRequest->MessageType == KerbChangePasswordMessage );
  1192. #if _WIN64
  1193. KERB_CHANGEPASSWORD_REQUEST LocalChangePasswordRequest;
  1194. //
  1195. // Thunk 32-bit pointers if this is a WOW caller
  1196. //
  1197. if (CallInfo.Attributes & SECPKG_CALL_WOWCLIENT)
  1198. {
  1199. PKERB_CHANGEPASSWORD_REQUEST_WOW64 ChangePasswordRequestWOW =
  1200. (PKERB_CHANGEPASSWORD_REQUEST_WOW64) ChangePasswordRequest;
  1201. LocalChangePasswordRequest.MessageType = ChangePasswordRequest->MessageType;
  1202. LocalChangePasswordRequest.Impersonating = ChangePasswordRequest->Impersonating;
  1203. UNICODE_STRING_FROM_WOW_STRING(&LocalChangePasswordRequest.DomainName,
  1204. &ChangePasswordRequestWOW->DomainName);
  1205. UNICODE_STRING_FROM_WOW_STRING(&LocalChangePasswordRequest.AccountName,
  1206. &ChangePasswordRequestWOW->AccountName);
  1207. UNICODE_STRING_FROM_WOW_STRING(&LocalChangePasswordRequest.OldPassword,
  1208. &ChangePasswordRequestWOW->OldPassword);
  1209. UNICODE_STRING_FROM_WOW_STRING(&LocalChangePasswordRequest.NewPassword,
  1210. &ChangePasswordRequestWOW->NewPassword);
  1211. ChangePasswordRequest = &LocalChangePasswordRequest;
  1212. }
  1213. #endif // _WIN64
  1214. RELOCATE_ONE( &ChangePasswordRequest->DomainName );
  1215. RELOCATE_ONE( &ChangePasswordRequest->AccountName );
  1216. RELOCATE_ONE_ENCODED( &ChangePasswordRequest->OldPassword );
  1217. RELOCATE_ONE_ENCODED( &ChangePasswordRequest->NewPassword );
  1218. //
  1219. // save away copies of validated buffers to check later.
  1220. //
  1221. RtlCopyMemory( &ValidatedDomainName, &ChangePasswordRequest->DomainName, sizeof(ValidatedDomainName) );
  1222. RtlCopyMemory( &ValidatedAccountName, &ChangePasswordRequest->AccountName, sizeof(ValidatedAccountName) );
  1223. ValidatedOldPasswordBuffer = ChangePasswordRequest->OldPassword.Buffer;
  1224. ValidatedNewPasswordBuffer = ChangePasswordRequest->NewPassword.Buffer;
  1225. SeedAndLength = (PSECURITY_SEED_AND_LENGTH) &ChangePasswordRequest->OldPassword.Length;
  1226. Seed = SeedAndLength->Seed;
  1227. SeedAndLength->Seed = 0;
  1228. //
  1229. // Check to see if the OldPassword will run over the buffer for the New
  1230. // Password
  1231. //
  1232. if ((ChangePasswordRequest->OldPassword.Buffer +
  1233. (ChangePasswordRequest->OldPassword.Length/sizeof(WCHAR)) )>
  1234. ChangePasswordRequest->NewPassword.Buffer)
  1235. {
  1236. Status = STATUS_ILL_FORMED_PASSWORD;
  1237. goto Cleanup;
  1238. }
  1239. if (Seed != 0) {
  1240. __try {
  1241. RtlRunDecodeUnicodeString(
  1242. Seed,
  1243. &ChangePasswordRequest->OldPassword
  1244. );
  1245. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1246. Status = STATUS_ILL_FORMED_PASSWORD;
  1247. goto Cleanup;
  1248. }
  1249. }
  1250. SeedAndLength = (PSECURITY_SEED_AND_LENGTH) &ChangePasswordRequest->NewPassword.Length;
  1251. Seed = SeedAndLength->Seed;
  1252. SeedAndLength->Seed = 0;
  1253. if (Seed != 0) {
  1254. __try {
  1255. RtlRunDecodeUnicodeString(
  1256. Seed,
  1257. &ChangePasswordRequest->NewPassword
  1258. );
  1259. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1260. Status = STATUS_ILL_FORMED_PASSWORD;
  1261. goto Cleanup;
  1262. }
  1263. }
  1264. //
  1265. // sanity check that we didn't whack over buffers.
  1266. //
  1267. if( !RtlCompareMemory(
  1268. &ValidatedDomainName,
  1269. &ChangePasswordRequest->DomainName,
  1270. sizeof(ValidatedDomainName)
  1271. )
  1272. ||
  1273. !RtlCompareMemory(
  1274. &ValidatedAccountName,
  1275. &ChangePasswordRequest->AccountName,
  1276. sizeof(ValidatedAccountName)
  1277. )
  1278. ||
  1279. (ValidatedOldPasswordBuffer != ChangePasswordRequest->OldPassword.Buffer)
  1280. ||
  1281. (ValidatedNewPasswordBuffer != ChangePasswordRequest->NewPassword.Buffer)
  1282. ) {
  1283. Status= STATUS_INVALID_PARAMETER;
  1284. goto Cleanup;
  1285. }
  1286. //
  1287. // Validate IN params, to not exceed KERB_MAX_UNICODE_STRING, as we add a NULL
  1288. // to UNICODE buffers when we're duping strings.
  1289. //
  1290. if (ChangePasswordRequest->OldPassword.Length > KERB_MAX_UNICODE_STRING ||
  1291. ChangePasswordRequest->NewPassword.Length > KERB_MAX_UNICODE_STRING ||
  1292. ChangePasswordRequest->AccountName.Length > KERB_MAX_UNICODE_STRING ||
  1293. ChangePasswordRequest->DomainName.Length > KERB_MAX_UNICODE_STRING)
  1294. {
  1295. Status = STATUS_NAME_TOO_LONG;
  1296. goto Cleanup;
  1297. }
  1298. PasswordBufferValidated = TRUE;
  1299. //
  1300. // The protocol requires a ticket to the kadmin/changepw service. We
  1301. // need to create a logon session to use the KerbGetAuthenticationTicket
  1302. // routine.
  1303. //
  1304. Status = NtAllocateLocallyUniqueId( &DummyLogonId );
  1305. if (!NT_SUCCESS(Status))
  1306. {
  1307. DebugLog((DEB_ERROR,"Failed to allocate locally unique ID: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  1308. goto Cleanup;
  1309. }
  1310. Status = KerbCreateLogonSession(
  1311. &DummyLogonId,
  1312. &ChangePasswordRequest->AccountName,
  1313. &ChangePasswordRequest->DomainName,
  1314. &ChangePasswordRequest->OldPassword,
  1315. NULL, // no old password
  1316. PRIMARY_CRED_CLEAR_PASSWORD,
  1317. 0,
  1318. FALSE,
  1319. &LogonSession
  1320. );
  1321. if (!NT_SUCCESS(Status))
  1322. {
  1323. goto Cleanup;
  1324. }
  1325. //
  1326. // Now get a ticket for the kpasswd service
  1327. //
  1328. Status = KerbGetKpasswdTicket(
  1329. LogonSession,
  1330. &KpasswdTicket,
  1331. &RealmName,
  1332. &ClientName
  1333. );
  1334. if (!NT_SUCCESS(Status))
  1335. {
  1336. goto Cleanup;
  1337. }
  1338. Status = KerbBuildKpasswdRequest(
  1339. KpasswdTicket,
  1340. &RealmName,
  1341. &ChangePasswordRequest->NewPassword,
  1342. &KpasswdRequest,
  1343. &SessionKey,
  1344. &Nonce
  1345. );
  1346. if (!NT_SUCCESS(Status))
  1347. {
  1348. DebugLog((DEB_ERROR,"Failed to build kpasswd request: 0x%x. %ws, line %d\n",
  1349. Status, THIS_FILE, __LINE__));
  1350. goto Cleanup;
  1351. }
  1352. //
  1353. // Call the KDC
  1354. //
  1355. Status = KerbMakeSocketCall(
  1356. &RealmName,
  1357. NULL, // no account name
  1358. FALSE, // don't call PDC
  1359. FALSE, // don't use TCP
  1360. TRUE,
  1361. &KpasswdRequest,
  1362. &KpasswdReply,
  1363. NULL, // no optional binding cache info
  1364. 0, // no additonal flags
  1365. &CalledPDC
  1366. );
  1367. if (!NT_SUCCESS(Status))
  1368. {
  1369. DebugLog((DEB_ERROR,"Failed to call kpasswd service: 0x%x. %ws, line %d\n",
  1370. Status, THIS_FILE, __LINE__ ));
  1371. goto Cleanup;
  1372. }
  1373. //
  1374. // Unpack the reply and return the error from it.
  1375. //
  1376. Status = KerbHandleKpasswdReply(
  1377. KpasswdTicket,
  1378. &SessionKey,
  1379. &KpasswdReply
  1380. );
  1381. if (!NT_SUCCESS(Status))
  1382. {
  1383. DebugLog((DEB_WARN,"Change password reply failed: 0x%x, %ws, line %d\n",
  1384. Status, THIS_FILE, __LINE__ ));
  1385. goto Cleanup;
  1386. }
  1387. //
  1388. // Update the password in the logon session, if need be.
  1389. //
  1390. Status = KerbUpdateLogonSessionPasswords(
  1391. LogonSession,
  1392. &ChangePasswordRequest->NewPassword
  1393. );
  1394. if (!NT_SUCCESS(Status))
  1395. {
  1396. //
  1397. // In some cases, we may not know about the caller's logon session
  1398. // (*e.g. anonymous caller). In that case, its normal not to know
  1399. // the logon session - don't fail.
  1400. //
  1401. if (Status == STATUS_NO_SUCH_LOGON_SESSION)
  1402. {
  1403. Status = STATUS_SUCCESS;
  1404. }
  1405. else
  1406. {
  1407. D_DebugLog((DEB_ERROR, "KerbUPdateLogonSEssionPasswords failed %x\n", Status));
  1408. }
  1409. goto Cleanup;
  1410. }
  1411. else
  1412. {
  1413. //
  1414. // Update credential manager password
  1415. //
  1416. KerbNotifyCredentialManager(
  1417. LogonSession,
  1418. ChangePasswordRequest,
  1419. ClientName,
  1420. &RealmName
  1421. );
  1422. }
  1423. Cleanup:
  1424. if( KerbEventTraceFlag ) // Event Trace: KerbChangePasswordEnd {Status, AccountName, DomainName}
  1425. {
  1426. INSERT_ULONG_INTO_MOF( Status, ChangePassTraceInfo.MofData, 0 );
  1427. ChangePassTraceInfo.EventTrace.Size = sizeof(EVENT_TRACE_HEADER) + 1*sizeof(MOF_FIELD);
  1428. if( ChangePasswordRequest != NULL )
  1429. {
  1430. INSERT_UNICODE_STRING_INTO_MOF( ChangePasswordRequest->AccountName, ChangePassTraceInfo.MofData, 1 );
  1431. INSERT_UNICODE_STRING_INTO_MOF( ChangePasswordRequest->DomainName, ChangePassTraceInfo.MofData, 3 );
  1432. ChangePassTraceInfo.EventTrace.Size += 4*sizeof(MOF_FIELD);
  1433. }
  1434. ChangePassTraceInfo.EventTrace.Guid = KerbChangePassGuid;
  1435. ChangePassTraceInfo.EventTrace.Class.Type = EVENT_TRACE_TYPE_END;
  1436. ChangePassTraceInfo.EventTrace.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
  1437. TraceEvent( KerbTraceLoggerHandle, (PEVENT_TRACE_HEADER) &ChangePassTraceInfo );
  1438. }
  1439. KerbFreeString(&RealmName);
  1440. KerbFreeKdcName(&ClientName);
  1441. if (KpasswdTicket != NULL)
  1442. {
  1443. KerbDereferenceTicketCacheEntry( KpasswdTicket );
  1444. }
  1445. if (LogonSession != NULL)
  1446. {
  1447. KerbReferenceLogonSessionByPointer(
  1448. LogonSession,
  1449. TRUE // Pull from list
  1450. );
  1451. KerbDereferenceLogonSession( LogonSession );
  1452. KerbDereferenceLogonSession( LogonSession );
  1453. }
  1454. //
  1455. // Don't let the password stay in the page file.
  1456. //
  1457. if ( PasswordBufferValidated ) {
  1458. RtlEraseUnicodeString( &ChangePasswordRequest->OldPassword );
  1459. RtlEraseUnicodeString( &ChangePasswordRequest->NewPassword );
  1460. }
  1461. if (KpasswdRequest.Buffer != NULL)
  1462. {
  1463. MIDL_user_free(KpasswdRequest.Buffer);
  1464. }
  1465. if (KpasswdReply.Buffer != NULL)
  1466. {
  1467. MIDL_user_free(KpasswdReply.Buffer);
  1468. }
  1469. if (SessionKey.keyvalue.value != NULL)
  1470. {
  1471. MIDL_user_free(SessionKey.keyvalue.value);
  1472. }
  1473. *ProtocolStatus = Status;
  1474. return(STATUS_SUCCESS);
  1475. }
  1476. //+-------------------------------------------------------------------------
  1477. //
  1478. // Function: KerbSetPasswordEx
  1479. //
  1480. // Synopsis: Uses the kerberos set password protocol to set an account
  1481. // password. It uses the identity of the caller to authenticate
  1482. // the request. It is called through the
  1483. // LsaCallAuthenticationPackage interface
  1484. //
  1485. // Effects:
  1486. //
  1487. // Arguments:
  1488. //
  1489. // Requires:
  1490. //
  1491. // Returns:
  1492. //
  1493. // Notes:
  1494. //
  1495. //
  1496. //--------------------------------------------------------------------------
  1497. NTSTATUS NTAPI
  1498. KerbSetPassword(
  1499. IN PLSA_CLIENT_REQUEST ClientRequest,
  1500. IN PVOID ProtocolSubmitBuffer,
  1501. IN PVOID ClientBufferBase,
  1502. IN ULONG SubmitBufferSize,
  1503. OUT PVOID *ProtocolReturnBuffer,
  1504. OUT PULONG ReturnBufferSize,
  1505. OUT PNTSTATUS ProtocolStatus
  1506. )
  1507. {
  1508. PKERB_SETPASSWORD_EX_REQUEST SetPasswordRequest = NULL;
  1509. NTSTATUS Status = STATUS_SUCCESS;
  1510. PSECURITY_SEED_AND_LENGTH SeedAndLength;
  1511. UCHAR Seed;
  1512. LUID DummyLogonId = {0};
  1513. PKERB_LOGON_SESSION LogonSession = NULL;
  1514. PKERB_CREDENTIAL Credential = NULL;
  1515. PKERB_TICKET_CACHE_ENTRY KpasswdTicket = NULL;
  1516. KERB_PRIMARY_CREDENTIAL PrimaryCreds = {0};
  1517. KERB_MESSAGE_BUFFER KpasswdRequest = {0};
  1518. KERB_MESSAGE_BUFFER KpasswdReply = {0};
  1519. KERB_ENCRYPTION_KEY SessionKey = {0};
  1520. ULONG Nonce = 0;
  1521. BOOLEAN PasswordBufferValidated = FALSE;
  1522. BOOLEAN CalledPDC = FALSE;
  1523. BOOLEAN SuppliedCreds = FALSE;
  1524. SECPKG_CLIENT_INFO ClientInfo;
  1525. PKERB_INTERNAL_NAME KpasswdName = NULL;
  1526. PKERB_INTERNAL_NAME ClientName = NULL;
  1527. PKERB_BINDING_CACHE_ENTRY OptionalBindingHandle = NULL;
  1528. UNICODE_STRING ClientRealm = {0};
  1529. PLUID LogonId;
  1530. ULONG StructureSize = sizeof(KERB_SETPASSWORD_REQUEST);
  1531. ULONG StructureSizeEx = sizeof(KERB_SETPASSWORD_EX_REQUEST);
  1532. KERB_SETPASS_INFO SetPassTraceInfo;
  1533. if( KerbEventTraceFlag ) // Event Trace: KerbSetPasswordStart {No Data}
  1534. {
  1535. SetPassTraceInfo.EventTrace.Guid = KerbSetPassGuid;
  1536. SetPassTraceInfo.EventTrace.Class.Type = EVENT_TRACE_TYPE_START;
  1537. SetPassTraceInfo.EventTrace.Flags = WNODE_FLAG_TRACED_GUID;
  1538. SetPassTraceInfo.EventTrace.Size = sizeof(EVENT_TRACE_HEADER);
  1539. TraceEvent( KerbTraceLoggerHandle, (PEVENT_TRACE_HEADER)&SetPassTraceInfo );
  1540. }
  1541. *ReturnBufferSize = 0;
  1542. *ProtocolReturnBuffer = NULL;
  1543. *ProtocolStatus = STATUS_PENDING;
  1544. SetPasswordRequest = (PKERB_SETPASSWORD_EX_REQUEST) ProtocolSubmitBuffer;
  1545. ASSERT( (SetPasswordRequest->MessageType == KerbSetPasswordExMessage
  1546. || SetPasswordRequest->MessageType == KerbSetPasswordMessage) );
  1547. #if _WIN64
  1548. SECPKG_CALL_INFO CallInfo;
  1549. if (!LsaFunctions->GetCallInfo(&CallInfo))
  1550. {
  1551. goto Cleanup;
  1552. }
  1553. if (CallInfo.Attributes & SECPKG_CALL_WOWCLIENT)
  1554. {
  1555. //
  1556. // These levels are not supported for WOW
  1557. //
  1558. Status = STATUS_NOT_SUPPORTED;
  1559. goto Cleanup;
  1560. }
  1561. #endif // _WIN64
  1562. //
  1563. // Sanity checks.
  1564. //
  1565. if (SubmitBufferSize < StructureSize)
  1566. {
  1567. Status = STATUS_INVALID_PARAMETER;
  1568. goto Cleanup;
  1569. }
  1570. if (SetPasswordRequest->MessageType == KerbSetPasswordExMessage)
  1571. {
  1572. if (SubmitBufferSize < StructureSizeEx)
  1573. {
  1574. Status = STATUS_INVALID_PARAMETER;
  1575. goto Cleanup;
  1576. }
  1577. NULL_RELOCATE_ONE( &SetPasswordRequest->KdcAddress );
  1578. NULL_RELOCATE_ONE( &SetPasswordRequest->ClientName );
  1579. NULL_RELOCATE_ONE( &SetPasswordRequest->ClientRealm );
  1580. }
  1581. //
  1582. // Note: although the struct members may be different, the type
  1583. // remains the same between EX and normal version of SETPASSWORD_REQUEST
  1584. // structure.
  1585. //
  1586. RELOCATE_ONE( &SetPasswordRequest->AccountRealm );
  1587. RELOCATE_ONE( &SetPasswordRequest->AccountName );
  1588. RELOCATE_ONE_ENCODED( &SetPasswordRequest->Password );
  1589. SeedAndLength = (PSECURITY_SEED_AND_LENGTH) &SetPasswordRequest->Password.Length;
  1590. Seed = SeedAndLength->Seed;
  1591. SeedAndLength->Seed = 0;
  1592. if (Seed != 0) {
  1593. __try {
  1594. RtlRunDecodeUnicodeString(
  1595. Seed,
  1596. &SetPasswordRequest->Password
  1597. );
  1598. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1599. Status = STATUS_ILL_FORMED_PASSWORD;
  1600. goto Cleanup;
  1601. }
  1602. }
  1603. if (SetPasswordRequest->AccountName.Length > KERB_MAX_UNICODE_STRING ||
  1604. SetPasswordRequest->AccountRealm.Length > KERB_MAX_UNICODE_STRING ||
  1605. SetPasswordRequest->Password.Length > KERB_MAX_UNICODE_STRING)
  1606. {
  1607. Status = STATUS_NAME_TOO_LONG;
  1608. goto Cleanup;
  1609. }
  1610. if (SetPasswordRequest->MessageType == KerbSetPasswordExMessage)
  1611. {
  1612. if(SetPasswordRequest->ClientRealm.Length > KERB_MAX_UNICODE_STRING ||
  1613. SetPasswordRequest->ClientName.Length > KERB_MAX_UNICODE_STRING ||
  1614. SetPasswordRequest->KdcAddress.Length > KERB_MAX_UNICODE_STRING )
  1615. {
  1616. Status = STATUS_NAME_TOO_LONG;
  1617. goto Cleanup;
  1618. }
  1619. }
  1620. PasswordBufferValidated = TRUE;
  1621. Status = LsaFunctions->GetClientInfo(&ClientInfo);
  1622. if (!NT_SUCCESS(Status))
  1623. {
  1624. goto Cleanup;
  1625. }
  1626. //
  1627. // If the caller did not provide a logon id, use the caller's logon id.
  1628. //
  1629. if ( (SetPasswordRequest->Flags & KERB_SETPASS_USE_LOGONID) != 0)
  1630. {
  1631. //
  1632. // Verify the caller has TCB privilege if they want access to someone
  1633. // elses ticket cache.
  1634. //
  1635. if (!ClientInfo.HasTcbPrivilege)
  1636. {
  1637. Status = STATUS_PRIVILEGE_NOT_HELD;
  1638. goto Cleanup;
  1639. }
  1640. LogonId = &SetPasswordRequest->LogonId;
  1641. }
  1642. else if ( (SetPasswordRequest->Flags & KERB_SETPASS_USE_CREDHANDLE) != 0)
  1643. {
  1644. //
  1645. // Get the associated credential
  1646. //
  1647. Status = KerbReferenceCredential(
  1648. SetPasswordRequest->CredentialsHandle.dwUpper,
  1649. KERB_CRED_OUTBOUND | KERB_CRED_TGT_AVAIL,
  1650. FALSE,
  1651. &Credential);
  1652. if (!NT_SUCCESS(Status))
  1653. {
  1654. DebugLog((DEB_WARN,"Failed to locate credential: 0x%x\n",Status));
  1655. goto Cleanup;
  1656. }
  1657. //
  1658. // Get the logon id from the credentials so we can locate the
  1659. // logon session.
  1660. //
  1661. SuppliedCreds = TRUE;
  1662. DummyLogonId = Credential->LogonId;
  1663. LogonId = &DummyLogonId;
  1664. }
  1665. else
  1666. {
  1667. LogonId = &ClientInfo.LogonId;
  1668. }
  1669. //
  1670. // The protocol requires a ticket to the kadmin/changepw service. We
  1671. // need to get the caller's logon session to use to get this
  1672. // ticket.
  1673. //
  1674. LogonSession = KerbReferenceLogonSession(
  1675. LogonId,
  1676. FALSE // don't unlink
  1677. );
  1678. if (LogonSession == NULL)
  1679. {
  1680. DebugLog((DEB_ERROR,"Can't locate caller's logon session\n"));
  1681. Status = STATUS_NO_SUCH_LOGON_SESSION;
  1682. goto Cleanup;
  1683. }
  1684. //
  1685. // Now get a ticket for the kpasswd service
  1686. //
  1687. Status = KerbBuildKpasswdName(
  1688. &KpasswdName
  1689. );
  1690. if (!NT_SUCCESS(Status))
  1691. {
  1692. goto Cleanup;
  1693. }
  1694. Status = KerbGetServiceTicket(
  1695. LogonSession,
  1696. Credential, // no credential
  1697. NULL,
  1698. KpasswdName,
  1699. &SetPasswordRequest->AccountRealm,
  1700. NULL,
  1701. TRUE, // don't do name canonicalization
  1702. 0, // no ticket options
  1703. 0, // no encryption type
  1704. NULL, // no error message
  1705. NULL, // no authorizatoin data,
  1706. NULL, // no tgt reply
  1707. &KpasswdTicket,
  1708. NULL // don't return logon guid
  1709. );
  1710. if (!NT_SUCCESS(Status))
  1711. {
  1712. goto Cleanup;
  1713. }
  1714. //
  1715. // Parse the names to get the real kerberos names
  1716. //
  1717. PrimaryCreds.UserName = SetPasswordRequest->AccountName;
  1718. PrimaryCreds.DomainName = SetPasswordRequest->AccountRealm;
  1719. Status = KerbGetClientNameAndRealm(
  1720. LogonId,
  1721. &PrimaryCreds,
  1722. SuppliedCreds,
  1723. NULL,
  1724. NULL,
  1725. FALSE, // default to wksta realm for UPN
  1726. &ClientName,
  1727. &ClientRealm
  1728. );
  1729. if (!NT_SUCCESS(Status))
  1730. {
  1731. DebugLog((DEB_ERROR,"Failed to get client name and realm: 0x%x file %ws, line %d\n",
  1732. Status, THIS_FILE, __LINE__));
  1733. goto Cleanup;
  1734. }
  1735. //
  1736. // Build the set password request
  1737. //
  1738. Status = KerbBuildSetPasswordRequest(
  1739. KpasswdTicket,
  1740. ClientName,
  1741. &ClientRealm,
  1742. &SetPasswordRequest->Password,
  1743. &KpasswdRequest,
  1744. &SessionKey,
  1745. &Nonce
  1746. );
  1747. if (!NT_SUCCESS(Status))
  1748. {
  1749. DebugLog((DEB_ERROR,"Failed to build kpasswd request: 0x%x. %ws, line %d\n",
  1750. Status, THIS_FILE, __LINE__));
  1751. goto Cleanup;
  1752. }
  1753. //
  1754. // Here we may possibly need to set the target KDC
  1755. // This KDC is not gaurenteed to succeeed, and retry logic
  1756. // will occur on a failed SetPwd request..
  1757. //
  1758. if (SetPasswordRequest->MessageType == KerbSetPasswordExMessage
  1759. && SetPasswordRequest->KdcAddress.Buffer != NULL)
  1760. {
  1761. OptionalBindingHandle = (PKERB_BINDING_CACHE_ENTRY)
  1762. KerbAllocate(sizeof(KERB_BINDING_CACHE_ENTRY));
  1763. if (NULL == OptionalBindingHandle)
  1764. {
  1765. Status = STATUS_INSUFFICIENT_RESOURCES;
  1766. }
  1767. OptionalBindingHandle->AddressType = SetPasswordRequest->KdcAddressType;
  1768. RtlCopyMemory(
  1769. &(OptionalBindingHandle->KdcAddress),
  1770. &(SetPasswordRequest->KdcAddress),
  1771. sizeof(UNICODE_STRING)
  1772. );
  1773. RtlCopyMemory(
  1774. &(OptionalBindingHandle->RealmName),
  1775. &(SetPasswordRequest->AccountRealm),
  1776. sizeof(UNICODE_STRING)
  1777. );
  1778. }
  1779. //
  1780. // Call the KDC
  1781. //
  1782. Status = KerbMakeSocketCall(
  1783. &ClientRealm,
  1784. NULL, // no account name
  1785. FALSE, // don't call PDC
  1786. FALSE, // don't use TCP
  1787. TRUE,
  1788. &KpasswdRequest,
  1789. &KpasswdReply,
  1790. OptionalBindingHandle,
  1791. 0, // no additional flags
  1792. &CalledPDC
  1793. );
  1794. if (!NT_SUCCESS(Status))
  1795. {
  1796. DebugLog((DEB_ERROR,"Failed to call kpasswd service: 0x%x. %ws, line %d\n",
  1797. Status, THIS_FILE, __LINE__ ));
  1798. goto Cleanup;
  1799. }
  1800. //
  1801. // Unpack the reply and return the error from it.
  1802. //
  1803. Status = KerbHandleKpasswdReply(
  1804. KpasswdTicket,
  1805. &SessionKey,
  1806. &KpasswdReply
  1807. );
  1808. if (!NT_SUCCESS(Status))
  1809. {
  1810. DebugLog((DEB_WARN,"Change password reply failed: 0x%x, %ws, line %d\n",
  1811. Status, THIS_FILE, __LINE__ ));
  1812. goto Cleanup;
  1813. }
  1814. Cleanup:
  1815. if( KerbEventTraceFlag ) // Event Trace: KerbSetPasswordEnd {Status, AccountName, AccountRealm, (ClientName), (ClientRealm), (KdcAddress)}
  1816. {
  1817. INSERT_ULONG_INTO_MOF( Status, SetPassTraceInfo.MofData, 0 );
  1818. SetPassTraceInfo.EventTrace.Size = sizeof(EVENT_TRACE_HEADER) + 1*sizeof(MOF_FIELD);
  1819. if( SetPasswordRequest != NULL )
  1820. {
  1821. INSERT_UNICODE_STRING_INTO_MOF(SetPasswordRequest->AccountName, SetPassTraceInfo.MofData, 1);
  1822. INSERT_UNICODE_STRING_INTO_MOF(SetPasswordRequest->AccountRealm, SetPassTraceInfo.MofData, 3);
  1823. SetPassTraceInfo.EventTrace.Size += 4 * sizeof(MOF_FIELD);
  1824. if (SetPasswordRequest->MessageType == KerbSetPasswordExMessage)
  1825. {
  1826. INSERT_UNICODE_STRING_INTO_MOF(SetPasswordRequest->ClientName, SetPassTraceInfo.MofData, 5);
  1827. INSERT_UNICODE_STRING_INTO_MOF(SetPasswordRequest->ClientRealm, SetPassTraceInfo.MofData, 7);
  1828. INSERT_UNICODE_STRING_INTO_MOF(SetPasswordRequest->KdcAddress, SetPassTraceInfo.MofData, 9);
  1829. SetPassTraceInfo.EventTrace.Size += 6 * sizeof(MOF_FIELD);
  1830. }
  1831. }
  1832. SetPassTraceInfo.EventTrace.Guid = KerbSetPassGuid;
  1833. SetPassTraceInfo.EventTrace.Class.Type = EVENT_TRACE_TYPE_END;
  1834. SetPassTraceInfo.EventTrace.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
  1835. TraceEvent( KerbTraceLoggerHandle, (PEVENT_TRACE_HEADER) &SetPassTraceInfo );
  1836. }
  1837. KerbFreeKdcName( &KpasswdName );
  1838. KerbFreeKdcName( &ClientName );
  1839. KerbFreeString( &ClientRealm );
  1840. KerbFreeKey( &SessionKey );
  1841. if (KpasswdTicket != NULL)
  1842. {
  1843. KerbDereferenceTicketCacheEntry( KpasswdTicket );
  1844. }
  1845. if (Credential != NULL)
  1846. {
  1847. KerbDereferenceCredential(Credential);
  1848. }
  1849. if (NULL != OptionalBindingHandle)
  1850. {
  1851. KerbFree(OptionalBindingHandle);
  1852. }
  1853. if (LogonSession != NULL)
  1854. {
  1855. KerbDereferenceLogonSession( LogonSession );
  1856. }
  1857. //
  1858. // Don't let the password stay in the page file.
  1859. //
  1860. if ( PasswordBufferValidated )
  1861. {
  1862. RtlEraseUnicodeString( &SetPasswordRequest->Password );
  1863. }
  1864. if (KpasswdRequest.Buffer != NULL)
  1865. {
  1866. MIDL_user_free(KpasswdRequest.Buffer);
  1867. }
  1868. if (KpasswdReply.Buffer != NULL)
  1869. {
  1870. MIDL_user_free(KpasswdReply.Buffer);
  1871. }
  1872. *ProtocolStatus = Status;
  1873. return(STATUS_SUCCESS);
  1874. }
  1875. #endif // WIN32_CHICAGO