Leaked source code of windows server 2003
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.

536 lines
14 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. Regcnreg.c
  5. Abstract:
  6. This module contains the Win32 Registry APIs to connect to a remote
  7. Registry. That is:
  8. - RegConnectRegistryA
  9. - RegConnectRegistryW
  10. Author:
  11. David J. Gilman (davegi) 25-Mar-1992
  12. Notes:
  13. The semantics of this API make it local only. That is there is no MIDL
  14. definition for RegConnectRegistry although it does call other client
  15. stubs, specifically OpenLocalMachine and OpenUsers.
  16. Revision History:
  17. John Vert (jvert) 16-Jun-1995
  18. Added connect support for protocols other than named pipes by
  19. stealing code from Win95. This enabled NT machines to connect
  20. to registries on Win95 machines
  21. --*/
  22. #include <rpc.h>
  23. #include "regrpc.h"
  24. #include "client.h"
  25. #include "shutinit.h"
  26. #include "..\regconn\regconn.h"
  27. LONG
  28. BaseBindToMachine(
  29. IN LPCWSTR lpMachineName,
  30. IN PBIND_CALLBACK BindCallback,
  31. IN PVOID Context1,
  32. IN PVOID Context2
  33. );
  34. typedef int (* RegConnFunction)(LPCWSTR, handle_t *);
  35. RegConnFunction conn_functions[] = {
  36. RegConn_np,
  37. RegConn_spx,
  38. RegConn_ip_tcp,
  39. RegConn_nb_nb,
  40. RegConn_nb_tcp,
  41. RegConn_nb_ipx,
  42. NULL
  43. };
  44. LONG
  45. Rpc_OpenPredefHandle(
  46. IN RPC_BINDING_HANDLE * pbinding OPTIONAL,
  47. IN HKEY hKey,
  48. OUT PHKEY phkResult
  49. )
  50. /*++
  51. Routine Description:
  52. Win32 Unicode API for establishing a connection to a predefined
  53. handle on another machine.
  54. Parameters:
  55. pbinding - This is a pointer to the binding handle in order
  56. to allow access to multiple protocols (NT remote registry is only over
  57. named pipes).
  58. hKey - Supplies the predefined handle to connect to on the remote
  59. machine. Currently this parameter must be one of:
  60. - HKEY_LOCAL_MACHINE
  61. - HKEY_PERFORMANCE_DATA
  62. - HKEY_USERS
  63. phkResult - Returns a handle which represents the supplied predefined
  64. handle on the supplied machine.
  65. Return Value:
  66. Returns ERROR_SUCCESS (0) for success; error-code for failure.
  67. On failure, the binding handle is freed.
  68. Notes:
  69. For administration purposes this API allows programs to access the
  70. Registry on a remote machine. In the current system the calling
  71. application must know the name of the remote machine that it wishes to
  72. connect to. However, it is expected that in the future a directory
  73. service API will return the parameters necessary for this API.
  74. --*/
  75. {
  76. LONG Error;
  77. HKEY PreviousResult;
  78. ASSERT( (phkResult != NULL));
  79. PreviousResult = *phkResult;
  80. switch ((int)(ULONG_PTR)hKey)
  81. {
  82. case (int)(ULONG_PTR)HKEY_LOCAL_MACHINE:
  83. Error = (LONG)OpenLocalMachine((PREGISTRY_SERVER_NAME) pbinding,
  84. MAXIMUM_ALLOWED,
  85. phkResult );
  86. break;
  87. case (int)(ULONG_PTR)HKEY_PERFORMANCE_DATA:
  88. Error = (LONG)OpenPerformanceData((PREGISTRY_SERVER_NAME) pbinding,
  89. MAXIMUM_ALLOWED,
  90. phkResult );
  91. break;
  92. case (int)(ULONG_PTR)HKEY_USERS:
  93. Error = (LONG)OpenUsers((PREGISTRY_SERVER_NAME) pbinding,
  94. MAXIMUM_ALLOWED,
  95. phkResult );
  96. break;
  97. case (int)(ULONG_PTR)HKEY_CLASSES_ROOT:
  98. Error = (LONG)OpenClassesRoot((PREGISTRY_SERVER_NAME) pbinding,
  99. MAXIMUM_ALLOWED,
  100. phkResult );
  101. break;
  102. case (int)(ULONG_PTR)HKEY_CURRENT_USER:
  103. Error = (LONG)OpenCurrentUser((PREGISTRY_SERVER_NAME) pbinding,
  104. MAXIMUM_ALLOWED,
  105. phkResult );
  106. break;
  107. case (int)(ULONG_PTR)HKEY_PERFORMANCE_TEXT:
  108. Error = (LONG)OpenPerformanceText((PREGISTRY_SERVER_NAME) pbinding,
  109. MAXIMUM_ALLOWED,
  110. phkResult );
  111. break;
  112. case (int)(ULONG_PTR)HKEY_PERFORMANCE_NLSTEXT:
  113. Error = (LONG)OpenPerformanceNlsText((PREGISTRY_SERVER_NAME) pbinding,
  114. MAXIMUM_ALLOWED,
  115. phkResult );
  116. break;
  117. default:
  118. Error = ERROR_INVALID_HANDLE;
  119. }
  120. if( Error != ERROR_SUCCESS) {
  121. //ASSERTMSG("WINREG: RPC failed, but modifed phkResult", *phkResult == PreviousResult);
  122. if (*pbinding != NULL)
  123. RpcBindingFree(pbinding);
  124. }
  125. return Error;
  126. }
  127. LONG
  128. LocalOpenPredefHandle(
  129. IN HKEY hKey,
  130. OUT PHKEY phkResult
  131. )
  132. /*++
  133. Routine Description:
  134. Opens a predefined handle locally. The purpose of this is to bypass RPC in the
  135. case of connecting to the local machine.
  136. Parameters:
  137. hKey - Supplies the predefined handle to connect to on the remote
  138. machine. Currently this parameter must be one of:
  139. - HKEY_LOCAL_MACHINE
  140. - HKEY_PERFORMANCE_DATA
  141. - HKEY_USERS
  142. phkResult - Returns a handle which represents the supplied predefined
  143. handle on the supplied machine.
  144. Return Value:
  145. Returns ERROR_SUCCESS (0) for success; error-code for failure.
  146. --*/
  147. {
  148. LONG Error;
  149. ASSERT( (phkResult != NULL));
  150. switch ((int)(ULONG_PTR)hKey)
  151. {
  152. case (int)(ULONG_PTR)HKEY_LOCAL_MACHINE:
  153. Error = (LONG)LocalOpenLocalMachine(NULL,
  154. MAXIMUM_ALLOWED,
  155. phkResult );
  156. break;
  157. case (int)(ULONG_PTR)HKEY_PERFORMANCE_DATA:
  158. Error = (LONG)LocalOpenPerformanceData(NULL,
  159. MAXIMUM_ALLOWED,
  160. phkResult );
  161. break;
  162. case (int)(ULONG_PTR)HKEY_USERS:
  163. Error = (LONG)LocalOpenUsers(NULL,
  164. MAXIMUM_ALLOWED,
  165. phkResult );
  166. break;
  167. case (int)(ULONG_PTR)HKEY_CLASSES_ROOT:
  168. Error = (LONG)LocalOpenClassesRoot(NULL,
  169. MAXIMUM_ALLOWED,
  170. phkResult );
  171. break;
  172. case (int)(ULONG_PTR)HKEY_CURRENT_USER:
  173. Error = (LONG)LocalOpenCurrentUser(NULL,
  174. MAXIMUM_ALLOWED,
  175. phkResult );
  176. break;
  177. case (int)(ULONG_PTR)HKEY_PERFORMANCE_TEXT:
  178. case (int)(ULONG_PTR)HKEY_PERFORMANCE_NLSTEXT:
  179. case (int)(ULONG_PTR)HKEY_CURRENT_CONFIG:
  180. case (int)(ULONG_PTR)HKEY_DYN_DATA:
  181. //
  182. // try not to break whoever used this
  183. //
  184. *phkResult = hKey;
  185. Error = ERROR_SUCCESS;
  186. break;
  187. default:
  188. Error = ERROR_INVALID_HANDLE;
  189. }
  190. return Error;
  191. }
  192. LONG
  193. RegConnectRegistryW (
  194. IN LPCWSTR lpMachineName OPTIONAL,
  195. IN HKEY hKey,
  196. OUT PHKEY phkResult
  197. )
  198. /*++
  199. Routine Description:
  200. Win32 Unicode API for establishing a connection to a predefined
  201. handle on another machine.
  202. Parameters:
  203. lpMachineName - Supplies a pointer to a null-terminated string that
  204. names the machine of interest. If this parameter is NULL, the local
  205. machine name is used.
  206. hKey - Supplies the predefined handle to connect to on the remote
  207. machine. Currently this parameter must be one of:
  208. - HKEY_LOCAL_MACHINE
  209. - HKEY_PERFORMANCE_DATA
  210. - HKEY_USERS
  211. phkResult - Returns a handle which represents the supplied predefined
  212. handle on the supplied machine.
  213. Return Value:
  214. Returns ERROR_SUCCESS (0) for success; error-code for failure.
  215. Notes:
  216. For administration purposes this API allows programs to access the
  217. Registry on a remote machine. In the current system the calling
  218. application must know the name of the remote machine that it wishes to
  219. connect to. However, it is expected that in the future a directory
  220. service API will return the parameters necessary for this API.
  221. Even though HKEY_CLASSES and HKEY_CURRENT_USER are predefined handles,
  222. they are not supported by this API as they do not make sense in the
  223. context of a remote Registry.
  224. --*/
  225. {
  226. LONG Error;
  227. WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  228. DWORD bufLen = MAX_COMPUTERNAME_LENGTH + 1;
  229. ASSERT( ARGUMENT_PRESENT( phkResult ));
  230. #if DBG
  231. if ( BreakPointOnEntry ) {
  232. DbgBreakPoint();
  233. }
  234. #endif
  235. //
  236. // Check for local connect
  237. //
  238. if (lpMachineName == NULL) {
  239. //
  240. // always return a valid handle
  241. //
  242. Error = LocalOpenPredefHandle(hKey,phkResult);
  243. return Error;
  244. } else if (lpMachineName[0] == L'\0') {
  245. //
  246. // always return a valid handle
  247. //
  248. Error = LocalOpenPredefHandle(hKey,phkResult);
  249. return Error;
  250. }
  251. if (GetComputerNameW(ComputerName,&bufLen)) {
  252. if ((_wcsicmp(ComputerName,lpMachineName) == 0) ||
  253. ((lpMachineName[0] == '\\') &&
  254. (lpMachineName[1] == '\\') &&
  255. (_wcsicmp(ComputerName,&(lpMachineName[2]))==0))) {
  256. //
  257. // local connect
  258. //
  259. //
  260. // always return a valid handle
  261. //
  262. Error = LocalOpenPredefHandle(hKey,phkResult);
  263. return Error;
  264. }
  265. }
  266. Error = BaseBindToMachine(lpMachineName,
  267. Rpc_OpenPredefHandle,
  268. (PVOID)hKey,
  269. (PVOID)phkResult);
  270. if( Error == ERROR_SUCCESS) {
  271. TagRemoteHandle( phkResult );
  272. }
  273. return Error;
  274. }
  275. LONG
  276. BaseBindToMachine(
  277. IN LPCWSTR lpMachineName,
  278. IN PBIND_CALLBACK BindCallback,
  279. IN PVOID Context1,
  280. IN PVOID Context2
  281. )
  282. /*++
  283. Routine Description:
  284. This is a helper routine used to create an RPC binding from
  285. a given machine name.
  286. Arguments:
  287. lpMachineName - Supplies a pointer to a machine name. Must not
  288. be NULL.
  289. BindCallback - Supplies the function that should be called once
  290. a binding has been created to initiate the connection.
  291. Context1 - Supplies the first parameter to pass to the callback routine.
  292. Context2 - Supplies the second parameter to pass to the callback routine.
  293. Return Value:
  294. Returns ERROR_SUCCESS (0) for success; error-code for failure.
  295. --*/
  296. {
  297. LONG Error;
  298. int i;
  299. RegConnFunction conn_fn;
  300. RPC_BINDING_HANDLE binding;
  301. conn_fn = conn_functions[0];
  302. i = 1;
  303. //
  304. // Iterate through the protocols until we find one that
  305. // can connect.
  306. //
  307. do {
  308. Error = conn_fn(lpMachineName,&binding);
  309. if (Error == ERROR_SUCCESS) {
  310. //
  311. // For the named pipes protocol, we use a static endpoint, so the
  312. // call to RpcEpResolveBinding is not needed.
  313. //
  314. if (conn_fn != RegConn_np) {
  315. Error = (LONG)RpcEpResolveBinding(binding,winreg_ClientIfHandle);
  316. if (Error == ERROR_SUCCESS) {
  317. Error = (LONG)RpcBindingSetAuthInfo(binding,
  318. "", // ServerPrincName
  319. RPC_C_AUTHN_LEVEL_CONNECT,
  320. RPC_C_AUTHN_WINNT,
  321. NULL, // AuthIdentity
  322. RPC_C_AUTHZ_NONE);
  323. }
  324. }
  325. if (Error == ERROR_SUCCESS) {
  326. Error = (BindCallback)(&binding,
  327. Context1,
  328. Context2);
  329. RpcBindingFree(&binding);
  330. if (Error != RPC_S_SERVER_UNAVAILABLE) {
  331. return Error;
  332. }
  333. } else {
  334. RpcBindingFree(&binding);
  335. }
  336. }
  337. //
  338. // Try the next protocol's connection function.
  339. //
  340. if (Error) {
  341. conn_fn = conn_functions[i];
  342. i++;
  343. }
  344. } while (!((Error == ERROR_SUCCESS) || (conn_fn == NULL)));
  345. if (Error != ERROR_SUCCESS) {
  346. if ((Error == RPC_S_INVALID_ENDPOINT_FORMAT) ||
  347. (Error == RPC_S_INVALID_NET_ADDR) ) {
  348. Error = ERROR_INVALID_COMPUTERNAME;
  349. } else {
  350. Error = ERROR_BAD_NETPATH;
  351. }
  352. }
  353. return(Error);
  354. }
  355. LONG
  356. APIENTRY
  357. RegConnectRegistryA (
  358. LPCSTR lpMachineName,
  359. HKEY hKey,
  360. PHKEY phkResult
  361. )
  362. /*++
  363. Routine Description:
  364. Win32 ANSI API for establishes a connection to a predefined handle on
  365. another machine.
  366. RegConnectRegistryA converts the lpMachineName argument to a Unicode
  367. string and then calls RegConnectRegistryW.
  368. --*/
  369. {
  370. UNICODE_STRING MachineName;
  371. ANSI_STRING AnsiString;
  372. NTSTATUS Status;
  373. LONG Error;
  374. #if DBG
  375. if ( BreakPointOnEntry ) {
  376. DbgBreakPoint();
  377. }
  378. #endif
  379. //
  380. // Convert the subkey to a counted Unicode string
  381. //
  382. Status = RtlInitAnsiStringEx( &AnsiString, lpMachineName );
  383. if( ! NT_SUCCESS( Status )) {
  384. return RtlNtStatusToDosError( Status );
  385. }
  386. Status = RtlAnsiStringToUnicodeString(&MachineName,
  387. &AnsiString,
  388. TRUE);
  389. if( ! NT_SUCCESS( Status )) {
  390. return RtlNtStatusToDosError( Status );
  391. }
  392. Error = (LONG)RegConnectRegistryW(MachineName.Buffer,
  393. hKey,
  394. phkResult);
  395. RtlFreeUnicodeString(&MachineName);
  396. return Error;
  397. }