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.

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