windows-nt/Source/XPSP1/NT/ds/netapi/access/uasp.c

1184 lines
27 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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;
}