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.

550 lines
14 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. ComRspnd
  5. Abstract:
  6. This module implements the Calais Communication Responder class.
  7. Author:
  8. Doug Barlow (dbarlow) 10/30/1996
  9. Environment:
  10. Win32, C++ w/ Exceptions
  11. Notes:
  12. --*/
  13. #define __SUBROUTINE__
  14. #ifndef WIN32_LEAN_AND_MEAN
  15. #define WIN32_LEAN_AND_MEAN
  16. #endif
  17. #include <windows.h>
  18. #include <WinSCard.h>
  19. #include <CalMsgs.h>
  20. #include <CalCom.h>
  21. #include <stdlib.h>
  22. #define CALCOM_PIPE_TIMEOUT 5000
  23. //
  24. //==============================================================================
  25. //
  26. // CComResponder
  27. //
  28. /*++
  29. CComResponder:
  30. This is the standard constructor and destructor for the Comm Responder
  31. class. They just call the clean and clear functions, respectively.
  32. Arguments:
  33. None
  34. Return Value:
  35. None
  36. Throws:
  37. None
  38. Author:
  39. Doug Barlow (dbarlow) 10/30/1996
  40. --*/
  41. #undef __SUBROUTINE__
  42. #define __SUBROUTINE__ DBGT("CComResponder::CComResponder")
  43. CComResponder::CComResponder(
  44. void)
  45. : m_bfPipeName(),
  46. m_aclPipe(),
  47. m_hComPipe(DBGT("CComResponder's Comm Pipe")),
  48. m_hAccessMutex(DBGT("CComResponder's Access Mutex")),
  49. m_hOvrWait(DBGT("CComResponder Overlapped I/O completion event"))
  50. {
  51. Clean();
  52. }
  53. #undef __SUBROUTINE__
  54. #define __SUBROUTINE__ DBGT("CComResponder::~CComResponder")
  55. CComResponder::~CComResponder()
  56. {
  57. Clear();
  58. }
  59. /*++
  60. Clean:
  61. This method sets the object to its default state. It does not perform any
  62. tear down -- use Clear for that.
  63. Arguments:
  64. None
  65. Return Value:
  66. None
  67. Throws:
  68. None
  69. Author:
  70. Doug Barlow (dbarlow) 10/30/1996
  71. --*/
  72. #undef __SUBROUTINE__
  73. #define __SUBROUTINE__ DBGT("CComResponder::Clean")
  74. void
  75. CComResponder::Clean(
  76. void)
  77. {
  78. ZeroMemory(&m_ovrlp, sizeof(m_ovrlp));
  79. m_bfPipeName.Reset();
  80. }
  81. /*++
  82. Clear:
  83. This method performs object tear-down and returns it to its initial state.
  84. Arguments:
  85. None
  86. Return Value:
  87. None
  88. Throws:
  89. None
  90. Author:
  91. Doug Barlow (dbarlow) 10/30/1996
  92. --*/
  93. #undef __SUBROUTINE__
  94. #define __SUBROUTINE__ DBGT("CComResponder::Clear")
  95. void
  96. CComResponder::Clear(
  97. void)
  98. {
  99. if (m_hAccessMutex.IsValid())
  100. {
  101. WaitForever(
  102. m_hAccessMutex,
  103. CALAIS_LOCK_TIMEOUT,
  104. DBGT("Waiting for final Service Thread quiescence: %1"),
  105. (LPCTSTR)NULL);
  106. m_hAccessMutex.Close();
  107. }
  108. if (m_hComPipe.IsValid())
  109. {
  110. if (!DisconnectNamedPipe(m_hComPipe))
  111. {
  112. CalaisWarning(
  113. __SUBROUTINE__,
  114. DBGT("Comm Responder could not disconnect Comm pipe: %1"),
  115. GetLastError());
  116. }
  117. m_hComPipe.Close();
  118. }
  119. if (m_hOvrWait.IsValid())
  120. m_hOvrWait.Close();
  121. Clean();
  122. }
  123. /*++
  124. Create:
  125. This method Establishes the named target. Close or the destructor takes it
  126. away.
  127. Arguments:
  128. szName supplies the name of the communication object to connect to.
  129. Return Value:
  130. None
  131. Throws:
  132. DWORDs containing the error code, should an error be encountered.
  133. Author:
  134. Doug Barlow (dbarlow) 10/30/1996
  135. --*/
  136. #undef __SUBROUTINE__
  137. #define __SUBROUTINE__ DBGT("CComResponder::Create")
  138. void
  139. CComResponder::Create(
  140. LPCTSTR szName)
  141. {
  142. LPCTSTR szPipeHdr = CalaisString(CALSTR_PIPEDEVICEHEADER);
  143. static DWORD s_nPipeNo = 0;
  144. static HKEY s_hCurrentKey = NULL;
  145. TCHAR szPipeNo[sizeof(s_nPipeNo)*2 + 1]; // Twice as many hex digits + zero
  146. try
  147. {
  148. DWORD cbPipeHeader = lstrlen(szPipeHdr) * sizeof(TCHAR);
  149. DWORD dwLen;
  150. DWORD dwError;
  151. dwLen = lstrlen(szName) * sizeof(TCHAR);
  152. m_bfPipeName.Presize(cbPipeHeader + dwLen + sizeof(szPipeNo));
  153. if (s_hCurrentKey == NULL)
  154. {
  155. HKEY hKey;
  156. //
  157. // Open the key to the Calais tree.
  158. //
  159. dwError = RegOpenKeyEx(
  160. HKEY_LOCAL_MACHINE,
  161. CalaisString(CALSTR_CALAISREGISTRYKEY),
  162. 0, // options (ignored)
  163. KEY_WRITE, // KEY_SET_VALUE | KEY_CREATE_SUB_KEY
  164. &hKey
  165. );
  166. if (ERROR_SUCCESS != dwError)
  167. {
  168. CalaisError(__SUBROUTINE__, 104, dwError);
  169. throw dwError;
  170. }
  171. //
  172. // Create a new key (or open existing one).
  173. //
  174. dwError = RegCreateKeyEx(
  175. hKey,
  176. _T("Current"),
  177. 0,
  178. 0,
  179. REG_OPTION_VOLATILE, // options
  180. KEY_SET_VALUE, // desired access
  181. NULL,
  182. &s_hCurrentKey,
  183. NULL);
  184. RegCloseKey(hKey);
  185. if (ERROR_SUCCESS != dwError)
  186. {
  187. CalaisError(__SUBROUTINE__, 103, dwError);
  188. throw dwError;
  189. }
  190. }
  191. //
  192. // Build the pipe ACL.
  193. //
  194. ASSERT(!m_hComPipe.IsValid());
  195. m_aclPipe.InitializeFromProcessToken();
  196. m_aclPipe.AllowOwner(
  197. GENERIC_READ | GENERIC_WRITE | GENERIC_ALL);
  198. m_aclPipe.Allow(
  199. &m_aclPipe.SID_Interactive,
  200. (FILE_GENERIC_WRITE | FILE_GENERIC_READ)
  201. & ~FILE_CREATE_PIPE_INSTANCE);
  202. m_aclPipe.Allow(
  203. &m_aclPipe.SID_System,
  204. (FILE_GENERIC_WRITE | FILE_GENERIC_READ)
  205. & ~FILE_CREATE_PIPE_INSTANCE);
  206. for (;;)
  207. {
  208. //
  209. // Build the pipe name.
  210. //
  211. _itot(s_nPipeNo, szPipeNo, 16);
  212. m_bfPipeName.Set((LPCBYTE)szPipeHdr, cbPipeHeader);
  213. m_bfPipeName.Append((LPCBYTE)szName, dwLen);
  214. m_bfPipeName.Append((LPCBYTE)szPipeNo, sizeof(szPipeNo));
  215. //
  216. // Build the Pipe (First instance)
  217. //
  218. m_hComPipe = CreateNamedPipe(
  219. (LPCTSTR)m_bfPipeName.Access(),
  220. PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
  221. PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
  222. PIPE_UNLIMITED_INSTANCES,
  223. CALAIS_COMM_MSGLEN,
  224. CALAIS_COMM_MSGLEN,
  225. CALCOM_PIPE_TIMEOUT,
  226. m_aclPipe);
  227. if (!m_hComPipe.IsValid())
  228. {
  229. dwError = m_hComPipe.GetLastError();
  230. if (dwError == ERROR_ACCESS_DENIED)
  231. {
  232. s_nPipeNo++;
  233. continue;
  234. }
  235. CalaisError(__SUBROUTINE__, 109, dwError);
  236. throw dwError;
  237. }
  238. else
  239. break;
  240. }
  241. dwError = RegSetValueEx(
  242. s_hCurrentKey,
  243. NULL, // Use key's unnamed value
  244. 0,
  245. REG_DWORD,
  246. (LPBYTE) &s_nPipeNo,
  247. sizeof(DWORD));
  248. if (ERROR_SUCCESS != dwError)
  249. {
  250. CalaisError(__SUBROUTINE__, 102, dwError);
  251. throw dwError;
  252. }
  253. //
  254. // Prepare the overlapped structure.
  255. //
  256. m_hOvrWait = m_ovrlp.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  257. if (!m_hOvrWait.IsValid())
  258. {
  259. DWORD dwErr = m_hOvrWait.GetLastError();
  260. CalaisWarning(
  261. __SUBROUTINE__,
  262. DBGT("Comm Responder failed to create overlapped event: %1"),
  263. dwErr);
  264. throw dwErr;
  265. }
  266. }
  267. catch (...)
  268. {
  269. CalaisError(__SUBROUTINE__, 110);
  270. Clear();
  271. throw;
  272. }
  273. }
  274. /*++
  275. Listen:
  276. This method listens on the previously created Communication channel for an
  277. incoming connection request. When one comes in, it establishes a containing
  278. CComChannel object for it, and returns it. To disconnect the comm channel,
  279. just delete the returned CComChannel object.
  280. Arguments:
  281. None
  282. Return Value:
  283. The CComChannel established.
  284. Throws:
  285. DWORDs containing any error codes encountered.
  286. Author:
  287. Doug Barlow (dbarlow) 10/30/1996
  288. --*/
  289. #undef __SUBROUTINE__
  290. #define __SUBROUTINE__ DBGT("CComResponder::Listen")
  291. CComChannel *
  292. CComResponder::Listen(
  293. void)
  294. {
  295. CComChannel *pChannel = NULL;
  296. for (;;)
  297. {
  298. CHandleObject hComPipe(DBGT("Comm Pipe handle from CComResponder::Listen"));
  299. try
  300. {
  301. BOOL fSts;
  302. //
  303. // Wait for an incoming connect request.
  304. //
  305. RetryConnect:
  306. fSts = ConnectNamedPipe(m_hComPipe, &m_ovrlp);
  307. if (!fSts)
  308. {
  309. BOOL fErrorProcessed;
  310. DWORD dwSts = GetLastError();
  311. DWORD dwSize;
  312. DWORD dwWait;
  313. do
  314. {
  315. fErrorProcessed = TRUE;
  316. switch (dwSts)
  317. {
  318. //
  319. // Block until something happens.
  320. case ERROR_IO_PENDING:
  321. dwWait = WaitForAnyObject(
  322. INFINITE,
  323. m_ovrlp.hEvent,
  324. g_hCalaisShutdown,
  325. NULL);
  326. switch (dwWait)
  327. {
  328. case 1: // We've got a connect request
  329. fErrorProcessed = FALSE;
  330. fSts = GetOverlappedResult(
  331. m_hComPipe,
  332. &m_ovrlp,
  333. &dwSize,
  334. TRUE);
  335. dwSts = fSts ? ERROR_SUCCESS : GetLastError();
  336. break;
  337. case 2: // Application shutdown
  338. throw (DWORD)SCARD_P_SHUTDOWN;
  339. break;
  340. default:
  341. CalaisWarning(
  342. __SUBROUTINE__,
  343. DBGT("Wait for connect pipe returned invalid value"));
  344. throw (DWORD)SCARD_F_INTERNAL_ERROR;
  345. }
  346. break;
  347. //
  348. // Success after a wait event.
  349. case ERROR_SUCCESS:
  350. break;
  351. //
  352. // Non-error. Just ignore it.
  353. case ERROR_PIPE_CONNECTED:
  354. break;
  355. //
  356. // The client has closed its end
  357. case ERROR_NO_DATA:
  358. CalaisWarning(
  359. __SUBROUTINE__,
  360. DBGT("ConnectNamedPipe returned ERROR_NO_DATA, disconnecting and retrying"));
  361. DisconnectNamedPipe(m_hComPipe);
  362. goto RetryConnect;
  363. //
  364. // Unexpected error. Report it.
  365. default:
  366. CalaisError(__SUBROUTINE__, 108, dwSts);
  367. throw dwSts;
  368. }
  369. } while (!fErrorProcessed);
  370. }
  371. //
  372. // Kick off another Pipe instance for the next request.
  373. //
  374. hComPipe = m_hComPipe.Relinquish();
  375. // m_hComPipe = INVALID_HANDLE_VALUE;
  376. m_hComPipe = CreateNamedPipe(
  377. (LPCTSTR)m_bfPipeName.Access(),
  378. PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
  379. PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
  380. PIPE_UNLIMITED_INSTANCES,
  381. CALAIS_COMM_MSGLEN,
  382. CALAIS_COMM_MSGLEN,
  383. CALCOM_PIPE_TIMEOUT,
  384. m_aclPipe);
  385. if (!m_hComPipe.IsValid())
  386. {
  387. DWORD dwErr = m_hComPipe.GetLastError();
  388. CalaisError(__SUBROUTINE__, 105, dwErr);
  389. throw dwErr;
  390. }
  391. //
  392. // Handle the connect request data.
  393. //
  394. pChannel = new CComChannel(hComPipe);
  395. if (NULL == pChannel)
  396. {
  397. DWORD dwSts = SCARD_E_NO_MEMORY;
  398. CalaisWarning(
  399. __SUBROUTINE__,
  400. DBGT("Com Responder could not allocate a Comm Channel: %1"),
  401. dwSts);
  402. throw dwSts;
  403. }
  404. hComPipe.Relinquish();
  405. break;
  406. }
  407. catch (...)
  408. {
  409. if (NULL != pChannel)
  410. {
  411. delete pChannel;
  412. pChannel = NULL;
  413. }
  414. if (hComPipe.IsValid())
  415. hComPipe.Close();
  416. throw;
  417. }
  418. }
  419. return pChannel;
  420. }