/*++ Copyright (c) 1990-1994 Microsoft Corporation All rights reserved Module Name: Cluster registry apis. Abstract: Determines whether ClusterReg or Reg apis should be used. The printer information is stored in the registry. When we access local printers, we hit the local registry; when we access cluster printers, we hit the cluster registry. Author: Albert Ting (AlbertT) 8-Oct-96 Environment: User Mode -Win32 Revision History: Felix Maxa (amaxa) 18-Jun-2000 Added ClusterGetResourceID ClusterGetResourceDriveLetter --*/ #include "precomp.h" #pragma hdrstop #include #include "clusspl.h" enum { kDriveLetterStringSize = 3, kGuidStringSize = 40 }; /******************************************************************** Globals. ********************************************************************/ typedef struct _CLUSAPI { HCLUSTER (*pfnOpenCluster)( IN LPCWSTR lpszClusterName ); BOOL (*pfnCloseCluster)( IN HCLUSTER hCluster ); HRESOURCE (*pfnOpenClusterResource)( IN HCLUSTER hCluster, IN LPCWSTR lpszResourceName ); BOOL (*pfnCloseClusterResource)( IN HRESOURCE hResource ); HKEY (*pfnGetClusterKey)( IN HCLUSTER hCluster, IN REGSAM samDesired ); HKEY (*pfnGetClusterResourceKey)( IN HRESOURCE hResource, IN REGSAM samDesired ); LONG (*pfnClusterRegCreateKey)( IN HKEY hKey, IN LPCWSTR lpszSubKey, IN DWORD dwOptions, IN REGSAM samDesired, IN LPSECURITY_ATTRIBUTES lpSecurityAttributes, OUT PHKEY phkResult, OUT OPTIONAL LPDWORD lpdwDisposition ); LONG (*pfnClusterRegOpenKey)( IN HKEY hKey, IN LPCWSTR lpszSubKey, IN REGSAM samDesired, OUT PHKEY phkResult ); LONG (*pfnClusterRegDeleteKey)( IN HKEY hKey, IN LPCWSTR lpszSubKey ); LONG (*pfnClusterRegCloseKey)( IN HKEY hKey ); LONG (*pfnClusterRegEnumKey)( IN HKEY hKey, IN DWORD dwIndex, OUT LPWSTR lpszName, IN OUT LPDWORD lpcbName, OUT PFILETIME lpftLastWriteTime ); DWORD (*pfnClusterRegSetValue)( IN HKEY hKey, IN LPCWSTR lpszValueName, IN DWORD dwType, IN CONST BYTE* lpData, IN DWORD cbData ); DWORD (*pfnClusterRegDeleteValue)( IN HKEY hKey, IN LPCWSTR lpszValueName ); LONG (*pfnClusterRegQueryValue)( IN HKEY hKey, IN LPCWSTR lpszValueName, OUT LPDWORD lpValueType, OUT LPBYTE lpData, IN OUT LPDWORD lpcbData ); DWORD (*pfnClusterRegEnumValue)( IN HKEY hKey, IN DWORD dwIndex, OUT LPWSTR lpszValueName, IN OUT LPDWORD lpcbValueName, OUT LPDWORD lpType, OUT LPBYTE lpData, IN OUT LPDWORD lpcbData ); LONG (*pfnClusterRegQueryInfoKey)( HKEY hKey, LPDWORD lpcSubKeys, LPDWORD lpcbMaxSubKeyLen, LPDWORD lpcValues, LPDWORD lpcbMaxValueNameLen, LPDWORD lpcbMaxValueLen, LPDWORD lpcbSecurityDescriptor, PFILETIME lpftLastWriteTime ); DWORD (*pfnClusterResourceControl)( HRESOURCE hResource, HNODE hHostNode, DWORD dwControlCode, LPVOID lpInBuffer, DWORD cbInBufferSize, LPVOID lpOutBuffer, DWORD cbOutBufferSize, LPDWORD lpcbBytesReturned ); } CLUSAPI, *PCLUSAPI; CLUSAPI ClusApi; LPCSTR aszClusApi[] = { "OpenCluster", "CloseCluster", "OpenClusterResource", "CloseClusterResource", "GetClusterKey", "GetClusterResourceKey", "ClusterRegCreateKey", "ClusterRegOpenKey", "ClusterRegDeleteKey", "ClusterRegCloseKey", "ClusterRegEnumKey", "ClusterRegSetValue", "ClusterRegDeleteValue", "ClusterRegQueryValue", "ClusterRegEnumValue", "ClusterRegQueryInfoKey", "ClusterResourceControl" }; /******************************************************************** OpenCluster CloseCluster OpenClusterResource CloseClusterResource GetClusterResourceKey ClusterRegCreateKey ClusterRegOpenKey ClusterRegDeleteKey ClusterRegCloseKey ClusterRegEnumKey ClusterRegSetValue ClusterRegDeleteValue ClusterRegQueryValue ClusterRegEnumValue ClusterRegQueryInfoKey ********************************************************************/ BOOL LoadClusterFunctions( VOID ) /*++ Routine Description: Load ClusApi functions. Must be called before any cluster api is used. Arguments: Return Value: TRUE - Success FALSE - Fail --*/ { HANDLE hLibrary; UINT i; FARPROC* pFarProc = (FARPROC*)&ClusApi; // // Size of string table and structure are identical. // SPLASSERT( COUNTOF( aszClusApi ) == sizeof( ClusApi )/sizeof( FARPROC )); if( ClusApi.pfnOpenCluster ){ return TRUE; } i = SetErrorMode(SEM_FAILCRITICALERRORS); hLibrary = LoadLibrary( TEXT( "clusapi.dll" )); SetErrorMode(i); if( !hLibrary ){ goto Fail; } for( i=0; i< COUNTOF( aszClusApi ); ++i, ++pFarProc) { *pFarProc = GetProcAddress( hLibrary, aszClusApi[i] ); if( !*pFarProc ){ DBGMSG( DBG_WARN, ( "LoadClusterFunctions: Loading function %hs failed %d\n", aszClusApi[i], GetLastError( ))); goto Fail; } } return TRUE; Fail: if( hLibrary ){ FreeLibrary( hLibrary ); } ClusApi.pfnOpenCluster = NULL; return FALSE; } HKEY OpenClusterParameterKey( IN LPCTSTR pszResource ) /*++ Routine Description: Based on a resource string, open the cluster key with FULL access. Arguments: pszResource - Name of the resource key. Return Value: HKEY - Success. Key must be closed with NULL - Failure. LastError set. --*/ { HCLUSTER hCluster; HRESOURCE hResource = NULL; HKEY hKeyResource = NULL; HKEY hKey = NULL; DWORD Status; DWORD dwDisposition; if( !LoadClusterFunctions( )){ return NULL; } hCluster = ClusApi.pfnOpenCluster( NULL ); if( !hCluster ){ DBGMSG( DBG_WARN, ( "OpenClusterResourceKey: failed to open cluster %d\n", GetLastError() )); goto Fail; } hResource = ClusApi.pfnOpenClusterResource( hCluster, pszResource ); if( !hResource ){ DBGMSG( DBG_WARN, ( "OpenClusterResourceKey: failed to open resource "TSTR" %d\n", pszResource, GetLastError() )); goto Fail; } hKeyResource = ClusApi.pfnGetClusterResourceKey( hResource, KEY_ALL_ACCESS ); if( !hKeyResource ){ DBGMSG( DBG_WARN, ( "OpenClusterResourceKey: failed to open resource key %d\n", GetLastError() )); goto Fail; } if((Status = ClusApi.pfnClusterRegOpenKey( hKeyResource, szParameters, KEY_CREATE_SUB_KEY | KEY_ALL_ACCESS, &hKey )) == ERROR_FILE_NOT_FOUND) { Status = ClusApi.pfnClusterRegCreateKey( hKeyResource, szParameters, 0, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition ); } if( Status != ERROR_SUCCESS ){ SetLastError( Status ); hKey = NULL; DBGMSG( DBG_WARN, ( "OpenClusterResourceKey: failed to create resource key %d\n", Status )); } Fail: if( hKeyResource ){ ClusApi.pfnClusterRegCloseKey( hKeyResource ); } if( hResource ){ ClusApi.pfnCloseClusterResource( hResource ); } if( hCluster ){ ClusApi.pfnCloseCluster( hCluster ); } return hKey; } /******************************************************************** SplReg*Key functions: Used for printer registry access. ********************************************************************/ LONG SplRegCreateKey( IN HKEY hKey, IN LPCTSTR pszSubKey, IN DWORD dwOptions, IN REGSAM samDesired, IN PSECURITY_ATTRIBUTES pSecurityAttributes, OUT PHKEY phkResult, OUT PDWORD pdwDisposition, IN PINISPOOLER pIniSpooler OPTIONAL ) { DWORD dwDisposition; DWORD Status; if( !pdwDisposition ){ pdwDisposition = &dwDisposition; } if( pIniSpooler && pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ) { if( !LoadClusterFunctions( )) { return GetLastError(); } if((Status = ClusApi.pfnClusterRegOpenKey( hKey, pszSubKey, KEY_CREATE_SUB_KEY | samDesired, phkResult)) == ERROR_FILE_NOT_FOUND) { Status = ClusApi.pfnClusterRegCreateKey( hKey, pszSubKey, dwOptions, samDesired, pSecurityAttributes, phkResult, &dwDisposition ); } } else { Status = RegCreateKeyEx( hKey, pszSubKey, 0, NULL, dwOptions, samDesired, pSecurityAttributes, phkResult, &dwDisposition ); } return(Status); } LONG SplRegOpenKey( IN HKEY hKey, IN LPCTSTR pszSubKey, IN REGSAM samDesired, OUT PHKEY phkResult, IN PINISPOOLER pIniSpooler OPTIONAL ) { if( pIniSpooler && pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ){ if( !LoadClusterFunctions( )){ return GetLastError(); } return ClusApi.pfnClusterRegOpenKey( hKey, pszSubKey, samDesired, phkResult ); } return RegOpenKeyEx( hKey, pszSubKey, 0, samDesired, phkResult ); } LONG SplRegCloseKey( IN HKEY hKey, IN PINISPOOLER pIniSpooler OPTIONAL ) { if( pIniSpooler && pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ){ if( !LoadClusterFunctions( )){ return GetLastError(); } return ClusApi.pfnClusterRegCloseKey( hKey ); } return RegCloseKey( hKey ); } LONG SplRegDeleteKey( IN HKEY hKey, IN LPCTSTR pszSubKey, IN PINISPOOLER pIniSpooler OPTIONAL ) { if( pIniSpooler && pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ){ if( !LoadClusterFunctions( )){ return GetLastError(); } return ClusApi.pfnClusterRegDeleteKey( hKey, pszSubKey ); } return RegDeleteKey( hKey, pszSubKey ); } LONG SplRegEnumKey( IN HKEY hKey, IN DWORD dwIndex, IN LPTSTR pszName, IN OUT PDWORD pcchName, OUT PFILETIME pft, IN PINISPOOLER pIniSpooler OPTIONAL ) { FILETIME ft; if( !pft ){ pft = &ft; } if( pIniSpooler && pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ){ if( !LoadClusterFunctions( )){ return GetLastError(); } return ClusApi.pfnClusterRegEnumKey( hKey, dwIndex, pszName, pcchName, pft ); } return RegEnumKeyEx( hKey, dwIndex, pszName, pcchName, NULL, NULL, NULL, pft ); } LONG SplRegSetValue( IN HKEY hKey, IN LPCTSTR pszValue, IN DWORD dwType, IN const BYTE* pData, IN DWORD cbData, IN PINISPOOLER pIniSpooler OPTIONAL ) { if( pIniSpooler && pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ){ if( !LoadClusterFunctions( )){ return GetLastError(); } // // ClusterRegSetValue doesn't like NULL pointers. // if( cbData == 0 ){ pData = (PBYTE)&cbData; } return ClusApi.pfnClusterRegSetValue( hKey, pszValue, dwType, pData, cbData ); } return RegSetValueEx( hKey, pszValue, 0, dwType, pData, cbData ); } LONG SplRegDeleteValue( IN HKEY hKey, IN LPCTSTR pszValue, IN PINISPOOLER pIniSpooler OPTIONAL ) { if( pIniSpooler && pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ){ if( !LoadClusterFunctions( )){ return GetLastError(); } return ClusApi.pfnClusterRegDeleteValue( hKey, pszValue ); } return RegDeleteValue( hKey, pszValue ); } LONG SplRegQueryValue( IN HKEY hKey, IN LPCTSTR pszValue, OUT PDWORD pType, OPTIONAL OUT PBYTE pData, IN OUT PDWORD pcbData, IN PINISPOOLER pIniSpooler OPTIONAL ) { if( pIniSpooler && pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ){ if( !LoadClusterFunctions( )){ return GetLastError(); } return ClusApi.pfnClusterRegQueryValue( hKey, pszValue, pType, pData, pcbData ); } return RegQueryValueEx( hKey, pszValue, NULL, pType, pData, pcbData ); } LONG SplRegEnumValue( IN HKEY hKey, IN DWORD dwIndex, OUT LPTSTR pszValue, IN OUT PDWORD pcbValue, OUT PDWORD pType, OPTIONAL OUT PBYTE pData, IN OUT PDWORD pcbData, IN PINISPOOLER pIniSpooler OPTIONAL ) { if( pIniSpooler && pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ){ if( !LoadClusterFunctions( )){ return GetLastError(); } return ClusApi.pfnClusterRegEnumValue( hKey, dwIndex, pszValue, pcbValue, pType, pData, pcbData ); } return RegEnumValue( hKey, dwIndex, pszValue, pcbValue, NULL, pType, pData, pcbData ); } LONG SplRegQueryInfoKey( HKEY hKey, PDWORD pcSubKeys, PDWORD pcbKey, PDWORD pcValues, PDWORD pcbValue, PDWORD pcbData, PDWORD pcbSecurityDescriptor, PFILETIME pftLastWriteTime, PINISPOOLER pIniSpooler ) { LONG rc; if( pIniSpooler && pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ){ if( !LoadClusterFunctions( )){ return GetLastError(); } rc = ClusApi.pfnClusterRegQueryInfoKey( hKey, pcSubKeys, pcbKey, pcValues, pcbValue, pcbData, pcbSecurityDescriptor, pftLastWriteTime); } else { rc = RegQueryInfoKey( hKey, // Key NULL, // lpClass NULL, // lpcbClass NULL, // lpReserved pcSubKeys, // lpcSubKeys pcbKey, // lpcbMaxSubKeyLen NULL, // lpcbMaxClassLen pcValues, // lpcValues pcbValue, // lpcbMaxValueNameLen pcbData, // lpcbMaxValueLen pcbSecurityDescriptor, // lpcbSecurityDescriptor pftLastWriteTime // lpftLastWriteTime ); } if( pcbValue ){ *pcbValue = ( *pcbValue + 1 ) * sizeof(WCHAR); } return rc; } /*++ Routine Name: ClusterGetResourceDriveLetter Routine Description: Gets the dependent disk for a cluster resource (a cluster spooler resource) Arguments: pszResource - spooler resource name ppszClusResDriveLetter - pointer that will get the pointer to string Must be freed by caller using FreeSplMem() Return Value: Win32 error code --*/ DWORD ClusterGetResourceDriveLetter( IN LPCWSTR pszResource, OUT LPWSTR *ppszClusResDriveLetter ) { DWORD dwError = ERROR_INVALID_PARAMETER; if (pszResource && ppszClusResDriveLetter) { HCLUSTER hCluster = NULL; HRESOURCE hRes = NULL; LPCWSTR pszDllName = L"resutils.dll"; HMODULE hModule = NULL; typedef DWORD (WINAPI *PFNFINDDISK)(HCLUSTER, HRESOURCE, LPWSTR, LPDWORD); PFNFINDDISK pfnFindDisk; // // Don't leave the out var uninitialized // *ppszClusResDriveLetter = NULL; if (LoadClusterFunctions() && (hCluster = ClusApi.pfnOpenCluster(NULL)) && (hRes = ClusApi.pfnOpenClusterResource(hCluster, pszResource)) && (hModule = LoadLibrary(pszDllName)) && (pfnFindDisk = (PFNFINDDISK)GetProcAddress(hModule, "ResUtilFindDependentDiskResourceDriveLetter"))) { // // We make a guess for how large the buffer must be. We may not have to call // the resutil function twice. Driver letter + colon + NULL = 3 // DWORD cchDriveLetter = kDriveLetterStringSize; dwError = ERROR_NOT_ENOUGH_MEMORY; if (*ppszClusResDriveLetter = AllocSplMem(cchDriveLetter * sizeof(WCHAR))) { dwError = pfnFindDisk(hCluster, hRes, *ppszClusResDriveLetter, &cchDriveLetter); // // Reallocate buffer if it was not sufficient // if (dwError == ERROR_MORE_DATA) { FreeSplMem(*ppszClusResDriveLetter); dwError = ERROR_NOT_ENOUGH_MEMORY; if (*ppszClusResDriveLetter = AllocSplMem(cchDriveLetter * sizeof(WCHAR))) { dwError = pfnFindDisk(hCluster, hRes, *ppszClusResDriveLetter, &cchDriveLetter); } } if (dwError != ERROR_SUCCESS) { // // Clean up in case of failure // FreeSplMem(*ppszClusResDriveLetter); *ppszClusResDriveLetter = NULL; } } } else { dwError = GetLastError(); } if (hCluster) { ClusApi.pfnCloseCluster(hCluster); } if (hRes) { ClusApi.pfnCloseClusterResource(hRes); } if (hModule) { FreeLibrary(hModule); } } DBGMSG(DBG_CLUSTER, ("ClusterGetResourceDriveLetter returns Win32 error %u\n", dwError)); return dwError; } /*++ Routine Name: ClusterGetResourceID Routine Description: Gets the resource id (guid) for a specified cluster resource. Arguments: pszResource - spooler resource name ppszClusResID - pointer that will get the pointer to string Must be freed by caller using FreeSplMem() Return Value: Win32 error code --*/ DWORD ClusterGetResourceID( IN LPCWSTR pszResource, OUT LPWSTR *ppszClusResID ) { DWORD dwError = ERROR_INVALID_PARAMETER; if (pszResource && ppszClusResID) { HCLUSTER hCluster = NULL; HRESOURCE hRes = NULL; *ppszClusResID = NULL; if (LoadClusterFunctions() && (hCluster = ClusApi.pfnOpenCluster(NULL)) && (hRes = ClusApi.pfnOpenClusterResource(hCluster, pszResource))) { // // The resource ID is a GUID. We make a gues for its size, maybe we // get around calling the function ClusterResourceControl twice. // DWORD cbIDString = kGuidStringSize * sizeof(WCHAR); dwError = ERROR_NOT_ENOUGH_MEMORY; if (*ppszClusResID = AllocSplMem(cbIDString)) { dwError = ClusApi.pfnClusterResourceControl(hRes, NULL, CLUSCTL_RESOURCE_GET_ID, NULL, 0, *ppszClusResID, cbIDString, &cbIDString); // // Reallocate buffer if it was not sufficiently large // if (dwError == ERROR_MORE_DATA) { FreeSplMem(*ppszClusResID); dwError = ERROR_NOT_ENOUGH_MEMORY; if (*ppszClusResID = AllocSplMem(cbIDString )) { dwError = ClusApi.pfnClusterResourceControl(hRes, NULL, CLUSCTL_RESOURCE_GET_ID, NULL, 0, *ppszClusResID, cbIDString, &cbIDString); } } if (dwError != ERROR_SUCCESS) { // // Clean up in case of failure // FreeSplMem(*ppszClusResID); *ppszClusResID = NULL; } } } else { dwError = GetLastError(); } if (hRes) { ClusApi.pfnCloseClusterResource(hRes); } if (hCluster) { ClusApi.pfnCloseCluster(hCluster); } } DBGMSG(DBG_CLUSTER, ("ClusterGetResourceID returns Win32 error %u\n", dwError)); return dwError; }