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.

2271 lines
63 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. nptrans.cxx
  5. Abstract:
  6. Named pipes specific transport interface layer.
  7. Author:
  8. Mario Goertzel [MarioGo]
  9. Revision History:
  10. MarioGo 3/18/1996 Bits 'n pieces
  11. MarioGo 10/30/1996 ASync RPC + client side
  12. --*/
  13. #include <precomp.hxx>
  14. #include <rpcqos.h> // mtrt for I_RpcParseSecurity
  15. //
  16. // Support functions not exported to the runtime
  17. //
  18. // Hard coded world (aka EveryOne) SID
  19. const SID World = { 1, 1, { 0, 0, 0, 0, 0, 1}, 0};
  20. // Hard coded world (aka EveryOne) SID
  21. const SID AnonymousLogonSid = { 1, 1, SECURITY_NT_AUTHORITY, SECURITY_ANONYMOUS_LOGON_RID};
  22. RPC_STATUS
  23. NMP_SetSecurity(
  24. IN NMP_ADDRESS *pAddress,
  25. IN PSECURITY_DESCRIPTOR SecurityDescriptor
  26. )
  27. /*++
  28. Routine Description:
  29. If the caller supplies an SD this validates and makes a copy of the
  30. security descriptor. Otherwise is generates a good default SD.
  31. Arguments:
  32. ThisAddress - Supplies the address which will own the security descriptor.
  33. SecurityDescriptor - Supplies the security descriptor to be copied.
  34. Return Value:
  35. RPC_S_OK - Everyone is happy; we successfully duplicated the security
  36. descriptor.
  37. RPC_S_INVALID_SECURITY_DESC - The supplied security descriptor is invalid.
  38. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to duplicate the
  39. security descriptor.
  40. --*/
  41. {
  42. BOOL b;
  43. SECURITY_DESCRIPTOR_CONTROL Control;
  44. DWORD Revision;
  45. DWORD BufferLength;
  46. if ( SecurityDescriptor == 0 )
  47. {
  48. // By default, RPC will create a SD which only allows the process owner to
  49. // create more pipe instances. This prevents other users from stealing
  50. // the pipe.
  51. pAddress->SecurityDescriptor = new SECURITY_DESCRIPTOR;
  52. if ( pAddress->SecurityDescriptor == 0
  53. || !InitializeSecurityDescriptor(pAddress->SecurityDescriptor,
  54. SECURITY_DESCRIPTOR_REVISION) )
  55. {
  56. return(RPC_S_OUT_OF_MEMORY);
  57. }
  58. // Open our thread token and pull out the owner SID. This is SID will be
  59. // added to the DACL below.
  60. ASSERT(GetSidLengthRequired(SID_MAX_SUB_AUTHORITIES) <= 0x44);
  61. DWORD cTokenOwner = sizeof(TOKEN_OWNER) + 0x44;
  62. PVOID buffer[sizeof(TOKEN_OWNER) + 0x44];
  63. PTOKEN_OWNER pTokenOwner = (PTOKEN_OWNER)buffer;
  64. HANDLE hToken;
  65. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken))
  66. {
  67. return(RPC_S_OUT_OF_RESOURCES);
  68. }
  69. b = GetTokenInformation(hToken, TokenOwner, pTokenOwner, cTokenOwner, &cTokenOwner);
  70. ASSERT(cTokenOwner <= sizeof(buffer));
  71. CloseHandle(hToken);
  72. if (!b)
  73. {
  74. return(RPC_S_OUT_OF_RESOURCES);
  75. }
  76. // Now allocate the ACL and add the owner and EveryOne (world) ACEs and Anonymous Logon ACESs
  77. DWORD size = 3*sizeof(ACCESS_ALLOWED_ACE) + sizeof(World) + sizeof(AnonymousLogonSid) + 0x44;
  78. PACL pdacl = new(size) ACL;
  79. ULONG ldacl = size + sizeof(ACL);
  80. if (NULL == pdacl)
  81. {
  82. return(RPC_S_OUT_OF_MEMORY);
  83. }
  84. ASSERT(IsValidSid((PVOID)&World));
  85. ASSERT(IsValidSid((PVOID)&AnonymousLogonSid));
  86. InitializeAcl(pdacl, ldacl, ACL_REVISION);
  87. if (!AddAccessAllowedAce(pdacl, ACL_REVISION,
  88. (FILE_GENERIC_READ|FILE_GENERIC_WRITE)&(~FILE_CREATE_PIPE_INSTANCE),
  89. (PVOID)&World))
  90. {
  91. ASSERT(0);
  92. return(RPC_S_OUT_OF_RESOURCES);
  93. }
  94. if (!AddAccessAllowedAce(pdacl, ACL_REVISION,
  95. (FILE_GENERIC_READ|FILE_GENERIC_WRITE)&(~FILE_CREATE_PIPE_INSTANCE),
  96. (PVOID)&AnonymousLogonSid ))
  97. {
  98. ASSERT(0);
  99. return(RPC_S_OUT_OF_RESOURCES);
  100. }
  101. if (!AddAccessAllowedAce(pdacl, ACL_REVISION, FILE_ALL_ACCESS, pTokenOwner->Owner))
  102. {
  103. ASSERT(0);
  104. return(RPC_S_OUT_OF_RESOURCES);
  105. }
  106. if (!SetSecurityDescriptorDacl(pAddress->SecurityDescriptor, TRUE, pdacl, FALSE))
  107. {
  108. return(RPC_S_OUT_OF_RESOURCES);
  109. }
  110. return(RPC_S_OK);
  111. }
  112. // Caller supplied SecurityDescriptor. Make sure it is valid and, if needed, make a
  113. // self relative copy.
  114. if ( IsValidSecurityDescriptor(SecurityDescriptor) == FALSE )
  115. {
  116. return(RPC_S_INVALID_SECURITY_DESC);
  117. }
  118. if (FALSE == GetSecurityDescriptorControl(SecurityDescriptor, &Control, &Revision))
  119. {
  120. return(RPC_S_INVALID_SECURITY_DESC);
  121. }
  122. if (Control & SE_SELF_RELATIVE)
  123. {
  124. // Already self-relative, just copy it.
  125. BufferLength = GetSecurityDescriptorLength(SecurityDescriptor);
  126. ASSERT(BufferLength >= sizeof(SECURITY_DESCRIPTOR));
  127. pAddress->SecurityDescriptor = new(BufferLength
  128. - sizeof(SECURITY_DESCRIPTOR))
  129. SECURITY_DESCRIPTOR;
  130. if (pAddress->SecurityDescriptor == 0 )
  131. {
  132. return(RPC_S_OUT_OF_MEMORY);
  133. }
  134. memcpy(pAddress->SecurityDescriptor, SecurityDescriptor, BufferLength);
  135. return(RPC_S_OK);
  136. }
  137. // Make self-relative and copy it.
  138. BufferLength = 0;
  139. b = MakeSelfRelativeSD(SecurityDescriptor, 0, &BufferLength);
  140. ASSERT(b == FALSE);
  141. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  142. {
  143. return(RPC_S_INVALID_SECURITY_DESC);
  144. }
  145. //
  146. // self-relative SD's can be of different size than the original SD.
  147. //
  148. ASSERT(BufferLength >= sizeof(SECURITY_DESCRIPTOR_RELATIVE));
  149. pAddress->SecurityDescriptor = new(BufferLength
  150. - sizeof(SECURITY_DESCRIPTOR_RELATIVE))
  151. SECURITY_DESCRIPTOR;
  152. if (pAddress->SecurityDescriptor == 0)
  153. {
  154. return(RPC_S_OUT_OF_MEMORY);
  155. }
  156. b = MakeSelfRelativeSD(SecurityDescriptor,
  157. pAddress->SecurityDescriptor,
  158. &BufferLength);
  159. if (b == FALSE)
  160. {
  161. ASSERT(GetLastError() != ERROR_INSUFFICIENT_BUFFER);
  162. delete pAddress->SecurityDescriptor;
  163. return(RPC_S_OUT_OF_MEMORY);
  164. }
  165. return(RPC_S_OK);
  166. }
  167. //
  168. // Functions exported to the RPC runtime.
  169. //
  170. RPC_STATUS RPC_ENTRY
  171. NMP_AbortHelper(
  172. IN RPC_TRANSPORT_CONNECTION Connection,
  173. IN BOOL fDontFlush
  174. )
  175. /*++
  176. Routine Description:
  177. Closes a connection, will be called only before NMP_Close() and
  178. maybe called by several threads at once. It must also handle
  179. the case where another thread is about to start IO on the connection.
  180. Arguments:
  181. Connection - pointer to a server connection object to abort.
  182. Return Value:
  183. RPC_S_OK
  184. --*/
  185. {
  186. HANDLE h;
  187. BOOL b;
  188. PNMP_CONNECTION p = (PNMP_CONNECTION)Connection;
  189. if (InterlockedIncrement(&p->fAborted) != 1)
  190. {
  191. // Another thread beat us to it. Normal during a call to NMP_Close.
  192. return(RPC_S_OK);
  193. }
  194. I_RpcLogEvent(SU_TRANS_CONN, EV_ABORT, Connection, 0, 0, 1, 2);
  195. // Wait for any threads which are starting IO to do so.
  196. while(p->IsIoStarting())
  197. Sleep(1);
  198. RTL_SOFT_ASSERT(p->fAborted != 0 && p->IsIoStarting() == 0);
  199. if (p->type & SERVER)
  200. {
  201. if (fDontFlush == 0)
  202. {
  203. // This will block until all pending writes on the connection
  204. // have been read. Needed on the server which writes (example: a
  205. // a fault) and closes the connection.
  206. b = FlushFileBuffers(p->Conn.Handle);
  207. //
  208. // the above call can fail if the pipe was disconnected
  209. //
  210. }
  211. // Once a pipe instance has been disconnected, it can be reused
  212. // for a future client connection. Each NMP address keeps a
  213. // small cache of free pipe instances. This is a performance
  214. // optimization.
  215. ASSERT(p->pAddress);
  216. b = DisconnectNamedPipe(p->Conn.Handle);
  217. if (b)
  218. {
  219. // will zero out Conn.Handle if it fits in the cache
  220. p->pAddress->sparePipes.CheckinHandle(&(p->Conn.Handle));
  221. }
  222. // else nothing - code down below will close it
  223. h = p->Conn.Handle;
  224. }
  225. else
  226. {
  227. ASSERT(p->pAddress == 0);
  228. h = p->Conn.Handle;
  229. }
  230. if (h)
  231. {
  232. b = CloseHandle(h);
  233. ASSERT(b);
  234. }
  235. return(RPC_S_OK);
  236. }
  237. RPC_STATUS NMP_CONNECTION::Abort(void)
  238. {
  239. return NMP_AbortHelper(this, 0);
  240. }
  241. RPC_STATUS
  242. RPC_ENTRY
  243. NMP_Close(
  244. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  245. IN BOOL fDontFlush
  246. )
  247. /*++
  248. Routine Description:
  249. Actually cleans up the resources associated with a connection.
  250. This is called exactly once one any connection. It may or
  251. may not have previously been aborted.
  252. Arguments:
  253. ThisConnection - pointer to the connection object to close.
  254. Return Value:
  255. RPC_S_OK
  256. --*/
  257. {
  258. BOOL b;
  259. HANDLE h;
  260. PNMP_CONNECTION p = (PNMP_CONNECTION)ThisConnection;
  261. NMP_AbortHelper(ThisConnection, fDontFlush);
  262. if (p->iLastRead)
  263. {
  264. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  265. DPFLTR_WARNING_LEVEL,
  266. RPCTRANS "Closing connection %p with left over data (%d) %p \n",
  267. p,
  268. p->iLastRead,
  269. p->pReadBuffer));
  270. }
  271. TransConnectionFreePacket(p, p->pReadBuffer);
  272. p->pReadBuffer = 0;
  273. return(RPC_S_OK);
  274. }
  275. void RPC_ENTRY
  276. NMP_ServerAbortListen(
  277. IN RPC_TRANSPORT_ADDRESS Address
  278. )
  279. /*++
  280. Routine Description:
  281. This routine will be called if an error occurs in setting up the
  282. address between the time that SetupWithEndpoint or SetupUnknownEndpoint
  283. successfully completed and before the next call into this loadable
  284. transport module. We need to do any cleanup from Setup*.
  285. Arguments:
  286. pAddress - The address which is being aborted.
  287. Return Value:
  288. None
  289. --*/
  290. {
  291. NMP_ADDRESS *p = (NMP_ADDRESS *)Address;
  292. // p->Endpoint is actually a pointer into p->LocalEndpoint
  293. delete p->SecurityDescriptor;
  294. delete p->LocalEndpoint;
  295. delete p->pAddressVector;
  296. // These are zero except when everything is setup ok.
  297. ASSERT(p->hConnectPipe == 0);
  298. ASSERT(p->sparePipes.IsSecondHandleUsed() == FALSE);
  299. return;
  300. }
  301. RPC_STATUS
  302. NMP_CreatePipeInstance(
  303. NMP_ADDRESS *pAddress
  304. )
  305. /*++
  306. Routine Description:
  307. Wrapper around CreateNamedPipe.
  308. Return Value:
  309. RPC_S_OK - A new pipe instance created.
  310. RPC_P_FOUND_IN_CACHE - Found a pipe instance to recycle.
  311. RPC_S_OUT_OF_MEMORY
  312. RPC_S_INVALID_ENDPOINT_FORMAT
  313. RPC_S_INTERNAL_ERROR
  314. --*/
  315. {
  316. RPC_STATUS status;
  317. SECURITY_ATTRIBUTES sa;
  318. ASSERT(pAddress->hConnectPipe == 0);
  319. sa.lpSecurityDescriptor = pAddress->SecurityDescriptor;
  320. sa.bInheritHandle = FALSE;
  321. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  322. // See if there are any cached pipe instances to reuse.
  323. pAddress->hConnectPipe = pAddress->sparePipes.CheckOutHandle();
  324. if (pAddress->hConnectPipe)
  325. return(RPC_P_FOUND_IN_CACHE);
  326. // The cache is empty, create a new pipe instance
  327. pAddress->hConnectPipe = CreateNamedPipeW(pAddress->LocalEndpoint,
  328. PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
  329. PIPE_WAIT | PIPE_READMODE_MESSAGE | PIPE_TYPE_MESSAGE,
  330. PIPE_UNLIMITED_INSTANCES,
  331. 2048,
  332. 2048,
  333. NMPWAIT_USE_DEFAULT_WAIT,
  334. &sa);
  335. if (pAddress->hConnectPipe != INVALID_HANDLE_VALUE)
  336. {
  337. return(RPC_S_OK);
  338. }
  339. pAddress->hConnectPipe = 0;
  340. switch(GetLastError())
  341. {
  342. case ERROR_NOT_ENOUGH_MEMORY:
  343. case ERROR_NOT_ENOUGH_QUOTA:
  344. case ERROR_NO_SYSTEM_RESOURCES:
  345. {
  346. status = RPC_S_OUT_OF_MEMORY;
  347. break;
  348. }
  349. case ERROR_FILE_NOT_FOUND:
  350. case ERROR_INVALID_NAME:
  351. case ERROR_PATH_NOT_FOUND:
  352. {
  353. status = RPC_S_INVALID_ENDPOINT_FORMAT;
  354. break;
  355. }
  356. case ERROR_ACCESS_DENIED:
  357. {
  358. // An odd mapping, but this error means the pipe already exists
  359. // which is what this error means.
  360. status = RPC_S_DUPLICATE_ENDPOINT;
  361. break;
  362. }
  363. default:
  364. {
  365. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  366. DPFLTR_WARNING_LEVEL,
  367. RPCTRANS "CreateNamedPipe failed: %d\n",
  368. GetLastError() ));
  369. ASSERT(0);
  370. status = RPC_S_INTERNAL_ERROR;
  371. }
  372. }
  373. return(status);
  374. }
  375. inline
  376. RPC_STATUS
  377. NMP_ConnectNamedPipe(
  378. NMP_ADDRESS *pAddress
  379. )
  380. /*++
  381. Routine Description:
  382. Inline wrapper for ConnectNamedPipe.
  383. Arguments:
  384. pAddress - The address to use to connect.
  385. Return Value:
  386. RPC_S_OK
  387. ConnectNamedPipe() error
  388. --*/
  389. {
  390. RPC_STATUS status;
  391. BOOL b = ConnectNamedPipe(pAddress->hConnectPipe,
  392. &pAddress->Listen.ol);
  393. if (!b)
  394. {
  395. status = GetLastError();
  396. switch(status)
  397. {
  398. case ERROR_NOT_ENOUGH_MEMORY:
  399. case ERROR_IO_PENDING:
  400. case ERROR_PIPE_CONNECTED:
  401. case ERROR_NO_SYSTEM_RESOURCES:
  402. {
  403. break;
  404. }
  405. case ERROR_NO_DATA:
  406. {
  407. b = CloseHandle(pAddress->hConnectPipe);
  408. ASSERT(b);
  409. pAddress->hConnectPipe = 0;
  410. break;
  411. }
  412. default:
  413. {
  414. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  415. DPFLTR_WARNING_LEVEL,
  416. RPCTRANS "ConnectNamedPipe failed: %d\n",
  417. status));
  418. ASSERT(0);
  419. }
  420. }
  421. }
  422. else
  423. {
  424. status = RPC_S_OK;
  425. }
  426. return(status);
  427. }
  428. void
  429. NMP_SubmitConnect(
  430. IN BASE_ADDRESS *Address
  431. )
  432. /*++
  433. Routine Description:
  434. Called on an address without a pending connect pipe or on an address
  435. who previous connect pipe has been aborted.
  436. Arguments:
  437. Address - The address to submit the connect on.
  438. Return Value:
  439. None
  440. --*/
  441. {
  442. RPC_STATUS status;
  443. NMP_ADDRESS *pAddress = (NMP_ADDRESS *)Address;
  444. BOOL b;
  445. //
  446. // We may or may not need to create a new instance. If a previous
  447. // ConnectNamedPipe was aborted then the existing instance is ok.
  448. //
  449. if (pAddress->hConnectPipe == 0)
  450. {
  451. status = NMP_CreatePipeInstance(pAddress);
  452. if (status == RPC_S_OK)
  453. {
  454. status = COMMON_PrepareNewHandle(pAddress->hConnectPipe);
  455. }
  456. else
  457. {
  458. if (status == RPC_P_FOUND_IN_CACHE)
  459. {
  460. status = RPC_S_OK;
  461. }
  462. }
  463. if (status != RPC_S_OK)
  464. {
  465. if (pAddress->hConnectPipe)
  466. {
  467. b = CloseHandle(pAddress->hConnectPipe);
  468. ASSERT(b);
  469. pAddress->hConnectPipe = 0;
  470. }
  471. COMMON_AddressManager(pAddress);
  472. return;
  473. }
  474. }
  475. status = NMP_ConnectNamedPipe(pAddress);
  476. if (status == ERROR_PIPE_CONNECTED)
  477. {
  478. // When a client connects here means that there will not be an IO
  479. // completion notification for this connection. We could call
  480. // NMP_NewConnection here but that makes error handling hard. We'll
  481. // just post the notification directly.
  482. b = PostQueuedCompletionStatus(RpcCompletionPort,
  483. 0,
  484. TRANSPORT_POSTED_KEY,
  485. &pAddress->Listen.ol);
  486. if (!b)
  487. {
  488. // Give up on this connection.
  489. b = CloseHandle(pAddress->hConnectPipe);
  490. ASSERT(b);
  491. pAddress->hConnectPipe = 0;
  492. COMMON_AddressManager(pAddress);
  493. }
  494. return;
  495. }
  496. if (status != ERROR_IO_PENDING)
  497. {
  498. COMMON_AddressManager(pAddress);
  499. }
  500. return;
  501. }
  502. RPC_STATUS
  503. NMP_NewConnection(
  504. IN PADDRESS Address,
  505. OUT PCONNECTION *ppConnection
  506. )
  507. /*++
  508. Routine Description:
  509. Called when an ConnectNamedPipe completes on the main recv any thread.
  510. Can't fail after it calls I_RpcTransServerNewConnection().
  511. Arguments:
  512. pAddress - The address used as context in a previous AcceptEx.
  513. ppConnection - A place to store the new pConnection. Used
  514. when a connection been created and then a failure occurs.
  515. Return Value:
  516. RPC_S_OK
  517. RPC_S_OUT_OF_RESOURCES
  518. RPC_S_OUT_OF_MEMORY
  519. --*/
  520. {
  521. RPC_STATUS status;
  522. NMP_ADDRESS *pAddress = (NMP_ADDRESS *)Address;
  523. HANDLE hClient = pAddress->hConnectPipe;
  524. NMP_CONNECTION *pConnection;
  525. // First, submit an new instance for the next client
  526. pAddress->hConnectPipe = 0;
  527. NMP_SubmitConnect(pAddress);
  528. // Allocate a new connection object
  529. pConnection = (PNMP_CONNECTION)I_RpcTransServerNewConnection(pAddress);
  530. *ppConnection = pConnection;
  531. if (!pConnection)
  532. {
  533. CloseHandle(hClient);
  534. return(RPC_S_OUT_OF_MEMORY);
  535. }
  536. // Got a good connection, initialize it..
  537. // start with the vtbl
  538. pConnection = new (pConnection) NMP_CONNECTION;
  539. pConnection->type = SERVER | CONNECTION;
  540. pConnection->id = NMP;
  541. pConnection->Conn.Handle = hClient;
  542. pConnection->fAborted = 0;
  543. pConnection->pReadBuffer = 0;
  544. pConnection->maxReadBuffer = 0;
  545. pConnection->iLastRead = 0;
  546. pConnection->iPostSize = gPostSize;
  547. memset(&pConnection->Read.ol, 0, sizeof(pConnection->Read.ol));
  548. pConnection->Read.pAsyncObject = pConnection;
  549. pConnection->InitIoCounter();
  550. pConnection->pAddress = pAddress;
  551. return(RPC_S_OK);
  552. }
  553. RPC_CHAR *
  554. ULongToHexString (
  555. IN RPC_CHAR * String,
  556. IN unsigned long Number
  557. );
  558. #ifdef TRANSPORT_DLL
  559. RPC_CHAR *
  560. ULongToHexString (
  561. IN RPC_CHAR * String,
  562. IN unsigned long Number
  563. )
  564. /*++
  565. Routine Description:
  566. We convert an unsigned long into hex representation in the specified
  567. string. The result is always eight characters long; zero padding is
  568. done if necessary.
  569. Arguments:
  570. String - Supplies a buffer to put the hex representation into.
  571. Number - Supplies the unsigned long to convert to hex.
  572. Return Value:
  573. A pointer to the end of the hex string is returned.
  574. --*/
  575. {
  576. *String++ = HexDigits[(Number >> 28) & 0x0F];
  577. *String++ = HexDigits[(Number >> 24) & 0x0F];
  578. *String++ = HexDigits[(Number >> 20) & 0x0F];
  579. *String++ = HexDigits[(Number >> 16) & 0x0F];
  580. *String++ = HexDigits[(Number >> 12) & 0x0F];
  581. *String++ = HexDigits[(Number >> 8) & 0x0F];
  582. *String++ = HexDigits[(Number >> 4) & 0x0F];
  583. *String++ = HexDigits[Number & 0x0F];
  584. return(String);
  585. }
  586. #endif
  587. #define NMP_EP_TRAILER_LENGTH 8
  588. RPC_STATUS
  589. NMP_ServerListen(
  590. IN RPC_TRANSPORT_ADDRESS ThisAddress,
  591. IN PWSTR NetworkAddress,
  592. IN OUT PWSTR *pEndpoint,
  593. IN UINT PendingQueueSize,
  594. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  595. IN ULONG EndpointFlags,
  596. IN ULONG NICFlags
  597. )
  598. /*++
  599. Routine Description:
  600. This routine allocates a new pipe to receive new client connections.
  601. If successful a call to NMP_CompleteListen() will actually allow
  602. new connection callbacks to the RPC runtime to occur. Setup
  603. before the call to NMP_CompleteListen() can be stopped after this
  604. function call with a call to NMP_ServerAbortListen().
  605. Arguments:
  606. pAddress - A pointer to the loadable transport interface address.
  607. pEndpoint - Optionally, the endpoint (pipe) to listen on. Set
  608. to listened pipe for dynamic endpoints.
  609. PendingQueueSize - Meaningless for named pipes.
  610. EndpointFlags - Meaningless for named pipes.
  611. NICFlags - Meaningless for named pipes.
  612. SecurityDescriptor - The SD to associate with this address.
  613. Return Value:
  614. RPC_S_OK
  615. RPC_S_OUT_OF_MEMORY
  616. RPC_S_OUT_OF_RESOURCES
  617. RPC_S_CANT_CREATE_ENDPOINT
  618. RPC_S_INVALID_SECURITY_DESC
  619. --*/
  620. {
  621. BOOL b;
  622. INT i;
  623. RPC_STATUS status;
  624. PWSTR LocalPipeEndpoint;
  625. PNMP_ADDRESS pAddress = (PNMP_ADDRESS)ThisAddress;
  626. BOOL fEndpointCreated = FALSE;
  627. pAddress->type = ADDRESS;
  628. pAddress->id = NMP;
  629. pAddress->NewConnection = NMP_NewConnection;
  630. pAddress->SubmitListen = NMP_SubmitConnect;
  631. pAddress->InAddressList = NotInList;
  632. pAddress->pNext = 0;
  633. pAddress->hConnectPipe = 0;
  634. memset(&pAddress->Listen, 0, sizeof(BASE_OVERLAPPED));
  635. pAddress->Listen.pAsyncObject = pAddress;
  636. pAddress->pAddressVector = 0;
  637. pAddress->LocalEndpoint = 0;
  638. pAddress->Endpoint = 0;
  639. pAddress->pNextAddress = 0;
  640. pAddress->pFirstAddress = pAddress;
  641. pAddress->sparePipes.Init();
  642. // Determine the network address we'll try to listen on
  643. if (*pEndpoint)
  644. {
  645. // User specified an endpoint to use.
  646. if (RpcpStringNCompare(*pEndpoint, RPC_CONST_STRING("\\pipe\\"), 6) != 0)
  647. return(RPC_S_INVALID_ENDPOINT_FORMAT);
  648. i = RpcpStringLength(*pEndpoint) + 1 + 3; // NULL, \\, \\, .
  649. LocalPipeEndpoint = new RPC_CHAR[i];
  650. if (NULL == LocalPipeEndpoint)
  651. {
  652. return(RPC_S_OUT_OF_MEMORY);
  653. }
  654. LocalPipeEndpoint[0] = L'\\';
  655. LocalPipeEndpoint[1] = L'\\';
  656. LocalPipeEndpoint[2] = L'.';
  657. RpcpStringCopy(&LocalPipeEndpoint[3], *pEndpoint);
  658. }
  659. else
  660. {
  661. // Make up an endpoint to use.
  662. // Format: \\.\pipe\<eight byte random number (16 hex digits)>\0
  663. BYTE RandomBytes[NMP_EP_TRAILER_LENGTH];
  664. status = GenerateRandomNumber(&RandomBytes[0], 8);
  665. if (status != RPC_S_OK)
  666. {
  667. return status;
  668. }
  669. LocalPipeEndpoint = new RPC_CHAR[3 + 6 + 16 + 1];
  670. if (NULL == LocalPipeEndpoint)
  671. {
  672. return(RPC_S_OUT_OF_MEMORY);
  673. }
  674. LONG counter;
  675. PWSTR pwstrT = LocalPipeEndpoint;
  676. *pwstrT++ = RPC_CONST_CHAR('\\');
  677. *pwstrT++ = RPC_CONST_CHAR('\\');
  678. *pwstrT++ = RPC_CONST_CHAR('.');
  679. *pwstrT++ = RPC_CONST_CHAR('\\');
  680. *pwstrT++ = RPC_CONST_CHAR('p');
  681. *pwstrT++ = RPC_CONST_CHAR('i');
  682. *pwstrT++ = RPC_CONST_CHAR('p');
  683. *pwstrT++ = RPC_CONST_CHAR('e');
  684. *pwstrT++ = RPC_CONST_CHAR('\\');
  685. for (i=0; i < NMP_EP_TRAILER_LENGTH; i++)
  686. {
  687. *pwstrT++ = HexDigits[(RandomBytes[i] >> 4) & 0x0F];
  688. *pwstrT++ = HexDigits[RandomBytes[i] & 0x0F];
  689. }
  690. *pwstrT = 0;
  691. *pEndpoint = DuplicateString(LocalPipeEndpoint + 3);
  692. if (!(*pEndpoint))
  693. {
  694. delete [] LocalPipeEndpoint;
  695. return RPC_S_OUT_OF_MEMORY;
  696. }
  697. fEndpointCreated = TRUE;
  698. }
  699. // Security setup
  700. status = NMP_SetSecurity(pAddress, SecurityDescriptor);
  701. if (status != RPC_S_OK)
  702. {
  703. delete [] LocalPipeEndpoint;
  704. if (fEndpointCreated)
  705. delete *pEndpoint;
  706. return(status);
  707. }
  708. // Network address setup
  709. NETWORK_ADDRESS_VECTOR *pVector;
  710. pVector = new( sizeof(RPC_CHAR *)
  711. + (3 + gdwComputerNameLength) * sizeof(RPC_CHAR))
  712. NETWORK_ADDRESS_VECTOR;
  713. if (NULL == pVector)
  714. {
  715. NMP_ServerAbortListen(pAddress);
  716. delete [] LocalPipeEndpoint;
  717. if (fEndpointCreated)
  718. delete *pEndpoint;
  719. return(RPC_S_OUT_OF_MEMORY);
  720. }
  721. pVector->Count = 1;
  722. pVector->NetworkAddresses[0] = (RPC_CHAR *)&pVector->NetworkAddresses[1];
  723. RpcpStringCopy(pVector->NetworkAddresses[0], RPC_CONST_STRING("\\\\"));
  724. RpcpStringCat(pVector->NetworkAddresses[0], gpstrComputerName);
  725. //
  726. // Setup address
  727. //
  728. pAddress->Endpoint = LocalPipeEndpoint + 3;
  729. pAddress->LocalEndpoint = LocalPipeEndpoint;
  730. pAddress->pAddressVector = pVector;
  731. // We need to create two pipe instances to start with. This is necessary
  732. // to avoid a race where a client connects and quickly disconnects.
  733. // Before the server can submit the next connect another client fails with
  734. // RPC_S_SERVER_UNAVAILABLE. The extra pipe instance forces the client to
  735. // retry and everything works.
  736. HANDLE hSpares[2];
  737. for (i = 0; i < 2; i++)
  738. {
  739. status = NMP_CreatePipeInstance(pAddress);
  740. ASSERT(status != RPC_P_FOUND_IN_CACHE);
  741. if (status != RPC_S_OK)
  742. {
  743. ASSERT(pAddress->hConnectPipe == 0);
  744. break;
  745. }
  746. hSpares[i] = pAddress->hConnectPipe;
  747. pAddress->hConnectPipe = 0;
  748. status = COMMON_PrepareNewHandle(hSpares[i]);
  749. if (status != RPC_S_OK)
  750. {
  751. break;
  752. }
  753. }
  754. if (status != RPC_S_OK)
  755. {
  756. NMP_ServerAbortListen(pAddress);
  757. if (fEndpointCreated)
  758. delete *pEndpoint;
  759. return(status);
  760. }
  761. // Move the pipe instances back into the address.
  762. pAddress->sparePipes.CheckinHandle(&hSpares[0]);
  763. // assert that it succeeded (i.e. did not zero out the handle)
  764. ASSERT(hSpares[0] == NULL);
  765. pAddress->sparePipes.CheckinHandle(&hSpares[1]);
  766. ASSERT(hSpares[1] == NULL);
  767. //
  768. // Done with phase one, now return to the runtime and wait.
  769. //
  770. return(RPC_S_OK);
  771. }
  772. RPC_STATUS
  773. RPC_ENTRY
  774. NMP_ConnectionImpersonateClient (
  775. IN RPC_TRANSPORT_CONNECTION SConnection
  776. )
  777. // Impersonate the client at the other end of the connection.
  778. {
  779. NMP_CONNECTION *p = (NMP_CONNECTION *)SConnection;
  780. BOOL b;
  781. p->StartingOtherIO();
  782. if (p->fAborted)
  783. {
  784. p->OtherIOFinished();
  785. return(RPC_S_NO_CONTEXT_AVAILABLE);
  786. }
  787. b = ImpersonateNamedPipeClient(p->Conn.Handle);
  788. p->OtherIOFinished();
  789. if (!b)
  790. {
  791. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  792. DPFLTR_WARNING_LEVEL,
  793. RPCTRANS "ImpersonateNamedPipeClient (%p) failed %d\n",
  794. p,
  795. GetLastError() ));
  796. return(RPC_S_NO_CONTEXT_AVAILABLE);
  797. }
  798. return(RPC_S_OK);
  799. }
  800. RPC_STATUS
  801. RPC_ENTRY
  802. NMP_ConnectionRevertToSelf (
  803. RPC_TRANSPORT_CONNECTION SConnection
  804. )
  805. /*++
  806. Routine Description:
  807. We want to stop impersonating the client. This means we want
  808. the current thread's security context to revert the the
  809. default.
  810. Arguments:
  811. SConnection - unused
  812. Return Value:
  813. RPC_S_OK
  814. RPC_S_INTERNAL_ERROR - Not impersonating or something else went wrong.
  815. (Debug systems only)
  816. --*/
  817. {
  818. BOOL b;
  819. UNUSED(SConnection);
  820. b = RevertToSelf();
  821. #if DBG
  822. if (!b)
  823. {
  824. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  825. DPFLTR_WARNING_LEVEL,
  826. RPCTRANS "RevertToSelf failed %d\n",
  827. GetLastError()));
  828. ASSERT(b);
  829. return(RPC_S_INTERNAL_ERROR);
  830. }
  831. #endif
  832. return(RPC_S_OK);
  833. }
  834. RPC_STATUS RPC_ENTRY
  835. NMP_ConnectionQueryClientAddress(
  836. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  837. OUT RPC_CHAR **pNetworkAddress
  838. )
  839. /*++
  840. Routine Description:
  841. Returns the address of the client. Uses an extended in NT 5
  842. ioctl to reterive the client machine name from named pipes.
  843. Arguments:
  844. ThisConnection - The server connection of interest.
  845. NetworkAddress - Will contain the string on success.
  846. Return Value:
  847. RPC_S_OK
  848. RPC_S_OUT_OF_RESOURCES
  849. RPC_S_OUT_OF_MEMORY
  850. --*/
  851. {
  852. NTSTATUS NtStatus;
  853. RPC_STATUS status;
  854. IO_STATUS_BLOCK IoStatus;
  855. NMP_CONNECTION *p = (NMP_CONNECTION *)ThisConnection;
  856. FILE_PIPE_CLIENT_PROCESS_BUFFER_EX ClientProcess;
  857. HANDLE hEvent = I_RpcTransGetThreadEvent();
  858. DWORD size;
  859. ClientProcess.ClientComputerNameLength = 0;
  860. ASSERT(hEvent);
  861. p->StartingOtherIO();
  862. if (p->fAborted)
  863. {
  864. p->OtherIOFinished();
  865. return(RPC_S_NO_CONTEXT_AVAILABLE);
  866. }
  867. NtStatus = NtFsControlFile(p->Conn.Handle,
  868. hEvent,
  869. 0,
  870. 0,
  871. &IoStatus,
  872. FSCTL_PIPE_QUERY_CLIENT_PROCESS,
  873. 0,
  874. 0,
  875. &ClientProcess,
  876. sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER_EX));
  877. p->OtherIOFinished();
  878. if (NtStatus == STATUS_PENDING)
  879. {
  880. status = WaitForSingleObject(hEvent, INFINITE);
  881. ASSERT(status == WAIT_OBJECT_0);
  882. if (status != WAIT_OBJECT_0)
  883. {
  884. return(RPC_S_OUT_OF_RESOURCES);
  885. }
  886. }
  887. if (!NT_SUCCESS(NtStatus))
  888. {
  889. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  890. DPFLTR_WARNING_LEVEL,
  891. RPCTRANS "QUERY_PIPE_PROCESS ioctl failed %x\n",
  892. NtStatus));
  893. return(RPC_S_OUT_OF_RESOURCES);
  894. }
  895. if (ClientProcess.ClientComputerNameLength == 0)
  896. {
  897. // Must be local, no ID. Just copy the local computer name into the
  898. // buffer and continue.
  899. size = gdwComputerNameLength; // Includes null
  900. wcscpy(ClientProcess.ClientComputerBuffer, gpstrComputerName);
  901. }
  902. else
  903. {
  904. ASSERT(wcslen(ClientProcess.ClientComputerBuffer) < 16);
  905. // Convert from bytes to characters, add one for the null.
  906. size = ClientProcess.ClientComputerNameLength/2 + 1;
  907. }
  908. *pNetworkAddress = new WCHAR[size];
  909. if (!*pNetworkAddress)
  910. {
  911. return(RPC_S_OUT_OF_MEMORY);
  912. }
  913. wcscpy(*pNetworkAddress, ClientProcess.ClientComputerBuffer);
  914. return(RPC_S_OK);
  915. }
  916. RPC_STATUS RPC_ENTRY
  917. NMP_ConnectionQueryClientId (
  918. IN RPC_TRANSPORT_CONNECTION SConnection,
  919. OUT RPC_CLIENT_PROCESS_IDENTIFIER * ClientProcess
  920. )
  921. /*++
  922. Routine Description:
  923. We want to query the identifier of the client process at the other
  924. of this named pipe. Two pipes from the same client process will always
  925. return the same identifier for their client process. Likewise, two
  926. pipes from different client processes will never return the same
  927. identifier for their respective client process.
  928. This is one of the few things you can't do in win32.
  929. Arguments:
  930. SConnection - Supplies the named pipe instance for which we want to
  931. obtain the client process identifier.
  932. ClientProcess - Returns the identifier for the client process at the
  933. other end of this named pipe instance.
  934. Return Value:
  935. RPC_S_OK - This value will always be returned.
  936. --*/
  937. {
  938. NTSTATUS NtStatus;
  939. RPC_STATUS status;
  940. IO_STATUS_BLOCK IoStatus;
  941. NMP_CONNECTION *p = (NMP_CONNECTION *)SConnection;
  942. FILE_PIPE_CLIENT_PROCESS_BUFFER ClientProcessBuffer;
  943. HANDLE hEvent = I_RpcTransGetThreadEvent();
  944. BOOL fLocal;
  945. ClientProcess->ZeroOut();
  946. ASSERT(hEvent);
  947. p->StartingOtherIO();
  948. if (p->fAborted)
  949. {
  950. p->OtherIOFinished();
  951. return(RPC_S_NO_CONTEXT_AVAILABLE);
  952. }
  953. NtStatus = NtFsControlFile(p->Conn.Handle,
  954. hEvent,
  955. 0,
  956. 0,
  957. &IoStatus,
  958. FSCTL_PIPE_QUERY_CLIENT_PROCESS,
  959. 0,
  960. 0,
  961. &ClientProcessBuffer,
  962. sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER));
  963. p->OtherIOFinished();
  964. if (NtStatus == STATUS_PENDING)
  965. {
  966. status = WaitForSingleObject(hEvent, INFINITE);
  967. ASSERT(status == WAIT_OBJECT_0);
  968. if (status != WAIT_OBJECT_0)
  969. {
  970. return(RPC_S_OUT_OF_RESOURCES);
  971. }
  972. }
  973. if (NT_SUCCESS(NtStatus))
  974. {
  975. if (ClientProcessBuffer.ClientSession)
  976. {
  977. ClientProcessBuffer.ClientSession = 0;
  978. fLocal = FALSE;
  979. }
  980. else
  981. fLocal = TRUE;
  982. ClientProcess->SetNMPClientIdentifier(&ClientProcessBuffer, fLocal);
  983. }
  984. return(RPC_S_OK);
  985. }
  986. NETWORK_ADDRESS_VECTOR *
  987. NMP_GetNetworkAddressVector (
  988. IN RPC_TRANSPORT_ADDRESS Address
  989. )
  990. {
  991. NMP_ADDRESS *p = (NMP_ADDRESS *)Address;
  992. return p->pAddressVector;
  993. }
  994. RPC_STATUS
  995. RPC_ENTRY
  996. NMP_Initialize (
  997. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  998. IN RPC_CHAR * NetworkAddress,
  999. IN RPC_CHAR * NetworkOptions,
  1000. IN BOOL fAsync
  1001. )
  1002. /*++
  1003. Routine Description:
  1004. Initialize the connection. This function is guaranteed to be called
  1005. in the thread that called GetBuffer.
  1006. Arguments:
  1007. ThisConnection - A place to store the connection
  1008. */
  1009. {
  1010. PNMP_CONNECTION pConnection = (PNMP_CONNECTION)ThisConnection;
  1011. // use explicit placement to initialize vtbl
  1012. pConnection = new (pConnection) NMP_CONNECTION;
  1013. pConnection->id = NMP;
  1014. pConnection->Initialize();
  1015. pConnection->pAddress = 0;
  1016. return RPC_S_OK;
  1017. }
  1018. RPC_STATUS
  1019. RPC_ENTRY
  1020. NMP_Open(
  1021. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  1022. IN RPC_CHAR * ProtocolSequence,
  1023. IN RPC_CHAR * NetworkAddress,
  1024. IN RPC_CHAR * Endpoint,
  1025. IN RPC_CHAR * NetworkOptions,
  1026. IN UINT ConnTimeout,
  1027. IN UINT SendBufferSize,
  1028. IN UINT RecvBufferSize,
  1029. IN void *ResolverHint,
  1030. IN BOOL fHintInitialized,
  1031. IN ULONG CallTimeout,
  1032. IN ULONG AdditionalTransportCredentialsType, OPTIONAL
  1033. IN void *AdditionalCredentials OPTIONAL
  1034. )
  1035. /*++
  1036. Routine Description:
  1037. Opens a connection to a server.
  1038. Arguments:
  1039. ThisConnection - A place to store the connection
  1040. ProtocolSeqeunce - "ncacn_np"
  1041. NetworkAddress - The name of the server, with or without the '\\'
  1042. NetworkOptions - Options from the string binding. For security:
  1043. security=
  1044. [anonymous|identification|impersonation|delegation]
  1045. [dynamic|static]
  1046. [true|false]
  1047. All three fields must be present. To specify impersonation
  1048. with dynamic tracking and effective only, use the following
  1049. string for the network options.
  1050. "security=impersonation dynamic true"
  1051. ConnTimeout - See RpcMgmtSetComTimeout
  1052. 0 - Min
  1053. 5 - Default
  1054. 9 - Max
  1055. 10 - Infinite
  1056. {Send,Recv}BufferSize - Ignored.
  1057. CallTimeout - call timeout in milliseconds. Ignored for named pipes.
  1058. AdditionalTransportCredentialsType - the type of additional credentials that we were
  1059. given. Not used for named pipes.
  1060. AdditionalCredentials - additional credentials that we were given.
  1061. Not used for named pipes.
  1062. Return Value:
  1063. RPC_S_OK
  1064. RPC_S_OUT_OF_MEMORY
  1065. RPC_S_OUT_OF_RESOURCES
  1066. RPC_S_INVALID_NETWORK_OPTIONS
  1067. RPC_S_SERVER_UNAVAILABLE
  1068. RPC_S_INVALID_ENDPOINT_FORMAT
  1069. RPC_S_INVALID_NET_ADDR
  1070. --*/
  1071. {
  1072. RPC_STATUS Status;
  1073. PNMP_CONNECTION pConnection = (PNMP_CONNECTION)ThisConnection;
  1074. BOOL f;
  1075. HANDLE hPipe;
  1076. DWORD SecurityQOSFlags = 0;
  1077. NTSTATUS NtStatus;
  1078. UINT AddressLen ;
  1079. UINT EndpointLen;
  1080. HANDLE ImpersonationToken = 0;
  1081. DWORD StartTickCount;
  1082. DWORD RetryCount;
  1083. BOOL fLocalAddress = FALSE;
  1084. if ((AdditionalTransportCredentialsType != 0) || (AdditionalCredentials != NULL))
  1085. return RPC_S_CANNOT_SUPPORT;
  1086. if (NetworkOptions && *NetworkOptions)
  1087. {
  1088. //
  1089. // Enable transport level security.
  1090. //
  1091. // By default named pipes (CreateFile) uses security with impersonation,
  1092. // dynamic tracking and effective only enabled.
  1093. //
  1094. // RPC level security sits on top of this and provides other features.
  1095. //
  1096. // Named pipes security is controlled via an options string in the string
  1097. // binding. The runtime exports an API to parse the string which is used
  1098. // here to do most of the work.
  1099. //
  1100. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  1101. Status = I_RpcParseSecurity(NetworkOptions,
  1102. &SecurityQualityOfService);
  1103. if ( Status != RPC_S_OK )
  1104. {
  1105. ASSERT( Status == RPC_S_INVALID_NETWORK_OPTIONS );
  1106. goto Cleanup;
  1107. }
  1108. // Convert into SecurityQOS into CreateFile flags
  1109. ASSERT(SECURITY_ANONYMOUS == (SecurityAnonymous <<16));
  1110. ASSERT(SECURITY_IDENTIFICATION == (SecurityIdentification <<16));
  1111. ASSERT(SECURITY_IMPERSONATION == (SecurityImpersonation <<16));
  1112. ASSERT(SECURITY_DELEGATION == (SecurityDelegation <<16));
  1113. SecurityQOSFlags = SECURITY_SQOS_PRESENT
  1114. | (SecurityQualityOfService.ImpersonationLevel << 16);
  1115. SecurityQOSFlags |= (SecurityQualityOfService.ContextTrackingMode
  1116. != SECURITY_STATIC_TRACKING) ? SECURITY_CONTEXT_TRACKING : 0;
  1117. SecurityQOSFlags |= (SecurityQualityOfService.EffectiveOnly)
  1118. ? SECURITY_EFFECTIVE_ONLY : 0;
  1119. }
  1120. ASSERT(NetworkAddress);
  1121. if (NetworkAddress[0] == '\\')
  1122. {
  1123. if ( NetworkAddress[1] == '\\'
  1124. && NetworkAddress[2] != '\0'
  1125. && NetworkAddress[3] != '\\')
  1126. {
  1127. NetworkAddress += 2;
  1128. }
  1129. else
  1130. {
  1131. RpcpErrorAddRecord(EEInfoGCRuntime,
  1132. RPC_S_INVALID_NET_ADDR,
  1133. EEInfoDLNMPOpen30,
  1134. NetworkAddress);
  1135. Status = RPC_S_INVALID_NET_ADDR;
  1136. goto Cleanup;
  1137. }
  1138. }
  1139. if ( (NetworkAddress[0] == 0)
  1140. || (RpcpStringCompare(NetworkAddress, gpstrComputerName) == 0) )
  1141. {
  1142. NetworkAddress = RPC_STRING_LITERAL(".");
  1143. fLocalAddress = TRUE;
  1144. }
  1145. ASSERT(Endpoint);
  1146. if ( Endpoint[0] != 0
  1147. && RpcpStringNCompare(Endpoint, RPC_CONST_STRING("\\pipe\\"), 6) != 0)
  1148. {
  1149. Status = RPC_S_INVALID_ENDPOINT_FORMAT;
  1150. goto Cleanup;
  1151. }
  1152. AddressLen = RpcpStringLength(NetworkAddress);
  1153. EndpointLen = RpcpStringLength(Endpoint);
  1154. RPC_CHAR *TransportAddress;
  1155. TransportAddress = (RPC_CHAR *)alloca( (2 + AddressLen + EndpointLen + 1)
  1156. * sizeof(RPC_CHAR) );
  1157. TransportAddress[0] = TransportAddress[1] = '\\';
  1158. memcpy(TransportAddress + 2,
  1159. NetworkAddress,
  1160. AddressLen * sizeof(RPC_CHAR));
  1161. memcpy(TransportAddress + 2 + AddressLen,
  1162. Endpoint,
  1163. (EndpointLen + 1) * sizeof(RPC_CHAR));
  1164. ASSERT( ((long)ConnTimeout >= RPC_C_BINDING_MIN_TIMEOUT)
  1165. && (ConnTimeout <= RPC_C_BINDING_INFINITE_TIMEOUT));
  1166. StartTickCount = GetTickCount();
  1167. RetryCount = 0;
  1168. do
  1169. {
  1170. hPipe = CreateFile((RPC_SCHAR *)TransportAddress,
  1171. GENERIC_READ | GENERIC_WRITE,
  1172. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1173. 0,
  1174. OPEN_EXISTING,
  1175. FILE_FLAG_OVERLAPPED | SecurityQOSFlags,
  1176. 0
  1177. );
  1178. if (hPipe != INVALID_HANDLE_VALUE)
  1179. {
  1180. DWORD Mode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
  1181. f = SetNamedPipeHandleState(hPipe, &Mode, 0, 0);
  1182. if (f)
  1183. {
  1184. Status = COMMON_PrepareNewHandle(hPipe);
  1185. if (Status == RPC_S_OK)
  1186. {
  1187. break;
  1188. }
  1189. else
  1190. {
  1191. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  1192. DPFLTR_WARNING_LEVEL,
  1193. RPCTRANS "COMMON_PrepareNewHandle: %d\n",
  1194. GetLastError()));
  1195. }
  1196. }
  1197. else
  1198. {
  1199. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  1200. DPFLTR_WARNING_LEVEL,
  1201. RPCTRANS "SetNamedPipeHandleState: %d\n",
  1202. GetLastError()));
  1203. Status = GetLastError();
  1204. }
  1205. CloseHandle(hPipe);
  1206. hPipe = INVALID_HANDLE_VALUE;
  1207. }
  1208. else
  1209. {
  1210. Status = GetLastError();
  1211. }
  1212. if (Status != ERROR_PIPE_BUSY)
  1213. {
  1214. RpcpErrorAddRecord(fLocalAddress ? EEInfoGCNPFS : EEInfoGCRDR,
  1215. Status,
  1216. EEInfoDLNMPOpen10,
  1217. TransportAddress,
  1218. SecurityQOSFlags);
  1219. switch(Status)
  1220. {
  1221. case ERROR_INVALID_NAME:
  1222. Status = RPC_S_INVALID_ENDPOINT_FORMAT;
  1223. break;
  1224. case ERROR_BAD_NET_NAME:
  1225. case ERROR_INVALID_NETNAME:
  1226. Status = RPC_S_INVALID_NET_ADDR;
  1227. break;
  1228. case ERROR_NOT_ENOUGH_MEMORY:
  1229. case ERROR_NOT_ENOUGH_QUOTA:
  1230. case ERROR_COMMITMENT_LIMIT:
  1231. case ERROR_TOO_MANY_OPEN_FILES:
  1232. case ERROR_OUTOFMEMORY:
  1233. Status = RPC_S_OUT_OF_MEMORY;
  1234. break;
  1235. case ERROR_NOT_ENOUGH_SERVER_MEMORY:
  1236. Status = RPC_S_SERVER_OUT_OF_MEMORY;
  1237. break;
  1238. case ERROR_NO_SYSTEM_RESOURCES:
  1239. case ERROR_WORKING_SET_QUOTA:
  1240. case ERROR_TOO_MANY_SESS:
  1241. Status = RPC_S_OUT_OF_RESOURCES;
  1242. break;
  1243. case ERROR_DOMAIN_TRUST_INCONSISTENT:
  1244. case ERROR_ACCESS_DENIED:
  1245. case ERROR_ACCOUNT_EXPIRED:
  1246. case ERROR_ACCOUNT_RESTRICTION:
  1247. case ERROR_ACCOUNT_LOCKED_OUT:
  1248. case ERROR_ACCOUNT_DISABLED:
  1249. case ERROR_NO_SUCH_USER:
  1250. case ERROR_BAD_IMPERSONATION_LEVEL:
  1251. case ERROR_BAD_LOGON_SESSION_STATE:
  1252. case ERROR_INVALID_PASSWORD:
  1253. case ERROR_INVALID_LOGON_HOURS:
  1254. case ERROR_INVALID_WORKSTATION:
  1255. case ERROR_INVALID_SERVER_STATE:
  1256. case ERROR_INVALID_DOMAIN_STATE:
  1257. case ERROR_INVALID_DOMAIN_ROLE:
  1258. case ERROR_LOGON_FAILURE:
  1259. case ERROR_LICENSE_QUOTA_EXCEEDED:
  1260. case ERROR_LOGON_NOT_GRANTED:
  1261. case ERROR_LOGON_TYPE_NOT_GRANTED:
  1262. case ERROR_MUTUAL_AUTH_FAILED:
  1263. case ERROR_NETWORK_ACCESS_DENIED:
  1264. case ERROR_NO_SUCH_DOMAIN:
  1265. case ERROR_NO_SUCH_LOGON_SESSION:
  1266. case ERROR_NO_LOGON_SERVERS:
  1267. case ERROR_NO_TRUST_SAM_ACCOUNT:
  1268. case ERROR_PASSWORD_EXPIRED:
  1269. case ERROR_PASSWORD_MUST_CHANGE:
  1270. case ERROR_TRUSTED_DOMAIN_FAILURE:
  1271. case ERROR_TRUSTED_RELATIONSHIP_FAILURE:
  1272. case ERROR_WRONG_TARGET_NAME:
  1273. case ERROR_WRONG_PASSWORD:
  1274. case ERROR_TIME_SKEW:
  1275. case ERROR_NO_TRUST_LSA_SECRET:
  1276. case ERROR_LOGIN_WKSTA_RESTRICTION:
  1277. case ERROR_SHUTDOWN_IN_PROGRESS:
  1278. case ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT:
  1279. case ERROR_DOWNGRADE_DETECTED:
  1280. case ERROR_CONTEXT_EXPIRED:
  1281. case SCARD_E_NO_SMARTCARD:
  1282. case ERROR_SMARTCARD_SUBSYSTEM_FAILURE:
  1283. case SCARD_E_COMM_DATA_LOST:
  1284. case ERROR_AUTHENTICATION_FIREWALL_FAILED:
  1285. Status = RPC_S_ACCESS_DENIED;
  1286. break;
  1287. //case ERROR_INTERNAL_ERROR:
  1288. case ERROR_NOACCESS:
  1289. // Really unexpected errors - fall into default on retail.
  1290. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  1291. DPFLTR_WARNING_LEVEL,
  1292. RPCTRANS "Unexpected error: %d\n",
  1293. Status));
  1294. ASSERT(0);
  1295. default:
  1296. VALIDATE(Status)
  1297. {
  1298. ERROR_REM_NOT_LIST,
  1299. ERROR_SHARING_PAUSED,
  1300. ERROR_NETNAME_DELETED,
  1301. ERROR_SEM_TIMEOUT,
  1302. ERROR_FILE_NOT_FOUND,
  1303. ERROR_PATH_NOT_FOUND,
  1304. ERROR_BAD_NETPATH,
  1305. ERROR_NETWORK_UNREACHABLE,
  1306. ERROR_UNEXP_NET_ERR,
  1307. ERROR_REQ_NOT_ACCEP,
  1308. ERROR_GEN_FAILURE,
  1309. ERROR_BAD_NET_RESP,
  1310. ERROR_PIPE_NOT_CONNECTED,
  1311. ERROR_NETLOGON_NOT_STARTED,
  1312. ERROR_DOMAIN_CONTROLLER_NOT_FOUND,
  1313. ERROR_CONNECTION_ABORTED,
  1314. ERROR_CONNECTION_INVALID,
  1315. ERROR_HOST_UNREACHABLE,
  1316. ERROR_CANT_ACCESS_DOMAIN_INFO,
  1317. ERROR_DUP_NAME,
  1318. ERROR_NO_SUCH_PACKAGE,
  1319. ERROR_INVALID_FUNCTION,
  1320. ERROR_BAD_DEV_TYPE,
  1321. ERROR_CONNECTION_REFUSED,
  1322. ERROR_BAD_COMMAND
  1323. } END_VALIDATE;
  1324. Status = RPC_S_SERVER_UNAVAILABLE;
  1325. break;
  1326. }
  1327. RpcpErrorAddRecord(EEInfoGCRuntime,
  1328. Status,
  1329. EEInfoDLNMPOpen40);
  1330. goto Cleanup;
  1331. }
  1332. ASSERT(hPipe == INVALID_HANDLE_VALUE);
  1333. // No pipe instances available, wait for one to show up...
  1334. WaitNamedPipe((RPC_SCHAR *)TransportAddress, 1000);
  1335. // attempt the connect for at least 40 seconds and at least 20 times
  1336. // note that since this is DWORD, even if the counter has wrapped
  1337. // the difference will be accurate
  1338. RetryCount ++;
  1339. }
  1340. while ((GetTickCount() - StartTickCount < 40000) || (RetryCount <= 20));
  1341. if (hPipe == INVALID_HANDLE_VALUE)
  1342. {
  1343. Status = RPC_S_SERVER_TOO_BUSY;
  1344. RpcpErrorAddRecord(fLocalAddress ? EEInfoGCNPFS : EEInfoGCRDR,
  1345. Status,
  1346. EEInfoDLNMPOpen20,
  1347. TransportAddress);
  1348. // No instances available
  1349. goto Cleanup;
  1350. }
  1351. // Pipe opened successfully
  1352. pConnection->Conn.Handle = hPipe;
  1353. pConnection->fAborted = 0;
  1354. pConnection->pReadBuffer = 0;
  1355. pConnection->maxReadBuffer = 0;
  1356. pConnection->iPostSize = gPostSize;
  1357. pConnection->iLastRead = 0;
  1358. memset(&pConnection->Read.ol, 0, sizeof(pConnection->Read.ol));
  1359. pConnection->Read.pAsyncObject = pConnection;
  1360. pConnection->Read.thread = 0;
  1361. pConnection->Read.ol.Internal = 0;
  1362. pConnection->InitIoCounter();
  1363. pConnection->pAddress = 0;
  1364. Status = RPC_S_OK;
  1365. Cleanup:
  1366. return(Status);
  1367. }
  1368. RPC_STATUS
  1369. RPC_ENTRY
  1370. NMP_SyncSend(
  1371. IN RPC_TRANSPORT_CONNECTION Connection,
  1372. IN UINT BufferLength,
  1373. IN BUFFER Buffer,
  1374. IN BOOL fDisableShutdownCheck,
  1375. IN BOOL fDisableCancelCheck,
  1376. ULONG Timeout
  1377. )
  1378. /*++
  1379. Routine Description:
  1380. Sends a message on the connection. This method must appear
  1381. to be synchronous from the callers perspective.
  1382. Arguments:
  1383. pConnection - The connection.
  1384. Buffer - The data to send.
  1385. BufferLength - The size of the buffer.
  1386. fDisableShutdownCheck - N/A to named pipes.
  1387. Return Value:
  1388. RPC_S_OK - Data sent
  1389. RPC_P_SEND_FAILED - Connection will be aborted if this is returned.
  1390. RPC_S_CALL_CANCELLED - The call was cancelled
  1391. --*/
  1392. {
  1393. NMP_CONNECTION *p = (NMP_CONNECTION *)Connection;
  1394. DWORD bytes;
  1395. RPC_STATUS status;
  1396. OVERLAPPED olWrite;
  1397. HANDLE hEvent;
  1398. BOOL fPendingReturned = FALSE;
  1399. hEvent = I_RpcTransGetThreadEvent();
  1400. ASSERT(hEvent);
  1401. p->StartingWriteIO();
  1402. if (p->fAborted)
  1403. {
  1404. p->WriteIOFinished();
  1405. return(RPC_P_SEND_FAILED);
  1406. }
  1407. // Setting the low bit of the event indicates that the write
  1408. // completion should NOT be sent to the i/o completion port.
  1409. olWrite.Internal = 0;
  1410. olWrite.InternalHigh = 0;
  1411. olWrite.Offset = 0;
  1412. olWrite.OffsetHigh = 0;
  1413. olWrite.hEvent = (HANDLE) ((ULONG_PTR)hEvent | 0x1);
  1414. #ifdef _INTERNAL_RPC_BUILD_
  1415. if (gpfnFilter)
  1416. {
  1417. (*gpfnFilter) (Buffer, BufferLength, 0);
  1418. }
  1419. #endif
  1420. status = p->NMP_CONNECTION::Send(p->Conn.Handle,
  1421. Buffer,
  1422. BufferLength,
  1423. &bytes,
  1424. &olWrite
  1425. );
  1426. p->WriteIOFinished();
  1427. if (status == RPC_S_OK)
  1428. {
  1429. ASSERT(bytes == BufferLength);
  1430. return(RPC_S_OK);
  1431. }
  1432. if (status == ERROR_IO_PENDING)
  1433. {
  1434. fPendingReturned = TRUE;
  1435. // if fDisableCancelCheck - not alertable. Else, alertable.
  1436. status = UTIL_GetOverlappedResultEx(Connection,
  1437. &olWrite,
  1438. &bytes,
  1439. (fDisableCancelCheck ? FALSE : TRUE),
  1440. Timeout);
  1441. if (status == RPC_S_OK)
  1442. {
  1443. ASSERT(bytes == BufferLength);
  1444. return(RPC_S_OK);
  1445. }
  1446. }
  1447. ASSERT(status != ERROR_SUCCESS);
  1448. RpcpErrorAddRecord(EEInfoGCNMP,
  1449. status,
  1450. EEInfoDLNMPSyncSend10,
  1451. (ULONGLONG)Connection,
  1452. (ULONGLONG)Buffer,
  1453. (ULONG)BufferLength,
  1454. (ULONG)fPendingReturned);
  1455. VALIDATE(status)
  1456. {
  1457. ERROR_NETNAME_DELETED,
  1458. ERROR_GRACEFUL_DISCONNECT,
  1459. ERROR_BROKEN_PIPE,
  1460. ERROR_PIPE_NOT_CONNECTED,
  1461. ERROR_NO_DATA,
  1462. ERROR_NO_SYSTEM_RESOURCES,
  1463. ERROR_WORKING_SET_QUOTA,
  1464. ERROR_SEM_TIMEOUT,
  1465. ERROR_UNEXP_NET_ERR,
  1466. ERROR_BAD_NET_RESP,
  1467. ERROR_HOST_UNREACHABLE,
  1468. RPC_S_CALL_CANCELLED,
  1469. ERROR_CONNECTION_ABORTED,
  1470. ERROR_NOT_ENOUGH_QUOTA,
  1471. RPC_P_TIMEOUT,
  1472. ERROR_LOGON_FAILURE,
  1473. ERROR_TIME_SKEW,
  1474. ERROR_NETWORK_UNREACHABLE,
  1475. ERROR_NO_LOGON_SERVERS,
  1476. ERROR_NO_SUCH_USER,
  1477. ERROR_NOT_ENOUGH_SERVER_MEMORY,
  1478. ERROR_INVALID_NETNAME,
  1479. ERROR_BAD_COMMAND,
  1480. ERROR_SMARTCARD_SUBSYSTEM_FAILURE
  1481. } END_VALIDATE;
  1482. p->NMP_CONNECTION::Abort();
  1483. if ((status == RPC_S_CALL_CANCELLED) || (status == RPC_P_TIMEOUT))
  1484. {
  1485. // Wait for the write to finish. Since we closed the pipe
  1486. // this won't take very long.
  1487. UTIL_WaitForSyncIO(&olWrite,
  1488. FALSE,
  1489. INFINITE);
  1490. }
  1491. else
  1492. {
  1493. status = RPC_P_SEND_FAILED;
  1494. }
  1495. return(status);
  1496. }
  1497. RPC_STATUS
  1498. RPC_ENTRY
  1499. NMP_SyncSendRecv(
  1500. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  1501. IN UINT InputBufferSize,
  1502. IN BUFFER InputBuffer,
  1503. OUT PUINT pOutputBufferSize,
  1504. OUT BUFFER *pOutputBuffer
  1505. )
  1506. /*++
  1507. Routine Description:
  1508. Sends a request to the server and waits to receive the next PDU
  1509. to arrive at the connection.
  1510. Arguments:
  1511. ThisConnection - The connection to wait on.
  1512. InputBufferSize - The size of the data to send to the server.
  1513. InputBuffer - The data to send to the server
  1514. pOutputBufferSize - On return it contains the size of the PDU received.
  1515. pOutputBuffer - On return contains the PDU received.
  1516. Return Value:
  1517. RPC_S_OK
  1518. RPC_P_SEND_FAILED - Connection aborted, data did not reach the server.
  1519. RPC_P_RECEIVE_FAILED - Connection aborted, data might have reached
  1520. the server.
  1521. --*/
  1522. {
  1523. PNMP_CONNECTION p = (PNMP_CONNECTION)ThisConnection;
  1524. BOOL b;
  1525. DWORD bytes;
  1526. DWORD readbytes;
  1527. RPC_STATUS status;
  1528. HANDLE hEvent;
  1529. ASSERT(p->pReadBuffer == 0);
  1530. ASSERT(p->iLastRead == 0);
  1531. p->pReadBuffer = TransConnectionAllocatePacket(p, p->iPostSize);
  1532. if (!p->pReadBuffer)
  1533. {
  1534. p->NMP_CONNECTION::Abort();
  1535. return(RPC_P_SEND_FAILED);
  1536. }
  1537. hEvent = I_RpcTransGetThreadEvent();
  1538. ASSERT(hEvent);
  1539. p->Read.ol.hEvent = (HANDLE) ((ULONG_PTR)hEvent | 0x1);
  1540. p->maxReadBuffer = p->iPostSize;
  1541. bytes = p->maxReadBuffer;
  1542. #ifdef _INTERNAL_RPC_BUILD_
  1543. if (gpfnFilter)
  1544. {
  1545. (*gpfnFilter) (InputBuffer, InputBufferSize, 0);
  1546. }
  1547. #endif
  1548. b = TransactNamedPipe(p->Conn.Handle,
  1549. InputBuffer,
  1550. InputBufferSize,
  1551. p->pReadBuffer,
  1552. bytes,
  1553. &bytes,
  1554. &p->Read.ol
  1555. );
  1556. if (!b)
  1557. {
  1558. status = GetLastError();
  1559. if (status == ERROR_IO_PENDING)
  1560. {
  1561. status = UTIL_GetOverlappedResult(p,
  1562. &p->Read.ol,
  1563. &bytes);
  1564. }
  1565. else
  1566. {
  1567. ASSERT(status != RPC_S_OK);
  1568. }
  1569. }
  1570. else
  1571. {
  1572. status = RPC_S_OK;
  1573. }
  1574. if (status == RPC_S_OK)
  1575. {
  1576. // Success - got the whole reply in the transact
  1577. *pOutputBuffer = p->pReadBuffer;
  1578. p->pReadBuffer = 0;
  1579. *pOutputBufferSize = bytes;
  1580. ASSERT(bytes == MessageLength((PCONN_RPC_HEADER)*pOutputBuffer));
  1581. return(RPC_S_OK);
  1582. }
  1583. if (status != ERROR_MORE_DATA)
  1584. {
  1585. RpcpErrorAddRecord(EEInfoGCNMP,
  1586. status,
  1587. EEInfoDLNMPSyncSendReceive10,
  1588. (ULONGLONG)p,
  1589. (ULONGLONG)InputBuffer,
  1590. InputBufferSize);
  1591. if (status == ERROR_BAD_PIPE)
  1592. {
  1593. status = RPC_P_SEND_FAILED;
  1594. }
  1595. else
  1596. {
  1597. // surprisingly enough, ERROR_PIPE_NOT_CONNECTED can be
  1598. // returned if the server died midway through the
  1599. // operation.
  1600. VALIDATE(status)
  1601. {
  1602. ERROR_NETNAME_DELETED,
  1603. ERROR_GRACEFUL_DISCONNECT,
  1604. ERROR_BROKEN_PIPE,
  1605. ERROR_PIPE_BUSY,
  1606. ERROR_NO_DATA,
  1607. ERROR_NO_SYSTEM_RESOURCES,
  1608. ERROR_SEM_TIMEOUT,
  1609. ERROR_UNEXP_NET_ERR,
  1610. ERROR_BAD_NET_RESP,
  1611. ERROR_CONNECTION_ABORTED,
  1612. ERROR_NETWORK_UNREACHABLE,
  1613. ERROR_HOST_UNREACHABLE,
  1614. ERROR_BAD_NETPATH,
  1615. ERROR_REM_NOT_LIST,
  1616. ERROR_ACCESS_DENIED,
  1617. ERROR_NOT_ENOUGH_QUOTA,
  1618. ERROR_LOGON_FAILURE,
  1619. ERROR_TIME_SKEW,
  1620. ERROR_PIPE_NOT_CONNECTED,
  1621. ERROR_WORKING_SET_QUOTA,
  1622. ERROR_NOT_ENOUGH_SERVER_MEMORY,
  1623. ERROR_INVALID_NETNAME,
  1624. ERROR_BAD_COMMAND,
  1625. ERROR_WORKING_SET_QUOTA
  1626. } END_VALIDATE;
  1627. status = RPC_P_RECEIVE_FAILED;
  1628. }
  1629. p->NMP_CONNECTION::Abort();
  1630. return(status);
  1631. }
  1632. // More data to read.
  1633. ASSERT(p->Read.ol.InternalHigh == p->maxReadBuffer);
  1634. ASSERT(MessageLength((PCONN_RPC_HEADER)p->pReadBuffer) > p->maxReadBuffer);
  1635. bytes = p->maxReadBuffer;
  1636. status = p->ProcessRead(bytes, pOutputBuffer, pOutputBufferSize);
  1637. if (status == RPC_P_PARTIAL_RECEIVE)
  1638. {
  1639. // More to arrive, submit a read for all of it.
  1640. status = CO_SubmitSyncRead(p, pOutputBuffer, pOutputBufferSize);
  1641. if (status == RPC_P_IO_PENDING)
  1642. {
  1643. status = UTIL_GetOverlappedResult(p, &p->Read.ol, &bytes);
  1644. // Since we read all the expected data and np is message mode
  1645. // this should either fail or give back all the data.
  1646. ASSERT(status != ERROR_MORE_DATA);
  1647. if (status == RPC_S_OK)
  1648. {
  1649. status = p->ProcessRead(bytes, pOutputBuffer, pOutputBufferSize);
  1650. ASSERT(status != RPC_P_PARTIAL_RECEIVE);
  1651. }
  1652. }
  1653. }
  1654. if (status != RPC_S_OK)
  1655. {
  1656. RpcpErrorAddRecord(EEInfoGCNMP,
  1657. status,
  1658. EEInfoDLNMPSyncSendReceive20,
  1659. (ULONGLONG)p,
  1660. (ULONGLONG)InputBuffer,
  1661. InputBufferSize);
  1662. p->NMP_CONNECTION::Abort();
  1663. if (status != RPC_P_TIMEOUT)
  1664. {
  1665. RpcpErrorAddRecord(EEInfoGCRuntime,
  1666. RPC_P_RECEIVE_FAILED,
  1667. EEInfoDLNMPSyncSendReceive30,
  1668. status);
  1669. return(RPC_P_RECEIVE_FAILED);
  1670. }
  1671. else
  1672. return (status);
  1673. }
  1674. ASSERT(*pOutputBufferSize == MessageLength((PCONN_RPC_HEADER)*pOutputBuffer));
  1675. ASSERT(p->pReadBuffer == 0);
  1676. return(RPC_S_OK);
  1677. }
  1678. RPC_STATUS
  1679. RPC_ENTRY
  1680. NMP_SyncSendRecv_Avrf(
  1681. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  1682. IN UINT InputBufferSize,
  1683. IN BUFFER InputBuffer,
  1684. OUT PUINT pOutputBufferSize,
  1685. OUT BUFFER *pOutputBuffer
  1686. )
  1687. /*++
  1688. Routine Description:
  1689. Wrapper for NMP_SyncSendRecv implementing corruption injection
  1690. under the RPC verifier.
  1691. SyncSendRecv member of the transport interface may only be called
  1692. by the cliet, hence we inject the corruption for a client receive.
  1693. Arguments:
  1694. Return Value:
  1695. --*/
  1696. {
  1697. RPC_STATUS Status;
  1698. Status = NMP_SyncSendRecv(
  1699. ThisConnection,
  1700. InputBufferSize,
  1701. InputBuffer,
  1702. pOutputBufferSize,
  1703. pOutputBuffer);
  1704. if (!Status)
  1705. {
  1706. if (gfRPCVerifierEnabled)
  1707. {
  1708. CorruptionInject(ClientReceive,
  1709. pOutputBufferSize,
  1710. (void **)pOutputBuffer);
  1711. }
  1712. }
  1713. return Status;
  1714. }
  1715. RPC_STATUS RPC_ENTRY NMP_Abort(IN RPC_TRANSPORT_CONNECTION Connection)
  1716. {
  1717. return ((NMP_CONNECTION *)Connection)->NMP_CONNECTION::Abort();
  1718. }
  1719. const RPC_CONNECTION_TRANSPORT
  1720. NMP_TransportInterface = {
  1721. RPC_TRANSPORT_INTERFACE_VERSION,
  1722. NMP_TOWER_ID,
  1723. UNC_ADDRESS_ID,
  1724. RPC_STRING_LITERAL("ncacn_np"),
  1725. "\\pipe\\epmapper",
  1726. COMMON_ProcessCalls,
  1727. COMMON_StartPnpNotifications,
  1728. COMMON_ListenForPNPNotifications,
  1729. COMMON_TowerConstruct,
  1730. COMMON_TowerExplode,
  1731. COMMON_PostRuntimeEvent,
  1732. FALSE,
  1733. NMP_GetNetworkAddressVector,
  1734. sizeof(NMP_ADDRESS),
  1735. sizeof(NMP_CONNECTION),
  1736. sizeof(NMP_CONNECTION),
  1737. sizeof(CO_SEND_CONTEXT),
  1738. 0,
  1739. NMP_MAX_SEND,
  1740. NMP_Initialize,
  1741. 0,
  1742. NMP_Open,
  1743. NMP_SyncSendRecv,
  1744. CO_SyncRecv,
  1745. NMP_Abort,
  1746. NMP_Close,
  1747. CO_Send,
  1748. CO_Recv,
  1749. NMP_SyncSend,
  1750. 0, // turn on/off keep alives
  1751. NMP_ServerListen,
  1752. NMP_ServerAbortListen,
  1753. COMMON_ServerCompleteListen,
  1754. NMP_ConnectionQueryClientAddress,
  1755. 0, // query local address
  1756. NMP_ConnectionQueryClientId,
  1757. 0, // query client ip address
  1758. NMP_ConnectionImpersonateClient,
  1759. NMP_ConnectionRevertToSelf,
  1760. 0, // FreeResolverHint
  1761. 0, // CopyResolverHint
  1762. 0, // CompareResolverHint
  1763. 0 // SetLastBufferToFree
  1764. };
  1765. // When the RPC verifier is enabled and we are corrupting client receives,
  1766. // we will use a modified transport interface given below. It will have the sync
  1767. // receive members overwritten.
  1768. RPC_CONNECTION_TRANSPORT *pNMP_TransportInterface_Avrf = NULL;
  1769. const RPC_CONNECTION_TRANSPORT *
  1770. NMP_TransportLoad (
  1771. )
  1772. {
  1773. // Overwrite the SyncSendRecv and SyncRecv members of the transport interfaces if the
  1774. // RPC verifier is enabled.
  1775. if (gfRpcVerifierCorruptionInjectClientReceives)
  1776. {
  1777. // Check if we have previously initialized the Avrf transport interface.
  1778. if (pNMP_TransportInterface_Avrf == NULL)
  1779. {
  1780. // Allocate a transport interface structure to override the default.
  1781. pNMP_TransportInterface_Avrf = new (RPC_CONNECTION_TRANSPORT);
  1782. if (pNMP_TransportInterface_Avrf == NULL)
  1783. {
  1784. return NULL;
  1785. }
  1786. // Initialize the Avrf transport interface with the default values.
  1787. RpcpMemoryCopy(pNMP_TransportInterface_Avrf,
  1788. &NMP_TransportInterface,
  1789. sizeof(RPC_CONNECTION_TRANSPORT));
  1790. // Override the interface functions for sync receive.
  1791. ASSERT(pNMP_TransportInterface_Avrf->SyncSendRecv == NMP_SyncSendRecv);
  1792. pNMP_TransportInterface_Avrf->SyncSendRecv = NMP_SyncSendRecv_Avrf;
  1793. ASSERT(pNMP_TransportInterface_Avrf->SyncRecv == CO_SyncRecv);
  1794. pNMP_TransportInterface_Avrf->SyncRecv = CO_SyncRecv_Avrf;
  1795. }
  1796. return(pNMP_TransportInterface_Avrf);
  1797. }
  1798. return(&NMP_TransportInterface);
  1799. }