/*++ 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 #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; }