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.

810 lines
23 KiB

  1. /*++
  2. Copyright (c) 1990 - 1995 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. portredn.c
  6. Abstract:
  7. This module contains functions to handle port redirection.
  8. Earlier this was done by localmon, the code is a modified version of
  9. localmon code.
  10. Author:
  11. Muhunthan Sivapragasam (MuhuntS) 10-Sep-1995
  12. Revision History:
  13. --*/
  14. #include <precomp.h>
  15. WCHAR szDeviceNameHeader[] = L"\\Device\\NamedPipe\\Spooler\\";
  16. WCHAR szCOM[] = L"COM";
  17. WCHAR szLPT[] = L"LPT";
  18. //
  19. // Definitions for MonitorThread:
  20. //
  21. #define TRANSMISSION_DATA_SIZE 0x400
  22. #define NUMBER_OF_PIPE_INSTANCES 10
  23. typedef struct _TRANSMISSION {
  24. HANDLE hPipe;
  25. BYTE Data[TRANSMISSION_DATA_SIZE];
  26. LPOVERLAPPED pOverlapped;
  27. HANDLE hPrinter;
  28. DWORD JobId;
  29. PINIPORT pIniPort;
  30. } TRANSMISSION, *PTRANSMISSION;
  31. typedef struct _REDIRECT_INFO {
  32. PINIPORT pIniPort;
  33. HANDLE hEvent;
  34. } REDIRECT_INFO, *PREDIRECT_INFO;
  35. VOID
  36. FreeRedirectInfo(
  37. PREDIRECT_INFO pRedirectInfo
  38. )
  39. {
  40. SplInSem();
  41. //
  42. // This is to handle the case when Redirection thread did not initialize
  43. // correctly and is terminating abnormally
  44. // Since CloseHandle has not been called it is ok to do this
  45. //
  46. if ( pRedirectInfo->pIniPort->hEvent == pRedirectInfo->hEvent )
  47. pRedirectInfo->pIniPort->hEvent = NULL;
  48. DECPORTREF(pRedirectInfo->pIniPort);
  49. CloseHandle(pRedirectInfo->hEvent);
  50. FreeSplMem(pRedirectInfo);
  51. }
  52. VOID
  53. RemoveColon(
  54. LPWSTR pName)
  55. {
  56. DWORD Length;
  57. Length = wcslen(pName);
  58. if (pName[Length-1] == L':')
  59. pName[Length-1] = 0;
  60. }
  61. VOID
  62. RemoveDeviceName(
  63. PINIPORT pIniPort
  64. )
  65. {
  66. SplInSem();
  67. if ( pIniPort->hEvent ) {
  68. //
  69. // Redirection thread is told to terminate here; It will close the
  70. // handle. If it has already terminated then this call will fail
  71. //
  72. SetEvent(pIniPort->hEvent);
  73. pIniPort->hEvent = NULL;
  74. }
  75. }
  76. #define MAX_ACE 6
  77. PSECURITY_DESCRIPTOR
  78. CreateNamedPipeSecurityDescriptor(
  79. VOID)
  80. /*++
  81. Routine Description:
  82. Creates a security descriptor giving everyone access.
  83. Arguments:
  84. Return Value:
  85. The security descriptor returned by BuildPrintObjectProtection.
  86. --*/
  87. {
  88. UCHAR AceType[MAX_ACE];
  89. PSID AceSid[MAX_ACE];
  90. BYTE InheritFlags[MAX_ACE];
  91. DWORD AceCount;
  92. PSECURITY_DESCRIPTOR ServerSD = NULL;
  93. //
  94. // For Code optimization we replace 5 individaul
  95. // SID_IDENTIFIER_AUTHORITY with an array of
  96. // SID_IDENTIFIER_AUTHORITYs
  97. // where
  98. // SidAuthority[0] = UserSidAuthority
  99. // SidAuthority[1] = PowerSidAuthority
  100. // SidAuthority[2] = EveryOneSidAuthority
  101. // SidAuthority[3] = CreatorSidAuthority
  102. // SidAuthority[4] = SystemSidAuthority
  103. // SidAuthority[5] = AdminSidAuthority
  104. //
  105. SID_IDENTIFIER_AUTHORITY SidAuthority[MAX_ACE] = {
  106. SECURITY_NT_AUTHORITY,
  107. SECURITY_NT_AUTHORITY,
  108. SECURITY_WORLD_SID_AUTHORITY,
  109. SECURITY_CREATOR_SID_AUTHORITY,
  110. SECURITY_NT_AUTHORITY,
  111. SECURITY_NT_AUTHORITY
  112. };
  113. //
  114. // For code optimization we replace 5 individual Sids with
  115. // an array of Sids
  116. // where
  117. // Sid[0] = UserSid
  118. // Sid[1] = PowerSid
  119. // Sid[2] = EveryOne
  120. // Sid[3] = CreatorSid
  121. // Sid[4] = SystemSid
  122. // Sid[5] = AdminSid
  123. //
  124. PSID Sids[MAX_ACE] = {NULL,NULL,NULL,NULL,NULL,NULL};
  125. ACCESS_MASK AceMask[MAX_ACE] = {
  126. FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE ,
  127. FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE ,
  128. (FILE_GENERIC_READ | FILE_WRITE_DATA | FILE_ALL_ACCESS) &
  129. ~WRITE_DAC &~WRITE_OWNER & ~DELETE & ~FILE_CREATE_PIPE_INSTANCE,
  130. STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE | FILE_GENERIC_READ | FILE_ALL_ACCESS,
  131. STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE | FILE_GENERIC_READ | FILE_ALL_ACCESS,
  132. STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE | FILE_GENERIC_READ | FILE_ALL_ACCESS
  133. };
  134. DWORD SubAuthorities[3*MAX_ACE] = {
  135. 2 , SECURITY_BUILTIN_DOMAIN_RID , DOMAIN_ALIAS_RID_USERS ,
  136. 2 , SECURITY_BUILTIN_DOMAIN_RID , DOMAIN_ALIAS_RID_POWER_USERS ,
  137. 1 , SECURITY_WORLD_RID , 0 ,
  138. 1 , SECURITY_CREATOR_OWNER_RID , 0 ,
  139. 1 , SECURITY_LOCAL_SYSTEM_RID , 0 ,
  140. 2 , SECURITY_BUILTIN_DOMAIN_RID , DOMAIN_ALIAS_RID_ADMINS
  141. };
  142. //
  143. // Name Pipe SD
  144. //
  145. for(AceCount = 0;
  146. ( (AceCount < MAX_ACE) &&
  147. AllocateAndInitializeSid(&SidAuthority[AceCount],
  148. (BYTE)SubAuthorities[AceCount*3],
  149. SubAuthorities[AceCount*3+1],
  150. SubAuthorities[AceCount*3+2],
  151. 0, 0, 0, 0, 0, 0,
  152. &Sids[AceCount]));
  153. AceCount++)
  154. {
  155. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  156. AceSid[AceCount] = Sids[AceCount];
  157. InheritFlags[AceCount] = 0;
  158. }
  159. if(AceCount == MAX_ACE)
  160. {
  161. if(!BuildPrintObjectProtection(AceType,
  162. AceCount,
  163. AceSid,
  164. AceMask,
  165. InheritFlags,
  166. NULL,
  167. NULL,
  168. NULL,
  169. &ServerSD ) )
  170. {
  171. DBGMSG( DBG_WARNING,( "Couldn't buidl Named Pipe protection" ) );
  172. }
  173. }
  174. else
  175. {
  176. DBGMSG( DBG_WARNING,( "Couldn't Allocate and initialize SIDs" ) );
  177. }
  178. for(AceCount=0;AceCount<MAX_ACE;AceCount++)
  179. {
  180. if(Sids[AceCount])
  181. FreeSid( Sids[AceCount] );
  182. }
  183. return ServerSD;
  184. }
  185. LPWSTR
  186. SetupDosDev(
  187. PINIPORT pIniPort,
  188. LPWSTR szPipeName,
  189. DWORD cchPipeName,
  190. PSECURITY_ATTRIBUTES pSecurityAttributes,
  191. PSECURITY_ATTRIBUTES* ppSecurityAttributes
  192. )
  193. {
  194. WCHAR NewNtDeviceName[MAX_PATH];
  195. WCHAR OldNtDeviceName[MAX_PATH];
  196. WCHAR DosDeviceName[MAX_PATH];
  197. LPWSTR pszNewDeviceName = NULL;
  198. PSECURITY_DESCRIPTOR lpSecurityDescriptor = NULL;
  199. BOOL bRet = FALSE;
  200. if (!BoolFromHResult(StringCchCopy(DosDeviceName, COUNTOF(DosDeviceName), pIniPort->pName))) {
  201. goto Cleanup;
  202. }
  203. RemoveColon(DosDeviceName);
  204. if(StrNCatBuff(NewNtDeviceName,
  205. COUNTOF(NewNtDeviceName),
  206. szDeviceNameHeader,
  207. pIniPort->pName,
  208. NULL) != ERROR_SUCCESS ) {
  209. goto Cleanup;
  210. }
  211. RemoveColon(NewNtDeviceName);
  212. pszNewDeviceName = AllocSplStr(NewNtDeviceName);
  213. if ( !pszNewDeviceName ||
  214. !QueryDosDevice(DosDeviceName, OldNtDeviceName,
  215. sizeof(OldNtDeviceName)/sizeof(OldNtDeviceName[0]))) {
  216. goto Cleanup;
  217. }
  218. lpSecurityDescriptor = CreateNamedPipeSecurityDescriptor();
  219. if (lpSecurityDescriptor) {
  220. pSecurityAttributes->nLength = sizeof(SECURITY_ATTRIBUTES);
  221. pSecurityAttributes->lpSecurityDescriptor = lpSecurityDescriptor;
  222. pSecurityAttributes->bInheritHandle = FALSE;
  223. } else {
  224. pSecurityAttributes = NULL;
  225. }
  226. //
  227. // If clause added to preclude multiple entries of the same named pipe in the device
  228. // name definition.
  229. // Ram 1\16
  230. //
  231. if (lstrcmp(NewNtDeviceName, OldNtDeviceName) != 0) {
  232. DefineDosDevice(DDD_RAW_TARGET_PATH, DosDeviceName, NewNtDeviceName);
  233. }
  234. if (StrNCatBuff(szPipeName,
  235. cchPipeName,
  236. L"\\\\.\\Pipe\\Spooler\\",
  237. pIniPort->pName,
  238. NULL) != ERROR_SUCCESS) {
  239. goto Cleanup;
  240. }
  241. RemoveColon(szPipeName);
  242. *ppSecurityAttributes = pSecurityAttributes;
  243. bRet = TRUE;
  244. Cleanup:
  245. if ( !bRet ) {
  246. FreeSplStr(pszNewDeviceName);
  247. pszNewDeviceName = NULL;
  248. }
  249. return pszNewDeviceName;
  250. }
  251. VOID
  252. ReadThread(
  253. PTRANSMISSION pTransmission)
  254. {
  255. DOC_INFO_1W DocInfo;
  256. DWORD BytesRead;
  257. DWORD BytesWritten;
  258. BOOL bStartDocPrinterResult = FALSE;
  259. BOOL bReadResult;
  260. LPWSTR pszPrinter=NULL;
  261. //
  262. // ImpersonateNamedPipeClient requires that some data is read before
  263. // the impersonation is done.
  264. //
  265. bReadResult = ReadFile(pTransmission->hPipe,
  266. pTransmission->Data,
  267. sizeof(pTransmission->Data),
  268. &BytesRead,
  269. NULL);
  270. if (!bReadResult)
  271. goto Fail;
  272. if (!ImpersonateNamedPipeClient(pTransmission->hPipe)) {
  273. DBGMSG(DBG_ERROR,("ImpersonateNamedPipeClient failed %d\n",
  274. GetLastError()));
  275. goto Fail;
  276. }
  277. SPLASSERT(pTransmission->pIniPort->cPrinters);
  278. pszPrinter = AllocSplStr(pTransmission->pIniPort->ppIniPrinter[0]->pName);
  279. if ( !pszPrinter ) {
  280. goto Fail;
  281. }
  282. //
  283. // Open the printer.
  284. //
  285. if (!OpenPrinter(pszPrinter, &pTransmission->hPrinter, NULL)) {
  286. DBGMSG(DBG_WARN, ("OpenPrinter(%ws) failed: Error %d\n",
  287. pszPrinter,
  288. GetLastError()));
  289. goto Fail;
  290. }
  291. memset(&DocInfo, 0, sizeof(DOC_INFO_1W));
  292. if (StartDocPrinter(pTransmission->hPrinter, 1, (LPBYTE)&DocInfo)) {
  293. DBGMSG(DBG_INFO, ("StartDocPrinter succeeded\n"));
  294. bStartDocPrinterResult = TRUE;
  295. } else {
  296. DBGMSG(DBG_WARN, ("StartDocPrinter failed: Error %d\n",
  297. GetLastError()));
  298. goto Fail;
  299. }
  300. while (bReadResult && BytesRead) {
  301. if (!WritePrinter(pTransmission->hPrinter,
  302. pTransmission->Data,
  303. BytesRead,
  304. &BytesWritten))
  305. {
  306. DBGMSG(DBG_WARN, ("WritePrinter failed: Error %d\n",
  307. GetLastError()));
  308. goto Fail;
  309. }
  310. bReadResult = ReadFile(pTransmission->hPipe,
  311. pTransmission->Data,
  312. sizeof(pTransmission->Data),
  313. &BytesRead,
  314. NULL);
  315. }
  316. DBGMSG(DBG_INFO, ("bool %d BytesRead 0x%x (Error = %d) EOT\n",
  317. bReadResult,
  318. BytesRead,
  319. GetLastError()));
  320. Fail:
  321. if (bStartDocPrinterResult) {
  322. if (!EndDocPrinter(pTransmission->hPrinter)) {
  323. DBGMSG(DBG_WARN, ("EndDocPrinter failed: Error %d\n",
  324. GetLastError()));
  325. }
  326. }
  327. FreeSplStr(pszPrinter);
  328. if (pTransmission->hPrinter)
  329. ClosePrinter(pTransmission->hPrinter);
  330. if ( !SetEvent(pTransmission->pOverlapped->hEvent)) {
  331. DBGMSG(DBG_ERROR, ("SetEvent failed %d\n", GetLastError()));
  332. }
  333. FreeSplMem(pTransmission);
  334. }
  335. BOOL
  336. ReconnectNamedPipe(
  337. HANDLE hPipe,
  338. LPOVERLAPPED pOverlapped)
  339. {
  340. DWORD Error;
  341. BOOL bIOPending = FALSE;
  342. DisconnectNamedPipe(hPipe);
  343. if (!ConnectNamedPipe(hPipe,
  344. pOverlapped)) {
  345. Error = GetLastError( );
  346. if (Error == ERROR_IO_PENDING) {
  347. DBGMSG(DBG_INFO, ("re-ConnectNamedPipe 0x%x IO pending\n", hPipe));
  348. bIOPending = TRUE;
  349. } else {
  350. DBGMSG(DBG_ERROR, ("re-ConnectNamedPipe 0x%x failed. Error %d\n",
  351. hPipe,
  352. Error));
  353. }
  354. } else {
  355. DBGMSG(DBG_INFO, ("re-ConnectNamedPipe successful 0x%x\n", hPipe));
  356. }
  357. return bIOPending;
  358. }
  359. BOOL
  360. RedirectionThread(
  361. PREDIRECT_INFO pRedirectInfo
  362. )
  363. /*++
  364. Redirection thread is responsible for freeing pRedirectInfo. Since
  365. the ref count on port thread is incremented before this is called we
  366. know that the IniPort will be valid till we decrement the ref count.
  367. We are also passed the event we should wait to die on.
  368. This is pIniPort->hEvent. But redirection thread should use the local
  369. copy passed and not the one in pIniPort. The reason is there could be a
  370. lag from the time this event is set and the redirection dies. In the
  371. meantime a new rediction thread could be spun off and in which case the
  372. pIniPort->hEvent will not be for this thread
  373. When redirection thread is told to die:
  374. a. it should decrement the ref count on the pIniPort object when it is
  375. done with it's reference to pIniPort
  376. b. it should call CloseHandle on pRedirectInfo->hEvent
  377. --*/
  378. {
  379. WCHAR szPipeName[MAX_PATH];
  380. HANDLE hPipe[NUMBER_OF_PIPE_INSTANCES];
  381. SECURITY_ATTRIBUTES SecurityAttributes;
  382. PSECURITY_ATTRIBUTES pSecurityAttributes;
  383. //
  384. // One extra event for our trigger (pIniPort->hEvent)
  385. //
  386. HANDLE ahEvent[NUMBER_OF_PIPE_INSTANCES+1];
  387. BOOL abReconnect[NUMBER_OF_PIPE_INSTANCES];
  388. OVERLAPPED Overlapped[NUMBER_OF_PIPE_INSTANCES];
  389. DWORD WaitResult, i, j, Error, dwThreadId;
  390. PTRANSMISSION pTransmission;
  391. HANDLE hThread;
  392. BOOL bTerminate = FALSE;
  393. LPWSTR pszNewDeviceName = NULL;
  394. SecurityAttributes.lpSecurityDescriptor = NULL;
  395. //
  396. // Setup the redirection.
  397. //
  398. if ( !(pszNewDeviceName = SetupDosDev(pRedirectInfo->pIniPort,
  399. szPipeName,
  400. COUNTOF(szPipeName),
  401. &SecurityAttributes,
  402. &pSecurityAttributes)) ) {
  403. EnterSplSem();
  404. FreeRedirectInfo(pRedirectInfo);
  405. LeaveSplSem();
  406. return FALSE;
  407. }
  408. //
  409. // Initialization
  410. //
  411. for (i = 0; i < NUMBER_OF_PIPE_INSTANCES; i++) {
  412. hPipe[i] = INVALID_HANDLE_VALUE;
  413. Overlapped[i].hEvent = ahEvent[i] = NULL;
  414. }
  415. //
  416. // Put the event in the extra member of the event array.
  417. //
  418. ahEvent[NUMBER_OF_PIPE_INSTANCES] = pRedirectInfo->hEvent;
  419. //
  420. // Create several instances of a named pipe, create an event for each,
  421. // and connect to wait for a client:
  422. //
  423. for (i = 0; i < NUMBER_OF_PIPE_INSTANCES; i++) {
  424. abReconnect[i] = FALSE;
  425. hPipe[i] = CreateNamedPipe(szPipeName,
  426. PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
  427. PIPE_WAIT | PIPE_READMODE_BYTE | PIPE_TYPE_BYTE,
  428. PIPE_UNLIMITED_INSTANCES,
  429. 4096,
  430. 64*1024, // 64k
  431. 0,
  432. pSecurityAttributes);
  433. if ( hPipe[i] == INVALID_HANDLE_VALUE ) {
  434. DBGMSG(DBG_ERROR, ("CreateNamedPipe failed for %ws. Error %d\n",
  435. szPipeName, GetLastError()));
  436. goto Cleanup;
  437. }
  438. ahEvent[i] = Overlapped[i].hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  439. if (!ahEvent[i]) {
  440. DBGMSG(DBG_ERROR, ("CreateEvent failed. Error %d\n",
  441. GetLastError()));
  442. goto Cleanup;
  443. }
  444. if (!ConnectNamedPipe(hPipe[i], &Overlapped[i])){
  445. Error = GetLastError();
  446. if (Error == ERROR_IO_PENDING) {
  447. DBGMSG(DBG_INFO, ("ConnectNamedPipe %d, IO pending\n",
  448. i));
  449. } else {
  450. DBGMSG(DBG_ERROR, ("ConnectNamedPipe failed. Error %d\n",
  451. GetLastError()));
  452. goto Cleanup;
  453. }
  454. }
  455. }
  456. while (TRUE) {
  457. DBGMSG(DBG_INFO, ("Waiting to connect...\n"));
  458. WaitResult = WaitForMultipleObjectsEx(NUMBER_OF_PIPE_INSTANCES + 1,
  459. ahEvent,
  460. FALSE,
  461. INFINITE,
  462. TRUE);
  463. DBGMSG(DBG_INFO, ("WaitForMultipleObjectsEx returned %d\n",
  464. WaitResult));
  465. if ((WaitResult >= NUMBER_OF_PIPE_INSTANCES)
  466. && (WaitResult != WAIT_IO_COMPLETION)) {
  467. DBGMSG(DBG_INFO, ("WaitForMultipleObjects returned %d; Last error = %d\n",
  468. WaitResult,
  469. GetLastError( ) ) );
  470. //
  471. // We need to terminate. But wait for any read thread that is spun
  472. // off by this redirection thread
  473. //
  474. for ( i = 0 ; i < NUMBER_OF_PIPE_INSTANCES ; ++i )
  475. if ( abReconnect[i] ) {
  476. bTerminate = TRUE;
  477. break; // the for loop
  478. }
  479. if ( i < NUMBER_OF_PIPE_INSTANCES )
  480. continue; // for the while loop
  481. else
  482. goto Cleanup;
  483. }
  484. i = WaitResult;
  485. //
  486. // If disco and reconnect was pending, do it again here.
  487. //
  488. if (abReconnect[i]) {
  489. abReconnect[i] = FALSE;
  490. //
  491. // If redirection thread has been told to quit check for termination
  492. //
  493. if ( bTerminate ) {
  494. for ( j = 0 ; j < NUMBER_OF_PIPE_INSTANCES ; ++j )
  495. if ( abReconnect[j] )
  496. break; // the for loop
  497. if ( j < NUMBER_OF_PIPE_INSTANCES )
  498. continue; // for while loop
  499. else
  500. goto Cleanup;
  501. } else {
  502. ReconnectNamedPipe(hPipe[i], &Overlapped[i]);
  503. continue;
  504. }
  505. }
  506. //
  507. // If we have been told to terminate do not spin a read thread
  508. //
  509. if ( bTerminate )
  510. continue;
  511. //
  512. // Set up the transmission structure with the handles etc. needed by
  513. // the completion callback routine:
  514. //
  515. pTransmission = (PTRANSMISSION)AllocSplMem(sizeof(TRANSMISSION));
  516. if (pTransmission) {
  517. pTransmission->hPipe = hPipe[i];
  518. pTransmission->pOverlapped = &Overlapped[i];
  519. pTransmission->hPrinter = NULL;
  520. pTransmission->pIniPort = pRedirectInfo->pIniPort;
  521. abReconnect[i] = TRUE;
  522. hThread = CreateThread(NULL,
  523. INITIAL_STACK_COMMIT,
  524. (LPTHREAD_START_ROUTINE)ReadThread,
  525. pTransmission,
  526. 0,
  527. &dwThreadId);
  528. if (hThread) {
  529. CloseHandle(hThread);
  530. } else {
  531. abReconnect[i] = FALSE;
  532. FreeSplMem(pTransmission);
  533. DBGMSG(DBG_WARN, ("CreateThread failed. Error %d\n",
  534. GetLastError()));
  535. }
  536. } else {
  537. DBGMSG(DBG_WARN, ("Alloc failed. Error %d\n",
  538. GetLastError()));
  539. }
  540. }
  541. Cleanup:
  542. if ( pszNewDeviceName ) {
  543. WCHAR DosDeviceName[MAX_PATH];
  544. if (SUCCEEDED(StringCchCopy(DosDeviceName, COUNTOF(DosDeviceName), pRedirectInfo->pIniPort->pName)))
  545. {
  546. RemoveColon(DosDeviceName);
  547. DefineDosDevice(DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE | DDD_RAW_TARGET_PATH,
  548. DosDeviceName,
  549. pszNewDeviceName);
  550. }
  551. FreeSplStr(pszNewDeviceName);
  552. }
  553. EnterSplSem();
  554. FreeRedirectInfo(pRedirectInfo);
  555. LeaveSplSem();
  556. for (i = 0; i < NUMBER_OF_PIPE_INSTANCES; i++) {
  557. if ( hPipe[i] != INVALID_HANDLE_VALUE ) {
  558. CloseHandle(hPipe[i]);
  559. hPipe[i] = INVALID_HANDLE_VALUE;
  560. }
  561. if ( ahEvent[i] ) {
  562. CloseHandle(ahEvent[i]);
  563. ahEvent[i] = NULL;
  564. Overlapped[i].hEvent = NULL;
  565. }
  566. }
  567. if (SecurityAttributes.lpSecurityDescriptor)
  568. DestroyPrivateObjectSecurity(&SecurityAttributes.lpSecurityDescriptor);
  569. return TRUE;
  570. }
  571. BOOL
  572. CreateRedirectionThread(
  573. PINIPORT pIniPort)
  574. {
  575. HANDLE hThread;
  576. DWORD dwThreadId;
  577. PREDIRECT_INFO pRedirectInfo = NULL;
  578. SplInSem();
  579. SPLASSERT(pIniPort->hEvent == NULL);
  580. //
  581. // Create redirection thread only once and only for LPT and COM ports
  582. //
  583. if ( !IsPortType(pIniPort->pName, szLPT) &&
  584. !IsPortType(pIniPort->pName, szCOM) ) {
  585. return TRUE;
  586. }
  587. pIniPort->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  588. pRedirectInfo = (PREDIRECT_INFO) AllocSplMem(sizeof(REDIRECT_INFO));
  589. if ( !pIniPort->hEvent || !pRedirectInfo ) {
  590. FreeSplMem(pRedirectInfo);
  591. if ( pIniPort->hEvent ) {
  592. CloseHandle(pIniPort->hEvent);
  593. pIniPort->hEvent = NULL;
  594. }
  595. return FALSE;
  596. }
  597. INCPORTREF(pIniPort);
  598. pRedirectInfo->pIniPort = pIniPort;
  599. pRedirectInfo->hEvent = pIniPort->hEvent;
  600. hThread = CreateThread(NULL,
  601. INITIAL_STACK_COMMIT,
  602. (LPTHREAD_START_ROUTINE)RedirectionThread,
  603. pRedirectInfo,
  604. 0,
  605. &dwThreadId);
  606. if (hThread) {
  607. CloseHandle(hThread);
  608. } else {
  609. pIniPort->hEvent = NULL;
  610. FreeRedirectInfo(pRedirectInfo);
  611. return FALSE;
  612. }
  613. return TRUE;
  614. }