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.

1634 lines
42 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Remoting support.
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999-2002.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "pch.hpp"
  9. #include <lmcons.h>
  10. #define DBGRPC_SIGNATURE 'CPRD'
  11. #define DBGRPC_PROTOCOL_VERSION 2
  12. enum
  13. {
  14. SEQ_HANDSHAKE = 0xffff0000,
  15. SEQ_IDENTITY,
  16. SEQ_PASSWORD,
  17. SEQ_CALL_HEADER,
  18. };
  19. #define DBGRPC_SHAKE_FULL_REMOTE_UNKNOWN 0x00000001
  20. struct DbgRpcHandshake
  21. {
  22. ULONG Signature;
  23. ULONG ProtocolVersion;
  24. GUID DesiredObject;
  25. DbgRpcObjectId RemoteObject;
  26. ULONG IdentityLength;
  27. ULONG PasswordLength;
  28. ULONG Flags;
  29. ULONG Reserved1;
  30. ULONG64 Reserved2[10];
  31. };
  32. ULONG g_DbgRpcCallSequence;
  33. CRITICAL_SECTION g_DbgRpcLock;
  34. #define CreateUserThread(Start, Param, Tid) \
  35. CreateThread(NULL, 0, Start, Param, 0, Tid)
  36. #ifdef NT_NATIVE
  37. #define ExitUserThread(Code) RtlExitUserThread(Code)
  38. #else
  39. #define ExitUserThread(Code) return Code
  40. #endif
  41. //----------------------------------------------------------------------------
  42. //
  43. // Basic initialization.
  44. //
  45. //----------------------------------------------------------------------------
  46. BOOL
  47. DbgRpcOneTimeInitialization(void)
  48. {
  49. #if NO_DEBUGGER_RPC_BUILD
  50. return FALSE;
  51. #else
  52. static BOOL s_Initialized = FALSE;
  53. if (s_Initialized)
  54. {
  55. return TRUE;
  56. }
  57. #ifndef NT_NATIVE
  58. WSADATA WsData;
  59. if (WSAStartup(MAKEWORD(2, 0), &WsData) != 0)
  60. {
  61. return FALSE;
  62. }
  63. #endif
  64. if (InitializeAllAccessSecObj() != S_OK)
  65. {
  66. return FALSE;
  67. }
  68. __try
  69. {
  70. InitializeCriticalSection(&g_DbgRpcLock);
  71. }
  72. __except(EXCEPTION_EXECUTE_HANDLER)
  73. {
  74. return FALSE;
  75. }
  76. DbgRpcInitializeClient();
  77. s_Initialized = TRUE;
  78. return TRUE;
  79. #endif // #if NO_DEBUGGER_RPC_BUILD
  80. }
  81. //----------------------------------------------------------------------------
  82. //
  83. // DbgRpcReceiveCalls.
  84. //
  85. //----------------------------------------------------------------------------
  86. HRESULT
  87. DbgRpcReceiveCalls(DbgRpcConnection* Conn, DbgRpcCall* Call, PUCHAR* InOutData)
  88. {
  89. HRESULT Status;
  90. ULONG RetSeq = Call->Sequence;
  91. DBG_ASSERT((Call->Flags & DBGRPC_RETURN) == 0 &&
  92. *InOutData == NULL);
  93. // If this thread isn't the owner of the connection we
  94. // cannot read the socket as that could create a
  95. // race condition with the owner thread reading
  96. // the socket.
  97. // If this is a locked call, where a higher-level lock
  98. // prevents socket contention, we can allow it.
  99. if ((Call->Flags & DBGRPC_LOCKED) == 0 &&
  100. Conn->m_ThreadId != GetCurrentThreadId())
  101. {
  102. return RPC_E_WRONG_THREAD;
  103. }
  104. for (;;)
  105. {
  106. DbgRpcCall ReadCall;
  107. if (Conn->m_Trans->Read(SEQ_CALL_HEADER, &ReadCall,
  108. sizeof(ReadCall)) != sizeof(ReadCall))
  109. {
  110. DRPC_ERR(("%X: Unable to receive call header\n",
  111. GetCurrentThreadId()));
  112. return RPC_E_CLIENT_DIED;
  113. }
  114. ULONG Size;
  115. PUCHAR Data;
  116. if (ReadCall.Flags & DBGRPC_RETURN)
  117. {
  118. Size = ReadCall.OutSize;
  119. }
  120. else
  121. {
  122. Size = ReadCall.InSize;
  123. ReadCall.Status = S_OK;
  124. }
  125. if (Size > 0)
  126. {
  127. Data = (PUCHAR)Conn->Alloc(Size);
  128. if (Data == NULL)
  129. {
  130. DRPC_ERR(("%X: Unable to allocate call body\n",
  131. GetCurrentThreadId()));
  132. return E_OUTOFMEMORY;
  133. }
  134. if (Conn->m_Trans->Read(ReadCall.Sequence, Data, Size) != Size)
  135. {
  136. DRPC_ERR(("%X: Unable to receive call body\n",
  137. GetCurrentThreadId()));
  138. Conn->Free(Data);
  139. return RPC_E_CLIENT_DIED;
  140. }
  141. }
  142. else
  143. {
  144. Data = NULL;
  145. }
  146. #ifdef DBG_RPC
  147. if (ReadCall.Flags & DBGRPC_RETURN)
  148. {
  149. DRPC(("%X: %X: Return %s (%X), ret 0x%X, out %d\n",
  150. GetCurrentThreadId(), ReadCall.Sequence,
  151. DbgRpcGetStubName(ReadCall.StubIndex),
  152. ReadCall.StubIndex, ReadCall.Status, ReadCall.OutSize));
  153. }
  154. else
  155. {
  156. DRPC(("%X: %X: Request %s (%X), fl %X, in %d\n",
  157. GetCurrentThreadId(), ReadCall.Sequence,
  158. DbgRpcGetStubName(ReadCall.StubIndex),
  159. ReadCall.StubIndex, ReadCall.Flags, ReadCall.InSize));
  160. }
  161. #endif
  162. if (ReadCall.Flags & DBGRPC_RETURN)
  163. {
  164. if (ReadCall.Sequence != RetSeq)
  165. {
  166. #if DBG
  167. DRPC_ERR(("%X: %X: Non-seq ret 0x%X for %s (%X)\n",
  168. GetCurrentThreadId(), ReadCall.Sequence,
  169. ReadCall.Status,
  170. DbgRpcGetStubName(ReadCall.StubIndex),
  171. ReadCall.StubIndex));
  172. #else
  173. DRPC_ERR(("%X: %X: Non-seq ret 0x%X for (%X)\n",
  174. GetCurrentThreadId(), ReadCall.Sequence,
  175. ReadCall.Status, ReadCall.StubIndex));
  176. #endif
  177. // This return is for some call other than the current
  178. // call, which means that RPC is messed up.
  179. // Discard the return and hope for the best.
  180. Conn->FreeData(Data);
  181. continue;
  182. }
  183. *Call = ReadCall;
  184. *InOutData = Data;
  185. return Call->Status;
  186. }
  187. PUCHAR OutData;
  188. if (ReadCall.OutSize > 0)
  189. {
  190. DBG_ASSERT((ReadCall.Flags & DBGRPC_NO_RETURN) == 0);
  191. OutData = (PUCHAR)Conn->Alloc(ReadCall.OutSize);
  192. if (OutData == NULL)
  193. {
  194. if (Data)
  195. {
  196. Conn->Free(Data);
  197. }
  198. return E_OUTOFMEMORY;
  199. }
  200. }
  201. else
  202. {
  203. OutData = NULL;
  204. }
  205. if (ReadCall.Flags & DBGRPC_NO_RETURN)
  206. {
  207. Conn->m_Flags |= DBGRPC_IN_ASYNC_CALL;
  208. }
  209. DbgRpcStubFunction StubFn = DbgRpcGetStub(ReadCall.StubIndex);
  210. if (StubFn != NULL)
  211. {
  212. ReadCall.Status = StubFn((IUnknown*)ReadCall.ObjectId,
  213. Conn, &ReadCall, Data, OutData);
  214. }
  215. else
  216. {
  217. ReadCall.Status = RPC_E_INVALIDMETHOD;
  218. }
  219. Conn->m_Flags &= ~DBGRPC_IN_ASYNC_CALL;
  220. DRPC(("%X: %X: Called %s (%X), ret 0x%X, out %d\n",
  221. GetCurrentThreadId(), ReadCall.Sequence,
  222. DbgRpcGetStubName(ReadCall.StubIndex),
  223. ReadCall.StubIndex, ReadCall.Status, ReadCall.OutSize));
  224. Status = S_OK;
  225. if ((ReadCall.Flags & DBGRPC_NO_RETURN) == 0)
  226. {
  227. ReadCall.Flags |= DBGRPC_RETURN;
  228. // Take a lock here to make sure that the header
  229. // and body are sequential in the stream.
  230. EnterCriticalSection(&g_DbgRpcLock);
  231. if (Conn->m_Trans->Write(ReadCall.Sequence,
  232. &ReadCall, sizeof(ReadCall)) !=
  233. sizeof(ReadCall) ||
  234. (ReadCall.OutSize > 0 &&
  235. Conn->m_Trans->Write(ReadCall.Sequence,
  236. OutData, ReadCall.OutSize) !=
  237. ReadCall.OutSize))
  238. {
  239. Status = RPC_E_CANTTRANSMIT_CALL;
  240. }
  241. LeaveCriticalSection(&g_DbgRpcLock);
  242. }
  243. if (OutData)
  244. {
  245. Conn->FreeData(OutData);
  246. }
  247. if (Data)
  248. {
  249. Conn->FreeData(Data);
  250. }
  251. if (Status != S_OK)
  252. {
  253. return Status;
  254. }
  255. }
  256. }
  257. //----------------------------------------------------------------------------
  258. //
  259. // DbgRpcConnection.
  260. //
  261. //----------------------------------------------------------------------------
  262. DbgRpcConnection* g_DbgRpcConns;
  263. DbgRpcConnection::DbgRpcConnection(DbgRpcTransport* Trans)
  264. {
  265. m_Trans = Trans;
  266. m_Next = NULL;
  267. m_ThreadId = GetCurrentThreadId();
  268. m_Buffer = PTR_ALIGN2(PUCHAR, m_UnalignedBuffer,
  269. DBGRPC_CONN_BUFFER_ALIGN);
  270. m_BufferUsed = 0;
  271. m_Flags = 0;
  272. m_Objects = 0;
  273. }
  274. DbgRpcConnection::~DbgRpcConnection(void)
  275. {
  276. Disconnect();
  277. }
  278. PUCHAR
  279. DbgRpcConnection::StartCall(DbgRpcCall* Call, DbgRpcObjectId ObjectId,
  280. ULONG StubIndex, ULONG InSize, ULONG OutSize)
  281. {
  282. PUCHAR Data;
  283. if (InSize > 0)
  284. {
  285. Data = (PUCHAR)Alloc(InSize);
  286. if (Data == NULL)
  287. {
  288. return NULL;
  289. }
  290. }
  291. else
  292. {
  293. // Have to return a non-zero pointer but
  294. // it doesn't need to be valid since it should
  295. // never be used.
  296. Data = DBGRPC_NO_DATA;
  297. }
  298. Call->ObjectId = ObjectId;
  299. DBG_ASSERT(StubIndex < 0x10000);
  300. Call->StubIndex = (USHORT)StubIndex;
  301. Call->Flags = 0;
  302. Call->InSize = InSize;
  303. Call->OutSize = OutSize;
  304. Call->Status = S_OK;
  305. Call->Sequence = InterlockedIncrement((PLONG)&g_DbgRpcCallSequence);
  306. Call->Reserved1 = 0;
  307. return Data;
  308. }
  309. HRESULT
  310. DbgRpcConnection::SendReceive(DbgRpcCall* Call, PUCHAR* InOutData)
  311. {
  312. //
  313. // Send call and in-parameter data.
  314. //
  315. DRPC(("%X: %X: Calling %s (%X), in %d, out %d\n",
  316. GetCurrentThreadId(), Call->Sequence,
  317. DbgRpcGetStubName(Call->StubIndex),
  318. Call->StubIndex, Call->InSize, Call->OutSize));
  319. // Allow async callouts from within async calls so
  320. // that things like output and notifications get
  321. // delivered when they happen to occur while in
  322. // an async call.
  323. if ((m_Flags & DBGRPC_IN_ASYNC_CALL) &&
  324. !(Call->Flags & DBGRPC_NO_RETURN))
  325. {
  326. return RPC_E_CANTCALLOUT_INASYNCCALL;
  327. }
  328. // Take a lock here to make sure that the header
  329. // and body are sequential in the stream.
  330. EnterCriticalSection(&g_DbgRpcLock);
  331. if (m_Trans->Write(SEQ_CALL_HEADER, Call, sizeof(*Call)) != sizeof(*Call))
  332. {
  333. LeaveCriticalSection(&g_DbgRpcLock);
  334. return RPC_E_CANTTRANSMIT_CALL;
  335. }
  336. if (Call->InSize > 0)
  337. {
  338. if (m_Trans->Write(Call->Sequence, *InOutData, Call->InSize) !=
  339. Call->InSize)
  340. {
  341. LeaveCriticalSection(&g_DbgRpcLock);
  342. return RPC_E_CANTTRANSMIT_CALL;
  343. }
  344. // In data is no longer necessary.
  345. Free(*InOutData);
  346. }
  347. LeaveCriticalSection(&g_DbgRpcLock);
  348. // Clear out data pointer in case of later failures.
  349. *InOutData = NULL;
  350. HRESULT Status;
  351. if (Call->Flags & DBGRPC_NO_RETURN)
  352. {
  353. Status = S_OK;
  354. }
  355. else
  356. {
  357. USHORT StubIndex = Call->StubIndex;
  358. Status = DbgRpcReceiveCalls(this, Call, InOutData);
  359. if (Call->StubIndex != StubIndex)
  360. {
  361. #if DBG
  362. DRPC_ERR(("%X: %X: Call to %s (%X) returned from %s (%d)\n",
  363. GetCurrentThreadId(), Call->Sequence,
  364. DbgRpcGetStubName(StubIndex), StubIndex,
  365. DbgRpcGetStubName(Call->StubIndex),
  366. Call->StubIndex));
  367. #else
  368. DRPC_ERR(("%X: %X: Mismatched call return\n",
  369. GetCurrentThreadId(), Call->Sequence));
  370. #endif
  371. Status = RPC_E_INVALID_DATAPACKET;
  372. }
  373. }
  374. return Status;
  375. }
  376. PVOID
  377. DbgRpcConnection::MallocAligned(ULONG Size)
  378. {
  379. PVOID Data, Align;
  380. // Not enough buffer space left so allocate. malloc
  381. // only gives out 8-byte-aligned memory so tweak things
  382. // to get it aligned.
  383. Data = malloc(Size + DBGRPC_CONN_BUFFER_ALIGN);
  384. if (Data != NULL)
  385. {
  386. if ((ULONG_PTR)Data & (DBGRPC_CONN_BUFFER_ALIGN - 1))
  387. {
  388. Align = PTR_ALIGN2(PVOID, Data, DBGRPC_CONN_BUFFER_ALIGN);
  389. }
  390. else
  391. {
  392. Align = (PVOID)((PUCHAR)Data + DBGRPC_CONN_BUFFER_ALIGN);
  393. }
  394. *((PVOID*)Align - 1) = Data;
  395. }
  396. else
  397. {
  398. Align = NULL;
  399. }
  400. return Align;
  401. }
  402. void
  403. DbgRpcConnection::FreeAligned(PVOID Ptr)
  404. {
  405. free(*((PVOID*)Ptr - 1));
  406. }
  407. PVOID
  408. DbgRpcConnection::Alloc(ULONG Size)
  409. {
  410. PVOID Data = NULL;
  411. // Keep every allocated chunk aligned.
  412. Size = INT_ALIGN2(Size, DBGRPC_CONN_BUFFER_ALIGN);
  413. #if DBG
  414. Size += DBGRPC_CONN_BUFFER_ALIGN;
  415. #endif
  416. // Don't burn up large parts of the buffer on big chunks
  417. // as that may force many smaller chunks into dynamic
  418. // allocations because the buffer is full.
  419. // Only allow the owning thread to allocate from the
  420. // local buffer to avoid usage conflicts between
  421. // threads.
  422. if (Size <= DBGRPC_CONN_BUFFER_DYNAMIC_LIMIT &&
  423. GetCurrentThreadId() == m_ThreadId)
  424. {
  425. if (m_BufferUsed + Size <= DBGRPC_CONN_BUFFER_SIZE)
  426. {
  427. // Data is allocated in strict LIFO order so
  428. // we just need to mark the end of the buffer as used.
  429. Data = &m_Buffer[m_BufferUsed];
  430. m_BufferUsed += Size;
  431. #if DBG
  432. *(PULONG)Data = Size;
  433. Data = (PUCHAR)Data + DBGRPC_CONN_BUFFER_ALIGN;
  434. #endif
  435. }
  436. }
  437. if (Data == NULL)
  438. {
  439. Data = MallocAligned(Size);
  440. }
  441. return Data;
  442. }
  443. void
  444. DbgRpcConnection::Free(PVOID Ptr)
  445. {
  446. if (Ptr >= m_Buffer && Ptr < m_Buffer + DBGRPC_CONN_BUFFER_SIZE)
  447. {
  448. #if DBG
  449. Ptr = (PUCHAR)Ptr - DBGRPC_CONN_BUFFER_ALIGN;
  450. // Assert that this allocation is at the end of the buffer.
  451. DBG_ASSERT((ULONG)((PUCHAR)Ptr - m_Buffer) + *(PULONG)Ptr ==
  452. m_BufferUsed);
  453. #endif
  454. // Data was allocated in the connection buffer.
  455. // Data is allocated in strict LIFO order so
  456. // we just need to back up prior to the data.
  457. m_BufferUsed = (ULONG)((PUCHAR)Ptr - m_Buffer);
  458. }
  459. else
  460. {
  461. // Data was dynamically allocated.
  462. FreeAligned(Ptr);
  463. }
  464. }
  465. void
  466. DbgRpcConnection::Disconnect(void)
  467. {
  468. delete m_Trans;
  469. m_Trans = NULL;
  470. }
  471. DbgRpcConnection*
  472. DbgRpcGetConnection(ULONG Tid)
  473. {
  474. DbgRpcConnection* Conn;
  475. EnterCriticalSection(&g_DbgRpcLock);
  476. for (Conn = g_DbgRpcConns; Conn != NULL; Conn = Conn->m_Next)
  477. {
  478. if (Conn->m_ThreadId == Tid)
  479. {
  480. break;
  481. }
  482. }
  483. LeaveCriticalSection(&g_DbgRpcLock);
  484. return Conn;
  485. }
  486. void
  487. DbgRpcAddConnection(DbgRpcConnection* Conn)
  488. {
  489. EnterCriticalSection(&g_DbgRpcLock);
  490. Conn->m_Next = g_DbgRpcConns;
  491. g_DbgRpcConns = Conn;
  492. LeaveCriticalSection(&g_DbgRpcLock);
  493. }
  494. void
  495. DbgRpcRemoveConnection(DbgRpcConnection* Conn)
  496. {
  497. EnterCriticalSection(&g_DbgRpcLock);
  498. DbgRpcConnection* Prev = NULL;
  499. DbgRpcConnection* Cur;
  500. for (Cur = g_DbgRpcConns; Cur != NULL; Cur = Cur->m_Next)
  501. {
  502. if (Cur == Conn)
  503. {
  504. break;
  505. }
  506. Prev = Cur;
  507. }
  508. DBG_ASSERT(Cur != NULL);
  509. if (Prev == NULL)
  510. {
  511. g_DbgRpcConns = Conn->m_Next;
  512. }
  513. else
  514. {
  515. Prev->m_Next = Conn->m_Next;
  516. }
  517. LeaveCriticalSection(&g_DbgRpcLock);
  518. }
  519. void
  520. DbgRpcDeleteConnection(DbgRpcConnection* Conn)
  521. {
  522. DbgRpcRemoveConnection(Conn);
  523. // It's possible that another thread is in the middle
  524. // of using the connection for an async send. Disconnect
  525. // the connection to force any pending calls to fail.
  526. // The connection is already removed from the list
  527. // so there shouldn't be any further usage.
  528. Conn->Disconnect();
  529. // Give up some time to let things fail. This
  530. // could be made more deterministic by tracking
  531. // connection usage but it doesn't seem necessary.
  532. Sleep(1000);
  533. delete Conn;
  534. }
  535. //----------------------------------------------------------------------------
  536. //
  537. // DbgRpcProxy.
  538. //
  539. //----------------------------------------------------------------------------
  540. DbgRpcProxy::DbgRpcProxy(ULONG InterfaceIndex)
  541. {
  542. m_Conn = NULL;
  543. m_InterfaceIndex = InterfaceIndex;
  544. m_LocalRefs = 0;
  545. m_RemoteRefs = 1;
  546. m_ObjectId = 0;
  547. m_OwningThread = GetCurrentThreadId();
  548. }
  549. DbgRpcProxy::~DbgRpcProxy(void)
  550. {
  551. // If this proxy was attached to a connection detach it.
  552. if (m_Conn)
  553. {
  554. DRPC_REF(("Conn %p obj %2d proxy %p\n",
  555. m_Conn, m_Conn->m_Objects - 1, this));
  556. if (InterlockedDecrement((PLONG)&m_Conn->m_Objects) == 0)
  557. {
  558. DbgRpcDeleteConnection(m_Conn);
  559. }
  560. }
  561. }
  562. IUnknown*
  563. DbgRpcProxy::InitializeProxy(DbgRpcConnection* Conn,
  564. DbgRpcObjectId ObjectId,
  565. IUnknown* ExistingProxy)
  566. {
  567. //
  568. // The current debugger remoting does not preserve
  569. // object identity as this simplifies proxy
  570. // management. Nobody currently needs it, so
  571. // we're not bothering with it. If object identity
  572. // becomes important this routine is the place
  573. // to implement proxy lookup and sharing.
  574. //
  575. // Handle NULL object case where proxy is unnecessary.
  576. if (ObjectId == 0)
  577. {
  578. DbgRpcDeleteProxy(this);
  579. return NULL;
  580. }
  581. m_Conn = Conn;
  582. if (m_Conn != NULL)
  583. {
  584. InterlockedIncrement((PLONG)&m_Conn->m_Objects);
  585. DRPC_REF(("Conn %p obj %2d proxy %p\n",
  586. m_Conn, m_Conn->m_Objects, this));
  587. }
  588. m_ObjectId = ObjectId;
  589. return ExistingProxy;
  590. }
  591. //----------------------------------------------------------------------------
  592. //
  593. // DbgRpcClientObject.
  594. //
  595. //----------------------------------------------------------------------------
  596. void
  597. DbgRpcClientObject::RpcFinalize(void)
  598. {
  599. // Do-nothing convenience implementation.
  600. }
  601. //----------------------------------------------------------------------------
  602. //
  603. // Registration functions.
  604. //
  605. //----------------------------------------------------------------------------
  606. struct DbgRpcActiveServer
  607. {
  608. DbgRpcActiveServer* Next;
  609. ULONG Id;
  610. DbgRpcTransport* Trans;
  611. DbgRpcClientObjectFactory* Factory;
  612. ULONG RegTid;
  613. ULONG RegIndex;
  614. BOOL Disabled;
  615. };
  616. DbgRpcActiveServer* g_DbgRpcActiveServers;
  617. ULONG
  618. DbgRpcNextActiveServerId(void)
  619. {
  620. DbgRpcActiveServer* Server;
  621. ULONG Id;
  622. //
  623. // Assumes the RPC lock is held.
  624. //
  625. Id = 0;
  626. for (;;)
  627. {
  628. for (Server = g_DbgRpcActiveServers; Server; Server = Server->Next)
  629. {
  630. if (Server->Id == Id)
  631. {
  632. Id++;
  633. break;
  634. }
  635. }
  636. if (!Server)
  637. {
  638. break;
  639. }
  640. }
  641. return Id;
  642. }
  643. void
  644. DbgRpcDescribeActiveServer(DbgRpcActiveServer* Server,
  645. PSTR Buffer, ULONG BufferSize)
  646. {
  647. DBG_ASSERT(BufferSize >= 2 * MAX_PARAM_VALUE);
  648. if (Server->Disabled)
  649. {
  650. CopyString(Buffer, "<Disabled, exit pending>", BufferSize);
  651. }
  652. else
  653. {
  654. PSTR Tail;
  655. Server->Factory->GetServerTypeName(Buffer, BufferSize);
  656. CatString(Buffer, " - ", BufferSize);
  657. Tail = Buffer + strlen(Buffer);
  658. Server->Trans->
  659. GetParameters(Tail, BufferSize - (ULONG)(Tail - Buffer));
  660. }
  661. }
  662. PVOID
  663. DbgRpcEnumActiveServers(PVOID Cookie,
  664. PULONG Id, PSTR Buffer, ULONG BufferSize)
  665. {
  666. DbgRpcActiveServer* Server = (DbgRpcActiveServer*)Cookie;
  667. if (!DbgRpcOneTimeInitialization())
  668. {
  669. return NULL;
  670. }
  671. EnterCriticalSection(&g_DbgRpcLock);
  672. Server = !Server ? g_DbgRpcActiveServers : Server->Next;
  673. if (!Server)
  674. {
  675. LeaveCriticalSection(&g_DbgRpcLock);
  676. return NULL;
  677. }
  678. *Id = Server->Id;
  679. DbgRpcDescribeActiveServer(Server, Buffer, BufferSize);
  680. LeaveCriticalSection(&g_DbgRpcLock);
  681. return Server;
  682. }
  683. void
  684. DbgRpcSystemRegisterActiveServer(DbgRpcActiveServer* Server)
  685. {
  686. // Start by assuming failure and no system registration.
  687. Server->RegTid = 0;
  688. Server->RegIndex = 0;
  689. #ifndef NT_NATIVE
  690. char Desc[2 * MAX_PARAM_VALUE];
  691. DbgRpcDescribeActiveServer(Server, Desc, sizeof(Desc));
  692. HKEY Key;
  693. LONG Status;
  694. char ValName[32];
  695. ULONG Index;
  696. // No servers will survive a reboot so create a volatile
  697. // key to ensure that even if the key isn't cleaned up
  698. // at process exit it'll go away at the next reboot.
  699. if ((Status = RegCreateKeyEx(HKEY_LOCAL_MACHINE, DEBUG_SERVER_KEY,
  700. 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS,
  701. NULL, &Key, NULL)) != ERROR_SUCCESS)
  702. {
  703. DRPC_ERR(("%X: Unable to register server '%s'\n",
  704. GetCurrentThreadId(), Desc));
  705. return;
  706. }
  707. // Prefix the value name with the thread ID to ensure that
  708. // every thread currently running has its own namespace. This
  709. // makes it impossible for two threads to attempt to write
  710. // the same value at the same time.
  711. sprintf(ValName, "%08X.", GetCurrentThreadId());
  712. // Find an unused value and store the server information.
  713. Index = 0;
  714. for (;;)
  715. {
  716. DWORD Len;
  717. sprintf(ValName + 9, "%08X", Index);
  718. if (RegQueryValueEx(Key, ValName, NULL, NULL, NULL,
  719. &Len) != ERROR_SUCCESS)
  720. {
  721. break;
  722. }
  723. Index++;
  724. }
  725. if ((Status = RegSetValueEx(Key, ValName, 0, REG_SZ, (LPBYTE)Desc,
  726. strlen(Desc) + 1)) != ERROR_SUCCESS)
  727. {
  728. DRPC_ERR(("%X: Unable to register server '%s'\n",
  729. GetCurrentThreadId(), Desc));
  730. }
  731. else
  732. {
  733. Server->RegTid = GetCurrentThreadId();
  734. Server->RegIndex = Index;
  735. }
  736. RegCloseKey(Key);
  737. #endif // #ifndef NT_NATIVE
  738. }
  739. void
  740. DbgRpcSystemDeregisterActiveServer(DbgRpcActiveServer* Server)
  741. {
  742. if (!Server->RegTid)
  743. {
  744. return;
  745. }
  746. #ifndef NT_NATIVE
  747. HKEY Key;
  748. LONG Status;
  749. if ((Status = RegCreateKeyEx(HKEY_LOCAL_MACHINE, DEBUG_SERVER_KEY,
  750. 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS,
  751. NULL, &Key, NULL)) != ERROR_SUCCESS)
  752. {
  753. return;
  754. }
  755. char ValName[32];
  756. sprintf(ValName, "%08X.%08X", Server->RegTid, Server->RegIndex);
  757. RegDeleteValue(Key, ValName);
  758. Server->RegTid = 0;
  759. Server->RegIndex = 0;
  760. RegCloseKey(Key);
  761. #endif // #ifndef NT_NATIVE
  762. }
  763. void
  764. DbgRpcRegisterActiveServer(DbgRpcActiveServer* Server)
  765. {
  766. DbgRpcActiveServer* Cur;
  767. DbgRpcActiveServer* Prev;
  768. EnterCriticalSection(&g_DbgRpcLock);
  769. //
  770. // Put entry in list sorted by ID.
  771. //
  772. Server->Id = DbgRpcNextActiveServerId();
  773. Prev = NULL;
  774. for (Cur = g_DbgRpcActiveServers; Cur; Cur = Cur->Next)
  775. {
  776. if (Cur->Id > Server->Id)
  777. {
  778. break;
  779. }
  780. Prev = Cur;
  781. }
  782. Server->Next = Cur;
  783. if (!Prev)
  784. {
  785. g_DbgRpcActiveServers = Server;
  786. }
  787. else
  788. {
  789. Prev->Next = Server;
  790. }
  791. DbgRpcSystemRegisterActiveServer(Server);
  792. LeaveCriticalSection(&g_DbgRpcLock);
  793. }
  794. void
  795. DbgRpcDeregisterActiveServer(DbgRpcActiveServer* Server)
  796. {
  797. DbgRpcActiveServer* Cur;
  798. DbgRpcActiveServer* Prev;
  799. EnterCriticalSection(&g_DbgRpcLock);
  800. Prev = NULL;
  801. for (Cur = g_DbgRpcActiveServers; Cur; Cur = Cur->Next)
  802. {
  803. if (Cur == Server)
  804. {
  805. break;
  806. }
  807. Prev = Cur;
  808. }
  809. if (Cur)
  810. {
  811. if (!Prev)
  812. {
  813. g_DbgRpcActiveServers = Server->Next;
  814. }
  815. else
  816. {
  817. Prev->Next = Server->Next;
  818. }
  819. }
  820. DbgRpcSystemDeregisterActiveServer(Server);
  821. LeaveCriticalSection(&g_DbgRpcLock);
  822. }
  823. HRESULT
  824. DbgRpcDisableServer(ULONG Id)
  825. {
  826. HRESULT Status;
  827. DbgRpcActiveServer* Cur;
  828. EnterCriticalSection(&g_DbgRpcLock);
  829. for (Cur = g_DbgRpcActiveServers; Cur; Cur = Cur->Next)
  830. {
  831. if (Cur->Id == Id)
  832. {
  833. break;
  834. }
  835. }
  836. if (Cur)
  837. {
  838. // Let the accept thread know that the server has been disabled.
  839. Cur->Disabled = TRUE;
  840. // Immediately remove the system registration as
  841. // this server will accept no more connections.
  842. // The active server entry will be cleaned up when
  843. // the accept thread exits.
  844. DbgRpcSystemDeregisterActiveServer(Cur);
  845. Status = S_OK;
  846. }
  847. else
  848. {
  849. Status = E_NOINTERFACE;
  850. }
  851. LeaveCriticalSection(&g_DbgRpcLock);
  852. return Status;
  853. }
  854. void
  855. DbgRpcDeregisterServers(void)
  856. {
  857. // Deregister handles the case of a stale pointer value
  858. // so there's no need to lock in this loop.
  859. while (g_DbgRpcActiveServers)
  860. {
  861. DbgRpcDeregisterActiveServer(g_DbgRpcActiveServers);
  862. }
  863. }
  864. //----------------------------------------------------------------------------
  865. //
  866. // Initialization functions.
  867. //
  868. //----------------------------------------------------------------------------
  869. DbgRpcConnection*
  870. DbgRpcCreateClientObject(DbgRpcTransport* Trans,
  871. DbgRpcClientObjectFactory* Factory,
  872. PSTR TransIdentity,
  873. DbgRpcClientObject** ClientObject)
  874. {
  875. DbgRpcConnection* Conn = new DbgRpcConnection(Trans);
  876. if (Conn == NULL)
  877. {
  878. DRPC_ERR(("%X: Unable to allocate client connection\n",
  879. GetCurrentThreadId()));
  880. delete Trans;
  881. return NULL;
  882. }
  883. DRPC(("%X: Read handshake\n",
  884. GetCurrentThreadId()));
  885. DbgRpcHandshake Shake;
  886. if (Trans->Read(SEQ_HANDSHAKE, &Shake, sizeof(Shake)) != sizeof(Shake))
  887. {
  888. DRPC_ERR(("%X: Unable to read handshake from remote client\n",
  889. GetCurrentThreadId()));
  890. goto EH_Conn;
  891. }
  892. DRPC(("%X: Read handshake, sig %X, ver %X, obj %I64X, id %d, pwd %d\n",
  893. GetCurrentThreadId(), Shake.Signature, Shake.ProtocolVersion,
  894. Shake.RemoteObject, Shake.IdentityLength, Shake.PasswordLength));
  895. if (Shake.Signature != DBGRPC_SIGNATURE ||
  896. Shake.ProtocolVersion != DBGRPC_PROTOCOL_VERSION ||
  897. Shake.RemoteObject != 0 ||
  898. Shake.IdentityLength > DBGRPC_MAX_IDENTITY ||
  899. (Shake.PasswordLength != 0 &&
  900. Shake.PasswordLength != MAX_PASSWORD_BUFFER))
  901. {
  902. DRPC_ERR(("%X: Invalid handshake from remote client\n",
  903. GetCurrentThreadId()));
  904. goto EH_Conn;
  905. }
  906. char ClientIdentity[DBGRPC_MAX_IDENTITY];
  907. if (Shake.IdentityLength > 0)
  908. {
  909. if (Trans->Read(SEQ_IDENTITY, ClientIdentity, Shake.IdentityLength) !=
  910. Shake.IdentityLength)
  911. {
  912. DRPC_ERR(("%X: Unable to read identity from remote client\n",
  913. GetCurrentThreadId()));
  914. goto EH_Conn;
  915. }
  916. ClientIdentity[Shake.IdentityLength - 1] = 0;
  917. }
  918. else
  919. {
  920. strcpy(ClientIdentity, "OldRpc\\NoIdentity");
  921. }
  922. //
  923. // Format the raw transport identity into something
  924. // that'll look better appended to the reported identity.
  925. //
  926. if (Shake.PasswordLength > 0)
  927. {
  928. if (!Trans->m_PasswordGiven)
  929. {
  930. DRPC_ERR(("%X: Password not given but client sent one\n",
  931. GetCurrentThreadId()));
  932. goto EH_Conn;
  933. }
  934. UCHAR Pwd[MAX_PASSWORD_BUFFER];
  935. if (Trans->Read(SEQ_PASSWORD, Pwd, Shake.PasswordLength) !=
  936. Shake.PasswordLength)
  937. {
  938. DRPC_ERR(("%X: Unable to read password from remote client\n",
  939. GetCurrentThreadId()));
  940. goto EH_Conn;
  941. }
  942. if (memcmp(Pwd, Trans->m_HashedPassword, MAX_PASSWORD_BUFFER) != 0)
  943. {
  944. DRPC_ERR(("%X: Client sent incorrect password\n",
  945. GetCurrentThreadId()));
  946. goto EH_Conn;
  947. }
  948. }
  949. else if (Trans->m_PasswordGiven)
  950. {
  951. DRPC_ERR(("%X: Password given but client didn't send one\n",
  952. GetCurrentThreadId()));
  953. goto EH_Conn;
  954. }
  955. if (Shake.Flags & DBGRPC_SHAKE_FULL_REMOTE_UNKNOWN)
  956. {
  957. Conn->m_Flags |= DBGRPC_FULL_REMOTE_UNKNOWN;
  958. }
  959. DbgRpcClientObject* Object;
  960. PVOID ObjInterface;
  961. if (Factory->CreateInstance(&Shake.DesiredObject, &Object) != S_OK)
  962. {
  963. DRPC_ERR(("%X: Unable to create client object instance\n",
  964. GetCurrentThreadId()));
  965. goto EH_Conn;
  966. }
  967. if (Object->RpcInitialize(ClientIdentity, TransIdentity,
  968. &ObjInterface) != S_OK)
  969. {
  970. DRPC_ERR(("%X: Unable to initialize client object\n",
  971. GetCurrentThreadId()));
  972. goto EH_Object;
  973. }
  974. ZeroMemory(&Shake, sizeof(Shake));
  975. Shake.Signature = DBGRPC_SIGNATURE;
  976. Shake.ProtocolVersion = DBGRPC_PROTOCOL_VERSION;
  977. Shake.RemoteObject = (DbgRpcObjectId)ObjInterface;
  978. Shake.Flags = DBGRPC_SHAKE_FULL_REMOTE_UNKNOWN;
  979. if (Trans->Write(SEQ_HANDSHAKE,
  980. &Shake, sizeof(Shake)) != sizeof(Shake))
  981. {
  982. DRPC_ERR(("%X: Unable to write handshake to remote client\n",
  983. GetCurrentThreadId()));
  984. goto EH_Object;
  985. }
  986. DRPC(("%X: Object %p created\n",
  987. GetCurrentThreadId(), Object));
  988. Object->RpcFinalize();
  989. *ClientObject = Object;
  990. DbgRpcAddConnection(Conn);
  991. return Conn;
  992. EH_Object:
  993. Object->RpcUninitialize();
  994. EH_Conn:
  995. delete Conn;
  996. return NULL;
  997. }
  998. struct ClientThreadData
  999. {
  1000. DbgRpcTransport* Trans;
  1001. DbgRpcClientObjectFactory* Factory;
  1002. char Identity[DBGRPC_MAX_IDENTITY];
  1003. };
  1004. DWORD WINAPI
  1005. DbgRpcClientThread(PVOID ThreadParam)
  1006. {
  1007. DbgRpcClientObject* Object;
  1008. ClientThreadData* ThreadData = (ClientThreadData*)ThreadParam;
  1009. DbgRpcTransport* Trans = ThreadData->Trans;
  1010. DbgRpcClientObjectFactory* Factory = ThreadData->Factory;
  1011. DbgRpcConnection* Conn =
  1012. DbgRpcCreateClientObject(Trans, Factory,
  1013. ThreadData->Identity, &Object);
  1014. // Don't need this information any more.
  1015. delete ThreadParam;
  1016. if (Conn == NULL)
  1017. {
  1018. ExitUserThread(0);
  1019. }
  1020. if (DbgRpcServerThreadInitialize() != S_OK)
  1021. {
  1022. ExitUserThread(0);
  1023. }
  1024. DRPC(("%X: Created connection %p\n",
  1025. GetCurrentThreadId(), Conn));
  1026. DbgRpcCall Call;
  1027. PUCHAR Data;
  1028. HRESULT Status;
  1029. // Take a reference on the connection to ensure that
  1030. // it stays alive as long as this thread does.
  1031. Conn->m_Objects++;
  1032. for (;;)
  1033. {
  1034. Data = NULL;
  1035. ZeroMemory(&Call, sizeof(Call));
  1036. Status = DbgRpcReceiveCalls(Conn, &Call, &Data);
  1037. Conn->FreeData(Data);
  1038. if (Status != S_OK)
  1039. {
  1040. DRPC_ERR(("%X: Client thread call receive failed, 0x%X\n",
  1041. GetCurrentThreadId(), Status));
  1042. if (Status == RPC_E_CLIENT_DIED)
  1043. {
  1044. break;
  1045. }
  1046. }
  1047. }
  1048. DRPC(("%X: Removing connection %p\n",
  1049. GetCurrentThreadId(), Conn));
  1050. Object->RpcUninitialize();
  1051. DbgRpcDeleteConnection(Conn);
  1052. DbgRpcServerThreadUninitialize();
  1053. ExitUserThread(0);
  1054. }
  1055. #if _MSC_FULL_VER >= 13008827
  1056. #pragma warning(push)
  1057. #pragma warning(disable:4715) // Not all control paths return (due to infinite loop)
  1058. #endif
  1059. #define WAIT_START_LOOPS 200
  1060. #define WAIT_START_DELAY 50
  1061. struct ServerThreadData
  1062. {
  1063. DbgRpcTransport* Trans;
  1064. DbgRpcClientObjectFactory* Factory;
  1065. BOOL WaitStart;
  1066. };
  1067. DWORD WINAPI
  1068. DbgRpcServerThread(PVOID ThreadParam)
  1069. {
  1070. ServerThreadData* ServerData = (ServerThreadData*)ThreadParam;
  1071. DbgRpcActiveServer Server;
  1072. ULONG Attempts = 0;
  1073. ZeroMemory(&Server, sizeof(Server));
  1074. Server.Trans = ServerData->Trans;
  1075. Server.Factory = ServerData->Factory;
  1076. HRESULT Status;
  1077. ClientThreadData* ClientData = NULL;
  1078. if (!Server.Trans->m_Hidden)
  1079. {
  1080. // Register this server for people browsing for servers.
  1081. DbgRpcRegisterActiveServer(&Server);
  1082. }
  1083. if (ServerData->WaitStart)
  1084. {
  1085. // If the creator is waiting for startup, signal
  1086. // that startup is complete and then wait
  1087. // for acknowledgement.
  1088. ServerData->WaitStart = FALSE;
  1089. while (!ServerData->WaitStart)
  1090. {
  1091. Sleep(WAIT_START_DELAY);
  1092. }
  1093. }
  1094. // Values are now cached locally so free passed-in data.
  1095. delete ServerData;
  1096. while (!Server.Disabled)
  1097. {
  1098. if (ClientData == NULL)
  1099. {
  1100. ClientData = new ClientThreadData;
  1101. if (ClientData == NULL)
  1102. {
  1103. DRPC_ERR(("%X: Unable to allocate ClientThreadData\n",
  1104. GetCurrentThreadId()));
  1105. Sleep(100);
  1106. continue;
  1107. }
  1108. }
  1109. Status = Server.Trans->AcceptConnection(&ClientData->Trans,
  1110. ClientData->Identity,
  1111. DIMA(ClientData->Identity));
  1112. Attempts++;
  1113. // If this server has been disabled we don't want
  1114. // to accept any more connections.
  1115. if (Status == S_OK && Server.Disabled)
  1116. {
  1117. delete ClientData->Trans;
  1118. Status = RPC_E_REMOTE_DISABLED;
  1119. }
  1120. if (Status == S_OK)
  1121. {
  1122. DWORD Tid;
  1123. ClientData->Factory = Server.Factory;
  1124. HANDLE Thread = CreateUserThread(DbgRpcClientThread,
  1125. ClientData, &Tid);
  1126. if (Thread == NULL)
  1127. {
  1128. DRPC_ERR(("%X: Client thread create failed, %d\n",
  1129. GetCurrentThreadId(), GetLastError()));
  1130. Sleep(100);
  1131. }
  1132. else
  1133. {
  1134. Attempts = 0;
  1135. CloseHandle(Thread);
  1136. ClientData = NULL;
  1137. }
  1138. if (Server.Trans->m_ClientConnect)
  1139. {
  1140. if (Server.Trans->m_ClientConnectAttempts == 0)
  1141. {
  1142. // If this is a client connect server
  1143. // it can't accept any more connections,
  1144. // so this thread is done.
  1145. break;
  1146. }
  1147. Server.Trans->m_ClientConnectAttempts--;
  1148. }
  1149. }
  1150. else if (!Server.Disabled)
  1151. {
  1152. DRPC_ERR(("%X: Accept failed, %X\n",
  1153. GetCurrentThreadId(), Status));
  1154. if (Server.Trans->m_ClientConnect)
  1155. {
  1156. Sleep(500);
  1157. }
  1158. else
  1159. {
  1160. Sleep(100);
  1161. }
  1162. }
  1163. }
  1164. DbgRpcDeregisterActiveServer(&Server);
  1165. delete Server.Trans;
  1166. ExitUserThread(0);
  1167. }
  1168. #if _MSC_FULL_VER >= 13008827
  1169. #pragma warning(pop)
  1170. #endif
  1171. HRESULT
  1172. DbgRpcCreateServer(PCSTR Options, DbgRpcClientObjectFactory* Factory,
  1173. BOOL Wait)
  1174. {
  1175. DbgRpcTransport* Trans;
  1176. HRESULT Status;
  1177. if (!DbgRpcOneTimeInitialization())
  1178. {
  1179. return E_FAIL;
  1180. }
  1181. Trans = DbgRpcInitializeTransport(Options);
  1182. if (Trans == NULL)
  1183. {
  1184. return E_INVALIDARG;
  1185. }
  1186. Status = Trans->CreateServer();
  1187. if (Status != S_OK)
  1188. {
  1189. goto EH_Trans;
  1190. }
  1191. ServerThreadData* ThreadData;
  1192. ThreadData = new ServerThreadData;
  1193. if (ThreadData == NULL)
  1194. {
  1195. Status = E_OUTOFMEMORY;
  1196. goto EH_Trans;
  1197. }
  1198. ThreadData->Trans = Trans;
  1199. ThreadData->Factory = Factory;
  1200. ThreadData->WaitStart = Wait;
  1201. DWORD Tid;
  1202. HANDLE Thread;
  1203. Thread = CreateUserThread(DbgRpcServerThread, ThreadData, &Tid);
  1204. if (Thread == NULL)
  1205. {
  1206. Status = WIN32_LAST_STATUS();
  1207. delete ThreadData;
  1208. goto EH_Trans;
  1209. }
  1210. CloseHandle(Thread);
  1211. if (Wait)
  1212. {
  1213. ULONG Loops = WAIT_START_LOOPS;
  1214. // Wait for the client thread to signal startup and
  1215. // then acknowledge the signal. There's a timeout
  1216. // just in case the thread faults or something.
  1217. while (ThreadData->WaitStart && Loops-- > 0)
  1218. {
  1219. Sleep(WAIT_START_DELAY);
  1220. }
  1221. ThreadData->WaitStart = TRUE;
  1222. }
  1223. return S_OK;
  1224. EH_Trans:
  1225. delete Trans;
  1226. return Status;
  1227. }
  1228. #define MIN_CLIENT_IDENTITY (DBGRPC_MAX_IDENTITY * 3 / 4)
  1229. void
  1230. GetClientIdentity(PSTR Identity, ULONG IdentitySize)
  1231. {
  1232. #if !defined(NT_NATIVE) && !defined(_WIN32_WCE)
  1233. char CompName[MAX_COMPUTERNAME_LENGTH + 1];
  1234. ULONG CompSize;
  1235. char UserName[UNLEN + 1];
  1236. ULONG UserSize;
  1237. CompSize = sizeof(CompName);
  1238. if (!GetComputerName(CompName, &CompSize))
  1239. {
  1240. sprintf(CompName, "CErr%d", GetLastError());
  1241. CompSize = strlen(CompName);
  1242. }
  1243. else if (CompSize == 0)
  1244. {
  1245. strcpy(CompName, "NoComp");
  1246. CompSize = 6;
  1247. }
  1248. if (CompSize > DBGRPC_MAX_IDENTITY - MIN_CLIENT_IDENTITY - 1)
  1249. {
  1250. CompSize = DBGRPC_MAX_IDENTITY - MIN_CLIENT_IDENTITY - 1;
  1251. }
  1252. CompName[CompSize] = 0;
  1253. UserSize = sizeof(UserName);
  1254. if (!GetUserName(UserName, &UserSize))
  1255. {
  1256. sprintf(UserName, "UErr%d", GetLastError());
  1257. UserSize = strlen(UserName);
  1258. }
  1259. else if (UserSize == 0)
  1260. {
  1261. strcpy(UserName, "NoUser");
  1262. UserSize = 6;
  1263. }
  1264. if (UserSize > DBGRPC_MAX_IDENTITY - MIN_CLIENT_IDENTITY - 1)
  1265. {
  1266. UserSize = DBGRPC_MAX_IDENTITY - MIN_CLIENT_IDENTITY - 1;
  1267. }
  1268. UserName[UserSize] = 0;
  1269. CopyString(Identity, CompName, IdentitySize);
  1270. CatString(Identity, "\\", IdentitySize);
  1271. CatString(Identity, UserName, IdentitySize);
  1272. #else
  1273. CopyString(Identity, "NtNative", IdentitySize);
  1274. #endif // #if !defined(NT_NATIVE) && !defined(_WIN32_WCE)
  1275. }
  1276. HRESULT
  1277. DbgRpcCreateServerConnection(DbgRpcTransport* Trans,
  1278. const GUID* DesiredObject,
  1279. IUnknown** ClientObject)
  1280. {
  1281. HRESULT Status;
  1282. DbgRpcConnection* Conn = new DbgRpcConnection(Trans);
  1283. if (Conn == NULL)
  1284. {
  1285. delete Trans;
  1286. return E_OUTOFMEMORY;
  1287. }
  1288. IUnknown* Object;
  1289. DbgRpcProxy* Proxy;
  1290. ULONG IfUnique;
  1291. Status = DbgRpcPreallocProxy(*DesiredObject, (void **)&Object,
  1292. &Proxy, &IfUnique);
  1293. if (Status != S_OK)
  1294. {
  1295. goto EH_Conn;
  1296. }
  1297. Status = Trans->ConnectServer();
  1298. if (Status != S_OK)
  1299. {
  1300. goto EH_Proxy;
  1301. }
  1302. char Identity[DBGRPC_MAX_IDENTITY];
  1303. GetClientIdentity(Identity, DIMA(Identity));
  1304. DbgRpcHandshake Shake;
  1305. ZeroMemory(&Shake, sizeof(Shake));
  1306. Shake.Signature = DBGRPC_SIGNATURE;
  1307. Shake.ProtocolVersion = DBGRPC_PROTOCOL_VERSION;
  1308. Shake.DesiredObject = *DesiredObject;
  1309. Shake.IdentityLength = sizeof(Identity);
  1310. Shake.PasswordLength = Trans->m_PasswordGiven ? MAX_PASSWORD_BUFFER : 0;
  1311. Shake.Flags = DBGRPC_SHAKE_FULL_REMOTE_UNKNOWN;
  1312. if (Trans->Write(SEQ_HANDSHAKE, &Shake, sizeof(Shake)) != sizeof(Shake))
  1313. {
  1314. Status = E_FAIL;
  1315. goto EH_Proxy;
  1316. }
  1317. if (Trans->Write(SEQ_IDENTITY, Identity, Shake.IdentityLength) !=
  1318. Shake.IdentityLength)
  1319. {
  1320. Status = E_FAIL;
  1321. goto EH_Proxy;
  1322. }
  1323. if (Trans->m_PasswordGiven &&
  1324. Trans->Write(SEQ_PASSWORD,
  1325. Trans->m_HashedPassword, Shake.PasswordLength) !=
  1326. Shake.PasswordLength)
  1327. {
  1328. Status = E_FAIL;
  1329. goto EH_Proxy;
  1330. }
  1331. if (Trans->Read(SEQ_HANDSHAKE, &Shake, sizeof(Shake)) != sizeof(Shake))
  1332. {
  1333. Status = E_FAIL;
  1334. goto EH_Proxy;
  1335. }
  1336. DRPC(("%X: Read handshake, sig %X, ver %X\n",
  1337. GetCurrentThreadId(), Shake.Signature, Shake.ProtocolVersion));
  1338. if (Shake.Signature != DBGRPC_SIGNATURE ||
  1339. Shake.ProtocolVersion != DBGRPC_PROTOCOL_VERSION ||
  1340. Shake.RemoteObject == 0)
  1341. {
  1342. Status = RPC_E_VERSION_MISMATCH;
  1343. goto EH_Proxy;
  1344. }
  1345. if (Shake.Flags & DBGRPC_SHAKE_FULL_REMOTE_UNKNOWN)
  1346. {
  1347. Conn->m_Flags |= DBGRPC_FULL_REMOTE_UNKNOWN;
  1348. }
  1349. DbgRpcAddConnection(Conn);
  1350. *ClientObject = Proxy->InitializeProxy(Conn, Shake.RemoteObject, Object);
  1351. DRPC(("%X: Object %I64X proxied by %p\n",
  1352. GetCurrentThreadId(), Shake.RemoteObject, *ClientObject));
  1353. return S_OK;
  1354. EH_Proxy:
  1355. DbgRpcDeleteProxy(Proxy);
  1356. EH_Conn:
  1357. delete Conn;
  1358. return Status;
  1359. }
  1360. HRESULT
  1361. DbgRpcConnectServer(PCSTR Options, const GUID* DesiredObject,
  1362. IUnknown** ClientObject)
  1363. {
  1364. DbgRpcTransport* Trans;
  1365. if (!DbgRpcOneTimeInitialization())
  1366. {
  1367. return E_FAIL;
  1368. }
  1369. Trans = DbgRpcInitializeTransport(Options);
  1370. if (Trans == NULL)
  1371. {
  1372. return E_INVALIDARG;
  1373. }
  1374. return DbgRpcCreateServerConnection(Trans, DesiredObject, ClientObject);
  1375. }