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.

414 lines
11 KiB

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