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.

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