windows-nt/Source/XPSP1/NT/printscan/print/spooler/spoolss/client/dsutil.cxx
2020-09-26 16:20:57 +08:00

1356 lines
32 KiB
C++

/*++
Copyright (c) 1997 Microsoft Corporation
Abstract:
This module provides utilities useful for Directory Service interactions
Author:
Steve Wilson (NT) November 1997
Revision History:
--*/
#define INC_OLE2
#include "precomp.h"
#pragma hdrstop
#include "client.h"
#include "pubprn.hxx"
#include "varconv.hxx"
#include "property.hxx"
#include "dsutil.hxx"
#include "winsprlp.h"
#include "dnsapi.h"
#define DN_SPECIAL_CHARS L",=\r\n+<>#;\"\\"
#define DN_SPECIAL_FILTER_CHARS L"\\*()"
PWSTR
GetUNCName(
HANDLE hPrinter
)
{
PPRINTER_INFO_2 pInfo2 = NULL;
DWORD cbNeeded;
PWSTR pszUNCName = NULL;
if (!GetPrinter(hPrinter, 2, (PBYTE) pInfo2, 0, &cbNeeded)) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
goto error;
}
if (!(pInfo2 = (PPRINTER_INFO_2) AllocSplMem(cbNeeded)))
goto error;
if (!GetPrinter(hPrinter, 2, (PBYTE) pInfo2, cbNeeded, &cbNeeded))
goto error;
// pPrinterName is already in correct UNC format since we
// opened handle with UNC name: just copy it
cbNeeded = wcslen(pInfo2->pPrinterName) + 1;
cbNeeded *= sizeof(WCHAR);
if (!(pszUNCName = (PWSTR) AllocSplMem(cbNeeded)))
goto error;
wcscpy(pszUNCName, pInfo2->pPrinterName);
error:
if (pInfo2)
FreeSplMem(pInfo2);
return pszUNCName;
}
PWSTR
CreateEscapedDN(
PCWSTR pszIn
)
{
PWSTR psz, pszO;
PWSTR pszOut = NULL;
DWORD cb;
// Count special characters
for (cb = 0, psz = (PWSTR) pszIn ; psz = wcspbrk(psz, DN_SPECIAL_FILTER_CHARS) ; ++cb, ++psz)
;
// Add in length of input string
// 2 = (\5c) - '\'
cb = (wcslen(pszIn) + cb*2 + 1)*sizeof *pszIn;
// Allocate output buffer and replace special chars with \HexEquivalent
// Ex: replace \ with \5c , ( with \28
if (pszOut = (PWSTR) AllocSplMem(cb)) {
for(psz = (PWSTR) pszIn, pszO = pszOut ; *psz ; ++psz) {
if (wcschr(DN_SPECIAL_FILTER_CHARS, *psz)) {
pszO += wsprintf(pszO, L"\\%x", *psz);
} else {
*pszO++ = *psz;
}
}
*pszO = L'\0';
}
return pszOut;
}
DWORD
PrintQueueExists(
HWND hwnd,
HANDLE hPrinter,
PWSTR pszUNCName,
DWORD dwAction,
PWSTR pszTargetDN,
PWSTR *ppszObjectDN
)
{
HRESULT hr = S_OK;
DWORD dwRet = ERROR_SUCCESS;
WCHAR szSearchPattern[MAX_UNC_PRINTER_NAME + 50];
WCHAR szFullUNCName[MAX_UNC_PRINTER_NAME];
PWSTR pNames[2];
WCHAR szName[MAX_PATH + 1];
WCHAR szDuplicateFormat[1024];
PWSTR pszSearchRoot = NULL;
PWSTR pszDuplicate = NULL;
PWSTR pszUNCNameSearch = NULL;
IDirectorySearch *pDSSearch = NULL;
DS_NAME_RESULT *pDNR = NULL;
DOMAIN_CONTROLLER_INFO *pDCI = NULL;
HANDLE hDS = NULL;
ADS_SEARCH_HANDLE hSearchHandle = NULL;
ADS_SEARCH_COLUMN ADsPath;
ADS_SEARCH_COLUMN UNCName;
PWSTR pszAttributes[] = {L"ADsPath", L"UNCName"};
DWORD nSize;
BOOL bRet = FALSE;
BOOL bDeleteDuplicate;
PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole = NULL;
dwRet = DsRoleGetPrimaryDomainInformation(NULL, DsRolePrimaryDomainInfoBasic, (PBYTE *) &pDsRole);
if (dwRet != ERROR_SUCCESS)
goto error;
wsprintf(szName, L"%ws\\", pDsRole->DomainNameFlat);
pNames[0] = szName;
pNames[1] = NULL;
dwRet = Bind2DS(&hDS, &pDCI, DS_GC_SERVER_REQUIRED);
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) {
if (pDNR->rItems[0].status == DS_NAME_ERROR_RESOLVING)
dwRet = ERROR_PATH_NOT_FOUND;
else
dwRet = pDNR->rItems[0].status;
goto error;
}
// GC:// + pDCName + 1
nSize = (wcslen(pDNR->rItems[0].pName) + 6)*sizeof(WCHAR);
if (!(pszSearchRoot = (PWSTR) AllocSplMem(nSize))) {
dwRet = GetLastError();
goto error;
}
wsprintf(pszSearchRoot, L"GC://%ws", pDNR->rItems[0].pName);
hr = ADsGetObject( pszSearchRoot,
IID_IDirectorySearch,
(void **)&pDSSearch);
BAIL_ON_FAILURE(hr);
if (!(pszUNCNameSearch = CreateEscapedDN(pszUNCName))) {
dwRet = GetLastError();
goto error;
}
wsprintf(szSearchPattern, L"(&(objectClass=printQueue)(uNCName=%ws))", pszUNCNameSearch);
hr = pDSSearch->ExecuteSearch(
szSearchPattern,
pszAttributes,
sizeof(pszAttributes)/sizeof *pszAttributes,
&hSearchHandle);
BAIL_ON_FAILURE(hr);
hr = pDSSearch->GetNextRow(hSearchHandle);
BAIL_ON_FAILURE(hr);
while (hr != S_ADS_NOMORE_ROWS) {
hr = pDSSearch->GetColumn(
hSearchHandle,
L"ADsPath",
&ADsPath
);
if (hr == S_OK) {
hr = pDSSearch->GetColumn(
hSearchHandle,
L"UNCName",
&UNCName
);
if (hr == S_OK) {
switch (dwAction) {
case PUBLISHPRINTER_QUERY:
if (!LoadString(hInst, IDS_DUPLICATE_PRINTQUEUE, szDuplicateFormat, COUNTOF(szDuplicateFormat))) {
dwRet = GetLastError();
goto error;
}
nSize = wcslen(szDuplicateFormat);
nSize += wcslen(ADsPath.pADsValues->DNString);
nSize += wcslen(pszTargetDN);
nSize = (nSize + 1)*sizeof(WCHAR);
if (!(pszDuplicate = (PWSTR) AllocSplMem(nSize))) {
dwRet = GetLastError();
goto error;
}
PWSTR pszCanonicalSource;
PWSTR pszCanonicalTarget;
pszCanonicalSource = pszCanonicalTarget = NULL;
FQDN2Canonical(ADsPath.pADsValues->DNString, &pszCanonicalSource);
FQDN2Canonical(pszTargetDN, &pszCanonicalTarget);
if (!pszCanonicalSource || !pszCanonicalTarget) {
wsprintf(pszDuplicate, szDuplicateFormat, ADsPath.pADsValues->DNString, pszTargetDN);
} else {
wsprintf(pszDuplicate, szDuplicateFormat, pszCanonicalSource, pszCanonicalTarget);
}
FreeSplStr(pszCanonicalSource);
FreeSplStr(pszCanonicalTarget);
if (!LoadString(hInst, IDS_DUPLICATE_PRINTQUEUE_TITLE, szDuplicateFormat, COUNTOF(szDuplicateFormat)))
goto error;
dwRet = MessageBox( hwnd,
pszDuplicate,
szDuplicateFormat,
MB_YESNO);
bDeleteDuplicate = (dwRet == IDYES);
dwRet = (dwRet == IDYES) ? ERROR_SUCCESS : ERROR_CANCELLED;
pszDuplicate = NULL;
break;
case PUBLISHPRINTER_DELETE_DUPLICATES:
bDeleteDuplicate = TRUE;
break;
case PUBLISHPRINTER_FAIL_ON_DUPLICATE:
bDeleteDuplicate = FALSE;
if (ppszObjectDN) {
if (!(*ppszObjectDN = AllocGlobalStr(ADsPath.pADsValues->DNString))) {
dwRet = GetLastError();
goto error;
}
}
dwRet = ERROR_FILE_EXISTS;
break;
case PUBLISHPRINTER_IGNORE_DUPLICATES:
bDeleteDuplicate = FALSE;
break;
default:
bDeleteDuplicate = FALSE;
dwRet = ERROR_INVALID_PARAMETER;
break;
}
if (bDeleteDuplicate) {
hr = DeleteDSObject(ADsPath.pADsValues->DNString);
if ( hr == ERROR_DS_NO_SUCH_OBJECT ) {
hr = S_OK;
}
}
pDSSearch->FreeColumn(&UNCName);
}
pDSSearch->FreeColumn(&ADsPath);
}
if (dwRet != ERROR_SUCCESS || hr != S_OK)
goto error;
hr = pDSSearch->GetNextRow(hSearchHandle);
BAIL_ON_FAILURE(hr);
}
hr = S_OK;
error:
if (hr != S_OK)
dwRet = ERROR_DS_UNAVAILABLE;
if (pDsRole)
DsRoleFreeMemory((PVOID) pDsRole);
if (pDNR)
DsFreeNameResult(pDNR);
if (hDS)
DsUnBind(&hDS);
if (pDCI)
NetApiBufferFree(pDCI);
if (hSearchHandle)
pDSSearch->CloseSearchHandle(hSearchHandle);
if (pszUNCNameSearch)
FreeSplMem(pszUNCNameSearch);
if (pDSSearch)
pDSSearch->Release();
if (pszSearchRoot)
FreeSplMem(pszSearchRoot);
if(pszDuplicate)
FreeSplMem(pszDuplicate);
return dwRet;
}
DWORD
MovePrintQueue(
PCWSTR pszObjectGUID,
PCWSTR pszNewContainer, // Container path
PCWSTR pszNewCN // Object CN
)
{
PWSTR pszCurrentContainer = NULL;
PWSTR pszCurrentCN = NULL;
HRESULT hr;
IADsContainer *pADsContainer = NULL;
IDispatch *pNewObject = NULL;
// Get PublishPoint from GUID
hr = GetPublishPointFromGUID(pszObjectGUID, &pszCurrentContainer, &pszCurrentCN);
BAIL_ON_FAILURE(hr);
if (pszCurrentContainer) {
// Get container
hr = ADsGetObject( pszCurrentContainer, IID_IADsContainer, (void **) &pADsContainer);
BAIL_ON_FAILURE(hr);
// Move PrintQueue
if (wcscmp(pszCurrentContainer, pszNewContainer)) {
hr = pADsContainer->MoveHere((PWSTR) pszNewContainer, (PWSTR) pszNewCN, &pNewObject);
BAIL_ON_FAILURE(hr);
}
}
error:
if (pszCurrentContainer)
FreeSplMem(pszCurrentContainer);
if (pszCurrentCN)
FreeSplMem(pszCurrentCN);
if (pADsContainer)
pADsContainer->Release();
if (pNewObject)
pNewObject->Release();
return hr;
}
HRESULT
GetPublishPointFromGUID(
PCWSTR pszObjectGUID,
PWSTR *ppszDN,
PWSTR *ppszCN
)
{
DWORD dwRet, nBytes, nChars;
PWSTR pNames[2];
DS_NAME_RESULT *pDNR = NULL;
DOMAIN_CONTROLLER_INFO *pDCI = NULL;
HANDLE hDS = NULL;
PWSTR psz;
HRESULT hr = S_OK;
dwRet = Bind2DS(&hDS, &pDCI, DS_DIRECTORY_SERVICE_PREFERRED);
if (dwRet != ERROR_SUCCESS)
goto error;
// Get Publish Point
if (ppszDN) {
pNames[0] = (PWSTR) 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();
goto error;
}
if (pDNR->rItems[0].status != DS_NAME_NO_ERROR) {
if (pDNR->rItems[0].status == DS_NAME_ERROR_RESOLVING)
dwRet = ERROR_PATH_NOT_FOUND;
else
dwRet = pDNR->rItems[0].status;
goto error;
}
// 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);
}
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)) {
FreeSplMem(*ppszCN);
FreeSplMem(*ppszDN);
*ppszCN = *ppszDN = NULL;
}
return hr;
}
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;
}
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
)
{
DWORD nBytes;
HRESULT hr;
// LDAP:// + pDCName + / + pName + 1
nBytes = (wcslen(pszDC) + wcslen(pszFQDN) + 9)*sizeof(WCHAR);
if (!(*ppszLDAPPath = (PWSTR) AllocSplMem(nBytes))) {
hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
BAIL_ON_FAILURE(hr);
}
wsprintf(*ppszLDAPPath, L"LDAP://%ws/%ws", pszDC,pszFQDN);
error:
return hr;
}
DWORD
UNC2Printer(
PCWSTR pszUNC,
PWSTR *ppszPrinter
)
{
PWSTR psz;
if (!pszUNC || pszUNC[0] != L'\\' || pszUNC[1] != L'\\')
return ERROR_INVALID_PARAMETER;
if(!(psz = wcsrchr(pszUNC + 2, L'\\')))
return ERROR_INVALID_PARAMETER;
if (!(*ppszPrinter = (PWSTR) AllocSplStr(psz + 1)))
return GetLastError();
return ERROR_SUCCESS;
}
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;
}
// Utility routine to report if a printer is color or monochrome
BOOL
ThisIsAColorPrinter(
LPCTSTR lpstrName
)
{
HANDLE hPrinter = NULL;
LPTSTR lpstrMe = const_cast <LPTSTR> (lpstrName);
BOOL bReturn = FALSE;
LPDEVMODE lpdm = NULL;
long lcbNeeded;
if (!OpenPrinter(lpstrMe, &hPrinter, NULL)) {
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 = DocumentProperties(NULL, hPrinter, lpstrMe, NULL, NULL, 0);
if (lcbNeeded <= 0) {
goto error;
}
lpdm = (LPDEVMODE) AllocSplMem(lcbNeeded);
if (lpdm) {
lpdm->dmSize = sizeof(DEVMODE);
lpdm->dmFields = DM_COLOR;
lpdm->dmColor = DMCOLOR_COLOR;
if (IDOK == DocumentProperties(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);
}
}
}
error:
FreeSplMem(lpdm);
if (hPrinter)
ClosePrinter(hPrinter);
return bReturn;
}
HRESULT
DeleteDSObject(
PWSTR pszADsPath
)
{
BSTR bstrCommonName = NULL;
PWSTR pszParent = NULL;
PWSTR pszCN = NULL;
PWSTR pszLDAPPath = NULL;
IADs *pADs = NULL;
IADsContainer *pContainer = NULL;
DWORD cb;
HRESULT hr;
DWORD nSize;
if(pszADsPath && !_wcsnicmp(pszADsPath , L"GC://" , 5)){
//
// Build LDAP://..... path from GC://.... path
// 3 comes from len(LDAP) - len(GC) + len(string_terminator)
//
nSize = (wcslen(pszADsPath) + 3)* sizeof(WCHAR);
if (!(pszLDAPPath = (PWSTR) AllocSplMem(nSize))) {
hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
goto error;
}
wsprintf(pszLDAPPath, L"LDAP%ws", pszADsPath + 2);
}
// Get PrintQueue object
hr = ADsGetObject(pszLDAPPath, IID_IADs, (void **) &pADs);
BAIL_ON_FAILURE(hr);
// Get the CommonName & don't forget the "CN="
hr = get_BSTR_Property(pADs, L"cn", &bstrCommonName);
BAIL_ON_FAILURE(hr);
cb = (SysStringLen(bstrCommonName) + 4)*sizeof(WCHAR);
if (!(pszCN = (PWSTR) AllocSplMem(cb))) {
hr = dw2hr(GetLastError());
BAIL_ON_FAILURE(hr);
}
wcscpy(pszCN, L"CN=");
wcscat(pszCN, bstrCommonName);
// Get the Parent ADsPath
hr = pADs->get_Parent(&pszParent);
BAIL_ON_FAILURE(hr);
// Get the Parent object
hr = ADsGetObject( pszParent,
IID_IADsContainer,
(void **) &pContainer);
BAIL_ON_FAILURE(hr);
// Delete the printqueue
hr = pContainer->Delete(SPLDS_PRINTER_CLASS, pszCN);
error:
if (pADs)
pADs->Release();
if (pContainer)
pContainer->Release();
if (bstrCommonName)
SysFreeString(bstrCommonName);
if (pszParent)
SysFreeString(pszParent);
if (pszCN)
FreeSplMem(pszCN);
if(pszLDAPPath)
FreeSplMem(pszLDAPPath);
return hr;
}
DWORD
GetCommonName(
HANDLE hPrinter,
PWSTR *ppszCommonName
)
{
DWORD nBytes;
PWSTR psz;
PPRINTER_INFO_2 pInfo2 = NULL;
DWORD cbNeeded;
DWORD dwRet;
PWSTR pszServerName, pszPrinterName;
// Get Server & Share names
if (!GetPrinter(hPrinter, 2, (PBYTE) pInfo2, 0, &cbNeeded)) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
dwRet = GetLastError();
goto error;
}
if (!(pInfo2 = (PPRINTER_INFO_2) AllocSplMem(cbNeeded))) {
dwRet = GetLastError();
goto error;
}
if (!GetPrinter(hPrinter, 2, (PBYTE) pInfo2, cbNeeded, &cbNeeded)) {
dwRet = GetLastError();
goto error;
}
pszServerName = pInfo2->pServerName;
if (!pszServerName) {
DBGMSG(DBG_ERROR,("GetPrinter returned NULL ServerName"));
dwRet = ERROR_INVALID_DATA;
goto error;
}
pszPrinterName = pInfo2->pShareName ? pInfo2->pShareName : pInfo2->pPrinterName;
} else {
// We should never get here. If we do, something is wrong
// with the server and we have no meaningful error to report,
// so just claim invalid data.
DBGMSG(DBG_ERROR,("INVALID GetPrinter return"));
dwRet = ERROR_INVALID_DATA;
goto error;
}
// "CN=Server-Printer"
nBytes = (wcslen(pszPrinterName) + wcslen(pszServerName) + 5)*sizeof(WCHAR);
if (!(*ppszCommonName = psz = (PWSTR) AllocSplMem(nBytes))) {
dwRet = GetLastError();
goto error;
}
// CN=
wcscpy(psz, 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(pszPrinterName) > 62)
pszPrinterName[63] = NULL;
error:
FreeSplMem(pInfo2);
return ERROR_SUCCESS;
}
PWSTR
AllocGlobalStr(
PWSTR pszIn
)
{
DWORD cb;
PWSTR pszOut = NULL;
if (!pszIn)
return NULL;
cb = (wcslen(pszIn) + 1)*sizeof *pszIn;
if (pszOut = (PWSTR) GlobalAlloc(GMEM_FIXED, cb))
wcscpy(pszOut, pszIn);
return pszOut;
}
VOID
FreeGlobalStr(
PWSTR pszIn
)
{
if (pszIn)
GlobalFree(pszIn);
}
DWORD
GetADsPathFromGUID(
PCWSTR pszObjectGUID,
PWSTR *ppszDN
)
{
DWORD dwRet, nBytes, nChars;
PWSTR pNames[2];
DS_NAME_RESULT *pDNR = NULL;
DOMAIN_CONTROLLER_INFO *pDCI = NULL;
HANDLE hDS = NULL;
PWSTR psz;
dwRet = Bind2DS(&hDS, &pDCI, DS_DIRECTORY_SERVICE_PREFERRED);
if (dwRet != ERROR_SUCCESS)
goto error;
// Get Publish Point
if (ppszDN) {
pNames[0] = (PWSTR) 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();
goto error;
}
if (pDNR->rItems[0].status != DS_NAME_NO_ERROR) {
if (pDNR->rItems[0].status == DS_NAME_ERROR_RESOLVING)
dwRet = ERROR_PATH_NOT_FOUND;
else
dwRet = pDNR->rItems[0].status;
goto error;
}
// LDAP:// + pDCName + / + pName + 1
nBytes = (wcslen(pDCI->DomainControllerName + 2) +
wcslen(pDNR->rItems[0].pName) + 9)*sizeof(WCHAR);
if (!(*ppszDN = (PWSTR) AllocSplMem(nBytes))) {
dwRet = GetLastError();
goto error;
}
wsprintf(*ppszDN, L"LDAP://%ws/%ws", pDCI->DomainControllerName + 2,pDNR->rItems[0].pName);
}
error:
if (pDNR)
DsFreeNameResult(pDNR);
if (hDS)
DsUnBind(&hDS);
if (pDCI)
NetApiBufferFree(pDCI);
if (dwRet != ERROR_SUCCESS) {
FreeSplMem(*ppszDN);
*ppszDN = NULL;
}
return dwRet;
}
PWSTR
GetDNWithServer(
PCWSTR pszDNIn
)
{
DOMAIN_CONTROLLER_INFO *pDCI = NULL;
DWORD nBytes;
PWSTR pszDNOut = NULL;
DWORD dwRet;
// Convert pszDNIn into a DN with the DC name, if it isn't already there
// Check for existing DC name or badly formed name
if (wcsncmp(pszDNIn, L"LDAP://", 7) || wcschr(pszDNIn + 7, L'/'))
goto error;
// Get DC name
dwRet = DsGetDcName(NULL, NULL, NULL, NULL, 0, &pDCI);
if (dwRet != ERROR_SUCCESS) {
goto error;
}
// Build name
// LDAP:// + pDCName + / + pName + 1
nBytes = (wcslen(pDCI->DomainControllerName + 2) +
wcslen(pszDNIn + 7) + 9)*sizeof(WCHAR);
if (!(pszDNOut = (PWSTR) AllocSplMem(nBytes)))
goto error;
wsprintf(pszDNOut, L"LDAP://%ws/%ws", pDCI->DomainControllerName + 2,pszDNIn + 7);
error:
if (pDCI)
NetApiBufferFree(pDCI);
return pszDNOut;
}
DWORD
hr2dw(
HRESULT hr
)
{
if (SUCCEEDED(hr))
return ERROR_SUCCESS;
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
return HRESULT_CODE(hr);
if (hr != HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS))
return ERROR_DS_UNAVAILABLE;
return hr;
}
PWSTR
DelimString2MultiSz(
PWSTR pszIn,
WCHAR wcDelim
)
{
DWORD cb;
PWSTR pszOut = NULL;
// pszIn looks like L"xxx,xxxx,xxx,xxx"
// the output looks like L"xxx0xxxx0xxx0xxx00"
// Replace all wcDelim characters with NULLs & add a NULL
if (!pszIn || !*pszIn)
return NULL;
cb = (wcslen(pszIn) + 2)*sizeof *pszIn;
pszOut = (PWSTR) AllocSplMem(cb);
if (pszOut) {
DWORD i;
for (i = 0 ; pszIn[i] ; ++i) {
pszOut[i] = (pszIn[i] == wcDelim) ? L'\0' : pszIn[i];
}
pszOut[i] = pszOut[i + 1] = L'\0';
}
return pszOut;
}
HRESULT
GetPrinterInfo2(
HANDLE hPrinter,
PPRINTER_INFO_2 *ppInfo2
)
{
HRESULT hr = S_OK;
DWORD cbNeeded;
// Get PRINTER_INFO_2 properties
if (!GetPrinter(hPrinter, 2, (PBYTE) *ppInfo2, 0, &cbNeeded)) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
hr = dw2hr(GetLastError());
goto error;
}
if (!(*ppInfo2 = (PPRINTER_INFO_2) AllocSplMem(cbNeeded))) {
hr = dw2hr(GetLastError());
goto error;
}
if (!GetPrinter(hPrinter, 2, (PBYTE) *ppInfo2, cbNeeded, &cbNeeded)) {
hr = dw2hr(GetLastError());
goto error;
}
}
error:
return hr;
}
DWORD
FQDN2Canonical(
PWSTR pszIn,
PWSTR *ppszOut
)
{
DWORD dwRet = ERROR_SUCCESS;
DS_NAME_RESULT *pDNR = NULL;
PWSTR pNames[2];
*ppszOut = NULL;
if (wcslen(pszIn) < 8) {
dwRet = ERROR_INVALID_PARAMETER;
goto error;
}
pNames[0] = pszIn + 7; // Input string is LDAP://CN=... Strip off the LDAP:// portion
pNames[1] = NULL;
if (!(DsCrackNames(
INVALID_HANDLE_VALUE,
DS_NAME_FLAG_SYNTACTICAL_ONLY,
DS_FQDN_1779_NAME,
DS_CANONICAL_NAME,
1,
&pNames[0],
&pDNR) == ERROR_SUCCESS)) {
dwRet = GetLastError();
goto error;
}
if (pDNR->rItems[0].status != DS_NAME_NO_ERROR) {
if (pDNR->rItems[0].status == DS_NAME_ERROR_RESOLVING)
dwRet = ERROR_PATH_NOT_FOUND;
else
dwRet = pDNR->rItems[0].status;
goto error;
}
*ppszOut = AllocSplStr(pDNR->rItems[0].pName);
error:
if (pDNR)
DsFreeNameResult(pDNR);
return dwRet;
}
BOOL
DevCapMultiSz(
PWSTR pszUNCName,
IADs *pPrintQueue,
WORD fwCapability,
DWORD dwElementBytes,
PWSTR pszAttributeName
)
{
DWORD dwResult, cbBytes;
PWSTR pszDevCapBuffer = NULL;
PWSTR pszRegData = NULL;
HRESULT hr;
_try {
dwResult = DeviceCapabilities( pszUNCName,
NULL,
fwCapability,
NULL,
NULL);
if (dwResult != GDI_ERROR) {
pszDevCapBuffer = (PWSTR) AllocSplMem(dwResult*dwElementBytes*sizeof(WCHAR));
if (pszDevCapBuffer) {
dwResult = DeviceCapabilities( pszUNCName,
NULL,
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) {
hr = PublishDsData( pPrintQueue,
pszAttributeName,
REG_MULTI_SZ,
(PBYTE) pszRegData);
if (FAILED(hr)) {
SetLastError(HRESULT_CODE(hr));
dwResult = GDI_ERROR;
}
}
FreeSplStr(pszDevCapBuffer);
FreeSplStr(pszRegData);
return dwResult != GDI_ERROR;
}
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;
}
HRESULT
MachineIsInMyForest(
PWSTR pszMachineName
)
{
DWORD dwRet;
HRESULT hr;
PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pMachineRole = NULL;
PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pMyRole = NULL;
dwRet = DsRoleGetPrimaryDomainInformation( pszMachineName,
DsRolePrimaryDomainInfoBasic,
(PBYTE *) &pMachineRole);
if (dwRet != ERROR_SUCCESS) {
hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwRet);
goto error;
}
dwRet = DsRoleGetPrimaryDomainInformation( NULL,
DsRolePrimaryDomainInfoBasic,
(PBYTE *) &pMyRole);
if (dwRet != ERROR_SUCCESS) {
hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwRet);
goto error;
}
dwRet = DnsNameCompare_W(pMachineRole->DomainForestName, pMyRole->DomainForestName);
hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_WIN32, dwRet);
error:
if (pMachineRole)
DsRoleFreeMemory((PVOID) pMachineRole);
if (pMyRole)
DsRoleFreeMemory((PVOID) pMyRole);
return hr;
}