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.

3128 lines
78 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. lsawrap.c
  5. Abstract:
  6. LSA - Database - wrapper APIs for secret, trusted domain, and account
  7. objects.
  8. NOTE: This module should remain as portable code that is independent
  9. of the implementation of the LSA Database. As such, it is
  10. permitted to use only the exported LSA Database interfaces
  11. contained in db.h and NOT the private implementation
  12. dependent functions in dbp.h.
  13. Author:
  14. Mike Swift (MikeSw) December 12, 1994
  15. Environment:
  16. Revision History:
  17. --*/
  18. #include <lsapch2.h>
  19. #include "dbp.h"
  20. #include <lmcons.h> // required by logonmsv.h
  21. #include <logonmsv.h> // SSI_SECRET_PREFIX...
  22. //
  23. // This structure holds the user right to system access mapping
  24. //
  25. typedef struct _LSAP_DB_RIGHT_AND_ACCESS {
  26. UNICODE_STRING UserRight;
  27. ULONG SystemAccess;
  28. } LSAP_DB_RIGHT_AND_ACCESS, *PLSAP_DB_RIGHT_AND_ACCESS;
  29. #define LSAP_DB_SYSTEM_ACCESS_TYPES 10
  30. LSAP_DB_RIGHT_AND_ACCESS LsapDbRightAndAccess[LSAP_DB_SYSTEM_ACCESS_TYPES];
  31. PSECURITY_DESCRIPTOR UserRightSD;
  32. UNICODE_STRING UserRightTypeName;
  33. GENERIC_MAPPING UserRightGenericMapping;
  34. NTSTATUS
  35. LsapDbInitializeRights(
  36. )
  37. {
  38. /*++
  39. Routine Description:
  40. Initializes global data for the new APIs handling user rights
  41. Arguments:
  42. None
  43. Return Value:
  44. STATUS_INSUFFICIENT_MEMORY - not enough memory to initialize the
  45. data structures.
  46. --*/
  47. SECURITY_DESCRIPTOR AbsoluteDescriptor;
  48. ULONG DaclLength;
  49. NTSTATUS Status;
  50. PACL Dacl = NULL;
  51. HANDLE LsaProcessTokenHandle = NULL;
  52. //
  53. // Interactive logons
  54. //
  55. RtlInitUnicodeString(
  56. &LsapDbRightAndAccess[0].UserRight,
  57. SE_INTERACTIVE_LOGON_NAME
  58. );
  59. LsapDbRightAndAccess[0].SystemAccess = SECURITY_ACCESS_INTERACTIVE_LOGON;
  60. //
  61. // network logons
  62. //
  63. RtlInitUnicodeString(
  64. &LsapDbRightAndAccess[1].UserRight,
  65. SE_NETWORK_LOGON_NAME
  66. );
  67. LsapDbRightAndAccess[1].SystemAccess = SECURITY_ACCESS_NETWORK_LOGON;
  68. //
  69. // SERVICE logons
  70. //
  71. RtlInitUnicodeString(
  72. &LsapDbRightAndAccess[2].UserRight,
  73. SE_SERVICE_LOGON_NAME
  74. );
  75. LsapDbRightAndAccess[2].SystemAccess = SECURITY_ACCESS_SERVICE_LOGON;
  76. //
  77. // BATCH logons
  78. //
  79. RtlInitUnicodeString(
  80. &LsapDbRightAndAccess[3].UserRight,
  81. SE_BATCH_LOGON_NAME
  82. );
  83. LsapDbRightAndAccess[3].SystemAccess = SECURITY_ACCESS_BATCH_LOGON;
  84. //
  85. // Deny Interactive logons
  86. //
  87. RtlInitUnicodeString(
  88. &LsapDbRightAndAccess[4].UserRight,
  89. SE_DENY_INTERACTIVE_LOGON_NAME
  90. );
  91. LsapDbRightAndAccess[4].SystemAccess = SECURITY_ACCESS_DENY_INTERACTIVE_LOGON;
  92. //
  93. // Deny network logons
  94. //
  95. RtlInitUnicodeString(
  96. &LsapDbRightAndAccess[5].UserRight,
  97. SE_DENY_NETWORK_LOGON_NAME
  98. );
  99. LsapDbRightAndAccess[5].SystemAccess = SECURITY_ACCESS_DENY_NETWORK_LOGON;
  100. //
  101. // Deny service logons
  102. //
  103. RtlInitUnicodeString(
  104. &LsapDbRightAndAccess[6].UserRight,
  105. SE_DENY_SERVICE_LOGON_NAME
  106. );
  107. LsapDbRightAndAccess[6].SystemAccess = SECURITY_ACCESS_DENY_SERVICE_LOGON;
  108. //
  109. // Deny batch logons
  110. //
  111. RtlInitUnicodeString(
  112. &LsapDbRightAndAccess[7].UserRight,
  113. SE_DENY_BATCH_LOGON_NAME
  114. );
  115. LsapDbRightAndAccess[7].SystemAccess = SECURITY_ACCESS_DENY_BATCH_LOGON;
  116. //
  117. // Remote Interactive logons
  118. //
  119. RtlInitUnicodeString(
  120. &LsapDbRightAndAccess[8].UserRight,
  121. SE_REMOTE_INTERACTIVE_LOGON_NAME
  122. );
  123. LsapDbRightAndAccess[8].SystemAccess = SECURITY_ACCESS_REMOTE_INTERACTIVE_LOGON ;
  124. //
  125. // Deny remote Interactive logons
  126. //
  127. RtlInitUnicodeString(
  128. &LsapDbRightAndAccess[9].UserRight,
  129. SE_DENY_REMOTE_INTERACTIVE_LOGON_NAME
  130. );
  131. LsapDbRightAndAccess[9].SystemAccess = SECURITY_ACCESS_DENY_REMOTE_INTERACTIVE_LOGON ;
  132. //
  133. // Create the security descriptor for the rights pseudo-object
  134. //
  135. //
  136. // The ACL looks like this:
  137. //
  138. // Admins - PRIVILEGE_VIEW | PRIVILEGE_ADJUST
  139. //
  140. Status = RtlCreateSecurityDescriptor(
  141. &AbsoluteDescriptor,
  142. SECURITY_DESCRIPTOR_REVISION
  143. );
  144. if (!NT_SUCCESS(Status)) {
  145. goto Cleanup;
  146. }
  147. DaclLength = sizeof(ACL) -
  148. sizeof(ULONG) + // for dummy in structure
  149. sizeof(ACCESS_ALLOWED_ACE) +
  150. RtlLengthSid(LsapAliasAdminsSid);
  151. Dacl = (PACL) LsapAllocateLsaHeap(DaclLength);
  152. if (Dacl == NULL) {
  153. Status = STATUS_INSUFFICIENT_RESOURCES;
  154. goto Cleanup;
  155. }
  156. Status = RtlCreateAcl(
  157. Dacl,
  158. DaclLength,
  159. ACL_REVISION
  160. );
  161. if (!NT_SUCCESS(Status)) {
  162. goto Cleanup;
  163. }
  164. //
  165. // Now add the access allowed ace for Admins. They are granted
  166. // PRIVILEGE_VIEW and PRIVILEGE_ADJUST access. For now,
  167. // PRIVILEGE_ADJUST is unused (since you can't add accounts to a
  168. // privilege).
  169. //
  170. // ********* NOTE *************
  171. //
  172. // If real privilege objects are ever implemented, this should be moved
  173. // to dbinit.c where the other LSA objects are created, and added to
  174. // the table of real LSA objects.
  175. //
  176. Status = RtlAddAccessAllowedAce(
  177. Dacl,
  178. ACL_REVISION,
  179. PRIVILEGE_VIEW | PRIVILEGE_ADJUST,
  180. LsapAliasAdminsSid
  181. );
  182. if (!NT_SUCCESS(Status)) {
  183. goto Cleanup;
  184. }
  185. Status = RtlSetOwnerSecurityDescriptor(
  186. &AbsoluteDescriptor,
  187. LsapAliasAdminsSid,
  188. FALSE // owner not defaulted
  189. );
  190. if (!NT_SUCCESS(Status)) {
  191. goto Cleanup;
  192. }
  193. Status = RtlSetDaclSecurityDescriptor(
  194. &AbsoluteDescriptor,
  195. TRUE, // DACL present
  196. Dacl,
  197. FALSE // DACL defaulted
  198. );
  199. if (!NT_SUCCESS(Status)) {
  200. goto Cleanup;
  201. }
  202. UserRightGenericMapping.GenericRead = PRIVILEGE_VIEW | STANDARD_RIGHTS_READ;
  203. UserRightGenericMapping.GenericWrite = PRIVILEGE_ADJUST | STANDARD_RIGHTS_WRITE;
  204. UserRightGenericMapping.GenericExecute = STANDARD_RIGHTS_EXECUTE;
  205. UserRightGenericMapping.GenericAll = PRIVILEGE_ALL;
  206. //
  207. // Now open the Lsa process's token with appropriate access (token is
  208. // needed to create the security object).
  209. //
  210. Status = NtOpenProcessToken(
  211. NtCurrentProcess(),
  212. TOKEN_QUERY,
  213. &LsaProcessTokenHandle
  214. );
  215. if (!NT_SUCCESS(Status)) {
  216. goto Cleanup;
  217. }
  218. Status = RtlNewSecurityObject(
  219. NULL,
  220. &AbsoluteDescriptor,
  221. &UserRightSD,
  222. FALSE, // not directory object
  223. LsaProcessTokenHandle,
  224. &UserRightGenericMapping
  225. );
  226. if (!NT_SUCCESS(Status)) {
  227. goto Cleanup;
  228. }
  229. RtlInitUnicodeString(
  230. &UserRightTypeName,
  231. L"UserRightObject"
  232. );
  233. Cleanup:
  234. if (Dacl != NULL) {
  235. LsapFreeLsaHeap(Dacl);
  236. }
  237. if (LsaProcessTokenHandle != NULL) {
  238. NtClose(LsaProcessTokenHandle);
  239. }
  240. return(Status);
  241. }
  242. NTSTATUS
  243. LsapDbFindNextSidWithRight(
  244. IN LSAPR_HANDLE ContainerHandle,
  245. IN OUT PLSA_ENUMERATION_HANDLE EnumerationContext,
  246. IN OPTIONAL PLUID Privilege,
  247. IN OPTIONAL PULONG SystemAccess,
  248. OUT PLSAPR_SID *NextSid
  249. )
  250. /*++
  251. Routine Description:
  252. This function finds the next Sid of object of a given type within a
  253. container object. The given object type must be one where objects
  254. have Sids. The Sids returned can be used on subsequent open calls to
  255. access the objects. The Account
  256. Arguments:
  257. ContainerHandle - Handle to container object.
  258. EnumerationContext - Pointer to a variable containing the index of
  259. the object to be found. A zero value indicates that the first
  260. object is to be found.
  261. Privilege - If present, determines what privilge the account must have.
  262. SystemAccess - If present, determines what kind of system access the
  263. account must have.
  264. NextSid - Receives a pointer to the next Sid found.
  265. Return Value:
  266. NTSTATUS - Standard Nt Result Code
  267. STATUS_INVALID_HANDLE - Invalid ContainerHandle specified
  268. STATUS_NO_MORE_ENTRIES - Warning that no more entries exist.
  269. --*/
  270. {
  271. NTSTATUS Status, SecondaryStatus;
  272. ULONG SidKeyValueLength = 0;
  273. ULONG RightKeyValueLength = 0;
  274. UNICODE_STRING SubKeyNameU;
  275. UNICODE_STRING SidKeyNameU;
  276. UNICODE_STRING RightKeyNameU;
  277. OBJECT_ATTRIBUTES ObjectAttributes;
  278. HANDLE ContDirKeyHandle = NULL;
  279. HANDLE SidKeyHandle = NULL;
  280. HANDLE RightKeyHandle = NULL;
  281. PSID ObjectSid = NULL;
  282. PPRIVILEGE_SET ObjectPrivileges = NULL;
  283. PULONG ObjectAccess = NULL;
  284. PBYTE ObjectRights = NULL;
  285. ULONG Index;
  286. BOOLEAN ValidSid = FALSE;
  287. //
  288. // Zero pointers for cleanup routine
  289. //
  290. SubKeyNameU.Buffer = NULL;
  291. SidKeyNameU.Buffer = NULL;
  292. RightKeyNameU.Buffer = NULL;
  293. //
  294. // Setup object attributes for opening the appropriate Containing
  295. // Directory. Since we're looking for Account objects,
  296. // the containing Directory is "Accounts". The Unicode strings for
  297. // containing Directories are set up during Lsa Initialization.
  298. //
  299. InitializeObjectAttributes(
  300. &ObjectAttributes,
  301. &LsapDbContDirs[AccountObject],
  302. OBJ_CASE_INSENSITIVE,
  303. ((LSAP_DB_HANDLE) ContainerHandle)->KeyHandle,
  304. NULL
  305. );
  306. Status = RtlpNtOpenKey(
  307. &ContDirKeyHandle,
  308. KEY_READ,
  309. &ObjectAttributes,
  310. 0
  311. );
  312. if (!NT_SUCCESS(Status)) {
  313. ContDirKeyHandle = NULL; // For error processing
  314. goto FindNextError;
  315. }
  316. //
  317. // Initialize the Unicode String in which the next object's Logical Name
  318. // will be returned. The Logical Name of an object equals its Registry
  319. // Key relative to its Containing Directory, and is also equal to
  320. // the Relative Id of the object represented in character form as an
  321. // 8-digit number with leading zeros.
  322. //
  323. // NOTE: The size of buffer allocated for the Logical Name must be
  324. // calculated dynamically when the Registry supports long names, because
  325. // it is possible that the Logical Name of an object will be equal to a
  326. // character representation of the full Sid, not just the Relative Id
  327. // part.
  328. //
  329. SubKeyNameU.MaximumLength = (USHORT) LSAP_DB_LOGICAL_NAME_MAX_LENGTH;
  330. SubKeyNameU.Length = 0;
  331. SubKeyNameU.Buffer = LsapAllocateLsaHeap(SubKeyNameU.MaximumLength);
  332. if (SubKeyNameU.Buffer == NULL) {
  333. Status = STATUS_INSUFFICIENT_RESOURCES;
  334. goto FindNextError;
  335. }
  336. //
  337. // Now enumerate the next subkey.
  338. //
  339. Status = RtlpNtEnumerateSubKey(
  340. ContDirKeyHandle,
  341. &SubKeyNameU,
  342. *EnumerationContext,
  343. NULL
  344. );
  345. if (!NT_SUCCESS(Status)) {
  346. goto FindNextError;
  347. }
  348. //
  349. // If a right was passed in, check for that right
  350. //
  351. if ((Privilege != NULL) || (SystemAccess != NULL)){
  352. ASSERT(((Privilege == NULL) && (SystemAccess != NULL)) ||
  353. ((SystemAccess == NULL) && (Privilege != NULL)));
  354. //
  355. // Construct a path to the Privilgs attribute of the object relative to
  356. // the containing directory. This path has the form
  357. //
  358. // <Object Logical Name>"\Privilgs"
  359. //
  360. // The Logical Name of the object has just been returned by the
  361. // above call to RtlpNtEnumerateSubKey.
  362. //
  363. if (Privilege != NULL) {
  364. Status = LsapDbJoinSubPaths(
  365. &SubKeyNameU,
  366. &LsapDbNames[Privilgs],
  367. &RightKeyNameU
  368. );
  369. } else {
  370. Status = LsapDbJoinSubPaths(
  371. &SubKeyNameU,
  372. &LsapDbNames[ActSysAc],
  373. &RightKeyNameU
  374. );
  375. }
  376. if (!NT_SUCCESS(Status)) {
  377. goto FindNextError;
  378. }
  379. //
  380. // Setup object attributes for opening the privilege or access attribute
  381. //
  382. InitializeObjectAttributes(
  383. &ObjectAttributes,
  384. &RightKeyNameU,
  385. OBJ_CASE_INSENSITIVE,
  386. ContDirKeyHandle,
  387. NULL
  388. );
  389. //
  390. // Open the Sid attribute
  391. //
  392. Status = RtlpNtOpenKey(
  393. &RightKeyHandle,
  394. KEY_READ,
  395. &ObjectAttributes,
  396. 0
  397. );
  398. if (!NT_SUCCESS(Status)) {
  399. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  400. Status = STATUS_NOT_ALL_ASSIGNED;
  401. (*EnumerationContext)++;
  402. }
  403. SidKeyHandle = NULL;
  404. goto FindNextError;
  405. }
  406. //
  407. // Now query the size of the buffer required to read the Sid
  408. // attribute's value.
  409. //
  410. RightKeyValueLength = 0;
  411. Status = RtlpNtQueryValueKey(
  412. RightKeyHandle,
  413. NULL,
  414. NULL,
  415. &RightKeyValueLength,
  416. NULL
  417. );
  418. //
  419. // We expect buffer overflow to be returned from a query buffer size
  420. // call.
  421. //
  422. if (Status == STATUS_BUFFER_OVERFLOW) {
  423. Status = STATUS_SUCCESS;
  424. } else {
  425. goto FindNextError;
  426. }
  427. //
  428. // Allocate memory for reading the Privileges attribute.
  429. //
  430. ObjectRights = MIDL_user_allocate(RightKeyValueLength);
  431. if (ObjectRights == NULL) {
  432. Status = STATUS_INSUFFICIENT_RESOURCES;
  433. goto FindNextError;
  434. }
  435. //
  436. // Supplied buffer is large enough to hold the SubKey's value.
  437. // Query the value.
  438. //
  439. Status = RtlpNtQueryValueKey(
  440. RightKeyHandle,
  441. NULL,
  442. ObjectRights,
  443. &RightKeyValueLength,
  444. NULL
  445. );
  446. if (!NT_SUCCESS(Status)) {
  447. goto FindNextError;
  448. }
  449. //
  450. // Check for the system access or privilege specified
  451. //
  452. if (Privilege != NULL) {
  453. ObjectPrivileges = (PPRIVILEGE_SET) ObjectRights;
  454. for (Index = 0; Index < ObjectPrivileges->PrivilegeCount ; Index++) {
  455. if (RtlEqualLuid(&ObjectPrivileges->Privilege[Index].Luid, Privilege)) {
  456. ValidSid = TRUE;
  457. break;
  458. }
  459. }
  460. } else if (SystemAccess != NULL) {
  461. ObjectAccess = (PULONG) ObjectRights;
  462. if (((*ObjectAccess) & (*SystemAccess)) != 0) {
  463. ValidSid = TRUE;
  464. }
  465. }
  466. //
  467. // If this sid didn't meet the criteria, return now. Make sure
  468. // to bump up the context so we don't try this sid again.
  469. //
  470. if (!ValidSid) {
  471. Status = STATUS_NOT_ALL_ASSIGNED;
  472. (*EnumerationContext)++;
  473. goto FindNextFinish;
  474. }
  475. } // privilege != NULL || systemaccess != NULL
  476. //
  477. // Construct a path to the Sid attribute of the object relative to
  478. // the containing directory. This path has the form
  479. //
  480. // <Object Logical Name>"\Sid"
  481. //
  482. // The Logical Name of the object has just been returned by the
  483. // above call to RtlpNtEnumerateSubKey.
  484. //
  485. Status = LsapDbJoinSubPaths(
  486. &SubKeyNameU,
  487. &LsapDbNames[Sid],
  488. &SidKeyNameU
  489. );
  490. if (!NT_SUCCESS(Status)) {
  491. goto FindNextError;
  492. }
  493. //
  494. // Setup object attributes for opening the Sid attribute
  495. //
  496. InitializeObjectAttributes(
  497. &ObjectAttributes,
  498. &SidKeyNameU,
  499. OBJ_CASE_INSENSITIVE,
  500. ContDirKeyHandle,
  501. NULL
  502. );
  503. //
  504. // Open the Sid attribute
  505. //
  506. Status = RtlpNtOpenKey(
  507. &SidKeyHandle,
  508. KEY_READ,
  509. &ObjectAttributes,
  510. 0
  511. );
  512. if (!NT_SUCCESS(Status)) {
  513. SidKeyHandle = NULL;
  514. goto FindNextError;
  515. }
  516. //
  517. // Now query the size of the buffer required to read the Sid
  518. // attribute's value.
  519. //
  520. SidKeyValueLength = 0;
  521. Status = RtlpNtQueryValueKey(
  522. SidKeyHandle,
  523. NULL,
  524. NULL,
  525. &SidKeyValueLength,
  526. NULL
  527. );
  528. //
  529. // We expect buffer overflow to be returned from a query buffer size
  530. // call.
  531. //
  532. if (Status == STATUS_BUFFER_OVERFLOW) {
  533. Status = STATUS_SUCCESS;
  534. } else {
  535. goto FindNextError;
  536. }
  537. //
  538. // Allocate memory for reading the Sid attribute.
  539. //
  540. ObjectSid = MIDL_user_allocate(SidKeyValueLength);
  541. if (ObjectSid == NULL) {
  542. Status = STATUS_INSUFFICIENT_RESOURCES;
  543. goto FindNextError;
  544. }
  545. //
  546. // Supplied buffer is large enough to hold the SubKey's value.
  547. // Query the value.
  548. //
  549. Status = RtlpNtQueryValueKey(
  550. SidKeyHandle,
  551. NULL,
  552. ObjectSid,
  553. &SidKeyValueLength,
  554. NULL
  555. );
  556. if (!NT_SUCCESS(Status)) {
  557. goto FindNextError;
  558. }
  559. (*EnumerationContext)++;
  560. //
  561. // Return the Sid.
  562. //
  563. *NextSid = ObjectSid;
  564. FindNextFinish:
  565. //
  566. // Cleanup the rights check
  567. //
  568. if (RightKeyHandle != NULL) {
  569. SecondaryStatus = NtClose(RightKeyHandle);
  570. #if DBG
  571. if (!NT_SUCCESS(SecondaryStatus)) {
  572. DbgPrint("LsapDbFindNextSid: NtClose failed 0x%lx\n", Status);
  573. }
  574. #endif // DBG
  575. }
  576. if (ObjectRights != NULL) {
  577. MIDL_user_free(ObjectRights);
  578. }
  579. //
  580. // If necessary, close the Sid key handle
  581. //
  582. if (SidKeyHandle != NULL) {
  583. SecondaryStatus = NtClose(SidKeyHandle);
  584. #if DBG
  585. if (!NT_SUCCESS(SecondaryStatus)) {
  586. DbgPrint("LsapDbFindNextSid: NtClose failed 0x%lx\n", Status);
  587. }
  588. #endif // DBG
  589. }
  590. //
  591. // If necessary, close the containing directory handle
  592. //
  593. if (ContDirKeyHandle != NULL) {
  594. SecondaryStatus = NtClose(ContDirKeyHandle);
  595. #if DBG
  596. if (!NT_SUCCESS(SecondaryStatus)) {
  597. DbgPrint(
  598. "LsapDbFindNextSid: NtClose failed 0x%lx\n",
  599. Status
  600. );
  601. }
  602. #endif // DBG
  603. }
  604. //
  605. // If necessary, free the Unicode String buffer allocated by
  606. // LsapDbJoinSubPaths for the Registry key name of the Sid attribute
  607. // relative to the containing directory Registry key.
  608. //
  609. if (SidKeyNameU.Buffer != NULL) {
  610. RtlFreeUnicodeString( &SidKeyNameU );
  611. }
  612. //
  613. // If necessary, free the Unicode String buffer allocated for
  614. // Registry key name of the object relative to its containing
  615. // directory.
  616. //
  617. if (SubKeyNameU.Buffer != NULL) {
  618. LsapFreeLsaHeap( SubKeyNameU.Buffer );
  619. }
  620. if ( RightKeyNameU.Buffer != NULL) {
  621. LsapFreeLsaHeap( RightKeyNameU.Buffer );
  622. }
  623. return(Status);
  624. FindNextError:
  625. //
  626. // If necessary, free the memory allocated for the object's Sid.
  627. //
  628. if (ObjectSid != NULL) {
  629. MIDL_user_free(ObjectSid);
  630. *NextSid = NULL;
  631. }
  632. goto FindNextFinish;
  633. }
  634. NTSTATUS
  635. LsapDbEnumerateSidsWithRight(
  636. IN LSAPR_HANDLE ContainerHandle,
  637. IN OPTIONAL PLUID Privilege,
  638. IN OPTIONAL PULONG SystemAccess,
  639. OUT PLSAP_DB_SID_ENUMERATION_BUFFER DbEnumerationBuffer
  640. )
  641. /*++
  642. Routine Description:
  643. This function enumerates Sids of objects of a given type within a container
  644. object. Since there may be more information than can be returned in a
  645. single call of the routine, multiple calls can be made to get all of the
  646. information. To support this feature, the caller is provided with a
  647. handle that can be used across calls. On the initial call,
  648. EnumerationContext should point to a variable that has been initialized
  649. to 0.
  650. Arguments:
  651. ContainerHandle - Handle to a container object.
  652. Privilege - If present, specifies what privilege the account must have.
  653. SystemAccess - If present, specifies what access type the account must
  654. have. This cannot be present with Privilege.
  655. EnumerationContext - API-specific handle to allow multiple calls
  656. (see Routine Description above).
  657. DbEnumerationBuffer - Receives a pointer to a structure that will receive
  658. the count of entries returned in an enumeration information array, and
  659. a pointer to the array. Currently, the only information returned is
  660. the object Sids. These Sids may be used together with object type to
  661. open the objects and obtain any further information available.
  662. CountReturned - Pointer to variable which will receive a count of the
  663. entries returned.
  664. Return Values:
  665. NTSTATUS - Standard Nt Result Code
  666. STATUS_ACCESS_DENIED - Caller does not have the appropriate access
  667. to complete the operation.
  668. STATUS_NO_MORE_ENTRIES - There are no more entries. This warning
  669. is returned if no objects have been enumerated because the
  670. EnumerationContext value passed in is too high.
  671. --*/
  672. {
  673. NTSTATUS Status = STATUS_SUCCESS;
  674. LSAP_DB_ENUMERATION_ELEMENT LastElement;
  675. PLSAP_DB_ENUMERATION_ELEMENT FirstElement, NextElement = NULL, FreeElement;
  676. PSID *Sids = NULL;
  677. BOOLEAN PreferedMaximumReached = FALSE;
  678. ULONG EntriesRead;
  679. ULONG Index, EnumerationIndex;
  680. BOOLEAN TrustedClient = ((LSAP_DB_HANDLE) ContainerHandle)->Trusted;
  681. LastElement.Next = NULL;
  682. FirstElement = &LastElement;
  683. //
  684. // If no enumeration buffer provided, return an error.
  685. //
  686. if ( !ARGUMENT_PRESENT(DbEnumerationBuffer) ) {
  687. return(STATUS_INVALID_PARAMETER);
  688. }
  689. //
  690. // Enumerate objects, stopping when the length of data to be returned
  691. // reaches or exceeds the Prefered Maximum Length, or reaches the
  692. // absolute maximum allowed for LSA object enumerations. We allow
  693. // the last object enumerated to bring the total amount of data to
  694. // be returned beyond the Prefered Maximum Length, but not beyond the
  695. // absolute maximum length.
  696. //
  697. EnumerationIndex = 0;
  698. for (EntriesRead = 0;;) {
  699. //
  700. // Allocate memory for next enumeration element (if we haven't
  701. // already). Set the Sid field to NULL for cleanup purposes.
  702. //
  703. if (NextElement == NULL ) {
  704. NextElement = MIDL_user_allocate(sizeof (LSAP_DB_ENUMERATION_ELEMENT));
  705. if (NextElement == NULL) {
  706. Status = STATUS_INSUFFICIENT_RESOURCES;
  707. break;
  708. }
  709. }
  710. NextElement->Sid = NULL;
  711. //
  712. // Find the next object's Sid, and fill in its object information.
  713. // Note that memory will be allocated via MIDL_user_allocate
  714. // and must be freed when no longer required.
  715. //
  716. Status = LsapDbFindNextSidWithRight (
  717. ContainerHandle,
  718. &EnumerationIndex,
  719. Privilege,
  720. SystemAccess,
  721. (PLSAPR_SID *) &NextElement->Sid );
  722. //
  723. // Stop the enumeration if any error or warning occurs. Note
  724. // that the warning STATUS_NO_MORE_ENTRIES will be returned when
  725. // we've gone beyond the last index.
  726. //
  727. if (Status != STATUS_SUCCESS) {
  728. //
  729. // If it failed because it was missing the privilege, continue
  730. //
  731. if (Status == STATUS_NOT_ALL_ASSIGNED) {
  732. continue;
  733. }
  734. //
  735. // Since NextElement is not on the list, it will not get
  736. // freed at the end so we must free it here.
  737. //
  738. MIDL_user_free( NextElement );
  739. break;
  740. }
  741. //
  742. // Link the object just found to the front of the enumeration list
  743. //
  744. NextElement->Next = FirstElement;
  745. FirstElement = NextElement;
  746. NextElement = NULL;
  747. EntriesRead++;
  748. }
  749. //
  750. // If an error other than STATUS_NO_MORE_ENTRIES occurred, return it.
  751. // If STATUS_NO_MORE_ENTRIES was returned, we have enumerated all of the
  752. // entries. In this case, return STATUS_SUCCESS if we enumerated at
  753. // least one entry, otherwise propagate STATUS_NO_MORE_ENTRIES back to
  754. // the caller.
  755. //
  756. if (!NT_SUCCESS(Status)) {
  757. if (Status != STATUS_NO_MORE_ENTRIES) {
  758. goto EnumerateSidsError;
  759. }
  760. if (EntriesRead == 0) {
  761. goto EnumerateSidsError;
  762. }
  763. Status = STATUS_SUCCESS;
  764. }
  765. //
  766. // Some entries were read, allocate an information buffer for returning
  767. // them.
  768. //
  769. Sids = (PSID *) MIDL_user_allocate( sizeof (PSID) * EntriesRead );
  770. if (Sids == NULL) {
  771. Status = STATUS_INSUFFICIENT_RESOURCES;
  772. goto EnumerateSidsError;
  773. }
  774. //
  775. // Memory was successfully allocated for the return buffer.
  776. // Copy in the enumerated Sids.
  777. //
  778. for (NextElement = FirstElement, Index = 0;
  779. NextElement != &LastElement;
  780. NextElement = NextElement->Next, Index++) {
  781. ASSERT(Index < EntriesRead);
  782. Sids[Index] = NextElement->Sid;
  783. }
  784. EnumerateSidsFinish:
  785. //
  786. // Free the enumeration element structures (if any).
  787. //
  788. for (NextElement = FirstElement; NextElement != &LastElement;) {
  789. //
  790. // If an error has occurred, dispose of memory allocated
  791. // for any Sids.
  792. //
  793. if (!(NT_SUCCESS(Status) || (Status == STATUS_NO_MORE_ENTRIES))) {
  794. if (NextElement->Sid != NULL) {
  795. MIDL_user_free(NextElement->Sid);
  796. }
  797. }
  798. //
  799. // Free the memory allocated for the enumeration element.
  800. //
  801. FreeElement = NextElement;
  802. NextElement = NextElement->Next;
  803. MIDL_user_free(FreeElement);
  804. }
  805. //
  806. // Fill in return enumeration structure (0 and NULL in error case).
  807. //
  808. DbEnumerationBuffer->EntriesRead = EntriesRead;
  809. DbEnumerationBuffer->Sids = Sids;
  810. return(Status);
  811. EnumerateSidsError:
  812. //
  813. // If necessary, free memory allocated for returning the Sids.
  814. //
  815. if (Sids != NULL) {
  816. MIDL_user_free( Sids );
  817. Sids = NULL;
  818. }
  819. goto EnumerateSidsFinish;
  820. }
  821. NTSTATUS
  822. LsarEnumerateAccountsWithUserRight(
  823. IN LSAPR_HANDLE PolicyHandle,
  824. IN OPTIONAL PLSAPR_UNICODE_STRING UserRight,
  825. OUT PLSAPR_ACCOUNT_ENUM_BUFFER EnumerationBuffer
  826. )
  827. /*++
  828. Routine Description:
  829. This function is the LSA server RPC worker routine for the
  830. LsaEnumerateAccountsWithUserRight API.
  831. The LsaEnumerateAccounts API returns information about the accounts
  832. in the target system's Lsa Database. This call requires
  833. POLICY_VIEW_LOCAL_INFORMATION access to the Policy object. Since this call
  834. accesses the privileges of an account, you must have PRIVILEGE_VIEW
  835. access to the pseudo-privilege object.
  836. Arguments:
  837. PolicyHandle - Handle from an LsaOpenPolicy call.
  838. UserRight - Name of the right that the account must have.
  839. EnumerationBuffer - Pointer to an enumeration structure that will receive
  840. a count of the accounts enumerated on this call and a pointer to
  841. an array of entries containing information for each enumerated
  842. account.
  843. Return Values:
  844. NTSTATUS - Standard Nt Result Code
  845. STATUS_ACCESS_DENIED - Caller does not have the appropriate access
  846. to complete the operation.
  847. STATUS_NO_MORE_ENTRIES - There are no more entries. This warning
  848. is returned if no objects are enumerated because the
  849. EnumerationContext value passed in is too high.
  850. --*/
  851. {
  852. NTSTATUS Status;
  853. LSAP_DB_SID_ENUMERATION_BUFFER DbEnumerationBuffer;
  854. ULONG MaxLength;
  855. ULONG Index;
  856. ULONG SystemAccess = 0;
  857. LUID PrivilegeValue;
  858. PLUID Privilege = NULL;
  859. PULONG Access = NULL;
  860. ACCESS_MASK GrantedAccess;
  861. NTSTATUS AccessStatus;
  862. BOOLEAN GenerateOnClose;
  863. LsarpReturnCheckSetup();
  864. //
  865. // If no Enumeration Structure or index is provided or we got a badly formatted argument,
  866. // return an error.
  867. //
  868. if ( !ARGUMENT_PRESENT(EnumerationBuffer) || !LsapValidateLsaUnicodeString( UserRight ) ) {
  869. return(STATUS_INVALID_PARAMETER);
  870. }
  871. //
  872. // Initialize the internal Lsa Database Enumeration Buffer, and
  873. // the provided Enumeration Buffer to NULL.
  874. //
  875. DbEnumerationBuffer.EntriesRead = 0;
  876. DbEnumerationBuffer.Sids = NULL;
  877. EnumerationBuffer->EntriesRead = 0;
  878. EnumerationBuffer->Information = NULL;
  879. //
  880. // Acquire the Lsa Database lock. Verify that the connection handle is
  881. // valid, is of the expected type and has all of the desired accesses
  882. // granted. Reference the handle.
  883. //
  884. Status = LsapDbReferenceObject(
  885. PolicyHandle,
  886. POLICY_VIEW_LOCAL_INFORMATION,
  887. PolicyObject,
  888. AccountObject,
  889. LSAP_DB_LOCK
  890. );
  891. if (!NT_SUCCESS(Status)) {
  892. return(Status);
  893. }
  894. //
  895. // Impersonate the caller
  896. //
  897. Status = I_RpcMapWin32Status(RpcImpersonateClient(0));
  898. if (!NT_SUCCESS(Status) ) {
  899. goto Cleanup;
  900. }
  901. //
  902. // Do an access check on with the UserRight security descriptor.
  903. //
  904. Status = NtAccessCheckAndAuditAlarm(
  905. &LsapState.SubsystemName,
  906. PolicyHandle,
  907. &UserRightTypeName,
  908. &UserRightTypeName,
  909. UserRightSD,
  910. PRIVILEGE_VIEW,
  911. &UserRightGenericMapping,
  912. FALSE,
  913. &GrantedAccess,
  914. &AccessStatus,
  915. &GenerateOnClose
  916. );
  917. (VOID) RpcRevertToSelf();
  918. //
  919. // Check both error codes
  920. //
  921. if (!NT_SUCCESS(Status) ) {
  922. goto Cleanup;
  923. }
  924. Status = AccessStatus;
  925. if (!NT_SUCCESS(Status)) {
  926. goto Cleanup;
  927. }
  928. //
  929. // If a right was specified, translate it to a privilege or a
  930. // system access type.
  931. //
  932. if (UserRight != NULL && UserRight->Buffer != NULL ) {
  933. //
  934. // Convert the user right string into a privilege or a system
  935. // access flag.
  936. //
  937. for (Index = 0; Index < LSAP_DB_SYSTEM_ACCESS_TYPES; Index++ ) {
  938. if (RtlEqualUnicodeString(
  939. &LsapDbRightAndAccess[Index].UserRight,
  940. (PUNICODE_STRING) UserRight,
  941. TRUE ) ) { // case insensitive
  942. SystemAccess = LsapDbRightAndAccess[Index].SystemAccess;
  943. Access = &SystemAccess;
  944. break;
  945. }
  946. }
  947. //
  948. // If system access is zero, try looking up the privilege name.
  949. //
  950. if (Access == NULL) {
  951. Status = LsarLookupPrivilegeValue(
  952. PolicyHandle,
  953. (PLSAPR_UNICODE_STRING) UserRight,
  954. &PrivilegeValue
  955. );
  956. if (!NT_SUCCESS(Status)) {
  957. goto Cleanup;
  958. }
  959. Privilege = &PrivilegeValue;
  960. }
  961. }
  962. //
  963. // Call general Sid enumeration routine.
  964. //
  965. Status = LsapDbEnumerateSidsWithRight(
  966. PolicyHandle,
  967. Privilege,
  968. Access,
  969. &DbEnumerationBuffer
  970. );
  971. //
  972. // Copy the enumerated information to the output. We can use the
  973. // information actually returned by LsapDbEnumerateSids because it
  974. // happens to be in exactly the correct form.
  975. //
  976. EnumerationBuffer->EntriesRead = DbEnumerationBuffer.EntriesRead;
  977. EnumerationBuffer->Information =
  978. (PLSAPR_ACCOUNT_INFORMATION) DbEnumerationBuffer.Sids;
  979. Cleanup:
  980. Status = LsapDbDereferenceObject(
  981. &PolicyHandle,
  982. PolicyObject,
  983. AccountObject,
  984. LSAP_DB_LOCK,
  985. (SECURITY_DB_DELTA_TYPE) 0,
  986. Status
  987. );
  988. LsarpReturnPrologue();
  989. return(Status);
  990. }
  991. NTSTATUS
  992. LsarEnumerateAccountRights(
  993. IN LSAPR_HANDLE PolicyHandle,
  994. IN PLSAPR_SID AccountSid,
  995. OUT PLSAPR_USER_RIGHT_SET UserRights
  996. )
  997. /*++
  998. Routine Description:
  999. Returns all the rights of an account. This is done by gathering the
  1000. privileges and system access of an account and translating that into
  1001. an array of strings.
  1002. Arguments:
  1003. PolicyHandle - Handle from an LsaOpenPolicyCall. This API requires
  1004. no special access.
  1005. AccountSid - Sid of account to open.
  1006. UserRights - receives an array of user rights for the account
  1007. Return Value:
  1008. STATUS_ACCESS_DENIED - the caller did not have sufficient access to
  1009. return the privileges or system access of the account.
  1010. STATUS_OBJECT_NAME_NOT_FOUND - the specified account did not exist.
  1011. STATUS_INSUFFICIENT_RESOURCES - not enough memory to process the
  1012. request.
  1013. --*/
  1014. {
  1015. NTSTATUS Status;
  1016. LSAPR_HANDLE AccountHandle = NULL;
  1017. PLSAPR_PRIVILEGE_SET PrivilegeSet = NULL;
  1018. ULONG SystemAccess;
  1019. ULONG UserRightCount = 0;
  1020. ULONG UserRightIndex;
  1021. ULONG PrivilegeIndex;
  1022. PUNICODE_STRING UserRightArray = NULL;
  1023. PUNICODE_STRING TempString;
  1024. LsarpReturnCheckSetup();
  1025. //
  1026. // Open the account for ACCOUNT_VIEW access
  1027. //
  1028. Status = LsarOpenAccount(
  1029. PolicyHandle,
  1030. AccountSid,
  1031. ACCOUNT_VIEW,
  1032. &AccountHandle
  1033. );
  1034. if (!NT_SUCCESS(Status)) {
  1035. return(Status);
  1036. }
  1037. //
  1038. // Get the system access flags
  1039. //
  1040. Status = LsarGetSystemAccessAccount(
  1041. AccountHandle,
  1042. &SystemAccess
  1043. );
  1044. if (!NT_SUCCESS(Status)) {
  1045. goto Cleanup;
  1046. }
  1047. //
  1048. // Get the privilege information
  1049. //
  1050. Status = LsarEnumeratePrivilegesAccount(
  1051. AccountHandle,
  1052. &PrivilegeSet
  1053. );
  1054. if (!NT_SUCCESS(Status)) {
  1055. goto Cleanup;
  1056. }
  1057. //
  1058. // Repackage the privileges and system access as user rights
  1059. //
  1060. UserRightCount = 0;
  1061. for (PrivilegeIndex = 0;
  1062. PrivilegeIndex < LSAP_DB_SYSTEM_ACCESS_TYPES;
  1063. PrivilegeIndex++ ) {
  1064. if ((SystemAccess & LsapDbRightAndAccess[PrivilegeIndex].SystemAccess) != 0 ) {
  1065. UserRightCount++;
  1066. }
  1067. }
  1068. UserRightCount += PrivilegeSet->PrivilegeCount;
  1069. //
  1070. // If there were no rights, say that and cleanup.
  1071. //
  1072. if (UserRightCount == 0) {
  1073. UserRights->Entries = 0;
  1074. UserRights->UserRights = NULL;
  1075. Status = STATUS_SUCCESS;
  1076. goto Cleanup;
  1077. }
  1078. UserRightArray = (PUNICODE_STRING)
  1079. MIDL_user_allocate(UserRightCount * sizeof(LSAPR_UNICODE_STRING));
  1080. if (UserRightArray == NULL) {
  1081. Status = STATUS_INSUFFICIENT_RESOURCES;
  1082. goto Cleanup;
  1083. }
  1084. //
  1085. // Zero this in case we have to clean it up partially.
  1086. //
  1087. RtlZeroMemory(
  1088. UserRightArray,
  1089. UserRightCount * sizeof(LSAPR_UNICODE_STRING)
  1090. );
  1091. UserRightIndex = 0;
  1092. for (PrivilegeIndex = 0;
  1093. PrivilegeIndex < PrivilegeSet->PrivilegeCount ;
  1094. PrivilegeIndex++ ) {
  1095. TempString = NULL;
  1096. Status = LsarLookupPrivilegeName(
  1097. PolicyHandle,
  1098. (PLUID) &PrivilegeSet->Privilege[PrivilegeIndex].Luid,
  1099. (PLSAPR_UNICODE_STRING *) &TempString
  1100. );
  1101. if (!NT_SUCCESS(Status)) {
  1102. goto Cleanup;
  1103. }
  1104. //
  1105. // The name that came back was allocated in two parts, the buffer
  1106. // and the string. Copy the buffer pointer to the return array
  1107. // and free the string structure.
  1108. //
  1109. UserRightArray[UserRightIndex++] = * TempString;
  1110. MIDL_user_free(TempString);
  1111. }
  1112. //
  1113. // Copy in the system access rights
  1114. for (PrivilegeIndex = 0;
  1115. PrivilegeIndex < LSAP_DB_SYSTEM_ACCESS_TYPES;
  1116. PrivilegeIndex++ ) {
  1117. if ((SystemAccess & LsapDbRightAndAccess[PrivilegeIndex].SystemAccess) != 0 ) {
  1118. //
  1119. // Allocate a new string and copy the access name into it.
  1120. //
  1121. UserRightArray[UserRightIndex] = LsapDbRightAndAccess[PrivilegeIndex].UserRight;
  1122. UserRightArray[UserRightIndex].Buffer = (LPWSTR)
  1123. MIDL_user_allocate(LsapDbRightAndAccess[PrivilegeIndex].UserRight.MaximumLength);
  1124. if (UserRightArray[UserRightIndex].Buffer == NULL ) {
  1125. Status = STATUS_INSUFFICIENT_RESOURCES;
  1126. goto Cleanup;
  1127. }
  1128. RtlCopyUnicodeString(
  1129. (PUNICODE_STRING) &UserRightArray[UserRightIndex],
  1130. &LsapDbRightAndAccess[PrivilegeIndex].UserRight
  1131. );
  1132. UserRightIndex++;
  1133. }
  1134. }
  1135. ASSERT(UserRightCount == UserRightIndex);
  1136. UserRights->Entries = UserRightCount;
  1137. UserRights->UserRights = (PLSAPR_UNICODE_STRING) UserRightArray;
  1138. Status = STATUS_SUCCESS;
  1139. Cleanup:
  1140. //
  1141. // Cleanup the system rights if we failed
  1142. //
  1143. if (!NT_SUCCESS(Status)) {
  1144. if (UserRightArray != NULL) {
  1145. for (UserRightIndex = 0;
  1146. UserRightIndex < UserRightCount ;
  1147. UserRightIndex++) {
  1148. if (UserRightArray[UserRightIndex].Buffer != NULL) {
  1149. MIDL_user_free(UserRightArray[UserRightIndex].Buffer);
  1150. }
  1151. }
  1152. }
  1153. }
  1154. if (AccountHandle != NULL) {
  1155. LsapCloseHandle(&AccountHandle, Status);
  1156. }
  1157. if (PrivilegeSet != NULL) {
  1158. MIDL_user_free(PrivilegeSet);
  1159. }
  1160. LsarpReturnPrologue();
  1161. return(Status);
  1162. }
  1163. NTSTATUS
  1164. LsapDbConvertRightsToPrivileges(
  1165. IN PLSAPR_HANDLE PolicyHandle,
  1166. IN PLSAPR_USER_RIGHT_SET UserRights,
  1167. OUT PLSAPR_PRIVILEGE_SET * PrivilegeSet,
  1168. OUT PULONG SystemAccess
  1169. )
  1170. /*++
  1171. Routine Description:
  1172. Converts an array of user right strings into a privilege set and a
  1173. system access flag.
  1174. Arguments:
  1175. UserRights - Contains an array of strings and a count of those strings.
  1176. PrivilegeSet - receives a privilege set of those rights corresponding
  1177. to privilges, allocated with MIDL_user_allocate.
  1178. SystemAccess - receives the access flags specified by the user rights
  1179. Return Value:
  1180. STATUS_NO_SUCH_PRIVILEGE - the user right could not be converted into
  1181. a privilege or an access type.
  1182. STATUS_INSUFFICIENT_RESOURCES - there was not enough memory to translate
  1183. the rights to privileges.
  1184. --*/
  1185. {
  1186. ULONG PrivilegeCount;
  1187. PLSAPR_PRIVILEGE_SET Privileges = NULL;
  1188. ULONG Access = 0;
  1189. ULONG PrivilegeSetSize;
  1190. ULONG PrivilegeIndex = 0;
  1191. ULONG RightIndex;
  1192. ULONG AccessIndex;
  1193. NTSTATUS Status;
  1194. PrivilegeSetSize = sizeof(LSAPR_PRIVILEGE_SET) +
  1195. (UserRights->Entries-1) * sizeof(LUID_AND_ATTRIBUTES);
  1196. Privileges = (PLSAPR_PRIVILEGE_SET) MIDL_user_allocate(PrivilegeSetSize);
  1197. if (Privileges == NULL) {
  1198. return(STATUS_INSUFFICIENT_RESOURCES);
  1199. }
  1200. for (RightIndex = 0;
  1201. RightIndex < UserRights->Entries;
  1202. RightIndex++ ) {
  1203. //
  1204. // First try to map the right as a privilege
  1205. //
  1206. if (NT_SUCCESS(LsarLookupPrivilegeValue(
  1207. PolicyHandle,
  1208. (PLSAPR_UNICODE_STRING) &UserRights->UserRights[RightIndex],
  1209. (PLUID) &Privileges->Privilege[PrivilegeIndex].Luid))) {
  1210. Privileges->Privilege[PrivilegeIndex].Attributes = 0;
  1211. PrivilegeIndex++;
  1212. } else {
  1213. //
  1214. // Try to map it to a system access type
  1215. //
  1216. for (AccessIndex = 0;
  1217. AccessIndex < LSAP_DB_SYSTEM_ACCESS_TYPES;
  1218. AccessIndex++ ) {
  1219. if (RtlEqualUnicodeString(
  1220. &LsapDbRightAndAccess[AccessIndex].UserRight,
  1221. (PUNICODE_STRING) &UserRights->UserRights[RightIndex],
  1222. FALSE) ) { // case sensistive
  1223. Access |= LsapDbRightAndAccess[AccessIndex].SystemAccess;
  1224. break;
  1225. }
  1226. }
  1227. if (AccessIndex == LSAP_DB_SYSTEM_ACCESS_TYPES) {
  1228. Status = STATUS_NO_SUCH_PRIVILEGE;
  1229. goto Cleanup;
  1230. }
  1231. }
  1232. }
  1233. Privileges->PrivilegeCount = PrivilegeIndex;
  1234. *PrivilegeSet = Privileges;
  1235. Privileges = NULL;
  1236. *SystemAccess = Access;
  1237. Status = STATUS_SUCCESS;
  1238. Cleanup:
  1239. if (Privileges != NULL) {
  1240. MIDL_user_free(Privileges);
  1241. }
  1242. return(Status);
  1243. }
  1244. NTSTATUS
  1245. LsarAddAccountRights(
  1246. IN LSAPR_HANDLE PolicyHandle,
  1247. IN PLSAPR_SID AccountSid,
  1248. IN PLSAPR_USER_RIGHT_SET UserRights
  1249. )
  1250. /*++
  1251. Routine Description:
  1252. Adds rights to the account specified by the account sid. If the account
  1253. does not exist, it creates the account.
  1254. Arguments:
  1255. PolicyHandle - Handle from an LsaOpenPolicy call. The handle must have
  1256. POLICY_CREATE_ACCOUNT access if this is the first call for this
  1257. AccountSid.
  1258. AccountSid - Sid of account to add rights to
  1259. UserRights - Array of unicode strings naming rights to add to the
  1260. account.
  1261. Return Value:
  1262. STATUS_INSUFFICIENT_RESOURCES - not enough memory to process the request
  1263. STATUS_INVALID_PARAMTER - one of the parameters was not present
  1264. STATUS_NO_SUCH_PRIVILEGE - One of the user rights was invalid
  1265. STATUS_ACCESS_DENIED - the caller does not have sufficient access to the
  1266. account to add privileges.
  1267. --*/
  1268. {
  1269. NTSTATUS Status = STATUS_SUCCESS;
  1270. LSAPR_HANDLE AccountHandle = NULL;
  1271. PLSAPR_PRIVILEGE_SET PrivilegeSet = NULL;
  1272. ULONG SystemAccess = 0;
  1273. ULONG OldSystemAccess = 0 ;
  1274. BOOLEAN ChangedAccess = FALSE;
  1275. LSAP_DB_HANDLE InternalHandle = ( LSAP_DB_HANDLE )PolicyHandle;
  1276. BOOLEAN ScePolicyLocked = FALSE;
  1277. LsarpReturnCheckSetup();
  1278. //
  1279. // Make sure we have all the arguments we need
  1280. //
  1281. if (!ARGUMENT_PRESENT(UserRights)) {
  1282. return(STATUS_INVALID_PARAMETER);
  1283. }
  1284. if (!ARGUMENT_PRESENT(AccountSid)) {
  1285. return(STATUS_INVALID_PARAMETER);
  1286. }
  1287. //
  1288. // Do not grab the SCE policy lock for handles opened as SCE policy handles
  1289. //
  1290. if ( !InternalHandle->SceHandle ) {
  1291. RtlEnterCriticalSection( &LsapDbState.ScePolicyLock.CriticalSection );
  1292. if ( LsapDbState.ScePolicyLock.NumberOfWaitingShared > MAX_SCE_WAITING_SHARED ) {
  1293. Status = STATUS_TOO_MANY_THREADS;
  1294. }
  1295. RtlLeaveCriticalSection( &LsapDbState.ScePolicyLock.CriticalSection );
  1296. if ( !NT_SUCCESS( Status )) {
  1297. goto Cleanup;
  1298. }
  1299. WaitForSingleObject( LsapDbState.SceSyncEvent, INFINITE );
  1300. RtlAcquireResourceShared( &LsapDbState.ScePolicyLock, TRUE );
  1301. ASSERT( !g_ScePolicyLocked );
  1302. ScePolicyLocked = TRUE;
  1303. }
  1304. //
  1305. // Open the account for ACCOUNT_VIEW access
  1306. //
  1307. Status = LsarOpenAccount(
  1308. PolicyHandle,
  1309. AccountSid,
  1310. ACCOUNT_ADJUST_PRIVILEGES | ACCOUNT_ADJUST_SYSTEM_ACCESS | ACCOUNT_VIEW,
  1311. &AccountHandle
  1312. );
  1313. //
  1314. // If the account did not exist, try to create it.
  1315. //
  1316. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1317. Status = LsarCreateAccount(
  1318. PolicyHandle,
  1319. AccountSid,
  1320. ACCOUNT_ADJUST_PRIVILEGES | ACCOUNT_ADJUST_SYSTEM_ACCESS | ACCOUNT_VIEW,
  1321. &AccountHandle
  1322. );
  1323. }
  1324. if ( NT_SUCCESS(Status)) {
  1325. Status = LsapDbConvertRightsToPrivileges(
  1326. PolicyHandle,
  1327. UserRights,
  1328. &PrivilegeSet,
  1329. &SystemAccess
  1330. );
  1331. }
  1332. if (!NT_SUCCESS(Status) ) {
  1333. goto Cleanup;
  1334. }
  1335. //
  1336. // If system access was changed, add it
  1337. //
  1338. if (SystemAccess != 0) {
  1339. Status = LsarGetSystemAccessAccount(
  1340. AccountHandle,
  1341. &OldSystemAccess
  1342. );
  1343. if (!NT_SUCCESS(Status)) {
  1344. goto Cleanup;
  1345. }
  1346. if ( SystemAccess != OldSystemAccess ) {
  1347. SystemAccess = SystemAccess | OldSystemAccess;
  1348. Status = LsapSetSystemAccessAccount(
  1349. AccountHandle,
  1350. SystemAccess,
  1351. FALSE
  1352. );
  1353. if ( !NT_SUCCESS( Status )) {
  1354. goto Cleanup;
  1355. }
  1356. ChangedAccess = TRUE;
  1357. }
  1358. }
  1359. //
  1360. // If privileges were changed, add them.
  1361. //
  1362. if (PrivilegeSet->PrivilegeCount != 0) {
  1363. Status = LsapAddPrivilegesToAccount(
  1364. AccountHandle,
  1365. PrivilegeSet,
  1366. FALSE
  1367. );
  1368. }
  1369. Cleanup:
  1370. //
  1371. // NOTE: we do NOT generate an SCE notification here, because
  1372. // one would already be sent through LsapSetSystemAccessAccount
  1373. // or LsapAddPrivilegesToAccount
  1374. //
  1375. //
  1376. // If we didn't make both changes, unroll the one we did
  1377. //
  1378. if (!NT_SUCCESS(Status) && ChangedAccess) {
  1379. //
  1380. // Ignore the error code since this is a last-ditch effort
  1381. //
  1382. (void) LsapSetSystemAccessAccount(
  1383. AccountHandle,
  1384. OldSystemAccess,
  1385. FALSE
  1386. );
  1387. }
  1388. if (PrivilegeSet != NULL) {
  1389. MIDL_user_free(PrivilegeSet);
  1390. }
  1391. if (AccountHandle != NULL) {
  1392. LsapCloseHandle(&AccountHandle, Status);
  1393. }
  1394. if ( ScePolicyLocked ) {
  1395. RtlReleaseResource( &LsapDbState.ScePolicyLock );
  1396. }
  1397. LsarpReturnPrologue();
  1398. return(Status);
  1399. }
  1400. NTSTATUS
  1401. LsarRemoveAccountRights(
  1402. IN LSAPR_HANDLE PolicyHandle,
  1403. IN PLSAPR_SID AccountSid,
  1404. IN BOOLEAN AllRights,
  1405. IN PLSAPR_USER_RIGHT_SET UserRights
  1406. )
  1407. /*++
  1408. Routine Description:
  1409. Removes rights to the account specified by the account sid. If the
  1410. AllRights flag is set or if all the rights are removed, the account
  1411. is deleted.
  1412. Arguments:
  1413. PolicyHandle - Handle from an LsaOpenPolicy call
  1414. AccountSid - Sid of account to remove rights from
  1415. AllRights - if TRUE, the account will be deleted
  1416. UserRights - Array of unicode strings naming rights to remove from the
  1417. account.
  1418. Return Value:
  1419. STATUS_INSUFFICIENT_RESOURCES - not enough memory to process the request
  1420. STATUS_INVALID_PARAMTER - one of the parameters was not present
  1421. STATUS_NO_SUCH_PRIVILEGE - One of the user rights was invalid
  1422. STATUS_ACCESS_DENIED - the caller does not have sufficient access to the
  1423. account to add privileges.
  1424. --*/
  1425. {
  1426. NTSTATUS Status = STATUS_SUCCESS;
  1427. LSAPR_HANDLE AccountHandle = NULL;
  1428. PLSAPR_PRIVILEGE_SET PrivilegeSet = NULL;
  1429. ULONG SystemAccess;
  1430. ULONG OldSystemAccess = 0;
  1431. BOOLEAN ChangedAccess = FALSE;
  1432. PLSAPR_PRIVILEGE_SET FinalPrivilegeSet = NULL;
  1433. LSAP_DB_HANDLE InternalHandle = ( LSAP_DB_HANDLE )PolicyHandle;
  1434. BOOLEAN ScePolicyLocked = FALSE;
  1435. LsarpReturnCheckSetup();
  1436. //
  1437. // Do not grab the SCE policy lock for handles opened as SCE policy handles
  1438. //
  1439. if ( !InternalHandle->SceHandle ) {
  1440. RtlEnterCriticalSection( &LsapDbState.ScePolicyLock.CriticalSection );
  1441. if ( LsapDbState.ScePolicyLock.NumberOfWaitingShared > MAX_SCE_WAITING_SHARED ) {
  1442. Status = STATUS_TOO_MANY_THREADS;
  1443. }
  1444. RtlLeaveCriticalSection( &LsapDbState.ScePolicyLock.CriticalSection );
  1445. if ( !NT_SUCCESS( Status )) {
  1446. goto Cleanup;
  1447. }
  1448. WaitForSingleObject( LsapDbState.SceSyncEvent, INFINITE );
  1449. RtlAcquireResourceShared( &LsapDbState.ScePolicyLock, TRUE );
  1450. ASSERT( !g_ScePolicyLocked );
  1451. ScePolicyLocked = TRUE;
  1452. }
  1453. //
  1454. // Open the account for ACCOUNT_VIEW access
  1455. //
  1456. Status = LsarOpenAccount(
  1457. PolicyHandle,
  1458. AccountSid,
  1459. ACCOUNT_ADJUST_PRIVILEGES |
  1460. ACCOUNT_ADJUST_SYSTEM_ACCESS |
  1461. ACCOUNT_VIEW |
  1462. DELETE,
  1463. &AccountHandle
  1464. );
  1465. if (!NT_SUCCESS(Status)) {
  1466. goto Cleanup;
  1467. }
  1468. //
  1469. // Convert the rights to privileges only if they don't want all
  1470. // rights removed. In that case, we don't care.
  1471. //
  1472. if (AllRights == FALSE) {
  1473. Status = LsapDbConvertRightsToPrivileges(
  1474. PolicyHandle,
  1475. UserRights,
  1476. &PrivilegeSet,
  1477. &SystemAccess
  1478. );
  1479. if (!NT_SUCCESS(Status) ) {
  1480. goto Cleanup;
  1481. }
  1482. } else {
  1483. Status = LsapDeleteObject(
  1484. &AccountHandle,
  1485. FALSE
  1486. );
  1487. ASSERT( AccountHandle == NULL );
  1488. goto Cleanup;
  1489. }
  1490. //
  1491. // If system access was changed, add it
  1492. //
  1493. Status = LsarGetSystemAccessAccount(
  1494. AccountHandle,
  1495. &OldSystemAccess
  1496. );
  1497. if (!NT_SUCCESS(Status)) {
  1498. goto Cleanup;
  1499. }
  1500. //
  1501. // After this block of code, SystemAccess should contain the final
  1502. // access for the account.
  1503. //
  1504. if (SystemAccess != 0) {
  1505. SystemAccess = OldSystemAccess & ~SystemAccess;
  1506. Status = LsapSetSystemAccessAccount(
  1507. AccountHandle,
  1508. SystemAccess,
  1509. FALSE
  1510. );
  1511. if (!NT_SUCCESS(Status)) {
  1512. goto Cleanup;
  1513. }
  1514. ChangedAccess = TRUE;
  1515. } else {
  1516. SystemAccess = OldSystemAccess;
  1517. }
  1518. //
  1519. // If privileges were changed, add them.
  1520. //
  1521. if (AllRights || PrivilegeSet->PrivilegeCount != 0) {
  1522. Status = LsapRemovePrivilegesFromAccount(
  1523. AccountHandle,
  1524. FALSE, // don't remove all rights
  1525. PrivilegeSet,
  1526. FALSE
  1527. );
  1528. }
  1529. //
  1530. // Check to see if all the privileges have been removed - if so,
  1531. // and system access is 0, delete the account.
  1532. //
  1533. Status = LsarEnumeratePrivilegesAccount(
  1534. AccountHandle,
  1535. &FinalPrivilegeSet
  1536. );
  1537. if (!NT_SUCCESS(Status)) {
  1538. goto Cleanup;
  1539. }
  1540. //
  1541. if ((FinalPrivilegeSet->PrivilegeCount == 0) &&
  1542. (SystemAccess == 0)) {
  1543. //
  1544. // The account has no privileges or system access - delete it.
  1545. //
  1546. Status = LsapDeleteObject(
  1547. &AccountHandle,
  1548. FALSE
  1549. );
  1550. ASSERT( AccountHandle == NULL );
  1551. }
  1552. Cleanup:
  1553. MIDL_user_free( FinalPrivilegeSet );
  1554. //
  1555. // NOTE: we do NOT generate an SCE notification here, because
  1556. // one would already be sent through LsapSetSystemAccessAccount,
  1557. // LsapAddPrivilegesToAccount or LsapDeleteObject
  1558. //
  1559. //
  1560. // If we didn't make both changes, unroll the one we did
  1561. //
  1562. if ( !NT_SUCCESS( Status ) && ChangedAccess ) {
  1563. NTSTATUS LocalStatus = STATUS_SUCCESS;
  1564. if ( AccountHandle == NULL ) {
  1565. //
  1566. // We probably failed to delete the object, so reopen
  1567. // the handle and attempt to restore the old account rights
  1568. //
  1569. LocalStatus = LsarOpenAccount(
  1570. PolicyHandle,
  1571. AccountSid,
  1572. ACCOUNT_ADJUST_PRIVILEGES |
  1573. ACCOUNT_ADJUST_SYSTEM_ACCESS |
  1574. ACCOUNT_VIEW,
  1575. &AccountHandle
  1576. );
  1577. }
  1578. if ( NT_SUCCESS( LocalStatus )) {
  1579. //
  1580. // Ignore the error code since this is a last-ditch effort
  1581. //
  1582. (void) LsapSetSystemAccessAccount(
  1583. AccountHandle,
  1584. OldSystemAccess,
  1585. FALSE
  1586. );
  1587. }
  1588. }
  1589. if (PrivilegeSet != NULL) {
  1590. MIDL_user_free(PrivilegeSet);
  1591. }
  1592. if (AccountHandle != NULL) {
  1593. LsapCloseHandle(&AccountHandle, Status);
  1594. }
  1595. if ( ScePolicyLocked ) {
  1596. RtlReleaseResource( &LsapDbState.ScePolicyLock );
  1597. }
  1598. LsarpReturnPrologue();
  1599. return(Status);
  1600. }
  1601. NTSTATUS
  1602. LsarQueryTrustedDomainInfo(
  1603. IN LSAPR_HANDLE PolicyHandle,
  1604. IN PLSAPR_SID TrustedDomainSid,
  1605. IN TRUSTED_INFORMATION_CLASS InformationClass,
  1606. IN PLSAPR_TRUSTED_DOMAIN_INFO * TrustedDomainInformation
  1607. )
  1608. /*++
  1609. Routine Description:
  1610. This function is the LSA server RPC worker routine for the
  1611. LsaQueryInfoTrustedDomain API.
  1612. The LsaQueryInfoTrustedDomain API obtains information from a
  1613. TrustedDomain object. The caller must have access appropriate to the
  1614. information being requested (see InformationClass parameter). It also
  1615. may query the secret object (for the TrustedDomainPasswordInformation
  1616. class).
  1617. Arguments:
  1618. PolicyHandle - Handle from an LsaOpenPolicy call.
  1619. TrustedDomainSid - Sid of domain to query.
  1620. InformationClass - Specifies the information to be returned.
  1621. Buffer - Receives a pointer to the buffer returned comtaining the
  1622. requested information. This buffer is allocated by this service
  1623. and must be freed when no longer needed by passing the returned
  1624. value to LsaFreeMemory().
  1625. Return Value:
  1626. NTSTATUS - Standard Nt Result Code
  1627. STATUS_ACCESS_DENIED - Caller does not have the appropriate
  1628. access to complete the operation.
  1629. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  1630. such as memory, to complete the call.
  1631. --*/
  1632. {
  1633. LSAPR_HANDLE DomainHandle = NULL;
  1634. LSAPR_HANDLE SecretHandle = NULL;
  1635. NTSTATUS Status;
  1636. PLSAPR_TRUSTED_DOMAIN_INFO DomainInfo = NULL;
  1637. PLSAPR_TRUSTED_PASSWORD_INFO PasswordInfo = NULL;
  1638. TRUSTED_INFORMATION_CLASS ClassToUse;
  1639. ULONG DesiredAccess;
  1640. BOOLEAN QueryPassword = FALSE;
  1641. UNICODE_STRING SecretName;
  1642. PLSAPR_CR_CIPHER_VALUE Password = NULL;
  1643. PLSAPR_CR_CIPHER_VALUE OldPassword = NULL;
  1644. LsarpReturnCheckSetup();
  1645. SecretName.Buffer = NULL;
  1646. ClassToUse = InformationClass;
  1647. switch(InformationClass) {
  1648. case TrustedPasswordInformation:
  1649. QueryPassword = TRUE;
  1650. ClassToUse = TrustedDomainNameInformation;
  1651. break;
  1652. case TrustedControllersInformation:
  1653. //
  1654. // This info class is obsolete
  1655. //
  1656. return(STATUS_NOT_IMPLEMENTED);
  1657. }
  1658. //
  1659. // Validate the Information Class and determine the access required to
  1660. // query this Trusted Domain Information Class.
  1661. //
  1662. Status = LsapDbVerifyInfoQueryTrustedDomain(
  1663. ClassToUse,
  1664. FALSE,
  1665. &DesiredAccess
  1666. );
  1667. if (!NT_SUCCESS(Status)) {
  1668. goto Cleanup;
  1669. }
  1670. Status = LsarOpenTrustedDomain(
  1671. PolicyHandle,
  1672. TrustedDomainSid,
  1673. DesiredAccess,
  1674. &DomainHandle
  1675. );
  1676. if (!NT_SUCCESS(Status)) {
  1677. goto Cleanup;
  1678. }
  1679. Status = LsarQueryInfoTrustedDomain(
  1680. DomainHandle,
  1681. ClassToUse,
  1682. &DomainInfo
  1683. );
  1684. if ( !NT_SUCCESS( Status ))
  1685. {
  1686. goto Cleanup;
  1687. }
  1688. //
  1689. // If the info we wanted was what we queried, cleanup now.
  1690. //
  1691. if (!QueryPassword) {
  1692. *TrustedDomainInformation = DomainInfo;
  1693. DomainInfo = NULL;
  1694. goto Cleanup;
  1695. }
  1696. //
  1697. // Build the secret name for the domain.
  1698. //
  1699. //
  1700. // Build the secret name
  1701. //
  1702. SecretName.Length = DomainInfo->TrustedDomainNameInfo.Name.Length;
  1703. SecretName.Length += (LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX_LENGTH) * sizeof(WCHAR);
  1704. SecretName.MaximumLength = SecretName.Length + sizeof(WCHAR);
  1705. SecretName.Buffer = (LPWSTR) MIDL_user_allocate(SecretName.MaximumLength);
  1706. if (SecretName.Buffer == NULL) {
  1707. Status = STATUS_INSUFFICIENT_RESOURCES;
  1708. goto Cleanup;
  1709. }
  1710. RtlCopyMemory(
  1711. SecretName.Buffer,
  1712. LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX,
  1713. LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX_LENGTH * sizeof(WCHAR)
  1714. );
  1715. RtlCopyMemory(
  1716. SecretName.Buffer + LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX_LENGTH,
  1717. DomainInfo->TrustedDomainNameInfo.Name.Buffer,
  1718. DomainInfo->TrustedDomainNameInfo.Name.MaximumLength
  1719. );
  1720. //
  1721. // Free the domain info so we can re-use it lower down
  1722. //
  1723. LsaIFree_LSAPR_TRUSTED_DOMAIN_INFO(
  1724. TrustedDomainNameInformation,
  1725. DomainInfo
  1726. );
  1727. DomainInfo = NULL;
  1728. //
  1729. // Now try to open the secret
  1730. //
  1731. Status = LsarOpenSecret(
  1732. PolicyHandle,
  1733. (PLSAPR_UNICODE_STRING) &SecretName,
  1734. SECRET_QUERY_VALUE,
  1735. &SecretHandle
  1736. );
  1737. if (!NT_SUCCESS(Status)) {
  1738. goto Cleanup;
  1739. }
  1740. Status = LsarQuerySecret(
  1741. SecretHandle,
  1742. &Password,
  1743. NULL,
  1744. &OldPassword,
  1745. NULL
  1746. );
  1747. if (!NT_SUCCESS(Status)) {
  1748. goto Cleanup;
  1749. }
  1750. //
  1751. // Build a new domain info with the secret information
  1752. //
  1753. DomainInfo = (PLSAPR_TRUSTED_DOMAIN_INFO)
  1754. MIDL_user_allocate(sizeof(LSAPR_TRUSTED_DOMAIN_INFO));
  1755. if (DomainInfo == NULL) {
  1756. Status = STATUS_INSUFFICIENT_RESOURCES;
  1757. goto Cleanup;
  1758. }
  1759. DomainInfo->TrustedPasswordInfo.Password = Password;
  1760. DomainInfo->TrustedPasswordInfo.OldPassword = OldPassword;
  1761. Password = NULL;
  1762. OldPassword = NULL;
  1763. *TrustedDomainInformation = DomainInfo;
  1764. DomainInfo = NULL;
  1765. Status = STATUS_SUCCESS;
  1766. Cleanup:
  1767. if (SecretName.Buffer != NULL) {
  1768. MIDL_user_free(SecretName.Buffer);
  1769. }
  1770. if (DomainHandle != NULL) {
  1771. LsapCloseHandle(&DomainHandle, Status);
  1772. }
  1773. if (SecretHandle != NULL) {
  1774. LsapCloseHandle(&SecretHandle, Status);
  1775. }
  1776. if (DomainInfo != NULL) {
  1777. LsaIFree_LSAPR_TRUSTED_DOMAIN_INFO(
  1778. ClassToUse,
  1779. DomainInfo
  1780. );
  1781. }
  1782. if (Password != NULL) {
  1783. LsaIFree_LSAPR_CR_CIPHER_VALUE(Password);
  1784. }
  1785. if (OldPassword != NULL) {
  1786. LsaIFree_LSAPR_CR_CIPHER_VALUE(OldPassword);
  1787. }
  1788. LsarpReturnPrologue();
  1789. return(Status);
  1790. }
  1791. NTSTATUS
  1792. LsarSetTrustedDomainInfo(
  1793. IN LSAPR_HANDLE PolicyHandle,
  1794. IN PLSAPR_SID TrustedDomainSid,
  1795. IN TRUSTED_INFORMATION_CLASS InformationClass,
  1796. IN PLSAPR_TRUSTED_DOMAIN_INFO TrustedDomainInformation
  1797. )
  1798. /*++
  1799. Routine Description:
  1800. This function is the LSA server RPC worker routine for the
  1801. LsaSetInfoTrustedDomain API.
  1802. The LsaSetInformationTrustedDomain API modifies information in the Trusted
  1803. Domain Object and in the Secret Object. The caller must have access
  1804. appropriate to the information to be changed in the Policy Object, see
  1805. the InformationClass parameter.
  1806. If the domain does not yet exist and the information class is
  1807. TrustedDomainNameInformation, then the domain is created. If the
  1808. domain exists and the class is TrustedDomainNameInformation, an
  1809. error is returned.
  1810. Arguments:
  1811. PolicyHandle - Handle from an LsaOpenPolicy call.
  1812. TrustedDomainSid - Sid of domain to modify.
  1813. InformationClass - Specifies the type of information being changed.
  1814. The information types and accesses required to change them are as
  1815. follows:
  1816. TrustedDomainNameInformation POLICY_TRUST_ADMIN
  1817. TrustedPosixOffsetInformation none
  1818. TrustedPasswordInformation POLICY_CREATE_SECRET
  1819. TrustedDomainNameInformationEx POLICY_TRUST_ADMIN
  1820. Buffer - Points to a structure containing the information appropriate
  1821. to the InformationClass parameter.
  1822. Return Value:
  1823. NTSTATUS - Standard Nt Result Code
  1824. STATUS_ACCESS_DENIED - Caller does not have the appropriate access
  1825. to complete the operation.
  1826. Others TBS
  1827. --*/
  1828. {
  1829. LSAPR_HANDLE DomainHandle = NULL;
  1830. LSAPR_HANDLE SecretHandle = NULL;
  1831. PLSAPR_TRUSTED_DOMAIN_INFO DomainInfo = NULL;
  1832. PTRUSTED_DOMAIN_FULL_INFORMATION CurrentTrustedDomainFullInfo = NULL;
  1833. UNICODE_STRING SecretName;
  1834. NTSTATUS Status = STATUS_SUCCESS;
  1835. LsarpReturnCheckSetup();
  1836. SecretName.Buffer = NULL;
  1837. //
  1838. // If the class is domain name, try to create the domain since you
  1839. // can't change the name of an existing domain.
  1840. //
  1841. if (InformationClass == TrustedDomainNameInformation) {
  1842. LSAPR_TRUST_INFORMATION TrustInformation;
  1843. //
  1844. // Try to create the domain if we have the name information
  1845. //
  1846. TrustInformation.Name = TrustedDomainInformation->TrustedDomainNameInfo.Name;
  1847. TrustInformation.Sid = TrustedDomainSid;
  1848. Status = LsarCreateTrustedDomain(
  1849. PolicyHandle,
  1850. &TrustInformation,
  1851. 0, // desired access
  1852. &DomainHandle
  1853. );
  1854. //
  1855. // Grab a copy of the current information on the object for auditing
  1856. // purposes if auditing is enabled.
  1857. //
  1858. if ( NT_SUCCESS( Status ) &&
  1859. LsapAdtAuditingEnabledHint(AuditCategoryPolicyChange, EVENTLOG_AUDIT_SUCCESS)) {
  1860. BOOLEAN SavedTrusted;
  1861. SavedTrusted = ((LSAP_DB_HANDLE) DomainHandle)->Trusted;
  1862. ((LSAP_DB_HANDLE) DomainHandle)->Trusted = TRUE;
  1863. Status = LsarQueryInfoTrustedDomain( DomainHandle,
  1864. TrustedDomainFullInformation,
  1865. (PLSAPR_TRUSTED_DOMAIN_INFO *)
  1866. &CurrentTrustedDomainFullInfo );
  1867. ((LSAP_DB_HANDLE) DomainHandle)->Trusted = SavedTrusted;
  1868. if ( !NT_SUCCESS( Status ) ) {
  1869. goto Cleanup;
  1870. }
  1871. }
  1872. goto Cleanup;
  1873. }
  1874. if ( InformationClass == TrustedDomainInformationEx ) {
  1875. //
  1876. // Create the domain trusted doman
  1877. // First, try to open the domain. If it fails, we'll create it
  1878. //
  1879. Status = LsarOpenTrustedDomain( PolicyHandle,
  1880. TrustedDomainSid,
  1881. 0,
  1882. &DomainHandle );
  1883. if ( Status == STATUS_OBJECT_PATH_NOT_FOUND ) {
  1884. Status = LsapCreateTrustedDomain2(
  1885. PolicyHandle,
  1886. (PLSAPR_TRUSTED_DOMAIN_INFORMATION_EX)TrustedDomainInformation,
  1887. NULL,
  1888. 0, // Desired access
  1889. &DomainHandle
  1890. );
  1891. } else if ( NT_SUCCESS( Status ) ) {
  1892. Status = LsarSetInformationTrustedDomain( DomainHandle,
  1893. InformationClass,
  1894. TrustedDomainInformation );
  1895. }
  1896. goto Cleanup;
  1897. }
  1898. if (InformationClass == TrustedPosixOffsetInformation) {
  1899. //
  1900. // For posix information, we just do the normal set information
  1901. //
  1902. Status = LsarOpenTrustedDomain(
  1903. PolicyHandle,
  1904. TrustedDomainSid,
  1905. TRUSTED_SET_POSIX,
  1906. &DomainHandle
  1907. );
  1908. if (!NT_SUCCESS(Status)) {
  1909. goto Cleanup;
  1910. }
  1911. Status = LsarSetInformationTrustedDomain(
  1912. DomainHandle,
  1913. InformationClass,
  1914. TrustedDomainInformation
  1915. );
  1916. goto Cleanup;
  1917. }
  1918. if (InformationClass != TrustedPasswordInformation) {
  1919. Status = STATUS_INVALID_PARAMETER;
  1920. goto Cleanup;
  1921. }
  1922. //
  1923. // For posix information, we just do the normal set information
  1924. //
  1925. Status = LsarOpenTrustedDomain(
  1926. PolicyHandle,
  1927. TrustedDomainSid,
  1928. TRUSTED_QUERY_DOMAIN_NAME,
  1929. &DomainHandle
  1930. );
  1931. if (!NT_SUCCESS(Status)) {
  1932. goto Cleanup;
  1933. }
  1934. //
  1935. // Query the name of the domain so we know what secret to set
  1936. //
  1937. Status = LsarQueryInfoTrustedDomain(
  1938. DomainHandle,
  1939. TrustedDomainNameInformation,
  1940. &DomainInfo
  1941. );
  1942. if (!NT_SUCCESS(Status)) {
  1943. goto Cleanup;
  1944. }
  1945. //
  1946. // Build the secret name
  1947. //
  1948. SecretName.Length = DomainInfo->TrustedDomainNameInfo.Name.Length;
  1949. SecretName.Length += (LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX_LENGTH) * sizeof(WCHAR);
  1950. SecretName.MaximumLength = SecretName.Length + sizeof(WCHAR);
  1951. SecretName.Buffer = (LPWSTR) MIDL_user_allocate(SecretName.MaximumLength);
  1952. if (SecretName.Buffer == NULL) {
  1953. Status = STATUS_INSUFFICIENT_RESOURCES;
  1954. goto Cleanup;
  1955. }
  1956. RtlCopyMemory(
  1957. SecretName.Buffer,
  1958. LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX,
  1959. LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX_LENGTH * sizeof(WCHAR)
  1960. );
  1961. RtlCopyMemory(
  1962. SecretName.Buffer + LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX_LENGTH,
  1963. DomainInfo->TrustedDomainNameInfo.Name.Buffer,
  1964. DomainInfo->TrustedDomainNameInfo.Name.MaximumLength
  1965. );
  1966. //
  1967. // Open the secret. If that fails, try to create it.
  1968. //
  1969. Status = LsarOpenSecret(
  1970. PolicyHandle,
  1971. (PLSAPR_UNICODE_STRING) &SecretName,
  1972. SECRET_SET_VALUE,
  1973. &SecretHandle
  1974. );
  1975. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1976. Status = LsarCreateSecret(
  1977. PolicyHandle,
  1978. (PLSAPR_UNICODE_STRING) &SecretName,
  1979. SECRET_SET_VALUE,
  1980. &SecretHandle
  1981. );
  1982. }
  1983. if (!NT_SUCCESS(Status)) {
  1984. goto Cleanup;
  1985. }
  1986. Status = LsarSetSecret(
  1987. SecretHandle,
  1988. TrustedDomainInformation->TrustedPasswordInfo.Password,
  1989. TrustedDomainInformation->TrustedPasswordInfo.OldPassword
  1990. );
  1991. Cleanup:
  1992. if (NT_SUCCESS(Status)) {
  1993. //
  1994. // TrustedDomainInformationEx and TrustedPosixOffsetInformation
  1995. // are audited in LsarSetInformationTrustedDomain.
  1996. //
  1997. //
  1998. // ISSUE-2000/08/09-kumarp : audit TrustedPasswordInformation change?
  1999. //
  2000. if ((InformationClass == TrustedDomainNameInformation) &&
  2001. LsapAdtAuditingEnabledHint(AuditCategoryPolicyChange, EVENTLOG_AUDIT_SUCCESS)) {
  2002. //
  2003. // generate the audit.
  2004. // since TrustedDomainNameInformation changes only the name,
  2005. // don't bother passing the trust type, direction, attributes
  2006. // just pass 0, 0, 0 for them
  2007. //
  2008. (void) LsapAdtTrustedDomainMod(
  2009. EVENTLOG_AUDIT_SUCCESS,
  2010. CurrentTrustedDomainFullInfo->Information.Sid,
  2011. (PUNICODE_STRING) &DomainInfo->TrustedDomainNameInfo.Name,
  2012. 0, 0, 0, // trust type, direction, attributes
  2013. (PUNICODE_STRING) &TrustedDomainInformation->TrustedDomainNameInfo.Name,
  2014. 0, 0, 0 // trust type, direction, attributes
  2015. );
  2016. }
  2017. }
  2018. if ( CurrentTrustedDomainFullInfo != NULL ) {
  2019. LsaIFree_LSAPR_TRUSTED_DOMAIN_INFO(
  2020. TrustedDomainFullInformation,
  2021. (PLSAPR_TRUSTED_DOMAIN_INFO) CurrentTrustedDomainFullInfo );
  2022. }
  2023. if (SecretName.Buffer != NULL) {
  2024. MIDL_user_free(SecretName.Buffer);
  2025. }
  2026. if (DomainInfo != NULL) {
  2027. LsaIFree_LSAPR_TRUSTED_DOMAIN_INFO(
  2028. TrustedDomainNameInformation,
  2029. DomainInfo
  2030. );
  2031. }
  2032. if (DomainHandle != NULL) {
  2033. LsapCloseHandle(&DomainHandle, Status);
  2034. }
  2035. if (SecretHandle != NULL) {
  2036. LsapCloseHandle(&SecretHandle, Status);
  2037. }
  2038. LsarpReturnPrologue();
  2039. return(Status);
  2040. }
  2041. NTSTATUS
  2042. LsarDeleteTrustedDomain(
  2043. IN LSAPR_HANDLE PolicyHandle,
  2044. IN PLSAPR_SID TrustedDomainSid
  2045. )
  2046. /*++
  2047. Routine Description:
  2048. This routine deletes a trusted domain and the associated secret.
  2049. Arguments:
  2050. PolicyHandle - Handle from an LsaOpenPolicy call.
  2051. TrustedDomainSid - Sid of domain to delete
  2052. Return Value:
  2053. STATUS_ACCESS_DENIED - caller has insufficient access to delete
  2054. the requested domain.
  2055. STATUS_OBJECT_NAME_NOT_FOUND - The requested domain does not exist.
  2056. --*/
  2057. {
  2058. LSAPR_HANDLE DomainHandle = NULL;
  2059. LSAPR_HANDLE SecretHandle = NULL;
  2060. UNICODE_STRING SecretName;
  2061. PLSAPR_TRUSTED_DOMAIN_INFO DomainInfo = NULL;
  2062. NTSTATUS Status;
  2063. LsarpReturnCheckSetup();
  2064. SecretName.Buffer = NULL;
  2065. //
  2066. // Open the domain so we can find its name (to delete the secret)
  2067. // and then delete it.
  2068. //
  2069. Status = LsarOpenTrustedDomain(
  2070. PolicyHandle,
  2071. TrustedDomainSid,
  2072. TRUSTED_QUERY_DOMAIN_NAME | DELETE,
  2073. &DomainHandle
  2074. );
  2075. if (!NT_SUCCESS(Status)) {
  2076. goto Cleanup;
  2077. }
  2078. //
  2079. // Query the domain name so we can delete the secret
  2080. //
  2081. Status = LsarQueryInfoTrustedDomain(
  2082. DomainHandle,
  2083. TrustedDomainNameInformation,
  2084. &DomainInfo
  2085. );
  2086. if (!NT_SUCCESS(Status)) {
  2087. goto Cleanup;
  2088. }
  2089. //
  2090. // Build the secret name
  2091. //
  2092. SecretName.Length = DomainInfo->TrustedDomainNameInfo.Name.Length;
  2093. SecretName.Length += (LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX_LENGTH) * sizeof(WCHAR);
  2094. SecretName.MaximumLength = SecretName.Length + sizeof(WCHAR);
  2095. SecretName.Buffer = (LPWSTR) MIDL_user_allocate(SecretName.MaximumLength);
  2096. if (SecretName.Buffer == NULL) {
  2097. Status = STATUS_INSUFFICIENT_RESOURCES;
  2098. goto Cleanup;
  2099. }
  2100. RtlCopyMemory(
  2101. SecretName.Buffer,
  2102. LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX,
  2103. LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX_LENGTH * sizeof(WCHAR)
  2104. );
  2105. RtlCopyMemory(
  2106. SecretName.Buffer + LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX_LENGTH,
  2107. DomainInfo->TrustedDomainNameInfo.Name.Buffer,
  2108. DomainInfo->TrustedDomainNameInfo.Name.MaximumLength
  2109. );
  2110. //
  2111. // Delete the domain
  2112. //
  2113. Status = LsarDeleteObject(&DomainHandle);
  2114. if (Status != STATUS_SUCCESS) {
  2115. goto Cleanup;
  2116. }
  2117. //
  2118. // Since we successfully deleted the secret, set it to zero so we don't
  2119. // try to close it later.
  2120. //
  2121. DomainHandle = NULL;
  2122. //
  2123. // Now try to open the secret and delete it.
  2124. //
  2125. Status = LsarOpenSecret(
  2126. PolicyHandle,
  2127. (PLSAPR_UNICODE_STRING) &SecretName,
  2128. DELETE,
  2129. &SecretHandle
  2130. );
  2131. if (!NT_SUCCESS(Status)) {
  2132. //
  2133. // If the secret does not exist, that just means that the password
  2134. // was never set.
  2135. //
  2136. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  2137. Status = STATUS_SUCCESS;
  2138. }
  2139. goto Cleanup;
  2140. }
  2141. Status = LsarDeleteObject(&SecretHandle);
  2142. //
  2143. // If we successfully deleted the secret, set it to zero so we don't
  2144. // try to close it later.
  2145. //
  2146. if (NT_SUCCESS(Status)) {
  2147. SecretHandle = NULL;
  2148. }
  2149. Cleanup:
  2150. if (SecretHandle != NULL) {
  2151. LsapCloseHandle(&SecretHandle, Status);
  2152. }
  2153. if (DomainHandle != NULL) {
  2154. LsapCloseHandle(&DomainHandle, Status);
  2155. }
  2156. if (DomainInfo != NULL) {
  2157. LsaIFree_LSAPR_TRUSTED_DOMAIN_INFO(
  2158. TrustedDomainNameInformation,
  2159. DomainInfo
  2160. );
  2161. }
  2162. if (SecretName.Buffer != NULL) {
  2163. MIDL_user_free(SecretName.Buffer);
  2164. }
  2165. LsarpReturnPrologue();
  2166. return(Status);
  2167. }
  2168. NTSTATUS
  2169. LsarStorePrivateData(
  2170. IN LSAPR_HANDLE PolicyHandle,
  2171. IN PLSAPR_UNICODE_STRING KeyName,
  2172. IN OPTIONAL PLSAPR_CR_CIPHER_VALUE EncryptedData
  2173. )
  2174. /*++
  2175. Routine Description:
  2176. This routine stores a secret under the name KeyName. If the password
  2177. is not present, the secret is deleted
  2178. Arguments:
  2179. PolicyHandle - Handle from an LsaOpenPolicyCall. If this is the
  2180. first call, it requres POLICY_CREATE_SECRET access.
  2181. KeyName - Name to store the secret under.
  2182. EncryptedData - private data encrypted with session key.
  2183. Return Value:
  2184. STATUS_ACCESS_DENIED - caller has insufficient privilege to set
  2185. the workstation password.
  2186. STATUS_INVALID_PARAMETER - A badly formatted KeyName parameter was given
  2187. --*/
  2188. {
  2189. LSAPR_HANDLE SecretHandle = NULL;
  2190. NTSTATUS Status;
  2191. ULONG DesiredAccess;
  2192. BOOLEAN DeletePassword = FALSE;
  2193. LsarpReturnCheckSetup();
  2194. //
  2195. // Validate the input buffer
  2196. //
  2197. if ( !LsapValidateLsaUnicodeString( KeyName ) ) {
  2198. Status = STATUS_INVALID_PARAMETER;
  2199. goto Cleanup;
  2200. }
  2201. if (ARGUMENT_PRESENT(EncryptedData)) {
  2202. DesiredAccess = SECRET_SET_VALUE;
  2203. } else {
  2204. DesiredAccess = DELETE;
  2205. DeletePassword = TRUE;
  2206. }
  2207. Status = LsarOpenSecret(
  2208. PolicyHandle,
  2209. KeyName,
  2210. DesiredAccess,
  2211. &SecretHandle
  2212. );
  2213. //
  2214. // If the secret didn't exist, and we aren't trying to delete it, create it.
  2215. //
  2216. if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) &&
  2217. (!DeletePassword)) {
  2218. Status = LsarCreateSecret(
  2219. PolicyHandle,
  2220. KeyName,
  2221. SECRET_SET_VALUE,
  2222. &SecretHandle
  2223. );
  2224. }
  2225. if (!NT_SUCCESS(Status)) {
  2226. goto Cleanup;
  2227. }
  2228. if (DeletePassword) {
  2229. Status = LsarDeleteObject(&SecretHandle);
  2230. //
  2231. // If we succeeded, zero the handle so we don't try to close
  2232. // it later.
  2233. //
  2234. if (NT_SUCCESS(Status)) {
  2235. SecretHandle = NULL;
  2236. }
  2237. } else {
  2238. Status = LsarSetSecret(
  2239. SecretHandle,
  2240. EncryptedData,
  2241. NULL
  2242. );
  2243. }
  2244. Cleanup:
  2245. if (SecretHandle != NULL ) {
  2246. LsapCloseHandle(&SecretHandle, Status);
  2247. }
  2248. LsarpReturnPrologue();
  2249. return(Status);
  2250. }
  2251. NTSTATUS
  2252. LsarRetrievePrivateData(
  2253. IN LSAPR_HANDLE PolicyHandle,
  2254. IN PLSAPR_UNICODE_STRING KeyName,
  2255. IN OUT PLSAPR_CR_CIPHER_VALUE *EncryptedData
  2256. )
  2257. /*++
  2258. Routine Description:
  2259. This routine returns the workstation password stored in the
  2260. KeyName secret.
  2261. Arguments:
  2262. PolicyHandle - Handle from an LsaOpenPolicyCall
  2263. KeyName - Name of secret to retrieve
  2264. EncryptedData - Receives data encrypted with session key
  2265. Return Value:
  2266. STATUS_ACCESS_DENIED - caller has insufficient access to get the
  2267. workstation password.
  2268. STATUS_OBJECT_NAME_NOT_FOUND - there is no workstation password.
  2269. STATUS_INVALID_PARAMETER - A badly formmated KeyName was given
  2270. --*/
  2271. {
  2272. LSAPR_HANDLE SecretHandle = NULL;
  2273. NTSTATUS Status;
  2274. LsarpReturnCheckSetup();
  2275. //
  2276. // Validate the input buffer
  2277. //
  2278. if ( !LsapValidateLsaUnicodeString( KeyName ) ) {
  2279. Status = STATUS_INVALID_PARAMETER;
  2280. goto Cleanup;
  2281. }
  2282. Status = LsarOpenSecret(
  2283. PolicyHandle,
  2284. KeyName,
  2285. SECRET_QUERY_VALUE,
  2286. &SecretHandle
  2287. );
  2288. if (!NT_SUCCESS(Status)) {
  2289. goto Cleanup;
  2290. }
  2291. Status = LsarQuerySecret(
  2292. SecretHandle,
  2293. EncryptedData,
  2294. NULL,
  2295. NULL,
  2296. NULL
  2297. );
  2298. Cleanup:
  2299. if (SecretHandle != NULL ) {
  2300. LsapCloseHandle(&SecretHandle, Status);
  2301. }
  2302. LsarpReturnPrologue();
  2303. return(Status);
  2304. }