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.

1020 lines
33 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. SafeWild.c (WinSAFER Wildcard SID handling)
  5. Abstract:
  6. This module implements various "Wildcard SID" operations that
  7. are used internally by the WinSAFER APIs to compute SID list
  8. intersections and inversions.
  9. Author:
  10. Jeffrey Lawson (JLawson) - Apr 2000
  11. Environment:
  12. User mode only.
  13. Exported Functions:
  14. CodeAuthzpConvertWildcardStringSidToSidW (private)
  15. CodeAuthzpCompareWildcardSidWithSid (private)
  16. CodeAuthzpSidInWildcardList (private)
  17. CodeAuthzpInvertAndAddSids (private)
  18. CodeAuthzpExpandWildcardList (private)
  19. Revision History:
  20. Created - Apr 2000
  21. --*/
  22. #include "pch.h"
  23. #pragma hdrstop
  24. #include <sddl.h> // ConvertStringSidToSidW
  25. #include "safewild.h"
  26. #include <winsafer.h>
  27. #include "saferp.h" // CodeAuthzpGetTokenInformation
  28. NTSTATUS NTAPI
  29. CodeAuthzpConvertWildcardStringSidToSidW(
  30. IN LPCWSTR szStringSid,
  31. OUT PAUTHZ_WILDCARDSID pWildcardSid
  32. )
  33. /*++
  34. Routine Description:
  35. Converts a textual SID into the machine-understanable binary format.
  36. For normal string SIDs, this is just a call to ConvertStringSidToSidW
  37. with the exception that this takes a AUTHZ_WILDCARDSID parameter.
  38. However, this function also allows a single SubAuthority to be
  39. optionally specified as a wildcard ('*'), which will match zero or
  40. more SubAuthority. Note that only one wildcard can be present within
  41. any SID and must represent whole SubAuthority values.
  42. (ie: "S-1-5-4-*-7" or "S-1-5-4-*" is okay; but "S-1-5-4*-7" and
  43. "S-1-5-*-4-*-7" are both not acceptable).
  44. Arguments:
  45. szStringSid - textual string SID possibly containing a wildcard.
  46. pWildcardSID - pointer to a AUTHZ_WILDCARDSID structure that will be
  47. filled with information about the boolean sid.
  48. Return Value:
  49. Returns STATUS_SUCCESS on success, or another error code.
  50. --*/
  51. {
  52. DWORD dwLength;
  53. LPWSTR pBuffer;
  54. LPCWSTR pStar = NULL;
  55. LPCWSTR p;
  56. //
  57. // Do a quick analysis pass on the String SID and verify that
  58. // there is at most one '*' in it. And if there is a '*',
  59. // it must represent a whole subauthority (possibly the last
  60. // subauthority).
  61. //
  62. ASSERT( ARGUMENT_PRESENT(szStringSid) && ARGUMENT_PRESENT(pWildcardSid) );
  63. for (p = szStringSid; *p; p++)
  64. {
  65. if (*p == L'-' &&
  66. *(p + 1) == L'*' &&
  67. (*(p + 2) == UNICODE_NULL || *(p + 2) == L'-') )
  68. {
  69. if (pStar != NULL) return STATUS_INVALID_SID;
  70. pStar = p + 1;
  71. p++;
  72. }
  73. else if (*p == L'*') return STATUS_INVALID_SID;
  74. }
  75. //
  76. // If this String SID does not contain a wildcard, then just
  77. // process it normally and quickly return.
  78. //
  79. if (pStar == NULL)
  80. {
  81. pWildcardSid->WildcardPos = (DWORD) -1;
  82. if (ConvertStringSidToSidW(szStringSid, &pWildcardSid->Sid))
  83. return STATUS_SUCCESS;
  84. else
  85. return STATUS_UNSUCCESSFUL;
  86. }
  87. //
  88. // Otherwise this was a String SID that contained a wildcard.
  89. //
  90. dwLength = wcslen(szStringSid);
  91. pBuffer = (LPWSTR) RtlAllocateHeap(RtlProcessHeap(), 0,
  92. sizeof(WCHAR) * (dwLength + 1));
  93. if (pBuffer != NULL)
  94. {
  95. PISID sid1, sid2;
  96. DWORD dwIndex;
  97. LPWSTR pNewStar;
  98. //
  99. // Copy the String SID and update our 'pStar' pointer to
  100. // point to the '*' within our newly copied buffer.
  101. //
  102. RtlCopyMemory(pBuffer, szStringSid,
  103. sizeof(WCHAR) * (dwLength + 1));
  104. pNewStar = pBuffer + (pStar - szStringSid);
  105. //
  106. // Change the '*' to a '0' and convert the SID once.
  107. //
  108. *pNewStar = L'0';
  109. if (ConvertStringSidToSidW(pBuffer, (PSID*) &sid1))
  110. {
  111. //
  112. // Change the '*' to a '1' and convert the SID again.
  113. //
  114. *pNewStar = L'1';
  115. if (ConvertStringSidToSidW(pBuffer, (PSID*) &sid2))
  116. {
  117. //
  118. // Compare the resulting SIDs and find the subauthority that
  119. // differs only by the '0' or '1' component. Since we expect
  120. // the converted SIDs to always be the same except for the
  121. // one SubAuthority that we changed, we use a lot of asserts.
  122. //
  123. ASSERT(sid1->Revision == sid2->Revision);
  124. ASSERT( RtlEqualMemory(&sid1->IdentifierAuthority.Value[0],
  125. &sid2->IdentifierAuthority.Value[0],
  126. 6 * sizeof(sid1->IdentifierAuthority.Value[0]) ) );
  127. ASSERT(sid1->SubAuthorityCount == sid2->SubAuthorityCount);
  128. for (dwIndex = 0; dwIndex < sid1->SubAuthorityCount; dwIndex++)
  129. {
  130. if (sid1->SubAuthority[dwIndex] != sid2->SubAuthority[dwIndex])
  131. {
  132. ASSERT(sid1->SubAuthority[dwIndex] == 0 &&
  133. sid2->SubAuthority[dwIndex] == 1);
  134. ASSERT( RtlEqualMemory(&sid1->SubAuthority[dwIndex + 1],
  135. &sid2->SubAuthority[dwIndex + 1],
  136. sizeof(sid1->SubAuthority[0]) *
  137. (sid1->SubAuthorityCount - dwIndex - 1)) );
  138. //
  139. // The position of the wildcard '*' has been found so
  140. // squeeze it out and move the postfix SubAuthorities.
  141. //
  142. RtlMoveMemory(&sid1->SubAuthority[dwIndex],
  143. &sid1->SubAuthority[dwIndex + 1],
  144. sizeof(sid1->SubAuthority[0]) *
  145. (sid1->SubAuthorityCount - dwIndex - 1) );
  146. sid1->SubAuthorityCount--;
  147. //
  148. // Fill in the SID_AND_ATTRIBUTES structure that
  149. // we'll return to the caller.
  150. // In debug builds, we place a marker in the
  151. // upper-bits of the member 'Attributes' so that
  152. // we can easily assert wildcard SIDs.
  153. //
  154. pWildcardSid->Sid = (PSID) sid1;
  155. pWildcardSid->WildcardPos = dwIndex;
  156. //
  157. // Free any remaining resources and return success.
  158. //
  159. LocalFree( (HLOCAL) sid2 );
  160. RtlFreeHeap(RtlProcessHeap(), 0, pBuffer);
  161. return STATUS_SUCCESS;
  162. }
  163. }
  164. //
  165. // We should never get here since we expect to find
  166. // at least the 1 difference that we introduced.
  167. //
  168. ASSERT(0);
  169. LocalFree( (HLOCAL) sid2 );
  170. }
  171. LocalFree( (HLOCAL) sid1 );
  172. }
  173. RtlFreeHeap(RtlProcessHeap(), 0, pBuffer);
  174. return STATUS_UNSUCCESSFUL;
  175. }
  176. return STATUS_NO_MEMORY;
  177. }
  178. NTSTATUS NTAPI
  179. CodeAuthzpConvertWildcardSidToStringSidW(
  180. IN PAUTHZ_WILDCARDSID pWildcardSid,
  181. OUT PUNICODE_STRING pUnicodeOutput)
  182. /*++
  183. Routine Description:
  184. Converts a machine-understandable Wildcard SID into a textual string
  185. representation of the SID.
  186. Arguments:
  187. pWildcardSID - pointer to a AUTHZ_WILDCARDSID structure that will be
  188. filled with information about the boolean sid.
  189. pUnicodeOutput - output buffer that will be allocated.
  190. Return Value:
  191. Returns STATUS_SUCCESS on success, or another error code.
  192. --*/
  193. {
  194. NTSTATUS Status;
  195. WCHAR UniBuffer[ 256 ];
  196. UNICODE_STRING LocalString ;
  197. UCHAR i;
  198. ULONG Tmp;
  199. LARGE_INTEGER Auth ;
  200. PISID iSid = (PISID) pWildcardSid->Sid; // pointer to opaque structure
  201. if (!ARGUMENT_PRESENT(pUnicodeOutput)) {
  202. return STATUS_INVALID_PARAMETER;
  203. }
  204. if (RtlValidSid( iSid ) != TRUE) {
  205. return STATUS_INVALID_SID;
  206. }
  207. if ( iSid->Revision != SID_REVISION ) {
  208. return STATUS_INVALID_SID;
  209. }
  210. if (pWildcardSid->WildcardPos != -1 &&
  211. pWildcardSid->WildcardPos > iSid->SubAuthorityCount) {
  212. return STATUS_INVALID_SID;
  213. }
  214. LocalString.Buffer = UniBuffer;
  215. LocalString.Length = 0;
  216. LocalString.MaximumLength = 256 * sizeof(WCHAR);
  217. RtlAppendUnicodeToString(&LocalString, L"S-1-");
  218. // adjust the buffer so that the start of it is where the end was.
  219. // (note that we don't set Length, since RtlIntXXXToUnicodeString
  220. // directly overwrite from at the start of the buffer)
  221. LocalString.MaximumLength -= LocalString.Length;
  222. LocalString.Buffer += LocalString.Length / sizeof(WCHAR);
  223. if ( (iSid->IdentifierAuthority.Value[0] != 0) ||
  224. (iSid->IdentifierAuthority.Value[1] != 0) ){
  225. //
  226. // Ugly hex dump.
  227. //
  228. Auth.HighPart = (LONG) (iSid->IdentifierAuthority.Value[ 0 ] << 8) +
  229. (LONG) iSid->IdentifierAuthority.Value[ 1 ] ;
  230. Auth.LowPart = (ULONG)iSid->IdentifierAuthority.Value[5] +
  231. (ULONG)(iSid->IdentifierAuthority.Value[4] << 8) +
  232. (ULONG)(iSid->IdentifierAuthority.Value[3] << 16) +
  233. (ULONG)(iSid->IdentifierAuthority.Value[2] << 24);
  234. Status = RtlInt64ToUnicodeString(Auth.QuadPart, 16, &LocalString);
  235. } else {
  236. Tmp = (ULONG)iSid->IdentifierAuthority.Value[5] +
  237. (ULONG)(iSid->IdentifierAuthority.Value[4] << 8) +
  238. (ULONG)(iSid->IdentifierAuthority.Value[3] << 16) +
  239. (ULONG)(iSid->IdentifierAuthority.Value[2] << 24);
  240. Status = RtlIntegerToUnicodeString(
  241. Tmp,
  242. 10,
  243. &LocalString);
  244. }
  245. if ( !NT_SUCCESS( Status ) )
  246. {
  247. return Status;
  248. }
  249. if (pWildcardSid->WildcardPos != -1)
  250. {
  251. //
  252. // Stringify the leading sub-authorities within the SID.
  253. //
  254. for (i = 0; i < pWildcardSid->WildcardPos; i++ ) {
  255. // Tack on a hyphen.
  256. Status = RtlAppendUnicodeToString(&LocalString, L"-");
  257. if ( !NT_SUCCESS( Status ) ) {
  258. return Status;
  259. }
  260. // adjust the buffer so that the start of it is where the end was.
  261. // (note that we don't set Length, since RtlIntXXXToUnicodeString
  262. // directly overwrite from at the start of the buffer)
  263. LocalString.MaximumLength -= LocalString.Length;
  264. LocalString.Buffer += LocalString.Length / sizeof(WCHAR);
  265. // Tack on the next subauthority.
  266. ASSERT( i < iSid->SubAuthorityCount );
  267. Status = RtlIntegerToUnicodeString(
  268. iSid->SubAuthority[ i ],
  269. 10,
  270. &LocalString );
  271. if ( !NT_SUCCESS( Status ) ) {
  272. return Status;
  273. }
  274. }
  275. //
  276. // Place the wildcard asterick within the buffer.
  277. //
  278. Status = RtlAppendUnicodeToString(&LocalString, L"-*");
  279. if (!NT_SUCCESS(Status)) {
  280. return Status;
  281. }
  282. //
  283. // Stringify all remaining sub-authorities within the SID.
  284. //
  285. for (; i < iSid->SubAuthorityCount; i++ ) {
  286. // tack on a hyphen.
  287. Status = RtlAppendUnicodeToString(&LocalString, L"-");
  288. if ( !NT_SUCCESS(Status) ) {
  289. return Status;
  290. }
  291. // adjust the buffer so that the start of it is where the end was.
  292. // (note that we don't set Length, since RtlIntXXXToUnicodeString
  293. // directly overwrite from at the start of the buffer)
  294. LocalString.MaximumLength -= LocalString.Length;
  295. LocalString.Buffer += LocalString.Length / sizeof(WCHAR);
  296. // tack on the next subauthority.
  297. Status = RtlIntegerToUnicodeString(
  298. iSid->SubAuthority[ i ],
  299. 10,
  300. &LocalString);
  301. if ( !NT_SUCCESS( Status ) ) {
  302. return Status;
  303. }
  304. }
  305. }
  306. else
  307. {
  308. for (i=0;i<iSid->SubAuthorityCount ;i++ ) {
  309. // tack on a hyphen.
  310. Status = RtlAppendUnicodeToString(&LocalString, L"-");
  311. if ( !NT_SUCCESS( Status ) ) {
  312. return Status;
  313. }
  314. // adjust the buffer so that the start of it is where the end was.
  315. // (note that we don't set Length, since RtlIntXXXToUnicodeString
  316. // directly overwrite from at the start of the buffer)
  317. LocalString.MaximumLength -= LocalString.Length;
  318. LocalString.Buffer += LocalString.Length / sizeof(WCHAR);
  319. // tack on the next subauthority.
  320. Status = RtlIntegerToUnicodeString(
  321. iSid->SubAuthority[ i ],
  322. 10,
  323. &LocalString );
  324. if ( !NT_SUCCESS( Status ) ) {
  325. return Status;
  326. }
  327. }
  328. }
  329. Status = RtlDuplicateUnicodeString(
  330. RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
  331. &LocalString, pUnicodeOutput);
  332. return Status;
  333. }
  334. BOOLEAN NTAPI
  335. CodeAuthzpCompareWildcardSidWithSid(
  336. IN PAUTHZ_WILDCARDSID pWildcardSid,
  337. IN PSID pMatchSid
  338. )
  339. /*++
  340. Routine Description:
  341. Determines if a given SID matches when compared against a
  342. wildcard SID pattern.
  343. Arguments:
  344. pWildcardSid - the wildcard SID pattern to evaluate.
  345. pMatchSid - the single SID to test.
  346. Return Value:
  347. Returns TRUE if the specified wildcard SID matches against the
  348. specified single SID. Otherwise returns FALSE.
  349. --*/
  350. {
  351. DWORD wildcardpos;
  352. ASSERT( ARGUMENT_PRESENT(pWildcardSid) && ARGUMENT_PRESENT(pMatchSid) );
  353. ASSERT( RtlValidSid(pWildcardSid->Sid) );
  354. wildcardpos = pWildcardSid->WildcardPos;
  355. if (wildcardpos != -1)
  356. {
  357. // This is a wildcard SID and needs to be handled specially.
  358. PISID wildsid = (PISID) pWildcardSid->Sid;
  359. PISID matchsid = (PISID) pMatchSid;
  360. ASSERT( wildcardpos <= wildsid->SubAuthorityCount );
  361. if (wildsid->Revision == matchsid->Revision )
  362. {
  363. if ( (wildsid->IdentifierAuthority.Value[0] ==
  364. matchsid->IdentifierAuthority.Value[0]) &&
  365. (wildsid->IdentifierAuthority.Value[1]==
  366. matchsid->IdentifierAuthority.Value[1]) &&
  367. (wildsid->IdentifierAuthority.Value[2] ==
  368. matchsid->IdentifierAuthority.Value[2]) &&
  369. (wildsid->IdentifierAuthority.Value[3] ==
  370. matchsid->IdentifierAuthority.Value[3]) &&
  371. (wildsid->IdentifierAuthority.Value[4] ==
  372. matchsid->IdentifierAuthority.Value[4]) &&
  373. (wildsid->IdentifierAuthority.Value[5] ==
  374. matchsid->IdentifierAuthority.Value[5])
  375. )
  376. {
  377. if (matchsid->SubAuthorityCount >= wildsid->SubAuthorityCount)
  378. {
  379. DWORD Index, IndexDiff;
  380. //
  381. // Ensure the prefix part of the wildcard matches.
  382. //
  383. ASSERT(wildcardpos <= matchsid->SubAuthorityCount );
  384. for (Index = 0; Index < wildcardpos; Index++) {
  385. if (wildsid->SubAuthority[Index] !=
  386. matchsid->SubAuthority[Index])
  387. return FALSE;
  388. }
  389. //
  390. // Ensure the postfix part of the wildcard matches.
  391. //
  392. IndexDiff = (matchsid->SubAuthorityCount - wildsid->SubAuthorityCount);
  393. for (Index = wildcardpos; Index < wildsid->SubAuthorityCount; Index++) {
  394. if (wildsid->SubAuthority[Index] !=
  395. matchsid->SubAuthority[Index + IndexDiff])
  396. return FALSE;
  397. }
  398. return TRUE; // matches okay!
  399. }
  400. }
  401. }
  402. return FALSE;
  403. }
  404. else
  405. {
  406. // This is a normal SID so we can compare directly.
  407. return RtlEqualSid(pWildcardSid->Sid, pMatchSid);
  408. }
  409. }
  410. BOOLEAN NTAPI
  411. CodeAuthzpSidInWildcardList (
  412. IN PAUTHZ_WILDCARDSID WildcardList OPTIONAL,
  413. IN ULONG WildcardCount,
  414. IN PSID SePrincipalSelfSid OPTIONAL,
  415. IN PSID PrincipalSelfSid OPTIONAL,
  416. IN PSID Sid
  417. )
  418. /*++
  419. Routine Description:
  420. Checks to see if a given SID is in the given list of Wildcards.
  421. N.B. The code to compute the length of a SID and test for equality
  422. is duplicated from the security runtime since this is such a
  423. frequently used routine.
  424. This function is mostly copied from the SepSidInSidAndAttributes
  425. found in ntos\se\tokendup.c, except it handles PrincipalSelfSid
  426. within the list as well as the passed in Sid. SePrincipalSelfSid
  427. is also a parameter here, instead of an ntoskrnl global. also the
  428. HonorEnabledAttribute argument was added.
  429. Arguments:
  430. WildcardList - Pointer to the wildcard sid list to be examined
  431. WildcardCount - Number of entries in the WildcardList array.
  432. SePrincipalSelfSid - This parameter should optionally be the SID that
  433. will be replaced with the PrincipalSelfSid if this SID is encountered
  434. in any ACE. This SID should be generated from SECURITY_PRINCIPAL_SELF_RID
  435. The parameter should be NULL if the object does not represent a principal.
  436. PrincipalSelfSid - If the object being access checked is an object which
  437. represents a principal (e.g., a user object), this parameter should
  438. be the SID of the object. Any ACE containing the constant
  439. SECURITY_PRINCIPAL_SELF_RID is replaced by this SID.
  440. The parameter should be NULL if the object does not represent a principal.
  441. Sid - Pointer to the SID of interest
  442. Return Value:
  443. A value of TRUE indicates that the SID is in the token, FALSE
  444. otherwise.
  445. --*/
  446. {
  447. ULONG i;
  448. ASSERT( ARGUMENT_PRESENT(Sid) );
  449. if ( !ARGUMENT_PRESENT(WildcardList) || !WildcardCount ) {
  450. return FALSE;
  451. }
  452. //
  453. // If Sid is the constant PrincipalSelfSid,
  454. // replace it with the passed in PrincipalSelfSid.
  455. //
  456. if ( ARGUMENT_PRESENT(PrincipalSelfSid) &&
  457. ARGUMENT_PRESENT(SePrincipalSelfSid) &&
  458. RtlEqualSid( SePrincipalSelfSid, Sid ) )
  459. {
  460. ASSERT( !RtlEqualSid(SePrincipalSelfSid, PrincipalSelfSid) );
  461. Sid = PrincipalSelfSid;
  462. }
  463. //
  464. // Scan through the user/groups and attempt to find a match with the
  465. // specified SID.
  466. //
  467. for (i = 0 ; i < WildcardCount ; i++, WildcardList++)
  468. {
  469. //
  470. // If the SID is the principal self SID, then compare it.
  471. //
  472. if ( ARGUMENT_PRESENT(SePrincipalSelfSid) &&
  473. ARGUMENT_PRESENT(PrincipalSelfSid) &&
  474. WildcardList->WildcardPos == -1 &&
  475. RtlEqualSid(SePrincipalSelfSid, WildcardList->Sid))
  476. {
  477. if (RtlEqualSid( PrincipalSelfSid, Sid ))
  478. return TRUE;
  479. }
  480. //
  481. // If the Wildcard SID matches the individual SID, then great.
  482. //
  483. else if ( CodeAuthzpCompareWildcardSidWithSid(WildcardList, Sid ) )
  484. {
  485. return TRUE;
  486. }
  487. }
  488. return FALSE;
  489. }
  490. BOOLEAN NTAPI
  491. CodeAuthzpInvertAndAddSids(
  492. IN HANDLE InAccessToken,
  493. IN PSID InTokenOwner OPTIONAL,
  494. IN DWORD InvertSidCount,
  495. IN PAUTHZ_WILDCARDSID SidsToInvert,
  496. IN DWORD SidsAddedCount OPTIONAL,
  497. IN PSID_AND_ATTRIBUTES SidsToAdd OPTIONAL,
  498. OUT DWORD *NewDisabledSidCount,
  499. OUT PSID_AND_ATTRIBUTES *NewSidsToDisable
  500. )
  501. /*++
  502. Routine Description:
  503. Takes an input token and extracts its membership groups.
  504. A "left outer" set combination (non-intersection) of the
  505. membership groups with the SidsToInvert parameter.
  506. Additionally, the SidsToAdd list specifies a list of SIDs
  507. that will be optionally added to the resulting set.
  508. The final result is returned within a specified pointer.
  509. Arguments:
  510. InAccessToken - Input token from which the membership group SIDs
  511. will be taken from.
  512. InTokenOwner - Optionally specifies the TokenUser of the specifies
  513. InAccessToken. This SID is used to replace any instances of
  514. SECURITY_PRINCIPAL_SELF_RID that are encountered in either
  515. the SidsToInvert or SidsToAdd arrays. If this value is not
  516. specified, then no replacements will be made.
  517. InvertSidCount - Number of SIDs in the SidsToInvert array.
  518. SidsToInvert - Array of the allowable SIDs that should be kept.
  519. All of the token's group SIDs that are not one of these
  520. will be removed from the resulting set.
  521. SidsAddedCount - Optional number of SIDs in the SidsToAdd array.
  522. SidsToAdd - Optionally specifies the SIDs that should be
  523. explicitly added into the resultant set after the
  524. NewDisabledSidCount - Receives the number of SIDs within the
  525. final group array.
  526. NewSidsToDisable - Receives a pointer to the final group array.
  527. This memory pointer must be freed by the caller with RtlFreeHeap().
  528. All SID pointers within this resultant array are pointers within
  529. the contiguous piece of memory that make up the list itself.
  530. Return Value:
  531. A value of TRUE indicates that the operation was successful,
  532. FALSE otherwise.
  533. --*/
  534. {
  535. SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
  536. DWORD Index;
  537. DWORD NewSidTotalSize;
  538. DWORD NewSidListCount;
  539. LPBYTE nextFreeByte;
  540. PSID_AND_ATTRIBUTES NewSidList = NULL;
  541. PTOKEN_GROUPS tokenGroupsPtr = NULL;
  542. PSID SePrincipalSelfSid = NULL;
  543. //
  544. // Generate the principal self sid value so we know what to replace.
  545. //
  546. if (ARGUMENT_PRESENT(InTokenOwner))
  547. {
  548. if (!NT_SUCCESS(RtlAllocateAndInitializeSid(&SIDAuth, 1,
  549. SECURITY_PRINCIPAL_SELF_RID, 0, 0, 0, 0, 0, 0, 0,
  550. &SePrincipalSelfSid))) goto ExitHandler;
  551. }
  552. //
  553. // Obtain the current SID membership list from the token.
  554. //
  555. ASSERT( ARGUMENT_PRESENT(InAccessToken) );
  556. tokenGroupsPtr = (PTOKEN_GROUPS) CodeAuthzpGetTokenInformation(InAccessToken, TokenGroups);
  557. if (!tokenGroupsPtr) goto ExitHandler;
  558. //
  559. // Edit (in place) the tokenGroups and keep only SIDs that
  560. // are not also present in SidsToInvert list.
  561. //
  562. NewSidTotalSize = 0;
  563. ASSERT( ARGUMENT_PRESENT(SidsToInvert) );
  564. for (Index = 0; Index < tokenGroupsPtr->GroupCount; Index++)
  565. {
  566. if ( CodeAuthzpSidInWildcardList(
  567. SidsToInvert, // the wildcard list
  568. InvertSidCount, // number of wildcards
  569. SePrincipalSelfSid, // principal self sid to search for
  570. InTokenOwner, // principal self sid to replace with
  571. tokenGroupsPtr->Groups[Index].Sid
  572. ))
  573. {
  574. // SID was found, so we need to remove its
  575. // SID_AND_ATTRIBUTES entry from the list.
  576. RtlMoveMemory(&tokenGroupsPtr->Groups[Index],
  577. &tokenGroupsPtr->Groups[Index+1],
  578. sizeof(SID_AND_ATTRIBUTES) *
  579. (tokenGroupsPtr->GroupCount - Index - 1));
  580. tokenGroupsPtr->GroupCount--;
  581. Index--;
  582. } else {
  583. // This SID should be kept, so remember how big it was.
  584. NewSidTotalSize += sizeof(SID_AND_ATTRIBUTES) +
  585. RtlLengthSid(tokenGroupsPtr->Groups[Index].Sid);
  586. }
  587. }
  588. //
  589. // Determine the space usage for any additional SIDs we need to add.
  590. //
  591. if (ARGUMENT_PRESENT(SidsToAdd))
  592. {
  593. for (Index = 0; Index < SidsAddedCount; Index++) {
  594. NewSidTotalSize += sizeof(SID_AND_ATTRIBUTES) +
  595. RtlLengthSid(SidsToAdd[Index].Sid);
  596. }
  597. } else {
  598. SidsAddedCount = 0;
  599. }
  600. //
  601. // Allocate a fresh SID_AND_ATTRIBUTES array that also includes
  602. // space for any extra SIDs we need to add.
  603. //
  604. ASSERT(NewSidTotalSize > 0);
  605. NewSidList = (PSID_AND_ATTRIBUTES) RtlAllocateHeap(RtlProcessHeap(),
  606. 0, NewSidTotalSize);
  607. if (NewSidList == NULL)
  608. goto ExitHandler;
  609. //
  610. // Populate the new SID_AND_ATTRIBUTES array.
  611. //
  612. nextFreeByte = ((LPBYTE)NewSidList) + sizeof(SID_AND_ATTRIBUTES) *
  613. (tokenGroupsPtr->GroupCount + SidsAddedCount);
  614. NewSidListCount = tokenGroupsPtr->GroupCount;
  615. for (Index = 0; Index < NewSidListCount; Index++)
  616. {
  617. DWORD dwSidLength = RtlLengthSid(tokenGroupsPtr->Groups[Index].Sid);
  618. ASSERT(nextFreeByte + dwSidLength <= ((LPBYTE)NewSidList) + NewSidTotalSize);
  619. NewSidList[Index].Sid = (PSID) nextFreeByte;
  620. NewSidList[Index].Attributes = 0; // must be zero.
  621. RtlCopyMemory(nextFreeByte, tokenGroupsPtr->Groups[Index].Sid, dwSidLength);
  622. nextFreeByte += dwSidLength;
  623. }
  624. for (Index = 0; Index < SidsAddedCount; Index++)
  625. {
  626. DWORD dwSidLength = RtlLengthSid(SidsToAdd[Index].Sid);
  627. ASSERT(nextFreeByte + dwSidLength <= ((LPBYTE) NewSidList) + NewSidTotalSize);
  628. NewSidList[NewSidListCount].Sid = (PSID) nextFreeByte;
  629. NewSidList[NewSidListCount].Attributes = 0; // must be zero.
  630. RtlCopyMemory(nextFreeByte, SidsToAdd[Index].Sid, dwSidLength);
  631. NewSidListCount++;
  632. nextFreeByte += dwSidLength;
  633. }
  634. ASSERT(nextFreeByte <= ((LPBYTE)NewSidList) + NewSidTotalSize);
  635. //
  636. // Release allocated memory, but not the resultant array that we'll return.
  637. //
  638. RtlFreeHeap(RtlProcessHeap(), 0, (LPVOID) tokenGroupsPtr);
  639. if (SePrincipalSelfSid != NULL)
  640. RtlFreeSid(SePrincipalSelfSid);
  641. //
  642. // Success, return the result.
  643. //
  644. *NewSidsToDisable = NewSidList;
  645. *NewDisabledSidCount = NewSidListCount;
  646. return TRUE;
  647. //
  648. // Release allocated memory.
  649. //
  650. ExitHandler:
  651. if (tokenGroupsPtr != NULL)
  652. RtlFreeHeap(RtlProcessHeap(), 0, (LPVOID) tokenGroupsPtr);
  653. if (NewSidList != NULL)
  654. RtlFreeHeap(RtlProcessHeap(), 0, (LPVOID) NewSidList);
  655. if (SePrincipalSelfSid != NULL)
  656. RtlFreeSid(SePrincipalSelfSid);
  657. return FALSE;
  658. }
  659. BOOLEAN NTAPI
  660. CodeAuthzpExpandWildcardList(
  661. IN HANDLE InAccessToken,
  662. IN PSID InTokenOwner OPTIONAL,
  663. IN DWORD WildcardCount,
  664. IN PAUTHZ_WILDCARDSID WildcardList,
  665. OUT DWORD *OutSidCount,
  666. OUT PSID_AND_ATTRIBUTES *OutSidList
  667. )
  668. /*++
  669. Routine Description:
  670. Takes an input token and extracts its membership groups.
  671. The specified list of Wildcard SIDs are used to identify
  672. all matching membership groups and an allocated list of all
  673. such SIDs are returned.
  674. Arguments:
  675. InAccessToken - Input token from which the membership group SIDs
  676. will be taken from.
  677. InTokenOwner - Optionally specifies the TokenUser of the specifies
  678. InAccessToken. This SID is used to replace any instances of
  679. SECURITY_PRINCIPAL_SELF_RID that are encountered in either
  680. the SidsToInvert or SidsToAdd arrays. If this value is not
  681. specified, then no replacements will be made.
  682. WildcardCount - Number of SIDs in the WildcardList array.
  683. WildcardList - Array of the allowable SIDs that should be kept.
  684. All of the token's group SIDs that are not one of these
  685. will be removed from the resulting set.
  686. OutSidCount - Receives the number of SIDs within the
  687. final group array.
  688. OutSidList - Receives a pointer to the final group array.
  689. This memory pointer must be freed by the caller with RtlFreeHeap().
  690. All SID pointers within this resultant array are pointers within
  691. the contiguous piece of memory that make up the list itself.
  692. Return Value:
  693. A value of TRUE indicates that the operation was successful,
  694. FALSE otherwise.
  695. --*/
  696. {
  697. SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
  698. DWORD Index;
  699. DWORD NewSidTotalSize;
  700. DWORD NewSidListCount;
  701. LPBYTE nextFreeByte;
  702. PSID_AND_ATTRIBUTES NewSidList = NULL;
  703. PTOKEN_GROUPS tokenGroupsPtr = NULL;
  704. PSID SePrincipalSelfSid = NULL;
  705. //
  706. // Generate the principal self sid value so we know what to replace.
  707. //
  708. if (ARGUMENT_PRESENT(InTokenOwner))
  709. {
  710. if (!NT_SUCCESS(RtlAllocateAndInitializeSid(&SIDAuth, 1,
  711. SECURITY_PRINCIPAL_SELF_RID, 0, 0, 0, 0, 0, 0, 0,
  712. &SePrincipalSelfSid))) goto ExitHandler;
  713. }
  714. //
  715. // Obtain the current SID membership list from the token.
  716. //
  717. ASSERT( ARGUMENT_PRESENT(InAccessToken) );
  718. tokenGroupsPtr = (PTOKEN_GROUPS) CodeAuthzpGetTokenInformation(InAccessToken, TokenGroups);
  719. if (!tokenGroupsPtr) goto ExitHandler;
  720. //
  721. // Edit (in place) the tokenGroups and keep only SIDs that
  722. // are not also present in SidsToInvert list.
  723. //
  724. NewSidTotalSize = 0;
  725. ASSERT( ARGUMENT_PRESENT(WildcardList) );
  726. for (Index = 0; Index < tokenGroupsPtr->GroupCount; Index++)
  727. {
  728. if ( CodeAuthzpSidInWildcardList(
  729. WildcardList, // the wildcard list
  730. WildcardCount, // number of wildcards
  731. SePrincipalSelfSid, // principal self sid to search for
  732. InTokenOwner, // principal self sid to replace with
  733. tokenGroupsPtr->Groups[Index].Sid
  734. ))
  735. {
  736. // This SID should be kept, so remember how big it was.
  737. NewSidTotalSize += sizeof(SID_AND_ATTRIBUTES) +
  738. RtlLengthSid(tokenGroupsPtr->Groups[Index].Sid);
  739. } else {
  740. // SID was not found, so we need to remove its
  741. // SID_AND_ATTRIBUTES entry from the list.
  742. RtlMoveMemory(&tokenGroupsPtr->Groups[Index],
  743. &tokenGroupsPtr->Groups[Index+1],
  744. sizeof(SID_AND_ATTRIBUTES) *
  745. (tokenGroupsPtr->GroupCount - Index - 1));
  746. tokenGroupsPtr->GroupCount--;
  747. Index--;
  748. }
  749. }
  750. //
  751. // Allocate a fresh SID_AND_ATTRIBUTES array that also includes
  752. // space for any extra SIDs we need to add.
  753. //
  754. NewSidList = (PSID_AND_ATTRIBUTES) RtlAllocateHeap(RtlProcessHeap(),
  755. 0, NewSidTotalSize);
  756. if (NewSidList == NULL)
  757. goto ExitHandler;
  758. //
  759. // Populate the new SID_AND_ATTRIBUTES array.
  760. //
  761. nextFreeByte = ((LPBYTE)NewSidList) + sizeof(SID_AND_ATTRIBUTES) *
  762. tokenGroupsPtr->GroupCount;
  763. NewSidListCount = tokenGroupsPtr->GroupCount;
  764. for (Index = 0; Index < NewSidListCount; Index++)
  765. {
  766. DWORD dwSidLength = RtlLengthSid(tokenGroupsPtr->Groups[Index].Sid);
  767. ASSERT(nextFreeByte + dwSidLength <= ((LPBYTE)NewSidList) + NewSidTotalSize);
  768. NewSidList[Index].Sid = (PSID) nextFreeByte;
  769. NewSidList[Index].Attributes = 0; // must be zero.
  770. RtlCopyMemory(nextFreeByte, tokenGroupsPtr->Groups[Index].Sid, dwSidLength);
  771. nextFreeByte += dwSidLength;
  772. }
  773. ASSERT(nextFreeByte <= ((LPBYTE)NewSidList) + NewSidTotalSize);
  774. //
  775. // Release allocated memory, but not the resultant array that we'll return.
  776. //
  777. RtlFreeHeap(RtlProcessHeap(), 0, (LPVOID) tokenGroupsPtr);
  778. if (SePrincipalSelfSid != NULL)
  779. RtlFreeSid(SePrincipalSelfSid);
  780. //
  781. // Success, return the result.
  782. //
  783. *OutSidList = NewSidList;
  784. *OutSidCount = NewSidListCount;
  785. return TRUE;
  786. //
  787. // Release allocated memory.
  788. //
  789. ExitHandler:
  790. if (tokenGroupsPtr != NULL)
  791. RtlFreeHeap(RtlProcessHeap(), 0, (LPVOID) tokenGroupsPtr);
  792. if (NewSidList != NULL)
  793. RtlFreeHeap(RtlProcessHeap(), 0, (LPVOID) NewSidList);
  794. if (SePrincipalSelfSid != NULL)
  795. RtlFreeSid(SePrincipalSelfSid);
  796. return FALSE;
  797. }