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.

537 lines
12 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. lsa.c
  5. Abstract:
  6. This module provides helpers to call LSA, particularly for
  7. manipulating secret objects.
  8. Author:
  9. Rita Wong (ritaw) 22-Apr-1993
  10. --*/
  11. #include <stdlib.h>
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <windef.h>
  16. #include <winerror.h>
  17. #include <winbase.h>
  18. #include <nwlsa.h>
  19. //-------------------------------------------------------------------//
  20. // //
  21. // Constants and Macros //
  22. // //
  23. //-------------------------------------------------------------------//
  24. #define NW_SECRET_PREFIX L"_MS_NWCS_"
  25. DWORD
  26. NwOpenPolicy(
  27. IN ACCESS_MASK DesiredAccess,
  28. OUT LSA_HANDLE *PolicyHandle
  29. )
  30. /*++
  31. Routine Description:
  32. This function gets a handle to the local security policy by calling
  33. LsaOpenPolicy.
  34. Arguments:
  35. DesiredAccess - Supplies the desired access to the local security
  36. policy.
  37. PolicyHandle - Receives a handle to the opened policy.
  38. Return Value:
  39. NO_ERROR - Policy handle is returned.
  40. Error from LSA.
  41. --*/
  42. {
  43. NTSTATUS ntstatus;
  44. OBJECT_ATTRIBUTES ObjAttributes;
  45. //
  46. // Open a handle to the local security policy. Initialize the
  47. // objects attributes structure first.
  48. //
  49. InitializeObjectAttributes(
  50. &ObjAttributes,
  51. NULL,
  52. 0L,
  53. NULL,
  54. NULL
  55. );
  56. ntstatus = LsaOpenPolicy(
  57. NULL,
  58. &ObjAttributes,
  59. DesiredAccess,
  60. PolicyHandle
  61. );
  62. if (! NT_SUCCESS(ntstatus)) {
  63. KdPrint(("NWWORKSTATION: LsaOpenPolicy returns %08lx\n",
  64. ntstatus));
  65. return RtlNtStatusToDosError(ntstatus);
  66. }
  67. return NO_ERROR;
  68. }
  69. DWORD
  70. NwOpenSecret(
  71. IN ACCESS_MASK DesiredAccess,
  72. IN LSA_HANDLE PolicyHandle,
  73. IN LPWSTR LsaSecretName,
  74. OUT PLSA_HANDLE SecretHandle
  75. )
  76. /*++
  77. Routine Description:
  78. This function opens a handle to the specified secret object.
  79. Arguments:
  80. DesiredAccess - Supplies the desired access to the secret object.
  81. PolicyHandle - Supplies a handle to an already opened LSA policy.
  82. LsaSecretName - Supplies the name of the secret to open.
  83. SecretHandle - Receives the handle of the opened secret.
  84. Return Value:
  85. NO_ERROR - Secret handle is returned.
  86. Error from LSA.
  87. --*/
  88. {
  89. NTSTATUS ntstatus;
  90. UNICODE_STRING SecretNameString;
  91. RtlInitUnicodeString(&SecretNameString, LsaSecretName);
  92. ntstatus = LsaOpenSecret(
  93. PolicyHandle,
  94. &SecretNameString,
  95. DesiredAccess,
  96. SecretHandle
  97. );
  98. if (! NT_SUCCESS(ntstatus)) {
  99. KdPrint(("NWWORKSTATION: LsaOpenSecret %ws returns %08lx\n",
  100. LsaSecretName, ntstatus));
  101. return RtlNtStatusToDosError(ntstatus);
  102. }
  103. return NO_ERROR;
  104. }
  105. DWORD
  106. NwFormSecretName(
  107. IN LPWSTR Qualifier,
  108. OUT LPWSTR *LsaSecretName
  109. )
  110. /*++
  111. Routine Description:
  112. This function creates a secret name from the user name.
  113. It also allocates the buffer to return the created secret name which
  114. must be freed by the caller using LocalFree when done with it.
  115. Arguments:
  116. Qualifier - Supplies the qualifier which forms part of part of the secret
  117. object name we are creating.
  118. LsaSecretName - Receives a pointer to the buffer which contains the
  119. secret object name.
  120. Return Value:
  121. NO_ERROR - Successfully returned secret name.
  122. ERROR_NOT_ENOUGH_MEMORY - Failed to allocate buffer to hold the secret
  123. name.
  124. --*/
  125. {
  126. if ((*LsaSecretName = (LPWSTR)LocalAlloc(
  127. 0,
  128. (wcslen(NW_SECRET_PREFIX) +
  129. wcslen(Qualifier) +
  130. 1) * sizeof(WCHAR)
  131. )) == NULL) {
  132. KdPrint(("NWWORKSTATION: NwFormSecretName: LocalAlloc failed %lu\n",
  133. GetLastError()));
  134. return ERROR_NOT_ENOUGH_MEMORY;
  135. }
  136. wcscpy(*LsaSecretName, NW_SECRET_PREFIX);
  137. wcscat(*LsaSecretName, Qualifier);
  138. return NO_ERROR;
  139. }
  140. DWORD
  141. NwSetPassword(
  142. IN LPWSTR Qualifier,
  143. IN LPWSTR Password
  144. )
  145. /*++
  146. Routine Description:
  147. This function opens ( creates one if needed ) the LSA secret object,
  148. and sets it with the specified password.
  149. Arguments:
  150. Qualifier - Supplies the qualifier which forms part of part of the secret
  151. object name to be created.
  152. Password - Supplies the user specified password for an account.
  153. Return Value:
  154. NO_ERROR - Secret object for the password is created and set with new value.
  155. Error from LSA.
  156. --*/
  157. {
  158. DWORD status;
  159. NTSTATUS ntstatus;
  160. LSA_HANDLE PolicyHandle;
  161. LSA_HANDLE SecretHandle;
  162. UNICODE_STRING SecretNameString;
  163. LPWSTR LsaSecretName;
  164. UNICODE_STRING NewPasswordString;
  165. UNICODE_STRING OldPasswordString;
  166. //
  167. // Open a handle to the local security policy.
  168. //
  169. if ((status = NwOpenPolicy(
  170. POLICY_CREATE_SECRET,
  171. &PolicyHandle
  172. )) != NO_ERROR) {
  173. KdPrint(("NWWORKSTATION: NwCreatePassword: NwOpenPolicy failed\n"));
  174. return status;
  175. }
  176. //
  177. // Create the LSA secret object. But first, form a secret name.
  178. //
  179. if ((status = NwFormSecretName(
  180. Qualifier,
  181. &LsaSecretName
  182. )) != NO_ERROR) {
  183. (void) LsaClose(PolicyHandle);
  184. return status;
  185. }
  186. RtlInitUnicodeString(&SecretNameString, LsaSecretName);
  187. ntstatus = LsaCreateSecret(
  188. PolicyHandle,
  189. &SecretNameString,
  190. SECRET_SET_VALUE | DELETE,
  191. &SecretHandle
  192. );
  193. //
  194. // note: ignore object already exists error. just use the existing
  195. // object. this could be because the user didnt completely cleanup
  196. // during deinstall. the unique names makes it unlikely to be a real
  197. // collision.
  198. //
  199. if ( ntstatus == STATUS_OBJECT_NAME_COLLISION ) {
  200. ntstatus = NwOpenSecret(
  201. SECRET_SET_VALUE,
  202. PolicyHandle,
  203. LsaSecretName,
  204. &SecretHandle
  205. );
  206. }
  207. //
  208. // Don't need the name or policy handle anymore.
  209. //
  210. (void) LocalFree((HLOCAL) LsaSecretName);
  211. (void) LsaClose(PolicyHandle);
  212. if (! NT_SUCCESS(ntstatus)) {
  213. KdPrint(("NWWORKSTATION: NwCreatePassword: LsaCreateSecret or LsaOpenSecret returned %08lx for %ws\n", ntstatus, LsaSecretName));
  214. return RtlNtStatusToDosError(ntstatus);
  215. }
  216. RtlInitUnicodeString(&OldPasswordString, NULL);
  217. RtlInitUnicodeString(&NewPasswordString, Password);
  218. ntstatus = LsaSetSecret(
  219. SecretHandle,
  220. &NewPasswordString,
  221. &OldPasswordString
  222. );
  223. if (! NT_SUCCESS(ntstatus)) {
  224. KdPrint(("NWWORKSTATION NwCreatePassword: LsaSetSecret returned %08lx\n",
  225. ntstatus));
  226. status = RtlNtStatusToDosError(ntstatus);
  227. //
  228. // Delete the secret object
  229. //
  230. ntstatus = LsaDelete(SecretHandle);
  231. if (! NT_SUCCESS(ntstatus)) {
  232. KdPrint(("NWWORKSTATION: NwCreatePassword: LsaDelete to restore back to original returned %08lx\n",
  233. ntstatus));
  234. (void) LsaClose(SecretHandle);
  235. }
  236. //
  237. // Secret handle is closed by LsaDelete if successfully deleted.
  238. //
  239. return status;
  240. }
  241. (void) LsaClose(SecretHandle);
  242. return NO_ERROR;
  243. }
  244. DWORD
  245. NwDeletePassword(
  246. IN LPWSTR Qualifier
  247. )
  248. /*++
  249. Routine Description:
  250. This function deletes the LSA secret object whose name is derived
  251. from the specified Qualifier.
  252. Arguments:
  253. Qualifier - Supplies the qualifier which forms part of part of the secret
  254. object name to be deleted.
  255. Return Value:
  256. NO_ERROR - Secret object for password is deleted.
  257. Error from LSA.
  258. --*/
  259. {
  260. DWORD status;
  261. NTSTATUS ntstatus;
  262. LSA_HANDLE PolicyHandle;
  263. LSA_HANDLE SecretHandle;
  264. LPWSTR LsaSecretName;
  265. //
  266. // Open a handle to the local security policy.
  267. //
  268. if ((status = NwOpenPolicy(
  269. POLICY_VIEW_LOCAL_INFORMATION,
  270. &PolicyHandle
  271. )) != NO_ERROR) {
  272. KdPrint(("NWWORKSTATION: NwDeletePassword: NwOpenPolicy failed\n"));
  273. return status;
  274. }
  275. //
  276. // Get the secret object name from the specified user name.
  277. //
  278. if ((status = NwFormSecretName(
  279. Qualifier,
  280. &LsaSecretName
  281. )) != NO_ERROR) {
  282. (void) LsaClose(PolicyHandle);
  283. return status;
  284. }
  285. status = NwOpenSecret(
  286. DELETE,
  287. PolicyHandle,
  288. LsaSecretName,
  289. &SecretHandle
  290. );
  291. //
  292. // Don't need the name or policy handle anymore.
  293. //
  294. (void) LocalFree((HLOCAL) LsaSecretName);
  295. (void) LsaClose(PolicyHandle);
  296. if (status != NO_ERROR) {
  297. KdPrint(("NWWORKSTATION: NwDeletePassword: NwOpenSecret failed\n"));
  298. return status;
  299. }
  300. ntstatus = LsaDelete(SecretHandle);
  301. if (! NT_SUCCESS(ntstatus)) {
  302. KdPrint(("NWWORKSTATION: NwDeletePassword: LsaDelete returned %08lx\n",
  303. ntstatus));
  304. (void) LsaClose(SecretHandle);
  305. return RtlNtStatusToDosError(ntstatus);
  306. }
  307. return NO_ERROR;
  308. }
  309. DWORD
  310. NwGetPassword(
  311. IN LPWSTR Qualifier,
  312. OUT PUNICODE_STRING *Password,
  313. OUT PUNICODE_STRING *OldPassword
  314. )
  315. /*++
  316. Routine Description:
  317. This function retrieves the current password and old password
  318. values from the service secret object given the user name.
  319. Arguments:
  320. Qualifier - Supplies the qualifier which forms part of the key to the
  321. secret object name.
  322. Password - Receives a pointer to the string structure that contains
  323. the password.
  324. OldPassword - Receives a pointer to the string structure that
  325. contains the old password.
  326. Return Value:
  327. NO_ERROR - Secret object for password is changed to new value.
  328. Error from LSA.
  329. --*/
  330. {
  331. DWORD status;
  332. NTSTATUS ntstatus;
  333. LSA_HANDLE PolicyHandle;
  334. LSA_HANDLE SecretHandle;
  335. LPWSTR LsaSecretName;
  336. //
  337. // Open a handle to the local security policy to read the
  338. // value of the secret.
  339. //
  340. if ((status = NwOpenPolicy(
  341. POLICY_VIEW_LOCAL_INFORMATION,
  342. &PolicyHandle
  343. )) != NO_ERROR) {
  344. return status;
  345. }
  346. //
  347. // Get the secret object name from the specified user name.
  348. //
  349. if ((status = NwFormSecretName(
  350. Qualifier,
  351. &LsaSecretName
  352. )) != NO_ERROR) {
  353. (void) LsaClose(PolicyHandle);
  354. return status;
  355. }
  356. status = NwOpenSecret(
  357. SECRET_QUERY_VALUE,
  358. PolicyHandle,
  359. LsaSecretName,
  360. &SecretHandle
  361. );
  362. //
  363. // Don't need the name or policy handle anymore.
  364. //
  365. (void) LocalFree((HLOCAL) LsaSecretName);
  366. (void) LsaClose(PolicyHandle);
  367. if (status != NO_ERROR) {
  368. KdPrint(("NWWORKSTATION: ScGetSecret: ScOpenSecret failed\n"));
  369. return status;
  370. }
  371. //
  372. // Query the old value of the secret object so that we can
  373. // we can restore it if we fail to change the password later.
  374. //
  375. ntstatus = LsaQuerySecret(
  376. SecretHandle,
  377. Password,
  378. NULL, // don't need set time
  379. OldPassword,
  380. NULL // don't need set time
  381. );
  382. (void) LsaClose(SecretHandle);
  383. if (! NT_SUCCESS(ntstatus)) {
  384. KdPrint(("NWWORKSTATION: NwGetPassword: LsaQuerySecret for previous values returned %08lx\n",
  385. ntstatus));
  386. return RtlNtStatusToDosError(ntstatus);
  387. }
  388. return NO_ERROR;
  389. }