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.

707 lines
19 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. rpcutil.c
  5. Abstract:
  6. This module contains high level rpc wrapper apis.
  7. This code is here because the code in the rpcutil
  8. project uses NT apis and the WINFAX dll but load
  9. and run on win95.
  10. Author:
  11. Wesley Witt (wesw) 13-Aug-1997
  12. Revision History:
  13. --*/
  14. #include "faxapi.h"
  15. #include "CritSec.h"
  16. #pragma hdrstop
  17. typedef RPC_STATUS (*PRPCSERVERUNREGISTERIFEX)(RPC_IF_HANDLE IfSpec, UUID __RPC_FAR * MgrTypeUuid, int RundownContextHandles);
  18. #define MIN_PORT_NUMBER 1024
  19. #define MAX_PORT_NUMBER 65534
  20. #ifdef UNICODE
  21. #define LPUTSTR unsigned short *
  22. #else
  23. #define LPUTSTR unsigned char *
  24. #endif
  25. CFaxCriticalSection g_CsFaxClientRpc; // This critical section provides mutual exclusion
  26. // for all RPC server initialization operations:
  27. // 1. Registration counter (g_dwFaxClientRpcNumInst).
  28. // 2. Selecting free endpoint.
  29. // 3. Register the RPC interface
  30. // 4. Start listening for remote procedure calls.
  31. // 5. Stop listening for remote procedure calls.
  32. // 6. remove the interface.
  33. //
  34. //
  35. // IMPORTNAT!!! g_CsFaxClientRpc should not be used in the implementation of the RPC calls because it can cause a dead lock.
  36. // because when the RPC server is going down in StopFaxClientRpcServer(), the wait opration (for all active calls to terminate) is inside g_CsFaxClientRpc.
  37. //
  38. DWORD g_dwFaxClientRpcNumInst;
  39. CFaxCriticalSection g_CsFaxAssyncInfo; // used to synchronize access to the assync info structures that are allocated on the heap (notification context).
  40. TCHAR g_tszEndPoint[MAX_ENDPOINT_LEN]; // Buffer to hold selected port (endpoint)
  41. // for RPC protoqol sequence
  42. static
  43. RPC_STATUS
  44. SafeRpcServerUnregisterIf(
  45. VOID
  46. )
  47. /*
  48. Routine Description:
  49. This function calls RpcServerUnregisterIfEx if it is exported from RPCRT4.DLL (WinXP and up).
  50. Otherwise it calls RpcServerUnregisterIf which is subject to rundown calls even after the interface is unregistered.
  51. Arguments:
  52. none
  53. Return Value:
  54. Win32 errors
  55. */
  56. {
  57. HMODULE hModule = NULL;
  58. RPC_STATUS RpcStatus;
  59. DEBUG_FUNCTION_NAME(TEXT("SafeRpcServerUnregisterIf"));
  60. if (hModule = LoadLibrary(TEXT("RPCRT4.DLL")))
  61. {
  62. PRPCSERVERUNREGISTERIFEX pRpcServerUnregisterIfEx = NULL;
  63. if (pRpcServerUnregisterIfEx = (PRPCSERVERUNREGISTERIFEX)GetProcAddress(hModule, "RpcServerUnregisterIfEx"))
  64. {
  65. RpcStatus = (*pRpcServerUnregisterIfEx)(faxclient_ServerIfHandle, 0, FALSE);
  66. goto Exit;
  67. }
  68. else
  69. {
  70. DebugPrintEx(
  71. DEBUG_ERR,
  72. TEXT("GetProcAddress RpcServerUnregisterIfEx failed: %ld"),
  73. GetLastError());
  74. }
  75. }
  76. else
  77. {
  78. DebugPrintEx(
  79. DEBUG_ERR,
  80. TEXT("LoadLibrary RPCRT4.DLL failed: %ld"),
  81. GetLastError());
  82. }
  83. DebugPrintEx(
  84. DEBUG_WRN,
  85. TEXT("Calling RpcServerUnregisterIf !!!"));
  86. RpcStatus = RpcServerUnregisterIf(faxclient_ServerIfHandle, 0, FALSE);
  87. Exit:
  88. if (hModule)
  89. {
  90. FreeLibrary(hModule);
  91. }
  92. return RpcStatus;
  93. }
  94. BOOL
  95. FaxClientInitRpcServer(
  96. VOID
  97. )
  98. /*++
  99. Routine Description:
  100. This function initializes the critical section used to protect the
  101. global server handle, instance count and assync info structures (notification context).
  102. Arguments:
  103. none
  104. Return Value:
  105. none
  106. --*/
  107. {
  108. DEBUG_FUNCTION_NAME(TEXT("FaxClientInitRpcServer"));
  109. ZeroMemory (g_tszEndPoint, sizeof(g_tszEndPoint));
  110. g_dwFaxClientRpcNumInst = 0;
  111. if (!g_CsFaxClientRpc.Initialize() ||
  112. !g_CsFaxAssyncInfo.Initialize())
  113. {
  114. DebugPrintEx(
  115. DEBUG_ERR,
  116. TEXT("CFaxCriticalSection.Initialize (g_CsFaxClientRpc or g_CsFaxAssyncInfo) failed: %ld"),
  117. GetLastError());
  118. return FALSE;
  119. }
  120. return TRUE;
  121. }
  122. VOID
  123. FaxClientTerminateRpcServer (VOID)
  124. /*++
  125. Routine Description: Delete critical section when PROCESS_DETACH.
  126. --*/
  127. {
  128. g_CsFaxClientRpc.SafeDelete();
  129. g_CsFaxAssyncInfo.SafeDelete();
  130. return;
  131. }
  132. DWORD
  133. StopFaxClientRpcServer(
  134. VOID
  135. )
  136. /*++
  137. Routine Description:
  138. Stops the RPC server. Deletes the interface.
  139. Note that an endpoint is allocated to a process as long as the process lives.
  140. Arguments:
  141. Return Value:
  142. NERR_Success, or any RPC error codes that can be returned from
  143. RpcServerUnregisterIf/Ex.
  144. --*/
  145. {
  146. RPC_STATUS RpcStatus = RPC_S_OK;
  147. DEBUG_FUNCTION_NAME(TEXT("StopFaxClientRpcServer"));
  148. EnterCriticalSection(&g_CsFaxClientRpc);
  149. if (0 == g_dwFaxClientRpcNumInst)
  150. {
  151. //
  152. // This can happen if the client tried to unregister from events using an invalid handle, or used the same handle twice
  153. //
  154. DebugPrintEx(
  155. DEBUG_ERR,
  156. TEXT("StopFaxClientRpcServer was called when the clients reference count was 0"));
  157. LeaveCriticalSection(&g_CsFaxClientRpc);
  158. return ERROR_INVALID_PARAMETER;
  159. }
  160. g_dwFaxClientRpcNumInst--;
  161. if (g_dwFaxClientRpcNumInst == 0)
  162. {
  163. RpcStatus = RpcMgmtStopServerListening(NULL);
  164. if (RPC_S_OK != RpcStatus)
  165. {
  166. DebugPrintEx(
  167. DEBUG_ERR,
  168. TEXT("RpcMgmtStopServerListening failed. (ec: %ld)"),
  169. RpcStatus);
  170. }
  171. RpcStatus = SafeRpcServerUnregisterIf();
  172. if (RPC_S_OK != RpcStatus)
  173. {
  174. DebugPrintEx(
  175. DEBUG_ERR,
  176. TEXT("SafeRpcServerUnregisterIf failed. (ec: %ld)"),
  177. RpcStatus);
  178. }
  179. RpcStatus = RpcMgmtWaitServerListen();
  180. if (RPC_S_OK != RpcStatus)
  181. {
  182. DebugPrintEx(
  183. DEBUG_ERR,
  184. TEXT("RpcMgmtStopServerListening failed. (ec: %ld)"),
  185. RpcStatus);
  186. goto exit;
  187. }
  188. }
  189. exit:
  190. LeaveCriticalSection(&g_CsFaxClientRpc);
  191. return(RpcStatus);
  192. }
  193. DWORD
  194. FaxClientUnbindFromFaxServer(
  195. IN RPC_BINDING_HANDLE BindingHandle
  196. )
  197. /*++
  198. Routine Description:
  199. Unbinds from the RPC interface.
  200. If we decide to cache bindings, this routine will do something more
  201. interesting.
  202. Arguments:
  203. BindingHandle - This points to the binding handle that is to be closed.
  204. Return Value:
  205. STATUS_SUCCESS - the unbinding was successful.
  206. --*/
  207. {
  208. RPC_STATUS RpcStatus;
  209. if (BindingHandle != NULL) {
  210. RpcStatus = RpcBindingFree(&BindingHandle);
  211. }
  212. return(ERROR_SUCCESS);
  213. }
  214. #if !defined(WIN95)
  215. RPC_STATUS RPC_ENTRY FaxClientSecurityCallBack(
  216. IN RPC_IF_HANDLE idIF,
  217. IN void *ctx
  218. )
  219. /*++
  220. Routine Description:
  221. Security callback function is automatically called when
  222. any RPC server function is called. (usually, once per client - but in some cases,
  223. the RPC run time may call the security-callback function more than
  224. once per client-per interface - For example when talking with BOS server
  225. with no authentication).
  226. The call-back will deny access for:
  227. o clients with a protocol other then ncacn_ip_tcp
  228. Arguments:
  229. idIF - UUID and version of the interface.
  230. ctx - Pointer to an RPC_IF_ID server binding handle representing the client.
  231. Return Value:
  232. The callback function should return RPC_S_OK if the client is allowed to call methods in this interface.
  233. Any other return code will cause the client to receive the exception RPC_S_ACCESS_DENIED.
  234. --*/
  235. {
  236. RPC_STATUS status = RPC_S_OK;
  237. RPC_STATUS rpcStatRet = RPC_S_OK;
  238. LPTSTR lptstrProtSeq = NULL;
  239. DEBUG_FUNCTION_NAME(TEXT("FaxClientSecurityCallBack"));
  240. //
  241. // Query the client's protseq
  242. //
  243. status = GetRpcStringBindingInfo(ctx,
  244. NULL,
  245. &lptstrProtSeq);
  246. if (status != RPC_S_OK)
  247. {
  248. DebugPrintEx(DEBUG_ERR,
  249. TEXT("RpcBindingServerFromClient failed - (ec: %lu)"),
  250. status);
  251. rpcStatRet = ERROR_ACCESS_DENIED;
  252. goto exit;
  253. }
  254. if (_tcsicmp((TCHAR*)lptstrProtSeq, RPC_PROT_SEQ_TCP_IP))
  255. {
  256. DebugPrintEx(DEBUG_ERR,
  257. TEXT("Client not using TCP/IP protSeq.")
  258. );
  259. rpcStatRet = ERROR_ACCESS_DENIED;
  260. goto exit;
  261. }
  262. exit:
  263. if(NULL != lptstrProtSeq)
  264. {
  265. MemFree(lptstrProtSeq);
  266. }
  267. return rpcStatRet;
  268. } // FaxClientSecurityCallBack
  269. #endif
  270. DWORD
  271. StartFaxClientRpcServer(
  272. VOID
  273. )
  274. /*++
  275. Routine Description:
  276. Starts an RPC Server, and adds the interface (dispatch table).
  277. Arguments:
  278. Return Value:
  279. Standard Win32 or RPC error code.
  280. --*/
  281. {
  282. DWORD ec = RPC_S_OK;
  283. DEBUG_FUNCTION_NAME(TEXT("StartFaxClientRpcServer"));
  284. EnterCriticalSection(&g_CsFaxClientRpc);
  285. if (0 == _tcslen(g_tszEndPoint))
  286. {
  287. //
  288. // Endpoint not yet allocated for this Fax handle. Find a free endpoint.
  289. // Note that an endpoint is allocated to a process as long as the process lives.
  290. TCHAR tszFreeEndPoint[MAX_ENDPOINT_LEN] = {0};
  291. DWORD i;
  292. DWORD PortNumber;
  293. for (i = MIN_PORT_NUMBER; i < MIN_PORT_NUMBER + 10 ; i++ )
  294. {
  295. //
  296. // Search for a free end point.
  297. // If we fail for an error other than a duplicate endpoint, we loop for nothing.
  298. // We do so since diffrent platformns (W2K, NT4, Win9X) return diffrent error codes for duplicate enpoint.
  299. //
  300. for (PortNumber = i; PortNumber < MAX_PORT_NUMBER; PortNumber += 10)
  301. {
  302. _stprintf (tszFreeEndPoint, TEXT("%d"), PortNumber);
  303. ec = RpcServerUseProtseqEp ( (LPUTSTR)RPC_PROT_SEQ_TCP_IP,
  304. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  305. (LPUTSTR)tszFreeEndPoint,
  306. NULL);
  307. if (RPC_S_OK == ec)
  308. {
  309. _tcscpy (g_tszEndPoint, tszFreeEndPoint);
  310. DebugPrintEx(
  311. DEBUG_MSG,
  312. TEXT("Found free endpoint - %s"),
  313. tszFreeEndPoint);
  314. break;
  315. }
  316. }
  317. if (RPC_S_OK == ec)
  318. {
  319. break;
  320. }
  321. }
  322. }
  323. if (0 == g_dwFaxClientRpcNumInst)
  324. {
  325. //
  326. // First rpc server instance - register interface, start listening for remote procedure calls
  327. //
  328. //
  329. // Register interface
  330. //
  331. //
  332. // The logic for registering the interface written below is done to preserve
  333. // BOS capability of sending notifications.
  334. // BOS Fax server does not "talk" with it's clients in a secure channel.
  335. //
  336. // Only on .NET OS we can call RpcServerRegisterIfEx for registering callback function even
  337. // when the RPC client is anonymous (using the RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH flag that
  338. // were introduce only on .NET).
  339. //
  340. // On all other OS we use RpcServerRegisterIf and have no callback.
  341. //
  342. // The callback will only check for proper ProtSeq.
  343. // We will check for proper authentication level (RPC_C_AUTHN_LEVEL_PKT_PRIVACY from .NET fax server
  344. // and no authentication for BOS fax server)
  345. //
  346. #if defined(WIN95)
  347. //
  348. // Win9x OS
  349. //
  350. ec = RpcServerRegisterIf (faxclient_ServerIfHandle,
  351. 0,
  352. 0);
  353. if (RPC_S_OK != ec)
  354. {
  355. DebugPrintEx(
  356. DEBUG_ERR,
  357. TEXT("RpcServerRegisterIf failed (ec = %lu)"),
  358. ec);
  359. goto exit;
  360. }
  361. #else
  362. //
  363. // NT4 and later OS
  364. //
  365. if (IsWinXPOS())
  366. {
  367. //
  368. // Running on .NET OS (XP client does not run this code)
  369. //
  370. ec = RpcServerRegisterIfEx (faxclient_ServerIfHandle,
  371. 0,
  372. 0,
  373. RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH,
  374. RPC_C_LISTEN_MAX_CALLS_DEFAULT, // Relieves the RPC run-time environment from enforcing an unnecessary restriction
  375. FaxClientSecurityCallBack // CallBack function address
  376. );
  377. if (RPC_S_OK != ec)
  378. {
  379. DebugPrintEx(
  380. DEBUG_ERR,
  381. TEXT("RpcServerRegisterIfEx failed (ec = %lu)"),
  382. ec);
  383. goto exit;
  384. }
  385. }
  386. else
  387. {
  388. //
  389. // Running on NT4 or Win2K OS
  390. //
  391. ec = RpcServerRegisterIf (faxclient_ServerIfHandle,
  392. 0,
  393. 0);
  394. if (RPC_S_OK != ec)
  395. {
  396. DebugPrintEx(
  397. DEBUG_ERR,
  398. TEXT("RpcServerRegisterIf failed (ec = %lu)"),
  399. ec);
  400. goto exit;
  401. }
  402. }
  403. #endif
  404. //
  405. // We use NTLM authentication RPC calls
  406. //
  407. ec = RpcServerRegisterAuthInfo (
  408. (LPUTSTR)TEXT(""), // Igonred by RPC_C_AUTHN_WINNT
  409. RPC_C_AUTHN_WINNT, // NTLM SPP authenticator
  410. NULL, // Ignored when using RPC_C_AUTHN_WINNT
  411. NULL); // Ignored when using RPC_C_AUTHN_WINNT
  412. if (ec != RPC_S_OK)
  413. {
  414. RPC_STATUS RpcStatus;
  415. DebugPrintEx(
  416. DEBUG_ERR,
  417. TEXT("RpcServerRegisterAuthInfo() failed (ec: %ld)"),
  418. ec);
  419. //
  420. // Unregister the interface if it is the first instance
  421. //
  422. RpcStatus = SafeRpcServerUnregisterIf();
  423. if (RPC_S_OK != RpcStatus)
  424. {
  425. DebugPrintEx(
  426. DEBUG_ERR,
  427. TEXT("SafeRpcServerUnregisterIf failed. (ec: %ld)"),
  428. RpcStatus);
  429. }
  430. goto exit;
  431. }
  432. // The first argument specifies the minimum number of threads to
  433. // be created to handle calls; the second argument specifies the
  434. // maximum number of concurrent calls allowed. The last argument
  435. // indicates not to wait.
  436. ec = RpcServerListen (1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, 1);
  437. if (ec != RPC_S_OK)
  438. {
  439. RPC_STATUS RpcStatus;
  440. DebugPrintEx(
  441. DEBUG_ERR,
  442. TEXT("RpcServerListen failed (ec = %ld"),
  443. ec);
  444. //
  445. // Unregister the interface if it is the first instance
  446. //
  447. RpcStatus = SafeRpcServerUnregisterIf();
  448. if (RPC_S_OK != RpcStatus)
  449. {
  450. DebugPrintEx(
  451. DEBUG_ERR,
  452. TEXT("SafeRpcServerUnregisterIf failed. (ec: %ld)"),
  453. RpcStatus);
  454. }
  455. goto exit;
  456. }
  457. }
  458. g_dwFaxClientRpcNumInst++;
  459. exit:
  460. LeaveCriticalSection(&g_CsFaxClientRpc);
  461. return ec;
  462. }
  463. DWORD
  464. FaxClientBindToFaxServer(
  465. IN LPCTSTR lpctstrServerName,
  466. IN LPCTSTR lpctstrServiceName,
  467. IN LPCTSTR lpctstrNetworkOptions,
  468. OUT RPC_BINDING_HANDLE * pBindingHandle
  469. )
  470. /*++
  471. Routine Description:
  472. Binds to the RPC server if possible.
  473. Arguments:
  474. ServerName - Name of server to bind with.
  475. ServiceName - Name of service to bind with.
  476. pBindingHandle - Location where binding handle is to be placed
  477. Return Value:
  478. STATUS_SUCCESS - The binding has been successfully completed.
  479. STATUS_INVALID_COMPUTER_NAME - The ServerName syntax is invalid.
  480. STATUS_NO_MEMORY - There is not sufficient memory available to the
  481. caller to perform the binding.
  482. --*/
  483. {
  484. RPC_STATUS RpcStatus;
  485. LPTSTR StringBinding;
  486. LPTSTR Endpoint;
  487. LPTSTR NewServerName = NULL;
  488. DWORD dwResult;
  489. DEBUG_FUNCTION_NAME(TEXT("FaxClientBindToFaxServer"));
  490. *pBindingHandle = NULL;
  491. if (IsLocalMachineName (lpctstrServerName))
  492. {
  493. NewServerName = NULL;
  494. }
  495. else
  496. {
  497. NewServerName = (LPTSTR)lpctstrServerName;
  498. }
  499. //
  500. // We need to concatenate \pipe\ to the front of the service
  501. // name.
  502. //
  503. Endpoint = (LPTSTR)LocalAlloc(
  504. 0,
  505. sizeof(NT_PIPE_PREFIX) + TCSSIZE(lpctstrServiceName));
  506. if (Endpoint == 0)
  507. {
  508. dwResult = STATUS_NO_MEMORY;
  509. goto exit;
  510. }
  511. _tcscpy(Endpoint,NT_PIPE_PREFIX);
  512. _tcscat(Endpoint,lpctstrServiceName);
  513. if (!NewServerName)
  514. {
  515. //
  516. // Local connection only - Make sure the service is up
  517. //
  518. if (!EnsureFaxServiceIsStarted (NULL))
  519. {
  520. dwResult = GetLastError ();
  521. DebugPrintEx(
  522. DEBUG_ERR,
  523. TEXT("EnsureFaxServiceIsStarted failed (ec = %ld"),
  524. dwResult);
  525. }
  526. else
  527. {
  528. //
  529. // Wait till the RPC service is up an running
  530. //
  531. if (!WaitForServiceRPCServer (60 * 1000))
  532. {
  533. dwResult = GetLastError ();
  534. DebugPrintEx(
  535. DEBUG_ERR,
  536. TEXT("WaitForServiceRPCServer failed (ec = %ld"),
  537. dwResult);
  538. }
  539. }
  540. }
  541. //
  542. // Start RPC connection binding
  543. //
  544. RpcStatus = RpcStringBindingCompose(
  545. 0,
  546. (LPUTSTR)RPC_PROT_SEQ_NP,
  547. (LPUTSTR)NewServerName,
  548. (LPUTSTR)Endpoint,
  549. (LPUTSTR)lpctstrNetworkOptions,
  550. (LPUTSTR *)&StringBinding);
  551. LocalFree(Endpoint);
  552. if ( RpcStatus != RPC_S_OK )
  553. {
  554. dwResult = STATUS_NO_MEMORY;
  555. goto exit;
  556. }
  557. RpcStatus = RpcBindingFromStringBinding((LPUTSTR)StringBinding, pBindingHandle);
  558. RpcStringFree((LPUTSTR *)&StringBinding);
  559. if ( RpcStatus != RPC_S_OK )
  560. {
  561. *pBindingHandle = NULL;
  562. if ( (RpcStatus == RPC_S_INVALID_ENDPOINT_FORMAT)
  563. || (RpcStatus == RPC_S_INVALID_NET_ADDR) )
  564. {
  565. dwResult = ERROR_INVALID_COMPUTERNAME ;
  566. goto exit;
  567. }
  568. dwResult = STATUS_NO_MEMORY;
  569. goto exit;
  570. }
  571. dwResult = ERROR_SUCCESS;
  572. exit:
  573. return dwResult;
  574. } // FaxClientBindToFaxServer