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.

4703 lines
109 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. context.c
  5. Abstract:
  6. This module implements the internal worker routines to create and manipulate
  7. client context.
  8. Author:
  9. Kedar Dubhashi - March 2000
  10. Environment:
  11. User mode only.
  12. Revision History:
  13. Created - March 2000
  14. --*/
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include <authzp.h>
  18. LUID AuthzTakeOwnershipPrivilege = {SE_TAKE_OWNERSHIP_PRIVILEGE, 0};
  19. LUID AuthzSecurityPrivilege = {SE_SECURITY_PRIVILEGE, 0};
  20. //
  21. // Definitions used by AuthzpGetAllGroups.
  22. //
  23. const DWORD c_dwMaxSidCount = LSAI_CONTEXT_SID_LIMIT;
  24. static DWORD s_dwPageSize = 0;
  25. typedef struct _SID_DESC
  26. {
  27. DWORD dwAttributes;
  28. DWORD dwLength;
  29. BYTE sid[SECURITY_MAX_SID_SIZE];
  30. }
  31. SID_DESC, *PSID_DESC;
  32. typedef struct _SID_SET
  33. {
  34. DWORD dwCount;
  35. DWORD dwMaxCount;
  36. PSID_DESC pSidDesc;
  37. DWORD dwFlags;
  38. DWORD dwBaseCount;
  39. // user information
  40. PSID pUserSid;
  41. PSID pDomainSid;
  42. PUNICODE_STRING pusUserName;
  43. PUNICODE_STRING pusDomainName;
  44. // user name & domain
  45. PLSA_TRANSLATED_NAME pNames;
  46. PLSA_REFERENCED_DOMAIN_LIST pDomains;
  47. PWSTR pDomainsName;
  48. PLSA_TRANSLATED_SID2 pSids;
  49. SID_NAME_USE sidUse;
  50. // information about the local machine
  51. PPOLICY_ACCOUNT_DOMAIN_INFO pAccountInfo;
  52. PPOLICY_PRIMARY_DOMAIN_INFO pPrimaryInfo;
  53. PWSTR pPrimaryInfoName;
  54. BOOL bStandalone;
  55. BOOL bSkipNonLocal;
  56. // user domain dc info
  57. PDOMAIN_CONTROLLER_INFO pUdDcInfo;
  58. PDOMAIN_CONTROLLER_INFO pPdDcInfo;
  59. PDOMAIN_CONTROLLER_INFO pRdDcInfo;
  60. // role information for user domain & primary domain
  61. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pUdBasicInfo;
  62. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPdBasicInfo;
  63. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pRdBasicInfo;
  64. // name of the user domain DC
  65. PWSTR pszUdDcName;
  66. PWSTR pszRdDcName;
  67. }
  68. SID_SET, *PSID_SET;
  69. //
  70. // Forward declarations of functions called by
  71. // AuthzpGetAllGroups.
  72. //
  73. DWORD
  74. AuthzpAddWellKnownSids(
  75. IN OUT PSID_SET pSidSet
  76. );
  77. DWORD
  78. AuthzpGetTokenGroupsXp(
  79. IN OUT PSID_SET pSidSet
  80. );
  81. DWORD
  82. AuthzpGetTokenGroupsDownlevel(
  83. IN OUT PSID_SET pSidSet
  84. );
  85. DWORD
  86. AuthzpGetAccountDomainGroupsDs(
  87. IN OUT PSID_SET pSidSet
  88. );
  89. DWORD
  90. AuthzpGetAccountDomainGroupsSam(
  91. IN OUT PSID_SET pSidSet
  92. );
  93. DWORD
  94. AuthzpGetResourceDomainGroups(
  95. IN OUT PSID_SET pSidSet
  96. );
  97. DWORD
  98. AuthzpGetLocalGroups(
  99. IN BOOL bAddPrimaryGroup,
  100. IN OUT PSID_SET pSidSet
  101. );
  102. DWORD
  103. AuthzpGetSidHistory(
  104. IN OUT PSID_SET pSidSet
  105. );
  106. DWORD
  107. AuthzpGetPrimaryGroup(
  108. IN SAM_HANDLE hSam,
  109. IN OUT PSID_SET pSidSet
  110. );
  111. DWORD
  112. AuthzpGetAliasMembership(
  113. IN SAM_HANDLE hSam,
  114. IN PSID pDomainSid,
  115. IN OUT PSID_SET pSidSet
  116. );
  117. DWORD
  118. AuthzpInitializeSidSetByName(
  119. IN PUNICODE_STRING pusUserName,
  120. IN PUNICODE_STRING pusDomainName,
  121. IN DWORD dwFlags,
  122. IN PSID_SET pSidSet
  123. );
  124. DWORD
  125. AuthzpIsDC(
  126. OUT PBOOL pbIsDC
  127. );
  128. DWORD
  129. AuthzpInitializeSidSetBySid(
  130. IN PSID pUserSid,
  131. IN DWORD dwFlags,
  132. IN PSID_SET pSidSet
  133. );
  134. DWORD
  135. AuthzpDeleteSidSet(
  136. IN PSID_SET pSidSet
  137. );
  138. DWORD
  139. AuthzpAddSidToSidSet(
  140. IN PSID_SET pSidSet,
  141. IN PSID pSid,
  142. IN DWORD dwSidLength,
  143. IN DWORD dwAttributes,
  144. OUT PBOOL pbAdded OPTIONAL,
  145. OUT PSID* ppSid OPTIONAL
  146. );
  147. DWORD
  148. AuthzpGetUserDomainSid(
  149. IN OUT PSID_SET pSidSet
  150. );
  151. DWORD
  152. AuthzpGetUserDomainName(
  153. IN OUT PSID_SET pSidSet
  154. );
  155. DWORD
  156. AuthzpGetLocalInfo(
  157. IN OUT PSID_SET pSidSet
  158. );
  159. DWORD
  160. AuthzpGetDcName(
  161. IN LPCTSTR pszDomain,
  162. IN OUT PDOMAIN_CONTROLLER_INFO* ppDcInfo
  163. );
  164. VOID
  165. AuthzpConvertSidToEdn(
  166. IN PSID pSid,
  167. OUT PWSTR pszSid
  168. );
  169. BOOL
  170. AuthzpCopySidsAndAttributes(
  171. IN OUT PSID_AND_ATTRIBUTES DestSidAttr,
  172. IN PSID_AND_ATTRIBUTES SidAttr1,
  173. IN DWORD Count1,
  174. IN PSID_AND_ATTRIBUTES SidAttr2,
  175. IN DWORD Count2
  176. )
  177. /*++
  178. Routine description:
  179. This routine takes two sets of sid and attribute strucutes and concatenates
  180. them into a single one. The new structure is constructed into the buffer
  181. supplied by the caller.
  182. Arguments:
  183. DestSidAttr - Caller supplied buffer into which the resultant structure
  184. will be copied. The caller has already computed the size of the buffer
  185. required to hold the output.
  186. SidAttr1 - The first sid and attributes structure.
  187. Count1 - The number of elements in SidAttr1 structure.
  188. SidAttr2 - The second sid and attributes structure.
  189. Count2 - The number of elements in SidAttr2 structure.
  190. Return Value:
  191. A value of TRUE is returned if the routine is successful. Otherwise,
  192. a value of FALSE is returned. In the failure case, error value may be
  193. retrieved using GetLastError().
  194. --*/
  195. {
  196. PUCHAR pCurrent = ((PUCHAR) DestSidAttr) + (sizeof(SID_AND_ATTRIBUTES) * (Count1 + Count2));
  197. NTSTATUS Status = STATUS_SUCCESS;
  198. DWORD Length = 0;
  199. DWORD i = 0;
  200. //
  201. // Loop thru the first set and copy the sids and their attribtes.
  202. //
  203. for (i = 0; i < Count1; i++)
  204. {
  205. Length = RtlLengthSid(SidAttr1[i].Sid);
  206. Status = RtlCopySid(
  207. Length,
  208. pCurrent,
  209. SidAttr1[i].Sid
  210. );
  211. if (!NT_SUCCESS(Status))
  212. {
  213. SetLastError(RtlNtStatusToDosError(Status));
  214. return FALSE;
  215. }
  216. DestSidAttr[i].Sid = (PSID) pCurrent;
  217. DestSidAttr[i].Attributes = SidAttr1[i].Attributes;
  218. pCurrent += Length;
  219. }
  220. //
  221. // Loop thru the second set and copy the sids and their attribtes.
  222. //
  223. for (; i < (Count1 + Count2); i++)
  224. {
  225. Length = RtlLengthSid(SidAttr2[i - Count1].Sid);
  226. Status = RtlCopySid(
  227. Length,
  228. pCurrent,
  229. SidAttr2[i - Count1].Sid
  230. );
  231. if (!NT_SUCCESS(Status))
  232. {
  233. SetLastError(RtlNtStatusToDosError(Status));
  234. return FALSE;
  235. }
  236. DestSidAttr[i].Sid = (PSID) pCurrent;
  237. DestSidAttr[i].Attributes = SidAttr2[i - Count1].Attributes;
  238. pCurrent += Length;
  239. }
  240. return TRUE;
  241. }
  242. VOID
  243. AuthzpCopyLuidAndAttributes(
  244. IN OUT PAUTHZI_CLIENT_CONTEXT pCC,
  245. IN PLUID_AND_ATTRIBUTES Source,
  246. IN DWORD Count,
  247. IN OUT PLUID_AND_ATTRIBUTES Destination
  248. )
  249. /*++
  250. Routine description:
  251. This routine takes a luid and attributes array and copies them into a caller
  252. supplied buffer. It also records presence of SecurityPrivilege and
  253. SeTakeOwnershipPrivilege into the client context flags.
  254. Arguments:
  255. pCC - Pointer to the client context structure into which the presence of
  256. privileges would be recorded.
  257. Source - The array of privileges and attributes to be copied into a supplied
  258. buffer.
  259. Count - Number of elements in the array.
  260. Destination - Caller allocated buffer into which the input array will be
  261. copied.
  262. Return Value:
  263. A value of TRUE is returned if the routine is successful. Otherwise,
  264. a value of FALSE is returned. In the failure case, error value may be
  265. retrieved using GetLastError().
  266. --*/
  267. {
  268. DWORD i = 0;
  269. for (i = 0; i < Count; i++)
  270. {
  271. //
  272. // Record the presence of SecurityPrivilege or SeTakeOwnershipPrivilege.
  273. //
  274. if ((RtlEqualLuid(&AuthzTakeOwnershipPrivilege, &Source[i].Luid)) &&
  275. (Source[i].Attributes & SE_PRIVILEGE_ENABLED))
  276. {
  277. pCC->Flags |= AUTHZ_TAKE_OWNERSHIP_PRIVILEGE_ENABLED;
  278. }
  279. else if ((RtlEqualLuid(&AuthzSecurityPrivilege, &Source[i].Luid)) &&
  280. (Source[i].Attributes & SE_PRIVILEGE_ENABLED))
  281. {
  282. pCC->Flags |= AUTHZ_SECURITY_PRIVILEGE_ENABLED;
  283. }
  284. RtlCopyLuid(&(Destination[i].Luid), &(Source[i].Luid));
  285. Destination[i].Attributes = Source[i].Attributes;
  286. }
  287. }
  288. BOOL
  289. AuthzpGetAllGroupsByName(
  290. IN PUNICODE_STRING pusUserName,
  291. IN PUNICODE_STRING pusDomainName,
  292. IN DWORD dwFlags,
  293. OUT PSID_AND_ATTRIBUTES* ppSidAndAttributes,
  294. OUT PDWORD pdwSidCount,
  295. OUT PDWORD pdwSidLength
  296. )
  297. /*++
  298. Routine description:
  299. This routine works as AuthzpGetAllGroupsBySid but takes a username
  300. domain name pair instead of a SID. It also accepts a UPN as the
  301. username and an empty domain name.
  302. Arguments:
  303. pusUserName - Name of the user. Can be a UPN.
  304. pusDomainName - domain name of the user account or NULL in case
  305. the user name is a UPN.
  306. Flags -
  307. AUTHZ_SKIP_TOKEN_GROUPS - Do not compute TokenGroups.
  308. AUTHZ_SKIP_WORLD_SID - Do not add the WORLD SID to the context.
  309. ppSidAttr - Returns SidAndAttribute array. The routine allocates memory
  310. for this array.
  311. pSidCount - Returns the number of sids in the array.
  312. pSidLength - Returns the size of memory allocated to hold the array.
  313. Return Value:
  314. A value of TRUE is returned if the routine is successful. Otherwise,
  315. a value of FALSE is returned. In the failure case, error value may be
  316. retrieved using GetLastError().
  317. --*/
  318. {
  319. DWORD dwError;
  320. BOOL bStatus = TRUE;
  321. SID_SET sidSet = {0};
  322. PSID_DESC pSidDesc;
  323. PBYTE pSid;
  324. PSID_AND_ATTRIBUTES pSidAndAttribs;
  325. DWORD i;
  326. //
  327. // Initialize output parameters to zero.
  328. //
  329. *ppSidAndAttributes = 0;
  330. *pdwSidCount = 0;
  331. *pdwSidLength = 0;
  332. //
  333. // Initialize the SID set
  334. //
  335. dwError = AuthzpInitializeSidSetByName(
  336. pusUserName,
  337. pusDomainName,
  338. dwFlags,
  339. &sidSet
  340. );
  341. if (dwError != ERROR_SUCCESS)
  342. {
  343. goto Cleanup;
  344. }
  345. if (sidSet.dwFlags & AUTHZ_SKIP_TOKEN_GROUPS)
  346. {
  347. //
  348. // Initialize the user SID.
  349. //
  350. dwError = AuthzpGetUserDomainSid(
  351. &sidSet
  352. );
  353. if (dwError != ERROR_SUCCESS)
  354. {
  355. goto Cleanup;
  356. }
  357. //
  358. // Stick the user SID, the WORLD SID and others
  359. // into the set if requested.
  360. //
  361. dwError = AuthzpAddWellKnownSids(
  362. &sidSet
  363. );
  364. if (dwError != ERROR_SUCCESS)
  365. {
  366. goto Cleanup;
  367. }
  368. }
  369. else
  370. {
  371. dwError = AuthzpGetTokenGroupsXp(
  372. &sidSet
  373. );
  374. if (dwError != ERROR_SUCCESS)
  375. {
  376. //
  377. // Detect the downlevel case.
  378. //
  379. // if (dwError != SEC_E_NO_S4U_PROT_SUPPORT)
  380. // {
  381. // goto Cleanup;
  382. // }
  383. //
  384. // Initialize the user SID.
  385. //
  386. dwError = AuthzpGetUserDomainSid(
  387. &sidSet
  388. );
  389. if (dwError != ERROR_SUCCESS)
  390. {
  391. goto Cleanup;
  392. }
  393. //
  394. // Stick the user SID, the WORLD SID and others
  395. // into the set if requested.
  396. //
  397. dwError = AuthzpAddWellKnownSids(
  398. &sidSet
  399. );
  400. if (dwError != ERROR_SUCCESS)
  401. {
  402. goto Cleanup;
  403. }
  404. //
  405. // In case AuthzpAddWellKnownSids finds that the SID is the
  406. // Anonymous SID, it sets the AUTHZ_SKIP_TOKEN_GROUPS flag.
  407. //
  408. if (!(sidSet.dwFlags & AUTHZ_SKIP_TOKEN_GROUPS))
  409. {
  410. //
  411. // Try the downlevel scenario.
  412. //
  413. dwError = AuthzpGetTokenGroupsDownlevel(
  414. &sidSet
  415. );
  416. if (dwError != ERROR_SUCCESS)
  417. {
  418. goto Cleanup;
  419. }
  420. }
  421. }
  422. }
  423. //
  424. // Allocate memory and copy all SIDs
  425. // from the SID set into ppSidAndAttributes.
  426. //
  427. *pdwSidCount = sidSet.dwCount;
  428. *pdwSidLength = sidSet.dwCount * sizeof(SID_AND_ATTRIBUTES);
  429. pSidDesc = sidSet.pSidDesc;
  430. for (i=0;i < sidSet.dwCount;i++,pSidDesc++)
  431. {
  432. *pdwSidLength += pSidDesc->dwLength;
  433. }
  434. *ppSidAndAttributes = (PSID_AND_ATTRIBUTES)AuthzpAlloc(*pdwSidLength);
  435. if (*ppSidAndAttributes == 0)
  436. {
  437. dwError = GetLastError();
  438. goto Cleanup;
  439. }
  440. pSid = ((PBYTE)*ppSidAndAttributes) +
  441. sidSet.dwCount * sizeof(SID_AND_ATTRIBUTES);
  442. pSidDesc = sidSet.pSidDesc;
  443. pSidAndAttribs = *ppSidAndAttributes;
  444. for (i=0;i < sidSet.dwCount;i++,pSidDesc++,pSidAndAttribs++)
  445. {
  446. pSidAndAttribs->Attributes = pSidDesc->dwAttributes;
  447. pSidAndAttribs->Sid = pSid;
  448. RtlCopyMemory(
  449. pSid,
  450. pSidDesc->sid,
  451. pSidDesc->dwLength
  452. );
  453. pSid += pSidDesc->dwLength;
  454. }
  455. dwError = ERROR_SUCCESS;
  456. Cleanup:
  457. if (dwError != ERROR_SUCCESS)
  458. {
  459. SetLastError(dwError);
  460. bStatus = FALSE;
  461. *pdwSidCount = 0;
  462. *pdwSidLength = 0;
  463. if (*ppSidAndAttributes)
  464. {
  465. AuthzpFree(*ppSidAndAttributes);
  466. *ppSidAndAttributes = 0;
  467. }
  468. }
  469. AuthzpDeleteSidSet(&sidSet);
  470. return bStatus;
  471. }
  472. BOOL
  473. AuthzpGetAllGroupsBySid(
  474. IN PSID pUserSid,
  475. IN DWORD dwFlags,
  476. OUT PSID_AND_ATTRIBUTES* ppSidAndAttributes,
  477. OUT PDWORD pdwSidCount,
  478. OUT PDWORD pdwSidLength
  479. )
  480. /*++
  481. Routine description:
  482. This routine computes the groups a given user is a member of.
  483. It uses a data structure called a SID_SET for collecting the SIDs.
  484. 1. Initialize the SID_SET.
  485. 2. Put the user SID into the set.
  486. If requested, put the EVERYONE SID into the set.
  487. Add Well Known SIDs.
  488. 3. If requested, put the SIDs for non-local groups the user is
  489. a member of into the set. There are three scenarios for this
  490. step, depending on the version of the DC we are talking to:
  491. xp: Use LsaLogonUser with the Kerberos S4U package and
  492. extract the groups from the token returned
  493. (AuthzpGetWXPDomainTokenGroups).
  494. W2k: Use ldap and the SAM API to compute memberships in
  495. NT4: the account and primary domain and to get the SID history
  496. (AuthzpGetW2kDomainTokenGroups).
  497. 4. Transmogrify the SID_SET into a SID_AND_ATTRIBUTES array
  498. and free the SID_SET.
  499. Arguments:
  500. pUserSid - The user SID for which the groups should be computed.
  501. Flags -
  502. AUTHZ_SKIP_TOKEN_GROUPS - Do not compute TokenGroups.
  503. AUTHZ_SKIP_WORLD_SID - Do not add the WORLD SID to the context.
  504. AUTHZ_REQUIRE_S4U_LOGON - Do not use the downlevel codepaths. Force S4U or fail.
  505. This is to enforce account restrictions.
  506. ppSidAttr - Returns SidAndAttribute array. The routine allocates memory
  507. for this array.
  508. pSidCount - Returns the number of sids in the array.
  509. pSidLength - Returns the size of memory allocated to hold the array.
  510. Return Value:
  511. A value of TRUE is returned if the routine is successful. Otherwise,
  512. a value of FALSE is returned. In the failure case, error value may be
  513. retrieved using GetLastError().
  514. --*/
  515. {
  516. DWORD dwError;
  517. BOOL bStatus = TRUE;
  518. SID_SET sidSet = {0};
  519. PSID_DESC pSidDesc;
  520. PBYTE pSid;
  521. PSID_AND_ATTRIBUTES pSidAndAttribs;
  522. DWORD i;
  523. //
  524. // Initialize output parameters to zero.
  525. //
  526. *ppSidAndAttributes = 0;
  527. *pdwSidCount = 0;
  528. *pdwSidLength = 0;
  529. //
  530. // Initialize the SID set
  531. //
  532. dwError = AuthzpInitializeSidSetBySid(
  533. pUserSid,
  534. dwFlags,
  535. &sidSet
  536. );
  537. if (dwError != ERROR_SUCCESS)
  538. {
  539. goto Cleanup;
  540. }
  541. if (sidSet.dwFlags & AUTHZ_SKIP_TOKEN_GROUPS)
  542. {
  543. //
  544. // Stick the user SID, the WORLD SID and others
  545. // into the set if requested.
  546. //
  547. dwError = AuthzpAddWellKnownSids(
  548. &sidSet
  549. );
  550. if (dwError != ERROR_SUCCESS)
  551. {
  552. goto Cleanup;
  553. }
  554. }
  555. else
  556. {
  557. //
  558. // Initialize user and domain name members of the sid set.
  559. //
  560. dwError = AuthzpGetUserDomainName(
  561. &sidSet
  562. );
  563. if (dwError != ERROR_SUCCESS)
  564. {
  565. goto Cleanup;
  566. }
  567. if (sidSet.pNames->Use == SidTypeAlias ||
  568. sidSet.pNames->Use == SidTypeGroup ||
  569. sidSet.pNames->Use == SidTypeWellKnownGroup)
  570. {
  571. //
  572. // LsaLogonUser cannot log on groups...
  573. //
  574. dwError = ERROR_NOT_SUPPORTED;
  575. }
  576. else
  577. {
  578. dwError = AuthzpGetTokenGroupsXp(
  579. &sidSet
  580. );
  581. }
  582. if (dwError != ERROR_SUCCESS)
  583. {
  584. //
  585. // Xp logon code failed. If user prohibits the downlevel path,
  586. // then exit now.
  587. //
  588. if (dwFlags & AUTHZ_REQUIRE_S4U_LOGON)
  589. {
  590. goto Cleanup;
  591. }
  592. //
  593. // Detect the downlevel case.
  594. //
  595. // if (dwError != SEC_E_NO_S4U_PROT_SUPPORT)
  596. // {
  597. // goto Cleanup;
  598. // }
  599. //
  600. //
  601. // Stick the user SID, the WORLD SID and others
  602. // into the set if requested.
  603. //
  604. dwError = AuthzpAddWellKnownSids(
  605. &sidSet
  606. );
  607. if (dwError != ERROR_SUCCESS)
  608. {
  609. goto Cleanup;
  610. }
  611. //
  612. // In case AuthzpAddWellKnownSids finds that the SID is the
  613. // Anonymous SID, it sets the AUTHZ_SKIP_TOKEN_GROUPS flag.
  614. //
  615. if (!(sidSet.dwFlags & AUTHZ_SKIP_TOKEN_GROUPS))
  616. {
  617. //
  618. // Try the downlevel scenario.
  619. //
  620. dwError = AuthzpGetTokenGroupsDownlevel(
  621. &sidSet
  622. );
  623. if (dwError != ERROR_SUCCESS)
  624. {
  625. goto Cleanup;
  626. }
  627. }
  628. }
  629. }
  630. //
  631. // Allocate memory and copy all SIDs
  632. // from the SID set into ppSidAndAttributes.
  633. //
  634. *pdwSidCount = sidSet.dwCount;
  635. *pdwSidLength = sidSet.dwCount * sizeof(SID_AND_ATTRIBUTES);
  636. pSidDesc = sidSet.pSidDesc;
  637. for (i=0;i < sidSet.dwCount;i++,pSidDesc++)
  638. {
  639. *pdwSidLength += pSidDesc->dwLength;
  640. }
  641. *ppSidAndAttributes = (PSID_AND_ATTRIBUTES)AuthzpAlloc(*pdwSidLength);
  642. if (*ppSidAndAttributes == 0)
  643. {
  644. dwError = GetLastError();
  645. goto Cleanup;
  646. }
  647. pSid = ((PBYTE)*ppSidAndAttributes) +
  648. sidSet.dwCount * sizeof(SID_AND_ATTRIBUTES);
  649. pSidDesc = sidSet.pSidDesc;
  650. pSidAndAttribs = *ppSidAndAttributes;
  651. for (i=0;i < sidSet.dwCount;i++,pSidDesc++,pSidAndAttribs++)
  652. {
  653. pSidAndAttribs->Attributes = pSidDesc->dwAttributes;
  654. pSidAndAttribs->Sid = pSid;
  655. RtlCopyMemory(
  656. pSid,
  657. pSidDesc->sid,
  658. pSidDesc->dwLength
  659. );
  660. pSid += pSidDesc->dwLength;
  661. }
  662. dwError = ERROR_SUCCESS;
  663. Cleanup:
  664. if (dwError != ERROR_SUCCESS)
  665. {
  666. SetLastError(dwError);
  667. bStatus = FALSE;
  668. *pdwSidCount = 0;
  669. *pdwSidLength = 0;
  670. if (*ppSidAndAttributes)
  671. {
  672. AuthzpFree(*ppSidAndAttributes);
  673. *ppSidAndAttributes = 0;
  674. }
  675. }
  676. AuthzpDeleteSidSet(&sidSet);
  677. return bStatus;
  678. }
  679. DWORD
  680. AuthzpAddWellKnownSids(
  681. IN OUT PSID_SET pSidSet
  682. )
  683. {
  684. DWORD dwError;
  685. BOOL bStatus;
  686. BOOL bEqual;
  687. BOOL bAddEveryone = TRUE;
  688. BOOL bAddAuthUsers = TRUE;
  689. BOOL bAddAdministrators = FALSE;
  690. BYTE sid[SECURITY_MAX_SID_SIZE];
  691. PSID pSid = (PSID)sid;
  692. DWORD dwLengthSid;
  693. //
  694. // Stick the user SID into the set
  695. //
  696. dwError = AuthzpAddSidToSidSet(
  697. pSidSet,
  698. pSidSet->pUserSid,
  699. 0,
  700. SE_GROUP_ENABLED,
  701. 0,
  702. 0
  703. );
  704. if (dwError != ERROR_SUCCESS)
  705. {
  706. goto Cleanup;
  707. }
  708. pSidSet->dwBaseCount = 1;
  709. //
  710. // Test for some well known SIDs.
  711. //
  712. // If the SID passed in is the Anonymous SID, then check the registry
  713. // value to determine if the Everyone SID should be included in the
  714. // resulting client context.
  715. //
  716. if (IsWellKnownSid(
  717. pSidSet->pUserSid,
  718. WinAnonymousSid))
  719. {
  720. bAddEveryone = FALSE;
  721. bAddAuthUsers = FALSE;
  722. bStatus = AuthzpEveryoneIncludesAnonymous(
  723. &bAddEveryone
  724. );
  725. if (bStatus == FALSE)
  726. {
  727. bAddEveryone = FALSE;
  728. }
  729. pSidSet->dwFlags |= AUTHZ_SKIP_TOKEN_GROUPS;
  730. }
  731. else if (IsWellKnownSid(
  732. pSidSet->pUserSid,
  733. WinLocalSystemSid))
  734. {
  735. bAddEveryone = TRUE;
  736. bAddAuthUsers = TRUE;
  737. bAddAdministrators = TRUE;
  738. pSidSet->dwFlags |= AUTHZ_SKIP_TOKEN_GROUPS;
  739. }
  740. else
  741. {
  742. //
  743. // This is a dummy context. Return now.
  744. //
  745. if (pSidSet->dwFlags & AUTHZ_SKIP_TOKEN_GROUPS)
  746. {
  747. return ERROR_SUCCESS;
  748. }
  749. dwLengthSid = SECURITY_MAX_SID_SIZE;
  750. bStatus = CreateWellKnownSid(
  751. WinBuiltinDomainSid,
  752. 0,
  753. pSid,
  754. &dwLengthSid
  755. );
  756. if (bStatus == FALSE)
  757. {
  758. dwError = GetLastError();
  759. goto Cleanup;
  760. }
  761. bStatus = EqualDomainSid(
  762. pSidSet->pUserSid,
  763. pSid,
  764. &bEqual
  765. );
  766. //
  767. // ERROR_NON_DOMAIN_SID is returned for wellknown sids.
  768. // It is ok to ignore this error and continue.
  769. //
  770. if ((bStatus == FALSE) && (GetLastError() != ERROR_NON_DOMAIN_SID))
  771. {
  772. dwError = GetLastError();
  773. goto Cleanup;
  774. }
  775. if (bEqual)
  776. {
  777. pSidSet->bSkipNonLocal = TRUE;
  778. }
  779. else
  780. {
  781. bAddEveryone = TRUE;
  782. bAddAuthUsers = TRUE;
  783. }
  784. }
  785. if (bAddEveryone)
  786. {
  787. dwLengthSid = SECURITY_MAX_SID_SIZE;
  788. bStatus = CreateWellKnownSid(
  789. WinWorldSid,
  790. 0,
  791. pSid,
  792. &dwLengthSid
  793. );
  794. if (bStatus == FALSE)
  795. {
  796. dwError = GetLastError();
  797. goto Cleanup;
  798. }
  799. dwError = AuthzpAddSidToSidSet(
  800. pSidSet,
  801. pSid,
  802. dwLengthSid,
  803. SE_GROUP_MANDATORY
  804. | SE_GROUP_ENABLED_BY_DEFAULT
  805. | SE_GROUP_ENABLED,
  806. 0,
  807. 0
  808. );
  809. if (dwError != ERROR_SUCCESS)
  810. {
  811. goto Cleanup;
  812. }
  813. pSidSet->dwBaseCount++;
  814. }
  815. //
  816. // Add NT AUTHORITY\Authenticated Users to the set
  817. // only if the user does not have the Guest RID
  818. //
  819. if (bAddAuthUsers &&
  820. *RtlSubAuthorityCountSid(pSidSet->pUserSid) > 0 &&
  821. (*RtlSubAuthoritySid(
  822. pSidSet->pUserSid,
  823. (ULONG)(*RtlSubAuthorityCountSid(
  824. pSidSet->pUserSid)) - 1) != DOMAIN_USER_RID_GUEST) &&
  825. (*RtlSubAuthoritySid(
  826. pSidSet->pUserSid,
  827. (ULONG)(*RtlSubAuthorityCountSid(
  828. pSidSet->pUserSid)) - 1) != DOMAIN_GROUP_RID_GUESTS))
  829. {
  830. dwLengthSid = SECURITY_MAX_SID_SIZE;
  831. bStatus = CreateWellKnownSid(
  832. WinAuthenticatedUserSid,
  833. 0,
  834. pSid,
  835. &dwLengthSid
  836. );
  837. if (bStatus == FALSE)
  838. {
  839. dwError = GetLastError();
  840. goto Cleanup;
  841. }
  842. dwError = AuthzpAddSidToSidSet(
  843. pSidSet,
  844. pSid,
  845. dwLengthSid,
  846. SE_GROUP_MANDATORY
  847. | SE_GROUP_ENABLED_BY_DEFAULT
  848. | SE_GROUP_ENABLED,
  849. 0,
  850. 0
  851. );
  852. if (dwError != ERROR_SUCCESS)
  853. {
  854. goto Cleanup;
  855. }
  856. pSidSet->dwBaseCount++;
  857. }
  858. if (bAddAdministrators)
  859. {
  860. dwLengthSid = SECURITY_MAX_SID_SIZE;
  861. bStatus = CreateWellKnownSid(
  862. WinBuiltinAdministratorsSid,
  863. 0,
  864. pSid,
  865. &dwLengthSid
  866. );
  867. if (bStatus == FALSE)
  868. {
  869. dwError = GetLastError();
  870. goto Cleanup;
  871. }
  872. dwError = AuthzpAddSidToSidSet(
  873. pSidSet,
  874. pSid,
  875. dwLengthSid,
  876. SE_GROUP_MANDATORY
  877. | SE_GROUP_ENABLED_BY_DEFAULT
  878. | SE_GROUP_ENABLED,
  879. 0,
  880. 0
  881. );
  882. if (dwError != ERROR_SUCCESS)
  883. {
  884. goto Cleanup;
  885. }
  886. pSidSet->dwBaseCount++;
  887. }
  888. dwError = ERROR_SUCCESS;
  889. Cleanup:
  890. return dwError;
  891. }
  892. DWORD
  893. AuthzpGetTokenGroupsXp(
  894. IN OUT PSID_SET pSidSet
  895. )
  896. /*++
  897. Routine description:
  898. This routine connects to the domain specified by the SID and
  899. retrieves the list of groups to which the user belongs.
  900. This routine assumes we are talking to a WinXP DC.
  901. We take advantage of the new LsaLogonUser package, KerbS4ULogon.
  902. Arguments:
  903. pUserSid - user SID for which the lookup should be performed.
  904. pSidSet - SID_SET in which we collect the SIDs of the groups
  905. we found in the token.
  906. Return Value:
  907. Win32 error code:
  908. - ERROR_NOT_SUPPORTED if the DC does not support the call
  909. (pre ~2475 or client)
  910. - ERROR_INVALID_PARAMETER if the code is running on a
  911. pre XP platform
  912. --*/
  913. {
  914. DWORD dwError = ERROR_SUCCESS;
  915. BOOL bStatus;
  916. NTSTATUS status;
  917. HANDLE hLsa = 0;
  918. LSA_STRING asProcessName;
  919. LSA_STRING asPackageName;
  920. ULONG ulAuthPackage;
  921. TOKEN_SOURCE sourceContext;
  922. PVOID pProfileBuffer = 0;
  923. ULONG ulProfileLength = 0;
  924. LUID luidLogonId;
  925. HANDLE hToken = 0;
  926. QUOTA_LIMITS quota;
  927. NTSTATUS subStatus;
  928. DWORD dwLength;
  929. DWORD i;
  930. PTOKEN_USER pTokenUser = 0;
  931. PTOKEN_GROUPS pTokenGroups = 0;
  932. PSID_AND_ATTRIBUTES pSidAndAttribs;
  933. ULONG ulPackageSize;
  934. PKERB_S4U_LOGON pPackage = 0;
  935. //
  936. // Set up the authentication package.
  937. //
  938. ulPackageSize = sizeof(KERB_S4U_LOGON);
  939. ulPackageSize += pSidSet->pusUserName->Length;
  940. if (pSidSet->pusDomainName)
  941. {
  942. ulPackageSize += pSidSet->pusDomainName->Length;
  943. }
  944. pPackage = (PKERB_S4U_LOGON)LocalAlloc(
  945. LMEM_FIXED,
  946. ulPackageSize
  947. );
  948. if (pPackage == 0)
  949. {
  950. dwError = GetLastError();
  951. goto Cleanup;
  952. }
  953. pPackage->MessageType = KerbS4ULogon;
  954. pPackage->Flags = 0;
  955. pPackage->ClientUpn.Length = pSidSet->pusUserName->Length;
  956. pPackage->ClientUpn.MaximumLength = pSidSet->pusUserName->Length;
  957. pPackage->ClientUpn.Buffer = (PWSTR)(pPackage + 1);
  958. RtlCopyMemory(
  959. pPackage->ClientUpn.Buffer,
  960. pSidSet->pusUserName->Buffer,
  961. pSidSet->pusUserName->Length
  962. );
  963. if (pSidSet->pusDomainName)
  964. {
  965. pPackage->ClientRealm.Length = pSidSet->pusDomainName->Length;
  966. pPackage->ClientRealm.MaximumLength = pSidSet->pusDomainName->Length;
  967. pPackage->ClientRealm.Buffer = (PWSTR)
  968. (((PBYTE)(pPackage->ClientUpn.Buffer)) + pPackage->ClientUpn.Length);
  969. RtlCopyMemory(
  970. pPackage->ClientRealm.Buffer,
  971. pSidSet->pusDomainName->Buffer,
  972. pSidSet->pusDomainName->Length
  973. );
  974. }
  975. else
  976. {
  977. pPackage->ClientRealm.Length = 0;
  978. pPackage->ClientRealm.MaximumLength = 0;
  979. pPackage->ClientRealm.Buffer = 0;
  980. }
  981. //
  982. // Our name is AuthzApi.
  983. //
  984. RtlInitString(
  985. &asProcessName,
  986. "AuthzApi"
  987. );
  988. //
  989. // Set up the process name and
  990. // register with the LSA.
  991. //
  992. status = LsaConnectUntrusted(
  993. &hLsa
  994. );
  995. if (!NT_SUCCESS(status))
  996. {
  997. dwError = LsaNtStatusToWinError(status);
  998. goto Cleanup;
  999. }
  1000. //
  1001. // Get the authentication package.
  1002. //
  1003. RtlInitString(&asPackageName, MICROSOFT_KERBEROS_NAME_A);
  1004. status = LsaLookupAuthenticationPackage(
  1005. hLsa,
  1006. &asPackageName,
  1007. &ulAuthPackage
  1008. );
  1009. if (!NT_SUCCESS(status))
  1010. {
  1011. dwError = LsaNtStatusToWinError(status);
  1012. goto Cleanup;
  1013. }
  1014. //
  1015. // Prepare the source context.
  1016. //
  1017. RtlCopyMemory(
  1018. sourceContext.SourceName,
  1019. "Authz ",
  1020. sizeof(sourceContext.SourceName)
  1021. );
  1022. status = NtAllocateLocallyUniqueId(
  1023. &sourceContext.SourceIdentifier
  1024. );
  1025. if (!NT_SUCCESS(status))
  1026. {
  1027. dwError = RtlNtStatusToDosError(status);
  1028. goto Cleanup;
  1029. }
  1030. //
  1031. // Do the logon.
  1032. //
  1033. status = LsaLogonUser(
  1034. hLsa,
  1035. &asProcessName,
  1036. Network,
  1037. ulAuthPackage,
  1038. pPackage,
  1039. ulPackageSize,
  1040. 0, // no LocalGroups
  1041. &sourceContext,
  1042. &pProfileBuffer,
  1043. &ulProfileLength,
  1044. &luidLogonId,
  1045. &hToken,
  1046. &quota,
  1047. &subStatus
  1048. );
  1049. if (!NT_SUCCESS(status))
  1050. {
  1051. dwError = LsaNtStatusToWinError(status);
  1052. goto Cleanup;
  1053. }
  1054. //
  1055. // Figure out how much memory to allocate for the user info.
  1056. //
  1057. dwLength = 0;
  1058. bStatus = GetTokenInformation(
  1059. hToken,
  1060. TokenUser,
  1061. 0,
  1062. 0,
  1063. &dwLength
  1064. );
  1065. if (bStatus == FALSE)
  1066. {
  1067. dwError = GetLastError();
  1068. if (dwError != ERROR_INSUFFICIENT_BUFFER)
  1069. {
  1070. goto Cleanup;
  1071. }
  1072. }
  1073. pTokenUser = (PTOKEN_USER)LocalAlloc(
  1074. LMEM_FIXED,
  1075. dwLength
  1076. );
  1077. if (pTokenUser == 0)
  1078. {
  1079. dwError = GetLastError();
  1080. goto Cleanup;
  1081. }
  1082. //
  1083. // Extract the user SID from the token and
  1084. // add it to pSidSet.
  1085. //
  1086. bStatus = GetTokenInformation(
  1087. hToken,
  1088. TokenUser,
  1089. pTokenUser,
  1090. dwLength,
  1091. &dwLength
  1092. );
  1093. if (bStatus == FALSE)
  1094. {
  1095. dwError = GetLastError();
  1096. goto Cleanup;
  1097. }
  1098. //
  1099. // Stick the user SID into the set.
  1100. //
  1101. if (!FLAG_ON(pTokenUser->User.Attributes, SE_GROUP_USE_FOR_DENY_ONLY))
  1102. {
  1103. pTokenUser->User.Attributes |= SE_GROUP_ENABLED;
  1104. }
  1105. dwError = AuthzpAddSidToSidSet(
  1106. pSidSet,
  1107. pTokenUser->User.Sid,
  1108. 0,
  1109. pTokenUser->User.Attributes,
  1110. 0,
  1111. 0
  1112. );
  1113. if (dwError != ERROR_SUCCESS)
  1114. {
  1115. goto Cleanup;
  1116. }
  1117. //
  1118. // Figure out how much memory to allocate for the token groups.
  1119. //
  1120. dwLength = 0;
  1121. bStatus = GetTokenInformation(
  1122. hToken,
  1123. TokenGroups,
  1124. 0,
  1125. 0,
  1126. &dwLength
  1127. );
  1128. if (bStatus == FALSE)
  1129. {
  1130. dwError = GetLastError();
  1131. if (dwError != ERROR_INSUFFICIENT_BUFFER)
  1132. {
  1133. goto Cleanup;
  1134. }
  1135. }
  1136. pTokenGroups = (PTOKEN_GROUPS)LocalAlloc(
  1137. LMEM_FIXED,
  1138. dwLength
  1139. );
  1140. if (pTokenGroups == 0)
  1141. {
  1142. dwError = GetLastError();
  1143. goto Cleanup;
  1144. }
  1145. //
  1146. // Extract the user groups from the token and
  1147. // add them to pSidSet.
  1148. //
  1149. bStatus = GetTokenInformation(
  1150. hToken,
  1151. TokenGroups,
  1152. pTokenGroups,
  1153. dwLength,
  1154. &dwLength
  1155. );
  1156. if (bStatus == FALSE)
  1157. {
  1158. dwError = GetLastError();
  1159. goto Cleanup;
  1160. }
  1161. //
  1162. // Stick the group SIDs into the set
  1163. // except for the Network and the LUID SID.
  1164. //
  1165. pSidAndAttribs = pTokenGroups->Groups;
  1166. for (i=0;i < pTokenGroups->GroupCount;i++,pSidAndAttribs++)
  1167. {
  1168. if (!IsWellKnownSid(
  1169. pSidAndAttribs->Sid,
  1170. WinNetworkSid) &&
  1171. !IsWellKnownSid(
  1172. pSidAndAttribs->Sid,
  1173. WinLogonIdsSid))
  1174. {
  1175. dwError = AuthzpAddSidToSidSet(
  1176. pSidSet,
  1177. pSidAndAttribs->Sid,
  1178. 0,
  1179. pSidAndAttribs->Attributes,
  1180. 0,
  1181. 0
  1182. );
  1183. if (dwError != ERROR_SUCCESS)
  1184. {
  1185. goto Cleanup;
  1186. }
  1187. }
  1188. }
  1189. dwError = ERROR_SUCCESS;
  1190. Cleanup:
  1191. if (pTokenUser)
  1192. {
  1193. AuthzpFree((HLOCAL)pTokenUser);
  1194. }
  1195. if (pTokenGroups)
  1196. {
  1197. AuthzpFree((HLOCAL)pTokenGroups);
  1198. }
  1199. if (hToken)
  1200. {
  1201. CloseHandle(hToken);
  1202. }
  1203. if (pProfileBuffer)
  1204. {
  1205. LsaFreeReturnBuffer(pProfileBuffer);
  1206. }
  1207. if (hLsa)
  1208. {
  1209. LsaDeregisterLogonProcess(hLsa);
  1210. }
  1211. if (pPackage)
  1212. {
  1213. AuthzpFree((HLOCAL)pPackage);
  1214. }
  1215. return dwError;
  1216. }
  1217. DWORD
  1218. AuthzpGetTokenGroupsDownlevel(
  1219. IN OUT PSID_SET pSidSet
  1220. )
  1221. /*++
  1222. Routine description:
  1223. This routine connects to the domain specified by the SID and
  1224. retrieves the list of groups to which the user belongs.
  1225. This routine assumes we are talking to a Win2k DC.
  1226. First get the users domain universal and global groups
  1227. memberships.
  1228. Next check for nested memberships in the primary domain.
  1229. The last step is getting the SID history for each SID collected
  1230. so far.
  1231. Arguments:
  1232. pUserSid - user SID for which the lookup should be performed.
  1233. pSidSet - Returns the number of rids in the alias list
  1234. Return Value:
  1235. Win32 error code.
  1236. --*/
  1237. {
  1238. DWORD dwError;
  1239. BOOL bUdIsNative = FALSE;
  1240. BOOL bRdIsNative = FALSE;
  1241. BOOL bAddPrimaryGroup = FALSE;
  1242. //
  1243. // Retrieve information about the machine.
  1244. //
  1245. dwError = AuthzpGetLocalInfo(pSidSet);
  1246. if (dwError != ERROR_SUCCESS)
  1247. {
  1248. goto Cleanup;
  1249. }
  1250. if (pSidSet->bStandalone ||
  1251. pSidSet->bSkipNonLocal)
  1252. {
  1253. //
  1254. // In the standalone case there is no need to hit the wire.
  1255. // We don't have to do anything here since local group
  1256. // memberships are computed later anyway.
  1257. //
  1258. bAddPrimaryGroup = TRUE;
  1259. goto LocalGroups;
  1260. }
  1261. //
  1262. // Compare the user domain SID to the machine domain SID.
  1263. // If they are equal, we can use the local machine for
  1264. // global group computing since the account is either
  1265. // a local account or we are sitting on a DC.
  1266. // The SID of the local machine is never zero in a non
  1267. // standalone / workgroup case.
  1268. //
  1269. if (pSidSet->pAccountInfo->DomainSid &&
  1270. RtlEqualSid(
  1271. pSidSet->pDomainSid,
  1272. pSidSet->pAccountInfo->DomainSid))
  1273. {
  1274. BOOL bIsDC = FALSE;
  1275. pSidSet->pszUdDcName = 0;
  1276. //
  1277. // Find out if this is a DC.
  1278. //
  1279. dwError = AuthzpIsDC(&bIsDC);
  1280. if (dwError != ERROR_SUCCESS)
  1281. {
  1282. goto Cleanup;
  1283. }
  1284. //
  1285. // If this is not a DC then give up on global group computing.
  1286. //
  1287. if (FALSE == bIsDC)
  1288. {
  1289. bAddPrimaryGroup = TRUE;
  1290. goto LocalGroups;
  1291. }
  1292. //
  1293. // Local machine is a DC. Since AuthZ is not supported on nt4 we can
  1294. // safely assume it is at least w2k.
  1295. //
  1296. }
  1297. else
  1298. {
  1299. //
  1300. // Find a DC and get its name.
  1301. //
  1302. dwError = AuthzpGetDcName(
  1303. pSidSet->pusDomainName->Buffer,
  1304. &pSidSet->pUdDcInfo
  1305. );
  1306. if (dwError != ERROR_SUCCESS)
  1307. {
  1308. goto Cleanup;
  1309. }
  1310. pSidSet->pszUdDcName = pSidSet->pUdDcInfo->DomainControllerName;
  1311. }
  1312. //
  1313. // User domain can only be in native mode if DS is running.
  1314. //
  1315. if ((pSidSet->pUdDcInfo == 0) ||
  1316. (pSidSet->pUdDcInfo->Flags & DS_DS_FLAG) != 0)
  1317. {
  1318. //
  1319. // Collect information about the domain.
  1320. //
  1321. dwError = DsRoleGetPrimaryDomainInformation(
  1322. pSidSet->pszUdDcName,
  1323. DsRolePrimaryDomainInfoBasic,
  1324. (PBYTE*)&pSidSet->pUdBasicInfo
  1325. );
  1326. if (dwError != ERROR_SUCCESS)
  1327. {
  1328. //
  1329. // If the domain is in mixed mode and we are passing in a DNS
  1330. // name, the call fails with RPC_S_SERVER_UNAVAILABLE.
  1331. // We have to get rid of the DC name and get a flat one and
  1332. // then try again.
  1333. //
  1334. if (dwError == RPC_S_SERVER_UNAVAILABLE &&
  1335. pSidSet->pUdDcInfo &&
  1336. (pSidSet->pUdDcInfo->Flags & DS_INET_ADDRESS))
  1337. {
  1338. NetApiBufferFree(pSidSet->pUdDcInfo);
  1339. pSidSet->pUdDcInfo = 0;
  1340. dwError = DsGetDcName(
  1341. 0,
  1342. pSidSet->pDomainsName,
  1343. 0,
  1344. 0,
  1345. 0,
  1346. &pSidSet->pUdDcInfo
  1347. );
  1348. if (dwError != ERROR_SUCCESS)
  1349. {
  1350. goto Cleanup;
  1351. }
  1352. pSidSet->pszUdDcName = pSidSet->pUdDcInfo->DomainControllerName;
  1353. dwError = DsRoleGetPrimaryDomainInformation(
  1354. pSidSet->pszUdDcName,
  1355. DsRolePrimaryDomainInfoBasic,
  1356. (PBYTE*)&pSidSet->pUdBasicInfo
  1357. );
  1358. if (dwError != ERROR_SUCCESS)
  1359. {
  1360. goto Cleanup;
  1361. }
  1362. }
  1363. else
  1364. {
  1365. goto Cleanup;
  1366. }
  1367. }
  1368. if ((pSidSet->pUdBasicInfo->Flags & DSROLE_PRIMARY_DS_RUNNING) &&
  1369. (pSidSet->pUdBasicInfo->Flags & DSROLE_PRIMARY_DS_MIXED_MODE) == 0)
  1370. {
  1371. bUdIsNative = TRUE;
  1372. }
  1373. }
  1374. //
  1375. // Check whether the account domain is in native or mixed mode
  1376. // and call the appropriate routine to get the groups.
  1377. //
  1378. if (bUdIsNative)
  1379. {
  1380. //
  1381. // User domain is in native mode.
  1382. //
  1383. dwError = AuthzpGetAccountDomainGroupsDs(
  1384. pSidSet
  1385. );
  1386. }
  1387. else
  1388. {
  1389. //
  1390. // User domain is in mixed mode.
  1391. //
  1392. dwError = AuthzpGetAccountDomainGroupsSam(
  1393. pSidSet
  1394. );
  1395. }
  1396. if (dwError != ERROR_SUCCESS)
  1397. {
  1398. goto Cleanup;
  1399. }
  1400. //
  1401. // Check whether user domain and resource domain are different.
  1402. //
  1403. if (pSidSet->pPrimaryInfo->Sid &&
  1404. RtlEqualSid(
  1405. pSidSet->pDomainSid,
  1406. pSidSet->pPrimaryInfo->Sid))
  1407. {
  1408. pSidSet->pszRdDcName = pSidSet->pszUdDcName;
  1409. pSidSet->pRdDcInfo = pSidSet->pUdDcInfo;
  1410. pSidSet->pRdBasicInfo = pSidSet->pUdBasicInfo;
  1411. bRdIsNative = bUdIsNative;
  1412. }
  1413. else
  1414. {
  1415. //
  1416. // Find a DC and get its name.
  1417. //
  1418. dwError = AuthzpGetDcName(
  1419. pSidSet->pPrimaryInfoName,
  1420. &pSidSet->pPdDcInfo
  1421. );
  1422. if (dwError != ERROR_SUCCESS)
  1423. {
  1424. goto Cleanup;
  1425. }
  1426. pSidSet->pszRdDcName = pSidSet->pPdDcInfo->DomainControllerName;
  1427. pSidSet->pRdDcInfo = pSidSet->pPdDcInfo;
  1428. //
  1429. // Resource domain can only be in native mode if DS is running.
  1430. //
  1431. if (pSidSet->pRdDcInfo->Flags & DS_DS_FLAG)
  1432. {
  1433. dwError = DsRoleGetPrimaryDomainInformation(
  1434. pSidSet->pszRdDcName,
  1435. DsRolePrimaryDomainInfoBasic,
  1436. (PBYTE*)&pSidSet->pPdBasicInfo
  1437. );
  1438. if (dwError != ERROR_SUCCESS)
  1439. {
  1440. //
  1441. // If the domain is in mixed mode and we are passing in a DNS
  1442. // name, the call fails. We have to get rid of the DC name
  1443. // and get a flat one and then try again.
  1444. //
  1445. if (dwError == RPC_S_SERVER_UNAVAILABLE &&
  1446. pSidSet->pPdDcInfo &&
  1447. (pSidSet->pPdDcInfo->Flags & DS_INET_ADDRESS))
  1448. {
  1449. NetApiBufferFree(pSidSet->pPdDcInfo);
  1450. pSidSet->pPdDcInfo = 0;
  1451. pSidSet->pRdDcInfo = 0;
  1452. dwError = DsGetDcName(
  1453. 0,
  1454. pSidSet->pPrimaryInfoName,
  1455. 0,
  1456. 0,
  1457. 0,
  1458. &pSidSet->pPdDcInfo
  1459. );
  1460. if (dwError != ERROR_SUCCESS)
  1461. {
  1462. goto Cleanup;
  1463. }
  1464. pSidSet->pRdDcInfo = pSidSet->pPdDcInfo;
  1465. pSidSet->pszRdDcName = pSidSet->pRdDcInfo->DomainControllerName;
  1466. dwError = DsRoleGetPrimaryDomainInformation(
  1467. pSidSet->pszRdDcName,
  1468. DsRolePrimaryDomainInfoBasic,
  1469. (PBYTE*)&pSidSet->pPdBasicInfo
  1470. );
  1471. if (dwError != ERROR_SUCCESS)
  1472. {
  1473. goto Cleanup;
  1474. }
  1475. }
  1476. else
  1477. {
  1478. goto Cleanup;
  1479. }
  1480. }
  1481. pSidSet->pRdBasicInfo = pSidSet->pPdBasicInfo;
  1482. if ((pSidSet->pRdBasicInfo->Flags & DSROLE_PRIMARY_DS_RUNNING) &&
  1483. (pSidSet->pRdBasicInfo->Flags & DSROLE_PRIMARY_DS_MIXED_MODE) == 0)
  1484. {
  1485. bRdIsNative = TRUE;
  1486. }
  1487. }
  1488. }
  1489. //
  1490. // Get domain local groups.
  1491. //
  1492. if (bRdIsNative)
  1493. {
  1494. //
  1495. // Primary domain operates in native mode.
  1496. // This means there could be domain local groups in the token.
  1497. //
  1498. dwError = AuthzpGetResourceDomainGroups(
  1499. pSidSet);
  1500. if (dwError != ERROR_SUCCESS)
  1501. {
  1502. goto Cleanup;
  1503. }
  1504. }
  1505. LocalGroups:
  1506. //
  1507. // Collect local groups information.
  1508. // If this is the local user case, we have to add the primary group
  1509. // for the user.
  1510. //
  1511. dwError = AuthzpGetLocalGroups(
  1512. bAddPrimaryGroup,
  1513. pSidSet
  1514. );
  1515. if (dwError != ERROR_SUCCESS)
  1516. {
  1517. goto Cleanup;
  1518. }
  1519. Cleanup:
  1520. return dwError;
  1521. }
  1522. DWORD
  1523. AuthzpGetAccountDomainGroupsDs(
  1524. IN OUT PSID_SET pSidSet
  1525. )
  1526. /*++
  1527. Routine description:
  1528. This routine connects to the user domain and queries AD for
  1529. the list of groups (global and universal) the user belongs to.
  1530. Arguments:
  1531. pbNativeDomain - Pointer to a BOOL that will receive TRUE or FALSE depending
  1532. on the domain operation mode (native or mixed, resp).
  1533. pSidSet - Pointer to set of SIDs. New groups will be added to this set.
  1534. Return Value:
  1535. Win32 error code.
  1536. --*/
  1537. {
  1538. DWORD dwError;
  1539. PLDAP pLdap = 0;
  1540. LDAPMessage* pResult = 0;
  1541. LDAPMessage* pEntry = 0;
  1542. PLDAP_BERVAL* ppValue = 0;
  1543. PWCHAR ppszAttributes[] = {L"tokenGroupsGlobalAndUniversal", 0};
  1544. DWORD i;
  1545. DWORD dwSidCount;
  1546. WCHAR szSidEdn[SECURITY_MAX_SID_SIZE * 2 + 8];
  1547. AuthzpConvertSidToEdn(
  1548. pSidSet->pUserSid,
  1549. szSidEdn
  1550. );
  1551. //
  1552. // We now have the user's SID in LDAP readable form. Fetch the
  1553. // tokenGroupsGlobalAndUniversal attribute.
  1554. //
  1555. pLdap = ldap_init(
  1556. pSidSet->pszUdDcName ? pSidSet->pszUdDcName + 2 : 0,
  1557. LDAP_PORT
  1558. );
  1559. if (pLdap == 0)
  1560. {
  1561. dwError = LdapMapErrorToWin32(LdapGetLastError());
  1562. goto Cleanup;
  1563. }
  1564. if (pSidSet->pszUdDcName)
  1565. {
  1566. dwError = ldap_set_option(
  1567. pLdap,
  1568. LDAP_OPT_AREC_EXCLUSIVE,
  1569. LDAP_OPT_ON
  1570. );
  1571. if (dwError != LDAP_SUCCESS)
  1572. {
  1573. dwError = LdapMapErrorToWin32(dwError);
  1574. goto Cleanup;
  1575. }
  1576. }
  1577. //
  1578. // Set the sign and seal options to true.
  1579. //
  1580. dwError = ldap_set_option(
  1581. pLdap,
  1582. LDAP_OPT_SIGN,
  1583. LDAP_OPT_ON
  1584. );
  1585. if (dwError != LDAP_SUCCESS)
  1586. {
  1587. dwError = LdapMapErrorToWin32(dwError);
  1588. goto Cleanup;
  1589. }
  1590. dwError = ldap_set_option(
  1591. pLdap,
  1592. LDAP_OPT_ENCRYPT,
  1593. LDAP_OPT_ON
  1594. );
  1595. if (dwError != LDAP_SUCCESS)
  1596. {
  1597. dwError = LdapMapErrorToWin32(dwError);
  1598. goto Cleanup;
  1599. }
  1600. dwError = ldap_bind_s(
  1601. pLdap,
  1602. 0,
  1603. 0,
  1604. LDAP_AUTH_NEGOTIATE
  1605. );
  1606. if (dwError != LDAP_SUCCESS)
  1607. {
  1608. dwError = LdapMapErrorToWin32(dwError);
  1609. goto Cleanup;
  1610. }
  1611. dwError = ldap_search_s(
  1612. pLdap,
  1613. szSidEdn,
  1614. LDAP_SCOPE_BASE,
  1615. L"objectClass=*",
  1616. ppszAttributes,
  1617. FALSE,
  1618. &pResult
  1619. );
  1620. if (dwError != LDAP_SUCCESS)
  1621. {
  1622. dwError = LdapMapErrorToWin32(dwError);
  1623. goto Cleanup;
  1624. }
  1625. pEntry = ldap_first_entry(
  1626. pLdap,
  1627. pResult
  1628. );
  1629. if (pEntry == 0)
  1630. {
  1631. dwError = ERROR_ACCESS_DENIED;
  1632. goto Cleanup;
  1633. }
  1634. ppValue = ldap_get_values_len(
  1635. pLdap,
  1636. pEntry,
  1637. ppszAttributes[0]
  1638. );
  1639. if (ppValue == 0)
  1640. {
  1641. switch (pSidSet->sidUse)
  1642. {
  1643. case SidTypeAlias:
  1644. case SidTypeWellKnownGroup:
  1645. case SidTypeInvalid:
  1646. case SidTypeUnknown:
  1647. case SidTypeGroup:
  1648. break;
  1649. case SidTypeComputer:
  1650. case SidTypeDomain:
  1651. case SidTypeDeletedAccount:
  1652. case SidTypeUser:
  1653. default:
  1654. dwError = ERROR_ACCESS_DENIED;
  1655. goto Cleanup;
  1656. }
  1657. }
  1658. dwSidCount = ldap_count_values_len(ppValue);
  1659. //
  1660. // Merge the groups for our user into the result set.
  1661. //
  1662. for (i=0;i < dwSidCount;i++)
  1663. {
  1664. dwError = AuthzpAddSidToSidSet(
  1665. pSidSet,
  1666. (*ppValue[i]).bv_val,
  1667. (*ppValue[i]).bv_len,
  1668. SE_GROUP_ENABLED,
  1669. 0,
  1670. 0
  1671. );
  1672. if (dwError != ERROR_SUCCESS)
  1673. {
  1674. goto Cleanup;
  1675. }
  1676. }
  1677. dwError = ERROR_SUCCESS;
  1678. Cleanup:
  1679. if (ppValue)
  1680. {
  1681. ldap_value_free_len(ppValue);
  1682. }
  1683. if (pResult)
  1684. {
  1685. ldap_msgfree(pResult);
  1686. }
  1687. if (pLdap)
  1688. {
  1689. ldap_unbind(pLdap);
  1690. }
  1691. return dwError;
  1692. }
  1693. DWORD
  1694. AuthzpGetAccountDomainGroupsSam(
  1695. IN OUT PSID_SET pSidSet
  1696. )
  1697. /*++
  1698. Routine description:
  1699. This routine connects to the domain specified by the SID and
  1700. retrieves the list of groups to which the user belongs.
  1701. This resembles what the NetUserGetGroups API does. We are
  1702. not using it, because the Net APIs are name based and we
  1703. are working with SIDs.
  1704. Arguments:
  1705. pusDcName - DC on which the lookup should be performed.
  1706. pSidSet - Returns the number of SIDs in the alias list.
  1707. Return Value:
  1708. Win32 error code.
  1709. --*/
  1710. {
  1711. NTSTATUS status;
  1712. DWORD dwError = ERROR_SUCCESS;
  1713. PGROUP_MEMBERSHIP pGroups = 0;
  1714. PGROUP_MEMBERSHIP pGroup;
  1715. DWORD dwGroupCount = 0;
  1716. DWORD dwRelativeId = 0;
  1717. DWORD i;
  1718. PSID pSid = 0;
  1719. SAM_HANDLE hSam = 0;
  1720. SAM_HANDLE hDomain = 0;
  1721. SAM_HANDLE hUser = 0;
  1722. OBJECT_ATTRIBUTES obja = {0};
  1723. UNICODE_STRING usUdDcName = {0};
  1724. //
  1725. // If the sid is not a principal,
  1726. // it won't be a member of a SAM group.
  1727. //
  1728. if (pSidSet->sidUse != SidTypeUser &&
  1729. pSidSet->sidUse != SidTypeComputer)
  1730. {
  1731. goto Cleanup;
  1732. }
  1733. //
  1734. // Connect to the SAM server on the DC.
  1735. // If we are on the DC, connect locally.
  1736. //
  1737. if (pSidSet->pszUdDcName)
  1738. {
  1739. RtlInitUnicodeString(
  1740. &usUdDcName,
  1741. pSidSet->pszUdDcName);
  1742. status = SamConnect(
  1743. &usUdDcName,
  1744. &hSam,
  1745. SAM_SERVER_LOOKUP_DOMAIN,
  1746. &obja
  1747. );
  1748. }
  1749. else
  1750. {
  1751. status = SamConnect(
  1752. 0,
  1753. &hSam,
  1754. SAM_SERVER_LOOKUP_DOMAIN,
  1755. &obja
  1756. );
  1757. }
  1758. if (!NT_SUCCESS(status))
  1759. {
  1760. dwError = RtlNtStatusToDosError(status);
  1761. goto Cleanup;
  1762. }
  1763. //
  1764. // Open the domain we are interested in.
  1765. //
  1766. status = SamOpenDomain(
  1767. hSam,
  1768. DOMAIN_LOOKUP,
  1769. pSidSet->pDomainSid,
  1770. &hDomain
  1771. );
  1772. if (!NT_SUCCESS(status))
  1773. {
  1774. dwError = RtlNtStatusToDosError(status);
  1775. goto Cleanup;
  1776. }
  1777. //
  1778. // Finally, get a SAM handle to the user.
  1779. //
  1780. dwRelativeId = *RtlSubAuthoritySid(
  1781. pSidSet->pUserSid,
  1782. *RtlSubAuthorityCountSid(pSidSet->pUserSid) - 1
  1783. );
  1784. status = SamOpenUser(
  1785. hDomain,
  1786. USER_LIST_GROUPS,
  1787. dwRelativeId,
  1788. &hUser
  1789. );
  1790. if (!NT_SUCCESS(status))
  1791. {
  1792. dwError = RtlNtStatusToDosError(status);
  1793. goto Cleanup;
  1794. }
  1795. //
  1796. // Request all groups the user is a member of.
  1797. //
  1798. status = SamGetGroupsForUser(
  1799. hUser,
  1800. &pGroups,
  1801. &dwGroupCount
  1802. );
  1803. if (!NT_SUCCESS(status))
  1804. {
  1805. dwError = RtlNtStatusToDosError(status);
  1806. goto Cleanup;
  1807. }
  1808. //
  1809. // Stuff the group SIDs into pSidSet.
  1810. //
  1811. pGroup = pGroups;
  1812. for (i=0;i < dwGroupCount;i++,pGroup++)
  1813. {
  1814. status = SamRidToSid(
  1815. hDomain,
  1816. pGroup->RelativeId,
  1817. &pSid
  1818. );
  1819. if (!NT_SUCCESS(status))
  1820. {
  1821. dwError = RtlNtStatusToDosError(status);
  1822. goto Cleanup;
  1823. }
  1824. dwError = AuthzpAddSidToSidSet(
  1825. pSidSet,
  1826. pSid,
  1827. 0,
  1828. pGroup->Attributes,
  1829. 0,
  1830. 0
  1831. );
  1832. SamFreeMemory(pSid);
  1833. pSid = 0;
  1834. if (dwError != ERROR_SUCCESS)
  1835. {
  1836. goto Cleanup;
  1837. }
  1838. }
  1839. dwError = ERROR_SUCCESS;
  1840. Cleanup:
  1841. if (pGroups)
  1842. {
  1843. SamFreeMemory(pGroups);
  1844. }
  1845. if (hUser)
  1846. {
  1847. SamCloseHandle(hUser);
  1848. }
  1849. if (hDomain)
  1850. {
  1851. SamCloseHandle(hDomain);
  1852. }
  1853. if (hSam)
  1854. {
  1855. SamCloseHandle(hSam);
  1856. }
  1857. return dwError;
  1858. }
  1859. DWORD
  1860. AuthzpGetResourceDomainGroups(
  1861. IN OUT PSID_SET pSidSet
  1862. )
  1863. /*++
  1864. Routine description:
  1865. This routine connects to the primary (resource) domain and
  1866. queries SAM for nested memberships.
  1867. Arguments:
  1868. pSidSet - Pointer to set of SIDs. New groups will be added to this set.
  1869. Return Value:
  1870. Win32 error code.
  1871. --*/
  1872. {
  1873. DWORD dwError = ERROR_SUCCESS;
  1874. NTSTATUS status;
  1875. OBJECT_ATTRIBUTES obja = {0};
  1876. SAM_HANDLE hSam = 0;
  1877. UNICODE_STRING usRdDcName;
  1878. //
  1879. // Open a SAM handle to the resource domain.
  1880. //
  1881. if (pSidSet->pszRdDcName)
  1882. {
  1883. RtlInitUnicodeString(
  1884. &usRdDcName,
  1885. pSidSet->pszRdDcName);
  1886. status = SamConnect(
  1887. &usRdDcName,
  1888. &hSam,
  1889. SAM_SERVER_LOOKUP_DOMAIN,
  1890. &obja
  1891. );
  1892. }
  1893. else
  1894. {
  1895. status = SamConnect(
  1896. 0,
  1897. &hSam,
  1898. SAM_SERVER_LOOKUP_DOMAIN,
  1899. &obja
  1900. );
  1901. }
  1902. if (!NT_SUCCESS(status))
  1903. {
  1904. dwError = RtlNtStatusToDosError(status);
  1905. goto Cleanup;
  1906. }
  1907. //
  1908. // Call AuthzpGetAliasMembership to get nested memberships.
  1909. //
  1910. dwError = AuthzpGetAliasMembership(
  1911. hSam,
  1912. pSidSet->pPrimaryInfo->Sid,
  1913. pSidSet
  1914. );
  1915. if (dwError != ERROR_SUCCESS)
  1916. {
  1917. goto Cleanup;
  1918. }
  1919. //
  1920. // Retrieve the SID history.
  1921. //
  1922. dwError = AuthzpGetSidHistory(
  1923. pSidSet
  1924. );
  1925. if (dwError != ERROR_SUCCESS)
  1926. {
  1927. goto Cleanup;
  1928. }
  1929. dwError = ERROR_SUCCESS;
  1930. Cleanup:
  1931. if (hSam)
  1932. {
  1933. SamCloseHandle(hSam);
  1934. }
  1935. return dwError;
  1936. }
  1937. DWORD
  1938. AuthzpGetLocalGroups(
  1939. IN BOOL bAddPrimaryGroup,
  1940. IN OUT PSID_SET pSidSet
  1941. )
  1942. /*++
  1943. Routine description:
  1944. This routine connects to the domain specified by the caller and
  1945. retrieves the list of groups to which the user belongs.
  1946. We are checking the account domain and the builtin domain
  1947. using Sam APIs.
  1948. Arguments:
  1949. bAddPrimaryGroup - Boolean that indicates wheter the primary group of the
  1950. user should be computed and added to the sid set.
  1951. pSidSet - Pointer to the SID of the user for which group membership array
  1952. will be returned.
  1953. Return Value:
  1954. Win32 error.
  1955. --*/
  1956. {
  1957. DWORD dwError = ERROR_SUCCESS;
  1958. NTSTATUS status;
  1959. SAM_HANDLE hSam = 0;
  1960. OBJECT_ATTRIBUTES obja = {0};
  1961. BOOL bStatus;
  1962. BYTE sid[SECURITY_MAX_SID_SIZE];
  1963. PSID pBuiltinSid = (PSID)sid;
  1964. DWORD dwLengthSid = SECURITY_MAX_SID_SIZE;
  1965. //
  1966. // Open a handle to the SAM on the local computer.
  1967. //
  1968. status = SamConnect(
  1969. 0,
  1970. &hSam,
  1971. SAM_SERVER_LOOKUP_DOMAIN,
  1972. &obja
  1973. );
  1974. if (!NT_SUCCESS(status))
  1975. {
  1976. dwError = RtlNtStatusToDosError(status);
  1977. goto Cleanup;
  1978. }
  1979. //
  1980. // Add primary group information if requested.
  1981. //
  1982. if (bAddPrimaryGroup)
  1983. {
  1984. dwError = AuthzpGetPrimaryGroup(
  1985. hSam,
  1986. pSidSet
  1987. );
  1988. if (dwError != ERROR_SUCCESS)
  1989. {
  1990. goto Cleanup;
  1991. }
  1992. }
  1993. //
  1994. // Retrieve recursive membership for the account domain.
  1995. //
  1996. dwError = AuthzpGetAliasMembership(
  1997. hSam,
  1998. pSidSet->pAccountInfo->DomainSid,
  1999. pSidSet
  2000. );
  2001. if (dwError != ERROR_SUCCESS)
  2002. {
  2003. goto Cleanup;
  2004. }
  2005. //
  2006. // Retrieve recursive membership for the BUILTIN domain.
  2007. //
  2008. bStatus = CreateWellKnownSid(
  2009. WinBuiltinDomainSid,
  2010. 0,
  2011. pBuiltinSid,
  2012. &dwLengthSid
  2013. );
  2014. if (bStatus == FALSE)
  2015. {
  2016. dwError = GetLastError();
  2017. goto Cleanup;
  2018. }
  2019. dwError = AuthzpGetAliasMembership(
  2020. hSam,
  2021. pBuiltinSid,
  2022. pSidSet
  2023. );
  2024. if (dwError != ERROR_SUCCESS)
  2025. {
  2026. goto Cleanup;
  2027. }
  2028. dwError = ERROR_SUCCESS;
  2029. Cleanup:
  2030. if (hSam)
  2031. {
  2032. SamCloseHandle(hSam);
  2033. }
  2034. return dwError;
  2035. }
  2036. DWORD
  2037. AuthzpGetSidHistory(
  2038. IN OUT PSID_SET pSidSet
  2039. )
  2040. /*++
  2041. Routine description:
  2042. This routine queries ldap for the sidHistory attribute for every SID
  2043. in the set and adds the history SIDs the the set as well.
  2044. Arguments:
  2045. pszDomainName - Name of the domain to connect to.
  2046. pSidSet - Pointer to set of SIDs. New groups will be added to this set.
  2047. Return Value:
  2048. Win32 error code.
  2049. --*/
  2050. {
  2051. DWORD dwError = ERROR_SUCCESS;
  2052. PLDAP pLdap = 0;
  2053. LDAPMessage* pResult = 0;
  2054. LDAPMessage* pEntry = 0;
  2055. PLDAP_BERVAL* ppValue = 0;
  2056. PWCHAR ppszAttributes[] = {L"sidHistory", 0};
  2057. DWORD i, j;
  2058. DWORD dwSidCount;
  2059. DWORD dwValueCount;
  2060. PSID_DESC pSidDesc;
  2061. WCHAR szSidEdn[SECURITY_MAX_SID_SIZE * 2 + 8];
  2062. //
  2063. // Open a ldap connection to the primary domain.
  2064. // Get rid of the leading \\ before using the DC name.
  2065. //
  2066. pLdap = ldap_init(
  2067. pSidSet->pszRdDcName ? pSidSet->pszRdDcName + 2 : 0,
  2068. LDAP_PORT
  2069. );
  2070. if (pLdap == 0)
  2071. {
  2072. dwError = LdapMapErrorToWin32(LdapGetLastError());
  2073. goto Cleanup;
  2074. }
  2075. if (pSidSet->pszRdDcName)
  2076. {
  2077. dwError = ldap_set_option(
  2078. pLdap,
  2079. LDAP_OPT_AREC_EXCLUSIVE,
  2080. LDAP_OPT_ON
  2081. );
  2082. if (dwError != LDAP_SUCCESS)
  2083. {
  2084. dwError = LdapMapErrorToWin32(dwError);
  2085. goto Cleanup;
  2086. }
  2087. }
  2088. //
  2089. // Set the sign and seal options to true.
  2090. //
  2091. dwError = ldap_set_option(
  2092. pLdap,
  2093. LDAP_OPT_SIGN,
  2094. LDAP_OPT_ON
  2095. );
  2096. if (dwError != LDAP_SUCCESS)
  2097. {
  2098. dwError = LdapMapErrorToWin32(dwError);
  2099. goto Cleanup;
  2100. }
  2101. dwError = ldap_set_option(
  2102. pLdap,
  2103. LDAP_OPT_ENCRYPT,
  2104. LDAP_OPT_ON
  2105. );
  2106. if (dwError != LDAP_SUCCESS)
  2107. {
  2108. dwError = LdapMapErrorToWin32(dwError);
  2109. goto Cleanup;
  2110. }
  2111. dwError = ldap_bind_s(
  2112. pLdap,
  2113. 0,
  2114. 0,
  2115. LDAP_AUTH_NEGOTIATE
  2116. );
  2117. if (dwError != LDAP_SUCCESS)
  2118. {
  2119. dwError = LdapMapErrorToWin32(dwError);
  2120. goto Cleanup;
  2121. }
  2122. //
  2123. // Loop through all SIDs and retrieve the history attribute
  2124. // for each one of them.
  2125. //
  2126. dwSidCount = pSidSet->dwCount;
  2127. pSidDesc = pSidSet->pSidDesc;
  2128. for (i=0;i < dwSidCount;i++,pSidDesc++)
  2129. {
  2130. AuthzpConvertSidToEdn(
  2131. pSidDesc->sid,
  2132. szSidEdn
  2133. );
  2134. dwError = ldap_search_s(
  2135. pLdap,
  2136. szSidEdn,
  2137. LDAP_SCOPE_BASE,
  2138. L"objectClass=*",
  2139. ppszAttributes,
  2140. FALSE,
  2141. &pResult
  2142. );
  2143. if (dwError != LDAP_SUCCESS)
  2144. {
  2145. if (dwError == LDAP_NO_SUCH_OBJECT)
  2146. {
  2147. //
  2148. // The SID was not found, this is not an error.
  2149. //
  2150. dwError = ERROR_SUCCESS;
  2151. if (pResult)
  2152. {
  2153. ldap_msgfree(pResult);
  2154. pResult = NULL;
  2155. }
  2156. continue;
  2157. }
  2158. dwError = LdapMapErrorToWin32(dwError);
  2159. goto Cleanup;
  2160. }
  2161. pEntry = ldap_first_entry(
  2162. pLdap,
  2163. pResult);
  2164. if (pEntry == 0)
  2165. {
  2166. dwError = ERROR_ACCESS_DENIED;
  2167. goto Cleanup;
  2168. }
  2169. ppValue = ldap_get_values_len(
  2170. pLdap,
  2171. pEntry,
  2172. ppszAttributes[0]
  2173. );
  2174. //
  2175. // Now we have the history attribute for our group.
  2176. // Merge it into the result set.
  2177. //
  2178. dwValueCount = ldap_count_values_len(ppValue);
  2179. for (j=0;j < dwValueCount;j++)
  2180. {
  2181. dwError = AuthzpAddSidToSidSet(
  2182. pSidSet,
  2183. (*ppValue[j]).bv_val,
  2184. (*ppValue[j]).bv_len,
  2185. SE_GROUP_MANDATORY
  2186. | SE_GROUP_ENABLED_BY_DEFAULT
  2187. | SE_GROUP_ENABLED,
  2188. 0,
  2189. 0
  2190. );
  2191. if (dwError != ERROR_SUCCESS)
  2192. {
  2193. goto Cleanup;
  2194. }
  2195. }
  2196. if (ppValue)
  2197. {
  2198. ldap_value_free_len(ppValue);
  2199. ppValue = 0;
  2200. }
  2201. if (pResult)
  2202. {
  2203. ldap_msgfree(pResult);
  2204. pResult = 0;
  2205. }
  2206. }
  2207. dwError = ERROR_SUCCESS;
  2208. Cleanup:
  2209. if (ppValue)
  2210. {
  2211. ldap_value_free_len(ppValue);
  2212. }
  2213. if (pResult)
  2214. {
  2215. ldap_msgfree(pResult);
  2216. }
  2217. if (pLdap)
  2218. {
  2219. ldap_unbind(pLdap);
  2220. }
  2221. return dwError;
  2222. }
  2223. DWORD
  2224. AuthzpGetAliasMembership(
  2225. IN SAM_HANDLE hSam,
  2226. IN PSID pDomainSid,
  2227. IN OUT PSID_SET pSidSet
  2228. )
  2229. /*++
  2230. Routine description:
  2231. We try to find nested groups here. This only makes sense on domains
  2232. in native mode.
  2233. This routine calls SamGetAliasMembership iteratively until no
  2234. more nested groups are returned.
  2235. Arguments:
  2236. hSam - Handle to the SAM database.
  2237. pDomainSid - SID of the domain to operate on.
  2238. ppSidSet - Set of SIDs that are checked for membership. Newly
  2239. found group SIDs are added to the set.
  2240. Return Value:
  2241. Win32 error code.
  2242. --*/
  2243. {
  2244. DWORD dwError = ERROR_SUCCESS;
  2245. NTSTATUS status;
  2246. PSID pSid = 0;
  2247. SAM_HANDLE hDomain = 0;
  2248. DWORD dwSidCount;
  2249. DWORD dwSidCountNew;
  2250. DWORD dwSidListSize;
  2251. DWORD i;
  2252. BOOL bAdded;
  2253. PSID* ppSidList = 0;
  2254. PDWORD pRidList = 0;
  2255. PDWORD pRid;
  2256. //
  2257. // Get a SAM handle to the domain.
  2258. //
  2259. status = SamOpenDomain(
  2260. hSam,
  2261. DOMAIN_GET_ALIAS_MEMBERSHIP,
  2262. pDomainSid,
  2263. &hDomain
  2264. );
  2265. if (!NT_SUCCESS(status))
  2266. {
  2267. dwError = RtlNtStatusToDosError(status);
  2268. goto Cleanup;
  2269. }
  2270. //
  2271. // Retrieve the memberships iteratively.
  2272. //
  2273. dwSidCount = pSidSet->dwCount;
  2274. dwSidListSize = dwSidCount;
  2275. ppSidList = (PSID*)AuthzpAlloc(
  2276. dwSidCount * sizeof(PSID)
  2277. );
  2278. if (ppSidList == 0)
  2279. {
  2280. dwError = GetLastError();
  2281. goto Cleanup;
  2282. }
  2283. for (i=0;i < dwSidCount;i++)
  2284. {
  2285. ppSidList[i] = pSidSet->pSidDesc[i].sid;
  2286. }
  2287. do
  2288. {
  2289. status = SamGetAliasMembership(
  2290. hDomain,
  2291. dwSidCount,
  2292. ppSidList,
  2293. &dwSidCountNew,
  2294. &pRidList
  2295. );
  2296. if (!NT_SUCCESS(status))
  2297. {
  2298. dwError = RtlNtStatusToDosError(status);
  2299. goto Cleanup;
  2300. }
  2301. if (dwSidCountNew > dwSidListSize)
  2302. {
  2303. AuthzpFree(ppSidList);
  2304. ppSidList = (PSID*)AuthzpAlloc(
  2305. dwSidCountNew * sizeof(PSID)
  2306. );
  2307. if (ppSidList == 0)
  2308. {
  2309. dwError = GetLastError();
  2310. goto Cleanup;
  2311. }
  2312. dwSidListSize = dwSidCountNew;
  2313. }
  2314. dwSidCount = 0;
  2315. pRid = pRidList;
  2316. for (i=0;i < dwSidCountNew;i++,pRid++)
  2317. {
  2318. status = SamRidToSid(
  2319. hDomain,
  2320. *pRid,
  2321. &pSid
  2322. );
  2323. if (!NT_SUCCESS(status))
  2324. {
  2325. dwError = RtlNtStatusToDosError(status);
  2326. goto Cleanup;
  2327. }
  2328. dwError = AuthzpAddSidToSidSet(
  2329. pSidSet,
  2330. pSid,
  2331. 0,
  2332. SE_GROUP_MANDATORY
  2333. | SE_GROUP_ENABLED_BY_DEFAULT
  2334. | SE_GROUP_ENABLED,
  2335. &bAdded,
  2336. ppSidList + dwSidCount
  2337. );
  2338. SamFreeMemory(pSid);
  2339. pSid = 0;
  2340. if (dwError != ERROR_SUCCESS)
  2341. {
  2342. goto Cleanup;
  2343. }
  2344. if (bAdded)
  2345. {
  2346. dwSidCount++;
  2347. }
  2348. }
  2349. if (pRidList)
  2350. {
  2351. SamFreeMemory(pRidList);
  2352. pRidList = 0;
  2353. }
  2354. }
  2355. while (dwSidCount);
  2356. dwError = ERROR_SUCCESS;
  2357. Cleanup:
  2358. if (pRidList)
  2359. {
  2360. SamFreeMemory(pRidList);
  2361. }
  2362. if (ppSidList)
  2363. {
  2364. AuthzpFree(ppSidList);
  2365. }
  2366. if (hDomain)
  2367. {
  2368. SamCloseHandle(hDomain);
  2369. }
  2370. return dwError;
  2371. }
  2372. DWORD
  2373. AuthzpGetPrimaryGroup(
  2374. IN SAM_HANDLE hSam,
  2375. IN OUT PSID_SET pSidSet
  2376. )
  2377. /*++
  2378. Routine description:
  2379. Add the primary group of the user to the sid set.
  2380. Arguments:
  2381. hSam - Handle to the SAM database.
  2382. pSidSet - Add the sid of the primary group to this set.
  2383. Return Value:
  2384. Win32 error code.
  2385. --*/
  2386. {
  2387. DWORD dwError = ERROR_SUCCESS;
  2388. NTSTATUS status;
  2389. SAM_HANDLE hDomain = 0;
  2390. SAM_HANDLE hUser = 0;
  2391. PUSER_PRIMARY_GROUP_INFORMATION
  2392. pInfo = 0;
  2393. PSID pPrimaryGroupSid = NULL;
  2394. DWORD dwRelativeId = 0;
  2395. //
  2396. // Open the account domain.
  2397. //
  2398. status = SamOpenDomain(
  2399. hSam,
  2400. DOMAIN_LOOKUP,
  2401. pSidSet->pDomainSid,
  2402. &hDomain
  2403. );
  2404. if (!NT_SUCCESS(status))
  2405. {
  2406. dwError = RtlNtStatusToDosError(status);
  2407. goto Cleanup;
  2408. }
  2409. //
  2410. // Extract the rid from the user sid.
  2411. //
  2412. dwRelativeId = *RtlSubAuthoritySid(
  2413. pSidSet->pUserSid,
  2414. *RtlSubAuthorityCountSid(pSidSet->pUserSid) - 1
  2415. );
  2416. //
  2417. // Open the user for read.
  2418. //
  2419. status = SamOpenUser(
  2420. hDomain,
  2421. USER_READ_GENERAL,
  2422. dwRelativeId,
  2423. &hUser
  2424. );
  2425. if (!NT_SUCCESS(status))
  2426. {
  2427. dwError = RtlNtStatusToDosError(status);
  2428. goto Cleanup;
  2429. }
  2430. //
  2431. // Get the primary group information for the user.
  2432. //
  2433. status = SamQueryInformationUser(
  2434. hUser,
  2435. UserPrimaryGroupInformation,
  2436. &pInfo
  2437. );
  2438. if (!NT_SUCCESS(status))
  2439. {
  2440. dwError = RtlNtStatusToDosError(status);
  2441. goto Cleanup;
  2442. }
  2443. //
  2444. // Convert the group rid to a sid.
  2445. //
  2446. status = SamRidToSid(
  2447. hDomain,
  2448. pInfo->PrimaryGroupId,
  2449. &pPrimaryGroupSid
  2450. );
  2451. SamFreeMemory(pInfo);
  2452. if (!NT_SUCCESS(status))
  2453. {
  2454. dwError = RtlNtStatusToDosError(status);
  2455. goto Cleanup;
  2456. }
  2457. //
  2458. // Add the group sid to the set.
  2459. //
  2460. dwError = AuthzpAddSidToSidSet(
  2461. pSidSet,
  2462. pPrimaryGroupSid,
  2463. 0,
  2464. SE_GROUP_ENABLED,
  2465. 0,
  2466. 0
  2467. );
  2468. SamFreeMemory(pPrimaryGroupSid);
  2469. if (dwError != ERROR_SUCCESS)
  2470. {
  2471. goto Cleanup;
  2472. }
  2473. dwError = ERROR_SUCCESS;
  2474. Cleanup:
  2475. if (hUser)
  2476. {
  2477. SamCloseHandle(hUser);
  2478. }
  2479. if (hDomain)
  2480. {
  2481. SamCloseHandle(hDomain);
  2482. }
  2483. return dwError;
  2484. }
  2485. DWORD
  2486. AuthzpInitializeSidSetByName(
  2487. IN PUNICODE_STRING pusUserName,
  2488. IN PUNICODE_STRING pusDomainName,
  2489. IN DWORD dwFlags,
  2490. IN PSID_SET pSidSet
  2491. )
  2492. /*++
  2493. Routine description:
  2494. Initializes a sid set and reserves memory for the
  2495. max amount of memory it will ever need.
  2496. The memory is not allocated yet. This only happens as SIDs get
  2497. added to the set. All members are initialized to meaningful values.
  2498. Arguments:
  2499. pSidSet - The sid set to operate on.
  2500. Return Value:
  2501. Win32 error code.
  2502. --*/
  2503. {
  2504. DWORD dwError = ERROR_SUCCESS;
  2505. SYSTEM_INFO sysInfo;
  2506. if (s_dwPageSize == 0)
  2507. {
  2508. GetSystemInfo(&sysInfo);
  2509. s_dwPageSize = sysInfo.dwPageSize;
  2510. }
  2511. pSidSet->pSidDesc = (PSID_DESC)VirtualAlloc(
  2512. 0,
  2513. c_dwMaxSidCount * sizeof(SID_DESC),
  2514. MEM_RESERVE,
  2515. PAGE_NOACCESS
  2516. );
  2517. if (pSidSet->pSidDesc == 0)
  2518. {
  2519. dwError = GetLastError();
  2520. goto Cleanup;
  2521. }
  2522. pSidSet->dwCount = 0;
  2523. pSidSet->dwMaxCount = 0;
  2524. pSidSet->dwBaseCount = 0;
  2525. pSidSet->dwFlags = dwFlags;
  2526. pSidSet->pUserSid = 0;
  2527. pSidSet->pDomainSid = 0;
  2528. pSidSet->pusUserName = pusUserName;
  2529. //
  2530. // Verify for once we got a valid domain.
  2531. // Otherwise we assume we got a UPN in pusUserName.
  2532. //
  2533. if (pusDomainName &&
  2534. pusDomainName->Length &&
  2535. pusDomainName->Buffer)
  2536. {
  2537. pSidSet->pusDomainName = pusDomainName;
  2538. }
  2539. else
  2540. {
  2541. pSidSet->pusDomainName = 0;
  2542. }
  2543. pSidSet->pNames = 0;
  2544. pSidSet->pDomains = 0;
  2545. pSidSet->pDomainsName = 0;
  2546. pSidSet->pSids = 0;
  2547. pSidSet->sidUse = SidTypeUnknown;
  2548. pSidSet->pAccountInfo = 0;
  2549. pSidSet->pPrimaryInfo = 0;
  2550. pSidSet->pPrimaryInfoName = 0;
  2551. pSidSet->bStandalone = TRUE;
  2552. pSidSet->bSkipNonLocal = FALSE;
  2553. pSidSet->pUdDcInfo = 0;
  2554. pSidSet->pPdDcInfo = 0;
  2555. pSidSet->pRdDcInfo = 0;
  2556. pSidSet->pUdBasicInfo = 0;
  2557. pSidSet->pPdBasicInfo = 0;
  2558. pSidSet->pRdBasicInfo = 0;
  2559. pSidSet->pszUdDcName = 0;
  2560. pSidSet->pszRdDcName = 0;
  2561. dwError = ERROR_SUCCESS;
  2562. Cleanup:
  2563. return dwError;
  2564. }
  2565. DWORD
  2566. AuthzpInitializeSidSetBySid(
  2567. IN PSID pUserSid,
  2568. IN DWORD dwFlags,
  2569. IN PSID_SET pSidSet
  2570. )
  2571. /*++
  2572. Routine description:
  2573. Initializes a sid set and reserves memory for the
  2574. max amount of memory it will ever need.
  2575. The memory is not allocated yet. This only happens as SIDs get
  2576. added to the set. All members are initialized to meaningful values.
  2577. Arguments:
  2578. pSidSet - The sid set to operate on.
  2579. Return Value:
  2580. Win32 error code.
  2581. --*/
  2582. {
  2583. DWORD dwError = ERROR_SUCCESS;
  2584. SYSTEM_INFO sysInfo;
  2585. if (s_dwPageSize == 0)
  2586. {
  2587. GetSystemInfo(&sysInfo);
  2588. s_dwPageSize = sysInfo.dwPageSize;
  2589. }
  2590. if (!RtlValidSid(pUserSid))
  2591. {
  2592. dwError = ERROR_INVALID_SID;
  2593. goto Cleanup;
  2594. }
  2595. pSidSet->pSidDesc = (PSID_DESC)VirtualAlloc(
  2596. 0,
  2597. c_dwMaxSidCount * sizeof(SID_DESC),
  2598. MEM_RESERVE,
  2599. PAGE_NOACCESS
  2600. );
  2601. if (pSidSet->pSidDesc == 0)
  2602. {
  2603. dwError = GetLastError();
  2604. goto Cleanup;
  2605. }
  2606. pSidSet->dwCount = 0;
  2607. pSidSet->dwMaxCount = 0;
  2608. pSidSet->dwBaseCount = 0;
  2609. pSidSet->dwFlags = dwFlags;
  2610. pSidSet->pUserSid = pUserSid;
  2611. pSidSet->pDomainSid = 0;
  2612. pSidSet->pusUserName = 0;
  2613. pSidSet->pusDomainName = 0;
  2614. pSidSet->pNames = 0;
  2615. pSidSet->pDomains = 0;
  2616. pSidSet->pDomainsName = 0;
  2617. pSidSet->pSids = 0;
  2618. pSidSet->sidUse = SidTypeUnknown;
  2619. pSidSet->pAccountInfo = 0;
  2620. pSidSet->pPrimaryInfo = 0;
  2621. pSidSet->pPrimaryInfoName = 0;
  2622. pSidSet->bStandalone = TRUE;
  2623. pSidSet->bSkipNonLocal = FALSE;
  2624. pSidSet->pUdDcInfo = 0;
  2625. pSidSet->pPdDcInfo = 0;
  2626. pSidSet->pRdDcInfo = 0;
  2627. pSidSet->pUdBasicInfo = 0;
  2628. pSidSet->pPdBasicInfo = 0;
  2629. pSidSet->pRdBasicInfo = 0;
  2630. pSidSet->pszUdDcName = 0;
  2631. pSidSet->pszRdDcName = 0;
  2632. dwError = ERROR_SUCCESS;
  2633. Cleanup:
  2634. return dwError;
  2635. }
  2636. DWORD
  2637. AuthzpDeleteSidSet(
  2638. IN PSID_SET pSidSet
  2639. )
  2640. /*++
  2641. Routine description:
  2642. Deletes all memory allocated to the sid set
  2643. structure and resets all members to zero.
  2644. Arguments:
  2645. pSidSet - The sid set to operate on.
  2646. Return Value:
  2647. Win32 error code.
  2648. --*/
  2649. {
  2650. if (pSidSet->pSidDesc)
  2651. {
  2652. VirtualFree(pSidSet->pSidDesc, 0, MEM_RELEASE);
  2653. }
  2654. if (pSidSet->pNames)
  2655. {
  2656. LsaFreeMemory(pSidSet->pNames);
  2657. }
  2658. if (pSidSet->pDomains)
  2659. {
  2660. LsaFreeMemory(pSidSet->pDomains);
  2661. }
  2662. if (pSidSet->pDomainsName)
  2663. {
  2664. AuthzpFree(pSidSet->pDomainsName);
  2665. }
  2666. if (pSidSet->pSids)
  2667. {
  2668. LsaFreeMemory(pSidSet->pSids);
  2669. }
  2670. if (pSidSet->pAccountInfo)
  2671. {
  2672. LsaFreeMemory(pSidSet->pAccountInfo);
  2673. }
  2674. if (pSidSet->pPrimaryInfo)
  2675. {
  2676. LsaFreeMemory(pSidSet->pPrimaryInfo);
  2677. }
  2678. if (pSidSet->pPrimaryInfoName)
  2679. {
  2680. AuthzpFree(pSidSet->pPrimaryInfoName);
  2681. }
  2682. if (pSidSet->pUdDcInfo)
  2683. {
  2684. NetApiBufferFree(pSidSet->pUdDcInfo);
  2685. }
  2686. if (pSidSet->pPdDcInfo)
  2687. {
  2688. NetApiBufferFree(pSidSet->pPdDcInfo);
  2689. }
  2690. if (pSidSet->pUdBasicInfo)
  2691. {
  2692. DsRoleFreeMemory(pSidSet->pUdBasicInfo);
  2693. }
  2694. if (pSidSet->pPdBasicInfo)
  2695. {
  2696. DsRoleFreeMemory(pSidSet->pPdBasicInfo);
  2697. }
  2698. RtlZeroMemory(
  2699. pSidSet,
  2700. sizeof(SID_SET));
  2701. return ERROR_SUCCESS;
  2702. }
  2703. DWORD
  2704. AuthzpAddSidToSidSet(
  2705. IN PSID_SET pSidSet,
  2706. IN PSID pSid,
  2707. IN DWORD dwSidLength OPTIONAL,
  2708. IN DWORD dwAttributes,
  2709. OUT PBOOL pbAdded OPTIONAL,
  2710. OUT PSID* ppSid OPTIONAL
  2711. )
  2712. /*++
  2713. Routine description:
  2714. Check if the given SID already exists in the set. If yes, return.
  2715. Otherwise, add it to the set.
  2716. Arguments:
  2717. pSidSet - The sid set to operate on.
  2718. pSid - The SID to add to the set.
  2719. dwSidLength - Length of the SID in bytes. If zero is passed in,
  2720. the routine calculates the length itself.
  2721. dwAttributes - Attributes of the SID like in the
  2722. SID_AND_ATTRIBUTES structure.
  2723. pbAdded - Optional pointer that receives indication if the SID
  2724. was indeed added or not (because it was a duplicate).
  2725. ppSid - Optional pointer to where the new sid is stored.
  2726. Return Value:
  2727. Win32 error code.
  2728. --*/
  2729. {
  2730. DWORD dwError = ERROR_SUCCESS;
  2731. DWORD i;
  2732. DWORD dwSize;
  2733. BOOL bAdded = FALSE;
  2734. PSID_DESC pSidDesc;
  2735. if (dwSidLength == 0)
  2736. {
  2737. dwSidLength = RtlLengthSid(pSid);
  2738. }
  2739. pSidDesc = pSidSet->pSidDesc;
  2740. for (i=0;i < pSidSet->dwCount;i++,pSidDesc++)
  2741. {
  2742. if (dwSidLength == pSidDesc->dwLength)
  2743. {
  2744. if (RtlEqualSid(
  2745. pSid,
  2746. pSidDesc->sid))
  2747. {
  2748. goto Cleanup;
  2749. }
  2750. }
  2751. }
  2752. if (pSidSet->dwCount >= pSidSet->dwMaxCount)
  2753. {
  2754. if (pSidSet->dwCount >= c_dwMaxSidCount)
  2755. {
  2756. dwError = ERROR_NOT_ENOUGH_MEMORY;
  2757. goto Cleanup;
  2758. }
  2759. //
  2760. // Commit one more page in the buffer.
  2761. //
  2762. dwSize = (pSidSet->dwCount + 1) * sizeof(SID_DESC);
  2763. dwSize += s_dwPageSize - 1;
  2764. dwSize &= ~(s_dwPageSize - 1);
  2765. pSidDesc = (PSID_DESC)VirtualAlloc(
  2766. pSidSet->pSidDesc,
  2767. dwSize,
  2768. MEM_COMMIT,
  2769. PAGE_READWRITE
  2770. );
  2771. if (pSidDesc != pSidSet->pSidDesc)
  2772. {
  2773. dwError = GetLastError();
  2774. goto Cleanup;
  2775. }
  2776. pSidSet->dwMaxCount = dwSize / sizeof(SID_DESC);
  2777. }
  2778. pSidDesc = pSidSet->pSidDesc + pSidSet->dwCount;
  2779. pSidDesc->dwAttributes = dwAttributes;
  2780. pSidDesc->dwLength = dwSidLength;
  2781. RtlCopyMemory(
  2782. pSidDesc->sid,
  2783. pSid,
  2784. dwSidLength
  2785. );
  2786. bAdded = TRUE;
  2787. pSidSet->dwCount++;
  2788. if (ppSid)
  2789. {
  2790. *ppSid = pSidDesc->sid;
  2791. }
  2792. dwError = ERROR_SUCCESS;
  2793. Cleanup:
  2794. if (pbAdded)
  2795. {
  2796. *pbAdded = bAdded;
  2797. }
  2798. return dwError;
  2799. }
  2800. DWORD
  2801. AuthzpGetUserDomainSid(
  2802. PSID_SET pSidSet
  2803. )
  2804. {
  2805. DWORD dwError;
  2806. NTSTATUS status;
  2807. LSA_HANDLE hPolicy = 0;
  2808. OBJECT_ATTRIBUTES obja = {0};
  2809. SECURITY_QUALITY_OF_SERVICE sqos;
  2810. WCHAR wc[2] = L"\\";
  2811. UNICODE_STRING usName = {0};
  2812. PUNICODE_STRING pusName = 0;
  2813. //
  2814. // Build the string domain - name string that should be
  2815. // translated.
  2816. //
  2817. if (pSidSet->pusDomainName)
  2818. {
  2819. usName.MaximumLength =
  2820. pSidSet->pusDomainName->Length +
  2821. sizeof(WCHAR) +
  2822. pSidSet->pusUserName->Length +
  2823. sizeof(WCHAR);
  2824. usName.Buffer = (PWSTR)LocalAlloc(
  2825. LMEM_FIXED,
  2826. usName.MaximumLength
  2827. );
  2828. if (usName.Buffer == 0)
  2829. {
  2830. dwError = GetLastError();
  2831. goto Cleanup;
  2832. }
  2833. RtlCopyMemory(
  2834. usName.Buffer,
  2835. pSidSet->pusDomainName->Buffer,
  2836. pSidSet->pusDomainName->Length
  2837. );
  2838. usName.Length = (USHORT)(usName.Length + pSidSet->pusDomainName->Length);
  2839. RtlCopyMemory(
  2840. ((PBYTE)usName.Buffer) + usName.Length,
  2841. wc + 0,
  2842. sizeof(WCHAR)
  2843. );
  2844. usName.Length += sizeof(WCHAR);
  2845. RtlCopyMemory(
  2846. ((PBYTE)usName.Buffer) + usName.Length,
  2847. pSidSet->pusUserName->Buffer,
  2848. pSidSet->pusUserName->Length
  2849. );
  2850. usName.Length = (USHORT)(usName.Length + pSidSet->pusUserName->Length);
  2851. RtlCopyMemory(
  2852. ((PBYTE)usName.Buffer) + usName.Length,
  2853. wc + 1,
  2854. sizeof(WCHAR)
  2855. );
  2856. pusName = &usName;
  2857. }
  2858. else
  2859. {
  2860. //
  2861. // Assume we got a UPN.
  2862. //
  2863. pusName = pSidSet->pusUserName;
  2864. }
  2865. //
  2866. // set up the object attributes prior to opening the LSA
  2867. //
  2868. sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  2869. sqos.ImpersonationLevel = SecurityImpersonation;
  2870. sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  2871. sqos.EffectiveOnly = FALSE;
  2872. obja.SecurityQualityOfService = &sqos;
  2873. //
  2874. // open the LSA policy
  2875. //
  2876. status = LsaOpenPolicy(
  2877. 0,
  2878. &obja,
  2879. POLICY_LOOKUP_NAMES,
  2880. &hPolicy
  2881. );
  2882. if (!NT_SUCCESS(status))
  2883. {
  2884. dwError = LsaNtStatusToWinError(status);
  2885. goto Cleanup;
  2886. }
  2887. status = LsaLookupNames2(
  2888. hPolicy,
  2889. 0, // no flags
  2890. 1,
  2891. pusName,
  2892. &pSidSet->pDomains,
  2893. &pSidSet->pSids
  2894. );
  2895. if (!NT_SUCCESS(status))
  2896. {
  2897. dwError = LsaNtStatusToWinError(status);
  2898. goto Cleanup;
  2899. }
  2900. if (pSidSet->pSids == 0)
  2901. {
  2902. dwError = ERROR_INVALID_PARAMETER;
  2903. goto Cleanup;
  2904. }
  2905. switch (pSidSet->pSids->Use)
  2906. {
  2907. case SidTypeDomain:
  2908. case SidTypeInvalid:
  2909. case SidTypeUnknown:
  2910. dwError = ERROR_INVALID_PARAMETER;
  2911. goto Cleanup;
  2912. }
  2913. //
  2914. // The name was successfully translated.
  2915. // There should be exactly one domain and its index should be zero.
  2916. //
  2917. ASSERT(pSidSet->pDomains->Entries == 1);
  2918. ASSERT(pSidSet->pDomains->Domains != 0);
  2919. ASSERT(pSidSet->pSids->DomainIndex == 0);
  2920. pSidSet->pUserSid = pSidSet->pSids->Sid;
  2921. pSidSet->pDomainSid = pSidSet->pDomains->Domains->Sid;
  2922. pSidSet->sidUse = pSidSet->pSids->Use;
  2923. pSidSet->pDomainsName = (PWSTR) AuthzpAlloc(pSidSet->pDomains->Domains->Name.Length + sizeof(WCHAR));
  2924. if (pSidSet->pDomainsName == NULL)
  2925. {
  2926. dwError = ERROR_NOT_ENOUGH_MEMORY;
  2927. goto Cleanup;
  2928. }
  2929. wcsncpy(pSidSet->pDomainsName, pSidSet->pDomains->Domains->Name.Buffer, pSidSet->pDomains->Domains->Name.Length/sizeof(WCHAR));
  2930. pSidSet->pDomainsName[pSidSet->pDomains->Domains->Name.Length/sizeof(WCHAR)] = L'\0';
  2931. dwError = ERROR_SUCCESS;
  2932. Cleanup:
  2933. if (hPolicy)
  2934. {
  2935. LsaClose(hPolicy);
  2936. }
  2937. if (usName.Buffer)
  2938. {
  2939. AuthzpFree((HLOCAL)usName.Buffer);
  2940. }
  2941. return dwError;
  2942. }
  2943. DWORD
  2944. AuthzpGetUserDomainName(
  2945. PSID_SET pSidSet
  2946. )
  2947. {
  2948. DWORD dwError;
  2949. NTSTATUS status;
  2950. LSA_HANDLE hPolicy = 0;
  2951. OBJECT_ATTRIBUTES obja = {0};
  2952. SECURITY_QUALITY_OF_SERVICE sqos;
  2953. //
  2954. // set up the object attributes prior to opening the LSA
  2955. //
  2956. sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  2957. sqos.ImpersonationLevel = SecurityImpersonation;
  2958. sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  2959. sqos.EffectiveOnly = FALSE;
  2960. obja.SecurityQualityOfService = &sqos;
  2961. //
  2962. // open the LSA policy
  2963. //
  2964. status = LsaOpenPolicy(
  2965. 0,
  2966. &obja,
  2967. POLICY_LOOKUP_NAMES,
  2968. &hPolicy
  2969. );
  2970. if (!NT_SUCCESS(status))
  2971. {
  2972. dwError = LsaNtStatusToWinError(status);
  2973. goto Cleanup;
  2974. }
  2975. status = LsaLookupSids(
  2976. hPolicy,
  2977. 1,
  2978. &pSidSet->pUserSid,
  2979. &pSidSet->pDomains,
  2980. &pSidSet->pNames
  2981. );
  2982. if (!NT_SUCCESS(status))
  2983. {
  2984. dwError = LsaNtStatusToWinError(status);
  2985. goto Cleanup;
  2986. }
  2987. if (pSidSet->pNames == 0)
  2988. {
  2989. dwError = ERROR_INVALID_PARAMETER;
  2990. goto Cleanup;
  2991. }
  2992. switch (pSidSet->pNames->Use)
  2993. {
  2994. case SidTypeDomain:
  2995. case SidTypeUnknown:
  2996. case SidTypeInvalid:
  2997. dwError = ERROR_INVALID_PARAMETER;
  2998. goto Cleanup;
  2999. }
  3000. //
  3001. // The SID was successfully translated.
  3002. // There should be exactly one domain and its index should be zero.
  3003. //
  3004. ASSERT(pSidSet->pDomains->Entries == 1);
  3005. ASSERT(pSidSet->pDomains->Domains != 0);
  3006. ASSERT(pSidSet->pNames->DomainIndex == 0);
  3007. pSidSet->pDomainSid = pSidSet->pDomains->Domains->Sid;
  3008. pSidSet->pusUserName = &pSidSet->pNames->Name;
  3009. pSidSet->pusDomainName = &pSidSet->pDomains->Domains->Name;
  3010. pSidSet->sidUse = pSidSet->pNames->Use;
  3011. dwError = ERROR_SUCCESS;
  3012. Cleanup:
  3013. if (hPolicy)
  3014. {
  3015. LsaClose(hPolicy);
  3016. }
  3017. return dwError;
  3018. }
  3019. DWORD
  3020. AuthzpGetLocalInfo(
  3021. IN PSID_SET pSidSet
  3022. )
  3023. {
  3024. DWORD dwError;
  3025. NTSTATUS status;
  3026. LSA_HANDLE hPolicy = 0;
  3027. OBJECT_ATTRIBUTES obja = {0};
  3028. SECURITY_QUALITY_OF_SERVICE sqos;
  3029. NT_PRODUCT_TYPE ProductType;
  3030. PPOLICY_LSA_SERVER_ROLE_INFO pRole = 0;
  3031. //
  3032. // Set up the object attributes prior to opening the LSA.
  3033. //
  3034. sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  3035. sqos.ImpersonationLevel = SecurityImpersonation;
  3036. sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  3037. sqos.EffectiveOnly = FALSE;
  3038. obja.SecurityQualityOfService = &sqos;
  3039. //
  3040. // open LSA policy
  3041. //
  3042. status = LsaOpenPolicy(
  3043. 0,
  3044. &obja,
  3045. POLICY_VIEW_LOCAL_INFORMATION,
  3046. &hPolicy
  3047. );
  3048. if (!NT_SUCCESS(status))
  3049. {
  3050. dwError = LsaNtStatusToWinError(status);
  3051. goto Cleanup;
  3052. }
  3053. status = LsaQueryInformationPolicy(
  3054. hPolicy,
  3055. PolicyAccountDomainInformation,
  3056. (PVOID*)&pSidSet->pAccountInfo
  3057. );
  3058. if (!NT_SUCCESS(status))
  3059. {
  3060. dwError = LsaNtStatusToWinError(status);
  3061. goto Cleanup;
  3062. }
  3063. status = LsaQueryInformationPolicy(
  3064. hPolicy,
  3065. PolicyPrimaryDomainInformation,
  3066. (PVOID*)&pSidSet->pPrimaryInfo
  3067. );
  3068. if (!NT_SUCCESS(status))
  3069. {
  3070. dwError = LsaNtStatusToWinError(status);
  3071. goto Cleanup;
  3072. }
  3073. pSidSet->pPrimaryInfoName = (PWSTR) AuthzpAlloc(pSidSet->pPrimaryInfo->Name.Length + sizeof(WCHAR));
  3074. if (pSidSet->pPrimaryInfoName == NULL)
  3075. {
  3076. dwError = ERROR_NOT_ENOUGH_MEMORY;
  3077. goto Cleanup;
  3078. }
  3079. wcsncpy(pSidSet->pPrimaryInfoName, pSidSet->pPrimaryInfo->Name.Buffer, pSidSet->pPrimaryInfo->Name.Length/sizeof(WCHAR));
  3080. pSidSet->pPrimaryInfoName[pSidSet->pPrimaryInfo->Name.Length/sizeof(WCHAR)] = L'\0';
  3081. //
  3082. // Determine the role of the machine.
  3083. //
  3084. if (RtlGetNtProductType(&ProductType) == FALSE)
  3085. {
  3086. dwError = ERROR_GEN_FAILURE;
  3087. goto Cleanup;
  3088. }
  3089. switch (ProductType)
  3090. {
  3091. case NtProductWinNt:
  3092. case NtProductServer:
  3093. pSidSet->bStandalone = pSidSet->pPrimaryInfo->Sid == 0 ? TRUE : FALSE;
  3094. break;
  3095. case NtProductLanManNt:
  3096. status = LsaQueryInformationPolicy(
  3097. hPolicy,
  3098. PolicyLsaServerRoleInformation,
  3099. (PVOID*)&pRole
  3100. );
  3101. if (!NT_SUCCESS(status))
  3102. {
  3103. dwError = LsaNtStatusToWinError(status);
  3104. goto Cleanup;
  3105. }
  3106. pSidSet->bStandalone = FALSE;
  3107. if (pRole->LsaServerRole == PolicyServerRolePrimary)
  3108. {
  3109. //
  3110. // If we think we're a primary domain controller, we'll need to
  3111. // guard against the case where we're actually standalone
  3112. // during setup
  3113. //
  3114. if (pSidSet->pPrimaryInfo->Sid == 0 ||
  3115. pSidSet->pAccountInfo->DomainSid == 0 ||
  3116. !RtlEqualSid(
  3117. pSidSet->pPrimaryInfo->Sid,
  3118. pSidSet->pAccountInfo->DomainSid))
  3119. {
  3120. pSidSet->bStandalone = TRUE;
  3121. }
  3122. }
  3123. break;
  3124. default:
  3125. dwError = ERROR_GEN_FAILURE;
  3126. goto Cleanup;
  3127. }
  3128. dwError = ERROR_SUCCESS;
  3129. Cleanup:
  3130. if (pRole)
  3131. {
  3132. LsaFreeMemory(pRole);
  3133. }
  3134. if (hPolicy)
  3135. {
  3136. LsaClose(hPolicy);
  3137. }
  3138. return dwError;
  3139. }
  3140. DWORD
  3141. AuthzpGetDcName(
  3142. IN LPCTSTR pszDomain,
  3143. IN OUT PDOMAIN_CONTROLLER_INFO* ppDcInfo
  3144. )
  3145. {
  3146. DWORD dwError;
  3147. //
  3148. // First try to get a DC with DS running.
  3149. //
  3150. dwError = DsGetDcName(
  3151. 0,
  3152. pszDomain,
  3153. 0,
  3154. 0,
  3155. DS_DIRECTORY_SERVICE_REQUIRED | DS_RETURN_DNS_NAME,
  3156. ppDcInfo
  3157. );
  3158. if (dwError == ERROR_NO_SUCH_DOMAIN)
  3159. {
  3160. //
  3161. // Try again with no flags set, because this is the only way
  3162. // an NT4 domain will reveal its secrets.
  3163. //
  3164. dwError = DsGetDcName(
  3165. 0,
  3166. pszDomain,
  3167. 0,
  3168. 0,
  3169. 0,
  3170. ppDcInfo
  3171. );
  3172. }
  3173. return dwError;
  3174. }
  3175. VOID
  3176. AuthzpConvertSidToEdn(
  3177. IN PSID pSid,
  3178. OUT PWSTR pszSidEdn
  3179. )
  3180. /*++
  3181. Print pSid into pszSidEdn as an Extended Distinguished Name.
  3182. pszSidEdn should provide room for at least
  3183. SECURITY_MAX_SID_SIZE * 2 + 8 WCHARs.
  3184. --*/
  3185. {
  3186. DWORD dwLength = RtlLengthSid(pSid);
  3187. DWORD i;
  3188. PBYTE pbSid = (PBYTE)pSid;
  3189. PWCHAR pChar = pszSidEdn;
  3190. static WCHAR szHex[] = L"0123456789ABCDEF";
  3191. *pChar++ = L'<';
  3192. *pChar++ = L'S';
  3193. *pChar++ = L'I';
  3194. *pChar++ = L'D';
  3195. *pChar++ = L'=';
  3196. for (i=0;i < dwLength;i++,pbSid++)
  3197. {
  3198. *pChar++ = szHex[*pbSid >> 4];
  3199. *pChar++ = szHex[*pbSid & 0x0F];
  3200. }
  3201. *pChar++ = L'>';
  3202. *pChar = L'\0';
  3203. }
  3204. BOOL
  3205. AuthzpAllocateAndInitializeClientContext(
  3206. OUT PAUTHZI_CLIENT_CONTEXT *ppCC,
  3207. IN PAUTHZI_CLIENT_CONTEXT Server,
  3208. IN DWORD Revision,
  3209. IN LUID Identifier,
  3210. IN LARGE_INTEGER ExpirationTime,
  3211. IN DWORD Flags,
  3212. IN DWORD SidCount,
  3213. IN DWORD SidLength,
  3214. IN PSID_AND_ATTRIBUTES Sids,
  3215. IN DWORD RestrictedSidCount,
  3216. IN DWORD RestrictedSidLength,
  3217. IN PSID_AND_ATTRIBUTES RestrictedSids,
  3218. IN DWORD PrivilegeCount,
  3219. IN DWORD PrivilegeLength,
  3220. IN PLUID_AND_ATTRIBUTES Privileges,
  3221. IN LUID AuthenticationId,
  3222. IN PAUTHZI_HANDLE AuthzHandleHead,
  3223. IN PAUTHZI_RESOURCE_MANAGER pRM
  3224. )
  3225. /*++
  3226. Routine description:
  3227. This routine initializes fields in a client context. It is called by all the
  3228. AuthzInitializClientContextFrom* routines.
  3229. Arguments:
  3230. ppCC - Returns the newly allocated and initialized client context structure.
  3231. Rest of the parameters are copied into the client context. For explanation
  3232. of these, see the definition of AUTHZI_CLIENT_CONTEXT.
  3233. Return Value:
  3234. A value of TRUE is returned if the routine is successful. Otherwise,
  3235. a value of FALSE is returned. In the failure case, error value may be
  3236. retrieved using GetLastError().
  3237. --*/
  3238. {
  3239. PAUTHZI_CLIENT_CONTEXT pCC = (PAUTHZI_CLIENT_CONTEXT) AuthzpAlloc(sizeof(AUTHZI_CLIENT_CONTEXT));
  3240. if (AUTHZ_ALLOCATION_FAILED(pCC))
  3241. {
  3242. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  3243. return FALSE;
  3244. }
  3245. *ppCC = pCC;
  3246. RtlZeroMemory(
  3247. pCC,
  3248. sizeof(AUTHZ_CLIENT_CONTEXT_HANDLE)
  3249. );
  3250. pCC->AuthenticationId = AuthenticationId;
  3251. pCC->AuthzHandleHead = AuthzHandleHead;
  3252. pCC->ExpirationTime = ExpirationTime;
  3253. pCC->Flags = Flags;
  3254. pCC->Identifier = Identifier;
  3255. pCC->pResourceManager = pRM;
  3256. pCC->PrivilegeCount = PrivilegeCount;
  3257. pCC->PrivilegeLength = PrivilegeLength;
  3258. pCC->Privileges = Privileges;
  3259. pCC->RestrictedSidCount = RestrictedSidCount;
  3260. pCC->RestrictedSidLength = RestrictedSidLength;
  3261. pCC->RestrictedSids = RestrictedSids;
  3262. pCC->Revision = Revision;
  3263. pCC->Server = Server;
  3264. pCC->SidCount = SidCount;
  3265. pCC->SidLength = SidLength;
  3266. pCC->Sids = Sids;
  3267. return TRUE;
  3268. }
  3269. BOOL
  3270. AuthzpAddDynamicSidsToToken(
  3271. IN PAUTHZI_CLIENT_CONTEXT pCC,
  3272. IN PAUTHZI_RESOURCE_MANAGER pRM,
  3273. IN PVOID DynamicGroupArgs,
  3274. IN PSID_AND_ATTRIBUTES Sids,
  3275. IN DWORD SidLength,
  3276. IN DWORD SidCount,
  3277. IN PSID_AND_ATTRIBUTES RestrictedSids,
  3278. IN DWORD RestrictedSidLength,
  3279. IN DWORD RestrictedSidCount,
  3280. IN PLUID_AND_ATTRIBUTES Privileges,
  3281. IN DWORD PrivilegeLength,
  3282. IN DWORD PrivilegeCount,
  3283. IN BOOL bAllocated
  3284. )
  3285. /*++
  3286. Routine description:
  3287. This routine computes resource manager specific groups and add them to the
  3288. client context. This is a worker routine for all AuthzInitializeFrom*
  3289. routines.
  3290. Arguments:
  3291. pCC - Pointer to the client context structure for which the three fields
  3292. will be set - sids, restricted sids, privileges.
  3293. pRM - Pointer to the resource manager structure, supplies the callback
  3294. function to be used.
  3295. DynamicGroupArgs - Caller supplied argument pointer to be passed as an input
  3296. to the callback function that'd compute dynamic groups
  3297. Sids - The sid and atttribute array for the normal part of the client
  3298. context.
  3299. SidLength - Size of the buffer required to hold this array.
  3300. SidCount - Number of sids in the array.
  3301. RestrictedSids - The sid and atttribute array for the normal part of the
  3302. client context.
  3303. RestrictedSidLength - Size of the buffer required to hold this array.
  3304. RestrictedSidCount - Number of restricted sids in the array.
  3305. Privileges - The privilege and attribute array.
  3306. PrivilegeLength - Size required to hold this array.
  3307. PrivilegeCount - The number of privileges in the array.
  3308. bAllocated - To specify whether the Sids and RestrictedSids pointers in
  3309. client context have been allocated separately.
  3310. When the client context has been created thru a token, the two pointers
  3311. point somewhere into a buffer and a new buffer has to be allocated to store
  3312. these.
  3313. When the client context has been created thru a sid, the buffer is a valid
  3314. allocated one. If no dynamic groups need to be added then we do not have to
  3315. do anything int this case.
  3316. Return Value:
  3317. A value of TRUE is returned if the routine is successful. Otherwise,
  3318. a value of FALSE is returned. In the failure case, error value may be
  3319. retrieved using GetLastError().
  3320. --*/
  3321. {
  3322. BOOL b = TRUE;
  3323. PSID_AND_ATTRIBUTES pRMSids = NULL;
  3324. PSID_AND_ATTRIBUTES pRMRestrictedSids = NULL;
  3325. PSID_AND_ATTRIBUTES pLocalSids = NULL;
  3326. PSID_AND_ATTRIBUTES pLocalRestrictedSids = NULL;
  3327. PLUID_AND_ATTRIBUTES pLocalPrivileges = NULL;
  3328. DWORD RMSidCount = 0;
  3329. DWORD RMRestrictedSidCount = 0;
  3330. DWORD LocalSidLength = 0;
  3331. DWORD LocalRestrictedSidLength = 0;
  3332. DWORD i = 0;
  3333. //
  3334. // Compute dynamic groups.
  3335. //
  3336. if (AUTHZ_NON_NULL_PTR(pRM->pfnComputeDynamicGroups))
  3337. {
  3338. b = pRM->pfnComputeDynamicGroups(
  3339. (AUTHZ_CLIENT_CONTEXT_HANDLE) pCC,
  3340. DynamicGroupArgs,
  3341. &pRMSids,
  3342. &RMSidCount,
  3343. &pRMRestrictedSids,
  3344. &RMRestrictedSidCount
  3345. );
  3346. if (!b) goto Cleanup;
  3347. }
  3348. //
  3349. // Copy the existing sids as well as the dynamic ones into a new buffer if
  3350. // needed.
  3351. //
  3352. if ((0 != RMSidCount) || !bAllocated)
  3353. {
  3354. LocalSidLength = SidLength + RMSidCount * sizeof(SID_AND_ATTRIBUTES);
  3355. for (i = 0; i < RMSidCount; i++)
  3356. {
  3357. LocalSidLength += RtlLengthSid(pRMSids[i].Sid);
  3358. }
  3359. pLocalSids = (PSID_AND_ATTRIBUTES) AuthzpAlloc(LocalSidLength);
  3360. if (AUTHZ_ALLOCATION_FAILED(pLocalSids))
  3361. {
  3362. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  3363. b = FALSE;
  3364. goto Cleanup;
  3365. }
  3366. pCC->SidCount = RMSidCount + SidCount;
  3367. pCC->Sids = pLocalSids;
  3368. b = AuthzpCopySidsAndAttributes(
  3369. pLocalSids,
  3370. Sids,
  3371. SidCount,
  3372. pRMSids,
  3373. RMSidCount
  3374. );
  3375. if (!b)
  3376. {
  3377. goto Cleanup;
  3378. }
  3379. if (!FLAG_ON(pCC->Sids[0].Attributes, SE_GROUP_USE_FOR_DENY_ONLY))
  3380. {
  3381. pCC->Sids[0].Attributes |= SE_GROUP_ENABLED;
  3382. }
  3383. pCC->SidLength = LocalSidLength;
  3384. }
  3385. if ((0 != RMRestrictedSidCount) || !bAllocated)
  3386. {
  3387. LocalRestrictedSidLength = RestrictedSidLength + RMRestrictedSidCount * sizeof(SID_AND_ATTRIBUTES);
  3388. for (i = 0; i < RMRestrictedSidCount; i++)
  3389. {
  3390. LocalRestrictedSidLength += RtlLengthSid(pRMRestrictedSids[i].Sid);
  3391. }
  3392. if (LocalRestrictedSidLength > 0)
  3393. {
  3394. pLocalRestrictedSids = (PSID_AND_ATTRIBUTES) AuthzpAlloc(LocalRestrictedSidLength);
  3395. if (AUTHZ_ALLOCATION_FAILED(pLocalRestrictedSids))
  3396. {
  3397. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  3398. b = FALSE;
  3399. goto Cleanup;
  3400. }
  3401. }
  3402. pCC->RestrictedSidCount = RMRestrictedSidCount + RestrictedSidCount;
  3403. pCC->RestrictedSids = pLocalRestrictedSids;
  3404. b = AuthzpCopySidsAndAttributes(
  3405. pLocalRestrictedSids,
  3406. RestrictedSids,
  3407. RestrictedSidCount,
  3408. pRMRestrictedSids,
  3409. RMRestrictedSidCount
  3410. );
  3411. if (!b) goto Cleanup;
  3412. pCC->RestrictedSidLength = LocalRestrictedSidLength;
  3413. }
  3414. //
  3415. // Privileges need to copied only in the case of initilize from token.
  3416. //
  3417. if (PrivilegeLength > 0)
  3418. {
  3419. pLocalPrivileges = (PLUID_AND_ATTRIBUTES) AuthzpAlloc(PrivilegeLength);
  3420. if (AUTHZ_ALLOCATION_FAILED(pLocalPrivileges))
  3421. {
  3422. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  3423. b = FALSE;
  3424. goto Cleanup;
  3425. }
  3426. pCC->PrivilegeCount = PrivilegeCount;
  3427. pCC->Privileges = pLocalPrivileges;
  3428. AuthzpCopyLuidAndAttributes(
  3429. pCC,
  3430. Privileges,
  3431. PrivilegeCount,
  3432. pLocalPrivileges
  3433. );
  3434. }
  3435. else
  3436. {
  3437. pCC->Privileges = NULL;
  3438. }
  3439. Cleanup:
  3440. if (!b)
  3441. {
  3442. AuthzpFreeNonNull(pLocalSids);
  3443. AuthzpFreeNonNull(pLocalRestrictedSids);
  3444. AuthzpFreeNonNull(pLocalPrivileges);
  3445. }
  3446. if (AUTHZ_NON_NULL_PTR(pRMSids))
  3447. {
  3448. pRM->pfnFreeDynamicGroups(pRMSids);
  3449. }
  3450. if (AUTHZ_NON_NULL_PTR(pRMRestrictedSids))
  3451. {
  3452. pRM->pfnFreeDynamicGroups(pRMSids);
  3453. }
  3454. return b;
  3455. }
  3456. BOOL
  3457. AuthzpComputeSkipFlagsForWellKnownSid(
  3458. IN PSID UserSid,
  3459. OUT PDWORD Flags
  3460. )
  3461. /*++
  3462. Routine description:
  3463. This routine computes skip flags if the User sid is a wellknown sid.
  3464. Arguments:
  3465. UserSid - User sid for which SKIP flag will be computed.
  3466. Flags - to return the SKIP flags.
  3467. A value of AUTHZ_SKIP_TOKEN_GROUPS is returned for well-known and builtin
  3468. sid. A value of 0 is returned in failure cases as well as other cases.
  3469. Return Value:
  3470. A value of TRUE is returned if the routine is successful. Otherwise,
  3471. a value of FALSE is returned. In the failure case, error value may be
  3472. retrieved using GetLastError().
  3473. --*/
  3474. {
  3475. DWORD dwErr = ERROR_SUCCESS;
  3476. BOOL b = TRUE;
  3477. LPWSTR Name = NULL;
  3478. LPWSTR RefDomainName = NULL;
  3479. DWORD NameSize = 0;
  3480. DWORD RefDomainNameSize = 0;
  3481. SID_NAME_USE SidNameUse = SidTypeUnknown;
  3482. *Flags = 0;
  3483. //
  3484. // Dummy call to get the size of the buffer.
  3485. //
  3486. b = LookupAccountSidW(
  3487. NULL,
  3488. UserSid,
  3489. NULL,
  3490. &NameSize,
  3491. NULL,
  3492. &RefDomainNameSize,
  3493. &SidNameUse
  3494. );
  3495. if (FALSE == b)
  3496. {
  3497. dwErr = GetLastError();
  3498. //
  3499. // Return if we failed because of any error other than insufficient
  3500. // buffer.
  3501. //
  3502. if(dwErr != ERROR_INSUFFICIENT_BUFFER)
  3503. {
  3504. return FALSE;
  3505. }
  3506. //
  3507. // LookupAccountSid returns the size in TCHARS.
  3508. //
  3509. NameSize *= sizeof(WCHAR);
  3510. RefDomainNameSize *= sizeof(WCHAR);
  3511. //
  3512. // Allocate memory required to hold the names.
  3513. //
  3514. Name = (LPWSTR) AuthzpAlloc(NameSize);
  3515. if (AUTHZ_ALLOCATION_FAILED(Name))
  3516. {
  3517. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  3518. return FALSE;
  3519. }
  3520. RefDomainName = (LPWSTR) AuthzpAlloc(RefDomainNameSize);
  3521. if (AUTHZ_ALLOCATION_FAILED(RefDomainName))
  3522. {
  3523. AuthzpFree(Name);
  3524. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  3525. return FALSE;
  3526. }
  3527. //
  3528. // Do the real lookup.
  3529. //
  3530. b = LookupAccountSidW(
  3531. NULL,
  3532. UserSid,
  3533. Name,
  3534. &NameSize,
  3535. RefDomainName,
  3536. &RefDomainNameSize,
  3537. &SidNameUse
  3538. );
  3539. AuthzpFree(Name);
  3540. AuthzpFree(RefDomainName);
  3541. if (FALSE == b)
  3542. {
  3543. return FALSE;
  3544. }
  3545. //
  3546. // Add the SKIP flag for the cases required.
  3547. //
  3548. switch (SidNameUse)
  3549. {
  3550. case SidTypeAlias:
  3551. case SidTypeWellKnownGroup:
  3552. case SidTypeInvalid:
  3553. case SidTypeUnknown:
  3554. case SidTypeGroup:
  3555. *Flags = AUTHZ_SKIP_TOKEN_GROUPS;
  3556. return TRUE;
  3557. case SidTypeComputer:
  3558. case SidTypeDomain:
  3559. case SidTypeDeletedAccount:
  3560. case SidTypeUser:
  3561. default:
  3562. return TRUE;
  3563. }
  3564. }
  3565. //
  3566. // Should not get here.
  3567. //
  3568. ASSERT(FALSE);
  3569. return TRUE;
  3570. }
  3571. DWORD
  3572. AuthzpIsDC(
  3573. OUT PBOOL pbIsDC
  3574. )
  3575. /*++
  3576. Routine description:
  3577. This routine decides whether a trip to the AD is required to fetch
  3578. TokenGroups attribute.
  3579. Arguments:
  3580. pbIsDC - Returns whether or not this is a DC.
  3581. Return Value:
  3582. Returns ERROR_SUCCESS on success, appropriate failure value otherwise.
  3583. --*/
  3584. {
  3585. static BOOL bFirstTime = TRUE;
  3586. static BOOL bIsDC = FALSE;
  3587. DWORD dwErr = ERROR_SUCCESS;
  3588. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC BasicInfo = NULL;
  3589. if (bFirstTime)
  3590. {
  3591. //
  3592. // Get the information about the local machine.
  3593. //
  3594. dwErr = DsRoleGetPrimaryDomainInformation(
  3595. NULL,
  3596. DsRolePrimaryDomainInfoBasic,
  3597. & (PBYTE) BasicInfo
  3598. );
  3599. if (ERROR_SUCCESS != dwErr)
  3600. {
  3601. return dwErr;
  3602. }
  3603. //
  3604. // If the local machine is a DC then TokenGroups should be computed anyway.
  3605. //
  3606. switch(BasicInfo->MachineRole)
  3607. {
  3608. case DsRole_RolePrimaryDomainController:
  3609. case DsRole_RoleBackupDomainController:
  3610. bIsDC = TRUE;
  3611. break;
  3612. default:
  3613. break;
  3614. }
  3615. DsRoleFreeMemory(BasicInfo);
  3616. bFirstTime = FALSE;
  3617. }
  3618. *pbIsDC = bIsDC;
  3619. return ERROR_SUCCESS;
  3620. }