|
|
/*++
Copyright (c) 1996 Microsoft Corporation All rights reserved
Abstract:
This module provides functionality for ADs within spooler
Author:
Steve Wilson (NT) Nov 1997
Revision History:
--*/
#include <precomp.h>
#pragma hdrstop
#define LOG_EVENT_ERROR_BUFFER_SIZE 11
#define MAX_CN 63 // DS limits common names to 63 non-null chars
#define UNIQUE_NUMBER_SIZE 10
#define MIN_CN (UNIQUE_NUMBER_SIZE + 3 + 1) // CN= + room for unique number if needed, plus NULL
extern BOOL gdwLogDsEvents;
extern "C" HANDLE ghDsUpdateThread; extern "C" DWORD gdwDsUpdateThreadId;
// Policy values
WCHAR *szPublishPrinters = L"PublishPrinters"; WCHAR *szPruneDownlevel = L"PruneDownlevel"; WCHAR *szPruningInterval = L"PruningInterval"; WCHAR *szPruningRetries = L"PruningRetries"; WCHAR *szPruningPriority = L"PruningPriority"; WCHAR *szVerifyPublishedState = L"VerifyPublishedState"; WCHAR *szImmortal = L"Immortal"; WCHAR *szServerThreadPolicy = L"ServerThread"; WCHAR *szPruningRetryLog = L"PruningRetryLog";
extern "C" BOOL (*pfnOpenPrinter)(LPTSTR, LPHANDLE, LPPRINTER_DEFAULTS); extern "C" BOOL (*pfnClosePrinter)(HANDLE); extern "C" LONG (*pfnDocumentProperties)(HWND, HANDLE, LPWSTR, PDEVMODE, PDEVMODE, DWORD);
DWORD dwLastPruningPriority = DEFAULT_PRUNING_PRIORITY;
HRESULT GetPrintQueue( HANDLE hPrinter, IADs **ppADs ) /*++
Function Description: This function returns the ADs PrintQueue object of the supplied printer handle.
Parameters: hPrinter - printer handle ppADs - return pointer to the PrintQueue object. Caller frees via ppADs->Release().
Return Values: HRESULT --*/ { HRESULT hr; PSPOOL pSpool = (PSPOOL) hPrinter; PINIPRINTER pIniPrinter = pSpool->pIniPrinter; IDispatch *pDispatch = NULL; IADsContainer *pADsContainer = NULL; WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE];
// Create the Print-Queue object
// Get the container
hr = GetPrintQueueContainer(hPrinter, &pADsContainer, ppADs); BAIL_ON_FAILURE(hr);
if (!*ppADs) { // PrintQueue object does not exist, so create it
hr = pADsContainer->Create( SPLDS_PRINTER_CLASS, pIniPrinter->pszCN, &pDispatch); if (FAILED(hr)) {
StringCchPrintf(ErrorBuffer, COUNTOF(ErrorBuffer), L"%0x", hr);
SplLogEvent(((PSPOOL)hPrinter)->pIniSpooler, gdwLogDsEvents & LOG_ERROR, MSG_CANT_CREATE_PRINTQUEUE, FALSE, pIniPrinter->pszDN, ErrorBuffer, NULL);
DBGMSG(DBG_WARNING,("Can't Create PrintQueue: %ws, %ws\n", pIniPrinter->pszDN, ErrorBuffer)); BAIL_ON_FAILURE(hr); }
hr = pDispatch->QueryInterface(IID_IADs, (void **) ppADs); BAIL_ON_FAILURE(hr); }
error:
if (pADsContainer) pADsContainer->Release();
if (pDispatch) pDispatch->Release();
return hr; }
HRESULT GetPublishPoint( HANDLE hPrinter ) /*++
Function Description: This function gets the publish point by setting pIniPrinter->pszDN and pIniPrinter->pszCN
Parameters: hPrinter - printer handle
Return Values: HRESULT --*/ { HRESULT hr; PSPOOL pSpool = (PSPOOL) hPrinter; PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
// We should only be here if we couldn't use the existing DN & CN, so free old ones
FreeSplStr(pIniPrinter->pszCN); pIniPrinter->pszCN = NULL;
FreeSplStr(pIniPrinter->pszDN); pIniPrinter->pszDN = NULL;
// If Published, update DN from GUID
if (pIniPrinter->pszObjectGUID) {
hr = GetPublishPointFromGUID( hPrinter, pIniPrinter->pszObjectGUID, &pIniPrinter->pszDN, &pIniPrinter->pszCN, TRUE);
//
// If the object is actually deleted, the error is ERROR_FILE_NOT_FOUND
// If the object is a tombstone, the error is ERROR_DS_NO_SUCH_OBJECT
//
if (HRESULT_CODE(hr) == ERROR_FILE_NOT_FOUND || HRESULT_CODE(hr) == ERROR_DS_NO_SUCH_OBJECT) { if (ghDsUpdateThread && gdwDsUpdateThreadId == GetCurrentThreadId()) { // We are in the background thread
pIniPrinter->DsKeyUpdate = DS_KEY_REPUBLISH; } else { pIniPrinter->DsKeyUpdateForeground = DS_KEY_REPUBLISH; } }
BAIL_ON_FAILURE(hr);
} else {
// Generate default publish point & common name
hr = GetDefaultPublishPoint(hPrinter, &pIniPrinter->pszDN); BAIL_ON_FAILURE(hr);
// Printer name might change, so make a copy here
EnterSplSem(); PWSTR pszPrinterName = AllocSplStr(pIniPrinter->pName); LeaveSplSem();
if (pszPrinterName) { hr = GetCommonName( hPrinter, pIniPrinter->pIniSpooler->pMachineName, pszPrinterName, pIniPrinter->pszDN, &pIniPrinter->pszCN); FreeSplStr(pszPrinterName); } else { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); } BAIL_ON_FAILURE(hr); }
error:
return hr; }
HRESULT GetPublishPointFromGUID( HANDLE hPrinter, PWSTR pszObjectGUID, PWSTR *ppszDN, PWSTR *ppszCN, BOOL bGetDNAndCN ) /*++
Function Description: This function returns the publish point of a specified GUID
Parameters: hPrinter - printer handle ppszObjectGUID - objectGUID of object for which we want to find the publish point ppszDN - ADsPath of container containing object. Caller frees via FreeSplMem(). ppszCN - Common Name of object. Caller frees via FreeSplMem(). bGetDNAndCN - if TRUE, DN of Container & CN of object are returned. If FALSE, DN is path to object
Return Values: HRESULT --*/ { PSPOOL pSpool = (PSPOOL) hPrinter; DWORD dwRet, nBytes, nChars; BOOL bRet; PWSTR pNames[2]; DS_NAME_RESULT *pDNR = NULL; DOMAIN_CONTROLLER_INFO *pDCI = NULL; HANDLE hDS = NULL; PWSTR psz; WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE]; HRESULT hr = S_OK;
dwRet = Bind2DS(&hDS, &pDCI, DS_DIRECTORY_SERVICE_PREFERRED); if (dwRet != ERROR_SUCCESS) { StringCchPrintf(ErrorBuffer, COUNTOF(ErrorBuffer), L"%0x", dwRet); if (pSpool) { SplLogEvent( pSpool->pIniSpooler, gdwLogDsEvents & LOG_ERROR, MSG_CANT_GET_DNS_DOMAIN_NAME, FALSE, ErrorBuffer, NULL ); } DBGMSG(DBG_WARNING,("Can't get DNS Domain Name: %ws\n", ErrorBuffer)); goto error; }
// Get Publish Point
if (ppszDN) {
pNames[0] = pszObjectGUID; pNames[1] = NULL;
if (!(DsCrackNames( hDS, DS_NAME_NO_FLAGS, DS_UNKNOWN_NAME, DS_FQDN_1779_NAME, 1, &pNames[0], &pDNR) == ERROR_SUCCESS)) {
dwRet = GetLastError(); StringCchPrintf(ErrorBuffer, COUNTOF(ErrorBuffer), L"%0x", dwRet); if (pSpool) { SplLogEvent( pSpool->pIniSpooler, gdwLogDsEvents & LOG_WARNING, MSG_CANT_CRACK_GUID, FALSE, pDCI->DomainName, ErrorBuffer, NULL ); DBGMSG(DBG_WARNING,("Can't crack GUID: %ws, %ws\n", pDCI->DomainName, ErrorBuffer)); } dwRet = ERROR_FILE_NOT_FOUND; goto error; }
if (pDNR->rItems[0].status != DS_NAME_NO_ERROR) { dwRet = DsCrackNamesStatus2Win32Error(pDNR->rItems[0].status);
StringCchPrintf(ErrorBuffer, COUNTOF(ErrorBuffer), L"%0x", dwRet); if (pSpool) { SplLogEvent( pSpool->pIniSpooler, gdwLogDsEvents & LOG_WARNING, MSG_CANT_CRACK_GUID, FALSE, pDCI->DomainName, ErrorBuffer, NULL ); } DBGMSG(DBG_WARNING,("Can't crack GUID: %ws %ws\n", pDCI->DomainName, ErrorBuffer)); dwRet = ERROR_FILE_NOT_FOUND; goto error; }
if (bGetDNAndCN) { // Separate DN into CN & PublishPoint
// pDNR has form: CN=CommonName,DN...
hr = FQDN2CNDN(pDCI->DomainControllerName + 2, pDNR->rItems[0].pName, ppszCN, ppszDN); BAIL_ON_FAILURE(hr);
} else {
hr = BuildLDAPPath(pDCI->DomainControllerName + 2, pDNR->rItems[0].pName, ppszDN); BAIL_ON_FAILURE(hr); } }
error:
if (pDNR) DsFreeNameResult(pDNR);
if (hDS) DsUnBind(&hDS);
if (pDCI) NetApiBufferFree(pDCI);
if (dwRet != ERROR_SUCCESS) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwRet); }
if (FAILED(hr)) { if (ppszCN) { FreeSplMem(*ppszCN); *ppszCN = NULL; } if (ppszDN) { FreeSplMem(*ppszDN); *ppszDN = NULL; } }
return hr; }
HRESULT FQDN2CNDN( PWSTR pszDCName, PWSTR pszFQDN, PWSTR *ppszCN, PWSTR *ppszDN ) { IADs *pADs = NULL; PWSTR pszCN = NULL; PWSTR pszDN = NULL; PWSTR pszLDAPPath = NULL; HRESULT hr;
// Get LDAP path to object
hr = BuildLDAPPath(pszDCName, pszFQDN, &pszLDAPPath); BAIL_ON_FAILURE(hr);
// Get DN
hr = ADsGetObject(pszLDAPPath, IID_IADs, (void **) &pADs); BAIL_ON_FAILURE(hr);
hr = pADs->get_Parent(&pszDN); BAIL_ON_FAILURE(hr);
if (!(*ppszDN = AllocSplStr(pszDN))) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); BAIL_ON_FAILURE(hr); }
// Get CN
hr = pADs->get_Name(&pszCN); BAIL_ON_FAILURE(hr);
if (!(*ppszCN = AllocSplStr(pszCN))) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); BAIL_ON_FAILURE(hr); }
error:
if (pADs) pADs->Release();
if (pszCN) SysFreeString(pszCN);
if (pszDN) SysFreeString(pszDN);
FreeSplStr(pszLDAPPath);
if (FAILED(hr)) { FreeSplStr(*ppszCN); FreeSplStr(*ppszDN); }
return hr; }
HRESULT BuildLDAPPath( PWSTR pszDC, PWSTR pszFQDN, PWSTR *ppszLDAPPath ) { PWSTR pszEscapedFQDN = NULL; DWORD nBytes; HRESULT hr = S_OK;
//
// pszFQDN is assumed to contain escaped DN_SPECIAL_CHARS characters, but
// ADSI has additional special characters that need to be escaped before using
// the LDAP path in ADSI calls.
//
pszEscapedFQDN = CreateEscapedString(pszFQDN, ADSI_SPECIAL_CHARS); if (!pszEscapedFQDN) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); BAIL_ON_FAILURE(hr); }
// LDAP:// + pDCName + / + pName + 1
nBytes = (wcslen(pszDC) + wcslen(pszEscapedFQDN) + 9)*sizeof(WCHAR);
if (!(*ppszLDAPPath = (PWSTR) AllocSplMem(nBytes))) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); BAIL_ON_FAILURE(hr); }
StringCbPrintf(*ppszLDAPPath, nBytes, L"LDAP://%ws/%ws", pszDC, pszEscapedFQDN);
error:
FreeSplStr(pszEscapedFQDN);
return hr; }
HRESULT GetPrintQueueContainer( HANDLE hPrinter, IADsContainer **ppADsContainer, IADs **ppADs ) /*++
Function Description: This function returns the container and, if it exists, the PrintQueue object pointer corresponding to the supplied printer handle
Parameters: hPrinter - printer handle ppADsContainer - return Container ADsPath. Caller frees via ppADsContainer->Release(). ppADs - return PrintQueue object ADsPath. Caller frees via ppADs->Release().
Return Values: If successful, returns the printqueue container and, if found, the printqueue dispatch. If there is no printqueue, the dispatch is set to NULL and the default container is returned. --*/ { HRESULT hr; PSPOOL pSpool = (PSPOOL) hPrinter; PINIPRINTER pIniPrinter = pSpool->pIniPrinter; WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE]; DWORD nBytes; PWSTR pszObjectGUID = NULL; IDispatch *pPrintQDispatch = NULL; LPWSTR pszPrinterObjectGUID = pIniPrinter->pszObjectGUID; LPWSTR pszPrinterDN = pIniPrinter->pszDN; LPWSTR pszPrinterCN = pIniPrinter->pszCN;
*ppADsContainer = NULL; *ppADs = NULL;
//
// Try quick search for object using known properties.
//
// We are outside Spooler CS and pIniPrinter->pszObjectGUID,
// pIniPrinter->pszDN, pIniPrinter->pszCN might get changed by
// the DS background thread. In the case they are set to NULL,
// we'll take an AV. So, even if they change or are set to NULL,
// we'll use whatever we have when we entered the function.
// The worst that can happen is to find a DS printQueue
// object that doesn't last till we use it, which is fine. This
// is already assumed. Or, to not find a DS printQueue that will
// be created just after we query the DS. This is also fine.
//
if (pszPrinterObjectGUID && pszPrinterDN && pszPrinterCN) {
// Try to get the container using existing DN
hr = ADsGetObject( pszPrinterDN, IID_IADsContainer, (void **) ppADsContainer );
if (SUCCEEDED(hr)) {
// Verify that printqueue exists in this container
hr = (*ppADsContainer)->GetObject( SPLDS_PRINTER_CLASS, pszPrinterCN, &pPrintQDispatch);
// Verify that the found printQueue object has the same GUID
if (SUCCEEDED(hr) && pPrintQDispatch) { hr = pPrintQDispatch->QueryInterface(IID_IADs, (void **) ppADs); BAIL_ON_FAILURE(hr);
hr = GetGUID(*ppADs, &pszObjectGUID); BAIL_ON_FAILURE(hr);
if (wcscmp(pszObjectGUID, pszPrinterObjectGUID)) hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND); } else { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND); } } } else { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND); }
// Couldn't find container or printQueue, so find by GUID or get default container
if (FAILED(hr)) {
// The following items may have been allocated above and need to be freed
// here since we're going to reallocate them
if (pPrintQDispatch) { pPrintQDispatch->Release(); pPrintQDispatch = NULL; } if (*ppADsContainer) { (*ppADsContainer)->Release(); *ppADsContainer = NULL; } if (*ppADs) { (*ppADs)->Release(); *ppADs = NULL; }
// find or create pszDN and pszCN
hr = GetPublishPoint(hPrinter); BAIL_ON_FAILURE(hr);
SPLASSERT(pIniPrinter->pszDN);
hr = ADsGetObject( pIniPrinter->pszDN, IID_IADsContainer, (void **) ppADsContainer );
if (FAILED(hr)) { StringCchPrintf(ErrorBuffer, COUNTOF(ErrorBuffer), L"%0x", hr); DBGMSG(DBG_WARNING,("Can't get Container: %ws, %ws\n", pIniPrinter->pszDN, ErrorBuffer)); SplLogEvent( ((PSPOOL) hPrinter)->pIniSpooler, gdwLogDsEvents & LOG_ERROR, MSG_CANT_GET_CONTAINER, FALSE, pIniPrinter->pszDN, ErrorBuffer, NULL );
BAIL_ON_FAILURE(hr); }
// Try to get the printqueue, but don't error out if we can't
(*ppADsContainer)->GetObject( SPLDS_PRINTER_CLASS, pIniPrinter->pszCN, &pPrintQDispatch); if (pPrintQDispatch) pPrintQDispatch->QueryInterface(IID_IADs, (void **) ppADs); }
error:
if (pPrintQDispatch) pPrintQDispatch->Release();
FreeSplStr(pszObjectGUID);
return hr; }
HRESULT GetCommonName( HANDLE hPrinter, PWSTR pszServerName, PWSTR pszPrinterName, PWSTR pszDN, PWSTR *ppszCommonName ) /*++
Function Description: This function returns a standard format Common Name of the PrintQueue object generated from the supplied Server and Printer names
Parameters: hPrinter - printer handle pszServerName - name of a server pszPrinterName - name of a printer on the server pszDN - container DN ppszCommonName - return CommonName. Caller frees via FreeSplMem().
Return Values: HRESULT --*/ { DWORD nBytes; PWSTR psz; PWSTR pszPrinterNameStart = pszPrinterName;
// "CN=Server-Printer"
nBytes = (wcslen(pszPrinterName) + wcslen(pszServerName) + 5)*sizeof(WCHAR);
// We need to also make room for a unique number if there is a conflict
if (nBytes < MIN_CN) nBytes = MIN_CN;
if (!(*ppszCommonName = psz = (PWSTR) AllocSplMem(nBytes))) { return MAKE_HRESULT( SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); }
// CN=
StringCbCopy(psz, nBytes, L"CN=");
// Server
for(psz += 3, pszServerName += 2 ; *pszServerName ; ++psz, ++pszServerName) { *psz = wcschr(DN_SPECIAL_CHARS, *pszServerName) ? TEXT('_') : *pszServerName; } *psz = L'-';
// Printer
for(++psz; *pszPrinterName ; ++psz, ++pszPrinterName) { *psz = wcschr(DN_SPECIAL_CHARS, *pszPrinterName) ? TEXT('_') : *pszPrinterName; }
// NULL
*psz = *pszPrinterName;
// DS only allows 64 characters in CN attribute, so shorten this if needed
if (wcslen(*ppszCommonName) > MAX_CN - 1) { (*ppszCommonName)[MAX_CN] = NULL; }
// Generate a non-conflicting name in this container
GetUniqueCN(pszDN, ppszCommonName, pszPrinterNameStart);
return S_OK; }
VOID GetUniqueCN( PWSTR pszDN, PWSTR *ppszCommonName, PWSTR pszPrinterName ) { // Check if an object with this CN already exists in this container
// Get Container
IADsContainer *pADsContainer = NULL; UINT32 CN; // This is a "random" number we append to the common name to make it unique
CN = (UINT32) (ULONG_PTR) &CN; // Initialize with some random number
HRESULT hr = ADsGetObject(pszDN, IID_IADsContainer, (void **) &pADsContainer);
if (SUCCEEDED(hr)) {
BOOL bTryAgain;
do { IDispatch *pPrintQDispatch = NULL; bTryAgain = FALSE;
// Get PrintQueue, if it exists
pADsContainer->GetObject( SPLDS_PRINTER_CLASS, *ppszCommonName, &pPrintQDispatch); if (pPrintQDispatch) {
IADs *pADs = NULL;
hr = pPrintQDispatch->QueryInterface(IID_IADs, (void **) &pADs);
if (SUCCEEDED(hr)) {
// Generate a unique Common Name.
UINT32 cchCommonName = wcslen(*ppszCommonName); PWSTR pszDigits;
if (cchCommonName >= MIN_CN) { pszDigits = *ppszCommonName + cchCommonName - UNIQUE_NUMBER_SIZE; } else { pszDigits = *ppszCommonName + 3; // CN=
}
bTryAgain = TRUE;
StringCchPrintf(pszDigits, (cchCommonName + 1) - (pszDigits - *ppszCommonName), L"%010d", ++CN);
pADs->Release(); } pPrintQDispatch->Release(); } } while(bTryAgain);
pADsContainer->Release(); } }
HRESULT GetDefaultPublishPoint( HANDLE hPrinter, PWSTR *ppszDN ) /*++
Function Description: This function returns the default publish point (Container) of a PrintQueue based on the supplied printer handle.
Parameters: hPrinter - printer handle ppszDN - return default PrintQueue container. Caller frees via FreeSplMem()
Return Values: HRESULT --*/ { WCHAR szServerName[MAX_COMPUTERNAME_LENGTH + 1]; WCHAR szName[MAX_PATH + 1]; DWORD nSize; HANDLE hDS = NULL; DWORD dwRet = ERROR_SUCCESS; BOOL bRet; PWSTR pNames[2]; DS_NAME_RESULT *pDNR = NULL; DOMAIN_CONTROLLER_INFO *pDCI = NULL; PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole = NULL; WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE]; HRESULT hr = S_OK;
// Get Computer name
nSize = MAX_COMPUTERNAME_LENGTH + 1; if (!(bRet = GetComputerName(szServerName, &nSize))) { dwRet = GetLastError(); goto error; }
// Get Domain name
dwRet = DsRoleGetPrimaryDomainInformation(NULL, DsRolePrimaryDomainInfoBasic, (PBYTE *) &pDsRole); if (dwRet) { StringCchPrintf(ErrorBuffer, COUNTOF(ErrorBuffer), L"%0x", dwRet); DBGMSG(DBG_WARNING,("Can't get Primary Domain Info: %ws\n", ErrorBuffer)); SplLogEvent(((PSPOOL) hPrinter)->pIniSpooler, gdwLogDsEvents & LOG_ERROR, MSG_CANT_GET_PRIMARY_DOMAIN_INFO, FALSE, ErrorBuffer, NULL ); goto error; }
// Domain\Server
StringCchPrintf(szName, COUNTOF(szName), L"%ws\\%ws$", pDsRole->DomainNameFlat, szServerName); pNames[0] = szName; pNames[1] = NULL;
dwRet = Bind2DS(&hDS, &pDCI, DS_DIRECTORY_SERVICE_PREFERRED); if (dwRet != ERROR_SUCCESS) { StringCchPrintf(ErrorBuffer, COUNTOF(ErrorBuffer), L"%0x", dwRet); DBGMSG(DBG_WARNING,("Can't get DNS Domain Name: %ws\n", ErrorBuffer)); SplLogEvent( ((PSPOOL) hPrinter)->pIniSpooler, gdwLogDsEvents & LOG_ERROR, MSG_CANT_GET_DNS_DOMAIN_NAME, FALSE, ErrorBuffer, NULL ); goto error; }
// Get Publish Point
if (ppszDN) { if (!(DsCrackNames( hDS, DS_NAME_NO_FLAGS, DS_UNKNOWN_NAME, DS_FQDN_1779_NAME, 1, &pNames[0], &pDNR) == ERROR_SUCCESS)) {
dwRet = GetLastError();
StringCchPrintf(ErrorBuffer, COUNTOF(ErrorBuffer), L"%0x", dwRet); DBGMSG(DBG_WARNING,("Can't Crack Name: %ws, %ws\n", pDCI->DomainName, ErrorBuffer)); SplLogEvent( ((PSPOOL) hPrinter)->pIniSpooler, gdwLogDsEvents & LOG_ERROR, MSG_CANT_CRACK, FALSE, pDCI->DomainName, ErrorBuffer, NULL ); goto error; }
if (pDNR->rItems[0].status != DS_NAME_NO_ERROR) { dwRet = DsCrackNamesStatus2Win32Error(pDNR->rItems[0].status);
StringCchPrintf(ErrorBuffer, COUNTOF(ErrorBuffer), L"%0x", dwRet); DBGMSG(DBG_WARNING,("Can't Crack Name: %ws, %ws\n", pDCI->DomainName, ErrorBuffer)); SplLogEvent( ((PSPOOL) hPrinter)->pIniSpooler, gdwLogDsEvents & LOG_ERROR, MSG_CANT_CRACK, FALSE, pDCI->DomainName, ErrorBuffer, NULL ); goto error; }
// LDAP:// + pDCName + / + pName + 1
hr = BuildLDAPPath(pDCI->DomainControllerName + 2, pDNR->rItems[0].pName, ppszDN); BAIL_ON_FAILURE(hr); }
error:
if (pDNR) DsFreeNameResult(pDNR);
if (hDS) DsUnBind(&hDS);
if (pDCI) NetApiBufferFree(pDCI);
if (pDsRole) DsRoleFreeMemory((PVOID) pDsRole);
// If dwRet has no facility, then make into HRESULT
if (dwRet != ERROR_SUCCESS) { if (HRESULT_CODE(dwRet) == dwRet) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwRet); } else { hr = dwRet; } }
// Finally, make absolutely sure we are failing if *ppszDN is NULL
if (hr == S_OK && (!ppszDN || !*ppszDN)) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND); }
return hr; }
// Utility routine to report if a printer is color or monochrome
BOOL ThisIsAColorPrinter( LPCTSTR lpstrName ) /*++
Function Description: This function determines whether or not a printer supports color printing
Parameters: lpstrName - Printer name
Return Values: If printer supports color, return is TRUE. Otherwise, return value is FALSE --*/ { HANDLE hPrinter = NULL; LPTSTR lpstrMe = const_cast <LPTSTR> (lpstrName); BOOL bReturn = FALSE; LPDEVMODE lpdm = NULL; long lcbNeeded;
if (!(*pfnOpenPrinter)(lpstrMe, &hPrinter, NULL)) { DBGMSG(DBG_WARNING, ("Unable to open printer '%ws'- error %d\n", lpstrName, GetLastError())); goto error; }
// First, use DocumentProperties to find the correct DEVMODE size- we
// must use the DEVMODE to force color on, in case the user's defaults
// have turned it off...
lcbNeeded = (*pfnDocumentProperties)(NULL, hPrinter, lpstrMe, NULL, NULL, 0);
if (lcbNeeded <= 0) { DBGMSG( DBG_WARNING, ("Document Properties (get size) for '%ws' returned %d\n", lpstrName,lcbNeeded)); goto error; }
lpdm = (LPDEVMODE) AllocSplMem(lcbNeeded); if (lpdm) {
lpdm->dmSize = sizeof(DEVMODE); lpdm->dmFields = DM_COLOR; lpdm->dmColor = DMCOLOR_COLOR;
if (IDOK == (*pfnDocumentProperties)(NULL, hPrinter, lpstrMe, lpdm, lpdm, DM_IN_BUFFER | DM_OUT_BUFFER)) {
// Finally, we can create the DC!
HDC hdcThis = CreateDC(NULL, lpstrName, NULL, lpdm);
if (hdcThis) { bReturn = 2 < (unsigned) GetDeviceCaps(hdcThis, NUMCOLORS); DeleteDC(hdcThis); } } else DBGMSG(DBG_WARNING, ("DocumentProperties (retrieve) on '%s' failed- error %d\n", lpstrName, GetLastError())); } else DBGMSG(DBG_WARNING, ("ThisIsAColorPrinter(%s) failed to get %d bytes\n", lpstrName, lcbNeeded));
error:
FreeSplMem(lpdm);
if (hPrinter) (*pfnClosePrinter)(hPrinter);
return bReturn; }
HRESULT GetSID( IADs *pADs, PWSTR *ppszObjectSID ) /*++
Function Description: This function returns the ObjectSID of a given ADs user object. ppszObjectGUID must be freed by caller using FreeSplStr().
Parameters: pADs - input ADs object pointer ppszObjectSID - objectSID of pADs
Return Values: HRESULT --*/ { HRESULT hr; LPWSTR pszObjectSID = NULL; SID ObjectSID;
hr = pADs->GetInfo();
if (SUCCEEDED(hr)) {
hr = get_SID_Property(pADs, L"ObjectSID", &pszObjectSID);
if (SUCCEEDED(hr)) {
if (!(*ppszObjectSID = AllocSplStr(pszObjectSID))) {
hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); }
LocalFree(pszObjectSID); } }
return hr; }
HRESULT GetGUID( IADs *pADs, PWSTR *ppszObjectGUID ) /*++
Function Description: This function returns the ObjectGUID of a given ADs object. ppszObjectGUID must be freed by caller using FreeSplStr().
Parameters: pADs - input ADs object pointer ppszObjectGUID - object GUID of pADs
Return Values: HRESULT --*/ { HRESULT hr; LPOLESTR pszObjectGUID = NULL; IID ObjectIID;
hr = pADs->GetInfo();
if (SUCCEEDED(hr)) { hr = get_UI1Array_Property(pADs, L"ObjectGUID", &ObjectIID);
if (SUCCEEDED(hr)) { hr = StringFromIID(ObjectIID, &pszObjectGUID);
if (SUCCEEDED(hr)) { if (!(*ppszObjectGUID = AllocSplStr(pszObjectGUID))) hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); } CoTaskMemFree(pszObjectGUID); } }
return hr; }
BOOL PrinterPublishProhibited() { return !GetSpoolerNumericPolicy(szPublishPrinters, DEFAULT_PRINT_PUBLISH_POLICY); }
DWORD VerifyPublishedStatePolicy() { return GetSpoolerNumericPolicy(szVerifyPublishedState, DEFAULT_VERIFY_PUBLISHED_STATE); }
DWORD PruneDownlevel() { return GetSpoolerNumericPolicy(szPruneDownlevel, DEFAULT_PRUNE_DOWNLEVEL); }
DWORD PruningInterval( ) { return GetSpoolerNumericPolicy(szPruningInterval, DEFAULT_PRUNING_INTERVAL); }
DWORD ImmortalPolicy( ) { return GetSpoolerNumericPolicy(szImmortal, DEFAULT_IMMORTAL); }
VOID ServerThreadPolicy( BOOL bHaveDs ) { DWORD dwPolicy;
dwPolicy = GetSpoolerNumericPolicy(szServerThreadPolicy, SERVER_THREAD_UNCONFIGURED);
if (dwPolicy == SERVER_THREAD_UNCONFIGURED) { ServerThreadRunning = !(bHaveDs ? SERVER_THREAD_OFF : SERVER_THREAD_ON); } else { ServerThreadRunning = !dwPolicy; } CreateServerThread(); }
DWORD PruningRetries( ) { DWORD dwPruningRetries;
dwPruningRetries = GetSpoolerNumericPolicy(szPruningRetries, DEFAULT_PRUNING_RETRIES);
if (dwPruningRetries > MAX_PRUNING_RETRIES) dwPruningRetries = MAX_PRUNING_RETRIES;
return dwPruningRetries; }
DWORD PruningRetryLog( ) { DWORD dwPruningRetryLog;
dwPruningRetryLog = GetSpoolerNumericPolicy(szPruningRetryLog, DEFAULT_PRUNING_RETRY_LOG);
return dwPruningRetryLog; }
VOID SetPruningPriority( ) { DWORD dwPriority = GetSpoolerNumericPolicy(szPruningPriority, DEFAULT_PRUNING_PRIORITY);
if (dwPriority != dwLastPruningPriority) { if (dwPriority == THREAD_PRIORITY_LOWEST || dwPriority == THREAD_PRIORITY_BELOW_NORMAL || dwPriority == THREAD_PRIORITY_NORMAL || dwPriority == THREAD_PRIORITY_ABOVE_NORMAL || dwPriority == THREAD_PRIORITY_HIGHEST) { SetThreadPriority(GetCurrentThread(), DEFAULT_PRUNING_PRIORITY); } else { SetThreadPriority(GetCurrentThread(), dwPriority); } dwLastPruningPriority = dwPriority; } }
BOOL ThisMachineIsADC( ) { NT_PRODUCT_TYPE NtProductType; RtlGetNtProductType(&NtProductType); return NtProductType == NtProductLanManNt; }
DWORD GetDomainRoot( PWSTR *ppszDomainRoot ) /*++
Function Description: This function returns the ADsPath of the root of the current domain
Parameters: ppszDomainRoot - pointer to buffer receiving string pointer of domain root ADsPath string free ppszDomainRoot with a call to FreeSplMem
Return Values: DWORD
--*/ { DWORD dwRet = ERROR_SUCCESS; PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole = NULL; DS_NAME_RESULT *pDNR = NULL; DOMAIN_CONTROLLER_INFO *pDCI = NULL; HANDLE hDS = NULL; WCHAR szName[MAX_PATH + 1]; PWSTR pNames[2]; PWSTR pszDomainRoot; DWORD cb;
if (!ppszDomainRoot) { dwRet = ERROR_INVALID_PARAMETER; goto error; }
// Get Domain name
dwRet = DsRoleGetPrimaryDomainInformation(NULL, DsRolePrimaryDomainInfoBasic, (PBYTE *) &pDsRole); if (dwRet) goto error;
StringCchPrintf(szName, COUNTOF(szName), L"%ws\\", pDsRole->DomainNameFlat);
pNames[0] = szName; pNames[1] = NULL;
dwRet = Bind2DS(&hDS, &pDCI, DS_DIRECTORY_SERVICE_PREFERRED); if (dwRet != ERROR_SUCCESS) { goto error; }
if (!(DsCrackNames( hDS, DS_NAME_NO_FLAGS, DS_UNKNOWN_NAME, DS_FQDN_1779_NAME, 1, &pNames[0], &pDNR) == ERROR_SUCCESS)) {
dwRet = GetLastError(); goto error; }
if (pDNR->rItems[0].status != DS_NAME_NO_ERROR) { dwRet = DsCrackNamesStatus2Win32Error(pDNR->rItems[0].status); goto error; }
// LDAP:// + pDCName + 1
cb = (wcslen(pDNR->rItems[0].pName) + 8)*sizeof(WCHAR);
if (!(*ppszDomainRoot = (PWSTR) AllocSplMem(cb))) { dwRet = GetLastError(); goto error; }
StringCbPrintf(*ppszDomainRoot, cb, L"LDAP://%ws", pDNR->rItems[0].pName);
error:
if (pDNR) DsFreeNameResult(pDNR);
if (hDS) DsUnBind(&hDS);
if (pDCI) NetApiBufferFree(pDCI);
if (pDsRole) DsRoleFreeMemory((PVOID) pDsRole);
return dwRet; }
PWSTR CreateSearchString( PWSTR pszIn ) { PWSTR psz, pszSS; PWSTR pszSearchString = NULL; DWORD cb;
/* Replace \ with \5c */
/* Count chars & pad */
for (cb = 0, psz = pszIn ; *psz ; ++psz, ++cb) { if (*psz == L'\\') cb += 2; } cb = (cb + 1)*sizeof *psz;
if (pszSearchString = (PWSTR) GlobalAlloc(GMEM_FIXED, cb)) {
for(psz = pszIn, pszSS = pszSearchString ; *psz ; ++psz, ++pszSS) { *pszSS = *psz;
if (*psz == L'\\') { *++pszSS = L'5'; *++pszSS = L'c'; } } *pszSS = L'\0'; }
return pszSearchString; }
BOOL ServerOnSite( PWSTR *ppszMySites, ULONG cMySites, PWSTR pszServer ) /*++
Function Description: This function returns TRUE if pszServer is on one of the ppszMySites and pszServer exists
Parameters: ppszMySites - input sites pszServer - input server name
Return Values: BOOL - TRUE if server exists on site, FALSE otherwise or on error
--*/ { PSOCKET_ADDRESS pSocketAddresses = NULL; PWSTR *ppszSiteNames = NULL; DWORD nAddresses; DWORD dwRet, i; ULONG j; WORD wVersion; WSADATA WSAData; BOOL bServerOnSite = FALSE;
wVersion = MAKEWORD(1, 1);
if (WSAStartup(wVersion, &WSAData) == ERROR_SUCCESS) {
// Find out if Server is on Site
GetSocketAddressesFromMachineName(pszServer, &pSocketAddresses, &nAddresses);
if (nAddresses == 0) { bServerOnSite = TRUE; // Claim server is on site if we can't find it
} else { dwRet = DsAddressToSiteNames( (PCWSTR) NULL, nAddresses, pSocketAddresses, &ppszSiteNames); if (dwRet == NO_ERROR) { for(i = 0 ; i < nAddresses ; ++i) { for(j = 0 ; j < cMySites ; ++j) { if (ppszSiteNames[i] && ppszMySites[j] && !wcscmp(ppszSiteNames[i], ppszMySites[j])) { bServerOnSite = TRUE; break; } } } } }
if (ppszSiteNames) NetApiBufferFree(ppszSiteNames);
if (pSocketAddresses) FreeSplSockets(pSocketAddresses, nAddresses);
WSACleanup(); }
return bServerOnSite; }
VOID FreeSplSockets( PSOCKET_ADDRESS pSocketAddress, DWORD nAddresses ) { DWORD i; PSOCKET_ADDRESS pSocket;
for(i = 0, pSocket = pSocketAddress ; i < nAddresses ; ++i, ++pSocket) FreeSplMem(pSocket->lpSockaddr);
FreeSplMem(pSocketAddress); }
VOID AllocSplSockets( struct hostent *pHostEnt, PSOCKET_ADDRESS *ppSocketAddress, DWORD *nSocketAddresses ) { DWORD i; PSOCKET_ADDRESS pSocket;
for ( *nSocketAddresses = 0 ; pHostEnt->h_addr_list[*nSocketAddresses] ; ++(*nSocketAddresses)) ;
// Allocate SOCKET_ADDRESS array
*ppSocketAddress = (PSOCKET_ADDRESS) AllocSplMem(*nSocketAddresses*sizeof(SOCKET_ADDRESS)); if (!*ppSocketAddress) *nSocketAddresses = 0;
// Allocate Sockaddr element for each SOCKET_ADDRESS
// If we fail partway through, just use partial list
for (i = 0, pSocket = *ppSocketAddress ; i < *nSocketAddresses ; ++i, ++pSocket) { if (!(pSocket->lpSockaddr = (struct sockaddr *) AllocSplMem(sizeof(struct sockaddr_in)))) { *nSocketAddresses = i; break; } if (pHostEnt->h_addrtype == AF_INET) { ((struct sockaddr_in *) pSocket->lpSockaddr)->sin_family = AF_INET; ((struct sockaddr_in *) pSocket->lpSockaddr)->sin_addr = *(struct in_addr *) pHostEnt->h_addr_list[i]; pSocket->iSockaddrLength = sizeof(struct sockaddr_in); } else { DBGMSG(DBG_WARNING,("AllocSplSockets: addrtype != AF_INET: %d\n", pHostEnt->h_addrtype)); } } }
VOID GetSocketAddressesFromMachineName( PWSTR pszMachineName, // \\Machine
PSOCKET_ADDRESS *ppSocketAddress, DWORD *nSocketAddresses ) /*++
Routine Description: This routine builds list of names other than the machine name that can be used to call spooler APIs.
--*/ { struct hostent *HostEnt; PSTR pszAnsiMachineName = NULL; DWORD iWsaError;
*nSocketAddresses = 0; *ppSocketAddress = 0;
if (SUCCEEDED(UnicodeToAnsiString(pszMachineName + 2, &pszAnsiMachineName))) { if (HostEnt = gethostbyname(pszAnsiMachineName)) { AllocSplSockets(HostEnt, ppSocketAddress, nSocketAddresses); } else { iWsaError = WSAGetLastError(); DBGMSG(DBG_WARNING, ("gethostbyname failed in DsPrune: %d\n", iWsaError)); } }
FreeSplMem(pszAnsiMachineName); }
DWORD UNC2Server( PCWSTR pszUNC, PWSTR *ppszServer ) { PWSTR psz; DWORD cb; DWORD nChars;
if (!pszUNC || pszUNC[0] != L'\\' || pszUNC[1] != L'\\') return ERROR_INVALID_PARAMETER;
if(!(psz = wcschr(pszUNC + 2, L'\\'))) return ERROR_INVALID_PARAMETER;
cb = (DWORD) ((ULONG_PTR) psz - (ULONG_PTR) pszUNC + sizeof *psz);
if (!(*ppszServer = (PWSTR) AllocSplMem(cb))) return GetLastError();
nChars = (DWORD) (psz - pszUNC); wcsncpy(*ppszServer, pszUNC, nChars); (*ppszServer)[nChars] = L'\0';
return ERROR_SUCCESS; }
BOOL ServerExists( PWSTR pszServerName ) { NET_API_STATUS Status; SERVER_INFO_100 *pServer; BOOL bServerExists;
Status = NetServerGetInfo(pszServerName, 100, (PBYTE *) &pServer); bServerExists = !Status; Status = NetApiBufferFree(pServer);
return bServerExists; }
HRESULT UnpublishByGUID( PINIPRINTER pIniPrinter ) { HRESULT hr;
SplOutSem();
if (!pIniPrinter->pszObjectGUID) { pIniPrinter->DsKeyUpdate = 0; pIniPrinter->DsKeyUpdateForeground = 0; hr = S_OK;
} else {
PWSTR pszDN = NULL; PWSTR pszCN = NULL;
hr = GetPublishPointFromGUID(NULL, pIniPrinter->pszObjectGUID, &pszDN, &pszCN, TRUE);
DBGMSG(DBG_EXEC, ("UnpublishByGUID: GUID %ws\n", pIniPrinter->pszObjectGUID));
if (SUCCEEDED(hr)) {
DBGMSG(DBG_EXEC, ("UnpublishByGUID: DN %ws CN %ws\n", pszDN, pszCN));
IADsContainer *pADsContainer = NULL;
// Get the container
hr = ADsGetObject( pszDN, IID_IADsContainer, (void **) &pADsContainer );
if (SUCCEEDED(hr)) { hr = pADsContainer->Delete(SPLDS_PRINTER_CLASS, pszCN); pADsContainer->Release(); }
// If the container or the object is gone, succeed
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;
} FreeSplStr(pszDN); FreeSplStr(pszCN); }
// free GUID if object is deleted
if (SUCCEEDED(hr)) { pIniPrinter->DsKeyUpdate = 0; pIniPrinter->DsKeyUpdateForeground = 0;
FreeSplStr(pIniPrinter->pszObjectGUID); pIniPrinter->pszObjectGUID = NULL;
FreeSplStr(pIniPrinter->pszCN); pIniPrinter->pszCN = NULL;
FreeSplStr(pIniPrinter->pszDN); pIniPrinter->pszDN = NULL;
EnterSplSem();
if (pIniPrinter->bDsPendingDeletion) { pIniPrinter->bDsPendingDeletion = 0; DECPRINTERREF(pIniPrinter); }
LeaveSplSem();
DBGMSG(DBG_EXEC, ("UnpublishByGUID Succeeded\n")); } else { pIniPrinter->DsKeyUpdate = DS_KEY_UNPUBLISH; DBGMSG(DBG_EXEC, ("UnpublishByGUID Failed\n")); }
SplOutSem();
return hr; }
HRESULT GetDNSMachineName( PWSTR pszShortMachineName, PWSTR *ppszMachineName ) { struct hostent *pHostEnt; DWORD dwRet = ERROR_SUCCESS; HRESULT hr = S_OK; PSTR pszAnsiMachineName = NULL; WORD wVersion; WSADATA WSAData;
wVersion = MAKEWORD(1, 1);
dwRet = WSAStartup(wVersion, &WSAData);
if (dwRet == ERROR_SUCCESS) {
if (!pszShortMachineName || !*pszShortMachineName) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_INVALID_PARAMETER); BAIL_ON_FAILURE(hr); }
hr = UnicodeToAnsiString(pszShortMachineName, &pszAnsiMachineName); BAIL_ON_FAILURE(hr);
if (!(pHostEnt = gethostbyname(pszAnsiMachineName))) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, WSAGetLastError()); BAIL_ON_FAILURE(hr); }
if (!(*ppszMachineName = AnsiToUnicodeStringWithAlloc(pHostEnt->h_name))) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); BAIL_ON_FAILURE(hr); }
} else { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwRet); }
error:
if (dwRet == ERROR_SUCCESS) { WSACleanup(); }
FreeSplMem(pszAnsiMachineName);
return hr; }
HRESULT GetClusterUser( IADs **ppADs ) { HRESULT hr; WCHAR szUserName[MAX_PATH + 8]; // Allow for LDAP://
PWSTR pszUserName = szUserName; DWORD cchUserName = MAX_PATH + 1; BOOL bRet;
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if (FAILED(hr)) return hr;
// Get cluster container's name, which must be the current user name
StringCchCopy(pszUserName, COUNTOF(szUserName), L"LDAP://");
if (!GetUserNameEx(NameFullyQualifiedDN, pszUserName + 7, &cchUserName)) { if (cchUserName > MAX_PATH + 1) {
pszUserName = (PWSTR) AllocSplMem((cchUserName + 7)*sizeof(WCHAR)); if (!pszUserName) { hr = MAKE_HRESULT( SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); goto error; }
StringCchPrintf(pszUserName, cchUserName + 7, L"LDAP://");
if (!GetUserNameEx(NameFullyQualifiedDN, pszUserName + 7, &cchUserName)) { hr = MAKE_HRESULT( SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); goto error; }
} else { hr = MAKE_HRESULT( SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); goto error; } }
// Get the object
hr = ADsGetObject( pszUserName, IID_IADs, (void **) ppADs ); BAIL_ON_FAILURE(hr);
error:
if (pszUserName != szUserName) FreeSplStr(pszUserName);
CoUninitialize();
return hr; }
HRESULT FQDN2Whatever( PWSTR pszIn, PWSTR *ppszOut, DS_NAME_FORMAT NameFormat ) { DWORD dwRet = ERROR_SUCCESS; DS_NAME_RESULT *pDNR = NULL; DOMAIN_CONTROLLER_INFO *pDCI = NULL; HANDLE hDS = NULL; PWSTR pNames[2]; PWSTR psz; HRESULT hr = S_OK;
*ppszOut = NULL;
// Get the DC name
dwRet = Bind2DS(&hDS, &pDCI, DS_DIRECTORY_SERVICE_PREFERRED); if (dwRet != ERROR_SUCCESS) goto error;
// Translate the name
if (wcslen(pszIn) < 8) { dwRet = ERROR_INVALID_PARAMETER; goto error; }
psz = wcschr(pszIn + 7, L'/'); if (!psz) { dwRet = ERROR_INVALID_PARAMETER; goto error; }
pNames[0] = ++psz; // Input string is LDAP://ntdev.microsoft.com/CN=... Strip off the LDAP://.../ portion
pNames[1] = NULL;
if (!(DsCrackNames( hDS, DS_NAME_NO_FLAGS, DS_FQDN_1779_NAME, NameFormat, 1, &pNames[0], &pDNR) == ERROR_SUCCESS)) {
dwRet = GetLastError(); goto error; }
if (pDNR->rItems[0].status != DS_NAME_NO_ERROR) { dwRet = DsCrackNamesStatus2Win32Error(pDNR->rItems[0].status); goto error; }
*ppszOut = AllocSplStr(pDNR->rItems[0].pName);
error:
if (pDNR) DsFreeNameResult(pDNR);
if (hDS) DsUnBind(&hDS);
if (pDCI) NetApiBufferFree(pDCI);
return dwRet == ERROR_SUCCESS ? S_OK : MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwRet); }
DWORD InitializeDSClusterInfo( PINISPOOLER pIniSpooler, HANDLE *phToken ) { HRESULT hr = S_OK; DWORD dwError = ERROR_SUCCESS; IADs *pADs = NULL;
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if (FAILED(hr)) { return HRESULT_CODE(hr); }
// Impersonate the client
if (!ImpersonatePrinterClient(*phToken)) { dwError = GetLastError(); DBGMSG(DBG_WARNING,("InitializeDSClusterInfo FAILED: %d\n", dwError)); CoUninitialize(); return dwError; }
// Get a copy of the client token
dwError = NtOpenThreadToken(NtCurrentThread(), TOKEN_IMPERSONATE, TRUE, &pIniSpooler->hClusterToken); if (dwError != STATUS_SUCCESS) { DBGMSG(DBG_WARNING,("InitializeDSClusterInfo DuplicateToken FAILED: %d\n", dwError)); pIniSpooler->hClusterToken = INVALID_HANDLE_VALUE; goto error; }
// Get the Cluster User Object
if (SUCCEEDED(hr = GetClusterUser(&pADs))) {
hr = GetSID(pADs, &pIniSpooler->pszClusterSID); }
error:
*phToken = RevertToPrinterSelf();
if (FAILED(hr)) { dwError = HRESULT_CODE(hr); FreeSplStr(pIniSpooler->pszClusterSID); pIniSpooler->pszClusterSID = NULL; }
if (pADs) pADs->Release();
CoUninitialize();
return dwError; }
BOOL CheckPublishedPrinters( ) { PINIPRINTER pIniPrinter; BOOL bHavePublishedPrinters = FALSE;
SplInSem();
if (VerifyPublishedStatePolicy() == INFINITE) return FALSE;
RunForEachSpooler(&bHavePublishedPrinters, CheckPublishedSpooler);
return bHavePublishedPrinters; }
BOOL CheckPublishedSpooler( HANDLE h, PINISPOOLER pIniSpooler ) { PBOOL pbHavePublishedPrinters = (PBOOL)h; PINIPRINTER pIniPrinter;
if (!(pIniSpooler->SpoolerFlags & SPL_TYPE_LOCAL)) return TRUE;
for (pIniPrinter = pIniSpooler->pIniPrinter ; pIniPrinter ; pIniPrinter = pIniPrinter->pNext) { if (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
// Refresh: verify that we're really published
// Note that if there isn't any new info to publish and we're published,
// we won't do any SetInfo so the overhead is minimal
pIniPrinter->DsKeyUpdate |= DS_KEY_PUBLISH; *pbHavePublishedPrinters = TRUE;
} else if (pIniPrinter->pszObjectGUID) {
// The only way we can get here is if someone is unpublishing the printer,
// so we don't really need to set the background DsKeyUpdate state. Doing
// so maintains symmetry with above statement and InitializeDS
pIniPrinter->DsKeyUpdate |= DS_KEY_UNPUBLISH; *pbHavePublishedPrinters = TRUE; } }
return TRUE; }
PWSTR CreateEscapedString( PCWSTR pszIn, PCWSTR pszSpecialChars ) { PWSTR psz, pszO; PWSTR pszOut = NULL; DWORD cb;
if (!pszIn || !pszSpecialChars) { SetLastError(ERROR_INVALID_NAME); return NULL; }
// Count special characters
for (cb = 0, psz = (PWSTR) pszIn ; psz = wcspbrk(psz, pszSpecialChars) ; ++cb, ++psz) ;
// Add in length of input string
cb = (wcslen(pszIn) + cb + 1)*sizeof *pszIn;
// Allocate output buffer and precede special DS chars with '\'
if (pszOut = (PWSTR) AllocSplMem(cb)) {
for(psz = (PWSTR) pszIn, pszO = pszOut ; *psz ; ++psz, ++pszO) { if (wcschr(pszSpecialChars, *psz)) { *pszO++ = L'\\'; } *pszO = *psz; } *pszO = L'\0'; }
return pszOut; }
PWSTR DevCapStrings2MultiSz( PWSTR pszDevCapString, DWORD nDevCapStrings, DWORD dwDevCapStringLength, DWORD *pcbBytes ) { DWORD i, cbBytes, cbSize; PWSTR pszMultiSz = NULL; PWSTR pStr;
if (!pszDevCapString || !pcbBytes) return NULL;
*pcbBytes = 0;
//
// Devcap buffers may not be NULL terminated
//
cbBytes = (nDevCapStrings*(dwDevCapStringLength + 1) + 1)*sizeof(WCHAR);
//
// Allocate and copy
//
if (pszMultiSz = (PWSTR) AllocSplMem(cbBytes)) { for(i = 0, pStr = pszMultiSz, cbBytes = 0 ; i < nDevCapStrings ; ++i, pStr += cbSize, cbBytes +=cbSize ) { wcsncpy(pStr, pszDevCapString + i*dwDevCapStringLength, dwDevCapStringLength); cbSize = *pStr ? wcslen(pStr) + 1 : 0; } *pStr = L'\0'; *pcbBytes = (cbBytes + 1) * sizeof(WCHAR); }
return pszMultiSz; }
DWORD Bind2DS( HANDLE *phDS, DOMAIN_CONTROLLER_INFO **ppDCI, ULONG Flags ) { DWORD dwRet;
dwRet = DsGetDcName(NULL, NULL, NULL, NULL, Flags, ppDCI); if (dwRet == ERROR_SUCCESS) {
if ((*ppDCI)->Flags & DS_DS_FLAG) {
dwRet = DsBind (NULL, (*ppDCI)->DomainName, phDS); if (dwRet != ERROR_SUCCESS) {
NetApiBufferFree(*ppDCI); *ppDCI = NULL;
if (!(Flags & DS_FORCE_REDISCOVERY)) { dwRet = Bind2DS(phDS, ppDCI, DS_FORCE_REDISCOVERY | Flags); } } } else { NetApiBufferFree(*ppDCI); *ppDCI = NULL; dwRet = ERROR_CANT_ACCESS_DOMAIN_INFO; } }
return dwRet; }
DWORD DsCrackNamesStatus2Win32Error( DWORD dwStatus ) { switch (dwStatus) { case DS_NAME_ERROR_RESOLVING: return ERROR_DS_NAME_ERROR_RESOLVING;
case DS_NAME_ERROR_NOT_FOUND: return ERROR_DS_NAME_ERROR_NOT_FOUND;
case DS_NAME_ERROR_NOT_UNIQUE: return ERROR_DS_NAME_ERROR_NOT_UNIQUE;
case DS_NAME_ERROR_NO_MAPPING: return ERROR_DS_NAME_ERROR_NO_MAPPING;
case DS_NAME_ERROR_DOMAIN_ONLY: return ERROR_DS_NAME_ERROR_DOMAIN_ONLY;
case DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING: return ERROR_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING; }
return ERROR_FILE_NOT_FOUND; }
DWORD GetDSSleepInterval ( HANDLE h ) { DWORD dwVerifyPublishedStateInterval; PDSUPDATEDATA pData = (PDSUPDATEDATA)h; DWORD dwTimeToSleep = 30 * ONE_MINUTE; //
// 30 min is the minimum interval that can be set with the policy editor.
// If someone enables the policy while we are sleeping, then we need to wake up
// to pick the settings. This doesn't apply if the DS doesn't respond.
//
if (pData && pData->bSleep) {
//
// If the updating is failing, Data.bSleep is set to TRUE.
// This happens when the DS is down.
//
dwTimeToSleep = pData->dwSleepTime;
//
// Sleep interval is doubled to a maximum of 2 hours.
// We still want to attempt publishing every 2 hours. We also attempt if
// a "publish" action is taken(the even will be signaled).
//
//
pData->dwSleepTime = pData->dwSleepTime * 2 > 2 * ONE_HOUR ? 2 * ONE_HOUR : pData->dwSleepTime * 2;
} else {
dwTimeToSleep = VerifyPublishedStatePolicy();
if (dwTimeToSleep != INFINITE) { dwTimeToSleep *= ONE_MINUTE; } }
return dwTimeToSleep; }
|