Source code of Windows XP (NT5)
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.

2161 lines
57 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. RPC_STATUS
  588. NMP_ServerListen(
  589. IN RPC_TRANSPORT_ADDRESS ThisAddress,
  590. IN PWSTR NetworkAddress,
  591. IN OUT PWSTR *pEndpoint,
  592. IN UINT PendingQueueSize,
  593. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  594. IN ULONG EndpointFlags,
  595. IN ULONG NICFlags,
  596. OUT NETWORK_ADDRESS_VECTOR **ppAddressVector
  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\<pid in hex (8).<counter in hex (3)>\0
  663. static LONG EndpointCounter = 0;
  664. LocalPipeEndpoint = new RPC_CHAR[3 + 6 + 8 + 1 + 3 + 1];
  665. if (NULL == LocalPipeEndpoint)
  666. {
  667. return(RPC_S_OUT_OF_MEMORY);
  668. }
  669. LONG counter;
  670. PWSTR pwstrT = LocalPipeEndpoint;
  671. *pwstrT++ = RPC_CONST_CHAR('\\');
  672. *pwstrT++ = RPC_CONST_CHAR('\\');
  673. *pwstrT++ = RPC_CONST_CHAR('.');
  674. *pwstrT++ = RPC_CONST_CHAR('\\');
  675. *pwstrT++ = RPC_CONST_CHAR('p');
  676. *pwstrT++ = RPC_CONST_CHAR('i');
  677. *pwstrT++ = RPC_CONST_CHAR('p');
  678. *pwstrT++ = RPC_CONST_CHAR('e');
  679. *pwstrT++ = RPC_CONST_CHAR('\\');
  680. pwstrT = ULongToHexString(pwstrT, GetCurrentProcessId());
  681. *pwstrT++ = RPC_CONST_CHAR('.');
  682. counter = InterlockedExchangeAdd(&EndpointCounter, 1);
  683. *pwstrT++ = HexDigits[(counter >> 8) & 0x0F];
  684. *pwstrT++ = HexDigits[(counter >> 4) & 0x0F];
  685. *pwstrT++ = HexDigits[counter & 0x0F];
  686. *pwstrT = 0;
  687. *pEndpoint = DuplicateString(LocalPipeEndpoint + 3);
  688. if (!(*pEndpoint))
  689. {
  690. delete LocalPipeEndpoint;
  691. return RPC_S_OUT_OF_MEMORY;
  692. }
  693. fEndpointCreated = TRUE;
  694. }
  695. // Security setup
  696. status = NMP_SetSecurity(pAddress, SecurityDescriptor);
  697. if (status != RPC_S_OK)
  698. {
  699. delete LocalPipeEndpoint;
  700. if (fEndpointCreated)
  701. delete *pEndpoint;
  702. return(status);
  703. }
  704. // Network address setup
  705. NETWORK_ADDRESS_VECTOR *pVector;
  706. pVector = new( sizeof(RPC_CHAR *)
  707. + (3 + gdwComputerNameLength) * sizeof(RPC_CHAR))
  708. NETWORK_ADDRESS_VECTOR;
  709. if (NULL == pVector)
  710. {
  711. NMP_ServerAbortListen(pAddress);
  712. delete LocalPipeEndpoint;
  713. if (fEndpointCreated)
  714. delete *pEndpoint;
  715. return(RPC_S_OUT_OF_MEMORY);
  716. }
  717. pVector->Count = 1;
  718. pVector->NetworkAddresses[0] = (RPC_CHAR *)&pVector->NetworkAddresses[1];
  719. RpcpStringCopy(pVector->NetworkAddresses[0], RPC_CONST_STRING("\\\\"));
  720. RpcpStringCat(pVector->NetworkAddresses[0], gpstrComputerName);
  721. //
  722. // Setup address
  723. //
  724. pAddress->Endpoint = LocalPipeEndpoint + 3;
  725. pAddress->LocalEndpoint = LocalPipeEndpoint;
  726. pAddress->pAddressVector = pVector;
  727. // We need to create two pipe instances to start with. This is necessary
  728. // to avoid a race where a client connects and quickly disconnects.
  729. // Before the server can submit the next connect another client fails with
  730. // RPC_S_SERVER_UNAVAILABLE. The extra pipe instance forces the client to
  731. // retry and everything works.
  732. HANDLE hSpares[2];
  733. for (i = 0; i < 2; i++)
  734. {
  735. status = NMP_CreatePipeInstance(pAddress);
  736. ASSERT(status != RPC_P_FOUND_IN_CACHE);
  737. if (status != RPC_S_OK)
  738. {
  739. ASSERT(pAddress->hConnectPipe == 0);
  740. break;
  741. }
  742. hSpares[i] = pAddress->hConnectPipe;
  743. pAddress->hConnectPipe = 0;
  744. status = COMMON_PrepareNewHandle(hSpares[i]);
  745. if (status != RPC_S_OK)
  746. {
  747. break;
  748. }
  749. }
  750. if (status != RPC_S_OK)
  751. {
  752. NMP_ServerAbortListen(pAddress);
  753. if (fEndpointCreated)
  754. delete *pEndpoint;
  755. return(status);
  756. }
  757. // Move the pipe instances back into the address.
  758. pAddress->sparePipes.CheckinHandle(&hSpares[0]);
  759. // assert that it succeeded (i.e. did not zero out the handle)
  760. ASSERT(hSpares[0] == NULL);
  761. pAddress->sparePipes.CheckinHandle(&hSpares[1]);
  762. ASSERT(hSpares[1] == NULL);
  763. //
  764. // Done with phase one, now return to the runtime and wait.
  765. //
  766. *ppAddressVector = pVector;
  767. return(RPC_S_OK);
  768. }
  769. RPC_STATUS
  770. RPC_ENTRY
  771. NMP_ConnectionImpersonateClient (
  772. IN RPC_TRANSPORT_CONNECTION SConnection
  773. )
  774. // Impersonate the client at the other end of the connection.
  775. {
  776. NMP_CONNECTION *p = (NMP_CONNECTION *)SConnection;
  777. BOOL b;
  778. p->StartingOtherIO();
  779. if (p->fAborted)
  780. {
  781. p->OtherIOFinished();
  782. return(RPC_S_NO_CONTEXT_AVAILABLE);
  783. }
  784. b = ImpersonateNamedPipeClient(p->Conn.Handle);
  785. p->OtherIOFinished();
  786. if (!b)
  787. {
  788. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  789. DPFLTR_WARNING_LEVEL,
  790. RPCTRANS "ImpersonateNamedPipeClient (%p) failed %d\n",
  791. p,
  792. GetLastError() ));
  793. return(RPC_S_NO_CONTEXT_AVAILABLE);
  794. }
  795. return(RPC_S_OK);
  796. }
  797. RPC_STATUS
  798. RPC_ENTRY
  799. NMP_ConnectionRevertToSelf (
  800. RPC_TRANSPORT_CONNECTION SConnection
  801. )
  802. /*++
  803. Routine Description:
  804. We want to stop impersonating the client. This means we want
  805. the current thread's security context to revert the the
  806. default.
  807. Arguments:
  808. SConnection - unused
  809. Return Value:
  810. RPC_S_OK
  811. RPC_S_INTERNAL_ERROR - Not impersonating or something else went wrong.
  812. (Debug systems only)
  813. --*/
  814. {
  815. BOOL b;
  816. UNUSED(SConnection);
  817. b = RevertToSelf();
  818. #if DBG
  819. if (!b)
  820. {
  821. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  822. DPFLTR_WARNING_LEVEL,
  823. RPCTRANS "RevertToSelf failed %d\n",
  824. GetLastError()));
  825. ASSERT(b);
  826. return(RPC_S_INTERNAL_ERROR);
  827. }
  828. #endif
  829. return(RPC_S_OK);
  830. }
  831. RPC_STATUS RPC_ENTRY
  832. NMP_ConnectionQueryClientAddress(
  833. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  834. OUT RPC_CHAR **pNetworkAddress
  835. )
  836. /*++
  837. Routine Description:
  838. Returns the address of the client. Uses an extended in NT 5
  839. ioctl to reterive the client machine name from named pipes.
  840. Arguments:
  841. ThisConnection - The server connection of interest.
  842. NetworkAddress - Will contain the string on success.
  843. Return Value:
  844. RPC_S_OK
  845. RPC_S_OUT_OF_RESOURCES
  846. RPC_S_OUT_OF_MEMORY
  847. --*/
  848. {
  849. NTSTATUS NtStatus;
  850. RPC_STATUS status;
  851. IO_STATUS_BLOCK IoStatus;
  852. NMP_CONNECTION *p = (NMP_CONNECTION *)ThisConnection;
  853. FILE_PIPE_CLIENT_PROCESS_BUFFER_EX ClientProcess;
  854. HANDLE hEvent = I_RpcTransGetThreadEvent();
  855. DWORD size;
  856. ClientProcess.ClientComputerNameLength = 0;
  857. ASSERT(hEvent);
  858. p->StartingOtherIO();
  859. if (p->fAborted)
  860. {
  861. p->OtherIOFinished();
  862. return(RPC_S_NO_CONTEXT_AVAILABLE);
  863. }
  864. NtStatus = NtFsControlFile(p->Conn.Handle,
  865. hEvent,
  866. 0,
  867. 0,
  868. &IoStatus,
  869. FSCTL_PIPE_QUERY_CLIENT_PROCESS,
  870. 0,
  871. 0,
  872. &ClientProcess,
  873. sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER_EX));
  874. p->OtherIOFinished();
  875. if (NtStatus == STATUS_PENDING)
  876. {
  877. status = WaitForSingleObject(hEvent, INFINITE);
  878. ASSERT(status == WAIT_OBJECT_0);
  879. if (status != WAIT_OBJECT_0)
  880. {
  881. return(RPC_S_OUT_OF_RESOURCES);
  882. }
  883. }
  884. if (!NT_SUCCESS(NtStatus))
  885. {
  886. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  887. DPFLTR_WARNING_LEVEL,
  888. RPCTRANS "QUERY_PIPE_PROCESS ioctl failed %x\n",
  889. NtStatus));
  890. return(RPC_S_OUT_OF_RESOURCES);
  891. }
  892. if (ClientProcess.ClientComputerNameLength == 0)
  893. {
  894. // Must be local, no ID. Just copy the local computer name into the
  895. // buffer and continue.
  896. size = gdwComputerNameLength; // Includes null
  897. wcscpy(ClientProcess.ClientComputerBuffer, gpstrComputerName);
  898. }
  899. else
  900. {
  901. ASSERT(wcslen(ClientProcess.ClientComputerBuffer) < 16);
  902. // Convert from bytes to characters, add one for the null.
  903. size = ClientProcess.ClientComputerNameLength/2 + 1;
  904. }
  905. *pNetworkAddress = new WCHAR[size];
  906. if (!*pNetworkAddress)
  907. {
  908. return(RPC_S_OUT_OF_MEMORY);
  909. }
  910. wcscpy(*pNetworkAddress, ClientProcess.ClientComputerBuffer);
  911. return(RPC_S_OK);
  912. }
  913. RPC_STATUS RPC_ENTRY
  914. NMP_ConnectionQueryClientId (
  915. IN RPC_TRANSPORT_CONNECTION SConnection,
  916. OUT RPC_CLIENT_PROCESS_IDENTIFIER * ClientProcess
  917. )
  918. /*++
  919. Routine Description:
  920. We want to query the identifier of the client process at the other
  921. of this named pipe. Two pipes from the same client process will always
  922. return the same identifier for their client process. Likewise, two
  923. pipes from different client processes will never return the same
  924. identifier for their respective client process.
  925. This is one of the few things you can't do in win32.
  926. Arguments:
  927. SConnection - Supplies the named pipe instance for which we want to
  928. obtain the client process identifier.
  929. ClientProcess - Returns the identifier for the client process at the
  930. other end of this named pipe instance.
  931. Return Value:
  932. RPC_S_OK - This value will always be returned.
  933. --*/
  934. {
  935. NTSTATUS NtStatus;
  936. RPC_STATUS status;
  937. IO_STATUS_BLOCK IoStatus;
  938. NMP_CONNECTION *p = (NMP_CONNECTION *)SConnection;
  939. FILE_PIPE_CLIENT_PROCESS_BUFFER ClientProcessBuffer;
  940. HANDLE hEvent = I_RpcTransGetThreadEvent();
  941. BOOL fLocal;
  942. ClientProcess->ZeroOut();
  943. ASSERT(hEvent);
  944. p->StartingOtherIO();
  945. if (p->fAborted)
  946. {
  947. p->OtherIOFinished();
  948. return(RPC_S_NO_CONTEXT_AVAILABLE);
  949. }
  950. NtStatus = NtFsControlFile(p->Conn.Handle,
  951. hEvent,
  952. 0,
  953. 0,
  954. &IoStatus,
  955. FSCTL_PIPE_QUERY_CLIENT_PROCESS,
  956. 0,
  957. 0,
  958. &ClientProcessBuffer,
  959. sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER));
  960. p->OtherIOFinished();
  961. if (NtStatus == STATUS_PENDING)
  962. {
  963. status = WaitForSingleObject(hEvent, INFINITE);
  964. ASSERT(status == WAIT_OBJECT_0);
  965. if (status != WAIT_OBJECT_0)
  966. {
  967. return(RPC_S_OUT_OF_RESOURCES);
  968. }
  969. }
  970. if (NT_SUCCESS(NtStatus))
  971. {
  972. if (ClientProcessBuffer.ClientSession)
  973. {
  974. ClientProcessBuffer.ClientSession = 0;
  975. fLocal = FALSE;
  976. }
  977. else
  978. fLocal = TRUE;
  979. ClientProcess->SetNMPClientIdentifier(&ClientProcessBuffer, fLocal);
  980. }
  981. return(RPC_S_OK);
  982. }
  983. RPC_STATUS
  984. RPC_ENTRY
  985. NMP_Initialize (
  986. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  987. IN RPC_CHAR * NetworkAddress,
  988. IN RPC_CHAR * NetworkOptions,
  989. IN BOOL fAsync
  990. )
  991. /*++
  992. Routine Description:
  993. Initialize the connection. This function is guaranteed to be called
  994. in the thread that called GetBuffer.
  995. Arguments:
  996. ThisConnection - A place to store the connection
  997. */
  998. {
  999. PNMP_CONNECTION pConnection = (PNMP_CONNECTION)ThisConnection;
  1000. // use explicit placement to initialize vtbl
  1001. pConnection = new (pConnection) NMP_CONNECTION;
  1002. pConnection->id = NMP;
  1003. pConnection->Initialize();
  1004. pConnection->pAddress = 0;
  1005. return RPC_S_OK;
  1006. }
  1007. RPC_STATUS
  1008. RPC_ENTRY
  1009. NMP_Open(
  1010. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  1011. IN RPC_CHAR * ProtocolSequence,
  1012. IN RPC_CHAR * NetworkAddress,
  1013. IN RPC_CHAR * Endpoint,
  1014. IN RPC_CHAR * NetworkOptions,
  1015. IN UINT ConnTimeout,
  1016. IN UINT SendBufferSize,
  1017. IN UINT RecvBufferSize,
  1018. IN void *ResolverHint,
  1019. IN BOOL fHintInitialized,
  1020. IN ULONG CallTimeout,
  1021. IN ULONG AdditionalTransportCredentialsType, OPTIONAL
  1022. IN void *AdditionalCredentials OPTIONAL
  1023. )
  1024. /*++
  1025. Routine Description:
  1026. Opens a connection to a server.
  1027. Arguments:
  1028. ThisConnection - A place to store the connection
  1029. ProtocolSeqeunce - "ncacn_np"
  1030. NetworkAddress - The name of the server, with or without the '\\'
  1031. NetworkOptions - Options from the string binding. For security:
  1032. security=
  1033. [anonymous|identification|impersonation|delegation]
  1034. [dynamic|static]
  1035. [true|false]
  1036. All three fields must be present. To specify impersonation
  1037. with dynamic tracking and effective only, use the following
  1038. string for the network options.
  1039. "security=impersonation dynamic true"
  1040. ConnTimeout - See RpcMgmtSetComTimeout
  1041. 0 - Min
  1042. 5 - Default
  1043. 9 - Max
  1044. 10 - Infinite
  1045. {Send,Recv}BufferSize - Ignored.
  1046. CallTimeout - call timeout in milliseconds. Ignored for named pipes.
  1047. AdditionalTransportCredentialsType - the type of additional credentials that we were
  1048. given. Not used for named pipes.
  1049. AdditionalCredentials - additional credentials that we were given.
  1050. Not used for named pipes.
  1051. Return Value:
  1052. RPC_S_OK
  1053. RPC_S_OUT_OF_MEMORY
  1054. RPC_S_OUT_OF_RESOURCES
  1055. RPC_S_INVALID_NETWORK_OPTIONS
  1056. RPC_S_SERVER_UNAVAILABLE
  1057. RPC_S_INVALID_ENDPOINT_FORMAT
  1058. RPC_S_INVALID_NET_ADDR
  1059. --*/
  1060. {
  1061. RPC_STATUS Status;
  1062. PNMP_CONNECTION pConnection = (PNMP_CONNECTION)ThisConnection;
  1063. BOOL f;
  1064. HANDLE hPipe;
  1065. DWORD SecurityQOSFlags = 0;
  1066. NTSTATUS NtStatus;
  1067. UINT AddressLen ;
  1068. UINT EndpointLen;
  1069. HANDLE ImpersonationToken = 0;
  1070. DWORD StartTickCount;
  1071. DWORD RetryCount;
  1072. BOOL fLocalAddress = FALSE;
  1073. if ((AdditionalTransportCredentialsType != 0) || (AdditionalCredentials != NULL))
  1074. return RPC_S_CANNOT_SUPPORT;
  1075. if (NetworkOptions && *NetworkOptions)
  1076. {
  1077. //
  1078. // Enable transport level security.
  1079. //
  1080. // By default named pipes (CreateFile) uses security with impersonation,
  1081. // dynamic tracking and effective only enabled.
  1082. //
  1083. // RPC level security sits on top of this and provides other features.
  1084. //
  1085. // Named pipes security is controlled via an options string in the string
  1086. // binding. The runtime exports an API to parse the string which is used
  1087. // here to do most of the work.
  1088. //
  1089. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  1090. Status = I_RpcParseSecurity(NetworkOptions,
  1091. &SecurityQualityOfService);
  1092. if ( Status != RPC_S_OK )
  1093. {
  1094. ASSERT( Status == RPC_S_INVALID_NETWORK_OPTIONS );
  1095. goto Cleanup;
  1096. }
  1097. // Convert into SecurityQOS into CreateFile flags
  1098. ASSERT(SECURITY_ANONYMOUS == (SecurityAnonymous <<16));
  1099. ASSERT(SECURITY_IDENTIFICATION == (SecurityIdentification <<16));
  1100. ASSERT(SECURITY_IMPERSONATION == (SecurityImpersonation <<16));
  1101. ASSERT(SECURITY_DELEGATION == (SecurityDelegation <<16));
  1102. SecurityQOSFlags = SECURITY_SQOS_PRESENT
  1103. | (SecurityQualityOfService.ImpersonationLevel << 16);
  1104. SecurityQOSFlags |= (SecurityQualityOfService.ContextTrackingMode
  1105. != SECURITY_STATIC_TRACKING) ? SECURITY_CONTEXT_TRACKING : 0;
  1106. SecurityQOSFlags |= (SecurityQualityOfService.EffectiveOnly)
  1107. ? SECURITY_EFFECTIVE_ONLY : 0;
  1108. }
  1109. ASSERT(NetworkAddress);
  1110. if (NetworkAddress[0] == '\\')
  1111. {
  1112. if ( NetworkAddress[1] == '\\'
  1113. && NetworkAddress[2] != '\0'
  1114. && NetworkAddress[3] != '\\')
  1115. {
  1116. NetworkAddress += 2;
  1117. }
  1118. else
  1119. {
  1120. RpcpErrorAddRecord(EEInfoGCRuntime,
  1121. RPC_S_INVALID_NET_ADDR,
  1122. EEInfoDLNMPOpen30,
  1123. NetworkAddress);
  1124. Status = RPC_S_INVALID_NET_ADDR;
  1125. goto Cleanup;
  1126. }
  1127. }
  1128. if ( (NetworkAddress[0] == 0)
  1129. || (RpcpStringCompare(NetworkAddress, gpstrComputerName) == 0) )
  1130. {
  1131. NetworkAddress = RPC_STRING_LITERAL(".");
  1132. fLocalAddress = TRUE;
  1133. }
  1134. ASSERT(Endpoint);
  1135. if ( Endpoint[0] != 0
  1136. && RpcpStringNCompare(Endpoint, RPC_CONST_STRING("\\pipe\\"), 6) != 0)
  1137. {
  1138. Status = RPC_S_INVALID_ENDPOINT_FORMAT;
  1139. goto Cleanup;
  1140. }
  1141. AddressLen = RpcpStringLength(NetworkAddress);
  1142. EndpointLen = RpcpStringLength(Endpoint);
  1143. RPC_CHAR *TransportAddress;
  1144. TransportAddress = (RPC_CHAR *)alloca( (2 + AddressLen + EndpointLen + 1)
  1145. * sizeof(RPC_CHAR) );
  1146. TransportAddress[0] = TransportAddress[1] = '\\';
  1147. memcpy(TransportAddress + 2,
  1148. NetworkAddress,
  1149. AddressLen * sizeof(RPC_CHAR));
  1150. memcpy(TransportAddress + 2 + AddressLen,
  1151. Endpoint,
  1152. (EndpointLen + 1) * sizeof(RPC_CHAR));
  1153. ASSERT( ((long)ConnTimeout >= RPC_C_BINDING_MIN_TIMEOUT)
  1154. && (ConnTimeout <= RPC_C_BINDING_INFINITE_TIMEOUT));
  1155. StartTickCount = GetTickCount();
  1156. RetryCount = 0;
  1157. do
  1158. {
  1159. hPipe = CreateFile((RPC_SCHAR *)TransportAddress,
  1160. GENERIC_READ | GENERIC_WRITE,
  1161. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1162. 0,
  1163. OPEN_EXISTING,
  1164. FILE_FLAG_OVERLAPPED | SecurityQOSFlags,
  1165. 0
  1166. );
  1167. if (hPipe != INVALID_HANDLE_VALUE)
  1168. {
  1169. DWORD Mode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
  1170. f = SetNamedPipeHandleState(hPipe, &Mode, 0, 0);
  1171. if (f)
  1172. {
  1173. Status = COMMON_PrepareNewHandle(hPipe);
  1174. if (Status == RPC_S_OK)
  1175. {
  1176. break;
  1177. }
  1178. else
  1179. {
  1180. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  1181. DPFLTR_WARNING_LEVEL,
  1182. RPCTRANS "COMMON_PrepareNewHandle: %d\n",
  1183. GetLastError()));
  1184. }
  1185. }
  1186. else
  1187. {
  1188. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  1189. DPFLTR_WARNING_LEVEL,
  1190. RPCTRANS "SetNamedPipeHandleState: %d\n",
  1191. GetLastError()));
  1192. Status = GetLastError();
  1193. }
  1194. CloseHandle(hPipe);
  1195. hPipe = INVALID_HANDLE_VALUE;
  1196. }
  1197. else
  1198. {
  1199. Status = GetLastError();
  1200. }
  1201. if (Status != ERROR_PIPE_BUSY)
  1202. {
  1203. RpcpErrorAddRecord(fLocalAddress ? EEInfoGCNPFS : EEInfoGCRDR,
  1204. Status,
  1205. EEInfoDLNMPOpen10,
  1206. TransportAddress,
  1207. SecurityQOSFlags);
  1208. switch(Status)
  1209. {
  1210. case ERROR_INVALID_NAME:
  1211. Status = RPC_S_INVALID_ENDPOINT_FORMAT;
  1212. break;
  1213. case ERROR_BAD_NET_NAME:
  1214. case ERROR_INVALID_NETNAME:
  1215. Status = RPC_S_INVALID_NET_ADDR;
  1216. break;
  1217. case ERROR_NOT_ENOUGH_MEMORY:
  1218. case ERROR_NOT_ENOUGH_QUOTA:
  1219. case ERROR_COMMITMENT_LIMIT:
  1220. case ERROR_TOO_MANY_OPEN_FILES:
  1221. case ERROR_OUTOFMEMORY:
  1222. Status = RPC_S_OUT_OF_MEMORY;
  1223. break;
  1224. case ERROR_NOT_ENOUGH_SERVER_MEMORY:
  1225. Status = RPC_S_SERVER_OUT_OF_MEMORY;
  1226. break;
  1227. case ERROR_NO_SYSTEM_RESOURCES:
  1228. case ERROR_WORKING_SET_QUOTA:
  1229. Status = RPC_S_OUT_OF_RESOURCES;
  1230. break;
  1231. case ERROR_ACCESS_DENIED:
  1232. case ERROR_ACCOUNT_EXPIRED:
  1233. case ERROR_ACCOUNT_RESTRICTION:
  1234. case ERROR_ACCOUNT_LOCKED_OUT:
  1235. case ERROR_ACCOUNT_DISABLED:
  1236. case ERROR_NO_SUCH_USER:
  1237. case ERROR_BAD_IMPERSONATION_LEVEL:
  1238. case ERROR_BAD_LOGON_SESSION_STATE:
  1239. case ERROR_INVALID_PASSWORD:
  1240. case ERROR_INVALID_LOGON_HOURS:
  1241. case ERROR_INVALID_WORKSTATION:
  1242. case ERROR_INVALID_SERVER_STATE:
  1243. case ERROR_INVALID_DOMAIN_STATE:
  1244. case ERROR_INVALID_DOMAIN_ROLE:
  1245. case ERROR_LOGON_FAILURE:
  1246. case ERROR_LICENSE_QUOTA_EXCEEDED:
  1247. case ERROR_LOGON_NOT_GRANTED:
  1248. case ERROR_LOGON_TYPE_NOT_GRANTED:
  1249. case ERROR_MUTUAL_AUTH_FAILED:
  1250. case ERROR_NETWORK_ACCESS_DENIED:
  1251. case ERROR_NO_SUCH_DOMAIN:
  1252. case ERROR_NO_SUCH_LOGON_SESSION:
  1253. case ERROR_NO_LOGON_SERVERS:
  1254. case ERROR_NO_TRUST_SAM_ACCOUNT:
  1255. case ERROR_PASSWORD_EXPIRED:
  1256. case ERROR_PASSWORD_MUST_CHANGE:
  1257. case ERROR_TRUSTED_DOMAIN_FAILURE:
  1258. case ERROR_TRUSTED_RELATIONSHIP_FAILURE:
  1259. case ERROR_WRONG_TARGET_NAME:
  1260. case ERROR_WRONG_PASSWORD:
  1261. case ERROR_TIME_SKEW:
  1262. case ERROR_NO_TRUST_LSA_SECRET:
  1263. case ERROR_LOGIN_WKSTA_RESTRICTION:
  1264. case ERROR_SHUTDOWN_IN_PROGRESS:
  1265. case ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT:
  1266. case ERROR_DOWNGRADE_DETECTED:
  1267. case ERROR_CONTEXT_EXPIRED:
  1268. Status = RPC_S_ACCESS_DENIED;
  1269. break;
  1270. //case ERROR_INTERNAL_ERROR:
  1271. case ERROR_NOACCESS:
  1272. // Really unexpected errors - fall into default on retail.
  1273. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  1274. DPFLTR_WARNING_LEVEL,
  1275. RPCTRANS "Unexpected error: %d\n",
  1276. Status));
  1277. ASSERT(0);
  1278. default:
  1279. VALIDATE(Status)
  1280. {
  1281. ERROR_REM_NOT_LIST,
  1282. ERROR_SHARING_PAUSED,
  1283. ERROR_NETNAME_DELETED,
  1284. ERROR_SEM_TIMEOUT,
  1285. ERROR_FILE_NOT_FOUND,
  1286. ERROR_PATH_NOT_FOUND,
  1287. ERROR_BAD_NETPATH,
  1288. ERROR_NETWORK_UNREACHABLE,
  1289. ERROR_UNEXP_NET_ERR,
  1290. ERROR_REQ_NOT_ACCEP,
  1291. ERROR_GEN_FAILURE,
  1292. ERROR_BAD_NET_RESP,
  1293. ERROR_PIPE_NOT_CONNECTED,
  1294. ERROR_NETLOGON_NOT_STARTED,
  1295. ERROR_DOMAIN_CONTROLLER_NOT_FOUND,
  1296. ERROR_CONNECTION_ABORTED,
  1297. ERROR_CONNECTION_INVALID,
  1298. ERROR_HOST_UNREACHABLE,
  1299. ERROR_CANT_ACCESS_DOMAIN_INFO,
  1300. ERROR_DUP_NAME,
  1301. ERROR_NO_SUCH_PACKAGE,
  1302. ERROR_INVALID_FUNCTION,
  1303. ERROR_BAD_DEV_TYPE
  1304. } END_VALIDATE;
  1305. Status = RPC_S_SERVER_UNAVAILABLE;
  1306. break;
  1307. }
  1308. RpcpErrorAddRecord(EEInfoGCRuntime,
  1309. Status,
  1310. EEInfoDLNMPOpen40);
  1311. goto Cleanup;
  1312. }
  1313. ASSERT(hPipe == INVALID_HANDLE_VALUE);
  1314. // No pipe instances available, wait for one to show up...
  1315. WaitNamedPipe((RPC_SCHAR *)TransportAddress, 1000);
  1316. // attempt the connect for at least 40 seconds and at least 20 times
  1317. // note that since this is DWORD, even if the counter has wrapped
  1318. // the difference will be accurate
  1319. RetryCount ++;
  1320. }
  1321. while ((GetTickCount() - StartTickCount < 40000) || (RetryCount <= 20));
  1322. if (hPipe == INVALID_HANDLE_VALUE)
  1323. {
  1324. Status = RPC_S_SERVER_TOO_BUSY;
  1325. RpcpErrorAddRecord(fLocalAddress ? EEInfoGCNPFS : EEInfoGCRDR,
  1326. Status,
  1327. EEInfoDLNMPOpen20,
  1328. TransportAddress);
  1329. // No instances available
  1330. goto Cleanup;
  1331. }
  1332. // Pipe opened successfully
  1333. pConnection->Conn.Handle = hPipe;
  1334. pConnection->fAborted = 0;
  1335. pConnection->pReadBuffer = 0;
  1336. pConnection->maxReadBuffer = 0;
  1337. pConnection->iPostSize = gPostSize;
  1338. pConnection->iLastRead = 0;
  1339. memset(&pConnection->Read.ol, 0, sizeof(pConnection->Read.ol));
  1340. pConnection->Read.pAsyncObject = pConnection;
  1341. pConnection->Read.thread = 0;
  1342. pConnection->Read.ol.Internal = 0;
  1343. pConnection->InitIoCounter();
  1344. pConnection->pAddress = 0;
  1345. Status = RPC_S_OK;
  1346. Cleanup:
  1347. return(Status);
  1348. }
  1349. RPC_STATUS
  1350. RPC_ENTRY
  1351. NMP_SyncSend(
  1352. IN RPC_TRANSPORT_CONNECTION Connection,
  1353. IN UINT BufferLength,
  1354. IN BUFFER Buffer,
  1355. IN BOOL fDisableShutdownCheck,
  1356. IN BOOL fDisableCancelCheck,
  1357. ULONG Timeout
  1358. )
  1359. /*++
  1360. Routine Description:
  1361. Sends a message on the connection. This method must appear
  1362. to be synchronous from the callers perspective.
  1363. Arguments:
  1364. pConnection - The connection.
  1365. Buffer - The data to send.
  1366. BufferLength - The size of the buffer.
  1367. fDisableShutdownCheck - N/A to named pipes.
  1368. Return Value:
  1369. RPC_S_OK - Data sent
  1370. RPC_P_SEND_FAILED - Connection will be aborted if this is returned.
  1371. RPC_S_CALL_CANCELLED - The call was cancelled
  1372. --*/
  1373. {
  1374. NMP_CONNECTION *p = (NMP_CONNECTION *)Connection;
  1375. DWORD bytes;
  1376. RPC_STATUS status;
  1377. OVERLAPPED olWrite;
  1378. HANDLE hEvent;
  1379. BOOL fPendingReturned = FALSE;
  1380. hEvent = I_RpcTransGetThreadEvent();
  1381. ASSERT(hEvent);
  1382. p->StartingWriteIO();
  1383. if (p->fAborted)
  1384. {
  1385. p->WriteIOFinished();
  1386. return(RPC_P_SEND_FAILED);
  1387. }
  1388. // Setting the low bit of the event indicates that the write
  1389. // completion should NOT be sent to the i/o completion port.
  1390. olWrite.Internal = 0;
  1391. olWrite.InternalHigh = 0;
  1392. olWrite.Offset = 0;
  1393. olWrite.OffsetHigh = 0;
  1394. olWrite.hEvent = (HANDLE) ((ULONG_PTR)hEvent | 0x1);
  1395. #ifdef _INTERNAL_RPC_BUILD_
  1396. if (gpfnFilter)
  1397. {
  1398. (*gpfnFilter) (Buffer, BufferLength, 0);
  1399. }
  1400. #endif
  1401. status = p->NMP_CONNECTION::Send(p->Conn.Handle,
  1402. Buffer,
  1403. BufferLength,
  1404. &bytes,
  1405. &olWrite
  1406. );
  1407. p->WriteIOFinished();
  1408. if (status == RPC_S_OK)
  1409. {
  1410. ASSERT(bytes == BufferLength);
  1411. return(RPC_S_OK);
  1412. }
  1413. if (status == ERROR_IO_PENDING)
  1414. {
  1415. fPendingReturned = TRUE;
  1416. // if fDisableCancelCheck - not alertable. Else, alertable.
  1417. status = UTIL_GetOverlappedResultEx(Connection,
  1418. &olWrite,
  1419. &bytes,
  1420. (fDisableCancelCheck ? FALSE : TRUE),
  1421. Timeout);
  1422. if (status == RPC_S_OK)
  1423. {
  1424. ASSERT(bytes == BufferLength);
  1425. return(RPC_S_OK);
  1426. }
  1427. }
  1428. ASSERT(status != ERROR_SUCCESS);
  1429. RpcpErrorAddRecord(EEInfoGCNMP,
  1430. status,
  1431. EEInfoDLNMPSyncSend10,
  1432. (ULONGLONG)Connection,
  1433. (ULONGLONG)Buffer,
  1434. BufferLength,
  1435. fPendingReturned);
  1436. VALIDATE(status)
  1437. {
  1438. ERROR_NETNAME_DELETED,
  1439. ERROR_GRACEFUL_DISCONNECT,
  1440. ERROR_BROKEN_PIPE,
  1441. ERROR_PIPE_NOT_CONNECTED,
  1442. ERROR_NO_DATA,
  1443. ERROR_NO_SYSTEM_RESOURCES,
  1444. ERROR_WORKING_SET_QUOTA,
  1445. ERROR_SEM_TIMEOUT,
  1446. ERROR_UNEXP_NET_ERR,
  1447. ERROR_BAD_NET_RESP,
  1448. ERROR_HOST_UNREACHABLE,
  1449. RPC_S_CALL_CANCELLED,
  1450. ERROR_CONNECTION_ABORTED,
  1451. ERROR_NOT_ENOUGH_QUOTA,
  1452. RPC_P_TIMEOUT,
  1453. ERROR_LOGON_FAILURE,
  1454. ERROR_TIME_SKEW,
  1455. ERROR_NETWORK_UNREACHABLE,
  1456. ERROR_NO_LOGON_SERVERS
  1457. } END_VALIDATE;
  1458. p->NMP_CONNECTION::Abort();
  1459. if ((status == RPC_S_CALL_CANCELLED) || (status == RPC_P_TIMEOUT))
  1460. {
  1461. // Wait for the write to finish. Since we closed the pipe
  1462. // this won't take very long.
  1463. UTIL_WaitForSyncIO(&olWrite,
  1464. FALSE,
  1465. INFINITE);
  1466. }
  1467. else
  1468. {
  1469. status = RPC_P_SEND_FAILED;
  1470. }
  1471. return(status);
  1472. }
  1473. RPC_STATUS
  1474. RPC_ENTRY
  1475. NMP_SyncSendRecv(
  1476. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  1477. IN UINT InputBufferSize,
  1478. IN BUFFER InputBuffer,
  1479. OUT PUINT pOutputBufferSize,
  1480. OUT BUFFER *pOutputBuffer
  1481. )
  1482. /*++
  1483. Routine Description:
  1484. Sends a request to the server and waits to receive the next PDU
  1485. to arrive at the connection.
  1486. Arguments:
  1487. ThisConnection - The connection to wait on.
  1488. InputBufferSize - The size of the data to send to the server.
  1489. InputBuffer - The data to send to the server
  1490. pOutputBufferSize - On return it contains the size of the PDU received.
  1491. pOutputBuffer - On return contains the PDU received.
  1492. Return Value:
  1493. RPC_S_OK
  1494. RPC_P_SEND_FAILED - Connection aborted, data did not reach the server.
  1495. RPC_P_RECEIVE_FAILED - Connection aborted, data might have reached
  1496. the server.
  1497. --*/
  1498. {
  1499. PNMP_CONNECTION p = (PNMP_CONNECTION)ThisConnection;
  1500. BOOL b;
  1501. DWORD bytes;
  1502. DWORD readbytes;
  1503. RPC_STATUS status;
  1504. HANDLE hEvent;
  1505. ASSERT(p->pReadBuffer == 0);
  1506. ASSERT(p->iLastRead == 0);
  1507. p->pReadBuffer = TransConnectionAllocatePacket(p, p->iPostSize);
  1508. if (!p->pReadBuffer)
  1509. {
  1510. p->NMP_CONNECTION::Abort();
  1511. return(RPC_P_SEND_FAILED);
  1512. }
  1513. hEvent = I_RpcTransGetThreadEvent();
  1514. ASSERT(hEvent);
  1515. p->Read.ol.hEvent = (HANDLE) ((ULONG_PTR)hEvent | 0x1);
  1516. p->maxReadBuffer = p->iPostSize;
  1517. bytes = p->maxReadBuffer;
  1518. #ifdef _INTERNAL_RPC_BUILD_
  1519. if (gpfnFilter)
  1520. {
  1521. (*gpfnFilter) (InputBuffer, InputBufferSize, 0);
  1522. }
  1523. #endif
  1524. b = TransactNamedPipe(p->Conn.Handle,
  1525. InputBuffer,
  1526. InputBufferSize,
  1527. p->pReadBuffer,
  1528. bytes,
  1529. &bytes,
  1530. &p->Read.ol
  1531. );
  1532. if (!b)
  1533. {
  1534. status = GetLastError();
  1535. if (status == ERROR_IO_PENDING)
  1536. {
  1537. status = UTIL_GetOverlappedResult(p,
  1538. &p->Read.ol,
  1539. &bytes);
  1540. }
  1541. else
  1542. {
  1543. ASSERT(status != RPC_S_OK);
  1544. }
  1545. }
  1546. else
  1547. {
  1548. status = RPC_S_OK;
  1549. }
  1550. if (status == RPC_S_OK)
  1551. {
  1552. // Success - got the whole reply in the transact
  1553. *pOutputBuffer = p->pReadBuffer;
  1554. p->pReadBuffer = 0;
  1555. *pOutputBufferSize = bytes;
  1556. ASSERT(bytes == MessageLength((PCONN_RPC_HEADER)*pOutputBuffer));
  1557. return(RPC_S_OK);
  1558. }
  1559. if (status != ERROR_MORE_DATA)
  1560. {
  1561. RpcpErrorAddRecord(EEInfoGCNMP,
  1562. status,
  1563. EEInfoDLNMPSyncSendReceive10,
  1564. (ULONGLONG)p,
  1565. (ULONGLONG)InputBuffer,
  1566. InputBufferSize);
  1567. if (status == ERROR_BAD_PIPE)
  1568. {
  1569. status = RPC_P_SEND_FAILED;
  1570. }
  1571. else
  1572. {
  1573. // surprisingly enough, ERROR_PIPE_NOT_CONNECTED can be
  1574. // returned if the server died midway through the
  1575. // operation.
  1576. VALIDATE(status)
  1577. {
  1578. ERROR_NETNAME_DELETED,
  1579. ERROR_GRACEFUL_DISCONNECT,
  1580. ERROR_BROKEN_PIPE,
  1581. ERROR_PIPE_BUSY,
  1582. ERROR_NO_DATA,
  1583. ERROR_NO_SYSTEM_RESOURCES,
  1584. ERROR_SEM_TIMEOUT,
  1585. ERROR_UNEXP_NET_ERR,
  1586. ERROR_BAD_NET_RESP,
  1587. ERROR_CONNECTION_ABORTED,
  1588. ERROR_NETWORK_UNREACHABLE,
  1589. ERROR_HOST_UNREACHABLE,
  1590. ERROR_BAD_NETPATH,
  1591. ERROR_REM_NOT_LIST,
  1592. ERROR_ACCESS_DENIED,
  1593. ERROR_NOT_ENOUGH_QUOTA,
  1594. ERROR_LOGON_FAILURE,
  1595. ERROR_TIME_SKEW,
  1596. ERROR_PIPE_NOT_CONNECTED
  1597. } END_VALIDATE;
  1598. status = RPC_P_RECEIVE_FAILED;
  1599. }
  1600. p->NMP_CONNECTION::Abort();
  1601. return(status);
  1602. }
  1603. // More data to read.
  1604. ASSERT(p->Read.ol.InternalHigh == p->maxReadBuffer);
  1605. ASSERT(MessageLength((PCONN_RPC_HEADER)p->pReadBuffer) > p->maxReadBuffer);
  1606. bytes = p->maxReadBuffer;
  1607. status = p->ProcessRead(bytes, pOutputBuffer, pOutputBufferSize);
  1608. if (status == RPC_P_PARTIAL_RECEIVE)
  1609. {
  1610. // More to arrive, submit a read for all of it.
  1611. status = CO_SubmitSyncRead(p, pOutputBuffer, pOutputBufferSize);
  1612. if (status == RPC_P_IO_PENDING)
  1613. {
  1614. status = UTIL_GetOverlappedResult(p, &p->Read.ol, &bytes);
  1615. // Since we read all the expected data and np is message mode
  1616. // this should either fail or give back all the data.
  1617. ASSERT(status != ERROR_MORE_DATA);
  1618. if (status == RPC_S_OK)
  1619. {
  1620. status = p->ProcessRead(bytes, pOutputBuffer, pOutputBufferSize);
  1621. ASSERT(status != RPC_P_PARTIAL_RECEIVE);
  1622. }
  1623. }
  1624. }
  1625. if (status != RPC_S_OK)
  1626. {
  1627. RpcpErrorAddRecord(EEInfoGCNMP,
  1628. status,
  1629. EEInfoDLNMPSyncSendReceive20,
  1630. (ULONGLONG)p,
  1631. (ULONGLONG)InputBuffer,
  1632. InputBufferSize);
  1633. p->NMP_CONNECTION::Abort();
  1634. if (status != RPC_P_TIMEOUT)
  1635. {
  1636. RpcpErrorAddRecord(EEInfoGCRuntime,
  1637. RPC_P_RECEIVE_FAILED,
  1638. EEInfoDLNMPSyncSendReceive30,
  1639. status);
  1640. return(RPC_P_RECEIVE_FAILED);
  1641. }
  1642. else
  1643. return (status);
  1644. }
  1645. ASSERT(*pOutputBufferSize == MessageLength((PCONN_RPC_HEADER)*pOutputBuffer));
  1646. ASSERT(p->pReadBuffer == 0);
  1647. return(RPC_S_OK);
  1648. }
  1649. RPC_STATUS RPC_ENTRY NMP_Abort(IN RPC_TRANSPORT_CONNECTION Connection)
  1650. {
  1651. return ((NMP_CONNECTION *)Connection)->NMP_CONNECTION::Abort();
  1652. }
  1653. const RPC_CONNECTION_TRANSPORT
  1654. NMP_TransportInterface = {
  1655. RPC_TRANSPORT_INTERFACE_VERSION,
  1656. NMP_TOWER_ID,
  1657. UNC_ADDRESS_ID,
  1658. RPC_STRING_LITERAL("ncacn_np"),
  1659. "\\pipe\\epmapper",
  1660. COMMON_ProcessCalls,
  1661. COMMON_StartPnpNotifications,
  1662. COMMON_ListenForPNPNotifications,
  1663. COMMON_TowerConstruct,
  1664. COMMON_TowerExplode,
  1665. COMMON_PostRuntimeEvent,
  1666. FALSE,
  1667. sizeof(NMP_ADDRESS),
  1668. sizeof(NMP_CONNECTION),
  1669. sizeof(NMP_CONNECTION),
  1670. sizeof(CO_SEND_CONTEXT),
  1671. 0,
  1672. NMP_MAX_SEND,
  1673. NMP_Initialize,
  1674. 0,
  1675. NMP_Open,
  1676. NMP_SyncSendRecv,
  1677. CO_SyncRecv,
  1678. NMP_Abort,
  1679. NMP_Close,
  1680. CO_Send,
  1681. CO_Recv,
  1682. NMP_SyncSend,
  1683. 0, // turn on/off keep alives
  1684. NMP_ServerListen,
  1685. NMP_ServerAbortListen,
  1686. COMMON_ServerCompleteListen,
  1687. NMP_ConnectionQueryClientAddress,
  1688. 0, // query local address
  1689. NMP_ConnectionQueryClientId,
  1690. NMP_ConnectionImpersonateClient,
  1691. NMP_ConnectionRevertToSelf,
  1692. 0, // FreeResolverHint
  1693. 0, // CopyResolverHint
  1694. 0, // CompareResolverHint
  1695. 0 // SetLastBufferToFree
  1696. };
  1697. const RPC_CONNECTION_TRANSPORT *
  1698. NMP_TransportLoad (
  1699. )
  1700. {
  1701. return(&NMP_TransportInterface);
  1702. }