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.

1107 lines
32 KiB

  1. //+------------------------------------------------------------------
  2. //
  3. // Copyright (C) Microsoft Corporation, 1994 - 1996.
  4. //
  5. // File: member.cxx
  6. //
  7. // Classes: CMemberCheck
  8. //
  9. // History: Nov-94 DaveMont Created.
  10. //
  11. //-------------------------------------------------------------------
  12. #include <aclpch.hxx>
  13. #pragma hdrstop
  14. extern "C"
  15. {
  16. #include <ntprov.hxx>
  17. #include <strings.h>
  18. }
  19. SID WORLD_SID = {SID_REVISION,
  20. 1,
  21. SECURITY_WORLD_SID_AUTHORITY,
  22. SECURITY_WORLD_RID};
  23. #define MARTA_MAX_RECURSION_COUNT 256
  24. //+---------------------------------------------------------------------------
  25. //
  26. // Member: CMemberCheck::Init, public
  27. //
  28. // Synopsis: initializes the class
  29. //
  30. // Arguments: none
  31. //
  32. // Returns: ERROR_SUCCESS -- Success
  33. //
  34. //----------------------------------------------------------------------------
  35. DWORD CMemberCheck::Init()
  36. {
  37. acDebugOut((DEB_TRACE, "In CMemberCheck::Init\n"));
  38. DWORD dwErr = ERROR_SUCCESS;
  39. //
  40. // get the local machine name
  41. //
  42. ULONG cSize = MAX_COMPUTERNAME_LENGTH + 1;
  43. if(GetComputerName(_wszComputerName, &cSize) == FALSE)
  44. {
  45. dwErr = GetLastError();
  46. }
  47. acDebugOut((DEB_TRACE, "Out CMemberCheck::Init: %lu\n", dwErr));
  48. return(dwErr);
  49. }
  50. //+---------------------------------------------------------------------------
  51. //
  52. // Member: CMemberCheck::IsMemberOf, public
  53. //
  54. // Synopsis: Checks if the current sid is a member of the input sid.
  55. // The current sid is a part of our initialize TRUSTEE_NODE and
  56. // the input sid is in our passed in TRUSTEE_NODE
  57. //
  58. // Arguments: [IN pTrusteeNode] -- Input TRUSTEE_NODE
  59. // [OUT pfIsMemberOf] -- Where the results are returned.
  60. // Is TRUE if the initialization
  61. // SID is a member of the input
  62. // SID.
  63. //
  64. // Returns: ERROR_SUCCESS -- Success
  65. //
  66. //----------------------------------------------------------------------------
  67. DWORD CMemberCheck::IsMemberOf(IN PTRUSTEE_NODE pTrusteeNode,
  68. OUT PBOOL pfIsMemberOf)
  69. {
  70. acDebugOut((DEB_TRACE, "In CMemberCheck::IsMemberOf\n"));
  71. DWORD dwErr = ERROR_SUCCESS;
  72. if(RtlEqualSid(pTrusteeNode->pSid, &WORLD_SID) == TRUE)
  73. {
  74. *pfIsMemberOf = TRUE;
  75. }
  76. else if(RtlEqualSid(_pCurrentNode->pSid, pTrusteeNode->pSid) == TRUE)
  77. {
  78. //
  79. // If they're the same sid, they're bound to be a member of eachother
  80. //
  81. *pfIsMemberOf = TRUE;
  82. }
  83. else if(pTrusteeNode->SidType == SidTypeGroup)
  84. {
  85. //
  86. // We'll have to look it up, and check for group membership
  87. //
  88. dwErr = CheckGroup(pTrusteeNode->pSid,
  89. pfIsMemberOf,
  90. 1);
  91. }
  92. else if(pTrusteeNode->SidType == SidTypeAlias)
  93. {
  94. //
  95. // We'll have to expand the alias and look
  96. //
  97. dwErr = CheckAlias(pTrusteeNode->pSid,
  98. pfIsMemberOf,
  99. 1);
  100. }
  101. else
  102. {
  103. //
  104. // Well, here's something we don't know how to handle
  105. //
  106. *pfIsMemberOf = FALSE;
  107. }
  108. acDebugOut((DEB_TRACE,
  109. "Out CMemberCheck::IsMemberOf(%lx)(%d)\n",
  110. dwErr,
  111. *pfIsMemberOf));
  112. return(dwErr);
  113. }
  114. //+---------------------------------------------------------------------------
  115. //
  116. // Member: GetDomainName, private
  117. //
  118. // Synopsis: gets the domain name for the given sid
  119. //
  120. // Arguments: [IN pSid] -- Input Sid
  121. // [OUT ppwszDomainName] -- To return the domain name
  122. //
  123. // Returns: ERROR_SUCCESS -- Success
  124. //
  125. //----------------------------------------------------------------------------
  126. DWORD
  127. GetDomainName(
  128. IN PSID pSid,
  129. OUT PWSTR *ppwszDomainName
  130. )
  131. {
  132. LPWSTR Name = NULL;
  133. LPWSTR RefName = NULL;
  134. SID_NAME_USE SidType;
  135. //
  136. // Lookup the sid and get the name for the user.
  137. //
  138. DWORD dwErr = AccLookupAccountName(
  139. NULL,
  140. pSid,
  141. ppwszDomainName,
  142. &RefName,
  143. &SidType
  144. );
  145. if (dwErr == ERROR_SUCCESS)
  146. {
  147. //
  148. // The returned string is of the type "Domain\\User". Strip off the
  149. // backslash to get the name of the domain.
  150. //
  151. PWSTR pwszTmp = wcschr(*ppwszDomainName, L'\\');
  152. if(pwszTmp != NULL)
  153. {
  154. *pwszTmp = L'\0';
  155. }
  156. //
  157. // We do not need this one. Free it.
  158. //
  159. AccFree(RefName);
  160. }
  161. return dwErr;
  162. }
  163. //+---------------------------------------------------------------------------
  164. //
  165. // Member: CMemberCheck::GetDomainInfo, private
  166. //
  167. // Synopsis: gets the domain handle for the domain of the specified account
  168. //
  169. // Arguments: [IN pSid] -- Input Sid
  170. //
  171. // Returns: ERROR_SUCCESS -- Success
  172. // ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
  173. //
  174. //----------------------------------------------------------------------------
  175. DWORD CMemberCheck::GetDomainInfo(IN PSID pSid)
  176. {
  177. acDebugOut((DEB_TRACE, "In CMemberCheck::GetDomainInfo\n"));
  178. NTSTATUS Status = STATUS_SUCCESS;
  179. BOOL fSidMatched = FALSE;
  180. PISID pCheckSid;
  181. DWORD dwErr = LoadDLLFuncTable();
  182. if(dwErr != ERROR_SUCCESS)
  183. {
  184. return(dwErr);
  185. }
  186. //
  187. // allocate a spare sid so we can grovel in it for the domain id
  188. //
  189. pCheckSid = (PISID)AccAlloc(RtlLengthSid(pSid));
  190. if(pCheckSid != NULL)
  191. {
  192. Status = RtlCopySid(RtlLengthSid(pSid),
  193. pCheckSid,
  194. pSid);
  195. if(NT_SUCCESS(Status))
  196. {
  197. //
  198. // make it the domain identifier
  199. //
  200. if(pCheckSid->SubAuthorityCount > 1)
  201. {
  202. --(pCheckSid->SubAuthorityCount);
  203. }
  204. //
  205. // if we already have a domain sid, check it against the input sid
  206. //
  207. if(_pDomainSid != NULL)
  208. {
  209. if(RtlEqualSid(pCheckSid, _pDomainSid))
  210. {
  211. //
  212. // in this case we are all done.
  213. //
  214. AccFree(pCheckSid);
  215. pCheckSid = NULL;
  216. fSidMatched = TRUE;
  217. }
  218. }
  219. if ( fSidMatched == FALSE)
  220. {
  221. PDOMAIN_CONTROLLER_INFO DomainInfo = NULL;
  222. //
  223. // Free the current sid
  224. //
  225. AccFree(_pDomainSid);
  226. _pDomainSid = NULL;
  227. if(_hDomain)
  228. {
  229. (*DLLFuncs.PSamCloseHandle)(_hDomain);
  230. _hDomain = NULL;
  231. }
  232. SAM_HANDLE hSam = NULL;
  233. PWSTR pwszDomainName = NULL;
  234. dwErr = GetDomainName(pSid, &pwszDomainName);
  235. if(dwErr == ERROR_SUCCESS)
  236. {
  237. //
  238. // If we know the domain name of the input sid, check for
  239. // well known, and local names
  240. //
  241. if(pwszDomainName != NULL)
  242. {
  243. WCHAR wszStringBuffer[256];
  244. if (!LoadString(ghDll,
  245. ACCPROV_BUILTIN,
  246. wszStringBuffer,
  247. sizeof( wszStringBuffer ) / sizeof( WCHAR ))
  248. ) {
  249. wszStringBuffer[0] = L'\0';
  250. }
  251. if(_wcsicmp(pwszDomainName,
  252. wszStringBuffer) != 0)
  253. {
  254. if (!LoadString(ghDll,
  255. ACCPROV_NTAUTHORITY,
  256. wszStringBuffer,
  257. sizeof( wszStringBuffer ) / sizeof( WCHAR ))
  258. ) {
  259. wszStringBuffer[0] = L'\0';
  260. }
  261. if(_wcsicmp(pwszDomainName,
  262. wszStringBuffer) != 0)
  263. {
  264. if(_wcsicmp(_wszComputerName,
  265. pwszDomainName) != 0)
  266. {
  267. dwErr = DsGetDcName(NULL, pwszDomainName, NULL, NULL, 0, &DomainInfo);
  268. }
  269. }
  270. }
  271. }
  272. if(dwErr == ERROR_SUCCESS)
  273. {
  274. UNICODE_STRING UnicodeString = {0};
  275. if (DomainInfo != NULL)
  276. {
  277. RtlInitUnicodeString(&UnicodeString, DomainInfo->DomainControllerName);
  278. }
  279. OBJECT_ATTRIBUTES ObjAttrib;
  280. Status = (*DLLFuncs.PSamConnect)(
  281. DomainInfo ? &UnicodeString : NULL,
  282. &hSam,
  283. GENERIC_EXECUTE,
  284. &ObjAttrib);
  285. if(NT_SUCCESS(Status))
  286. {
  287. //
  288. // open the domain
  289. //
  290. Status = (*DLLFuncs.PSamOpenDomain)(
  291. hSam,
  292. GENERIC_READ | DOMAIN_LOOKUP,
  293. pCheckSid,
  294. &_hDomain);
  295. (*DLLFuncs.PSamCloseHandle)(hSam);
  296. }
  297. dwErr = RtlNtStatusToDosError(Status);
  298. }
  299. if (DomainInfo)
  300. {
  301. NetApiBufferFree(DomainInfo);
  302. DomainInfo = NULL;
  303. }
  304. AccFree(pwszDomainName);
  305. if(dwErr == ERROR_SUCCESS)
  306. {
  307. //
  308. // We have a new DomainSid
  309. //
  310. _pDomainSid = pCheckSid;
  311. pCheckSid = NULL;
  312. }
  313. }
  314. }
  315. }
  316. else
  317. {
  318. dwErr = RtlNtStatusToDosError(Status);
  319. }
  320. }
  321. else
  322. {
  323. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  324. }
  325. if (pCheckSid != NULL)
  326. {
  327. AccFree(pCheckSid);
  328. }
  329. acDebugOut((DEB_TRACE, "Out CMemberCheck::_GetDomainInfo: %lu\n",
  330. dwErr));
  331. return(dwErr);
  332. }
  333. //+---------------------------------------------------------------------------
  334. //
  335. // Member: CMemberCheck::CheckDomainUsers, private
  336. //
  337. // Synopsis: Checks if the Group is Domain Users and if the Users Domain sid
  338. // is the same as that of the group.
  339. //
  340. // Arguments: [IN pSid] -- Input Sid
  341. // [OUT pfIsMemberOf] -- Where the results are returned.
  342. // Is TRUE if the current SID
  343. // is a member of the input SID
  344. // group.
  345. // [OUT pbQuitEarly] -- Is TRUE if the group is Domain Users
  346. //
  347. // Returns: ERROR_SUCCESS -- Success
  348. //
  349. //----------------------------------------------------------------------------
  350. DWORD CMemberCheck::CheckDomainUsers(IN PSID pSid,
  351. OUT PBOOL pfIsMemberOf,
  352. OUT PBOOL pbQuitEarly)
  353. {
  354. DWORD Rid = ((PISID) pSid)->SubAuthority[((PISID) pSid)->SubAuthorityCount-1];
  355. BOOL b = FALSE;
  356. BOOL bEqual = FALSE;
  357. SAM_HANDLE hUser = 0;
  358. PUCHAR Buffer = NULL;
  359. NTSTATUS status = STATUS_SUCCESS;
  360. if (Rid != DOMAIN_GROUP_RID_USERS)
  361. {
  362. //
  363. // No need to do anything. Just return.
  364. //
  365. return ERROR_SUCCESS;
  366. }
  367. //
  368. // Since it is domain users we will quit early.
  369. //
  370. *pbQuitEarly = TRUE;
  371. b = EqualDomainSid(pSid, _pCurrentNode->pSid, &bEqual);
  372. //
  373. // ERROR_NON_DOMAIN_SID is returned for wellknown sids.
  374. // It is ok to ignore this error and continue.
  375. //
  376. if ((b == FALSE) && (GetLastError() != ERROR_NON_DOMAIN_SID))
  377. {
  378. return GetLastError();
  379. }
  380. //
  381. // If the domains do not match, return FALSE.
  382. //
  383. if (!bEqual)
  384. {
  385. return ERROR_SUCCESS;
  386. }
  387. //
  388. // Get the Rid for the user.
  389. //
  390. DWORD dwRelativeId = *RtlSubAuthoritySid(
  391. _pCurrentNode->pSid,
  392. *RtlSubAuthorityCountSid(_pCurrentNode->pSid) - 1
  393. );
  394. //
  395. // Open the user for read.
  396. //
  397. status = SamOpenUser(
  398. _hDomain,
  399. USER_READ_GENERAL,
  400. dwRelativeId,
  401. &hUser
  402. );
  403. if (!NT_SUCCESS(status))
  404. {
  405. return RtlNtStatusToDosError(status);
  406. }
  407. //
  408. // Get the primary group information for the user.
  409. //
  410. status = SamQueryInformationUser(
  411. hUser,
  412. UserPrimaryGroupInformation,
  413. (PVOID *) &Buffer
  414. );
  415. SamCloseHandle(hUser);
  416. if (!NT_SUCCESS(status))
  417. {
  418. return RtlNtStatusToDosError(status);
  419. }
  420. //
  421. // If the primary group matched then return TRUE.
  422. //
  423. if (DOMAIN_GROUP_RID_USERS == ((USER_PRIMARY_GROUP_INFORMATION *) Buffer)->PrimaryGroupId)
  424. {
  425. *pfIsMemberOf = TRUE;
  426. }
  427. (VOID) SamFreeMemory(Buffer);
  428. return ERROR_SUCCESS;
  429. }
  430. //+---------------------------------------------------------------------------
  431. //
  432. // Member: CMemberCheck::CheckGroup, private
  433. //
  434. // Synopsis: Checks if the objects account is in the specifed group
  435. // account
  436. //
  437. // Arguments: [IN pSid] -- Input Sid
  438. // [OUT pfIsMemberOf] -- Where the results are returned.
  439. // Is TRUE if the current SID
  440. // is a member of the input SID
  441. // group.
  442. // [IN RecursionCount] -- Recursion level
  443. //
  444. // Returns: ERROR_SUCCESS -- Success
  445. //
  446. //----------------------------------------------------------------------------
  447. DWORD CMemberCheck::CheckGroup(IN PSID pSid,
  448. OUT PBOOL pfIsMemberOf,
  449. IN DWORD RecursionCount)
  450. {
  451. acDebugOut((DEB_TRACE, "In CMemberCheck::CheckGroup\n"));
  452. NTSTATUS Status;
  453. SAM_HANDLE hSam = NULL;
  454. ULONG rid = ((PISID)(pSid))->SubAuthority[
  455. ((PISID)(pSid))->SubAuthorityCount-1];
  456. BYTE LocalBuffer[8 + 4 * SID_MAX_SUB_AUTHORITIES];
  457. PISID LocalSid = (PISID) LocalBuffer;
  458. PULONG attributes = NULL;
  459. PULONG Members = NULL;
  460. ULONG cMembers;
  461. DWORD dwErr;
  462. BOOL bQuitEarly = FALSE;
  463. *pfIsMemberOf = FALSE;
  464. if (RecursionCount > MARTA_MAX_RECURSION_COUNT)
  465. {
  466. return ERROR_CIRCULAR_DEPENDENCY;
  467. }
  468. dwErr = LoadDLLFuncTable();
  469. if (dwErr != ERROR_SUCCESS)
  470. {
  471. acDebugOut((DEB_TRACE, "Out CMemberCheck::CheckGroup: %lu\n", dwErr));
  472. return(dwErr);
  473. }
  474. dwErr = GetDomainInfo(pSid);
  475. if(dwErr != ERROR_SUCCESS)
  476. {
  477. acDebugOut((DEB_TRACE, "Out CMemberCheck::CheckGroup: %lu\n", dwErr));
  478. return(dwErr);
  479. }
  480. Status = RtlCopySid(RtlLengthSid(_pDomainSid), LocalSid, _pDomainSid);
  481. if(!NT_SUCCESS(Status))
  482. {
  483. return RtlNtStatusToDosError(Status);
  484. }
  485. //
  486. // Special case the Domain Users sid.
  487. //
  488. dwErr = CheckDomainUsers(pSid, pfIsMemberOf, &bQuitEarly);
  489. if (dwErr != ERROR_SUCCESS)
  490. {
  491. return(dwErr);
  492. }
  493. if (bQuitEarly)
  494. {
  495. //
  496. // We are looking at Domain Users group. No need to enumerate this one.
  497. //
  498. return ERROR_SUCCESS;
  499. }
  500. //
  501. // open the group
  502. //
  503. Status = (*DLLFuncs.PSamOpenGroup)(_hDomain,
  504. GENERIC_READ,
  505. rid,
  506. &hSam);
  507. if(NT_SUCCESS(Status))
  508. {
  509. //
  510. // Get the members
  511. //
  512. Status = (*DLLFuncs.PSamGetMembersInGroup)(hSam,
  513. &Members,
  514. &attributes,
  515. &cMembers);
  516. if(NT_SUCCESS(Status) && cMembers )
  517. {
  518. //
  519. // ugly sid rid twiddling
  520. //
  521. ++(LocalSid->SubAuthorityCount);
  522. //
  523. // loop thru the members and check if the user sid is an immediate
  524. // member.
  525. //
  526. for (ULONG iIndex = 0; iIndex < cMembers; iIndex++ )
  527. {
  528. //
  529. // Plug the rid into the sid
  530. //
  531. LocalSid->SubAuthority[LocalSid->SubAuthorityCount-1] =
  532. Members[iIndex];
  533. //
  534. // and compare
  535. //
  536. if(RtlEqualSid(_pCurrentNode->pSid,LocalSid) == TRUE)
  537. {
  538. *pfIsMemberOf = TRUE;
  539. break;
  540. }
  541. }
  542. //
  543. // If we did not match the sid, enumerate recursively.
  544. //
  545. if (*pfIsMemberOf == FALSE)
  546. {
  547. ULONG SidLength = RtlLengthSid(LocalSid);
  548. ULONG TotalSize = cMembers * (sizeof(PSID) + SidLength);
  549. PUCHAR Buffer = NULL;
  550. PSID *Sids = NULL;
  551. //
  552. // Allocate memory to hold the sid array.
  553. //
  554. Buffer = (PUCHAR) AccAlloc(TotalSize);
  555. Sids = (PSID *) Buffer;
  556. if (Sids != NULL)
  557. {
  558. PLSA_TRANSLATED_NAME Names = NULL;
  559. Buffer += (sizeof(PSID) * cMembers);
  560. //
  561. // Copy the sids into the allocated array.
  562. //
  563. for (ULONG iIndex = 0; iIndex < cMembers; iIndex++ )
  564. {
  565. Sids[iIndex] = Buffer;
  566. Buffer += SidLength;
  567. LocalSid->SubAuthority[LocalSid->SubAuthorityCount-1] =
  568. Members[iIndex];
  569. Status = RtlCopySid(SidLength, Sids[iIndex], LocalSid);
  570. if (!NT_SUCCESS( Status ))
  571. {
  572. break;
  573. }
  574. }
  575. if (NT_SUCCESS( Status ))
  576. {
  577. //
  578. // Do a single lookup and get the types of the sids
  579. // in the group.
  580. //
  581. dwErr = GetSidTypeMultiple(
  582. cMembers,
  583. Sids,
  584. &Names
  585. );
  586. if (dwErr == ERROR_SUCCESS)
  587. {
  588. //
  589. // Loop thru the sids and call the recursive routines
  590. // if the sidtype is a group or alias.
  591. //
  592. for (ULONG iIndex = 0; iIndex < cMembers; iIndex++ )
  593. {
  594. if (Names[iIndex].Use == SidTypeGroup)
  595. {
  596. dwErr = CheckGroup(Sids[iIndex], pfIsMemberOf, RecursionCount+1);
  597. if (dwErr != ERROR_SUCCESS)
  598. {
  599. break;
  600. }
  601. if (*pfIsMemberOf == TRUE)
  602. {
  603. //
  604. // We have a match. There is no need to
  605. // enumerate any more.
  606. //
  607. break;
  608. }
  609. }
  610. else if (Names[iIndex].Use == SidTypeAlias)
  611. {
  612. dwErr = CheckAlias(Sids[iIndex], pfIsMemberOf, RecursionCount+1);
  613. if (dwErr != ERROR_SUCCESS)
  614. {
  615. break;
  616. }
  617. if (*pfIsMemberOf == TRUE)
  618. {
  619. //
  620. // We have a match. There is no need to
  621. // enumerate any more.
  622. //
  623. break;
  624. }
  625. }
  626. }
  627. (VOID) LsaFreeMemory(Names);
  628. }
  629. }
  630. AccFree(Sids);
  631. }
  632. else
  633. {
  634. Status = STATUS_NO_MEMORY;
  635. }
  636. }
  637. }
  638. if (attributes != NULL)
  639. {
  640. LocalFree(attributes);
  641. attributes = NULL;
  642. }
  643. if (Members != NULL)
  644. {
  645. LocalFree(Members);
  646. Members = NULL;
  647. }
  648. (*DLLFuncs.PSamCloseHandle)(hSam);
  649. }
  650. if(!NT_SUCCESS(Status))
  651. {
  652. dwErr = RtlNtStatusToDosError(Status);
  653. }
  654. acDebugOut((DEB_TRACE, "Out CMemberCheck::CheckGroup: %lu\n", dwErr));
  655. return(dwErr);
  656. }
  657. //+---------------------------------------------------------------------------
  658. //
  659. // Member: CMemberCheck::GetSidType, private
  660. //
  661. // Synopsis: Returns the type of the Sid
  662. //
  663. // Arguments: [IN pSid] -- Input Sid
  664. // [OUT pSidType] -- Returns the type of Sid.
  665. //
  666. // Returns: ERROR_SUCCESS -- Success
  667. //
  668. //----------------------------------------------------------------------------
  669. DWORD CMemberCheck::GetSidType(
  670. IN PSID Sid,
  671. OUT SID_NAME_USE *pSidType)
  672. {
  673. LPWSTR Name = NULL;
  674. LPWSTR DomainName = NULL;
  675. DWORD dwErr;
  676. dwErr = AccLookupAccountName(NULL,
  677. Sid,
  678. &Name,
  679. &DomainName,
  680. pSidType);
  681. if (dwErr == ERROR_SUCCESS)
  682. {
  683. AccFree(Name);
  684. AccFree(DomainName);
  685. }
  686. return dwErr;
  687. }
  688. //+---------------------------------------------------------------------------
  689. //
  690. // Member: CMemberCheck::GetSidTypeMultiple, private
  691. //
  692. // Synopsis: Returns the tanslated names of the Sids
  693. //
  694. // Arguments: [IN Count] -- Number of sids
  695. // [IN pSid] -- Input Sid
  696. // [OUT pNames] -- Returns lsa names structure
  697. //
  698. // Returns: ERROR_SUCCESS -- Success
  699. //
  700. //----------------------------------------------------------------------------
  701. DWORD CMemberCheck::GetSidTypeMultiple(
  702. IN LONG Count,
  703. IN PSID *Sids,
  704. OUT PLSA_TRANSLATED_NAME *pNames
  705. )
  706. {
  707. OBJECT_ATTRIBUTES ObjectAttributes;
  708. LSA_HANDLE PolicyHandle;
  709. PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains;
  710. PLSA_TRANSLATED_NAME Names = NULL;
  711. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  712. NTSTATUS Status;
  713. NTSTATUS TmpStatus;
  714. *pNames = NULL;
  715. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  716. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  717. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  718. SecurityQualityOfService.EffectiveOnly = FALSE;
  719. //
  720. // Set up the object attributes prior to opening the LSA.
  721. //
  722. InitializeObjectAttributes(
  723. &ObjectAttributes,
  724. NULL,
  725. 0L,
  726. NULL,
  727. NULL
  728. );
  729. //
  730. // The InitializeObjectAttributes macro presently stores NULL for
  731. // the SecurityQualityOfService field, so we must manually copy that
  732. // structure for now.
  733. //
  734. ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
  735. Status = LsaOpenPolicy(
  736. NULL,
  737. &ObjectAttributes,
  738. POLICY_LOOKUP_NAMES,
  739. &PolicyHandle
  740. );
  741. if ( !NT_SUCCESS( Status )) {
  742. return RtlNtStatusToDosError(Status);
  743. }
  744. Status = LsaLookupSids(
  745. PolicyHandle,
  746. Count,
  747. Sids,
  748. &ReferencedDomains,
  749. &Names
  750. );
  751. TmpStatus = LsaClose( PolicyHandle );
  752. //
  753. // If an error was returned, check specifically for STATUS_NONE_MAPPED.
  754. // In this case, we may need to dispose of the returned Referenced Domain
  755. // List and Names structures. For all other errors, LsaLookupSids()
  756. // frees these structures prior to exit.
  757. //
  758. if ( !NT_SUCCESS( Status )) {
  759. if (Status == STATUS_NONE_MAPPED) {
  760. if (ReferencedDomains != NULL) {
  761. TmpStatus = LsaFreeMemory( ReferencedDomains );
  762. ASSERT( NT_SUCCESS( TmpStatus ));
  763. }
  764. if (Names != NULL) {
  765. TmpStatus = LsaFreeMemory( Names );
  766. ASSERT( NT_SUCCESS( TmpStatus ));
  767. }
  768. }
  769. return RtlNtStatusToDosError(Status);
  770. }
  771. if (ReferencedDomains != NULL) {
  772. Status = LsaFreeMemory( ReferencedDomains );
  773. ASSERT( NT_SUCCESS( Status ));
  774. }
  775. *pNames = Names;
  776. return ERROR_SUCCESS;
  777. }
  778. //+---------------------------------------------------------------------------
  779. //
  780. // Member: CMemberCheck::CheckAlias, private
  781. //
  782. // Synopsis: checks if the objects account is in the specifed alias account
  783. //
  784. // Arguments: [IN pSid] -- Input Sid
  785. // [OUT pfIsMemberOf] -- Where the results are returned.
  786. // Is TRUE if the current SID
  787. // is a member of the input SID
  788. // group.
  789. // [IN RecursionCount] -- Recursion level
  790. //
  791. // Returns: ERROR_SUCCESS -- Success
  792. //
  793. //----------------------------------------------------------------------------
  794. DWORD CMemberCheck::CheckAlias(IN PSID pSid,
  795. OUT PBOOL pfIsMemberOf,
  796. IN DWORD RecursionCount)
  797. {
  798. acDebugOut((DEB_TRACE, "In CMemberCheck::CheckAlias\n"));
  799. NTSTATUS Status;
  800. SAM_HANDLE hSam = NULL;
  801. ULONG rid = ((PISID)(pSid))->SubAuthority[
  802. ((PISID)(pSid))->SubAuthorityCount-1];
  803. ULONG_PTR * Members;
  804. ULONG cMembers;
  805. DWORD dwErr;
  806. *pfIsMemberOf = FALSE;
  807. if (RecursionCount > MARTA_MAX_RECURSION_COUNT)
  808. {
  809. return ERROR_CIRCULAR_DEPENDENCY;
  810. }
  811. dwErr = LoadDLLFuncTable();
  812. if (dwErr != ERROR_SUCCESS)
  813. {
  814. acDebugOut((DEB_TRACE, "Out CMemberCheck::CheckGroup: %lu\n", dwErr));
  815. return(dwErr);
  816. }
  817. dwErr = GetDomainInfo(pSid);
  818. if(dwErr != ERROR_SUCCESS)
  819. {
  820. acDebugOut((DEB_TRACE, "Out CMemberCheck::CheckGroup: %lu\n", dwErr));
  821. return(dwErr);
  822. }
  823. //
  824. // open the alias
  825. //
  826. Status = (*DLLFuncs.PSamOpenAlias)(_hDomain,
  827. GENERIC_READ,
  828. rid,
  829. &hSam);
  830. if(NT_SUCCESS(Status))
  831. {
  832. //
  833. // get the members
  834. //
  835. Status = (*DLLFuncs.PSamGetMembersInAlias)(hSam,
  836. (void ***)&Members,
  837. &cMembers);
  838. if(NT_SUCCESS(Status) && cMembers)
  839. {
  840. //
  841. // loop thru the members
  842. //
  843. for (ULONG iIndex = 0; iIndex < cMembers; iIndex++)
  844. {
  845. if(RtlEqualSid(_pCurrentNode->pSid,
  846. ((SID **)(Members))[iIndex]) == TRUE)
  847. {
  848. *pfIsMemberOf = TRUE;
  849. break;
  850. }
  851. }
  852. //
  853. // If we did not match the sid, enumerate recursively.
  854. //
  855. if (*pfIsMemberOf == FALSE)
  856. {
  857. PLSA_TRANSLATED_NAME Names = NULL;
  858. //
  859. // Do a single lookup and get the types of the sids
  860. // in the group.
  861. //
  862. dwErr = GetSidTypeMultiple(
  863. cMembers,
  864. (PSID *) Members,
  865. &Names
  866. );
  867. if (dwErr == ERROR_SUCCESS)
  868. {
  869. //
  870. // Loop thru the sids and call the recursive routines
  871. // if the sidtype is a group or an alias.
  872. //
  873. for (ULONG iIndex = 0; iIndex < cMembers; iIndex++ )
  874. {
  875. if (Names[iIndex].Use == SidTypeGroup)
  876. {
  877. dwErr = CheckGroup(((SID **) (Members))[iIndex], pfIsMemberOf, RecursionCount+1);
  878. if (dwErr != ERROR_SUCCESS)
  879. {
  880. break;
  881. }
  882. if (*pfIsMemberOf == TRUE)
  883. {
  884. //
  885. // We have a match. There is no need to
  886. // enumerate any more.
  887. //
  888. break;
  889. }
  890. }
  891. else if (Names[iIndex].Use == SidTypeAlias)
  892. {
  893. dwErr = CheckAlias(((SID **) (Members))[iIndex], pfIsMemberOf, RecursionCount+1);
  894. if (dwErr != ERROR_SUCCESS)
  895. {
  896. break;
  897. }
  898. if (*pfIsMemberOf == TRUE)
  899. {
  900. //
  901. // We have a match. There is no need to
  902. // enumerate any more.
  903. //
  904. break;
  905. }
  906. }
  907. }
  908. (VOID) LsaFreeMemory(Names);
  909. }
  910. }
  911. if(cMembers > 0)
  912. {
  913. LocalFree(Members);
  914. }
  915. }
  916. (*DLLFuncs.PSamCloseHandle)(hSam);
  917. }
  918. if(!NT_SUCCESS(Status))
  919. {
  920. dwErr = RtlNtStatusToDosError(Status);
  921. }
  922. acDebugOut((DEB_TRACE, "Out CMemberCheck::CheckGroup: %lu\n", dwErr));
  923. return(dwErr);
  924. }