Leaked source code of windows server 2003
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.
 
 
 
 
 
 

777 lines
22 KiB

/*****************************************************************************\
* MODULE: inet.cxx
*
* The module contains routines for the setting up the WWW Printer Service during spooler start up.
*
* The entry point here should be called by localspl\init.c\InitializePrintProvidor() once it is done
* with its work.
*
* Copyright (C) 1996 Microsoft Corporation
*
* History:
* Dec-1996 BabakJ Wrote it for IIS 2.0.
* June-1997 BabakJ Rewrote to use IIS 4.0's new Metabase interface
* Feb-1998 Weihaic Modify the URL in default.htm
* Feb 1999 BabakJ Made metabase interface a global to avoi calling too many CoCreateInstance() for perfrmance.
\*****************************************************************************/
//
//
// Note: We cannot use precomp.h here since we requrie ATL which can only be included in C++ source files.
//
//
#define INITGUID // Needed to do it to get GUID_NULL defined.
#include "precomp.h"
#pragma hdrstop
#include <iadmw.h> // Interface header
#include <iiscnfg.h> // MD_ & IIS_MD_ defines
#define MY_META_TIMEOUT 1000
TCHAR const cszW3SvcRootPath[] = TEXT("/LM/W3svc/1/Root");
TCHAR const cszPrinters[] = TEXT("Printers");
TCHAR const cszW3SvcReg[] = TEXT("System\\CurrentControlSet\\Services\\W3SVC");
typedef enum
{
kWebPrintingStateUnknown,
kWebPrintingStateNotInstalled,
kWebPrintingStateInstalled
} EWebPrintingState;
EWebPrintingState WebPrintingInstalled = kWebPrintingStateUnknown; // Gobal flag telling if WebPrinting is currently installed
class CWebShareData
{
public:
LPWSTR m_pszShareName;
BOOL m_bSharePrinter;
BOOL m_bValid;
public:
CWebShareData (LPWSTR pszShareName, BOOL bSharePrinter);
~CWebShareData ();
int Compare (CWebShareData *pSecond)
{
return 0;
};
};
class CWebShareList :
public CSingleList<CWebShareData*>
{
public:
CWebShareList ()
{
};
~CWebShareList ()
{
};
void WebSharePrinterList (IMSAdminBase *pIMetaBase);
};
HRESULT
AccessMetaBase(
OUT IMSAdminBase** ppIMetaBase
);
void
ReleaseMetaBase(
IN IMSAdminBase** ppIMetaBase
);
DWORD
ManageAllWebShares(
IN IMSAdminBase* pIMetaBase,
IN PINISPOOLER pIniSpooler,
IN BOOL bEnableWebShares
);
void
WebShareManagement(
IN LPWSTR pShareName,
IN BOOL bShare // If TRUE, will share it, else unshare it.
);
HRESULT
IsWebPrintingInstalled(
IN IMSAdminBase* pIMetaBase
);
HRESULT
ProcessWebShare(
IN IMSAdminBase* pIMetaBase,
IN LPWSTR pShareName,
IN BOOL bCreateShare
);
HRESULT
CreateVirtualDirForPrinterShare(
IN IMSAdminBase *pIMetaBase,
IN LPWSTR pShareName
);
HRESULT
RemoveVirtualDirForPrinterShare(
IN IMSAdminBase *pIMetaBase,
IN LPWSTR pShareName
);
DWORD
CheckWebPrinting(
BOOL* pbWebPrintingInstalled
)
{
HRESULT hr = S_OK;
IMSAdminBase* pIMetaBase = NULL;
*pbWebPrintingInstalled = FALSE;
//
// If this is the first time we have called a Web function
// init the installed variable.
//
if (WebPrintingInstalled == kWebPrintingStateUnknown)
{
//
// First get a MetaBase interface
//
hr = AccessMetaBase( &pIMetaBase );
if (SUCCEEDED(hr))
{
hr = IsWebPrintingInstalled(pIMetaBase);
}
//
// If we have a MetaBase interface free it and uninit COM.
//
ReleaseMetaBase(&pIMetaBase);
}
if (SUCCEEDED(hr))
{
*pbWebPrintingInstalled = (WebPrintingInstalled == kWebPrintingStateInstalled);
}
else
{
// Something failed so just set thstate to uninstalled but don't change the saved state,
// so we will look again the next time this function is called
*pbWebPrintingInstalled = FALSE;
}
return ERROR_SUCCESS;
}
DWORD
WebShareManager(
IN PINISPOOLER pIniSpooler,
IN BOOL bEnableWebShares
)
{
IMSAdminBase* pIMetaBase = NULL;
HRESULT hr;
DWORD dwRet = ERROR_SUCCESS;
//
// The IniSpooler needs to be from the local server
//
if ((pIniSpooler != NULL) &&
(pIniSpooler != pLocalIniSpooler) )
{
dwRet = ERROR_INVALID_PARAMETER;
}
else
{
//
// Get an interface for the MetaBase
//
hr = AccessMetaBase( &pIMetaBase );
if (SUCCEEDED(hr))
{
dwRet = ManageAllWebShares( pIMetaBase, pIniSpooler, bEnableWebShares );
if (dwRet == ERROR_SUCCESS)
{
if (bEnableWebShares)
WebPrintingInstalled = kWebPrintingStateInstalled;
else
WebPrintingInstalled = kWebPrintingStateNotInstalled;
}
}
else
{
//
// Did we fail beause the WWW Service is gone??
//
HKEY hKey;
if( ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE, cszW3SvcReg, 0, KEY_READ, &hKey))
{
RegCloseKey( hKey );
dwRet = HRESULT_CODE(hr);
}
else
{
WebPrintingInstalled = kWebPrintingStateNotInstalled;
dwRet = ERROR_SUCCESS;
}
}
ReleaseMetaBase(&pIMetaBase);
}
return dwRet;
}
/*++
Routine Name:
AccessMetaBase
Routine Description:
Open an interface handle to the IIS MetaBase
Arguments:
ppIMetaBase - The Address of a MetaBase Interface pointer
Return Value:
HRESULT
--*/
HRESULT
AccessMetaBase(
OUT IMSAdminBase** ppIMetaBase
)
{
HRESULT hr;
hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );
if ( SUCCEEDED(hr) )
{
hr = ::CoCreateInstance(CLSID_MSAdminBase,
NULL,
CLSCTX_ALL,
IID_IMSAdminBase,
(void **)ppIMetaBase);
if (FAILED(hr))
{
CoUninitialize();
*ppIMetaBase = NULL;
}
}
return hr;
}
/*++
Routine Name:
ReleaseMetaBase
Routine Description:
Release an open interface handle to the IIS MetaBase and
uninit COM.
Arguments:
pIMetaBase - A MetaBase Interface pointer
Return Value:
--*/
void
ReleaseMetaBase(
IN OUT IMSAdminBase** ppIMetaBase
)
{
if (*ppIMetaBase)
{
(*ppIMetaBase)->Release();
*ppIMetaBase = NULL;
CoUninitialize();
}
}
DWORD
ManageAllWebShares(
IMSAdminBase* pIMetaBase,
PINISPOOLER pIniSpooler,
BOOL bEnableWebShares
)
{
CWebShareList *pWebShareList = NULL;
BOOL bProcessedEntry = FALSE;
PINIPRINTER pIniPrinter;
DWORD dwRet = ERROR_SUCCESS;
if ( pWebShareList = new CWebShareList () )
{
EnterSplSem();
//
// Update VDIRs for each shared printers.
// Either add or delete the VDIRS based on bEnableWebShares
//
for ( pIniPrinter = pIniSpooler->pIniPrinter;
pIniPrinter;
pIniPrinter = pIniPrinter->pNext )
{
if ( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED )
{
CWebShareData *pData = new CWebShareData (pIniPrinter->pShareName, bEnableWebShares);
if ( pData && pData->m_bValid &&
pWebShareList->Insert (pData) )
{
bProcessedEntry = TRUE;
continue;
}
else
{
if ( pData )
{
delete pData;
}
break;
}
}
}
LeaveSplSem ();
if ( bProcessedEntry )
{
pWebShareList->WebSharePrinterList (pIMetaBase);
}
delete pWebShareList;
}
else
dwRet = GetLastError();
return dwRet;
}
//=====================================================================================================
//=====================================================================================================
//=====================================================================================================
//
// Adding printer shares:
//
// To support http://<server>/<share>, we create a virtual directory with a redirect property.
//
//
//=====================================================================================================
//=====================================================================================================
//=====================================================================================================
//=====================================================================================================
//
// This function may be called during initialization time after fW3SvcInstalled is set,
// which means, a printer maybe webshared twice (once in InstallWebPrnSvcWorkerThread,
// and the other time when WebShare () is calleb by ShareThisPrinter() in net.c by
// FinalInitAfterRouterInitCompleteThread () during localspl initialization time.
//
//=====================================================================================================
void
WebShare(
LPWSTR pShareName
)
{
WebShareManagement( pShareName, TRUE );
}
//=====================================================================================================
//=====================================================================================================
//=====================================================================================================
//
// Removing printer shares
//
//
//=====================================================================================================
//=====================================================================================================
//=====================================================================================================
void
WebUnShare(
LPWSTR pShareName
)
{
WebShareManagement( pShareName, FALSE );
}
void
WebShareManagement(
LPWSTR pShareName,
BOOL bShare // If TRUE, will share it, else unshare it.
)
{
HRESULT hr = S_OK;
IMSAdminBase* pIMetaBase = NULL;
//
// If this is the first time we have called a Web function
// init the installed variable.
//
if (WebPrintingInstalled == kWebPrintingStateUnknown)
{
//
// First get a MetaBase interface
//
hr = AccessMetaBase( &pIMetaBase );
if (SUCCEEDED(hr))
{
hr = IsWebPrintingInstalled( pIMetaBase );
}
}
if (SUCCEEDED(hr) &&
(WebPrintingInstalled == kWebPrintingStateInstalled))
{
// If we don't have a metabase interface yet
if (!pIMetaBase)
hr = AccessMetaBase( &pIMetaBase );
if (SUCCEEDED(hr))
hr = ProcessWebShare( pIMetaBase, pShareName, bShare );
}
//
// If we have a MetaBase interface free it and uninit COM.
//
ReleaseMetaBase(&pIMetaBase);
}
HRESULT
IsWebPrintingInstalled(
IMSAdminBase* pIMetaBase
)
{
BOOL bInstalled = FALSE;
WCHAR szVirPath[MAX_PATH];
HRESULT hr; // com error status
METADATA_HANDLE hMeta = NULL; // handle to metabase
DWORD dwMDRequiredDataLen;
METADATA_RECORD mr;
// open key to ROOT on website #1 (default)
hr = pIMetaBase->OpenKey(METADATA_MASTER_ROOT_HANDLE,
cszW3SvcRootPath,
METADATA_PERMISSION_READ,
MY_META_TIMEOUT,
&hMeta);
if ( SUCCEEDED( hr ) )
{
mr.dwMDIdentifier = MD_VR_PATH;
mr.dwMDAttributes = 0;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = STRING_METADATA;
mr.dwMDDataLen = sizeof( szVirPath );
mr.pbMDData = reinterpret_cast<unsigned char *>(szVirPath);
// Read LM/W3Svc/1/Root/Printers see if MD_VR_PATH exists.
hr = pIMetaBase->GetData( hMeta, cszPrinters, &mr, &dwMDRequiredDataLen );
if ( SUCCEEDED(hr) )
{
WebPrintingInstalled = kWebPrintingStateInstalled;
}
else if ( HRESULT_CODE(hr) == ERROR_PATH_NOT_FOUND )
{
WebPrintingInstalled = kWebPrintingStateNotInstalled;
hr = S_OK;
}
//
// Close the Web Server Key
//
pIMetaBase->CloseKey( hMeta );
}
return hr;
}
HRESULT
ProcessWebShare(
IMSAdminBase* pIMetaBase,
LPWSTR pShareName,
BOOL bCreateShare
)
{
HRESULT hr; // com error status
if (bCreateShare)
hr = CreateVirtualDirForPrinterShare( pIMetaBase, pShareName );
else
hr = RemoveVirtualDirForPrinterShare( pIMetaBase, pShareName );
if (SUCCEEDED(hr))
{
// Flush out the changes and close
// Call SaveData() after making bulk changes, do not call it on each update
hr = pIMetaBase->SaveData();
}
return hr;
}
HRESULT
CreateVirtualDirForPrinterShare(
IMSAdminBase *pIMetaBase,
LPWSTR pShareName
)
{
METADATA_HANDLE hMeta = NULL; // handle to metabase
WCHAR szOldURL[MAX_PATH];
WCHAR szPath[MAX_PATH];
DWORD dwMDRequiredDataLen;
DWORD dwAccessPerm;
METADATA_RECORD mr;
HRESULT hr;
BOOL fRet;
// Attempt to open the virtual dir set on Web server #1 (default server)
hr = pIMetaBase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
cszW3SvcRootPath,
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
MY_META_TIMEOUT,
&hMeta );
// Create the key if it does not exist.
if ( SUCCEEDED( hr ) )
{
mr.dwMDIdentifier = MD_HTTP_REDIRECT;
mr.dwMDAttributes = 0;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = STRING_METADATA;
mr.dwMDDataLen = sizeof( szOldURL );
mr.pbMDData = reinterpret_cast<unsigned char *>(szOldURL);
// Read LM/W3Svc/1/Root/Printers to see if MD_HTTP_REDIRECT exists.
// Note that we are only concerned with the presence of the vir dir,
// not any properties it might have.
//
hr = pIMetaBase->GetData( hMeta, pShareName, &mr, &dwMDRequiredDataLen );
if ( FAILED( hr ) )
{
// Notice if the virtual dir exists, we won't touch it. One scenario is
// if there is a name collision between a printer sharename and an existing,
// unrelated virtual dir.
if ( HRESULT_CODE(hr) == ERROR_PATH_NOT_FOUND )
{
// Write both the key and the values if GetData() failed with any of the two errors.
pIMetaBase->AddKey( hMeta, pShareName );
dwAccessPerm = MD_ACCESS_READ;
mr.dwMDIdentifier = MD_ACCESS_PERM;
mr.dwMDAttributes = 0; // no need for inheritence
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = DWORD_METADATA;
mr.dwMDDataLen = sizeof(DWORD);
mr.pbMDData = reinterpret_cast<unsigned char *>(&dwAccessPerm);
// Write MD_ACCESS_PERM value
hr = pIMetaBase->SetData( hMeta, pShareName, &mr );
if (SUCCEEDED( hr ))
{
PWCHAR szKeyType = IIS_CLASS_WEB_VDIR_W;
mr.dwMDIdentifier = MD_KEY_TYPE;
mr.dwMDAttributes = 0; // no need for inheritence
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = STRING_METADATA;
mr.dwMDDataLen = (wcslen(szKeyType) + 1) * sizeof(WCHAR);
mr.pbMDData = reinterpret_cast<unsigned char *>(szKeyType);
// Write MD_DEFAULT_LOAD_FILE value
hr = pIMetaBase->SetData( hMeta, pShareName, &mr );
}
if (SUCCEEDED( hr ))
{
WCHAR szURL[MAX_PATH];
hr = StringCchPrintf(szURL, COUNTOF(szURL), L"/printers/%ws/.printer", pShareName );
if ( SUCCEEDED(hr) )
{
mr.dwMDIdentifier = MD_HTTP_REDIRECT;
mr.dwMDAttributes = 0; // no need for inheritence
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = STRING_METADATA;
mr.dwMDDataLen = (wcslen(szURL) + 1) * sizeof(WCHAR);
mr.pbMDData = reinterpret_cast<unsigned char *>(szURL);
// Write MD_DEFAULT_LOAD_FILE value
hr = pIMetaBase->SetData( hMeta, pShareName, &mr );
}
}
}
}
pIMetaBase->CloseKey( hMeta );
}
return hr;
}
HRESULT
RemoveVirtualDirForPrinterShare(
IMSAdminBase *pIMetaBase,
LPWSTR pShareName
)
{
METADATA_HANDLE hMeta = NULL; // handle to metabase
HRESULT hr;
// Attempt to open the virtual dir set on Web server #1 (default server)
hr = pIMetaBase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
cszW3SvcRootPath,
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
MY_META_TIMEOUT,
&hMeta );
// Create the key if it does not exist.
if ( SUCCEEDED( hr ) )
{
pIMetaBase->DeleteKey( hMeta, pShareName ); // We don't check the retrun value since the key may already not exist and we could get an error for that reason.
pIMetaBase->CloseKey( hMeta );
}
return hr;
}
CWebShareData::CWebShareData (LPWSTR pszShareName, BOOL bSharePrinter)
{
m_bValid = FALSE;
m_pszShareName = NULL;
m_bSharePrinter = bSharePrinter;
DWORD cchShareLen = lstrlen (pszShareName) +1;
if ( m_pszShareName = new WCHAR[cchShareLen] )
{
StringCchCopy(m_pszShareName, cchShareLen, pszShareName);
m_bValid = TRUE;
}
}
CWebShareData::~CWebShareData ()
{
if ( m_pszShareName )
{
delete [] m_pszShareName;
}
}
void CWebShareList::WebSharePrinterList ( IMSAdminBase *pIMetaBase )
{
CSingleItem<CWebShareData*> * pItem = m_Dummy.GetNext();
CWebShareData * pData = NULL;
while ( pItem && (pData = pItem->GetData ()) && pData->m_bValid )
{
(VOID) ProcessWebShare(pIMetaBase, pData->m_pszShareName, pData->m_bSharePrinter);
pItem = pItem->GetNext ();
}
}
PWSTR
GetPrinterUrl(
PSPOOL pSpool
)
{
PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
DWORD cb;
PWSTR pszURL = NULL;
PWSTR pszServerName = NULL;
LPWSTR pszMachineName = NULL;
HRESULT hr;
SplInSem();
// http://machine/share
if ( !pIniPrinter->pShareName )
{
goto error;
}
// Get FQDN of this machine
//
// Since we should not make a network call while holding the critical section, we
// shall save all the needed variables and leave the CS, make the call and take it
// back.
//
pszMachineName = AllocSplStr(pIniPrinter->pIniSpooler->pMachineName);
if ( !pszMachineName )
{
goto error;
}
LeaveSplSem();
SplOutSem();
hr = GetDNSMachineName(pszMachineName+2, &pszServerName);
EnterSplSem();
if ( FAILED(hr) )
{
SetLastError(HRESULT_CODE(hr));
goto error;
}
cb = 7 + wcslen(pszServerName); // http://machine
cb += 1 + wcslen(pIniPrinter->pShareName) + 1; // /share + NULL
cb *= sizeof(WCHAR);
if ( pszURL = (PWSTR) AllocSplMem(cb) )
{
StringCbPrintf(pszURL, cb, L"http://%ws/%ws", pszServerName, pIniPrinter->pShareName);
}
error:
FreeSplStr(pszServerName);
FreeSplStr(pszMachineName);
return pszURL;
}