1735 lines
47 KiB
C
1735 lines
47 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1990 - 1995 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
setprn.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module provides all the public exported APIs relating to Printer
|
||
|
management for the Local Print Providor
|
||
|
|
||
|
SplSetPrinter
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Dave Snipp (DaveSn) 15-Mar-1991
|
||
|
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
Muhunthan Sivapragasam (MuhuntS) 25-Aug-95
|
||
|
-- support for level 4, and PRINTER_CONTROL_SET_STATUS.
|
||
|
-- eliminate duplicate code
|
||
|
Muhunthan Sivapragasam (MuhuntS) 18-Jun-1995 -- PeinterInfo5 changes
|
||
|
Krishna Ganugapati (KrishnaG) 1-Jun-1994 -- rewrote these functions.
|
||
|
|
||
|
--*/
|
||
|
#define NOMINMAX
|
||
|
#include <precomp.h>
|
||
|
|
||
|
#define PRINTER_NO_CONTROL 0x00
|
||
|
|
||
|
typedef enum {
|
||
|
SECURITY_SUCCESS = 0,
|
||
|
SECURITY_NOCHANGE = 1,
|
||
|
SECURITY_FAIL = 2
|
||
|
} SECURITY_STATUS;
|
||
|
|
||
|
SECURITY_STATUS
|
||
|
SetPrinterSecurity(
|
||
|
SECURITY_INFORMATION SecurityInformation,
|
||
|
PINIPRINTER pIniPrinter,
|
||
|
PSECURITY_DESCRIPTOR pSecurityDescriptor
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
RegClearKey(
|
||
|
HKEY hKey
|
||
|
);
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
PurgePrinter(
|
||
|
PINIPRINTER pIniPrinter
|
||
|
);
|
||
|
|
||
|
DWORD
|
||
|
ValidatePrinterAttributes(
|
||
|
DWORD SourceAttributes,
|
||
|
BOOL bSettableOnly
|
||
|
);
|
||
|
|
||
|
BOOL
|
||
|
ChangePrinterAttributes(
|
||
|
DWORD dNewAttributes,
|
||
|
DWORD dOldAttributes,
|
||
|
PINIPRINTER pIniPrinter,
|
||
|
PINISPOOLER pIniSpooler,
|
||
|
LPWSTR pszNewShareName,
|
||
|
BOOL bForceUpdate
|
||
|
);
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
SplSetPrinterExtra(
|
||
|
HANDLE hPrinter,
|
||
|
LPBYTE pExtraData
|
||
|
)
|
||
|
{
|
||
|
BOOL ReturnValue;
|
||
|
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
|
||
|
EnterSplSem();
|
||
|
|
||
|
if (ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER)) {
|
||
|
|
||
|
pSpool->pIniPrinter->pExtraData = pExtraData;
|
||
|
UpdatePrinterIni( pSpool->pIniPrinter , UPDATE_CHANGEID );
|
||
|
ReturnValue = TRUE;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
ReturnValue = FALSE;
|
||
|
|
||
|
}
|
||
|
|
||
|
LeaveSplSem();
|
||
|
|
||
|
return ReturnValue;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
SplGetPrinterExtra(
|
||
|
HANDLE hPrinter,
|
||
|
LPDWORD ppExtraData
|
||
|
)
|
||
|
{
|
||
|
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
BOOL ReturnValue;
|
||
|
|
||
|
if (ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER)) {
|
||
|
|
||
|
*ppExtraData = (DWORD)pSpool->pIniPrinter->pExtraData;
|
||
|
ReturnValue = TRUE;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
ReturnValue = FALSE;
|
||
|
|
||
|
}
|
||
|
|
||
|
return ReturnValue;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ValidateLevelAndSecurityAccesses(
|
||
|
PSPOOL pSpool,
|
||
|
DWORD Level,
|
||
|
LPBYTE pPrinterInfo,
|
||
|
DWORD Command,
|
||
|
PDWORD pdwAccessRequired,
|
||
|
PDWORD pSecurityInformation
|
||
|
)
|
||
|
{
|
||
|
DWORD AccessRequired = 0;
|
||
|
DWORD SecurityInformation= 0;
|
||
|
PSECURITY_DESCRIPTOR pSecurityDescriptor;
|
||
|
|
||
|
//
|
||
|
// Set pdwAccessRequired = 0 and
|
||
|
// Set pSecurityInformation = 0;
|
||
|
|
||
|
*pdwAccessRequired = 0;
|
||
|
*pSecurityInformation = 0;
|
||
|
|
||
|
switch (Level) {
|
||
|
case 0:
|
||
|
case 6:
|
||
|
AccessRequired = PRINTER_ACCESS_ADMINISTER;
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
pSecurityDescriptor =
|
||
|
((PPRINTER_INFO_2)pPrinterInfo)->pSecurityDescriptor;
|
||
|
|
||
|
AccessRequired = PRINTER_ACCESS_ADMINISTER;
|
||
|
if (GetSecurityInformation(pSecurityDescriptor,
|
||
|
&SecurityInformation)) {
|
||
|
AccessRequired |= GetPrivilegeRequired( SecurityInformation );
|
||
|
} else {
|
||
|
//
|
||
|
// BugBug- We should be returning the false on GetSecurityInformation
|
||
|
// failing. The reason we're not doing it is because this will break
|
||
|
// Printman. Printman should pass in Valid security descriptors for Level 2
|
||
|
// Fix in Printman KrishnaG 6/17
|
||
|
//
|
||
|
|
||
|
// LastError = GetLastError();
|
||
|
// return FALSE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 3:
|
||
|
pSecurityDescriptor =
|
||
|
((PPRINTER_INFO_3)pPrinterInfo)->pSecurityDescriptor;
|
||
|
|
||
|
if (GetSecurityInformation(pSecurityDescriptor,
|
||
|
&SecurityInformation)) {
|
||
|
AccessRequired |= GetPrivilegeRequired( SecurityInformation );
|
||
|
} else {
|
||
|
// LastError = GetLastError();
|
||
|
return FALSE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 4:
|
||
|
case 5:
|
||
|
AccessRequired = PRINTER_ACCESS_ADMINISTER;
|
||
|
break;
|
||
|
|
||
|
|
||
|
default:
|
||
|
SetLastError(ERROR_INVALID_LEVEL);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (!AccessGranted(SPOOLER_OBJECT_PRINTER,
|
||
|
AccessRequired,
|
||
|
pSpool) ) {
|
||
|
SetLastError(ERROR_ACCESS_DENIED);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
*pdwAccessRequired = AccessRequired;
|
||
|
*pSecurityInformation = SecurityInformation;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
PKEYDATA
|
||
|
CreateAndValidatePortTokenList(
|
||
|
LPWSTR pPortName,
|
||
|
PINISPOOLER pIniSpooler
|
||
|
)
|
||
|
{
|
||
|
PKEYDATA pKeyData = CreateTokenList(pPortName);
|
||
|
|
||
|
if ( pKeyData ) {
|
||
|
|
||
|
if ( !ValidatePortTokenList(pKeyData, pIniSpooler) ) {
|
||
|
|
||
|
FreePortTokenList(pKeyData);
|
||
|
SetLastError(ERROR_UNKNOWN_PORT);
|
||
|
pKeyData = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pKeyData;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ChangePrinterName(
|
||
|
LPWSTR pszNewName,
|
||
|
PINIPRINTER pIniPrinter,
|
||
|
PINISPOOLER pIniSpooler,
|
||
|
LPDWORD pdwPrinterVector
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Changes printer name
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pszNewName - New printer name allocated using AllocSplStr
|
||
|
|
||
|
pIniPrinter - for the printer we changing name
|
||
|
|
||
|
pIniSpooler - Spooler that owns printer
|
||
|
|
||
|
pdwPrinterVector - pointer to notification vector
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
nothing
|
||
|
|
||
|
History:
|
||
|
|
||
|
MuhuntS (Muhunthan Sivapragasam) July 95
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
LPWSTR pNewName, pOldName;
|
||
|
|
||
|
//
|
||
|
// Before deleting the printer entry make sure you copy
|
||
|
// all information with respect to the printer to the registry
|
||
|
// There could be several levels of keys.
|
||
|
//
|
||
|
|
||
|
CopyPrinterIni(pIniPrinter, pszNewName);
|
||
|
DeletePrinterIni(pIniPrinter);
|
||
|
|
||
|
pOldName = pIniPrinter->pName;
|
||
|
pIniPrinter->pName = pszNewName;
|
||
|
|
||
|
*pdwPrinterVector |= BIT(I_PRINTER_PRINTER_NAME);
|
||
|
|
||
|
//
|
||
|
// Delete the old entries in WIN.INI:
|
||
|
//
|
||
|
CheckAndUpdatePrinterRegAll(pIniSpooler,
|
||
|
pOldName,
|
||
|
NULL,
|
||
|
UPDATE_REG_DELETE );
|
||
|
|
||
|
FreeSplStr(pOldName);
|
||
|
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
SetLocalPrinterSTRESS(
|
||
|
PINIPRINTER pIniPrinter,
|
||
|
PPRINTER_INFO_STRESS pPrinterSTRESS
|
||
|
)
|
||
|
{
|
||
|
|
||
|
if ( !pPrinterSTRESS ) {
|
||
|
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allow the caller to update the counters.
|
||
|
//
|
||
|
pIniPrinter->cTotalJobs = pPrinterSTRESS->cTotalJobs;
|
||
|
pIniPrinter->cTotalBytes.LowPart = pPrinterSTRESS->cTotalBytes;
|
||
|
pIniPrinter->cTotalBytes.HighPart = pPrinterSTRESS->dwHighPartTotalBytes;
|
||
|
pIniPrinter->MaxcRef = pPrinterSTRESS->MaxcRef;
|
||
|
pIniPrinter->cTotalPagesPrinted = pPrinterSTRESS->cTotalPagesPrinted;
|
||
|
pIniPrinter->cMaxSpooling = pPrinterSTRESS->cMaxSpooling;
|
||
|
pIniPrinter->cErrorOutOfPaper = pPrinterSTRESS->cErrorOutOfPaper;
|
||
|
pIniPrinter->cErrorNotReady = pPrinterSTRESS->cErrorNotReady;
|
||
|
pIniPrinter->cJobError = pPrinterSTRESS->cJobError;
|
||
|
pIniPrinter->dwLastError = pPrinterSTRESS->dwLastError;
|
||
|
pIniPrinter->stUpTime = pPrinterSTRESS->stUpTime;
|
||
|
|
||
|
pIniPrinter->pIniSpooler->cEnumerateNetworkPrinters =
|
||
|
pPrinterSTRESS->cEnumerateNetworkPrinters;
|
||
|
pIniPrinter->pIniSpooler->cAddNetPrinters =
|
||
|
pPrinterSTRESS->cAddNetPrinters;
|
||
|
|
||
|
UpdatePrinterIni( pIniPrinter, KEEP_CHANGEID );
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
SetPrinterStatus(
|
||
|
PINIPRINTER pIniPrinter,
|
||
|
DWORD Status
|
||
|
)
|
||
|
{
|
||
|
DWORD OldStatus = pIniPrinter->Status;
|
||
|
|
||
|
pIniPrinter->Status &= PRINTER_STATUS_PRIVATE;
|
||
|
|
||
|
pIniPrinter->Status |= MapPrinterStatus(MAP_SETTABLE, Status);
|
||
|
|
||
|
if ( PrinterStatusBad(OldStatus) &&
|
||
|
!PrinterStatusBad(pIniPrinter->Status) ) {
|
||
|
|
||
|
CHECK_SCHEDULER();
|
||
|
}
|
||
|
|
||
|
SetPrinterChange(pIniPrinter,
|
||
|
NULL,
|
||
|
NVPrinterStatus,
|
||
|
PRINTER_CHANGE_SET_PRINTER,
|
||
|
pIniPrinter->pIniSpooler);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
SetLocalPrinter0(
|
||
|
PINIPRINTER pIniPrinter,
|
||
|
DWORD Command
|
||
|
)
|
||
|
{
|
||
|
DWORD Change = PRINTER_CHANGE_SET_PRINTER;
|
||
|
BOOL bReturn = TRUE;
|
||
|
|
||
|
switch (Command) {
|
||
|
|
||
|
case PRINTER_CONTROL_PURGE:
|
||
|
|
||
|
//
|
||
|
// PurgePrinter always returns TRUE now, still ..
|
||
|
//
|
||
|
if ( PurgePrinter(pIniPrinter) ) {
|
||
|
|
||
|
LogEvent(pIniPrinter->pIniSpooler,
|
||
|
LOG_WARNING,
|
||
|
MSG_PRINTER_PURGED,
|
||
|
pIniPrinter->pName,
|
||
|
NULL );
|
||
|
|
||
|
Change |= PRINTER_CHANGE_DELETE_JOB;
|
||
|
} else {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case PRINTER_CONTROL_RESUME:
|
||
|
|
||
|
pIniPrinter->Status &= ~PRINTER_PAUSED;
|
||
|
|
||
|
CHECK_SCHEDULER();
|
||
|
|
||
|
UpdatePrinterIni( pIniPrinter, KEEP_CHANGEID );
|
||
|
|
||
|
LogEvent(pIniPrinter->pIniSpooler,
|
||
|
LOG_WARNING,
|
||
|
MSG_PRINTER_UNPAUSED,
|
||
|
pIniPrinter->pName,
|
||
|
NULL );
|
||
|
break;
|
||
|
|
||
|
case PRINTER_CONTROL_PAUSE:
|
||
|
|
||
|
pIniPrinter->Status |= PRINTER_PAUSED;
|
||
|
|
||
|
UpdatePrinterIni( pIniPrinter, KEEP_CHANGEID );
|
||
|
|
||
|
LogEvent(pIniPrinter->pIniSpooler,
|
||
|
LOG_WARNING,
|
||
|
MSG_PRINTER_PAUSED,
|
||
|
pIniPrinter->pName,
|
||
|
NULL);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
SetLastError(ERROR_INVALID_PRINTER_COMMAND);
|
||
|
return FALSE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
SetPrinterChange(pIniPrinter,
|
||
|
NULL,
|
||
|
(Command == PRINTER_CONTROL_PURGE) ? NVPurge :
|
||
|
NVPrinterStatus,
|
||
|
Change,
|
||
|
pIniPrinter->pIniSpooler);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
ValidateSetPrinter2(
|
||
|
PINIPRINTER pIniPrinter,
|
||
|
PINIPRINTER pTempIniPrinter,
|
||
|
PPRINTER_INFO_2 pPrinterInfo2
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Validates and builds request info about a SetPrinter info call for
|
||
|
Printer information that could be changed only for level2.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pIniPrinter - PINIPRINTER of the printer handle passed in
|
||
|
|
||
|
pTempIniPrinter - this structure is used to gather info about all
|
||
|
parameters being changed
|
||
|
|
||
|
pPrinterInfo2 - the PrinterInfo2 structure being passed in
|
||
|
|
||
|
Return Value:
|
||
|
TRUE: If all the validation is succesful
|
||
|
FALSE: If validation of one or more request fails
|
||
|
|
||
|
On succesful return fields which need to be changed will be set in
|
||
|
pTempIniPrinter. Cleanup of this structure will be done later.
|
||
|
|
||
|
History:
|
||
|
MuhuntS (Muhunthan Sivapragasam) Aug 95
|
||
|
--*/
|
||
|
{
|
||
|
BOOL bFail = FALSE;
|
||
|
DWORD LastError = ERROR_SUCCESS;
|
||
|
|
||
|
// Servername can't change
|
||
|
// Printername handled for level 2, 4, 5
|
||
|
|
||
|
// Share Name (validation later if required)
|
||
|
AllocOrUpdateString(&pTempIniPrinter->pShareName,
|
||
|
pPrinterInfo2->pShareName,
|
||
|
pIniPrinter->pShareName,
|
||
|
&bFail);
|
||
|
|
||
|
if ( bFail )
|
||
|
goto Cleanup;
|
||
|
|
||
|
// Port Name for level 2, 5
|
||
|
|
||
|
// DriverName
|
||
|
pTempIniPrinter->pIniDriver = FindLocalDriver(pPrinterInfo2->pDriverName);
|
||
|
|
||
|
if ( !pTempIniPrinter->pIniDriver ) {
|
||
|
|
||
|
LastError = ERROR_UNKNOWN_PRINTER_DRIVER;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
if ( pTempIniPrinter->pIniDriver != pIniPrinter->pIniDriver )
|
||
|
INCDRIVERREF(pTempIniPrinter->pIniDriver);
|
||
|
|
||
|
// Comment
|
||
|
AllocOrUpdateString(&pTempIniPrinter->pComment,
|
||
|
pPrinterInfo2->pComment,
|
||
|
pIniPrinter->pComment,
|
||
|
&bFail);
|
||
|
|
||
|
// Location
|
||
|
AllocOrUpdateString(&pTempIniPrinter->pLocation,
|
||
|
pPrinterInfo2->pLocation,
|
||
|
pIniPrinter->pLocation,
|
||
|
&bFail);
|
||
|
|
||
|
// DevMode at the end
|
||
|
|
||
|
// SepFile
|
||
|
AllocOrUpdateString(&pTempIniPrinter->pSepFile,
|
||
|
pPrinterInfo2->pSepFile,
|
||
|
pIniPrinter->pSepFile,
|
||
|
&bFail);
|
||
|
|
||
|
if ( bFail )
|
||
|
goto Cleanup;
|
||
|
|
||
|
if ( pIniPrinter->pSepFile != pTempIniPrinter->pSepFile &&
|
||
|
!CheckSepFile(pPrinterInfo2->pSepFile) ) {
|
||
|
|
||
|
LastError = ERROR_INVALID_SEPARATOR_FILE;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
// Print Processor
|
||
|
pTempIniPrinter->pIniPrintProc =
|
||
|
FindLocalPrintProc(pPrinterInfo2->pPrintProcessor);
|
||
|
|
||
|
if ( !pTempIniPrinter->pIniPrintProc ) {
|
||
|
|
||
|
LastError = ERROR_UNKNOWN_PRINTPROCESSOR;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
if ( pTempIniPrinter->pIniPrintProc != pIniPrinter->pIniPrintProc )
|
||
|
pTempIniPrinter->pIniPrintProc->cRef++;
|
||
|
|
||
|
// Datatype
|
||
|
if ( !pPrinterInfo2->pDatatype ) {
|
||
|
|
||
|
LastError = ERROR_INVALID_DATATYPE;
|
||
|
goto Cleanup; // Ok to fail ???
|
||
|
} else {
|
||
|
|
||
|
AllocOrUpdateString(&pTempIniPrinter->pDatatype,
|
||
|
pPrinterInfo2->pDatatype,
|
||
|
pIniPrinter->pDatatype,
|
||
|
&bFail);
|
||
|
}
|
||
|
|
||
|
// Parameters
|
||
|
AllocOrUpdateString(&pTempIniPrinter->pParameters,
|
||
|
pPrinterInfo2->pParameters,
|
||
|
pIniPrinter->pParameters,
|
||
|
&bFail);
|
||
|
|
||
|
if ( bFail )
|
||
|
goto Cleanup;
|
||
|
|
||
|
// SecurityDescriptor for level 2, 3
|
||
|
// Attributes for level 2, 4, 5
|
||
|
|
||
|
// Priority
|
||
|
pTempIniPrinter->Priority = pPrinterInfo2->Priority;
|
||
|
if ( pTempIniPrinter->Priority != pIniPrinter->Priority &&
|
||
|
pTempIniPrinter->Priority != NO_PRIORITY &&
|
||
|
( pTempIniPrinter->Priority > MAX_PRIORITY ||
|
||
|
pTempIniPrinter->Priority < MIN_PRIORITY ) ) {
|
||
|
|
||
|
LastError = ERROR_INVALID_PRIORITY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
// Default Priority
|
||
|
pTempIniPrinter->DefaultPriority = pPrinterInfo2->DefaultPriority;
|
||
|
if ( pTempIniPrinter->DefaultPriority != pIniPrinter->DefaultPriority &&
|
||
|
pTempIniPrinter->DefaultPriority != NO_PRIORITY &&
|
||
|
( pTempIniPrinter->DefaultPriority > MAX_PRIORITY ||
|
||
|
pTempIniPrinter->DefaultPriority < MIN_PRIORITY ) ) {
|
||
|
|
||
|
LastError = ERROR_INVALID_PRIORITY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
// Start time
|
||
|
pTempIniPrinter->StartTime = pPrinterInfo2->StartTime;
|
||
|
if ( pTempIniPrinter->StartTime != pIniPrinter->StartTime &&
|
||
|
pTempIniPrinter->StartTime >= ONEDAY ) {
|
||
|
|
||
|
LastError = ERROR_INVALID_TIME;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
// Until time
|
||
|
pTempIniPrinter->UntilTime = pPrinterInfo2->UntilTime;
|
||
|
if ( pTempIniPrinter->UntilTime != pIniPrinter->UntilTime &&
|
||
|
pTempIniPrinter->StartTime >= ONEDAY ) {
|
||
|
|
||
|
LastError = ERROR_INVALID_TIME;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
// Status for level 0, 2
|
||
|
// Status can't chg
|
||
|
// AveragePPM can't chg
|
||
|
|
||
|
Cleanup:
|
||
|
if ( LastError ) {
|
||
|
|
||
|
SetLastError(LastError);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if ( bFail )
|
||
|
return FALSE;
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ProcessSetPrinter2(
|
||
|
PINIPRINTER pIniPrinter,
|
||
|
PINIPRINTER pTempIniPrinter,
|
||
|
PPRINTER_INFO_2 pPrinterInfo2,
|
||
|
LPDWORD pdwPrinterVector,
|
||
|
PDEVMODE pDevMode
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Process SetPrinter for level 2. Only fields which can be changed ONLY
|
||
|
by level 2 will be processed here. That is: All the fields built by
|
||
|
ValidateSetPrinter2.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pIniPrinter - PINIPRINTER of the printer handle passed in
|
||
|
|
||
|
pTempIniPrinter - this structure is has all the fields which needs to
|
||
|
be set. Other fields will be the same as the previous
|
||
|
|
||
|
pPrinterInfo2 - the PrinterInfo2 structure being passed in
|
||
|
|
||
|
pdwPrinterVector - Notification Info
|
||
|
|
||
|
pDevMode - New dev mode to be set
|
||
|
|
||
|
Return Value:
|
||
|
nothing
|
||
|
|
||
|
History:
|
||
|
MuhuntS (Muhunthan Sivapragasam) Aug 95
|
||
|
--*/
|
||
|
{
|
||
|
HANDLE hToken;
|
||
|
|
||
|
|
||
|
// Sharename
|
||
|
if ( pTempIniPrinter->pShareName != pIniPrinter->pShareName ) {
|
||
|
|
||
|
FreeSplStr(pIniPrinter->pShareName);
|
||
|
pIniPrinter->pShareName = pTempIniPrinter->pShareName;
|
||
|
*pdwPrinterVector |= BIT(I_PRINTER_SHARE_NAME);
|
||
|
}
|
||
|
|
||
|
// Driver
|
||
|
if ( pTempIniPrinter->pIniDriver != pIniPrinter->pIniDriver ) {
|
||
|
|
||
|
DECDRIVERREF(pIniPrinter->pIniDriver);
|
||
|
|
||
|
hToken = RevertToPrinterSelf();
|
||
|
|
||
|
DeleteSubkeys( pIniPrinter->hPrinterDataKey);
|
||
|
RegClearKey( pIniPrinter->hPrinterDataKey );
|
||
|
|
||
|
ImpersonatePrinterClient(hToken);
|
||
|
|
||
|
pIniPrinter->pIniDriver = pTempIniPrinter->pIniDriver;
|
||
|
*pdwPrinterVector |= BIT(I_PRINTER_DRIVER_NAME);
|
||
|
}
|
||
|
|
||
|
// Comment
|
||
|
if ( pTempIniPrinter->pComment != pIniPrinter->pComment ) {
|
||
|
|
||
|
FreeSplStr(pIniPrinter->pComment);
|
||
|
pIniPrinter->pComment = pTempIniPrinter->pComment;
|
||
|
*pdwPrinterVector |= BIT(I_PRINTER_COMMENT);
|
||
|
}
|
||
|
|
||
|
// Location
|
||
|
if ( pTempIniPrinter->pLocation != pIniPrinter->pLocation ) {
|
||
|
|
||
|
FreeSplStr(pIniPrinter->pLocation);
|
||
|
pIniPrinter->pLocation = pTempIniPrinter->pLocation;
|
||
|
*pdwPrinterVector |= BIT(I_PRINTER_LOCATION);
|
||
|
}
|
||
|
|
||
|
// DevMode at the end
|
||
|
if ( CopyPrinterDevModeToIniPrinter(pIniPrinter,
|
||
|
pDevMode) ) {
|
||
|
|
||
|
*pdwPrinterVector |= BIT(I_PRINTER_DEVMODE);
|
||
|
}
|
||
|
|
||
|
// SepFile
|
||
|
if ( pTempIniPrinter->pSepFile != pIniPrinter->pSepFile ) {
|
||
|
|
||
|
FreeSplStr(pIniPrinter->pSepFile);
|
||
|
pIniPrinter->pSepFile = pTempIniPrinter->pSepFile;
|
||
|
*pdwPrinterVector |= BIT(I_PRINTER_SEPFILE);
|
||
|
}
|
||
|
|
||
|
// PrintProcessor
|
||
|
if ( pIniPrinter->pIniPrintProc != pTempIniPrinter->pIniPrintProc) {
|
||
|
|
||
|
pIniPrinter->pIniPrintProc->cRef--;
|
||
|
|
||
|
pIniPrinter->pIniPrintProc = pTempIniPrinter->pIniPrintProc;
|
||
|
*pdwPrinterVector |= BIT(I_PRINTER_PRINT_PROCESSOR);
|
||
|
}
|
||
|
|
||
|
// Datatype
|
||
|
if ( pIniPrinter->pDatatype != pTempIniPrinter->pDatatype ) {
|
||
|
|
||
|
FreeSplStr(pIniPrinter->pDatatype);
|
||
|
pIniPrinter->pDatatype = pTempIniPrinter->pDatatype;
|
||
|
*pdwPrinterVector |= BIT(I_PRINTER_DATATYPE);
|
||
|
}
|
||
|
|
||
|
// Parameters
|
||
|
if ( pIniPrinter->pParameters != pTempIniPrinter->pParameters ) {
|
||
|
|
||
|
FreeSplStr(pIniPrinter->pParameters);
|
||
|
pIniPrinter->pParameters = pTempIniPrinter->pParameters;
|
||
|
*pdwPrinterVector |= BIT(I_PRINTER_PARAMETERS);
|
||
|
}
|
||
|
|
||
|
// Priority
|
||
|
if ( pTempIniPrinter->Priority != pIniPrinter->Priority ) {
|
||
|
|
||
|
pIniPrinter->Priority = pTempIniPrinter->Priority;
|
||
|
*pdwPrinterVector |= BIT(I_PRINTER_PRIORITY);
|
||
|
}
|
||
|
|
||
|
// Default Priority
|
||
|
if ( pTempIniPrinter->DefaultPriority != pIniPrinter->DefaultPriority ) {
|
||
|
|
||
|
pIniPrinter->DefaultPriority = pTempIniPrinter->DefaultPriority;
|
||
|
*pdwPrinterVector |= BIT(I_PRINTER_DEFAULT_PRIORITY);
|
||
|
}
|
||
|
|
||
|
// Start time
|
||
|
if ( pTempIniPrinter->StartTime != pIniPrinter->StartTime ) {
|
||
|
|
||
|
pIniPrinter->StartTime = pTempIniPrinter->StartTime;
|
||
|
*pdwPrinterVector |= BIT(I_PRINTER_START_TIME);
|
||
|
}
|
||
|
|
||
|
// Until time
|
||
|
if ( pTempIniPrinter->UntilTime != pIniPrinter->UntilTime ) {
|
||
|
|
||
|
pIniPrinter->UntilTime = pTempIniPrinter->UntilTime;
|
||
|
*pdwPrinterVector |= BIT(I_PRINTER_UNTIL_TIME);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CleanupSetPrinter(
|
||
|
PINIPRINTER pIniPrinter,
|
||
|
PINIPRINTER pTempIniPrinter,
|
||
|
PKEYDATA pKeyData,
|
||
|
DWORD Level,
|
||
|
BOOL bReturnValue
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine is called at the end of SplSetPrinter call to free up all
|
||
|
the allocations done to process it which are not needed.
|
||
|
|
||
|
At the beginning of a SetPrinter we make an identical copy of the
|
||
|
pIniPrinter in pTempIniPrinter and collect all arguments in there.
|
||
|
Now if the call is failing each of the arguments collected in there
|
||
|
need to be freed.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pIniPrinter - PINIPRINTER of the printer handle passed in
|
||
|
|
||
|
pTempIniPrinter - this structure is has all the fields which needs to
|
||
|
be freed. Any field different than pIniPrinter was
|
||
|
built part of processing the call and needs to be freed.
|
||
|
|
||
|
pPrinterInfo2 - built for port info
|
||
|
|
||
|
bReturnValue - return value of SetPrinter
|
||
|
|
||
|
Return Value:
|
||
|
nothing
|
||
|
|
||
|
History:
|
||
|
MuhuntS (Muhunthan Sivapragasam) Aug 95
|
||
|
--*/
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// We adjust INIPORT, INIDRIVER refcounts. So should be inside the spl sem
|
||
|
//
|
||
|
SplInSem();
|
||
|
|
||
|
FreePortTokenList(pKeyData);
|
||
|
|
||
|
if ( pTempIniPrinter ) {
|
||
|
|
||
|
if ( !bReturnValue && Level == 2 ) {
|
||
|
|
||
|
if ( pTempIniPrinter->pShareName != pIniPrinter->pShareName )
|
||
|
FreeSplStr(pTempIniPrinter->pShareName);
|
||
|
|
||
|
if ( pTempIniPrinter->pComment != pIniPrinter->pComment )
|
||
|
FreeSplStr(pTempIniPrinter->pComment);
|
||
|
|
||
|
if ( pTempIniPrinter->pLocation != pIniPrinter->pLocation )
|
||
|
FreeSplStr(pTempIniPrinter->pLocation);
|
||
|
|
||
|
if ( pTempIniPrinter->pSepFile != pIniPrinter->pSepFile )
|
||
|
FreeSplStr(pTempIniPrinter->pSepFile);
|
||
|
|
||
|
if ( pTempIniPrinter->pDatatype != pIniPrinter->pDatatype )
|
||
|
FreeSplStr(pTempIniPrinter->pDatatype);
|
||
|
|
||
|
if ( pTempIniPrinter->pParameters != pIniPrinter->pParameters )
|
||
|
FreeSplStr(pTempIniPrinter->pParameters);
|
||
|
|
||
|
if ( ( pTempIniPrinter->pIniDriver != NULL ) &&
|
||
|
( pTempIniPrinter->pIniDriver != pIniPrinter->pIniDriver )) {
|
||
|
|
||
|
DECDRIVERREF(pTempIniPrinter->pIniDriver);
|
||
|
}
|
||
|
|
||
|
if ( ( pTempIniPrinter->pIniPrintProc != NULL ) &&
|
||
|
( pTempIniPrinter->pIniPrintProc != pIniPrinter->pIniPrintProc )) {
|
||
|
|
||
|
pTempIniPrinter->pIniPrintProc->cRef--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FreeSplMem(pTempIniPrinter);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
ValidateAndBuildSetPrinterRequest(
|
||
|
PINIPRINTER pIniPrinter,
|
||
|
PINIPRINTER pTempIniPrinter,
|
||
|
LPBYTE pPrinterInfo,
|
||
|
DWORD Level,
|
||
|
SECURITY_INFORMATION SecurityInformation,
|
||
|
LPBOOL pbSecurityChg,
|
||
|
LPBOOL pbNameChg,
|
||
|
LPBOOL pbAttributeChg,
|
||
|
LPWSTR *ppszNewPrinterName,
|
||
|
PKEYDATA *ppKeyData
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine is called to validate a SetPrinter request. We try to as
|
||
|
much vaidation as possible at the beginning to see the changes are
|
||
|
possible. The routine will collect all changes requested in the
|
||
|
pTempIniPrinter structure.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pIniPrinter - PINIPRINTER of the printer handle passed in
|
||
|
|
||
|
pTempIniPrinter - this structure will be used to collect all the
|
||
|
changes requested
|
||
|
|
||
|
pPrinterInfo - PrinterInfo_N structure passed in
|
||
|
|
||
|
Level - Level of PrinterInfo_N
|
||
|
|
||
|
SecurityInformation - security information
|
||
|
|
||
|
pbSecurityChg - this will be set if a security change is requested
|
||
|
|
||
|
pbNameChg - this will be set if a name change is requested
|
||
|
|
||
|
pbAttributeChg - this will be set if a attribute change is requested
|
||
|
|
||
|
ppszNewPrinterName - *ppszNewPrinterName will give the new printer name
|
||
|
to be set on a name change
|
||
|
ppKeyData - *ppKeyData will give the Port token info for a level 2 or 5
|
||
|
call
|
||
|
|
||
|
Return Value:
|
||
|
TRUE - if all the validations succeed
|
||
|
FALSE - a validation fails
|
||
|
|
||
|
History:
|
||
|
MuhuntS (Muhunthan Sivapragasam) Aug 95
|
||
|
--*/
|
||
|
{
|
||
|
PPRINTER_INFO_2 pPrinterInfo2 = (PPRINTER_INFO_2)pPrinterInfo;
|
||
|
PPRINTER_INFO_3 pPrinterInfo3 = (PPRINTER_INFO_3)pPrinterInfo;
|
||
|
PPRINTER_INFO_4 pPrinterInfo4 = (PPRINTER_INFO_4)pPrinterInfo;
|
||
|
PPRINTER_INFO_5 pPrinterInfo5 = (PPRINTER_INFO_5)pPrinterInfo;
|
||
|
LPWSTR pPortName;
|
||
|
DWORD dwLastError;
|
||
|
|
||
|
switch (Level) {
|
||
|
|
||
|
case 2:
|
||
|
pTempIniPrinter->pSecurityDescriptor =
|
||
|
pPrinterInfo2->pSecurityDescriptor;
|
||
|
|
||
|
if ( !ValidateSetPrinter2(pIniPrinter, pTempIniPrinter, pPrinterInfo2) )
|
||
|
return FALSE;
|
||
|
|
||
|
pTempIniPrinter->pName = pPrinterInfo2->pPrinterName;
|
||
|
|
||
|
pPortName = pPrinterInfo2->pPortName;
|
||
|
|
||
|
if ( !pTempIniPrinter->pIniDriver->pIniLangMonitor )
|
||
|
pPrinterInfo2->Attributes &= ~PRINTER_ATTRIBUTE_ENABLE_BIDI;
|
||
|
|
||
|
if ( pIniPrinter->pIniDriver != pTempIniPrinter->pIniDriver ) {
|
||
|
|
||
|
pPrinterInfo2->Attributes &= ~PRINTER_ATTRIBUTE_ENABLE_BIDI;
|
||
|
if ( pTempIniPrinter->pIniDriver->pIniLangMonitor )
|
||
|
pPrinterInfo2->Attributes |= PRINTER_ATTRIBUTE_ENABLE_BIDI;
|
||
|
}
|
||
|
|
||
|
pTempIniPrinter->Attributes =
|
||
|
ValidatePrinterAttributes(pPrinterInfo2->Attributes,
|
||
|
TRUE);
|
||
|
|
||
|
*pbAttributeChg = pTempIniPrinter->Attributes != pIniPrinter->Attributes;
|
||
|
break;
|
||
|
|
||
|
case 3:
|
||
|
pTempIniPrinter->pSecurityDescriptor = pPrinterInfo3->pSecurityDescriptor;
|
||
|
if ( !SecurityInformation || !pTempIniPrinter->pSecurityDescriptor ) {
|
||
|
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
return FALSE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 4:
|
||
|
pTempIniPrinter->pName = pPrinterInfo4->pPrinterName;
|
||
|
|
||
|
if ( !pIniPrinter->pIniDriver->pIniLangMonitor )
|
||
|
pPrinterInfo4->Attributes &= ~PRINTER_ATTRIBUTE_ENABLE_BIDI;
|
||
|
|
||
|
pTempIniPrinter->Attributes =
|
||
|
ValidatePrinterAttributes(pPrinterInfo4->Attributes,
|
||
|
TRUE);
|
||
|
|
||
|
*pbAttributeChg = pTempIniPrinter->Attributes != pIniPrinter->Attributes;
|
||
|
break;
|
||
|
|
||
|
case 5:
|
||
|
pTempIniPrinter->pName = pPrinterInfo5->pPrinterName;
|
||
|
|
||
|
pPortName = pPrinterInfo5->pPortName;
|
||
|
|
||
|
if ( !pIniPrinter->pIniDriver->pIniLangMonitor )
|
||
|
pPrinterInfo5->Attributes &= ~PRINTER_ATTRIBUTE_ENABLE_BIDI;
|
||
|
|
||
|
pTempIniPrinter->Attributes =
|
||
|
ValidatePrinterAttributes(pPrinterInfo5->Attributes,
|
||
|
TRUE);
|
||
|
|
||
|
*pbAttributeChg = pTempIniPrinter->Attributes != pIniPrinter->Attributes;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Validate timeout?
|
||
|
//
|
||
|
pTempIniPrinter->dnsTimeout = pPrinterInfo5->DeviceNotSelectedTimeout;
|
||
|
pTempIniPrinter->txTimeout = pPrinterInfo5->TransmissionRetryTimeout;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
SetLastError(ERROR_INVALID_LEVEL);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Validate share name if the shared bit is getting set or share name
|
||
|
// is being changed
|
||
|
//
|
||
|
if ( (pTempIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED) &&
|
||
|
( !(pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED) ||
|
||
|
pTempIniPrinter->pShareName != pIniPrinter->pShareName) ) {
|
||
|
|
||
|
dwLastError = ValidatePrinterShareName(pTempIniPrinter->pShareName,
|
||
|
pIniPrinter->pIniSpooler,
|
||
|
pIniPrinter);
|
||
|
if ( dwLastError != ERROR_SUCCESS ) {
|
||
|
|
||
|
SetLastError(dwLastError);
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Is there a security change?
|
||
|
//
|
||
|
if ( SecurityInformation && (Level == 2 || Level == 3) ) {
|
||
|
|
||
|
DWORD dwSize;
|
||
|
dwSize = GetSecurityDescriptorLength(pIniPrinter->pSecurityDescriptor);
|
||
|
|
||
|
if ( dwSize !=
|
||
|
GetSecurityDescriptorLength(pTempIniPrinter->pSecurityDescriptor) ||
|
||
|
!memcmp(pTempIniPrinter->pSecurityDescriptor,
|
||
|
pIniPrinter->pSecurityDescriptor,
|
||
|
dwSize) ) {
|
||
|
|
||
|
*pbSecurityChg = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Is there a name change?
|
||
|
//
|
||
|
if ( Level == 2 || Level == 4 || Level == 5 ) {
|
||
|
|
||
|
DWORD LastError;
|
||
|
|
||
|
if ( !pTempIniPrinter->pName || !*pTempIniPrinter->pName ) {
|
||
|
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Validate name if a change is requested
|
||
|
//
|
||
|
if ( lstrcmpi(pTempIniPrinter->pName, pIniPrinter->pName) ) {
|
||
|
|
||
|
LastError = ValidatePrinterName(pTempIniPrinter->pName,
|
||
|
pIniPrinter->pIniSpooler,
|
||
|
pIniPrinter,
|
||
|
ppszNewPrinterName);
|
||
|
if ( LastError != ERROR_SUCCESS ) {
|
||
|
|
||
|
*ppszNewPrinterName = NULL;
|
||
|
SetLastError(LastError);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check if printer name really changed for remote calls
|
||
|
//
|
||
|
if ( lstrcmpi(*ppszNewPrinterName, pIniPrinter->pName) ) {
|
||
|
|
||
|
*ppszNewPrinterName = AllocSplStr(*ppszNewPrinterName);
|
||
|
if ( !*ppszNewPrinterName )
|
||
|
return FALSE;
|
||
|
*pbNameChg = TRUE;
|
||
|
} else {
|
||
|
|
||
|
*ppszNewPrinterName = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Validate attributes if a change is requested
|
||
|
// Don't allow a change from queued to direct or vice versa
|
||
|
// if there are already jobs on the printer.
|
||
|
//
|
||
|
if ( pIniPrinter->cJobs > 0 ) {
|
||
|
|
||
|
if ( (pTempIniPrinter->Attributes & PRINTER_ATTRIBUTE_DIRECT) !=
|
||
|
(pIniPrinter->Attributes & PRINTER_ATTRIBUTE_DIRECT) ) {
|
||
|
|
||
|
SetLastError(ERROR_PRINTER_HAS_JOBS_QUEUED);
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( Level == 2 || Level == 5 ) {
|
||
|
|
||
|
if ( !pPortName || !*pPortName ) {
|
||
|
|
||
|
SetLastError(ERROR_UNKNOWN_PORT);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
*ppKeyData = CreateAndValidatePortTokenList(pPortName,
|
||
|
pIniPrinter->pIniSpooler);
|
||
|
if ( !*ppKeyData )
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
SplSetPrinter(
|
||
|
HANDLE hPrinter,
|
||
|
DWORD Level,
|
||
|
LPBYTE pPrinterInfo,
|
||
|
DWORD Command
|
||
|
)
|
||
|
{
|
||
|
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
DWORD i, LastError = ERROR_SUCCESS;
|
||
|
DWORD AccessRequired = 0;
|
||
|
PINIPRINTER pIniPrinter = pSpool->pIniPrinter, pTempIniPrinter = NULL;
|
||
|
PINISPOOLER pIniSpooler;
|
||
|
BOOL bReturn = TRUE;
|
||
|
BOOL bForceUpdate = FALSE;
|
||
|
DWORD dwPrinterVector = 0;
|
||
|
NOTIFYVECTOR NotifyVector;
|
||
|
|
||
|
PPRINTER_INFO_2 pPrinterInfo2 = (PPRINTER_INFO_2)pPrinterInfo;
|
||
|
PPRINTER_INFO_3 pPrinterInfo3 = (PPRINTER_INFO_3)pPrinterInfo;
|
||
|
PPRINTER_INFO_4 pPrinterInfo4 = (PPRINTER_INFO_4)pPrinterInfo;
|
||
|
PPRINTER_INFO_5 pPrinterInfo5 = (PPRINTER_INFO_5)pPrinterInfo;
|
||
|
|
||
|
BOOL bSecurityChg, bNameChg, bAttributeChg;
|
||
|
LPWSTR pszNewPrinterName = NULL;
|
||
|
PINIJOB pIniJob;
|
||
|
PINIPORT *ppIniPorts = NULL;
|
||
|
PKEYDATA pKeyData = NULL;
|
||
|
PDEVMODE pDevMode = NULL;
|
||
|
PINIDRIVER pIniDriver;
|
||
|
PINIPRINTPROC pIniPrintProc;
|
||
|
SECURITY_INFORMATION SecurityInformation;
|
||
|
|
||
|
ZERONV(NotifyVector);
|
||
|
|
||
|
//
|
||
|
// If level != 0 info struct should be non-null, and command 0
|
||
|
//
|
||
|
if ( Level && Command ) {
|
||
|
|
||
|
SetLastError(ERROR_INVALID_PRINTER_COMMAND);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if ( Level && !pPrinterInfo ) {
|
||
|
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
EnterSplSem();
|
||
|
if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER )) {
|
||
|
|
||
|
bReturn = FALSE;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If it is a remote call get default devmode from driver and then update it
|
||
|
//
|
||
|
if ( Level == 2 ) {
|
||
|
|
||
|
pDevMode = pPrinterInfo2->pDevMode;
|
||
|
if ( pDevMode && (pSpool->TypeofHandle & PRINTER_HANDLE_REMOTE) ) {
|
||
|
|
||
|
//
|
||
|
// If the driver can't convert devmode user's can't set devmode from remote m/c
|
||
|
//
|
||
|
pDevMode = ConvertDevModeToSpecifiedVersion(pIniPrinter,
|
||
|
pDevMode,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
CURRENT_VERSION);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
SplInSem();
|
||
|
|
||
|
pIniSpooler = pIniPrinter->pIniSpooler;
|
||
|
|
||
|
SPLASSERT(pIniPrinter->signature == IP_SIGNATURE );
|
||
|
SPLASSERT(pIniSpooler->signature == ISP_SIGNATURE );
|
||
|
|
||
|
if (pSpool->pIniPrinter->Status & PRINTER_ZOMBIE_OBJECT) {
|
||
|
|
||
|
LastError = ERROR_PRINTER_DELETED;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
if ( !ValidateLevelAndSecurityAccesses(pSpool,
|
||
|
Level,
|
||
|
pPrinterInfo,
|
||
|
Command,
|
||
|
&AccessRequired,
|
||
|
&SecurityInformation) ){
|
||
|
|
||
|
bReturn = FALSE;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// We need to do this for Level 0, 2, 3, 4, 5
|
||
|
// (except for level 3 which is security case)
|
||
|
//
|
||
|
if ( Level != 3 && pSpool->hPort ) {
|
||
|
|
||
|
if ( pSpool->hPort == INVALID_PORT_HANDLE ) {
|
||
|
|
||
|
//
|
||
|
// If this value is 0, then when we return GetLastError,
|
||
|
// the client will think we succeeded.
|
||
|
//
|
||
|
SPLASSERT( pSpool->OpenPortError );
|
||
|
|
||
|
LastError = pSpool->OpenPortError;
|
||
|
goto Cleanup;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
bReturn = SetPrinter(pSpool->hPort,
|
||
|
Level,
|
||
|
pPrinterInfo,
|
||
|
Command);
|
||
|
|
||
|
if ( !Level )
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bSecurityChg = bNameChg = bAttributeChg = FALSE;
|
||
|
|
||
|
if ( Level != 6 && Level != 0 ) {
|
||
|
|
||
|
pTempIniPrinter = (PINIPRINTER) AllocSplMem(sizeof(INIPRINTER));
|
||
|
if ( !pTempIniPrinter )
|
||
|
goto Cleanup;
|
||
|
CopyMemory(pTempIniPrinter, pIniPrinter, sizeof(INIPRINTER));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// The actual processing begins here
|
||
|
//
|
||
|
if ( !Level && !Command ) {
|
||
|
|
||
|
bReturn = SetLocalPrinterSTRESS(pIniPrinter,
|
||
|
(PPRINTER_INFO_STRESS)pPrinterInfo);
|
||
|
goto Cleanup;
|
||
|
} else if ( !Level ) {
|
||
|
|
||
|
bReturn = SetLocalPrinter0(pIniPrinter, Command);
|
||
|
goto Cleanup;
|
||
|
} else if ( Level == 6 ) {
|
||
|
|
||
|
bReturn = SetPrinterStatus(pIniPrinter,
|
||
|
((LPPRINTER_INFO_6)pPrinterInfo)->dwStatus);
|
||
|
goto Cleanup;
|
||
|
} else {
|
||
|
|
||
|
if ( !ValidateAndBuildSetPrinterRequest(pIniPrinter,
|
||
|
pTempIniPrinter,
|
||
|
pPrinterInfo,
|
||
|
Level,
|
||
|
SecurityInformation,
|
||
|
&bSecurityChg,
|
||
|
&bNameChg,
|
||
|
&bAttributeChg,
|
||
|
&pszNewPrinterName,
|
||
|
&pKeyData) ) {
|
||
|
|
||
|
bReturn = FALSE;
|
||
|
goto Cleanup;
|
||
|
} // else we follow thru rest of code since all valiations succeded
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// --------------------All validation done---------------------------
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Now set security information; Remember we have
|
||
|
// a valid SecurityDescriptor and "SecurityInformation
|
||
|
// is non-zero at this point. We have validated this
|
||
|
// information
|
||
|
//
|
||
|
if ( bSecurityChg ) {
|
||
|
|
||
|
if ( SetPrinterSecurityDescriptor(SecurityInformation,
|
||
|
pTempIniPrinter->pSecurityDescriptor,
|
||
|
&pIniPrinter->pSecurityDescriptor) ) {
|
||
|
|
||
|
dwPrinterVector |= BIT(I_PRINTER_SECURITY_DESCRIPTOR);
|
||
|
bForceUpdate = TRUE;
|
||
|
} else {
|
||
|
|
||
|
bReturn = FALSE;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( Level == 2 || Level == 5 ) {
|
||
|
|
||
|
ppIniPorts = AllocSplMem(pKeyData->cTokens * sizeof(INIPORT));
|
||
|
if ( !ppIniPorts )
|
||
|
goto Cleanup;
|
||
|
|
||
|
bReturn = SetPrinterPorts(pSpool, pIniPrinter, pKeyData);
|
||
|
|
||
|
if ( !bReturn )
|
||
|
goto Cleanup;
|
||
|
|
||
|
FreeSplMem(pIniPrinter->ppIniPorts);
|
||
|
|
||
|
pIniPrinter->ppIniPorts = ppIniPorts;
|
||
|
pIniPrinter->cPorts = pKeyData->cTokens;
|
||
|
ppIniPorts = NULL;
|
||
|
|
||
|
for ( i = 0 ; i < pKeyData->cTokens ; ++i ) {
|
||
|
|
||
|
pIniPrinter->ppIniPorts[i] = (PINIPORT) pKeyData->pTokens[i];
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( bAttributeChg ) {
|
||
|
|
||
|
if ( !(pTempIniPrinter->Attributes & PRINTER_ATTRIBUTE_ENABLE_DEVQ) &&
|
||
|
pIniPrinter->cJobs) {
|
||
|
|
||
|
pIniJob = pIniPrinter->pIniFirstJob;
|
||
|
|
||
|
while (pIniJob) {
|
||
|
if (pIniJob->Status & JOB_BLOCKED_DEVQ) {
|
||
|
|
||
|
PNOTIFYVECTOR pNotifyVector = &NVJobStatus;
|
||
|
pIniJob->Status &= ~JOB_BLOCKED_DEVQ;
|
||
|
|
||
|
if( pIniJob->pStatus ){
|
||
|
|
||
|
FreeSplStr(pIniJob->pStatus);
|
||
|
pIniJob->pStatus = NULL;
|
||
|
pNotifyVector = &NVJobStatusAndString;
|
||
|
}
|
||
|
|
||
|
SetPrinterChange(pIniJob->pIniPrinter,
|
||
|
pIniJob,
|
||
|
*pNotifyVector,
|
||
|
PRINTER_CHANGE_SET_JOB,
|
||
|
pIniJob->pIniPrinter->pIniSpooler);
|
||
|
|
||
|
}
|
||
|
pIniJob = pIniJob->pIniNextJob;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// The comment must be changed here since ShareThisPrinter
|
||
|
// will look at pComment when the printer is reshared.
|
||
|
//
|
||
|
if ( Level == 2 &&
|
||
|
pIniPrinter->pComment != pTempIniPrinter->pComment ) {
|
||
|
|
||
|
FreeSplStr(pIniPrinter->pComment);
|
||
|
|
||
|
pIniPrinter->pComment = pTempIniPrinter->pComment;
|
||
|
|
||
|
dwPrinterVector |= BIT(I_PRINTER_COMMENT);
|
||
|
|
||
|
//
|
||
|
// If the printer description has changed, we must reshare out
|
||
|
// the printer.
|
||
|
//
|
||
|
// !! LATER !!
|
||
|
// There must be a way of just changing the remark.
|
||
|
//
|
||
|
if (pTempIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED) {
|
||
|
|
||
|
bForceUpdate = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Change printer name if different
|
||
|
//
|
||
|
if ( bNameChg ) {
|
||
|
|
||
|
ChangePrinterName(pszNewPrinterName, pIniPrinter, pIniSpooler,
|
||
|
&dwPrinterVector);
|
||
|
bForceUpdate = TRUE;
|
||
|
pszNewPrinterName = NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If Share name changed force update
|
||
|
//
|
||
|
if ( pIniPrinter->pShareName != pTempIniPrinter->pShareName ) {
|
||
|
|
||
|
bForceUpdate = TRUE;
|
||
|
}
|
||
|
|
||
|
if ( bAttributeChg || bForceUpdate ) {
|
||
|
|
||
|
DWORD OldAttributes = pIniPrinter->Attributes;
|
||
|
pIniPrinter->Attributes = pTempIniPrinter->Attributes;
|
||
|
|
||
|
bReturn = ChangePrinterAttributes(pIniPrinter->Attributes,
|
||
|
OldAttributes,
|
||
|
pIniPrinter,
|
||
|
pIniSpooler,
|
||
|
pTempIniPrinter->pShareName,
|
||
|
bForceUpdate);
|
||
|
|
||
|
if (pIniPrinter->Attributes != OldAttributes) {
|
||
|
|
||
|
dwPrinterVector |= BIT(I_PRINTER_ATTRIBUTES);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if ( Level == 2 ) {
|
||
|
|
||
|
ProcessSetPrinter2(pIniPrinter,
|
||
|
pTempIniPrinter,
|
||
|
pPrinterInfo2,
|
||
|
&dwPrinterVector,
|
||
|
pDevMode);
|
||
|
}
|
||
|
|
||
|
CHECK_SCHEDULER();
|
||
|
|
||
|
UpdatePrinterIni( pIniPrinter, UPDATE_CHANGEID );
|
||
|
|
||
|
UpdateWinIni( pIniPrinter ); // So the port on the device is correct
|
||
|
|
||
|
//
|
||
|
// Log event that the SetPrinter was done.
|
||
|
//
|
||
|
|
||
|
LogEvent(pIniSpooler, LOG_INFO, MSG_PRINTER_SET, pIniPrinter->pName, NULL);
|
||
|
|
||
|
NotifyVector[PRINTER_NOTIFY_TYPE] |= dwPrinterVector;
|
||
|
//
|
||
|
// Indicate that a change has occurred.
|
||
|
//
|
||
|
SetPrinterChange(pIniPrinter,
|
||
|
NULL,
|
||
|
NotifyVector,
|
||
|
PRINTER_CHANGE_SET_PRINTER,
|
||
|
pIniSpooler);
|
||
|
|
||
|
Cleanup:
|
||
|
|
||
|
if ( LastError != ERROR_SUCCESS ) {
|
||
|
|
||
|
SetLastError(LastError);
|
||
|
bReturn = FALSE;
|
||
|
}
|
||
|
|
||
|
CleanupSetPrinter(pIniPrinter, pTempIniPrinter, pKeyData,
|
||
|
Level, bReturn);
|
||
|
|
||
|
LeaveSplSem();
|
||
|
SplOutSem();
|
||
|
|
||
|
if ( pDevMode && pDevMode != pPrinterInfo2->pDevMode )
|
||
|
FreeSplMem(pDevMode);
|
||
|
|
||
|
FreeSplStr(pszNewPrinterName);
|
||
|
FreeSplMem(ppIniPorts);
|
||
|
|
||
|
//
|
||
|
// If the printer driver changed
|
||
|
// Call the printer driver to initialize itself
|
||
|
//
|
||
|
if ( bReturn &&
|
||
|
( dwPrinterVector & BIT(I_PRINTER_DRIVER_NAME)) ) {
|
||
|
|
||
|
PrinterDriverEvent(pIniPrinter, PRINTER_EVENT_INITIALIZE, (LPARAM)NULL);
|
||
|
}
|
||
|
|
||
|
return bReturn;
|
||
|
}
|
||
|
|
||
|
|
||
|
SECURITY_STATUS
|
||
|
SetPrinterSecurity(
|
||
|
SECURITY_INFORMATION SecurityInformation,
|
||
|
PINIPRINTER pIniPrinter,
|
||
|
PSECURITY_DESCRIPTOR pSecurityDescriptor)
|
||
|
{
|
||
|
DWORD dwSize;
|
||
|
|
||
|
if (!pSecurityDescriptor)
|
||
|
return SECURITY_FAIL;
|
||
|
|
||
|
if (pIniPrinter->pSecurityDescriptor) {
|
||
|
|
||
|
dwSize = GetSecurityDescriptorLength(pIniPrinter->pSecurityDescriptor);
|
||
|
|
||
|
if (dwSize == GetSecurityDescriptorLength(pSecurityDescriptor)) {
|
||
|
|
||
|
if (!memcmp(pSecurityDescriptor,
|
||
|
pIniPrinter->pSecurityDescriptor,
|
||
|
dwSize)) {
|
||
|
|
||
|
return SECURITY_NOCHANGE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( !SetPrinterSecurityDescriptor( SecurityInformation,
|
||
|
pSecurityDescriptor,
|
||
|
&pIniPrinter->pSecurityDescriptor ) ) {
|
||
|
|
||
|
DBGMSG(DBG_WARNING, ("SetPrinterSecurityDescriptor failed. Error = %d\n",
|
||
|
GetLastError()));
|
||
|
return SECURITY_FAIL;
|
||
|
}
|
||
|
|
||
|
UpdatePrinterIni(pIniPrinter, UPDATE_CHANGEID);
|
||
|
|
||
|
return SECURITY_SUCCESS;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
RegClearKey(
|
||
|
HKEY hKey
|
||
|
)
|
||
|
{
|
||
|
DWORD dwError;
|
||
|
WCHAR szValue[MAX_PATH];
|
||
|
|
||
|
DWORD cchValue;
|
||
|
|
||
|
while (TRUE) {
|
||
|
|
||
|
cchValue = COUNTOF(szValue);
|
||
|
dwError = RegEnumValue(hKey,
|
||
|
0,
|
||
|
szValue,
|
||
|
&cchValue,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
|
||
|
if( dwError != ERROR_SUCCESS ){
|
||
|
|
||
|
if( dwError != ERROR_NO_MORE_ITEMS ){
|
||
|
DBGMSG( DBG_ERROR, ( "RegClearKey: Failed %d\n", dwError ));
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
dwError = RegDeleteValue(hKey, szValue);
|
||
|
|
||
|
if( dwError != ERROR_SUCCESS ){
|
||
|
DBGMSG( DBG_ERROR, ( "RegDeleteValue: %s Failed %d\n",
|
||
|
szValue, dwError ));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ChangePrinterAttributes(
|
||
|
DWORD dNewAttributes,
|
||
|
DWORD dOldAttributes,
|
||
|
PINIPRINTER pIniPrinter,
|
||
|
PINISPOOLER pIniSpooler,
|
||
|
LPWSTR pszNewShareName,
|
||
|
BOOL bForceUpdate
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Changes printer attributes by validating sharing information.
|
||
|
Already the validated attributes are set, we want to validate
|
||
|
by changing the share information
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
dNewAttributes - New attributes specified on SetPrinter call
|
||
|
|
||
|
dOldAttributes - pIniPrinter->Attributes before the call
|
||
|
|
||
|
pIniPrinter - of the printer we are changing attributes
|
||
|
|
||
|
pIniSpooler - Spooler that owns printer
|
||
|
|
||
|
pszNewShareName - the share name that will be set if SetPrinter succeds
|
||
|
|
||
|
bForceUpdate - do we have to update because description is different
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
DWORD TRUE on success, FALSE else.
|
||
|
|
||
|
History:
|
||
|
MuhuntS (Muhunthan Sivapragasam) July 95
|
||
|
*/
|
||
|
{
|
||
|
BOOL Shared, bReturn = TRUE;
|
||
|
|
||
|
//
|
||
|
// We are going to have to be able to restore the attributes if the share
|
||
|
// modification fails. We need to set the current attributes now because
|
||
|
// the NetSharexxx is going to call OpenPrinter, and possibly an AddJob
|
||
|
// which needs the correct Attributes.
|
||
|
//
|
||
|
if (dNewAttributes & PRINTER_ATTRIBUTE_SHARED) {
|
||
|
|
||
|
if (!(dOldAttributes & PRINTER_ATTRIBUTE_SHARED)) {
|
||
|
|
||
|
pIniPrinter->Attributes |= PRINTER_ATTRIBUTE_SHARED;
|
||
|
|
||
|
Shared = ShareThisPrinter( pIniPrinter, pszNewShareName, TRUE );
|
||
|
|
||
|
if ( !Shared ) {
|
||
|
|
||
|
pIniPrinter->Attributes = dOldAttributes;
|
||
|
bReturn = FALSE;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// We are shared, and so is the old one. If share name changed
|
||
|
// we have to remove old share and reshare.
|
||
|
//
|
||
|
if ( _wcsicmp(pszNewShareName, pIniPrinter->pShareName) ) {
|
||
|
|
||
|
if (ShareThisPrinter(pIniPrinter,
|
||
|
pIniPrinter->pShareName,
|
||
|
FALSE)) {
|
||
|
|
||
|
#if DBG
|
||
|
WCHAR pwszError[256];
|
||
|
|
||
|
wsprintf(pwszError,
|
||
|
L"Error %d, removing share",
|
||
|
GetLastError());
|
||
|
|
||
|
//
|
||
|
// Error: the printer shouldn't be shared at this
|
||
|
// point.
|
||
|
//
|
||
|
LogEvent(pIniSpooler,
|
||
|
LOG_ERROR,
|
||
|
MSG_SHARE_FAILED,
|
||
|
L"SetLocalPrinter ShareThisPrinter FALSE",
|
||
|
pIniPrinter->pName,
|
||
|
pIniPrinter->pShareName,
|
||
|
pwszError,
|
||
|
NULL);
|
||
|
#endif
|
||
|
|
||
|
bReturn = FALSE;
|
||
|
|
||
|
} else if (!ShareThisPrinter(pIniPrinter,
|
||
|
pszNewShareName,
|
||
|
TRUE)) {
|
||
|
#if DBG
|
||
|
WCHAR pwszError[256];
|
||
|
|
||
|
wsprintf(pwszError,
|
||
|
L"Error %d, adding share",
|
||
|
GetLastError());
|
||
|
|
||
|
//
|
||
|
// Error: the printer shouldn't be shared at this
|
||
|
// point.
|
||
|
//
|
||
|
LogEvent(pIniSpooler,
|
||
|
LOG_ERROR,
|
||
|
MSG_SHARE_FAILED,
|
||
|
L"SetLocalPrinter ShareThisPrinter TRUE",
|
||
|
pIniPrinter->pName,
|
||
|
pIniPrinter->pShareName,
|
||
|
pwszError,
|
||
|
NULL);
|
||
|
#endif
|
||
|
|
||
|
pIniPrinter->Attributes &= ~PRINTER_ATTRIBUTE_SHARED;
|
||
|
pIniPrinter->Status |= PRINTER_WAS_SHARED;
|
||
|
bReturn = FALSE;
|
||
|
}
|
||
|
} else if ( bForceUpdate ) {
|
||
|
//
|
||
|
// If comment/description changed then we just do a NetShareSet
|
||
|
//
|
||
|
bReturn = SetPrinterShareInfo(pIniPrinter);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} else if (dOldAttributes & PRINTER_ATTRIBUTE_SHARED) {
|
||
|
|
||
|
Shared = ShareThisPrinter(pIniPrinter, pIniPrinter->pShareName, FALSE);
|
||
|
|
||
|
if (!Shared) {
|
||
|
|
||
|
pIniPrinter->Attributes &= ~PRINTER_ATTRIBUTE_SHARED;
|
||
|
pIniPrinter->Status |= PRINTER_WAS_SHARED;
|
||
|
CreateServerThread( pIniPrinter->pIniSpooler );
|
||
|
|
||
|
|
||
|
} else {
|
||
|
pIniPrinter->Attributes = dOldAttributes;
|
||
|
bReturn = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return bReturn;
|
||
|
}
|