WindowsXP-SP1/ds/netapi/netdom/trust.cxx

4447 lines
140 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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;
}