2063 lines
52 KiB
C
2063 lines
52 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
rpcapi.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the routines for the dssetup APIs that use RPC. The
|
||
routines in this module are merely wrappers that work as follows:
|
||
|
||
Fuke copied lsa\uclient and hacked on to make it work for DsRole apis
|
||
|
||
Author:
|
||
|
||
Mac McLain (MacM) April 14, 1997
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include <lsacomp.h>
|
||
#include "dssetup_c.h"
|
||
#include <rpcndr.h>
|
||
#include <dssetp.h>
|
||
#include <winreg.h>
|
||
|
||
#include <wxlpc.h>
|
||
#include <crypt.h>
|
||
#include <rc4.h>
|
||
#include <md5.h>
|
||
|
||
//
|
||
// Local prototypes
|
||
//
|
||
DWORD
|
||
DsRolepGetPrimaryDomainInformationDownlevel(
|
||
IN LPWSTR Server,
|
||
OUT PBYTE *Buffer
|
||
);
|
||
|
||
DWORD
|
||
DsRolepGetProductTypeForServer(
|
||
IN LPWSTR Server,
|
||
IN OUT PNT_PRODUCT_TYPE ProductType
|
||
);
|
||
|
||
|
||
DWORD
|
||
DsRolepEncryptPasswordStart(
|
||
IN LPCWSTR ServerName OPTIONAL,
|
||
IN LPCWSTR *Passwords,
|
||
IN ULONG Count,
|
||
OUT RPC_BINDING_HANDLE *RpcBindingHandle,
|
||
OUT HANDLE *RedirHandle,
|
||
IN OUT PDSROLEPR_ENCRYPTED_USER_PASSWORD *EncryptedUserPassword
|
||
);
|
||
|
||
VOID
|
||
DsRolepEncryptPasswordEnd(
|
||
IN RPC_BINDING_HANDLE RpcBindingHandle,
|
||
IN HANDLE RedirHandle OPTIONAL,
|
||
IN PDSROLEPR_ENCRYPTED_USER_PASSWORD *EncryptedUserPassword OPTIONAL,
|
||
IN ULONG Count
|
||
);
|
||
|
||
DWORD
|
||
DsRolepHashkey(
|
||
IN OUT LPWSTR Key,
|
||
OUT PVOID Syskey,
|
||
IN OUT ULONG cbSyskey
|
||
);
|
||
|
||
DWORD
|
||
DsRolepEncryptHash(
|
||
OUT PUNICODE_STRING EncryptedSyskey
|
||
);
|
||
|
||
////////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// DS Setup and initialization routines //
|
||
// //
|
||
////////////////////////////////////////////////////////////////////////////
|
||
|
||
BOOLEAN
|
||
DsRolepIsSetupRunning(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine determines if this call is being made during setup or not
|
||
|
||
Arguments:
|
||
|
||
VOID
|
||
|
||
Return Value:
|
||
|
||
TRUE -- The call is being made during setup
|
||
|
||
FALSE -- The call is not being made during setup
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
HANDLE InstallationEvent;
|
||
OBJECT_ATTRIBUTES EventAttributes;
|
||
UNICODE_STRING EventName;
|
||
BOOLEAN Setup = FALSE;
|
||
|
||
//
|
||
// If the following event exists, then we are in setup mode
|
||
//
|
||
RtlInitUnicodeString( &EventName,
|
||
L"\\INSTALLATION_SECURITY_HOLD" );
|
||
InitializeObjectAttributes( &EventAttributes,
|
||
&EventName, 0, 0, NULL );
|
||
|
||
Status = NtOpenEvent( &InstallationEvent,
|
||
SYNCHRONIZE,
|
||
&EventAttributes );
|
||
|
||
if ( NT_SUCCESS( Status) ) {
|
||
|
||
NtClose( InstallationEvent );
|
||
Setup = TRUE;
|
||
|
||
}
|
||
|
||
return( Setup );
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
DsRolepServerBind(
|
||
IN OPTIONAL PDSROLE_SERVER_NAME ServerName,
|
||
OUT handle_t *BindHandle
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called from the LSA client stubs when
|
||
it is necessary to bind to the LSA on some server.
|
||
|
||
Arguments:
|
||
|
||
ServerName - A pointer to a string containing the name of the server
|
||
to bind with.
|
||
|
||
Return Value:
|
||
|
||
The binding handle is returned to the stub routine. If the
|
||
binding is unsuccessful, a NULL will be returned.
|
||
|
||
--*/
|
||
{
|
||
handle_t BindingHandle = NULL;
|
||
NTSTATUS Status;
|
||
|
||
//
|
||
// Can't go remote when running in setup mode
|
||
//
|
||
if ( DsRolepIsSetupRunning() && ServerName != NULL ) {
|
||
|
||
return( STATUS_INVALID_SERVER_STATE );
|
||
}
|
||
|
||
Status = RpcpBindRpc ( ServerName,
|
||
L"lsarpc",
|
||
0,
|
||
&BindingHandle );
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
DbgPrint("DsRolepServerBind: RpcpBindRpc failed 0x%lx\n", Status);
|
||
|
||
} else {
|
||
|
||
*BindHandle = BindingHandle;
|
||
}
|
||
|
||
return( RtlNtStatusToDosError( Status ) );
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
DsRolepServerUnbind (
|
||
IN OPTIONAL PDSROLE_SERVER_NAME ServerName,
|
||
IN handle_t BindingHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called from the LSA client stubs when
|
||
it is necessary to unbind from the LSA server.
|
||
|
||
|
||
Arguments:
|
||
|
||
ServerName - This is the name of the server from which to unbind.
|
||
|
||
BindingHandle - This is the binding handle that is to be closed.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
{
|
||
UNREFERENCED_PARAMETER( ServerName ); // This parameter is not used
|
||
|
||
RpcpUnbindRpc ( BindingHandle );
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
DsRolepApiReturnResult(
|
||
ULONG ExceptionCode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function converts an exception code or status value returned
|
||
from the client stub to a value suitable for return by the API to
|
||
the client.
|
||
|
||
Arguments:
|
||
|
||
ExceptionCode - The exception code to be converted.
|
||
|
||
Return Value:
|
||
|
||
DWORD - The converted Nt Status code.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Return the actual value if compatible with Nt status codes,
|
||
// otherwise, return STATUS_UNSUCCESSFUL.
|
||
//
|
||
NTSTATUS Status;
|
||
DWORD Results;
|
||
|
||
if ( !NT_SUCCESS( ( NTSTATUS )ExceptionCode ) ) {
|
||
|
||
Results = RtlNtStatusToDosError( ( NTSTATUS )ExceptionCode );
|
||
|
||
} else {
|
||
|
||
Results = ExceptionCode;
|
||
}
|
||
|
||
return( Results );
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
WINAPI
|
||
DsRoleFreeMemory(
|
||
IN PVOID Buffer
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Some setup services that return a potentially large amount of memory,
|
||
such as an enumeration might, allocate the buffer in which the data
|
||
is returned. This function is used to free those buffers when they
|
||
are no longer needed.
|
||
|
||
Parameters:
|
||
|
||
Buffer - Pointer to the buffer to be freed. This buffer must
|
||
have been allocated by a previous dssetup service call.
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - normal, successful completion.
|
||
|
||
--*/
|
||
{
|
||
MIDL_user_free( Buffer );
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
DsRoleDnsNameToFlatName(
|
||
IN LPCWSTR lpServer OPTIONAL,
|
||
IN LPCWSTR lpDnsName,
|
||
OUT LPWSTR *lpFlatName,
|
||
OUT PULONG lpStatusFlag
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will get the default NetBIOS (or flat) domain name for the given Dns domain name
|
||
|
||
Arguments:
|
||
|
||
lpServer - Server on which to remote the call (NULL is local)
|
||
|
||
lpDnsName - Dns domain name to generate the flat name for
|
||
|
||
lpFlatName - Where the flat name is returned. Must be freed via MIDL_user_free
|
||
(or DsRoleFreeMemory)
|
||
|
||
lpStatusFlag - Flags that indicate information about the returned name. Valid flags are:
|
||
DSROLE_FLATNAME_DEFAULT -- This is the default NetBIOS name for this dns domain name
|
||
DSROLE_FLATNAME_UPGRADE -- This is the name that is current in use by this machine as
|
||
a flat name and cannot be changed.
|
||
|
||
Return Values:
|
||
|
||
ERROR_SUCCESS - Success
|
||
|
||
--*/
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
handle_t Handle = NULL;
|
||
|
||
Win32Err = DsRolepServerBind( (PDSROLE_SERVER_NAME)lpServer,
|
||
&Handle );
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
*lpFlatName = NULL;
|
||
*lpStatusFlag = 0;
|
||
|
||
Win32Err = DsRolerDnsNameToFlatName(
|
||
Handle,
|
||
( LPWSTR )lpDnsName,
|
||
lpFlatName,
|
||
lpStatusFlag );
|
||
|
||
} RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
||
Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
|
||
|
||
} RpcEndExcept;
|
||
|
||
|
||
DsRolepServerUnbind( (PDSROLE_SERVER_NAME)lpServer, Handle );
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
DsRoleDcAsDc(
|
||
IN LPCWSTR lpServer OPTIONAL,
|
||
IN LPCWSTR lpDnsDomainName,
|
||
IN LPCWSTR lpFlatDomainName,
|
||
IN LPCWSTR lpDomainAdminPassword OPTIONAL,
|
||
IN LPCWSTR lpSiteName OPTIONAL,
|
||
IN LPCWSTR lpDsDatabasePath,
|
||
IN LPCWSTR lpDsLogPath,
|
||
IN LPCWSTR lpSystemVolumeRootPath,
|
||
IN LPCWSTR lpParentDnsDomainName OPTIONAL,
|
||
IN LPCWSTR lpParentServer OPTIONAL,
|
||
IN LPCWSTR lpAccount OPTIONAL,
|
||
IN LPCWSTR lpPassword OPTIONAL,
|
||
IN LPCWSTR lpDsRepairPassword OPTIONAL,
|
||
IN ULONG Options,
|
||
OUT DSROLE_SERVEROP_HANDLE *DsOperationHandle
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will get the promote a server to be a DC in a domain
|
||
|
||
Arguments:
|
||
|
||
lpServer - Server on which to remote the call (NULL is local)
|
||
|
||
lpDnsDomainName - Dns domain name of the domain to install
|
||
|
||
lpFlatDomainName - NetBIOS domain name of the domain to install
|
||
|
||
lpDomainAdminPassword - Password to set on the administrator account if it is a new install
|
||
|
||
SiteName - Name of the site this DC should belong to
|
||
|
||
lpDsDatabasePath - Absolute path on the local machine where the Ds DIT should go
|
||
|
||
lpDsLogPath - Absolute path on the local machine where the Ds log files should go
|
||
|
||
lpSystemVolumeRootPath - Absolute path on the local machine which will be the root of
|
||
the system volume.
|
||
|
||
lpParentDnsDomainName - Optional. If present, set this domain up as a child of the
|
||
specified domain
|
||
|
||
lpParentServer - Optional. If present, use this server in the parent domain to replicate
|
||
the required information from
|
||
|
||
lpAccount - User account to use when setting up as a child domain
|
||
|
||
lpPassword - Password to use with the above account
|
||
|
||
lpDsRepairPassword - Password to use for the admin account of the repair mode
|
||
|
||
Options - Options to control the creation of the domain
|
||
|
||
DsOperationHandle - Handle to the operation is returned here.
|
||
|
||
Return Values:
|
||
|
||
ERROR_SUCCESS - Success
|
||
|
||
--*/
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
handle_t Handle = NULL;
|
||
HANDLE RedirHandle = NULL;
|
||
|
||
#define DSROLEP_DC_AS_DC_DA_PWD_INDEX 0
|
||
#define DSROLEP_DC_AS_DC_PWD_INDEX 1
|
||
#define DSROLEP_DC_AS_DC_DS_REPAIR_PWD_INDEX 2
|
||
#define DSROLEP_DC_AS_DC_MAX_PWD_COUNT 3
|
||
|
||
PDSROLEPR_ENCRYPTED_USER_PASSWORD EncryptedPasswords[DSROLEP_DC_AS_DC_MAX_PWD_COUNT];
|
||
LPCWSTR Passwords[DSROLEP_DC_AS_DC_MAX_PWD_COUNT];
|
||
|
||
Passwords[DSROLEP_DC_AS_DC_DA_PWD_INDEX] = lpDomainAdminPassword;
|
||
Passwords[DSROLEP_DC_AS_DC_PWD_INDEX] = lpPassword;
|
||
Passwords[DSROLEP_DC_AS_DC_DS_REPAIR_PWD_INDEX] = lpDsRepairPassword;
|
||
RtlZeroMemory( EncryptedPasswords, sizeof(EncryptedPasswords) );
|
||
|
||
Win32Err = DsRolepEncryptPasswordStart( lpServer,
|
||
Passwords,
|
||
NELEMENTS(Passwords),
|
||
&Handle,
|
||
&RedirHandle,
|
||
EncryptedPasswords );
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
RpcTryExcept {
|
||
|
||
Win32Err = DsRolerDcAsDc( Handle,
|
||
( LPWSTR )lpDnsDomainName,
|
||
( LPWSTR )lpFlatDomainName,
|
||
EncryptedPasswords[DSROLEP_DC_AS_DC_DA_PWD_INDEX],
|
||
( LPWSTR )lpSiteName,
|
||
( LPWSTR )lpDsDatabasePath,
|
||
( LPWSTR )lpDsLogPath,
|
||
( LPWSTR )lpSystemVolumeRootPath,
|
||
( LPWSTR )lpParentDnsDomainName,
|
||
( LPWSTR )lpParentServer,
|
||
( LPWSTR )lpAccount,
|
||
EncryptedPasswords[DSROLEP_DC_AS_DC_PWD_INDEX],
|
||
EncryptedPasswords[DSROLEP_DC_AS_DC_DS_REPAIR_PWD_INDEX],
|
||
Options,
|
||
( PDSROLER_HANDLE )DsOperationHandle );
|
||
|
||
} RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
||
Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
|
||
|
||
} RpcEndExcept;
|
||
|
||
|
||
DsRolepEncryptPasswordEnd( Handle,
|
||
RedirHandle,
|
||
EncryptedPasswords,
|
||
NELEMENTS(EncryptedPasswords) );
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
DsRoleDcAsReplica(
|
||
IN LPCWSTR lpServer OPTIONAL,
|
||
IN LPCWSTR lpDnsDomainName,
|
||
IN LPCWSTR lpReplicaServer,
|
||
IN LPCWSTR lpSiteName OPTIONAL,
|
||
IN LPCWSTR lpDsDatabasePath,
|
||
IN LPCWSTR lpDsLogPath,
|
||
IN LPCWSTR lpRestorePath OPTIONAL,
|
||
IN LPCWSTR lpSystemVolumeRootPath,
|
||
IN OUT LPWSTR lpBootkey OPTIONAL,
|
||
IN LPCWSTR lpAccount OPTIONAL,
|
||
IN LPCWSTR lpPassword OPTIONAL,
|
||
IN LPCWSTR lpDsRepairPassword OPTIONAL,
|
||
IN ULONG Options,
|
||
OUT DSROLE_SERVEROP_HANDLE *DsOperationHandle
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will install a server as a replica of an existing domain.
|
||
|
||
Arguments:
|
||
|
||
lpServer - OPTIONAL. Server to remote the call to.
|
||
|
||
lpDnsDomainName - Dns domain name of the domain to install into
|
||
|
||
lpReplicaServer - The name of a Dc within the existing domain, against which to replicate
|
||
|
||
lpSiteName - Name of the site this DC should belong to
|
||
|
||
lpDsDatabasePath - Absolute path on the local machine where the Ds DIT should go
|
||
|
||
lpDsLogPath - Absolute path on the local machine where the Ds log files should go
|
||
|
||
lpRestorepath - This is the path to a restored directory.
|
||
|
||
lpSystemVolumeRootPath - Absolute path on the local machine which will be the root of
|
||
the system volume.
|
||
|
||
lpAccount - User account to use when setting up as a child domain
|
||
|
||
lpPassword - Password to use with the above account
|
||
|
||
lpDsRepairPassword - Password to use for the admin account of the repair mode
|
||
|
||
Options - Options to control the creation of the domain
|
||
|
||
DsOperationHandle - Handle to the operation is returned here.
|
||
|
||
Return Values:
|
||
|
||
--*/
|
||
{
|
||
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
handle_t Handle = NULL;
|
||
HANDLE RedirHandle = NULL;
|
||
PVOID Syskey[16];
|
||
USHORT cbSyskey=sizeof(Syskey)/sizeof(Syskey[0]);
|
||
UNICODE_STRING EncryptedBootKey;
|
||
|
||
|
||
#define DSROLEP_DC_AS_REPLICA_PWD_INDEX 0
|
||
#define DSROLEP_DC_AS_REPLICA_DS_REPAIR_PWD_INDEX 1
|
||
#define DSROLEP_DC_AS_REPLICA_MAX_PWD_COUNT 2
|
||
|
||
PDSROLEPR_ENCRYPTED_USER_PASSWORD EncryptedPasswords[DSROLEP_DC_AS_REPLICA_MAX_PWD_COUNT];
|
||
LPCWSTR Passwords[DSROLEP_DC_AS_REPLICA_MAX_PWD_COUNT];
|
||
|
||
Passwords[DSROLEP_DC_AS_REPLICA_PWD_INDEX] = lpPassword;
|
||
Passwords[DSROLEP_DC_AS_REPLICA_DS_REPAIR_PWD_INDEX] = lpDsRepairPassword;
|
||
RtlZeroMemory( EncryptedPasswords, sizeof(EncryptedPasswords) );
|
||
|
||
Win32Err = DsRolepEncryptPasswordStart( lpServer,
|
||
Passwords,
|
||
NELEMENTS(Passwords),
|
||
&Handle,
|
||
&RedirHandle,
|
||
EncryptedPasswords );
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if(lpBootkey)
|
||
{
|
||
Win32Err = DsRolepHashkey(lpBootkey,
|
||
Syskey,
|
||
cbSyskey
|
||
);
|
||
if (Win32Err != ERROR_SUCCESS) {
|
||
return Win32Err;
|
||
}
|
||
|
||
EncryptedBootKey.Buffer = (LPWSTR) MIDL_user_allocate(cbSyskey);
|
||
if (!EncryptedBootKey.Buffer) {
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
CopyMemory(EncryptedBootKey.Buffer,Syskey,cbSyskey);
|
||
ZeroMemory(Syskey,cbSyskey);
|
||
EncryptedBootKey.Length=(USHORT)cbSyskey;
|
||
EncryptedBootKey.MaximumLength=(USHORT)cbSyskey;
|
||
|
||
Win32Err = DsRolepEncryptHash(&EncryptedBootKey);
|
||
if (Win32Err != ERROR_SUCCESS) {
|
||
MIDL_user_free(EncryptedBootKey.Buffer);
|
||
return Win32Err;
|
||
}
|
||
} else {
|
||
EncryptedBootKey.Buffer = NULL;
|
||
EncryptedBootKey.Length=0;
|
||
EncryptedBootKey.MaximumLength=0;
|
||
}
|
||
|
||
Win32Err = DsRolerDcAsReplica( Handle,
|
||
( LPWSTR )lpDnsDomainName,
|
||
( LPWSTR )lpReplicaServer,
|
||
( LPWSTR )lpSiteName,
|
||
( LPWSTR )lpDsDatabasePath,
|
||
( LPWSTR )lpDsLogPath,
|
||
( LPWSTR )lpRestorePath,
|
||
( LPWSTR )lpSystemVolumeRootPath,
|
||
&EncryptedBootKey,
|
||
( LPWSTR )lpAccount,
|
||
EncryptedPasswords[DSROLEP_DC_AS_REPLICA_PWD_INDEX],
|
||
EncryptedPasswords[DSROLEP_DC_AS_REPLICA_DS_REPAIR_PWD_INDEX],
|
||
Options,
|
||
( PDSROLER_HANDLE )DsOperationHandle );
|
||
|
||
} RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
||
Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
|
||
|
||
} RpcEndExcept;
|
||
|
||
if(EncryptedBootKey.Buffer)
|
||
{
|
||
MIDL_user_free(EncryptedBootKey.Buffer);
|
||
EncryptedBootKey.Length=0;
|
||
EncryptedBootKey.MaximumLength=0;
|
||
}
|
||
|
||
|
||
|
||
DsRolepEncryptPasswordEnd( Handle,
|
||
RedirHandle,
|
||
EncryptedPasswords,
|
||
NELEMENTS(EncryptedPasswords) );
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
DsRoleDemoteDc(
|
||
IN LPCWSTR lpServer OPTIONAL,
|
||
IN LPCWSTR lpDnsDomainName,
|
||
IN DSROLE_SERVEROP_DEMOTE_ROLE ServerRole,
|
||
IN LPCWSTR lpAccount OPTIONAL,
|
||
IN LPCWSTR lpPassword OPTIONAL,
|
||
IN ULONG Options,
|
||
IN BOOL fLastDcInDomain,
|
||
IN LPCWSTR lpAdminPassword OPTIONAL,
|
||
OUT DSROLE_SERVEROP_HANDLE *DsOperationHandle
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will demote an existing Dc to a standalone or member server.
|
||
|
||
Arguments:
|
||
|
||
lpServer - Server to remote the call to
|
||
|
||
lpDnsDomainName - Name of the domain on this machine to demote. If NULL, demote all of the
|
||
domains on this machine
|
||
|
||
ServerRole - The new role this machine should take
|
||
|
||
lpAccount - OPTIONAL User account to use when deleting the trusted domain object
|
||
|
||
lpPassword - Password to use with the above account
|
||
|
||
Options - Options to control the demotion of the domain
|
||
|
||
fLastDcInDomain - If TRUE, this is the last dc in the domain
|
||
|
||
lpAdminPassword - New local addmin password
|
||
|
||
DsOperationHandle - Handle to the operation is returned here.
|
||
|
||
Return Values:
|
||
|
||
ERROR_SUCCESS - Success
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
handle_t Handle = NULL;
|
||
HANDLE RedirHandle = NULL;
|
||
|
||
#define DSROLEP_DEMOTE_PWD_INDEX 0
|
||
#define DSROLEP_DEMOTE_ADMIN_PWD_INDEX 1
|
||
#define DSROLEP_DEMOTE_MAX_PWD_COUNT 2
|
||
|
||
PDSROLEPR_ENCRYPTED_USER_PASSWORD EncryptedPasswords[DSROLEP_DEMOTE_MAX_PWD_COUNT];
|
||
LPCWSTR Passwords[DSROLEP_DEMOTE_MAX_PWD_COUNT];
|
||
|
||
Passwords[DSROLEP_DEMOTE_PWD_INDEX] = lpPassword;
|
||
Passwords[DSROLEP_DEMOTE_ADMIN_PWD_INDEX] = lpAdminPassword;
|
||
RtlZeroMemory( EncryptedPasswords, sizeof(EncryptedPasswords) );
|
||
|
||
Win32Err = DsRolepEncryptPasswordStart( lpServer,
|
||
Passwords,
|
||
NELEMENTS(Passwords),
|
||
&Handle,
|
||
&RedirHandle,
|
||
EncryptedPasswords );
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
Win32Err = DsRolerDemoteDc( Handle,
|
||
( LPWSTR )lpDnsDomainName,
|
||
ServerRole,
|
||
( LPWSTR )lpAccount,
|
||
EncryptedPasswords[DSROLEP_DEMOTE_PWD_INDEX],
|
||
Options,
|
||
fLastDcInDomain,
|
||
EncryptedPasswords[DSROLEP_DEMOTE_ADMIN_PWD_INDEX],
|
||
( PDSROLER_HANDLE )DsOperationHandle );
|
||
|
||
|
||
} RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
||
Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
|
||
|
||
} RpcEndExcept;
|
||
|
||
|
||
DsRolepEncryptPasswordEnd( Handle,
|
||
RedirHandle,
|
||
EncryptedPasswords,
|
||
NELEMENTS(EncryptedPasswords) );
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
DsRoleGetDcOperationProgress(
|
||
IN LPCWSTR lpServer OPTIONAL,
|
||
IN DSROLE_SERVEROP_HANDLE DsOperationHandle,
|
||
OUT PDSROLE_SERVEROP_STATUS *ServerOperationStatus
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Gets the progress of the currently running operation
|
||
|
||
Arguments:
|
||
|
||
lpServer - Server to remote the call to
|
||
|
||
DsOperationHandle - Handle of currently running operation. Returned by one of the DsRoleDcAs
|
||
apis
|
||
|
||
ServerOperationStatus - Where the current operation status is returned. Must be freed via
|
||
MIDL_user_free (or DsRoleFreeMemory)
|
||
|
||
Return Values:
|
||
|
||
ERROR_SUCCESS - Success
|
||
|
||
--*/
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
PDSROLER_SERVEROP_STATUS ServerStatus = NULL;
|
||
handle_t Handle = NULL;
|
||
|
||
Win32Err = DsRolepServerBind( (PDSROLE_SERVER_NAME)lpServer,
|
||
&Handle );
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
Win32Err = DsRolerGetDcOperationProgress(
|
||
Handle,
|
||
(PDSROLER_HANDLE)&DsOperationHandle,
|
||
&ServerStatus );
|
||
|
||
if ( Win32Err == ERROR_SUCCESS || Win32Err == ERROR_IO_PENDING ) {
|
||
|
||
*ServerOperationStatus = ( PDSROLE_SERVEROP_STATUS )ServerStatus;
|
||
}
|
||
|
||
} RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
||
Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
|
||
|
||
} RpcEndExcept;
|
||
|
||
|
||
DsRolepServerUnbind( (PDSROLE_SERVER_NAME)lpServer, Handle );
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
DsRoleGetDcOperationResults(
|
||
IN LPCWSTR lpServer OPTIONAL,
|
||
IN DSROLE_SERVEROP_HANDLE DsOperationHandle,
|
||
OUT PDSROLE_SERVEROP_RESULTS *ServerOperationResults
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Gets the final results of an attempted promotion/demotion operation
|
||
|
||
Arguments:
|
||
|
||
lpServer - Server to remote the call to
|
||
|
||
DsOperationHandle - Handle of currently running operation. Returned by one of the DsRoleDcAs
|
||
apis
|
||
|
||
ServerOperationResults - Where the current operation result is returned. Must be freed via
|
||
MIDL_user_free (or DsRoleFreeMemory)
|
||
|
||
Return Values:
|
||
|
||
ERROR_SUCCESS - Success
|
||
|
||
--*/
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
PDSROLER_SERVEROP_RESULTS ServerResults = NULL;
|
||
handle_t Handle = NULL;
|
||
|
||
Win32Err = DsRolepServerBind( (PDSROLE_SERVER_NAME)lpServer,
|
||
&Handle );
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
*ServerOperationResults = 0;
|
||
Win32Err = DsRolerGetDcOperationResults(
|
||
Handle,
|
||
(PDSROLER_HANDLE)&DsOperationHandle,
|
||
&ServerResults );
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
*ServerOperationResults = ( PDSROLE_SERVEROP_RESULTS )ServerResults;
|
||
}
|
||
|
||
} RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
||
Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
|
||
|
||
} RpcEndExcept;
|
||
|
||
|
||
DsRolepServerUnbind( (PDSROLE_SERVER_NAME)lpServer, Handle );
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
DsRoleGetPrimaryDomainInformation(
|
||
IN LPCWSTR lpServer OPTIONAL,
|
||
IN DSROLE_PRIMARY_DOMAIN_INFO_LEVEL InfoLevel,
|
||
OUT PBYTE *Buffer )
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Gets information on the machine
|
||
|
||
Arguments:
|
||
|
||
lpServer - Server to remote the call to
|
||
|
||
InfoLevel - What level of information is being requested. Currently supported levels are:
|
||
DsRolePrimaryDomainInfoBasic
|
||
|
||
Buffer - Where the information is returned. The returned pointer should be cast to the
|
||
appropriate type for the info level passed in. The returned buffer should be freed via
|
||
MIDL_user_free (or DsRoleFreeMemory)
|
||
|
||
|
||
Return Values:
|
||
|
||
ERROR_SUCCESS - Success
|
||
|
||
--*/
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
PDSROLER_PRIMARY_DOMAIN_INFORMATION PrimaryDomainInfo = NULL;
|
||
handle_t Handle = NULL;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
if ( Buffer == NULL ) {
|
||
|
||
return( ERROR_INVALID_PARAMETER );
|
||
}
|
||
|
||
Win32Err = DsRolepServerBind( (PDSROLE_SERVER_NAME)lpServer,
|
||
&Handle );
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
if ( NULL == Handle) {
|
||
|
||
return( ERROR_NOT_ENOUGH_MEMORY );
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
*Buffer = NULL;
|
||
Win32Err = DsRolerGetPrimaryDomainInformation(
|
||
Handle,
|
||
InfoLevel,
|
||
&PrimaryDomainInfo );
|
||
|
||
*Buffer = ( PBYTE )PrimaryDomainInfo;
|
||
|
||
} RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
||
Status = I_RpcMapWin32Status( RpcExceptionCode() );
|
||
Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
|
||
|
||
} RpcEndExcept;
|
||
|
||
|
||
DsRolepServerUnbind( (PDSROLE_SERVER_NAME)lpServer, Handle );
|
||
|
||
//
|
||
// If this fails because we are calling a downlevel server, cobble up the information here
|
||
//
|
||
if ( ( Status == RPC_NT_UNKNOWN_IF || Status == RPC_NT_PROCNUM_OUT_OF_RANGE ) &&
|
||
InfoLevel == DsRolePrimaryDomainInfoBasic ) {
|
||
|
||
Win32Err = DsRolepGetPrimaryDomainInformationDownlevel( ( LPWSTR )lpServer, Buffer );
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
DsRoleCancel(
|
||
IN LPCWSTR lpServer OPTIONAL,
|
||
IN DSROLE_SERVEROP_HANDLE DsOperationHandle
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Cancels a currently running operation
|
||
|
||
Arguments:
|
||
|
||
lpServer - Server to remote the call to
|
||
|
||
DsOperationHandle - Handle of currently running operation. Returned by one of the DsRoleDcAs
|
||
apis
|
||
|
||
|
||
Return Values:
|
||
|
||
ERROR_SUCCESS - Success
|
||
|
||
--*/
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
handle_t Handle = NULL;
|
||
|
||
Win32Err = DsRolepServerBind( (PDSROLE_SERVER_NAME)lpServer,
|
||
&Handle );
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
Win32Err = DsRolerCancel( Handle,
|
||
( PDSROLER_HANDLE )&DsOperationHandle );
|
||
|
||
} RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
||
Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
|
||
|
||
} RpcEndExcept;
|
||
|
||
|
||
DsRolepServerUnbind( (PDSROLE_SERVER_NAME)lpServer, Handle );
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
DsRoleServerSaveStateForUpgrade(
|
||
IN LPCWSTR lpAnswerFile OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is to be invoked during setup and saves the required server state to
|
||
complete the promotion following the reboot. Following the successful completion
|
||
of this API call, the server will be demoted to a member server in the same domain.
|
||
|
||
Arguments:
|
||
|
||
lpAnswerFile -- Optional path to an answer file to be used by DCPROMO when it is
|
||
invoked to do the upgrade
|
||
|
||
|
||
Return Values:
|
||
|
||
ERROR_SUCCESS - Success
|
||
|
||
--*/
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
handle_t Handle = NULL;
|
||
|
||
Win32Err = DsRolepServerBind( NULL,
|
||
&Handle );
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
Win32Err = DsRolerServerSaveStateForUpgrade( Handle, ( LPWSTR )lpAnswerFile );
|
||
|
||
} RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
||
Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
|
||
|
||
} RpcEndExcept;
|
||
|
||
|
||
DsRolepServerUnbind( NULL, Handle );
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
DsRoleUpgradeDownlevelServer(
|
||
IN LPCWSTR lpDnsDomainName,
|
||
IN LPCWSTR lpSiteName,
|
||
IN LPCWSTR lpDsDatabasePath,
|
||
IN LPCWSTR lpDsLogPath,
|
||
IN LPCWSTR lpSystemVolumeRootPath,
|
||
IN LPCWSTR lpParentDnsDomainName OPTIONAL,
|
||
IN LPCWSTR lpParentServer OPTIONAL,
|
||
IN LPCWSTR lpAccount OPTIONAL,
|
||
IN LPCWSTR lpPassword OPTIONAL,
|
||
IN LPCWSTR lpDsRepairPassword OPTIONAL,
|
||
IN ULONG Options,
|
||
OUT DSROLE_SERVEROP_HANDLE *DsOperationHandle
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine process the information saved from a DsRoleServerSaveStateForUpgrade to
|
||
promote a downlevel (NT4 or previous) server to an NT5 DC
|
||
|
||
Arguments:
|
||
|
||
lpDnsDomainName - Dns domain name of the domain to install
|
||
|
||
SiteName - Name of the site this DC should belong to
|
||
|
||
lpDsDatabasePath - Absolute path on the local machine where the Ds DIT should go
|
||
|
||
lpDsLogPath - Absolute path on the local machine where the Ds log files should go
|
||
|
||
lpSystemVolumeRootPath - Absolute path on the local machine which will be the root of
|
||
the system volume.
|
||
|
||
lpParentDnsDomainName - Optional. If present, set this domain up as a child of the
|
||
specified domain
|
||
|
||
lpParentServer - Optional. If present, use this server in the parent domain to replicate
|
||
the required information from
|
||
|
||
lpAccount - User account to use when setting up as a child domain
|
||
|
||
lpPassword - Password to use with the above account
|
||
|
||
lpDsRepairPassword - Password to use for the admin account of the repair mode
|
||
|
||
Options - Options to control the creation of the domain
|
||
|
||
DsOperationHandle - Handle to the operation is returned here.
|
||
|
||
|
||
Return Values:
|
||
|
||
ERROR_SUCCESS - Success
|
||
|
||
--*/
|
||
{
|
||
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
handle_t Handle = NULL;
|
||
HANDLE RedirHandle = NULL;
|
||
|
||
#define DSROLEP_UPGRADE_PWD_INDEX 0
|
||
#define DSROLEP_UPGRADE_DS_REPAIR_PWD_INDEX 1
|
||
#define DSROLEP_UPGRADE_MAX_PWD_COUNT 2
|
||
|
||
PDSROLEPR_ENCRYPTED_USER_PASSWORD EncryptedPasswords[DSROLEP_UPGRADE_MAX_PWD_COUNT];
|
||
LPCWSTR Passwords[DSROLEP_UPGRADE_MAX_PWD_COUNT];
|
||
|
||
Passwords[DSROLEP_UPGRADE_PWD_INDEX] = lpPassword;
|
||
Passwords[DSROLEP_UPGRADE_DS_REPAIR_PWD_INDEX] = lpDsRepairPassword;
|
||
RtlZeroMemory( EncryptedPasswords, sizeof(EncryptedPasswords) );
|
||
|
||
Win32Err = DsRolepEncryptPasswordStart( NULL,
|
||
Passwords,
|
||
NELEMENTS(Passwords),
|
||
&Handle,
|
||
&RedirHandle,
|
||
EncryptedPasswords );
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
RpcTryExcept {
|
||
|
||
Win32Err = DsRolerUpgradeDownlevelServer( Handle,
|
||
( LPWSTR )lpDnsDomainName,
|
||
( LPWSTR )lpSiteName,
|
||
( LPWSTR )lpDsDatabasePath,
|
||
( LPWSTR )lpDsLogPath,
|
||
( LPWSTR )lpSystemVolumeRootPath,
|
||
( LPWSTR )lpParentDnsDomainName,
|
||
( LPWSTR )lpParentServer,
|
||
( LPWSTR )lpAccount,
|
||
EncryptedPasswords[DSROLEP_UPGRADE_PWD_INDEX],
|
||
EncryptedPasswords[DSROLEP_UPGRADE_DS_REPAIR_PWD_INDEX],
|
||
Options,
|
||
( PDSROLER_HANDLE )DsOperationHandle );
|
||
|
||
} RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
||
Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
|
||
|
||
} RpcEndExcept;
|
||
|
||
|
||
DsRolepEncryptPasswordEnd( Handle,
|
||
RedirHandle,
|
||
EncryptedPasswords,
|
||
NELEMENTS(EncryptedPasswords) );
|
||
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
DsRoleAbortDownlevelServerUpgrade(
|
||
IN LPCWSTR lpAdminPassword,
|
||
IN LPCWSTR lpAccount, OPTIONAL
|
||
IN LPCWSTR lpPassword, OPTIONAL
|
||
IN ULONG Options
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine cleans up the information saved from a DsRoleSaveServerStateForUpgrade call,
|
||
leaving the machine as a member or standalone server
|
||
|
||
Arguments:
|
||
|
||
lpAdminPassword - New local administrator account password
|
||
|
||
lpAccount - User account to use when setting up as a child domain
|
||
|
||
lpPassword - Password to use with the above account
|
||
|
||
|
||
Return Values:
|
||
|
||
ERROR_SUCCESS - Success
|
||
|
||
--*/
|
||
{
|
||
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
handle_t Handle = NULL;
|
||
HANDLE RedirHandle = NULL;
|
||
|
||
#define DSROLEP_ABORT_PWD_INDEX 0
|
||
#define DSROLEP_ABORT_ADMIN_PWD_INDEX 1
|
||
#define DSROLEP_ABORT_MAX_PWD_COUNT 2
|
||
|
||
PDSROLEPR_ENCRYPTED_USER_PASSWORD EncryptedPasswords[DSROLEP_ABORT_MAX_PWD_COUNT];
|
||
LPCWSTR Passwords[DSROLEP_ABORT_MAX_PWD_COUNT];
|
||
|
||
Passwords[DSROLEP_ABORT_PWD_INDEX] = lpPassword;
|
||
Passwords[DSROLEP_ABORT_ADMIN_PWD_INDEX] = lpAdminPassword;
|
||
RtlZeroMemory( EncryptedPasswords, sizeof(EncryptedPasswords) );
|
||
|
||
Win32Err = DsRolepEncryptPasswordStart( NULL,
|
||
Passwords,
|
||
NELEMENTS(Passwords),
|
||
&Handle,
|
||
&RedirHandle,
|
||
EncryptedPasswords );
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
Win32Err = DsRolerAbortDownlevelServerUpgrade( Handle,
|
||
( LPWSTR )lpAccount,
|
||
EncryptedPasswords[DSROLEP_ABORT_PWD_INDEX],
|
||
EncryptedPasswords[DSROLEP_ABORT_ADMIN_PWD_INDEX],
|
||
Options );
|
||
} RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
||
Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
|
||
|
||
} RpcEndExcept;
|
||
|
||
|
||
DsRolepEncryptPasswordEnd( Handle,
|
||
RedirHandle,
|
||
EncryptedPasswords,
|
||
NELEMENTS(EncryptedPasswords) );
|
||
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
DWORD
|
||
WINAPI
|
||
DsRoleGetDatabaseFacts(
|
||
IN LPCWSTR lpServer OPTIONAL,
|
||
IN LPCWSTR lpRestorePath,
|
||
OUT LPWSTR *lpDNSDomainName,
|
||
OUT PULONG State
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function will give information about a restore database
|
||
1. the way the syskey is stored
|
||
2. the domain that the database came from
|
||
3. where the backup was taken from a GC or not
|
||
|
||
Arguments:
|
||
|
||
lpServer - The server to get the Facts from
|
||
|
||
lpRestorePath - The location of the restored files.
|
||
|
||
lpDNSDomainName - This parameter will recieve the name of the domain that this backup came
|
||
from
|
||
|
||
State - The return Values that report How the syskey is stored and If the back was likely
|
||
taken form a GC or not.
|
||
|
||
|
||
Return Values:
|
||
|
||
ERROR_SUCCESS - Success
|
||
|
||
--*/
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
handle_t Handle = NULL;
|
||
|
||
if(IsBadWritePtr(lpDNSDomainName,
|
||
sizeof(LPWSTR*) )){
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
Win32Err = DsRolepServerBind( (PDSROLE_SERVER_NAME)lpServer,
|
||
&Handle );
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
Win32Err = DsRolerGetDatabaseFacts( Handle,
|
||
( LPWSTR )lpRestorePath,
|
||
lpDNSDomainName,
|
||
State );
|
||
} RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
||
Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
|
||
|
||
} RpcEndExcept;
|
||
|
||
DsRolepServerUnbind( (PDSROLE_SERVER_NAME)lpServer, Handle );
|
||
|
||
|
||
return Win32Err;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Local functions
|
||
//
|
||
DWORD
|
||
DsRolepGetPrimaryDomainInformationDownlevel(
|
||
IN LPWSTR Server,
|
||
OUT PBYTE *Buffer
|
||
)
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
NTSTATUS Status;
|
||
LSA_HANDLE PolicyHandle;
|
||
PPOLICY_PRIMARY_DOMAIN_INFO PDI = NULL;
|
||
PPOLICY_LSA_SERVER_ROLE_INFO ServerRole = NULL;
|
||
PPOLICY_ACCOUNT_DOMAIN_INFO ADI = NULL;
|
||
UNICODE_STRING UnicodeServer;
|
||
OBJECT_ATTRIBUTES OA;
|
||
PDSROLE_PRIMARY_DOMAIN_INFO_BASIC PDIB = NULL;
|
||
DSROLE_MACHINE_ROLE MachineRole = DsRole_RoleStandaloneServer;
|
||
NT_PRODUCT_TYPE ProductType;
|
||
|
||
Win32Err = DsRolepGetProductTypeForServer( Server, &ProductType );
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
InitializeObjectAttributes( &OA, NULL, 0, NULL, NULL);
|
||
if ( Server ) {
|
||
|
||
RtlInitUnicodeString( &UnicodeServer, Server );
|
||
}
|
||
|
||
Status = LsaOpenPolicy( Server ? &UnicodeServer : NULL,
|
||
&OA,
|
||
POLICY_VIEW_LOCAL_INFORMATION,
|
||
&PolicyHandle );
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
Status = LsaQueryInformationPolicy( PolicyHandle,
|
||
PolicyPrimaryDomainInformation,
|
||
( PVOID * ) &PDI );
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
switch ( ProductType ) {
|
||
case NtProductWinNt:
|
||
if ( PDI->Sid == NULL ) {
|
||
|
||
MachineRole = DsRole_RoleStandaloneWorkstation;
|
||
|
||
} else {
|
||
|
||
MachineRole = DsRole_RoleMemberWorkstation;
|
||
|
||
}
|
||
break;
|
||
|
||
case NtProductServer:
|
||
if ( PDI->Sid == NULL ) {
|
||
|
||
MachineRole = DsRole_RoleStandaloneServer;
|
||
|
||
} else {
|
||
|
||
MachineRole = DsRole_RoleMemberServer;
|
||
|
||
}
|
||
break;
|
||
|
||
case NtProductLanManNt:
|
||
|
||
Status = LsaQueryInformationPolicy( PolicyHandle,
|
||
PolicyLsaServerRoleInformation,
|
||
( PVOID * )&ServerRole );
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
if ( ServerRole->LsaServerRole == PolicyServerRolePrimary ) {
|
||
|
||
//
|
||
// If we think we're a primary domain controller, we'll need to
|
||
// guard against the case where we're actually standalone during setup
|
||
//
|
||
Status = LsaQueryInformationPolicy( PolicyHandle,
|
||
PolicyAccountDomainInformation,
|
||
( PVOID * )&ADI );
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
|
||
if ( PDI->Sid == NULL ||
|
||
ADI->DomainSid == NULL ||
|
||
!RtlEqualSid( ADI->DomainSid, PDI->Sid ) ) {
|
||
|
||
MachineRole = DsRole_RoleStandaloneServer;
|
||
|
||
} else {
|
||
|
||
MachineRole = DsRole_RolePrimaryDomainController;
|
||
|
||
}
|
||
}
|
||
|
||
|
||
} else {
|
||
|
||
MachineRole = DsRole_RoleBackupDomainController;
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Build the return buffer
|
||
//
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
PDIB = MIDL_user_allocate( sizeof( DSROLE_PRIMARY_DOMAIN_INFO_BASIC ) +
|
||
PDI->Name.Length + sizeof( WCHAR ) );
|
||
|
||
if ( PDIB == NULL ) {
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
} else {
|
||
|
||
RtlZeroMemory( PDIB, sizeof( DSROLE_PRIMARY_DOMAIN_INFO_BASIC ) +
|
||
PDI->Name.Length + sizeof( WCHAR ) );
|
||
|
||
PDIB->MachineRole = MachineRole;
|
||
PDIB->DomainNameFlat = ( LPWSTR ) ( ( PBYTE )PDIB +
|
||
sizeof( DSROLE_PRIMARY_DOMAIN_INFO_BASIC ) );
|
||
RtlCopyMemory( PDIB->DomainNameFlat, PDI->Name.Buffer, PDI->Name.Length );
|
||
|
||
*Buffer = ( PBYTE )PDIB;
|
||
}
|
||
}
|
||
|
||
LsaClose( PolicyHandle );
|
||
|
||
LsaFreeMemory( PDI );
|
||
|
||
if ( ADI != NULL ) {
|
||
|
||
LsaFreeMemory( ADI );
|
||
}
|
||
|
||
if ( ServerRole != NULL ) {
|
||
|
||
LsaFreeMemory( ServerRole );
|
||
}
|
||
}
|
||
|
||
Win32Err = RtlNtStatusToDosError( Status );
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
DWORD
|
||
DsRolepGetProductTypeForServer(
|
||
IN LPWSTR Server,
|
||
IN OUT PNT_PRODUCT_TYPE ProductType
|
||
)
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
PWSTR RegServer = NULL;
|
||
HKEY RemoteKey, ProductKey;
|
||
PBYTE Buffer = NULL;
|
||
ULONG Type, Size = 0;
|
||
|
||
|
||
|
||
if ( Server == NULL ) {
|
||
|
||
if ( RtlGetNtProductType( ProductType ) == FALSE ) {
|
||
|
||
Win32Err = RtlNtStatusToDosError( STATUS_UNSUCCESSFUL );
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
if ( wcslen( Server ) > 2 && *Server == L'\\' && *( Server + 1 ) == L'\\' ) {
|
||
|
||
RegServer = Server;
|
||
|
||
} else {
|
||
|
||
RegServer = LocalAlloc( LMEM_FIXED, ( wcslen( Server ) + 3 ) * sizeof( WCHAR ) );
|
||
|
||
if ( RegServer ) {
|
||
|
||
swprintf( RegServer, L"\\\\%ws", Server );
|
||
|
||
} else {
|
||
|
||
Win32Err = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
||
}
|
||
}
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
Win32Err = RegConnectRegistry( RegServer,
|
||
HKEY_LOCAL_MACHINE,
|
||
&RemoteKey );
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
Win32Err = RegOpenKeyEx( RemoteKey,
|
||
L"system\\currentcontrolset\\control\\productoptions",
|
||
0,
|
||
KEY_READ,
|
||
&ProductKey );
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
Win32Err = RegQueryValueEx( ProductKey,
|
||
L"ProductType",
|
||
0,
|
||
&Type,
|
||
0,
|
||
&Size );
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
Buffer = LocalAlloc( LMEM_FIXED, Size );
|
||
|
||
if ( Buffer ) {
|
||
|
||
Win32Err = RegQueryValueEx( ProductKey,
|
||
L"ProductType",
|
||
0,
|
||
&Type,
|
||
Buffer,
|
||
&Size );
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
if ( !_wcsicmp( ( PWSTR )Buffer, L"LanmanNt" ) ) {
|
||
|
||
*ProductType = NtProductLanManNt;
|
||
|
||
} else if ( !_wcsicmp( ( PWSTR )Buffer, L"ServerNt" ) ) {
|
||
|
||
*ProductType = NtProductServer;
|
||
|
||
} else if ( !_wcsicmp( ( PWSTR )Buffer, L"WinNt" ) ) {
|
||
|
||
*ProductType = NtProductWinNt;
|
||
|
||
} else {
|
||
|
||
Win32Err = ERROR_UNKNOWN_PRODUCT;
|
||
}
|
||
}
|
||
|
||
LocalFree( Buffer );
|
||
|
||
} else {
|
||
|
||
Win32Err = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
}
|
||
|
||
RegCloseKey( ProductKey );
|
||
}
|
||
|
||
|
||
RegCloseKey( RemoteKey );
|
||
}
|
||
|
||
}
|
||
|
||
if ( RegServer != Server ) {
|
||
|
||
LocalFree( RegServer );
|
||
}
|
||
}
|
||
|
||
return( Win32Err );
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
DsRolepRandomFill(
|
||
IN ULONG BufferSize,
|
||
IN OUT PUCHAR Buffer
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine fills a buffer with random data.
|
||
|
||
Parameters:
|
||
|
||
BufferSize - Length of the input buffer, in bytes.
|
||
|
||
Buffer - Input buffer to be filled with random data.
|
||
|
||
Return Values:
|
||
|
||
Errors from NtQuerySystemTime()
|
||
|
||
|
||
--*/
|
||
{
|
||
ULONG Index;
|
||
LARGE_INTEGER Time;
|
||
ULONG Seed;
|
||
NTSTATUS NtStatus;
|
||
|
||
|
||
NtStatus = NtQuerySystemTime(&Time);
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
Seed = Time.LowPart ^ Time.HighPart;
|
||
|
||
for (Index = 0 ; Index < BufferSize ; Index++ )
|
||
{
|
||
*Buffer++ = (UCHAR) (RtlRandom(&Seed) % 256);
|
||
}
|
||
return(STATUS_SUCCESS);
|
||
|
||
}
|
||
|
||
DWORD
|
||
DsRolepEncryptPasswordStart(
|
||
IN LPCWSTR ServerName OPTIONAL,
|
||
IN LPCWSTR *Passwords,
|
||
IN ULONG Count,
|
||
OUT RPC_BINDING_HANDLE *RpcBindingHandle,
|
||
OUT HANDLE *RedirHandle,
|
||
IN OUT PDSROLEPR_ENCRYPTED_USER_PASSWORD *EncryptedUserPasswords
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine takes a number of cleartext unicode NT password from the user,
|
||
and encrypts them with the session key.
|
||
|
||
This routine's algorithm was taken from CliffV's work when encrypting the
|
||
passwords for the NetrJoinDomain2 interface.
|
||
|
||
Parameters:
|
||
|
||
ServerName - UNC server name of the server to remote the API to
|
||
|
||
Passwords - the cleartext unicode NT passwords.
|
||
|
||
Count - the number of password
|
||
|
||
RpcBindingHandle - RPC handle used for acquiring a session key.
|
||
|
||
RedirHandle - Returns a handle to the redir. Since RpcBindingHandles don't represent
|
||
and open connection to the server, we have to ensure the connection stays open
|
||
until the server side has a chance to get this same UserSessionKey. The only
|
||
way to do that is to keep the connect open.
|
||
|
||
Returns NULL if no handle is needed.
|
||
|
||
EncryptedUserPassword - receives the encrypted cleartext passwords.
|
||
If lpPassword is NULL, a NULL is returned for that entry.
|
||
|
||
Return Values:
|
||
|
||
If this routine returns NO_ERROR, the returned data must be freed using
|
||
LocalFree.
|
||
|
||
|
||
--*/
|
||
{
|
||
DWORD WinError = ERROR_SUCCESS;
|
||
NTSTATUS NtStatus;
|
||
USER_SESSION_KEY UserSessionKey;
|
||
RC4_KEYSTRUCT Rc4Key;
|
||
MD5_CTX Md5Context;
|
||
PDSROLEPR_USER_PASSWORD UserPassword = NULL;
|
||
ULONG PasswordSize;
|
||
ULONG i;
|
||
|
||
//
|
||
// Initialization
|
||
//
|
||
|
||
*RpcBindingHandle = NULL;
|
||
*RedirHandle = NULL;
|
||
for ( i = 0; i < Count; i++ ) {
|
||
EncryptedUserPasswords[i] = NULL;
|
||
}
|
||
|
||
//
|
||
// Verify parameters
|
||
//
|
||
for ( i = 0; i < Count; i++ ) {
|
||
if ( Passwords[i] ) {
|
||
PasswordSize = wcslen( Passwords[i] ) * sizeof(WCHAR);
|
||
if ( PasswordSize > DSROLE_MAX_PASSWORD_LENGTH * sizeof(WCHAR)) {
|
||
WinError = ERROR_PASSWORD_RESTRICTION;
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Get an RPC handle to the server.
|
||
//
|
||
|
||
WinError = DsRolepServerBind( (PDSROLE_SERVER_NAME) ServerName,
|
||
RpcBindingHandle );
|
||
|
||
if ( ERROR_SUCCESS != WinError ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Get the session key.
|
||
//
|
||
|
||
NtStatus = RtlGetUserSessionKeyClientBinding(
|
||
*RpcBindingHandle,
|
||
RedirHandle,
|
||
&UserSessionKey );
|
||
|
||
if ( !NT_SUCCESS(NtStatus) ) {
|
||
WinError = RtlNtStatusToDosError( NtStatus );
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Encrypt the passwords
|
||
//
|
||
for ( i = 0; i < Count; i++ ) {
|
||
|
||
|
||
if ( NULL == Passwords[i] ) {
|
||
// Nothing to encrypt
|
||
continue;
|
||
}
|
||
|
||
PasswordSize = wcslen( Passwords[i] ) * sizeof(WCHAR);
|
||
|
||
//
|
||
// Allocate a buffer to encrypt and fill it in.
|
||
//
|
||
|
||
UserPassword = LocalAlloc( 0, sizeof(DSROLEPR_USER_PASSWORD) );
|
||
|
||
if ( UserPassword == NULL ) {
|
||
WinError = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Copy the password into the tail end of the buffer.
|
||
//
|
||
|
||
RtlCopyMemory(
|
||
((PCHAR) UserPassword->Buffer) +
|
||
(DSROLE_MAX_PASSWORD_LENGTH * sizeof(WCHAR)) -
|
||
PasswordSize,
|
||
Passwords[i],
|
||
PasswordSize );
|
||
|
||
UserPassword->Length = PasswordSize;
|
||
|
||
//
|
||
// Fill the front of the buffer with random data
|
||
//
|
||
|
||
NtStatus = DsRolepRandomFill(
|
||
(DSROLE_MAX_PASSWORD_LENGTH * sizeof(WCHAR)) -
|
||
PasswordSize,
|
||
(PUCHAR) UserPassword->Buffer );
|
||
|
||
if ( !NT_SUCCESS(NtStatus) ) {
|
||
WinError = RtlNtStatusToDosError( NtStatus );
|
||
goto Cleanup;
|
||
}
|
||
|
||
NtStatus = DsRolepRandomFill(
|
||
DSROLE_OBFUSCATOR_LENGTH,
|
||
(PUCHAR) UserPassword->Obfuscator );
|
||
|
||
if ( !NT_SUCCESS(NtStatus) ) {
|
||
WinError = RtlNtStatusToDosError( NtStatus );
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
//
|
||
// The UserSessionKey is the same for the life of the session. RC4'ing multiple
|
||
// strings with a single key is weak (if you crack one you've cracked them all).
|
||
// So compute a key that's unique for this particular encryption.
|
||
//
|
||
//
|
||
|
||
MD5Init(&Md5Context);
|
||
|
||
MD5Update( &Md5Context, (LPBYTE)&UserSessionKey, sizeof(UserSessionKey) );
|
||
MD5Update( &Md5Context, UserPassword->Obfuscator, sizeof(UserPassword->Obfuscator) );
|
||
|
||
MD5Final( &Md5Context );
|
||
|
||
rc4_key( &Rc4Key, MD5DIGESTLEN, Md5Context.digest );
|
||
|
||
|
||
//
|
||
// Encrypt it.
|
||
// Don't encrypt the obfuscator. The server needs that to compute the key.
|
||
//
|
||
|
||
rc4( &Rc4Key, sizeof(UserPassword->Buffer)+sizeof(UserPassword->Length), (LPBYTE) UserPassword->Buffer );
|
||
|
||
EncryptedUserPasswords[i] = (PDSROLEPR_ENCRYPTED_USER_PASSWORD) UserPassword;
|
||
UserPassword = NULL;
|
||
|
||
}
|
||
|
||
WinError = ERROR_SUCCESS;
|
||
|
||
Cleanup:
|
||
|
||
if ( WinError != ERROR_SUCCESS ) {
|
||
if ( UserPassword != NULL ) {
|
||
LocalFree( UserPassword );
|
||
}
|
||
if ( *RpcBindingHandle != NULL ) {
|
||
DsRolepServerUnbind( NULL, *RpcBindingHandle );
|
||
*RpcBindingHandle = NULL;
|
||
}
|
||
if ( *RedirHandle != NULL ) {
|
||
NtClose( *RedirHandle );
|
||
*RedirHandle = NULL;
|
||
}
|
||
for ( i = 0; i < Count; i++ ) {
|
||
if ( EncryptedUserPasswords[i] ) {
|
||
LocalFree( EncryptedUserPasswords[i] );
|
||
EncryptedUserPasswords[i] = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
return WinError;
|
||
}
|
||
|
||
|
||
VOID
|
||
DsRolepEncryptPasswordEnd(
|
||
IN RPC_BINDING_HANDLE RpcBindingHandle,
|
||
IN HANDLE RedirHandle OPTIONAL,
|
||
IN PDSROLEPR_ENCRYPTED_USER_PASSWORD *EncryptedUserPasswords OPTIONAL,
|
||
IN ULONG Count
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine takes the variables returned by DsRolepEncryptPasswordStart and
|
||
frees them.
|
||
|
||
Parameters:
|
||
|
||
RpcBindingHandle - RPC handle used for acquiring a session key.
|
||
|
||
RedirHandle - Handle to the redirector
|
||
|
||
EncryptedUserPasswords - the encrypted cleartext passwords.
|
||
|
||
Count - the number of passwords
|
||
|
||
Return Values:
|
||
|
||
--*/
|
||
{
|
||
ULONG i;
|
||
|
||
//
|
||
// Free the RPC binding handle.
|
||
//
|
||
|
||
if ( RpcBindingHandle != NULL ) {
|
||
(VOID) DsRolepServerUnbind ( NULL, RpcBindingHandle );
|
||
}
|
||
|
||
//
|
||
// Close the redir handle.
|
||
//
|
||
|
||
if ( RedirHandle != NULL ) {
|
||
NtClose( RedirHandle );
|
||
}
|
||
|
||
//
|
||
// Free the encrypted passwords.
|
||
//
|
||
|
||
for ( i = 0; i < Count; i++ ) {
|
||
if ( EncryptedUserPasswords[i] != NULL ) {
|
||
LocalFree( EncryptedUserPasswords[i] );
|
||
}
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
DWORD
|
||
DsRolepHashkey(
|
||
IN OUT LPWSTR key,
|
||
OUT PVOID SysKey,
|
||
IN ULONG cbSysKey
|
||
)
|
||
/*++
|
||
|
||
Routine Description
|
||
|
||
This routine is used to store the boot type
|
||
in the registry
|
||
|
||
Paramaeters
|
||
|
||
NewType Indicates the new boot type
|
||
|
||
Return Values
|
||
|
||
STATUS_SUCCESS
|
||
STATUS_UNSUCCESSFUL
|
||
--*/
|
||
{
|
||
MD5_CTX Md5;
|
||
if(cbSysKey<SYSKEY_SIZE) {
|
||
return ERROR_INSUFFICIENT_BUFFER;
|
||
}
|
||
cbSysKey=wcslen(key)*sizeof(WCHAR);
|
||
|
||
MD5Init( &Md5 );
|
||
MD5Update( &Md5, (PUCHAR) key, cbSysKey );
|
||
MD5Final( &Md5 );
|
||
|
||
ZeroMemory( key, cbSysKey );
|
||
|
||
cbSysKey=SYSKEY_SIZE;
|
||
CopyMemory( SysKey, Md5.digest, cbSysKey );
|
||
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
DWORD
|
||
DsRolepEncryptHash(
|
||
IN OUT PUNICODE_STRING EncryptedSyskey
|
||
)
|
||
/*++
|
||
|
||
Routine Description
|
||
|
||
This routine is used to store the boot type
|
||
in the registry
|
||
|
||
Paramaeters
|
||
|
||
NewType Indicates the new boot type
|
||
|
||
Return Values
|
||
|
||
STATUS_SUCCESS
|
||
STATUS_UNSUCCESSFUL
|
||
--*/
|
||
{
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|