mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1794 lines
45 KiB
1794 lines
45 KiB
/*++
|
|
|
|
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 <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 <lmuse.h> // NetUseAdd
|
|
#include <netlogon.h> // Needed by logonp.h
|
|
#include <logonp.h> // I_NetGetDCList()
|
|
#include <names.h>
|
|
#include <netdebug.h>
|
|
#include <netlib.h>
|
|
#include <netlibnt.h>
|
|
|
|
// #include <secobj.h>
|
|
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <uasp.h>
|
|
|
|
// #include <rpc.h> // Needed by NetRpc.h
|
|
// #include <netrpc.h> // My prototype, NET_REMOTE_FLAG_ equates.
|
|
// #include <rpcutil.h> // NetpRpcStatusToApiStatus().
|
|
#include <tstring.h> // NetAllocWStrFromWStr
|
|
|
|
//
|
|
// Server Description Cache
|
|
//
|
|
// The most recently accessed server description is cached in the
|
|
// per-process instance data.
|
|
//
|
|
|
|
typedef struct _SERVER_CACHE_ENTRY {
|
|
|
|
BOOL Valid; // True if cache entry is valid.
|
|
|
|
LPWSTR ServerName; // The server name
|
|
|
|
SAM_HANDLE SamServerHandle; // Sam Connection handle.
|
|
|
|
PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo;
|
|
// this info structure will have the name
|
|
// of the account domain and the domain SID.
|
|
|
|
} SERVER_CACHE_ENTRY, *PSERVER_CACHE_ENTRY;
|
|
|
|
DBGSTATIC SID_IDENTIFIER_AUTHORITY UaspBuiltinAuthority = SECURITY_NT_AUTHORITY;
|
|
DBGSTATIC SERVER_CACHE_ENTRY UaspTheServerCache;
|
|
DBGSTATIC PSERVER_CACHE_ENTRY UaspServerCache = &UaspTheServerCache;
|
|
|
|
DBGSTATIC CRITICAL_SECTION UaspCacheCritSect;
|
|
// Critical Section which serializes access to cache
|
|
|
|
#ifdef UAS_DEBUG
|
|
DWORD UasTrace = 0;
|
|
#endif // UAS_DEBUG
|
|
|
|
|
|
NET_API_STATUS
|
|
UaspInitialize(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Perform per-process initialization
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Error code for the operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Initialize the critical section that protects the server cache
|
|
//
|
|
|
|
InitializeCriticalSection( &UaspCacheCritSect );
|
|
|
|
//
|
|
// Clear the cache entry.
|
|
//
|
|
|
|
UaspServerCache->Valid = FALSE;
|
|
UaspServerCache->ServerName = NULL;
|
|
UaspServerCache->SamServerHandle = NULL;
|
|
UaspServerCache->AccountDomainInfo = NULL;
|
|
|
|
return NERR_Success;
|
|
} // UaspInitialize
|
|
|
|
|
|
DBGSTATIC VOID
|
|
UaspInvalidateCache(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Invalidate the server cache entry deallocating any allocated buffers.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
UaspServerCache->Valid = FALSE;
|
|
|
|
if ( UaspServerCache->ServerName != NULL ) {
|
|
NetpMemoryFree( UaspServerCache->ServerName );
|
|
UaspServerCache->ServerName = NULL;
|
|
}
|
|
|
|
if ( UaspServerCache->SamServerHandle != NULL ) {
|
|
(VOID) SamCloseHandle( UaspServerCache->SamServerHandle );
|
|
UaspServerCache->SamServerHandle = NULL;
|
|
}
|
|
|
|
if ( UaspServerCache->AccountDomainInfo != NULL ) {
|
|
LsaFreeMemory( UaspServerCache->AccountDomainInfo );
|
|
UaspServerCache->AccountDomainInfo = NULL;
|
|
}
|
|
|
|
} // UaspInvalidateCache
|
|
|
|
|
|
VOID
|
|
UaspFlush(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Invalidate the server cache entry deallocating any allocated buffers.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Lock the Crit Sect while flushing the cache.
|
|
//
|
|
|
|
EnterCriticalSection( &UaspCacheCritSect );
|
|
UaspInvalidateCache();
|
|
LeaveCriticalSection( &UaspCacheCritSect );
|
|
|
|
} // UaspFlush
|
|
|
|
|
|
VOID
|
|
UaspClose(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Perform per-process cleanup
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Free up any resources consumed by the server cache.
|
|
//
|
|
|
|
UaspInvalidateCache();
|
|
|
|
//
|
|
// Delete the critical section that protects the server cache
|
|
//
|
|
|
|
DeleteCriticalSection( &UaspCacheCritSect );
|
|
|
|
return;
|
|
} // UaspClose
|
|
|
|
|
|
NET_API_STATUS
|
|
UaspUpdateCache(
|
|
LPCWSTR ServerName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update the server cache. This function is called after entering in
|
|
'UaspCacheCritSect' critical section.
|
|
|
|
Arguments:
|
|
|
|
ServerName : name of the new server.
|
|
|
|
Return Value:
|
|
|
|
Error code for the operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS NetStatus;
|
|
|
|
//
|
|
// Uncache any existing cache entry.
|
|
//
|
|
|
|
if ( UaspServerCache->Valid ) {
|
|
UaspInvalidateCache();
|
|
}
|
|
|
|
//
|
|
// Cache the new server name.
|
|
//
|
|
|
|
UaspServerCache->ServerName =
|
|
NetpMemoryAllocate( (wcslen(ServerName)+1) * sizeof(WCHAR) );
|
|
|
|
if (UaspServerCache->ServerName == NULL) {
|
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
return NetStatus;
|
|
}
|
|
(VOID) wcscpy( UaspServerCache->ServerName, ServerName );
|
|
|
|
//
|
|
// Connect to the SAM server and
|
|
// Determine the Domain Id of the account domain for this server.
|
|
//
|
|
|
|
NetStatus = UaspGetDomainId( UaspServerCache->ServerName,
|
|
&UaspServerCache->SamServerHandle,
|
|
&UaspServerCache->AccountDomainInfo );
|
|
|
|
if ( NetStatus != NERR_Success ) {
|
|
UaspInvalidateCache();
|
|
IF_DEBUG( UAS_DEBUG_UASP ) {
|
|
NetpKdPrint(( "UaspUpdateCache: Cannot UaspGetDomainId %ld\n",
|
|
NetStatus ));
|
|
}
|
|
return ( NetStatus );
|
|
}
|
|
|
|
//
|
|
// Finally, mark the cache entry as valid.
|
|
//
|
|
|
|
UaspServerCache->Valid = TRUE;
|
|
|
|
return NERR_Success;
|
|
|
|
}
|
|
|
|
|
|
NET_API_STATUS
|
|
UaspGetDomainId(
|
|
IN LPCWSTR ServerName OPTIONAL,
|
|
OUT PSAM_HANDLE SamServerHandle OPTIONAL,
|
|
OUT PPOLICY_ACCOUNT_DOMAIN_INFO * AccountDomainInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return a domain ID of the account domain of a 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.
|
|
|
|
SamServerHandle - Returns the SAM connection handle if the caller wants it.
|
|
|
|
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_HANDLE LocalSamHandle = NULL;
|
|
|
|
ACCESS_MASK LSADesiredAccess;
|
|
LSA_HANDLE LSAPolicyHandle = NULL;
|
|
OBJECT_ATTRIBUTES LSAObjectAttributes;
|
|
|
|
UNICODE_STRING ServerNameString;
|
|
|
|
|
|
//
|
|
// Connect to the SAM server
|
|
//
|
|
|
|
RtlInitUnicodeString( &ServerNameString, ServerName );
|
|
|
|
Status = SamConnect(
|
|
&ServerNameString,
|
|
&LocalSamHandle,
|
|
SAM_SERVER_LOOKUP_DOMAIN,
|
|
NULL);
|
|
|
|
if ( !NT_SUCCESS(Status)) {
|
|
IF_DEBUG( UAS_DEBUG_UASP ) {
|
|
NetpKdPrint(( "UaspGetDomainId: Cannot connect to Sam %lX\n",
|
|
Status ));
|
|
}
|
|
LocalSamHandle = NULL;
|
|
NetStatus = NetpNtStatusToApiStatus( Status );
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Open LSA to read account domain info.
|
|
//
|
|
|
|
if ( AccountDomainInfo != NULL) {
|
|
//
|
|
// set desired access mask.
|
|
//
|
|
|
|
LSADesiredAccess = POLICY_VIEW_LOCAL_INFORMATION;
|
|
|
|
InitializeObjectAttributes( &LSAObjectAttributes,
|
|
NULL, // Name
|
|
0, // Attributes
|
|
NULL, // Root
|
|
NULL ); // Security Descriptor
|
|
|
|
Status = LsaOpenPolicy( &ServerNameString,
|
|
&LSAObjectAttributes,
|
|
LSADesiredAccess,
|
|
&LSAPolicyHandle );
|
|
|
|
if( !NT_SUCCESS(Status) ) {
|
|
|
|
IF_DEBUG( UAS_DEBUG_UASP ) {
|
|
NetpKdPrint(( "UaspGetDomainId: "
|
|
"Cannot open LSA Policy %lX\n", Status ));
|
|
}
|
|
|
|
NetStatus = NetpNtStatusToApiStatus( Status );
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// now read account domain info from LSA.
|
|
//
|
|
|
|
Status = LsaQueryInformationPolicy(
|
|
LSAPolicyHandle,
|
|
PolicyAccountDomainInformation,
|
|
(PVOID *) AccountDomainInfo );
|
|
|
|
if( !NT_SUCCESS(Status) ) {
|
|
|
|
IF_DEBUG( UAS_DEBUG_UASP ) {
|
|
NetpKdPrint(( "UaspGetDomainId: "
|
|
"Cannot read LSA %lX\n", Status ));
|
|
}
|
|
|
|
NetStatus = NetpNtStatusToApiStatus( Status );
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return the SAM connection handle to the caller if he wants it.
|
|
// Otherwise, disconnect from SAM.
|
|
//
|
|
|
|
if ( ARGUMENT_PRESENT( SamServerHandle ) ) {
|
|
*SamServerHandle = LocalSamHandle;
|
|
LocalSamHandle = NULL;
|
|
}
|
|
|
|
NetStatus = NERR_Success;
|
|
|
|
|
|
//
|
|
// Cleanup locally used resources
|
|
//
|
|
Cleanup:
|
|
if ( LocalSamHandle != NULL ) {
|
|
(VOID) SamCloseHandle( LocalSamHandle );
|
|
}
|
|
|
|
if( LSAPolicyHandle != NULL ) {
|
|
LsaClose( LSAPolicyHandle );
|
|
}
|
|
|
|
return NetStatus;
|
|
|
|
} // UaspGetDomainId
|
|
|
|
|
|
NET_API_STATUS
|
|
UaspOpenDomainNonCached(
|
|
IN LPCWSTR ServerName OPTIONAL,
|
|
IN ULONG DesiredAccess,
|
|
IN BOOL AccountDomain,
|
|
OUT PSAM_HANDLE DomainHandle,
|
|
OUT PSID *DomainId OPTIONAL,
|
|
OUT LPWSTR *ShareName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return a domain handle given the server name and the access desired to the domain.
|
|
|
|
Arguments:
|
|
|
|
ServerName - A pointer to a string containing the name of the remote
|
|
server 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.
|
|
|
|
ShareName - Returns the name of the share used to set up alternate credentials.
|
|
This name will only be returned if alternate (NULL) credentials were needed.
|
|
If this buffer is returned, the caller is responsible for call NetUseDel
|
|
for this share name after closing all handle to the server (including
|
|
UaspCloseDomain on DomainHandle).
|
|
|
|
Buffer should be free by NetApiBufferFree.
|
|
|
|
Return Value:
|
|
|
|
Error code for the operation. NULL means initialization was successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NET_API_STATUS NetStatus;
|
|
NTSTATUS Status;
|
|
PSID LocalDomainId;
|
|
DWORD LocalBuiltinDomainSid[sizeof(SID)/sizeof(DWORD) + SID_MAX_SUB_AUTHORITIES ];
|
|
|
|
LPWSTR LocalShareName = NULL;
|
|
BOOL NetUseAddSucceeded = FALSE;
|
|
|
|
SAM_HANDLE SamServerHandle = NULL;
|
|
|
|
PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo = NULL;
|
|
|
|
//
|
|
// Give everyone DOMAIN_LOOKUP access.
|
|
//
|
|
|
|
DesiredAccess |= DOMAIN_LOOKUP;
|
|
|
|
|
|
//
|
|
// Sanity check the server name
|
|
//
|
|
|
|
if ( ServerName == NULL ) {
|
|
ServerName = L"";
|
|
}
|
|
|
|
if ( *ServerName != L'\0' &&
|
|
(ServerName[0] != L'\\' || ServerName[1] != L'\\') ) {
|
|
return NERR_InvalidComputer;
|
|
}
|
|
|
|
|
|
//
|
|
// Connect to the SAM server and
|
|
// Determine the Domain Id of the account domain for this server.
|
|
//
|
|
|
|
NetStatus = UaspGetDomainId( ServerName,
|
|
&SamServerHandle,
|
|
AccountDomain ? &AccountDomainInfo : NULL );
|
|
|
|
//
|
|
// Consider the case where we don't have access to the primary domain DC.
|
|
//
|
|
|
|
if ( NetStatus == ERROR_ACCESS_DENIED ) {
|
|
DWORD TempStatus;
|
|
USE_INFO_2 UseInfo2;
|
|
|
|
|
|
//
|
|
// Try setting up a null session to the DC in the primary domain.
|
|
//
|
|
|
|
LocalShareName =
|
|
NetpMemoryAllocate( (wcslen( ServerName ) + 5 + 1) * sizeof(WCHAR) );
|
|
|
|
if ( LocalShareName == NULL ) {
|
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
wcscpy( LocalShareName, ServerName );
|
|
wcscat( LocalShareName, L"\\IPC$" );
|
|
|
|
|
|
UseInfo2.ui2_local = NULL;
|
|
UseInfo2.ui2_remote = LocalShareName;
|
|
UseInfo2.ui2_password = L"";
|
|
UseInfo2.ui2_asg_type = USE_IPC;
|
|
UseInfo2.ui2_username = L"";
|
|
UseInfo2.ui2_domainname = L"";
|
|
|
|
TempStatus = NetUseAdd( NULL, 2, (LPBYTE) &UseInfo2, NULL );
|
|
|
|
if ( TempStatus == NERR_Success ) {
|
|
|
|
NetUseAddSucceeded = TRUE;
|
|
NetStatus = UaspGetDomainId( ServerName,
|
|
&SamServerHandle,
|
|
AccountDomain ? &AccountDomainInfo : NULL );
|
|
|
|
|
|
} else {
|
|
IF_DEBUG( UAS_DEBUG_UASP ) {
|
|
NetpKdPrint(( "UaspOpenDomainNonCached: %ws: Cannot NetUseAdd (Null Session) %ld\n",
|
|
ServerName,
|
|
TempStatus ));
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if ( NetStatus != NERR_Success ) {
|
|
IF_DEBUG( UAS_DEBUG_UASP ) {
|
|
NetpKdPrint(( "UaspOpenDomainNonCached: %ws: Cannot UaspGetDomainId %ld\n",
|
|
ServerName,
|
|
NetStatus ));
|
|
}
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Choose the domain ID for the right SAM domain.
|
|
//
|
|
|
|
if ( AccountDomain ) {
|
|
LocalDomainId = AccountDomainInfo->DomainSid;
|
|
} 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(( "UaspOpenDomainNonCached: %ws: Cannot SamOpenDomain %lX\n",
|
|
ServerName,
|
|
Status ));
|
|
}
|
|
*DomainHandle = NULL;
|
|
NetStatus = NetpNtStatusToApiStatus( Status );
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Return the DomainId to the caller in an allocated buffer
|
|
//
|
|
|
|
if (ARGUMENT_PRESENT( DomainId ) ) {
|
|
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 ( AccountDomainInfo != NULL ) {
|
|
LsaFreeMemory( AccountDomainInfo );
|
|
}
|
|
if ( SamServerHandle != NULL ) {
|
|
(VOID) SamCloseHandle( SamServerHandle );
|
|
}
|
|
|
|
//
|
|
//
|
|
|
|
if ( LocalShareName != NULL ) {
|
|
|
|
//
|
|
// If success,
|
|
// pass any share name to our caller.
|
|
//
|
|
if ( NetStatus == NERR_Success ) {
|
|
*ShareName = LocalShareName;
|
|
|
|
//
|
|
// If failure,
|
|
// clean up the share.
|
|
//
|
|
} else {
|
|
|
|
if ( NetUseAddSucceeded ) {
|
|
NET_API_STATUS TempStatus;
|
|
|
|
TempStatus = NetUseDel( NULL, LocalShareName, FALSE );
|
|
|
|
if ( TempStatus != NERR_Success ) {
|
|
IF_DEBUG( UAS_DEBUG_UASP ) {
|
|
NetpKdPrint(( "UaspOpenDomainNonCached: %ws: Cannot NetUseDel (Null Session) %ld\n",
|
|
ServerName,
|
|
TempStatus ));
|
|
}
|
|
}
|
|
}
|
|
|
|
NetpMemoryFree( LocalShareName );
|
|
}
|
|
}
|
|
|
|
return NetStatus;
|
|
|
|
} // UaspOpenDomainNonCached
|
|
|
|
|
|
NET_API_STATUS
|
|
UaspOpenDomainWithDomainName(
|
|
IN LPCWSTR DomainName,
|
|
IN ULONG DesiredAccess,
|
|
IN BOOL AccountDomain,
|
|
OUT PSAM_HANDLE DomainHandle,
|
|
OUT PSID *DomainId OPTIONAL,
|
|
OUT LPWSTR *ServerName,
|
|
OUT LPWSTR *ShareName
|
|
)
|
|
|
|
/*++
|
|
|
|
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.
|
|
|
|
ServerName - Returns the UNC name of a DC in the specified domain. Returns
|
|
NULL if the current machine is to be used.
|
|
|
|
Buffer should be free by NetApiBufferFree.
|
|
|
|
ShareName - Returns the name of the share used to set up alternate credentials.
|
|
This name will only be returned if alternate (NULL) credentials were needed.
|
|
If this buffer is returned, the caller is responsible for call NetUseDel
|
|
for this share name after closing all handle to the server (including
|
|
UaspCloseDomain on DomainHandle).
|
|
|
|
Buffer should be free by NetApiBufferFree.
|
|
|
|
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 MyDomainName = NULL;
|
|
LPWSTR MyPrimaryDomainDc = NULL;
|
|
LPWSTR MyPrimaryDomainDcShare = NULL;
|
|
BOOLEAN MyPrimaryDomainDcShareConnected = FALSE;
|
|
|
|
ULONG DcCount;
|
|
PUNICODE_STRING DcNames = NULL;
|
|
ULONG DomainIndex;
|
|
ULONG DomainStartingIndex;
|
|
|
|
//
|
|
// Initialization
|
|
//
|
|
*ServerName = NULL;
|
|
|
|
//
|
|
// Check to see if the domain specified refers to this machine.
|
|
//
|
|
|
|
if ( DomainName == NULL || *DomainName == L'\0' ) {
|
|
*ServerName = NULL;
|
|
|
|
NetStatus = UaspOpenDomainNonCached(
|
|
*ServerName,
|
|
DesiredAccess,
|
|
AccountDomain,
|
|
DomainHandle,
|
|
DomainId,
|
|
ShareName );
|
|
|
|
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 ) {
|
|
*ServerName = NULL;
|
|
|
|
NetStatus = UaspOpenDomainNonCached(
|
|
*ServerName,
|
|
DesiredAccess,
|
|
AccountDomain,
|
|
DomainHandle,
|
|
DomainId,
|
|
ShareName );
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// See if this machine has a secure channel to the target domain.
|
|
//
|
|
|
|
NetStatus = NetGetAnyDCName (
|
|
NULL,
|
|
DomainName,
|
|
(LPBYTE *)ServerName );
|
|
|
|
if ( NetStatus == NERR_Success ) {
|
|
|
|
NetStatus = UaspOpenDomainNonCached(
|
|
*ServerName,
|
|
DesiredAccess,
|
|
AccountDomain,
|
|
DomainHandle,
|
|
DomainId,
|
|
ShareName );
|
|
|
|
goto Cleanup;
|
|
|
|
} else if ( NetStatus == ERROR_NO_LOGON_SERVERS ) {
|
|
|
|
|
|
IF_DEBUG( UAS_DEBUG_UASP ) {
|
|
NetpKdPrint(( "UaspOpenDomainWithDomainName: %ws: Cannot NetGetAnyDCName %ld\n",
|
|
DomainName,
|
|
NetStatus ));
|
|
}
|
|
|
|
// If we get a definitive answer, don't try any more.
|
|
NetStatus = NERR_DCNotFound;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// On non-DCs
|
|
// Try seeing if my primary domain has a secure channel to the target domain.
|
|
//
|
|
// Start by getting the name of a DC in our primary domain.
|
|
//
|
|
|
|
if ( NtProductType != NtProductLanManNt ) {
|
|
|
|
NetStatus = NetGetAnyDCName (
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE *)&MyPrimaryDomainDc );
|
|
|
|
if ( NetStatus == NERR_Success ) {
|
|
|
|
//
|
|
// See if my primary domain has a secure channel to the target domain.
|
|
//
|
|
|
|
NetStatus = NetGetAnyDCName (
|
|
MyPrimaryDomainDc,
|
|
DomainName,
|
|
(LPBYTE *)ServerName );
|
|
|
|
if ( NetStatus == NERR_Success ) {
|
|
NetStatus = UaspOpenDomainNonCached(
|
|
*ServerName,
|
|
DesiredAccess,
|
|
AccountDomain,
|
|
DomainHandle,
|
|
DomainId,
|
|
ShareName );
|
|
|
|
goto Cleanup;
|
|
|
|
} else if ( NetStatus == ERROR_NO_LOGON_SERVERS ) {
|
|
|
|
IF_DEBUG( UAS_DEBUG_UASP ) {
|
|
NetpKdPrint(( "UaspOpenDomainWithDomainName: %ws (%ws): Cannot NetGetAnyDCName %ld\n",
|
|
DomainName,
|
|
MyPrimaryDomainDc,
|
|
NetStatus ));
|
|
}
|
|
|
|
// If we get a definitive answer, don't try any more.
|
|
NetStatus = NERR_DCNotFound;
|
|
goto Cleanup;
|
|
|
|
//
|
|
// Consider the case where we don't have access to the primary domain DC.
|
|
//
|
|
|
|
} else if ( NetStatus == ERROR_ACCESS_DENIED ) {
|
|
USE_INFO_2 UseInfo2;
|
|
|
|
|
|
//
|
|
// Try setting up a null session to the DC in the primary domain.
|
|
//
|
|
|
|
MyPrimaryDomainDcShare =
|
|
NetpMemoryAllocate( (wcslen( MyPrimaryDomainDc ) + 5 + 1) * sizeof(WCHAR) );
|
|
|
|
if ( MyPrimaryDomainDcShare == NULL ) {
|
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
wcscpy( MyPrimaryDomainDcShare, MyPrimaryDomainDc );
|
|
wcscat( MyPrimaryDomainDcShare, L"\\IPC$" );
|
|
|
|
|
|
UseInfo2.ui2_local = NULL;
|
|
UseInfo2.ui2_remote = MyPrimaryDomainDcShare;
|
|
UseInfo2.ui2_password = L"";
|
|
UseInfo2.ui2_asg_type = USE_IPC;
|
|
UseInfo2.ui2_username = L"";
|
|
UseInfo2.ui2_domainname = L"";
|
|
|
|
NetStatus = NetUseAdd( NULL, 2, (LPBYTE) &UseInfo2, NULL );
|
|
|
|
if ( NetStatus == NERR_Success ) {
|
|
MyPrimaryDomainDcShareConnected = TRUE;
|
|
|
|
//
|
|
// Try again using the null session.
|
|
//
|
|
|
|
NetStatus = NetGetAnyDCName (
|
|
MyPrimaryDomainDc,
|
|
DomainName,
|
|
(LPBYTE *)ServerName );
|
|
|
|
if ( NetStatus == NERR_Success ) {
|
|
NetStatus = UaspOpenDomainNonCached(
|
|
*ServerName,
|
|
DesiredAccess,
|
|
AccountDomain,
|
|
DomainHandle,
|
|
DomainId,
|
|
ShareName );
|
|
|
|
goto Cleanup;
|
|
} else if ( NetStatus == ERROR_NO_LOGON_SERVERS ) {
|
|
|
|
IF_DEBUG( UAS_DEBUG_UASP ) {
|
|
NetpKdPrint(( "UaspOpenDomainWithDomainName: %ws (%ws): Cannot NetGetAnyDCName on Null session %ld\n",
|
|
DomainName,
|
|
MyPrimaryDomainDc,
|
|
NetStatus ));
|
|
}
|
|
|
|
// If we get a definitive answer, don't try any more.
|
|
NetStatus = NERR_DCNotFound;
|
|
goto Cleanup;
|
|
} else {
|
|
|
|
IF_DEBUG( UAS_DEBUG_UASP ) {
|
|
NetpKdPrint(( "UaspOpenDomainWithDomainName: %ws (%ws): Cannot NetGetAnyDCName on Null session %ld (continuing)\n",
|
|
DomainName,
|
|
MyPrimaryDomainDc,
|
|
NetStatus ));
|
|
}
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
IF_DEBUG( UAS_DEBUG_UASP ) {
|
|
NetpKdPrint(( "UaspOpenDomainWithDomainName: %ws (%ws): Cannot NetUseAdd %ld (continuing)\n",
|
|
DomainName,
|
|
MyPrimaryDomainDc,
|
|
NetStatus ));
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
IF_DEBUG( UAS_DEBUG_UASP ) {
|
|
NetpKdPrint(( "UaspOpenDomainWithDomainName: %ws (%ws): Cannot NetGetAnyDCName %ld (continuing)\n",
|
|
DomainName,
|
|
MyPrimaryDomainDc,
|
|
NetStatus ));
|
|
}
|
|
}
|
|
} else {
|
|
IF_DEBUG( UAS_DEBUG_UASP ) {
|
|
NetpKdPrint(( "UaspOpenDomainWithDomainName: %ws: Cannot NetGetAnyDCName of primary domain %ld (Continuing)\n",
|
|
DomainName,
|
|
NetStatus ));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// ASSERT: All attempts to find a DC in the target domain have failed.
|
|
//
|
|
|
|
//
|
|
// Try using NetGetDcList to get a list of all DCs in the domain.
|
|
// Iterate through that list connecting to a random entry available.
|
|
//
|
|
// One might argue that the caller of this routine doesn't care about domains
|
|
// that aren't in its trust hierarchy. However, the original API might be
|
|
// focused on a server other than this one. In that case we'd have to write this
|
|
// routine centric to that machine (not this machine). That'd be hard.
|
|
//
|
|
|
|
|
|
NetStatus = I_NetGetDCList (
|
|
NULL,
|
|
(LPWSTR) DomainName,
|
|
&DcCount,
|
|
&DcNames );
|
|
|
|
|
|
if ( NetStatus != NERR_Success ) {
|
|
|
|
IF_DEBUG( UAS_DEBUG_UASP ) {
|
|
NetpKdPrint(( "UaspOpenDomainWithDomainName: %ws: Cannot I_NetGetDCList %ld\n",
|
|
DomainName,
|
|
NetStatus ));
|
|
}
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( DcCount == 0 ) {
|
|
|
|
NetStatus = NERR_DCNotFound;
|
|
IF_DEBUG( UAS_DEBUG_UASP ) {
|
|
NetpKdPrint(( "UaspOpenDomainWithDomainName: %ws: Cannot I_NetGetDCList %ld (Count == 0)\n",
|
|
DomainName,
|
|
NetStatus ));
|
|
}
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Loop through the DCs finding one we can actually connect to.
|
|
// Pick a starting place at random.
|
|
//
|
|
|
|
DomainStartingIndex = (GetTickCount() >> 5) % DcCount;
|
|
DomainIndex = DomainStartingIndex;
|
|
|
|
do {
|
|
|
|
if ( DcNames[DomainIndex].Length != 0 &&
|
|
DcNames[DomainIndex].Length < UNCLEN*sizeof(WCHAR) ) {
|
|
|
|
WCHAR LocalServerName[UNCLEN+1];
|
|
|
|
RtlCopyMemory( LocalServerName,
|
|
DcNames[DomainIndex].Buffer,
|
|
DcNames[DomainIndex].Length );
|
|
LocalServerName[DcNames[DomainIndex].Length/sizeof(WCHAR)] = L'\0';
|
|
|
|
NetStatus = UaspOpenDomainNonCached(
|
|
LocalServerName,
|
|
DesiredAccess,
|
|
AccountDomain,
|
|
DomainHandle,
|
|
DomainId,
|
|
ShareName );
|
|
|
|
if ( NetStatus == NERR_Success ) {
|
|
*ServerName = NetpAllocWStrFromWStr( LocalServerName );
|
|
if ( *ServerName == NULL ) {
|
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
(VOID) UaspCloseDomain( *DomainHandle );
|
|
}
|
|
goto Cleanup;
|
|
}
|
|
|
|
}
|
|
|
|
DomainIndex = (DomainIndex + 1) % DcCount;
|
|
|
|
} while ( DomainIndex != DomainStartingIndex );
|
|
|
|
NetStatus = NERR_DCNotFound;
|
|
|
|
|
|
//
|
|
// Delete locally used resources
|
|
//
|
|
|
|
Cleanup:
|
|
|
|
if ( MyDomainName != NULL ) {
|
|
NetApiBufferFree( MyDomainName );
|
|
}
|
|
if ( MyPrimaryDomainDc != NULL ) {
|
|
NetApiBufferFree( MyPrimaryDomainDc );
|
|
}
|
|
if ( MyPrimaryDomainDcShare != NULL ) {
|
|
if ( MyPrimaryDomainDcShareConnected ) {
|
|
DWORD TempStatus;
|
|
TempStatus = NetUseDel( NULL, MyPrimaryDomainDcShare, FALSE );
|
|
if ( TempStatus != NERR_Success ) {
|
|
IF_DEBUG( UAS_DEBUG_UASP ) {
|
|
NetpKdPrint(( "UaspOpenDomainWithDomainName: %ws (%ws): Cannot NetUseDel %ld\n",
|
|
DomainName,
|
|
MyPrimaryDomainDcShare,
|
|
TempStatus ));
|
|
}
|
|
}
|
|
}
|
|
NetpMemoryFree( MyPrimaryDomainDcShare );
|
|
}
|
|
if ( DcNames != NULL ) {
|
|
NetApiBufferFree( DcNames );
|
|
}
|
|
|
|
if ( NetStatus != NERR_Success ) {
|
|
|
|
if ( *ServerName != NULL ) {
|
|
NetApiBufferFree( *ServerName );
|
|
*ServerName = NULL;
|
|
}
|
|
|
|
*DomainHandle = NULL;
|
|
}
|
|
|
|
return NetStatus;
|
|
} // UaspOpenDomainWithDomainName
|
|
|
|
|
|
NET_API_STATUS
|
|
UaspOpenDomain(
|
|
IN LPCWSTR ServerName OPTIONAL,
|
|
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:
|
|
|
|
ServerName - A pointer to a string containing the name of the remote
|
|
server 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:
|
|
|
|
Error code for the operation. NULL means initialization was successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NET_API_STATUS NetStatus;
|
|
NTSTATUS Status;
|
|
PSID LocalDomainId;
|
|
DWORD LocalBuiltinDomainSid[sizeof(SID)/sizeof(DWORD) + SID_MAX_SUB_AUTHORITIES ];
|
|
BOOLEAN UpdatedCache = FALSE;
|
|
// DWORD WaitStatus;
|
|
|
|
//
|
|
// Give everyone DOMAIN_LOOKUP access.
|
|
//
|
|
|
|
DesiredAccess |= DOMAIN_LOOKUP;
|
|
|
|
//
|
|
// Gain exclusive access to the server cache.
|
|
//
|
|
|
|
EnterCriticalSection( &UaspCacheCritSect );
|
|
|
|
//
|
|
// If the correct SAM connection is not cached,
|
|
// Uncache the current entry.
|
|
// Cache the new entry.
|
|
//
|
|
|
|
if ( ServerName == NULL ) {
|
|
ServerName = L"";
|
|
}
|
|
|
|
if ( *ServerName != L'\0' &&
|
|
(ServerName[0] != L'\\' || ServerName[1] != L'\\') ) {
|
|
LeaveCriticalSection( &UaspCacheCritSect );
|
|
return NERR_InvalidComputer;
|
|
}
|
|
|
|
if ( !(UaspServerCache->Valid &&
|
|
((*UaspServerCache->ServerName == L'\0' &&
|
|
*ServerName == L'\0' ) ||
|
|
UaspNameCompare( UaspServerCache->ServerName+2,
|
|
(LPWSTR)ServerName+2,
|
|
NAMETYPE_COMPUTER ) == 0))) {
|
|
|
|
//
|
|
// update server cache.
|
|
//
|
|
|
|
NetStatus = UaspUpdateCache( ServerName );
|
|
|
|
if( NetStatus != NERR_Success ) {
|
|
LeaveCriticalSection( &UaspCacheCritSect );
|
|
return NetStatus;
|
|
}
|
|
|
|
UpdatedCache = TRUE;
|
|
}
|
|
|
|
//
|
|
// Choose the domain ID for the right SAM domain.
|
|
//
|
|
|
|
if ( AccountDomain ) {
|
|
LocalDomainId = UaspServerCache->AccountDomainInfo->DomainSid;
|
|
} else {
|
|
RtlInitializeSid( (PSID) LocalBuiltinDomainSid, &UaspBuiltinAuthority, 1 );
|
|
*(RtlSubAuthoritySid( (PSID)LocalBuiltinDomainSid, 0 )) = SECURITY_BUILTIN_DOMAIN_RID;
|
|
LocalDomainId = (PSID) LocalBuiltinDomainSid;
|
|
}
|
|
|
|
//
|
|
// At this point the domain ID of the account domain of the server is
|
|
// cached. Open the domain.
|
|
//
|
|
|
|
Status = SamOpenDomain( UaspServerCache->SamServerHandle,
|
|
DesiredAccess,
|
|
LocalDomainId,
|
|
DomainHandle );
|
|
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
|
|
//
|
|
// Many errors occur because we have a stale Sam Server handle.
|
|
//
|
|
|
|
if ( ! UpdatedCache ) {
|
|
//
|
|
// update server cache.
|
|
//
|
|
|
|
NetStatus = UaspUpdateCache( ServerName );
|
|
|
|
if( NetStatus != NERR_Success ) {
|
|
LeaveCriticalSection( &UaspCacheCritSect );
|
|
*DomainHandle = NULL;
|
|
return NetStatus;
|
|
}
|
|
|
|
// Update Cache re-allocated the Domain Sid, too.
|
|
if ( AccountDomain ) {
|
|
LocalDomainId = UaspServerCache->AccountDomainInfo->DomainSid;
|
|
}
|
|
|
|
Status = SamOpenDomain( UaspServerCache->SamServerHandle,
|
|
DesiredAccess,
|
|
LocalDomainId,
|
|
DomainHandle );
|
|
|
|
}
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
LeaveCriticalSection( &UaspCacheCritSect );
|
|
IF_DEBUG( UAS_DEBUG_UASP ) {
|
|
NetpKdPrint(( "UaspOpenDomain: Cannot SamOpenDomain %lX\n",
|
|
Status ));
|
|
}
|
|
*DomainHandle = NULL;
|
|
return NetpNtStatusToApiStatus( Status );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return the DomainId to the caller in an allocated buffer
|
|
//
|
|
|
|
if (ARGUMENT_PRESENT( DomainId ) ) {
|
|
ULONG SidSize;
|
|
SidSize = RtlLengthSid( LocalDomainId );
|
|
|
|
*DomainId = NetpMemoryAllocate( SidSize );
|
|
|
|
if ( *DomainId == NULL ) {
|
|
LeaveCriticalSection( &UaspCacheCritSect );
|
|
(VOID) SamCloseHandle( *DomainHandle );
|
|
*DomainHandle = NULL;
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
if ( !NT_SUCCESS( RtlCopySid( SidSize, *DomainId, LocalDomainId) ) ) {
|
|
LeaveCriticalSection( &UaspCacheCritSect );
|
|
(VOID) SamCloseHandle( *DomainHandle );
|
|
*DomainHandle = NULL;
|
|
NetpMemoryFree( *DomainId );
|
|
*DomainId = NULL;
|
|
return NERR_InternalError;
|
|
}
|
|
|
|
}
|
|
|
|
LeaveCriticalSection( &UaspCacheCritSect );
|
|
return NERR_Success;
|
|
|
|
} // UaspOpenDomain
|
|
|
|
|
|
|
|
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 LPCWSTR ServerName,
|
|
IN PDOMAIN_SERVER_ROLE_INFORMATION DomainServerRole
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sets the server role in builtin domain.
|
|
|
|
This function will make use of the server cache for the connection
|
|
handle. If the ServerName specified is the same as the one in the
|
|
cache then it will use the server handle from cache and open
|
|
builtin domain. Otherwise this function update the server cache
|
|
exclusively and then open builtin domain.
|
|
|
|
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;
|
|
|
|
SAM_HANDLE BuiltinDomainHandle = NULL;
|
|
|
|
//
|
|
// Open the domain asking for accumulated desired access
|
|
//
|
|
|
|
NetStatus = UaspOpenDomain( ServerName,
|
|
DOMAIN_ADMINISTER_SERVER,
|
|
FALSE, // Builtin Domain
|
|
&BuiltinDomainHandle,
|
|
NULL ); // DomainId
|
|
|
|
if ( NetStatus != NERR_Success ) {
|
|
|
|
IF_DEBUG( UAS_DEBUG_UASP ) {
|
|
NetpKdPrint(( "UaspBuiltinSetServerRole: "
|
|
"Cannot UaspOpenDomain [Butilin] %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;
|
|
}
|