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.

389 lines
8.9 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. setpwd.c
  5. Abstract:
  6. Sets a user's password based on OWF password hash strings
  7. Calls SamiChangePasswordUser with encoded passwords.
  8. Author:
  9. Ovidiu Temereanca 17-Mar-2000 Initial implementation
  10. Revision History:
  11. --*/
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #undef DOMAIN_ALL_ACCESS // defined in both ntsam.h and ntwinapi.h
  16. #include <ntsam.h>
  17. #include <ntsamp.h>
  18. //#include <ntlsa.h>
  19. #include <windef.h>
  20. #include <winbase.h>
  21. //#include <lmcons.h>
  22. #include <align.h>
  23. //#include <lm.h>
  24. //#include <limits.h>
  25. //#include <rpcutil.h>
  26. //#include <secobj.h>
  27. //#include <stddef.h>
  28. //#include <ntdsapi.h>
  29. //#include <dsgetdc.h>
  30. #include <windows.h>
  31. #include "encrypt.h"
  32. NTSTATUS
  33. pGetDomainId (
  34. IN SAM_HANDLE ServerHandle,
  35. OUT PSID* DomainId
  36. )
  37. /*++
  38. Routine Description:
  39. Return a domain ID of the account domain of a server.
  40. Arguments:
  41. ServerHandle - A handle to the SAM server to open the domain on
  42. DomainId - Receives a pointer to the domain ID.
  43. Caller must deallocate buffer using SamFreeMemory.
  44. Return Value:
  45. Error code for the operation.
  46. --*/
  47. {
  48. NTSTATUS status;
  49. SAM_ENUMERATE_HANDLE EnumContext;
  50. PSAM_RID_ENUMERATION EnumBuffer = NULL;
  51. DWORD CountReturned = 0;
  52. PSID LocalDomainId = NULL;
  53. DWORD LocalBuiltinDomainSid[sizeof(SID) / sizeof(DWORD) + SID_MAX_SUB_AUTHORITIES];
  54. SID_IDENTIFIER_AUTHORITY BuiltinAuthority = SECURITY_NT_AUTHORITY;
  55. BOOL b = FALSE;
  56. ULONG i;
  57. //
  58. // Compute the builtin domain sid.
  59. //
  60. RtlInitializeSid((PSID) LocalBuiltinDomainSid, &BuiltinAuthority, 1);
  61. *(RtlSubAuthoritySid((PSID)LocalBuiltinDomainSid, 0)) = SECURITY_BUILTIN_DOMAIN_RID;
  62. //
  63. // Loop getting the list of domain ids from SAM
  64. //
  65. EnumContext = 0;
  66. do {
  67. //
  68. // Get several domain names.
  69. //
  70. status = SamEnumerateDomainsInSamServer (
  71. ServerHandle,
  72. &EnumContext,
  73. &EnumBuffer,
  74. 8192,
  75. &CountReturned
  76. );
  77. if (!NT_SUCCESS (status)) {
  78. goto exit;
  79. }
  80. if (status != STATUS_MORE_ENTRIES) {
  81. b = TRUE;
  82. }
  83. //
  84. // Lookup the domain ids for the domains
  85. //
  86. for(i = 0; i < CountReturned; i++) {
  87. //
  88. // Free the sid from the previous iteration.
  89. //
  90. if (LocalDomainId != NULL) {
  91. SamFreeMemory (LocalDomainId);
  92. LocalDomainId = NULL;
  93. }
  94. //
  95. // Lookup the domain id
  96. //
  97. status = SamLookupDomainInSamServer (
  98. ServerHandle,
  99. &EnumBuffer[i].Name,
  100. &LocalDomainId
  101. );
  102. if (!NT_SUCCESS (status)) {
  103. goto exit;
  104. }
  105. if (RtlEqualSid ((PSID)LocalBuiltinDomainSid, LocalDomainId)) {
  106. continue;
  107. }
  108. *DomainId = LocalDomainId;
  109. LocalDomainId = NULL;
  110. status = NO_ERROR;
  111. goto exit;
  112. }
  113. SamFreeMemory(EnumBuffer);
  114. EnumBuffer = NULL;
  115. } while (!b);
  116. status = ERROR_NO_SUCH_DOMAIN;
  117. exit:
  118. if (EnumBuffer != NULL) {
  119. SamFreeMemory(EnumBuffer);
  120. }
  121. return status;
  122. }
  123. DWORD
  124. pSamOpenLocalUser (
  125. IN PCWSTR UserName,
  126. IN ACCESS_MASK DesiredAccess,
  127. IN PSAM_HANDLE DomainHandle,
  128. OUT PSAM_HANDLE UserHandle
  129. )
  130. /*++
  131. Routine Description:
  132. Returns a user handle given its name, desired access and a domain handle.
  133. Arguments:
  134. UserName - Specifies the user name
  135. DesiredAccess - Specifies the desired access to this user
  136. DoaminHandle - A handle to the domain to open the user on
  137. UserHandle - Receives a user handle.
  138. Caller must free the handle using SamCloseHandle.
  139. Return Value:
  140. Error code for the operation.
  141. --*/
  142. {
  143. DWORD status;
  144. UNICODE_STRING uniUserName;
  145. ULONG rid, *prid;
  146. PSID_NAME_USE nameUse;
  147. //
  148. // Lookup the RID
  149. //
  150. RtlInitUnicodeString (&uniUserName, UserName);
  151. status = SamLookupNamesInDomain (
  152. DomainHandle,
  153. 1,
  154. &uniUserName,
  155. &prid,
  156. &nameUse
  157. );
  158. if (status != NO_ERROR) {
  159. return status;
  160. }
  161. //
  162. // Save the RID
  163. //
  164. rid = *prid;
  165. //
  166. // free the memory.
  167. //
  168. SamFreeMemory (prid);
  169. SamFreeMemory (nameUse);
  170. //
  171. // Open the user object.
  172. //
  173. status = SamOpenUser(
  174. DomainHandle,
  175. DesiredAccess,
  176. rid,
  177. UserHandle
  178. );
  179. return status;
  180. }
  181. DWORD
  182. SetLocalUserEncryptedPassword (
  183. IN PCWSTR User,
  184. IN PCWSTR OldPassword,
  185. IN BOOL OldIsEncrypted,
  186. IN PCWSTR NewPassword,
  187. IN BOOL NewIsEncrypted
  188. )
  189. /*++
  190. Routine Description:
  191. Sets a new password for the given user. The password is in encrypted format (see encrypt.h for details).
  192. Arguments:
  193. User - Specifies the user name
  194. OldPassword - Specifies the old password
  195. OldIsEncrypted - Specifies TRUE if old password is provided in encrypted form
  196. or FALSE if it's in clear text
  197. OldIsComplex - Specifies TRUE if old password is complex; used only if OldIsEncrypted is TRUE,
  198. otherwise it's ignored.
  199. NewPassword - Specifies the new password
  200. NewIsEncrypted - Specifies TRUE if new password is provided in encrypted form
  201. or FALSE if it's in clear text
  202. Return Value:
  203. Win32 error code for the operation.
  204. --*/
  205. {
  206. DWORD status;
  207. LM_OWF_PASSWORD lmOwfOldPwd;
  208. NT_OWF_PASSWORD ntOwfOldPwd;
  209. BOOL complexOldPassword;
  210. LM_OWF_PASSWORD lmOwfNewPwd;
  211. NT_OWF_PASSWORD ntOwfNewPwd;
  212. UNICODE_STRING unicodeString;
  213. PSID serverHandle = NULL;
  214. PSID sidAccountsDomain = NULL;
  215. SAM_HANDLE handleAccountsDomain = NULL;
  216. SAM_HANDLE handleUser = NULL;
  217. if (!User) {
  218. return ERROR_INVALID_PARAMETER;
  219. }
  220. if (OldIsEncrypted) {
  221. if (!StringDecodeOwfPasswordW (OldPassword, &lmOwfOldPwd, &ntOwfOldPwd, &complexOldPassword)) {
  222. return ERROR_INVALID_PARAMETER;
  223. }
  224. } else {
  225. if (!EncodeLmOwfPasswordW (OldPassword, &lmOwfOldPwd, &complexOldPassword) ||
  226. !EncodeNtOwfPasswordW (OldPassword, &ntOwfOldPwd)
  227. ) {
  228. return ERROR_INVALID_PARAMETER;
  229. }
  230. }
  231. if (NewIsEncrypted) {
  232. if (!StringDecodeOwfPasswordW (NewPassword, &lmOwfNewPwd, &ntOwfNewPwd, NULL)) {
  233. return ERROR_INVALID_PARAMETER;
  234. }
  235. } else {
  236. if (!EncodeLmOwfPasswordW (NewPassword, &lmOwfNewPwd, NULL) ||
  237. !EncodeNtOwfPasswordW (NewPassword, &ntOwfNewPwd)
  238. ) {
  239. return ERROR_INVALID_PARAMETER;
  240. }
  241. }
  242. __try {
  243. //
  244. // Use SamConnect to connect to the local domain ("")
  245. // and get a handle to the local SAM server
  246. //
  247. RtlInitUnicodeString (&unicodeString, L"");
  248. status = SamConnect (
  249. &unicodeString,
  250. &serverHandle,
  251. SAM_SERVER_LOOKUP_DOMAIN | SAM_SERVER_ENUMERATE_DOMAINS,
  252. NULL
  253. );
  254. if (status != NO_ERROR) {
  255. __leave;
  256. }
  257. status = pGetDomainId (serverHandle, &sidAccountsDomain);
  258. if (status != NO_ERROR) {
  259. __leave;
  260. }
  261. //
  262. // Open the domain.
  263. //
  264. status = SamOpenDomain (
  265. serverHandle,
  266. DOMAIN_LOOKUP | DOMAIN_READ_PASSWORD_PARAMETERS,
  267. sidAccountsDomain,
  268. &handleAccountsDomain
  269. );
  270. if (status != NO_ERROR) {
  271. __leave;
  272. }
  273. status = pSamOpenLocalUser (
  274. User,
  275. USER_CHANGE_PASSWORD,
  276. handleAccountsDomain,
  277. &handleUser
  278. );
  279. if (status != NO_ERROR) {
  280. __leave;
  281. }
  282. status = SamiChangePasswordUser (
  283. handleUser,
  284. !complexOldPassword,
  285. &lmOwfOldPwd,
  286. &lmOwfNewPwd,
  287. TRUE,
  288. &ntOwfOldPwd,
  289. &ntOwfNewPwd
  290. );
  291. }
  292. __finally {
  293. if (handleUser) {
  294. SamCloseHandle (handleUser);
  295. }
  296. if (handleAccountsDomain) {
  297. SamCloseHandle (handleAccountsDomain);
  298. }
  299. if (sidAccountsDomain) {
  300. SamFreeMemory (sidAccountsDomain);
  301. }
  302. if (serverHandle) {
  303. SamCloseHandle (serverHandle);
  304. }
  305. }
  306. return RtlNtStatusToDosError (status);
  307. }