windows-nt/Source/XPSP1/NT/base/screg/winreg/client/regcnreg.c

535 lines
14 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
Regcnreg.c
Abstract:
This module contains the Win32 Registry APIs to connect to a remote
Registry. That is:
- RegConnectRegistryA
- RegConnectRegistryW
Author:
David J. Gilman (davegi) 25-Mar-1992
Notes:
The semantics of this API make it local only. That is there is no MIDL
definition for RegConnectRegistry although it does call other client
stubs, specifically OpenLocalMachine and OpenUsers.
Revision History:
John Vert (jvert) 16-Jun-1995
Added connect support for protocols other than named pipes by
stealing code from Win95. This enabled NT machines to connect
to registries on Win95 machines
--*/
#include <rpc.h>
#include "regrpc.h"
#include "client.h"
#include "shutinit.h"
#include "..\regconn\regconn.h"
LONG
BaseBindToMachine(
IN LPCWSTR lpMachineName,
IN PBIND_CALLBACK BindCallback,
IN PVOID Context1,
IN PVOID Context2
);
typedef int (* RegConnFunction)(LPCWSTR, handle_t *);
RegConnFunction conn_functions[] = {
RegConn_np,
RegConn_spx,
RegConn_ip_tcp,
RegConn_nb_nb,
RegConn_nb_tcp,
RegConn_nb_ipx,
NULL
};
LONG
Rpc_OpenPredefHandle(
IN RPC_BINDING_HANDLE * pbinding OPTIONAL,
IN HKEY hKey,
OUT PHKEY phkResult
)
/*++
Routine Description:
Win32 Unicode API for establishing a connection to a predefined
handle on another machine.
Parameters:
pbinding - This is a pointer to the binding handle in order
to allow access to multiple protocols (NT remote registry is only over
named pipes).
hKey - Supplies the predefined handle to connect to on the remote
machine. Currently this parameter must be one of:
- HKEY_LOCAL_MACHINE
- HKEY_PERFORMANCE_DATA
- HKEY_USERS
phkResult - Returns a handle which represents the supplied predefined
handle on the supplied machine.
Return Value:
Returns ERROR_SUCCESS (0) for success; error-code for failure.
On failure, the binding handle is freed.
Notes:
For administration purposes this API allows programs to access the
Registry on a remote machine. In the current system the calling
application must know the name of the remote machine that it wishes to
connect to. However, it is expected that in the future a directory
service API will return the parameters necessary for this API.
--*/
{
LONG Error;
HKEY PreviousResult;
ASSERT( (phkResult != NULL));
PreviousResult = *phkResult;
switch ((int)(ULONG_PTR)hKey)
{
case (int)(ULONG_PTR)HKEY_LOCAL_MACHINE:
Error = (LONG)OpenLocalMachine((PREGISTRY_SERVER_NAME) pbinding,
MAXIMUM_ALLOWED,
phkResult );
break;
case (int)(ULONG_PTR)HKEY_PERFORMANCE_DATA:
Error = (LONG)OpenPerformanceData((PREGISTRY_SERVER_NAME) pbinding,
MAXIMUM_ALLOWED,
phkResult );
break;
case (int)(ULONG_PTR)HKEY_USERS:
Error = (LONG)OpenUsers((PREGISTRY_SERVER_NAME) pbinding,
MAXIMUM_ALLOWED,
phkResult );
break;
case (int)(ULONG_PTR)HKEY_CLASSES_ROOT:
Error = (LONG)OpenClassesRoot((PREGISTRY_SERVER_NAME) pbinding,
MAXIMUM_ALLOWED,
phkResult );
break;
case (int)(ULONG_PTR)HKEY_CURRENT_USER:
Error = (LONG)OpenCurrentUser((PREGISTRY_SERVER_NAME) pbinding,
MAXIMUM_ALLOWED,
phkResult );
break;
case (int)(ULONG_PTR)HKEY_PERFORMANCE_TEXT:
Error = (LONG)OpenPerformanceText((PREGISTRY_SERVER_NAME) pbinding,
MAXIMUM_ALLOWED,
phkResult );
break;
case (int)(ULONG_PTR)HKEY_PERFORMANCE_NLSTEXT:
Error = (LONG)OpenPerformanceNlsText((PREGISTRY_SERVER_NAME) pbinding,
MAXIMUM_ALLOWED,
phkResult );
break;
default:
Error = ERROR_INVALID_HANDLE;
}
if( Error != ERROR_SUCCESS) {
ASSERTMSG("WINREG: RPC failed, but modifed phkResult", *phkResult == PreviousResult);
if (*pbinding != NULL)
RpcBindingFree(pbinding);
}
return Error;
}
LONG
LocalOpenPredefHandle(
IN HKEY hKey,
OUT PHKEY phkResult
)
/*++
Routine Description:
Opens a predefined handle locally. The purpose of this is to bypass RPC in the
case of connecting to the local machine.
Parameters:
hKey - Supplies the predefined handle to connect to on the remote
machine. Currently this parameter must be one of:
- HKEY_LOCAL_MACHINE
- HKEY_PERFORMANCE_DATA
- HKEY_USERS
phkResult - Returns a handle which represents the supplied predefined
handle on the supplied machine.
Return Value:
Returns ERROR_SUCCESS (0) for success; error-code for failure.
--*/
{
LONG Error;
ASSERT( (phkResult != NULL));
switch ((int)(ULONG_PTR)hKey)
{
case (int)(ULONG_PTR)HKEY_LOCAL_MACHINE:
Error = (LONG)LocalOpenLocalMachine(NULL,
MAXIMUM_ALLOWED,
phkResult );
break;
case (int)(ULONG_PTR)HKEY_PERFORMANCE_DATA:
Error = (LONG)LocalOpenPerformanceData(NULL,
MAXIMUM_ALLOWED,
phkResult );
break;
case (int)(ULONG_PTR)HKEY_USERS:
Error = (LONG)LocalOpenUsers(NULL,
MAXIMUM_ALLOWED,
phkResult );
break;
case (int)(ULONG_PTR)HKEY_CLASSES_ROOT:
Error = (LONG)LocalOpenClassesRoot(NULL,
MAXIMUM_ALLOWED,
phkResult );
break;
case (int)(ULONG_PTR)HKEY_CURRENT_USER:
Error = (LONG)LocalOpenCurrentUser(NULL,
MAXIMUM_ALLOWED,
phkResult );
break;
case (int)(ULONG_PTR)HKEY_PERFORMANCE_TEXT:
case (int)(ULONG_PTR)HKEY_PERFORMANCE_NLSTEXT:
case (int)(ULONG_PTR)HKEY_CURRENT_CONFIG:
case (int)(ULONG_PTR)HKEY_DYN_DATA:
//
// try not to break whoever used this
//
*phkResult = hKey;
Error = ERROR_SUCCESS;
break;
default:
Error = ERROR_INVALID_HANDLE;
}
return Error;
}
LONG
RegConnectRegistryW (
IN LPCWSTR lpMachineName OPTIONAL,
IN HKEY hKey,
OUT PHKEY phkResult
)
/*++
Routine Description:
Win32 Unicode API for establishing a connection to a predefined
handle on another machine.
Parameters:
lpMachineName - Supplies a pointer to a null-terminated string that
names the machine of interest. If this parameter is NULL, the local
machine name is used.
hKey - Supplies the predefined handle to connect to on the remote
machine. Currently this parameter must be one of:
- HKEY_LOCAL_MACHINE
- HKEY_PERFORMANCE_DATA
- HKEY_USERS
phkResult - Returns a handle which represents the supplied predefined
handle on the supplied machine.
Return Value:
Returns ERROR_SUCCESS (0) for success; error-code for failure.
Notes:
For administration purposes this API allows programs to access the
Registry on a remote machine. In the current system the calling
application must know the name of the remote machine that it wishes to
connect to. However, it is expected that in the future a directory
service API will return the parameters necessary for this API.
Even though HKEY_CLASSES and HKEY_CURRENT_USER are predefined handles,
they are not supported by this API as they do not make sense in the
context of a remote Registry.
--*/
{
LONG Error;
WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD bufLen = MAX_COMPUTERNAME_LENGTH + 1;
ASSERT( ARGUMENT_PRESENT( phkResult ));
#if DBG
if ( BreakPointOnEntry ) {
DbgBreakPoint();
}
#endif
//
// Check for local connect
//
if (lpMachineName == NULL) {
//
// always return a valid handle
//
Error = LocalOpenPredefHandle(hKey,phkResult);
return Error;
} else if (lpMachineName[0] == L'\0') {
//
// always return a valid handle
//
Error = LocalOpenPredefHandle(hKey,phkResult);
return Error;
}
if (GetComputerNameW(ComputerName,&bufLen)) {
if ((_wcsicmp(ComputerName,lpMachineName) == 0) ||
((lpMachineName[0] == '\\') &&
(lpMachineName[1] == '\\') &&
(_wcsicmp(ComputerName,&(lpMachineName[2]))==0))) {
//
// local connect
//
//
// always return a valid handle
//
Error = LocalOpenPredefHandle(hKey,phkResult);
return Error;
}
}
Error = BaseBindToMachine(lpMachineName,
Rpc_OpenPredefHandle,
(PVOID)hKey,
(PVOID)phkResult);
if( Error == ERROR_SUCCESS) {
TagRemoteHandle( phkResult );
}
return Error;
}
LONG
BaseBindToMachine(
IN LPCWSTR lpMachineName,
IN PBIND_CALLBACK BindCallback,
IN PVOID Context1,
IN PVOID Context2
)
/*++
Routine Description:
This is a helper routine used to create an RPC binding from
a given machine name.
Arguments:
lpMachineName - Supplies a pointer to a machine name. Must not
be NULL.
BindCallback - Supplies the function that should be called once
a binding has been created to initiate the connection.
Context1 - Supplies the first parameter to pass to the callback routine.
Context2 - Supplies the second parameter to pass to the callback routine.
Return Value:
Returns ERROR_SUCCESS (0) for success; error-code for failure.
--*/
{
LONG Error;
int i;
RegConnFunction conn_fn;
RPC_BINDING_HANDLE binding;
conn_fn = conn_functions[0];
i = 1;
//
// Iterate through the protocols until we find one that
// can connect.
//
do {
Error = conn_fn(lpMachineName,&binding);
if (Error == ERROR_SUCCESS) {
//
// For the named pipes protocol, we use a static endpoint, so the
// call to RpcEpResolveBinding is not needed.
// Also, the server checks the user's credentials on opening
// the named pipe, so RpcBindingSetAuthInfo is not needed.
//
if (conn_fn != RegConn_np) {
Error = (LONG)RpcEpResolveBinding(binding,winreg_ClientIfHandle);
if (Error == ERROR_SUCCESS) {
Error = (LONG)RpcBindingSetAuthInfo(binding,
"", // ServerPrincName
RPC_C_AUTHN_LEVEL_CONNECT,
RPC_C_AUTHN_WINNT,
NULL, // AuthIdentity
RPC_C_AUTHZ_NONE);
}
}
if (Error == ERROR_SUCCESS) {
Error = (BindCallback)(&binding,
Context1,
Context2);
RpcBindingFree(&binding);
if (Error != RPC_S_SERVER_UNAVAILABLE) {
return Error;
}
} else {
RpcBindingFree(&binding);
}
}
//
// Try the next protocol's connection function.
//
if (Error) {
conn_fn = conn_functions[i];
i++;
}
} while (!((Error == ERROR_SUCCESS) || (conn_fn == NULL)));
if (Error != ERROR_SUCCESS) {
if ((Error == RPC_S_INVALID_ENDPOINT_FORMAT) ||
(Error == RPC_S_INVALID_NET_ADDR) ) {
Error = ERROR_INVALID_COMPUTERNAME;
} else {
Error = ERROR_BAD_NETPATH;
}
}
return(Error);
}
LONG
APIENTRY
RegConnectRegistryA (
LPCSTR lpMachineName,
HKEY hKey,
PHKEY phkResult
)
/*++
Routine Description:
Win32 ANSI API for establishes a connection to a predefined handle on
another machine.
RegConnectRegistryA converts the lpMachineName argument to a Unicode
string and then calls RegConnectRegistryW.
--*/
{
UNICODE_STRING MachineName;
ANSI_STRING AnsiString;
NTSTATUS Status;
LONG Error;
#if DBG
if ( BreakPointOnEntry ) {
DbgBreakPoint();
}
#endif
//
// Convert the subkey to a counted Unicode string
//
RtlInitAnsiString( &AnsiString, lpMachineName );
Status = RtlAnsiStringToUnicodeString(&MachineName,
&AnsiString,
TRUE);
if( ! NT_SUCCESS( Status )) {
return RtlNtStatusToDosError( Status );
}
Error = (LONG)RegConnectRegistryW(MachineName.Buffer,
hKey,
phkResult);
RtlFreeUnicodeString(&MachineName);
return Error;
}