Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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