|
|
/*++
Microsoft Windows
Copyright (C) Microsoft Corporation, 1998 - 2001
Module Name:
trust.cxx
Abstract:
Handles the various functions for managing domain trust.
--*/ #include "pch.h"
#pragma hdrstop
#include <netdom.h>
VOID NetDompFreeDomInfo( IN OUT PND5_TRUST_INFO TrustInfo ) {
if ( TrustInfo->Connected ) {
LOG_VERBOSE(( MSG_VERBOSE_DELETE_SESSION, TrustInfo->Server )); NetpManageIPCConnect( TrustInfo->Server, NULL, NULL, NETSETUPP_DISCONNECT_IPC ); }
NetApiBufferFree( TrustInfo->Server );
if (TrustInfo->BlobToFree) { LsaFreeMemory( TrustInfo->BlobToFree ); } else { if (TrustInfo->DomainName && TrustInfo->DomainName->Buffer) { NetApiBufferFree(TrustInfo->DomainName->Buffer); NetApiBufferFree(TrustInfo->DomainName); } }
if ( TrustInfo->LsaHandle ) {
LsaClose( TrustInfo->LsaHandle ); }
if ( TrustInfo->TrustHandle ) {
LsaClose( TrustInfo->TrustHandle ); }
}
DWORD NetDompTrustGetDomInfo( IN PWSTR Domain, IN PWSTR DomainController OPTIONAL, IN PND5_AUTH_INFO AuthInfo, IN OUT PND5_TRUST_INFO TrustInfo, IN BOOL ManageTrust, IN BOOL fForce, IN BOOL fUseNullSession ) /*++
Routine Description:
This function will connect to the domain controller for a given domain and determine the appropriate information required for managing trusts.
Arguments:
Domain - Domain to connect to
DomainController - Optional name of a dc within the domain to connect to
TrustInfo - Trusted domain info to accumulate
ManageTrust - Determines how the Lsa is opened. Also if true, and DomainController is NULL, find a writable DC
fForce - If true, set the name info even if the domain can't be contacted.
Return Value:
ERROR_SUCCESS - Success ERROR_INVALID_PARAMETER - No object name was supplied
--*/ { DWORD Win32Err = ERROR_SUCCESS; PDOMAIN_CONTROLLER_INFO DcInfo = NULL; PPOLICY_PRIMARY_DOMAIN_INFO PolicyPDI = NULL; PPOLICY_DNS_DOMAIN_INFO PolicyDDI = NULL; OBJECT_ATTRIBUTES OA; PWSTR pwzDomainName; UNICODE_STRING ServerU, DomainNameU; NTSTATUS Status; ULONG DsGetDcOptions = DS_DIRECTORY_SERVICE_PREFERRED, LsaOptions;
if ( !DomainController ) {
if ( ManageTrust ) {
DsGetDcOptions |= DS_WRITABLE_REQUIRED; }
if (TrustInfo->Flags & NETDOM_TRUST_PDC_REQUIRED) { DsGetDcOptions |= DS_PDC_REQUIRED; }
Win32Err = DsGetDcName( NULL, Domain, NULL, NULL, DsGetDcOptions, &DcInfo );
if ( Win32Err == ERROR_SUCCESS ) {
DomainController = DcInfo->DomainControllerName; } }
//
// Save off the server name
//
if ( Win32Err == ERROR_SUCCESS ) {
Win32Err = NetApiBufferAllocate( ( wcslen( DomainController ) + 1 ) * sizeof( WCHAR ), (PVOID*)&( TrustInfo->Server ) );
if ( Win32Err == ERROR_SUCCESS ) {
wcscpy( TrustInfo->Server, DomainController ); } }
//
// Connect to the machine
//
if ( Win32Err == ERROR_SUCCESS ) {
LOG_VERBOSE(( MSG_VERBOSE_ESTABLISH_SESSION, DomainController )); Win32Err = NetpManageIPCConnect( DomainController, (fUseNullSession) ? L"" : AuthInfo->User, (fUseNullSession) ? L"" : AuthInfo->Password, (fUseNullSession) ? NETSETUPP_NULL_SESSION_IPC : NETSETUPP_CONNECT_IPC); if ( Win32Err == ERROR_SUCCESS ) {
TrustInfo->Connected = TRUE; }
if (ERROR_SESSION_CREDENTIAL_CONFLICT == Win32Err) { if (fUseNullSession) { // Ignore conflict of creds.
//
Win32Err = ERROR_SUCCESS; } else { NetDompDisplayMessage(MSG_ALREADY_CONNECTED, DomainController); } }
if (ERROR_LOGON_FAILURE == Win32Err) { NetApiBufferFree( DcInfo ); return Win32Err; } }
//
// Get the domain information
//
if ( Win32Err == ERROR_SUCCESS ) {
RtlInitUnicodeString( &ServerU, DomainController );
InitializeObjectAttributes( &OA, NULL, 0, NULL, NULL );
LOG_VERBOSE(( MSG_VERBOSE_GET_LSA ));
LsaOptions = POLICY_VIEW_LOCAL_INFORMATION | POLICY_LOOKUP_NAMES;
if ( ManageTrust ) {
LsaOptions |= POLICY_CREATE_SECRET | POLICY_TRUST_ADMIN; }
Status = LsaOpenPolicy( &ServerU, &OA, LsaOptions, &( TrustInfo->LsaHandle ) );
if ( NT_SUCCESS( Status ) ) {
Status = LsaQueryInformationPolicy( TrustInfo->LsaHandle, PolicyDnsDomainInformation, ( PVOID * )&PolicyDDI ); if ( NT_SUCCESS( Status ) ) {
TrustInfo->DomainName = &PolicyDDI->DnsDomainName; TrustInfo->FlatName = &PolicyDDI->Name; TrustInfo->Sid = PolicyDDI->Sid; TrustInfo->BlobToFree = ( PVOID )PolicyDDI; TrustInfo->Uplevel = TRUE; TrustInfo->fWasDownlevel = FALSE;
} else if ( Status == RPC_NT_PROCNUM_OUT_OF_RANGE ) {
Status = LsaQueryInformationPolicy( TrustInfo->LsaHandle, PolicyPrimaryDomainInformation, ( PVOID * )&PolicyPDI ); if ( NT_SUCCESS( Status ) ) {
TrustInfo->DomainName = &PolicyPDI->Name; TrustInfo->FlatName = &PolicyPDI->Name; TrustInfo->Sid = PolicyPDI->Sid; TrustInfo->BlobToFree = ( PVOID )PolicyPDI; TrustInfo->Uplevel = TrustInfo->fWasDownlevel = FALSE; } } }
Win32Err = RtlNtStatusToDosError( Status );
if ( Win32Err != ERROR_SUCCESS ) { LOG_VERBOSE(( MSG_VERBOSE_DELETE_SESSION, DomainController )); NetpManageIPCConnect( DomainController, NULL, NULL, NETSETUPP_DISCONNECT_IPC ); TrustInfo->Connected = FALSE; }
} else if (fForce) {
LOG_VERBOSE(( MSG_VERBOSE_DOMAIN_NOT_FOUND, Domain ));
TrustInfo->Flags = NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND;
// Allocate space to save the user-entered domain name.
Win32Err = NetApiBufferAllocate((wcslen(Domain) + 1) * sizeof(WCHAR), (PVOID*)&pwzDomainName);
if ( Win32Err == ERROR_SUCCESS ) {
Win32Err = NetApiBufferAllocate(sizeof(UNICODE_STRING), (PVOID*)&TrustInfo->DomainName);
if ( Win32Err == ERROR_SUCCESS ) {
wcscpy( pwzDomainName, Domain );
RtlInitUnicodeString( TrustInfo->DomainName, pwzDomainName );
TrustInfo->FlatName = TrustInfo->DomainName; } } } else { LOG_VERBOSE((MSG_DOMAIN_NOT_FOUND, Domain)); }
NetApiBufferFree( DcInfo ); return( Win32Err ); }
DWORD NetDompTrustRemoveIncomingDownlevelObject( IN PND5_TRUST_INFO TrustingInfo, IN PND5_TRUST_INFO TrustedInfo ) /*++
Routine Description:
This function removes the interdomain trust account object on the trusted domain.
Arguments:
TrustingInfo - Info on the trusting domain
TrustedInfo - Info on the trusted domain
Return Value:
ERROR_INVALID_PARAMETER - No object name was supplied
--*/ { DWORD Win32Err = ERROR_SUCCESS; WCHAR AccountName[ UNLEN + 1 ]; PWSTR FullServer = NULL;
if ( TrustingInfo->FlatName->Length > DNLEN * sizeof( WCHAR ) ) {
return( ERROR_INVALID_DOMAINNAME ); }
if ( TrustedInfo->Server && *( TrustedInfo->Server ) != L'\\' ) {
Win32Err = NetApiBufferAllocate( ( wcslen( TrustedInfo->Server ) + 3 ) * sizeof( WCHAR ), ( PVOID * )&FullServer );
if ( Win32Err == ERROR_SUCCESS ) {
swprintf( FullServer, L"\\\\%ws", TrustedInfo->Server ); }
} else {
FullServer = TrustedInfo->Server; }
//
// Build the account name...
//
if ( Win32Err == ERROR_SUCCESS ) {
swprintf( AccountName, L"%ws$", TrustingInfo->FlatName->Buffer );
LOG_VERBOSE(( MSG_VERBOSE_DELETE_TACCT, AccountName )); Win32Err = NetUserDel( FullServer, AccountName ); }
if ( FullServer != TrustedInfo->Server ) {
NetApiBufferFree( FullServer ); }
return( Win32Err ); }
DWORD NetDompTrustRemoveOutgoingDownlevelObject( IN PND5_TRUST_INFO TrustingInfo, IN PND5_TRUST_INFO TrustedInfo ) /*++
Routine Description:
This function deletes the trust object/secret on the trusting domain.
Arguments:
TrustingInfo - Info on the trusting domain
TrustedInfo - Info on the trusted domain
Return Value:
ERROR_INVALID_PARAMETER - No object name was supplied
--*/ { DWORD Win32Err = ERROR_SUCCESS; WCHAR SecretName[ DNLEN + 4 ]; LSA_HANDLE TrustedDomain, SecretHandle; NTSTATUS Status; UNICODE_STRING Secret;
if ( TrustedInfo->FlatName->Length > DNLEN * sizeof( WCHAR ) ) {
return( ERROR_INVALID_DOMAINNAME ); }
if ( !TrustedInfo->Sid ) {
// Must be an orphaned trust, nothing we can do.
return NO_ERROR; }
//
// Build the secret name
//
swprintf( SecretName, L"%ws$%ws", LSA_GLOBAL_SECRET_PREFIX, TrustedInfo->FlatName->Buffer );
//
// Ok, first, delete the trust object. It's ok if the trust object is deleted but the
// secret is not
//
LOG_VERBOSE(( MSG_VERBOSE_OPEN_TRUST, TrustedInfo->DomainName->Buffer )); Status = LsaOpenTrustedDomain( TrustingInfo->LsaHandle, TrustedInfo->Sid, DELETE, &TrustedDomain );
if ( NT_SUCCESS( Status ) ) {
LOG_VERBOSE(( MSG_VERBOSE_DELETE_TRUST, TrustedInfo->DomainName->Buffer )); Status = LsaDelete( TrustedDomain );
if ( !NT_SUCCESS( Status ) ) {
LsaClose( TrustedDomain ); } }
//
// Now, the same with the secret
//
if ( NT_SUCCESS( Status ) ) {
RtlInitUnicodeString( &Secret, SecretName );
LOG_VERBOSE(( MSG_VERBOSE_OPEN_SECRET, Secret.Buffer )); Status = LsaOpenSecret( TrustingInfo->LsaHandle, &Secret, DELETE, &SecretHandle ); if ( NT_SUCCESS( Status ) ) { LOG_VERBOSE(( MSG_VERBOSE_DELETE_SECRET, Secret.Buffer )); Status = LsaDelete( SecretHandle );
if ( !NT_SUCCESS( Status ) ) {
LsaClose( SecretHandle ); } } }
Win32Err = RtlNtStatusToDosError( Status );
return( Win32Err ); }
DWORD NetDompTrustSetPasswordSam( IN PWSTR Server, IN PWSTR AccountName, IN PWSTR Password ) /*++
Routine Description:
This function will set the password on a SAM trust object
Arguments:
Server - Server that holds the account object
AccountName - Name of the account
Password - Password to set
Return Value:
ERROR_SUCCESS - The function succeeded
--*/ { DWORD Win32Err = ERROR_SUCCESS; USER_INFO_1 UI1, *ReadUI1 = NULL; PWSTR FullServer = NULL;
if ( Server && *( Server ) != L'\\' ) {
Win32Err = NetApiBufferAllocate( ( wcslen( Server ) + 3 ) * sizeof( WCHAR ), ( PVOID * )&FullServer );
if ( Win32Err == ERROR_SUCCESS ) {
swprintf( FullServer, L"\\\\%ws", Server ); }
} else {
FullServer = Server; }
if ( Win32Err == ERROR_SUCCESS ) {
Win32Err = NetUserGetInfo( FullServer, AccountName, 1, ( LPBYTE * )&ReadUI1 );
if ( Win32Err == ERROR_SUCCESS ) {
if ( !FLAG_ON( ReadUI1->usri1_flags, UF_INTERDOMAIN_TRUST_ACCOUNT ) ) {
Win32Err = ERROR_SPECIAL_ACCOUNT;
} else {
ReadUI1->usri1_password = Password; ReadUI1->usri1_flags = UF_INTERDOMAIN_TRUST_ACCOUNT | UF_SCRIPT; Win32Err = NetUserSetInfo( FullServer, AccountName, 1, ( LPBYTE )ReadUI1, NULL ); }
NetApiBufferFree( ReadUI1 ); } }
if ( FullServer != Server ) {
NetApiBufferFree( FullServer ); }
return( Win32Err ); }
DWORD NetDompTrustAddIncomingDownlevelObject( IN PND5_TRUST_INFO TrustingInfo, IN PND5_TRUST_INFO TrustedInfo, IN PWSTR TrustPassword, IN ULONG PasswordLength ) /*++
Routine Description:
This function creates the interdomain trust account object on the trusted domain.
Arguments:
TrustingInfo - Info on the trusting domain
TrustedInfo - Info on the trusted domain
Return Value:
ERROR_INVALID_PARAMETER - No object name was supplied
--*/ { DWORD Win32Err = ERROR_SUCCESS; WCHAR AccountName[ UNLEN + 1 ]; USER_INFO_1 UI1; PWSTR FullServer = NULL;
if ( TrustingInfo->FlatName->Length > DNLEN * sizeof( WCHAR ) ) {
return( ERROR_INVALID_DOMAINNAME ); }
//
// Build the account name...
//
swprintf( AccountName, L"%ws$", TrustingInfo->FlatName->Buffer );
LOG_VERBOSE(( MSG_VERBOSE_ADD_TACCT, AccountName ));
UI1.usri1_name = AccountName; UI1.usri1_password = TrustPassword; UI1.usri1_password_age = 0; UI1.usri1_priv = USER_PRIV_USER; UI1.usri1_home_dir = NULL; UI1.usri1_comment = NULL; UI1.usri1_flags = UF_INTERDOMAIN_TRUST_ACCOUNT | UF_SCRIPT; UI1.usri1_script_path = NULL;
if ( TrustedInfo->Server && *( TrustedInfo->Server ) != L'\\' ) {
Win32Err = NetApiBufferAllocate( ( wcslen( TrustedInfo->Server ) + 3 ) * sizeof( WCHAR ), ( PVOID * )&FullServer );
if ( Win32Err == ERROR_SUCCESS ) {
swprintf( FullServer, L"\\\\%ws", TrustedInfo->Server );
}
} else {
FullServer = TrustedInfo->Server; }
if ( Win32Err == ERROR_SUCCESS ) {
Win32Err = NetUserAdd( FullServer, 1, ( LPBYTE )&UI1, NULL );
if ( Win32Err == NERR_UserExists ) {
Win32Err = NetDompTrustSetPasswordSam( FullServer, AccountName, TrustPassword ); } }
if ( FullServer != TrustedInfo->Server ) {
NetApiBufferFree( FullServer ); }
return( Win32Err ); }
DWORD NetDompTrustAddOutgoingDownlevelObject( IN PND5_TRUST_INFO TrustingInfo, IN PND5_TRUST_INFO TrustedInfo, IN PWSTR TrustPassword, IN ULONG PasswordLength ) /*++
Routine Description:
This function creates the trust secret on the trusting domain.
Arguments:
TrustingInfo - Info on the trusting domain
TrustedInfo - Info on the trusted domain
Return Value:
ERROR_INVALID_PARAMETER - No object name was supplied
--*/ { DWORD Win32Err = ERROR_SUCCESS; WCHAR SecretName[ DNLEN + 4 ]; LSA_HANDLE TrustedDomain = NULL, SecretHandle = NULL; NTSTATUS Status; UNICODE_STRING Secret, Password; BOOL DeleteSecret = FALSE; LSA_TRUST_INFORMATION TrustInfo;
if ( TrustedInfo->FlatName->Length > DNLEN * sizeof( WCHAR ) ) {
return( ERROR_INVALID_DOMAINNAME ); }
//
// Build the secret name
//
swprintf( SecretName, L"%ws$%ws", LSA_GLOBAL_SECRET_PREFIX, TrustedInfo->FlatName->Buffer );
//
// Ok, first, create the secret, It's ok if the secret is created but the
// trust object is not
//
RtlInitUnicodeString( &Secret, SecretName ); LOG_VERBOSE(( MSG_VERBOSE_CREATE_SECRET, Secret.Buffer ));
Status = LsaCreateSecret( TrustingInfo->LsaHandle, &Secret, SECRET_SET_VALUE, &SecretHandle );
if ( NT_SUCCESS( Status ) ) {
DeleteSecret = TRUE;
} else if ( Status == STATUS_OBJECT_NAME_COLLISION ) {
LOG_VERBOSE(( MSG_VERBOSE_OPEN_SECRET, Secret.Buffer )); Status = LsaOpenSecret( TrustingInfo->LsaHandle, &Secret, SECRET_SET_VALUE, &SecretHandle ); }
if ( NT_SUCCESS( Status ) ) {
RtlInitUnicodeString( &Password, TrustPassword ); Status = LsaSetSecret( SecretHandle, &Password, NULL ); }
//
// Ok, now create the trust object
//
if ( NT_SUCCESS( Status ) ) {
TrustInfo.Sid = TrustedInfo->Sid; RtlCopyMemory( &TrustInfo.Name, TrustedInfo->FlatName, sizeof( UNICODE_STRING ) );
LOG_VERBOSE(( MSG_VERBOSE_CREATE_TRUST, TrustInfo.Name.Buffer )); Status = LsaCreateTrustedDomain( TrustingInfo->LsaHandle, &TrustInfo, TRUSTED_QUERY_DOMAIN_NAME, &TrustedDomain );
if ( Status == STATUS_OBJECT_NAME_COLLISION ) {
Status = STATUS_SUCCESS; } }
if ( !NT_SUCCESS( Status ) && DeleteSecret ) {
LsaDelete( SecretHandle ); SecretHandle = NULL; }
Win32Err = RtlNtStatusToDosError( Status );
if ( SecretHandle ) {
LsaClose( SecretHandle ); }
if ( TrustedDomain ) {
LsaClose( TrustedDomain ); }
return( Win32Err ); }
DWORD NetDompAddOnTrustingSide( IN PND5_TRUST_INFO TrustedInfo, IN PND5_TRUST_INFO TrustingInfo, IN PWSTR TrustPassword, IN ULONG Direction, IN BOOL Mit ) /*++
Routine Description:
This function creates the trust object on the trusting domain.
Arguments:
TrustedInfo - Info on the trusted domain
TrustingInfo - Info on the trusting domain
Direction - The direction of the trust
Mit - If true, this is an MIT style trust
Return Value:
ERROR_INVALID_PARAMETER - No object name was supplied
--*/ { DWORD Win32Err = ERROR_SUCCESS; TRUSTED_DOMAIN_INFORMATION_EX TDIEx; PTRUSTED_DOMAIN_FULL_INFORMATION pFullInfo; TRUSTED_DOMAIN_AUTH_INFORMATION TDAI; LSA_AUTH_INFORMATION AuthData; ULONG PasswordLength = wcslen(TrustPassword); NTSTATUS Status; BOOL fSidSet = FALSE; PLSA_UNICODE_STRING pName;
if (TrustingInfo->Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND) { if (Mit) { return ERROR_SUCCESS; } else { return ERROR_INVALID_PARAMETER; } }
if ( TrustingInfo->Uplevel ) {
RtlCopyMemory( &TDIEx.Name, TrustedInfo->DomainName, sizeof( UNICODE_STRING ) ); TDIEx.Sid = TrustedInfo->Sid; TDIEx.TrustDirection = Direction;
if ( Mit ) {
TDIEx.TrustType = TRUST_TYPE_MIT; TDIEx.TrustAttributes = TRUST_ATTRIBUTE_NON_TRANSITIVE; RtlCopyMemory( &TDIEx.FlatName, TrustedInfo->DomainName, sizeof( UNICODE_STRING ) );
} else {
TDIEx.TrustType = TrustedInfo->Uplevel ? TRUST_TYPE_UPLEVEL : TRUST_TYPE_DOWNLEVEL; TDIEx.TrustAttributes = 0; RtlCopyMemory( &TDIEx.FlatName, TrustedInfo->FlatName, sizeof( UNICODE_STRING ) ); }
Status = NtQuerySystemTime( &AuthData.LastUpdateTime );
if ( NT_SUCCESS( Status ) ) {
AuthData.AuthType = TRUST_AUTH_TYPE_CLEAR; AuthData.AuthInfoLength = PasswordLength * sizeof( WCHAR ); AuthData.AuthInfo = ( PUCHAR )TrustPassword;
TDAI.OutgoingAuthInfos = 1; TDAI.OutgoingAuthenticationInformation = &AuthData; TDAI.OutgoingPreviousAuthenticationInformation = NULL;
if ( FLAG_ON( Direction, TRUST_DIRECTION_INBOUND ) ) {
TDAI.IncomingAuthInfos = 1; TDAI.IncomingAuthenticationInformation = &AuthData; TDAI.IncomingPreviousAuthenticationInformation = NULL;
} else {
TDAI.IncomingAuthInfos = 0; TDAI.IncomingAuthenticationInformation = NULL; TDAI.IncomingPreviousAuthenticationInformation = NULL; }
Status = LsaCreateTrustedDomainEx( TrustingInfo->LsaHandle, &TDIEx, &TDAI, TRUSTED_ALL_ACCESS, &( TrustingInfo->TrustHandle ) );
//
// If the object already exists, morph our info into it.
//
if ( Status == STATUS_OBJECT_NAME_COLLISION ) {
pName = &TDIEx.Name;
Status = LsaQueryTrustedDomainInfoByName(TrustingInfo->LsaHandle, pName, TrustedDomainFullInformation, (PVOID*)&pFullInfo);
if (STATUS_OBJECT_NAME_NOT_FOUND == Status) { // Now try by flat name; can get here if a downlevel domain
// is upgraded to NT5. The name used above was the DNS name
// but the TDO would be named after the flat name.
//
pName = TrustingInfo->FlatName;
Status = LsaQueryTrustedDomainInfoByName(TrustedInfo->LsaHandle, pName, TrustedDomainFullInformation, (PVOID*)&pFullInfo); }
if ( NT_SUCCESS( Status ) ) {
if ( pFullInfo->Information.TrustDirection == Direction ) {
Status = STATUS_OBJECT_NAME_COLLISION;
} else {
pFullInfo->Information.TrustDirection = TRUST_DIRECTION_BIDIRECTIONAL; pFullInfo->AuthInformation.OutgoingAuthInfos = 1; pFullInfo->AuthInformation.OutgoingAuthenticationInformation = &AuthData; pFullInfo->AuthInformation.OutgoingPreviousAuthenticationInformation = NULL;
// Check for a NULL domain SID. The SID can be NULL if the
// trust was created when the domain was still NT4.
//
if (!pFullInfo->Information.Sid) { pFullInfo->Information.Sid = TrustedInfo->Sid; fSidSet = TRUE; }
Status = LsaSetTrustedDomainInfoByName(TrustingInfo->LsaHandle, pName, TrustedDomainFullInformation, pFullInfo); } }
if (fSidSet) { // Sid memory is owned by the TrustingInfo struct, so don't free
// it here.
//
pFullInfo->Information.Sid = NULL; } LsaFreeMemory( pFullInfo ); } }
Win32Err = RtlNtStatusToDosError( Status );
} else {
//
// Doing downlevel
//
if ( Mit ) {
Win32Err = ERROR_INVALID_PARAMETER;
} else {
Win32Err = NetDompTrustAddOutgoingDownlevelObject( TrustingInfo, TrustedInfo, TrustPassword, PasswordLength );
if ( Win32Err == ERROR_SUCCESS && Direction == TRUST_DIRECTION_BIDIRECTIONAL ) {
Win32Err = NetDompTrustAddIncomingDownlevelObject( TrustedInfo, TrustingInfo, TrustPassword, PasswordLength );
if ( Win32Err != ERROR_SUCCESS ) {
Win32Err = NetDompTrustRemoveOutgoingDownlevelObject( TrustingInfo, TrustedInfo );
} }
} }
if (ERROR_SUCCESS == Win32Err) { LOG_VERBOSE((MSG_VERBOSE_CREATED_TRUST, TrustedInfo->DomainName->Buffer, TrustingInfo->DomainName->Buffer)); }
return( Win32Err ); }
DWORD NetDompAddOnTrustedSide( IN PND5_TRUST_INFO TrustedInfo, IN PND5_TRUST_INFO TrustingInfo, IN PWSTR TrustPassword, IN ULONG Direction, IN BOOL Mit ) /*++
Routine Description:
This function creates the trust object on the trusted domain.
Arguments:
TrustedInfo - Info on the trusted domain
TrustingInfo - Info on the trusting domain
Direction - The direction of the trust
Mit - If true, this is an MIT style trust
Return Value:
ERROR_INVALID_PARAMETER - No object name was supplied
--*/ { DWORD Win32Err = ERROR_SUCCESS; TRUSTED_DOMAIN_INFORMATION_EX TDIEx; PTRUSTED_DOMAIN_FULL_INFORMATION pFullInfo; LSA_AUTH_INFORMATION AuthData; TRUSTED_DOMAIN_AUTH_INFORMATION TDAI; ULONG PasswordLength = wcslen(TrustPassword); NTSTATUS Status; BOOL fSidSet = FALSE; PLSA_UNICODE_STRING pName;
if (TrustedInfo->Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND) { if (Mit) { return ERROR_SUCCESS; } else { return ERROR_INVALID_PARAMETER; } }
if ( TrustedInfo->Uplevel) {
RtlCopyMemory( &TDIEx.Name, TrustingInfo->DomainName, sizeof( UNICODE_STRING ) ); TDIEx.Sid = TrustingInfo->Sid; TDIEx.TrustDirection = Direction;
if ( Mit ) {
TDIEx.TrustType = TRUST_TYPE_MIT; TDIEx.TrustAttributes = TRUST_ATTRIBUTE_NON_TRANSITIVE; RtlCopyMemory( &TDIEx.FlatName, TrustingInfo->DomainName, sizeof( UNICODE_STRING ) );
} else {
TDIEx.TrustType = TrustingInfo->Uplevel ? TRUST_TYPE_UPLEVEL : TRUST_TYPE_DOWNLEVEL; TDIEx.TrustAttributes = 0; RtlCopyMemory( &TDIEx.FlatName, TrustingInfo->FlatName, sizeof( UNICODE_STRING ) ); }
Status = NtQuerySystemTime( &AuthData.LastUpdateTime );
if ( NT_SUCCESS( Status ) ) {
AuthData.AuthType = TRUST_AUTH_TYPE_CLEAR; AuthData.AuthInfoLength = PasswordLength * sizeof( WCHAR ); AuthData.AuthInfo = ( PUCHAR )TrustPassword;
TDAI.IncomingAuthInfos = 1; TDAI.IncomingAuthenticationInformation = &AuthData; TDAI.IncomingPreviousAuthenticationInformation = &AuthData;
if ( FLAG_ON( Direction, TRUST_DIRECTION_OUTBOUND ) ) {
TDAI.OutgoingAuthInfos = 1; TDAI.OutgoingAuthenticationInformation = &AuthData; TDAI.OutgoingPreviousAuthenticationInformation = NULL;
} else {
TDAI.OutgoingAuthInfos = 0; TDAI.OutgoingAuthenticationInformation = NULL; TDAI.OutgoingPreviousAuthenticationInformation = NULL; }
Status = LsaCreateTrustedDomainEx( TrustedInfo->LsaHandle, &TDIEx, &TDAI, TRUSTED_ALL_ACCESS, &( TrustedInfo->TrustHandle ) );
//
// If the object already exists, morph our info into it.
//
if ( Status == STATUS_OBJECT_NAME_COLLISION ) {
pName = &TDIEx.Name;
Status = LsaQueryTrustedDomainInfoByName(TrustedInfo->LsaHandle, pName, TrustedDomainFullInformation, (PVOID*)&pFullInfo);
if (STATUS_OBJECT_NAME_NOT_FOUND == Status) { // Now try by flat name; can get here if a downlevel domain
// is upgraded to NT5. The name used above was the DNS name
// but the TDO would be named after the flat name.
//
pName = TrustingInfo->FlatName;
Status = LsaQueryTrustedDomainInfoByName(TrustedInfo->LsaHandle, pName, TrustedDomainFullInformation, (PVOID*)&pFullInfo); }
if ( NT_SUCCESS( Status ) ) {
if ( pFullInfo->Information.TrustDirection == Direction ) {
Status = STATUS_OBJECT_NAME_COLLISION;
} else {
pFullInfo->Information.TrustDirection = TRUST_DIRECTION_BIDIRECTIONAL; pFullInfo->AuthInformation.IncomingAuthInfos = 1; pFullInfo->AuthInformation.IncomingAuthenticationInformation = &AuthData; pFullInfo->AuthInformation.IncomingPreviousAuthenticationInformation = NULL;
// Check for a NULL domain SID. The SID can be NULL if the
// trust was created when the domain was still NT4.
//
if (!pFullInfo->Information.Sid) { pFullInfo->Information.Sid = TrustingInfo->Sid; fSidSet = TRUE; }
Status = LsaSetTrustedDomainInfoByName(TrustedInfo->LsaHandle, pName, TrustedDomainFullInformation, pFullInfo); } }
if (fSidSet) { // Sid memory is owned by the TrustingInfo struct, so don't free
// it here.
//
pFullInfo->Information.Sid = NULL; } LsaFreeMemory( pFullInfo ); } }
Win32Err = RtlNtStatusToDosError( Status );
} else {
//
// Doing downlevel
//
if ( Mit ) {
Win32Err = ERROR_INVALID_PARAMETER;
} else {
Win32Err = NetDompTrustAddIncomingDownlevelObject( TrustingInfo, TrustedInfo, TrustPassword, PasswordLength );
if ( Win32Err == ERROR_SUCCESS && FLAG_ON( Direction, TRUST_DIRECTION_OUTBOUND ) ) {
Win32Err = NetDompTrustAddOutgoingDownlevelObject( TrustedInfo, TrustingInfo, TrustPassword, PasswordLength );
if ( Win32Err != ERROR_SUCCESS ) {
Win32Err = NetDompTrustRemoveIncomingDownlevelObject( TrustingInfo, TrustedInfo );
} } } }
if (ERROR_SUCCESS == Win32Err) { LOG_VERBOSE((MSG_VERBOSE_CREATED_TRUST, TrustingInfo->DomainName->Buffer, TrustedInfo->DomainName->Buffer)); }
return( Win32Err ); }
DWORD NetDompResetTrustSC( IN PND5_TRUST_INFO TrustingInfo, IN PND5_TRUST_INFO TrustedInfo ) /*++
Routine Description:
This function will reset the secure channel between two domains
Arguments:
TrustingInfo - Information on the trusting side of the domain
TrustedInfo - Information on the trusted side of the domain
Return Value:
ERROR_SUCCESS - The function succeeded
--*/ { DWORD Win32Err = ERROR_SUCCESS; PWSTR ScDomain = NULL; PNETLOGON_INFO_2 NetlogonInfo2 = NULL; PWSTR FullServer = NULL, pwzDomName = NULL;
if (!TrustingInfo->Server) { return ERROR_INVALID_PARAMETER; }
Win32Err = NetApiBufferAllocate( TrustedInfo->DomainName->Length + sizeof( WCHAR ) + ( wcslen( TrustedInfo->Server ) * sizeof( WCHAR ) ) + sizeof( WCHAR ), (PVOID*)&ScDomain );
if (ERROR_SUCCESS != Win32Err) { return Win32Err; }
if (*(TrustingInfo->Server) == L'\\') { FullServer = TrustingInfo->Server; } else { Win32Err = NetApiBufferAllocate((wcslen(TrustingInfo->Server) + 3) * sizeof(WCHAR), (PVOID *)&FullServer);
if (ERROR_SUCCESS != Win32Err) { return Win32Err; }
swprintf(FullServer, L"\\\\%ws", TrustingInfo->Server); }
if (TrustedInfo->fWasDownlevel) { pwzDomName = TrustedInfo->FlatName->Buffer; } else { pwzDomName = TrustedInfo->DomainName->Buffer; }
if (*(TrustedInfo->Server) == L'\\') { swprintf(ScDomain, L"%ws%ws", pwzDomName, TrustedInfo->Server + 1); } else { swprintf(ScDomain, L"%ws\\%ws", pwzDomName, TrustedInfo->Server); }
if ( Win32Err == ERROR_SUCCESS ) {
LOG_VERBOSE(( MSG_VERBOSE_RESET_SC, ScDomain )); Win32Err = I_NetLogonControl2( FullServer, NETLOGON_CONTROL_REDISCOVER, 2, ( LPBYTE )&ScDomain, ( LPBYTE *)&NetlogonInfo2 );
if ( Win32Err == ERROR_NO_SUCH_DOMAIN || Win32Err == ERROR_INVALID_PARAMETER ) {
LOG_VERBOSE(( MSG_VERBOSE_RETRY_RESET_SC, ScDomain, TrustedInfo->DomainName->Buffer ));
//
// Must be using an downlevel domain, so try it again with out the server
//
Win32Err = I_NetLogonControl2( FullServer, NETLOGON_CONTROL_REDISCOVER, 2, ( LPBYTE )&( TrustedInfo->DomainName->Buffer ), ( LPBYTE *)&NetlogonInfo2 );
if ( Win32Err == ERROR_SUCCESS ) {
LOG_VERBOSE(( MSG_VERBOSE_RESET_NOT_NAMED, TrustedInfo->Server )); } } }
NetApiBufferFree( ScDomain ); if (FullServer != TrustingInfo->Server) { NetApiBufferFree(FullServer); }
return( Win32Err ); }
DWORD NetDompTrustRemoveObject( IN PND5_TRUST_INFO LocalDomainInfo, IN PND5_TRUST_INFO TrustDomainInfo, IN ULONG Direction, IN BOOL fForce, IN PND5_AUTH_INFO pAuthInfo ) /*++
Routine Description:
This function removes the specified trust
Arguments:
LocalDomainInfo - Info on the domain where the operation is being performed
TrustDomainInfo - Info on the trusted/trusting domain
Direction - The direction of the trust
fForce - If true, remove even if a child.
Return Value:
ERROR_INVALID_PARAMETER - No object name was supplied
--*/ { DWORD Win32Err = ERROR_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; PTRUSTED_DOMAIN_INFORMATION_EX ReadTDIEx = NULL; BOOL fChild = (TrustDomainInfo->Flags & NETDOM_TRUST_FLAG_CHILD); PLDAP pLdap; HANDLE hDS; PWSTR pwzConfigPath, pwzPartitionsPath, pwzFSMORoleOwner, pwzServerPath, pwzServerDNSname, pwzDomainName, pwzNcName, pwzServerObjDN, pwzSettingsDN, pwzFilter; WCHAR wzPartition[] = L"CN=Partitions,"; WCHAR wzFilterFormat[] = L"(&(objectClass=nTDSDSA)(hasMasterNCs=%s))"; RPC_AUTH_IDENTITY_HANDLE AuthHandle; PDS_NAME_RESULT pNameResult; LDAPMessage *Message = NULL, *Entry; PWSTR Attrib[2] = { L"foo", NULL };
ASSERT(!(fChild && !fForce)); ASSERT(!(TrustDomainInfo->Flags & NETDOM_TRUST_FLAG_PARENT));
if ( LocalDomainInfo->Uplevel ) {
LOG_VERBOSE(( MSG_VERBOSE_OPEN_TRUST, TrustDomainInfo->DomainName->Buffer ));
if ( !LocalDomainInfo->TrustHandle ) {
Status = LsaOpenTrustedDomainByName( LocalDomainInfo->LsaHandle, TrustDomainInfo->DomainName, TRUSTED_ALL_ACCESS, // DELETE | TRUSTED_QUERY_DOMAIN_NAME,
&( LocalDomainInfo->TrustHandle ) ); }
if (STATUS_OBJECT_NAME_NOT_FOUND == Status && TrustDomainInfo->Uplevel) { // Pre-existing TDOs for domains upgraded from NT4 to NT5 will continue to
// have a flat name.
//
TrustDomainInfo->fWasDownlevel = TRUE;
Status = LsaOpenTrustedDomainByName( LocalDomainInfo->LsaHandle, TrustDomainInfo->FlatName, TRUSTED_ALL_ACCESS, // DELETE | TRUSTED_QUERY_DOMAIN_NAME,
&( LocalDomainInfo->TrustHandle ) ); }
if ( NT_SUCCESS( Status ) ) {
if ( Direction == TRUST_DIRECTION_BIDIRECTIONAL ) {
LOG_VERBOSE(( MSG_VERBOSE_DELETE_TRUST, TrustDomainInfo->DomainName->Buffer ));
Status = LsaDelete( LocalDomainInfo->TrustHandle );
if ( NT_SUCCESS( Status ) ) {
LocalDomainInfo->TrustHandle = NULL; }
} else {
LOG_VERBOSE(( MSG_VERBOSE_GET_TRUST, TrustDomainInfo->DomainName->Buffer ));
Status = LsaQueryInfoTrustedDomain( LocalDomainInfo->TrustHandle, TrustedDomainInformationEx, (PVOID*)&ReadTDIEx );
if ( NT_SUCCESS( Status ) ) {
ReadTDIEx->TrustDirection &= ~Direction;
if ( 0 == ReadTDIEx->TrustDirection ) { LOG_VERBOSE(( MSG_VERBOSE_DELETE_TRUST, TrustDomainInfo->DomainName->Buffer ));
Status = LsaDelete( LocalDomainInfo->TrustHandle );
if ( NT_SUCCESS( Status ) ) {
LocalDomainInfo->TrustHandle = NULL; } } else {
LOG_VERBOSE(( MSG_VERBOSE_SET_TRUST, TrustDomainInfo->DomainName->Buffer ));
Status = LsaSetInformationTrustedDomain( LocalDomainInfo->TrustHandle, TrustedDomainInformationEx, ReadTDIEx ); }
LsaFreeMemory( ReadTDIEx ); } } } else {
if (STATUS_OBJECT_NAME_NOT_FOUND == Status) {
LOG_VERBOSE(( MSG_VERBOSE_TDO_NOT_FOUND, TrustDomainInfo->DomainName->Buffer )); } }
Win32Err = LsaNtStatusToWinError(Status);
DBG_VERBOSE(("Return code from LsaOpen: %d (LSA: %x)\n", Win32Err, Status));
if (fChild) {
// Remove the cross ref object. To do that, locate and bind to the naming
// FSMO DC.
//
LOG_VERBOSE((MSG_VERBOSE_DELETE_CROSS_REF, TrustDomainInfo->DomainName->Buffer));
Win32Err = NetDompLdapBind(LocalDomainInfo->Server + 2, // skip the backslashes
(pAuthInfo->pwzUsersDomain) ? pAuthInfo->pwzUsersDomain : NULL, (pAuthInfo->pwzUserWoDomain) ? pAuthInfo->pwzUserWoDomain : pAuthInfo->User, pAuthInfo->Password, LDAP_AUTH_SSPI, &pLdap);
if (Win32Err != ERROR_SUCCESS) { return Win32Err; }
DBG_VERBOSE(("bind succeeded\n"));
Win32Err = NetDompLdapReadOneAttribute(pLdap, NULL, //L"RootDSE",
L"configurationNamingContext", &pwzConfigPath);
if (Win32Err != ERROR_SUCCESS) { NetDompLdapUnbind(pLdap); return Win32Err; }
Win32Err = NetApiBufferAllocate((wcslen(pwzConfigPath) + wcslen(wzPartition) + 1) * sizeof(WCHAR), (PVOID*)&pwzPartitionsPath);
if (Win32Err != ERROR_SUCCESS) { NetApiBufferFree(pwzConfigPath); NetDompLdapUnbind(pLdap); return Win32Err; }
wsprintf(pwzPartitionsPath, L"%s%s", wzPartition, pwzConfigPath);
DBG_VERBOSE(("path: %ws\n", pwzPartitionsPath));
Win32Err = NetDompLdapReadOneAttribute(pLdap, pwzPartitionsPath, L"fSMORoleOwner", &pwzFSMORoleOwner); NetApiBufferFree(pwzPartitionsPath);
if (Win32Err != ERROR_SUCCESS) { NetApiBufferFree(pwzConfigPath); NetDompLdapUnbind(pLdap); return Win32Err; }
DBG_VERBOSE(("fSMORoleOwner: %ws\n", pwzFSMORoleOwner));
pwzServerPath = wcschr(pwzFSMORoleOwner, L',');
if (!pwzServerPath) { NetApiBufferFree(pwzConfigPath); NetApiBufferFree(pwzFSMORoleOwner); NetDompLdapUnbind(pLdap); return ERROR_INVALID_DATA; }
pwzServerPath++;
Win32Err = NetDompLdapReadOneAttribute(pLdap, pwzServerPath, L"dNSHostName", &pwzServerDNSname); NetApiBufferFree(pwzFSMORoleOwner);
if (Win32Err != ERROR_SUCCESS) { NetApiBufferFree(pwzConfigPath); NetDompLdapUnbind(pLdap); return Win32Err; }
DBG_VERBOSE(("Role owner server DNS name: %ws\n", pwzServerDNSname));
Win32Err = DsMakePasswordCredentials((pAuthInfo->pwzUserWoDomain) ? pAuthInfo->pwzUserWoDomain : pAuthInfo->User, (pAuthInfo->pwzUsersDomain) ? pAuthInfo->pwzUsersDomain : NULL, pAuthInfo->Password, &AuthHandle); if (Win32Err != ERROR_SUCCESS) { NetApiBufferFree(pwzConfigPath); NetApiBufferFree(pwzServerDNSname); return Win32Err; }
Win32Err = DsBindWithCred(pwzServerDNSname, NULL, AuthHandle, &hDS);
NetApiBufferFree(pwzServerDNSname); DsFreePasswordCredentials(AuthHandle);
if (Win32Err != ERROR_SUCCESS) { NetApiBufferFree(pwzConfigPath); return Win32Err; }
DBG_VERBOSE(("DsBind Succeeded, getting domain NC name.\n"));
Win32Err = NetApiBufferAllocate((wcslen(TrustDomainInfo->DomainName->Buffer) + 2) * sizeof(WCHAR), (PVOID*)&pwzDomainName); if (Win32Err != ERROR_SUCCESS) { NetApiBufferFree(pwzConfigPath); NetDompLdapUnbind(pLdap); DsUnBind(&hDS); return Win32Err; }
//
// Get the domain Naming Context DN to use for the removal of the cross-ref.
// On the first try to get the domain NC DN, assume that the domain name is
// an NT4 flat name. A backslash must be appended.
//
wcscpy(pwzDomainName, TrustDomainInfo->DomainName->Buffer); wcscat(pwzDomainName, L"\\");
DBG_VERBOSE(("Name passed to DsCrackNames is %ws.\n", pwzDomainName));
Win32Err = DsCrackNames(hDS, DS_NAME_NO_FLAGS, DS_NT4_ACCOUNT_NAME, DS_FQDN_1779_NAME, 1, &pwzDomainName, &pNameResult);
if (Win32Err != ERROR_SUCCESS) { NetApiBufferFree(pwzConfigPath); NetApiBufferFree(pwzDomainName); NetDompLdapUnbind(pLdap); DsUnBind(&hDS); return Win32Err; }
ASSERT(pNameResult); ASSERT(pNameResult->cItems == 1);
if (DS_NAME_NO_ERROR != pNameResult->rItems->status) { // Try again, this time assume that it might be a DNS name. Replace
// the back slash with a forward slash.
//
pwzDomainName[wcslen(pwzDomainName) -1] = L'/';
DsFreeNameResultW(pNameResult);
DBG_VERBOSE(("Try again, name passed to DsCrackNames is %ws.\n", pwzDomainName));
Win32Err = DsCrackNames(hDS, DS_NAME_NO_FLAGS, DS_CANONICAL_NAME, DS_FQDN_1779_NAME, 1, &pwzDomainName, &pNameResult);
if (Win32Err != ERROR_SUCCESS) { NetApiBufferFree(pwzConfigPath); NetApiBufferFree(pwzDomainName); NetDompLdapUnbind(pLdap); DsUnBind(&hDS); return Win32Err; } ASSERT(pNameResult); ASSERT(pNameResult->cItems == 1); }
NetApiBufferFree(pwzDomainName);
if (DS_NAME_NO_ERROR != pNameResult->rItems->status) { NetApiBufferFree(pwzConfigPath); DsFreeNameResultW(pNameResult); NetDompLdapUnbind(pLdap); DsUnBind(&hDS); return ERROR_NO_SUCH_DOMAIN; }
//
// Delete the Server object for the domain. Get the name of the server
// object by searching for the NTDS-Settings object that references the
// domain NC.
//
Win32Err = NetApiBufferAllocate((wcslen(wzFilterFormat) + wcslen(pNameResult->rItems->pName) + 1) * sizeof(WCHAR), (PVOID*)&pwzFilter);
if (Win32Err != ERROR_SUCCESS) { DsFreeNameResultW(pNameResult); NetApiBufferFree(pwzConfigPath); NetDompLdapUnbind(pLdap); DsUnBind(&hDS); return Win32Err; }
swprintf(pwzFilter, wzFilterFormat, pNameResult->rItems->pName);
DBG_VERBOSE(("search filter: %ws\n", pwzFilter));
Win32Err = LdapMapErrorToWin32(ldap_search_s(pLdap, pwzConfigPath, LDAP_SCOPE_SUBTREE, pwzFilter, Attrib, 0, &Message));
if (Win32Err != ERROR_SUCCESS) { DBG_VERBOSE(("search for Settings object failed with error %d\n", Win32Err)); NetApiBufferFree(pwzConfigPath); DsFreeNameResultW(pNameResult); NetDompLdapUnbind(pLdap); DsUnBind(&hDS); return Win32Err; }
Entry = ldap_first_entry(pLdap, Message);
if (Entry) {
pwzSettingsDN = ldap_get_dnW(pLdap, Entry);
DBG_VERBOSE(("NTDS Settings object DN: %ws\n", pwzSettingsDN));
if (pwzSettingsDN) {
pwzServerObjDN = wcschr(pwzSettingsDN, L',');
if (pwzServerObjDN) {
pwzServerObjDN++;
Win32Err = DsRemoveDsServerW(hDS, pwzServerObjDN, NULL, NULL, TRUE);
if (Win32Err == ERROR_SUCCESS) { LOG_VERBOSE((MSG_VERBOSE_NTDSDSA_DELETED, pwzServerObjDN)); } else { DBG_VERBOSE(("DsRemoveDsServer failed with error %d\n", Win32Err));
LOG_VERBOSE((MSG_VERBOSE_NTDSDSA_NOT_REMOVED, pwzServerObjDN)); } } }
ldap_memfree(pwzSettingsDN); } else {
Win32Err = LdapMapErrorToWin32(pLdap->ld_errno); DBG_VERBOSE(("search results for Settings object failed with error %d\n", Win32Err)); } ldap_msgfree(Message);
NetDompLdapUnbind(pLdap); // add to error returns above.
NetApiBufferFree(pwzConfigPath);
//
// Now remove the cross-ref object.
//
DBG_VERBOSE(("About to remove the cross-ref for NC %ws.\n", pNameResult->rItems->pName));
Win32Err = DsRemoveDsDomainW(hDS, pNameResult->rItems->pName);
if (Win32Err == ERROR_SUCCESS) { LOG_VERBOSE((MSG_VERBOSE_CROSS_REF_DELETED, pNameResult->rItems->pName)); } else { DBG_VERBOSE(("DsRemoveDsDomain returned %d.\n", Win32Err));
if (ERROR_DS_NO_CROSSREF_FOR_NC == Win32Err) { LOG_VERBOSE((MSG_VERBOSE_CROSS_REF_NOT_FOUND, pNameResult->rItems->pName)); } }
DsFreeNameResultW(pNameResult); DsUnBind(&hDS); }
} else {
if ( FLAG_ON( Direction, TRUST_DIRECTION_INBOUND ) ) {
Win32Err = NetDompTrustRemoveIncomingDownlevelObject( TrustDomainInfo, LocalDomainInfo ); if ( Win32Err == NERR_UserNotFound ) {
Win32Err = ERROR_SUCCESS; } }
if ( Win32Err == ERROR_SUCCESS && FLAG_ON( Direction, TRUST_DIRECTION_OUTBOUND ) ) {
Win32Err = NetDompTrustRemoveOutgoingDownlevelObject( LocalDomainInfo, TrustDomainInfo ); } }
return( Win32Err ); }
DWORD NetDompCreateTrustObject( IN ARG_RECORD * rgNetDomArgs, IN PWSTR TrustingDomain, IN PWSTR TrustedDomain, IN PND5_AUTH_INFO pTrustingCreds, IN PND5_AUTH_INFO pTrustedCreds, IN PWSTR pwzTrustPW, IN PWSTR pwzWhichSide ) /*++
Routine Description:
This function will handle the adding of a trusted domain object
Arguments:
rgNetDomArgs - List of arguments present in the Args list
TrustingDomain - Trusting side of the trust
TrustedDomain - Trusted side of the trust
pTrustingCreds - Credentials to use when connecting to a domain controller in the trusting domain
pTrustedCreds - Credentials to use when connecting to a domain controller in the trusted domain
pwzTrustPW - Required for creating MIT trust.
pwzWhichSide - Required for creating one-side-only, names the side.
Return Value:
ERROR_INVALID_PARAMETER - No object name was supplied
--*/ { DWORD Win32Err = ERROR_SUCCESS; ND5_TRUST_INFO TrustingInfo, TrustedInfo; WCHAR TrustPassword[ LM20_PWLEN + 1 ]; PWSTR pwzPW = NULL; WCHAR wzTrusted[NETDOM_STR_LEN], wzTrusting[NETDOM_STR_LEN]; BOOL fCreateOnTrusted = FALSE, fCreateOnTrusting = FALSE;
RtlZeroMemory( &TrustingInfo, sizeof( TrustingInfo ) ); RtlZeroMemory( &TrustedInfo, sizeof( TrustedInfo ) );
if (CmdFlagOn(rgNetDomArgs, eTrustOneSide)) { if (!LoadString(g_hInstance, IDS_ONESIDE_TRUSTED, wzTrusted, NETDOM_STR_LEN) || !LoadString(g_hInstance, IDS_ONESIDE_TRUSTING, wzTrusting, NETDOM_STR_LEN)) { printf("LoadString FAILED!\n"); return ERROR_RESOURCE_NAME_NOT_FOUND; }
// Determine on which domain the trust should be created.
//
if (_wcsicmp(pwzWhichSide, wzTrusted) == 0) { fCreateOnTrusted = TRUE; } else if (_wcsicmp(pwzWhichSide, wzTrusting) == 0) { fCreateOnTrusting = TRUE; } else { NetDompDisplayMessage(MSG_ONESIDE_ARG_STRING); return ERROR_INVALID_PARAMETER; } }
Win32Err = NetDompTrustGetDomInfo( TrustingDomain, NULL, pTrustingCreds, &TrustingInfo, !fCreateOnTrusted, CmdFlagOn(rgNetDomArgs, eTrustRealm), fCreateOnTrusted);
if ( Win32Err == ERROR_SUCCESS ) {
Win32Err = NetDompTrustGetDomInfo( TrustedDomain, NULL, pTrustedCreds, &TrustedInfo, !fCreateOnTrusting, CmdFlagOn(rgNetDomArgs, eTrustRealm), fCreateOnTrusting); }
if ( Win32Err != ERROR_SUCCESS ) {
goto TrustAddExit; }
if (CmdFlagOn(rgNetDomArgs, eTrustRealm)) { if (!(TrustingInfo.Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND) && !(TrustedInfo.Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND)) { // Both domains found (both are Windows domains), can't establish an MIT trust.
//
NetDompDisplayMessage(MSG_RESET_MIT_TRUST_NOT_MIT); Win32Err = ERROR_INVALID_PARAMETER; goto TrustAddExit; }
pwzPW = pwzTrustPW; } else if (CmdFlagOn(rgNetDomArgs, eTrustOneSide)) { // Create the trust on only one of the two domains.
//
if (fCreateOnTrusted) { Win32Err = NetDompAddOnTrustedSide(&TrustedInfo, &TrustingInfo, pwzTrustPW, CmdFlagOn(rgNetDomArgs, eTrustTwoWay) ? TRUST_DIRECTION_BIDIRECTIONAL : TRUST_DIRECTION_INBOUND, FALSE); } else { Win32Err = NetDompAddOnTrustingSide(&TrustedInfo, &TrustingInfo, pwzTrustPW, CmdFlagOn(rgNetDomArgs, eTrustTwoWay) ? TRUST_DIRECTION_BIDIRECTIONAL : TRUST_DIRECTION_OUTBOUND, FALSE); } goto TrustAddExit; } else { Win32Err = NetDompGenerateRandomPassword( TrustPassword, LM20_PWLEN );
if ( Win32Err != ERROR_SUCCESS ) {
goto TrustAddExit; }
pwzPW = TrustPassword; }
//
// Ok, now that we have the password, let's create the trust
//
Win32Err = NetDompAddOnTrustedSide( &TrustedInfo, &TrustingInfo, pwzPW, CmdFlagOn(rgNetDomArgs, eTrustTwoWay) ? TRUST_DIRECTION_BIDIRECTIONAL : TRUST_DIRECTION_INBOUND, CmdFlagOn(rgNetDomArgs, eTrustRealm));
if ( Win32Err == ERROR_SUCCESS ) {
Win32Err = NetDompAddOnTrustingSide( &TrustedInfo, &TrustingInfo, pwzPW, CmdFlagOn(rgNetDomArgs, eTrustTwoWay) ? TRUST_DIRECTION_BIDIRECTIONAL : TRUST_DIRECTION_OUTBOUND, CmdFlagOn(rgNetDomArgs, eTrustRealm)); } TrustAddExit:
NetDompFreeDomInfo( &TrustedInfo ); NetDompFreeDomInfo( &TrustingInfo );
return( Win32Err ); }
DWORD NetDompRemoveTrustObject( IN ARG_RECORD * rgNetDomArgs, IN PWSTR TrustingDomain, IN PWSTR TrustedDomain, IN PND5_AUTH_INFO pTrustingCreds, IN PND5_AUTH_INFO pTrustedCreds ) /*++
Routine Description:
This function will handle the removal of a trusted domain object
Arguments:
rgNetDomArgs - List of arguments present in the Args list
TrustingDomain - Trusting side of the trust
TrustedDomain - Trusted side of the trust
pTrustingCreds - Credentials to use when connecting to a domain controller in the trusting domain
pTrustedCreds - Credentials to use when connecting to a domain controller in the trusted domain
Return Value:
ERROR_INVALID_PARAMETER - No object name was supplied
--*/ { DWORD Win32Err = ERROR_SUCCESS; ND5_TRUST_INFO TrustingInfo, TrustedInfo; BOOL fForce = CmdFlagOn(rgNetDomArgs, eCommForce); BOOL TwoWay = CmdFlagOn(rgNetDomArgs, eTrustTwoWay); BOOL fParentChild = FALSE, fVerifyChildDelete = FALSE;
RtlZeroMemory( &TrustingInfo, sizeof( TrustingInfo ) ); RtlZeroMemory( &TrustedInfo, sizeof( TrustedInfo ) );
Win32Err = NetDompTrustGetDomInfo( TrustingDomain, NULL, pTrustingCreds, &TrustingInfo, TRUE, fForce, FALSE );
if ( Win32Err == ERROR_SUCCESS ) {
Win32Err = NetDompTrustGetDomInfo( TrustedDomain, NULL, pTrustedCreds, &TrustedInfo, TRUE, fForce, FALSE ); }
if ( Win32Err != ERROR_SUCCESS ) {
if (ERROR_NO_SUCH_DOMAIN == Win32Err) {
NetDompDisplayMessage(MSG_TRUST_DOMAIN_NOT_FOUND); }
goto TrustRemoveExit; }
Win32Err = NetDompIsParentChild(&TrustingInfo, &TrustedInfo, &fParentChild);
if ( Win32Err != ERROR_SUCCESS ) {
goto TrustRemoveExit; }
if (fParentChild) { // Enforce rules for parent-child trust.
//
if (TrustingInfo.Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND) { if (TrustingInfo.Flags & NETDOM_TRUST_FLAG_PARENT) { // The domain that wasn't found was the parent, deletion not allowed.
//
NetDompDisplayMessage(MSG_CANT_DELETE_PARENT); printf("\n"); Win32Err = ERROR_NOT_SUPPORTED; goto TrustRemoveExit; } else { if (!fForce) { // Force flag required to delete non-existant child.
//
NetDompDisplayMessage(MSG_DELETE_CHILD_FORCE_REQ); printf("\n"); Win32Err = ERROR_NOT_SUPPORTED; goto TrustRemoveExit; } else { fVerifyChildDelete = TRUE; } } } else { if (TrustedInfo.Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND) { if (TrustedInfo.Flags & NETDOM_TRUST_FLAG_PARENT) { // The domain that wasn't found was the parent, deletion not allowed.
//
NetDompDisplayMessage(MSG_CANT_DELETE_PARENT); printf("\n"); Win32Err = ERROR_NOT_SUPPORTED; goto TrustRemoveExit; } else { if (!fForce) { // Force flag required to delete non-existant child.
//
NetDompDisplayMessage(MSG_DELETE_CHILD_FORCE_REQ); printf("\n"); Win32Err = ERROR_NOT_SUPPORTED; goto TrustRemoveExit; } else { fVerifyChildDelete = TRUE; } } } else { // Both domains were found, don't allow deletion.
//
NetDompDisplayMessage(MSG_CANT_DELETE_PARENT_CHILD); printf("\n"); Win32Err = ERROR_NOT_SUPPORTED; goto TrustRemoveExit; } } }
if (fVerifyChildDelete) { // Put up a message box asking for confirmation of the deletion.
//
PWSTR pwzDomain = (TrustingInfo.Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND) ? TrustingInfo.DomainName->Buffer : TrustedInfo.DomainName->Buffer;
if (!NetDompGetUserConfirmation(IDS_PROMPT_DEL_TRUST, pwzDomain)) { goto TrustRemoveExit; } }
if (!(TrustingInfo.Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND)) { Win32Err = NetDompTrustRemoveObject( &TrustingInfo, &TrustedInfo, (TwoWay || fForce) ? TRUST_DIRECTION_BIDIRECTIONAL : TRUST_DIRECTION_OUTBOUND, fForce, pTrustingCreds ); }
if ((Win32Err == ERROR_SUCCESS && !CmdFlagOn(rgNetDomArgs, eTrustRealm)) && !(TrustedInfo.Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND)) {
Win32Err = NetDompTrustRemoveObject( &TrustedInfo, &TrustingInfo, (TwoWay || fForce) ? TRUST_DIRECTION_BIDIRECTIONAL : TRUST_DIRECTION_INBOUND, fForce, pTrustedCreds ); }
TrustRemoveExit:
NetDompFreeDomInfo( &TrustedInfo ); NetDompFreeDomInfo( &TrustingInfo );
return( Win32Err ); }
DWORD NetDompSetTrustPW( IN PND5_TRUST_INFO pDomain1Info, IN PND5_TRUST_INFO pDomain2Info, IN PWSTR pwzNewTrustPW, OUT PDWORD pDirection ) /*++
Routine Description:
This function will set the trust password on Domain1.
Arguments:
pDomain1Info - Domain on which to set the trust passwords
pDomain2Info - Domain whose TDO should be set.
pwzNewTrustPW - new trust password to use.
Return Value:
ERROR_INVALID_PARAMETER - No object name was supplied
--*/ { DWORD Win32Err = ERROR_SUCCESS; PTRUSTED_DOMAIN_FULL_INFORMATION pOldDomain1TDFInfo = NULL; TRUSTED_DOMAIN_FULL_INFORMATION NewDomain1TDFInfo; LSA_AUTH_INFORMATION NewAuthInfo; LARGE_INTEGER ft; NTSTATUS Status = STATUS_SUCCESS;
LOG_VERBOSE((MSG_VERBOSE_GET_TRUST, pDomain1Info->DomainName->Buffer));
if (pDomain2Info->Sid) { Status = LsaQueryTrustedDomainInfo(pDomain1Info->LsaHandle, pDomain2Info->Sid, TrustedDomainFullInformation, (PVOID *)&pOldDomain1TDFInfo); } else { Status = LsaQueryTrustedDomainInfoByName(pDomain1Info->LsaHandle, pDomain2Info->DomainName, TrustedDomainFullInformation, (PVOID *)&pOldDomain1TDFInfo); }
Win32Err = LsaNtStatusToWinError(Status);
CHECK_WIN32(Win32Err, goto TrustPwSetExit);
if (pDirection) { *pDirection = pOldDomain1TDFInfo->Information.TrustDirection; }
GetSystemTimeAsFileTime((PFILETIME)&ft);
//
// Set the current password data.
//
NewAuthInfo.LastUpdateTime = ft; NewAuthInfo.AuthType = TRUST_AUTH_TYPE_CLEAR; NewAuthInfo.AuthInfoLength = wcslen(pwzNewTrustPW) * sizeof(WCHAR); NewAuthInfo.AuthInfo = (PUCHAR)pwzNewTrustPW;
ZeroMemory(&NewDomain1TDFInfo, sizeof(TRUSTED_DOMAIN_FULL_INFORMATION));
if (pOldDomain1TDFInfo->Information.TrustDirection & TRUST_DIRECTION_INBOUND) { NewDomain1TDFInfo.AuthInformation.IncomingAuthInfos = 1; NewDomain1TDFInfo.AuthInformation.IncomingAuthenticationInformation = &NewAuthInfo; NewDomain1TDFInfo.AuthInformation.IncomingPreviousAuthenticationInformation = NULL; NewDomain1TDFInfo.Information = pOldDomain1TDFInfo->Information; }
if (pOldDomain1TDFInfo->Information.TrustDirection & TRUST_DIRECTION_OUTBOUND) { NewDomain1TDFInfo.AuthInformation.OutgoingAuthInfos = 1; NewDomain1TDFInfo.AuthInformation.OutgoingAuthenticationInformation = &NewAuthInfo; NewDomain1TDFInfo.AuthInformation.OutgoingPreviousAuthenticationInformation = NULL; NewDomain1TDFInfo.Information = pOldDomain1TDFInfo->Information; }
LOG_VERBOSE((MSG_VERBOSE_SET_TRUST, pDomain1Info->DomainName->Buffer));
// Save changes.
//
Status = LsaSetTrustedDomainInfoByName(pDomain1Info->LsaHandle, pDomain2Info->DomainName, TrustedDomainFullInformation, &NewDomain1TDFInfo);
if (STATUS_OBJECT_NAME_NOT_FOUND == Status && pDomain2Info->Uplevel) { // Pre-existing TDOs for domains upgraded from NT4 to NT5 will continue to
// have a flat name.
//
pDomain2Info->fWasDownlevel = TRUE;
Status = LsaSetTrustedDomainInfoByName(pDomain1Info->LsaHandle, pDomain2Info->FlatName, TrustedDomainFullInformation, &NewDomain1TDFInfo); }
Win32Err = LsaNtStatusToWinError(Status);
CHECK_WIN32(Win32Err, goto TrustPwSetExit);
TrustPwSetExit:
if (pOldDomain1TDFInfo) LsaFreeMemory(pOldDomain1TDFInfo);
return Win32Err; }
DWORD NetDompResetTrustPasswords( IN PWSTR pwzDomain1, IN PWSTR pwzDomain2, IN PND5_AUTH_INFO pDomain1Creds, IN PND5_AUTH_INFO pDomain2Creds ) /*++
Routine Description:
This function will handle the password reset of the trusted domain objects
Arguments:
pwzDomain1, pwzDomain2 - Names of domains with trust.
pDomain1Creds, pDomain2Creds - Credentials to use when connecting to a domain controller in the domain --*/ { DWORD Win32Err = ERROR_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; ND5_TRUST_INFO Domain1Info, Domain2Info; WCHAR wzNewPw[MAX_COMPUTERNAME_LENGTH]; ULONG Length, i; LARGE_INTEGER ft; DWORD Direction;
RtlZeroMemory( &Domain1Info, sizeof( Domain1Info ) ); RtlZeroMemory( &Domain2Info, sizeof( Domain2Info ) );
Win32Err = NetDompTrustGetDomInfo( pwzDomain1, NULL, pDomain1Creds, &Domain1Info, TRUE, FALSE, FALSE );
if (Win32Err == ERROR_SUCCESS) { Win32Err = NetDompTrustGetDomInfo( pwzDomain2, NULL, pDomain2Creds, &Domain2Info, TRUE, FALSE, FALSE ); }
CHECK_WIN32(Win32Err, goto TrustResetExit);
if (Domain1Info.Uplevel && Domain2Info.Uplevel) { NetDompDisplayMessage(MSG_RESET_TRUST_STARTING, pwzDomain1, pwzDomain2); } else { NetDompDisplayMessage(MSG_RESET_TRUST_NOT_UPLEVEL);
goto TrustResetExit; }
//
// Build a random password
//
CDGenerateRandomBits((PUCHAR)wzNewPw, sizeof(wzNewPw));
// Terminate the password
Length = MAX_COMPUTERNAME_LENGTH; Length--; wzNewPw[Length] = L'\0'; // Make sure there aren't any NULL's in the password
for (i = 0; i < Length; i++) { if (wzNewPw[i] == L'\0') { // arbitrary letter
wzNewPw[i] = L'c'; } }
Win32Err = NetDompSetTrustPW(&Domain1Info, &Domain2Info, wzNewPw, &Direction);
CHECK_WIN32(Win32Err, goto TrustResetExit);
Win32Err = NetDompSetTrustPW(&Domain2Info, &Domain1Info, wzNewPw, NULL);
CHECK_WIN32(Win32Err, goto TrustResetExit);
//
// Verify the repaired trust.
//
if (Direction & TRUST_DIRECTION_OUTBOUND) { Win32Err = NetDompResetTrustSC( &Domain1Info, &Domain2Info );
CHECK_WIN32(Win32Err, goto TrustResetExit); }
if (Direction & TRUST_DIRECTION_INBOUND) { Win32Err = NetDompResetTrustSC( &Domain2Info, &Domain1Info );
CHECK_WIN32(Win32Err, goto TrustResetExit); }
NetDompDisplayMessage(MSG_RESET_TRUST_OK, pwzDomain1, pwzDomain2);
TrustResetExit:
NetDompFreeDomInfo( &Domain2Info ); NetDompFreeDomInfo( &Domain1Info );
return( Win32Err ); }
DWORD NetDompSetMitTrustPW( IN PWSTR pwzDomain1, IN PWSTR pwzDomain2, IN PND5_AUTH_INFO pDomain1Creds, IN PND5_AUTH_INFO pDomain2Creds, IN PWSTR pwzNewTrustPW ) /*++
Routine Description:
This function will handle the password reset of an MIT trusted domain object
Arguments:
pwzDomain1, pwzDomain2 - Trusted domains
pDomain1Creds - Credentials to use when connecting to a domain controller in domain21
pDomain2Creds - Credentials to use when connecting to a domain controller in domain 2
pwzNewTrustPW - new trust password to use.
Return Value:
ERROR_INVALID_PARAMETER - No object name was supplied
--*/ { DWORD Win32Err = ERROR_SUCCESS; ND5_TRUST_INFO Domain1Info, Domain2Info; PND5_TRUST_INFO pDomFoundInfo, pMitDomInfo;
RtlZeroMemory( &Domain1Info, sizeof( Domain1Info ) ); RtlZeroMemory( &Domain2Info, sizeof( Domain2Info ) );
Win32Err = NetDompTrustGetDomInfo( pwzDomain1, NULL, pDomain1Creds, &Domain1Info, TRUE, TRUE, FALSE );
CHECK_WIN32(Win32Err, goto MitTrustPwSetExit);
Win32Err = NetDompTrustGetDomInfo( pwzDomain2, NULL, pDomain2Creds, &Domain2Info, TRUE, TRUE, FALSE );
CHECK_WIN32(Win32Err, goto MitTrustPwSetExit);
if ((Domain1Info.Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND) && (Domain2Info.Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND)) { // at least one must be found.
//
Win32Err = ERROR_NO_SUCH_DOMAIN; goto MitTrustPwSetExit; }
if (Domain1Info.Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND) { pMitDomInfo = &Domain1Info; pDomFoundInfo = &Domain2Info; } else { if (Domain2Info.Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND) { pMitDomInfo = &Domain2Info; pDomFoundInfo = &Domain1Info; } else { NetDompDisplayMessage(MSG_RESET_MIT_TRUST_NOT_MIT); Win32Err = ERROR_INVALID_PARAMETER; goto MitTrustPwSetExit; } }
NetDompDisplayMessage(MSG_RESET_MIT_TRUST_STARTING, pDomFoundInfo->DomainName->Buffer, pMitDomInfo->DomainName->Buffer);
Win32Err = NetDompSetTrustPW(pDomFoundInfo, pMitDomInfo, pwzNewTrustPW, NULL);
CHECK_WIN32(Win32Err, goto MitTrustPwSetExit);
NetDompDisplayMessage(MSG_RESET_MIT_TRUST_OK, pMitDomInfo->DomainName->Buffer);
MitTrustPwSetExit:
NetDompFreeDomInfo( &Domain2Info ); NetDompFreeDomInfo( &Domain1Info );
return( Win32Err ); }
DWORD NetDomTransitivity(PWSTR pwzTransArg, PWSTR pwzDomain1, PWSTR pwzDomain2, PND5_AUTH_INFO pDomain1Creds, PND5_AUTH_INFO pDomain2Creds) /*++
Routine Description:
This routine will display or change the transitivity of a trust.
Arguments:
pwzTransArg -- Either blank (display the transitivity) or one of yes or no (change the transitivity).
pwzDomain1 -- Name of one domain
pwzDomain2 -- Name of the other domain
pDomain1Creds -- Credentials of the user of domain1
pDomain2Creds -- Credentials of the user of domain2 Return Value:
STATUS_SUCCESS -- Success
--*/ { DWORD Win32Err = ERROR_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; BOOL fDisplayOnly = FALSE; BOOL fTransOn = FALSE; ND5_TRUST_INFO Domain1Info, Domain2Info; PND5_TRUST_INFO pDomFoundInfo, pMitDomInfo; PTRUSTED_DOMAIN_INFORMATION_EX pTDIx = NULL; WCHAR wzYes[NETDOM_STR_LEN], wzNo[NETDOM_STR_LEN];
RtlZeroMemory( &Domain1Info, sizeof( Domain1Info ) ); RtlZeroMemory( &Domain2Info, sizeof( Domain2Info ) );
Win32Err = NetDompTrustGetDomInfo( pwzDomain1, NULL, pDomain1Creds, &Domain1Info, TRUE, TRUE, FALSE );
CHECK_WIN32(Win32Err, goto TrustSetTransExit);
Win32Err = NetDompTrustGetDomInfo( pwzDomain2, NULL, pDomain2Creds, &Domain2Info, TRUE, TRUE, FALSE );
CHECK_WIN32(Win32Err, goto TrustSetTransExit);
if ((Domain1Info.Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND) && (Domain2Info.Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND)) { // at least one must be found.
//
Win32Err = ERROR_NO_SUCH_DOMAIN; goto TrustSetTransExit; }
if (Domain1Info.Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND) { pMitDomInfo = &Domain1Info; pDomFoundInfo = &Domain2Info; } else { if (Domain2Info.Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND) { pMitDomInfo = &Domain2Info; pDomFoundInfo = &Domain1Info; } else { NetDompDisplayMessage(MSG_RESET_MIT_TRUST_NOT_MIT); Win32Err = ERROR_INVALID_PARAMETER; goto TrustSetTransExit; } }
if (NULL == pwzTransArg) { fDisplayOnly = TRUE; } else { if (!LoadString(g_hInstance, IDS_YES, wzYes, NETDOM_STR_LEN) || !LoadString(g_hInstance, IDS_NO, wzNo, NETDOM_STR_LEN)) { printf("LoadString FAILED!\n"); Win32Err = ERROR_RESOURCE_NAME_NOT_FOUND; goto TrustSetTransExit; }
if (_wcsicmp(wzYes, pwzTransArg) == 0) { fTransOn = TRUE; } else { if (_wcsicmp(wzNo, pwzTransArg) != 0) { fDisplayOnly = TRUE; } } }
LOG_VERBOSE((MSG_VERBOSE_GET_TRUST, pDomFoundInfo->DomainName->Buffer));
if (pMitDomInfo->Sid) { Status = LsaQueryTrustedDomainInfo(pDomFoundInfo->LsaHandle, pMitDomInfo->Sid, TrustedDomainInformationEx, (PVOID *)&pTDIx); } else { Status = LsaQueryTrustedDomainInfoByName(pDomFoundInfo->LsaHandle, pMitDomInfo->DomainName, TrustedDomainInformationEx, (PVOID *)&pTDIx); }
Win32Err = LsaNtStatusToWinError(Status);
CHECK_WIN32(Win32Err, goto TrustSetTransExit);
if (TRUST_TYPE_MIT != pTDIx->TrustType) { NetDompDisplayMessage(MSG_RESET_MIT_TRUST_NOT_MIT); Win32Err = ERROR_INVALID_PARAMETER; goto TrustSetTransExit; }
if (fDisplayOnly) { NetDompDisplayMessage((pTDIx->TrustAttributes & TRUST_ATTRIBUTE_NON_TRANSITIVE) ? MSG_TRUST_NON_TRANSITIVE : MSG_TRUST_TRANSITIVE); goto TrustSetTransExit; }
if (fTransOn) { if (pTDIx->TrustAttributes & TRUST_ATTRIBUTE_NON_TRANSITIVE) { NetDompDisplayMessage(MSG_TRUST_SET_TRANSITIVE); pTDIx->TrustAttributes &= ~(TRUST_ATTRIBUTE_NON_TRANSITIVE); } else { NetDompDisplayMessage(MSG_TRUST_ALREADY_TRANSITIVE); goto TrustSetTransExit; } } else { if (pTDIx->TrustAttributes & TRUST_ATTRIBUTE_NON_TRANSITIVE) { NetDompDisplayMessage(MSG_TRUST_ALREADY_NON_TRANSITIVE); goto TrustSetTransExit; } else { NetDompDisplayMessage(MSG_TRUST_SET_NON_TRANSITIVE); pTDIx->TrustAttributes |= TRUST_ATTRIBUTE_NON_TRANSITIVE; } }
LOG_VERBOSE((MSG_VERBOSE_SET_TRUST, pDomFoundInfo->DomainName->Buffer));
Status = LsaSetTrustedDomainInfoByName(pDomFoundInfo->LsaHandle, pMitDomInfo->DomainName, TrustedDomainInformationEx, pTDIx);
Win32Err = LsaNtStatusToWinError(Status);
CHECK_WIN32(Win32Err, goto TrustSetTransExit);
TrustSetTransExit:
NetDompFreeDomInfo( &Domain2Info ); NetDompFreeDomInfo( &Domain1Info ); if (pTDIx) LsaFreeMemory(pTDIx);
return Win32Err; }
DWORD NetDomFilterSID(PWSTR pwzFilterArg, PWSTR pwzTrustingDomain, PWSTR pwzTrustedDomain, PND5_AUTH_INFO pTrustingDomainCreds, PND5_AUTH_INFO pDomain2Creds) /*++
Routine Description:
This routine will display or change the SID filtering state of a trust.
Arguments:
pwzFilterArg -- Either blank (display the filtering state) or one of yes or no (change the filtering state).
pwzTrustingDomain -- Name of the trusting domain domain
pwzTrustedDomain -- Name of the trusted domain
pTrustingDomainCreds -- Credentials of the user of the trusting domain
pDomain2Creds -- Credentials of the user of domain2 BUGBUG not needed? Return Value:
STATUS_SUCCESS -- Success
--*/ { DWORD Win32Err = ERROR_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; BOOL fDisplayOnly = FALSE; BOOL fFilterOn = FALSE; ND5_TRUST_INFO TrustingDomainInfo, TrustedDomainInfo; PTRUSTED_DOMAIN_INFORMATION_EX pTDIx = NULL; WCHAR wzYes[NETDOM_STR_LEN], wzNo[NETDOM_STR_LEN];
RtlZeroMemory(&TrustingDomainInfo, sizeof(TrustingDomainInfo)); RtlZeroMemory(&TrustedDomainInfo, sizeof(TrustedDomainInfo));
Win32Err = NetDompTrustGetDomInfo(pwzTrustingDomain, NULL, pTrustingDomainCreds, &TrustingDomainInfo, TRUE, FALSE, FALSE);
CHECK_WIN32(Win32Err, goto TrustSetFilterExit);
Win32Err = NetDompTrustGetDomInfo(pwzTrustedDomain, NULL, NULL, &TrustedDomainInfo, FALSE, TRUE, TRUE);
CHECK_WIN32(Win32Err, goto TrustSetFilterExit);
if (TrustingDomainInfo.Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND) { Win32Err = ERROR_NO_SUCH_DOMAIN; goto TrustSetFilterExit; }
if (NULL == pwzFilterArg) { fDisplayOnly = TRUE; } else { if (!LoadString(g_hInstance, IDS_YES, wzYes, NETDOM_STR_LEN) || !LoadString(g_hInstance, IDS_NO, wzNo, NETDOM_STR_LEN)) { printf("LoadString FAILED!\n"); Win32Err = ERROR_RESOURCE_NAME_NOT_FOUND; NetApiBufferFree(pwzFilterArg); goto TrustSetFilterExit; }
if (_wcsicmp(wzYes, pwzFilterArg) == 0) { fFilterOn = TRUE; } else { if (_wcsicmp(wzNo, pwzFilterArg) != 0) { fDisplayOnly = TRUE; } } NetApiBufferFree(pwzFilterArg); }
LOG_VERBOSE((MSG_VERBOSE_GET_TRUST, TrustingDomainInfo.DomainName->Buffer));
if (TrustedDomainInfo.Sid) { Status = LsaQueryTrustedDomainInfo(TrustingDomainInfo.LsaHandle, TrustedDomainInfo.Sid, TrustedDomainInformationEx, (PVOID *)&pTDIx); } else { Status = LsaQueryTrustedDomainInfoByName(TrustingDomainInfo.LsaHandle, TrustedDomainInfo.DomainName, TrustedDomainInformationEx, (PVOID *)&pTDIx); }
Win32Err = LsaNtStatusToWinError(Status);
CHECK_WIN32(Win32Err, goto TrustSetFilterExit);
if (!(pTDIx->TrustDirection & TRUST_DIRECTION_OUTBOUND)) { NetDompDisplayMessage(MSG_TRUST_FILTER_SIDS_WRONG_DIR, pwzTrustingDomain); goto TrustSetFilterExit; }
if (fDisplayOnly) { NetDompDisplayMessage((pTDIx->TrustAttributes & TRUST_ATTRIBUTE_FILTER_SIDS) ? MSG_TRUST_FILTER_SIDS : MSG_TRUST_DONT_FILTER_SIDS); goto TrustSetFilterExit; }
if (fFilterOn) { if (pTDIx->TrustAttributes & TRUST_ATTRIBUTE_FILTER_SIDS) { NetDompDisplayMessage(MSG_TRUST_ALREADY_FILTER_SIDS); goto TrustSetFilterExit; } else { NetDompDisplayMessage(MSG_TRUST_SET_FILTER_SIDS); pTDIx->TrustAttributes |= TRUST_ATTRIBUTE_FILTER_SIDS; } } else { if (pTDIx->TrustAttributes & TRUST_ATTRIBUTE_FILTER_SIDS) { NetDompDisplayMessage(MSG_TRUST_SET_DONT_FILTER_SIDS); pTDIx->TrustAttributes &= ~(TRUST_ATTRIBUTE_FILTER_SIDS); } else { NetDompDisplayMessage(MSG_TRUST_ALREADY_DONT_FILTER_SIDS); goto TrustSetFilterExit; } }
LOG_VERBOSE((MSG_VERBOSE_SET_TRUST, TrustingDomainInfo.DomainName->Buffer));
Status = LsaSetTrustedDomainInfoByName(TrustingDomainInfo.LsaHandle, TrustedDomainInfo.DomainName, TrustedDomainInformationEx, pTDIx);
Win32Err = LsaNtStatusToWinError(Status);
CHECK_WIN32(Win32Err, goto TrustSetFilterExit);
TrustSetFilterExit:
NetDompFreeDomInfo( &TrustedDomainInfo ); NetDompFreeDomInfo( &TrustingDomainInfo ); if (pTDIx) LsaFreeMemory(pTDIx);
return Win32Err; }
typedef INT_PTR (*DSPROP_DumpFTInfos)(PCWSTR pwzDcName, PCWSTR pwzTrust, PCWSTR pwzUser, PCWSTR pwzPw);
typedef INT_PTR (*DSPROP_ToggleFTName)(PCWSTR pwzLocalDc, PWSTR pwzTrust, ULONG iSel, PCWSTR pwzUser, PCWSTR pwzPW);
DWORD NetDomForestSuffix(PWSTR pwzTrustPartnerArg, ULONG iSel, PWSTR pwzLocalDomain, PND5_AUTH_INFO pLocalDomainCreds) /*++
Routine Description:
This routine will toggle the status of a name suffix claimed by a forest trust domain or if iSel is zero will display the name suffixes claimed by a forest trust domain.
Arguments:
pwzTrustPartnerArg -- the domain whose TDO will be read for the name suffixes attribute (ms-DS-Trust-Forest-Trust-Info).
iSel -- the one-based index of the name to toggle (if zero, display the names).
pwzLocalDomain -- Name of the domain on which the TDO resides.
pLocalDomainCreds -- Credentials of the user of the local domain
Return Value:
STATUS_SUCCESS -- Success
--*/ { DWORD Win32Err = ERROR_SUCCESS; PDOMAIN_CONTROLLER_INFO pDcInfo = NULL; PWSTR pwzDcName = NULL; NTSTATUS Status = STATUS_SUCCESS; HMODULE hm = NULL; DSPROP_DumpFTInfos pDumpFTInfos = NULL; DSPROP_ToggleFTName pToggleFTName = NULL;
ASSERT(pwzTrustPartnerArg && pwzLocalDomain && pLocalDomainCreds);
Win32Err = DsGetDcName(NULL, pwzLocalDomain, NULL, NULL, DS_PDC_REQUIRED, &pDcInfo );
CHECK_WIN32(Win32Err, return Win32Err);
ASSERT(pDcInfo);
pwzDcName = pDcInfo->DomainControllerName;
hm = LoadLibrary(L"adprop.dll"); if (!hm) { Win32Err = GetLastError(); NetApiBufferFree(pDcInfo); return Win32Err; }
if (0 == iSel) { pDumpFTInfos = (DSPROP_DumpFTInfos)GetProcAddress(hm, "DSPROP_DumpFTInfos"); } else { pToggleFTName = (DSPROP_ToggleFTName)GetProcAddress(hm, "DSPROP_ToggleFTName"); }
if (!pDumpFTInfos && !pToggleFTName) { Win32Err = GetLastError(); NetApiBufferFree(pDcInfo); NetDompDisplayMessage(MSG_WRONG_DSPROP_DLL); return Win32Err; }
if (0 == iSel) { Win32Err = (DWORD)(*pDumpFTInfos)(pwzDcName, pwzTrustPartnerArg, pLocalDomainCreds->User, pLocalDomainCreds->Password); } else { Win32Err = (DWORD)(*pToggleFTName)(pwzDcName, pwzTrustPartnerArg, iSel, pLocalDomainCreds->User, pLocalDomainCreds->Password); }
NetApiBufferFree(pDcInfo); return Win32Err; }
DWORD NetDompVerifyIndividualTrustKerberos( IN PWSTR TrustingDomain, IN PWSTR TrustedDomain, IN PND5_AUTH_INFO pTrustingCreds, IN PND5_AUTH_INFO pTrustedCreds ) /*++
Routine Description:
This routine will verify a single trust in the one direction only.
Arguments:
TrustingDomain -- Name of the domain on the outbound side
TrustedDomain -- Name of the domain on the inbound side
pTrustingCreds -- Credentials of the user on the outbound side
pTrustedCreds -- Credentials of the user on the inbound side Return Value:
STATUS_SUCCESS -- Success
--*/ { //
// Copy the relevant info into local pointers so that I don't have
// to rewrite the rest of the function.
//
PWSTR PackageName = NULL; PWSTR UserNameU = pTrustedCreds->pwzUserWoDomain; PWSTR DomainNameU = pTrustedCreds->pwzUsersDomain; PWSTR PasswordU = pTrustedCreds->Password; PWSTR ServerUserNameU = pTrustingCreds->pwzUserWoDomain; PWSTR ServerDomainNameU = pTrustingCreds->pwzUsersDomain; PWSTR ServerPasswordU = pTrustingCreds->Password; ULONG ContextReq = 0; ULONG CredFlags = 0;
SECURITY_STATUS SecStatus; SECURITY_STATUS AcceptStatus; SECURITY_STATUS InitStatus; CredHandle CredentialHandle2; CtxtHandle ClientContextHandle; CtxtHandle ServerContextHandle; TimeStamp Lifetime; ULONG ContextAttributes; ULONG PackageCount; PSecPkgInfo PackageInfo = NULL; ULONG ClientFlags; ULONG ServerFlags; BOOLEAN AcquiredServerCred = FALSE; LPWSTR DomainName = NULL; LPWSTR UserName = NULL; TCHAR TargetName[256]; PSEC_WINNT_AUTH_IDENTITY_EXW AuthIdentity = NULL; PSEC_WINNT_AUTH_IDENTITY_W ServerAuthIdentity = NULL; PUCHAR Where; ULONG CredSize;
SecBufferDesc NegotiateDesc; SecBuffer NegotiateBuffer; SecBufferDesc ChallengeDesc; SecBuffer ChallengeBuffer; SecBufferDesc AuthenticateDesc; SecBuffer AuthenticateBuffer;
SecPkgCredentials_Names CredNames;
CredHandle ServerCredHandleStorage; PCredHandle ServerCredHandle = NULL;
//
// Set the package to wide-char
//
if (PackageName == NULL) { PackageName = MICROSOFT_KERBEROS_NAME_W; }
//
// Allocate the Authentication Identity for the outbound trust
//
if ((UserNameU != NULL) || (DomainNameU != NULL) || (PasswordU != NULL) || (CredFlags != 0)) { CredSize = (((UserNameU != NULL) ? wcslen(UserNameU) + 1 : 0) + ((DomainNameU != NULL) ? wcslen(DomainNameU) + 1 : 0 ) + ((PasswordU != NULL) ? wcslen(PasswordU) + 1 : 0) ) * sizeof(WCHAR) + sizeof(SEC_WINNT_AUTH_IDENTITY_EXW); AuthIdentity = (PSEC_WINNT_AUTH_IDENTITY_EXW) LocalAlloc(LMEM_ZEROINIT,CredSize);
if (!AuthIdentity) { return ERROR_NOT_ENOUGH_MEMORY; }
AuthIdentity->Version = SEC_WINNT_AUTH_IDENTITY_VERSION; Where = (PUCHAR) (AuthIdentity + 1);
if (UserNameU != NULL) { AuthIdentity->UserLength = wcslen(UserNameU); AuthIdentity->User = (LPWSTR) Where; wcscpy( (LPWSTR) Where, UserNameU ); Where += (wcslen(UserNameU) + 1) * sizeof(WCHAR); }
if (DomainNameU != NULL) { AuthIdentity->DomainLength = wcslen(DomainNameU); AuthIdentity->Domain = (LPWSTR) Where; wcscpy( (LPWSTR) Where, DomainNameU ); Where += (wcslen(DomainNameU) + 1) * sizeof(WCHAR); }
if (PasswordU != NULL) { AuthIdentity->PasswordLength = wcslen(PasswordU); AuthIdentity->Password = (LPWSTR) Where; wcscpy( (LPWSTR) Where, PasswordU ); Where += (wcslen(PasswordU) + 1) * sizeof(WCHAR); } AuthIdentity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE | CredFlags; }
//
// Allocate the Authentication Identity for the outbound trust
//
if ((ServerUserNameU != NULL) || (ServerDomainNameU != NULL) || (ServerPasswordU != NULL)) { CredSize = (((ServerUserNameU != NULL) ? wcslen(ServerUserNameU) + 1 : 0) + ((ServerDomainNameU != NULL) ? wcslen(ServerDomainNameU) + 1 : 0 ) + ((ServerPasswordU != NULL) ? wcslen(ServerPasswordU) + 1 : 0) ) * sizeof(WCHAR) + sizeof(SEC_WINNT_AUTH_IDENTITY); ServerAuthIdentity = (PSEC_WINNT_AUTH_IDENTITY_W) LocalAlloc(LMEM_ZEROINIT,CredSize);
if (!ServerAuthIdentity) { return ERROR_NOT_ENOUGH_MEMORY; }
Where = (PUCHAR) (ServerAuthIdentity + 1);
if (ServerUserNameU != NULL) { ServerAuthIdentity->UserLength = wcslen(ServerUserNameU); ServerAuthIdentity->User = (LPWSTR) Where; wcscpy( (LPWSTR) Where, ServerUserNameU ); Where += (wcslen(ServerUserNameU) + 1) * sizeof(WCHAR); }
if (ServerDomainNameU != NULL) { ServerAuthIdentity->DomainLength = wcslen(ServerDomainNameU); ServerAuthIdentity->Domain = (LPWSTR) Where; wcscpy( (LPWSTR) Where, ServerDomainNameU ); Where += (wcslen(ServerDomainNameU) + 1) * sizeof(WCHAR); }
if (ServerPasswordU != NULL) { ServerAuthIdentity->PasswordLength = wcslen(ServerPasswordU); ServerAuthIdentity->Password = (LPWSTR) Where; wcscpy( (LPWSTR) Where, ServerPasswordU ); Where += (wcslen(ServerPasswordU) + 1) * sizeof(WCHAR); } ServerAuthIdentity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE | SEC_WINNT_AUTH_IDENTITY_MARSHALLED;
}
CredNames.sUserName = NULL; NegotiateBuffer.pvBuffer = NULL; ChallengeBuffer.pvBuffer = NULL; AuthenticateBuffer.pvBuffer = NULL;
DomainName = _wgetenv(L"USERDOMAIN"); UserName = _wgetenv(L"USERNAME");
//
// Get info about the security packages.
//
SecStatus = EnumerateSecurityPackages( &PackageCount, &PackageInfo );
if ( SecStatus != STATUS_SUCCESS ) { NetDompDisplayMessage( MSG_KERBEROS_TRUST_FAILED, TrustingDomain, TrustedDomain ); return SecStatus; }
//
// Get info about the security packages.
//
SecStatus = QuerySecurityPackageInfo( PackageName, &PackageInfo );
if ( SecStatus != STATUS_SUCCESS ) { NetDompDisplayMessage( MSG_KERBEROS_TRUST_FAILED, TrustingDomain, TrustedDomain ); return SecStatus; }
//
// Acquire a credential handle for the server side
//
if (ServerCredHandle == NULL) {
ServerCredHandle = &ServerCredHandleStorage; AcquiredServerCred = TRUE;
SecStatus = AcquireCredentialsHandle( NULL, PackageName, SECPKG_CRED_INBOUND, NULL, ServerAuthIdentity, NULL, NULL, ServerCredHandle, &Lifetime );
if ( SecStatus != STATUS_SUCCESS ) { NetDompDisplayMessage( MSG_KERBEROS_TRUST_FAILED, TrustingDomain, TrustedDomain ); return SecStatus; } }
//
// Acquire a credential handle for the client side
//
SecStatus = AcquireCredentialsHandle( NULL, // New principal
PackageName, SECPKG_CRED_OUTBOUND, NULL, AuthIdentity, NULL, NULL, &CredentialHandle2, &Lifetime );
if ( SecStatus != STATUS_SUCCESS ) { NetDompDisplayMessage( MSG_KERBEROS_TRUST_FAILED, TrustingDomain, TrustedDomain ); return SecStatus; }
//
// Query some cred attributes
//
SecStatus = QueryCredentialsAttributes( &CredentialHandle2, SECPKG_CRED_ATTR_NAMES, &CredNames );
if ( SecStatus != STATUS_SUCCESS ) { if ( !NT_SUCCESS(SecStatus) ) { NetDompDisplayMessage( MSG_KERBEROS_TRUST_FAILED, TrustingDomain, TrustedDomain ); return SecStatus; } } else { FreeContextBuffer(CredNames.sUserName); }
//
// Do the same for the client
//
SecStatus = QueryCredentialsAttributes( ServerCredHandle, SECPKG_CRED_ATTR_NAMES, &CredNames );
if ( SecStatus != STATUS_SUCCESS ) { if ( !NT_SUCCESS(SecStatus) ) { NetDompDisplayMessage( MSG_KERBEROS_TRUST_FAILED, TrustingDomain, TrustedDomain ); return SecStatus; } } else { FreeContextBuffer(CredNames.sUserName); }
//
// Get the NegotiateMessage (ClientSide)
//
NegotiateDesc.ulVersion = 0; NegotiateDesc.cBuffers = 1; NegotiateDesc.pBuffers = &NegotiateBuffer;
NegotiateBuffer.cbBuffer = PackageInfo->cbMaxToken; NegotiateBuffer.BufferType = SECBUFFER_TOKEN; NegotiateBuffer.pvBuffer = LocalAlloc( 0, NegotiateBuffer.cbBuffer ); if ( NegotiateBuffer.pvBuffer == NULL ) { DWORD dwError = GetLastError(); NetDompDisplayMessage( MSG_KERBEROS_TRUST_FAILED, TrustingDomain, TrustedDomain ); return dwError; }
if (ContextReq == 0) { ClientFlags = ISC_REQ_MUTUAL_AUTH | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY; // USE_DCE_STYLE | ISC_REQ_MUTUAL_AUTH | ISC_REQ_USE_SESSION_KEY; // | ISC_REQ_DATAGRAM;
} else { ClientFlags = ContextReq; }
if (ServerUserNameU != NULL && ServerDomainNameU != NULL) { wcscpy( TargetName, ServerUserNameU ); wcscat( TargetName, L"@" ); wcscat( TargetName, ServerDomainNameU ); }
InitStatus = InitializeSecurityContext( &CredentialHandle2, NULL, // No Client context yet
TargetName, // Faked target name
ClientFlags, 0, // Reserved 1
SECURITY_NATIVE_DREP, NULL, // No initial input token
0, // Reserved 2
&ClientContextHandle, &NegotiateDesc, &ContextAttributes, &Lifetime );
if ( InitStatus != STATUS_SUCCESS ) { if ( !NT_SUCCESS(InitStatus) ) { NetDompDisplayMessage( MSG_KERBEROS_TRUST_FAILED, TrustingDomain, TrustedDomain ); return InitStatus; } }
//
// Get the ChallengeMessage (ServerSide)
//
NegotiateBuffer.BufferType |= SECBUFFER_READONLY; ChallengeDesc.ulVersion = 0; ChallengeDesc.cBuffers = 1; ChallengeDesc.pBuffers = &ChallengeBuffer;
ChallengeBuffer.cbBuffer = PackageInfo->cbMaxToken; ChallengeBuffer.BufferType = SECBUFFER_TOKEN; ChallengeBuffer.pvBuffer = LocalAlloc( 0, ChallengeBuffer.cbBuffer ); if ( ChallengeBuffer.pvBuffer == NULL ) { DWORD dwError = GetLastError(); NetDompDisplayMessage( MSG_KERBEROS_TRUST_FAILED, TrustingDomain, TrustedDomain ); return dwError; } ServerFlags = ASC_REQ_EXTENDED_ERROR;
AcceptStatus = AcceptSecurityContext( ServerCredHandle, NULL, // No Server context yet
&NegotiateDesc, ServerFlags, SECURITY_NATIVE_DREP, &ServerContextHandle, &ChallengeDesc, &ContextAttributes, &Lifetime );
if ( AcceptStatus != STATUS_SUCCESS ) { if ( !NT_SUCCESS(AcceptStatus) ) { NetDompDisplayMessage( MSG_KERBEROS_TRUST_FAILED, TrustingDomain, TrustedDomain ); return AcceptStatus; } }
while (InitStatus != STATUS_SUCCESS) {
//
// Get the AuthenticateMessage (ClientSide)
//
ChallengeBuffer.BufferType |= SECBUFFER_READONLY; AuthenticateDesc.ulVersion = 0; AuthenticateDesc.cBuffers = 1; AuthenticateDesc.pBuffers = &AuthenticateBuffer;
AuthenticateBuffer.cbBuffer = PackageInfo->cbMaxToken; AuthenticateBuffer.BufferType = SECBUFFER_TOKEN; if (AuthenticateBuffer.pvBuffer == NULL) { AuthenticateBuffer.pvBuffer = LocalAlloc( 0, AuthenticateBuffer.cbBuffer ); if ( AuthenticateBuffer.pvBuffer == NULL ) { DWORD dwError = GetLastError(); NetDompDisplayMessage( MSG_KERBEROS_TRUST_FAILED, TrustingDomain, TrustedDomain ); return dwError; } }
InitStatus = InitializeSecurityContext( NULL, &ClientContextHandle, TargetName, ClientFlags, 0, // Reserved 1
SECURITY_NATIVE_DREP, &ChallengeDesc, 0, // Reserved 2
&ClientContextHandle, &AuthenticateDesc, &ContextAttributes, &Lifetime );
if ( InitStatus != STATUS_SUCCESS ) { if ( !NT_SUCCESS(InitStatus) ) { NetDompDisplayMessage( MSG_KERBEROS_TRUST_FAILED, TrustingDomain, TrustedDomain ); return InitStatus; } }
if (AcceptStatus != STATUS_SUCCESS) { //
// Finally authenticate the user (ServerSide)
//
AuthenticateBuffer.BufferType |= SECBUFFER_READONLY;
ChallengeBuffer.BufferType = SECBUFFER_TOKEN; ChallengeBuffer.cbBuffer = PackageInfo->cbMaxToken;
AcceptStatus = AcceptSecurityContext( NULL, &ServerContextHandle, &AuthenticateDesc, ServerFlags, SECURITY_NATIVE_DREP, &ServerContextHandle, &ChallengeDesc, &ContextAttributes, &Lifetime );
if ( AcceptStatus != STATUS_SUCCESS ) { if ( !NT_SUCCESS(AcceptStatus) ) { NetDompDisplayMessage( MSG_KERBEROS_TRUST_FAILED, TrustingDomain, TrustedDomain ); return AcceptStatus; } } } } NetDompDisplayMessage( MSG_KERBEROS_TRUST_SUCCEEDED, TrustedDomain, TrustingDomain );
return AcceptStatus; }
DWORD NetDompVerifyTrust( IN PND5_TRUST_INFO pTrustingInfo, // outbound
IN PND5_TRUST_INFO pTrustedInfo, // inbound
BOOL fShowResults ) /*++
Routine Description:
This function will verify a trust connection
Arguments:
TrustingInfo - Information on the trusting (outbound) side of the domain
TrustedInfo - Information on the trusted (inbound) side of the domain
Return Value:
ERROR_SUCCESS - The function succeeded
--*/ { NTSTATUS Status = STATUS_SUCCESS; DWORD SidBuff[ sizeof( SID ) / sizeof( DWORD ) + 5 ]; PSID DomAdminSid = ( PSID )SidBuff; PLSA_REFERENCED_DOMAIN_LIST Domains = NULL; PLSA_TRANSLATED_NAME Names = NULL; NET_API_STATUS NetStatus; PNETLOGON_INFO_2 NetlogonInfo2 = NULL; PWSTR pwzDomSvr = pTrustedInfo->DomainName->Buffer; PWSTR pwzTrustedDomain = pTrustedInfo->DomainName->Buffer; BOOL fBufferAlloced = FALSE;
ASSERT( RtlValidSid( pTrustedInfo->Sid ) );
if ( !RtlValidSid( pTrustedInfo->Sid ) ) {
return( ERROR_INVALID_SID ); }
if (!pTrustingInfo->Uplevel) { pwzTrustedDomain = pwzDomSvr = pTrustedInfo->FlatName->Buffer; }
//
// Check netlogon's secure channel
//
NetStatus = I_NetLogonControl2(pTrustingInfo->Server, NETLOGON_CONTROL_TC_VERIFY, 2, (LPBYTE)&pwzTrustedDomain, (LPBYTE *)&NetlogonInfo2);
if (ERROR_NO_SUCH_DOMAIN == NetStatus && pTrustingInfo->Uplevel) { // Pre-existing TDOs for domains upgraded from NT4 to NT5 will continue to
// have a flat name.
//
pwzTrustedDomain = pwzDomSvr = pTrustedInfo->FlatName->Buffer; pTrustedInfo->fWasDownlevel = TRUE;
NetStatus = I_NetLogonControl2(pTrustingInfo->Server, NETLOGON_CONTROL_TC_VERIFY, 2, (LPBYTE)&pwzTrustedDomain, (LPBYTE *)&NetlogonInfo2); }
if (ERROR_NOT_SUPPORTED == NetStatus) { // Must be remoted to a Win2k/NT4 DC that doesn't support SC verify.
//
NetStatus = I_NetLogonControl2(pTrustingInfo->Server, NETLOGON_CONTROL_TC_QUERY, 2, (LPBYTE)&pwzTrustedDomain, (LPBYTE *)&NetlogonInfo2); }
if (NERR_Success == NetStatus) { NetStatus = NetlogonInfo2->netlog2_tc_connection_status;
if (NERR_Success == NetStatus) { if (pTrustingInfo->Uplevel) { // Form the name domain\DC so a reset can done against the same
// DC that is currently being used for the secure channel.
//
NetStatus = NetApiBufferAllocate((wcslen(NetlogonInfo2->netlog2_trusted_dc_name) + wcslen(pwzTrustedDomain) + 1) * sizeof(WCHAR), (PVOID*)&pwzDomSvr); if (NERR_Success != NetStatus) { NetApiBufferFree( NetlogonInfo2 ); return ERROR_NOT_ENOUGH_MEMORY; }
fBufferAlloced = TRUE;
wsprintf(pwzDomSvr, L"%s\\%s", pwzTrustedDomain, (L'\\' == *NetlogonInfo2->netlog2_trusted_dc_name) ? NetlogonInfo2->netlog2_trusted_dc_name + 2 : NetlogonInfo2->netlog2_trusted_dc_name); } } else { if (fShowResults) { // Report Query failure.
//
NetDompDisplayMessage(MSG_VERIFY_TRUST_QUERY_FAILED, pTrustingInfo->Server, pwzTrustedDomain); NetDompDisplayErrorMessage(NetStatus); } }
NetApiBufferFree( NetlogonInfo2 ); } else { if (fShowResults) { // Report I_NetLogonControl2 error.
//
NetDompDisplayMessage(MSG_VERIFY_TRUST_NLQUERY_FAILED, pTrustingInfo->Server, pwzTrustedDomain); NetDompDisplayErrorMessage(NetStatus); return NetStatus; } }
NetStatus = I_NetLogonControl2(pTrustingInfo->Server, NETLOGON_CONTROL_REDISCOVER, 2, (LPBYTE)&pwzDomSvr, (LPBYTE *)&NetlogonInfo2 );
if (fBufferAlloced) { NetApiBufferFree(pwzDomSvr); }
if (NERR_Success == NetStatus) { NetStatus = NetlogonInfo2->netlog2_tc_connection_status;
if (NERR_Success != NetStatus) { if (fShowResults) { // Report Reset failure.
//
NetDompDisplayMessage(MSG_VERIFY_TRUST_RESET_FAILED, pTrustingInfo->Server, pwzTrustedDomain); NetDompDisplayErrorMessage(NetStatus); } NetApiBufferFree( NetlogonInfo2 ); return NetStatus; } NetApiBufferFree( NetlogonInfo2 ); } else { if (fShowResults) { // Report failure
//
NetDompDisplayMessage(MSG_VERIFY_TRUST_NLRESET_FAILED, pTrustingInfo->Server, pwzTrustedDomain); NetDompDisplayErrorMessage(NetStatus); } return NetStatus; }
//
// Now, try a lookup
//
if (ERROR_SUCCESS == NetStatus) { //
// Build the domain admins sid for the inbound side of the trust
//
RtlCopyMemory( DomAdminSid, pTrustedInfo->Sid, RtlLengthSid( pTrustedInfo->Sid ) );
( ( PISID )( DomAdminSid ) )->SubAuthorityCount++; *( RtlSubAuthoritySid( DomAdminSid, *( RtlSubAuthorityCountSid( pTrustedInfo->Sid ) ) ) ) = DOMAIN_GROUP_RID_ADMINS; //
// Now, we'll simply do a remote lookup, and ensure that we get back success
//
Status = LsaLookupSids( pTrustingInfo->LsaHandle, 1, &DomAdminSid, &Domains, &Names );
if ( NT_SUCCESS( Status ) ) { LsaFreeMemory( Domains ); LsaFreeMemory( Names ); NetStatus = ERROR_SUCCESS; } else { if ( Status == STATUS_NONE_MAPPED ) { NetStatus = ERROR_TRUSTED_DOMAIN_FAILURE; } else { NetStatus = RtlNtStatusToDosError( Status ); }
if (fShowResults) { // Report failure
//
NetDompDisplayMessage(MSG_VERIFY_TRUST_LOOKUP_FAILED, pTrustingInfo->Server, pwzTrustedDomain); NetDompDisplayErrorMessage(NetStatus); } } }
return NetStatus; }
DWORD NetDompVerifyTrustObject( IN ARG_RECORD * rgNetDomArgs, IN PWSTR pwzDomain1, IN PWSTR pwzDomain2, IN PND5_AUTH_INFO pDomain1Creds, IN PND5_AUTH_INFO pDomain2Creds ) /*++
Routine Description:
This function will handle the adding of a trusted domain object
Arguments:
rgNetDomArgs - List of arguments present in the Args list
pwzDomain1, pwzDomain2 - domains with trust
pDomain1Creds, pDomain2Creds - Credentials to use when connecting to the domain controllers
Return Value:
ERROR_INVALID_PARAMETER - No object name was supplied
--*/ { DWORD Win32Err, Win32Err1; ND5_TRUST_INFO TrustInfo1, TrustInfo2; PND5_TRUST_INFO pTrustInfoUplevel, pTrustInfoOther; DWORD Direction;
if (CmdFlagOn(rgNetDomArgs, eTrustRealm)) { return ERROR_INVALID_PARAMETER; }
RtlZeroMemory( &TrustInfo1, sizeof( TrustInfo1 ) ); RtlZeroMemory( &TrustInfo2, sizeof( TrustInfo2 ) );
Win32Err = NetDompTrustGetDomInfo( pwzDomain1, NULL, pDomain1Creds, &TrustInfo1, TRUE, FALSE, FALSE );
if (ERROR_SUCCESS == Win32Err) {
Win32Err = NetDompTrustGetDomInfo( pwzDomain2, NULL, pDomain2Creds, &TrustInfo2, TRUE, FALSE, FALSE ); }
if (ERROR_SUCCESS != Win32Err) { goto TrustVerifyExit; }
Win32Err = NetDompGetTrustDirection(&TrustInfo1, &TrustInfo2, &Direction); if (ERROR_SUCCESS != Win32Err) { goto TrustVerifyExit; }
if (TRUST_DIRECTION_DISABLED == Direction) { NetDompDisplayMessage(MSG_VERIFY_TRUST_DISABLED); goto TrustVerifyExit; }
if (Direction & TRUST_DIRECTION_OUTBOUND) { LOG_VERBOSE((MSG_VERBOSE_VERIFY_TRUST, pwzDomain1, pwzDomain2));
Win32Err = NetDompVerifyTrust(&TrustInfo1, &TrustInfo2, TRUE); }
if (Direction & TRUST_DIRECTION_INBOUND) { LOG_VERBOSE((MSG_VERBOSE_VERIFY_TRUST, pwzDomain2, pwzDomain1));
Win32Err1 = NetDompVerifyTrust(&TrustInfo2, &TrustInfo1, TRUE); }
if (ERROR_SUCCESS == Win32Err && ERROR_SUCCESS == Win32Err1) { NetDompDisplayMessage(MSG_VERIFY_TRUST_OK, pwzDomain1, pwzDomain2); }
TrustVerifyExit:
NetDompFreeDomInfo( &TrustInfo2 ); NetDompFreeDomInfo( &TrustInfo1 );
return( Win32Err ); }
DWORD NetDompHandleTrust(ARG_RECORD * rgNetDomArgs) /*++
Routine Description:
This function manages inter-domain trust
Arguments:
Args - List of command line arguments
Return Value:
ERROR_INVALID_PARAMETER - No object name was supplied
--*/ { DWORD Win32Err = ERROR_SUCCESS; ULONG Ops = 0, i; NETDOM_ARG_ENUM BadOp = eArgBegin; PWSTR TrustedDomain = NULL, pwzArgValue = NULL, pwzArgValue2 = NULL; ND5_AUTH_INFO TrustedDomainUser, TrustingDomainUser;
RtlZeroMemory( &TrustedDomainUser, sizeof( ND5_AUTH_INFO ) ); RtlZeroMemory( &TrustingDomainUser, sizeof( ND5_AUTH_INFO ) );
PWSTR TrustingDomain = rgNetDomArgs[eObject].strValue;
if ( !TrustingDomain ) {
DisplayHelp(ePriTrust); return( ERROR_INVALID_PARAMETER ); }
Win32Err = NetDompValidateSecondaryArguments(rgNetDomArgs, eObject, eCommDomain, eCommUserNameO, eCommPasswordO, eCommUserNameD, eCommPasswordD, eTrustRealm, eTrustPasswordT, eCommAdd, eCommRemove, eTrustTwoWay, eTrustKerberos, eTrustTransitive, eTrustOneSide, eTrustNameSuffixes, eTrustToggleSuffixes, eTrustFilterSIDs, eCommVerify, eCommReset, eCommForce, eCommVerbose, eArgEnd); if ( Win32Err != ERROR_SUCCESS ) {
DisplayHelp(ePriTrust); return Win32Err; }
//
// See if we are doing an add, remove, or verify
//
if ( CmdFlagOn(rgNetDomArgs, eCommAdd) ) {
Ops++;
if (CmdFlagOn(rgNetDomArgs, eTrustTransitive)) { BadOp = eTrustTransitive; } }
if ( CmdFlagOn(rgNetDomArgs, eCommRemove) ) {
if ( Ops ) {
BadOp = eCommRemove;
} else {
Ops++; }
if ( CmdFlagOn(rgNetDomArgs, eTrustRealm) ) {
BadOp = eTrustRealm; } }
if ( CmdFlagOn(rgNetDomArgs, eCommVerify) ) {
if ( Ops ) {
BadOp = eCommVerify;
} else {
Ops++; } }
if (BadOp != eArgBegin) {
Win32Err = ERROR_INVALID_PARAMETER; NetDompDisplayUnexpectedParameter(rgNetDomArgs[BadOp].strArg1);
goto HandleTrustExit; }
if (!CmdFlagOn(rgNetDomArgs, eTrustNameSuffixes)) { //
// Make sure that we have a specified domain (if not listing claimed names).
//
Win32Err = NetDompGetDomainForOperation(rgNetDomArgs, NULL, // no server specified
FALSE, // don't default to current domain.
&TrustedDomain);
if ( Win32Err != ERROR_SUCCESS ) {
goto HandleTrustExit; } }
//
// Get the password and user if it exists
//
if ( CmdFlagOn(rgNetDomArgs, eCommUserNameD) ) {
Win32Err = NetDompGetUserAndPasswordForOperation(rgNetDomArgs, eCommUserNameD, TrustedDomain, &TrustedDomainUser );
if ( Win32Err != ERROR_SUCCESS ) {
goto HandleTrustExit; } }
if ( CmdFlagOn(rgNetDomArgs, eCommUserNameO) ) {
Win32Err = NetDompGetUserAndPasswordForOperation(rgNetDomArgs, eCommUserNameO, TrustingDomain, &TrustingDomainUser );
if ( Win32Err != ERROR_SUCCESS ) {
goto HandleTrustExit; } }
if ( CmdFlagOn(rgNetDomArgs, eCommAdd) ) {
if (CmdFlagOn(rgNetDomArgs, eTrustRealm)) { // Get the trust PW.
//
Win32Err = NetDompGetArgumentString(rgNetDomArgs, eTrustPasswordT, &pwzArgValue2); if (ERROR_SUCCESS != Win32Err) { goto HandleTrustExit; }
if (pwzArgValue2) { Win32Err = NetDompCreateTrustObject( rgNetDomArgs, TrustingDomain, TrustedDomain, &TrustingDomainUser, &TrustedDomainUser, pwzArgValue2, NULL); NetApiBufferFree(pwzArgValue2); } else { NetDompDisplayMessage(MSG_TRUST_PW_MISSING); Win32Err = ERROR_INVALID_PARAMETER; } } else if (CmdFlagOn(rgNetDomArgs, eTrustOneSide)) { // Get the trust PW.
//
Win32Err = NetDompGetArgumentString(rgNetDomArgs, eTrustPasswordT, &pwzArgValue2); if (ERROR_SUCCESS != Win32Err) { goto HandleTrustExit; }
if (!pwzArgValue2) { NetDompDisplayMessage(MSG_TRUST_PW_MISSING); Win32Err = ERROR_INVALID_PARAMETER; goto HandleTrustExit; }
// Get the side on which to create the trust.
//
Win32Err = NetDompGetArgumentString(rgNetDomArgs, eTrustOneSide, &pwzArgValue); if (ERROR_SUCCESS != Win32Err) { NetApiBufferFree(pwzArgValue2); goto HandleTrustExit; }
if (!pwzArgValue) { NetDompDisplayMessage(MSG_ONESIDE_ARG_STRING); Win32Err = ERROR_INVALID_PARAMETER; NetApiBufferFree(pwzArgValue2); goto HandleTrustExit; }
Win32Err = NetDompCreateTrustObject( rgNetDomArgs, TrustingDomain, TrustedDomain, &TrustingDomainUser, &TrustedDomainUser, pwzArgValue2, pwzArgValue); NetApiBufferFree(pwzArgValue2); } else { Win32Err = NetDompCreateTrustObject( rgNetDomArgs, TrustingDomain, TrustedDomain, &TrustingDomainUser, &TrustedDomainUser, NULL, NULL); }
} else if ( CmdFlagOn(rgNetDomArgs, eCommRemove) ) {
Win32Err = NetDompRemoveTrustObject( rgNetDomArgs, TrustingDomain, TrustedDomain, &TrustingDomainUser, &TrustedDomainUser );
} else if ( CmdFlagOn(rgNetDomArgs, eCommReset) ) {
//
// See if a password is specifed
//
if (CmdFlagOn(rgNetDomArgs, eTrustPasswordT)) { Win32Err = NetDompGetArgumentString(rgNetDomArgs, eTrustPasswordT, &pwzArgValue2); if (ERROR_SUCCESS != Win32Err) { goto HandleTrustExit; }
if (pwzArgValue2) { Win32Err = NetDompSetMitTrustPW(TrustingDomain, TrustedDomain, &TrustingDomainUser, &TrustedDomainUser, pwzArgValue2); NetApiBufferFree(pwzArgValue2); } else { Win32Err = ERROR_INVALID_PARAMETER; } } else { Win32Err = NetDompResetTrustPasswords(TrustingDomain, TrustedDomain, &TrustingDomainUser, &TrustedDomainUser); }
} else if ( CmdFlagOn(rgNetDomArgs, eCommVerify ) ) {
Win32Err = NetDompVerifyTrustObject( rgNetDomArgs, TrustingDomain, TrustedDomain, &TrustingDomainUser, &TrustedDomainUser );
} else if ( CmdFlagOn(rgNetDomArgs, eTrustKerberos) ) {
Win32Err = NetDompVerifyIndividualTrustKerberos( TrustingDomain, TrustedDomain, &TrustingDomainUser, &TrustedDomainUser );
} else if (CmdFlagOn(rgNetDomArgs, eTrustTransitive)) {
//
// Get the transitivity parameter
//
Win32Err = NetDompGetArgumentString(rgNetDomArgs, eTrustTransitive, &pwzArgValue); if (ERROR_SUCCESS != Win32Err) { goto HandleTrustExit; }
Win32Err = NetDomTransitivity(pwzArgValue, TrustingDomain, TrustedDomain, &TrustingDomainUser, &TrustedDomainUser );
} else if (CmdFlagOn(rgNetDomArgs, eTrustFilterSIDs)) {
//
// Get the transitivity parameter
//
Win32Err = NetDompGetArgumentString(rgNetDomArgs, eTrustFilterSIDs, &pwzArgValue); if (ERROR_SUCCESS != Win32Err) { goto HandleTrustExit; }
Win32Err = NetDomFilterSID(pwzArgValue, TrustingDomain, TrustedDomain, &TrustingDomainUser, &TrustedDomainUser );
} else if (CmdFlagOn(rgNetDomArgs, eTrustNameSuffixes)) {
//
// Get the name of the domain whose name is to be toggled.
//
Win32Err = NetDompGetArgumentString(rgNetDomArgs, eTrustNameSuffixes, &pwzArgValue); if (ERROR_SUCCESS != Win32Err) { goto HandleTrustExit; }
if (CmdFlagOn(rgNetDomArgs, eTrustToggleSuffixes)) { //
// Get the number of the name to toggle.
//
Win32Err = NetDompGetArgumentString(rgNetDomArgs, eTrustToggleSuffixes, &pwzArgValue2); if (ERROR_SUCCESS != Win32Err) { goto HandleTrustExit; }
if (!pwzArgValue2) { NetDompDisplayMessage(MSG_SUFFIX_INDEX_MISSING); Win32Err = ERROR_INVALID_PARAMETER; goto HandleTrustExit; }
i = wcstoul(pwzArgValue2, L'\0', 10);
NetApiBufferFree(pwzArgValue2); pwzArgValue2 = NULL;
if (1 > i) { NetDompDisplayMessage(MSG_SUFFIX_INDEX_BOUNDS); Win32Err = ERROR_INVALID_PARAMETER; goto HandleTrustExit; }
Win32Err = NetDomForestSuffix(pwzArgValue, i, TrustingDomain, &TrustingDomainUser); } else { Win32Err = NetDomForestSuffix(pwzArgValue, 0, TrustingDomain, &TrustingDomainUser); }
} else {
Win32Err = ERROR_INVALID_PARAMETER; }
HandleTrustExit: if (pwzArgValue) { NetApiBufferFree(pwzArgValue); } NetApiBufferFree( TrustedDomain ); NetDompFreeAuthIdent( &TrustedDomainUser ); NetDompFreeAuthIdent( &TrustingDomainUser );
if (NO_ERROR != Win32Err) { NetDompDisplayErrorMessage(Win32Err); }
return( Win32Err ); }
DWORD NetDompIsParentChild( IN PND5_TRUST_INFO pFirstDomainInfo, IN PND5_TRUST_INFO pSecondDomainInfo, OUT BOOL * pfParentChild) /*++
Routine Description:
Is the domain named by the second argument a child or parent of the first argument domain.
The Parent or Child bits of the trust-info Flags element is set as appropriate.
--*/ { DWORD Win32Err; PDS_DOMAIN_TRUSTS rgDomains = NULL; ULONG ulCount = 0, i, ulLocalDomainIdx = (ULONG)-1, ulOtherDomainIdx = (ULONG)-1; ULONG ulLocalDomainParent = (ULONG)-1, ulOtherDomainParent = (ULONG)-1; PWSTR pwzServer, pwzOtherDomainDnsName, pwzOtherDomainNetbiosName; BOOL fFirstIsLocal = TRUE;
*pfParentChild = FALSE;
// The domain which is used as the starting point for the enumeration is
// called the "local" domain and the remaining domain is the "other" domain.
//
if (pFirstDomainInfo->Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND) { // The first domain does not exist, so use the second domain's server
// as the starting point for the domain enumeration.
//
pwzServer = pSecondDomainInfo->Server; ASSERT(!(pSecondDomainInfo->Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND)); pwzOtherDomainDnsName = pFirstDomainInfo->DomainName->Buffer; pwzOtherDomainNetbiosName = pFirstDomainInfo->DomainName->Buffer; fFirstIsLocal = FALSE; } else { // The first domain exists, so use its server as the starting point
// for the domain enumeration.
//
pwzServer = pFirstDomainInfo->Server; pwzOtherDomainDnsName = pSecondDomainInfo->DomainName->Buffer; pwzOtherDomainNetbiosName = (pSecondDomainInfo->Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND) ? pSecondDomainInfo->DomainName->Buffer : pSecondDomainInfo->FlatName->Buffer; }
ASSERT(pwzServer);
// Specifying DS_DOMAIN_IN_FOREST will eliminate any external trusts
// in the result set.
//
Win32Err = DsEnumerateDomainTrusts(pwzServer, DS_DOMAIN_IN_FOREST, &rgDomains, &ulCount);
if (Win32Err != ERROR_SUCCESS) { return Win32Err; }
for (i = 0; i < ulCount; i++) { ASSERT(rgDomains[i].TrustType & TRUST_TYPE_UPLEVEL);
if (rgDomains[i].Flags & DS_DOMAIN_PRIMARY) { ulLocalDomainIdx = i; DBG_VERBOSE(("%2d: Local domain: %ws (%ws)\n", i, rgDomains[i].DnsDomainName, rgDomains[i].NetbiosDomainName)) if (!(rgDomains[i].Flags & DS_DOMAIN_TREE_ROOT)) { DBG_VERBOSE(("\tParent index of above domain: %d\n", rgDomains[i].ParentIndex)) ulLocalDomainParent = rgDomains[i].ParentIndex; } else { DBG_VERBOSE(("\tThis domain is a tree root\n")) } continue; }
#if DBG == 1
DBG_VERBOSE(("%2d: Domain: %ws (%ws)\n", i, rgDomains[i].DnsDomainName, rgDomains[i].NetbiosDomainName)) if (rgDomains[i].Flags & DS_DOMAIN_TREE_ROOT) DBG_VERBOSE(("\tThis domain is a tree root\n")) else DBG_VERBOSE(("\tParent index of above domain: %d\n", rgDomains[i].ParentIndex)) #endif
if ((rgDomains[i].NetbiosDomainName && _wcsicmp(rgDomains[i].NetbiosDomainName, pwzOtherDomainNetbiosName) == 0) || (rgDomains[i].DnsDomainName && _wcsicmp(rgDomains[i].DnsDomainName, pwzOtherDomainDnsName) == 0)) { ulOtherDomainIdx = i; DBG_VERBOSE(("\tThis domain is the second domain\n")) if (!(rgDomains[i].Flags & DS_DOMAIN_TREE_ROOT)) { ulOtherDomainParent = rgDomains[i].ParentIndex; } continue; }
#if DBG == 1
if (!(rgDomains[i].Flags & DS_DOMAIN_DIRECT_OUTBOUND)) { DBG_VERBOSE(("%2d: Indirectly trusted domain: %ws (%ws)\n", i, rgDomains[i].DnsDomainName, rgDomains[i].NetbiosDomainName)) } #endif
}
if (rgDomains) { NetApiBufferFree(rgDomains); }
// Determine the relationship between the two domains. One of three
// situations will apply:
// 1. The local domain is the parent of the other domain. If true, then
// the parent index of the other domain will point to the local domain.
// In addition, the other domain cannot be a tree root.
// 2. The local domain is the child of the other domain. If true, then
// the parent index of the local domain will point to the other domain.
// The local domain then cannot be a tree root.
// 3. The two domains don't have a parent-child relationship. It must be
// a shortcut or external trust.
//
if (ulOtherDomainIdx == (ULONG)-1) { // Other domain not found, it must be a shortcut trust (case 3 above).
//
DBG_VERBOSE(("\n")) return ERROR_SUCCESS; }
if (ulLocalDomainParent == ulOtherDomainIdx) { // Case 2, the local domain is the child of the other domain.
//
if (fFirstIsLocal) { pFirstDomainInfo->Flags |= NETDOM_TRUST_FLAG_CHILD; pSecondDomainInfo->Flags |= NETDOM_TRUST_FLAG_PARENT; } else { pSecondDomainInfo->Flags |= NETDOM_TRUST_FLAG_CHILD; pFirstDomainInfo->Flags |= NETDOM_TRUST_FLAG_PARENT; } } else { //
// Case 1 above, the local domain is the parent of the other domain.
//
if (fFirstIsLocal) { pFirstDomainInfo->Flags |= NETDOM_TRUST_FLAG_PARENT; pSecondDomainInfo->Flags |= NETDOM_TRUST_FLAG_CHILD; } else { pSecondDomainInfo->Flags |= NETDOM_TRUST_FLAG_PARENT; pFirstDomainInfo->Flags |= NETDOM_TRUST_FLAG_CHILD; } }
*pfParentChild = TRUE; DBG_VERBOSE(("\tpfParentChild set to TRUE\n\n"))
return ERROR_SUCCESS; }
|