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.
2265 lines
66 KiB
2265 lines
66 KiB
/*++
|
|
|
|
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.
|
|
SWilson - Added SetPrinter Level 7
|
|
|
|
--*/
|
|
#define NOMINMAX
|
|
#include <precomp.h>
|
|
#pragma hdrstop
|
|
|
|
#include "clusspl.h"
|
|
|
|
#define PRINTER_NO_CONTROL 0x00
|
|
|
|
typedef enum {
|
|
SECURITY_SUCCESS = 0,
|
|
SECURITY_NOCHANGE = 1,
|
|
SECURITY_FAIL = 2
|
|
} PRINTER_SECURITY_STATUS;
|
|
|
|
PRINTER_SECURITY_STATUS
|
|
SetPrinterSecurity(
|
|
SECURITY_INFORMATION SecurityInformation,
|
|
PINIPRINTER pIniPrinter,
|
|
PSECURITY_DESCRIPTOR pSecurityDescriptor
|
|
);
|
|
|
|
VOID
|
|
RegClearKey(
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
);
|
|
|
|
DWORD
|
|
ValidatePrinterAttributes(
|
|
DWORD SourceAttributes,
|
|
DWORD OriginalAttributes,
|
|
LPWSTR pDatatype,
|
|
LPBOOL pbValid,
|
|
BOOL bSettableOnly
|
|
);
|
|
|
|
BOOL
|
|
ChangePrinterAttributes(
|
|
DWORD dNewAttributes,
|
|
DWORD dOldAttributes,
|
|
PINIPRINTER pIniPrinter,
|
|
PINISPOOLER pIniSpooler,
|
|
LPWSTR pszNewShareName,
|
|
BOOL bShareRecreate,
|
|
BOOL bShareUpdate
|
|
);
|
|
|
|
BOOL
|
|
NewPort(
|
|
PKEYDATA pKeyData,
|
|
PINIPRINTER pIniPrinter
|
|
);
|
|
|
|
BOOL
|
|
SplSetPrinterExtraEx(
|
|
HANDLE hPrinter,
|
|
DWORD dwPrivateFlag
|
|
)
|
|
{
|
|
BOOL ReturnValue = FALSE;
|
|
PSPOOL pSpool = (PSPOOL)hPrinter;
|
|
|
|
EnterSplSem();
|
|
|
|
if (ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER)) {
|
|
|
|
pSpool->pIniPrinter->dwPrivateFlag = dwPrivateFlag;
|
|
ReturnValue = TRUE;
|
|
}
|
|
|
|
LeaveSplSem();
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
BOOL
|
|
SplGetPrinterExtraEx(
|
|
HANDLE hPrinter,
|
|
LPDWORD pdwPrivateFlag
|
|
)
|
|
{
|
|
BOOL ReturnValue = FALSE;
|
|
PSPOOL pSpool = (PSPOOL)hPrinter;
|
|
|
|
EnterSplSem();
|
|
|
|
if ((pSpool != NULL) &&
|
|
(pSpool != INVALID_HANDLE_VALUE) &&
|
|
ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER) &&
|
|
pdwPrivateFlag) {
|
|
|
|
*pdwPrivateFlag = pSpool->pIniPrinter->dwPrivateFlag;
|
|
ReturnValue = TRUE;
|
|
}
|
|
|
|
LeaveSplSem();
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
|
|
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,
|
|
PBYTE *ppExtraData
|
|
)
|
|
{
|
|
PSPOOL pSpool = (PSPOOL)hPrinter;
|
|
BOOL ReturnValue;
|
|
|
|
if (ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER)) {
|
|
|
|
*ppExtraData = 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 4:
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
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 {
|
|
//
|
|
// Bug 54918 - 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.
|
|
//
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
|
|
pSecurityDescriptor =
|
|
((PPRINTER_INFO_3)pPrinterInfo)->pSecurityDescriptor;
|
|
|
|
if (!pSecurityDescriptor) {
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return FALSE;
|
|
}
|
|
|
|
if (GetSecurityInformation(pSecurityDescriptor,
|
|
&SecurityInformation)) {
|
|
AccessRequired |= GetPrivilegeRequired( SecurityInformation );
|
|
} else {
|
|
// LastError = GetLastError();
|
|
return FALSE;
|
|
}
|
|
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, FALSE, NULL) ) {
|
|
|
|
FreePortTokenList(pKeyData);
|
|
SetLastError(ERROR_UNKNOWN_PORT);
|
|
pKeyData = NULL;
|
|
}
|
|
}
|
|
|
|
return pKeyData;
|
|
}
|
|
|
|
|
|
BOOL
|
|
NewPort(
|
|
PKEYDATA pKeyData,
|
|
PINIPRINTER pIniPrinter
|
|
)
|
|
{
|
|
DWORD i, j;
|
|
BOOL rc=TRUE;
|
|
|
|
if (!pKeyData) {
|
|
SetLastError(ERROR_UNKNOWN_PORT);
|
|
return FALSE;
|
|
}
|
|
|
|
// Check if # of requested vs. existing ports differs
|
|
if (pIniPrinter->cPorts != pKeyData->cTokens)
|
|
return TRUE;
|
|
|
|
// for each requested port see if printer already has it
|
|
for (i = 0 ; i < pKeyData->cTokens ; ++i) {
|
|
|
|
// see if requested port is already assigned to printer
|
|
for (j = 0 ; j < pIniPrinter->cPorts &&
|
|
wcscmp(pIniPrinter->ppIniPorts[j]->pName, ((PINIPORT)pKeyData->pTokens[i])->pName)
|
|
; ++j) {
|
|
|
|
DBGMSG(DBG_TRACE,("NewPort (Existing vs. Requested): \"%ws\" ?= \"%ws\"\n",
|
|
pIniPrinter->ppIniPorts[j]->pName, ((PINIPORT)pKeyData->pTokens[i])->pName));
|
|
}
|
|
|
|
if (j == pIniPrinter->cPorts) { // found new port, so return
|
|
DBGMSG(DBG_TRACE,("NewPort FOUND: \"%ws\"\n", ((PINIPORT)pKeyData->pTokens[i])->pName));
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
--*/
|
|
|
|
{
|
|
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);
|
|
|
|
//
|
|
// If printer is offline we need to write that info back with new name
|
|
//
|
|
if ( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_WORK_OFFLINE )
|
|
WritePrinterOnlineStatusInCurrentConfig(pIniPrinter);
|
|
}
|
|
|
|
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;
|
|
|
|
INCPRINTERREF( pIniPrinter );
|
|
|
|
switch (Command) {
|
|
|
|
case PRINTER_CONTROL_PURGE:
|
|
|
|
//
|
|
// PurgePrinter always returns TRUE now, still ..
|
|
//
|
|
if ( PurgePrinter(pIniPrinter) ) {
|
|
|
|
SplLogEvent(pIniPrinter->pIniSpooler,
|
|
LOG_WARNING,
|
|
MSG_PRINTER_PURGED,
|
|
TRUE,
|
|
pIniPrinter->pName,
|
|
NULL );
|
|
|
|
Change |= PRINTER_CHANGE_DELETE_JOB;
|
|
|
|
} else {
|
|
|
|
bReturn = FALSE;
|
|
}
|
|
break;
|
|
|
|
case PRINTER_CONTROL_RESUME:
|
|
|
|
pIniPrinter->Status &= ~PRINTER_PAUSED;
|
|
|
|
CHECK_SCHEDULER();
|
|
|
|
UpdatePrinterIni( pIniPrinter, KEEP_CHANGEID );
|
|
|
|
SplLogEvent(pIniPrinter->pIniSpooler,
|
|
LOG_WARNING,
|
|
MSG_PRINTER_UNPAUSED,
|
|
TRUE,
|
|
pIniPrinter->pName,
|
|
NULL );
|
|
//
|
|
// WMI Trace Events.
|
|
//
|
|
{
|
|
//
|
|
// Wmi only knows about jobs, so each job needs to be resumed
|
|
// separately.
|
|
//
|
|
PINIJOB pIniJob = pIniPrinter->pIniFirstJob;
|
|
while (pIniJob)
|
|
{
|
|
if ( !((pIniJob->Status & JOB_DESPOOLING) ||
|
|
(pIniJob->Status & JOB_PRINTING) ||
|
|
(pIniJob->Status & JOB_PRINTED) ||
|
|
(pIniJob->Status & JOB_ABANDON)) )
|
|
{
|
|
LogWmiTraceEvent(pIniJob->JobId,
|
|
EVENT_TRACE_TYPE_SPL_RESUME, NULL);
|
|
}
|
|
pIniJob = pIniJob->pIniNextJob;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PRINTER_CONTROL_PAUSE:
|
|
|
|
//
|
|
// You can't pause a fax printer. This locks up the fax server. The
|
|
// fax service also has its own concept of paused.
|
|
//
|
|
if (!(pIniPrinter->Attributes & PRINTER_ATTRIBUTE_FAX)) {
|
|
|
|
pIniPrinter->Status |= PRINTER_PAUSED;
|
|
|
|
UpdatePrinterIni( pIniPrinter, KEEP_CHANGEID );
|
|
|
|
SplLogEvent(pIniPrinter->pIniSpooler,
|
|
LOG_WARNING,
|
|
MSG_PRINTER_PAUSED,
|
|
TRUE,
|
|
pIniPrinter->pName,
|
|
NULL);
|
|
//
|
|
// WMI Trace Events
|
|
//
|
|
{
|
|
//
|
|
// Wmi only knows about jobs, so each job needs to be paused
|
|
// separately.
|
|
//
|
|
PINIJOB pIniJob = pIniPrinter->pIniFirstJob;
|
|
while (pIniJob)
|
|
{
|
|
//
|
|
// HANDLE PRINTING DIRECT ???
|
|
// I don't believe pausing a printer can stop a job already
|
|
// being sent to the printer.
|
|
//
|
|
if ( !((pIniJob->Status & JOB_DESPOOLING) ||
|
|
(pIniJob->Status & JOB_PRINTING) ||
|
|
(pIniJob->Status & JOB_PRINTED) ||
|
|
(pIniJob->Status & JOB_ABANDON)) )
|
|
{
|
|
LogWmiTraceEvent(pIniJob->JobId,
|
|
EVENT_TRACE_TYPE_SPL_PAUSE,
|
|
NULL);
|
|
}
|
|
pIniJob = pIniJob->pIniNextJob;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
|
|
bReturn = FALSE;
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
SetLastError(ERROR_INVALID_PRINTER_COMMAND);
|
|
bReturn = FALSE;
|
|
break;
|
|
}
|
|
|
|
DECPRINTERREF( pIniPrinter );
|
|
|
|
if (bReturn) {
|
|
|
|
SetPrinterChange(pIniPrinter,
|
|
NULL,
|
|
(Command == PRINTER_CONTROL_PURGE) ? NVPurge
|
|
: NVPrinterStatus,
|
|
Change,
|
|
pIniPrinter->pIniSpooler);
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
BOOL bFail = FALSE;
|
|
DWORD LastError = ERROR_SUCCESS;
|
|
PINIVERSION pIniVersion = NULL;
|
|
PINIENVIRONMENT pIniEnvironment = NULL;
|
|
BOOL bSuccess = FALSE;
|
|
|
|
// Servername can't change
|
|
// Printername handled for level 2, 4, 5
|
|
|
|
// Sharenname length validation
|
|
if ( pPrinterInfo2->pShareName && wcslen(pPrinterInfo2->pShareName) > PATHLEN-1 ){
|
|
bFail = TRUE;
|
|
LastError = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Share Name (validation later if required)
|
|
AllocOrUpdateString(&pTempIniPrinter->pShareName,
|
|
pPrinterInfo2->pShareName,
|
|
pIniPrinter->pShareName,
|
|
TRUE,
|
|
&bFail);
|
|
|
|
if ( bFail )
|
|
goto Cleanup;
|
|
|
|
// Port Name for level 2, 5
|
|
|
|
// DriverName
|
|
bSuccess = FindLocalDriverAndVersion(pIniPrinter->pIniSpooler,
|
|
pPrinterInfo2->pDriverName,
|
|
&pTempIniPrinter->pIniDriver,
|
|
&pIniVersion);
|
|
|
|
if ( !bSuccess ) {
|
|
|
|
LastError = ERROR_UNKNOWN_PRINTER_DRIVER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
pIniEnvironment = GetLocalArchEnv(pIniPrinter->pIniSpooler);
|
|
|
|
//
|
|
// If we have a queue with a KMPD, then we need to let the user manage it,
|
|
// even if the policy for blocking KMPD is enabled. However, if the caller
|
|
// wants to change the printer driver to a KMPD, then we do not allow that
|
|
//
|
|
if (pTempIniPrinter->pIniDriver != pIniPrinter->pIniDriver)
|
|
{
|
|
INCDRIVERREF(pTempIniPrinter->pIniDriver);
|
|
|
|
if (KMPrintersAreBlocked() &&
|
|
IniDriverIsKMPD(pIniPrinter->pIniSpooler,
|
|
pIniEnvironment,
|
|
pIniVersion,
|
|
pTempIniPrinter->pIniDriver)) {
|
|
|
|
SplLogEvent( pIniPrinter->pIniSpooler,
|
|
LOG_ERROR,
|
|
MSG_KM_PRINTERS_BLOCKED,
|
|
TRUE,
|
|
pIniPrinter->pName,
|
|
NULL );
|
|
|
|
LastError = ERROR_KM_DRIVER_BLOCKED;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
// Comment length validation
|
|
if ( pPrinterInfo2->pComment && wcslen(pPrinterInfo2->pComment) > PATHLEN-1 ){
|
|
bFail = TRUE;
|
|
LastError = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Comment
|
|
AllocOrUpdateString(&pTempIniPrinter->pComment,
|
|
pPrinterInfo2->pComment,
|
|
pIniPrinter->pComment,
|
|
TRUE,
|
|
&bFail);
|
|
|
|
// Location length validation
|
|
if ( pPrinterInfo2->pLocation && wcslen(pPrinterInfo2->pLocation) > MAX_PATH-1 ){
|
|
bFail = TRUE;
|
|
LastError = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Location
|
|
AllocOrUpdateString(&pTempIniPrinter->pLocation,
|
|
pPrinterInfo2->pLocation,
|
|
pIniPrinter->pLocation,
|
|
TRUE,
|
|
&bFail);
|
|
|
|
// DevMode at the end
|
|
|
|
// SepFile length validation
|
|
if( !CheckSepFile( pPrinterInfo2->pSepFile )) {
|
|
bFail = TRUE;
|
|
LastError = ERROR_INVALID_SEPARATOR_FILE;
|
|
}
|
|
|
|
// SepFile
|
|
AllocOrUpdateString(&pTempIniPrinter->pSepFile,
|
|
pPrinterInfo2->pSepFile,
|
|
pIniPrinter->pSepFile,
|
|
TRUE,
|
|
&bFail);
|
|
|
|
if ( bFail )
|
|
goto Cleanup;
|
|
|
|
if ( pIniPrinter->pSepFile != pTempIniPrinter->pSepFile &&
|
|
!CheckSepFile(pPrinterInfo2->pSepFile) ) {
|
|
|
|
LastError = ERROR_INVALID_SEPARATOR_FILE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Print Processor
|
|
pTempIniPrinter->pIniPrintProc = FindPrintProc(
|
|
pPrinterInfo2->pPrintProcessor,
|
|
pIniEnvironment );
|
|
|
|
if ( !pTempIniPrinter->pIniPrintProc ) {
|
|
|
|
LastError = ERROR_UNKNOWN_PRINTPROCESSOR;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( pTempIniPrinter->pIniPrintProc != pIniPrinter->pIniPrintProc )
|
|
pTempIniPrinter->pIniPrintProc->cRef++;
|
|
|
|
// Datatype
|
|
if ( !pPrinterInfo2->pDatatype || wcslen(pPrinterInfo2->pDatatype) > MAX_PATH-1) {
|
|
|
|
LastError = ERROR_INVALID_DATATYPE;
|
|
goto Cleanup; // Ok to fail ???
|
|
} else {
|
|
|
|
AllocOrUpdateString(&pTempIniPrinter->pDatatype,
|
|
pPrinterInfo2->pDatatype,
|
|
pIniPrinter->pDatatype,
|
|
TRUE,
|
|
&bFail);
|
|
}
|
|
|
|
// Parameters length validation
|
|
if (pPrinterInfo2->pParameters && wcslen(pPrinterInfo2->pParameters) > MAX_PATH-1){
|
|
bFail = TRUE;
|
|
LastError = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Parameters
|
|
AllocOrUpdateString(&pTempIniPrinter->pParameters,
|
|
pPrinterInfo2->pParameters,
|
|
pIniPrinter->pParameters,
|
|
TRUE,
|
|
&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
|
|
|
|
--*/
|
|
{
|
|
HANDLE hToken;
|
|
PINISPOOLER pIniSpooler = pIniPrinter->pIniSpooler;
|
|
HKEY hKey = NULL;
|
|
DWORD dwResult;
|
|
|
|
// 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);
|
|
|
|
if (pIniPrinter->pIniSpooler->SpoolerFlags & SPL_PRINTER_DRIVER_EVENT)
|
|
{
|
|
|
|
hToken = RevertToPrinterSelf();
|
|
|
|
dwResult = OpenPrinterKey(pIniPrinter, KEY_READ | KEY_WRITE, &hKey, szPrinterData, TRUE);
|
|
|
|
if (dwResult == ERROR_SUCCESS) {
|
|
|
|
DeleteSubkeys( hKey, pIniSpooler );
|
|
RegClearKey( hKey, pIniSpooler );
|
|
SplRegCloseKey(hKey, pIniPrinter->pIniSpooler);
|
|
}
|
|
|
|
if (hToken)
|
|
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
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// 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
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
BOOL bValid = TRUE;
|
|
|
|
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,
|
|
pIniPrinter->Attributes,
|
|
pPrinterInfo2->pDatatype,
|
|
&bValid,
|
|
TRUE);
|
|
|
|
if (!bValid) {
|
|
return FALSE;
|
|
}
|
|
|
|
*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,
|
|
pIniPrinter->Attributes,
|
|
pIniPrinter->pDatatype,
|
|
&bValid,
|
|
TRUE);
|
|
|
|
if (!bValid) {
|
|
return FALSE;
|
|
}
|
|
|
|
*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,
|
|
pIniPrinter->Attributes,
|
|
pIniPrinter->pDatatype,
|
|
&bValid,
|
|
TRUE);
|
|
|
|
if (!bValid) {
|
|
return FALSE;
|
|
}
|
|
|
|
*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) ) {
|
|
|
|
if (gRemoteRPCEndPointPolicy == RpcEndPointPolicyDisabled)
|
|
{
|
|
SetLastError(ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED);
|
|
return FALSE;
|
|
}
|
|
|
|
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;
|
|
DWORD dwResult;
|
|
BOOL bShareUpdate;
|
|
BOOL bShareRecreate;
|
|
DWORD dwPrinterVector = 0;
|
|
NOTIFYVECTOR NotifyVector;
|
|
BOOL bUpdateDsSpoolerKey = FALSE;
|
|
BOOL bNewPort;
|
|
BOOL bDataChanged = FALSE;
|
|
DWORD OldAttributes = 0;
|
|
|
|
DWORD dwPrnEvntError = ERROR_SUCCESS;
|
|
|
|
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;
|
|
PPRINTER_INFO_7 pPrinterInfo7 = (PPRINTER_INFO_7)pPrinterInfo;
|
|
PRINTER_INFO_7 PrinterInfo7;
|
|
|
|
BOOL bSecurityChg, bNameChg, bAttributeChg;
|
|
LPWSTR pszNewPrinterName = NULL, pszOldPrinterName = NULL;
|
|
PINIJOB pIniJob;
|
|
PKEYDATA pKeyData = NULL;
|
|
PDEVMODE pDevMode = NULL;
|
|
PINIDRIVER pIniDriver;
|
|
PINIPRINTPROC pIniPrintProc;
|
|
SECURITY_INFORMATION SecurityInformation;
|
|
|
|
ZERONV(NotifyVector);
|
|
|
|
bSecurityChg = bNameChg = bAttributeChg = FALSE;
|
|
bShareUpdate = bShareRecreate = FALSE;
|
|
|
|
//
|
|
// 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_DATA) ) {
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
|
|
//
|
|
// Level 7 & publishing levels
|
|
//
|
|
if (Level == 7) {
|
|
|
|
if ( !(pIniPrinter->pIniSpooler->SpoolerFlags & SPL_TYPE_CACHE)) {
|
|
|
|
if (pPrinterInfo7->dwAction != DSPRINT_PUBLISH &&
|
|
pPrinterInfo7->dwAction != DSPRINT_UNPUBLISH &&
|
|
pPrinterInfo7->dwAction != DSPRINT_REPUBLISH &&
|
|
pPrinterInfo7->dwAction != DSPRINT_UPDATE) {
|
|
LastError = ERROR_INVALID_PARAMETER;
|
|
bReturn = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
DBGMSG(DBG_EXEC, ("SplSetPrinter: DS Action %d: %ws %ws",
|
|
pPrinterInfo7->dwAction,
|
|
pIniPrinter->pName,
|
|
pIniPrinter->pszObjectGUID ?
|
|
pIniPrinter->pszObjectGUID : L"<NULL>"));
|
|
|
|
bUpdateDsSpoolerKey = TRUE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// For connections, we rely directly on pPrinterInfo7->dwAction because
|
|
// then we cannot determine a pending publishing state based on attributes and GUID.
|
|
// If the remote printer is in Pending publishing, we need to save this in dwAction.
|
|
//
|
|
if (!pIniPrinter->pszObjectGUID || !pPrinterInfo7->pszObjectGUID) {
|
|
|
|
FreeSplStr(pIniPrinter->pszObjectGUID);
|
|
pIniPrinter->pszObjectGUID = NULL;
|
|
dwPrinterVector |= BIT(I_PRINTER_OBJECT_GUID);
|
|
|
|
} else if (wcscmp(pIniPrinter->pszObjectGUID, pPrinterInfo7->pszObjectGUID)) {
|
|
|
|
FreeSplStr(pIniPrinter->pszObjectGUID);
|
|
}
|
|
|
|
if ( pPrinterInfo7->pszObjectGUID ) {
|
|
|
|
if (!(pIniPrinter->pszObjectGUID = AllocSplStr(pPrinterInfo7->pszObjectGUID))) {
|
|
bReturn = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
pIniPrinter->dwAction = pPrinterInfo7->dwAction;
|
|
dwPrinterVector |= BIT(I_PRINTER_OBJECT_GUID);
|
|
|
|
}
|
|
goto Finish;
|
|
|
|
} else if (Level != 3 && Level != 0) {
|
|
bUpdateDsSpoolerKey = TRUE;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
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
|
|
|
|
// Just a flag stating whether we have a new port
|
|
bNewPort = NewPort(pKeyData, pIniPrinter);
|
|
if (bNewPort) {
|
|
dwPrinterVector |= BIT(I_PRINTER_PORT_NAME);
|
|
}
|
|
}
|
|
|
|
//
|
|
// --------------------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);
|
|
bShareUpdate = TRUE;
|
|
} else {
|
|
|
|
bReturn = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// Can we avoid doing this if bNewPort == NULL?
|
|
if ( Level == 2 || Level == 5 ) {
|
|
|
|
//
|
|
// bi-dir associate pIniPrinter with ports inside pKeyData.
|
|
//
|
|
bReturn = SetPrinterPorts(pSpool, pIniPrinter, pKeyData);
|
|
|
|
if ( !bReturn )
|
|
goto Cleanup;
|
|
}
|
|
|
|
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;
|
|
InterlockedAnd((LONG*)&(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 (pTempIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED) {
|
|
|
|
bShareUpdate = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Change printer name if different
|
|
//
|
|
if ( bNameChg ) {
|
|
|
|
pszOldPrinterName = AllocSplStr(pIniPrinter->pName);
|
|
|
|
if (!pszOldPrinterName && pIniPrinter->pName) {
|
|
bReturn = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ChangePrinterName(pszNewPrinterName, pIniPrinter, pIniSpooler,
|
|
&dwPrinterVector);
|
|
|
|
pszNewPrinterName = NULL;
|
|
|
|
//
|
|
// The print share must be recreated since there's no way
|
|
// to change the path without deleting and creating a new one.
|
|
//
|
|
bShareRecreate = TRUE;
|
|
}
|
|
|
|
//
|
|
// If Share name changed force update
|
|
//
|
|
if ( pIniPrinter->pShareName != pTempIniPrinter->pShareName ) {
|
|
|
|
bShareRecreate = TRUE;
|
|
}
|
|
|
|
if ( bAttributeChg || bShareUpdate || bShareRecreate ) {
|
|
|
|
OldAttributes = pIniPrinter->Attributes;
|
|
pIniPrinter->Attributes = pTempIniPrinter->Attributes;
|
|
|
|
bReturn = ChangePrinterAttributes(pIniPrinter->Attributes,
|
|
OldAttributes,
|
|
pIniPrinter,
|
|
pIniSpooler,
|
|
pTempIniPrinter->pShareName,
|
|
bShareRecreate,
|
|
bShareUpdate);
|
|
|
|
if (!bReturn) {
|
|
LastError = GetLastError();
|
|
}
|
|
|
|
if (pIniPrinter->Attributes != OldAttributes) {
|
|
dwPrinterVector |= BIT(I_PRINTER_ATTRIBUTES);
|
|
}
|
|
}
|
|
|
|
|
|
if ( Level == 2 ) {
|
|
|
|
ProcessSetPrinter2(pIniPrinter,
|
|
pTempIniPrinter,
|
|
pPrinterInfo2,
|
|
&dwPrinterVector,
|
|
pDevMode);
|
|
}
|
|
|
|
Finish:
|
|
|
|
// Sometimes SetPrinter can fail certain calls after it has modified some parameters.
|
|
// For instance, we may have failed to update some sharing fields. If we get to this
|
|
// point (or anywhere after the last goto Cleanup), then we need to update the ds keys.
|
|
// We should really clean up SetPrinter so it undoes everything, but we don't have enough time
|
|
// to fix it properly before NT6.
|
|
bDataChanged = TRUE;
|
|
|
|
CHECK_SCHEDULER();
|
|
|
|
// Can we avoid doing this if dwPrinterVector == NULL?
|
|
UpdatePrinterIni( pIniPrinter, UPDATE_CHANGEID );
|
|
|
|
// Can we avoid doing this if dwPrinterVector == NULL?
|
|
UpdateWinIni( pIniPrinter ); // So the port on the device is correct
|
|
|
|
//
|
|
// Log event that the SetPrinter was done.
|
|
//
|
|
|
|
INCPRINTERREF(pIniPrinter);
|
|
SplLogEvent(pIniSpooler, LOG_INFO, MSG_PRINTER_SET, TRUE, pIniPrinter->pName, NULL);
|
|
DECPRINTERREF(pIniPrinter);
|
|
|
|
NotifyVector[PRINTER_NOTIFY_TYPE] |= dwPrinterVector;
|
|
//
|
|
// Indicate that a change has occurred.
|
|
//
|
|
SetPrinterChange(pIniPrinter,
|
|
NULL,
|
|
NotifyVector,
|
|
PRINTER_CHANGE_SET_PRINTER,
|
|
pIniSpooler);
|
|
|
|
Cleanup:
|
|
|
|
SplInSem();
|
|
|
|
if ( LastError != ERROR_SUCCESS ) {
|
|
|
|
SetLastError(LastError);
|
|
bReturn = FALSE;
|
|
}
|
|
|
|
CleanupSetPrinter(pIniPrinter, pTempIniPrinter, pKeyData,
|
|
Level, bReturn);
|
|
|
|
if (bDataChanged) {
|
|
INCPRINTERREF(pIniPrinter);
|
|
LeaveSplSem();
|
|
SplOutSem();
|
|
|
|
//
|
|
// If the printer driver changed
|
|
// Call the printer driver to initialize itself
|
|
//
|
|
if (dwPrinterVector & BIT(I_PRINTER_DRIVER_NAME)) {
|
|
|
|
PDEVMODE pDevMode = NULL;
|
|
|
|
PrinterDriverEvent(pIniPrinter, PRINTER_EVENT_INITIALIZE, (LPARAM)NULL, &dwPrnEvntError);
|
|
|
|
//
|
|
// If the driver name changed then convert the devmode to the new driver's
|
|
// devmode. Note this must be done after the printer event initialize
|
|
// because the driver is not able to handle a convert devmode call before
|
|
// being initialized. Also if the conversion fails we potentially end up
|
|
// having the old devmode in the registry. We could null out the devmode
|
|
// but is it better to have a bad old devmode in the registry rather than a null
|
|
// devmode. A null devmode is more dangerous because an application may
|
|
// get really confused with a null devmode rather than a bad devmode
|
|
// which the driver will eventually fix, because they have to handle foreign
|
|
// devmodes any way.
|
|
//
|
|
|
|
EnterSplSem();
|
|
|
|
//
|
|
// Now convert the devmode to the driver specific devmode.
|
|
//
|
|
pDevMode = ConvertDevModeToSpecifiedVersion(pIniPrinter,
|
|
pIniPrinter->pDevMode,
|
|
NULL,
|
|
NULL,
|
|
CURRENT_VERSION);
|
|
|
|
//
|
|
// If a new devmode was returned then release the current printer's
|
|
// devmode and save the new devmode.
|
|
//
|
|
if (pDevMode) {
|
|
|
|
FreeSplMem(pIniPrinter->pDevMode);
|
|
pIniPrinter->pDevMode = pDevMode;
|
|
pIniPrinter->cbDevMode = pDevMode->dmSize + pDevMode->dmDriverExtra;
|
|
}
|
|
|
|
//
|
|
// Write the newly converted devmode to the registry again.
|
|
//
|
|
UpdatePrinterIni( pIniPrinter, UPDATE_CHANGEID );
|
|
|
|
LeaveSplSem();
|
|
}
|
|
|
|
//
|
|
// If the printer attributes changed, call the driver with the two
|
|
// different sets of attributes, this is to allow the fax driver to
|
|
// start up the fax service when a printer gets shared out.
|
|
//
|
|
if (dwPrinterVector & BIT(I_PRINTER_ATTRIBUTES)) {
|
|
|
|
PRINTER_EVENT_ATTRIBUTES_INFO AttributesInfo = {
|
|
sizeof(PRINTER_EVENT_ATTRIBUTES_INFO),
|
|
OldAttributes,
|
|
pIniPrinter->Attributes
|
|
};
|
|
|
|
PrinterDriverEvent(pIniPrinter, PRINTER_EVENT_ATTRIBUTES_CHANGED, (LPARAM)&AttributesInfo, &dwPrnEvntError);
|
|
}
|
|
|
|
EnterSplSem();
|
|
SplInSem();
|
|
DECPRINTERREF(pIniPrinter);
|
|
}
|
|
|
|
|
|
// Don't update if this is from cache
|
|
if (!bDataChanged || ((Level == 2 || Level == 5) && !dwPrinterVector) ||
|
|
(pIniPrinter->pIniSpooler->SpoolerFlags & SPL_TYPE_CACHE)) {
|
|
|
|
bUpdateDsSpoolerKey = FALSE;
|
|
|
|
} else if (bUpdateDsSpoolerKey) {
|
|
|
|
if (Level != 7)
|
|
{
|
|
//
|
|
// Update unly values that changed.
|
|
//
|
|
UpdateDsSpoolerKey(hPrinter, dwPrinterVector);
|
|
|
|
} else if (pPrinterInfo7->dwAction != DSPRINT_UNPUBLISH)
|
|
{
|
|
//
|
|
// Update the all values in Registry for level 7.
|
|
//
|
|
UpdateDsSpoolerKey(hPrinter, 0xffffffff);
|
|
}
|
|
|
|
//
|
|
// Reset Driver DS Properties if driver changed
|
|
//
|
|
if (dwPrinterVector & BIT(I_PRINTER_DRIVER_NAME)) {
|
|
|
|
INCPRINTERREF(pIniPrinter);
|
|
LeaveSplSem();
|
|
|
|
//
|
|
// This calls SetPrinterDs with DSPRINT_UPDATE anyway.
|
|
//
|
|
RecreateDsKey(hPrinter, SPLDS_DRIVER_KEY);
|
|
|
|
EnterSplSem();
|
|
DECPRINTERREF(pIniPrinter);
|
|
|
|
} else if (Level != 7 || pPrinterInfo7->dwAction != DSPRINT_UNPUBLISH) {
|
|
|
|
//
|
|
// If the driver didn't change, query the driver again for capabilities.
|
|
//
|
|
UpdateDsDriverKey(hPrinter);
|
|
}
|
|
}
|
|
|
|
if (bUpdateDsSpoolerKey) {
|
|
if (pIniPrinter->DsKeyUpdateForeground || (Level == 7 && pPrinterInfo7->dwAction == DSPRINT_UNPUBLISH)) {
|
|
if (Level == 7) {
|
|
if ((dwResult = SetPrinterDs(hPrinter, pPrinterInfo7->dwAction, FALSE)) != ERROR_SUCCESS) {
|
|
SetLastError(dwResult);
|
|
bReturn = FALSE;
|
|
}
|
|
} else {
|
|
//
|
|
// Update only, in the background thread.
|
|
//
|
|
SetPrinterDs(hPrinter, DSPRINT_UPDATE, FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
LeaveSplSem();
|
|
SplOutSem();
|
|
|
|
|
|
if ( pDevMode && pDevMode != pPrinterInfo2->pDevMode )
|
|
FreeSplMem(pDevMode);
|
|
|
|
if ( pszOldPrinterName ) {
|
|
FreeSplStr(pszOldPrinterName);
|
|
}
|
|
|
|
FreeSplStr(pszNewPrinterName);
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
|
|
PRINTER_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,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
DWORD dwError;
|
|
WCHAR szValue[4*MAX_PATH];
|
|
|
|
DWORD cchValue;
|
|
|
|
while (TRUE) {
|
|
|
|
cchValue = COUNTOF(szValue);
|
|
dwError = SplRegEnumValue( hKey,
|
|
0,
|
|
szValue,
|
|
&cchValue,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
pIniSpooler );
|
|
|
|
if( dwError != ERROR_SUCCESS ){
|
|
|
|
if( dwError != ERROR_NO_MORE_ITEMS ){
|
|
DBGMSG( DBG_ERROR, ( "RegClearKey: Failed %d\n", dwError ));
|
|
}
|
|
break;
|
|
}
|
|
|
|
dwError = SplRegDeleteValue( hKey, szValue, pIniSpooler );
|
|
|
|
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 bShareRecreate,
|
|
BOOL bShareUpdate
|
|
)
|
|
/*++
|
|
|
|
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 succeeds
|
|
|
|
bShareRecreate - Share must be recreated because the printer or share
|
|
name changed.
|
|
|
|
bShareUpdate - Share just needs to be updated, since comment / SD changed.
|
|
|
|
Return Value:
|
|
|
|
DWORD TRUE on success, FALSE else.
|
|
|
|
--*/
|
|
|
|
{
|
|
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 ( bShareRecreate ) {
|
|
|
|
if (ShareThisPrinter(pIniPrinter,
|
|
pIniPrinter->pShareName,
|
|
FALSE)) {
|
|
|
|
#if DBG
|
|
WCHAR szError[256];
|
|
|
|
StringCchPrintf(szError, COUNTOF(szError), L"Error %d, removing share", GetLastError());
|
|
|
|
//
|
|
// Error: the printer shouldn't be shared at this
|
|
// point.
|
|
//
|
|
|
|
INCPRINTERREF(pIniPrinter);
|
|
|
|
SplLogEvent(pIniSpooler,
|
|
LOG_ERROR,
|
|
MSG_SHARE_FAILED,
|
|
TRUE,
|
|
L"SetLocalPrinter ShareThisPrinter FALSE",
|
|
pIniPrinter->pName,
|
|
pIniPrinter->pShareName,
|
|
szError,
|
|
NULL);
|
|
|
|
DECPRINTERREF(pIniPrinter);
|
|
#endif
|
|
|
|
bReturn = FALSE;
|
|
|
|
} else if (!ShareThisPrinter(pIniPrinter,
|
|
pszNewShareName,
|
|
TRUE)) {
|
|
#if DBG
|
|
WCHAR szError[256];
|
|
|
|
StringCchPrintf(szError, COUNTOF(szError), L"Error %d, adding share", GetLastError());
|
|
|
|
//
|
|
// Error: the printer shouldn't be shared at this
|
|
// point.
|
|
//
|
|
|
|
INCPRINTERREF(pIniPrinter);
|
|
|
|
SplLogEvent(pIniSpooler,
|
|
LOG_ERROR,
|
|
MSG_SHARE_FAILED,
|
|
TRUE,
|
|
L"SetLocalPrinter ShareThisPrinter TRUE",
|
|
pIniPrinter->pName,
|
|
pIniPrinter->pShareName,
|
|
szError,
|
|
NULL);
|
|
|
|
DECPRINTERREF(pIniPrinter);
|
|
#endif
|
|
|
|
pIniPrinter->Attributes &= ~PRINTER_ATTRIBUTE_SHARED;
|
|
pIniPrinter->Status |= PRINTER_WAS_SHARED;
|
|
bReturn = FALSE;
|
|
}
|
|
} else if ( bShareUpdate ) {
|
|
//
|
|
// 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();
|
|
|
|
|
|
} else {
|
|
pIniPrinter->Attributes = dOldAttributes;
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
|
|
if (((dOldAttributes & PRINTER_ATTRIBUTE_WORK_OFFLINE) &&
|
|
!(dNewAttributes & PRINTER_ATTRIBUTE_WORK_OFFLINE) ) ||
|
|
(!(dOldAttributes & PRINTER_ATTRIBUTE_WORK_OFFLINE) &&
|
|
(dNewAttributes & PRINTER_ATTRIBUTE_WORK_OFFLINE) ) ) {
|
|
|
|
WritePrinterOnlineStatusInCurrentConfig(pIniPrinter);
|
|
}
|
|
|
|
|
|
return bReturn;
|
|
}
|
|
|