|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Abstract:
This module provides functionality for ADs within spooler
Author:
Steve Wilson (NT) December 1996
Revision History:
--*/
#include <precomp.h>
#pragma hdrstop
#include "ds.hxx"
#define LOG_EVENT_ERROR_BUFFER_SIZE 11
#define PPM_FACTOR 48
#define LOTS_OF_FORMS 300 // This is a little more than twice the number of built-in forms
extern BOOL gbInDomain; extern BOOL gdwLogDsEvents;
extern "C" HANDLE ghDsUpdateThread; extern "C" DWORD gdwDsUpdateThreadId;
extern "C" BOOL (*pfnOpenPrinter)(LPTSTR, LPHANDLE, LPPRINTER_DEFAULTS); extern "C" BOOL (*pfnClosePrinter)(HANDLE);
extern "C" DWORD SetPrinterDs( HANDLE hPrinter, DWORD dwAction, BOOL bSynchronous ) { PSPOOL pSpool = (PSPOOL) hPrinter; PINIPRINTER pIniPrinter = pSpool->pIniPrinter; HRESULT hr; HANDLE hToken = NULL; PWSTR pszObjectGUID, pszCN, pszDN; DWORD DsKeyUpdate, Attributes; BOOL DoChange = FALSE; NOTIFYVECTOR NotifyVector;
SplInSem();
if (!gbInDomain) return ERROR_DS_UNAVAILABLE;
// Don't allow masquerading printer publishing
if (pSpool->pIniPort && !(pSpool->pIniPort->Status & PP_MONITOR)) return ERROR_INVALID_PARAMETER;
hToken = RevertToPrinterSelf(); // All DS accesses are done by LocalSystem account
// If any of these change we'll update the registry entry
DsKeyUpdate = pIniPrinter->DsKeyUpdate; pszObjectGUID = pIniPrinter->pszObjectGUID; pszCN = pIniPrinter->pszCN; pszDN = pIniPrinter->pszDN; Attributes = pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED;
// Attribute states desired state, not current state
switch (dwAction) { case DSPRINT_UPDATE: if (!(pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED)) { hr = MAKE_HRESULT( SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND);
} else if (bSynchronous) {
// We are in the background thread.
if (pIniPrinter->DsKeyUpdate) { INCPRINTERREF(pIniPrinter); LeaveSplSem(); hr = DsPrinterPublish(hPrinter); EnterSplSem(); DECPRINTERREF(pIniPrinter); } else { hr = ERROR_SUCCESS; } } else {
// Here we are in the foreground thread.
if (pIniPrinter->DsKeyUpdateForeground) { pIniPrinter->Attributes |= PRINTER_ATTRIBUTE_PUBLISHED; pIniPrinter->dwAction = DSPRINT_PUBLISH; hr = ERROR_IO_PENDING; } else { hr = ERROR_SUCCESS; } } break;
case DSPRINT_PUBLISH: if (!(pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED) && PrinterPublishProhibited()) {
// There is a policy against publishing printers from this machine.
hr = MAKE_HRESULT( SEVERITY_ERROR, FACILITY_WIN32, ERROR_ACCESS_DENIED);
} else { if (bSynchronous) { INCPRINTERREF(pIniPrinter); LeaveSplSem(); hr = DsPrinterPublish(hPrinter); EnterSplSem(); DECPRINTERREF(pIniPrinter); } else {
// This is a Pending Unpublish state
if (!(pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED) && pIniPrinter->pszObjectGUID) pIniPrinter->dwAction = DSPRINT_REPUBLISH; else pIniPrinter->dwAction = DSPRINT_PUBLISH;
pIniPrinter->Attributes |= PRINTER_ATTRIBUTE_PUBLISHED; hr = ERROR_IO_PENDING; } } break;
case DSPRINT_REPUBLISH: if (PrinterPublishProhibited()) {
// There is a policy against publishing printers from this machine.
hr = MAKE_HRESULT( SEVERITY_ERROR, FACILITY_WIN32, ERROR_ACCESS_DENIED);
} else { // Synchronous mode is from background thread and it should only call Publish/Unpublish
if (bSynchronous) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_INVALID_PARAMETER); SPLASSERT(FALSE); } else { pIniPrinter->dwAction = DSPRINT_REPUBLISH; pIniPrinter->Attributes |= PRINTER_ATTRIBUTE_PUBLISHED; hr = ERROR_IO_PENDING; } } break;
case DSPRINT_UNPUBLISH: if (bSynchronous) { INCPRINTERREF(pIniPrinter); LeaveSplSem(); hr = DsPrinterUnpublish(hPrinter); EnterSplSem(); DECPRINTERREF(pIniPrinter); } else { pIniPrinter->Attributes &= ~PRINTER_ATTRIBUTE_PUBLISHED; pIniPrinter->dwAction = DSPRINT_UNPUBLISH; hr = ERROR_IO_PENDING; } break;
default: hr = ERROR_INVALID_PARAMETER; break; }
// Update Registry and set notifications
if (pszCN != pIniPrinter->pszCN || pszDN != pIniPrinter->pszDN || pszObjectGUID != pIniPrinter->pszObjectGUID || DsKeyUpdate != pIniPrinter->DsKeyUpdate || Attributes != (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
ZERONV(NotifyVector);
if (pszObjectGUID != pIniPrinter->pszObjectGUID) { NotifyVector[PRINTER_NOTIFY_TYPE] |= BIT(I_PRINTER_OBJECT_GUID); DoChange = TRUE; } if (Attributes != (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED)) { NotifyVector[PRINTER_NOTIFY_TYPE] |= BIT(I_PRINTER_ATTRIBUTES); DoChange = TRUE; } if (DoChange) { UpdatePrinterIni(pIniPrinter, UPDATE_CHANGEID); SetPrinterChange(pIniPrinter, NULL, NotifyVector, PRINTER_CHANGE_SET_PRINTER, pIniPrinter->pIniSpooler);
} else if (DsKeyUpdate != pIniPrinter->DsKeyUpdate) { UpdatePrinterIni(pIniPrinter, UPDATE_DS_ONLY); } }
SplInSem();
if (hr == ERROR_IO_PENDING && !bSynchronous) SpawnDsUpdate(1);
if (hToken) ImpersonatePrinterClient(hToken);
return (DWORD) hr; }
HRESULT DsPrinterPublish( HANDLE hPrinter ) { HRESULT hr; PSPOOL pSpool = (PSPOOL) hPrinter; PINIPRINTER pIniPrinter = pSpool->pIniPrinter; WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE]; BOOL bUpdating = !!pIniPrinter->pszObjectGUID; DWORD dwDsKeyUpdate;
SplOutSem();
#if DBG
EnterSplSem(); DBGMSG( DBG_EXEC, ("DsPrinterPublish: %ws\n", pIniPrinter->pName)); LeaveSplSem(); #endif
// On first publish update all keys and tell the driver to write its non-devcap properties
if (!bUpdating) {
// We execute this on the background thread and hence donot need any
// to be in the critical section.
pIniPrinter->DsKeyUpdate |= DS_KEY_PUBLISH | DS_KEY_SPOOLER | DS_KEY_DRIVER | DS_KEY_USER; }
// Update DS properties
dwDsKeyUpdate = pIniPrinter->DsKeyUpdate & (DS_KEY_SPOOLER | DS_KEY_DRIVER | DS_KEY_USER); hr = DsPrinterUpdate(hPrinter); BAIL_ON_FAILURE(hr); DBGMSG( DBG_EXEC, ("PublishDsUpdate: Printer Updated\n" ) );
error:
if (SUCCEEDED(hr)) { // Only write a success event if something changed
if (dwDsKeyUpdate != pIniPrinter->DsKeyUpdate) { SplLogEvent( pIniPrinter->pIniSpooler, gdwLogDsEvents & LOG_INFO, bUpdating ? MSG_PRINTER_UPDATED : MSG_PRINTER_PUBLISHED, FALSE, pIniPrinter->pszCN, pIniPrinter->pszDN, NULL ); } } else if (pIniPrinter->pszCN && pIniPrinter->pszDN) { wsprintf(ErrorBuffer, L"%x", hr); SplLogEvent( pIniPrinter->pIniSpooler, gdwLogDsEvents & LOG_ERROR, MSG_PRINTER_NOT_PUBLISHED, FALSE, pIniPrinter->pszCN, pIniPrinter->pszDN, ErrorBuffer, NULL ); }
if (pIniPrinter->DsKeyUpdate) hr = ERROR_IO_PENDING;
return hr; }
HRESULT DsPrinterUpdate( HANDLE hPrinter ) { PSPOOL pSpool = (PSPOOL) hPrinter; PINIPRINTER pIniPrinter = pSpool->pIniPrinter; HRESULT hr = S_OK; DWORD dwResult; BOOL bImpersonating = FALSE; IADs *pADs = NULL;
SplOutSem();
if(!(pIniPrinter->DsKeyUpdate & (DS_KEY_SPOOLER | DS_KEY_DRIVER | DS_KEY_USER))) { pIniPrinter->DsKeyUpdate = 0; }
// If we aren't truly published yet, be sure to publish mandatory properties first!
if (!pIniPrinter->pszObjectGUID) { //
// Fail if we're on a cluster but couldn't get the Cluster GUID
// The Cluster GUID is required later in AddClusterAce
//
if ((pIniPrinter->pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG) && !pIniPrinter->pIniSpooler->pszClusterGUID) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_CLUSTER_NO_SECURITY_CONTEXT); BAIL_ON_FAILURE(hr); }
// Get or Create printQueue object
hr = GetPrintQueue(hPrinter, &pADs); BAIL_ON_FAILURE(hr);
hr = PublishMandatoryProperties(hPrinter, pADs); BAIL_ON_FAILURE(hr);
} else {
// If we are a Cluster, impersonate the Cluster User
if (pIniPrinter->pIniSpooler->hClusterToken != INVALID_HANDLE_VALUE) { // Impersonate the client
if (!ImpersonatePrinterClient(pIniPrinter->pIniSpooler->hClusterToken)) { dwResult = GetLastError(); DBGMSG(DBG_WARNING,("DsPrinterPublish FAILED: %d\n", dwResult)); hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult); BAIL_ON_FAILURE(hr); } bImpersonating = TRUE; }
// Get or Create printQueue object
hr = GetPrintQueue(hPrinter, &pADs); BAIL_ON_FAILURE(hr); }
// Update User - updates from Registry
//
// CopyRegistry2Ds for DS_KEY_USER values must
// be called in the first place since there could be duplicate values
// that might overwrite properties contained by either
// DS_KEY_SPOOLER or DS_KEY_DRIVER.
// Ignore the return value since publishing of DS_KEY_USER values
// is not critical
//
if (pIniPrinter->DsKeyUpdate & DS_KEY_USER) { CopyRegistry2Ds(hPrinter, DS_KEY_USER, pADs); }
// Update Spooler - updates from Registry
if (pIniPrinter->DsKeyUpdate & DS_KEY_SPOOLER) { hr = CopyRegistry2Ds(hPrinter, DS_KEY_SPOOLER, pADs); BAIL_ON_FAILURE(hr); }
// Update Driver - updates from Registry
if (pIniPrinter->DsKeyUpdate & DS_KEY_DRIVER) { hr = CopyRegistry2Ds(hPrinter, DS_KEY_DRIVER, pADs);
// Ignore missing key
if (HRESULT_CODE(hr) == ERROR_FILE_NOT_FOUND) hr = S_OK;
BAIL_ON_FAILURE(hr); }
error:
if (pADs) pADs->Release();
if (bImpersonating) pIniPrinter->pIniSpooler->hClusterToken = RevertToPrinterSelf();
return hr; }
HRESULT DsDeletePQObject( HANDLE hPrinter ) { PSPOOL pSpool = (PSPOOL) hPrinter; PINIPRINTER pIniPrinter = pSpool->pIniPrinter; IADsContainer *pADsContainer = NULL; IADs *pADs = NULL; HRESULT hr = E_FAIL; WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE]; BOOL bImpersonating = FALSE; DWORD dwError;
//
// This routine is called when AddClusterAce failed. Even if we faild deleteing the object,
// we really want to clean up the pIniPrinter structure so that we prevent the case where
// the object stays forever in pending un/publishing.
// That's because the other cluster node fails to delete/update it
// since the printQueue object doesn't have the cluster user ace added. Pruner also fails to delete it
// since the PrintQueue's GUID matches the pIniPrinter's GUID.
//
SplOutSem();
hr = GetPrintQueueContainer(hPrinter, &pADsContainer, &pADs); BAIL_ON_FAILURE(hr);
// Delete Printer Object
hr = pADsContainer->Delete(SPLDS_PRINTER_CLASS, pIniPrinter->pszCN); DBGMSG(DBG_EXEC,("DsPrinterUnpublish FAILED: %x, %ws\n", hr, pIniPrinter->pszCN)); BAIL_ON_FAILURE(hr);
error:
if (pADs) pADs->Release();
if (pADsContainer) pADsContainer->Release();
pIniPrinter->DsKeyUpdate = 0;
FreeSplStr(pIniPrinter->pszObjectGUID); pIniPrinter->pszObjectGUID = NULL;
FreeSplStr(pIniPrinter->pszCN); pIniPrinter->pszCN = NULL;
FreeSplStr(pIniPrinter->pszDN); pIniPrinter->pszDN = NULL;
return hr; }
HRESULT DsPrinterUnpublish( HANDLE hPrinter ) { PSPOOL pSpool = (PSPOOL) hPrinter; PINIPRINTER pIniPrinter = pSpool->pIniPrinter; IADsContainer *pADsContainer = NULL; IADs *pADs = NULL; HRESULT hr = E_FAIL; WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE]; BOOL bImpersonating = FALSE; DWORD dwError;
SplOutSem();
// If we are a Cluster, impersonate the Cluster User
if (pIniPrinter->pIniSpooler->hClusterToken != INVALID_HANDLE_VALUE) { // Impersonate the client
if (!ImpersonatePrinterClient(pIniPrinter->pIniSpooler->hClusterToken)) { dwError = GetLastError(); DBGMSG(DBG_WARNING,("DsPrinterUnpublish FAILED: %d\n", dwError)); hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwError); goto error; } bImpersonating = TRUE; }
hr = GetPrintQueueContainer(hPrinter, &pADsContainer, &pADs); BAIL_ON_FAILURE(hr);
// Delete Printer Object
hr = pADsContainer->Delete(SPLDS_PRINTER_CLASS, pIniPrinter->pszCN); DBGMSG(DBG_EXEC,("DsPrinterUnpublish FAILED: %x, %ws\n", hr, pIniPrinter->pszCN)); BAIL_ON_FAILURE(hr);
error:
if (bImpersonating) pIniPrinter->pIniSpooler->hClusterToken = RevertToPrinterSelf();
if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT) || HRESULT_CODE(hr) == ERROR_FILE_NOT_FOUND || HRESULT_CODE(hr) == ERROR_PATH_NOT_FOUND) { hr = S_OK; SplLogEvent( pIniPrinter->pIniSpooler, gdwLogDsEvents & LOG_INFO, MSG_MISSING_PRINTER_UNPUBLISHED, FALSE, pIniPrinter->pName, NULL );
} else if (SUCCEEDED(hr)) { SplLogEvent( pIniPrinter->pIniSpooler, gdwLogDsEvents & LOG_INFO, MSG_PRINTER_UNPUBLISHED, FALSE, pIniPrinter->pszCN, pIniPrinter->pszDN, NULL );
} else if(pIniPrinter->pszCN && pIniPrinter->pszDN) { wsprintf(ErrorBuffer, L"%x", hr); SplLogEvent( pIniPrinter->pIniSpooler, gdwLogDsEvents & LOG_ERROR, MSG_CANT_DELETE_PRINTQUEUE, FALSE, pIniPrinter->pszCN, pIniPrinter->pszDN, ErrorBuffer, NULL ); }
if (SUCCEEDED(hr)) { pIniPrinter->DsKeyUpdate = 0;
FreeSplStr(pIniPrinter->pszObjectGUID); pIniPrinter->pszObjectGUID = NULL;
FreeSplStr(pIniPrinter->pszCN); pIniPrinter->pszCN = NULL;
FreeSplStr(pIniPrinter->pszDN); pIniPrinter->pszDN = NULL;
} else { pIniPrinter->DsKeyUpdate = DS_KEY_UNPUBLISH; }
if (pADs) pADs->Release();
if (pADsContainer) pADsContainer->Release();
if (pIniPrinter->DsKeyUpdate) hr = ERROR_IO_PENDING;
return hr; }
LPCWSTR MapDSFlag2DSKey( DWORD Flag ) { DWORD idx; LPCWSTR pKey = NULL;
struct DSEntry { DWORD Flag; LPCWSTR pKey; };
static DSEntry DSKeys [] = { {DS_KEY_SPOOLER , SPLDS_SPOOLER_KEY}, {DS_KEY_DRIVER , SPLDS_DRIVER_KEY}, {DS_KEY_USER , SPLDS_USER_KEY}, {0 , NULL}, };
for (idx = 0; DSKeys[idx].pKey; idx++) { if(DSKeys[idx].Flag & Flag) { pKey = DSKeys[idx].pKey; } } return pKey; }
HRESULT CopyRegistry2Ds( HANDLE hPrinter, DWORD Flag, IADs *pADs ) { HRESULT hr = ERROR_SUCCESS; DWORD i; DWORD dwLDAPError; DWORD cbEnumValues = 0; PPRINTER_ENUM_VALUES pEnumValues = NULL; DWORD nEnumValues; DWORD dwResult; WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE]; BSTR bstrADsPath = NULL; PINIPRINTER pIniPrinter = ((PSPOOL)hPrinter)->pIniPrinter; LPCWSTR pKey = MapDSFlag2DSKey(Flag);
#if DBG
EnterSplSem(); DBGMSG(DBG_EXEC, ("Mass Publish %ws", ((PSPOOL)hPrinter)->pIniPrinter->pName)); LeaveSplSem(); #endif
// Enumerate and Publish Key
dwResult = SplEnumPrinterDataEx( hPrinter, pKey, (LPBYTE) pEnumValues, cbEnumValues, &cbEnumValues, &nEnumValues );
if (dwResult != ERROR_MORE_DATA) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult); if( HRESULT_CODE(hr) == ERROR_FILE_NOT_FOUND && Flag != DS_KEY_SPOOLER) { goto IgnoreError; } else { goto error; } }
if (!(pEnumValues = (PPRINTER_ENUM_VALUES) AllocSplMem(cbEnumValues))) { DBGMSG(DBG_EXEC,("CopyRegistry2Ds EnumPrinterDataEx FAILED: %d\n", GetLastError())); hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); BAIL_ON_FAILURE(hr); }
dwResult = SplEnumPrinterDataEx( hPrinter, pKey, (LPBYTE) pEnumValues, cbEnumValues, &cbEnumValues, &nEnumValues ); if (dwResult != ERROR_SUCCESS) { DBGMSG(DBG_EXEC,("CopyRegistry2Ds 2nd EnumPrinterDataEx FAILED: %d\n", GetLastError())); hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult); if( HRESULT_CODE(hr) == ERROR_FILE_NOT_FOUND && Flag != DS_KEY_SPOOLER) { goto IgnoreError; } else { goto error; } }
// Mass publish
for (i = 0 ; i < nEnumValues ; ++i) {
hr = PublishDsData( pADs, pEnumValues[i].pValueName, pEnumValues[i].dwType, (PBYTE) pEnumValues[i].pData);
// Don't bail out on failure to put a specific property
if (FAILED(hr)) { if (pEnumValues[i].pValueName) { DBGMSG(DBG_EXEC, ("Put property failed: %x, %ws\n", hr, pEnumValues[i].pValueName)); } else { DBGMSG(DBG_EXEC, ("Put property failed: %x\n", hr)); } } else { DBGMSG(DBG_EXEC, ("Put %ws succeeded\n", pEnumValues[i].pValueName)); } }
hr = pADs->SetInfo();
// Mass publishing failed, now try Setting on every Put
if (SUCCEEDED(hr)) {
DBGMSG( DBG_EXEC, ("Mass Publishing Succeeded for %ws\n", pKey) );
} else {
if (HRESULT_CODE(hr) == ERROR_EXTENDED_ERROR) ADsGetLastError(&dwLDAPError, NULL, 0, NULL, 0); else dwLDAPError = hr;
DBGMSG( DBG_EXEC, ("Mass Publishing FAILED for %ws: %x\n", pKey, dwLDAPError) );
// Now we have to try SetInfo/GetInfo on every Put.
// If the DS lacks a spooler property, then the spooler will never
// be able to publish any properties. Also, we'll fail if duplicate
// strings exist in REG_MULTISZ attributes.
// Maybe it is better to publish what we can,
// but this requires calling SetInfo() for every property, which defeats the cache.
// Alternatively, we could try doing the single SetInfo once and if that fails, resort
// to the SetInfo on every Put.
// Additionally, when SetInfo fails it is necessary to call GetInfo on that property
// in order to clear the cache's update flag for the property. When SetInfo fails
// it does not clear the update flag: the update flag is only cleared when SetInfo
// succeeds. Not calling GetInfo will result in SetInfo() errors on all subsequent
// attempts to publish a property.
// Refresh the cache
hr = pADs->GetInfo(); BAIL_ON_FAILURE(hr);
for (i = 0 ; i < nEnumValues ; ++i) {
hr = PublishDsData( pADs, pEnumValues[i].pValueName, pEnumValues[i].dwType, (PBYTE) pEnumValues[i].pData);
// Don't bail out on failure to put a specific property
if (FAILED(hr)) { if (pEnumValues[i].pValueName) { DBGMSG(DBG_EXEC, ("Put property failed: %x, %ws\n", hr, pEnumValues[i].pValueName)); } else { DBGMSG(DBG_EXEC, ("Put property failed: %x\n", hr)); }
wsprintf(ErrorBuffer, L"%x", hr); hr = pADs->get_ADsPath(&bstrADsPath); if (SUCCEEDED(hr)) { SplLogEvent( ((PSPOOL) hPrinter)->pIniSpooler, gdwLogDsEvents & LOG_WARNING, MSG_CANT_PUBLISH_PROPERTY, FALSE, pEnumValues[i].pValueName ? pEnumValues[i].pValueName : L"NULLName", bstrADsPath, ErrorBuffer, NULL ); SysFreeString(bstrADsPath); } } else { DBGMSG(DBG_EXEC, ("Put2 %ws succeeded\n", pEnumValues[i].pValueName)); }
hr = pADs->SetInfo(); if (FAILED(hr)) {
if (HRESULT_CODE(hr) == ERROR_EXTENDED_ERROR) ADsGetLastError(&dwLDAPError, NULL, 0, NULL, 0);
if (pEnumValues[i].dwType == REG_SZ) DBGMSG(DBG_EXEC, ("PUBLISH FAILED: %ws, \"%ws\", %x\n", pEnumValues[i].pValueName, (LPWSTR) pEnumValues[i].pData, dwLDAPError)); else DBGMSG(DBG_EXEC, ("PUBLISH FAILED: %ws, %x\n", pEnumValues[i].pValueName, dwLDAPError));
wsprintf(ErrorBuffer, L"%x", hr); hr = pADs->get_ADsPath(&bstrADsPath); if (SUCCEEDED(hr)) { SplLogEvent( ((PSPOOL) hPrinter)->pIniSpooler, gdwLogDsEvents & LOG_WARNING, MSG_CANT_PUBLISH_PROPERTY, FALSE, pEnumValues[i].pValueName ? pEnumValues[i].pValueName : L"NULLName", bstrADsPath, ErrorBuffer, NULL ); SysFreeString(bstrADsPath); }
// reset cache update flag
// If this fails, there's nothing more that can be done except throw our hands up
// in despair. If this fails, no spooler properties will ever be published.
hr = pADs->GetInfo(); BAIL_ON_FAILURE(hr); } else { DBGMSG( DBG_EXEC, ("Published: %ws\n", pEnumValues[i].pValueName) ); } } }
IgnoreError:
EnterSplSem(); pIniPrinter->DsKeyUpdate &= ~Flag;
if(!(pIniPrinter->DsKeyUpdate & (DS_KEY_SPOOLER | DS_KEY_DRIVER | DS_KEY_USER))) { pIniPrinter->DsKeyUpdate = 0; } LeaveSplSem();
error:
FreeSplMem(pEnumValues);
return hr; }
HRESULT PublishDsData( IADs *pADs, LPWSTR pValue, DWORD dwType, PBYTE pData ) { HRESULT hr; BOOL bCreated = FALSE;
switch (dwType) { case REG_SZ: hr = put_BSTR_Property(pADs, pValue, (LPWSTR) pData); break;
case REG_MULTI_SZ: hr = put_MULTISZ_Property(pADs, pValue, (LPWSTR) pData); break;
case REG_DWORD: hr = put_DWORD_Property(pADs, pValue, (DWORD *) pData); break;
case REG_BINARY: hr = put_BOOL_Property(pADs, pValue, (BOOL *) pData); break; }
return hr; }
HRESULT PublishMandatoryProperties( HANDLE hPrinter, IADs *pADs ) { PSPOOL pSpool = (PSPOOL) hPrinter; PINIPRINTER pIniPrinter = pSpool->pIniPrinter; HRESULT hr, hrAce; WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE];
#if DBG
EnterSplSem(); DBGMSG(DBG_EXEC, ("PublishMandatoryProperties: %ws\n", pIniPrinter->pName)); LeaveSplSem(); #endif
hr = SetMandatoryProperties(hPrinter, pADs);
DBGMSG(DBG_EXEC, ("PublishMandatoryProperties: SMP result %d\n", hr)); BAIL_ON_FAILURE(hr);
// New Schema has correct SD by default, so no need to call PutDSSD
// hr = PutDSSD(pIniPrinter, pADs);
hr = pADs->SetInfo();
if (FAILED(hr)) {
DBGMSG(DBG_EXEC, ("PublishMandatoryProperties: SetInfo failed %d\n", hr));
wsprintf(ErrorBuffer, L"%x", hr); SplLogEvent( pSpool->pIniSpooler, gdwLogDsEvents & LOG_ERROR, MSG_CANT_PUBLISH_MANDATORY_PROPERTIES, FALSE, pIniPrinter->pszCN, pIniPrinter->pszDN, ErrorBuffer, NULL );
// If SetInfo returns ERROR_BUSY it means the object already exists.
// We should have avoided this conflict when we created the CN because
// we check for conflicts and generate a random name. Nonetheless, an
// object could have appeared between the time we generated the CN and this SetInfo,
// so failing here will let us try again and we'll generate a new name if we clear the
// current one.
if (HRESULT_CODE(hr) == ERROR_BUSY) { FreeSplMem(pIniPrinter->pszCN); pIniPrinter->pszCN = NULL; FreeSplMem(pIniPrinter->pszDN); pIniPrinter->pszDN = NULL; }
BAIL_ON_FAILURE(hr); }
// Get & Set ACE if we're a cluster
hrAce = AddClusterAce(pSpool, pADs);
// Get & store GUID
hr = GetGUID(pADs, &pIniPrinter->pszObjectGUID);
//
// Keep the first failure, if present
//
if (FAILED(hrAce)) { hr = hrAce; wsprintf(ErrorBuffer, L"%x", hrAce); SplLogEvent( pSpool->pIniSpooler, gdwLogDsEvents & LOG_ERROR, MSG_CANT_ADD_CLUSTER_ACE, FALSE, pIniPrinter->pszCN, pIniPrinter->pszDN, ErrorBuffer, NULL ); DsDeletePQObject(hPrinter); DBGMSG(DBG_EXEC, ("PublishMandatoryProperties: AddClusterAce failed %d\n", hr)); BAIL_ON_FAILURE(hr); }
//
// Unpublish if we can't add the cluster ace or get the GUID
// If we can't get the GUID, unpublishing will fail, but internal flags
// will be set correctly and pruner will delete the orphan
//
if (FAILED(hr)){ DsPrinterUnpublish(hPrinter); DBGMSG(DBG_EXEC, ("PublishMandatoryProperties: GetGuid failed %d\n", hr)); BAIL_ON_FAILURE(hr);
} else { DBGMSG(DBG_EXEC, ("PublishMandatoryProperties: GetGuid success %ws\n", pIniPrinter->pszObjectGUID)); }
error:
if (FAILED(hr)) { pIniPrinter->Attributes &= ~PRINTER_ATTRIBUTE_PUBLISHED; }
return hr; }
HRESULT SetMandatoryProperties( HANDLE hPrinter, IADs *pADs ) { PSPOOL pSpool = (PSPOOL) hPrinter; PINIPRINTER pIniPrinter = pSpool->pIniPrinter; WCHAR szBuffer[MAX_UNC_PRINTER_NAME + 1]; DWORD dwResult; DWORD dwTemp; HRESULT hr; PWSTR pszServerName = NULL;
// Get FQDN of this machine
hr = GetDNSMachineName(pIniPrinter->pIniSpooler->pMachineName + 2, &pszServerName); BAIL_ON_FAILURE(hr);
// UNC Printer Name
// Build the UNC Printer Path
wcscpy(szBuffer, L"\\\\"); wcscat(szBuffer, pszServerName); wcscat(szBuffer, TEXT("\\")); wcscat(szBuffer, pIniPrinter->pName); dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_SPOOLER_KEY, SPLDS_UNC_NAME, REG_SZ, (PBYTE) szBuffer, (wcslen(szBuffer) + 1)*sizeof *szBuffer); if (dwResult != ERROR_SUCCESS) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult); BAIL_ON_FAILURE(hr); }
if (pADs) { hr = PublishDsData( pADs, SPLDS_UNC_NAME, REG_SZ, (PBYTE) szBuffer); BAIL_ON_FAILURE(hr); }
// versionNumber
dwTemp = DS_PRINTQUEUE_VERSION_WIN2000; dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_SPOOLER_KEY, SPLDS_VERSION_NUMBER, REG_DWORD, (PBYTE) &dwTemp, sizeof dwTemp); if (dwResult != ERROR_SUCCESS) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult); BAIL_ON_FAILURE(hr); }
if (pADs) { hr = PublishDsData( pADs, SPLDS_VERSION_NUMBER, REG_DWORD, (PBYTE) &dwTemp); BAIL_ON_FAILURE(hr); }
// ServerName (without \\)
dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_SPOOLER_KEY, SPLDS_SERVER_NAME, REG_SZ, (PBYTE) pszServerName, (wcslen(pszServerName) + 1)*sizeof(WCHAR)); if (dwResult != ERROR_SUCCESS) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult); BAIL_ON_FAILURE(hr); }
if (pADs) { hr = PublishDsData( pADs, SPLDS_SERVER_NAME, REG_SZ, (PBYTE) pszServerName); BAIL_ON_FAILURE(hr); }
// ShortServerName (without \\)
dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_SPOOLER_KEY, SPLDS_SHORT_SERVER_NAME, REG_SZ, (PBYTE) (pIniPrinter->pIniSpooler->pMachineName + 2), (wcslen(pIniPrinter->pIniSpooler->pMachineName + 2) + 1)*sizeof(WCHAR)); if (dwResult != ERROR_SUCCESS) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult); BAIL_ON_FAILURE(hr); }
if (pADs) { hr = PublishDsData( pADs, SPLDS_SHORT_SERVER_NAME, REG_SZ, (PBYTE) pIniPrinter->pIniSpooler->pMachineName + 2); BAIL_ON_FAILURE(hr); }
// printerName
dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_SPOOLER_KEY, SPLDS_PRINTER_NAME, REG_SZ, (PBYTE) pIniPrinter->pName, pIniPrinter->pName ? (wcslen(pIniPrinter->pName) + 1)*sizeof *pIniPrinter->pName : 0); if (dwResult != ERROR_SUCCESS) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult); BAIL_ON_FAILURE(hr); }
if (pADs) { hr = PublishDsData( pADs, SPLDS_PRINTER_NAME, REG_SZ, (PBYTE) pIniPrinter->pName); BAIL_ON_FAILURE(hr); }
error:
FreeSplStr(pszServerName);
return hr; }
// UpdateDsSpoolerKey - writes IniPrinter to registry
VOID UpdateDsSpoolerKey( HANDLE hPrinter, DWORD dwVector ) { PSPOOL pSpool = (PSPOOL) hPrinter; PINIPRINTER pIniPrinter = pSpool->pIniPrinter; DWORD i, cbBytes, dwTemp; LPWSTR pString = NULL, pStr; DWORD dwResult = ERROR_SUCCESS; BOOL bSet = FALSE; BYTE Byte; PWSTR pszUrl = NULL;
SplInSem();
// *** PRINTER_INFO_2 properties ***
// Description
if (dwVector & BIT(I_PRINTER_COMMENT)) { dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_SPOOLER_KEY, SPLDS_DESCRIPTION, REG_SZ, (PBYTE) pIniPrinter->pComment, pIniPrinter->pComment ? (wcslen(pIniPrinter->pComment) + 1)*sizeof *pIniPrinter->pComment : 0); bSet = TRUE; #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: Description, %x\n", dwResult) ); #endif
}
// Driver-Name
if (dwVector & BIT(I_PRINTER_DRIVER_NAME)) { dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_SPOOLER_KEY, SPLDS_DRIVER_NAME, REG_SZ, (PBYTE) pIniPrinter->pIniDriver->pName, pIniPrinter->pIniDriver->pName ? (wcslen(pIniPrinter->pIniDriver->pName) + 1)*sizeof *pIniPrinter->pIniDriver->pName : 0); bSet = TRUE; #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: DriverName, %x\n", dwResult) ); #endif
}
// Location
if (dwVector & BIT(I_PRINTER_LOCATION)) { dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_SPOOLER_KEY, SPLDS_LOCATION, REG_SZ, (PBYTE) pIniPrinter->pLocation, pIniPrinter->pLocation ? (wcslen(pIniPrinter->pLocation) + 1)*sizeof *pIniPrinter->pLocation : 0); bSet = TRUE; #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: Location, %x\n", dwResult) ); #endif
}
// portName
if (dwVector & BIT(I_PRINTER_PORT_NAME)) {
for(i = cbBytes = 0 ; i < pIniPrinter->cPorts ; ++i) cbBytes += (wcslen(pIniPrinter->ppIniPorts[i]->pName) + 1)*sizeof(WCHAR); cbBytes += sizeof(WCHAR); // final NULL of MULTI_SZ
if (!(pString = (LPWSTR) AllocSplMem(cbBytes))) { dwResult = GetLastError(); goto error; }
for(i = 0, pStr = pString ; i < pIniPrinter->cPorts ; ++i, pStr += wcslen(pStr) + 1) wcscpy(pStr, pIniPrinter->ppIniPorts[i]->pName);
dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_SPOOLER_KEY, SPLDS_PORT_NAME, REG_MULTI_SZ, (PBYTE) pString, cbBytes);
bSet = TRUE; #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: PortName, %x\n", dwResult) ); #endif
}
// startTime
if (dwVector & BIT(I_PRINTER_START_TIME)) { dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_SPOOLER_KEY, SPLDS_PRINT_START_TIME, REG_DWORD, (PBYTE) &pIniPrinter->StartTime, sizeof pIniPrinter->StartTime); bSet = TRUE; #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: StartTime, %x\n", dwResult) ); #endif
}
// endTime
if (dwVector & BIT(I_PRINTER_UNTIL_TIME)) { dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_SPOOLER_KEY, SPLDS_PRINT_END_TIME, REG_DWORD, (PBYTE) &pIniPrinter->UntilTime, sizeof pIniPrinter->UntilTime); bSet = TRUE; #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: EndTime, %x\n", dwResult) ); #endif
}
// printerName
if (dwVector & BIT(I_PRINTER_PRINTER_NAME)) { dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_SPOOLER_KEY, SPLDS_PRINTER_NAME, REG_SZ, (PBYTE) pIniPrinter->pName, pIniPrinter->pName ? (wcslen(pIniPrinter->pName) + 1)*sizeof *pIniPrinter->pName : 0); bSet = TRUE; #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: PrinterName, %x\n", dwResult) ); #endif
}
// keepPrintedJobs
if (dwVector & BIT(I_PRINTER_ATTRIBUTES)) { Byte = (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS) ? 1 : 0; dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_SPOOLER_KEY, SPLDS_PRINT_KEEP_PRINTED_JOBS, REG_BINARY, &Byte, sizeof Byte); bSet = TRUE; #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: KeepPrintedJobs, %x\n", dwResult) ); #endif
}
// printSeparatorFile
if (dwVector & BIT(I_PRINTER_SEPFILE)) { dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_SPOOLER_KEY, SPLDS_PRINT_SEPARATOR_FILE, REG_SZ, (PBYTE) pIniPrinter->pSepFile, pIniPrinter->pSepFile ? (wcslen(pIniPrinter->pSepFile) + 1)*sizeof *pIniPrinter->pSepFile : 0); bSet = TRUE; #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: SeparatorFile, %x\n", dwResult) ); #endif
}
// printShareName
if (dwVector & BIT(I_PRINTER_SHARE_NAME)) { dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_SPOOLER_KEY, SPLDS_PRINT_SHARE_NAME, REG_SZ, (PBYTE) pIniPrinter->pShareName, pIniPrinter->pShareName ? (wcslen(pIniPrinter->pShareName) + 1)*sizeof *pIniPrinter->pShareName : 0); bSet = TRUE; #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: ShareName, %x\n", dwResult) ); #endif
}
// printSpooling
if (dwVector & BIT(I_PRINTER_ATTRIBUTES)) { if (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_DIRECT) { pStr = L"PrintDirect"; } else if (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST) { pStr = L"PrintAfterSpooled"; } else { pStr = L"PrintWhileSpooling"; }
dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_SPOOLER_KEY, SPLDS_PRINT_SPOOLING, REG_SZ, (PBYTE) pStr, (wcslen(pStr) + 1)*sizeof *pStr); bSet = TRUE; #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: PrintSpooling, %x\n", dwResult) ); #endif
}
// priority
if (dwVector & BIT(I_PRINTER_PRIORITY)) { dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_SPOOLER_KEY, SPLDS_PRIORITY, REG_DWORD, (PBYTE) &pIniPrinter->Priority, sizeof pIniPrinter->Priority); bSet = TRUE; #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: Priority, %x\n", dwResult) ); #endif
}
// Non-Info2 properties
if (bSet) {
SetMandatoryProperties(hPrinter, NULL);
// URL
if (pszUrl = GetPrinterUrl(pSpool)) { dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_SPOOLER_KEY, SPLDS_URL, REG_SZ, (PBYTE) pszUrl, (wcslen(pszUrl) + 1)*sizeof *pszUrl); #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: URL, %x\n", dwResult) ); #endif
}
// Immortal
dwResult = ImmortalPolicy(); dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_SPOOLER_KEY, SPLDS_FLAGS, REG_DWORD, (PBYTE) &dwResult, sizeof(dwResult)); #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: Immortal, %x\n", dwResult) ); #endif
}
error:
FreeSplMem(pszUrl); FreeSplMem(pString); }
VOID UpdateDsDriverKey( HANDLE hPrinter ) { PSPOOL pSpool = (PSPOOL) hPrinter; PINIPRINTER pIniPrinter = pSpool->pIniPrinter; DWORD i, cbBytes; WCHAR szBuffer[33]; // Used by ltow
LPWSTR pString, pStr; BOOL bResult; DWORD dwResult; BYTE Byte; LPWSTR pOutput = NULL, pTemp = NULL, pTemp1 = NULL; DWORD cOutputBytes, cTempBytes; POINTS point; DWORD dwServerMajorVersion, dwServerMinorVersion; DWORD cbNeeded; HANDLE hModule = FALSE; PDEVCAP pDevCap; PSPLDEVCAP pSplDevCaps; HANDLE hDevCapPrinter = NULL; WCHAR pPrinterName[MAX_UNC_PRINTER_NAME]; WCHAR pBuf[100]; BOOL bInSplSem = TRUE; DWORD dwTemp, dwPrintRate, dwPrintRateUnit, dwPrintPPM;
// *** DeviceCapability properties ***
SplInSem();
DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: %ws\n", pIniPrinter->pName));
pOutput = (LPWSTR) AllocSplMem(cOutputBytes = 200); if (!pOutput) goto error;
pTemp = (LPWSTR) AllocSplMem(cTempBytes = 200); if (!pTemp) goto error;
// Get & Load Driver
PINIENVIRONMENT pIniEnvironment;
pIniEnvironment = FindEnvironment(szEnvironment, pSpool->pIniSpooler);
if (pIniEnvironment) {
WCHAR szConfigFile[INTERNET_MAX_HOST_NAME_LENGTH + MAX_PATH + 1]; PINIVERSION pIniVersion;
pIniVersion = FindVersionForDriver(pIniEnvironment, pIniPrinter->pIniDriver); if (!pIniVersion) goto error;
if( !(i = GetDriverVersionDirectory(szConfigFile, (DWORD)(COUNTOF(szConfigFile) - wcslen(pIniPrinter->pIniDriver->pConfigFile) - 1), pSpool->pIniSpooler, pIniEnvironment, pIniVersion, pIniPrinter->pIniDriver, NULL)) ) { goto error; }
szConfigFile[i++] = L'\\'; wcscpy(szConfigFile + i, pIniPrinter->pIniDriver->pConfigFile);
if (!(hModule = LoadLibrary(szConfigFile))) { goto error; }
if (!(pDevCap = reinterpret_cast<PDEVCAP>(GetProcAddress(hModule, "DrvDeviceCapabilities")))) { goto error; }
pSplDevCaps = reinterpret_cast<PSPLDEVCAP>(GetProcAddress(hModule, (LPCSTR) MAKELPARAM(254, 0)));
} else { goto error; }
DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: driver found\n"));
INCPRINTERREF(pIniPrinter);
// We need to use UNC format so we go to the right pIniSpooler.
// For instance, we won't find the printer if it's in the cluster pIniSpooler and we don't use
// the virtual cluster name (\\server\printer).
wsprintf(pPrinterName, L"%s\\%s", pIniPrinter->pIniSpooler->pMachineName, pIniPrinter->pName); LeaveSplSem(); bInSplSem = FALSE;
if (!(*pfnOpenPrinter)(pPrinterName, &hDevCapPrinter, NULL)) { dwResult = GetLastError(); DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: OpenPrinter failed %d\n", dwResult));
goto error; }
// printBinNames
if (!DevCapMultiSz( hPrinter, hDevCapPrinter, pDevCap, NULL, pPrinterName, DC_BINNAMES, 24, SPLDS_PRINT_BIN_NAMES)) { DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_BINNAMES failed %d\n", GetLastError())); }
// printCollate (awaiting DC_COLLATE)
_try { dwResult = (*pDevCap)( hDevCapPrinter, pPrinterName, DC_COLLATE, NULL, NULL); } _except(1) { SetLastError(GetExceptionCode()); dwResult = GDI_ERROR; } if (dwResult != GDI_ERROR) {
dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_DRIVER_KEY, SPLDS_PRINT_COLLATE, REG_BINARY, (PBYTE) &dwResult, sizeof(BYTE)); #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Collate, %x\n", dwResult) ); #endif
} else {
DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_COLLATE failed %d\n", GetLastError())); }
// printColor
_try { dwResult = (*pDevCap)( hDevCapPrinter, pPrinterName, DC_COLORDEVICE, NULL, NULL); } _except(1) { SetLastError(GetExceptionCode()); dwResult = GDI_ERROR; } if (dwResult == GDI_ERROR) {
// Try alternative method
dwResult = ThisIsAColorPrinter(pIniPrinter->pName); } else {
DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_COLORDEVICE failed %d\n", GetLastError())); }
dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_DRIVER_KEY, SPLDS_PRINT_COLOR, REG_BINARY, (PBYTE) &dwResult, sizeof(BYTE)); #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Color, %x\n", dwResult) ); #endif
// printDuplexSupported
_try { dwResult = (*pDevCap)( hDevCapPrinter, pPrinterName, DC_DUPLEX, NULL, NULL); } _except(1) { SetLastError(GetExceptionCode()); dwResult = GDI_ERROR; } if (dwResult != GDI_ERROR) { dwResult = !!dwResult; dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_DRIVER_KEY, SPLDS_PRINT_DUPLEX_SUPPORTED, REG_BINARY, (PBYTE) &dwResult, sizeof(BYTE)); #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Duplex, %x\n", dwResult) ); #endif
} else {
DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_DUPLEX failed %d\n", GetLastError())); }
// printStaplingSupported
_try { dwResult = (*pDevCap)( hDevCapPrinter, pPrinterName, DC_STAPLE, NULL, NULL); } _except(1) { SetLastError(GetExceptionCode()); dwResult = GDI_ERROR; } if (dwResult != GDI_ERROR) { dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_DRIVER_KEY, SPLDS_PRINT_STAPLING_SUPPORTED, REG_BINARY, (PBYTE) &dwResult, sizeof(BYTE)); #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Duplex, %x\n", dwResult) ); #endif
} else {
DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_STAPLE failed %d\n", GetLastError())); }
// printMaxXExtent & printMaxYExtent
_try { dwResult = (*pDevCap)( hDevCapPrinter, pPrinterName, DC_MAXEXTENT, NULL, NULL); } _except(1) { SetLastError(GetExceptionCode()); dwResult = GDI_ERROR; } if (dwResult != GDI_ERROR) {
*((DWORD *) &point) = dwResult;
dwTemp = (DWORD) point.x; dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_DRIVER_KEY, SPLDS_PRINT_MAX_X_EXTENT, REG_DWORD, (PBYTE) &dwTemp, sizeof(DWORD)); #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: MaxXExtent, %x\n", dwResult) ); #endif
dwTemp = (DWORD) point.y; dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_DRIVER_KEY, SPLDS_PRINT_MAX_Y_EXTENT, REG_DWORD, (PBYTE) &dwTemp, sizeof(DWORD)); #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: MaxYExtent, %x\n", dwResult) ); #endif
} else {
DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_MAXEXTENT failed %d\n", GetLastError())); }
// printMinXExtent & printMinYExtent
_try { dwResult = (*pDevCap)( hDevCapPrinter, pPrinterName, DC_MINEXTENT, NULL, NULL); } _except(1) { SetLastError(GetExceptionCode()); dwResult = GDI_ERROR; } if (dwResult != GDI_ERROR) {
*((DWORD *) &point) = dwResult;
dwTemp = (DWORD) point.x; dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_DRIVER_KEY, SPLDS_PRINT_MIN_X_EXTENT, REG_DWORD, (PBYTE) &dwTemp, sizeof(DWORD)); #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: MinXExtent, %x\n", dwResult) ); #endif
dwTemp = (DWORD) point.y; dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_DRIVER_KEY, SPLDS_PRINT_MIN_Y_EXTENT, REG_DWORD, (PBYTE) &dwTemp, sizeof(DWORD)); #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: MinYExtent, %x\n", dwResult) ); #endif
} else {
DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_MINEXTENT failed %d\n", GetLastError())); }
// printMediaSupported - Not part of printQueue, but is in Schema
if (!DevCapMultiSz( hPrinter, hDevCapPrinter, pDevCap, pSplDevCaps, pPrinterName, DC_PAPERNAMES, 64, SPLDS_PRINT_MEDIA_SUPPORTED)) { DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_PAPERNAMES failed %d\n", GetLastError())); }
// printMediaReady
if (!DevCapMultiSz( hPrinter, hDevCapPrinter, pDevCap, pSplDevCaps, pPrinterName, DC_MEDIAREADY, 64, SPLDS_PRINT_MEDIA_READY)) { DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_MEDIAREADY failed %d\n", GetLastError())); }
// printNumberUp
_try { dwResult = (*pDevCap)( hDevCapPrinter, pPrinterName, DC_NUP, NULL, NULL); } _except(1) { SetLastError(GetExceptionCode()); dwResult = GDI_ERROR; } if (dwResult != GDI_ERROR) {
dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_DRIVER_KEY, SPLDS_PRINT_NUMBER_UP, REG_DWORD, (PBYTE) &dwResult, sizeof(DWORD));
#if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: NumberUp, %x\n", dwResult) ); #endif
} else {
DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_NUP failed %d\n", GetLastError())); }
// printMemory
_try { dwResult = (*pDevCap)( hDevCapPrinter, pPrinterName, DC_PRINTERMEM, NULL, NULL); } _except(1) { SetLastError(GetExceptionCode()); dwResult = GDI_ERROR; } if (dwResult != GDI_ERROR) { dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_DRIVER_KEY, SPLDS_PRINT_MEMORY, REG_DWORD, (PBYTE) &dwResult, sizeof(DWORD));
#if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: printMemory, %x\n", dwResult) ); #endif
} else {
DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_PRINTERMEM failed %d\n", GetLastError())); }
// printOrientationsSupported
_try { dwResult = (*pDevCap)( hDevCapPrinter, pPrinterName, DC_ORIENTATION, NULL, NULL); } _except(1) { SetLastError(GetExceptionCode()); dwResult = GDI_ERROR; } if (dwResult != GDI_ERROR) {
if (dwResult == 90 || dwResult == 270) { wcscpy(pBuf, L"PORTRAIT"); wcscpy(pStr = pBuf + wcslen(pBuf) + 1, L"LANDSCAPE"); } else { wcscpy(pStr = pBuf, L"PORTRAIT"); } pStr += wcslen(pStr) + 1; *pStr++ = L'\0';
dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_DRIVER_KEY, SPLDS_PRINT_ORIENTATIONS_SUPPORTED, REG_MULTI_SZ, (PBYTE) pBuf, (DWORD) ((ULONG_PTR) pStr - (ULONG_PTR) pBuf)); #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Orientations, %x\n", dwResult) ); #endif
} else {
DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_ORIENTATION failed %d\n", GetLastError())); }
// printMaxResolutionSupported
_try { dwResult = (*pDevCap)( hDevCapPrinter, pPrinterName, DC_ENUMRESOLUTIONS, NULL, NULL); } _except(1) { SetLastError(GetExceptionCode()); dwResult = GDI_ERROR; } if (dwResult != GDI_ERROR) {
if (cOutputBytes < dwResult*2*sizeof(DWORD)) { if(!(pTemp1 = (LPWSTR) ReallocSplMem(pOutput, 0, cOutputBytes = dwResult*2*sizeof(DWORD)))) goto error; pOutput = pTemp1; }
_try { dwResult = (*pDevCap)( hDevCapPrinter, pPrinterName, DC_ENUMRESOLUTIONS, pOutput, NULL); } _except(1) { SetLastError(GetExceptionCode()); dwResult = GDI_ERROR; } if (dwResult != GDI_ERROR && dwResult > 0) {
// Find the maximum resolution: we have dwResult*2 resolutions to check
_try { for(i = dwTemp = 0 ; i < dwResult*2 ; ++i) { if (((DWORD *) pOutput)[i] > dwTemp) dwTemp = ((DWORD *) pOutput)[i]; }
dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_DRIVER_KEY, SPLDS_PRINT_MAX_RESOLUTION_SUPPORTED, REG_DWORD, (PBYTE) &dwTemp, sizeof(DWORD)); } _except(1) { SetLastError(dwResult = GetExceptionCode()); }
#if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Resolution, %x\n", dwResult) ); #endif
} } else {
DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_ENUMRESOLUTIONS failed %d\n", GetLastError())); }
// printLanguage
if (!DevCapMultiSz( hPrinter, hDevCapPrinter, pDevCap, NULL, pPrinterName, DC_PERSONALITY, 32, SPLDS_PRINT_LANGUAGE)) { DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_PERSONALITY failed %d\n", GetLastError())); }
// printRate
// NOTE: If PrintRate is 0, no value is published
_try { dwResult = (*pDevCap)( hDevCapPrinter, pPrinterName, DC_PRINTRATE, NULL, NULL); } _except(1) { SetLastError(GetExceptionCode()); dwResult = GDI_ERROR; } dwPrintRate = dwResult ? dwResult : GDI_ERROR; if (dwPrintRate != GDI_ERROR) { dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_DRIVER_KEY, SPLDS_PRINT_RATE, REG_DWORD, (PBYTE) &dwPrintRate, sizeof(DWORD)); #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: PrintRate, %x\n", dwResult) ); #endif
} else {
DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_PRINTRATE failed %d\n", GetLastError())); }
// printRateUnit
_try { dwResult = (*pDevCap)( hDevCapPrinter, pPrinterName, DC_PRINTRATEUNIT, NULL, NULL); } _except(1) { SetLastError(GetExceptionCode()); dwResult = GDI_ERROR; } dwPrintRateUnit = dwResult;
//
// If the capability isn't supported, set printRateUnit to empty string.
//
switch (dwPrintRateUnit) { case PRINTRATEUNIT_PPM: pStr = L"PagesPerMinute"; break;
case PRINTRATEUNIT_CPS: pStr = L"CharactersPerSecond"; break;
case PRINTRATEUNIT_LPM: pStr = L"LinesPerMinute"; break;
case PRINTRATEUNIT_IPM: pStr = L"InchesPerMinute"; break;
default: pStr = L""; break; }
if (pStr) { dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_DRIVER_KEY, SPLDS_PRINT_RATE_UNIT, REG_SZ, (PBYTE) pStr, (wcslen(pStr) + 1)*sizeof *pStr); #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: PrintRateUnit, %x\n", dwResult) ); #endif
} else { DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_PRINTRATEUNIT no unit %d\n", dwPrintRateUnit )); }
// printPagesPerMinute
// DevCap returns 0 if there is no entry in GPD
_try { dwResult = (*pDevCap)( hDevCapPrinter, pPrinterName, DC_PRINTRATEPPM, NULL, NULL); } _except(1) { SetLastError(GetExceptionCode()); dwResult = GDI_ERROR; }
if (dwResult == GDI_ERROR) dwResult = 0;
dwPrintPPM = dwResult;
// If dwPrintPPM == 0, then calculate PPM from PrintRate
if (dwPrintPPM == 0) { if (dwPrintRate == GDI_ERROR) { dwPrintPPM = GDI_ERROR; } else { switch (dwPrintRateUnit) { case PRINTRATEUNIT_PPM: dwPrintPPM = dwPrintRate; break;
case PRINTRATEUNIT_CPS: case PRINTRATEUNIT_LPM: dwPrintPPM = dwPrintRate/PPM_FACTOR; if (dwPrintPPM == 0) dwPrintPPM = 1; // min PPM is 1
break;
default:
DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: PRINTRATEUNIT not found %d\n", dwPrintRateUnit)); dwPrintPPM = GDI_ERROR; break; } } } if (dwPrintPPM != GDI_ERROR) { dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_DRIVER_KEY, SPLDS_PRINT_PAGES_PER_MINUTE, REG_DWORD, (PBYTE) &dwPrintPPM, sizeof(DWORD)); #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG(DBG_WARNING, ("UpdateDsDriverKey: PrintPagesPerMinute, %x\n", dwResult)); #endif
} else {
DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: PPM failed %d\n", GetLastError())); }
// printDriverVersion
_try { dwResult = (*pDevCap)( hDevCapPrinter, pPrinterName, DC_VERSION, NULL, NULL); } _except(1) { SetLastError(GetExceptionCode()); dwResult = GDI_ERROR; } if (dwResult != GDI_ERROR) { dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_DRIVER_KEY, SPLDS_DRIVER_VERSION, REG_DWORD, (PBYTE) &dwResult, sizeof(DWORD)); #if DBG
if (dwResult != ERROR_SUCCESS) DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Driver Version, %x\n", dwResult) ); #endif
} else {
DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_VERSION failed %d\n", GetLastError())); }
error:
if (hDevCapPrinter) (*pfnClosePrinter)(hDevCapPrinter);
if (!bInSplSem) { EnterSplSem(); DECPRINTERREF(pIniPrinter); }
if (hModule) FreeLibrary(hModule);
FreeSplMem(pOutput); FreeSplMem(pTemp); }
BOOL DevCapMultiSz( HANDLE hPrinter, HANDLE hDevCapPrinter, PDEVCAP pDevCap, PSPLDEVCAP pSplDevCap, PWSTR pszPrinterName, WORD fwCapability, DWORD dwElementBytes, PWSTR pszRegValue ) /*++
Function Description: This function writes a multisz devcap string to the DsDriverKey registry
Parameters: hPrinter - printer handle hDevCapPrinter - devcap handle pDevCap - devcap function pointer pszPrinterName - name of the printer fwCapability - devcap capability entry dwElementBytes - length of each string element in the array returned by devcaps pszRegValue - name of the registry value to which the multisz string will be written
Return Values: BOOL - TRUE if successful, FALSE if not. Call GetLastError to retrieve failure error.
--*/ { DWORD dwResult, cbBytes; PWSTR pszDevCapBuffer = NULL; PWSTR pszRegData = NULL;
_try { dwResult = GDI_ERROR; if (pSplDevCap) { dwResult = (*pSplDevCap)( hDevCapPrinter, pszPrinterName, fwCapability, NULL, 0, NULL); } if (dwResult == GDI_ERROR) { dwResult = (*pDevCap)( hDevCapPrinter, pszPrinterName, fwCapability, NULL, NULL); }
if (dwResult != GDI_ERROR) {
//
// DeviceCapabilities doesn't take a buffer size parameter, so if you get
// printer properties on a hundred or so printers at the same time, you will
// occasionally hit the case where win32 cache is deleting & adding forms in
// RefreshFormsCache and DC_PAPERNAMES calls EnumForms and gets different
// results. The first call may return 3 forms and second returns 20. So we
// allocate a big buffer here so third party drivers don't AV. For unidrv
// we have a different interface that accepts a buffer size.
//
if ((fwCapability == DC_PAPERNAMES || fwCapability == DC_MEDIAREADY) && dwResult < LOTS_OF_FORMS) { cbBytes = LOTS_OF_FORMS*dwElementBytes*sizeof(WCHAR); } else { cbBytes = dwResult*dwElementBytes*sizeof(WCHAR); } pszDevCapBuffer = (PWSTR) AllocSplMem(cbBytes);
if (pszDevCapBuffer) { dwResult = GDI_ERROR; if (pSplDevCap) { dwResult = (*pSplDevCap)( hDevCapPrinter, pszPrinterName, fwCapability, pszDevCapBuffer, cbBytes/sizeof(WCHAR), NULL); } if (dwResult == GDI_ERROR) { dwResult = (*pDevCap)( hDevCapPrinter, pszPrinterName, fwCapability, pszDevCapBuffer, NULL); }
if (dwResult != GDI_ERROR) { if (!(pszRegData = DevCapStrings2MultiSz(pszDevCapBuffer, dwResult, dwElementBytes, &cbBytes))) { dwResult = GDI_ERROR; } } } else { dwResult = GDI_ERROR; } } } _except(1) { SetLastError(GetExceptionCode()); dwResult = GDI_ERROR; }
if (dwResult != GDI_ERROR) {
dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_DRIVER_KEY, pszRegValue, REG_MULTI_SZ, (PBYTE) pszRegData, cbBytes);
if (dwResult != ERROR_SUCCESS) { SetLastError(dwResult); dwResult = GDI_ERROR; } } else {
WCHAR szzNull[2]; szzNull[0] = szzNull[1] = '\0';
dwResult = SplSetPrinterDataEx( hPrinter, SPLDS_DRIVER_KEY, pszRegValue, REG_MULTI_SZ, (PBYTE) szzNull, 2 * sizeof(WCHAR)); }
FreeSplStr(pszDevCapBuffer); FreeSplStr(pszRegData);
return dwResult != GDI_ERROR; }
// RecreateDsKey: Clears existing published properties and recreates & republishes Registry key
extern "C" DWORD RecreateDsKey( HANDLE hPrinter, PWSTR pszKey ) { PSPOOL pSpool = (PSPOOL)hPrinter; PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
SplOutSem();
// 1) Clear all published Properties under Key
ClearDsKey(hPrinter, pszKey);
// 2) Delete Key
EnterSplSem(); SplDeletePrinterKey(hPrinter, pszKey);
// 3) Recreate Key
if (!wcscmp(pszKey, SPLDS_DRIVER_KEY)) { UpdateDsDriverKey(hPrinter); } else if (!wcscmp(pszKey, SPLDS_SPOOLER_KEY)) { UpdateDsSpoolerKey(hPrinter, 0xffffffff); }
// 4) Republish Key
SetPrinterDs(hPrinter, DSPRINT_UPDATE, FALSE);
LeaveSplSem(); SplOutSem();
return ERROR_SUCCESS; }
// ClearDsKey: clears all properties in specified key
HRESULT ClearDsKey( HANDLE hPrinter, PWSTR pszKey ) { HRESULT hr = ERROR_SUCCESS; DWORD i; DWORD cbEnumValues = 0; PPRINTER_ENUM_VALUES pEnumValues = NULL; DWORD nEnumValues; DWORD dwResult; PSPOOL pSpool = (PSPOOL)hPrinter; PINIPRINTER pIniPrinter = pSpool->pIniPrinter; IADs *pADs = NULL; HANDLE hToken = NULL; VARIANT var;
SplOutSem();
//
// If we're not published, there's no DS key to clear, so just return success
//
if (!pIniPrinter->pszObjectGUID) return S_OK;
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if (FAILED(hr)) return hr;
hToken = RevertToPrinterSelf(); // All DS accesses are done by LocalSystem account
// 1) Enumerate all the Values under key
// Enumerate and Publish Key
dwResult = SplEnumPrinterDataEx( hPrinter, pszKey, NULL, 0, &cbEnumValues, &nEnumValues );
if (dwResult != ERROR_MORE_DATA) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult); goto error; }
if (!(pEnumValues = (PPRINTER_ENUM_VALUES) AllocSplMem(cbEnumValues))) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); BAIL_ON_FAILURE(hr); }
dwResult = SplEnumPrinterDataEx( hPrinter, pszKey, (LPBYTE) pEnumValues, cbEnumValues, &cbEnumValues, &nEnumValues ); if (dwResult != ERROR_SUCCESS) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult); goto error; }
// Get or Create printQueue object
hr = GetPrintQueue(hPrinter, &pADs); BAIL_ON_FAILURE(hr);
// 2) Clear Published Properties
VariantInit(&var);
for (i = 0 ; i < nEnumValues ; ++i) {
hr = pADs->PutEx( ADS_PROPERTY_CLEAR, pEnumValues[i].pValueName, var );
#if DBG
if (FAILED(hr)) DBGMSG(DBG_EXEC, ("Failed to clear property: %ws\n", pEnumValues[i].pValueName)); #endif
}
hr = pADs->SetInfo(); BAIL_ON_FAILURE(hr);
error:
FreeSplMem(pEnumValues);
if (hToken) ImpersonatePrinterClient(hToken);
if (pADs) { pADs->Release(); }
CoUninitialize();
return hr; }
HRESULT PutDSSD( PINIPRINTER pIniPrinter, IADs *pADs ) { IADsSecurityDescriptor *pSD = NULL; IADsAccessControlList *pACL = NULL; IDispatch *pSDDispatch = NULL; IDispatch *pACLDispatch = NULL; HRESULT hr, hr1; DWORD cb, cbDomain; DOMAIN_CONTROLLER_INFO *pDCI = NULL; PWSTR pszTrustee = NULL; PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole = NULL; DWORD dwRet; WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE]; BSTR bstrADsPath = NULL;
// Get SecurityDescriptor
// *** Create ACE
hr = CoCreateInstance( CLSID_SecurityDescriptor, NULL, CLSCTX_INPROC_SERVER, IID_IADsSecurityDescriptor, (void **) &pSD); BAIL_ON_FAILURE(hr);
hr = pSD->QueryInterface(IID_IDispatch, (void **) &pSDDispatch); BAIL_ON_FAILURE(hr);
// Create DACL
hr = CoCreateInstance( CLSID_AccessControlList, NULL, CLSCTX_INPROC_SERVER, IID_IADsAccessControlList, (void **) &pACL); BAIL_ON_FAILURE(hr);
hr = pACL->QueryInterface(IID_IDispatch, (void **) &pACLDispatch); BAIL_ON_FAILURE(hr);
// Get Domain name
dwRet = DsRoleGetPrimaryDomainInformation(NULL, DsRolePrimaryDomainInfoBasic, (PBYTE *) &pDsRole); if (dwRet) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwRet); BAIL_ON_FAILURE(hr); }
// *** Create ACEs ***
// NTPRINTING\SWILSONTEST$
cbDomain = wcslen(pDsRole->DomainNameFlat); cb = cbDomain + wcslen(pIniPrinter->pIniSpooler->pMachineName + 2) + 3; // add \, $, NULL
cb *= sizeof(WCHAR); if (!(pszTrustee = (PWSTR) AllocSplMem(cb))) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); BAIL_ON_FAILURE(hr); } wsprintf(pszTrustee, L"%ws\\%ws$", pDsRole->DomainNameFlat, pIniPrinter->pIniSpooler->pMachineName + 2);
hr = CreateAce(pACL, (BSTR) pszTrustee, GENERIC_ALL); BAIL_ON_FAILURE(hr);
hr = CreateAce(pACL, (BSTR) L"Domain Admins", GENERIC_ALL); BAIL_ON_FAILURE(hr);
hr = CreateAce(pACL, (BSTR) L"Authenticated Users", GENERIC_READ); BAIL_ON_FAILURE(hr);
hr = CreateAce(pACL, (BSTR) L"System", GENERIC_ALL); BAIL_ON_FAILURE(hr);
// Write it out
hr = pACL->put_AclRevision(ACL_REVISION4); BAIL_ON_FAILURE(hr);
hr = pSD->put_DiscretionaryAcl(pACLDispatch); BAIL_ON_FAILURE(hr);
hr = put_Dispatch_Property(pADs, L"nTSecurityDescriptor", pSDDispatch); BAIL_ON_FAILURE(hr);
// If SetInfo returns ERROR_BUSY it means the object already exists
// If the object exists, delete it and create a new one
hr = pADs->SetInfo();
if (HRESULT_CODE(hr) == ERROR_BUSY) pIniPrinter->DsKeyUpdate = DS_KEY_REPUBLISH;
BAIL_ON_FAILURE(hr);
DBGMSG(DBG_EXEC, ("PutDSSD: Successfully added ACL\n"));
error:
FreeSplMem(pszTrustee);
if (pSDDispatch) pSDDispatch->Release();
if (pACLDispatch) pACLDispatch->Release();
if (pSD) pSD->Release();
if (pACL) pACL->Release();
if (pDCI) NetApiBufferFree(pDCI);
if (pDsRole) DsRoleFreeMemory((PVOID) pDsRole);
if (FAILED(hr)) { DBGMSG(DBG_EXEC, ("PutDSSD: Failed to add ACL: %x\n\n", hr)); wsprintf(ErrorBuffer, L"%x", hr); hr1 = pADs->get_ADsPath(&bstrADsPath); if (SUCCEEDED(hr1)) { SplLogEvent( pIniPrinter->pIniSpooler, gdwLogDsEvents & LOG_ERROR, MSG_CANT_WRITE_ACL, FALSE, bstrADsPath, ErrorBuffer, NULL ); SysFreeString(bstrADsPath); } }
return hr; }
HRESULT CreateAce( IADsAccessControlList *pACL, BSTR pszTrustee, DWORD dwAccessMask ) { IADsAccessControlEntry *pACE = NULL; IDispatch *pACEDispatch = NULL; HRESULT hr;
// *** Create ACE
hr = CoCreateInstance( CLSID_AccessControlEntry, NULL, CLSCTX_INPROC_SERVER, IID_IADsAccessControlEntry, (void **) &pACE); BAIL_ON_FAILURE(hr);
hr = pACE->put_AccessMask(dwAccessMask); BAIL_ON_FAILURE(hr);
hr = pACE->put_AceType(ACCESS_ALLOWED_ACE_TYPE); BAIL_ON_FAILURE(hr);
hr = pACE->put_AceFlags(0); BAIL_ON_FAILURE(hr);
hr = pACE->put_Trustee(pszTrustee); BAIL_ON_FAILURE(hr);
hr = pACE->QueryInterface(IID_IDispatch, (void **) &pACEDispatch); BAIL_ON_FAILURE(hr);
hr = pACL->AddAce(pACEDispatch); BAIL_ON_FAILURE(hr);
error:
if (pACEDispatch) pACEDispatch->Release();
if (pACE) pACE->Release();
return hr; }
HRESULT AddClusterAce( PSPOOL pSpool, IADs *pADsPrintQueue ) { PINIPRINTER pIniPrinter = pSpool->pIniPrinter; IDispatch *pSDPrintQueueDispatch = NULL; IADsSecurityDescriptor *pSDPrintQueue = NULL; IDispatch *pACLPrintQueueDispatch = NULL; IADsAccessControlList *pACLPrintQueue = NULL; PWSTR pszClusterDN = NULL; PWSTR pszAccount = NULL; HRESULT hr;
// If we don't have a GUID, then we're not a cluster and we don't need to add the ACE
if (!pIniPrinter->pIniSpooler->pszClusterGUID) return S_OK;
// Get the Cluster Object DN
hr = GetPublishPointFromGUID(NULL, pIniPrinter->pIniSpooler->pszClusterGUID, &pszClusterDN, NULL, FALSE); BAIL_ON_FAILURE(hr);
// Get the PrintQueue Security Descriptor
hr = get_Dispatch_Property(pADsPrintQueue, L"nTSecurityDescriptor", &pSDPrintQueueDispatch); BAIL_ON_FAILURE(hr);
hr = pSDPrintQueueDispatch->QueryInterface(IID_IADsSecurityDescriptor, (void **) &pSDPrintQueue); BAIL_ON_FAILURE(hr);
// Get DACL from the Security Descriptor
hr = pSDPrintQueue->get_DiscretionaryAcl(&pACLPrintQueueDispatch); BAIL_ON_FAILURE(hr);
hr = pACLPrintQueueDispatch->QueryInterface(IID_IADsAccessControlList, (void **) &pACLPrintQueue); BAIL_ON_FAILURE(hr);
// Create the new ACE & Add it to the ACL
// Cluster account is a user account, so get current user and stick it in this ACE
hr = FQDN2Whatever(pszClusterDN, &pszAccount, DS_NT4_ACCOUNT_NAME); BAIL_ON_FAILURE(hr);
hr = CreateAce(pACLPrintQueue, (BSTR) pszAccount, GENERIC_ALL); BAIL_ON_FAILURE(hr);
// Write the ACL back to the Security Descriptor
hr = pSDPrintQueue->put_DiscretionaryAcl(pACLPrintQueueDispatch); BAIL_ON_FAILURE(hr);
// Write the Security Descriptor back to the object
hr = put_Dispatch_Property(pADsPrintQueue, L"nTSecurityDescriptor", pSDPrintQueueDispatch); BAIL_ON_FAILURE(hr);
hr = pADsPrintQueue->SetInfo(); BAIL_ON_FAILURE(hr);
error:
if (pACLPrintQueueDispatch) pACLPrintQueueDispatch->Release();
if (pACLPrintQueue) pACLPrintQueue->Release();
if (pSDPrintQueueDispatch) pSDPrintQueueDispatch->Release();
if (pSDPrintQueue) pSDPrintQueue->Release();
FreeSplStr(pszClusterDN); FreeSplStr(pszAccount);
return hr; }
|