Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

2653 lines
81 KiB

/*++
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;
}