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.

1596 lines
35 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. isrpc.cxx
  5. Abstract:
  6. Contains ISRPC class implementation.
  7. Author:
  8. Murali R. Krishnan 11-Dec-1995
  9. Environment:
  10. User Mode - Win32
  11. Revision History:
  12. --*/
  13. /************************************************************
  14. * Include Headers
  15. ************************************************************/
  16. #ifndef dllexp
  17. #define dllexp __declspec( dllexport )
  18. #endif
  19. //
  20. // System include files.
  21. //
  22. #include "smtpinc.h"
  23. #ifdef __cplusplus
  24. extern "C" {
  25. #endif
  26. #include <nt.h>
  27. #include <ntrtl.h>
  28. #include <nturtl.h>
  29. #include <windows.h>
  30. #include <winsock2.h>
  31. #include <lm.h>
  32. #include <stdio.h>
  33. #include <stdarg.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <tchar.h>
  37. #ifdef __cplusplus
  38. } // extern "C"
  39. #endif // __cplusplus
  40. #include <isrpc.hxx>
  41. /************************************************************
  42. * Functions
  43. ************************************************************/
  44. DWORD
  45. InetinfoStartRpcServerListen(
  46. VOID
  47. )
  48. /*++
  49. Routine Description:
  50. This function starts RpcServerListen for this process. The first
  51. service that is calling this function will actually start the
  52. RpcServerListen, subsequent calls are just noted down in num count.
  53. Arguments:
  54. None.
  55. Return Value:
  56. None.
  57. --*/
  58. {
  59. RPC_STATUS Status = RPC_S_OK;
  60. Status = RpcServerListen(
  61. 1, // minimum num threads.
  62. RPC_C_LISTEN_MAX_CALLS_DEFAULT, // max concurrent calls.
  63. TRUE ); // don't wait
  64. return( Status );
  65. }
  66. DWORD
  67. InetinfoStopRpcServerListen(
  68. VOID
  69. )
  70. /*++
  71. Routine Description:
  72. Arguments:
  73. None.
  74. Return Value:
  75. None.
  76. --*/
  77. {
  78. RPC_STATUS Status = RPC_S_OK;
  79. Status = RpcMgmtStopServerListening(0);
  80. //
  81. // wait for all RPC threads to go away.
  82. //
  83. if( Status == RPC_S_OK) {
  84. Status = RpcMgmtWaitServerListen();
  85. }
  86. return( Status );
  87. }
  88. ISRPC::ISRPC(IN LPCTSTR pszServiceName)
  89. /*++
  90. This function constructs a new ISRPC object, initializing the
  91. members to proper state.
  92. Always the ISRPC members will use RPC_C_AUTHN_WINNT.
  93. Arguments:
  94. pszServiceName - pointer to string containing the name of the service
  95. dwServiceAuthId - DWORD containing the service Authentication Identifier.
  96. Returns:
  97. A valid initialized ISRPC object on success.
  98. --*/
  99. : m_dwProtocols ( 0),
  100. m_fInterfaceAdded ( FALSE),
  101. m_fEpRegistered ( FALSE),
  102. m_fServerStarted ( FALSE),
  103. m_hRpcInterface ( NULL),
  104. m_pszServiceName ( pszServiceName),
  105. m_pBindingVector ( NULL)
  106. {
  107. //DBG_REQUIRE( SetSecurityDescriptor() == NO_ERROR);
  108. SetSecurityDescriptor();
  109. #if 0
  110. IF_DEBUG( DLL_RPC) {
  111. DBGPRINTF(( DBG_CONTEXT,
  112. " Created new ISRPC object for %s at %08x\n",
  113. m_pszServiceName, this));
  114. }
  115. #endif
  116. } // ISRPC::ISRPC()
  117. ISRPC::~ISRPC(VOID)
  118. /*++
  119. This function cleans up the ISRPC object and releases any dynamic memory or
  120. state associated with this object.
  121. --*/
  122. {
  123. CleanupData();
  124. Cleanup();
  125. #if 0
  126. IF_DEBUG( DLL_RPC) {
  127. DBGPRINTF(( DBG_CONTEXT,
  128. " Destroyed ISRPC object for %s at %08x\n",
  129. m_pszServiceName, this));
  130. }
  131. #endif
  132. } // ISRPC::~ISRPC()
  133. DWORD
  134. ISRPC::CleanupData(VOID)
  135. /*++
  136. Routine Description:
  137. This member function cleans up the ISRPC object.
  138. Arguments:
  139. None.
  140. Return Value:
  141. None.
  142. --*/
  143. {
  144. DWORD rpcStatus = RPC_S_OK;
  145. #if 0
  146. IF_DEBUG( DLL_RPC) {
  147. DBGPRINTF(( DBG_CONTEXT,
  148. " ISRPC(%08x)::Cleaning up for %s\n",
  149. m_pszServiceName));
  150. }
  151. #endif
  152. if ( m_fServerStarted) {
  153. rpcStatus = StopServer( );
  154. }
  155. //DBG_ASSERT( rpcStatus == RPC_S_OK);
  156. rpcStatus = UnRegisterInterface();
  157. m_dwProtocols = 0;
  158. m_hRpcInterface = NULL;
  159. return (rpcStatus);
  160. } // ISRPC::CleanupData()
  161. DWORD
  162. ISRPC::RegisterInterface( IN RPC_IF_HANDLE hRpcInterface)
  163. /*++
  164. This function registers the RPC inteface in the object.
  165. If there is already a valid instance present in the object,
  166. this function fails and returns error.
  167. If this is the new interface specified, the function registers the
  168. interface both for dynamic and static bindings.
  169. Should be called after calling AddProtocol() and before StartServer()
  170. Arguments:
  171. hRpcInteface - RPC inteface handle.
  172. Returns:
  173. Win32 Error Code - NO_ERROR on success.
  174. --*/
  175. {
  176. DWORD dwError = NO_ERROR;
  177. if ( m_dwProtocols == 0) {
  178. // No protocol added. Return failure.
  179. return ( ERROR_INVALID_PARAMETER);
  180. }
  181. if ( m_hRpcInterface != NULL) {
  182. dwError = ( RPC_S_DUPLICATE_ENDPOINT);
  183. } else {
  184. //
  185. // since there is no duplicate, just set the new value and return.
  186. //
  187. if ( hRpcInterface == NULL) {
  188. dwError = ERROR_INVALID_PARAMETER;
  189. } else {
  190. m_hRpcInterface = hRpcInterface;
  191. }
  192. }
  193. if ( dwError == RPC_S_OK) {
  194. dwError = RpcServerRegisterIf(m_hRpcInterface,
  195. 0, // MgrUuid
  196. 0 // MgrEpv (Entry Point Vector)
  197. );
  198. if ( dwError == RPC_S_OK ) {
  199. m_fInterfaceAdded = TRUE;
  200. //
  201. // Establish the dynamic bindings if any.
  202. //
  203. if ( (m_dwProtocols & (ISRPC_OVER_TCPIP | ISRPC_OVER_SPX)) != 0) {
  204. dwError = RpcServerInqBindings( &m_pBindingVector);
  205. if ( dwError == RPC_S_OK) {
  206. //DBG_ASSERT( m_pBindingVector != NULL);
  207. dwError = RpcEpRegister(m_hRpcInterface,
  208. m_pBindingVector,
  209. NULL,
  210. (unsigned char *) "" );
  211. if ( dwError == RPC_S_OK) {
  212. m_fEpRegistered = TRUE;
  213. }
  214. } // Ep registering
  215. } // dynamic bindings
  216. } // registration successful
  217. }
  218. #if 0
  219. IF_DEBUG(DLL_RPC) {
  220. DBGPRINTF(( DBG_CONTEXT, "ISRPC(%08x)::RegisterInterface(%08x)"
  221. " returns %ld\n",
  222. this, hRpcInterface, dwError));
  223. }
  224. #endif
  225. return ( dwError);
  226. } // ISRPC::RegisterInterface()
  227. DWORD
  228. ISRPC::UnRegisterInterface( VOID)
  229. /*++
  230. This function unregisters the RPC inteface in the object.
  231. Should be called after after StopServer() and before cleanup.
  232. Arguments:
  233. None
  234. Returns:
  235. Win32 Error Code - NO_ERROR on success.
  236. --*/
  237. {
  238. DWORD rpcStatus = RPC_S_OK;
  239. if ( m_fEpRegistered) {
  240. //DBG_ASSERT( m_hRpcInterface != NULL && m_pBindingVector != NULL);
  241. rpcStatus = RpcEpUnregister(m_hRpcInterface,
  242. m_pBindingVector,
  243. NULL // pUuidVector
  244. );
  245. //_ASSERT( rpcStatus == RPC_S_OK);
  246. m_fEpRegistered = FALSE;
  247. }
  248. if ( m_pBindingVector != NULL) {
  249. rpcStatus = RpcBindingVectorFree( &m_pBindingVector);
  250. //_ASSERT( rpcStatus == RPC_S_OK);
  251. m_pBindingVector = NULL;
  252. }
  253. if ( m_fInterfaceAdded != NULL) {
  254. rpcStatus = RpcServerUnregisterIf(m_hRpcInterface,
  255. NULL, // MgrUuid
  256. TRUE // wait for calls to complete
  257. );
  258. //_ASSERT(rpcStatus == RPC_S_OK);
  259. m_fInterfaceAdded = FALSE;
  260. }
  261. return ( rpcStatus);
  262. } // ISRPC::UnRegisterInterface()
  263. DWORD
  264. ISRPC::AddProtocol( IN DWORD Protocol)
  265. /*++
  266. Routine Description:
  267. This member function adds another protocol to the binding list.
  268. Arguments:
  269. protocol - protocol binding opcode.
  270. fDynamic - Boolean indicating if the call should do dynamic or static
  271. RPC binding for the protocol specified.
  272. Return Value:
  273. RPC error code.
  274. --*/
  275. {
  276. DWORD rpcStatus = RPC_S_OK;
  277. if ( Protocol & ISRPC_OVER_LPC ) {
  278. // Currently we only support static binding
  279. rpcStatus = BindOverLpc( FALSE);
  280. }
  281. #ifndef CHICAGO
  282. //
  283. // Enable all remote bindings
  284. //
  285. if ( rpcStatus == RPC_S_OK ) {
  286. if ( Protocol & ISRPC_OVER_TCPIP ) {
  287. // Currently we only support dynamic binding
  288. rpcStatus = BindOverTcp( TRUE);
  289. }
  290. if ( rpcStatus == RPC_S_OK && Protocol & ISRPC_OVER_NP ) {
  291. // Currently we only support static binding
  292. rpcStatus = BindOverNamedPipe( FALSE);
  293. }
  294. if ( rpcStatus == RPC_S_OK && Protocol & ISRPC_OVER_SPX ) {
  295. // Currently we only support dynamic binding
  296. rpcStatus = BindOverSpx( TRUE);
  297. }
  298. }
  299. #else // CHICAGO
  300. rpcStatus = RPC_S_OK;
  301. if ( Protocol & ISRPC_OVER_TCPIP ) {
  302. // Currently we only support dynamic binding
  303. rpcStatus = BindOverTcp( TRUE);
  304. }
  305. if ( Protocol & ISRPC_OVER_NB ) {
  306. // Currently we only support dynamic binding
  307. // Ignore status for NB for now
  308. (VOID)BindOverNetBios(TRUE);
  309. }
  310. #endif // CHICAGO
  311. #if 0
  312. IF_DEBUG( DLL_RPC) {
  313. DBGPRINTF(( DBG_CONTEXT,
  314. "ISRPC(%08x)::AddProtocol(%08x) returns %ld.\n",
  315. this, Protocol, rpcStatus ));
  316. }
  317. #endif
  318. return( rpcStatus );
  319. } // ISRPC::AddProtocol()
  320. DWORD
  321. ISRPC::RemoveProtocol(IN DWORD Protocol)
  322. /*++
  323. Routine Description:
  324. This member function removes a protocol from the binding list.
  325. Arguments:
  326. protocol - protocol binding opcode.
  327. Return Value:
  328. RPC error code.
  329. Note:
  330. As a side effect, this function removes the dynamic endpoing on
  331. TCPIP when SPX binding is removed and vice-versa.
  332. --*/
  333. {
  334. #if 0
  335. DBGPRINTF(( DBG_CONTEXT,
  336. " ISRPC(%08x)::RemoveProtocol(%s) is not implemented\n",
  337. this, m_pszServiceName));
  338. DBG_ASSERT( FALSE);
  339. #endif
  340. return ( ERROR_CALL_NOT_IMPLEMENTED);
  341. } // ISRPC::RemoveProtocol()
  342. DWORD
  343. ISRPC::StartServer(
  344. VOID
  345. )
  346. /*++
  347. Routine Description:
  348. This member function start RPC server.
  349. Arguments:
  350. None.
  351. Return Value:
  352. RPC error code.
  353. --*/
  354. {
  355. DWORD rpcStatus;
  356. //
  357. // add the interface.
  358. //
  359. if ( m_hRpcInterface == NULL) {
  360. return (ERROR_INVALID_PARAMETER);
  361. }
  362. //
  363. // start rpc server.
  364. //
  365. #ifndef SERVICE_AS_EXE
  366. rpcStatus = InetinfoStartRpcServerListen();
  367. #else
  368. rpcStatus = RpcServerListen(
  369. 1, // minimum num threads.
  370. 1, // max concurrent calls.
  371. TRUE ); // don't wait
  372. #endif // SERVICE_AS_EXE
  373. if ( rpcStatus == RPC_S_OK ) {
  374. m_fServerStarted = TRUE;
  375. }
  376. #if 0
  377. IF_DEBUG( DLL_RPC) {
  378. DBGPRINTF(( DBG_CONTEXT, "ISRPC(%08x)::StartServer(%s) returns %ld\n",
  379. this, m_pszServiceName, rpcStatus));
  380. }
  381. #endif
  382. return( rpcStatus );
  383. } // ISRPC::StartServer()
  384. DWORD
  385. ISRPC::StopServer(
  386. VOID
  387. )
  388. {
  389. DWORD rpcStatus = RPC_S_OK;
  390. if( m_fServerStarted ) {
  391. #ifndef SERVICE_AS_EXE
  392. rpcStatus = InetinfoStopRpcServerListen();
  393. #else
  394. //
  395. // stop server listen.
  396. //
  397. rpcStatus = RpcMgmtStopServerListening(0);
  398. //
  399. // wait for all RPC threads to go away.
  400. //
  401. if( rpcStatus == RPC_S_OK) {
  402. rpcStatus = RpcMgmtWaitServerListen();
  403. }
  404. #endif // SERVICE_AS_EXE
  405. m_fServerStarted = FALSE;
  406. }
  407. #if 0
  408. IF_DEBUG( DLL_RPC) {
  409. DBGPRINTF(( DBG_CONTEXT,
  410. "ISRPC(%08x)::StopServer( %s) returns %d\n",
  411. this, m_pszServiceName, rpcStatus));
  412. }
  413. #endif
  414. return ( rpcStatus);
  415. } // ISRPC::StopServer()
  416. DWORD
  417. ISRPC::EnumBindingStrings(
  418. IN OUT LPINET_BINDINGS pBindings
  419. )
  420. /*++
  421. Routine Description:
  422. This member function enumurates the binding strings of the protocols
  423. bound to the server.
  424. Arguments:
  425. pBindings : pointer to a binding strings structure. The caller
  426. should call FreeBindingStrings member function to free the string
  427. after use.
  428. Return Value:
  429. Windows Error Code;
  430. --*/
  431. {
  432. DWORD dwError;
  433. RPC_BINDING_VECTOR * pBindingVector = NULL;
  434. LPINET_BIND_INFO pBindingsInfo;
  435. DWORD dwCount = 0;
  436. DWORD i;
  437. //
  438. // query RPC for RPC_BINDING_VECTORS.
  439. //
  440. dwError = RpcServerInqBindings( &pBindingVector );
  441. if( dwError != NO_ERROR ) {
  442. goto Cleanup;
  443. }
  444. //DBG_ASSERT( pBindingVector->Count > 0 );
  445. //
  446. // alloc memory for INET_RPC_BINDING_STRINGS.
  447. //
  448. pBindingsInfo = (LPINET_BIND_INFO)
  449. LocalAlloc( GPTR, sizeof(INET_BIND_INFO) * pBindingVector->Count );
  450. if( pBindingsInfo == NULL ) {
  451. dwError = ERROR_NOT_ENOUGH_MEMORY;
  452. goto Cleanup;
  453. }
  454. //
  455. // convert binding handle to binding vectors.
  456. //
  457. pBindings->NumBindings = 0;
  458. pBindings->BindingsInfo = pBindingsInfo;
  459. for( i = 0; i < pBindingVector->Count; i++ ) {
  460. LPSTR BindingString;
  461. BindingString = NULL;
  462. dwError = RpcBindingToStringBindingA(pBindingVector->BindingH[i],
  463. (LPBYTE *)&BindingString );
  464. if( dwError != NO_ERROR ) {
  465. goto Cleanup;
  466. }
  467. #if 0
  468. IF_DEBUG( DLL_RPC) {
  469. DBGPRINTF(( DBG_CONTEXT, "Binding Handle[%d] = %08x. String = %s\n",
  470. i, pBindingVector->BindingH[i], BindingString));
  471. }
  472. #endif
  473. //
  474. // check to we get only our named-pipe endpoint.
  475. //
  476. if( strstr( BindingString, "ncacn_np" ) != NULL ) {
  477. //
  478. // found a named-pipe binding string.
  479. //
  480. if( strstr(BindingString,
  481. m_pszServiceName ) == NULL ) {
  482. //
  483. // found a non service named-pipe entry.
  484. // ignore it.
  485. //
  486. RpcStringFreeA( (LPBYTE *)&BindingString );
  487. } else {
  488. #if 0
  489. IF_DEBUG( DLL_RPC) {
  490. DBGPRINTF(( DBG_CONTEXT, "Binding String Chosen = %s\n",
  491. BindingString));
  492. }
  493. #endif
  494. pBindings->BindingsInfo[dwCount].Length =
  495. (strlen(BindingString) + 1) * sizeof(CHAR);
  496. pBindings->BindingsInfo[dwCount].BindData = BindingString;
  497. dwCount++;
  498. }
  499. }
  500. } // for
  501. dwError = NO_ERROR;
  502. pBindings->NumBindings = dwCount;
  503. #if 0
  504. IF_DEBUG( DLL_RPC) {
  505. DBGPRINTF(( DBG_CONTEXT, "Binding Vectors chosen"
  506. " Service = %s, NumBindings = %d of Total = %d\n",
  507. m_pszServiceName, dwCount, pBindingVector->Count));
  508. }
  509. #endif
  510. Cleanup:
  511. if( pBindingVector != NULL ) {
  512. DWORD LocalError;
  513. LocalError = RpcBindingVectorFree( &pBindingVector );
  514. //DBG_ASSERT( LocalError == NO_ERROR );
  515. }
  516. if( dwError != NO_ERROR ) {
  517. FreeBindingStrings( pBindings );
  518. pBindings->NumBindings = 0;
  519. #if 0
  520. IF_DEBUG( DLL_RPC) {
  521. DBGPRINTF(( DBG_CONTEXT,
  522. "ISRPC(%08x)::EnumBindingStrings(%s) failed, %ld.",
  523. this, m_pszServiceName, dwError ));
  524. }
  525. #endif
  526. }
  527. return( dwError );
  528. } // ISRPC::EnumBindingStrings()
  529. VOID
  530. ISRPC::FreeBindingStrings(
  531. IN OUT LPINET_BINDINGS pInetBindings
  532. )
  533. /*++
  534. Routine Description:
  535. This member function deletes a binding vector that was returned by the
  536. EnumBindingStrings member function.
  537. Arguments:
  538. pBindings : pointer to a binding vector.
  539. Return Value:
  540. Windows Error Code;
  541. --*/
  542. {
  543. DWORD dwError;
  544. DWORD i;
  545. //
  546. // free binding strings.
  547. //
  548. for( i = 0; i < pInetBindings->NumBindings; i++) {
  549. dwError = RpcStringFreeA( ((LPBYTE *)&pInetBindings
  550. ->BindingsInfo[i].BindData ));
  551. //DBG_ASSERT( dwError == NO_ERROR );
  552. }
  553. pInetBindings->NumBindings = 0;
  554. //
  555. // free bindings info array.
  556. //
  557. if( pInetBindings->BindingsInfo != NULL ) {
  558. LocalFree( (HANDLE)pInetBindings->BindingsInfo );
  559. pInetBindings->BindingsInfo = NULL;
  560. }
  561. return;
  562. } // ISRPC::FreeBindingStrings()
  563. DWORD
  564. ISRPC::BindOverTcp(IN BOOL fDynamic)
  565. {
  566. DWORD rpcStatus = RPC_S_OK;
  567. //DBG_ASSERT( (m_dwProtocols & ISRPC_OVER_TCPIP) == 0);
  568. if ( !fDynamic) {
  569. rpcStatus = ( ERROR_CALL_NOT_IMPLEMENTED);
  570. } else {
  571. rpcStatus = ( ISRPC::DynamicBindOverTcp());
  572. }
  573. if ( rpcStatus == RPC_S_OK) {
  574. m_dwProtocols |= ISRPC_OVER_TCPIP;
  575. }
  576. #if 0
  577. IF_DEBUG( DLL_RPC) {
  578. DBGPRINTF(( DBG_CONTEXT, "(%08x)::BindOverTcp(%s) returns %d\n",
  579. this, m_pszServiceName, rpcStatus));
  580. }
  581. #endif
  582. return ( rpcStatus);
  583. } // ISRPC::BindOverTcpIp()
  584. #ifdef CHICAGO
  585. DWORD
  586. ISRPC::BindOverNetBios(IN BOOL fDynamic)
  587. {
  588. DWORD rpcStatus = RPC_S_OK;
  589. //DBG_ASSERT( (m_dwProtocols & ISRPC_OVER_NB) == 0);
  590. if ( !fDynamic) {
  591. return ( ERROR_CALL_NOT_IMPLEMENTED);
  592. }
  593. // We will use Dynamic endpoint for the NetBios binding.
  594. rpcStatus =
  595. RpcServerUseProtseqW(
  596. L"ncacn_nb_ipx", // protocol string.
  597. ISRPC_PROTSEQ_MAX_REQS, //max concurrent calls
  598. &sm_sid[ACL_INDEX_ALLOW_ADMIN] ); // security
  599. rpcStatus =
  600. RpcServerUseProtseqW(
  601. L"ncacn_nb_tcp", // protocol string.
  602. ISRPC_PROTSEQ_MAX_REQS, //max concurrent calls
  603. &sm_sid[ACL_INDEX_ALLOW_ADMIN] ); // security
  604. switch (rpcStatus) {
  605. case RPC_S_OK:
  606. //
  607. // set the protocol bit.
  608. //
  609. m_dwProtocols |= ISRPC_OVER_NB;
  610. break;
  611. case RPC_S_DUPLICATE_ENDPOINT:
  612. //DBGPRINTF(( DBG_CONTEXT,
  613. // "(%08x) ncacn_nb is already added for %s\n",
  614. // this,
  615. // m_pszServiceName));
  616. rpcStatus = RPC_S_OK;
  617. break;
  618. case RPC_S_PROTSEQ_NOT_SUPPORTED:
  619. case RPC_S_CANT_CREATE_ENDPOINT:
  620. //DBGPRINTF(( DBG_CONTEXT,
  621. // "(%08x) ncacn_nb is not supported for %s (%ld).\n",
  622. // this, m_pszServiceName, rpcStatus ));
  623. rpcStatus = RPC_S_OK;
  624. break;
  625. default:
  626. break;
  627. } // switch()
  628. //
  629. // if the security support provider is not enabled, do so.
  630. //
  631. if( rpcStatus == RPC_S_OK && !IsSecurityEnabled() ) {
  632. rpcStatus = AddSecurity();
  633. }
  634. #if 0
  635. IF_DEBUG( DLL_RPC) {
  636. DBGPRINTF(( DBG_CONTEXT, "(%08x)::BindOverNetBios(%s) returns %d\n",
  637. this, m_pszServiceName, rpcStatus));
  638. }
  639. #endif
  640. return ( rpcStatus);
  641. } // ISRPC::BindOverNetBios()
  642. #endif // CHICAGO
  643. DWORD
  644. ISRPC::BindOverNamedPipe(IN BOOL fDynamic)
  645. {
  646. DWORD rpcStatus = RPC_S_OK;
  647. //DBG_ASSERT( (m_dwProtocols & ISRPC_OVER_NP) == 0);
  648. //
  649. // On Named Pipe, we support only static bindings. No dynamic Binding.
  650. //
  651. if ( fDynamic) {
  652. return ( ERROR_CALL_NOT_IMPLEMENTED);
  653. }
  654. if( (m_dwProtocols & ISRPC_OVER_NP) == 0 ) {
  655. WCHAR rgchNp[1024];
  656. wsprintfW( rgchNp,
  657. #ifdef UNICODE
  658. L"%ws%s"
  659. #else
  660. L"%ws%S"
  661. #endif // UNICODE
  662. ,
  663. ISRPC_NAMED_PIPE_PREFIX_W,
  664. m_pszServiceName);
  665. //
  666. // Establish a static Named pipe binding.
  667. //
  668. rpcStatus =
  669. RpcServerUseProtseqEpW(
  670. L"ncacn_np", // protocol string.
  671. ISRPC_PROTSEQ_MAX_REQS, //max concurrent calls
  672. rgchNp, // end point!
  673. &sm_sid[ACL_INDEX_ALLOW_ADMIN] ); // security
  674. switch (rpcStatus) {
  675. case RPC_S_OK:
  676. //
  677. // set the protocol bit.
  678. //
  679. m_dwProtocols |= ISRPC_OVER_NP;
  680. break;
  681. case RPC_S_DUPLICATE_ENDPOINT:
  682. //
  683. // Ignore the duplicate end point error
  684. //
  685. //DBGPRINTF(( DBG_CONTEXT,
  686. // "(%08x) ncacn_np is already added for %s\n",
  687. // this,
  688. // m_pszServiceName));
  689. m_dwProtocols |= ISRPC_OVER_NP;
  690. rpcStatus = RPC_S_OK;
  691. break;
  692. case RPC_S_PROTSEQ_NOT_SUPPORTED:
  693. case RPC_S_CANT_CREATE_ENDPOINT:
  694. //DBGPRINTF(( DBG_CONTEXT,
  695. // "(%08x) ncacn_np is not supported for %s (%ld).\n",
  696. // this, m_pszServiceName, rpcStatus ));
  697. rpcStatus = RPC_S_OK;
  698. break;
  699. default:
  700. break;
  701. } // switch()
  702. }
  703. return ( rpcStatus);
  704. } // ISRPC::BindOverNamedPipe()
  705. DWORD
  706. ISRPC::BindOverLpc(IN BOOL fDynamic)
  707. {
  708. DWORD rpcStatus = RPC_S_OK;
  709. //DBG_ASSERT( (m_dwProtocols & ISRPC_OVER_LPC) == 0);
  710. //
  711. // On LPC, we support only static bindings. No dynamic Binding.
  712. //
  713. if ( fDynamic) {
  714. return ( ERROR_CALL_NOT_IMPLEMENTED);
  715. }
  716. if( (m_dwProtocols & ISRPC_OVER_LPC) == 0 ) {
  717. WCHAR rgchLpc[1024];
  718. // LPC Endpoint string is: <InterfaceName>_LPC
  719. wsprintfW( rgchLpc,
  720. #ifdef UNICODE
  721. L"%s_%ws"
  722. #else
  723. L"%S_%ws"
  724. #endif // UNICODE
  725. ,
  726. m_pszServiceName,
  727. ISRPC_LPC_NAME_SUFFIX_W);
  728. //
  729. // Establish a static Lpc binding.
  730. //
  731. rpcStatus =
  732. RpcServerUseProtseqEpW(
  733. L"ncalrpc", // protocol string.
  734. ISRPC_PROTSEQ_MAX_REQS, //max concurrent calls
  735. rgchLpc, // end point!
  736. &sm_sid[ACL_INDEX_ALLOW_ALL] ); // security
  737. switch (rpcStatus) {
  738. case RPC_S_OK:
  739. //
  740. // set the protocol bit.
  741. //
  742. m_dwProtocols |= ISRPC_OVER_LPC;
  743. break;
  744. case RPC_S_DUPLICATE_ENDPOINT:
  745. //
  746. // Ignore the duplicate end point error
  747. //
  748. //DBGPRINTF(( DBG_CONTEXT,
  749. // "(%08x) ncalrpc is already added for %s\n",
  750. // this,
  751. // m_pszServiceName));
  752. m_dwProtocols |= ISRPC_OVER_LPC;
  753. rpcStatus = RPC_S_OK;
  754. break;
  755. case RPC_S_PROTSEQ_NOT_SUPPORTED:
  756. case RPC_S_CANT_CREATE_ENDPOINT:
  757. //DBGPRINTF(( DBG_CONTEXT,
  758. // "(%08x) ncalrpc is not supported for %s (%ld).\n",
  759. // this, m_pszServiceName, rpcStatus ));
  760. rpcStatus = RPC_S_OK;
  761. break;
  762. default:
  763. break;
  764. } // switch()
  765. }
  766. return ( rpcStatus);
  767. } // ISRPC::BindOverLpc()
  768. DWORD
  769. ISRPC::BindOverSpx(IN BOOL fDynamic)
  770. {
  771. DWORD rpcStatus = RPC_S_OK;
  772. //DBG_ASSERT( (m_dwProtocols & ISRPC_OVER_SPX) == 0);
  773. if ( !fDynamic) {
  774. rpcStatus = ( ERROR_CALL_NOT_IMPLEMENTED);
  775. } else {
  776. rpcStatus = ISRPC::DynamicBindOverSpx();
  777. }
  778. if ( rpcStatus == RPC_S_OK) {
  779. m_dwProtocols |= ISRPC_OVER_SPX;
  780. }
  781. #if 0
  782. IF_DEBUG( DLL_RPC) {
  783. DBGPRINTF(( DBG_CONTEXT, "(%08x)::BindOverSpx(%s) returns %d\n",
  784. this, m_pszServiceName, rpcStatus));
  785. }
  786. #endif
  787. return ( rpcStatus);
  788. } // ISRPC::BindOverSpx()
  789. # if DBG
  790. VOID
  791. ISRPC::Print(VOID) const
  792. {
  793. #if 0
  794. DBGPRINTF(( DBG_CONTEXT,
  795. " ISRPC(%08x). SvcName=%s\n"
  796. " Protocols = %d.\n"
  797. " RPC Interface = %08x. Binding Vector = %08x\n"
  798. " InterfaceAdded = %d.\n"
  799. " EpRegistered = %d. ServerStarted = %d.\n"
  800. ,
  801. this, m_pszServiceName,
  802. m_dwProtocols,
  803. m_hRpcInterface, m_pBindingVector,
  804. m_fInterfaceAdded,
  805. m_fEpRegistered, m_fServerStarted
  806. ));
  807. #endif
  808. } // ISRPC::Print()
  809. # endif // DBG
  810. /******************************
  811. * STATIC Member Definitions
  812. ******************************/
  813. DWORD ISRPC::sm_dwProtocols = 0;
  814. SECURITY_DESCRIPTOR ISRPC::sm_sid[2];
  815. BOOL ISRPC::sm_fSecurityEnabled = FALSE;
  816. DWORD
  817. ISRPC::Initialize(VOID)
  818. {
  819. sm_dwProtocols = 0;
  820. return SetSecurityDescriptor();
  821. } // ISRPC::Initialize()
  822. DWORD
  823. ISRPC::Cleanup(VOID)
  824. {
  825. //
  826. // Free up the security descriptor
  827. //
  828. if (sm_sid[0].Dacl)
  829. delete [] (BYTE *) (sm_sid[0].Dacl);
  830. if (sm_sid[1].Dacl)
  831. delete [] (BYTE *) (sm_sid[1].Dacl);
  832. ZeroMemory( (PVOID) &sm_sid, sizeof(sm_sid));
  833. //
  834. // For now nothing to do. Just a place holder.
  835. //
  836. return ( NO_ERROR);
  837. } // ISRPC::Cleanup()
  838. DWORD
  839. ISRPC::DynamicBindOverTcp(VOID)
  840. /*++
  841. This static function (ISRPC member) establishes a dynamic endpoing
  842. RPC binding over TCP/IP, using a run-time library call to RPC.
  843. RPC run-time library allows one to create as many dynamic end points
  844. as one wishes. So we maintain external state and control the number
  845. of end points created to 1.
  846. Arguments:
  847. None
  848. Returns:
  849. RPC status - RPC_S_OK for success.
  850. --*/
  851. {
  852. DWORD rpcStatus = RPC_S_OK;
  853. if( (sm_dwProtocols & ISRPC_OVER_TCPIP) == 0 ) {
  854. //
  855. // Not already present. Add dynamic endpoint over TCP/IP
  856. //
  857. rpcStatus =
  858. RpcServerUseProtseqW(
  859. L"ncacn_ip_tcp", // protocol string.
  860. ISRPC_PROTSEQ_MAX_REQS, //max concurrent calls
  861. &sm_sid[ACL_INDEX_ALLOW_ADMIN] ); // security
  862. switch (rpcStatus) {
  863. case RPC_S_OK:
  864. //
  865. // set the protocol bit.
  866. //
  867. sm_dwProtocols |= ISRPC_OVER_TCPIP;
  868. break;
  869. case RPC_S_DUPLICATE_ENDPOINT:
  870. //DBGPRINTF(( DBG_CONTEXT,
  871. // "ncacn_ip_tcp is already added.\n"));
  872. sm_dwProtocols |= ISRPC_OVER_TCPIP;
  873. rpcStatus = RPC_S_OK;
  874. break;
  875. case RPC_S_PROTSEQ_NOT_SUPPORTED:
  876. case RPC_S_CANT_CREATE_ENDPOINT:
  877. //DBGPRINTF(( DBG_CONTEXT,
  878. // "ncacn_ip_tcp is not supported. Error = %ld\n",
  879. // rpcStatus));
  880. break;
  881. default:
  882. break;
  883. } // switch()
  884. //
  885. // if the security support provider is not enabled, do so.
  886. //
  887. if( rpcStatus == RPC_S_OK && !IsSecurityEnabled() ) {
  888. rpcStatus = AddSecurity();
  889. }
  890. }
  891. #if 0
  892. IF_DEBUG( DLL_RPC) {
  893. DBGPRINTF(( DBG_CONTEXT, "DynamicBindOverTcp() returns %d\n",
  894. rpcStatus));
  895. }
  896. #endif
  897. return ( rpcStatus);
  898. } // ISRPC::DynamicBindOverTcp()
  899. DWORD
  900. ISRPC::DynamicBindOverSpx(VOID)
  901. /*++
  902. This static function (ISRPC member) establishes a dynamic endpoing
  903. RPC binding over SPX, using a run-time library call to RPC.
  904. RPC run-time library allows one to create as many dynamic end points
  905. as one wishes. So we maintain external state and control the number
  906. of end points created to 1.
  907. Arguments:
  908. None
  909. Returns:
  910. RPC status - RPC_S_OK for success.
  911. --*/
  912. {
  913. DWORD rpcStatus = RPC_S_OK;
  914. if( (sm_dwProtocols & ISRPC_OVER_SPX) == 0 ) {
  915. // Use dynamic end point for the server.
  916. rpcStatus =
  917. RpcServerUseProtseqW(
  918. L"ncacn_spx", // protocol string.
  919. ISRPC_PROTSEQ_MAX_REQS, //max concurrent calls
  920. &sm_sid[ACL_INDEX_ALLOW_ADMIN] ); // security
  921. switch (rpcStatus) {
  922. case RPC_S_OK:
  923. //
  924. // set the protocol bit.
  925. //
  926. sm_dwProtocols |= ISRPC_OVER_SPX;
  927. break;
  928. case RPC_S_DUPLICATE_ENDPOINT:
  929. //DBGPRINTF(( DBG_CONTEXT,
  930. // "ncacn_spx is already added.\n"
  931. // ));
  932. sm_dwProtocols |= ISRPC_OVER_SPX;
  933. rpcStatus = RPC_S_OK;
  934. break;
  935. case RPC_S_PROTSEQ_NOT_SUPPORTED:
  936. case RPC_S_CANT_CREATE_ENDPOINT:
  937. //DBGPRINTF(( DBG_CONTEXT,
  938. // "ncacn_spx is not supported. Error (%ld).\n",
  939. // rpcStatus ));
  940. break;
  941. default:
  942. break;
  943. } // switch()
  944. //
  945. // if the security support provider is not enabled, do so.
  946. //
  947. if( rpcStatus == RPC_S_OK && !IsSecurityEnabled()) {
  948. rpcStatus = AddSecurity();
  949. }
  950. }
  951. #if 0
  952. IF_DEBUG( DLL_RPC) {
  953. DBGPRINTF(( DBG_CONTEXT, "DynamicBindOverSpx() returns %d\n",
  954. rpcStatus));
  955. }
  956. #endif
  957. return ( rpcStatus);
  958. } // ISRPC::DynamicBindOverSpx()
  959. //----------------------------------------------------------------
  960. // Description:
  961. // Initializes a SECURITY_DESCRIPTOR to allow access to all
  962. // ("World").
  963. // Arguments:
  964. // pSd Pass in a pointer to the SECURITY_DESCRIPTOR
  965. // bAdminOnly: TRUE: allow admin, FALSE: allow everyone
  966. // Returns:
  967. // ERROR_SUCCESS if initialization proceeded successfully.
  968. // Win32 error if some failure occurred.
  969. //----------------------------------------------------------------
  970. DWORD InitializeSmtpSecurityDescriptor (PSECURITY_DESCRIPTOR pSd, BOOL bAdminOnly)
  971. {
  972. DWORD dwErr = ERROR_SUCCESS;
  973. PSID pSidWorld = NULL;
  974. PSID pSidAdmins = NULL;
  975. PSID pSid2Allow = NULL;
  976. SID_IDENTIFIER_AUTHORITY sidWorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
  977. SID_IDENTIFIER_AUTHORITY sidNtAuthority = SECURITY_NT_AUTHORITY;
  978. ACL *pAcl = NULL;
  979. DWORD dwAclSize = 0;
  980. _ASSERT (pSd);
  981. if (!AllocateAndInitializeSid (
  982. &sidWorldAuthority,
  983. 1,
  984. SECURITY_WORLD_RID,
  985. 0,0,0,0,0,0,0,
  986. &pSidWorld)){
  987. dwErr = GetLastError ();
  988. goto Exit;
  989. }
  990. if ( !bAdminOnly ) pSid2Allow = pSidWorld;
  991. else
  992. {
  993. if (!AllocateAndInitializeSid( &sidNtAuthority,
  994. 2,
  995. SECURITY_BUILTIN_DOMAIN_RID,
  996. DOMAIN_ALIAS_RID_ADMINS,
  997. 0,0,0,0,0,0,
  998. &pSidAdmins ) )
  999. {
  1000. dwErr = GetLastError ();
  1001. goto Exit;
  1002. }
  1003. pSid2Allow = pSidAdmins;
  1004. }
  1005. dwAclSize = sizeof (ACL) + // Length of ACL
  1006. (sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD)) + // Length of ACE #1
  1007. GetLengthSid (pSid2Allow) + // Length of SID for ACE #1
  1008. (sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD)) + // Length of ACE #2
  1009. GetLengthSid (pSidWorld); // Length of SID for ACE #2
  1010. pAcl = (PACL) new BYTE [dwAclSize];
  1011. if (!pAcl) {
  1012. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1013. goto Exit;
  1014. }
  1015. if (!InitializeAcl (
  1016. pAcl,
  1017. dwAclSize,
  1018. ACL_REVISION)) {
  1019. dwErr = GetLastError ();
  1020. goto Exit;
  1021. }
  1022. if (!AddAccessDeniedAce (pAcl, ACL_REVISION, WRITE_DAC | WRITE_OWNER, pSidWorld) ||
  1023. !AddAccessAllowedAce (pAcl, ACL_REVISION, GENERIC_ALL, pSid2Allow)) {
  1024. dwErr = GetLastError ();
  1025. goto Exit;
  1026. }
  1027. if (!SetSecurityDescriptorDacl (pSd, TRUE, pAcl, FALSE)) {
  1028. dwErr = GetLastError ();
  1029. goto Exit;
  1030. }
  1031. pAcl = NULL; // Now pAcl is set on pSd... and will be deleted as pSd->Dacl
  1032. Exit:
  1033. if (pSidWorld)
  1034. FreeSid (pSidWorld);
  1035. if (pSidAdmins)
  1036. FreeSid (pSidAdmins);
  1037. if (pAcl)
  1038. delete [] pAcl;
  1039. return dwErr;
  1040. }
  1041. DWORD
  1042. ISRPC::SetSecurityDescriptor( VOID)
  1043. /*++
  1044. Routine Description:
  1045. This member function builds the security descriptor used by RPC module.
  1046. Arguments:
  1047. None.
  1048. Return Value:
  1049. Windows error code.
  1050. --*/
  1051. {
  1052. DWORD dwError = NO_ERROR;
  1053. if (!InitializeSecurityDescriptor (&sm_sid[0], SECURITY_DESCRIPTOR_REVISION) ||
  1054. !InitializeSecurityDescriptor (&sm_sid[1], SECURITY_DESCRIPTOR_REVISION)) {
  1055. // return directly, don't go to Exit and try to free the Dacl
  1056. return GetLastError();
  1057. }
  1058. //
  1059. // build a security descriptor that will grant everyone
  1060. // all access to the object --- this is done by setting a
  1061. // "World" DACL in the SECURITY_DESCRIPTOR.
  1062. //
  1063. dwError = InitializeSmtpSecurityDescriptor(&sm_sid[ACL_INDEX_ALLOW_ALL], false);
  1064. if (dwError!=ERROR_SUCCESS) goto Exit;
  1065. dwError = InitializeSmtpSecurityDescriptor(&sm_sid[ACL_INDEX_ALLOW_ADMIN], true);
  1066. if (dwError!=ERROR_SUCCESS) goto Exit;
  1067. Exit:
  1068. if (dwError != ERROR_SUCCESS) {
  1069. //
  1070. // free up security discriptor memory and set it to NULL.
  1071. //
  1072. if (sm_sid[0].Dacl)
  1073. delete [] (BYTE*) sm_sid[0].Dacl;
  1074. if (sm_sid[1].Dacl)
  1075. delete [] (BYTE*) sm_sid[1].Dacl;
  1076. memset( (PVOID ) &sm_sid, 0, sizeof(sm_sid));
  1077. }
  1078. return( dwError );
  1079. } // ISRPC::SetSecurityDescriptor()
  1080. DWORD
  1081. ISRPC::AddSecurity(
  1082. VOID
  1083. )
  1084. /*++
  1085. Routine Description:
  1086. This member function adds security support provider over RPC.
  1087. Arguments:
  1088. None.
  1089. Return Value:
  1090. Windows error code.
  1091. --*/
  1092. {
  1093. DWORD rpcStatus;
  1094. //
  1095. // Register for authentication using WinNT.
  1096. //
  1097. rpcStatus = RpcServerRegisterAuthInfo(
  1098. (unsigned char * ) NULL, // app name to security provider
  1099. RPC_C_AUTHN_WINNT, // Auth package ID.
  1100. NULL, // RPC_C_AUTHN_WINNT ==> NULL
  1101. NULL // args ptr for authn function.
  1102. );
  1103. if ( rpcStatus == RPC_S_OK) {
  1104. sm_fSecurityEnabled = TRUE;
  1105. }
  1106. #if 0
  1107. IF_DEBUG( DLL_RPC) {
  1108. DBGPRINTF(( DBG_CONTEXT, "AddSecurity() returns Error %u\n",
  1109. rpcStatus));
  1110. }
  1111. #endif
  1112. return (rpcStatus);
  1113. } // ISRPC::AddSecurity()