Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1244 lines
35 KiB

  1. /*++
  2. Copyright (c) 1987-1996 Microsoft Corporation
  3. Module Name:
  4. rgroups.c
  5. Abstract:
  6. Routines to expand transitive group membership.
  7. Author:
  8. Mike Swift (mikesw) 8-May-1998
  9. Environment:
  10. User mode only.
  11. Contains NT-specific code.
  12. Requires ANSI C extensions: slash-slash comments, long external names.
  13. Revision History:
  14. --*/
  15. //
  16. // Common include files.
  17. //
  18. #include "logonsrv.h" // Include files common to entire service
  19. #pragma hdrstop
  20. #include <authz.h> // Authz API
  21. GUID GUID_A_SECURED_FOR_CROSS_ORGANIZATION = {0x68B1D179,0x0D15,0x4d4f,0xAB,0x71,0x46,0x15,0x2E,0x79,0xA7,0xBC};
  22. typedef struct _NL_AUTHZ_INFO {
  23. PNETLOGON_SID_AND_ATTRIBUTES SidAndAttributes;
  24. ULONG SidCount;
  25. } NL_AUTHZ_INFO, *PNL_AUTHZ_INFO;
  26. AUTHZ_RESOURCE_MANAGER_HANDLE NlAuthzRM = NULL;
  27. BOOL
  28. NlComputeAuthzGroups(
  29. IN AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzClientContext,
  30. IN PVOID Args,
  31. OUT PSID_AND_ATTRIBUTES *pSidAttrArray,
  32. OUT PDWORD pSidCount,
  33. OUT PSID_AND_ATTRIBUTES *pRestrictedSidAttrArray,
  34. OUT PDWORD pRestrictedSidCount
  35. )
  36. /*++
  37. Routine Description:
  38. Authz callback for add groups to authz client context
  39. Arguments:
  40. See Authz SDK documentation
  41. Return Value:
  42. Always TRUE
  43. --*/
  44. {
  45. PNL_AUTHZ_INFO AuthzInfo = (PNL_AUTHZ_INFO) Args;
  46. *pSidAttrArray = (PSID_AND_ATTRIBUTES) AuthzInfo->SidAndAttributes;
  47. *pSidCount = AuthzInfo->SidCount;
  48. *pRestrictedSidAttrArray = NULL;
  49. *pRestrictedSidCount = 0;
  50. return (TRUE);
  51. UNREFERENCED_PARAMETER( hAuthzClientContext );
  52. }
  53. VOID
  54. NlFreeAuthzGroups(
  55. IN PSID_AND_ATTRIBUTES pSidAttrArray
  56. )
  57. /*++
  58. Routine Description:
  59. Authz callback to cleanup after adding groups to authz client context.
  60. Basically a no-op, as we already have a copy of the SIDs.
  61. Arguments:
  62. See Authz SDK documentation
  63. Return Value:
  64. None
  65. --*/
  66. {
  67. return;
  68. UNREFERENCED_PARAMETER( pSidAttrArray );
  69. }
  70. NET_API_STATUS
  71. NlInitializeAuthzRM(
  72. VOID
  73. )
  74. /*++
  75. Routine Description:
  76. Initializes the Authz manager for netlogon
  77. Arguments:
  78. None
  79. Return Value:
  80. Status of Authz operation
  81. --*/
  82. {
  83. NET_API_STATUS NetStatus = NO_ERROR;
  84. if ( !AuthzInitializeResourceManager( 0,
  85. NULL,
  86. NlComputeAuthzGroups,
  87. NlFreeAuthzGroups,
  88. L"NetLogon",
  89. &NlAuthzRM) ) {
  90. NetStatus = GetLastError();
  91. NlPrint(( NL_CRITICAL, "NlInitializeAuthzRM: AuthzInitializeRm failed 0x%lx\n",
  92. NetStatus ));
  93. }
  94. return NetStatus;
  95. }
  96. VOID
  97. NlFreeAuthzRm(
  98. VOID
  99. )
  100. /*++
  101. Routine Description:
  102. Frees the Authz manager for netlogon
  103. Arguments:
  104. None
  105. Return Value:
  106. None
  107. --*/
  108. {
  109. if ( NlAuthzRM != NULL ) {
  110. if ( !AuthzFreeResourceManager(NlAuthzRM) ) {
  111. NlPrint((NL_CRITICAL, "AuthzFreeResourceManager failed 0x%lx\n", GetLastError()));
  112. } else {
  113. NlAuthzRM = NULL;
  114. }
  115. }
  116. }
  117. PSID
  118. NlpCopySid(
  119. IN PSID Sid
  120. )
  121. /*++
  122. Routine Description:
  123. Given a SID allocatees space for a new SID from the LSA heap and copies
  124. the original SID.
  125. Arguments:
  126. Sid - The original SID.
  127. Return Value:
  128. Sid - Returns a pointer to a buffer allocated from the LsaHeap
  129. containing the resultant Sid.
  130. --*/
  131. {
  132. PSID NewSid;
  133. ULONG Size;
  134. Size = RtlLengthSid( Sid );
  135. if ((NewSid = MIDL_user_allocate( Size )) == NULL ) {
  136. return NULL;
  137. }
  138. if ( !NT_SUCCESS( RtlCopySid( Size, NewSid, Sid ) ) ) {
  139. MIDL_user_free( NewSid );
  140. return NULL;
  141. }
  142. return NewSid;
  143. }
  144. NTSTATUS
  145. NlpBuildPacSidList(
  146. IN PNETLOGON_VALIDATION_SAM_INFO4 UserInfo,
  147. OUT PSAMPR_PSID_ARRAY Sids,
  148. OUT PULONG NonExtraSidCount
  149. )
  150. /*++
  151. Routine Description:
  152. Given the validation information for a user, expands the group member-
  153. ships and user id into a list of sids. If user id is present, it
  154. will be expanded into the first entry of the list.
  155. Arguments:
  156. UserInfo - user's validation information
  157. Sids - receives an array of all the user's group sids and user id
  158. NonExtraSidCount - Returns the number of SIDs in the UserInfo which
  159. are not Extra SIDs.
  160. Return Value:
  161. STATUS_INSUFFICIENT_RESOURCES - there wasn't enough memory to
  162. create the list of sids.
  163. --*/
  164. {
  165. NTSTATUS Status = STATUS_SUCCESS;
  166. NET_API_STATUS NetStatus;
  167. ULONG Size = 0, i;
  168. Sids->Count = 0;
  169. Sids->Sids = NULL;
  170. *NonExtraSidCount = 0;
  171. if (UserInfo->UserId != 0) {
  172. Size += sizeof(SAMPR_SID_INFORMATION);
  173. }
  174. Size += UserInfo->GroupCount * (ULONG)sizeof(SAMPR_SID_INFORMATION);
  175. //
  176. // If there are extra SIDs, add space for them
  177. //
  178. if (UserInfo->UserFlags & LOGON_EXTRA_SIDS) {
  179. Size += UserInfo->SidCount * (ULONG)sizeof(SAMPR_SID_INFORMATION);
  180. }
  181. Sids->Sids = (PSAMPR_SID_INFORMATION) MIDL_user_allocate( Size );
  182. if ( Sids->Sids == NULL ) {
  183. Status = STATUS_INSUFFICIENT_RESOURCES;
  184. goto Cleanup;
  185. }
  186. RtlZeroMemory(
  187. Sids->Sids,
  188. Size
  189. );
  190. //
  191. // Start copying SIDs into the structure
  192. //
  193. i = 0;
  194. //
  195. // If the UserId is non-zero, then it contians the users RID.
  196. // This must be the first entry in the list as this is the
  197. // order NlpVerifyAllowedToAuthenticate assumes.
  198. //
  199. if ( UserInfo->UserId ) {
  200. NetStatus = NetpDomainIdToSid(
  201. UserInfo->LogonDomainId,
  202. UserInfo->UserId,
  203. (PSID *) &Sids->Sids[0].SidPointer
  204. );
  205. if( NetStatus != ERROR_SUCCESS ) {
  206. Status = STATUS_INSUFFICIENT_RESOURCES;
  207. goto Cleanup;
  208. }
  209. Sids->Count++;
  210. (*NonExtraSidCount) ++;
  211. }
  212. //
  213. // Copy over all the groups passed as RIDs
  214. //
  215. for ( i=0; i < UserInfo->GroupCount; i++ ) {
  216. NetStatus = NetpDomainIdToSid(
  217. UserInfo->LogonDomainId,
  218. UserInfo->GroupIds[i].RelativeId,
  219. (PSID *) &Sids->Sids[Sids->Count].SidPointer
  220. );
  221. if( NetStatus != ERROR_SUCCESS ) {
  222. Status = STATUS_INSUFFICIENT_RESOURCES;
  223. goto Cleanup;
  224. }
  225. Sids->Count++;
  226. (*NonExtraSidCount) ++;
  227. }
  228. //
  229. // Add in the extra SIDs
  230. //
  231. //
  232. // ???: no need to allocate these
  233. //
  234. if (UserInfo->UserFlags & LOGON_EXTRA_SIDS) {
  235. for ( i = 0; i < UserInfo->SidCount; i++ ) {
  236. Sids->Sids[Sids->Count].SidPointer = NlpCopySid(
  237. UserInfo->ExtraSids[i].Sid
  238. );
  239. if (Sids->Sids[Sids->Count].SidPointer == NULL) {
  240. Status = STATUS_INSUFFICIENT_RESOURCES;
  241. goto Cleanup;
  242. }
  243. Sids->Count++;
  244. }
  245. }
  246. //
  247. // Deallocate any memory we've allocated
  248. //
  249. Cleanup:
  250. if (!NT_SUCCESS(Status)) {
  251. if (Sids->Sids != NULL) {
  252. for (i = 0; i < Sids->Count ;i++ ) {
  253. if (Sids->Sids[i].SidPointer != NULL) {
  254. MIDL_user_free(Sids->Sids[i].SidPointer);
  255. }
  256. }
  257. MIDL_user_free(Sids->Sids);
  258. Sids->Sids = NULL;
  259. Sids->Count = 0;
  260. }
  261. *NonExtraSidCount = 0;
  262. }
  263. return Status;
  264. }
  265. NTSTATUS
  266. NlpAddResourceGroupsToSamInfo (
  267. IN NETLOGON_VALIDATION_INFO_CLASS ValidationLevel,
  268. IN OUT PNETLOGON_VALIDATION_SAM_INFO4 *ValidationInformation,
  269. IN PSAMPR_PSID_ARRAY ResourceGroups
  270. )
  271. /*++
  272. Routine Description:
  273. This function converts a NETLOGON_VALIDATION_SAM_INFO version 1, 2, or 4 to
  274. a NETLOGON_VALIDATION_SAM_INFO version 4 and optionally adds in an array of
  275. ResourceGroup sids.
  276. Since version 4 is a superset of the other two levels, the returned structure can
  277. be used even though one of the other info levels are needed.
  278. Arguments:
  279. ValidationLevel -- Specifies the level of information passed as input in
  280. ValidationInformation. Must be NetlogonValidationSamInfo or
  281. NetlogonValidationSamInfo2, NetlogonValidationSamInfo4
  282. NetlogonValidationSamInfo4 is always returned on output.
  283. ValidationInformation -- Specifies the NETLOGON_VALIDATION_SAM_INFO
  284. to convert.
  285. ResourceGroups - The list of resource groups to add to the structure.
  286. If NULL, no resource groups are added.
  287. Return Value:
  288. STATUS_INSUFFICIENT_RESOURCES: not enough memory to allocate the new
  289. structure.
  290. --*/
  291. {
  292. ULONG Length;
  293. PNETLOGON_VALIDATION_SAM_INFO4 SamInfo = *ValidationInformation;
  294. PNETLOGON_VALIDATION_SAM_INFO4 SamInfo4;
  295. PBYTE Where;
  296. ULONG Index;
  297. ULONG GroupIndex;
  298. ULONG ExtraSids = 0;
  299. //
  300. // Calculate the size of the new structure
  301. //
  302. Length = sizeof( NETLOGON_VALIDATION_SAM_INFO4 )
  303. + SamInfo->GroupCount * sizeof(GROUP_MEMBERSHIP)
  304. + RtlLengthSid( SamInfo->LogonDomainId );
  305. //
  306. // Add space for extra sids & resource groups
  307. //
  308. if ( ValidationLevel != NetlogonValidationSamInfo &&
  309. (SamInfo->UserFlags & LOGON_EXTRA_SIDS) != 0 ) {
  310. for (Index = 0; Index < SamInfo->SidCount ; Index++ ) {
  311. Length += sizeof(NETLOGON_SID_AND_ATTRIBUTES) + RtlLengthSid(SamInfo->ExtraSids[Index].Sid);
  312. }
  313. ExtraSids += SamInfo->SidCount;
  314. }
  315. if ( ResourceGroups != NULL ) {
  316. for (Index = 0; Index < ResourceGroups->Count ; Index++ ) {
  317. Length += sizeof(NETLOGON_SID_AND_ATTRIBUTES) + RtlLengthSid(ResourceGroups->Sids[Index].SidPointer);
  318. }
  319. ExtraSids += ResourceGroups->Count;
  320. }
  321. //
  322. // Round up now to take into account the round up in the
  323. // middle of marshalling
  324. //
  325. Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
  326. + SamInfo->LogonDomainName.Length + sizeof(WCHAR)
  327. + SamInfo->LogonServer.Length + sizeof(WCHAR)
  328. + SamInfo->EffectiveName.Length + sizeof(WCHAR)
  329. + SamInfo->FullName.Length + sizeof(WCHAR)
  330. + SamInfo->LogonScript.Length + sizeof(WCHAR)
  331. + SamInfo->ProfilePath.Length + sizeof(WCHAR)
  332. + SamInfo->HomeDirectory.Length + sizeof(WCHAR)
  333. + SamInfo->HomeDirectoryDrive.Length + sizeof(WCHAR);
  334. if ( ValidationLevel == NetlogonValidationSamInfo4 ) {
  335. Length += SamInfo->DnsLogonDomainName.Length + sizeof(WCHAR)
  336. + SamInfo->Upn.Length + sizeof(WCHAR);
  337. //
  338. // The ExpansionStrings may be used to transport byte aligned data
  339. Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
  340. + SamInfo->ExpansionString1.Length + sizeof(WCHAR);
  341. Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
  342. + SamInfo->ExpansionString2.Length + sizeof(WCHAR);
  343. Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
  344. + SamInfo->ExpansionString3.Length + sizeof(WCHAR);
  345. Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
  346. + SamInfo->ExpansionString4.Length + sizeof(WCHAR);
  347. Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
  348. + SamInfo->ExpansionString5.Length + sizeof(WCHAR);
  349. Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
  350. + SamInfo->ExpansionString6.Length + sizeof(WCHAR);
  351. Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
  352. + SamInfo->ExpansionString7.Length + sizeof(WCHAR);
  353. Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
  354. + SamInfo->ExpansionString8.Length + sizeof(WCHAR);
  355. Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
  356. + SamInfo->ExpansionString9.Length + sizeof(WCHAR);
  357. Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
  358. + SamInfo->ExpansionString10.Length + sizeof(WCHAR);
  359. }
  360. Length = ROUND_UP_COUNT( Length, sizeof(WCHAR) );
  361. SamInfo4 = (PNETLOGON_VALIDATION_SAM_INFO4) MIDL_user_allocate( Length );
  362. if ( !SamInfo4 ) {
  363. //
  364. // Free the passed-in allocated SAM info
  365. //
  366. if ( SamInfo ) {
  367. //
  368. // Zero out sensitive data
  369. //
  370. RtlSecureZeroMemory( &SamInfo->UserSessionKey, sizeof(SamInfo->UserSessionKey) );
  371. RtlSecureZeroMemory( &SamInfo->ExpansionRoom, sizeof(SamInfo->ExpansionRoom) );
  372. MIDL_user_free(SamInfo);
  373. }
  374. *ValidationInformation = NULL;
  375. return STATUS_INSUFFICIENT_RESOURCES;
  376. }
  377. //
  378. // First copy the whole structure, since most parts are the same
  379. //
  380. RtlCopyMemory( SamInfo4, SamInfo, sizeof(NETLOGON_VALIDATION_SAM_INFO));
  381. RtlZeroMemory( &((LPBYTE)SamInfo4)[sizeof(NETLOGON_VALIDATION_SAM_INFO)],
  382. sizeof(NETLOGON_VALIDATION_SAM_INFO4) - sizeof(NETLOGON_VALIDATION_SAM_INFO) );
  383. //
  384. // Copy all the variable length data
  385. //
  386. Where = (PBYTE) (SamInfo4 + 1);
  387. RtlCopyMemory(
  388. Where,
  389. SamInfo->GroupIds,
  390. SamInfo->GroupCount * sizeof( GROUP_MEMBERSHIP) );
  391. SamInfo4->GroupIds = (PGROUP_MEMBERSHIP) Where;
  392. Where += SamInfo->GroupCount * sizeof( GROUP_MEMBERSHIP );
  393. //
  394. // Copy the extra groups
  395. //
  396. if (ExtraSids != 0) {
  397. ULONG SidLength;
  398. SamInfo4->ExtraSids = (PNETLOGON_SID_AND_ATTRIBUTES) Where;
  399. Where += sizeof(NETLOGON_SID_AND_ATTRIBUTES) * ExtraSids;
  400. GroupIndex = 0;
  401. if ( ValidationLevel != NetlogonValidationSamInfo &&
  402. (SamInfo->UserFlags & LOGON_EXTRA_SIDS) != 0 ) {
  403. for (Index = 0; Index < SamInfo->SidCount ; Index++ ) {
  404. SamInfo4->ExtraSids[GroupIndex].Attributes = SamInfo->ExtraSids[Index].Attributes;
  405. SamInfo4->ExtraSids[GroupIndex].Sid = (PSID) Where;
  406. SidLength = RtlLengthSid(SamInfo->ExtraSids[Index].Sid);
  407. RtlCopyMemory(
  408. Where,
  409. SamInfo->ExtraSids[Index].Sid,
  410. SidLength
  411. );
  412. Where += SidLength;
  413. GroupIndex++;
  414. }
  415. }
  416. //
  417. // Add the resource groups
  418. //
  419. if ( ResourceGroups != NULL ) {
  420. for (Index = 0; Index < ResourceGroups->Count ; Index++ ) {
  421. SamInfo4->ExtraSids[GroupIndex].Attributes = SE_GROUP_MANDATORY |
  422. SE_GROUP_ENABLED |
  423. SE_GROUP_ENABLED_BY_DEFAULT;
  424. SamInfo4->ExtraSids[GroupIndex].Sid = (PSID) Where;
  425. SidLength = RtlLengthSid(ResourceGroups->Sids[Index].SidPointer);
  426. RtlCopyMemory(
  427. Where,
  428. ResourceGroups->Sids[Index].SidPointer,
  429. SidLength
  430. );
  431. Where += SidLength;
  432. GroupIndex++;
  433. }
  434. }
  435. SamInfo4->SidCount = GroupIndex;
  436. NlAssert(GroupIndex == ExtraSids);
  437. }
  438. RtlCopyMemory(
  439. Where,
  440. SamInfo->LogonDomainId,
  441. RtlLengthSid( SamInfo->LogonDomainId ) );
  442. SamInfo4->LogonDomainId = (PSID) Where;
  443. Where += RtlLengthSid( SamInfo->LogonDomainId );
  444. //
  445. // Copy the WCHAR-aligned data
  446. //
  447. Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
  448. NlpPutString( &SamInfo4->EffectiveName,
  449. &SamInfo->EffectiveName,
  450. &Where );
  451. NlpPutString( &SamInfo4->FullName,
  452. &SamInfo->FullName,
  453. &Where );
  454. NlpPutString( &SamInfo4->LogonScript,
  455. &SamInfo->LogonScript,
  456. &Where );
  457. NlpPutString( &SamInfo4->ProfilePath,
  458. &SamInfo->ProfilePath,
  459. &Where );
  460. NlpPutString( &SamInfo4->HomeDirectory,
  461. &SamInfo->HomeDirectory,
  462. &Where );
  463. NlpPutString( &SamInfo4->HomeDirectoryDrive,
  464. &SamInfo->HomeDirectoryDrive,
  465. &Where );
  466. NlpPutString( &SamInfo4->LogonServer,
  467. &SamInfo->LogonServer,
  468. &Where );
  469. NlpPutString( &SamInfo4->LogonDomainName,
  470. &SamInfo->LogonDomainName,
  471. &Where );
  472. if ( ValidationLevel == NetlogonValidationSamInfo4 ) {
  473. NlpPutString( &SamInfo4->DnsLogonDomainName,
  474. &SamInfo->DnsLogonDomainName,
  475. &Where );
  476. NlpPutString( &SamInfo4->Upn,
  477. &SamInfo->Upn,
  478. &Where );
  479. NlpPutString( &SamInfo4->ExpansionString1,
  480. &SamInfo->ExpansionString1,
  481. &Where );
  482. Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
  483. NlpPutString( &SamInfo4->ExpansionString2,
  484. &SamInfo->ExpansionString2,
  485. &Where );
  486. Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
  487. NlpPutString( &SamInfo4->ExpansionString3,
  488. &SamInfo->ExpansionString3,
  489. &Where );
  490. Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
  491. NlpPutString( &SamInfo4->ExpansionString4,
  492. &SamInfo->ExpansionString4,
  493. &Where );
  494. Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
  495. NlpPutString( &SamInfo4->ExpansionString5,
  496. &SamInfo->ExpansionString5,
  497. &Where );
  498. Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
  499. NlpPutString( &SamInfo4->ExpansionString6,
  500. &SamInfo->ExpansionString6,
  501. &Where );
  502. Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
  503. NlpPutString( &SamInfo4->ExpansionString7,
  504. &SamInfo->ExpansionString7,
  505. &Where );
  506. Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
  507. NlpPutString( &SamInfo4->ExpansionString8,
  508. &SamInfo->ExpansionString8,
  509. &Where );
  510. Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
  511. NlpPutString( &SamInfo4->ExpansionString9,
  512. &SamInfo->ExpansionString9,
  513. &Where );
  514. Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
  515. NlpPutString( &SamInfo4->ExpansionString10,
  516. &SamInfo->ExpansionString10,
  517. &Where );
  518. Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
  519. }
  520. //
  521. // Zero out sensitive data
  522. //
  523. RtlSecureZeroMemory( &SamInfo->UserSessionKey, sizeof(SamInfo->UserSessionKey) );
  524. RtlSecureZeroMemory( &SamInfo->ExpansionRoom, sizeof(SamInfo->ExpansionRoom) );
  525. MIDL_user_free(SamInfo);
  526. *ValidationInformation = SamInfo4;
  527. return STATUS_SUCCESS;
  528. }
  529. NTSTATUS
  530. NlpVerifyAllowedToAuthenticate(
  531. IN PDOMAIN_INFO DomainInfo,
  532. IN ULONG ComputerAccountId,
  533. IN PSAMPR_PSID_ARRAY SamSidList,
  534. IN ULONG SamSidCount,
  535. IN PNETLOGON_SID_AND_ATTRIBUTES NlSidsAndAttributes,
  536. IN ULONG NlSidsAndAttributesCount
  537. )
  538. /*++
  539. Routine Description:
  540. This routine performs an access check to determine whether
  541. the user logon is allowed to a specified computer. This
  542. check is performed on the DC that is the computer uses on
  543. the secure channel in its domain. Note that the computer
  544. may be this DC when the logon is initiated locally from
  545. MSV package.
  546. This access check is performed only if the trust path traversed
  547. to validate the logon involved an Other Organization trust link.
  548. In this case, the well-known OtherOrg SID will be present in the
  549. passed-in netlogon SIDs list.
  550. The access check is performed on the security descriptor for the
  551. specified computer given the passed-in lists of SIDs.
  552. Arguments:
  553. DomainInfo - Hosted domain the logon is for.
  554. ComputerAccountId - The RID of the computer being logged into.
  555. SamSidList - The list of SIDs in the form of SAM data structure.
  556. These are the SIDs which have been expanded from the group
  557. membership in the validation info.
  558. SamSidCount - The number of SIDs in SamSidList.
  559. NlSidsAndAttributes - The list of SIDs in the form of Netlogon
  560. data structure. These are the SIDs from the extra SIDs
  561. field in the validation info.
  562. NlSidsAndAttributesCount - The number of SIDs in NlSidsAndAttributes.
  563. Return Value:
  564. STATUS_SUCCESS - The access check succedded.
  565. STATUS_AUTHENTICATION_FIREWALL_FAILED - The access check failed.
  566. STATUS_INSUFFICIENT_RESOURCES - there wasn't enough memory to
  567. create the combined list of sids.
  568. --*/
  569. {
  570. NTSTATUS Status = STATUS_SUCCESS;
  571. NET_API_STATUS NetStatus = NO_ERROR;
  572. ULONG SidAndAttributesCount = 0;
  573. PNETLOGON_SID_AND_ATTRIBUTES SidAndAttributes = NULL;
  574. ULONG Index = 0;
  575. PSID ComputerAccountSid = NULL;
  576. UNICODE_STRING ComputerAccountSidStr;
  577. PUSER_INTERNAL6_INFORMATION LocalUserInfo = NULL;
  578. SID_AND_ATTRIBUTES_LIST LocalMembership = {0};
  579. NL_AUTHZ_INFO AuthzInfo = {0};
  580. AUTHZ_ACCESS_REPLY Reply = {0};
  581. OBJECT_TYPE_LIST TypeList = {0};
  582. AUTHZ_CLIENT_CONTEXT_HANDLE hClientContext = NULL;
  583. AUTHZ_ACCESS_REQUEST Request = {0};
  584. DWORD AccessMask = 0;
  585. LUID ZeroLuid = {0,0};
  586. DWORD Error = ERROR_ACCESS_DENIED;
  587. //
  588. // Per the specification, the access check is only performed if the
  589. // "other org" SID is in the list. The SID can only appear in the
  590. // ExtraSids list which is what passed as the netlogon SIDs.
  591. //
  592. for ( Index = 0; Index < NlSidsAndAttributesCount; Index++ ) {
  593. if ( RtlEqualSid(NlSidsAndAttributes[Index].Sid, OtherOrganizationSid) ) {
  594. break;
  595. }
  596. }
  597. //
  598. // If the Other Org SID is not there, there is nothing to check
  599. //
  600. if ( Index == NlSidsAndAttributesCount ) {
  601. Status = STATUS_SUCCESS;
  602. goto Cleanup;
  603. }
  604. //
  605. // OK, the Other Org SID is there, so proceed with the check.
  606. //
  607. // Allocate memory to hold all the SIDs in a common structure
  608. // that AuthZ proper understands
  609. //
  610. //
  611. // add everyone and authenticated users (note guess fallback should not
  612. // have the OtherOrg sid, therefore should not get this far)
  613. //
  614. SidAndAttributesCount = SamSidCount + NlSidsAndAttributesCount + 2;
  615. SidAndAttributes = LocalAlloc( LMEM_ZEROINIT,
  616. SidAndAttributesCount * sizeof(NETLOGON_SID_AND_ATTRIBUTES) );
  617. if ( SidAndAttributes == NULL ) {
  618. Status = STATUS_INSUFFICIENT_RESOURCES;
  619. goto Cleanup;
  620. }
  621. //
  622. // Convert the SIDs from the SAM structure into the Netlogon
  623. // structure that AuthZ proper understands
  624. //
  625. SidAndAttributesCount = 0;
  626. for ( Index = 0; Index < SamSidCount; Index++ ) {
  627. SidAndAttributes[SidAndAttributesCount].Sid = (PSID) SamSidList->Sids[Index].SidPointer;
  628. SidAndAttributes[SidAndAttributesCount].Attributes = SE_GROUP_MANDATORY |
  629. SE_GROUP_ENABLED |
  630. SE_GROUP_ENABLED_BY_DEFAULT;
  631. SidAndAttributesCount ++;
  632. }
  633. //
  634. // Copy the SIDs from the Netlogon passed-in structure
  635. // into the common array
  636. //
  637. for ( Index = 0; Index < NlSidsAndAttributesCount; Index++ ) {
  638. SidAndAttributes[SidAndAttributesCount] = NlSidsAndAttributes[Index];
  639. SidAndAttributesCount ++;
  640. }
  641. SidAndAttributes[SidAndAttributesCount].Sid = WorldSid;
  642. SidAndAttributes[SidAndAttributesCount].Attributes = SE_GROUP_MANDATORY |
  643. SE_GROUP_ENABLED |
  644. SE_GROUP_ENABLED_BY_DEFAULT;
  645. SidAndAttributesCount ++;
  646. SidAndAttributes[SidAndAttributesCount].Sid = AuthenticatedUserSid;
  647. SidAndAttributes[SidAndAttributesCount].Attributes = SE_GROUP_MANDATORY |
  648. SE_GROUP_ENABLED |
  649. SE_GROUP_ENABLED_BY_DEFAULT;
  650. SidAndAttributesCount ++;
  651. //
  652. // Set the AuthZ info for use by the AuthZ callback routine
  653. //
  654. AuthzInfo.SidAndAttributes = SidAndAttributes;
  655. AuthzInfo.SidCount = SidAndAttributesCount;
  656. //
  657. // Get the computer account SID from the RID
  658. //
  659. NetStatus = NetpDomainIdToSid( DomainInfo->DomAccountDomainId,
  660. ComputerAccountId,
  661. &ComputerAccountSid );
  662. if ( NetStatus != ERROR_SUCCESS ) {
  663. Status = STATUS_INSUFFICIENT_RESOURCES;
  664. goto Cleanup;
  665. }
  666. //
  667. // Retrieve the workstation machine account Security Descriptor
  668. // to be checked for access. Using the SID as the input yields
  669. // the fastest search.
  670. //
  671. // We have to do this on every logon as the SD can change. There
  672. // is no notification mechanism for SD changes. Kerberos has been
  673. // doing this search on every logon and it hasn't been a big
  674. // perf hit so far.
  675. //
  676. ComputerAccountSidStr.Buffer = ComputerAccountSid;
  677. ComputerAccountSidStr.MaximumLength =
  678. ComputerAccountSidStr.Length = (USHORT) RtlLengthSid( ComputerAccountSid );
  679. Status = SamIGetUserLogonInformation2(
  680. DomainInfo->DomSamAccountDomainHandle,
  681. SAM_NO_MEMBERSHIPS | // Don't need group memberships
  682. SAM_OPEN_BY_SID, // Next parameter is the SID of the account
  683. &ComputerAccountSidStr,
  684. USER_ALL_SECURITYDESCRIPTOR, // Only need the security descriptor
  685. 0, // no extended fields
  686. &LocalUserInfo,
  687. &LocalMembership,
  688. NULL );
  689. if ( !NT_SUCCESS(Status) ) {
  690. NlPrint(( NL_CRITICAL,
  691. "NlpVerifyAllowedToAuthenticate: SamIGetUserLogonInformation2 failed 0x%lx\n",
  692. Status ));
  693. goto Cleanup;
  694. }
  695. //
  696. // Now initialize the AuthZ client context
  697. //
  698. if ( !AuthzInitializeContextFromSid(
  699. AUTHZ_SKIP_TOKEN_GROUPS, // take the SIDs as they are
  700. AuthzInfo.SidAndAttributes[0].Sid, // userid is first element in array
  701. NlAuthzRM,
  702. NULL,
  703. ZeroLuid,
  704. &AuthzInfo,
  705. &hClientContext) ) {
  706. NetStatus = GetLastError();
  707. NlPrint(( NL_CRITICAL,
  708. "NlpVerifyAllowedToAuthenticate: AuthzInitializeContextFromSid failed 0x%lx\n",
  709. NetStatus ));
  710. Status = NetpApiStatusToNtStatus( NetStatus );
  711. goto Cleanup;
  712. }
  713. //
  714. // Perform the access check
  715. //
  716. TypeList.Level = ACCESS_OBJECT_GUID;
  717. TypeList.ObjectType = &GUID_A_SECURED_FOR_CROSS_ORGANIZATION;
  718. TypeList.Sbz = 0;
  719. Request.DesiredAccess = ACTRL_DS_CONTROL_ACCESS; // ACTRL_DS_READ_PROP
  720. Request.ObjectTypeList = &TypeList;
  721. Request.ObjectTypeListLength = 1;
  722. Request.OptionalArguments = NULL;
  723. Request.PrincipalSelfSid = NULL;
  724. Reply.ResultListLength = 1; // all or nothing w.r.t. access check.
  725. Reply.GrantedAccessMask = &AccessMask;
  726. Reply.Error = &Error;
  727. if ( !AuthzAccessCheck(
  728. 0,
  729. hClientContext,
  730. &Request,
  731. NULL, // TBD: add audit
  732. LocalUserInfo->I1.SecurityDescriptor.SecurityDescriptor,
  733. NULL,
  734. 0,
  735. &Reply,
  736. NULL) ) { // don't cache result? Check to see if optimal.
  737. NetStatus = GetLastError();
  738. NlPrint(( NL_CRITICAL,
  739. "NlpVerifyAllowedToAuthenticate: AuthzAccessCheck failed unexpectedly 0x%lx\n",
  740. NetStatus ));
  741. Status = NetpApiStatusToNtStatus( NetStatus );
  742. } else if ( (*Reply.Error) != ERROR_SUCCESS ) {
  743. NlPrint(( NL_LOGON,
  744. "NlpVerifyAllowedToAuthenticate: AuthzAccessCheck failed 0x%lx\n",
  745. *Reply.Error ));
  746. Status = STATUS_AUTHENTICATION_FIREWALL_FAILED;
  747. } else {
  748. Status = STATUS_SUCCESS;
  749. }
  750. Cleanup:
  751. if ( SidAndAttributes != NULL ) {
  752. LocalFree( SidAndAttributes );
  753. }
  754. if ( ComputerAccountSid != NULL ) {
  755. NetpMemoryFree( ComputerAccountSid );
  756. }
  757. if ( hClientContext != NULL ) {
  758. AuthzFreeContext( hClientContext );
  759. }
  760. if ( LocalUserInfo != NULL ) {
  761. SamIFree_UserInternal6Information( LocalUserInfo );
  762. }
  763. SamIFreeSidAndAttributesList( &LocalMembership );
  764. return Status;
  765. }
  766. NTSTATUS
  767. NlpExpandResourceGroupMembership(
  768. IN NETLOGON_VALIDATION_INFO_CLASS ValidationLevel,
  769. IN OUT PNETLOGON_VALIDATION_SAM_INFO4 * UserInfo,
  770. IN PDOMAIN_INFO DomainInfo,
  771. IN ULONG ComputerAccountId
  772. )
  773. /*++
  774. Routine Description:
  775. Given the validation information for a user, expands the group member-
  776. ships and user id into a list of sids.
  777. Also, performs an access check to determine whether the specified
  778. user can logon to the specified computer when Other Org trust link
  779. was traversed in the course of the logon validation.
  780. Arguments:
  781. ValidationLevel -- Specifies the level of information passed as input in
  782. UserInfo. Must be NetlogonValidationSamInfo or
  783. NetlogonValidationSamInfo2, NetlogonValidationSamInfo4
  784. NetlogonValidationSamInfo4 is always returned on output.
  785. UserInfo - user's validation information
  786. This structure is updated to include the resource groups that the user is a member of
  787. DomainInfo - Structure identifying the hosted domain used to determine the group membership.
  788. ComputerAccountId - The ID of the computer account for the workstation that passed the
  789. logon to this domain controller.
  790. Return Value:
  791. STATUS_INSUFFICIENT_RESOURCES - there wasn't enough memory to
  792. create the list of sids.
  793. --*/
  794. {
  795. NTSTATUS Status = STATUS_SUCCESS;
  796. SAMPR_PSID_ARRAY SidList = {0};
  797. PSAMPR_PSID_ARRAY ResourceGroups = NULL;
  798. ULONG Index;
  799. ULONG NonExtraSidCount = 0;
  800. Status = NlpBuildPacSidList( *UserInfo,
  801. &SidList,
  802. &NonExtraSidCount );
  803. if (!NT_SUCCESS(Status)) {
  804. goto Cleanup;
  805. }
  806. //
  807. // Call SAM to get the sids
  808. //
  809. Status = SamIGetResourceGroupMembershipsTransitive(
  810. DomainInfo->DomSamAccountDomainHandle,
  811. &SidList,
  812. 0, // no flags
  813. &ResourceGroups
  814. );
  815. if (!NT_SUCCESS(Status)) {
  816. goto Cleanup;
  817. }
  818. //
  819. // Build a new validation information structure
  820. //
  821. if (ResourceGroups->Count != 0) {
  822. Status = NlpAddResourceGroupsToSamInfo(
  823. ValidationLevel,
  824. UserInfo,
  825. ResourceGroups
  826. );
  827. if (!NT_SUCCESS(Status)) {
  828. goto Cleanup;
  829. }
  830. }
  831. //
  832. // If we have the user ID, ensure this user has the access to
  833. // authenticate to the computer that sent this logon to us.
  834. // Do this check only if all DCs in the domain are doing this
  835. // check (all DCs are .NET or higher) to ensure the consistent
  836. // behavior.
  837. //
  838. if ( (*UserInfo)->UserId != 0 &&
  839. ComputerAccountId != 0 &&
  840. LsaINoMoreWin2KDomain() ) {
  841. Status = NlpVerifyAllowedToAuthenticate( DomainInfo,
  842. ComputerAccountId,
  843. &SidList,
  844. NonExtraSidCount,
  845. (*UserInfo)->ExtraSids,
  846. (*UserInfo)->SidCount );
  847. }
  848. Cleanup:
  849. SamIFreeSidArray(
  850. ResourceGroups
  851. );
  852. if (SidList.Sids != NULL) {
  853. for (Index = 0; Index < SidList.Count ;Index++ ) {
  854. if (SidList.Sids[Index].SidPointer != NULL) {
  855. MIDL_user_free(SidList.Sids[Index].SidPointer);
  856. }
  857. }
  858. MIDL_user_free(SidList.Sids);
  859. }
  860. return(Status);
  861. }
  862. NTSTATUS
  863. NlpAddOtherOrganizationSid (
  864. IN NETLOGON_VALIDATION_INFO_CLASS ValidationLevel,
  865. IN OUT PNETLOGON_VALIDATION_SAM_INFO4 *ValidationInformation
  866. )
  867. /*++
  868. Routine Description:
  869. This routine adds the Other Org SID to the extra SIDs field of
  870. the passed in validation info.
  871. Arguments:
  872. ValidationLevel -- Specifies the level of information passed as input in
  873. ValidationInformation. Must beNetlogonValidationSamInfo2 or
  874. NetlogonValidationSamInfo4.
  875. ValidationInformation -- Specifies the NETLOGON_VALIDATION_SAM_INFO
  876. to add the OtherOrg SID to.
  877. Return Value:
  878. STATUS_INSUFFICIENT_RESOURCES: not enough memory to allocate the new
  879. structure.
  880. --*/
  881. {
  882. NTSTATUS Status = STATUS_SUCCESS;
  883. ULONG Index;
  884. SAMPR_PSID_ARRAY SidArray = {0};
  885. SAMPR_SID_INFORMATION Sid = {0};
  886. //
  887. // Check if the OtherOrg SID is already there
  888. //
  889. for ( Index = 0;
  890. Index < (*ValidationInformation)->SidCount;
  891. Index++ ) {
  892. //
  893. // If the Other Org SID is already there, there is nothing to add
  894. //
  895. if ( RtlEqualSid((*ValidationInformation)->ExtraSids[Index].Sid,
  896. OtherOrganizationSid) ) {
  897. return STATUS_SUCCESS;
  898. }
  899. }
  900. //
  901. // Add the OtherOrg SID
  902. //
  903. SidArray.Count = 1;
  904. SidArray.Sids = &Sid;
  905. Sid.SidPointer = OtherOrganizationSid; // well known SID
  906. Status = NlpAddResourceGroupsToSamInfo(
  907. ValidationLevel,
  908. ValidationInformation,
  909. &SidArray );
  910. return Status;
  911. }