1184 lines
27 KiB
C
1184 lines
27 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
uasp.c
|
||
|
||
Abstract:
|
||
|
||
Private functions shared by the UAS API routines.
|
||
|
||
Author:
|
||
|
||
Cliff Van Dyke (cliffv) 20-Feb-1991
|
||
|
||
Environment:
|
||
|
||
User mode only.
|
||
Contains NT-specific code.
|
||
Requires ANSI C extensions: slash-slash comments, long external names.
|
||
|
||
Revision History:
|
||
|
||
17-Apr-1991 (cliffv)
|
||
Incorporated review comments.
|
||
|
||
--*/
|
||
|
||
#include <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
#undef DOMAIN_ALL_ACCESS // defined in both ntsam.h and ntwinapi.h
|
||
#include <ntsam.h>
|
||
#include <ntlsa.h>
|
||
|
||
#include <windef.h>
|
||
#include <winbase.h>
|
||
#include <lmcons.h>
|
||
|
||
#include <accessp.h>
|
||
#include <dsgetdc.h>
|
||
#include <icanon.h>
|
||
#include <lmerr.h>
|
||
#include <lmwksta.h>
|
||
#include <lmaccess.h>
|
||
#include <lmapibuf.h>
|
||
#include <lmremutl.h> // NetpRemoteComputerSupports(), SUPPORTS_ stuff
|
||
#include <lmsvc.h> // SERVICE_WORKSTATION.
|
||
#include <names.h>
|
||
#include <netdebug.h>
|
||
#include <netlib.h>
|
||
#include <netlibnt.h>
|
||
|
||
#include <stddef.h>
|
||
#include <stdlib.h>
|
||
|
||
#include <uasp.h>
|
||
|
||
#include <tstring.h> // NetAllocWStrFromWStr
|
||
|
||
SID_IDENTIFIER_AUTHORITY UaspBuiltinAuthority = SECURITY_NT_AUTHORITY;
|
||
|
||
#ifdef UAS_DEBUG
|
||
DWORD UasTrace = 0;
|
||
#endif // UAS_DEBUG
|
||
|
||
|
||
NET_API_STATUS
|
||
UaspOpenSam(
|
||
IN LPCWSTR ServerName OPTIONAL,
|
||
IN BOOL AllowNullSession,
|
||
OUT PSAM_HANDLE SamServerHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Open a handle to a Sam server.
|
||
|
||
Arguments:
|
||
|
||
ServerName - A pointer to a string containing the name of the
|
||
Domain Controller (DC) to query. A NULL pointer
|
||
or string specifies the local machine.
|
||
|
||
AllowNullSession - TRUE if we should fall back to the NULL session if
|
||
we cannot connect using current credentials
|
||
|
||
SamServerHandle - Returns the SAM connection handle if the caller wants it.
|
||
Close this handle by calling SamCloseHandle
|
||
|
||
Return Value:
|
||
|
||
Error code for the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS NetStatus;
|
||
NTSTATUS Status;
|
||
|
||
BOOLEAN ImpersonatingAnonymous = FALSE;
|
||
HANDLE CurrentToken = NULL;
|
||
|
||
UNICODE_STRING ServerNameString;
|
||
|
||
|
||
//
|
||
// Sanity check the server name
|
||
//
|
||
|
||
if ( ServerName == NULL ) {
|
||
ServerName = L"";
|
||
}
|
||
|
||
#ifdef notdef
|
||
if ( *ServerName != L'\0' &&
|
||
(ServerName[0] != L'\\' || ServerName[1] != L'\\') ) {
|
||
return NERR_InvalidComputer;
|
||
}
|
||
#endif // notdef
|
||
|
||
|
||
//
|
||
// Connect to the SAM server
|
||
//
|
||
|
||
RtlInitUnicodeString( &ServerNameString, ServerName );
|
||
|
||
Status = SamConnect(
|
||
&ServerNameString,
|
||
SamServerHandle,
|
||
SAM_SERVER_LOOKUP_DOMAIN | SAM_SERVER_ENUMERATE_DOMAINS,
|
||
NULL);
|
||
|
||
//
|
||
// If the caller would rather use the null session than fail,
|
||
// impersonate the anonymous token.
|
||
//
|
||
|
||
if ( AllowNullSession && Status == STATUS_ACCESS_DENIED ) {
|
||
*SamServerHandle = NULL;
|
||
|
||
//
|
||
// Check to see if we're already impsonating
|
||
//
|
||
|
||
Status = NtOpenThreadToken(
|
||
NtCurrentThread(),
|
||
TOKEN_IMPERSONATE,
|
||
TRUE, // as self to ensure we never fail
|
||
&CurrentToken
|
||
);
|
||
|
||
if ( Status == STATUS_NO_TOKEN ) {
|
||
//
|
||
// We're not already impersonating
|
||
CurrentToken = NULL;
|
||
|
||
} else if ( !NT_SUCCESS(Status) ) {
|
||
IF_DEBUG( UAS_DEBUG_UASP ) {
|
||
NetpKdPrint(( "UaspOpenSam: cannot NtOpenThreadToken: 0x%lx\n",
|
||
Status ));
|
||
}
|
||
|
||
NetStatus = NetpNtStatusToApiStatus( Status );
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
//
|
||
// Impersonate the anonymous token
|
||
//
|
||
Status = NtImpersonateAnonymousToken( NtCurrentThread() );
|
||
|
||
if ( !NT_SUCCESS( Status)) {
|
||
IF_DEBUG( UAS_DEBUG_UASP ) {
|
||
NetpKdPrint(( "UaspOpenSam: cannot NtImpersonateAnonymousToken: 0x%lx\n",
|
||
Status ));
|
||
}
|
||
|
||
NetStatus = NetpNtStatusToApiStatus( Status );
|
||
goto Cleanup;
|
||
}
|
||
|
||
ImpersonatingAnonymous = TRUE;
|
||
|
||
//
|
||
// Connect again now that we're impersonating anonymous
|
||
//
|
||
|
||
Status = SamConnect(
|
||
&ServerNameString,
|
||
SamServerHandle,
|
||
SAM_SERVER_LOOKUP_DOMAIN | SAM_SERVER_ENUMERATE_DOMAINS,
|
||
NULL);
|
||
|
||
}
|
||
|
||
if ( !NT_SUCCESS(Status)) {
|
||
IF_DEBUG( UAS_DEBUG_UASP ) {
|
||
NetpKdPrint(( "UaspOpenSam: Cannot connect to Sam %lX\n",
|
||
Status ));
|
||
}
|
||
*SamServerHandle = NULL;
|
||
NetStatus = NetpNtStatusToApiStatus( Status );
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
NetStatus = NERR_Success;
|
||
|
||
|
||
//
|
||
// Cleanup locally used resources
|
||
//
|
||
Cleanup:
|
||
|
||
if ( ImpersonatingAnonymous ) {
|
||
|
||
Status = NtSetInformationThread(
|
||
NtCurrentThread(),
|
||
ThreadImpersonationToken,
|
||
&CurrentToken,
|
||
sizeof(HANDLE) );
|
||
|
||
if ( !NT_SUCCESS( Status)) {
|
||
IF_DEBUG( UAS_DEBUG_UASP ) {
|
||
NetpKdPrint(( "UaspOpenSam: cannot NtSetInformationThread: 0x%lx\n",
|
||
Status ));
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
if ( CurrentToken != NULL ) {
|
||
NtClose( CurrentToken );
|
||
}
|
||
|
||
return NetStatus;
|
||
|
||
}
|
||
|
||
|
||
NET_API_STATUS
|
||
UaspGetDomainId(
|
||
IN SAM_HANDLE SamServerHandle,
|
||
OUT PSID *DomainId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Return a domain ID of the account domain of a server.
|
||
|
||
Arguments:
|
||
|
||
SamServerHandle - A handle to the SAM server to open the domain on
|
||
|
||
DomainId - Receives a pointer to the domain ID.
|
||
Caller must deallocate buffer using NetpMemoryFree.
|
||
|
||
Return Value:
|
||
|
||
Error code for the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS NetStatus;
|
||
NTSTATUS Status;
|
||
|
||
SAM_ENUMERATE_HANDLE EnumContext;
|
||
PSAM_RID_ENUMERATION EnumBuffer = NULL;
|
||
DWORD CountReturned = 0;
|
||
PSID LocalDomainId = NULL;
|
||
DWORD LocalBuiltinDomainSid[sizeof(SID)/sizeof(DWORD) + SID_MAX_SUB_AUTHORITIES ];
|
||
|
||
|
||
BOOL AllDone = FALSE;
|
||
ULONG i;
|
||
|
||
//
|
||
// Compute the builtin domain sid.
|
||
//
|
||
|
||
RtlInitializeSid( (PSID) LocalBuiltinDomainSid, &UaspBuiltinAuthority, 1 );
|
||
*(RtlSubAuthoritySid( (PSID)LocalBuiltinDomainSid, 0 )) = SECURITY_BUILTIN_DOMAIN_RID;
|
||
|
||
|
||
//
|
||
// Loop getting the list of domain ids from SAM
|
||
//
|
||
|
||
EnumContext = 0;
|
||
do {
|
||
|
||
//
|
||
// Get several domain names.
|
||
//
|
||
|
||
Status = SamEnumerateDomainsInSamServer(
|
||
SamServerHandle,
|
||
&EnumContext,
|
||
&EnumBuffer,
|
||
8192, // PrefMaxLen
|
||
&CountReturned );
|
||
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
|
||
IF_DEBUG( UAS_DEBUG_UASP ) {
|
||
NetpKdPrint(( "UaspGetDomainId: Cannot SamEnumerateDomainsInSamServer %lX\n",
|
||
Status ));
|
||
}
|
||
NetStatus = NetpNtStatusToApiStatus( Status );
|
||
goto Cleanup;
|
||
}
|
||
|
||
if( Status != STATUS_MORE_ENTRIES ) {
|
||
AllDone = TRUE;
|
||
}
|
||
|
||
|
||
//
|
||
// Lookup the domain ids for the domains
|
||
//
|
||
|
||
for( i = 0; i < CountReturned; i++ ) {
|
||
|
||
IF_DEBUG( UAS_DEBUG_UASP ) {
|
||
NetpKdPrint(( "UaspGetDomainId: %wZ: domain name\n",
|
||
&EnumBuffer[i].Name ));
|
||
}
|
||
|
||
//
|
||
// Free the sid from the previous iteration.
|
||
//
|
||
|
||
if ( LocalDomainId != NULL ) {
|
||
SamFreeMemory( LocalDomainId );
|
||
LocalDomainId = NULL;
|
||
}
|
||
|
||
//
|
||
// Lookup the domain id
|
||
//
|
||
|
||
Status = SamLookupDomainInSamServer(
|
||
SamServerHandle,
|
||
&EnumBuffer[i].Name,
|
||
&LocalDomainId );
|
||
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
IF_DEBUG( UAS_DEBUG_UASP ) {
|
||
NetpKdPrint(( "UaspGetDomainId: Cannot SamLookupDomainInSamServer %lX\n",
|
||
Status ));
|
||
}
|
||
NetStatus = NetpNtStatusToApiStatus( Status );
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// If this is the builtin domain,
|
||
// ignore it.
|
||
//
|
||
|
||
if ( RtlEqualSid( (PSID)LocalBuiltinDomainSid, LocalDomainId ) ) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Found it.
|
||
//
|
||
|
||
*DomainId = LocalDomainId;
|
||
LocalDomainId = NULL;
|
||
NetStatus = NO_ERROR;
|
||
goto Cleanup;
|
||
|
||
}
|
||
|
||
//
|
||
// free up current EnumBuffer and get another EnumBuffer.
|
||
//
|
||
|
||
Status = SamFreeMemory( EnumBuffer );
|
||
NetpAssert( NT_SUCCESS(Status) );
|
||
EnumBuffer = NULL;
|
||
|
||
} while ( !AllDone );
|
||
|
||
NetStatus = ERROR_NO_SUCH_DOMAIN;
|
||
|
||
//
|
||
// Cleanup locally used resources
|
||
//
|
||
Cleanup:
|
||
|
||
if ( EnumBuffer != NULL ) {
|
||
Status = SamFreeMemory( EnumBuffer );
|
||
NetpAssert( NT_SUCCESS(Status) );
|
||
}
|
||
|
||
return NetStatus;
|
||
|
||
} // UaspGetDomainId
|
||
|
||
|
||
|
||
NET_API_STATUS
|
||
UaspOpenDomain(
|
||
IN SAM_HANDLE SamServerHandle,
|
||
IN ULONG DesiredAccess,
|
||
IN BOOL AccountDomain,
|
||
OUT PSAM_HANDLE DomainHandle,
|
||
OUT PSID *DomainId OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Return a domain handle given the server name and the access desired to the domain.
|
||
|
||
Arguments:
|
||
|
||
SamServerHandle - A handle to the SAM server to open the domain on
|
||
|
||
DesiredAccess - Supplies the access mask indicating which access types
|
||
are desired to the domain. This routine always requests DOMAIN_LOOKUP
|
||
access in addition to those specified.
|
||
|
||
AccountDomain - TRUE to open the Account domain. FALSE to open the
|
||
builtin domain.
|
||
|
||
DomainHandle - Receives the Domain handle to be used on future calls
|
||
to the SAM server.
|
||
|
||
DomainId - Recieves a pointer to the Sid of the domain. This domain ID
|
||
must be freed using NetpMemoryFree.
|
||
|
||
Return Value:
|
||
|
||
Error code for the operation. NULL means initialization was successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
NET_API_STATUS NetStatus;
|
||
NTSTATUS Status;
|
||
PSID LocalDomainId;
|
||
PSID AccountDomainId = NULL;
|
||
DWORD LocalBuiltinDomainSid[sizeof(SID)/sizeof(DWORD) + SID_MAX_SUB_AUTHORITIES ];
|
||
|
||
//
|
||
// Give everyone DOMAIN_LOOKUP access.
|
||
//
|
||
|
||
DesiredAccess |= DOMAIN_LOOKUP;
|
||
|
||
|
||
//
|
||
// Choose the domain ID for the right SAM domain.
|
||
//
|
||
|
||
if ( AccountDomain ) {
|
||
NetStatus = UaspGetDomainId( SamServerHandle, &AccountDomainId );
|
||
|
||
if ( NetStatus != NO_ERROR ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
LocalDomainId = AccountDomainId;
|
||
} else {
|
||
RtlInitializeSid( (PSID) LocalBuiltinDomainSid, &UaspBuiltinAuthority, 1 );
|
||
*(RtlSubAuthoritySid( (PSID)LocalBuiltinDomainSid, 0 )) = SECURITY_BUILTIN_DOMAIN_RID;
|
||
LocalDomainId = (PSID) LocalBuiltinDomainSid;
|
||
}
|
||
|
||
//
|
||
// Open the domain.
|
||
//
|
||
|
||
Status = SamOpenDomain( SamServerHandle,
|
||
DesiredAccess,
|
||
LocalDomainId,
|
||
DomainHandle );
|
||
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
|
||
IF_DEBUG( UAS_DEBUG_UASP ) {
|
||
NetpKdPrint(( "UaspOpenDomain: Cannot SamOpenDomain %lX\n",
|
||
Status ));
|
||
}
|
||
*DomainHandle = NULL;
|
||
NetStatus = NetpNtStatusToApiStatus( Status );
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Return the DomainId to the caller in an allocated buffer
|
||
//
|
||
|
||
if (ARGUMENT_PRESENT( DomainId ) ) {
|
||
|
||
//
|
||
// If we've already allocated the sid,
|
||
// just return it.
|
||
//
|
||
|
||
if ( AccountDomainId != NULL ) {
|
||
*DomainId = AccountDomainId;
|
||
AccountDomainId = NULL;
|
||
|
||
//
|
||
// Otherwise make a copy.
|
||
//
|
||
|
||
} else {
|
||
ULONG SidSize;
|
||
SidSize = RtlLengthSid( LocalDomainId );
|
||
|
||
*DomainId = NetpMemoryAllocate( SidSize );
|
||
|
||
if ( *DomainId == NULL ) {
|
||
(VOID) SamCloseHandle( *DomainHandle );
|
||
*DomainHandle = NULL;
|
||
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto Cleanup;
|
||
}
|
||
|
||
if ( !NT_SUCCESS( RtlCopySid( SidSize, *DomainId, LocalDomainId) ) ) {
|
||
(VOID) SamCloseHandle( *DomainHandle );
|
||
*DomainHandle = NULL;
|
||
NetpMemoryFree( *DomainId );
|
||
*DomainId = NULL;
|
||
NetStatus = NERR_InternalError;
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
NetStatus = NERR_Success;
|
||
|
||
|
||
Cleanup:
|
||
if ( AccountDomainId != NULL ) {
|
||
NetpMemoryFree( AccountDomainId );
|
||
}
|
||
|
||
return NetStatus;
|
||
|
||
}
|
||
|
||
|
||
NET_API_STATUS
|
||
UaspOpenDomainWithDomainName(
|
||
IN LPCWSTR DomainName,
|
||
IN ULONG DesiredAccess,
|
||
IN BOOL AccountDomain,
|
||
OUT PSAM_HANDLE DomainHandle,
|
||
OUT PSID *DomainId OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the name of a DC in the specified domain. The Server is guaranteed
|
||
to be up at the instance of this call.
|
||
|
||
Arguments:
|
||
|
||
DoaminName - A pointer to a string containing the name of the remote
|
||
domain containing the SAM database. A NULL pointer
|
||
or string specifies the local machine.
|
||
|
||
DesiredAccess - Supplies the access mask indicating which access types
|
||
are desired to the domain. This routine always requests DOMAIN_LOOKUP
|
||
access in addition to those specified.
|
||
|
||
AccountDomain - TRUE to open the Account domain. FALSE to open the
|
||
builtin domain.
|
||
|
||
DomainHandle - Receives the Domain handle to be used on future calls
|
||
to the SAM server.
|
||
|
||
DomainId - Recieves a pointer to the Sid of the domain. This domain ID
|
||
must be freed using NetpMemoryFree.
|
||
|
||
Return Value:
|
||
|
||
NERR_Success - Operation completed successfully
|
||
NERR_DCNotFound - DC for the specified domain could not be found.
|
||
etc.
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS NetStatus;
|
||
|
||
NT_PRODUCT_TYPE NtProductType;
|
||
LPWSTR ServerName;
|
||
LPWSTR MyDomainName = NULL;
|
||
ULONG Flags;
|
||
ULONG i;
|
||
PDOMAIN_CONTROLLER_INFOW DcInfo = NULL;
|
||
SAM_HANDLE SamServerHandle = NULL;
|
||
|
||
|
||
//
|
||
// Check to see if the domain specified refers to this machine.
|
||
//
|
||
|
||
if ( DomainName == NULL || *DomainName == L'\0' ) {
|
||
|
||
//
|
||
// Connect to the SAM server
|
||
//
|
||
|
||
NetStatus = UaspOpenSam( NULL,
|
||
FALSE, // Don't try null session
|
||
&SamServerHandle );
|
||
|
||
if ( NetStatus != NERR_Success ) {
|
||
IF_DEBUG( UAS_DEBUG_UASP ) {
|
||
NetpKdPrint(( "UaspOpenDomainWithDomainName: Cannot UaspOpenSam %ld\n", NetStatus ));
|
||
}
|
||
}
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
//
|
||
// Validate the DomainName
|
||
//
|
||
|
||
if ( !NetpIsDomainNameValid( (LPWSTR)DomainName) ) {
|
||
NetStatus = NERR_DCNotFound;
|
||
IF_DEBUG( UAS_DEBUG_UASP ) {
|
||
NetpKdPrint(( "UaspOpenDomainWithDomainName: %ws: Cannot SamOpenDomain %ld\n",
|
||
DomainName,
|
||
NetStatus ));
|
||
}
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Grab the product type once.
|
||
//
|
||
|
||
if ( !RtlGetNtProductType( &NtProductType ) ) {
|
||
NtProductType = NtProductWinNt;
|
||
}
|
||
|
||
//
|
||
// If this machine is a DC, this machine is refered to by domain name.
|
||
//
|
||
|
||
if ( NtProductType == NtProductLanManNt ) {
|
||
|
||
NetStatus = NetpGetDomainName( &MyDomainName );
|
||
|
||
if ( NetStatus != NERR_Success ) {
|
||
IF_DEBUG( UAS_DEBUG_UASP ) {
|
||
NetpKdPrint(( "UaspOpenDomainWithDomainName: %ws: Cannot NetpGetDomainName %ld\n",
|
||
DomainName,
|
||
NetStatus ));
|
||
}
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// If this machine is not a DC, this machine is refered to by computer name.
|
||
//
|
||
|
||
} else {
|
||
|
||
NetStatus = NetpGetComputerName( &MyDomainName );
|
||
|
||
if ( NetStatus != NERR_Success ) {
|
||
IF_DEBUG( UAS_DEBUG_UASP ) {
|
||
NetpKdPrint(( "UaspOpenDomainWithDomainName: %ws: Cannot NetpGetComputerName %ld\n",
|
||
DomainName,
|
||
NetStatus ));
|
||
}
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
if ( UaspNameCompare( MyDomainName, (LPWSTR) DomainName, NAMETYPE_DOMAIN ) == 0 ) {
|
||
|
||
//
|
||
// Connect to the SAM server
|
||
//
|
||
|
||
NetStatus = UaspOpenSam( NULL,
|
||
FALSE, // Don't try null session
|
||
&SamServerHandle );
|
||
|
||
if ( NetStatus != NERR_Success ) {
|
||
IF_DEBUG( UAS_DEBUG_UASP ) {
|
||
NetpKdPrint(( "UaspOpenDomainWithDomainName: Cannot UaspOpenSam %ld\n", NetStatus ));
|
||
}
|
||
}
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
//
|
||
// Try at least twice to find a DC.
|
||
//
|
||
|
||
Flags = 0;
|
||
for ( i=0; i<2; i++ ) {
|
||
|
||
|
||
//
|
||
// Get the name of a DC in the domain.
|
||
//
|
||
|
||
NetStatus = DsGetDcNameW( NULL,
|
||
DomainName,
|
||
NULL, // No domain GUID
|
||
NULL, // No site name
|
||
Flags |
|
||
DS_IS_FLAT_NAME |
|
||
DS_RETURN_FLAT_NAME,
|
||
&DcInfo );
|
||
|
||
if ( NetStatus != NO_ERROR ) {
|
||
|
||
IF_DEBUG( UAS_DEBUG_UASP ) {
|
||
NetpKdPrint(( "UaspOpenDomainWithDomainName: %ws: Cannot DsGetDcName %ld\n",
|
||
DomainName,
|
||
NetStatus ));
|
||
}
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Connect to the SAM server on that DC
|
||
//
|
||
|
||
NetStatus = UaspOpenSam( DcInfo->DomainControllerName,
|
||
TRUE, // Try null session
|
||
&SamServerHandle );
|
||
|
||
if ( NetStatus != NERR_Success ) {
|
||
IF_DEBUG( UAS_DEBUG_UASP ) {
|
||
NetpKdPrint(( "UaspOpenDomainWithDomainName: Cannot UaspOpenSam %ld\n", NetStatus ));
|
||
}
|
||
}
|
||
|
||
//
|
||
// If we got a definitive answer back from this DC,
|
||
// use it.
|
||
//
|
||
|
||
switch ( NetStatus ) {
|
||
case NO_ERROR:
|
||
case ERROR_ACCESS_DENIED:
|
||
case ERROR_NOT_ENOUGH_MEMORY:
|
||
case NERR_InvalidComputer:
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Otherwise, force rediscovery of a new DC.
|
||
//
|
||
|
||
Flags |= DS_FORCE_REDISCOVERY;
|
||
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Delete locally used resources
|
||
//
|
||
|
||
Cleanup:
|
||
|
||
//
|
||
// If we've successfully gotten this far,
|
||
// we have a SamServer handle.
|
||
//
|
||
// Just open the domain.
|
||
//
|
||
|
||
if ( NetStatus == NO_ERROR && SamServerHandle != NULL ) {
|
||
|
||
NetStatus = UaspOpenDomain(
|
||
SamServerHandle,
|
||
DesiredAccess,
|
||
AccountDomain,
|
||
DomainHandle,
|
||
DomainId );
|
||
}
|
||
|
||
//
|
||
// The SamServerHandle has outlived its usefulness
|
||
//
|
||
if ( SamServerHandle != NULL ) {
|
||
(VOID) SamCloseHandle( SamServerHandle );
|
||
}
|
||
|
||
|
||
if ( MyDomainName != NULL ) {
|
||
NetApiBufferFree( MyDomainName );
|
||
}
|
||
if ( DcInfo != NULL) {
|
||
NetApiBufferFree( DcInfo );
|
||
}
|
||
|
||
if ( NetStatus != NERR_Success ) {
|
||
*DomainHandle = NULL;
|
||
}
|
||
|
||
return NetStatus;
|
||
} // UaspOpenDomainWithDomainName
|
||
|
||
|
||
|
||
|
||
VOID
|
||
UaspCloseDomain(
|
||
IN SAM_HANDLE DomainHandle OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Close a Domain handle opened by UaspOpenDomain.
|
||
|
||
Arguments:
|
||
|
||
DomainHandle - Supplies the Domain Handle to close.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// Close the Domain Handle
|
||
//
|
||
|
||
if ( DomainHandle != NULL ) {
|
||
(VOID) SamCloseHandle( DomainHandle );
|
||
}
|
||
|
||
return;
|
||
} // UaspCloseDomain
|
||
|
||
|
||
|
||
NET_API_STATUS
|
||
UaspDownlevel(
|
||
IN LPCWSTR ServerName OPTIONAL,
|
||
IN NET_API_STATUS OriginalError,
|
||
OUT LPBOOL TryDownLevel
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is based on NetpHandleRpcFailure (courtesy of JohnRo).
|
||
It is different in that it doesn't handle RPC failures. Rather,
|
||
it tries to determine if a Sam call should go downlevel simply by
|
||
calling using the specified ServerName.
|
||
|
||
Arguments:
|
||
|
||
ServerName - The server name to handle the call.
|
||
|
||
OriginalError - Error gotten from RPC attempt.
|
||
|
||
TryDownLevel - Returns TRUE if we should try down-level.
|
||
|
||
Return Value:
|
||
|
||
NERR_Success - Use SAM to handle the call.
|
||
|
||
Other - Return the error to the caller.
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS NetStatus;
|
||
DWORD OptionsSupported = 0;
|
||
|
||
|
||
*TryDownLevel = FALSE;
|
||
|
||
//
|
||
// Learn about the machine. This is fairly easy since the
|
||
// NetRemoteComputerSupports also handles the local machine (whether
|
||
// or not a server name is given).
|
||
//
|
||
NetStatus = NetRemoteComputerSupports(
|
||
(LPWSTR) ServerName,
|
||
SUPPORTS_RPC | SUPPORTS_LOCAL | SUPPORTS_SAM_PROTOCOL,
|
||
&OptionsSupported);
|
||
|
||
if (NetStatus != NERR_Success) {
|
||
// This is where machine not found gets handled.
|
||
return NetStatus;
|
||
}
|
||
|
||
//
|
||
// If the machine supports SAM,
|
||
// just return now.
|
||
//
|
||
if (OptionsSupported & SUPPORTS_SAM_PROTOCOL) {
|
||
// SAM is only supported over RPC
|
||
NetpAssert((OptionsSupported & SUPPORTS_RPC) == SUPPORTS_RPC );
|
||
return OriginalError;
|
||
}
|
||
|
||
// The local system should always support SAM
|
||
NetpAssert((OptionsSupported & SUPPORTS_LOCAL) == 0 );
|
||
|
||
//
|
||
// Local workstation is not started? (It must be in order to
|
||
// remote APIs to the other system.)
|
||
//
|
||
|
||
if ( ! NetpIsServiceStarted(SERVICE_WORKSTATION) ) {
|
||
return (NERR_WkstaNotStarted);
|
||
}
|
||
|
||
//
|
||
// Tell the caller to try the RxNet routine.
|
||
//
|
||
*TryDownLevel = TRUE;
|
||
return OriginalError;
|
||
|
||
} // UaspDownlevel
|
||
|
||
|
||
|
||
NET_API_STATUS
|
||
UaspLSASetServerRole(
|
||
IN LPCWSTR ServerName,
|
||
IN PDOMAIN_SERVER_ROLE_INFORMATION DomainServerRole
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function sets the server role in LSA.
|
||
|
||
Arguments:
|
||
|
||
ServerName - The server name to handle the call.
|
||
|
||
ServerRole - The server role information.
|
||
|
||
Return Value:
|
||
|
||
NERR_Success - if the server role is successfully set in LSA.
|
||
|
||
Error code for the operation - if the operation was unsuccessful.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
NET_API_STATUS NetStatus;
|
||
|
||
UNICODE_STRING UnicodeStringServerName;
|
||
|
||
ACCESS_MASK LSADesiredAccess;
|
||
LSA_HANDLE LSAPolicyHandle = NULL;
|
||
OBJECT_ATTRIBUTES LSAObjectAttributes;
|
||
|
||
POLICY_LSA_SERVER_ROLE_INFO PolicyLsaServerRoleInfo;
|
||
|
||
|
||
RtlInitUnicodeString( &UnicodeStringServerName, ServerName );
|
||
|
||
//
|
||
// set desired access mask.
|
||
//
|
||
|
||
LSADesiredAccess = POLICY_SERVER_ADMIN;
|
||
|
||
InitializeObjectAttributes( &LSAObjectAttributes,
|
||
NULL, // Name
|
||
0, // Attributes
|
||
NULL, // Root
|
||
NULL ); // Security Descriptor
|
||
|
||
Status = LsaOpenPolicy( &UnicodeStringServerName,
|
||
&LSAObjectAttributes,
|
||
LSADesiredAccess,
|
||
&LSAPolicyHandle );
|
||
|
||
if( !NT_SUCCESS(Status) ) {
|
||
|
||
IF_DEBUG( UAS_DEBUG_UASP ) {
|
||
NetpKdPrint(( "UaspLSASetServerRole: "
|
||
"Cannot open LSA Policy %lX\n", Status ));
|
||
}
|
||
|
||
NetStatus = NetpNtStatusToApiStatus( Status );
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
//
|
||
// make PolicyLsaServerRoleInfo
|
||
//
|
||
|
||
switch( DomainServerRole->DomainServerRole ) {
|
||
|
||
case DomainServerRoleBackup :
|
||
|
||
PolicyLsaServerRoleInfo.LsaServerRole = PolicyServerRoleBackup;
|
||
|
||
break;
|
||
|
||
case DomainServerRolePrimary :
|
||
|
||
PolicyLsaServerRoleInfo.LsaServerRole = PolicyServerRolePrimary;
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
IF_DEBUG( UAS_DEBUG_UASP ) {
|
||
NetpKdPrint(( "UaspLSASetServerRole: "
|
||
"Unknown Server Role %lX\n",
|
||
DomainServerRole->DomainServerRole ));
|
||
}
|
||
|
||
NetStatus = NERR_InternalError;
|
||
goto Cleanup;
|
||
|
||
}
|
||
|
||
//
|
||
// now set PolicyLsaServerRoleInformation
|
||
//
|
||
|
||
Status = LsaSetInformationPolicy(
|
||
LSAPolicyHandle,
|
||
PolicyLsaServerRoleInformation,
|
||
(PVOID) &PolicyLsaServerRoleInfo );
|
||
|
||
if( !NT_SUCCESS(Status) ) {
|
||
|
||
IF_DEBUG( UAS_DEBUG_UASP ) {
|
||
NetpKdPrint(( "UaspLSASetServerRole: "
|
||
"Cannot set Information Policy %lX\n", Status ));
|
||
}
|
||
|
||
NetStatus = NetpNtStatusToApiStatus( Status );
|
||
goto Cleanup;
|
||
|
||
}
|
||
|
||
//
|
||
// Successfully done
|
||
//
|
||
|
||
NetStatus = NERR_Success;
|
||
|
||
Cleanup:
|
||
|
||
if( LSAPolicyHandle != NULL ) {
|
||
Status = LsaClose( LSAPolicyHandle );
|
||
NetpAssert( NT_SUCCESS( Status ) );
|
||
}
|
||
|
||
return NetStatus;
|
||
|
||
}
|
||
|
||
|
||
NET_API_STATUS
|
||
UaspBuiltinDomainSetServerRole(
|
||
IN SAM_HANDLE SamServerHandle,
|
||
IN PDOMAIN_SERVER_ROLE_INFORMATION DomainServerRole
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function sets the server role in builtin domain.
|
||
|
||
Arguments:
|
||
|
||
SamServerHandle - A handle to the SAM server to set the role on
|
||
|
||
ServerRole - The server role information.
|
||
|
||
Return Value:
|
||
|
||
NERR_Success - if the server role is successfully set in LSA.
|
||
|
||
Error code for the operation - if the operation was unsuccessful.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
NET_API_STATUS NetStatus;
|
||
|
||
SAM_HANDLE BuiltinDomainHandle = NULL;
|
||
|
||
//
|
||
// Open the domain asking for accumulated desired access
|
||
//
|
||
|
||
NetStatus = UaspOpenDomain( SamServerHandle,
|
||
DOMAIN_ADMINISTER_SERVER,
|
||
FALSE, // Builtin Domain
|
||
&BuiltinDomainHandle,
|
||
NULL ); // DomainId
|
||
|
||
if ( NetStatus != NERR_Success ) {
|
||
|
||
IF_DEBUG( UAS_DEBUG_UASP ) {
|
||
NetpKdPrint(( "UaspBuiltinSetServerRole: "
|
||
"Cannot UaspOpenDomain [Builtin] %ld\n",
|
||
NetStatus ));
|
||
}
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// now we have open the builtin domain, update server role.
|
||
//
|
||
|
||
Status = SamSetInformationDomain(
|
||
BuiltinDomainHandle,
|
||
DomainServerRoleInformation,
|
||
DomainServerRole );
|
||
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
|
||
IF_DEBUG( UAS_DEBUG_UASP ) {
|
||
NetpKdPrint(( "UaspBuiltinSetServerRole: "
|
||
"Cannot SamSetInformationDomain %lX\n",
|
||
Status ));
|
||
}
|
||
|
||
NetStatus = NetpNtStatusToApiStatus( Status );
|
||
goto Cleanup;
|
||
}
|
||
|
||
NetStatus = NERR_Success;
|
||
|
||
Cleanup:
|
||
|
||
//
|
||
// Close DomainHandle.
|
||
//
|
||
|
||
if ( BuiltinDomainHandle != NULL ) {
|
||
(VOID) SamCloseHandle( BuiltinDomainHandle );
|
||
}
|
||
|
||
return NetStatus;
|
||
}
|