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.

1099 lines
31 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: kpasswd.cxx
  7. //
  8. // Contents: Functions for the kpasswd protocol
  9. //
  10. // History: 30-Sep-97 MikeSw Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include "kdcsvr.hxx"
  14. #include "kpasswd.h"
  15. #include "kdctrace.h"
  16. extern "C"
  17. {
  18. #include <nlrepl.h>
  19. }
  20. #define FILENO FILENO_KPASSWD
  21. //+-------------------------------------------------------------------------
  22. //
  23. // Function: KdcbMarshallApReply
  24. //
  25. // Synopsis: Takes a reply and reply body and encrypts and marshalls them
  26. // into a return message
  27. //
  28. // Effects: Allocates output buffer
  29. //
  30. // Arguments: Reply - The outer reply to marshall
  31. // ReplyBody - The reply body to marshall
  32. // EncryptionType - Encryption algorithm to use
  33. // SessionKey - Session key to encrypt reply
  34. // PackedReply - Recives marshalled reply buffer
  35. // PackedReplySize - Receives size in bytes of marshalled reply
  36. //
  37. // Requires:
  38. //
  39. // Returns: STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES
  40. //
  41. // Notes:
  42. //
  43. //
  44. //--------------------------------------------------------------------------
  45. KERBERR
  46. KdcMarshallApReply(
  47. IN PKERB_AP_REPLY Reply,
  48. IN PKERB_ENCRYPTED_AP_REPLY ReplyBody,
  49. IN ULONG EncryptionType,
  50. IN PKERB_ENCRYPTION_KEY SessionKey,
  51. OUT PUCHAR * PackedReply,
  52. OUT PULONG PackedReplySize
  53. )
  54. {
  55. KERBERR KerbErr = KDC_ERR_NONE;
  56. ULONG PackedApReplySize;
  57. PUCHAR PackedApReply = NULL;
  58. ULONG EncryptionOverhead;
  59. ULONG BlockSize;
  60. ULONG ReplySize;
  61. KerbErr = KerbPackApReplyBody(
  62. ReplyBody,
  63. &PackedApReplySize,
  64. &PackedApReply
  65. );
  66. if (!KERB_SUCCESS(KerbErr))
  67. {
  68. goto Cleanup;
  69. }
  70. //
  71. // Now encrypt the response
  72. //
  73. KerbErr = KerbAllocateEncryptionBufferWrapper(
  74. EncryptionType,
  75. PackedApReplySize,
  76. &Reply->encrypted_part.cipher_text.length,
  77. &Reply->encrypted_part.cipher_text.value
  78. );
  79. if (!KERB_SUCCESS(KerbErr))
  80. {
  81. goto Cleanup;
  82. }
  83. KerbErr = KerbEncryptDataEx(
  84. &Reply->encrypted_part,
  85. PackedApReplySize,
  86. PackedApReply,
  87. EncryptionType,
  88. KERB_AP_REP_SALT,
  89. SessionKey
  90. );
  91. if (!KERB_SUCCESS(KerbErr))
  92. {
  93. D_DebugLog((DEB_ERROR,"Failed to encrypt AP Reply.%d\n", KerbErr));
  94. goto Cleanup;
  95. }
  96. //
  97. // Now pack the reply into the output buffer
  98. //
  99. KerbErr = KerbPackApReply(
  100. Reply,
  101. PackedReplySize,
  102. PackedReply
  103. );
  104. if (!KERB_SUCCESS(KerbErr))
  105. {
  106. goto Cleanup;
  107. }
  108. Cleanup:
  109. if (Reply->encrypted_part.cipher_text.value != NULL)
  110. {
  111. MIDL_user_free(Reply->encrypted_part.cipher_text.value);
  112. Reply->encrypted_part.cipher_text.value = NULL;
  113. }
  114. if (PackedApReply != NULL)
  115. {
  116. MIDL_user_free(PackedApReply);
  117. }
  118. return(KerbErr);
  119. }
  120. //+-------------------------------------------------------------------------
  121. //
  122. // Function: KdcBuildKpasswdResponse
  123. //
  124. // Synopsis: builds the response to a kpasswd request
  125. //
  126. // Effects:
  127. //
  128. // Arguments:
  129. //
  130. // Requires:
  131. //
  132. // Returns:
  133. //
  134. // Notes:
  135. //
  136. //
  137. //--------------------------------------------------------------------------
  138. KERBERR
  139. KdcBuildKpasswdResponse(
  140. IN OPTIONAL PKERB_ENCRYPTED_TICKET EncryptedTicket,
  141. IN OPTIONAL PKERB_AUTHENTICATOR Authenticator,
  142. IN OPTIONAL PKERB_ENCRYPTION_KEY SessionKey,
  143. IN OPTIONAL PSOCKADDR ServerAddress,
  144. IN NTSTATUS ChangeResult,
  145. IN KERBERR ProtocolResult,
  146. IN PKERB_EXT_ERROR pExtendedError,
  147. OUT PKERB_MESSAGE_BUFFER Response
  148. )
  149. {
  150. KERB_PRIV_MESSAGE PrivMessage = {0};
  151. KERB_ENCRYPTED_PRIV PrivBody = {0};
  152. USHORT ReplySize = 0;
  153. PBYTE PackedApReply = NULL;
  154. ULONG PackedApReplySize = 0;
  155. BYTE ResultData[2] = {0};
  156. PBYTE PackedPrivBody = NULL;
  157. ULONG PackedPrivBodySize = 0;
  158. ULONG EncryptionOverhead;
  159. ULONG BlockSize;
  160. KERBERR KerbErr = KRB_ERR_GENERIC;
  161. PBYTE ReplyData = NULL;
  162. ULONG ReplyDataSize = 0;
  163. PSOCKET_ADDRESS IpAddresses = NULL;
  164. ULONG AddressCount = 0;
  165. BOOLEAN ReturningError = TRUE;
  166. if (!NT_SUCCESS(ChangeResult))
  167. {
  168. switch(ChangeResult)
  169. {
  170. case STATUS_PASSWORD_RESTRICTION:
  171. SET_SHORT(ResultData,KERB_KPASSWD_POLICY);
  172. ProtocolResult = KDC_ERR_POLICY;
  173. break;
  174. case STATUS_ACCOUNT_RESTRICTION:
  175. SET_SHORT(ResultData, KERB_KPASSWD_AUTHENTICATION);
  176. ProtocolResult = KDC_ERR_CLIENT_REVOKED;
  177. break;
  178. case STATUS_INVALID_PARAMETER:
  179. SET_SHORT(ResultData, KERB_KPASSWD_MALFORMED);
  180. ProtocolResult = KRB_ERR_GENERIC;
  181. break;
  182. case STATUS_ACCESS_DENIED:
  183. SET_SHORT(ResultData, KERB_KPASSWD_AUTHORIZATION);
  184. ProtocolResult = KRB_ERR_GENERIC;
  185. break;
  186. default:
  187. SET_SHORT(ResultData, KERB_KPASSWD_ERROR);
  188. ProtocolResult = KRB_ERR_GENERIC;
  189. break;
  190. }
  191. }
  192. else if (!KERB_SUCCESS(ProtocolResult))
  193. {
  194. switch(ProtocolResult)
  195. {
  196. case KRB_ERR_GENERIC:
  197. //
  198. // BUG 453652: how does this distinguish between random hard errors
  199. // and malformed data?
  200. //
  201. SET_SHORT(ResultData, KERB_KPASSWD_MALFORMED);
  202. break;
  203. default:
  204. //
  205. // The other errors come from the call to verify the
  206. // AP request
  207. //
  208. SET_SHORT(ResultData, KERB_KPASSWD_AUTHENTICATION);
  209. break;
  210. }
  211. }
  212. //
  213. // Now build the AP reply, if possible.
  214. //
  215. if (ARGUMENT_PRESENT(EncryptedTicket))
  216. {
  217. NTSTATUS Status = STATUS_SUCCESS;
  218. KERB_AP_REPLY Reply = {0};
  219. KERB_ENCRYPTED_AP_REPLY ReplyBody = {0};
  220. Reply.version = KERBEROS_VERSION;
  221. Reply.message_type = KRB_AP_REP;
  222. ReplyBody.client_time = Authenticator->client_time;
  223. ReplyBody.client_usec = Authenticator->client_usec;
  224. KerbErr = KdcMarshallApReply(
  225. &Reply,
  226. &ReplyBody,
  227. EncryptedTicket->key.keytype,
  228. &EncryptedTicket->key,
  229. &PackedApReply,
  230. &PackedApReplySize
  231. );
  232. if (!KERB_SUCCESS(KerbErr))
  233. {
  234. goto BuildError;
  235. }
  236. PrivBody.sender_address.addr_type = KERB_ADDRTYPE_INET;
  237. if (ARGUMENT_PRESENT(ServerAddress))
  238. {
  239. PrivBody.sender_address.address.length = 4;
  240. PrivBody.sender_address.address.value =
  241. (PUCHAR) &((PSOCKADDR_IN)ServerAddress)->sin_addr.S_un.S_addr;
  242. }
  243. else
  244. {
  245. PrivBody.sender_address.address.length = 0;
  246. PrivBody.sender_address.address.value = NULL;
  247. }
  248. PrivBody.user_data.length = sizeof(ResultData);
  249. PrivBody.user_data.value = ResultData;
  250. KerbErr = KerbPackData(
  251. &PrivBody,
  252. KERB_ENCRYPTED_PRIV_PDU,
  253. &PackedPrivBodySize,
  254. &PackedPrivBody
  255. );
  256. if (!KERB_SUCCESS(KerbErr))
  257. {
  258. goto BuildError;
  259. }
  260. //
  261. // Now encrypt it with the session key
  262. //
  263. KerbErr = KerbAllocateEncryptionBufferWrapper(
  264. SessionKey->keytype,
  265. PackedPrivBodySize,
  266. &PrivMessage.encrypted_part.cipher_text.length,
  267. &PrivMessage.encrypted_part.cipher_text.value
  268. );
  269. if (!KERB_SUCCESS(KerbErr))
  270. {
  271. goto BuildError;
  272. }
  273. KerbErr = KerbEncryptDataEx(
  274. &PrivMessage.encrypted_part,
  275. PackedPrivBodySize,
  276. PackedPrivBody,
  277. SessionKey->keytype,
  278. KERB_PRIV_SALT,
  279. SessionKey
  280. );
  281. if (!KERB_SUCCESS(KerbErr))
  282. {
  283. goto BuildError;
  284. }
  285. PrivMessage.version = KERBEROS_VERSION;
  286. PrivMessage.message_type = KRB_PRIV;
  287. //
  288. // Now pack the KERB_PRIV
  289. //
  290. KerbErr = KerbPackData(
  291. &PrivMessage,
  292. KERB_PRIV_MESSAGE_PDU,
  293. &ReplyDataSize,
  294. &ReplyData
  295. );
  296. if (!KERB_SUCCESS(KerbErr))
  297. {
  298. goto BuildError;
  299. }
  300. ReturningError = FALSE;
  301. }
  302. BuildError:
  303. //
  304. // If we have an error of one of the three error codes, build the
  305. // appropriate result code & error code for the KERB_ERROR
  306. //
  307. if (!KERB_SUCCESS(KerbErr) || (ReplyData == NULL))
  308. {
  309. UNICODE_STRING TempString;
  310. RtlInitUnicodeString(
  311. &TempString,
  312. KERB_KPASSWD_NAME
  313. );
  314. KerbErr = KerbBuildErrorMessageEx(
  315. ProtocolResult,
  316. pExtendedError, // note: probably won't get used
  317. SecData.KdcDnsRealmName(),
  318. SecData.KpasswdInternalName(),
  319. NULL, // no client realm,
  320. ResultData,
  321. sizeof(ResultData),
  322. &ReplyDataSize,
  323. &ReplyData
  324. );
  325. if (!KERB_SUCCESS(KerbErr))
  326. {
  327. goto Cleanup;
  328. }
  329. }
  330. //
  331. // Now, if we have an AP reply, build a kpasswd response. Otherwise
  332. // return the kerb_error message
  333. //
  334. if (ReturningError)
  335. {
  336. Response->Buffer = ReplyData;
  337. ReplyData = NULL;
  338. Response->BufferSize = ReplyDataSize;
  339. goto Cleanup;
  340. }
  341. else
  342. {
  343. USHORT TempShort;
  344. PKERB_KPASSWD_REP Reply = NULL;
  345. if ((FIELD_OFFSET(KERB_KPASSWD_REP,Data) +
  346. PackedApReplySize +
  347. ReplyDataSize) > SHRT_MAX)
  348. {
  349. D_DebugLog((DEB_ERROR,"Kpasswd reply too long!\n"));
  350. KerbErr = KRB_ERR_FIELD_TOOLONG;
  351. goto Cleanup;
  352. }
  353. ReplySize = (USHORT) (FIELD_OFFSET(KERB_KPASSWD_REP,Data) +
  354. PackedApReplySize +
  355. ReplyDataSize);
  356. Reply = (PKERB_KPASSWD_REP) MIDL_user_allocate(ReplySize);
  357. if (Reply == NULL)
  358. {
  359. KerbErr = KRB_ERR_GENERIC;
  360. goto Cleanup;
  361. }
  362. SET_SHORT(Reply->MessageLength,ReplySize);
  363. SET_SHORT(Reply->Version, KERB_KPASSWD_VERSION);
  364. SET_SHORT(Reply->ApRepLength, (USHORT) PackedApReplySize);
  365. RtlCopyMemory(
  366. Reply->Data,
  367. PackedApReply,
  368. PackedApReplySize
  369. );
  370. RtlCopyMemory(
  371. Reply->Data + PackedApReplySize,
  372. ReplyData,
  373. ReplyDataSize
  374. );
  375. Response->Buffer = (PBYTE) Reply;
  376. Response->BufferSize = ReplySize;
  377. }
  378. Cleanup:
  379. if (IpAddresses != NULL)
  380. {
  381. I_NetLogonFree(IpAddresses);
  382. }
  383. if (PackedApReply != NULL)
  384. {
  385. MIDL_user_free(PackedApReply);
  386. }
  387. if (PackedPrivBody !=NULL)
  388. {
  389. MIDL_user_free(PackedPrivBody);
  390. }
  391. if (ReplyData != NULL)
  392. {
  393. MIDL_user_free(ReplyData);
  394. }
  395. return(KerbErr);
  396. }
  397. //+-------------------------------------------------------------------------
  398. //
  399. // Function: KdcChangePassword
  400. //
  401. // Synopsis: receives a kerb-change-password buffer and attempts the
  402. // password change
  403. //
  404. // Effects:
  405. //
  406. // Arguments: Context - ATQ context, used for requesting more data if the
  407. // buffer isn't complete
  408. // ClientAddress - Address of client, from the socket
  409. // ServerAddress - address client used to contact this server.
  410. // InputMessage - Receives data sent by client
  411. // OutputMessage - Contains data to be sent to client & freed
  412. // using KdcFreeEncodedData
  413. //
  414. // Requires:
  415. //
  416. // Returns:
  417. //
  418. // Notes:
  419. //
  420. //
  421. //--------------------------------------------------------------------------
  422. extern "C"
  423. KERBERR
  424. KdcChangePassword(
  425. IN OPTIONAL PVOID Context,
  426. IN OPTIONAL PSOCKADDR ClientAddress,
  427. IN OPTIONAL PSOCKADDR ServerAddress,
  428. IN PKERB_MESSAGE_BUFFER InputMessage,
  429. OUT PKERB_MESSAGE_BUFFER OutputMessage
  430. )
  431. {
  432. PKERB_KPASSWD_REQ Request = NULL;
  433. PKERB_KPASSWD_REP Reply = NULL;
  434. NTSTATUS Status = STATUS_SUCCESS;
  435. KERBERR KerbErr = KDC_ERR_NONE;
  436. KERB_EXT_ERROR ExtendedError = {0,0};
  437. PKERB_EXT_ERROR pExtendedError = &ExtendedError;
  438. USHORT ProtocolVersion;
  439. USHORT MessageLength;
  440. USHORT ApReqLength;
  441. ULONG PrivLength;
  442. PKERB_AUTHENTICATOR Authenticator = NULL;
  443. PKERB_ENCRYPTED_TICKET EncryptedTicket = NULL;
  444. KERB_ENCRYPTION_KEY SessionKey = {0};
  445. KERB_ENCRYPTION_KEY ServerKey = {0};
  446. KDC_TICKET_INFO ServerTicketInfo = {0};
  447. KDC_TICKET_INFO ClientTicketInfo = {0};
  448. UNICODE_STRING Password = {0};
  449. ANSI_STRING AnsiPassword = {0};
  450. PKERB_PRIV_MESSAGE PrivMessage = NULL;
  451. PKERB_ENCRYPTED_PRIV PrivBody = NULL;
  452. BOOLEAN UseSubKey = FALSE;
  453. ULONG TicketFlags;
  454. BOOLEAN DoPasswordSet = FALSE;
  455. PKERB_CHANGE_PASSWORD_DATA ChangeData = NULL;
  456. PKERB_INTERNAL_NAME ClientName = NULL;
  457. UNICODE_STRING ClientRealm = {0};
  458. UNICODE_STRING ReferralRealm = {0};
  459. BOOLEAN ClientReferral = FALSE;
  460. HANDLE TokenHandle = NULL;
  461. PSID UserSid = NULL;
  462. ULONG UserRid = 0;
  463. SAM_CLIENT_INFO SamClientInfoBuffer;
  464. PSAM_CLIENT_INFO SamClientInfo = NULL;
  465. KDC_CHANGEPASS_INFO ChangePassTraceInfo;
  466. if( KdcEventTraceFlag ) // Event Trace: KerbChangePasswordStart {No Data}
  467. {
  468. ChangePassTraceInfo.EventTrace.Guid = KdcChangePassGuid;
  469. ChangePassTraceInfo.EventTrace.Class.Type = EVENT_TRACE_TYPE_START;
  470. ChangePassTraceInfo.EventTrace.Flags = WNODE_FLAG_TRACED_GUID;
  471. ChangePassTraceInfo.EventTrace.Size = sizeof(EVENT_TRACE_HEADER);
  472. TraceEvent( KdcTraceLoggerHandle, (PEVENT_TRACE_HEADER)&ChangePassTraceInfo );
  473. }
  474. Status = EnterApiCall();
  475. if (!NT_SUCCESS(Status))
  476. {
  477. return(Status);
  478. }
  479. if (InputMessage->BufferSize < sizeof(KERB_KPASSWD_REQ))
  480. {
  481. D_DebugLog((DEB_ERROR,"Bad message size to KdcChangePassword: %d\n",InputMessage->BufferSize));
  482. FILL_EXT_ERROR(pExtendedError, STATUS_KDC_INVALID_REQUEST, FILENO, __LINE__);
  483. KerbErr = KDC_ERR_NO_RESPONSE;
  484. goto NoMsgResponse;
  485. }
  486. Request = (PKERB_KPASSWD_REQ) InputMessage->Buffer;
  487. //
  488. // Verify the length & protocol version
  489. //
  490. GET_SHORT(MessageLength, Request->MessageLength);
  491. GET_SHORT(ProtocolVersion, Request->Version);
  492. if (ProtocolVersion == KERB_KPASSWD_SET_VERSION)
  493. {
  494. //
  495. // This is the advanced protocol
  496. //
  497. DoPasswordSet = TRUE;
  498. }
  499. else if (ProtocolVersion != KERB_KPASSWD_VERSION)
  500. {
  501. D_DebugLog((DEB_ERROR,"Bad version passed to KdcChangePassword: %d\n",
  502. ProtocolVersion ));
  503. FILL_EXT_ERROR(pExtendedError, STATUS_KDC_INVALID_REQUEST, FILENO, __LINE__);
  504. KerbErr = KDC_ERR_NO_RESPONSE;
  505. goto NoMsgResponse;
  506. }
  507. if ((ULONG)MessageLength != InputMessage->BufferSize)
  508. {
  509. D_DebugLog((DEB_ERROR,"Bad length passed to KdcChangePassword: %d instead of %d\n",
  510. MessageLength, InputMessage->BufferSize ));
  511. FILL_EXT_ERROR(pExtendedError, STATUS_KDC_INVALID_REQUEST, FILENO, __LINE__);
  512. KerbErr = KDC_ERR_NO_RESPONSE;
  513. goto NoMsgResponse;
  514. }
  515. //
  516. // Unpack the AP request
  517. //
  518. GET_SHORT(ApReqLength, Request->ApReqLength);
  519. if (FIELD_OFFSET(KERB_KPASSWD_REQ, ApReqLength) + ApReqLength > MessageLength)
  520. {
  521. D_DebugLog((DEB_ERROR,"ApReqLength in kpasswd request bad: %d\n",ApReqLength));
  522. FILL_EXT_ERROR(pExtendedError, STATUS_KDC_INVALID_REQUEST, FILENO, __LINE__);
  523. KerbErr = KDC_ERR_NO_RESPONSE;
  524. goto NoMsgResponse;
  525. }
  526. //
  527. // Verify the AP request
  528. //
  529. KerbErr = KdcVerifyKdcRequest(
  530. Request->Data,
  531. ApReqLength,
  532. ClientAddress,
  533. FALSE, // this is not a kdc request
  534. NULL,
  535. &Authenticator,
  536. &EncryptedTicket,
  537. &SessionKey,
  538. &ServerKey,
  539. &ServerTicketInfo,
  540. &UseSubKey,
  541. pExtendedError
  542. );
  543. if (!KERB_SUCCESS(KerbErr))
  544. {
  545. if (KerbErr == KDC_ERR_NO_RESPONSE)
  546. {
  547. goto NoMsgResponse;
  548. }
  549. DebugLog((DEB_WARN,"Failed to unpack AP req in kpasswd request: 0x%x\n",
  550. KerbErr ));
  551. goto Cleanup;
  552. }
  553. //
  554. // The spec says the client has to ask for a sub key.
  555. //
  556. if (!UseSubKey)
  557. {
  558. D_DebugLog((DEB_ERROR,"The client of kpasswd did not ask for a sub key.\n"));
  559. FILL_EXT_ERROR(pExtendedError, STATUS_KDC_INVALID_REQUEST, FILENO, __LINE__);
  560. KerbErr = KRB_ERR_GENERIC;
  561. goto Cleanup;
  562. }
  563. //
  564. // The name of the principal must be correct.
  565. //
  566. // WAS BUG: check by RID
  567. //
  568. if (ServerTicketInfo.UserId != DOMAIN_USER_RID_KRBTGT)
  569. {
  570. D_DebugLog((DEB_ERROR,"Wrong principal for kpasswd: %wZ\n",
  571. &ServerTicketInfo.AccountName ));
  572. FILL_EXT_ERROR(pExtendedError, STATUS_KDC_INVALID_REQUEST, FILENO, __LINE__);
  573. KerbErr = KRB_AP_ERR_NOT_US;
  574. goto Cleanup;
  575. }
  576. //
  577. // Now try to unpack the KERB_PRIV
  578. //
  579. PrivLength = MessageLength - (ApReqLength + FIELD_OFFSET(KERB_KPASSWD_REQ, Data));
  580. KerbErr = KerbUnpackData(
  581. Request->Data + ApReqLength,
  582. PrivLength,
  583. KERB_PRIV_MESSAGE_PDU,
  584. (PVOID *) &PrivMessage
  585. );
  586. if (!KERB_SUCCESS(KerbErr))
  587. {
  588. D_DebugLog((DEB_ERROR,"Failed to decode priv message in kpasswd req: 0x%x\n",KerbErr));
  589. FILL_EXT_ERROR(pExtendedError, STATUS_KDC_INVALID_REQUEST, FILENO, __LINE__);
  590. goto Cleanup;
  591. }
  592. //
  593. // Now decrypt the KERB_PRIV message
  594. //
  595. if (PrivMessage->version != KERBEROS_VERSION)
  596. {
  597. D_DebugLog((DEB_ERROR,"Bad version in kpasswd priv message: %d\n",
  598. PrivMessage->version ));
  599. KerbErr = KRB_AP_ERR_BADVERSION;
  600. goto Cleanup;
  601. }
  602. if (PrivMessage->message_type != KRB_PRIV)
  603. {
  604. D_DebugLog((DEB_ERROR,"Bad message type in kpasswd priv message: %d\n",
  605. PrivMessage->message_type ));
  606. KerbErr = KRB_ERR_GENERIC;
  607. goto Cleanup;
  608. }
  609. KerbErr = KerbDecryptDataEx(
  610. &PrivMessage->encrypted_part,
  611. &SessionKey,
  612. KERB_PRIV_SALT,
  613. (PULONG) &PrivMessage->encrypted_part.cipher_text.length,
  614. PrivMessage->encrypted_part.cipher_text.value
  615. );
  616. if (!KERB_SUCCESS(KerbErr))
  617. {
  618. D_DebugLog((DEB_ERROR,"Failed to decrypt priv message from kpasswd: 0x%x\n",
  619. KerbErr));
  620. goto Cleanup;
  621. }
  622. //
  623. // Now decode the kerb priv body
  624. //
  625. KerbErr = KerbUnpackData(
  626. PrivMessage->encrypted_part.cipher_text.value,
  627. (ULONG) PrivMessage->encrypted_part.cipher_text.length,
  628. KERB_ENCRYPTED_PRIV_PDU,
  629. (PVOID *) &PrivBody
  630. );
  631. if (!KERB_SUCCESS(KerbErr))
  632. {
  633. D_DebugLog((DEB_ERROR,"Failed to unpack priv body from kpasswd: 0x%x\n",
  634. KerbErr));
  635. goto Cleanup;
  636. }
  637. //
  638. // Verify the client's address
  639. //
  640. if (ARGUMENT_PRESENT(ClientAddress))
  641. {
  642. KERB_HOST_ADDRESSES Addresses;
  643. //
  644. // Build a host_addresses structure because the caller sent a single
  645. // address.
  646. //
  647. Addresses.next = NULL;
  648. Addresses.value.address_type = PrivBody->sender_address.addr_type;
  649. Addresses.value.address.value = PrivBody->sender_address.address.value;
  650. Addresses.value.address.length = PrivBody->sender_address.address.length;
  651. KerbErr = KdcVerifyClientAddress(
  652. ClientAddress,
  653. &Addresses
  654. );
  655. if (!KERB_SUCCESS(KerbErr))
  656. {
  657. D_DebugLog((DEB_ERROR,"Client sent kpasswd request with wrong address\n"));
  658. goto Cleanup;
  659. }
  660. }
  661. //
  662. // Now, we should have a password
  663. //
  664. if (DoPasswordSet)
  665. {
  666. //
  667. // Unpack the chaneg password data in the priv body.
  668. //
  669. KerbErr = KerbUnpackData(
  670. PrivBody->user_data.value,
  671. PrivBody->user_data.length,
  672. KERB_CHANGE_PASSWORD_DATA_PDU,
  673. (PVOID *) &ChangeData
  674. );
  675. if (!KERB_SUCCESS(KerbErr))
  676. {
  677. D_DebugLog((DEB_ERROR,"Failed to unpack password change data from kpasswd: 0x%x\n",
  678. KerbErr));
  679. goto Cleanup;
  680. }
  681. if (ChangeData->new_password.length > SHRT_MAX / 2)
  682. {
  683. D_DebugLog((DEB_ERROR,"Password length too long: %d\n",
  684. ChangeData->new_password.length ));
  685. KerbErr = KRB_ERR_FIELD_TOOLONG;
  686. goto Cleanup;
  687. }
  688. AnsiPassword.Length = (USHORT)ChangeData->new_password.length;
  689. AnsiPassword.MaximumLength = AnsiPassword.Length;
  690. AnsiPassword.Buffer = (PCHAR) ChangeData->new_password.value;
  691. KerbErr = KerbStringToUnicodeString(
  692. &Password,
  693. &AnsiPassword
  694. );
  695. if (!KERB_SUCCESS(KerbErr))
  696. {
  697. goto Cleanup;
  698. }
  699. //
  700. // if the target name and realm aren't present, this is a
  701. // change password
  702. //
  703. if ((ChangeData->bit_mask & (target_name_present | target_realm_present)) !=
  704. (target_name_present | target_realm_present))
  705. {
  706. DoPasswordSet = FALSE;
  707. }
  708. else
  709. {
  710. //
  711. // Get the names from the change data
  712. //
  713. KerbErr = KerbConvertPrincipalNameToKdcName(
  714. &ClientName,
  715. &ChangeData->target_name
  716. );
  717. if (!NT_SUCCESS(KerbErr))
  718. {
  719. goto Cleanup;
  720. }
  721. KerbErr = KerbConvertRealmToUnicodeString(
  722. &ClientRealm,
  723. &ChangeData->target_realm
  724. );
  725. if (!KERB_SUCCESS(KerbErr))
  726. {
  727. goto Cleanup;
  728. }
  729. }
  730. }
  731. if (!DoPasswordSet)
  732. {
  733. //
  734. // The spec says the ticket must be an initial ticket for a
  735. // change.
  736. //
  737. TicketFlags = KerbConvertFlagsToUlong(&EncryptedTicket->flags);
  738. if ((TicketFlags & KERB_TICKET_FLAGS_initial) == 0)
  739. {
  740. D_DebugLog((DEB_ERROR,"Ticket to kpasswd was not initial\n"));
  741. KerbErr = KRB_ERR_GENERIC;
  742. goto Cleanup;
  743. }
  744. //
  745. // NOTE: verify other kerb-priv fields here
  746. // Current ID doesn't require other kerb priv fields, so
  747. // this is a no-op. If things change, however, we'll need
  748. // to add code here.
  749. //
  750. //
  751. // If we didn't get a password from the change password data,
  752. // get it directly from the data
  753. //
  754. if (Password.Buffer == NULL)
  755. {
  756. //
  757. // The password has to fit in a unicode string, so it can't be longer
  758. // than half a ushort.
  759. //
  760. if (PrivBody->user_data.length > SHRT_MAX / 2)
  761. {
  762. D_DebugLog((DEB_ERROR,"Password length too long: %d\n",
  763. PrivBody->user_data.length ));
  764. KerbErr = KRB_ERR_FIELD_TOOLONG;
  765. goto Cleanup;
  766. }
  767. AnsiPassword.Length = (USHORT)PrivBody->user_data.length;
  768. AnsiPassword.MaximumLength = AnsiPassword.Length;
  769. AnsiPassword.Buffer = (PCHAR) PrivBody->user_data.value;
  770. KerbErr = KerbStringToUnicodeString(
  771. &Password,
  772. &AnsiPassword
  773. );
  774. if (!KERB_SUCCESS(KerbErr))
  775. {
  776. goto Cleanup;
  777. }
  778. }
  779. KerbErr = KerbConvertPrincipalNameToKdcName(
  780. &ClientName,
  781. &EncryptedTicket->client_name
  782. );
  783. if (!NT_SUCCESS(KerbErr))
  784. {
  785. goto Cleanup;
  786. }
  787. KerbErr = KerbConvertRealmToUnicodeString(
  788. &ClientRealm,
  789. &EncryptedTicket->client_realm
  790. );
  791. if (!KERB_SUCCESS(KerbErr))
  792. {
  793. goto Cleanup;
  794. }
  795. }
  796. //
  797. // Get the client ticket info so we can do a set pass
  798. //
  799. KerbErr = KdcNormalize(
  800. ClientName,
  801. NULL,
  802. &ClientRealm,
  803. KDC_NAME_CLIENT,
  804. &ClientReferral,
  805. &ReferralRealm,
  806. &ClientTicketInfo,
  807. pExtendedError,
  808. NULL, // no UserHandle
  809. 0L, // no fields to fetch
  810. 0L, // no extended fields
  811. NULL, // no fields to fetch
  812. NULL // no GroupMembership
  813. );
  814. if (!KERB_SUCCESS(KerbErr))
  815. {
  816. DebugLog((DEB_ERROR,"Failed to normalize name "));
  817. KerbPrintKdcName(DEB_ERROR,ClientName);
  818. goto Cleanup;
  819. }
  820. {
  821. LUID LogonId = {0};
  822. UNICODE_STRING UClientName = {0};
  823. UNICODE_STRING UClientDomain = {0};
  824. Status = KerbCreateTokenFromTicket(
  825. EncryptedTicket,
  826. Authenticator,
  827. 0, // no flags
  828. &ServerKey,
  829. SecData.KdcDnsRealmName(),
  830. &SessionKey,
  831. &LogonId,
  832. &UserSid,
  833. &TokenHandle,
  834. &UClientName,
  835. &UClientDomain
  836. );
  837. if (!NT_SUCCESS(Status))
  838. {
  839. DebugLog((DEB_ERROR,"Failed to create token from ticket: 0x%x\n",Status));
  840. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  841. KerbErr = KRB_ERR_GENERIC;
  842. goto Cleanup;
  843. }
  844. //
  845. // Setup the client info
  846. //
  847. if ( (ClientAddress == NULL)
  848. || (ClientAddress->sa_family == AF_INET) ) {
  849. // Set to local address (known to be 4 bytes) or IP address
  850. RtlZeroMemory(&SamClientInfoBuffer, sizeof(SamClientInfoBuffer));
  851. SamClientInfoBuffer.Type = SamClientIpAddr;
  852. SamClientInfoBuffer.Data.IpAddr = *((ULONG*)GET_CLIENT_ADDRESS(ClientAddress));
  853. SamClientInfo = &SamClientInfoBuffer;
  854. }
  855. //
  856. // Free all the memory returned
  857. //
  858. KerbFree(UClientName.Buffer);
  859. KerbFree(UClientDomain.Buffer);
  860. KerbFree(UserSid);
  861. //
  862. // Store the password on the user's account
  863. //
  864. //
  865. // We shouldn't enforce password policy restrictions if we do a password SET
  866. //
  867. if (!DoPasswordSet)
  868. {
  869. Status = SamIChangePasswordForeignUser2(
  870. SamClientInfo,
  871. &ClientTicketInfo.AccountName,
  872. &Password,
  873. TokenHandle,
  874. USER_CHANGE_PASSWORD
  875. );
  876. } else {
  877. Status = SamISetPasswordForeignUser2(
  878. SamClientInfo,
  879. &ClientTicketInfo.AccountName,
  880. &Password,
  881. TokenHandle
  882. );
  883. }
  884. if (!NT_SUCCESS(Status))
  885. {
  886. DebugLog((DEB_ERROR,"Failed to change password for user %wZ: 0x%x\n",
  887. &ClientTicketInfo.AccountName, Status ));
  888. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  889. KerbErr = KDC_ERR_POLICY;
  890. goto Cleanup;
  891. }
  892. }
  893. Cleanup:
  894. KerbErr = KdcBuildKpasswdResponse(
  895. EncryptedTicket,
  896. Authenticator,
  897. &SessionKey,
  898. ServerAddress,
  899. Status,
  900. KerbErr,
  901. pExtendedError,
  902. OutputMessage
  903. );
  904. NoMsgResponse:
  905. if( KdcEventTraceFlag ) // Event Trace: KdcChangePasswordEnd {KerbErr, ExtErr, Klininfo, (ClientRealm), (AccountName)}
  906. {
  907. INSERT_ULONG_INTO_MOF( KerbErr, ChangePassTraceInfo.MofData, 0 );
  908. INSERT_ULONG_INTO_MOF( ExtendedError.status, ChangePassTraceInfo.MofData, 1 );
  909. INSERT_ULONG_INTO_MOF( ExtendedError.klininfo, ChangePassTraceInfo.MofData, 2 );
  910. // Protect against uninitialized UNICODE_STRINGs
  911. WCHAR UnicodeNullChar = 0;
  912. UNICODE_STRING UnicodeEmptyString = {sizeof(WCHAR),sizeof(WCHAR),&UnicodeNullChar};
  913. PUNICODE_STRING pClientRealmTraceString = &ClientRealm;
  914. PUNICODE_STRING pAccountNameTraceString = &ClientTicketInfo.AccountName;
  915. if( ClientRealm.Buffer == NULL || ClientRealm.Length <= 0 )
  916. pClientRealmTraceString = &UnicodeEmptyString;
  917. if( ClientTicketInfo.AccountName.Buffer == NULL || ClientTicketInfo.AccountName.Length <= 0 )
  918. pAccountNameTraceString = &UnicodeEmptyString;
  919. //
  920. INSERT_UNICODE_STRING_INTO_MOF( *pClientRealmTraceString, ChangePassTraceInfo.MofData, 3 );
  921. INSERT_UNICODE_STRING_INTO_MOF( *pAccountNameTraceString, ChangePassTraceInfo.MofData, 5 );
  922. ChangePassTraceInfo.EventTrace.Size = sizeof(EVENT_TRACE_HEADER) + 7*sizeof(MOF_FIELD);
  923. ChangePassTraceInfo.EventTrace.Guid = KdcChangePassGuid;
  924. ChangePassTraceInfo.EventTrace.Class.Type = EVENT_TRACE_TYPE_END;
  925. ChangePassTraceInfo.EventTrace.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
  926. TraceEvent( KdcTraceLoggerHandle, (PEVENT_TRACE_HEADER)&ChangePassTraceInfo );
  927. }
  928. KerbFreeKey( &SessionKey );
  929. KerbFreeKey( &ServerKey );
  930. KerbFreeTicket(EncryptedTicket);
  931. FreeTicketInfo(&ServerTicketInfo);
  932. FreeTicketInfo(&ClientTicketInfo);
  933. KerbFreeData(KERB_PRIV_MESSAGE_PDU, PrivMessage);
  934. KerbFreeData(KERB_ENCRYPTED_PRIV_PDU, PrivBody);
  935. KerbFreeData(KERB_CHANGE_PASSWORD_DATA_PDU, ChangeData);
  936. KerbFreeString(&Password);
  937. KerbFreeAuthenticator(Authenticator);
  938. KerbFreeKdcName(&ClientName);
  939. KerbFreeString(&ClientRealm);
  940. KerbFreeString(&ReferralRealm);
  941. if (TokenHandle != NULL)
  942. {
  943. NtClose(TokenHandle);
  944. }
  945. LeaveApiCall();
  946. return(KerbErr);
  947. }