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
810 lines
23 KiB
/*++
|
|
|
|
Copyright (c) 1990 - 1995 Microsoft Corporation
|
|
All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
portredn.c
|
|
|
|
Abstract:
|
|
|
|
This module contains functions to handle port redirection.
|
|
Earlier this was done by localmon, the code is a modified version of
|
|
localmon code.
|
|
|
|
Author:
|
|
|
|
Muhunthan Sivapragasam (MuhuntS) 10-Sep-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
|
|
WCHAR szDeviceNameHeader[] = L"\\Device\\NamedPipe\\Spooler\\";
|
|
WCHAR szCOM[] = L"COM";
|
|
WCHAR szLPT[] = L"LPT";
|
|
|
|
//
|
|
// Definitions for MonitorThread:
|
|
//
|
|
#define TRANSMISSION_DATA_SIZE 0x400
|
|
#define NUMBER_OF_PIPE_INSTANCES 10
|
|
|
|
|
|
typedef struct _TRANSMISSION {
|
|
HANDLE hPipe;
|
|
BYTE Data[TRANSMISSION_DATA_SIZE];
|
|
LPOVERLAPPED pOverlapped;
|
|
HANDLE hPrinter;
|
|
DWORD JobId;
|
|
PINIPORT pIniPort;
|
|
} TRANSMISSION, *PTRANSMISSION;
|
|
|
|
typedef struct _REDIRECT_INFO {
|
|
PINIPORT pIniPort;
|
|
HANDLE hEvent;
|
|
} REDIRECT_INFO, *PREDIRECT_INFO;
|
|
|
|
|
|
VOID
|
|
FreeRedirectInfo(
|
|
PREDIRECT_INFO pRedirectInfo
|
|
)
|
|
{
|
|
SplInSem();
|
|
|
|
//
|
|
// This is to handle the case when Redirection thread did not initialize
|
|
// correctly and is terminating abnormally
|
|
// Since CloseHandle has not been called it is ok to do this
|
|
//
|
|
if ( pRedirectInfo->pIniPort->hEvent == pRedirectInfo->hEvent )
|
|
pRedirectInfo->pIniPort->hEvent = NULL;
|
|
|
|
DECPORTREF(pRedirectInfo->pIniPort);
|
|
CloseHandle(pRedirectInfo->hEvent);
|
|
FreeSplMem(pRedirectInfo);
|
|
}
|
|
|
|
|
|
VOID
|
|
RemoveColon(
|
|
LPWSTR pName)
|
|
{
|
|
DWORD Length;
|
|
|
|
Length = wcslen(pName);
|
|
|
|
if (pName[Length-1] == L':')
|
|
pName[Length-1] = 0;
|
|
}
|
|
|
|
|
|
VOID
|
|
RemoveDeviceName(
|
|
PINIPORT pIniPort
|
|
)
|
|
{
|
|
SplInSem();
|
|
|
|
if ( pIniPort->hEvent ) {
|
|
|
|
//
|
|
// Redirection thread is told to terminate here; It will close the
|
|
// handle. If it has already terminated then this call will fail
|
|
//
|
|
SetEvent(pIniPort->hEvent);
|
|
pIniPort->hEvent = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
#define MAX_ACE 6
|
|
|
|
PSECURITY_DESCRIPTOR
|
|
CreateNamedPipeSecurityDescriptor(
|
|
VOID)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a security descriptor giving everyone access.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
The security descriptor returned by BuildPrintObjectProtection.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
UCHAR AceType[MAX_ACE];
|
|
PSID AceSid[MAX_ACE];
|
|
BYTE InheritFlags[MAX_ACE];
|
|
DWORD AceCount;
|
|
PSECURITY_DESCRIPTOR ServerSD = NULL;
|
|
|
|
//
|
|
// For Code optimization we replace 5 individaul
|
|
// SID_IDENTIFIER_AUTHORITY with an array of
|
|
// SID_IDENTIFIER_AUTHORITYs
|
|
// where
|
|
// SidAuthority[0] = UserSidAuthority
|
|
// SidAuthority[1] = PowerSidAuthority
|
|
// SidAuthority[2] = EveryOneSidAuthority
|
|
// SidAuthority[3] = CreatorSidAuthority
|
|
// SidAuthority[4] = SystemSidAuthority
|
|
// SidAuthority[5] = AdminSidAuthority
|
|
//
|
|
SID_IDENTIFIER_AUTHORITY SidAuthority[MAX_ACE] = {
|
|
SECURITY_NT_AUTHORITY,
|
|
SECURITY_NT_AUTHORITY,
|
|
SECURITY_WORLD_SID_AUTHORITY,
|
|
SECURITY_CREATOR_SID_AUTHORITY,
|
|
SECURITY_NT_AUTHORITY,
|
|
SECURITY_NT_AUTHORITY
|
|
};
|
|
//
|
|
// For code optimization we replace 5 individual Sids with
|
|
// an array of Sids
|
|
// where
|
|
// Sid[0] = UserSid
|
|
// Sid[1] = PowerSid
|
|
// Sid[2] = EveryOne
|
|
// Sid[3] = CreatorSid
|
|
// Sid[4] = SystemSid
|
|
// Sid[5] = AdminSid
|
|
//
|
|
PSID Sids[MAX_ACE] = {NULL,NULL,NULL,NULL,NULL,NULL};
|
|
|
|
ACCESS_MASK AceMask[MAX_ACE] = {
|
|
FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE ,
|
|
FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE ,
|
|
(FILE_GENERIC_READ | FILE_WRITE_DATA | FILE_ALL_ACCESS) &
|
|
~WRITE_DAC &~WRITE_OWNER & ~DELETE & ~FILE_CREATE_PIPE_INSTANCE,
|
|
STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE | FILE_GENERIC_READ | FILE_ALL_ACCESS,
|
|
STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE | FILE_GENERIC_READ | FILE_ALL_ACCESS,
|
|
STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE | FILE_GENERIC_READ | FILE_ALL_ACCESS
|
|
};
|
|
|
|
DWORD SubAuthorities[3*MAX_ACE] = {
|
|
2 , SECURITY_BUILTIN_DOMAIN_RID , DOMAIN_ALIAS_RID_USERS ,
|
|
2 , SECURITY_BUILTIN_DOMAIN_RID , DOMAIN_ALIAS_RID_POWER_USERS ,
|
|
1 , SECURITY_WORLD_RID , 0 ,
|
|
1 , SECURITY_CREATOR_OWNER_RID , 0 ,
|
|
1 , SECURITY_LOCAL_SYSTEM_RID , 0 ,
|
|
2 , SECURITY_BUILTIN_DOMAIN_RID , DOMAIN_ALIAS_RID_ADMINS
|
|
};
|
|
//
|
|
// Name Pipe SD
|
|
//
|
|
|
|
for(AceCount = 0;
|
|
( (AceCount < MAX_ACE) &&
|
|
AllocateAndInitializeSid(&SidAuthority[AceCount],
|
|
(BYTE)SubAuthorities[AceCount*3],
|
|
SubAuthorities[AceCount*3+1],
|
|
SubAuthorities[AceCount*3+2],
|
|
0, 0, 0, 0, 0, 0,
|
|
&Sids[AceCount]));
|
|
AceCount++)
|
|
{
|
|
AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
|
|
AceSid[AceCount] = Sids[AceCount];
|
|
InheritFlags[AceCount] = 0;
|
|
}
|
|
|
|
if(AceCount == MAX_ACE)
|
|
{
|
|
if(!BuildPrintObjectProtection(AceType,
|
|
AceCount,
|
|
AceSid,
|
|
AceMask,
|
|
InheritFlags,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&ServerSD ) )
|
|
{
|
|
DBGMSG( DBG_WARNING,( "Couldn't buidl Named Pipe protection" ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGMSG( DBG_WARNING,( "Couldn't Allocate and initialize SIDs" ) );
|
|
}
|
|
|
|
for(AceCount=0;AceCount<MAX_ACE;AceCount++)
|
|
{
|
|
if(Sids[AceCount])
|
|
FreeSid( Sids[AceCount] );
|
|
}
|
|
return ServerSD;
|
|
}
|
|
|
|
|
|
LPWSTR
|
|
SetupDosDev(
|
|
PINIPORT pIniPort,
|
|
LPWSTR szPipeName,
|
|
DWORD cchPipeName,
|
|
PSECURITY_ATTRIBUTES pSecurityAttributes,
|
|
PSECURITY_ATTRIBUTES* ppSecurityAttributes
|
|
)
|
|
{
|
|
WCHAR NewNtDeviceName[MAX_PATH];
|
|
WCHAR OldNtDeviceName[MAX_PATH];
|
|
WCHAR DosDeviceName[MAX_PATH];
|
|
LPWSTR pszNewDeviceName = NULL;
|
|
PSECURITY_DESCRIPTOR lpSecurityDescriptor = NULL;
|
|
BOOL bRet = FALSE;
|
|
|
|
|
|
if (!BoolFromHResult(StringCchCopy(DosDeviceName, COUNTOF(DosDeviceName), pIniPort->pName))) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
RemoveColon(DosDeviceName);
|
|
|
|
if(StrNCatBuff(NewNtDeviceName,
|
|
COUNTOF(NewNtDeviceName),
|
|
szDeviceNameHeader,
|
|
pIniPort->pName,
|
|
NULL) != ERROR_SUCCESS ) {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
RemoveColon(NewNtDeviceName);
|
|
|
|
pszNewDeviceName = AllocSplStr(NewNtDeviceName);
|
|
|
|
if ( !pszNewDeviceName ||
|
|
!QueryDosDevice(DosDeviceName, OldNtDeviceName,
|
|
sizeof(OldNtDeviceName)/sizeof(OldNtDeviceName[0]))) {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
lpSecurityDescriptor = CreateNamedPipeSecurityDescriptor();
|
|
|
|
if (lpSecurityDescriptor) {
|
|
pSecurityAttributes->nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
pSecurityAttributes->lpSecurityDescriptor = lpSecurityDescriptor;
|
|
pSecurityAttributes->bInheritHandle = FALSE;
|
|
} else {
|
|
pSecurityAttributes = NULL;
|
|
}
|
|
|
|
//
|
|
// If clause added to preclude multiple entries of the same named pipe in the device
|
|
// name definition.
|
|
// Ram 1\16
|
|
//
|
|
|
|
if (lstrcmp(NewNtDeviceName, OldNtDeviceName) != 0) {
|
|
DefineDosDevice(DDD_RAW_TARGET_PATH, DosDeviceName, NewNtDeviceName);
|
|
}
|
|
|
|
if (StrNCatBuff(szPipeName,
|
|
cchPipeName,
|
|
L"\\\\.\\Pipe\\Spooler\\",
|
|
pIniPort->pName,
|
|
NULL) != ERROR_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
RemoveColon(szPipeName);
|
|
|
|
|
|
*ppSecurityAttributes = pSecurityAttributes;
|
|
bRet = TRUE;
|
|
|
|
Cleanup:
|
|
if ( !bRet ) {
|
|
|
|
FreeSplStr(pszNewDeviceName);
|
|
pszNewDeviceName = NULL;
|
|
}
|
|
|
|
return pszNewDeviceName;
|
|
}
|
|
|
|
|
|
VOID
|
|
ReadThread(
|
|
PTRANSMISSION pTransmission)
|
|
{
|
|
DOC_INFO_1W DocInfo;
|
|
DWORD BytesRead;
|
|
DWORD BytesWritten;
|
|
BOOL bStartDocPrinterResult = FALSE;
|
|
BOOL bReadResult;
|
|
|
|
LPWSTR pszPrinter=NULL;
|
|
|
|
//
|
|
// ImpersonateNamedPipeClient requires that some data is read before
|
|
// the impersonation is done.
|
|
//
|
|
bReadResult = ReadFile(pTransmission->hPipe,
|
|
pTransmission->Data,
|
|
sizeof(pTransmission->Data),
|
|
&BytesRead,
|
|
NULL);
|
|
|
|
if (!bReadResult)
|
|
goto Fail;
|
|
|
|
if (!ImpersonateNamedPipeClient(pTransmission->hPipe)) {
|
|
|
|
DBGMSG(DBG_ERROR,("ImpersonateNamedPipeClient failed %d\n",
|
|
GetLastError()));
|
|
|
|
goto Fail;
|
|
}
|
|
|
|
SPLASSERT(pTransmission->pIniPort->cPrinters);
|
|
pszPrinter = AllocSplStr(pTransmission->pIniPort->ppIniPrinter[0]->pName);
|
|
|
|
if ( !pszPrinter ) {
|
|
|
|
goto Fail;
|
|
}
|
|
|
|
|
|
//
|
|
// Open the printer.
|
|
//
|
|
if (!OpenPrinter(pszPrinter, &pTransmission->hPrinter, NULL)) {
|
|
|
|
DBGMSG(DBG_WARN, ("OpenPrinter(%ws) failed: Error %d\n",
|
|
pszPrinter,
|
|
GetLastError()));
|
|
goto Fail;
|
|
}
|
|
|
|
memset(&DocInfo, 0, sizeof(DOC_INFO_1W));
|
|
|
|
if (StartDocPrinter(pTransmission->hPrinter, 1, (LPBYTE)&DocInfo)) {
|
|
|
|
DBGMSG(DBG_INFO, ("StartDocPrinter succeeded\n"));
|
|
bStartDocPrinterResult = TRUE;
|
|
|
|
} else {
|
|
|
|
DBGMSG(DBG_WARN, ("StartDocPrinter failed: Error %d\n",
|
|
GetLastError()));
|
|
|
|
goto Fail;
|
|
}
|
|
|
|
while (bReadResult && BytesRead) {
|
|
|
|
if (!WritePrinter(pTransmission->hPrinter,
|
|
pTransmission->Data,
|
|
BytesRead,
|
|
&BytesWritten))
|
|
{
|
|
DBGMSG(DBG_WARN, ("WritePrinter failed: Error %d\n",
|
|
GetLastError()));
|
|
|
|
goto Fail;
|
|
}
|
|
|
|
bReadResult = ReadFile(pTransmission->hPipe,
|
|
pTransmission->Data,
|
|
sizeof(pTransmission->Data),
|
|
&BytesRead,
|
|
NULL);
|
|
}
|
|
|
|
DBGMSG(DBG_INFO, ("bool %d BytesRead 0x%x (Error = %d) EOT\n",
|
|
bReadResult,
|
|
BytesRead,
|
|
GetLastError()));
|
|
|
|
|
|
Fail:
|
|
|
|
if (bStartDocPrinterResult) {
|
|
|
|
if (!EndDocPrinter(pTransmission->hPrinter)) {
|
|
|
|
DBGMSG(DBG_WARN, ("EndDocPrinter failed: Error %d\n",
|
|
GetLastError()));
|
|
}
|
|
}
|
|
|
|
FreeSplStr(pszPrinter);
|
|
if (pTransmission->hPrinter)
|
|
ClosePrinter(pTransmission->hPrinter);
|
|
|
|
if ( !SetEvent(pTransmission->pOverlapped->hEvent)) {
|
|
|
|
DBGMSG(DBG_ERROR, ("SetEvent failed %d\n", GetLastError()));
|
|
}
|
|
|
|
FreeSplMem(pTransmission);
|
|
}
|
|
|
|
|
|
BOOL
|
|
ReconnectNamedPipe(
|
|
HANDLE hPipe,
|
|
LPOVERLAPPED pOverlapped)
|
|
{
|
|
DWORD Error;
|
|
BOOL bIOPending = FALSE;
|
|
|
|
DisconnectNamedPipe(hPipe);
|
|
|
|
if (!ConnectNamedPipe(hPipe,
|
|
pOverlapped)) {
|
|
|
|
Error = GetLastError( );
|
|
|
|
if (Error == ERROR_IO_PENDING) {
|
|
|
|
DBGMSG(DBG_INFO, ("re-ConnectNamedPipe 0x%x IO pending\n", hPipe));
|
|
bIOPending = TRUE;
|
|
|
|
} else {
|
|
|
|
DBGMSG(DBG_ERROR, ("re-ConnectNamedPipe 0x%x failed. Error %d\n",
|
|
hPipe,
|
|
Error));
|
|
}
|
|
} else {
|
|
|
|
DBGMSG(DBG_INFO, ("re-ConnectNamedPipe successful 0x%x\n", hPipe));
|
|
}
|
|
return bIOPending;
|
|
}
|
|
|
|
|
|
BOOL
|
|
RedirectionThread(
|
|
PREDIRECT_INFO pRedirectInfo
|
|
)
|
|
/*++
|
|
Redirection thread is responsible for freeing pRedirectInfo. Since
|
|
the ref count on port thread is incremented before this is called we
|
|
know that the IniPort will be valid till we decrement the ref count.
|
|
|
|
We are also passed the event we should wait to die on.
|
|
This is pIniPort->hEvent. But redirection thread should use the local
|
|
copy passed and not the one in pIniPort. The reason is there could be a
|
|
lag from the time this event is set and the redirection dies. In the
|
|
meantime a new rediction thread could be spun off and in which case the
|
|
pIniPort->hEvent will not be for this thread
|
|
|
|
When redirection thread is told to die:
|
|
a. it should decrement the ref count on the pIniPort object when it is
|
|
done with it's reference to pIniPort
|
|
b. it should call CloseHandle on pRedirectInfo->hEvent
|
|
--*/
|
|
{
|
|
WCHAR szPipeName[MAX_PATH];
|
|
HANDLE hPipe[NUMBER_OF_PIPE_INSTANCES];
|
|
SECURITY_ATTRIBUTES SecurityAttributes;
|
|
PSECURITY_ATTRIBUTES pSecurityAttributes;
|
|
|
|
//
|
|
// One extra event for our trigger (pIniPort->hEvent)
|
|
//
|
|
HANDLE ahEvent[NUMBER_OF_PIPE_INSTANCES+1];
|
|
BOOL abReconnect[NUMBER_OF_PIPE_INSTANCES];
|
|
OVERLAPPED Overlapped[NUMBER_OF_PIPE_INSTANCES];
|
|
DWORD WaitResult, i, j, Error, dwThreadId;
|
|
PTRANSMISSION pTransmission;
|
|
HANDLE hThread;
|
|
BOOL bTerminate = FALSE;
|
|
LPWSTR pszNewDeviceName = NULL;
|
|
|
|
SecurityAttributes.lpSecurityDescriptor = NULL;
|
|
|
|
//
|
|
// Setup the redirection.
|
|
//
|
|
if ( !(pszNewDeviceName = SetupDosDev(pRedirectInfo->pIniPort,
|
|
szPipeName,
|
|
COUNTOF(szPipeName),
|
|
&SecurityAttributes,
|
|
&pSecurityAttributes)) ) {
|
|
|
|
EnterSplSem();
|
|
FreeRedirectInfo(pRedirectInfo);
|
|
LeaveSplSem();
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Initialization
|
|
//
|
|
for (i = 0; i < NUMBER_OF_PIPE_INSTANCES; i++) {
|
|
|
|
hPipe[i] = INVALID_HANDLE_VALUE;
|
|
Overlapped[i].hEvent = ahEvent[i] = NULL;
|
|
}
|
|
|
|
//
|
|
// Put the event in the extra member of the event array.
|
|
//
|
|
ahEvent[NUMBER_OF_PIPE_INSTANCES] = pRedirectInfo->hEvent;
|
|
|
|
//
|
|
// Create several instances of a named pipe, create an event for each,
|
|
// and connect to wait for a client:
|
|
//
|
|
for (i = 0; i < NUMBER_OF_PIPE_INSTANCES; i++) {
|
|
|
|
abReconnect[i] = FALSE;
|
|
|
|
hPipe[i] = CreateNamedPipe(szPipeName,
|
|
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
|
|
PIPE_WAIT | PIPE_READMODE_BYTE | PIPE_TYPE_BYTE,
|
|
PIPE_UNLIMITED_INSTANCES,
|
|
4096,
|
|
64*1024, // 64k
|
|
0,
|
|
pSecurityAttributes);
|
|
|
|
if ( hPipe[i] == INVALID_HANDLE_VALUE ) {
|
|
|
|
DBGMSG(DBG_ERROR, ("CreateNamedPipe failed for %ws. Error %d\n",
|
|
szPipeName, GetLastError()));
|
|
goto Cleanup;
|
|
}
|
|
|
|
ahEvent[i] = Overlapped[i].hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
if (!ahEvent[i]) {
|
|
|
|
DBGMSG(DBG_ERROR, ("CreateEvent failed. Error %d\n",
|
|
GetLastError()));
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!ConnectNamedPipe(hPipe[i], &Overlapped[i])){
|
|
|
|
Error = GetLastError();
|
|
|
|
if (Error == ERROR_IO_PENDING) {
|
|
|
|
DBGMSG(DBG_INFO, ("ConnectNamedPipe %d, IO pending\n",
|
|
i));
|
|
|
|
} else {
|
|
|
|
DBGMSG(DBG_ERROR, ("ConnectNamedPipe failed. Error %d\n",
|
|
GetLastError()));
|
|
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
}
|
|
|
|
while (TRUE) {
|
|
|
|
DBGMSG(DBG_INFO, ("Waiting to connect...\n"));
|
|
|
|
WaitResult = WaitForMultipleObjectsEx(NUMBER_OF_PIPE_INSTANCES + 1,
|
|
ahEvent,
|
|
FALSE,
|
|
INFINITE,
|
|
TRUE);
|
|
|
|
DBGMSG(DBG_INFO, ("WaitForMultipleObjectsEx returned %d\n",
|
|
WaitResult));
|
|
|
|
if ((WaitResult >= NUMBER_OF_PIPE_INSTANCES)
|
|
&& (WaitResult != WAIT_IO_COMPLETION)) {
|
|
|
|
DBGMSG(DBG_INFO, ("WaitForMultipleObjects returned %d; Last error = %d\n",
|
|
WaitResult,
|
|
GetLastError( ) ) );
|
|
|
|
//
|
|
// We need to terminate. But wait for any read thread that is spun
|
|
// off by this redirection thread
|
|
//
|
|
for ( i = 0 ; i < NUMBER_OF_PIPE_INSTANCES ; ++i )
|
|
if ( abReconnect[i] ) {
|
|
|
|
bTerminate = TRUE;
|
|
break; // the for loop
|
|
}
|
|
|
|
if ( i < NUMBER_OF_PIPE_INSTANCES )
|
|
continue; // for the while loop
|
|
else
|
|
goto Cleanup;
|
|
}
|
|
|
|
i = WaitResult;
|
|
|
|
//
|
|
// If disco and reconnect was pending, do it again here.
|
|
//
|
|
if (abReconnect[i]) {
|
|
|
|
abReconnect[i] = FALSE;
|
|
|
|
//
|
|
// If redirection thread has been told to quit check for termination
|
|
//
|
|
if ( bTerminate ) {
|
|
|
|
for ( j = 0 ; j < NUMBER_OF_PIPE_INSTANCES ; ++j )
|
|
if ( abReconnect[j] )
|
|
break; // the for loop
|
|
|
|
if ( j < NUMBER_OF_PIPE_INSTANCES )
|
|
continue; // for while loop
|
|
else
|
|
goto Cleanup;
|
|
} else {
|
|
|
|
ReconnectNamedPipe(hPipe[i], &Overlapped[i]);
|
|
continue;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// If we have been told to terminate do not spin a read thread
|
|
//
|
|
if ( bTerminate )
|
|
continue;
|
|
|
|
//
|
|
// Set up the transmission structure with the handles etc. needed by
|
|
// the completion callback routine:
|
|
//
|
|
pTransmission = (PTRANSMISSION)AllocSplMem(sizeof(TRANSMISSION));
|
|
|
|
if (pTransmission) {
|
|
|
|
pTransmission->hPipe = hPipe[i];
|
|
pTransmission->pOverlapped = &Overlapped[i];
|
|
pTransmission->hPrinter = NULL;
|
|
pTransmission->pIniPort = pRedirectInfo->pIniPort;
|
|
abReconnect[i] = TRUE;
|
|
|
|
hThread = CreateThread(NULL,
|
|
INITIAL_STACK_COMMIT,
|
|
(LPTHREAD_START_ROUTINE)ReadThread,
|
|
pTransmission,
|
|
0,
|
|
&dwThreadId);
|
|
|
|
if (hThread) {
|
|
|
|
CloseHandle(hThread);
|
|
} else {
|
|
|
|
abReconnect[i] = FALSE;
|
|
FreeSplMem(pTransmission);
|
|
DBGMSG(DBG_WARN, ("CreateThread failed. Error %d\n",
|
|
GetLastError()));
|
|
}
|
|
|
|
} else {
|
|
|
|
DBGMSG(DBG_WARN, ("Alloc failed. Error %d\n",
|
|
GetLastError()));
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if ( pszNewDeviceName ) {
|
|
|
|
WCHAR DosDeviceName[MAX_PATH];
|
|
|
|
if (SUCCEEDED(StringCchCopy(DosDeviceName, COUNTOF(DosDeviceName), pRedirectInfo->pIniPort->pName)))
|
|
{
|
|
RemoveColon(DosDeviceName);
|
|
|
|
DefineDosDevice(DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE | DDD_RAW_TARGET_PATH,
|
|
DosDeviceName,
|
|
pszNewDeviceName);
|
|
}
|
|
|
|
FreeSplStr(pszNewDeviceName);
|
|
}
|
|
|
|
EnterSplSem();
|
|
FreeRedirectInfo(pRedirectInfo);
|
|
LeaveSplSem();
|
|
|
|
|
|
for (i = 0; i < NUMBER_OF_PIPE_INSTANCES; i++) {
|
|
|
|
if ( hPipe[i] != INVALID_HANDLE_VALUE ) {
|
|
|
|
CloseHandle(hPipe[i]);
|
|
hPipe[i] = INVALID_HANDLE_VALUE;
|
|
}
|
|
if ( ahEvent[i] ) {
|
|
|
|
CloseHandle(ahEvent[i]);
|
|
ahEvent[i] = NULL;
|
|
Overlapped[i].hEvent = NULL;
|
|
}
|
|
}
|
|
|
|
if (SecurityAttributes.lpSecurityDescriptor)
|
|
DestroyPrivateObjectSecurity(&SecurityAttributes.lpSecurityDescriptor);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CreateRedirectionThread(
|
|
PINIPORT pIniPort)
|
|
{
|
|
HANDLE hThread;
|
|
DWORD dwThreadId;
|
|
PREDIRECT_INFO pRedirectInfo = NULL;
|
|
|
|
SplInSem();
|
|
SPLASSERT(pIniPort->hEvent == NULL);
|
|
|
|
//
|
|
// Create redirection thread only once and only for LPT and COM ports
|
|
//
|
|
if ( !IsPortType(pIniPort->pName, szLPT) &&
|
|
!IsPortType(pIniPort->pName, szCOM) ) {
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
pIniPort->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
pRedirectInfo = (PREDIRECT_INFO) AllocSplMem(sizeof(REDIRECT_INFO));
|
|
|
|
if ( !pIniPort->hEvent || !pRedirectInfo ) {
|
|
|
|
FreeSplMem(pRedirectInfo);
|
|
if ( pIniPort->hEvent ) {
|
|
|
|
CloseHandle(pIniPort->hEvent);
|
|
pIniPort->hEvent = NULL;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
INCPORTREF(pIniPort);
|
|
pRedirectInfo->pIniPort = pIniPort;
|
|
pRedirectInfo->hEvent = pIniPort->hEvent;
|
|
|
|
hThread = CreateThread(NULL,
|
|
INITIAL_STACK_COMMIT,
|
|
(LPTHREAD_START_ROUTINE)RedirectionThread,
|
|
pRedirectInfo,
|
|
0,
|
|
&dwThreadId);
|
|
|
|
if (hThread) {
|
|
|
|
CloseHandle(hThread);
|
|
|
|
} else {
|
|
|
|
pIniPort->hEvent = NULL;
|
|
FreeRedirectInfo(pRedirectInfo);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|