mirror of https://github.com/tongzx/nt5src
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.
4446 lines
136 KiB
4446 lines
136 KiB
/*++
|
|
|
|
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;
|
|
}
|