683 lines
17 KiB
C
683 lines
17 KiB
C
/*++
|
||
|
||
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);
|
||
}
|