windows-nt/Source/XPSP1/NT/ds/netapi/svcdlls/logonsrv/server/rgroups.c

683 lines
17 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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
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
)
/*++
Routine Description:
Given the validation information for a user, expands the group member-
ships and user id into a list of sids
Arguments:
UserInfo - user's validation information
Sids - receives an array of all the user's group sids and user id
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;
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.
//
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++;
}
//
// 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++;
}
//
// 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;
}
}
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 ) {
*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) );
}
MIDL_user_free(SamInfo);
*ValidationInformation = SamInfo4;
return STATUS_SUCCESS;
}
NTSTATUS
NlpExpandResourceGroupMembership(
IN NETLOGON_VALIDATION_INFO_CLASS ValidationLevel,
IN OUT PNETLOGON_VALIDATION_SAM_INFO4 * UserInfo,
IN PDOMAIN_INFO DomainInfo
)
/*++
Routine Description:
Given the validation information for a user, expands the group member-
ships and user id into a list of sids
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.
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;
Status = NlpBuildPacSidList(
*UserInfo,
&SidList
);
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;
}
}
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);
}