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.

478 lines
11 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1999
  6. //
  7. // File: changepw.cxx
  8. //
  9. // Contents: Code for KerbSetPassword and KerbChangePassword
  10. //
  11. //
  12. // History: 24-May-1999 MikeSw Created
  13. //
  14. //------------------------------------------------------------------------
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include <windows.h>
  19. #include <sspi.h>
  20. #include <ntsecapi.h>
  21. #include <align.h>
  22. #include <dsgetdc.h>
  23. #include <kerbcli.h>
  24. //+-------------------------------------------------------------------------
  25. //
  26. // Function: KerbChangePasswordUserEx
  27. //
  28. // Synopsis: Changes a users password. If the user is logged on,
  29. // it also updates the in-memory password.
  30. //
  31. // Effects:
  32. //
  33. // Arguments:
  34. //
  35. // Requires:
  36. //
  37. // Returns:
  38. //
  39. // Notes:
  40. //
  41. //
  42. //--------------------------------------------------------------------------
  43. NTSTATUS
  44. KerbChangePasswordUser(
  45. IN LPWSTR DomainName,
  46. IN LPWSTR UserName,
  47. IN LPWSTR OldPassword,
  48. IN LPWSTR NewPassword
  49. )
  50. {
  51. NTSTATUS Status;
  52. BOOLEAN WasEnabled;
  53. STRING Name;
  54. ULONG Dummy;
  55. HANDLE LogonHandle = NULL;
  56. ULONG PackageId;
  57. PVOID Response = NULL ;
  58. ULONG ResponseSize;
  59. NTSTATUS SubStatus;
  60. PKERB_CHANGEPASSWORD_REQUEST ChangeRequest = NULL;
  61. ULONG ChangeSize;
  62. UNICODE_STRING User,Domain,OldPass,NewPass;
  63. Status = LsaConnectUntrusted(
  64. &LogonHandle
  65. );
  66. if (!NT_SUCCESS(Status))
  67. {
  68. goto Cleanup;
  69. }
  70. RtlInitString(
  71. &Name,
  72. MICROSOFT_KERBEROS_NAME_A
  73. );
  74. Status = LsaLookupAuthenticationPackage(
  75. LogonHandle,
  76. &Name,
  77. &PackageId
  78. );
  79. if (!NT_SUCCESS(Status))
  80. {
  81. goto Cleanup;
  82. }
  83. RtlInitUnicodeString(
  84. &User,
  85. UserName
  86. );
  87. RtlInitUnicodeString(
  88. &Domain,
  89. DomainName
  90. );
  91. RtlInitUnicodeString(
  92. &OldPass,
  93. OldPassword
  94. );
  95. RtlInitUnicodeString(
  96. &NewPass,
  97. NewPassword
  98. );
  99. if ( OldPass.Length > (127*sizeof(WCHAR)) ||
  100. NewPass.Length > (127*sizeof(WCHAR)) )
  101. {
  102. Status = STATUS_NAME_TOO_LONG;
  103. goto Cleanup;
  104. }
  105. ChangeSize = ROUND_UP_COUNT(sizeof(KERB_CHANGEPASSWORD_REQUEST),4)+
  106. User.Length +
  107. Domain.Length +
  108. OldPass.Length +
  109. NewPass.Length ;
  110. ChangeRequest = (PKERB_CHANGEPASSWORD_REQUEST) LocalAlloc(LMEM_ZEROINIT, ChangeSize );
  111. if (NULL == ChangeRequest)
  112. {
  113. goto Cleanup;
  114. }
  115. ChangeRequest->MessageType = KerbChangePasswordMessage;
  116. ChangeRequest->AccountName = User;
  117. ChangeRequest->AccountName.Buffer = (LPWSTR) ROUND_UP_POINTER(sizeof(KERB_CHANGEPASSWORD_REQUEST) + (PBYTE) ChangeRequest,4);
  118. RtlCopyMemory(
  119. ChangeRequest->AccountName.Buffer,
  120. User.Buffer,
  121. User.Length
  122. );
  123. ChangeRequest->DomainName = Domain;
  124. ChangeRequest->DomainName.Buffer = ChangeRequest->AccountName.Buffer + ChangeRequest->AccountName.Length / sizeof(WCHAR);
  125. RtlCopyMemory(
  126. ChangeRequest->DomainName.Buffer,
  127. Domain.Buffer,
  128. Domain.Length
  129. );
  130. ChangeRequest->OldPassword = OldPass;
  131. ChangeRequest->OldPassword.Buffer = ChangeRequest->DomainName.Buffer + ChangeRequest->DomainName.Length / sizeof(WCHAR);
  132. RtlCopyMemory(
  133. ChangeRequest->OldPassword.Buffer,
  134. OldPass.Buffer,
  135. OldPass.Length
  136. );
  137. ChangeRequest->NewPassword = NewPass;
  138. ChangeRequest->NewPassword.Buffer = ChangeRequest->OldPassword.Buffer + ChangeRequest->OldPassword.Length / sizeof(WCHAR);
  139. RtlCopyMemory(
  140. ChangeRequest->NewPassword.Buffer,
  141. NewPass.Buffer,
  142. NewPass.Length
  143. );
  144. //
  145. // We are running as the caller, so state we are impersonating
  146. //
  147. ChangeRequest->Impersonating = TRUE;
  148. Status = LsaCallAuthenticationPackage(
  149. LogonHandle,
  150. PackageId,
  151. ChangeRequest,
  152. ChangeSize,
  153. &Response,
  154. &ResponseSize,
  155. &SubStatus
  156. );
  157. if (!NT_SUCCESS(Status) || !NT_SUCCESS(SubStatus))
  158. {
  159. if (NT_SUCCESS(Status))
  160. {
  161. Status = SubStatus;
  162. }
  163. goto Cleanup;
  164. }
  165. Cleanup:
  166. if (LogonHandle != NULL)
  167. {
  168. LsaDeregisterLogonProcess(LogonHandle);
  169. }
  170. if (Response != NULL)
  171. {
  172. LsaFreeReturnBuffer(Response);
  173. }
  174. if (ChangeRequest != NULL)
  175. {
  176. LocalFree(ChangeRequest);
  177. }
  178. return(Status);
  179. }
  180. //+-------------------------------------------------------------------------
  181. //
  182. // Function: KerbSetPasswordUserEx
  183. //
  184. // Synopsis: Sets a password for a user in the specified domain
  185. //
  186. // Effects:
  187. //
  188. // Arguments:
  189. //
  190. // Requires:
  191. //
  192. // Returns:
  193. //
  194. // Notes:
  195. //
  196. //
  197. //--------------------------------------------------------------------------
  198. NTSTATUS
  199. KerbSetPasswordUserEx(
  200. IN LPWSTR DomainName,
  201. IN LPWSTR UserName,
  202. IN LPWSTR NewPassword,
  203. IN OPTIONAL PCredHandle CredentialsHandle,
  204. IN OPTIONAL LPWSTR KdcAddress
  205. )
  206. {
  207. NTSTATUS Status;
  208. BOOLEAN WasEnabled;
  209. STRING Name;
  210. ULONG Dummy;
  211. HANDLE LogonHandle = NULL;
  212. ULONG PackageId;
  213. PVOID Response = NULL;
  214. ULONG ResponseSize;
  215. KERB_PROTOCOL_MESSAGE_TYPE MessageType = KerbSetPasswordMessage;
  216. NTSTATUS SubStatus;
  217. PKERB_SETPASSWORD_EX_REQUEST SetRequest = NULL;
  218. ULONG ChangeSize;
  219. UNICODE_STRING User,Domain,OldPass,NewPass, KdcAddr, ClientName, ClientRealm;
  220. // If you supply a KdcAddress, you must supply name type
  221. if (ARGUMENT_PRESENT(KdcAddress))
  222. {
  223. MessageType = KerbSetPasswordExMessage;
  224. RtlInitUnicodeString(
  225. &KdcAddr,
  226. KdcAddress
  227. );
  228. }
  229. else
  230. {
  231. RtlInitUnicodeString(
  232. &KdcAddr,
  233. NULL
  234. );
  235. }
  236. Status = LsaConnectUntrusted(
  237. &LogonHandle
  238. );
  239. if (!NT_SUCCESS(Status))
  240. {
  241. goto Cleanup;
  242. }
  243. RtlInitString(
  244. &Name,
  245. MICROSOFT_KERBEROS_NAME_A
  246. );
  247. Status = LsaLookupAuthenticationPackage(
  248. LogonHandle,
  249. &Name,
  250. &PackageId
  251. );
  252. if (!NT_SUCCESS(Status))
  253. {
  254. goto Cleanup;
  255. }
  256. RtlInitUnicodeString(
  257. &User,
  258. UserName
  259. );
  260. RtlInitUnicodeString(
  261. &Domain,
  262. DomainName
  263. );
  264. RtlInitUnicodeString(
  265. &NewPass,
  266. NewPassword
  267. );
  268. // These aren't used here (yet)
  269. RtlInitUnicodeString(
  270. &ClientName,
  271. NULL
  272. );
  273. RtlInitUnicodeString(
  274. &ClientRealm,
  275. NULL
  276. );
  277. if ( NewPass.Length > (127 * sizeof(WCHAR)) )
  278. {
  279. Status = STATUS_NAME_TOO_LONG;
  280. goto Cleanup;
  281. }
  282. ChangeSize = ROUND_UP_COUNT(sizeof(KERB_SETPASSWORD_EX_REQUEST),4)+
  283. User.Length +
  284. Domain.Length +
  285. NewPass.Length +
  286. KdcAddr.Length +
  287. ClientName.Length +
  288. ClientRealm.Length;
  289. SetRequest = (PKERB_SETPASSWORD_EX_REQUEST) LocalAlloc(LMEM_ZEROINIT, ChangeSize );
  290. if (NULL == SetRequest)
  291. {
  292. goto Cleanup;
  293. }
  294. SetRequest->MessageType = MessageType;
  295. SetRequest->KdcAddressType = DS_UNKNOWN_ADDRESS_TYPE;
  296. SetRequest->AccountRealm = Domain;
  297. SetRequest->AccountRealm.Buffer = (LPWSTR) ROUND_UP_POINTER(sizeof(KERB_SETPASSWORD_EX_REQUEST) + (PBYTE) SetRequest,4);
  298. RtlCopyMemory(
  299. SetRequest->AccountRealm.Buffer,
  300. Domain.Buffer,
  301. Domain.Length
  302. );
  303. SetRequest->AccountName = User;
  304. SetRequest->AccountName.Buffer = SetRequest->AccountRealm.Buffer + SetRequest->AccountRealm.Length / sizeof(WCHAR);
  305. RtlCopyMemory(
  306. SetRequest->AccountName.Buffer,
  307. User.Buffer,
  308. User.Length
  309. );
  310. SetRequest->Password = NewPass;
  311. SetRequest->Password.Buffer = SetRequest->AccountName.Buffer + SetRequest->AccountName.Length / sizeof(WCHAR);
  312. RtlCopyMemory(
  313. SetRequest->Password.Buffer,
  314. NewPass.Buffer,
  315. NewPass.Length
  316. );
  317. // Not yet implemented
  318. SetRequest->ClientRealm = ClientRealm;
  319. SetRequest->ClientRealm.Buffer = SetRequest->Password.Buffer + SetRequest->Password.Length / sizeof(WCHAR);
  320. RtlCopyMemory(
  321. SetRequest->ClientRealm.Buffer,
  322. ClientRealm.Buffer,
  323. ClientRealm.Length
  324. );
  325. SetRequest->ClientName = ClientName;
  326. SetRequest->ClientName.Buffer = SetRequest->ClientRealm.Buffer + SetRequest->ClientRealm.Length / sizeof(WCHAR);
  327. RtlCopyMemory(
  328. SetRequest->ClientName.Buffer,
  329. ClientName.Buffer,
  330. ClientName.Length
  331. );
  332. //
  333. SetRequest->KdcAddress = KdcAddr;
  334. SetRequest->KdcAddress.Buffer = SetRequest->ClientRealm.Buffer + SetRequest->ClientRealm.Length / sizeof(WCHAR);
  335. RtlCopyMemory(
  336. SetRequest->KdcAddress.Buffer,
  337. KdcAddr.Buffer,
  338. KdcAddr.Length
  339. );
  340. if (ARGUMENT_PRESENT(CredentialsHandle))
  341. {
  342. SetRequest->CredentialsHandle = *CredentialsHandle;
  343. SetRequest->Flags |= KERB_SETPASS_USE_CREDHANDLE;
  344. }
  345. Status = LsaCallAuthenticationPackage(
  346. LogonHandle,
  347. PackageId,
  348. SetRequest,
  349. ChangeSize,
  350. &Response,
  351. &ResponseSize,
  352. &SubStatus
  353. );
  354. if (!NT_SUCCESS(Status) || !NT_SUCCESS(SubStatus))
  355. {
  356. if (NT_SUCCESS(Status))
  357. {
  358. Status = SubStatus;
  359. }
  360. goto Cleanup;
  361. }
  362. Cleanup:
  363. if (LogonHandle != NULL)
  364. {
  365. LsaDeregisterLogonProcess(LogonHandle);
  366. }
  367. if (Response != NULL)
  368. {
  369. LsaFreeReturnBuffer(Response);
  370. }
  371. if (SetRequest != NULL)
  372. {
  373. LocalFree(SetRequest);
  374. }
  375. return(Status);
  376. }
  377. //+-------------------------------------------------------------------------
  378. //
  379. // Function: KerbSetPasswordUser
  380. //
  381. // Synopsis: Sets a password for a user in the specified domain
  382. //
  383. // Effects:
  384. //
  385. // Arguments:
  386. //
  387. // Requires:
  388. //
  389. // Returns:
  390. //
  391. // Notes:
  392. //
  393. //
  394. //--------------------------------------------------------------------------
  395. NTSTATUS
  396. KerbSetPasswordUser(
  397. IN LPWSTR DomainName,
  398. IN LPWSTR UserName,
  399. IN LPWSTR NewPassword,
  400. IN OPTIONAL PCredHandle CredentialsHandle
  401. )
  402. {
  403. return(KerbSetPasswordUserEx(
  404. DomainName,
  405. UserName,
  406. NewPassword,
  407. CredentialsHandle,
  408. NULL
  409. ));
  410. }