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.
 
 
 
 
 
 

657 lines
17 KiB

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
xcv.c
Author:
Steve Wilson (SWilson) March 25, 1997
Revision History:
Ali Naqvi (alinaqvi) October 17, 2001
Changed IniXcv to keep IniMonitor rather than Monitor2. This way we can keep a refcount on
IniMonitor, preventing the monitor to be deleted when in use. We are going to use the
IniMonitor to get the Monitor2.
--*/
#include <precomp.h>
#include <offsets.h>
PINIXCV
CreateXcvEntry(
PCWSTR pszMachine,
PCWSTR pszName,
PINIMONITOR pIniMonitor,
PINISPOOLER pIniSpooler,
HANDLE hXcv
);
VOID
DeleteXcvEntry(
PINIXCV pIniXcv
);
BOOL
SplXcvOpenPort(
PCWSTR pszMachine,
PCWSTR pszObject,
DWORD dwType,
PPRINTER_DEFAULTS pDefault,
PHANDLE phXcv,
PINISPOOLER pIniSpooler
);
INIXCV IniXcvStart;
typedef struct {
PWSTR pszMethod;
BOOL (*pfn)(PINIXCV pIniXcv,
PCWSTR pszDataName,
PBYTE pInputData,
DWORD cbInputData,
PBYTE pOutputData,
DWORD cbOutputData,
PDWORD pcbOutputNeeded,
PDWORD pdwStatus,
PINISPOOLER pIniSpooler
);
} XCV_METHOD, *PXCV_METHOD;
XCV_METHOD gpXcvMethod[] = {
{L"DeletePort", XcvDeletePort},
{L"AddPort", XcvAddPort},
{NULL, NULL}
};
BOOL
LocalXcvData(
HANDLE hXcv,
LPCWSTR pszDataName,
PBYTE pInputData,
DWORD cbInputData,
PBYTE pOutputData,
DWORD cbOutputData,
PDWORD pcbOutputNeeded,
PDWORD pdwStatus
)
{
PINIXCV pIniXcv = ((PSPOOL) hXcv)->pIniXcv;
BOOL bReturn;
if (!ValidateXcvHandle(pIniXcv))
return ROUTER_UNKNOWN;
bReturn = SplXcvData(hXcv,
pszDataName,
pInputData,
cbInputData,
pOutputData,
cbOutputData,
pcbOutputNeeded,
pdwStatus,
pIniXcv->pIniSpooler);
return bReturn;
}
BOOL
SplXcvData(
HANDLE hXcv,
PCWSTR pszDataName,
PBYTE pInputData,
DWORD cbInputData,
PBYTE pOutputData,
DWORD cbOutputData,
PDWORD pcbOutputNeeded,
PDWORD pdwStatus,
PINISPOOLER pIniSpooler
)
{
PINIPORT pIniPort;
BOOL rc = FALSE;
BOOL bCallXcvData = FALSE;
PINIXCV pIniXcv = ((PSPOOL) hXcv)->pIniXcv;
DWORD i;
SPLASSERT(pIniXcv->pIniMonitor->Monitor2.pfnXcvDataPort);
//
// Check to see whether the pointers we use always are not NULL
//
if (pdwStatus && pszDataName && pcbOutputNeeded)
{
rc = TRUE;
}
else
{
SetLastError(ERROR_INVALID_PARAMETER);
}
if (rc)
{
//
// Execute well-known methods
//
for(i = 0 ; gpXcvMethod[i].pszMethod &&
wcscmp(gpXcvMethod[i].pszMethod, pszDataName) ; ++i)
;
if (gpXcvMethod[i].pszMethod)
{
PINIPORT pIniPort = NULL;
if (!_wcsicmp(gpXcvMethod[i].pszMethod, L"AddPort"))
{
//
// Before we use the pInputData buffer, we need to check if the string
// is NULL terminated somewhere inside it.
//
if (pInputData && cbInputData && IsStringNullTerminatedInBuffer((PWSTR)pInputData, cbInputData / sizeof(WCHAR)))
{
EnterSplSem();
//
// Port name is the first field in the input structure. Keep Refcount on
// IniPort while outside CS.
//
pIniPort = FindPort(pInputData, pIniSpooler);
if ( pIniPort )
{
INCPORTREF(pIniPort);
}
LeaveSplSem();
//
// If this pIniPort doesn't have a monitor associated with it, it is
// a temporary port. We will allow it to be added, if there still is
// no monitor associated with it later, we will simply use this
// structure again.
//
if (pIniPort && !(pIniPort->Status & PP_PLACEHOLDER))
{
rc = TRUE;
*pdwStatus = ERROR_ALREADY_EXISTS;
}
else
{
bCallXcvData = TRUE;
}
}
else
{
SetLastError(ERROR_INVALID_DATA);
rc = FALSE;
}
}
else
{
bCallXcvData = TRUE;
}
//
// Don't make the function call if we do AddPort and the port already exists.
// If it is a placeholder, that's OK.
//
if (bCallXcvData)
{
rc = (*gpXcvMethod[i].pfn)( pIniXcv,
pszDataName,
pInputData,
cbInputData,
pOutputData,
cbOutputData,
pcbOutputNeeded,
pdwStatus,
pIniSpooler);
}
if(pIniPort)
{
EnterSplSem();
DECPORTREF(pIniPort);
LeaveSplSem();
}
}
else
{
*pdwStatus = (*pIniXcv->pIniMonitor->Monitor2.pfnXcvDataPort)( pIniXcv->hXcv,
pszDataName,
pInputData,
cbInputData,
pOutputData,
cbOutputData,
pcbOutputNeeded );
rc = TRUE;
}
}
return rc;
}
DWORD
XcvOpen(
PCWSTR pszServer,
PCWSTR pszObject,
DWORD dwObjectType,
PPRINTER_DEFAULTS pDefault,
PHANDLE phXcv,
PINISPOOLER pIniSpooler
)
{
BOOL bRet;
DWORD dwRet;
DWORD dwLastError;
if (dwObjectType == XCVPORT || dwObjectType == XCVMONITOR) {
bRet = SplXcvOpenPort( pszServer,
pszObject,
dwObjectType,
pDefault,
phXcv,
pIniSpooler);
if (!bRet) {
dwLastError = GetLastError();
if (dwLastError == ERROR_INVALID_NAME)
dwRet = ROUTER_UNKNOWN;
else if (dwLastError == ERROR_UNKNOWN_PORT)
// This is a case where a port exists without an associated port monitor
// (i.e. a masq port), we need to give the partial print provider a chance
// to intercept the XCV call
//
dwRet = ROUTER_UNKNOWN;
else
dwRet = ROUTER_STOP_ROUTING;
}
else {
dwRet = ROUTER_SUCCESS;
}
} else {
dwRet = ROUTER_UNKNOWN;
}
return dwRet;
}
BOOL
SplXcvOpenPort(
PCWSTR pszMachine,
PCWSTR pszObject,
DWORD dwType,
PPRINTER_DEFAULTS pDefault,
PHANDLE phXcv,
PINISPOOLER pIniSpooler
)
{
PINIMONITOR pIniMonitor = NULL;
PINIPORT pIniPort = NULL;
BOOL rc = FALSE;
DWORD dwStatus;
HANDLE hMonitor;
PSPOOL pSpool;
PINIXCV pIniXcv = NULL;
EnterSplSem();
if (dwType == XCVMONITOR) {
pIniMonitor = FindMonitor(pszObject, pIniSpooler);
}
else {
pIniPort = FindPort(pszObject, pIniSpooler);
if(pIniPort && (pIniPort->Status & PP_MONITOR))
pIniMonitor = pIniPort->pIniMonitor;
}
if (pIniMonitor) {
if (!pIniMonitor->Monitor2.pfnXcvOpenPort ||
!pIniMonitor->Monitor2.pfnXcvDataPort ||
!pIniMonitor->Monitor2.pfnXcvClosePort) {
SetLastError(ERROR_INVALID_PRINT_MONITOR);
} else {
//
// Keeping a RefCount on IniMonitor and IniPort while outside CS.
//
INCMONITORREF(pIniMonitor);
LeaveSplSem();
dwStatus = CreateServerHandle( (PWSTR) pszMachine,
phXcv,
pDefault,
pIniSpooler,
PRINTER_HANDLE_XCV_PORT);
EnterSplSem();
if (dwStatus == ROUTER_SUCCESS) { // Create port handle
pSpool = *(PSPOOL *) phXcv; // *phXcv is pSpool
rc = (*pIniMonitor->Monitor2.pfnXcvOpenPort)(
pIniMonitor->hMonitor,
pszObject,
pSpool->GrantedAccess,
&hMonitor);
if (rc) { // Create Spooler XCV entry
pIniXcv = CreateXcvEntry( pszMachine,
pszObject,
pIniMonitor,
pIniSpooler,
hMonitor);
if (pIniXcv) {
pSpool->pIniXcv = pIniXcv;
} else {
(*pIniMonitor->Monitor2.pfnXcvClosePort)(hMonitor);
rc = FALSE;
}
}
}
DECMONITORREF(pIniMonitor);
}
} else {
SetLastError(ERROR_UNKNOWN_PORT);
rc = FALSE;
}
LeaveSplSem();
return rc;
}
PINIXCV
CreateXcvEntry(
PCWSTR pszMachine,
PCWSTR pszName,
PINIMONITOR pIniMonitor,
PINISPOOLER pIniSpooler,
HANDLE hXcv
)
{
PINIXCV pIniXcvPrev = &IniXcvStart;
PINIXCV pIniXcv = IniXcvStart.pNext;
for(; pIniXcv ; pIniXcv = pIniXcv->pNext)
pIniXcvPrev = pIniXcv;
if (!(pIniXcv = (PINIXCV) AllocSplMem(sizeof(INIXCV))))
goto Cleanup;
pIniXcv->hXcv = hXcv;
pIniXcv->signature = XCV_SIGNATURE;
pIniXcv->pIniSpooler = pIniSpooler;
INCSPOOLERREF( pIniSpooler );
if (pszMachine && !(pIniXcv->pszMachineName = AllocSplStr(pszMachine)))
goto Cleanup;
if (pszName && !(pIniXcv->pszName = AllocSplStr(pszName)))
goto Cleanup;
pIniXcv->pIniMonitor = pIniMonitor;
//
// During the lifespan of the IniXcv we keep a Refcount on the IniMonitor
//
INCMONITORREF(pIniXcv->pIniMonitor);
return pIniXcvPrev->pNext = pIniXcv;
Cleanup:
DeleteXcvEntry( pIniXcv );
return NULL;
}
VOID
DeleteXcvEntry(
PINIXCV pIniXcv
)
{
if( pIniXcv ){
if( pIniXcv->pIniSpooler ){
DECSPOOLERREF( pIniXcv->pIniSpooler );
}
//
// Release the IniMonitor
//
if (pIniXcv->pIniMonitor)
{
DECMONITORREF(pIniXcv->pIniMonitor);
}
FreeSplStr(pIniXcv->pszMachineName);
FreeSplStr(pIniXcv->pszName);
FreeSplMem(pIniXcv);
}
}
BOOL
XcvClose(
PINIXCV pIniXcvIn
)
{
PINIXCV pIniXcvPrev = &IniXcvStart;
PINIXCV pIniXcv = IniXcvStart.pNext;
BOOL bRet;
for(; pIniXcv ; pIniXcv = pIniXcv->pNext) {
if (pIniXcv == pIniXcvIn) {
bRet = pIniXcv->pIniMonitor->Monitor2.pfnXcvClosePort(pIniXcv->hXcv);
if (bRet) {
pIniXcvPrev->pNext = pIniXcv->pNext;
DeleteXcvEntry( pIniXcv );
}
return bRet;
}
pIniXcvPrev = pIniXcv;
}
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
BOOL
XcvDeletePort(
PINIXCV pIniXcv,
PCWSTR pszDataName,
PBYTE pInputData,
DWORD cbInputData,
PBYTE pOutputData,
DWORD cbOutputData,
PDWORD pcbOutputNeeded,
PDWORD pdwStatus,
PINISPOOLER pIniSpooler
)
{
PINIPORT pIniPort;
BOOL rc = FALSE;
PWSTR pPortName = (PWSTR) pInputData;
//
// Check to see whether the pInputData is NULL terminated within its buffer
// before going down this path.
//
if (pInputData && cbInputData && IsStringNullTerminatedInBuffer((PWSTR)pInputData, cbInputData / sizeof(WCHAR)))
{
EnterSplSem();
pIniPort = FindPort(pPortName, pIniSpooler);
if ( !pIniPort || !(pIniPort->Status & PP_MONITOR) ) {
SetLastError (*pdwStatus = ERROR_UNKNOWN_PORT);
LeaveSplSem();
return FALSE;
}
rc = DeletePortFromSpoolerStart(pIniPort);
*pdwStatus = GetLastError ();
LeaveSplSem();
if (!rc)
goto Cleanup;
*pdwStatus = (*pIniXcv->pIniMonitor->Monitor2.pfnXcvDataPort)( pIniXcv->hXcv,
pszDataName,
pInputData,
cbInputData,
pOutputData,
cbOutputData,
pcbOutputNeeded);
DeletePortFromSpoolerEnd(pIniPort, pIniSpooler, *pdwStatus == ERROR_SUCCESS);
rc = TRUE;
}
else
{
SetLastError(ERROR_INVALID_PARAMETER);
}
Cleanup:
return rc;
}
BOOL
XcvAddPort(
PINIXCV pIniXcv,
PCWSTR pszDataName,
PBYTE pInputData,
DWORD cbInputData,
PBYTE pOutputData,
DWORD cbOutputData,
PDWORD pcbOutputNeeded,
PDWORD pdwStatus,
PINISPOOLER pIniSpooler
)
{
BOOL rc;
PINIMONITOR pIniMonitor = NULL;
PINIPORT pIniPort = NULL;
pIniMonitor = pIniXcv->pIniMonitor;
if (pIniMonitor) {
*pdwStatus = (*pIniXcv->pIniMonitor->Monitor2.pfnXcvDataPort)( pIniXcv->hXcv,
pszDataName,
pInputData,
cbInputData,
pOutputData,
cbOutputData,
pcbOutputNeeded);
if (*pdwStatus == ERROR_SUCCESS) {
EnterSplSem();
//
// Check to see if we have a placeholder port by the same name. If we
// do this set this as the monitor and revoke its placeholder status.
//
// This pInputData has already been validated by the "Add" method in
// XcvData itself.
//
pIniPort = FindPort(pInputData, pIniSpooler);
if (pIniPort && pIniPort->Status & PP_PLACEHOLDER)
{
pIniPort->pIniMonitor = pIniMonitor;
pIniPort->Status |= PP_MONITOR;
pIniPort->Status &= ~PP_PLACEHOLDER;
}
else
{
CreatePortEntry((PWSTR) pInputData, pIniMonitor, pIniSpooler);
}
LeaveSplSem();
}
rc = TRUE;
} else {
SetLastError(ERROR_INVALID_NAME);
rc = FALSE;
}
return rc;
}
BOOL
ValidateXcvHandle(
PINIXCV pIniXcv
)
{
BOOL ReturnValue;
try {
if (!pIniXcv || pIniXcv->signature != XCV_SIGNATURE) {
ReturnValue = FALSE;
} else {
ReturnValue = TRUE;
}
}except (1) {
ReturnValue = FALSE;
}
if ( !ReturnValue )
SetLastError( ERROR_INVALID_HANDLE );
return ReturnValue;
}