//+----------------------------------------------------------------------- // // 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 #pragma hdrstop #include #include #include #include extern "C" { #include #include #include #include #include } //+------------------------------------------------------------------------- // // 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); }