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.

1365 lines
34 KiB

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