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.

1161 lines
26 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. lsaprtl.c
  5. Abstract:
  6. Local Security Authority - Temporary Rtl Routine Definitions.
  7. This file contains routines used in the LSA that could be made into Rtl
  8. routines. They have been written in general purpose form with this in
  9. mind - the only exception to thisa is that their names have Lsap prefixes
  10. to indicate that they are currently used only by the LSA.
  11. Author:
  12. Scott Birrell (ScottBi) April 8, 1992
  13. Environment:
  14. Revision History:
  15. --*/
  16. #include <lsacomp.h>
  17. #include <align.h>
  18. BOOLEAN
  19. LsapRtlPrefixSid(
  20. IN PSID PrefixSid,
  21. IN PSID Sid
  22. )
  23. /*++
  24. Routine Description:
  25. This function checks if one Sid is the Prefix Sid of another.
  26. Arguments:
  27. PrefixSid - Pointer to Prefix Sid.
  28. Sid - Pointer to Sid to be checked.
  29. Return Values:
  30. BOOLEAN - TRUE if PrefixSid is the Prefix Sid of Sid, else FALSE.
  31. --*/
  32. {
  33. BOOLEAN BooleanStatus = FALSE;
  34. if ((*RtlSubAuthorityCountSid(Sid)) > 0) {
  35. //
  36. // Decrement the SubAuthorityCount of Sid temporarily.
  37. //
  38. (*RtlSubAuthorityCountSid(Sid))--;
  39. //
  40. // Compare the Prefix Sid with the modified Sid.
  41. //
  42. BooleanStatus = RtlEqualSid( PrefixSid, Sid);
  43. //
  44. // Restore the original SubAuthorityCount.
  45. //
  46. (*RtlSubAuthorityCountSid(Sid))++;
  47. }
  48. return(BooleanStatus);
  49. }
  50. BOOLEAN
  51. LsapRtlPrefixName(
  52. IN PUNICODE_STRING PrefixName,
  53. IN PUNICODE_STRING Name
  54. )
  55. /*++
  56. Routine Description:
  57. This function checks if a Name has the given name as a Prefix
  58. Arguments:
  59. PrefixName - Pointer to Prefix Name.
  60. Name - Pointer to Name to be checked.
  61. Return Values:
  62. BOOLEAN - TRUE if the Name is composite (i.e. contains a "\") and
  63. PrefixName is the Prefix part of Name, else FALSE.
  64. --*/
  65. {
  66. UNICODE_STRING TruncatedName = *Name;
  67. if ((PrefixName->Length < Name->Length) &&
  68. Name->Buffer[PrefixName->Length / 2] == L'\\') {
  69. TruncatedName.Length = PrefixName->Length;
  70. if (RtlEqualUnicodeString(PrefixName, &TruncatedName, FALSE)) {
  71. return(TRUE);
  72. }
  73. }
  74. return(FALSE);
  75. }
  76. VOID
  77. LsapRtlSplitNames(
  78. IN PUNICODE_STRING Names,
  79. IN ULONG Count,
  80. IN PUNICODE_STRING Separator,
  81. OUT PUNICODE_STRING PrefixNames,
  82. OUT PUNICODE_STRING SuffixNames
  83. )
  84. /*++
  85. Routine Description:
  86. This function splits an array of Names into Prefix and Suffix parts
  87. separated by the given separator. The input array may contain names of
  88. the following form:
  89. <SuffixName>
  90. <PrefixName> "\" <SuffixName>
  91. The NULL string
  92. Note that the output arrays will reference the original name strings.
  93. No copying is done.
  94. Arguments:
  95. Names - Pointer to array of Unicode Names.
  96. Count - Count of Names in Names.
  97. PrefixNames - Pointer to an array of Count Unicode String structures
  98. that will be initialized to point to the Prefix portions of the
  99. Names.
  100. SuffixNames - Pointer to an array of Count Unicode String structures
  101. that will be initialized to point to the Suffix portions of the
  102. Names.
  103. Return Values:
  104. None.
  105. --*/
  106. {
  107. ULONG Index;
  108. LONG SeparatorOffset;
  109. LONG WideSeparatorOffset;
  110. //
  111. // Scan each name, initializing the output Unicode structures.
  112. //
  113. for (Index = 0; Index < Count; Index++) {
  114. PrefixNames[Index] = Names[Index];
  115. SuffixNames[Index] = Names[Index];
  116. //
  117. // Locate the separator "\" if any.
  118. //
  119. SeparatorOffset = LsapRtlFindCharacterInUnicodeString(
  120. &Names[Index],
  121. Separator,
  122. FALSE
  123. );
  124. //
  125. // If there is a separator, make the Prefix Name point to the
  126. // part of the name before the separator and make the Suffix Name
  127. // point to the part of the name after the separator. If there
  128. // is no separator, set the Prefix Name part to Null. Rememeber
  129. // that the Length fields are byte counts, not Wide Character
  130. // counts.
  131. //
  132. if (SeparatorOffset >= 0) {
  133. WideSeparatorOffset = (SeparatorOffset / sizeof(WCHAR));
  134. PrefixNames[Index].Length = (USHORT) SeparatorOffset;
  135. SuffixNames[Index].Buffer += (WideSeparatorOffset + 1);
  136. SuffixNames[Index].Length -= (USHORT)(SeparatorOffset + sizeof(WCHAR));
  137. } else {
  138. WideSeparatorOffset = SeparatorOffset;
  139. PrefixNames[Index].Length = 0;
  140. }
  141. //
  142. // Set MaximumLengths equal to Lengths and, for safety, clear buffer
  143. // pointers(s) to NULL in output strings if Length(s) are 0.
  144. //
  145. PrefixNames[Index].MaximumLength = PrefixNames[Index].Length;
  146. SuffixNames[Index].MaximumLength = SuffixNames[Index].Length;
  147. if (PrefixNames[Index].Length == 0) {
  148. PrefixNames[Index].Buffer = NULL;
  149. }
  150. if (SuffixNames[Index].Length == 0) {
  151. SuffixNames[Index].Buffer = NULL;
  152. }
  153. }
  154. }
  155. LONG
  156. LsapRtlFindCharacterInUnicodeString(
  157. IN PUNICODE_STRING InputString,
  158. IN PUNICODE_STRING Character,
  159. IN BOOLEAN CaseInsensitive
  160. )
  161. /*++
  162. Routine Description:
  163. This function returns the byte offset of the first occurrence (if any) of
  164. a Unicode Character within a Unicode String.
  165. Arguments
  166. InputString - Pointer to Unicode String to be searched.
  167. Character - Pointer to Unicode String initialized to character
  168. to be searched for.
  169. CaseInsensitive - TRUE if case is to be ignored, else FALSE.
  170. NOTE - Only FALSE is supported just now.
  171. Return Value:
  172. LONG - If the character is present within the string, its non-negative
  173. byte offset is returned. If the character is not present within
  174. the string, a negative value is returned.
  175. --*/
  176. {
  177. BOOLEAN CharacterFound = FALSE;
  178. ULONG Offset = 0;
  179. if (!CaseInsensitive) {
  180. Offset = 0;
  181. while (Offset < InputString->Length) {
  182. if (*(Character->Buffer) ==
  183. InputString->Buffer[Offset / sizeof (WCHAR)]) {
  184. CharacterFound = TRUE;
  185. break;
  186. }
  187. Offset += 2;
  188. }
  189. } else {
  190. //
  191. // Case Insensitive is not supported
  192. //
  193. CharacterFound = FALSE;
  194. }
  195. if (!CharacterFound) {
  196. Offset = LSA_UNKNOWN_ID;
  197. }
  198. return(Offset);
  199. }
  200. VOID
  201. LsapRtlSetSecurityAccessMask(
  202. IN SECURITY_INFORMATION SecurityInformation,
  203. OUT PACCESS_MASK DesiredAccess
  204. )
  205. /*++
  206. Routine Description:
  207. NOTE! THIS ROUTINE IS IDENTICAL WITH SeSetSecurityAccessMask()
  208. IN \nt\private\ntos\se\semethod.c
  209. This routine builds an access mask representing the accesses necessary
  210. to set the object security information specified in the SecurityInformation
  211. parameter. While it is not difficult to determine this information,
  212. the use of a single routine to generate it will ensure minimal impact
  213. when the security information associated with an object is extended in
  214. the future (to include mandatory access control information).
  215. Arguments:
  216. SecurityInformation - Identifies the object's security information to be
  217. modified.
  218. DesiredAccess - Points to an access mask to be set to represent the
  219. accesses necessary to modify the information specified in the
  220. SecurityInformation parameter.
  221. Return Value:
  222. None.
  223. --*/
  224. {
  225. //
  226. // Figure out accesses needed to perform the indicated operation(s).
  227. //
  228. (*DesiredAccess) = 0;
  229. if ((SecurityInformation & OWNER_SECURITY_INFORMATION) ||
  230. (SecurityInformation & GROUP_SECURITY_INFORMATION) ) {
  231. (*DesiredAccess) |= WRITE_OWNER;
  232. }
  233. if (SecurityInformation & DACL_SECURITY_INFORMATION) {
  234. (*DesiredAccess) |= WRITE_DAC;
  235. }
  236. if (SecurityInformation & SACL_SECURITY_INFORMATION) {
  237. (*DesiredAccess) |= ACCESS_SYSTEM_SECURITY;
  238. }
  239. return;
  240. }
  241. VOID
  242. LsapRtlQuerySecurityAccessMask(
  243. IN SECURITY_INFORMATION SecurityInformation,
  244. OUT PACCESS_MASK DesiredAccess
  245. )
  246. /*++
  247. Routine Description:
  248. NOTE! THIS ROUTINE IS IDENTICAL WITH SeQuerySecurityAccessMask()
  249. IN \nt\private\ntos\se\semethod.c.
  250. This routine builds an access mask representing the accesses necessary
  251. to query the object security information specified in the
  252. SecurityInformation parameter. While it is not difficult to determine
  253. this information, the use of a single routine to generate it will ensure
  254. minimal impact when the security information associated with an object is
  255. extended in the future (to include mandatory access control information).
  256. Arguments:
  257. SecurityInformation - Identifies the object's security information to be
  258. queried.
  259. DesiredAccess - Points to an access mask to be set to represent the
  260. accesses necessary to query the information specified in the
  261. SecurityInformation parameter.
  262. Return Value:
  263. None.
  264. --*/
  265. {
  266. //
  267. // Figure out accesses needed to perform the indicated operation(s).
  268. //
  269. (*DesiredAccess) = 0;
  270. if ((SecurityInformation & OWNER_SECURITY_INFORMATION) ||
  271. (SecurityInformation & GROUP_SECURITY_INFORMATION) ||
  272. (SecurityInformation & DACL_SECURITY_INFORMATION)) {
  273. (*DesiredAccess) |= READ_CONTROL;
  274. }
  275. if ((SecurityInformation & SACL_SECURITY_INFORMATION)) {
  276. (*DesiredAccess) |= ACCESS_SYSTEM_SECURITY;
  277. }
  278. return;
  279. }
  280. NTSTATUS
  281. LsapRtlSidToUnicodeRid(
  282. IN PSID Sid,
  283. OUT PUNICODE_STRING UnicodeRid
  284. )
  285. /*++
  286. Routine Description:
  287. This function extracts the Relative Id (Rid) from a Sid and
  288. converts it to a Unicode String. The Rid is extracted and converted
  289. to an 8-digit Unicode Integer.
  290. Arguments:
  291. Sid - Pointer to the Sid to be converted. It is the caller's
  292. responsibility to ensure that the Sid has valid syntax.
  293. UnicodeRid - Pointer to a Unicode String structure that will receive
  294. the Rid in Unicode form. Note that memory for the string buffer
  295. in this Unicode String will be allocated by this routine if
  296. successful. The caller must free this memory after use by calling
  297. RtlFreeUnicodeString.
  298. Return Value:
  299. NTSTATUS - Standard Nt Status code
  300. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources
  301. to allocate buffer for Unicode String name.
  302. --*/
  303. {
  304. NTSTATUS Status;
  305. ULONG Rid;
  306. UCHAR SubAuthorityCount;
  307. UCHAR RidNameBufferAnsi[9];
  308. ANSI_STRING CharacterSidAnsi;
  309. //
  310. // First, verify that the given Sid is valid
  311. //
  312. if (!RtlValidSid( Sid )) {
  313. return STATUS_INVALID_PARAMETER;
  314. }
  315. //
  316. // Sid is valid. If however, the SubAuthorityCount is zero,
  317. // we cannot have a Rid so return error.
  318. //
  319. SubAuthorityCount = ((PISID) Sid)->SubAuthorityCount;
  320. if (SubAuthorityCount == 0) {
  321. return STATUS_INVALID_PARAMETER;
  322. }
  323. //
  324. // Sid has at least one subauthority. Get the lowest subauthority
  325. // (i.e. the Rid).
  326. //
  327. Rid = ((PISID) Sid)->SubAuthority[SubAuthorityCount - 1];
  328. //
  329. // Now convert the Rid to an 8-digit numeric character string
  330. //
  331. Status = RtlIntegerToChar( Rid, 16, -8, RidNameBufferAnsi );
  332. //
  333. // Need to add null terminator to string
  334. //
  335. RidNameBufferAnsi[8] = 0;
  336. //
  337. // Initialize an ANSI string structure with the converted name.
  338. //
  339. RtlInitString( &CharacterSidAnsi, RidNameBufferAnsi );
  340. //
  341. // Convert the ANSI string structure to Unicode form
  342. //
  343. Status = RtlAnsiStringToUnicodeString(
  344. UnicodeRid,
  345. &CharacterSidAnsi,
  346. TRUE
  347. );
  348. if (!NT_SUCCESS(Status)) {
  349. Status = STATUS_INSUFFICIENT_RESOURCES;
  350. }
  351. return Status;
  352. }
  353. NTSTATUS
  354. LsapRtlPrivilegeSetToLuidAndAttributes(
  355. IN OPTIONAL PPRIVILEGE_SET PrivilegeSet,
  356. OUT PULONG PrivilegeCount,
  357. OUT PLUID_AND_ATTRIBUTES *LuidAndAttributes
  358. )
  359. /*++
  360. Routine Description:
  361. This function converts a Privilege Set to a Privilege Count and Luid and
  362. Attributes array.
  363. Arguments:
  364. PrivilegeSet - Pointer to Privilege Set to be converted. If NULL or a zero
  365. length Privilege Set is specified, NULL is returned for the LUID and
  366. attributes pointer, with a Privilege Count of 0.
  367. PrivilegeCount - Receives the output Privilege Count
  368. LuidAndAttributes - Receives pointer to Luid and Attributes array. If there
  369. are no privileges, NULL is returned.
  370. Return Values:
  371. NTSTATUS - Standard Nt Result Code
  372. --*/
  373. {
  374. NTSTATUS Status = STATUS_SUCCESS;
  375. PLUID_AND_ATTRIBUTES OutputLuidAndAttributes = NULL;
  376. ULONG OutputPrivilegeCount = 0;
  377. ULONG LuidAndAttributesLength;
  378. if (PrivilegeSet != NULL) {
  379. OutputPrivilegeCount = PrivilegeSet->PrivilegeCount;
  380. if (OutputPrivilegeCount > 0) {
  381. //
  382. // Allocate space for the output LUID_AND_ATTRIBUTES array.
  383. //
  384. LuidAndAttributesLength = sizeof(LUID_AND_ATTRIBUTES) * OutputPrivilegeCount;
  385. OutputLuidAndAttributes = MIDL_user_allocate( LuidAndAttributesLength );
  386. if (OutputLuidAndAttributes == NULL) {
  387. Status = STATUS_NO_MEMORY;
  388. goto PrivilegeSetToLuidAndAttributesError;
  389. }
  390. Status = STATUS_SUCCESS;
  391. //
  392. // Copy the LUID and attributes from the input Privilege Set.
  393. //
  394. RtlCopyMemory(
  395. OutputLuidAndAttributes,
  396. PrivilegeSet->Privilege,
  397. LuidAndAttributesLength
  398. );
  399. }
  400. }
  401. //
  402. // Return LUID and Attributes array or NULL, plus Count.
  403. //
  404. *LuidAndAttributes = OutputLuidAndAttributes;
  405. *PrivilegeCount = OutputPrivilegeCount;
  406. PrivilegeSetToLuidAndAttributesFinish:
  407. return(Status);
  408. PrivilegeSetToLuidAndAttributesError:
  409. goto PrivilegeSetToLuidAndAttributesFinish;
  410. }
  411. NTSTATUS
  412. LsapRtlWellKnownPrivilegeCheck(
  413. IN PVOID ObjectHandle,
  414. IN BOOLEAN ImpersonateClient,
  415. IN ULONG PrivilegeId,
  416. IN OPTIONAL PCLIENT_ID ClientId
  417. )
  418. /*++
  419. Routine Description:
  420. This function checks if the given well known privilege is enabled for an
  421. impersonated client or for the current process.
  422. Arguments:
  423. ImpersonateClient - If TRUE, impersonate the client. If FALSE, don't
  424. impersonate the client (we may already be doing so).
  425. PrivilegeId - Specifies the well known Privilege Id
  426. ClientId - Specifies the client process/thread Id. If already
  427. impersonating the client, or impersonation is requested, this
  428. parameter should be omitted.
  429. Return Value:
  430. NTSTATUS - Standard Nt Result Code
  431. STATUS_SUCCESS - The call completed successfully and the client
  432. is either trusted or has the necessary privilege enabled.
  433. --*/
  434. {
  435. NTSTATUS Status, SecondaryStatus;
  436. BOOLEAN PrivilegeHeld = FALSE;
  437. HANDLE ClientThread = NULL, ClientProcess = NULL, ClientToken = NULL;
  438. OBJECT_ATTRIBUTES NullAttributes;
  439. PRIVILEGE_SET Privilege;
  440. BOOLEAN ClientImpersonatedHere = FALSE;
  441. UNICODE_STRING SubsystemName;
  442. InitializeObjectAttributes( &NullAttributes, NULL, 0, NULL, NULL );
  443. //
  444. // If requested, impersonate the client.
  445. //
  446. if (ImpersonateClient) {
  447. Status = I_RpcMapWin32Status(RpcImpersonateClient( NULL ));
  448. if ( !NT_SUCCESS(Status) ) {
  449. goto WellKnownPrivilegeCheckError;
  450. }
  451. ClientImpersonatedHere = TRUE;
  452. }
  453. //
  454. // If a client process other than ourself has been specified , open it
  455. // for query information access.
  456. //
  457. if (ARGUMENT_PRESENT(ClientId)) {
  458. if (ClientId->UniqueProcess != NtCurrentProcess()) {
  459. Status = NtOpenProcess(
  460. &ClientProcess,
  461. PROCESS_QUERY_INFORMATION, // To open primary token
  462. &NullAttributes,
  463. ClientId
  464. );
  465. if ( !NT_SUCCESS(Status) ) {
  466. goto WellKnownPrivilegeCheckError;
  467. }
  468. } else {
  469. ClientProcess = NtCurrentProcess();
  470. }
  471. if (ClientId->UniqueThread != NtCurrentThread()) {
  472. Status = NtOpenThread(
  473. &ClientThread,
  474. THREAD_QUERY_INFORMATION,
  475. &NullAttributes,
  476. ClientId
  477. );
  478. if ( !NT_SUCCESS(Status) ) {
  479. goto WellKnownPrivilegeCheckError;
  480. }
  481. } else {
  482. ClientThread = NtCurrentThread();
  483. }
  484. }
  485. else {
  486. ClientThread = NtCurrentThread();
  487. }
  488. //
  489. // Open the specified or current thread's impersonation token (if any).
  490. //
  491. Status = NtOpenThreadToken(
  492. ClientThread,
  493. TOKEN_QUERY,
  494. TRUE,
  495. &ClientToken
  496. );
  497. if ( !NT_SUCCESS(Status) ) {
  498. goto WellKnownPrivilegeCheckError;
  499. }
  500. //
  501. // OK, we have a token open. Now check for the privilege to execute this
  502. // service.
  503. //
  504. Privilege.PrivilegeCount = 1;
  505. Privilege.Control = PRIVILEGE_SET_ALL_NECESSARY;
  506. Privilege.Privilege[0].Luid = RtlConvertLongToLuid(PrivilegeId);
  507. Privilege.Privilege[0].Attributes = 0;
  508. Status = NtPrivilegeCheck(
  509. ClientToken,
  510. &Privilege,
  511. &PrivilegeHeld
  512. );
  513. if (!NT_SUCCESS(Status)) {
  514. goto WellKnownPrivilegeCheckError;
  515. }
  516. RtlInitUnicodeString( &SubsystemName, L"LSA" );
  517. (VOID) NtPrivilegeObjectAuditAlarm ( &SubsystemName,
  518. ObjectHandle,
  519. ClientToken,
  520. ACCESS_SYSTEM_SECURITY,
  521. &Privilege,
  522. PrivilegeHeld
  523. );
  524. if ( !PrivilegeHeld ) {
  525. Status = STATUS_PRIVILEGE_NOT_HELD;
  526. goto WellKnownPrivilegeCheckError;
  527. }
  528. WellKnownPrivilegeCheckFinish:
  529. //
  530. // If we impersonated the client, revert to ourself.
  531. //
  532. if (ClientImpersonatedHere) {
  533. SecondaryStatus = I_RpcMapWin32Status(RpcRevertToSelf());
  534. }
  535. //
  536. // If necessary, close the client Process.
  537. //
  538. if ((ARGUMENT_PRESENT(ClientId)) &&
  539. (ClientId->UniqueProcess != NtCurrentProcess()) &&
  540. (ClientProcess != NULL)) {
  541. SecondaryStatus = NtClose( ClientProcess );
  542. ASSERT(NT_SUCCESS(SecondaryStatus));
  543. ClientProcess = NULL;
  544. }
  545. //
  546. // If necessary, close the client token.
  547. //
  548. if (ClientToken != NULL) {
  549. SecondaryStatus = NtClose( ClientToken );
  550. ASSERT(NT_SUCCESS(SecondaryStatus));
  551. ClientToken = NULL;
  552. }
  553. //
  554. // If necessary, close the client thread
  555. //
  556. if ((ARGUMENT_PRESENT(ClientId)) &&
  557. (ClientId->UniqueThread != NtCurrentThread()) &&
  558. (ClientThread != NULL)) {
  559. SecondaryStatus = NtClose( ClientThread );
  560. ASSERT(NT_SUCCESS(SecondaryStatus));
  561. ClientThread = NULL;
  562. }
  563. return(Status);
  564. WellKnownPrivilegeCheckError:
  565. goto WellKnownPrivilegeCheckFinish;
  566. }
  567. NTSTATUS
  568. LsapSplitSid(
  569. IN PSID AccountSid,
  570. IN OUT PSID *DomainSid,
  571. OUT ULONG *Rid
  572. )
  573. /*++
  574. Routine Description:
  575. This function splits a sid into its domain sid and rid. The caller
  576. can either provide a memory buffer for the returned DomainSid, or
  577. request that one be allocated. If the caller provides a buffer, the buffer
  578. is assumed to be of sufficient size. If allocated on the caller's behalf,
  579. the buffer must be freed when no longer required via MIDL_user_free.
  580. Arguments:
  581. AccountSid - Specifies the Sid to be split. The Sid is assumed to be
  582. syntactically valid. Sids with zero subauthorities cannot be split.
  583. DomainSid - Pointer to location containing either NULL or a pointer to
  584. a buffer in which the Domain Sid will be returned. If NULL is
  585. specified, memory will be allocated on behalf of the caller.
  586. Return Value:
  587. NTSTATUS - Standard Nt Result Code
  588. STATUS_SUCCESS - The call completed successfully.
  589. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  590. such as memory, to complete the call successfully.
  591. STATUS_INVALID_SID - The Sid is has a subauthority count of 0.
  592. --*/
  593. {
  594. NTSTATUS NtStatus;
  595. UCHAR AccountSubAuthorityCount;
  596. ULONG AccountSidLength;
  597. //
  598. // Calculate the size of the domain sid
  599. //
  600. AccountSubAuthorityCount = *RtlSubAuthorityCountSid(AccountSid);
  601. if (AccountSubAuthorityCount < 1) {
  602. NtStatus = STATUS_INVALID_SID;
  603. goto SplitSidError;
  604. }
  605. AccountSidLength = RtlLengthSid(AccountSid);
  606. //
  607. // If no buffer is required for the Domain Sid, we have to allocate one.
  608. //
  609. if (*DomainSid == NULL) {
  610. //
  611. // Allocate space for the domain sid (allocate the same size as the
  612. // account sid so we can use RtlCopySid)
  613. //
  614. *DomainSid = MIDL_user_allocate(AccountSidLength);
  615. if (*DomainSid == NULL) {
  616. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  617. goto SplitSidError;
  618. }
  619. }
  620. //
  621. // Copy the Account sid into the Domain sid
  622. //
  623. RtlMoveMemory(*DomainSid, AccountSid, AccountSidLength);
  624. //
  625. // Decrement the domain sid sub-authority count
  626. //
  627. (*RtlSubAuthorityCountSid(*DomainSid))--;
  628. //
  629. // Copy the rid out of the account sid
  630. //
  631. *Rid = *RtlSubAuthoritySid(AccountSid, AccountSubAuthorityCount-1);
  632. NtStatus = STATUS_SUCCESS;
  633. SplitSidFinish:
  634. return(NtStatus);
  635. SplitSidError:
  636. goto SplitSidFinish;
  637. }
  638. ULONG
  639. LsapDsSizeAuthInfo(
  640. IN PLSAPR_AUTH_INFORMATION AuthInfo,
  641. IN ULONG Infos
  642. )
  643. /*++
  644. Routine Description:
  645. This function returns the size, in bytes, of an authentication information structure
  646. Arguments:
  647. AuthInfo - AuthenticationInformation to size
  648. Infos - Number of items in the list
  649. Returns:
  650. Size, in bytes, of the AuthInfos
  651. --*/
  652. {
  653. ULONG Len = 0, i;
  654. if ( AuthInfo == NULL ) {
  655. return( 0 );
  656. }
  657. for ( i = 0 ; i < Infos; i++ ) {
  658. //
  659. // This calculation must match LsapDsMarshalAuthInfo
  660. //
  661. Len += sizeof(LARGE_INTEGER) +
  662. sizeof(ULONG) +
  663. sizeof(ULONG) +
  664. ROUND_UP_COUNT(AuthInfo[ i ].AuthInfoLength, ALIGN_DWORD);
  665. }
  666. return( Len );
  667. }
  668. VOID
  669. LsapDsMarshalAuthInfo(
  670. IN PBYTE Buffer,
  671. IN PLSAPR_AUTH_INFORMATION AuthInfo,
  672. IN ULONG Infos
  673. )
  674. /*++
  675. Routine Description:
  676. This function will marshal an authinfo list into an already allocated buffer
  677. Arguments:
  678. Buffer - Buffer to marshal into
  679. AuthInfo - AuthenticationInformation to marshal
  680. Infos - Number of items in the list
  681. Returns:
  682. VOID
  683. --*/
  684. {
  685. ULONG i;
  686. if ( AuthInfo != NULL ) {
  687. for (i = 0; i < Infos ; i++ ) {
  688. ULONG AlignmentBytes;
  689. RtlCopyMemory( Buffer, &AuthInfo[i].LastUpdateTime, sizeof( LARGE_INTEGER ) );
  690. Buffer += sizeof( LARGE_INTEGER );
  691. *(PULONG)Buffer = AuthInfo[i].AuthType;
  692. Buffer += sizeof ( ULONG );
  693. *(PULONG)Buffer = AuthInfo[i].AuthInfoLength;
  694. Buffer += sizeof ( ULONG );
  695. RtlCopyMemory( Buffer, AuthInfo[i].AuthInfo, AuthInfo[i].AuthInfoLength );
  696. Buffer += AuthInfo[i].AuthInfoLength;
  697. // Zero out the next couple of bytes in the DWORD.
  698. AlignmentBytes = ROUND_UP_COUNT(AuthInfo[ i ].AuthInfoLength, ALIGN_DWORD) -
  699. AuthInfo[ i ].AuthInfoLength;
  700. RtlZeroMemory( Buffer, AlignmentBytes );
  701. Buffer += AlignmentBytes;
  702. }
  703. }
  704. }
  705. NTSTATUS
  706. LsapDsMarshalAuthInfoHalf(
  707. IN PLSAPR_TRUST_DOMAIN_AUTH_INFO_HALF AuthInfo,
  708. OUT PULONG Length,
  709. OUT PBYTE *Buffer
  710. )
  711. /*++
  712. Routine Description:
  713. This function will take an AuthInfo half and marshal it into a single self
  714. relative buffer.
  715. Arguments:
  716. AuthInfo - AuthenticationInformation to marshal
  717. Length - Returns the length of the allocated buffer.
  718. Buffer - Returns an allocated buffer containing the marshalled auth info
  719. The buffer should be freed using MIDL_user_free.
  720. Returns:
  721. STATUS_SUCCESS - Success
  722. STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed.
  723. --*/
  724. {
  725. NTSTATUS Status = STATUS_SUCCESS;
  726. PBYTE LocalBuffer, Current;
  727. ULONG Len, PrevLen;
  728. if ( AuthInfo == NULL ) {
  729. *Length = 0;
  730. *Buffer = NULL;
  731. return STATUS_SUCCESS;
  732. }
  733. try {
  734. //
  735. // First, size the entire auth info buffer...
  736. //
  737. Len = LsapDsSizeAuthInfo( AuthInfo->AuthenticationInformation, AuthInfo->AuthInfos );
  738. PrevLen = LsapDsSizeAuthInfo( AuthInfo->PreviousAuthenticationInformation,
  739. AuthInfo->AuthInfos );
  740. //
  741. // The format of the buffer we will create is:
  742. //
  743. LocalBuffer = MIDL_user_allocate( Len + PrevLen + ( 3 * sizeof( ULONG ) ) );
  744. if ( LocalBuffer == NULL ) {
  745. Status = STATUS_INSUFFICIENT_RESOURCES;
  746. } else {
  747. //
  748. // The format of the buffer is:
  749. //
  750. // [Info count][OffsetCurrent][OffsetPrevious] and then some number of the
  751. // following:
  752. // [UpdateTime(LargeInteger)][AuthType][AuthInfoLen][data (sizeis(AuthInfoLen) ]
  753. //
  754. //
  755. // Number of items...
  756. //
  757. *(PULONG)LocalBuffer = AuthInfo->AuthInfos;
  758. Current = LocalBuffer + sizeof( ULONG );
  759. //
  760. //
  761. *(PULONG)(Current) = 3 * sizeof(ULONG);
  762. *(PULONG)(Current + sizeof(ULONG)) = *(PULONG)Current + Len;
  763. Current += 2 * sizeof(ULONG);
  764. LsapDsMarshalAuthInfo( Current,
  765. AuthInfo->AuthenticationInformation,
  766. AuthInfo->AuthInfos );
  767. Current += Len;
  768. LsapDsMarshalAuthInfo( Current,
  769. AuthInfo->PreviousAuthenticationInformation,
  770. AuthInfo->AuthInfos );
  771. Status = STATUS_SUCCESS;
  772. }
  773. *Length = Len + PrevLen + ( 3 * sizeof( ULONG ) );
  774. *Buffer = LocalBuffer;
  775. } except( EXCEPTION_EXECUTE_HANDLER ) {
  776. Status = GetExceptionCode();
  777. }
  778. return( Status );
  779. }