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

/*++
Copyright (c) 1987-1996 Microsoft Corporation
Module Name:
rgroups.c
Abstract:
Routines to expand transitive group membership.
Author:
Mike Swift (mikesw) 8-May-1998
Environment:
User mode only.
Contains NT-specific code.
Requires ANSI C extensions: slash-slash comments, long external names.
Revision History:
--*/
//
// Common include files.
//
#include "logonsrv.h" // Include files common to entire service
#pragma hdrstop
#include <authz.h> // Authz API
GUID GUID_A_SECURED_FOR_CROSS_ORGANIZATION = {0x68B1D179,0x0D15,0x4d4f,0xAB,0x71,0x46,0x15,0x2E,0x79,0xA7,0xBC};
typedef struct _NL_AUTHZ_INFO {
PNETLOGON_SID_AND_ATTRIBUTES SidAndAttributes;
ULONG SidCount;
} NL_AUTHZ_INFO, *PNL_AUTHZ_INFO;
AUTHZ_RESOURCE_MANAGER_HANDLE NlAuthzRM = NULL;
BOOL
NlComputeAuthzGroups(
IN AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzClientContext,
IN PVOID Args,
OUT PSID_AND_ATTRIBUTES *pSidAttrArray,
OUT PDWORD pSidCount,
OUT PSID_AND_ATTRIBUTES *pRestrictedSidAttrArray,
OUT PDWORD pRestrictedSidCount
)
/*++
Routine Description:
Authz callback for add groups to authz client context
Arguments:
See Authz SDK documentation
Return Value:
Always TRUE
--*/
{
PNL_AUTHZ_INFO AuthzInfo = (PNL_AUTHZ_INFO) Args;
*pSidAttrArray = (PSID_AND_ATTRIBUTES) AuthzInfo->SidAndAttributes;
*pSidCount = AuthzInfo->SidCount;
*pRestrictedSidAttrArray = NULL;
*pRestrictedSidCount = 0;
return (TRUE);
UNREFERENCED_PARAMETER( hAuthzClientContext );
}
VOID
NlFreeAuthzGroups(
IN PSID_AND_ATTRIBUTES pSidAttrArray
)
/*++
Routine Description:
Authz callback to cleanup after adding groups to authz client context.
Basically a no-op, as we already have a copy of the SIDs.
Arguments:
See Authz SDK documentation
Return Value:
None
--*/
{
return;
UNREFERENCED_PARAMETER( pSidAttrArray );
}
NET_API_STATUS
NlInitializeAuthzRM(
VOID
)
/*++
Routine Description:
Initializes the Authz manager for netlogon
Arguments:
None
Return Value:
Status of Authz operation
--*/
{
NET_API_STATUS NetStatus = NO_ERROR;
if ( !AuthzInitializeResourceManager( 0,
NULL,
NlComputeAuthzGroups,
NlFreeAuthzGroups,
L"NetLogon",
&NlAuthzRM) ) {
NetStatus = GetLastError();
NlPrint(( NL_CRITICAL, "NlInitializeAuthzRM: AuthzInitializeRm failed 0x%lx\n",
NetStatus ));
}
return NetStatus;
}
VOID
NlFreeAuthzRm(
VOID
)
/*++
Routine Description:
Frees the Authz manager for netlogon
Arguments:
None
Return Value:
None
--*/
{
if ( NlAuthzRM != NULL ) {
if ( !AuthzFreeResourceManager(NlAuthzRM) ) {
NlPrint((NL_CRITICAL, "AuthzFreeResourceManager failed 0x%lx\n", GetLastError()));
} else {
NlAuthzRM = NULL;
}
}
}
PSID
NlpCopySid(
IN PSID Sid
)
/*++
Routine Description:
Given a SID allocatees space for a new SID from the LSA heap and copies
the original SID.
Arguments:
Sid - The original SID.
Return Value:
Sid - Returns a pointer to a buffer allocated from the LsaHeap
containing the resultant Sid.
--*/
{
PSID NewSid;
ULONG Size;
Size = RtlLengthSid( Sid );
if ((NewSid = MIDL_user_allocate( Size )) == NULL ) {
return NULL;
}
if ( !NT_SUCCESS( RtlCopySid( Size, NewSid, Sid ) ) ) {
MIDL_user_free( NewSid );
return NULL;
}
return NewSid;
}
NTSTATUS
NlpBuildPacSidList(
IN PNETLOGON_VALIDATION_SAM_INFO4 UserInfo,
OUT PSAMPR_PSID_ARRAY Sids,
OUT PULONG NonExtraSidCount
)
/*++
Routine Description:
Given the validation information for a user, expands the group member-
ships and user id into a list of sids. If user id is present, it
will be expanded into the first entry of the list.
Arguments:
UserInfo - user's validation information
Sids - receives an array of all the user's group sids and user id
NonExtraSidCount - Returns the number of SIDs in the UserInfo which
are not Extra SIDs.
Return Value:
STATUS_INSUFFICIENT_RESOURCES - there wasn't enough memory to
create the list of sids.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
NET_API_STATUS NetStatus;
ULONG Size = 0, i;
Sids->Count = 0;
Sids->Sids = NULL;
*NonExtraSidCount = 0;
if (UserInfo->UserId != 0) {
Size += sizeof(SAMPR_SID_INFORMATION);
}
Size += UserInfo->GroupCount * (ULONG)sizeof(SAMPR_SID_INFORMATION);
//
// If there are extra SIDs, add space for them
//
if (UserInfo->UserFlags & LOGON_EXTRA_SIDS) {
Size += UserInfo->SidCount * (ULONG)sizeof(SAMPR_SID_INFORMATION);
}
Sids->Sids = (PSAMPR_SID_INFORMATION) MIDL_user_allocate( Size );
if ( Sids->Sids == NULL ) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RtlZeroMemory(
Sids->Sids,
Size
);
//
// Start copying SIDs into the structure
//
i = 0;
//
// If the UserId is non-zero, then it contians the users RID.
// This must be the first entry in the list as this is the
// order NlpVerifyAllowedToAuthenticate assumes.
//
if ( UserInfo->UserId ) {
NetStatus = NetpDomainIdToSid(
UserInfo->LogonDomainId,
UserInfo->UserId,
(PSID *) &Sids->Sids[0].SidPointer
);
if( NetStatus != ERROR_SUCCESS ) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
Sids->Count++;
(*NonExtraSidCount) ++;
}
//
// Copy over all the groups passed as RIDs
//
for ( i=0; i < UserInfo->GroupCount; i++ ) {
NetStatus = NetpDomainIdToSid(
UserInfo->LogonDomainId,
UserInfo->GroupIds[i].RelativeId,
(PSID *) &Sids->Sids[Sids->Count].SidPointer
);
if( NetStatus != ERROR_SUCCESS ) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
Sids->Count++;
(*NonExtraSidCount) ++;
}
//
// Add in the extra SIDs
//
//
// ???: no need to allocate these
//
if (UserInfo->UserFlags & LOGON_EXTRA_SIDS) {
for ( i = 0; i < UserInfo->SidCount; i++ ) {
Sids->Sids[Sids->Count].SidPointer = NlpCopySid(
UserInfo->ExtraSids[i].Sid
);
if (Sids->Sids[Sids->Count].SidPointer == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
Sids->Count++;
}
}
//
// Deallocate any memory we've allocated
//
Cleanup:
if (!NT_SUCCESS(Status)) {
if (Sids->Sids != NULL) {
for (i = 0; i < Sids->Count ;i++ ) {
if (Sids->Sids[i].SidPointer != NULL) {
MIDL_user_free(Sids->Sids[i].SidPointer);
}
}
MIDL_user_free(Sids->Sids);
Sids->Sids = NULL;
Sids->Count = 0;
}
*NonExtraSidCount = 0;
}
return Status;
}
NTSTATUS
NlpAddResourceGroupsToSamInfo (
IN NETLOGON_VALIDATION_INFO_CLASS ValidationLevel,
IN OUT PNETLOGON_VALIDATION_SAM_INFO4 *ValidationInformation,
IN PSAMPR_PSID_ARRAY ResourceGroups
)
/*++
Routine Description:
This function converts a NETLOGON_VALIDATION_SAM_INFO version 1, 2, or 4 to
a NETLOGON_VALIDATION_SAM_INFO version 4 and optionally adds in an array of
ResourceGroup sids.
Since version 4 is a superset of the other two levels, the returned structure can
be used even though one of the other info levels are needed.
Arguments:
ValidationLevel -- Specifies the level of information passed as input in
ValidationInformation. Must be NetlogonValidationSamInfo or
NetlogonValidationSamInfo2, NetlogonValidationSamInfo4
NetlogonValidationSamInfo4 is always returned on output.
ValidationInformation -- Specifies the NETLOGON_VALIDATION_SAM_INFO
to convert.
ResourceGroups - The list of resource groups to add to the structure.
If NULL, no resource groups are added.
Return Value:
STATUS_INSUFFICIENT_RESOURCES: not enough memory to allocate the new
structure.
--*/
{
ULONG Length;
PNETLOGON_VALIDATION_SAM_INFO4 SamInfo = *ValidationInformation;
PNETLOGON_VALIDATION_SAM_INFO4 SamInfo4;
PBYTE Where;
ULONG Index;
ULONG GroupIndex;
ULONG ExtraSids = 0;
//
// Calculate the size of the new structure
//
Length = sizeof( NETLOGON_VALIDATION_SAM_INFO4 )
+ SamInfo->GroupCount * sizeof(GROUP_MEMBERSHIP)
+ RtlLengthSid( SamInfo->LogonDomainId );
//
// Add space for extra sids & resource groups
//
if ( ValidationLevel != NetlogonValidationSamInfo &&
(SamInfo->UserFlags & LOGON_EXTRA_SIDS) != 0 ) {
for (Index = 0; Index < SamInfo->SidCount ; Index++ ) {
Length += sizeof(NETLOGON_SID_AND_ATTRIBUTES) + RtlLengthSid(SamInfo->ExtraSids[Index].Sid);
}
ExtraSids += SamInfo->SidCount;
}
if ( ResourceGroups != NULL ) {
for (Index = 0; Index < ResourceGroups->Count ; Index++ ) {
Length += sizeof(NETLOGON_SID_AND_ATTRIBUTES) + RtlLengthSid(ResourceGroups->Sids[Index].SidPointer);
}
ExtraSids += ResourceGroups->Count;
}
//
// Round up now to take into account the round up in the
// middle of marshalling
//
Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
+ SamInfo->LogonDomainName.Length + sizeof(WCHAR)
+ SamInfo->LogonServer.Length + sizeof(WCHAR)
+ SamInfo->EffectiveName.Length + sizeof(WCHAR)
+ SamInfo->FullName.Length + sizeof(WCHAR)
+ SamInfo->LogonScript.Length + sizeof(WCHAR)
+ SamInfo->ProfilePath.Length + sizeof(WCHAR)
+ SamInfo->HomeDirectory.Length + sizeof(WCHAR)
+ SamInfo->HomeDirectoryDrive.Length + sizeof(WCHAR);
if ( ValidationLevel == NetlogonValidationSamInfo4 ) {
Length += SamInfo->DnsLogonDomainName.Length + sizeof(WCHAR)
+ SamInfo->Upn.Length + sizeof(WCHAR);
//
// The ExpansionStrings may be used to transport byte aligned data
Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
+ SamInfo->ExpansionString1.Length + sizeof(WCHAR);
Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
+ SamInfo->ExpansionString2.Length + sizeof(WCHAR);
Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
+ SamInfo->ExpansionString3.Length + sizeof(WCHAR);
Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
+ SamInfo->ExpansionString4.Length + sizeof(WCHAR);
Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
+ SamInfo->ExpansionString5.Length + sizeof(WCHAR);
Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
+ SamInfo->ExpansionString6.Length + sizeof(WCHAR);
Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
+ SamInfo->ExpansionString7.Length + sizeof(WCHAR);
Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
+ SamInfo->ExpansionString8.Length + sizeof(WCHAR);
Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
+ SamInfo->ExpansionString9.Length + sizeof(WCHAR);
Length = ROUND_UP_COUNT(Length, sizeof(WCHAR))
+ SamInfo->ExpansionString10.Length + sizeof(WCHAR);
}
Length = ROUND_UP_COUNT( Length, sizeof(WCHAR) );
SamInfo4 = (PNETLOGON_VALIDATION_SAM_INFO4) MIDL_user_allocate( Length );
if ( !SamInfo4 ) {
//
// Free the passed-in allocated SAM info
//
if ( SamInfo ) {
//
// Zero out sensitive data
//
RtlSecureZeroMemory( &SamInfo->UserSessionKey, sizeof(SamInfo->UserSessionKey) );
RtlSecureZeroMemory( &SamInfo->ExpansionRoom, sizeof(SamInfo->ExpansionRoom) );
MIDL_user_free(SamInfo);
}
*ValidationInformation = NULL;
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// First copy the whole structure, since most parts are the same
//
RtlCopyMemory( SamInfo4, SamInfo, sizeof(NETLOGON_VALIDATION_SAM_INFO));
RtlZeroMemory( &((LPBYTE)SamInfo4)[sizeof(NETLOGON_VALIDATION_SAM_INFO)],
sizeof(NETLOGON_VALIDATION_SAM_INFO4) - sizeof(NETLOGON_VALIDATION_SAM_INFO) );
//
// Copy all the variable length data
//
Where = (PBYTE) (SamInfo4 + 1);
RtlCopyMemory(
Where,
SamInfo->GroupIds,
SamInfo->GroupCount * sizeof( GROUP_MEMBERSHIP) );
SamInfo4->GroupIds = (PGROUP_MEMBERSHIP) Where;
Where += SamInfo->GroupCount * sizeof( GROUP_MEMBERSHIP );
//
// Copy the extra groups
//
if (ExtraSids != 0) {
ULONG SidLength;
SamInfo4->ExtraSids = (PNETLOGON_SID_AND_ATTRIBUTES) Where;
Where += sizeof(NETLOGON_SID_AND_ATTRIBUTES) * ExtraSids;
GroupIndex = 0;
if ( ValidationLevel != NetlogonValidationSamInfo &&
(SamInfo->UserFlags & LOGON_EXTRA_SIDS) != 0 ) {
for (Index = 0; Index < SamInfo->SidCount ; Index++ ) {
SamInfo4->ExtraSids[GroupIndex].Attributes = SamInfo->ExtraSids[Index].Attributes;
SamInfo4->ExtraSids[GroupIndex].Sid = (PSID) Where;
SidLength = RtlLengthSid(SamInfo->ExtraSids[Index].Sid);
RtlCopyMemory(
Where,
SamInfo->ExtraSids[Index].Sid,
SidLength
);
Where += SidLength;
GroupIndex++;
}
}
//
// Add the resource groups
//
if ( ResourceGroups != NULL ) {
for (Index = 0; Index < ResourceGroups->Count ; Index++ ) {
SamInfo4->ExtraSids[GroupIndex].Attributes = SE_GROUP_MANDATORY |
SE_GROUP_ENABLED |
SE_GROUP_ENABLED_BY_DEFAULT;
SamInfo4->ExtraSids[GroupIndex].Sid = (PSID) Where;
SidLength = RtlLengthSid(ResourceGroups->Sids[Index].SidPointer);
RtlCopyMemory(
Where,
ResourceGroups->Sids[Index].SidPointer,
SidLength
);
Where += SidLength;
GroupIndex++;
}
}
SamInfo4->SidCount = GroupIndex;
NlAssert(GroupIndex == ExtraSids);
}
RtlCopyMemory(
Where,
SamInfo->LogonDomainId,
RtlLengthSid( SamInfo->LogonDomainId ) );
SamInfo4->LogonDomainId = (PSID) Where;
Where += RtlLengthSid( SamInfo->LogonDomainId );
//
// Copy the WCHAR-aligned data
//
Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
NlpPutString( &SamInfo4->EffectiveName,
&SamInfo->EffectiveName,
&Where );
NlpPutString( &SamInfo4->FullName,
&SamInfo->FullName,
&Where );
NlpPutString( &SamInfo4->LogonScript,
&SamInfo->LogonScript,
&Where );
NlpPutString( &SamInfo4->ProfilePath,
&SamInfo->ProfilePath,
&Where );
NlpPutString( &SamInfo4->HomeDirectory,
&SamInfo->HomeDirectory,
&Where );
NlpPutString( &SamInfo4->HomeDirectoryDrive,
&SamInfo->HomeDirectoryDrive,
&Where );
NlpPutString( &SamInfo4->LogonServer,
&SamInfo->LogonServer,
&Where );
NlpPutString( &SamInfo4->LogonDomainName,
&SamInfo->LogonDomainName,
&Where );
if ( ValidationLevel == NetlogonValidationSamInfo4 ) {
NlpPutString( &SamInfo4->DnsLogonDomainName,
&SamInfo->DnsLogonDomainName,
&Where );
NlpPutString( &SamInfo4->Upn,
&SamInfo->Upn,
&Where );
NlpPutString( &SamInfo4->ExpansionString1,
&SamInfo->ExpansionString1,
&Where );
Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
NlpPutString( &SamInfo4->ExpansionString2,
&SamInfo->ExpansionString2,
&Where );
Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
NlpPutString( &SamInfo4->ExpansionString3,
&SamInfo->ExpansionString3,
&Where );
Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
NlpPutString( &SamInfo4->ExpansionString4,
&SamInfo->ExpansionString4,
&Where );
Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
NlpPutString( &SamInfo4->ExpansionString5,
&SamInfo->ExpansionString5,
&Where );
Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
NlpPutString( &SamInfo4->ExpansionString6,
&SamInfo->ExpansionString6,
&Where );
Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
NlpPutString( &SamInfo4->ExpansionString7,
&SamInfo->ExpansionString7,
&Where );
Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
NlpPutString( &SamInfo4->ExpansionString8,
&SamInfo->ExpansionString8,
&Where );
Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
NlpPutString( &SamInfo4->ExpansionString9,
&SamInfo->ExpansionString9,
&Where );
Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
NlpPutString( &SamInfo4->ExpansionString10,
&SamInfo->ExpansionString10,
&Where );
Where = ROUND_UP_POINTER(Where, sizeof(WCHAR) );
}
//
// Zero out sensitive data
//
RtlSecureZeroMemory( &SamInfo->UserSessionKey, sizeof(SamInfo->UserSessionKey) );
RtlSecureZeroMemory( &SamInfo->ExpansionRoom, sizeof(SamInfo->ExpansionRoom) );
MIDL_user_free(SamInfo);
*ValidationInformation = SamInfo4;
return STATUS_SUCCESS;
}
NTSTATUS
NlpVerifyAllowedToAuthenticate(
IN PDOMAIN_INFO DomainInfo,
IN ULONG ComputerAccountId,
IN PSAMPR_PSID_ARRAY SamSidList,
IN ULONG SamSidCount,
IN PNETLOGON_SID_AND_ATTRIBUTES NlSidsAndAttributes,
IN ULONG NlSidsAndAttributesCount
)
/*++
Routine Description:
This routine performs an access check to determine whether
the user logon is allowed to a specified computer. This
check is performed on the DC that is the computer uses on
the secure channel in its domain. Note that the computer
may be this DC when the logon is initiated locally from
MSV package.
This access check is performed only if the trust path traversed
to validate the logon involved an Other Organization trust link.
In this case, the well-known OtherOrg SID will be present in the
passed-in netlogon SIDs list.
The access check is performed on the security descriptor for the
specified computer given the passed-in lists of SIDs.
Arguments:
DomainInfo - Hosted domain the logon is for.
ComputerAccountId - The RID of the computer being logged into.
SamSidList - The list of SIDs in the form of SAM data structure.
These are the SIDs which have been expanded from the group
membership in the validation info.
SamSidCount - The number of SIDs in SamSidList.
NlSidsAndAttributes - The list of SIDs in the form of Netlogon
data structure. These are the SIDs from the extra SIDs
field in the validation info.
NlSidsAndAttributesCount - The number of SIDs in NlSidsAndAttributes.
Return Value:
STATUS_SUCCESS - The access check succedded.
STATUS_AUTHENTICATION_FIREWALL_FAILED - The access check failed.
STATUS_INSUFFICIENT_RESOURCES - there wasn't enough memory to
create the combined list of sids.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
NET_API_STATUS NetStatus = NO_ERROR;
ULONG SidAndAttributesCount = 0;
PNETLOGON_SID_AND_ATTRIBUTES SidAndAttributes = NULL;
ULONG Index = 0;
PSID ComputerAccountSid = NULL;
UNICODE_STRING ComputerAccountSidStr;
PUSER_INTERNAL6_INFORMATION LocalUserInfo = NULL;
SID_AND_ATTRIBUTES_LIST LocalMembership = {0};
NL_AUTHZ_INFO AuthzInfo = {0};
AUTHZ_ACCESS_REPLY Reply = {0};
OBJECT_TYPE_LIST TypeList = {0};
AUTHZ_CLIENT_CONTEXT_HANDLE hClientContext = NULL;
AUTHZ_ACCESS_REQUEST Request = {0};
DWORD AccessMask = 0;
LUID ZeroLuid = {0,0};
DWORD Error = ERROR_ACCESS_DENIED;
//
// Per the specification, the access check is only performed if the
// "other org" SID is in the list. The SID can only appear in the
// ExtraSids list which is what passed as the netlogon SIDs.
//
for ( Index = 0; Index < NlSidsAndAttributesCount; Index++ ) {
if ( RtlEqualSid(NlSidsAndAttributes[Index].Sid, OtherOrganizationSid) ) {
break;
}
}
//
// If the Other Org SID is not there, there is nothing to check
//
if ( Index == NlSidsAndAttributesCount ) {
Status = STATUS_SUCCESS;
goto Cleanup;
}
//
// OK, the Other Org SID is there, so proceed with the check.
//
// Allocate memory to hold all the SIDs in a common structure
// that AuthZ proper understands
//
//
// add everyone and authenticated users (note guess fallback should not
// have the OtherOrg sid, therefore should not get this far)
//
SidAndAttributesCount = SamSidCount + NlSidsAndAttributesCount + 2;
SidAndAttributes = LocalAlloc( LMEM_ZEROINIT,
SidAndAttributesCount * sizeof(NETLOGON_SID_AND_ATTRIBUTES) );
if ( SidAndAttributes == NULL ) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
//
// Convert the SIDs from the SAM structure into the Netlogon
// structure that AuthZ proper understands
//
SidAndAttributesCount = 0;
for ( Index = 0; Index < SamSidCount; Index++ ) {
SidAndAttributes[SidAndAttributesCount].Sid = (PSID) SamSidList->Sids[Index].SidPointer;
SidAndAttributes[SidAndAttributesCount].Attributes = SE_GROUP_MANDATORY |
SE_GROUP_ENABLED |
SE_GROUP_ENABLED_BY_DEFAULT;
SidAndAttributesCount ++;
}
//
// Copy the SIDs from the Netlogon passed-in structure
// into the common array
//
for ( Index = 0; Index < NlSidsAndAttributesCount; Index++ ) {
SidAndAttributes[SidAndAttributesCount] = NlSidsAndAttributes[Index];
SidAndAttributesCount ++;
}
SidAndAttributes[SidAndAttributesCount].Sid = WorldSid;
SidAndAttributes[SidAndAttributesCount].Attributes = SE_GROUP_MANDATORY |
SE_GROUP_ENABLED |
SE_GROUP_ENABLED_BY_DEFAULT;
SidAndAttributesCount ++;
SidAndAttributes[SidAndAttributesCount].Sid = AuthenticatedUserSid;
SidAndAttributes[SidAndAttributesCount].Attributes = SE_GROUP_MANDATORY |
SE_GROUP_ENABLED |
SE_GROUP_ENABLED_BY_DEFAULT;
SidAndAttributesCount ++;
//
// Set the AuthZ info for use by the AuthZ callback routine
//
AuthzInfo.SidAndAttributes = SidAndAttributes;
AuthzInfo.SidCount = SidAndAttributesCount;
//
// Get the computer account SID from the RID
//
NetStatus = NetpDomainIdToSid( DomainInfo->DomAccountDomainId,
ComputerAccountId,
&ComputerAccountSid );
if ( NetStatus != ERROR_SUCCESS ) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
//
// Retrieve the workstation machine account Security Descriptor
// to be checked for access. Using the SID as the input yields
// the fastest search.
//
// We have to do this on every logon as the SD can change. There
// is no notification mechanism for SD changes. Kerberos has been
// doing this search on every logon and it hasn't been a big
// perf hit so far.
//
ComputerAccountSidStr.Buffer = ComputerAccountSid;
ComputerAccountSidStr.MaximumLength =
ComputerAccountSidStr.Length = (USHORT) RtlLengthSid( ComputerAccountSid );
Status = SamIGetUserLogonInformation2(
DomainInfo->DomSamAccountDomainHandle,
SAM_NO_MEMBERSHIPS | // Don't need group memberships
SAM_OPEN_BY_SID, // Next parameter is the SID of the account
&ComputerAccountSidStr,
USER_ALL_SECURITYDESCRIPTOR, // Only need the security descriptor
0, // no extended fields
&LocalUserInfo,
&LocalMembership,
NULL );
if ( !NT_SUCCESS(Status) ) {
NlPrint(( NL_CRITICAL,
"NlpVerifyAllowedToAuthenticate: SamIGetUserLogonInformation2 failed 0x%lx\n",
Status ));
goto Cleanup;
}
//
// Now initialize the AuthZ client context
//
if ( !AuthzInitializeContextFromSid(
AUTHZ_SKIP_TOKEN_GROUPS, // take the SIDs as they are
AuthzInfo.SidAndAttributes[0].Sid, // userid is first element in array
NlAuthzRM,
NULL,
ZeroLuid,
&AuthzInfo,
&hClientContext) ) {
NetStatus = GetLastError();
NlPrint(( NL_CRITICAL,
"NlpVerifyAllowedToAuthenticate: AuthzInitializeContextFromSid failed 0x%lx\n",
NetStatus ));
Status = NetpApiStatusToNtStatus( NetStatus );
goto Cleanup;
}
//
// Perform the access check
//
TypeList.Level = ACCESS_OBJECT_GUID;
TypeList.ObjectType = &GUID_A_SECURED_FOR_CROSS_ORGANIZATION;
TypeList.Sbz = 0;
Request.DesiredAccess = ACTRL_DS_CONTROL_ACCESS; // ACTRL_DS_READ_PROP
Request.ObjectTypeList = &TypeList;
Request.ObjectTypeListLength = 1;
Request.OptionalArguments = NULL;
Request.PrincipalSelfSid = NULL;
Reply.ResultListLength = 1; // all or nothing w.r.t. access check.
Reply.GrantedAccessMask = &AccessMask;
Reply.Error = &Error;
if ( !AuthzAccessCheck(
0,
hClientContext,
&Request,
NULL, // TBD: add audit
LocalUserInfo->I1.SecurityDescriptor.SecurityDescriptor,
NULL,
0,
&Reply,
NULL) ) { // don't cache result? Check to see if optimal.
NetStatus = GetLastError();
NlPrint(( NL_CRITICAL,
"NlpVerifyAllowedToAuthenticate: AuthzAccessCheck failed unexpectedly 0x%lx\n",
NetStatus ));
Status = NetpApiStatusToNtStatus( NetStatus );
} else if ( (*Reply.Error) != ERROR_SUCCESS ) {
NlPrint(( NL_LOGON,
"NlpVerifyAllowedToAuthenticate: AuthzAccessCheck failed 0x%lx\n",
*Reply.Error ));
Status = STATUS_AUTHENTICATION_FIREWALL_FAILED;
} else {
Status = STATUS_SUCCESS;
}
Cleanup:
if ( SidAndAttributes != NULL ) {
LocalFree( SidAndAttributes );
}
if ( ComputerAccountSid != NULL ) {
NetpMemoryFree( ComputerAccountSid );
}
if ( hClientContext != NULL ) {
AuthzFreeContext( hClientContext );
}
if ( LocalUserInfo != NULL ) {
SamIFree_UserInternal6Information( LocalUserInfo );
}
SamIFreeSidAndAttributesList( &LocalMembership );
return Status;
}
NTSTATUS
NlpExpandResourceGroupMembership(
IN NETLOGON_VALIDATION_INFO_CLASS ValidationLevel,
IN OUT PNETLOGON_VALIDATION_SAM_INFO4 * UserInfo,
IN PDOMAIN_INFO DomainInfo,
IN ULONG ComputerAccountId
)
/*++
Routine Description:
Given the validation information for a user, expands the group member-
ships and user id into a list of sids.
Also, performs an access check to determine whether the specified
user can logon to the specified computer when Other Org trust link
was traversed in the course of the logon validation.
Arguments:
ValidationLevel -- Specifies the level of information passed as input in
UserInfo. Must be NetlogonValidationSamInfo or
NetlogonValidationSamInfo2, NetlogonValidationSamInfo4
NetlogonValidationSamInfo4 is always returned on output.
UserInfo - user's validation information
This structure is updated to include the resource groups that the user is a member of
DomainInfo - Structure identifying the hosted domain used to determine the group membership.
ComputerAccountId - The ID of the computer account for the workstation that passed the
logon to this domain controller.
Return Value:
STATUS_INSUFFICIENT_RESOURCES - there wasn't enough memory to
create the list of sids.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
SAMPR_PSID_ARRAY SidList = {0};
PSAMPR_PSID_ARRAY ResourceGroups = NULL;
ULONG Index;
ULONG NonExtraSidCount = 0;
Status = NlpBuildPacSidList( *UserInfo,
&SidList,
&NonExtraSidCount );
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Call SAM to get the sids
//
Status = SamIGetResourceGroupMembershipsTransitive(
DomainInfo->DomSamAccountDomainHandle,
&SidList,
0, // no flags
&ResourceGroups
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Build a new validation information structure
//
if (ResourceGroups->Count != 0) {
Status = NlpAddResourceGroupsToSamInfo(
ValidationLevel,
UserInfo,
ResourceGroups
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
}
//
// If we have the user ID, ensure this user has the access to
// authenticate to the computer that sent this logon to us.
// Do this check only if all DCs in the domain are doing this
// check (all DCs are .NET or higher) to ensure the consistent
// behavior.
//
if ( (*UserInfo)->UserId != 0 &&
ComputerAccountId != 0 &&
LsaINoMoreWin2KDomain() ) {
Status = NlpVerifyAllowedToAuthenticate( DomainInfo,
ComputerAccountId,
&SidList,
NonExtraSidCount,
(*UserInfo)->ExtraSids,
(*UserInfo)->SidCount );
}
Cleanup:
SamIFreeSidArray(
ResourceGroups
);
if (SidList.Sids != NULL) {
for (Index = 0; Index < SidList.Count ;Index++ ) {
if (SidList.Sids[Index].SidPointer != NULL) {
MIDL_user_free(SidList.Sids[Index].SidPointer);
}
}
MIDL_user_free(SidList.Sids);
}
return(Status);
}
NTSTATUS
NlpAddOtherOrganizationSid (
IN NETLOGON_VALIDATION_INFO_CLASS ValidationLevel,
IN OUT PNETLOGON_VALIDATION_SAM_INFO4 *ValidationInformation
)
/*++
Routine Description:
This routine adds the Other Org SID to the extra SIDs field of
the passed in validation info.
Arguments:
ValidationLevel -- Specifies the level of information passed as input in
ValidationInformation. Must beNetlogonValidationSamInfo2 or
NetlogonValidationSamInfo4.
ValidationInformation -- Specifies the NETLOGON_VALIDATION_SAM_INFO
to add the OtherOrg SID to.
Return Value:
STATUS_INSUFFICIENT_RESOURCES: not enough memory to allocate the new
structure.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG Index;
SAMPR_PSID_ARRAY SidArray = {0};
SAMPR_SID_INFORMATION Sid = {0};
//
// Check if the OtherOrg SID is already there
//
for ( Index = 0;
Index < (*ValidationInformation)->SidCount;
Index++ ) {
//
// If the Other Org SID is already there, there is nothing to add
//
if ( RtlEqualSid((*ValidationInformation)->ExtraSids[Index].Sid,
OtherOrganizationSid) ) {
return STATUS_SUCCESS;
}
}
//
// Add the OtherOrg SID
//
SidArray.Count = 1;
SidArray.Sids = &Sid;
Sid.SidPointer = OtherOrganizationSid; // well known SID
Status = NlpAddResourceGroupsToSamInfo(
ValidationLevel,
ValidationInformation,
&SidArray );
return Status;
}