windows-nt/Source/XPSP1/NT/ds/security/protocols/kerberos/rtl/pac.cxx

1872 lines
45 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+-----------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (c) Microsoft Corporation 1991 - 1996
//
// File: pac.cxx
//
// Contents: Implementation of routines to manipulate new PACs
//
// Description:
//
//
// History: 23-Jan-96 MikeSw Created
//
//------------------------------------------------------------------------
#include <secpch2.hxx>
#pragma hdrstop
#include <pac.hxx>
#include <sectrace.hxx>
#include <tostring.hxx>
#include <ntlmsp.h>
extern "C"
{
#include <align.h>
#include <ntsam.h>
#include <lmaccess.h>
#include <midles.h>
#include <pacndr.h>
}
//+-------------------------------------------------------------------------
//
// Function: Helper Functions for NDR encoding data types
//
// Synopsis:
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
typedef struct _PAC_BUFFER_STATE {
PBYTE BufferPointer;
ULONG BufferSize;
} PAC_BUFFER_STATE, *PPAC_BUFFER_STATE;
VOID NTAPI
PacAllocFcn(
IN OUT PVOID pvState,
OUT PCHAR * ppbOut,
IN PUINT32 pulSize
)
{
PPAC_BUFFER_STATE state = (PPAC_BUFFER_STATE) pvState;
//
// MIDL pickling calls this routine with the size of the object
// obtained by _GetSize(). This routine must return a buffer in
// ppbOut with at least *pulSize bytes.
//
DsysAssert( state->BufferPointer != NULL );
DsysAssert( state->BufferSize >= *pulSize );
*ppbOut = (char*)state->BufferPointer;
state->BufferPointer += *pulSize;
state->BufferSize -= *pulSize;
}
VOID NTAPI
PacWriteFcn(
IN OUT PVOID pvState,
OUT PCHAR pbOut,
IN UINT32 ulSize
)
{
//
// Since the data was pickled directly to the target buffer, don't
// do anything here.
//
}
VOID NTAPI
PacReadFcn(
IN OUT PVOID pvState,
OUT PCHAR * ppbOut,
IN OUT PUINT32 pulSize
)
{
PPAC_BUFFER_STATE state = (PPAC_BUFFER_STATE) pvState;
//
// MIDL pickling calls this routine with the size to read.
// This routine must return a buffer in ppbOut which contains the
// encoded data.
//
DsysAssert( state->BufferPointer != NULL );
DsysAssert( state->BufferSize >= *pulSize );
*ppbOut = (char*)state->BufferPointer;
state->BufferPointer += *pulSize;
state->BufferSize -= *pulSize;
}
//+-------------------------------------------------------------------------
//
// Function: PAC_EncodeValidationInformation
//
// Synopsis: NDR encodes the validation information
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
PAC_EncodeValidationInformation(
IN PNETLOGON_VALIDATION_SAM_INFO3 ValidationInfo,
OUT PBYTE * EncodedData,
OUT PULONG DataSize
)
{
NTSTATUS Status = STATUS_SUCCESS;
handle_t PickleHandle = 0;
PAC_BUFFER_STATE BufferState = {0};
ULONG EncodingStatus = 0;
PUCHAR OutputBuffer = NULL;
ULONG OutputSize = 0;
EncodingStatus = MesEncodeIncrementalHandleCreate(
&BufferState,
PacAllocFcn,
PacWriteFcn,
&PickleHandle
);
if (EncodingStatus != 0)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
//
// Calculate the size of the required buffer
//
OutputSize = PPAC_IDL_VALIDATION_INFO_AlignSize(
PickleHandle,
&ValidationInfo
);
OutputBuffer = (PBYTE) MIDL_user_allocate(OutputSize);
if (OutputBuffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
BufferState.BufferSize = OutputSize;
BufferState.BufferPointer = OutputBuffer;
//
// Now encode the structure
//
MesIncrementalHandleReset(
PickleHandle,
NULL,
NULL,
NULL,
NULL,
MES_ENCODE
);
PPAC_IDL_VALIDATION_INFO_Encode(
PickleHandle,
&ValidationInfo
);
*EncodedData = OutputBuffer;
*DataSize = OutputSize;
OutputBuffer = NULL;
Cleanup:
if (OutputBuffer != NULL)
{
MIDL_user_free(OutputBuffer);
}
if (PickleHandle != NULL)
{
MesHandleFree(PickleHandle);
}
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: PAC_DecodeValidationInformation
//
// Synopsis: NDR decodes the validation information
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
PAC_DecodeValidationInformation(
IN PBYTE EncodedData,
IN ULONG DataSize,
OUT PNETLOGON_VALIDATION_SAM_INFO3 * ValidationInfo
)
{
NTSTATUS Status = STATUS_SUCCESS;
handle_t PickleHandle = 0;
PAC_BUFFER_STATE BufferState = {0};
ULONG EncodingStatus = 0;
DsysAssert(ROUND_UP_POINTER(EncodedData,8) == (PVOID) EncodedData);
EncodingStatus = MesDecodeIncrementalHandleCreate(
&BufferState,
PacReadFcn,
&PickleHandle
);
if (EncodingStatus != 0)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
BufferState.BufferSize = DataSize;
BufferState.BufferPointer = EncodedData;
__try {
PPAC_IDL_VALIDATION_INFO_Decode(
PickleHandle,
ValidationInfo
);
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
Cleanup:
if (PickleHandle != NULL)
{
MesHandleFree(PickleHandle);
}
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: PAC_EncodeCredentialData
//
// Synopsis: NDR encodes the credential data
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
PAC_EncodeCredentialData(
IN PSECPKG_SUPPLEMENTAL_CRED_ARRAY CredentialData,
OUT PBYTE * EncodedData,
OUT PULONG DataSize
)
{
NTSTATUS Status = STATUS_SUCCESS;
handle_t PickleHandle = 0;
PAC_BUFFER_STATE BufferState = {0};
ULONG EncodingStatus = 0;
PUCHAR OutputBuffer = NULL;
ULONG OutputSize = 0;
EncodingStatus = MesEncodeIncrementalHandleCreate(
&BufferState,
PacAllocFcn,
PacWriteFcn,
&PickleHandle
);
if (EncodingStatus != 0)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
//
// Calculate the size of the required buffer
//
OutputSize = PPAC_IDL_CREDENTIAL_DATA_AlignSize(
PickleHandle,
&CredentialData
);
OutputBuffer = (PBYTE) MIDL_user_allocate(OutputSize);
if (OutputBuffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
BufferState.BufferSize = OutputSize;
BufferState.BufferPointer = OutputBuffer;
//
// Now encode the structure
//
MesIncrementalHandleReset(
PickleHandle,
NULL,
NULL,
NULL,
NULL,
MES_ENCODE
);
PPAC_IDL_CREDENTIAL_DATA_Encode(
PickleHandle,
&CredentialData
);
*EncodedData = OutputBuffer;
*DataSize = OutputSize;
OutputBuffer = NULL;
Cleanup:
if (OutputBuffer != NULL)
{
MIDL_user_free(OutputBuffer);
}
if (PickleHandle != NULL)
{
MesHandleFree(PickleHandle);
}
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: PAC_DecodeCredentialData
//
// Synopsis: NDR decodes the validation information
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
PAC_DecodeCredentialData(
IN PBYTE EncodedData,
IN ULONG DataSize,
OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY * CredentialData
)
{
NTSTATUS Status = STATUS_SUCCESS;
handle_t PickleHandle = 0;
PAC_BUFFER_STATE BufferState = {0};
ULONG EncodingStatus = 0;
DsysAssert(ROUND_UP_POINTER(EncodedData,8) == (PVOID) EncodedData);
EncodingStatus = MesDecodeIncrementalHandleCreate(
&BufferState,
PacReadFcn,
&PickleHandle
);
if (EncodingStatus != 0)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
BufferState.BufferSize = DataSize;
BufferState.BufferPointer = EncodedData;
__try {
PPAC_IDL_CREDENTIAL_DATA_Decode(
PickleHandle,
CredentialData
);
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
Cleanup:
if (PickleHandle != NULL)
{
MesHandleFree(PickleHandle);
}
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: PAC_EncodeTokenRestrictions
//
// Synopsis: NDR encodes the token restrictions
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
extern "C"
NTSTATUS
PAC_EncodeTokenRestrictions(
IN PKERB_TOKEN_RESTRICTIONS TokenRestrictions,
OUT PBYTE * EncodedData,
OUT PULONG DataSize
)
{
NTSTATUS Status = STATUS_SUCCESS;
handle_t PickleHandle = 0;
PAC_BUFFER_STATE BufferState = {0};
ULONG EncodingStatus = 0;
PUCHAR OutputBuffer = NULL;
ULONG OutputSize = 0;
EncodingStatus = MesEncodeIncrementalHandleCreate(
&BufferState,
PacAllocFcn,
PacWriteFcn,
&PickleHandle
);
if (EncodingStatus != 0)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
//
// Calculate the size of the required buffer
//
OutputSize = PKERB_TOKEN_RESTRICTIONS_AlignSize(
PickleHandle,
&TokenRestrictions
);
OutputBuffer = (PBYTE) MIDL_user_allocate(OutputSize);
if (OutputBuffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
BufferState.BufferSize = OutputSize;
BufferState.BufferPointer = OutputBuffer;
//
// Now encode the structure
//
MesIncrementalHandleReset(
PickleHandle,
NULL,
NULL,
NULL,
NULL,
MES_ENCODE
);
PKERB_TOKEN_RESTRICTIONS_Encode(
PickleHandle,
&TokenRestrictions
);
*EncodedData = OutputBuffer;
*DataSize = OutputSize;
OutputBuffer = NULL;
Cleanup:
if (OutputBuffer != NULL)
{
MIDL_user_free(OutputBuffer);
}
if (PickleHandle != NULL)
{
MesHandleFree(PickleHandle);
}
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: PAC_DecodeTokenRestrictions
//
// Synopsis: NDR decodes the token restrictions
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
extern "C"
NTSTATUS
PAC_DecodeTokenRestrictions(
IN PBYTE EncodedData,
IN ULONG DataSize,
OUT PKERB_TOKEN_RESTRICTIONS * TokenRestrictions
)
{
NTSTATUS Status = STATUS_SUCCESS;
handle_t PickleHandle = 0;
PAC_BUFFER_STATE BufferState = {0};
ULONG EncodingStatus = 0;
DsysAssert(ROUND_UP_POINTER(EncodedData,8) == (PVOID) EncodedData);
EncodingStatus = MesDecodeIncrementalHandleCreate(
&BufferState,
PacReadFcn,
&PickleHandle
);
if (EncodingStatus != 0)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
BufferState.BufferSize = DataSize;
BufferState.BufferPointer = EncodedData;
__try {
PKERB_TOKEN_RESTRICTIONS_Decode(
PickleHandle,
TokenRestrictions
);
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
Cleanup:
if (PickleHandle != NULL)
{
MesHandleFree(PickleHandle);
}
return(Status);
}
//+---------------------------------------------------------------------------
//
// Function: PAC_GetSize
//
// Synopsis: Determines the number of bytes required to marshal the
// given PAC.
//
// Arguments:
//
// History: 24-May-95 SuChang Created
//
// Notes:
//
//----------------------------------------------------------------------------
ULONG
PAC_GetSize( IN PACTYPE *pPac )
{
ULONG cbSize = 0;
if (pPac != NULL)
{
cbSize += sizeof( PACTYPE );
cbSize += (pPac->cBuffers - ANYSIZE_ARRAY) * sizeof(PAC_INFO_BUFFER);
cbSize = ROUND_UP_COUNT( cbSize, ALIGN_QUAD );
for (ULONG i = 0; i < pPac->cBuffers; i++ )
{
cbSize += ROUND_UP_COUNT(pPac->Buffers[i].cbBufferSize, ALIGN_QUAD);
}
}
return (cbSize);
}
//+---------------------------------------------------------------------------
//
// Function: PAC_Marshal
//
// Synopsis: Marshals the given PAC into the provided buffer.
//
// Arguments:
//
// History: 24-May-95 SuChang Created
//
// Notes: This assumes the PAC is the same form as created
// by PAC_Init. See header description of the PAC
// structure.
//
// Returns the number of bytes used or 0 if an error
// occurred.
//
//----------------------------------------------------------------------------
ULONG
PAC_Marshal( IN PACTYPE *pPac,
IN ULONG cbBuffer,
OUT PBYTE pBufferOut)
{
DsysAssert( pPac != NULL && pBufferOut != NULL );
ULONG PacLen = PAC_GetSize( pPac );
if (cbBuffer < PacLen)
{
return 0;
}
//
// Copy into pBufferOut and then change the pointers of each
// PAC_INFO_BUFFER to be offsets from pPac.
//
CopyMemory( pBufferOut, pPac, PacLen );
PPACTYPE pPacTemp = (PPACTYPE) pBufferOut;
for (ULONG i = 0; i < pPacTemp->cBuffers; i++ )
{
pPacTemp->Buffers[i].Offset = (ULONG) (pPacTemp->Buffers[i].Data -
(PBYTE)pPac);
}
return PacLen;
}
//+---------------------------------------------------------------------------
//
// Function: PAC_UnMarshal
//
// Synopsis: Does in place unmarshalling of the marshalled PAC.
//
// Arguments:
//
// History: 24-May-95 SuChang Created
//
// Notes: Does in place unmarshalling. No new memory is allocated.
//
// This assumes the PAC is the same form as created
// by PAC_Init. See header description of the PAC
// structure.
//
//----------------------------------------------------------------------------
ULONG
PAC_UnMarshal( IN PPACTYPE pPac,
IN ULONG cbSize )
{
ULONG i;
ULONG cbUnmarshalled = 0;
PBYTE pEnd = (PBYTE)pPac + cbSize;
PBYTE pBufferAddress;
DsysAssert( pPac != NULL );
//
// Do a validation loop. Make sure that the offsets are
// correct. We don't want to do this validation inside the modification
// loop because it wouldn't be nice to change the buffer if it weren't
// valid.
//
if ((pPac->cBuffers * sizeof(PAC_INFO_BUFFER) + sizeof(PACTYPE)) > cbSize)
{
return(0);
}
if (pPac->Version != PAC_VERSION)
{
return(0);
}
for (i = 0; i < pPac->cBuffers; i++)
{
pBufferAddress = (ULONG)pPac->Buffers[i].Offset + (PBYTE)pPac;
if ( (pBufferAddress >= pEnd ) || (pBufferAddress < (PBYTE) pPac) ||
(pBufferAddress + pPac->Buffers[i].cbBufferSize > pEnd))
{
//
// Invalid offset or length
//
return (0);
}
}
for (i = 0; i < pPac->cBuffers; i++ )
{
cbUnmarshalled += pPac->Buffers[i].cbBufferSize;
pPac->Buffers[i].Data = pPac->Buffers[i].Offset +
(PBYTE)pPac;
}
return (cbUnmarshalled);
}
//+---------------------------------------------------------------------------
//
// Function: PAC_ReMarshal
//
// Synopsis: Does in place re-marshalling of an un-marshalled PAC.
//
// Arguments:
//
// History: 24-May-95 SuChang Created
//
// Notes: Does in place re-marshalling. No new memory is allocated.
//
// This assumes the PAC is the same form as created
// by PAC_UnMarshal. See header description of the PAC
// structure.
//
//----------------------------------------------------------------------------
BOOLEAN
PAC_ReMarshal( IN PPACTYPE pPac,
IN ULONG cbSize )
{
ULONG Offset;
ULONG i;
//
// Do a validation loop. Make sure that the offsets are
// correct. We don't want to do this validation inside the modification
// loop because it wouldn't be nice to change the buffer if it weren't
// valid.
//
for (i = 0; i < pPac->cBuffers; i++ )
{
Offset = (ULONG) (pPac->Buffers[i].Data - (PBYTE) pPac);
if ( Offset >= cbSize )
{
//
// Invalid offset or length
//
return (FALSE);
}
pPac->Buffers[i].Offset = Offset;
}
return (TRUE);
}
VOID
PAC_PutString(
IN PVOID Base,
IN PUNICODE_STRING OutString,
IN PUNICODE_STRING InString,
IN PUCHAR *Where
)
/*++
Routine Description:
This routine copies the InString string to the memory pointed to by
the Where parameter, and fixes the OutString string to point to that
new copy.
Parameters:
OutString - A pointer to a destination NT string
InString - A pointer to an NT string to be copied
Where - A pointer to space to put the actual string for the
OutString. The pointer is adjusted to point to the first byte
following the copied string.
Return Values:
None.
--*/
{
DsysAssert( OutString != NULL );
DsysAssert( InString != NULL );
DsysAssert( Where != NULL && *Where != NULL);
DsysAssert( *Where == ROUND_UP_POINTER( *Where, sizeof(WCHAR) ) );
if ( InString->Length > 0 ) {
OutString->Buffer = (PWCH) *Where;
OutString->MaximumLength = (USHORT)(InString->Length + sizeof(WCHAR));
RtlCopyUnicodeString( OutString, InString );
//
// Rest the pointer to be an offset.
//
OutString->Buffer = (PWCH) (*Where - (PUCHAR) Base);
*Where += InString->Length;
// *((WCHAR *)(*Where)) = L'\0';
*(*Where) = '\0';
*(*Where + 1) = '\0';
*Where += 2;
} else {
RtlInitUnicodeString(OutString, NULL);
}
return;
}
//+-------------------------------------------------------------------------
//
// Function: PAC_MarshallValidationInfo
//
// Synopsis: marshals a NETLOGON_VALIDATION_SAM_INFO2
//
// Effects: allocates memory with MIDL_user_allocate
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
PAC_MarshallValidationInfo
(
IN PSAMPR_USER_ALL_INFORMATION UserAll,
IN PSAMPR_GET_GROUPS_BUFFER GroupsBuffer,
IN PSID_AND_ATTRIBUTES_LIST ExtraGroups,
IN PSID LogonDomainId,
IN PUNICODE_STRING LogonDomainName,
IN PUNICODE_STRING LogonServer,
IN BOOLEAN IncludeUserParms,
IN BOOLEAN NetworkProfile,
OUT PBYTE * ValidationInfo,
OUT PULONG ValidationInfoSize
)
{
NETLOGON_VALIDATION_SAM_INFO3 ValidationSam = {0};
PNETLOGON_SID_AND_ATTRIBUTES MarshalledSids = NULL;
SID ServerSid = {SID_REVISION, 1, SECURITY_NT_AUTHORITY, SECURITY_SERVER_LOGON_RID };
NTSTATUS Status = STATUS_SUCCESS;
BYTE SidBuffer[sizeof(SID) + SID_MAX_SUB_AUTHORITIES * sizeof(ULONG)];
PSID BuiltinSid = SidBuffer;
PUCHAR Where;
ULONG ExtraGroupSize = 0;
ULONG ExtraGroupCount = 0;
ULONG Index;
//
// Allocate a return buffer for validation information.
// (Return less information for a network logon)
// (Return UserParameters for a MNS logon)
//
//
// First calculate the space needed for the extra groups.
//
if (ARGUMENT_PRESENT(ExtraGroups))
{
ExtraGroupCount += ExtraGroups->Count;
}
//
// Add the enterprise server's sids
//
if ((UserAll->UserAccountControl & USER_SERVER_TRUST_ACCOUNT) != 0)
{
ExtraGroupCount += 1;
}
//
// Set the UF_SMARTCARD_REQUIRED flag
//
if ((UserAll->UserAccountControl & USER_SMARTCARD_REQUIRED) != 0)
{
ValidationSam.UserFlags |= UF_SMARTCARD_REQUIRED;
}
//
// Copy the scalars to the validation buffer.
//
ValidationSam.LogonTime = UserAll->LastLogon;
//
// BUG 455821: need logoff time & kickoff time
//
#ifdef notdef
NEW_TO_OLD_LARGE_INTEGER( LogoffTime, ValidationSam.LogoffTime );
NEW_TO_OLD_LARGE_INTEGER( KickoffTime, ValidationSam.KickOffTime );
#else
ValidationSam.LogoffTime.LowPart = 0xffffffff;
ValidationSam.LogoffTime.HighPart = 0x7fffffff;
ValidationSam.KickOffTime.LowPart = 0xffffffff;
ValidationSam.KickOffTime.HighPart = 0x7fffffff;
#endif
ValidationSam.PasswordLastSet = UserAll->PasswordLastSet;
ValidationSam.PasswordCanChange = UserAll->PasswordCanChange;
ValidationSam.PasswordMustChange = UserAll->PasswordMustChange;
ValidationSam.LogonCount = UserAll->LogonCount;
ValidationSam.BadPasswordCount = UserAll->BadPasswordCount;
ValidationSam.UserId = UserAll->UserId;
ValidationSam.PrimaryGroupId = UserAll->PrimaryGroupId;
if (ARGUMENT_PRESENT( GroupsBuffer) )
{
ValidationSam.GroupCount = GroupsBuffer->MembershipCount;
ValidationSam.GroupIds = GroupsBuffer->Groups;
}
else
{
ValidationSam.GroupCount = 0;
ValidationSam.GroupIds = NULL;
}
ValidationSam.ExpansionRoom[SAMINFO_USER_ACCOUNT_CONTROL] = UserAll->UserAccountControl;
//
// If the client asked for extra information, return that
// we support it
//
ValidationSam.UserFlags |= LOGON_EXTRA_SIDS;
//
// Copy ULONG aligned data to the validation buffer.
//
if (ExtraGroupCount != 0)
{
ValidationSam.SidCount = ExtraGroupCount;
MarshalledSids = (PNETLOGON_SID_AND_ATTRIBUTES) MIDL_user_allocate(ExtraGroupCount * sizeof(NETLOGON_SID_AND_ATTRIBUTES));
if (MarshalledSids == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
ValidationSam.ExtraSids = MarshalledSids;
Index = 0;
if (ARGUMENT_PRESENT(ExtraGroups))
{
//
// Now marshall each sid into the buffer
//
DsysAssert(sizeof(SID_AND_ATTRIBUTES) == sizeof(NETLOGON_SID_AND_ATTRIBUTES));
RtlCopyMemory(
&MarshalledSids[Index],
ExtraGroups->SidAndAttributes,
ExtraGroups->Count * sizeof(SID_AND_ATTRIBUTES)
);
Index += ExtraGroups->Count;
}
//
// Add in special sids for domain controllers
//
if ((UserAll->UserAccountControl & USER_SERVER_TRUST_ACCOUNT) != 0)
{
//
// Add in the constant server logon sid
//
MarshalledSids[Index].Attributes = SE_GROUP_MANDATORY |
SE_GROUP_ENABLED |
SE_GROUP_ENABLED_BY_DEFAULT;
MarshalledSids[Index].Sid = &ServerSid;
Index++;
}
}
ValidationSam.LogonDomainId = LogonDomainId;
//
// Copy WCHAR aligned data to the validation buffer.
// (Return less information for a network logon)
//
if ( ! NetworkProfile ) {
ValidationSam.EffectiveName = *(PUNICODE_STRING)&UserAll->UserName;
ValidationSam.FullName = *(PUNICODE_STRING)&UserAll->FullName;
ValidationSam.LogonScript = *(PUNICODE_STRING)&UserAll->ScriptPath;
ValidationSam.ProfilePath = *(PUNICODE_STRING)&UserAll->ProfilePath;
ValidationSam.HomeDirectory = *(PUNICODE_STRING)&UserAll->HomeDirectory;
ValidationSam.HomeDirectoryDrive = *(PUNICODE_STRING)&UserAll->HomeDirectoryDrive;
}
ValidationSam.LogonServer = *LogonServer;
ValidationSam.LogonDomainName = *LogonDomainName;
//
// Kludge: Pass back UserParameters in HomeDirectoryDrive since we
// can't change the NETLOGON_VALIDATION_SAM_INFO2 structure between
// releases NT 1.0 and NT 1.0A. HomeDirectoryDrive was NULL for release 1.0A
// so we'll use that field.
//
if ( IncludeUserParms && NetworkProfile ) {
ValidationSam.HomeDirectoryDrive = *(PUNICODE_STRING)&UserAll->Parameters;
}
Status = PAC_EncodeValidationInformation(
&ValidationSam,
ValidationInfo,
ValidationInfoSize
);
Cleanup:
if (MarshalledSids != NULL)
{
MIDL_user_free(MarshalledSids);
}
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: PAC_MarshallValidationInfoWithGroups
//
// Synopsis: marshals a NETLOGON_VALIDATION_SAM_INFO2
//
// Effects: allocates memory with MIDL_user_allocate
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
PAC_ReMarshallValidationInfoWithGroups(
IN PNETLOGON_VALIDATION_SAM_INFO3 OldValidationInfo,
IN PSAMPR_PSID_ARRAY ResourceGroups,
OUT PBYTE * ValidationInfo,
OUT PULONG ValidationInfoSize
)
{
NETLOGON_VALIDATION_SAM_INFO3 ValidationSam = {0};
PNETLOGON_SID_AND_ATTRIBUTES ExtraSids = NULL;
ULONG ExtraSidCount = 0;
NTSTATUS Status = STATUS_SUCCESS;
ULONG Index, Index2;
//
// Copy the original validation information
//
ValidationSam = *OldValidationInfo;
ValidationSam.UserFlags &= ~LOGON_RESOURCE_GROUPS;
//
// Clear any old resource groups
//
ValidationSam.ResourceGroupDomainSid = NULL;
ValidationSam.ResourceGroupIds = NULL;
ValidationSam.ResourceGroupCount = 0;
//
// Set the flag indicating resource groups may be present
//
if (ResourceGroups->Count != 0)
{
ExtraSidCount = ValidationSam.SidCount + ResourceGroups->Count;
ValidationSam.UserFlags |= LOGON_EXTRA_SIDS;
ExtraSids = (PNETLOGON_SID_AND_ATTRIBUTES) MIDL_user_allocate(sizeof(NETLOGON_SID_AND_ATTRIBUTES) * ExtraSidCount);
if (ExtraSids == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
//
// Add in all the extra sids that are not resource groups
//
Index2 = 0;
for (Index = 0; Index < OldValidationInfo->SidCount; Index++ )
{
if ((OldValidationInfo->ExtraSids[Index].Attributes & SE_GROUP_RESOURCE) == 0)
{
ExtraSids[Index2] = OldValidationInfo->ExtraSids[Index];
Index2++;
}
}
//
// Copy all the resource group SIDs
//
for (Index = 0; Index < ResourceGroups->Count ; Index++ )
{
ExtraSids[Index2].Sid = ResourceGroups->Sids[Index].SidPointer;
ExtraSids[Index2].Attributes = SE_GROUP_MANDATORY |
SE_GROUP_ENABLED |
SE_GROUP_ENABLED_BY_DEFAULT |
SE_GROUP_RESOURCE;
Index2++;
}
ValidationSam.ExtraSids = ExtraSids;
ValidationSam.SidCount = Index2;
}
Status = PAC_EncodeValidationInformation(
&ValidationSam,
ValidationInfo,
ValidationInfoSize
);
Cleanup:
if (ExtraSids != NULL)
{
MIDL_user_free(ExtraSids);
}
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: PAC_UnmarshallValidationInfo
//
// Synopsis: un marshals a NETLOGON_VALIDATION_SAM_INFO3
//
// Effects: resets offset to be pointers
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
PAC_UnmarshallValidationInfo(
OUT PNETLOGON_VALIDATION_SAM_INFO3 * ValidationInfo,
IN PBYTE MarshalledInfo,
IN ULONG ValidationInfoSize
)
{
NTSTATUS Status;
*ValidationInfo = NULL;
Status = PAC_DecodeValidationInformation(
MarshalledInfo,
ValidationInfoSize,
ValidationInfo
);
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: PAC_BuildCredentials
//
// Synopsis: Builds the buffer containing supplemental credentials for
// the pac.
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
PAC_BuildCredentials(
IN PSAMPR_USER_ALL_INFORMATION UserAll,
OUT PBYTE * Credentials,
OUT PULONG CredentialSize
)
{
PSECPKG_SUPPLEMENTAL_CRED_ARRAY PacCreds = NULL;
PMSV1_0_SUPPLEMENTAL_CREDENTIAL MsvCredentials;
PUCHAR Where;
ULONG CredSize;
NTSTATUS Status = STATUS_SUCCESS;
*Credentials = NULL;
//
// The size of the credentials is the overhead for the structures
// plus the name "msv1_0"
//
CredSize = sizeof(SECPKG_SUPPLEMENTAL_CRED_ARRAY) +
sizeof(SECPKG_SUPPLEMENTAL_CRED) +
sizeof(MSV1_0_SUPPLEMENTAL_CREDENTIAL) +
NTLMSP_NAME_SIZE;
PacCreds = (PSECPKG_SUPPLEMENTAL_CRED_ARRAY) MIDL_user_allocate(CredSize);
if (PacCreds == NULL)
{
return(STATUS_INSUFFICIENT_RESOURCES);
}
//
// Build the PAC credential
//
Where = (PBYTE) PacCreds;
PacCreds->CredentialCount = 1;
Where += sizeof(SECPKG_SUPPLEMENTAL_CRED_ARRAY) + sizeof(SECPKG_SUPPLEMENTAL_CRED) - (ANYSIZE_ARRAY * sizeof(SECPKG_SUPPLEMENTAL_CRED));
//
// Build the secpkg creds
//
RtlCopyMemory(
Where,
NTLMSP_NAME,
NTLMSP_NAME_SIZE
);
PacCreds->Credentials[0].PackageName.Buffer = (LPWSTR) Where;
Where += ROUND_UP_COUNT(NTLMSP_NAME_SIZE,sizeof(ULONG));
PacCreds->Credentials[0].PackageName.Length = (USHORT) NTLMSP_NAME_SIZE;
PacCreds->Credentials[0].PackageName.MaximumLength = (USHORT) NTLMSP_NAME_SIZE;
PacCreds->Credentials[0].CredentialSize = sizeof(MSV1_0_SUPPLEMENTAL_CREDENTIAL);
PacCreds->Credentials[0].Credentials = Where;
MsvCredentials = (PMSV1_0_SUPPLEMENTAL_CREDENTIAL) Where;
Where += sizeof(MSV1_0_SUPPLEMENTAL_CREDENTIAL);
RtlZeroMemory(
MsvCredentials,
sizeof(MSV1_0_SUPPLEMENTAL_CREDENTIAL)
);
MsvCredentials->Version = MSV1_0_CRED_VERSION;
if (UserAll->NtPasswordPresent)
{
DsysAssert(UserAll->NtOwfPassword.Length == MSV1_0_OWF_PASSWORD_LENGTH);
MsvCredentials->Flags |= MSV1_0_CRED_NT_PRESENT;
RtlCopyMemory(
MsvCredentials->NtPassword,
UserAll->NtOwfPassword.Buffer,
UserAll->NtOwfPassword.Length
);
}
if (UserAll->LmPasswordPresent)
{
DsysAssert(UserAll->LmOwfPassword.Length == MSV1_0_OWF_PASSWORD_LENGTH);
MsvCredentials->Flags |= MSV1_0_CRED_LM_PRESENT;
RtlCopyMemory(
MsvCredentials->LmPassword,
UserAll->LmOwfPassword.Buffer,
UserAll->LmOwfPassword.Length
);
}
Status = PAC_EncodeCredentialData(
PacCreds,
Credentials,
CredentialSize
);
if (PacCreds != NULL)
{
MIDL_user_free(PacCreds);
}
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: PAC_UnmarshallCredentials
//
// Synopsis: un marshals a SECPKG_SUPPLEMENTAL_CRED_ARRAY
//
// Effects: resets offset to be pointers
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
PAC_UnmarshallCredentials(
OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY * Credentials,
IN PBYTE MarshalledInfo,
OUT ULONG CredentialInfoSize
)
{
NTSTATUS Status;
*Credentials = NULL;
Status = PAC_DecodeCredentialData(
MarshalledInfo,
CredentialInfoSize,
Credentials
);
return(Status);
}
//+---------------------------------------------------------------------------
//
// Function: PAC_Init
//
// Synopsis: Creates a new PAC with the provided info
//
// Arguments: UserAll - UserAllInformation for the user
// GroupsBuffer - The buffer returned from a call to
// SamrGetGroupsForUser, contains all global groups
// LogonDomainId - Domain SID for the domain of this DC
// SignatureSize - Space to reserve for signatures. If zero,
// no signatures are added.
// ppPac - Receives a pac, allocated with MIDL_user_allocate
//
//
// History: 24-May-95 SuChang Created
//
// Notes:
//
//----------------------------------------------------------------------------
NTSTATUS
PAC_Init(
IN PSAMPR_USER_ALL_INFORMATION UserAll,
IN OPTIONAL PSAMPR_GET_GROUPS_BUFFER GroupsBuffer,
IN OPTIONAL PSID_AND_ATTRIBUTES_LIST ExtraGroups,
IN PSID LogonDomainId,
IN PUNICODE_STRING LogonDomainName,
IN PUNICODE_STRING LogonServer,
IN ULONG SignatureSize,
IN ULONG AdditionalDataCount,
IN PPAC_INFO_BUFFER * AdditionalData,
OUT PPACTYPE * ppPac
)
{
ULONG cbBytes = 0;
ULONG cPacBuffers = 0;
PPACTYPE pNewPac = NULL;
ULONG iBuffer = 0;
ULONG cbProxyData = 0;
PBYTE ValidationInfo = NULL;
ULONG ValidationInfoSize;
NTSTATUS Status;
PBYTE pDataStore;
ULONG Index;
*ppPac = NULL;
//
// We need to determine the number of bytes required to store the provided
// information. For each type of info, determine the required number of
// bytes to store that type of info. Then allocate a contiguous buffer
// for the PAC and store all the info into the buffer.
//
//
// First we will create the validation info buffer. We can copy it into
// the PAC later.
//
Status = PAC_MarshallValidationInfo(
UserAll,
GroupsBuffer,
ExtraGroups,
LogonDomainId,
LogonDomainName,
LogonServer,
FALSE, // don't include user parms
FALSE, // not a network logon
&ValidationInfo,
&ValidationInfoSize
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
//
// We need a PAC_INFO_BUFFER to store the validation info.
//
cbBytes += ROUND_UP_COUNT(ValidationInfoSize, ALIGN_QUAD);
cPacBuffers += 1;
for (Index = 0; Index < AdditionalDataCount ; Index++ )
{
cbBytes += ROUND_UP_COUNT(AdditionalData[Index]->cbBufferSize,ALIGN_QUAD);
cPacBuffers++;
}
//
// If signature size is non-zero, add in space for signatures.
//
if (SignatureSize != 0)
{
cPacBuffers += 2;
cbBytes += 2 * (ROUND_UP_COUNT(PAC_SIGNATURE_SIZE(SignatureSize), ALIGN_QUAD));
}
//
// We need space for the PAC structure itself. Because the PAC_INFO_BUFFER
// is defined to be an array, a sizeof(PAC) already includes the
// size of ANYSIZE_ARRAY PAC_INFO_BUFFERs so we can subtract some bytes off.
//
cbBytes += sizeof(PACTYPE) +
(cPacBuffers - ANYSIZE_ARRAY) * sizeof(PAC_INFO_BUFFER);
cbBytes = ROUND_UP_COUNT( cbBytes, ALIGN_QUAD );
pNewPac = (PPACTYPE) MIDL_user_allocate( cbBytes );
if (pNewPac == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
ZeroMemory( pNewPac, cbBytes );
pNewPac->Version = PAC_VERSION;
pNewPac->cBuffers = cPacBuffers;
//
// Store data in such a way that the variable length data of
// PAC_INFO_BUFFER are at the end of all the PAC info buffers.
//
pDataStore = (PBYTE)&(pNewPac->Buffers[pNewPac->cBuffers]);
pDataStore = (PBYTE) ROUND_UP_POINTER( pDataStore, ALIGN_QUAD );
//
// Save the PAC identity ...
//
pNewPac->Buffers[iBuffer].ulType = PAC_LOGON_INFO;
pNewPac->Buffers[iBuffer].cbBufferSize = ValidationInfoSize;
pNewPac->Buffers[iBuffer].Data = pDataStore;
CopyMemory(
pDataStore,
ValidationInfo,
ValidationInfoSize
);
pDataStore += pNewPac->Buffers[iBuffer].cbBufferSize;
pDataStore = (PBYTE) ROUND_UP_POINTER( pDataStore, ALIGN_QUAD );
iBuffer ++;
//
// Store the additional data
//
for (Index = 0; Index < AdditionalDataCount ; Index++ )
{
pNewPac->Buffers[iBuffer].ulType = AdditionalData[Index]->ulType;
pNewPac->Buffers[iBuffer].cbBufferSize = AdditionalData[Index]->cbBufferSize;
pNewPac->Buffers[iBuffer].Data = pDataStore;
CopyMemory(
pDataStore,
AdditionalData[Index]->Data,
AdditionalData[Index]->cbBufferSize
);
pDataStore += pNewPac->Buffers[iBuffer].cbBufferSize;
pDataStore = (PBYTE) ROUND_UP_POINTER( pDataStore, ALIGN_QUAD );
iBuffer ++;
}
//
// Store the signatures
//
if (SignatureSize != 0)
{
pNewPac->Buffers[iBuffer].ulType = PAC_SERVER_CHECKSUM;
pNewPac->Buffers[iBuffer].cbBufferSize = PAC_SIGNATURE_SIZE(SignatureSize);
pNewPac->Buffers[iBuffer].Data = pDataStore;
pDataStore += ROUND_UP_COUNT(PAC_SIGNATURE_SIZE(SignatureSize),ALIGN_QUAD);
iBuffer ++;
pNewPac->Buffers[iBuffer].ulType = PAC_PRIVSVR_CHECKSUM;
pNewPac->Buffers[iBuffer].cbBufferSize = PAC_SIGNATURE_SIZE(SignatureSize);
pNewPac->Buffers[iBuffer].Data = pDataStore;
pDataStore += ROUND_UP_COUNT(PAC_SIGNATURE_SIZE(SignatureSize), ALIGN_QUAD);
iBuffer ++;
}
*ppPac = pNewPac;
pNewPac = NULL;
Cleanup:
if (ValidationInfo != NULL)
{
MIDL_user_free(ValidationInfo);
}
if (pNewPac != NULL)
{
MIDL_user_free(pNewPac);
}
return(Status);
}
//+---------------------------------------------------------------------------
//
// Function: PAC_InitAndUpdateGroups
//
// Synopsis: Creates a new PAC from old validation info and a list of
// resource groupss.
//
// Arguments: OldValidationInfo - Old info from a previous PAC
// ResourceGroups - Resource groups in this domain
// OldPac - OldPac to copy data from
// ppPac - Receives a pac, allocated with MIDL_user_allocate
//
//
// History: 24-May-95 SuChang Created
//
// Notes:
//
//----------------------------------------------------------------------------
NTSTATUS
PAC_InitAndUpdateGroups(
IN PNETLOGON_VALIDATION_SAM_INFO3 OldValidationInfo,
IN PSAMPR_PSID_ARRAY ResourceGroups,
IN PPACTYPE OldPac,
OUT PPACTYPE * ppPac
)
{
ULONG cbBytes = 0;
ULONG cPacBuffers = 0;
PPACTYPE pNewPac = NULL;
ULONG iBuffer = 0;
ULONG cbProxyData = 0;
PBYTE ValidationInfo = NULL;
ULONG ValidationInfoSize;
NTSTATUS Status;
PBYTE pDataStore;
ULONG Index;
*ppPac = NULL;
//
// We need to determine the number of bytes required to store the provided
// information. For each type of info, determine the required number of
// bytes to store that type of info. Then allocate a contiguous buffer
// for the PAC and store all the info into the buffer.
//
//
// First we will create the validation info buffer. We can copy it into
// the PAC later.
//
Status = PAC_ReMarshallValidationInfoWithGroups(
OldValidationInfo,
ResourceGroups,
&ValidationInfo,
&ValidationInfoSize
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
//
// We need a PAC_INFO_BUFFER to store the PAC_IDENTITY which
// contain the principal RID and the principal's domain GUID.
//
cbBytes += ROUND_UP_COUNT(ValidationInfoSize, ALIGN_QUAD);
cPacBuffers += 1;
for (Index = 0; Index < OldPac->cBuffers ; Index++ )
{
if (OldPac->Buffers[Index].ulType != PAC_LOGON_INFO)
{
cbBytes += ROUND_UP_COUNT(OldPac->Buffers[Index].cbBufferSize,ALIGN_QUAD);
cPacBuffers++;
}
}
//
// We need space for the PAC structure itself. Because the PAC_INFO_BUFFER
// is defined to be an array, a sizeof(PAC) already includes the
// size of ANYSIZE_ARRAY PAC_INFO_BUFFERs so we can subtract some bytes off.
//
cbBytes += sizeof(PACTYPE) +
(cPacBuffers - ANYSIZE_ARRAY) * sizeof(PAC_INFO_BUFFER);
cbBytes = ROUND_UP_COUNT( cbBytes, ALIGN_QUAD );
pNewPac = (PPACTYPE) MIDL_user_allocate( cbBytes );
if (pNewPac == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
ZeroMemory( pNewPac, cbBytes );
pNewPac->cBuffers = cPacBuffers;
//
// Store data in such a way that the variable length data of
// PAC_INFO_BUFFER are at the end of all the PAC info buffers.
//
pDataStore = (PBYTE)&(pNewPac->Buffers[pNewPac->cBuffers]);
pDataStore = (PBYTE) ROUND_UP_POINTER( pDataStore, ALIGN_QUAD );
//
// Save the PAC identity ...
//
pNewPac->Buffers[iBuffer].ulType = PAC_LOGON_INFO;
pNewPac->Buffers[iBuffer].cbBufferSize = ValidationInfoSize;
pNewPac->Buffers[iBuffer].Data = pDataStore;
CopyMemory(
pDataStore,
ValidationInfo,
ValidationInfoSize
);
pDataStore += pNewPac->Buffers[iBuffer].cbBufferSize;
pDataStore = (PBYTE) ROUND_UP_POINTER( pDataStore, ALIGN_QUAD );
iBuffer ++;
//
// Store the additional data
//
for (Index = 0; Index < OldPac->cBuffers ; Index++ )
{
if (OldPac->Buffers[Index].ulType != PAC_LOGON_INFO)
{
pNewPac->Buffers[iBuffer].ulType = OldPac->Buffers[Index].ulType;
pNewPac->Buffers[iBuffer].cbBufferSize = OldPac->Buffers[Index].cbBufferSize;
pNewPac->Buffers[iBuffer].Data = pDataStore;
CopyMemory(
pDataStore,
OldPac->Buffers[Index].Data,
OldPac->Buffers[Index].cbBufferSize
);
pDataStore += pNewPac->Buffers[iBuffer].cbBufferSize;
pDataStore = (PBYTE) ROUND_UP_POINTER( pDataStore, ALIGN_QUAD );
iBuffer ++;
}
}
*ppPac = pNewPac;
pNewPac = NULL;
Cleanup:
if (ValidationInfo != NULL)
{
MIDL_user_free(ValidationInfo);
}
if (pNewPac != NULL)
{
MIDL_user_free(pNewPac);
}
return(Status);
}
//+---------------------------------------------------------------------------
//
// Function: PAC_Find
//
// Synopsis: Finds a type of PAC info buffer in the given PAC.
// If pElem is NULL, the first buffer found matching the
// specified type is returned. Otherwise, the next buffer
// after pElem found matching that type is returned.
//
// Arguments:
//
// History: 01-June-95 SuChang Created
//
// Notes:
//
//----------------------------------------------------------------------------
PPAC_INFO_BUFFER
PAC_Find( IN PPACTYPE pPac,
IN ULONG ulType,
PPAC_INFO_BUFFER pElem)
{
PAC_INFO_BUFFER *pTemp = NULL, *pEnd;
if (pPac)
{
pEnd = &(pPac->Buffers[pPac->cBuffers]);
if (pElem)
{
pTemp = pElem + 1;
}
else
{
pTemp = &(pPac->Buffers[0]);
}
while ( pTemp < pEnd && pTemp->ulType != ulType )
{
pTemp++;
}
if (pTemp >= pEnd)
{
// element not found in the PAC
pTemp = NULL;
}
}
return (pTemp);
}