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.

417 lines
11 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2000, Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // changepwd.h
  8. //
  9. // SYNOPSIS
  10. //
  11. // Defines the class ChangePassword.
  12. //
  13. ///////////////////////////////////////////////////////////////////////////////
  14. #include <ias.h>
  15. #include <changepwd.h>
  16. #include <blob.h>
  17. #include <iaslsa.h>
  18. #include <iastlutl.h>
  19. #include <ntsamauth.h>
  20. #include <samutil.h>
  21. STDMETHODIMP ChangePassword::Initialize()
  22. {
  23. DWORD error = IASLsaInitialize();
  24. return HRESULT_FROM_WIN32(error);
  25. }
  26. STDMETHODIMP ChangePassword::Shutdown()
  27. {
  28. IASLsaUninitialize();
  29. return S_OK;
  30. }
  31. IASREQUESTSTATUS ChangePassword::onSyncRequest(IRequest* pRequest) throw ()
  32. {
  33. try
  34. {
  35. IASTL::IASRequest request(pRequest);
  36. // Only process change password requests.
  37. IASTL::IASAttribute authType;
  38. if (authType.load(
  39. request,
  40. IAS_ATTRIBUTE_AUTHENTICATION_TYPE,
  41. IASTYPE_ENUM
  42. ))
  43. {
  44. switch (authType->Value.Enumerator)
  45. {
  46. case IAS_AUTH_MSCHAP_CPW:
  47. // Fall through.
  48. case IAS_AUTH_MSCHAP2_CPW:
  49. doChangePassword(request, authType->Value.Enumerator);
  50. break;
  51. default:
  52. // Do nothing.
  53. break;
  54. }
  55. }
  56. }
  57. catch (const _com_error& ce)
  58. {
  59. IASTraceExcept();
  60. IASProcessFailure(pRequest, ce.Error());
  61. }
  62. return IAS_REQUEST_STATUS_CONTINUE;
  63. }
  64. bool ChangePassword::tryMsChapCpw1(
  65. IASTL::IASRequest& request,
  66. PCWSTR domainName,
  67. PCWSTR username,
  68. PBYTE challenge
  69. )
  70. {
  71. // Is the MS-CHAP-CPW-1 VSA present?
  72. IASTL::IASAttribute attr;
  73. if (!attr.load(
  74. request,
  75. MS_ATTRIBUTE_CHAP_CPW1,
  76. IASTYPE_OCTET_STRING
  77. ))
  78. {
  79. return false;
  80. }
  81. MSChapCPW1& cpw1 = blob_cast<MSChapCPW1>(attr);
  82. IASTraceString("Processing MS-CHAP-CPW-1.");
  83. // Is LM Authentication allowed?
  84. if (NTSamAuthentication::enforceLmRestriction(request))
  85. {
  86. // Change the password.
  87. BYTE newNtResponse[_NT_RESPONSE_LENGTH];
  88. BYTE newLmResponse[_LM_RESPONSE_LENGTH];
  89. DWORD status;
  90. status = IASChangePassword1(
  91. username,
  92. domainName,
  93. challenge,
  94. cpw1.get().lmOldPwd,
  95. cpw1.get().lmNewPwd,
  96. cpw1.get().ntOldPwd,
  97. cpw1.get().ntNewPwd,
  98. cpw1.getNewLmPwdLen(),
  99. cpw1.isNtPresent(),
  100. newNtResponse,
  101. newLmResponse
  102. );
  103. if (status == NO_ERROR)
  104. {
  105. IASTraceString("Password successfully changed.");
  106. // Password was successfully changed, so authenticate the user.
  107. NTSamAuthentication::doMsChapAuthentication(
  108. request,
  109. domainName,
  110. username,
  111. cpw1.get().ident,
  112. challenge,
  113. newNtResponse,
  114. newLmResponse
  115. );
  116. }
  117. else
  118. {
  119. IASTraceFailure("IASChangePassword1", status);
  120. if (status == ERROR_ACCESS_DENIED)
  121. {
  122. status = IAS_CHANGE_PASSWORD_FAILURE;
  123. }
  124. else
  125. {
  126. status = IASMapWin32Error(status, IAS_CHANGE_PASSWORD_FAILURE);
  127. }
  128. IASProcessFailure(request, status);
  129. }
  130. }
  131. return true;
  132. }
  133. bool ChangePassword::tryMsChapCpw2(
  134. IASTL::IASRequest& request,
  135. PCWSTR domainName,
  136. PCWSTR username,
  137. PBYTE challenge
  138. )
  139. {
  140. // Is the MS-CHAP-CPW-2 VSA present?
  141. IASAttribute attr;
  142. if (!attr.load(
  143. request,
  144. MS_ATTRIBUTE_CHAP_CPW2,
  145. IASTYPE_OCTET_STRING
  146. ))
  147. {
  148. return false;
  149. }
  150. MSChapCPW2& cpw2 = blob_cast<MSChapCPW2>(attr);
  151. IASTraceString("Processing MS-CHAP-CPW-2.");
  152. // Check LM Authentication.
  153. if (!cpw2.isLmPresent() ||
  154. NTSamAuthentication::enforceLmRestriction(request))
  155. {
  156. //////////
  157. // Assemble the encrypted passwords.
  158. //////////
  159. BYTE ntEncPW[_SAMPR_ENCRYPTED_USER_PASSWORD_LENGTH];
  160. if (!MSChapEncPW::getEncryptedPassword(
  161. request,
  162. MS_ATTRIBUTE_CHAP_NT_ENC_PW,
  163. ntEncPW
  164. ))
  165. {
  166. _com_issue_error(IAS_MALFORMED_REQUEST);
  167. }
  168. BOOL lmPresent = FALSE;
  169. BYTE lmEncPW[_SAMPR_ENCRYPTED_USER_PASSWORD_LENGTH];
  170. if (cpw2.isLmHashValid())
  171. {
  172. lmPresent = MSChapEncPW::getEncryptedPassword(
  173. request,
  174. MS_ATTRIBUTE_CHAP_LM_ENC_PW,
  175. lmEncPW
  176. );
  177. }
  178. //////////
  179. // Change the password.
  180. //////////
  181. DWORD status;
  182. status = IASChangePassword2(
  183. username,
  184. domainName,
  185. cpw2.get().oldNtHash,
  186. cpw2.get().oldLmHash,
  187. ntEncPW,
  188. lmPresent ? lmEncPW : NULL,
  189. cpw2.isLmHashValid()
  190. );
  191. if (status == NO_ERROR)
  192. {
  193. IASTraceString("Password successfully changed.");
  194. // Password was successfully changed, so authenticate the user.
  195. PBYTE ntResponse;
  196. if (cpw2.isNtResponseValid())
  197. {
  198. ntResponse = cpw2.get().ntResponse;
  199. }
  200. else
  201. {
  202. ntResponse = NULL;
  203. }
  204. NTSamAuthentication::doMsChapAuthentication(
  205. request,
  206. domainName,
  207. username,
  208. cpw2.get().ident,
  209. challenge,
  210. ntResponse,
  211. cpw2.get().lmResponse
  212. );
  213. }
  214. else
  215. {
  216. IASTraceFailure("IASChangePassword2", status);
  217. if (status == ERROR_ACCESS_DENIED)
  218. {
  219. status = IAS_CHANGE_PASSWORD_FAILURE;
  220. }
  221. else
  222. {
  223. status = IASMapWin32Error(status, IAS_CHANGE_PASSWORD_FAILURE);
  224. }
  225. IASProcessFailure(request, status);
  226. }
  227. }
  228. return true;
  229. }
  230. void ChangePassword::doMsChapCpw(
  231. IASTL::IASRequest& request,
  232. PCWSTR domainName,
  233. PCWSTR username,
  234. IAS_OCTET_STRING& msChapChallenge
  235. )
  236. {
  237. if (msChapChallenge.dwLength != _MSV1_0_CHALLENGE_LENGTH)
  238. {
  239. _com_issue_error(IAS_MALFORMED_REQUEST);
  240. }
  241. PBYTE challenge = msChapChallenge.lpValue;
  242. if (!tryMsChapCpw2(request, domainName, username, challenge) &&
  243. !tryMsChapCpw1(request, domainName, username, challenge))
  244. {
  245. _com_issue_error(IAS_INTERNAL_ERROR);
  246. }
  247. }
  248. void ChangePassword::doMsChap2Cpw(
  249. IASTL::IASRequest& request,
  250. PCWSTR domainName,
  251. PCWSTR username,
  252. IAS_OCTET_STRING& msChapChallenge
  253. )
  254. {
  255. IASTraceString("Processing MS-CHAP v2 change password.");
  256. // Is the necessary attribute present ?
  257. IASAttribute attr;
  258. if (!attr.load(
  259. request,
  260. MS_ATTRIBUTE_CHAP2_CPW,
  261. IASTYPE_OCTET_STRING
  262. ))
  263. {
  264. _com_issue_error(IAS_INTERNAL_ERROR);
  265. }
  266. MSChap2CPW& cpw = blob_cast<MSChap2CPW>(attr);
  267. //////////
  268. // Assemble the encrypted password.
  269. //////////
  270. BYTE encPW[_SAMPR_ENCRYPTED_USER_PASSWORD_LENGTH];
  271. if (!MSChapEncPW::getEncryptedPassword(
  272. request,
  273. MS_ATTRIBUTE_CHAP_NT_ENC_PW,
  274. encPW
  275. ))
  276. {
  277. _com_issue_error(IAS_MALFORMED_REQUEST);
  278. }
  279. //////////
  280. // Change the password.
  281. //////////
  282. DWORD status;
  283. status = IASChangePassword3(
  284. username,
  285. domainName,
  286. cpw.get().encryptedHash,
  287. encPW
  288. );
  289. if (status == NO_ERROR)
  290. {
  291. IASTraceString("Password successfully changed.");
  292. // Password was successfully changed, so authenticate the user.
  293. NTSamAuthentication::doMsChap2Authentication(
  294. request,
  295. domainName,
  296. username,
  297. cpw.get().ident,
  298. msChapChallenge,
  299. cpw.get().response,
  300. cpw.get().peerChallenge
  301. );
  302. }
  303. else
  304. {
  305. IASTraceFailure("IASChangePassword3", status);
  306. if (status == ERROR_ACCESS_DENIED)
  307. {
  308. status = IAS_CHANGE_PASSWORD_FAILURE;
  309. }
  310. else
  311. {
  312. status = IASMapWin32Error(status, IAS_CHANGE_PASSWORD_FAILURE);
  313. }
  314. IASProcessFailure(request, status);
  315. }
  316. }
  317. void ChangePassword::doChangePassword(
  318. IASTL::IASRequest& request,
  319. DWORD authType
  320. )
  321. {
  322. IASTL::IASAttribute identity;
  323. if (!identity.load(
  324. request,
  325. IAS_ATTRIBUTE_NT4_ACCOUNT_NAME,
  326. IASTYPE_STRING
  327. ))
  328. {
  329. _com_issue_error(IAS_INTERNAL_ERROR);
  330. }
  331. // Convert the User-Name to SAM format.
  332. PCWSTR domain, username;
  333. EXTRACT_SAM_IDENTITY(identity->Value.String, domain, username);
  334. IASAttribute msChapChallenge;
  335. if (!msChapChallenge.load(
  336. request,
  337. MS_ATTRIBUTE_CHAP_CHALLENGE,
  338. IASTYPE_OCTET_STRING
  339. ))
  340. {
  341. _com_issue_error(IAS_INTERNAL_ERROR);
  342. }
  343. switch (authType)
  344. {
  345. case IAS_AUTH_MSCHAP_CPW:
  346. doMsChapCpw(
  347. request,
  348. domain,
  349. username,
  350. msChapChallenge->Value.OctetString
  351. );
  352. break;
  353. case IAS_AUTH_MSCHAP2_CPW:
  354. doMsChap2Cpw(
  355. request,
  356. domain,
  357. username,
  358. msChapChallenge->Value.OctetString
  359. );
  360. break;
  361. default:
  362. _com_issue_error(IAS_INTERNAL_ERROR);
  363. }
  364. }