/*++ Copyright (c) 1997 Microsoft Corporation Module Name: dstrust.c Abstract: Implementation of a variety of TrustedDomain features that interface soley with the DS Author: Mac McLain (MacM) Jan 17, 1997 Environment: User Mode Revision History: --*/ #include #include #include #include #include // // Local function prototypes // NTSTATUS LsapDsUnmarshalAuthInfoHalf( IN LSAPR_HANDLE ObjectHandle, IN BOOLEAN ReturnOnlyFirstAuthInfo, IN BOOLEAN AllowEmptyPreviousInfo, IN PBYTE Buffer, IN ULONG Length, IN OUT PLSAPR_TRUST_DOMAIN_AUTH_INFO_HALF AuthInfo ); VOID LsapDsFreeUnmarshaledAuthInfo( IN ULONG Items, IN PLSAPR_AUTH_INFORMATION AuthInfo ); NTSTATUS LsapDsFindAuthTypeInAuthInfo( IN ULONG AuthType, IN PLSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION AuthInfo, IN BOOLEAN Incoming, IN BOOLEAN AddIfNotFound, OUT BOOLEAN *Added, OUT PULONG AuthTypeIndex ); // // Macros to help with copying over the domain information // #define LSAPDS_SET_AUTH_INFO( dest, time, type, length, data ) \ RtlCopyMemory( &(dest)->LastUpdateTime, time, sizeof( LARGE_INTEGER ) ); \ (dest)->AuthType = type; \ (dest)->AuthInfoLength = length; \ (dest)->AuthInfo = data; NTSTATUS LsapDsGetListOfSystemContainerItems( IN ULONG ClassId, OUT PULONG Items, OUT PDSNAME **DsNames ) /*++ Routine Description: This function obtain a list of DsNames of all indicated class types in the system container in the Ds NOTE: This function uses a single operation DS transaction only Arguments: ClassId - Class types to find Items - Where the number of items is returned DsNames - Where the list of DsNames is returned Returns: STATUS_SUCCESS - Success --*/ { NTSTATUS Status = STATUS_SUCCESS; PDSNAME CategoryName = NULL; ATTRVAL AttrVal; ATTR Attr = { ATT_OBJECT_CATEGORY, { 1, &AttrVal } }; LsapEnterFunc( "LsapDsGetListOfSystemContainerItems" ); *Items = 0; // // We need to map object class to object category, because apparently object_class is no // longer indexed. // switch ( ClassId ) { case CLASS_TRUSTED_DOMAIN: CategoryName = LsaDsStateInfo.SystemContainerItems.TrustedDomainObject; break; case CLASS_SECRET: CategoryName = LsaDsStateInfo.SystemContainerItems.SecretObject; break; default: Status = STATUS_NONE_MAPPED; break; } if ( NT_SUCCESS( Status ) ) { LSAP_DS_SET_DS_ATTRIBUTE_DSNAME( &Attr, CategoryName ); Status = LsapDsSearchNonUnique( LSAPDS_OP_NO_TRANS, LsaDsStateInfo.DsSystemContainer, &Attr, 1, DsNames, Items ); } LsapExitFunc( "LsapDsGetListOfSystemContainerItems", Status ); return( Status ); } NTSTATUS LsapDsEnumerateTrustedDomainsEx( PLSA_ENUMERATION_HANDLE EnumerationContext, TRUSTED_INFORMATION_CLASS InformationClass, PLSAPR_TRUSTED_DOMAIN_INFO *TrustedDomainInformation, ULONG PreferedMaximumLength, PULONG CountReturned, IN ULONG EnumerationFlags ) /*++ Routine Description: This function enumerate all of the trusted domains in a Ds, returning the requested info level of information. Arguments: EnumerationContext - Context of new or ongoing enumeration InformationClass - Level of information being requested Must be TrustedDomainInformationEx or TrustedDomainInformatinBasic TrustedDomainInformation - Where the enumerated information is returned PreferedMaximumLength - Rough upper size limit of buffer to return CountReturned - Where the count of the number of items in the list is returned EnumerationFlags -- Controls how the enumeration is done Returns: STATUS_SUCCESS - Success STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed STATUS_NO_MORE_ENTRIES - All of the appropriate entries have been enumerated --*/ { NTSTATUS Status = STATUS_SUCCESS; PDSNAME *DsNames = NULL; ULONG Items = 0, BuffSize, Read, Index = 0, Skip, i = 0; PLSAPR_TRUSTED_DOMAIN_INFO TDInfo = NULL; LSAPR_TRUSTED_DOMAIN_INFORMATION_EX ExInfo; PBYTE Buffer = NULL; ULONG Size = 0; ULONG Direction = 0, Type = 0, Attributes = 0; LsapEnterFunc( "LsapDsEnumerateTrustedDomainsEx" ); ASSERT( InformationClass == TrustedDomainInformationEx || InformationClass == TrustedDomainInformationBasic || InformationClass == TrustedDomainFullInformation || InformationClass == TrustedDomainFullInformation2Internal ); switch ( InformationClass ) { case TrustedDomainInformationBasic: Size = sizeof( LSAPR_TRUSTED_DOMAIN_INFORMATION_BASIC ); break; case TrustedDomainInformationEx: Size = sizeof( LSAPR_TRUSTED_DOMAIN_INFORMATION_EX ); break; case TrustedDomainFullInformation: Size = sizeof( LSAPR_TRUSTED_DOMAIN_FULL_INFORMATION ); break; case TrustedDomainFullInformation2Internal: Size = sizeof( LSAPR_TRUSTED_DOMAIN_FULL_INFORMATION2 ); break; default: return( STATUS_INVALID_PARAMETER ); } Skip = (ULONG)*EnumerationContext; LsapDbAcquireLockEx( TrustedDomainObject, LSAP_DB_READ_ONLY_TRANSACTION ); // // First, enumerate all of the trusted domains // Status = LsapDsGetListOfSystemContainerItems( CLASS_TRUSTED_DOMAIN, &Items, &DsNames ); if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) { Status = STATUS_NO_MORE_ENTRIES; *TrustedDomainInformation = NULL; *CountReturned = 0; } if ( NT_SUCCESS( Status ) ) { // // See if we've already enumerated all of our items... // if ( Items <= (ULONG)*EnumerationContext) { Status = STATUS_NO_MORE_ENTRIES; *TrustedDomainInformation = NULL; *CountReturned = 0; } else { TDInfo = MIDL_user_allocate( ( Items - Skip ) * Size ); if( TDInfo == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { Buffer = ( PBYTE )TDInfo; } } } // // Now, we'll start getting the information from each of the objects // if ( NT_SUCCESS( Status ) ) { BuffSize = 0; Index = 0; i = 0; while ( TRUE ) { Status = LsapDsGetTrustedDomainInfoEx( DsNames[ Index + Skip ], LSAPDS_READ_NO_LOCK, InformationClass, ( PLSAPR_TRUSTED_DOMAIN_INFO )Buffer, &Read ); // // See if we need to do any masking... // if ( NT_SUCCESS( Status ) && EnumerationFlags != LSAP_DB_ENUMERATE_NO_OPTIONS ) { if ( FLAG_ON( EnumerationFlags, LSAP_DB_ENUMERATE_AS_NT4 ) ) { if ( InformationClass == TrustedDomainInformationEx || InformationClass == TrustedDomainFullInformation ) { Direction = ( ( PLSAPR_TRUSTED_DOMAIN_INFORMATION_EX )Buffer )->TrustDirection; Type = ( ( PLSAPR_TRUSTED_DOMAIN_INFORMATION_EX )Buffer )->TrustType; Attributes = ( ( PLSAPR_TRUSTED_DOMAIN_INFORMATION_EX )Buffer )->TrustAttributes; } else { // // We'll re-read the full info, and if it doesn't match our criteria, // we'll ignore it. Our critera state that the it must be outgoing, // uplevel or downlevel, and not have the UPLEVEL only attribute set // Status = LsapDsGetTrustedDomainInfoEx( DsNames[ Index + Skip ], LSAPDS_READ_NO_LOCK, TrustedDomainInformationEx, (PLSAPR_TRUSTED_DOMAIN_INFO)&ExInfo, NULL ); if ( Status == STATUS_SUCCESS ) { Direction = ExInfo.TrustDirection; Type = ExInfo.TrustType; Attributes = ExInfo.TrustAttributes; _fgu__LSAPR_TRUSTED_DOMAIN_INFO( (PLSAPR_TRUSTED_DOMAIN_INFO)&ExInfo, TrustedDomainInformationEx ); } } if ( NT_SUCCESS( Status ) ) { if ( !FLAG_ON( Direction, TRUST_DIRECTION_OUTBOUND ) || !( Type == TRUST_TYPE_DOWNLEVEL || Type == TRUST_TYPE_UPLEVEL ) || FLAG_ON( Attributes, TRUST_ATTRIBUTE_UPLEVEL_ONLY ) ) { // // This one doesn't match, so we'll basically drop it on the // floor // _fgu__LSAPR_TRUSTED_DOMAIN_INFO( (PLSAPR_TRUSTED_DOMAIN_INFO)Buffer, InformationClass ); LsapDsDebugOut(( DEB_TRACE, "Trust object %ws doesn't match: D:0x%lx T:0x%lx A:0x%lx\n", LsapDsNameFromDsName( DsNames[ Index + Skip ] ), Direction, Type, Attributes )); Status = STATUS_OBJECT_NAME_NOT_FOUND; } } } } if ( NT_SUCCESS( Status ) ) { Index++; i++; BuffSize += Read; if ( (Index + Skip) >= Items ) { break; } if ( (BuffSize >= PreferedMaximumLength) ) { break; } Buffer += Size; } else if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) { Index++; // // We'll have to pretend this item doesn't exist if we get back no information... // Status = STATUS_SUCCESS; LsapDsDebugOut(( DEB_TRACE, "Trust object %ws being dropped. %lu current items\n", LsapDsNameFromDsName( DsNames[ Index + Skip ] ), Items )); } else { break; } if ( (Index + Skip) >= Items ) { break; } } } // // Return the information on success // if ( NT_SUCCESS( Status ) ) { *(PULONG)EnumerationContext += Index; if ( i == 0 ) { *TrustedDomainInformation = NULL; *CountReturned = 0; MIDL_user_free( TDInfo ); } else { *TrustedDomainInformation = TDInfo; *CountReturned = i; } if( Index + Skip >= Items ) { if( i == 0 ) { Status = STATUS_NO_MORE_ENTRIES; } else { Status = STATUS_SUCCESS; } } else { ASSERT( i != 0 && "We should be returning something here" ); Status = STATUS_MORE_ENTRIES; } } // // Free any allocated memory we no longer need // if ( DsNames != NULL ) { LsapFreeLsaHeap( DsNames ); } if ( !NT_SUCCESS( Status ) && Status != STATUS_NO_MORE_ENTRIES ) { MIDL_user_free( TDInfo ); } LsapDbReleaseLockEx( TrustedDomainObject, LSAP_DB_READ_ONLY_TRANSACTION ); LsapExitFunc( "LsapDsEnumerateTrustedDomainsEx", Status ); return( Status ); } NTSTATUS LsapDsGetTrustedDomainInfoEx( IN PDSNAME ObjectPath, IN ULONG ReadOptions, TRUSTED_INFORMATION_CLASS InformationClass, PLSAPR_TRUSTED_DOMAIN_INFO TrustedDomainInformation, OUT OPTIONAL PULONG Size ) /*++ Routine Description: This function will read the requested level of information off the specified trusted domain object Arguments: ObjectPath - DsName of the trusted domain object InformationClass - Level of information being requested TrustedDomainInformation - Where the information is returned Size - OPTIONAL size of the information buffer is returned here. Returns: STATUS_SUCCESS - Success STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed STATUS_INVALID_PARAMETER - A bad InformationClass was given --*/ { NTSTATUS Status = STATUS_SUCCESS; ATTRBLOCK ReadBlock, ReturnedBlock; ULONG Items = 0, i, RetSize = 0; ATTR DomainOrgTreeAttrVals[] = { {0, {0, NULL} }, {0, {0, NULL} }, {0, {0, NULL} }, {0, {0, NULL} }, {0, {0, NULL} }, {0, {0, NULL} }, {0, {0, NULL} }, {0, {0, NULL} } }; // // List of returned parameters // UNICODE_STRING Name, FlatName; ULONG Offset = 0, Direction = 0, Type = 0, Attributes = 0; PSID Sid = NULL; PBYTE Incoming = NULL, Outgoing = NULL; ULONG IncomingSize = 0, OutgoingSize = 0; ULONG ForestTrustLength = 0; PBYTE ForestTrustInfo = NULL; // // Different info types // // PLSAPR_TRUSTED_DOMAIN_NAME_INFO NameInfo; // PTRUSTED_POSIX_OFFSET_INFO PosixOffset; // PLSAPR_TRUSTED_PASSWORD_INFO PasswordInfo; PLSAPR_TRUSTED_DOMAIN_INFORMATION_EX DomainInfoEx; PLSAPR_TRUSTED_DOMAIN_INFORMATION_BASIC DomainInfoBasic; PLSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION AuthInfo; PLSAPR_TRUSTED_DOMAIN_FULL_INFORMATION FullInfo; PLSAPR_TRUSTED_DOMAIN_FULL_INFORMATION2 FullInfo2; LsapEnterFunc( "LsapDsGetTrustedDomainInfoEx" ); RtlZeroMemory( &FlatName, sizeof( UNICODE_STRING ) ); RtlZeroMemory( &Name, sizeof( UNICODE_STRING ) ); switch ( InformationClass ) { case TrustedDomainAuthInformation: // FALL THROUGH DomainOrgTreeAttrVals[ 0 ].attrTyp = ATT_TRUST_AUTH_INCOMING; DomainOrgTreeAttrVals[ 1 ].attrTyp = ATT_TRUST_AUTH_OUTGOING; Items = 2; break; case TrustedDomainInformationBasic: DomainOrgTreeAttrVals[ 0 ].attrTyp = ATT_FLAT_NAME; DomainOrgTreeAttrVals[ 1 ].attrTyp = ATT_SECURITY_IDENTIFIER; Items = 2; break; case TrustedDomainInformationEx: DomainOrgTreeAttrVals[ 0 ].attrTyp = ATT_TRUST_PARTNER; DomainOrgTreeAttrVals[ 1 ].attrTyp = ATT_FLAT_NAME; DomainOrgTreeAttrVals[ 2 ].attrTyp = ATT_SECURITY_IDENTIFIER; DomainOrgTreeAttrVals[ 3 ].attrTyp = ATT_TRUST_DIRECTION; DomainOrgTreeAttrVals[ 4 ].attrTyp = ATT_TRUST_TYPE; DomainOrgTreeAttrVals[ 5 ].attrTyp = ATT_TRUST_ATTRIBUTES; Items = 6; break; case TrustedDomainFullInformation: DomainOrgTreeAttrVals[ 0 ].attrTyp = ATT_TRUST_PARTNER; DomainOrgTreeAttrVals[ 1 ].attrTyp = ATT_FLAT_NAME; DomainOrgTreeAttrVals[ 2 ].attrTyp = ATT_SECURITY_IDENTIFIER; DomainOrgTreeAttrVals[ 3 ].attrTyp = ATT_TRUST_DIRECTION; DomainOrgTreeAttrVals[ 4 ].attrTyp = ATT_TRUST_TYPE; DomainOrgTreeAttrVals[ 5 ].attrTyp = ATT_TRUST_ATTRIBUTES; DomainOrgTreeAttrVals[ 6 ].attrTyp = ATT_TRUST_POSIX_OFFSET; // No caller currently needs auth information. // DomainOrgTreeAttrVals[ 7 ].attrTyp = ATT_TRUST_AUTH_INCOMING; // DomainOrgTreeAttrVals[ 8 ].attrTyp = ATT_TRUST_AUTH_OUTGOING; // Items = 9; Items = 7; break; case TrustedDomainFullInformation2Internal: DomainOrgTreeAttrVals[ 0 ].attrTyp = ATT_TRUST_PARTNER; DomainOrgTreeAttrVals[ 1 ].attrTyp = ATT_FLAT_NAME; DomainOrgTreeAttrVals[ 2 ].attrTyp = ATT_SECURITY_IDENTIFIER; DomainOrgTreeAttrVals[ 3 ].attrTyp = ATT_TRUST_DIRECTION; DomainOrgTreeAttrVals[ 4 ].attrTyp = ATT_TRUST_TYPE; DomainOrgTreeAttrVals[ 5 ].attrTyp = ATT_TRUST_ATTRIBUTES; DomainOrgTreeAttrVals[ 6 ].attrTyp = ATT_TRUST_POSIX_OFFSET; DomainOrgTreeAttrVals[ 7 ].attrTyp = ATT_MS_DS_TRUST_FOREST_TRUST_INFO; Items = 8; // No caller currently needs auth information. // DomainOrgTreeAttrVals[ 8 ].attrTyp = ATT_TRUST_AUTH_INCOMING; // DomainOrgTreeAttrVals[ 9 ].attrTyp = ATT_TRUST_AUTH_OUTGOING; // Items = 10; break; default: Status = STATUS_INVALID_PARAMETER; break; } // // Now, read all of the attributes we care about // if ( NT_SUCCESS( Status ) ) { ReadBlock.attrCount = Items; ReadBlock.pAttr = DomainOrgTreeAttrVals; Status = LsapDsReadByDsName( ObjectPath, ReadOptions, &ReadBlock, &ReturnedBlock ); // // If that succeeded, then return the proper information // if ( NT_SUCCESS( Status ) ) { if ( Items != ReturnedBlock.attrCount ) { LsapDsDebugOut(( DEB_WARN, "LsapDsGetTrustedDomainInfoEx: Expected %lu attributes, got %lu\n", Items, ReturnedBlock.attrCount )); } for ( i = 0; i < ReturnedBlock.attrCount && NT_SUCCESS( Status ); i++) { switch ( ReturnedBlock.pAttr[i].attrTyp ) { case ATT_TRUST_PARTNER: Name.Buffer = MIDL_user_allocate( ReturnedBlock.pAttr[i].AttrVal.pAVal->valLen + sizeof( WCHAR ) ); if ( Name.Buffer == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { RtlZeroMemory( Name.Buffer, ReturnedBlock.pAttr[i].AttrVal.pAVal->valLen + sizeof(WCHAR) ); RtlCopyMemory( Name.Buffer, ReturnedBlock.pAttr[i].AttrVal.pAVal->pVal, ReturnedBlock.pAttr[i].AttrVal.pAVal->valLen ); Name.Length = (USHORT)ReturnedBlock.pAttr[i].AttrVal.pAVal->valLen; Name.MaximumLength = Name.Length + sizeof( WCHAR ); } break; case ATT_FLAT_NAME: FlatName.Buffer = MIDL_user_allocate( ReturnedBlock.pAttr[i].AttrVal.pAVal->valLen + sizeof( WCHAR ) ); if ( FlatName.Buffer == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { RtlZeroMemory( FlatName.Buffer, ReturnedBlock.pAttr[i].AttrVal.pAVal->valLen + sizeof(WCHAR) ); RtlCopyMemory( FlatName.Buffer, ReturnedBlock.pAttr[i].AttrVal.pAVal->pVal, ReturnedBlock.pAttr[i].AttrVal.pAVal->valLen ); FlatName.Length = (USHORT)ReturnedBlock.pAttr[i].AttrVal.pAVal->valLen; FlatName.MaximumLength = FlatName.Length + sizeof( WCHAR ); } break; case ATT_SECURITY_IDENTIFIER: Sid = MIDL_user_allocate( ReturnedBlock.pAttr[i].AttrVal.pAVal->valLen ); if ( Sid == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { RtlCopyMemory( Sid, ReturnedBlock.pAttr[i].AttrVal.pAVal->pVal, ReturnedBlock.pAttr[i].AttrVal.pAVal->valLen ); ASSERT( RtlValidSid( Sid ) ); } break; case ATT_TRUST_DIRECTION: Direction = LSAP_DS_GET_DS_ATTRIBUTE_AS_ULONG( &ReturnedBlock.pAttr[i] ); break; case ATT_TRUST_TYPE: Type = LSAP_DS_GET_DS_ATTRIBUTE_AS_ULONG( &ReturnedBlock.pAttr[i] ); break; case ATT_TRUST_ATTRIBUTES: Attributes = LSAP_DS_GET_DS_ATTRIBUTE_AS_ULONG( &ReturnedBlock.pAttr[i] ); break; case ATT_TRUST_POSIX_OFFSET: Offset = LSAP_DS_GET_DS_ATTRIBUTE_AS_ULONG( &ReturnedBlock.pAttr[i] ); break; case ATT_TRUST_AUTH_INCOMING: Incoming = ReturnedBlock.pAttr[i].AttrVal.pAVal->pVal; IncomingSize = ReturnedBlock.pAttr[i].AttrVal.pAVal->valLen; break; case ATT_TRUST_AUTH_OUTGOING: Outgoing = ReturnedBlock.pAttr[i].AttrVal.pAVal->pVal; OutgoingSize = ReturnedBlock.pAttr[i].AttrVal.pAVal->valLen; break; case ATT_MS_DS_TRUST_FOREST_TRUST_INFO: ForestTrustLength = ReturnedBlock.pAttr[i].AttrVal.pAVal->valLen; if ( ForestTrustLength > 0 ) { ForestTrustInfo = ( PBYTE )MIDL_user_allocate( ForestTrustLength ); if ( ForestTrustInfo == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { RtlCopyMemory( ForestTrustInfo, ReturnedBlock.pAttr[i].AttrVal.pAVal->pVal, ForestTrustLength ); } } break; default: Status = STATUS_INVALID_PARAMETER; break; } } } else if ( Status == STATUS_NOT_FOUND ) { // // We map the NOT_FOUND error code to OBJECT_NAME_NOT_FOUND, so we don't end up // returning an unexpected error code to the outside world // if ( !FLAG_ON( ReadOptions, LSAPDS_READ_RETURN_NOT_FOUND ) ) { Status = STATUS_OBJECT_NAME_NOT_FOUND; } } // // Now, simply assemble everything, and return it... Also, compute the size while // we're at it... // if ( NT_SUCCESS( Status ) ) { RetSize = 0; switch ( InformationClass ) { case TrustedDomainAuthInformation: AuthInfo = (PLSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION)TrustedDomainInformation; RtlZeroMemory( AuthInfo, sizeof( AuthInfo ) ); Status = LsapDsUnmarshalAuthInfoHalf( NULL, FALSE, FALSE, Incoming, IncomingSize, LsapDsAuthHalfFromAuthInfo( AuthInfo, TRUE ) ); if ( NT_SUCCESS( Status ) ) { Status = LsapDsUnmarshalAuthInfoHalf( NULL, FALSE, FALSE, Outgoing, OutgoingSize, LsapDsAuthHalfFromAuthInfo( AuthInfo, FALSE ) ); if ( !NT_SUCCESS( Status ) ) { LsapDsFreeUnmarshalAuthInfoHalf( LsapDsAuthHalfFromAuthInfo( AuthInfo, TRUE ) ); } } break; case TrustedDomainInformationBasic: DomainInfoBasic = ( PLSAPR_TRUSTED_DOMAIN_INFORMATION_BASIC )TrustedDomainInformation; RtlZeroMemory( DomainInfoBasic, sizeof( DomainInfoBasic ) ); RetSize += sizeof( PLSAPR_TRUSTED_DOMAIN_INFORMATION_BASIC ); RetSize += FlatName.MaximumLength; RtlCopyMemory( &DomainInfoBasic->Name, &FlatName, sizeof( UNICODE_STRING ) ); DomainInfoBasic->Sid = Sid; if ( Sid ) { RetSize += RtlLengthSid( Sid ); } break; case TrustedDomainFullInformation2Internal: FullInfo2 = ( PLSAPR_TRUSTED_DOMAIN_FULL_INFORMATION2 )TrustedDomainInformation; RtlZeroMemory( FullInfo2, sizeof( LSAPR_TRUSTED_DOMAIN_FULL_INFORMATION2 )); RtlCopyMemory( &FullInfo2->Information.Name, &Name, sizeof( UNICODE_STRING )); RtlCopyMemory( &FullInfo2->Information.FlatName, &FlatName, sizeof( UNICODE_STRING )); FullInfo2->Information.Sid = Sid; FullInfo2->Information.TrustType = Type; FullInfo2->Information.TrustAttributes = Attributes; FullInfo2->Information.TrustDirection = Direction; FullInfo2->Information.ForestTrustInfo = ForestTrustInfo; FullInfo2->Information.ForestTrustLength = ForestTrustLength; FullInfo2->PosixOffset.Offset = Offset; RetSize += Name.MaximumLength + FlatName.MaximumLength + ( Sid ? RtlLengthSid( Sid ) : 0 ) + 6 * sizeof( ULONG ) + ForestTrustLength; break; case TrustedDomainFullInformation: FullInfo = ( PLSAPR_TRUSTED_DOMAIN_FULL_INFORMATION )TrustedDomainInformation; RtlZeroMemory( FullInfo, sizeof(FullInfo) ); FullInfo->PosixOffset.Offset = Offset; RetSize += sizeof(ULONG); /* Drop through */ case TrustedDomainInformationEx: DomainInfoEx = ( PLSAPR_TRUSTED_DOMAIN_INFORMATION_EX )TrustedDomainInformation; RtlZeroMemory( DomainInfoEx, sizeof( DomainInfoEx ) ); RetSize += sizeof( PLSAPR_TRUSTED_DOMAIN_INFORMATION_EX ); RetSize += Name.MaximumLength; RtlCopyMemory( &DomainInfoEx->Name, &Name, sizeof( UNICODE_STRING ) ); RetSize += FlatName.MaximumLength; RtlCopyMemory( &DomainInfoEx->FlatName, &FlatName, sizeof( UNICODE_STRING ) ); DomainInfoEx->Sid = Sid; if ( Sid ) { RetSize += RtlLengthSid( Sid ); } DomainInfoEx->TrustType = Type; DomainInfoEx->TrustAttributes = Attributes; DomainInfoEx->TrustDirection = Direction; RetSize += 3 * sizeof( ULONG ); break; } } } if ( !NT_SUCCESS( Status ) ) { MIDL_user_free( ForestTrustInfo ); MIDL_user_free( Name.Buffer ); MIDL_user_free( Sid ); } else if ( Size != NULL ) { *Size = RetSize; } LsapExitFunc( "LsapDsGetTrustedDomainInfoEx", Status ); return( Status ); } NTSTATUS LsapDsUnMarshalAuthInfoForReturn( IN ULONG Items, IN OPTIONAL PBYTE Buffer, IN ULONG Length, OUT PLSAPR_AUTH_INFORMATION *RetAuthInfo ) /*++ Routine Description: This function will unmarshal an authinfo list Arguments: Infos - Number of authinfos in Buffer Buffer - Buffer to unmarshal from. Length - Length (in bytes) of Buffer. RetAuthInfo - AuthenticationInformation to fill in. Free by calling LsapDsFreeUnmarshaledAuthInfo then MIDL_user_free. Returns: STATUS_SUCCESS -- Success STATUS_INSUFFICIENT_RESOURCES -- A memory allocation failed STATUS_INTERNAL_DB_CORRUPTION -- Buffer is corrupt --*/ { NTSTATUS Status = STATUS_SUCCESS; ULONG i; ULONG ArraySize; PLSAPR_AUTH_INFORMATION AuthInfo; PBYTE BufferEnd = Buffer + Length; LsapEnterFunc( "LsapDsUnMarshalAuthInfoForReturn" ); // // If there is no input auth info, // we're done. // *RetAuthInfo = NULL; if ( Buffer == NULL || Length == 0 ) { Status = STATUS_SUCCESS; goto Cleanup; } // // Determine the size of the authinfo array. // if ( Items > 0xFFFFFFFF/sizeof(LSAPR_AUTH_INFORMATION) ) { Status = STATUS_INTERNAL_DB_CORRUPTION; LsapExitFunc( "LsapDsUnMarshalAuthInfoForReturn", Status ); return Status; } ArraySize = Items * sizeof(LSAPR_AUTH_INFORMATION); // // Allocate a buffer for the authinfo array. // *RetAuthInfo = MIDL_user_allocate( ArraySize ); if ( *RetAuthInfo == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } AuthInfo = *RetAuthInfo; RtlZeroMemory( AuthInfo, ArraySize ); // // Copy each authinfo // for (i = 0; i < Items ; i++ ) { if ( Buffer+sizeof(LARGE_INTEGER)+sizeof(ULONG)+sizeof(ULONG) > BufferEnd ) { Status = STATUS_INTERNAL_DB_CORRUPTION; goto Cleanup; } RtlCopyMemory( &(AuthInfo[ i ].LastUpdateTime), Buffer, sizeof( LARGE_INTEGER ) ); Buffer += sizeof( LARGE_INTEGER ); AuthInfo[ i ].AuthType = *(PULONG)Buffer; Buffer += sizeof ( ULONG ); AuthInfo[i].AuthInfoLength = *(PULONG)Buffer; Buffer += sizeof ( ULONG ); if ( AuthInfo[ i ]. AuthInfoLength == 0 ) { AuthInfo[i].AuthInfo = NULL; } else { if ( AuthInfo[ i ].AuthInfoLength > Length || Buffer + AuthInfo[ i ].AuthInfoLength > BufferEnd ) { Status = STATUS_INTERNAL_DB_CORRUPTION; goto Cleanup; } AuthInfo[i].AuthInfo = MIDL_user_allocate( AuthInfo[i].AuthInfoLength ); if ( AuthInfo[ i ].AuthInfo == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } RtlCopyMemory( AuthInfo[ i ].AuthInfo, Buffer, AuthInfo[i].AuthInfoLength ); Buffer += ROUND_UP_COUNT(AuthInfo[ i ].AuthInfoLength, ALIGN_DWORD); } } Status = STATUS_SUCCESS; Cleanup: if ( !NT_SUCCESS(Status) ) { if ( *RetAuthInfo != NULL ) { LsapDsFreeUnmarshaledAuthInfo( Items, *RetAuthInfo ); MIDL_user_free( *RetAuthInfo ); *RetAuthInfo = NULL; } } LsapExitFunc( "LsapDsUnMarshalAuthInfoForReturn", Status ); return( Status ); } NTSTATUS LsapDsBuildAuthInfoFromAttribute( IN LSAPR_HANDLE Handle, IN PBYTE Buffer, IN ULONG Len, OUT PLSAPR_TRUST_DOMAIN_AUTH_INFO_HALF NewAuthInfo ) /*++ Routine Description: This function builds an authentication information structure from a marshaled blob Arguments: Handle - Handle to the trusted domain object which holds this information Incoming - Building incoming or outgoing authinfo Buffer - Marshaled buffer Len - Length of the buffer NewAuthInfo - AuthenticationInformation structure to fill in Free this buffer by calling LsapDsFreeUnmarshalAuthInfoHalf or by letting the RPC server side stub free it. Returns: STATUS_SUCCESS - Success STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed. --*/ { NTSTATUS Status = STATUS_SUCCESS; ULONG Items = 0; PBYTE Current, Prev; PLSAPR_AUTH_INFORMATION CurrentAuth = NULL; PLSAPR_AUTH_INFORMATION PrevAuth = NULL; LsapEnterFunc( "LsapDsBuildAuthInfoFromAttribute" ); if ( Buffer == NULL || ( Len == sizeof(ULONG) && *Buffer == 0 ) ) { NewAuthInfo->AuthInfos = 0; NewAuthInfo->AuthenticationInformation = NULL; NewAuthInfo->PreviousAuthenticationInformation = NULL; } else { Status = LsapDsUnmarshalAuthInfoHalf( Handle, TRUE, FALSE, Buffer, Len, NewAuthInfo ); } LsapExitFunc( "LsapDsBuildAuthInfoFromAttribute", Status ); return( Status ); } NTSTATUS LsapDsUnmarshalAuthInfoHalf( IN LSAPR_HANDLE ObjectHandle, IN BOOLEAN ReturnOnlyFirstAuthInfo, IN BOOLEAN AllowEmptyPreviousInfo, IN PBYTE Buffer, IN ULONG Length, OUT PLSAPR_TRUST_DOMAIN_AUTH_INFO_HALF AuthInfo ) /*++ Routine Description: This function will take a marshaled authinfo structure, decrypt it using the Lsa key, unmarshal it, and optionally reencrypt it with the session key Arguments: ObjectHandle - Handle to the trusted domain object which holds this information ReturnOnlyFirstAuthInfo - Pass TRUE if only the first element of the auth info array is to be returned. AllowEmptyPreviousInfo - Pass TRUE if it is OK to return NULL as the previuos AuthInfo. Otherwise, the current auth info will be duplicated. Buffer - Marshaled buffer Length - Length of the buffer AuthInfo - Unmarshaled AuthInfo goes here. Free this buffer by calling LsapDsFreeUnmarshalAuthInfoHalf or by letting the RPC server side stub free it. Returns: STATUS_SUCCESS - Success --*/ { NTSTATUS Status; ULONG Items; PBYTE Auth, Prev; ULONG AuthLen, PrevLen; PBYTE Where; LsapEnterFunc( "LsapDsUnmarshalAuthInfoHalf" ); // // Make sure we don't have the plug // RtlZeroMemory( AuthInfo, sizeof( LSAPR_TRUST_DOMAIN_AUTH_INFO_HALF ) ); if ( ( Length == 0 || Length == sizeof( ULONG ) ) && ( Buffer == NULL || *( PULONG )Buffer == 0 ) ) { Status = STATUS_SUCCESS; goto Cleanup; } // // The format of the buffer is: // // [Info count][OffsetCurrent][OffsetPrevious] and then some number of the following: // [UpdateTime(LargeInteger)][AuthType][AuthInfoLen][data (sizeis(AuthInfoLen) ] // Where = Buffer; Items = *(PULONG)Where; Where += sizeof(ULONG ); if ( (*(PULONG)Where) > Length ) { Status = STATUS_INTERNAL_DB_CORRUPTION; goto Cleanup; } Auth = Buffer + *(PULONG)Where; Where += sizeof(ULONG ); if ( (*(PULONG)Where) > Length ) { Status = STATUS_INTERNAL_DB_CORRUPTION; goto Cleanup; } Prev = Buffer + *(PULONG)Where; AuthLen = (ULONG)(Prev - Auth); PrevLen = (ULONG)((Buffer + Length) - Prev); AuthInfo->AuthInfos = Items; // // There is a bug in the idl definition of LSAPR_TRUST_DOMAIN_AUTH_INFO_HALF // At most, one AuthInfo can be returned. So, for out of process clients, // don't return more than one. // if ( ReturnOnlyFirstAuthInfo && ObjectHandle && !((LSAP_DB_HANDLE)ObjectHandle)->Trusted && AuthInfo->AuthInfos > 1 ) { AuthInfo->AuthInfos = 1; } // // If we have no previous info, return the current info as previous. // if ( !AllowEmptyPreviousInfo && PrevLen == 0 && AuthLen > 0 ) { PrevLen = AuthLen; Prev = Auth; if ( ObjectHandle ) { LsapDsDebugOut(( DEB_ERROR, "No PREVIOUS auth info. Returning current for %wZ\n", &( ( LSAP_DB_HANDLE )ObjectHandle )->PhysicalNameDs )); } } // // Do the actual unmarshalling // Status = LsapDsUnMarshalAuthInfoForReturn( AuthInfo->AuthInfos, Auth, AuthLen, &AuthInfo->AuthenticationInformation ); if ( NT_SUCCESS( Status ) ) { Status = LsapDsUnMarshalAuthInfoForReturn( AuthInfo->AuthInfos, Prev, PrevLen, &AuthInfo->PreviousAuthenticationInformation ); } // // If something failed, clean up after ourselves // Cleanup: if ( !NT_SUCCESS( Status ) ) { LsapDsFreeUnmarshalAuthInfoHalf( AuthInfo ); AuthInfo->AuthInfos = 0; AuthInfo->PreviousAuthenticationInformation = NULL; AuthInfo->AuthenticationInformation = NULL; } LsapExitFunc( "LsapDsUnmarshalAuthInfoHalf", Status ); return( Status ); } VOID LsapDsFreeUnmarshaledAuthInfo( IN ULONG Items, IN PLSAPR_AUTH_INFORMATION AuthInfo ) /*++ Routine Description: This function will free an authinfo struct allocated during unmarshalling Arguments: Items - Number of items in the list AuthInfo - AuthenticationInformation to free Returns: VOID --*/ { ULONG i; if ( AuthInfo != NULL ) { for ( i = 0; i < Items; i++) { MIDL_user_free( AuthInfo[ i ].AuthInfo ); } } } NTSTATUS LsapDsBuildAuthInfoAttribute( IN LSAPR_HANDLE Handle, IN PLSAPR_TRUST_DOMAIN_AUTH_INFO_HALF NewAuthInfo, IN PLSAPR_TRUST_DOMAIN_AUTH_INFO_HALF PreviousAuthInfo, OUT PBYTE *Buffer, OUT PULONG Len ) /*++ Routine Description: This function will take an AuthInfo, merge it with the old AuthInfo, convert it into a writable blob Arguments: Handle - Handle to open trusted domain object NewAuthInfo - AuthInfo to set on the object PreviousAuthInfo - AuthInfo that currently exists on the object Buffer - Where to return the allocated buffer Len - Where to return the buffer length Returns: STATUS_SUCCESS - Success STATUS_UNSUCCESSFUL - Client coming in is trusted. STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed. --*/ { NTSTATUS Status; PLSAP_CR_CIPHER_VALUE Encrypted; PLSAPR_AUTH_INFORMATION Prev = NULL; LSAPR_TRUST_DOMAIN_AUTH_INFO_HALF SetAuthHalf; ULONG i,j; LsapEnterFunc( "LsapDsBuildAuthInfoAttribute" ); if ( NewAuthInfo == NULL ) { *Buffer = NULL; *Len = 0; Status = STATUS_SUCCESS; LsapExitFunc( "LsapDsBuildAuthInfoAttribute", Status ); return Status; } // // Always use the new authentication info passed by the caller // SetAuthHalf.AuthInfos = NewAuthInfo->AuthInfos; SetAuthHalf.AuthenticationInformation = NewAuthInfo->AuthenticationInformation; // // If the caller passed in explicit Previous Authentication info, // use it. // if ( NewAuthInfo->PreviousAuthenticationInformation != NULL ) { SetAuthHalf.PreviousAuthenticationInformation = NewAuthInfo->PreviousAuthenticationInformation; // // Verify that the AuthTypes in this array are in the same order as // the new auth info. // for( i = 0; i < SetAuthHalf.AuthInfos; i++ ) { if ( ( SetAuthHalf.AuthenticationInformation[i].AuthType != SetAuthHalf.PreviousAuthenticationInformation[i].AuthType ) && ( SetAuthHalf.PreviousAuthenticationInformation[i].AuthType != TRUST_AUTH_TYPE_NONE ) && ( SetAuthHalf.AuthenticationInformation[i].AuthType != TRUST_AUTH_TYPE_NONE ) ) { Status = STATUS_INVALID_PARAMETER; goto Cleanup; } } // // If the caller didn't pass explicit Previous Authentication info, // compute it. } else { // // Default the Previous Authentication info to the new authentication info // explicitly passed by the caller. // // This copy of the Authentication info has all of the AuthTypes in the // right order. // // If none of the current auth info can be merged in, // we'll simply end up with the previous auth info equaling the // new auth info. // SetAuthHalf.PreviousAuthenticationInformation = SetAuthHalf.AuthenticationInformation; // // If there was Auth info on the object before, // try to use as much auth info from the object as we can. // // That is, if the caller just passes a new auth info data, // the "current" auth info data on the object is now the previuos auth info. // The only gotcha is that the new auth info data might have totally // different AuthTypes. So, we grab only that portion of the current // auth info data that matches the AuthTypes from the new auth info. // if ( PreviousAuthInfo != NULL ) { // // Allocate a buffer to do the merge into. // Prev = LsapAllocateLsaHeap( sizeof( LSAPR_AUTH_INFORMATION) * NewAuthInfo->AuthInfos ); if ( Prev == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } // // Initialize the buffer to simply be a copy of the new auth info. // RtlCopyMemory( Prev, SetAuthHalf.PreviousAuthenticationInformation, SetAuthHalf.AuthInfos * sizeof( LSAPR_AUTH_INFORMATION) ); SetAuthHalf.PreviousAuthenticationInformation = Prev; // // Loop through each of these entries ... // for( i = 0; i < SetAuthHalf.AuthInfos; i++ ) { // // ... finding the corresponding entry in the old list. // for ( j = 0; j < PreviousAuthInfo->AuthInfos; j++) { if ( SetAuthHalf.PreviousAuthenticationInformation[i].AuthType == PreviousAuthInfo->AuthenticationInformation[j].AuthType ) { // // If the entry used to exist on the object, // use that entry rather than the default. // // Note, we don't need to copy the actual auth data here. // We just copy the structure that points to the data. // SetAuthHalf.PreviousAuthenticationInformation[i] = PreviousAuthInfo->AuthenticationInformation[j]; break; } } } } } // // Marshall the resultant auth info. // Status = LsapDsMarshalAuthInfoHalf( &SetAuthHalf, Len, Buffer ); // // Free any memory we may have allocated // Cleanup: if ( Prev ) { LsapFreeLsaHeap( Prev ); } LsapExitFunc( "LsapDsBuildAuthInfoAttribute", Status ); return( Status ); } NTSTATUS LsapDsFindAuthTypeInAuthInfo( IN ULONG AuthType, IN PLSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION AuthInfo, IN BOOLEAN Incoming, IN BOOLEAN AddIfNotFound, OUT BOOLEAN *Added, OUT PULONG AuthTypeIndex ) /*++ Routine Description: This function will find the index of the first auth blob it finds of the given type. Optionally, if the entry is not found, a new node can be allocated and added to the lsit Arguments: AuthType - AuthType to find AuthInfo - Auth info to search Incoming - Search incoming or outgoing AddIfNotFound - If TRUE, the entry is added to the end of the list AutyTypeIndex - Where the index is returned Returns: STATUS_SUCCESS - Success STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed. STATUS_NOT_FOUND - The object wasn't found --*/ { NTSTATUS Status = STATUS_SUCCESS; ULONG Items, Index = 0xFFFFFFFF, i; PLSAPR_AUTH_INFORMATION SearchList, SearchPrev; PLSAPR_AUTH_INFORMATION Current = NULL, Previous = NULL; *Added = FALSE; if ( Incoming ) { Items = AuthInfo->IncomingAuthInfos; SearchList = AuthInfo->IncomingAuthenticationInformation; SearchPrev = AuthInfo->IncomingPreviousAuthenticationInformation; } else { Items = AuthInfo->OutgoingAuthInfos; SearchList = AuthInfo->OutgoingAuthenticationInformation; SearchPrev = AuthInfo->OutgoingPreviousAuthenticationInformation; } // // Now, find the index of the entry in the auth list // for ( i = 0; i < Items ; i++ ) { if ( SearchList[ i ].AuthType == AuthType) { Index = i; break; } } if ( Index == 0xFFFFFFFF ) { if ( !AddIfNotFound ) { Status = STATUS_NOT_FOUND; } else { // // We'll have to add it, since it doesn't currently exist. // Current = LsapAllocateLsaHeap( sizeof( LSAPR_AUTH_INFORMATION ) * ( Items + 1 ) ); if ( Current != NULL ) { Previous = LsapAllocateLsaHeap( sizeof( LSAPR_AUTH_INFORMATION ) * ( Items + 1 ) ); } if ( Current == NULL || Previous == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { Index = Items; RtlCopyMemory( Current, SearchList, sizeof( LSAPR_AUTH_INFORMATION ) * Items ); if ( SearchPrev ) { RtlCopyMemory( Previous, SearchPrev, sizeof( LSAPR_AUTH_INFORMATION ) * Items ); } Items++; *Added = TRUE; } if ( Incoming ) { AuthInfo->IncomingAuthInfos = Items; AuthInfo->IncomingAuthenticationInformation = Current; AuthInfo->IncomingPreviousAuthenticationInformation = Previous; } else { AuthInfo->OutgoingAuthInfos = Items; AuthInfo->OutgoingAuthenticationInformation = Current; AuthInfo->OutgoingPreviousAuthenticationInformation = Previous; } } } if ( NT_SUCCESS( Status ) ) { *AuthTypeIndex = Index; } if ( !*Added ) { LsapFreeLsaHeap( Previous ); LsapFreeLsaHeap( Current ); } return( Status ); } NTSTATUS LsapDsSetSecretOnTrustedDomainObject( IN LSAP_DB_HANDLE TrustedDomainHandle, IN ULONG AuthDataType, IN PLSAP_CR_CLEAR_VALUE ClearCurrent, IN PLSAP_CR_CLEAR_VALUE ClearOld, IN PLARGE_INTEGER CurrentValueSetTime ) /*++ Routine Description: This function perform the equvialent of setting the values on a secret that corresponds to a trusted domain object. Arguments: TrustedDomainHandle - Handle to trusted domain object ClearCurrent - New secret value ClearOld - Old secret value Returns: STATUS_SUCCESS - Success STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed. --*/ { // // Use a common routine that supports both incoming and outgoing trust. // return LsapDsAuthDataOnTrustedDomainObject( TrustedDomainHandle, FALSE, // Set the outgoing trust AuthDataType, ClearCurrent, ClearOld, CurrentValueSetTime ); } NTSTATUS LsapDsAuthDataOnTrustedDomainObject( IN LSAP_DB_HANDLE TrustedDomainHandle, IN BOOLEAN Incoming, IN ULONG AuthDataType, IN PLSAP_CR_CLEAR_VALUE ClearCurrent, IN PLSAP_CR_CLEAR_VALUE ClearOld, IN PLARGE_INTEGER CurrentValueSetTime ) /*++ Routine Description: This function perform the equvialent of setting the values on a secret that corresponds to a trusted domain object. Arguments: TrustedDomainHandle - Handle to trusted domain object Incoming -- Whether to set the incoming or going data AuthDataType -- Type of the auth data being set ClearCurrent - New secret value ClearOld - Old secret value CurrentValueSetTime -- Time of the set. Returns: STATUS_SUCCESS - Success STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed. --*/ { NTSTATUS Status = STATUS_SUCCESS; LSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION AuthInfo = { 0 }; ULONG Index, Options = 0; PDSNAME DsName; BOOLEAN Added = FALSE ; BOOLEAN CloseTransaction; PLSA_AUTH_INFORMATION NewIncoming = NULL, NewPrevious = NULL; LsapEnterFunc( "LsapDsAuthDataOnTrustedDomainObject" ); if ( AuthDataType != TRUST_AUTH_TYPE_CLEAR && AuthDataType != TRUST_AUTH_TYPE_NT4OWF ) { Status = STATUS_INVALID_PARAMETER; LsapExitFunc( "LsapDsAuthDataOnTrustedDomainObject", Status ); return( Status ); } Status = LsapDsInitAllocAsNeededEx( LSAP_DB_DS_OP_TRANSACTION | LSAP_DB_READ_ONLY_TRANSACTION, TrustedDomainObject, &CloseTransaction ); if ( !NT_SUCCESS( Status ) ) { LsapExitFunc( "LsapDsAuthDataOnTrustedDomainObject", Status ); return( Status ); } Status = LsapAllocAndInitializeDsNameFromUnicode( &TrustedDomainHandle->PhysicalNameDs, &DsName ); if ( NT_SUCCESS( Status ) ) { RtlZeroMemory( &AuthInfo, sizeof( LSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION ) ); Status = LsapDsGetTrustedDomainInfoEx( DsName, LSAPDS_READ_NO_LOCK, TrustedDomainAuthInformation, (PLSAPR_TRUSTED_DOMAIN_INFO)&AuthInfo, NULL ); if ( NT_SUCCESS( Status ) || Status == STATUS_NOT_FOUND || Status == STATUS_OBJECT_NAME_NOT_FOUND ) { BOOLEAN MustFreeClearOld = FALSE; // // Now, find the index of the CLEAR entry in the correct auth list // Status = LsapDsFindAuthTypeInAuthInfo( AuthDataType, &AuthInfo, Incoming, TRUE, &Added, &Index ); if ( NT_SUCCESS( Status ) ) { if ( ClearCurrent == NULL ) { if ( Incoming ) { RtlZeroMemory( &AuthInfo.IncomingAuthenticationInformation[ Index ], sizeof( LSAPR_AUTH_INFORMATION ) ); } else { RtlZeroMemory( &AuthInfo.OutgoingAuthenticationInformation[ Index ], sizeof( LSAPR_AUTH_INFORMATION ) ); } } else { LSAPDS_SET_AUTH_INFO( Incoming ? &AuthInfo.IncomingAuthenticationInformation[ Index ] : &AuthInfo.OutgoingAuthenticationInformation[ Index ], CurrentValueSetTime, AuthDataType, ClearCurrent->Length, ClearCurrent->Buffer ); } // // LsaDbSetSecret expects the old password // to be set to the previous current password // if ( ClearOld == NULL ) { BOOLEAN SavedTrusted; // // We may not have access, so go as trusted. // Password comes back in the clear. // SavedTrusted = TrustedDomainHandle->Trusted; TrustedDomainHandle->Trusted = TRUE; Status = LsarQuerySecret( TrustedDomainHandle, &(PLSAPR_CR_CIPHER_VALUE)ClearOld, NULL, NULL, NULL); TrustedDomainHandle->Trusted = SavedTrusted; if ( !NT_SUCCESS( Status ) && ClearOld) { LsapCrFreeMemoryValue( ClearOld ); ClearOld = NULL; } else { MustFreeClearOld = TRUE; } Status = STATUS_SUCCESS; // // Failure to obtain old value should not stop us, as the worst // thing that could happen is it won't be set, and that's not fatal // } if ( ClearOld == NULL ) { if ( Incoming ) { RtlZeroMemory( &AuthInfo.IncomingPreviousAuthenticationInformation[ Index ], sizeof( LSAPR_AUTH_INFORMATION ) ); } else { RtlZeroMemory( &AuthInfo.OutgoingPreviousAuthenticationInformation[ Index ], sizeof( LSAPR_AUTH_INFORMATION ) ); } } else { LSAPDS_SET_AUTH_INFO( Incoming ? &AuthInfo.IncomingPreviousAuthenticationInformation[ Index ] : &AuthInfo.OutgoingPreviousAuthenticationInformation[ Index ], CurrentValueSetTime, AuthDataType, ClearOld->Length, ClearOld->Buffer ); } } // // Finally, set it // if ( NT_SUCCESS (Status ) ) { // // Since we already have the db locked, we'll fool the set routine into // thinking we're a trusted client and have therefore locked the database // if ( !Incoming ) { Options = TrustedDomainHandle->Options; TrustedDomainHandle->Options |= LSAP_DB_DS_TRUSTED_DOMAIN_AS_SECRET; } Status = LsarSetInformationTrustedDomain( TrustedDomainHandle, TrustedDomainAuthInformation, (PLSAPR_TRUSTED_DOMAIN_INFO)&AuthInfo ); if ( !Incoming ) { TrustedDomainHandle->Options = Options; } } if ( MustFreeClearOld ) { LsapCrFreeMemoryValue( ClearOld ); ClearOld = NULL; } } LsapDsFree( DsName ); } if ( Added ) { if ( Incoming ) { LsapFreeLsaHeap( AuthInfo.IncomingAuthenticationInformation ); LsapFreeLsaHeap( AuthInfo.IncomingPreviousAuthenticationInformation ); } else { LsapFreeLsaHeap( AuthInfo.OutgoingAuthenticationInformation ); LsapFreeLsaHeap( AuthInfo.OutgoingPreviousAuthenticationInformation ); } } // // Destruction of the thread state will delete any allocated Ds memory // LsapDsDeleteAllocAsNeededEx( LSAP_DB_DS_OP_TRANSACTION | LSAP_DB_READ_ONLY_TRANSACTION, TrustedDomainObject, CloseTransaction ); LsapExitFunc( "LsapDsAuthDataOnTrustedDomainObject", Status ); return( Status ); } NTSTATUS LsapDsGetSecretOnTrustedDomainObject( IN LSAP_DB_HANDLE TrustedDomainHandle, IN OPTIONAL PLSAP_CR_CIPHER_KEY SessionKey, OUT OPTIONAL PLSAP_CR_CIPHER_VALUE *CipherCurrent, OUT OPTIONAL PLSAP_CR_CIPHER_VALUE *CipherOld, OUT OPTIONAL PLARGE_INTEGER CurrentValueSetTime, OUT OPTIONAL PLARGE_INTEGER OldValueSetTime ) /*++ Routine Description: This function perform the equvialent of getting the values on a secret that corresponds to a trusted domain object. Arguments: TrustedDomainHandle - Handle to trusted domain object SessionKey - Optional SessionKey to use for encrypting the values CipherCurrent - Where to return the current value CipherOld - Where to return previous current value CurrValueSetTime - Where to return the current set time OldValueSetTime - Where to return the old set time Returns: STATUS_SUCCESS - Success STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed. STATUS_NOT_FOUND - No such auth data exists STATUS_INVALID_PARAMETER - No information was requested --*/ { NTSTATUS Status = STATUS_SUCCESS; LSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION AuthInfo; ULONG Index; PDSNAME DsName; BOOLEAN Added; BOOLEAN CloseTransaction; LSAP_CR_CLEAR_VALUE ClearValue; if ( !ARGUMENT_PRESENT( CipherCurrent ) && !ARGUMENT_PRESENT( CipherOld ) && !ARGUMENT_PRESENT( CurrentValueSetTime) && !ARGUMENT_PRESENT( OldValueSetTime ) ) { return( STATUS_INVALID_PARAMETER ); } LsapEnterFunc( "LsapDsGetSecretOnTrustedDomainObject" ); // // See if we already have a transaction going // Status = LsapDsInitAllocAsNeededEx( LSAP_DB_DS_OP_TRANSACTION | LSAP_DB_READ_ONLY_TRANSACTION, TrustedDomainObject, &CloseTransaction ); if ( !NT_SUCCESS( Status ) ) { LsapExitFunc( "LsapDsGetSecretOnTrustedDomainObject", Status ); return( Status ); } Status = LsapAllocAndInitializeDsNameFromUnicode( &TrustedDomainHandle->PhysicalNameDs, &DsName ); if ( NT_SUCCESS( Status ) ) { Status = LsapDsGetTrustedDomainInfoEx( DsName, LSAPDS_READ_RETURN_NOT_FOUND, TrustedDomainAuthInformation, (PLSAPR_TRUSTED_DOMAIN_INFO)&AuthInfo, NULL ); if ( NT_SUCCESS( Status ) ) { // // Now, find the index of the CLEAR entry in the outgoing auth list // Status = LsapDsFindAuthTypeInAuthInfo( TRUST_AUTH_TYPE_CLEAR, &AuthInfo, FALSE, FALSE, &Added, &Index ); if ( NT_SUCCESS( Status ) ) { if ( ARGUMENT_PRESENT( CipherCurrent ) ) { ClearValue.Length = AuthInfo.OutgoingAuthenticationInformation[ Index ].AuthInfoLength; ClearValue.MaximumLength = ClearValue.Length; ClearValue.Buffer = AuthInfo.OutgoingAuthenticationInformation[ Index ].AuthInfo; if ( !LsapValidateLsaCipherValue( &ClearValue ) ) { Status = STATUS_INVALID_PARAMETER; } else if ( SessionKey != NULL ) { Status = LsapCrEncryptValue ( &ClearValue, SessionKey, CipherCurrent ); } else { *CipherCurrent = MIDL_user_allocate( sizeof( LSAP_CR_CIPHER_VALUE ) + ClearValue.Length ); if ( *CipherCurrent == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { (*CipherCurrent)->Length = ClearValue.Length; (*CipherCurrent)->MaximumLength = ClearValue.Length; (*CipherCurrent)->Buffer = (PBYTE)(*CipherCurrent) + sizeof( LSAP_CR_CIPHER_VALUE ); RtlCopyMemory( (*CipherCurrent)->Buffer, ClearValue.Buffer, ClearValue.Length ); } } } if ( NT_SUCCESS( Status ) && ARGUMENT_PRESENT( CipherOld ) ) { ClearValue.Length = AuthInfo.OutgoingPreviousAuthenticationInformation[ Index ].AuthInfoLength; ClearValue.MaximumLength = ClearValue.Length; ClearValue.Buffer = AuthInfo.OutgoingPreviousAuthenticationInformation[ Index ].AuthInfo; if ( !LsapValidateLsaCipherValue( &ClearValue ) ) { Status = STATUS_INVALID_PARAMETER; } else if ( SessionKey != NULL ) { Status = LsapCrEncryptValue ( &ClearValue, SessionKey, CipherOld ); } else { *CipherOld = MIDL_user_allocate( sizeof( LSAP_CR_CIPHER_VALUE ) + ClearValue.Length ); if ( *CipherOld == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { (*CipherOld)->Length = ClearValue.Length; (*CipherOld)->MaximumLength = ClearValue.Length; (*CipherOld)->Buffer = (PBYTE)(*CipherOld) + sizeof( LSAP_CR_CIPHER_VALUE ); RtlCopyMemory( (*CipherOld)->Buffer, ClearValue.Buffer, ClearValue.Length ); } } if ( !NT_SUCCESS( Status ) && ARGUMENT_PRESENT( CipherCurrent ) ) { LsapCrFreeMemoryValue( CipherCurrent ); } } if ( NT_SUCCESS( Status ) && ARGUMENT_PRESENT( CurrentValueSetTime ) ) { RtlCopyMemory( CurrentValueSetTime, &AuthInfo.OutgoingAuthenticationInformation[ Index ]. LastUpdateTime, sizeof( LARGE_INTEGER ) ); } if ( NT_SUCCESS( Status ) && ARGUMENT_PRESENT( OldValueSetTime ) ) { RtlCopyMemory( OldValueSetTime, &AuthInfo.OutgoingPreviousAuthenticationInformation[ Index ]. LastUpdateTime, sizeof( LARGE_INTEGER ) ); } } LsapDsFreeUnmarshalAuthInfoHalf( LsapDsAuthHalfFromAuthInfo( &AuthInfo, TRUE ) ); LsapDsFreeUnmarshalAuthInfoHalf( LsapDsAuthHalfFromAuthInfo( &AuthInfo, FALSE ) ); } if ( Status == STATUS_NOT_FOUND ) { if ( ARGUMENT_PRESENT( CipherCurrent ) ) { *CipherCurrent = NULL; } if ( ARGUMENT_PRESENT( CipherOld ) ) { *CipherOld = NULL; } if ( ARGUMENT_PRESENT( CurrentValueSetTime ) ) { RtlZeroMemory( CurrentValueSetTime, sizeof( LARGE_INTEGER ) ); } if ( ARGUMENT_PRESENT( OldValueSetTime ) ) { RtlZeroMemory( CurrentValueSetTime, sizeof( LARGE_INTEGER ) ); } Status = STATUS_SUCCESS; } LsapDsFree( DsName ); } // // Destruction of the thread state will delete any allocated Ds memory // LsapDsDeleteAllocAsNeededEx( LSAP_DB_DS_OP_TRANSACTION | LSAP_DB_READ_ONLY_TRANSACTION, TrustedDomainObject, CloseTransaction ); LsapExitFunc( "LsapDsGetSecretOnTrustedDomainObject", Status ); return( Status ); } NTSTATUS LsapDsEnumerateTrustedDomainsAsSecrets( IN OUT PLSAP_DB_NAME_ENUMERATION_BUFFER EnumerationBuffer ) /*++ Routine Description: This function returns a list of trusted domain objects as if they were secret objects Arguments: EnumerationBuffer - Where the enumerated information is returned Returns: STATUS_SUCCESS - Success STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed. --*/ { NTSTATUS Status = STATUS_SUCCESS; LSA_ENUMERATION_HANDLE EnumContext = 0; LSAPR_TRUSTED_ENUM_BUFFER EnumBuffer; PLSAPR_TRUSTED_DOMAIN_INFORMATION_EX TDInfoEx; LSAPR_HANDLE TDHandle; PUNICODE_STRING Names = NULL; PBYTE Buffer; ULONG i; // // Just return if the Ds isn't running // if (!LsapDsWriteDs ) { RtlZeroMemory( EnumerationBuffer, sizeof( LSAP_DB_NAME_ENUMERATION_BUFFER ) ); return( Status ); } Status = LsarEnumerateTrustedDomains( LsapPolicyHandle, &EnumContext, &EnumBuffer, TENMEG ); if ( NT_SUCCESS( Status ) ) { Names = MIDL_user_allocate( EnumBuffer.EntriesRead * sizeof( UNICODE_STRING ) ); if( Names == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { for ( i = 0; i < EnumBuffer.EntriesRead; i++ ) { Status = LsapDbOpenTrustedDomain( LsapPolicyHandle, EnumBuffer.Information[ i ].Sid, MAXIMUM_ALLOWED, &TDHandle, LSAP_DB_TRUSTED ); if ( NT_SUCCESS( Status ) ) { Status = LsarQueryInfoTrustedDomain( TDHandle, TrustedDomainInformationEx, (PLSAPR_TRUSTED_DOMAIN_INFO *)&TDInfoEx ); LsapCloseHandle( &TDHandle, Status ); // // Allocate a buffer to hold the name. The sizeof below accounts for our // terminating NULL // if ( NT_SUCCESS( Status ) ) { if ( FLAG_ON( TDInfoEx->TrustDirection, TRUST_DIRECTION_OUTBOUND ) ) { Buffer = MIDL_user_allocate( TDInfoEx->FlatName.Length + sizeof( LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX ) ); if ( Buffer == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; LsaIFree_LSAPR_TRUSTED_DOMAIN_INFO( TrustedDomainInformationEx, (PLSAPR_TRUSTED_DOMAIN_INFO)TDInfoEx ); break; } else { RtlCopyMemory( Buffer, LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX, sizeof( LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX ) ); RtlCopyMemory( Buffer + sizeof( LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX ) - sizeof(WCHAR), TDInfoEx->FlatName.Buffer, TDInfoEx->FlatName.Length + sizeof( WCHAR ) ); RtlInitUnicodeString( &Names[ i ], (PWSTR)Buffer ); } } LsaIFree_LSAPR_TRUSTED_DOMAIN_INFO( TrustedDomainInformationEx, (PLSAPR_TRUSTED_DOMAIN_INFO)TDInfoEx ); } } } } LsaIFree_LSAPR_TRUSTED_ENUM_BUFFER ( &EnumBuffer ); EnumerationBuffer->Names = Names; EnumerationBuffer->EntriesRead = EnumBuffer.EntriesRead; } else if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) { RtlZeroMemory( EnumerationBuffer, sizeof( LSAP_DB_NAME_ENUMERATION_BUFFER ) ); Status = STATUS_SUCCESS; } LsapExitFunc( "LsapDsEnumerateTrustedDomainsAsSecrets", Status ); return( Status ); } BOOLEAN LsapDsIsNtStatusResourceError( NTSTATUS NtStatus ) { switch ( NtStatus ) { case STATUS_NO_MEMORY: case STATUS_INSUFFICIENT_RESOURCES: case STATUS_DISK_FULL: return TRUE; default: return FALSE; } } NTSTATUS LsapDeleteUpgradedTrustedDomain( IN HANDLE LsaPolicyHandle, IN PSID DomainSid ) /*++ Routine Description: This routine deletes the trusted domain pointed to by DomainSid. This routine is only meant to be called during an upgrade from nt4 to nt5 Arguments: LsaPolicyHandle - a valid policy handle DomainSid -- domain to delete Return Values: STATUS_SUCCESS -- Success --*/ { NTSTATUS Status = STATUS_SUCCESS; LSAPR_HANDLE TDHandle = 0; Status = LsapDbOpenTrustedDomain( LsaPolicyHandle, DomainSid, MAXIMUM_ALLOWED, &TDHandle, LSAP_DB_TRUSTED ); if ( NT_SUCCESS( Status ) ) { Status = LsapRegOpenTransaction(); if ( NT_SUCCESS( Status ) ) { Status = LsapDbDeleteObject( TDHandle ); if ( NT_SUCCESS( Status ) ) { Status = LsapRegApplyTransaction(); } else { NTSTATUS IgnoreStatus; IgnoreStatus = LsapRegAbortTransaction(); } } else { LsapDbCloseHandle(TDHandle); } } return Status; } NTSTATUS LsapDsDomainUpgradeRegistryToDs( IN BOOLEAN DeleteOnly ) /*++ Routine Description: This routine will move the remaining registry based trusted domains into the Ds NOTE: It is assumed that the database is locked before calling this routine Arguments: DeleteOldValues -- If TRUE, the registry values are deleted following the upgade. Return Values: STATUS_SUCCESS -- Success --*/ { NTSTATUS Status = STATUS_SUCCESS; LSA_ENUMERATION_HANDLE EnumContext = 0; LSAPR_TRUSTED_ENUM_BUFFER EnumBuffer; PLSAPR_TRUSTED_DOMAIN_INFORMATION_EX TDInfoEx = { 0 }; LSAPR_HANDLE TDHandle; BOOLEAN UseDsOld = LsaDsStateInfo.UseDs; ULONG i; if ( !LsapDsWriteDs && !DeleteOnly ) { return( STATUS_SUCCESS ); } LsapEnterFunc( "LsapDsDomainUpgradeRegistryToDs" ); ( ( LSAP_DB_HANDLE )LsapPolicyHandle )->Options |= LSAP_DB_HANDLE_UPGRADE; // // First, enumerate all of the registry based trusted domains // while ( NT_SUCCESS( Status ) ) { LsaDsStateInfo.UseDs = FALSE; LsapDbMakeCacheInvalid( TrustedDomainObject ); Status = LsarEnumerateTrustedDomains( LsapPolicyHandle, &EnumContext, &EnumBuffer, TENMEG ); LsaDsStateInfo.UseDs = UseDsOld; LsapDbMakeCacheValid( TrustedDomainObject ); if ( Status == STATUS_SUCCESS || Status == STATUS_MORE_ENTRIES ) { for ( i = 0; i < EnumBuffer.EntriesRead && NT_SUCCESS( Status ) ; i++ ) { // // Get the information from the registry for this sid... // LsaDsStateInfo.UseDs = FALSE; if ( DeleteOnly ) { Status = LsapDeleteUpgradedTrustedDomain( LsapPolicyHandle, EnumBuffer.Information[ i ].Sid ); if ( !NT_SUCCESS( Status ) ) { LsapDsDebugOut(( DEB_UPGRADE, "Failed to delete trust object (0x%x)\n", Status )); Status = STATUS_SUCCESS; } LsaDsStateInfo.UseDs = UseDsOld; continue; } Status = LsapDbOpenTrustedDomain( LsapPolicyHandle, EnumBuffer.Information[ i ].Sid, MAXIMUM_ALLOWED, &TDHandle, LSAP_DB_TRUSTED ); if ( NT_SUCCESS( Status ) ) { Status = LsarQueryInfoTrustedDomain( TDHandle, TrustedDomainInformationEx, (PLSAPR_TRUSTED_DOMAIN_INFO *)&TDInfoEx ); LsapCloseHandle( &TDHandle, Status); } LsaDsStateInfo.UseDs = UseDsOld; // // Now, if that worked, write it out to the Ds // if ( NT_SUCCESS( Status ) ) { Status = LsapCreateTrustedDomain2( LsapPolicyHandle, ( PLSAPR_TRUSTED_DOMAIN_INFORMATION_EX )TDInfoEx, NULL, MAXIMUM_ALLOWED, &TDHandle ); if ( NT_SUCCESS( Status ) ) { LsapCloseHandle( &TDHandle, STATUS_SUCCESS ); LsapDsDebugOut(( DEB_UPGRADE, "Moved trusted domain %wZ to Ds\n", &TDInfoEx->Name )); } if ( Status == STATUS_OBJECT_NAME_COLLISION ) { Status = STATUS_SUCCESS; } LsaIFree_LSAPR_TRUSTED_DOMAIN_INFO( TrustedDomainInformationEx, (PLSAPR_TRUSTED_DOMAIN_INFO)TDInfoEx ); } if (!NT_SUCCESS(Status)) { if (!LsapDsIsNtStatusResourceError(Status)) { SpmpReportEventU( EVENTLOG_ERROR_TYPE, LSA_TRUST_UPGRADE_ERROR, 0, sizeof( ULONG ), &Status, 1, &EnumBuffer.Information[i].Name ); // // Continue on all errors excepting resource errors // Status = STATUS_SUCCESS; } else { // // Break out of the loop and terminate the status // break; } } } LsaIFree_LSAPR_TRUSTED_ENUM_BUFFER ( &EnumBuffer ); } } if ( Status == STATUS_NO_MORE_ENTRIES ) { Status = STATUS_SUCCESS; } ( ( LSAP_DB_HANDLE )LsapPolicyHandle )->Options &= ~LSAP_DB_HANDLE_UPGRADE; LsapExitFunc( "LsapDsDomainUpgradeRegistryToDs", Status ); return( Status ); } NTSTATUS LsapDsCreateSetITAForTrustInfo( IN PUNICODE_STRING AccountName, IN PTRUSTED_DOMAIN_AUTH_INFORMATION AuthInfo ) /*++ Routine Description: This function creates/sets a SAM interdomain trust account for an NT5 style trust object, given the trust information Arguments: AccountName - Name of the account to create/set AuthInfo - AuthInfo for the trust object Return Values: STATUS_SUCCESS -- Success STATUS_UNSUCCESSFUL -- The Sam domain handle has not been opened. --*/ { NTSTATUS Status = STATUS_SUCCESS; SAM_HANDLE AccountHandle = NULL ; ULONG Access, Rid, i; USER_ALL_INFORMATION UserAllInfo; SAMPR_USER_INTERNAL1_INFORMATION UserInternalInfo1; PVOID SamData = NULL; ULONG SamInfoLevel = 0; BOOLEAN SetPassword = FALSE; UNICODE_STRING Account; WCHAR AccountNameBuffer[ UNLEN + 2 ]; LsapEnterFunc( "LsapDsCreateSetITAForTrustInfo" ); if ( AccountName->Length > UNLEN * sizeof( WCHAR ) ) { LsapDsDebugOut(( DEB_ERROR, "LsapDsCreateSetITAForTrustInfo: Name too long: %wZ\n", AccountName )); Status = STATUS_OBJECT_NAME_INVALID; LsapExitFunc( "LsapDsCreateSetITAForTrustInfo", Status ); } Status = LsapOpenSam(); if ( !NT_SUCCESS( Status ) ) { LsapDsDebugOut(( DEB_ERROR, "LsapDsCreateSetITAForTrustInfo: Sam not opened\n")); LsapExitFunc( "LsapDsCreateSetITAForTrustInfo", Status ); return( Status ); } if ( NT_SUCCESS( Status ) ) { // // Find the clear password, if it exists // for ( i = 0; i < AuthInfo->IncomingAuthInfos; i++ ) { if ( AuthInfo->IncomingAuthenticationInformation[ i ].AuthType == TRUST_AUTH_TYPE_CLEAR) { RtlZeroMemory( &UserAllInfo, sizeof( USER_ALL_INFORMATION ) ); UserAllInfo.NtPassword.Buffer = (PUSHORT)( AuthInfo-> IncomingAuthenticationInformation[ i ].AuthInfo ); UserAllInfo.NtPassword.Length = (USHORT)( AuthInfo-> IncomingAuthenticationInformation[ i ].AuthInfoLength ); UserAllInfo.NtPassword.MaximumLength = UserAllInfo.NtPassword.Length; UserAllInfo.NtPasswordPresent = TRUE; UserAllInfo.WhichFields = USER_ALL_NTPASSWORDPRESENT | USER_ALL_USERACCOUNTCONTROL; UserAllInfo.UserAccountControl = USER_INTERDOMAIN_TRUST_ACCOUNT | USER_PASSWORD_NOT_REQUIRED; SetPassword = TRUE; SamData = &UserAllInfo; SamInfoLevel = UserAllInformation; break; } } // // Find the OWF password, if we are supposed to use it, // and we haven't already used the cleartext one // if ( SetPassword == FALSE ) { for ( i = 0; i < AuthInfo->IncomingAuthInfos; i++ ) { if ( AuthInfo->IncomingAuthenticationInformation[ i ].AuthType == TRUST_AUTH_TYPE_NT4OWF ) { RtlZeroMemory( &UserInternalInfo1, sizeof( SAMPR_USER_INTERNAL1_INFORMATION ) ); RtlCopyMemory( &UserInternalInfo1.EncryptedNtOwfPassword, AuthInfo->IncomingAuthenticationInformation[ i ].AuthInfo, ENCRYPTED_LM_OWF_PASSWORD_LENGTH ); UserInternalInfo1.NtPasswordPresent = TRUE; SamData = &UserInternalInfo1; SamInfoLevel = UserInternal1Information; SetPassword = TRUE; break; } } } } LsapSaveDsThreadState(); // // Create the user // if ( NT_SUCCESS( Status ) ) { RtlZeroMemory( &AccountNameBuffer, sizeof( AccountNameBuffer ) ); RtlCopyMemory( AccountNameBuffer, AccountName->Buffer, AccountName->Length ); *( PWSTR )( ( ( PBYTE )AccountNameBuffer ) + AccountName->Length ) = L'$'; RtlInitUnicodeString( &Account, AccountNameBuffer ); Status = LsaOpenSamUser( ( PSECURITY_STRING )&Account, SecNameSamCompatible, NULL, FALSE, 0, &AccountHandle ); if ( NT_SUCCESS( Status )) { // // Account already exists? This might be a stale machine account. // Check it out before proceeding. // SID_AND_ATTRIBUTES_LIST GroupMembership = {0}; PSAMPR_USER_INFO_BUFFER UserAllInfoLocal = NULL; SAMPR_HANDLE UserHandle = NULL; Status = SamIGetUserLogonInformationEx( LsapAccountDomainHandle, SAM_OPEN_BY_UPN_OR_ACCOUNTNAME | SAM_NO_MEMBERSHIPS, &Account, USER_ALL_USERACCOUNTCONTROL, &UserAllInfoLocal, &GroupMembership, &UserHandle ); if ( NT_SUCCESS( Status )) { if (( UserAllInfoLocal->All.UserAccountControl & USER_INTERDOMAIN_TRUST_ACCOUNT ) == 0 ) { // // The existing account is not an ITA. Fail TDO creation. // Status = STATUS_USER_EXISTS; } if ( GroupMembership.SidAndAttributes != NULL ) { SamIFreeSidAndAttributesList(&GroupMembership); } if ( UserAllInfoLocal != NULL ) { SamIFree_SAMPR_USER_INFO_BUFFER( UserAllInfoLocal, UserAllInformation ); } if ( UserHandle != NULL ) { SamrCloseHandle( &UserHandle ); } } } else if ( Status == STATUS_NO_SUCH_USER || Status == STATUS_NONE_MAPPED ) { Status = SamrCreateUser2InDomain( LsapAccountDomainHandle, ( PRPC_UNICODE_STRING )&Account, USER_INTERDOMAIN_TRUST_ACCOUNT, MAXIMUM_ALLOWED, &AccountHandle, &Access, &Rid ); if ( !NT_SUCCESS( Status )) { LsapDsDebugOut(( DEB_ERROR, "SamrCreateUser2InDomain on %wZ failed with 0x%lx\n", &Account, Status)); } } else if ( !NT_SUCCESS( Status ) ) { LsapDsDebugOut(( DEB_ERROR, "LsaOpenSamUser on %wZ failed with 0x%lx\n", &Account, Status)); } // // Set the password // if ( NT_SUCCESS( Status ) ) { DsysAssert( AccountHandle ); if ( SetPassword ) { Status = SamrSetInformationUser( AccountHandle, SamInfoLevel, SamData ); } SamrCloseHandle( &AccountHandle ); } } LsapRestoreDsThreadState( ); LsapExitFunc( "LsapDsCreateSetITAForTrustInfo", Status ); return( Status ); } NTSTATUS LsapDsCreateInterdomainTrustAccount( IN LSAPR_HANDLE TrustedDomain ) /*++ Routine Description: This function creates a SAM interdomain trust account for an NT5 style trust object Arguments: TrustedDomain - Handle to the newly created trusted domain object Return Values: STATUS_SUCCESS -- Success STATUS_UNSUCCESSFUL -- The Sam domain handle has not been opened. --*/ { NTSTATUS Status = STATUS_SUCCESS; PTRUSTED_DOMAIN_FULL_INFORMATION FullInfo = NULL; BOOLEAN SavedTrusted; LSAP_DB_HANDLE InternalTdoHandle = (LSAP_DB_HANDLE) TrustedDomain; LsapEnterFunc( "LsapDsCreateInterdomainTrustAccount" ); // // If this is the case of an NT4 upgrade in progress then bail // if (LsaDsStateInfo.Nt4UpgradeInProgress) { return (STATUS_SUCCESS); } if (LsapProductSuiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED) { return STATUS_NOT_SUPPORTED_ON_SBS; } Status = LsapOpenSam(); if ( !NT_SUCCESS( Status ) ) { LsapDsDebugOut(( DEB_ERROR, "CreateInterdomainTrustAccount: Sam not opened\n")); LsapExitFunc( "LsapDsCreateInterdomainTrustAccount", Status ); return( Status ); } // // First, find the domain. We'll need to get the full info on it // // Do this operation as trusted since it is an internal operation and the // handle might not grant access to do this operation. // SavedTrusted = InternalTdoHandle->Trusted; InternalTdoHandle->Trusted = TRUE; Status = LsarQueryInfoTrustedDomain( TrustedDomain, TrustedDomainFullInformation, (PLSAPR_TRUSTED_DOMAIN_INFO *)&FullInfo ); InternalTdoHandle->Trusted = SavedTrusted; if ( NT_SUCCESS( Status ) ) { Status = LsapDsCreateSetITAForTrustInfo( &FullInfo->Information.FlatName, &FullInfo->AuthInformation ); } // // Free our info // if ( FullInfo != NULL ) { LsaIFree_LSAPR_TRUSTED_DOMAIN_INFO( TrustedDomainFullInformation, ( PLSAPR_TRUSTED_DOMAIN_INFO )FullInfo ); } LsapExitFunc( "LsapDsCreateInterdomainTrustAccount", Status ); return( Status ); } NTSTATUS LsapDsCreateInterdomainTrustAccountByDsName( IN PDSNAME TrustedDomainPath, IN PUNICODE_STRING FlatName ) /*++ Routine Description: This function creates a SAM interdomain trust account for an NT5 style trust object Arguments: DomainName -- Name of the newly added domain AccountPassword -- Auth data set on the trust account Return Values: STATUS_SUCCESS -- Success STATUS_UNSUCCESSFUL -- The Sam domain handle has not been opened. --*/ { NTSTATUS Status = STATUS_SUCCESS; TRUSTED_DOMAIN_AUTH_INFORMATION AuthInfo; LsapEnterFunc( "LsapDsCreateInterdomainTrustAccountByDsName" ); Status = LsapOpenSam(); if ( !NT_SUCCESS( Status ) ) { LsapDsDebugOut(( DEB_ERROR, "CreateInterdomainTrustAccount: Sam not opened\n")); LsapExitFunc( "LsapDsCreateInterdomainTrustAccountByDsName", Status ); return( Status ); } // // Get the auth data // RtlZeroMemory( &AuthInfo, sizeof( AuthInfo ) ); Status = LsapDsGetTrustedDomainInfoEx( TrustedDomainPath, 0, TrustedDomainAuthInformation, ( PLSAPR_TRUSTED_DOMAIN_INFO )&AuthInfo, NULL ); if ( NT_SUCCESS( Status ) ) { Status = LsapDsCreateSetITAForTrustInfo( FlatName, ( PTRUSTED_DOMAIN_AUTH_INFORMATION )&AuthInfo ); } // // Free our info // LsapDsFreeUnmarshalAuthInfoHalf( LsapDsAuthHalfFromAuthInfo( &AuthInfo, TRUE ) ); LsapDsFreeUnmarshalAuthInfoHalf( LsapDsAuthHalfFromAuthInfo( &AuthInfo, FALSE ) ); LsapExitFunc( "LsapDsCreateInterdomainTrustAccountByDsName", Status ); return( Status ); } NTSTATUS LsapDsDeleteInterdomainTrustAccount( IN LSAPR_HANDLE TrustedDomainObject ) /*++ Routine Description: This function deletes a SAM interdomain trust account for an NT5 style trust object Arguments: TrustedDomainObject -- Handle to the trusted domain object Return Values: STATUS_SUCCESS -- Success STATUS_UNSUCCESSFUL -- The Sam domain handle has not been opened. --*/ { NTSTATUS Status = STATUS_SUCCESS; SAM_HANDLE AccountHandle; LSAP_DB_HANDLE InternalTdoHandle = (LSAP_DB_HANDLE) TrustedDomainObject; PTRUSTED_DOMAIN_INFORMATION_EX ExInfo = NULL; UNICODE_STRING Account; WCHAR AccountName[ UNLEN + 2 ], *Accnt = AccountName; BOOLEAN SavedTrusted; LsapEnterFunc( "LsapDsDeleteInterdomainTrustAccount" ); Status = LsapOpenSam(); if ( !NT_SUCCESS( Status ) ) { LsapDsDebugOut(( DEB_ERROR, "LsapDsDeleteInterdomainTrustAccount: Sam not opened\n")); LsapExitFunc( "LsapDsDeleteInterdomainTrustAccount", Status ); return( Status ); } // // First, find the domain. We'll need to get the full info on it // // Do this operation as trusted since it is an internal operation and the // handle might not grant access to do this operation. // SavedTrusted = InternalTdoHandle->Trusted; InternalTdoHandle->Trusted = TRUE; Status = LsarQueryInfoTrustedDomain( TrustedDomainObject, TrustedDomainInformationEx, (PLSAPR_TRUSTED_DOMAIN_INFO *)&ExInfo ); InternalTdoHandle->Trusted = SavedTrusted; // // Delete the user // // First, create the name to look for // if ( NT_SUCCESS( Status ) ) { RtlZeroMemory( &AccountName, sizeof( AccountName ) ); if ( ExInfo->FlatName.MaximumLength >= sizeof( AccountName ) - sizeof( WCHAR ) ) { Accnt = LsapAllocateLsaHeap( ExInfo->FlatName.MaximumLength + sizeof( WCHAR ) + sizeof( WCHAR ) ); if ( Accnt == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; } } if ( NT_SUCCESS( Status ) ) { RtlCopyMemory( Accnt, ExInfo->FlatName.Buffer, ExInfo->FlatName.MaximumLength ); *( PWSTR )( ( ( PBYTE) Accnt ) + ExInfo->FlatName.Length ) = L'$'; RtlInitUnicodeString( &Account, Accnt ); // // We can't call into sam with an active thread state // LsapSaveDsThreadState(); // // Open the user. If the user doesn't exist, it's not an error // Status = LsaOpenSamUser( ( PSECURITY_STRING )&Account, SecNameSamCompatible, NULL, FALSE, 0, &AccountHandle ); if ( NT_SUCCESS( Status ) ) { // // Now, delete it // Status = SamrDeleteUser( &AccountHandle ); if ( !NT_SUCCESS( Status ) ) { LsapDsDebugOut(( DEB_ERROR, "Failed to delete user %wZ: 0x%lx\n", &Account, Status )); SpmpReportEventU( EVENTLOG_WARNING_TYPE, LSAEVENT_ITA_NOT_DELETED, 0, sizeof( ULONG ), &Status, 1, &ExInfo->Name ); SamrCloseHandle( &AccountHandle ); } } else if ( Status == STATUS_NONE_MAPPED ) { Status = STATUS_SUCCESS; } if ( Accnt != AccountName ) { LsapFreeLsaHeap( Accnt ); } LsapRestoreDsThreadState(); } } // // Free our info // if ( ExInfo != NULL ) { LsaIFree_LSAPR_TRUSTED_DOMAIN_INFO( TrustedDomainInformationEx, ( PLSAPR_TRUSTED_DOMAIN_INFO )ExInfo ); } LsapExitFunc( "LsapDsDeleteInterdomainTrustAccount", Status ); return( Status ); } NTSTATUS LsapDsDomainUpgradeInterdomainTrustAccountsToDs( VOID ) /*++ Routine Description: This routine will create the appropriate part of the trust object if an interdomain trust account by that name is found NOTE: It is assumed that the database is locked before calling this routine Arguments: VOID Return Values: STATUS_SUCCESS -- Success --*/ { NTSTATUS Status = STATUS_SUCCESS; SAM_ENUMERATE_HANDLE SamEnum = 0; SAMPR_HANDLE UserHandle; PSAMPR_ENUMERATION_BUFFER RidEnum = NULL; PSAMPR_USER_INTERNAL1_INFORMATION UserInfo1 = NULL; PLSAPR_TRUSTED_DOMAIN_FULL_INFORMATION FullInfo = NULL; LSAPR_TRUSTED_DOMAIN_FULL_INFORMATION NewFullInfo; LSAPR_AUTH_INFORMATION NewIncomingAuthInfo; LSAPR_HANDLE TrustedDomain = NULL; NT_OWF_PASSWORD EmptyPassword; UNICODE_STRING EmptyString; ULONG SamCount = 0; PVOID CurrentState; ULONG i; if ( !LsapDsWriteDs ) { return( STATUS_SUCCESS ); } LsapEnterFunc( "LsapDsDomainUpgradeInterdomainTrustAccountsToDs" ); ( ( LSAP_DB_HANDLE )LsapPolicyHandle )->Options |= LSAP_DB_HANDLE_UPGRADE; LsapSaveDsThreadState(); Status = LsapOpenSam(); if ( !NT_SUCCESS( Status ) ) { LsapDsDebugOut(( DEB_ERROR, "LsapDsDomainUpgradeInterdomainTrustAccountsToDs: Sam not opened\n")); } else { Status = SamIEnumerateInterdomainTrustAccountsForUpgrade( &SamEnum, &RidEnum, 0xFFFFFFFF, &SamCount ); if ( !NT_SUCCESS( Status ) ) { LsapDsDebugOut(( DEB_FIXUP, "SamEnumerateUsersInDomain failed with 0x%lx\n", Status )); } else { LsapDsDebugOut(( DEB_FIXUP, "SamEnumerateUsersInDomain returned %lu accounts\n", SamCount )); } } LsapRestoreDsThreadState(); // // Now, we'll process them all. If the domain already exists, we'll simply set it's // information appropriately. Otherwise, we'll create it. // for ( i = 0; NT_SUCCESS( Status ) && i < RidEnum->EntriesRead; i++ ) { UCHAR NtOwfPassword[NT_OWF_PASSWORD_LENGTH]; UCHAR LmOwfPassword[LM_OWF_PASSWORD_LENGTH]; BOOLEAN NtPasswordPresent = FALSE; BOOLEAN LmPasswordPresent = FALSE; // // Burn the trailing '$' from the account name // RidEnum->Buffer[ i ].Name.Length -= sizeof( WCHAR ); // // Save Thread state before calling into SAM // LsapSaveDsThreadState(); // // Next, we'll need to read the current nt4 owf from the account // Status = SamIGetInterdomainTrustAccountPasswordsForUpgrade( RidEnum->Buffer[ i ].RelativeId, // RID of the account NtOwfPassword, &NtPasswordPresent, LmOwfPassword, &LmPasswordPresent ); // // Restore the thread state after the SAM call // LsapRestoreDsThreadState(); // // Now, we've got the user info. We'll get the domain information, and // set it on the trust object (or alternately create it if it doesn't exist) // if ( NT_SUCCESS( Status ) ) { // // Build the new AUTHINFO // GetSystemTimeAsFileTime( (LPFILETIME) &NewIncomingAuthInfo.LastUpdateTime ); NewIncomingAuthInfo.AuthType = TRUST_AUTH_TYPE_NT4OWF; NewIncomingAuthInfo.AuthInfoLength = NT_OWF_PASSWORD_LENGTH; if ( NtPasswordPresent ) { NewIncomingAuthInfo.AuthInfo = NtOwfPassword; } else { RtlInitUnicodeString( &EmptyString, L"" ); Status = RtlCalculateNtOwfPassword( ( PNT_PASSWORD )&EmptyString, &EmptyPassword ); if ( NT_SUCCESS( Status ) ) { NewIncomingAuthInfo.AuthInfo = ( PUCHAR )&EmptyPassword; } } Status = LsapDbOpenTrustedDomainByName( NULL, // use global policy handle ( PUNICODE_STRING )&RidEnum->Buffer[ i ].Name, &TrustedDomain, MAXIMUM_ALLOWED, LSAP_DB_START_TRANSACTION, TRUE ); // Trusted if ( NT_SUCCESS( Status ) ) { Status = LsarQueryInfoTrustedDomain( TrustedDomain, TrustedDomainFullInformation, (PLSAPR_TRUSTED_DOMAIN_INFO *) &FullInfo ); if ( NT_SUCCESS( Status ) ) { // // Add our new information in // if ( !FLAG_ON( FullInfo->Information.TrustDirection, TRUST_DIRECTION_INBOUND ) ) { FullInfo->Information.TrustDirection |= TRUST_DIRECTION_INBOUND; FullInfo->AuthInformation.IncomingAuthInfos = 1; FullInfo->AuthInformation.IncomingAuthenticationInformation = &NewIncomingAuthInfo; FullInfo->AuthInformation.IncomingPreviousAuthenticationInformation = NULL; Status = LsarSetInformationTrustedDomain( TrustedDomain, TrustedDomainFullInformation, ( PLSAPR_TRUSTED_DOMAIN_INFO ) FullInfo ); // // NULL out the IncomingAuthenticationInformation variable, as that // is a stack buffer and we do not want to free it. // FullInfo->AuthInformation.IncomingAuthInfos = 0; FullInfo->AuthInformation.IncomingAuthenticationInformation = NULL; LsaIFree_LSAPR_TRUSTED_DOMAIN_INFO( TrustedDomainFullInformation, (PLSAPR_TRUSTED_DOMAIN_INFO) FullInfo ); } } } else if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) { // // We'll have to create it... // RtlZeroMemory( &NewFullInfo, sizeof( NewFullInfo ) ); RtlCopyMemory( &NewFullInfo.Information.Name, &RidEnum->Buffer[ i ].Name, sizeof( LSAPR_UNICODE_STRING ) ); RtlCopyMemory( &NewFullInfo.Information.FlatName, &RidEnum->Buffer[ i ].Name, sizeof( LSAPR_UNICODE_STRING ) ); NewFullInfo.Information.TrustDirection = TRUST_DIRECTION_INBOUND; NewFullInfo.Information.TrustType = TRUST_TYPE_DOWNLEVEL; NewFullInfo.AuthInformation.IncomingAuthInfos = 1; NewFullInfo.AuthInformation.IncomingAuthenticationInformation = &NewIncomingAuthInfo; NewFullInfo.AuthInformation.IncomingPreviousAuthenticationInformation = NULL; Status = LsapCreateTrustedDomain2( LsapPolicyHandle, &NewFullInfo.Information, &NewFullInfo.AuthInformation, MAXIMUM_ALLOWED, &TrustedDomain ); } } if ( TrustedDomain != NULL ) { LsapCloseHandle( &TrustedDomain, Status ); } if ( UserInfo1 ) { SamIFree_SAMPR_USER_INFO_BUFFER( ( PSAMPR_USER_INFO_BUFFER )UserInfo1, UserInternal1Information ); UserInfo1 = NULL; } if (!NT_SUCCESS(Status)) { if (!LsapDsIsNtStatusResourceError(Status)) { // // Log an event log message indicating the failure // SpmpReportEventU( EVENTLOG_ERROR_TYPE, LSA_ITA_UPGRADE_ERROR, 0, sizeof( ULONG ), &Status, 1, &RidEnum->Buffer[i].Name ); // // Continue on all errors excepting resource errors // Status = STATUS_SUCCESS; } else { // // Break out of the loop and terminate the upgrade // break; } } } // // We're done with the sam enumeration // if ( RidEnum ) { SamFreeMemory( RidEnum ); } ( ( LSAP_DB_HANDLE )LsapPolicyHandle )->Options &= ~LSAP_DB_HANDLE_UPGRADE; LsapExitFunc( "LsapDsDomainUpgradeInterdomainTrustAccountsToDs", Status ); return( Status ); } VOID LsapDsFreeUnmarshalAuthInfoHalf( IN PLSAPR_TRUST_DOMAIN_AUTH_INFO_HALF AuthInfo ) /*++ Routine Description: This routine will free the memory allocated by LsapDsUnMarshalAuthInfoForReturn Arguments: VOID Return Values: VOID --*/ { if ( !AuthInfo ) { return; } LsapDsFreeUnmarshaledAuthInfo( AuthInfo->AuthInfos, AuthInfo->AuthenticationInformation ); LsapDsFreeUnmarshaledAuthInfo( AuthInfo->AuthInfos, AuthInfo->PreviousAuthenticationInformation ); MIDL_user_free( AuthInfo->AuthenticationInformation ); AuthInfo->AuthenticationInformation = NULL; MIDL_user_free( AuthInfo->PreviousAuthenticationInformation ); AuthInfo->PreviousAuthenticationInformation = NULL; return; } NTSTATUS LsapDecryptAuthDataWithSessionKey( IN PLSAP_CR_CIPHER_KEY SessionKey, IN PLSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION_INTERNAL AuthInformationInternal, IN PTRUSTED_DOMAIN_AUTH_INFORMATION AuthInfo ) /*++ Routine Description: This routine decrypts the auth info as passed to us on an RPC call. Arguments: SessionKey - Session key to decrypt with. AuthInformationInternal - Pointer to the encrypted auth info. AuthInfo - Buffer to return the authentication information into. Free the buffer using: LsapDsFreeUnmarshalAuthInfoHalf( LsapDsAuthHalfFromAuthInfo( AuthInfo, TRUE ) ); LsapDsFreeUnmarshalAuthInfoHalf( LsapDsAuthHalfFromAuthInfo( AuthInfo, FALSE ) ); Return Value: --*/ { NTSTATUS Status; struct RC4_KEYSTRUCT Rc4Key; ULONG OverheadSize = LSAP_ENCRYPTED_AUTH_DATA_FILL + sizeof(ULONG) + sizeof(ULONG); ULONG MessageSize; PUCHAR Where; ULONG IncomingAuthInfoSize = 0; PUCHAR IncomingAuthInfo = NULL; ULONG OutgoingAuthInfoSize = 0; PUCHAR OutgoingAuthInfo = NULL; // // Initialization. // RtlZeroMemory( AuthInfo, sizeof(*AuthInfo) ); if ( SessionKey == NULL ) { Status = STATUS_INVALID_PARAMETER; goto Cleanup; } // // Ensure the auth data is big enough. // // Here's the format of the decrypted buffer: // 512 random bytes // The Outgoing auth info buffer. // The Incoming auth info buffer. // The length of the outgoing auth info buffer. // The length of the incoming auth info buffer. // MessageSize = AuthInformationInternal->AuthBlob.AuthSize; if ( MessageSize < OverheadSize ) { Status = STATUS_INVALID_PARAMETER; goto Cleanup; } MessageSize -= OverheadSize; // // Decrypt the auth info // rc4_key( &Rc4Key, SessionKey->Length, SessionKey->Buffer ); rc4( &Rc4Key, AuthInformationInternal->AuthBlob.AuthSize, AuthInformationInternal->AuthBlob.AuthBlob ); // // Sanity check the decrypted data. // Where = AuthInformationInternal->AuthBlob.AuthBlob + AuthInformationInternal->AuthBlob.AuthSize - sizeof(ULONG); RtlCopyMemory( &IncomingAuthInfoSize, Where, sizeof(ULONG)); Where -= sizeof(ULONG); if ( IncomingAuthInfoSize > MessageSize ) { Status = STATUS_INVALID_PARAMETER; goto Cleanup; } MessageSize -= IncomingAuthInfoSize; RtlCopyMemory( &OutgoingAuthInfoSize, Where, sizeof(ULONG)); if ( OutgoingAuthInfoSize != MessageSize ) { Status = STATUS_INVALID_PARAMETER; goto Cleanup; } Where -= IncomingAuthInfoSize; IncomingAuthInfo = Where; Where -= OutgoingAuthInfoSize; OutgoingAuthInfo = Where; // // Unmarshal the auth info. // Status = LsapDsUnmarshalAuthInfoHalf( NULL, FALSE, TRUE, IncomingAuthInfo, IncomingAuthInfoSize, LsapDsAuthHalfFromAuthInfo( AuthInfo, TRUE ) ); if ( !NT_SUCCESS(Status)) { Status = STATUS_INVALID_PARAMETER; goto Cleanup; } Status = LsapDsUnmarshalAuthInfoHalf( NULL, FALSE, TRUE, OutgoingAuthInfo, OutgoingAuthInfoSize, LsapDsAuthHalfFromAuthInfo( AuthInfo, FALSE ) ); if ( !NT_SUCCESS(Status)) { Status = STATUS_INVALID_PARAMETER; goto Cleanup; } Cleanup: if ( !NT_SUCCESS(Status)) { LsapDsFreeUnmarshalAuthInfoHalf( LsapDsAuthHalfFromAuthInfo( AuthInfo, TRUE ) ); LsapDsFreeUnmarshalAuthInfoHalf( LsapDsAuthHalfFromAuthInfo( AuthInfo, FALSE ) ); } return Status; } UUID LsapNullUuidValue = {0,0,0,{0,0,0,0,0,0,0,0}}; // Return TRUE if the ptr to the UUID is NULL, or the uuid is all zeroes BOOLEAN LsapNullUuid (const UUID *pUuid) { if (!pUuid) { return TRUE; } if (memcmp (pUuid, &LsapNullUuidValue, sizeof (UUID))) { return FALSE; } return TRUE; } NTSTATUS LsapDsTrustedDomainObjectNameForDomain( IN PUNICODE_STRING TrustedDomainName, IN BOOLEAN NameAsFlatName, OUT PDSNAME *DsObjectName ) /*++ Routine Description: This routine will find the DS object name associated with the given domain name. The domain name can be either the flat name or the dns name, depending on the given flags Arguments: TrustedDomainName - Name of the domain to find the object name for NameAsFlatName - If TRUE, assume that the input name is the flat name. Otherwise, it's the Dns domain name DsObjectName - Where the path to the object is returned. Freed via LsapFreeLsaHeap Return Values: STATUS_SUCCESS - Success STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed --*/ { NTSTATUS Status = STATUS_SUCCESS; ATTRVAL AttrVal; LSAPR_TRUST_INFORMATION InputTrustInformation; PLSAP_DB_TRUSTED_DOMAIN_LIST_ENTRY TrustEntry; LsapEnterFunc( "LsapDsTrustedDomainObjectNameForDomain" ); // // Lookup the object in the trusted domain cache. Currently this is // for duplicate detection and reconciliation. Later we can extend // the cache to always keep the guid of the object in the DS. This way // this will be a useful performance optimization // // // Acquire the Read Lock for the Trusted Domain List // Status = LsapDbAcquireReadLockTrustedDomainList(); if (!NT_SUCCESS(Status)) { goto Cleanup; } RtlCopyMemory(&InputTrustInformation.Name,TrustedDomainName,sizeof(UNICODE_STRING)); InputTrustInformation.Sid = NULL; Status = LsapDbLookupEntryTrustedDomainList( &InputTrustInformation, &TrustEntry ); if ((STATUS_SUCCESS==Status) && (!LsapNullUuid(&TrustEntry->ObjectGuidInDs))) { GUID ObjectGuid; // // Duplicate detection filled in a GUID. use that // RtlCopyMemory(&ObjectGuid, &TrustEntry->ObjectGuidInDs,sizeof(GUID)); AttrVal.valLen = sizeof(GUID); AttrVal.pVal = ( PUCHAR )&ObjectGuid; LsapDbReleaseLockTrustedDomainList(); Status = LsapDsFindUnique( 0, NULL, // Default naming context TrustedDomainObject, &AttrVal, ATT_OBJECT_GUID, DsObjectName ); } else { LsapDbReleaseLockTrustedDomainList(); AttrVal.valLen = TrustedDomainName->Length; AttrVal.pVal = ( PUCHAR )TrustedDomainName->Buffer; Status = LsapDsFindUnique( 0, NULL, // Default naming context TrustedDomainObject, &AttrVal, NameAsFlatName ? LsapDsAttributeIds[ LsapDsAttrTrustPartnerFlat ] : LsapDsAttributeIds[ LsapDsAttrTrustPartner ], DsObjectName ); } Cleanup: LsapExitFunc( "LsapDsTrustedDomainObjectNameForDomain", Status ); return( Status ); }