You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3770 lines
113 KiB
3770 lines
113 KiB
/*++
|
|
|
|
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 <lsapch2.h>
|
|
#include <dbp.h>
|
|
#include <lmcons.h>
|
|
#include <align.h>
|
|
#include <rc4.h>
|
|
|
|
//
|
|
// 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 );
|
|
}
|