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.
 
 
 
 
 
 

1484 lines
48 KiB

/*****************************************************************************\
* MODULE: IppOcm.cxx
*
* The module contains routines for the setting up the WWW Printer Service. The main entry point is
* IppOCEntry which will be called by the Optional Component Manager.
*
* Copyright (C) 2002 Microsoft Corporation
*
\*****************************************************************************/
//
//
// 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
#include <ocmanage.h> // OC_ defines
// for adsi objects
#include <Iads.h>
#include <Adshlp.h>
// for the IID_IISWebService object
#include "iiisext.h"
#include "iisext_i.c"
#define MY_META_TIMEOUT 1000
TCHAR const cszMimeMap[] = TEXT("MimeMap");
TCHAR const cszWebPnPMap[] = TEXT(".webpnp,application/octet-stream");
TCHAR const cszW3SvcRootPath[] = TEXT("/LM/W3svc/1/Root");
TCHAR const cszPrinters[] = TEXT("Printers");
TCHAR const cszWebSvcExtRestrictionListADSILocation[] = TEXT("IIS://LOCALHOST/W3SVC");
//
// Component ID for the OCM
//
TCHAR const cszComponentId[] = TEXT("InetPrint");
TCHAR const cszExtPathFmt[] = TEXT("%ws\\msw3prt.dll");
TCHAR const cszGroupId[] = TEXT("W3PRT");
TCHAR const cszGroupDescription[] = TEXT("Internet Printing");
TCHAR const cszASPId[] = TEXT("ASP");
//
// Service ID & Reg Key for the WWW Service
//
TCHAR const cszW3Svc[] = TEXT("w3svc");
TCHAR const cszW3SvcReg[] = TEXT("System\\CurrentControlSet\\Services\\W3SVC");
//
// Strings to fire up the RunDll32 process
//
TCHAR const cszInstallInetPrint[] = TEXT("rundll32 ntprint.dll,SetupInetPrint Install");
TCHAR const cszRemoveInetPrint[] = TEXT("rundll32 ntprint.dll,SetupInetPrint Remove");
CHAR const cszInstall[] = "Install";
CHAR const cszRemove[] = "Remove";
typedef struct MySetupStruct
{
OCMANAGER_ROUTINES OCHelpers;
SETUP_DATA OCData;
BOOL bFirstCall;
BOOL bInitState;
} MYSETUPSTRUCT;
//
// Function Prototypes
//
HRESULT
AddVirtualDir(
IMSAdminBase *pIMetaBase
);
HRESULT
AddWebExtension(
VOID
);
HRESULT
AddScriptAtPrinterVDir(
IMSAdminBase *pIMetaBase
);
HRESULT
AddMimeType(
IMSAdminBase *pIMetaBase
);
HRESULT
RemoveWebExtension(
VOID
);
DWORD
WriteStrippedScriptValue(
IMSAdminBase *pIMetaBase,
METADATA_HANDLE hMeta, // Handle to /LM tree
PWCHAR pszScripts // MULTI_SZ string already there
);
DWORD
WriteStrippedMimeMapValue(
IMSAdminBase *pIMetaBase,
METADATA_HANDLE hMeta, // Handle to /LM tree
PWCHAR pszMimeMap // MULTI_SZ string already there
);
LPWSTR
mystrstrni(
LPWSTR pSrc,
LPWSTR pSearch
);
LPWSTR
IsStrInMultiSZ(
LPWSTR pMultiSzSrc,
LPWSTR pSearch
);
DWORD
GetMultiSZLen(
IN LPWSTR pMultiSzSrc
);
BOOL
IsVDIRInstalled(
VOID
)
{
IMSAdminBase *pIMetaBase = NULL;
BOOL bInstalled = FALSE;
//
// Init up the MetaBase
//
if ( SUCCEEDED(CoInitializeEx( NULL, COINIT_MULTITHREADED )) &&
SUCCEEDED(::CoCreateInstance(CLSID_MSAdminBase,
NULL,
CLSCTX_ALL,
IID_IMSAdminBase,
(void **)&pIMetaBase)) )
{
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) )
bInstalled = TRUE;
//
// Close the Web Server Key
//
pIMetaBase->CloseKey( hMeta );
}
pIMetaBase->Release();
}
CoUninitialize();
return bInstalled;
}
DWORD
InstallWebPrinting(
VOID
)
{
IMSAdminBase *pIMetaBase = NULL;
BOOL bInstalled = FALSE;
HRESULT hr = S_OK;
DBGMSG(DBG_INFO, ("Installing Web Printing.\n"));
//
// Init up the MetaBase
//
if ( SUCCEEDED(CoInitializeEx( NULL, COINIT_MULTITHREADED )) &&
SUCCEEDED(::CoCreateInstance(CLSID_MSAdminBase,
NULL,
CLSCTX_ALL,
IID_IMSAdminBase,
(void **)&pIMetaBase)) )
{
//
// Add the Virtual Directory
//
hr = AddVirtualDir(pIMetaBase);
if (SUCCEEDED(hr))
{
//
// Add Inet Print to the Security Console
//
hr = AddWebExtension();
}
if (SUCCEEDED(hr))
{
//
// Add the .printer Script Map
//
hr = AddScriptAtPrinterVDir(pIMetaBase);
}
if (SUCCEEDED(hr))
{
//
// Add the .webpnp MimeType
//
hr = AddMimeType(pIMetaBase);
}
pIMetaBase->Release();
}
CoUninitialize();
return HRESULT_CODE(hr);
}
HRESULT
AddVirtualDir(
IMSAdminBase *pIMetaBase
)
{
METADATA_HANDLE hMeta = NULL; // handle to metabase
WCHAR szVirPath[MAX_PATH];
WCHAR szPath[MAX_PATH];
DWORD dwMDRequiredDataLen;
DWORD dwAccessPerm;
METADATA_RECORD mr;
HRESULT hr;
DBGMSG(DBG_INFO, ("Adding the Virtual Dir\r\n"));
// 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_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 ( FAILED( hr ) )
{
if ( hr == MD_ERROR_DATA_NOT_FOUND ||
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, cszPrinters );
if ( GetWindowsDirectory( szPath, sizeof(szPath) / sizeof (TCHAR)) )
{ // Return value is the length in chars w/o null char.
DBGMSG(DBG_INFO, ("Writing our virtual dir.\n"));
hr = StringCchPrintf(szVirPath, COUNTOF(szVirPath), L"%ws\\web\\printers", szPath);
if ( SUCCEEDED(hr) )
{
mr.dwMDIdentifier = MD_VR_PATH;
mr.dwMDAttributes = METADATA_INHERIT;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = STRING_METADATA;
mr.dwMDDataLen = (wcslen(szVirPath) + 1) * sizeof(WCHAR);
mr.pbMDData = reinterpret_cast<unsigned char *>(szVirPath);
//
// Write MD_VR_PATH value
//
hr = pIMetaBase->SetData( hMeta, cszPrinters, &mr );
}
//
// Set the default authentication method
//
if ( SUCCEEDED(hr) )
{
DWORD dwAuthorization = MD_AUTH_NT; // NTLM only.
mr.dwMDIdentifier = MD_AUTHORIZATION;
mr.dwMDAttributes = METADATA_INHERIT; // need to inherit so that all subdirs are also protected.
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = DWORD_METADATA;
mr.dwMDDataLen = sizeof(DWORD);
mr.pbMDData = reinterpret_cast<unsigned char *>(&dwAuthorization);
// Write MD_AUTHORIZATION value
hr = pIMetaBase->SetData( hMeta, cszPrinters, &mr );
}
}
}
}
// In the following, do the stuff that we always want to do to the virtual dir, regardless of Admin's setting.
if ( SUCCEEDED(hr) )
{
dwAccessPerm = MD_ACCESS_READ | MD_ACCESS_SCRIPT;
mr.dwMDIdentifier = MD_ACCESS_PERM;
mr.dwMDAttributes = METADATA_INHERIT; // Make it inheritable so all subdirectories will have the same rights.
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, cszPrinters, &mr );
}
if ( SUCCEEDED(hr) )
{
PWCHAR szDefLoadFile = L"ipp_0001.asp";
mr.dwMDIdentifier = MD_DEFAULT_LOAD_FILE;
mr.dwMDAttributes = METADATA_INHERIT;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = STRING_METADATA;
mr.dwMDDataLen = (wcslen(szDefLoadFile) + 1) * sizeof(WCHAR);
mr.pbMDData = reinterpret_cast<unsigned char *>(szDefLoadFile);
// Write MD_DEFAULT_LOAD_FILE value
hr = pIMetaBase->SetData( hMeta, cszPrinters, &mr );
}
if ( SUCCEEDED(hr) )
{
PWCHAR szKeyType = IIS_CLASS_WEB_VDIR_W;
mr.dwMDIdentifier = MD_KEY_TYPE;
mr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
mr.dwMDUserType = IIS_MD_UT_SERVER;
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, cszPrinters, &mr );
}
}
pIMetaBase->CloseKey( hMeta );
return hr;
}
HRESULT
AddWebExtension(
VOID
)
{
WCHAR szExtPath[MAX_PATH];
WCHAR szSystemPath[MAX_PATH];
LPTSTR pszGroupDesc = NULL;
IISWebService* pWeb = NULL;
DBGMSG(DBG_INFO, ("Adding the Web Extension\r\n"));
HRESULT hr = ADsGetObject(cszWebSvcExtRestrictionListADSILocation, IID_IISWebService, (void**)&pWeb);
if (SUCCEEDED(hr) && NULL != pWeb)
{
VARIANT var1,var2;
VariantInit(&var1);
VariantInit(&var2);
var1.vt = VT_BOOL;
var1.boolVal = VARIANT_TRUE;
var2.vt = VT_BOOL;
var2.boolVal = VARIANT_FALSE;
pszGroupDesc = GetStringFromRcFile(IDS_INTERNET_PRINTING);
hr = (pszGroupDesc ? S_OK : E_FAIL);
if (SUCCEEDED(hr))
{
hr = GetSystemDirectory(szSystemPath, COUNTOF (szSystemPath)) > 0 ? S_OK : E_FAIL;
}
if (SUCCEEDED(hr))
{
hr = StringCchPrintf(szExtPath, COUNTOF(szExtPath), cszExtPathFmt, szSystemPath);
}
if (SUCCEEDED(hr))
{
hr = pWeb->AddExtensionFile(szExtPath,var1,(LPWSTR) cszGroupId,var2,(LPWSTR) pszGroupDesc);
}
if (FAILED(hr))
{
if (ERROR_DUP_NAME == HRESULT_CODE(hr))
{
hr = S_OK;
}
else
{
DBGMSG(DBG_INFO, ("AddExtension failed,probably already exists\r\n"));
}
}
VariantClear(&var1);
VariantClear(&var2);
}
if (SUCCEEDED(hr) && NULL != pWeb)
{
hr = pWeb->AddDependency((LPWSTR) pszGroupDesc,(LPWSTR) cszASPId);
if (FAILED(hr))
{
if (ERROR_DUP_NAME == HRESULT_CODE(hr))
{
hr = S_OK;
}
else
{
DBGMSG(DBG_INFO, ("AddDependency failed,probably already exists\r\n"));
}
}
}
if (NULL != pWeb)
pWeb->Release();
if (pszGroupDesc)
LocalFreeMem(pszGroupDesc);
return hr;
}
/*++
Routine Name:
AddScriptAtPrinterVDir
Description:
Add the .printer and .asp script mapping at printers virtual directory
Arguments:
pIMetaBase - Pointer to the IIS Admin base
Returns:
An HRESULT
--*/
HRESULT
AddScriptAtPrinterVDir(
IMSAdminBase *pIMetaBase
)
{
static WCHAR szScritMapFmt[] = L"%ws%c.printer,%ws\\msw3prt.dll,1,GET,POST%c";
static WCHAR szPrinterVDir[] = L"w3svc/1/root/printers";
METADATA_HANDLE hMeta = NULL; // handle to metabase
PWCHAR pszFullFormat = NULL;
DWORD dwMDRequiredDataLen;
METADATA_RECORD mr;
HRESULT hr = S_OK;
DWORD nLen;
WCHAR szSystemDir[MAX_PATH];
PWCHAR pszAspMapping = NULL;
DWORD dwMappingLen = 0;
PWCHAR pszScriptMap = NULL;
DBGMSG(DBG_INFO, ("Adding the ScriptMap\r\n"));
//
// Read any script map set at the top, on LM\w3svc where all other default ones are (e.g. .asp, etc.)
//
hr = pIMetaBase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
L"/LM",
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
MY_META_TIMEOUT,
&hMeta);
if ( SUCCEEDED(hr) )
{
mr.dwMDIdentifier = MD_SCRIPT_MAPS;
mr.dwMDAttributes = 0;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = MULTISZ_METADATA;
mr.dwMDDataLen = 0;
mr.pbMDData = NULL;
hr = pIMetaBase->GetData( hMeta, cszW3Svc, &mr, &dwMDRequiredDataLen );
hr = hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER) ? S_OK : E_FAIL;
}
if ( SUCCEEDED(hr) )
{
//
// allocate for existing stuff plus our new script map.
//
pszFullFormat = new WCHAR[dwMDRequiredDataLen];
hr = pszFullFormat? S_OK : E_OUTOFMEMORY;
}
if ( SUCCEEDED(hr) )
{
mr.dwMDIdentifier = MD_SCRIPT_MAPS;
mr.dwMDAttributes = 0;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = MULTISZ_METADATA;
mr.dwMDDataLen = dwMDRequiredDataLen * sizeof (WCHAR);
mr.pbMDData = reinterpret_cast<unsigned char *>(pszFullFormat);
hr = pIMetaBase->GetData( hMeta, cszW3Svc, &mr, &dwMDRequiredDataLen );
}
if ( SUCCEEDED(hr) )
{
pszAspMapping = IsStrInMultiSZ( pszFullFormat, L".asp" );
hr = pszAspMapping? S_OK: E_FAIL;
}
if ( SUCCEEDED(hr) )
{
nLen = COUNTOF (szScritMapFmt) + MAX_PATH + lstrlen (pszAspMapping);
pszScriptMap = new WCHAR[nLen];
hr = pszScriptMap ? S_OK : E_OUTOFMEMORY;
}
if ( SUCCEEDED(hr) )
{
//
// Return value is the length in chars w/o null char.
//
hr = GetSystemDirectory(szSystemDir, COUNTOF (szSystemDir)) > 0 ? S_OK : E_FAIL;
}
if ( SUCCEEDED(hr) )
{
PWSTR pszNewPos = NULL;
hr = StringCchPrintfEx(pszScriptMap, nLen, &pszNewPos, NULL, 0, szScritMapFmt, pszAspMapping, L'\0', szSystemDir, L'\0');
//
// The actual number of characters in the string will be the number of
// characters in the original string minus the remaining characters.
//
dwMappingLen = (DWORD)(pszNewPos - pszScriptMap);
}
if ( SUCCEEDED(hr) )
{
//
// Write the new SCRIPT value
//
mr.dwMDIdentifier = MD_SCRIPT_MAPS;
mr.dwMDAttributes = METADATA_INHERIT;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = MULTISZ_METADATA;
mr.dwMDDataLen = sizeof (WCHAR) * (dwMappingLen + 1) ;
mr.pbMDData = reinterpret_cast<unsigned char *>(pszScriptMap);
hr = pIMetaBase->SetData(hMeta, szPrinterVDir, &mr );
}
if ( hMeta )
{
pIMetaBase->CloseKey( hMeta );
hMeta = NULL;
}
delete [] pszScriptMap;
delete [] pszFullFormat;
return hr;
}
/*++
Routine Name:
AddMimeType
Description:
Add the .webpnp MimeType to the standard MimeType mappings
Arguments:
pIMetaBase - Pointer to the IIS Admin base
Returns:
An HRESULT
--*/
HRESULT
AddMimeType(
IMSAdminBase *pIMetaBase
)
{
METADATA_HANDLE hMeta = NULL; // handle to metabase
DWORD dwMDRequiredDataLen,
dwCurrentMapBytes,
dwWebPnPMapLen;
METADATA_RECORD mr;
HRESULT hr = S_OK;
DWORD nLen;
PWCHAR pszCurrentMimeMap = NULL;
PWCHAR pszNewMimeMap = NULL;
PWCHAR pszWebPnPMap = NULL;
DWORD dwMappingLen = 0;
DBGMSG(DBG_INFO, ("Adding the MimeType\r\n"));
//
// Read the current MimeType mapping, on LM\MimeMap
//
hr = pIMetaBase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
L"/LM",
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
MY_META_TIMEOUT,
&hMeta);
if ( SUCCEEDED(hr) )
{
mr.dwMDIdentifier = MD_MIME_MAP;
mr.dwMDAttributes = 0;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = MULTISZ_METADATA;
mr.dwMDDataLen = 0;
mr.pbMDData = NULL;
hr = pIMetaBase->GetData( hMeta, cszMimeMap, &mr, &dwCurrentMapBytes );
hr = hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER) ? S_OK : E_FAIL;
}
if ( SUCCEEDED(hr) )
{
//
// allocate for existing stuff plus our new script map.
//
pszCurrentMimeMap = (PWCHAR) new BYTE[dwCurrentMapBytes];
hr = pszCurrentMimeMap? S_OK : E_OUTOFMEMORY;
}
if ( SUCCEEDED(hr) )
{
mr.dwMDIdentifier = MD_MIME_MAP;
mr.dwMDAttributes = 0;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = MULTISZ_METADATA;
mr.dwMDDataLen = dwCurrentMapBytes;
mr.pbMDData = reinterpret_cast<unsigned char *>(pszCurrentMimeMap);
hr = pIMetaBase->GetData( hMeta, cszMimeMap, &mr, &dwMDRequiredDataLen );
}
if ( SUCCEEDED(hr) )
{
pszWebPnPMap = IsStrInMultiSZ( pszCurrentMimeMap, L".webpnp" );
//
// If the map doesn't currently exist
//
if (!pszWebPnPMap)
{
dwWebPnPMapLen = COUNTOF (cszWebPnPMap);
nLen = (dwWebPnPMapLen * sizeof(WCHAR)) + dwCurrentMapBytes;
pszNewMimeMap = (PWCHAR) new BYTE[nLen];
hr = pszNewMimeMap ? S_OK : E_OUTOFMEMORY;
if ( SUCCEEDED(hr) )
{
CopyMemory( pszNewMimeMap, // Remove our script map by copying the remainder of the multi_sz on top of the string containing the map.
pszCurrentMimeMap,
dwCurrentMapBytes);
pszWebPnPMap = pszNewMimeMap + (dwCurrentMapBytes/sizeof(WCHAR));
pszWebPnPMap--; // Back up onto the Double NULL
hr = StringCchCopy(pszWebPnPMap, dwWebPnPMapLen, cszWebPnPMap);
}
if ( SUCCEEDED(hr) )
{
pszWebPnPMap+=dwWebPnPMapLen;
*pszWebPnPMap = 0x00;
//
// Write the new MimeType Map value
//
mr.dwMDIdentifier = MD_MIME_MAP;
mr.dwMDAttributes = METADATA_INHERIT;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = MULTISZ_METADATA;
mr.dwMDDataLen = nLen;
mr.pbMDData = reinterpret_cast<unsigned char *>(pszNewMimeMap);
hr = pIMetaBase->SetData(hMeta, cszMimeMap, &mr );
if (FAILED(hr))
{
DBGMSG(DBG_INFO, ("AddMimeType Failed. RC = %d\r\n", HRESULT_CODE(hr)));
}
}
}
}
if ( hMeta )
{
pIMetaBase->CloseKey( hMeta );
hMeta = NULL;
}
delete [] pszCurrentMimeMap;
delete [] pszNewMimeMap;
return hr;
}
DWORD
RemoveWebPrinting(
VOID
)
{
IMSAdminBase* pIMetaBase = NULL;
DWORD dwRet = NO_ERROR;
HKEY hKey;
DBGMSG(DBG_INFO, ("Removing Web Printing.\n"));
//
// Before we try to uninstall check to see is the WWW
// service has already been uninstalled. If it is gone so are
// all of our reg entries.
//
if( ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE, cszW3SvcReg, 0, KEY_READ, &hKey))
{
RegCloseKey( hKey );
//
// Init up the MetaBase
//
if ( SUCCEEDED(CoInitializeEx( NULL, COINIT_MULTITHREADED )))
{
if ( SUCCEEDED(::CoCreateInstance(CLSID_MSAdminBase,
NULL,
CLSCTX_ALL,
IID_IMSAdminBase,
(void **)&pIMetaBase)) )
{
HRESULT hr; // com error status
METADATA_HANDLE hMeta = NULL; // handle to metabase
//
// First Remove the Virtual Directory
//
// 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, cszPrinters ); // 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 );
hMeta = NULL;
//
// Next Remove the Web Extention Record & App Dependency
//
hr = RemoveWebExtension();
if (SUCCEEDED(hr))
{
//
// Next Remove the .printers ScriptMap
//
PWCHAR pszScripts = NULL,
pszMimeMap = NULL;
DWORD dwMDRequiredDataLen;
METADATA_RECORD mr;
// Read any script map set at the top, on LM\w3svc where all other default ones are (e.g. .asp, etc.)
hr = pIMetaBase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
L"/LM",
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
MY_META_TIMEOUT,
&hMeta);
if ( SUCCEEDED( hr ) )
{
mr.dwMDIdentifier = MD_SCRIPT_MAPS;
mr.dwMDAttributes = 0;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = MULTISZ_METADATA;
mr.dwMDDataLen = 0;
mr.pbMDData = NULL;
hr = pIMetaBase->GetData( hMeta, cszW3Svc, &mr, &dwMDRequiredDataLen );
if ( FAILED( hr ) )
{
if ( HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER )
{
// allocate for existing stuff
pszScripts = new WCHAR[dwMDRequiredDataLen];
if ( pszScripts )
{
mr.dwMDIdentifier = MD_SCRIPT_MAPS;
mr.dwMDAttributes = 0;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = MULTISZ_METADATA;
mr.dwMDDataLen = dwMDRequiredDataLen;
mr.pbMDData = reinterpret_cast<unsigned char *>(pszScripts);
hr = pIMetaBase->GetData( hMeta, cszW3Svc, &mr, &dwMDRequiredDataLen );
if ( SUCCEEDED( hr ) )
dwRet = WriteStrippedScriptValue( pIMetaBase, hMeta, pszScripts ); // Remove the .printer map from the multi_sz if there;
delete pszScripts;
}
}
}
if ( SUCCEEDED( hr ) )
{
mr.dwMDIdentifier = MD_MIME_MAP;
mr.dwMDAttributes = 0;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = MULTISZ_METADATA;
mr.dwMDDataLen = 0;
mr.pbMDData = NULL;
hr = pIMetaBase->GetData( hMeta, cszMimeMap, &mr, &dwMDRequiredDataLen );
if ( FAILED( hr ) )
{
if ( HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER )
{
// allocate for existing stuff
pszMimeMap = (PWCHAR) new BYTE[dwMDRequiredDataLen];
if ( pszMimeMap )
{
mr.dwMDIdentifier = MD_MIME_MAP;
mr.dwMDAttributes = 0;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = MULTISZ_METADATA;
mr.dwMDDataLen = dwMDRequiredDataLen;
mr.pbMDData = reinterpret_cast<unsigned char *>(pszMimeMap);
hr = pIMetaBase->GetData( hMeta, cszMimeMap, &mr, &dwMDRequiredDataLen );
if ( SUCCEEDED( hr ) )
dwRet = WriteStrippedMimeMapValue( pIMetaBase, hMeta, pszMimeMap ); // Remove the .printer map from the multi_sz if there;
delete pszMimeMap;
}
}
}
}
pIMetaBase->CloseKey( hMeta );
}
else
dwRet = GetLastError();
}
else
dwRet = GetLastError();
}
else
dwRet = GetLastError();
if (SUCCEEDED(hr))
{
hr = pIMetaBase->SaveData();
dwRet = HRESULT_CODE(hr);
}
pIMetaBase->Release();
}
CoUninitialize();
}
}
return dwRet;
}
HRESULT
RemoveWebExtension(
VOID
)
{
WCHAR szExtPath[MAX_PATH];
WCHAR szSystemPath[MAX_PATH];
IISWebService* pWeb = NULL;
DBGMSG(DBG_INFO, ("Removing the Web Extension\r\n"));
HRESULT hr = ADsGetObject(cszWebSvcExtRestrictionListADSILocation, IID_IISWebService, (void**)&pWeb);
if (SUCCEEDED(hr) && NULL != pWeb)
{
hr = GetSystemDirectory(szSystemPath, COUNTOF (szSystemPath)) > 0 ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
hr = StringCchPrintf(szExtPath, COUNTOF(szExtPath), cszExtPathFmt, szSystemPath);
}
if (SUCCEEDED(hr))
{
hr = pWeb->DeleteExtensionFileRecord(szExtPath);
}
if (FAILED(hr))
{
DBGMSG(DBG_INFO, ("DeleteExtension failed,probably already gone\r\n"));
}
}
if (SUCCEEDED(hr) && NULL != pWeb)
{
LPTSTR pszGroupDesc = GetStringFromRcFile(IDS_INTERNET_PRINTING);
hr = (pszGroupDesc ? S_OK : E_FAIL);
if (SUCCEEDED(hr))
{
hr = pWeb->RemoveDependency((LPWSTR) pszGroupDesc,(LPWSTR) cszASPId);
}
if (FAILED(hr))
{
DBGMSG(DBG_INFO, ("RemoveDep failed,probably already gone\r\n"));
}
if (pszGroupDesc)
LocalFreeMem(pszGroupDesc);
}
if (NULL != pWeb)
pWeb->Release();
return hr;
}
//
//
// Finds and removed our script map from the multi_sz, and writes it back to the metabase.
//
//
DWORD
WriteStrippedScriptValue(
IMSAdminBase *pIMetaBase,
METADATA_HANDLE hMeta, // Handle to /LM tree
PWCHAR pszScripts // MULTI_SZ string already there
)
{
LPWSTR pStrToKill, pNextStr;
HRESULT hr;
DBGMSG(DBG_INFO, ("Removing the ScriptMap\r\n"));
// See if our script map is already there.
if ( !(pStrToKill = IsStrInMultiSZ( pszScripts, L".printer" )) )
return NO_ERROR;
// Find the next string (could be the final NULL char)
pNextStr = pStrToKill + (wcslen(pStrToKill) + 1);
if ( !*pNextStr )
*pStrToKill = 0; // Our scipt map was at the end of multi_sz. Write the 2nd NULL char and we are done.
else
CopyMemory( pStrToKill, // Remove our script map by copying the remainder of the multi_sz on top of the string containing the map.
pNextStr,
GetMultiSZLen(pNextStr) * sizeof(WCHAR));
// Write the new SCRIPT value
METADATA_RECORD mr;
mr.dwMDIdentifier = MD_SCRIPT_MAPS;
mr.dwMDAttributes = METADATA_INHERIT;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = MULTISZ_METADATA;
mr.dwMDDataLen = GetMultiSZLen(pszScripts) * sizeof(WCHAR);
mr.pbMDData = reinterpret_cast<unsigned char *>(pszScripts);
hr = pIMetaBase->SetData( hMeta, cszW3Svc, &mr );
return( HRESULT_CODE( hr ));
}
//
//
// Finds and removed our .webpnp MimeType from the multi_sz, and writes it back to the metabase.
//
//
DWORD
WriteStrippedMimeMapValue(
IMSAdminBase *pIMetaBase,
METADATA_HANDLE hMeta, // Handle to /LM tree
PWCHAR pszMimeMap // MULTI_SZ string already there
)
{
LPWSTR pStrToKill, pNextStr;
HRESULT hr;
DBGMSG(DBG_INFO, ("Removing the MimeType\r\n"));
// See if our script map is already there.
if ( !(pStrToKill = IsStrInMultiSZ( pszMimeMap, L".webpnp" )) )
return NO_ERROR;
// Find the next string (could be the final NULL char)
pNextStr = pStrToKill + (wcslen(pStrToKill) + 1);
if ( !*pNextStr )
*pStrToKill = 0; // Our scipt map was at the end of multi_sz. Write the 2nd NULL char and we are done.
else
CopyMemory( pStrToKill, // Remove our script map by copying the remainder of the multi_sz on top of the string containing the map.
pNextStr,
GetMultiSZLen(pNextStr) * sizeof(WCHAR));
// Write the new SCRIPT value
METADATA_RECORD mr;
mr.dwMDIdentifier = MD_MIME_MAP;
mr.dwMDAttributes = METADATA_INHERIT;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = MULTISZ_METADATA;
mr.dwMDDataLen = GetMultiSZLen(pszMimeMap) * sizeof(WCHAR);
mr.pbMDData = reinterpret_cast<unsigned char *>(pszMimeMap);
hr = pIMetaBase->SetData( hMeta, cszMimeMap, &mr );
return( HRESULT_CODE( hr ));
}
//
//
// Finds the string pSearch in pSrc buffer and returns a ptr to the occurance of pSearch in pSrc.
//
//
LPWSTR mystrstrni( LPWSTR pSrc, LPWSTR pSearch )
{
UINT uSearchSize = wcslen( pSearch );
UINT uSrcSize = wcslen( pSrc );
LPCTSTR pEnd;
if ( uSrcSize < uSearchSize )
return(NULL);
pEnd = pSrc + uSrcSize - uSearchSize;
for ( ; pSrc <= pEnd; ++pSrc )
{
if ( !_wcsnicmp( pSrc, pSearch, uSearchSize ) )
return((LPWSTR)pSrc);
}
return(NULL);
}
//
// Determines if the string pSearch can be found inside of a MULTI_SZ string. If it can, it retunrs a
// pointer to the beginning of the string in multi-sz that contains pSearch.
//
LPWSTR IsStrInMultiSZ( LPWSTR pMultiSzSrc, LPWSTR pSearch )
{
LPWSTR pTmp = pMultiSzSrc;
while ( TRUE )
{
if ( mystrstrni( pTmp, pSearch ) ) // See pSearch (i.e. ".printer" appears anywhere within this string. If it does, it must be ours.
return pTmp;
pTmp = pTmp + (wcslen(pTmp) + 1); // Point to the beginning of the next string in the MULTI_SZ
if ( !*pTmp )
return NULL; // reached the end of the MULTI_SZ string.
}
}
/*++
Routine Name
GetMultiSZLen
Routine Description:
This returns the number of characters in a multisz string, including NULLs.
Arguments:
pMultiSzSrc - The multisz string to search.
Return Value:
The number of characters in the string.
--*/
DWORD
GetMultiSZLen(
IN LPWSTR pMultiSzSrc
)
{
DWORD dwLen = 0;
LPWSTR pTmp = pMultiSzSrc;
while( TRUE ) {
dwLen += wcslen(pTmp) + 1; // Incude the terminating NULL char
pTmp = pMultiSzSrc + dwLen; // Point to the beginning of the next string in the MULTI_SZ
if( !*pTmp )
return ++dwLen; // Reached the end of the MULTI_SZ string. Add 1 to the count for the last NULL char.
}
}
//
// Routine: IppOcEntry
//
DWORD
IppOcEntry(
IN LPCVOID ComponentId,
IN LPCVOID SubcomponentId,
IN UINT Function,
IN UINT Param1,
IN OUT PVOID Param2
)
{
BOOL bWrongCompId = TRUE;
DWORD dwRet = NO_ERROR;
static MYSETUPSTRUCT* pMySetupInfo = NULL;
//
// Check if the ComponentId is correct
//
if ( ComponentId )
bWrongCompId = _tcsicmp(cszComponentId, (LPCTSTR) ComponentId);
switch ( Function )
{
case OC_PREINITIALIZE:
DBGMSG(DBG_INFO, ("In OC_PREINITIALIZE.\n"));
//
// We are just starting up
//
if ( bWrongCompId ||
!(Param1 && OCFLAG_UNICODE) )
dwRet = 0;
else
dwRet = OCFLAG_UNICODE;
//
// Cleanup Any leftover data
//
if ( pMySetupInfo )
{
LocalFree(pMySetupInfo);
pMySetupInfo = NULL;
}
break;
case OC_INIT_COMPONENT:
DBGMSG(DBG_INFO, ("In OC_INIT_COMPONENT.\n"));
{
//
// Setup our Internal info
//
PSETUP_INIT_COMPONENT pInputData = (PSETUP_INIT_COMPONENT) Param2;
if ( bWrongCompId ||
!pInputData ||
(HIWORD(pInputData->OCManagerVersion) < OCVER_MAJOR) )
{
dwRet = ERROR_CALL_NOT_IMPLEMENTED;
}
else
{
//
// We have a good version of the OCM
//
// Set our desired version
pInputData->ComponentVersion = OCMANAGER_VERSION;
//
// Save away the usefal data
//
pMySetupInfo = (MYSETUPSTRUCT*) LocalAlloc(LPTR, sizeof(MYSETUPSTRUCT));
if ( pMySetupInfo )
{
// Copy the SetupData
CopyMemory(&pMySetupInfo->OCData, &pInputData->SetupData, sizeof(SETUP_DATA));
// Copy Helper Routines Function Pointers
CopyMemory(&pMySetupInfo->OCHelpers, &pInputData->HelperRoutines, sizeof(OCMANAGER_ROUTINES));
// Set the FirstPass flag
pMySetupInfo->bFirstCall = TRUE;
dwRet = NO_ERROR;
}
else
dwRet = GetLastError();
}
}
break;
case OC_SET_LANGUAGE:
//
// Don't Fail since we doan't actually need language support
//
dwRet = TRUE;
break;
case OC_QUERY_CHANGE_SEL_STATE:
//
// If we are getting asked to be turned on because our parent was selected -
//
if (Param1 &&
(((UINT) (ULONG_PTR)Param2) & OCQ_DEPENDENT_SELECTION) &&
!(((UINT) (ULONG_PTR)Param2) & OCQ_ACTUAL_SELECTION ))
{
// Don't do it...
dwRet = FALSE;
}
else
{
// Otherwise it is OK.
dwRet = TRUE;
}
break;
case OC_QUERY_STEP_COUNT:
//
// We only have one step
// Create/Delete the VDIR & ScriptMap
//
dwRet = 1;
break;
case OC_COMPLETE_INSTALLATION:
DBGMSG(DBG_INFO, ("In OC_COMPLETE_INSTALLATION.\n"));
//
// Check the state of the Checkbox and either create or delete the VDIR.
//
if ( !bWrongCompId &&
pMySetupInfo && pMySetupInfo->OCHelpers.QuerySelectionState )
{
//
// If this is the first call then skip until more things are installed.
//
if (pMySetupInfo->bFirstCall)
{
pMySetupInfo->bFirstCall = FALSE;
}
else
{
BOOL bDoInstall;
//
// Get the current selection state
//
bDoInstall = pMySetupInfo->OCHelpers.QuerySelectionState( pMySetupInfo->OCHelpers.OcManagerContext,
cszComponentId, OCSELSTATETYPE_CURRENT);
if ( (NO_ERROR == GetLastError()) &&
(bDoInstall != pMySetupInfo->bInitState) )
{
//
// We got a valid state
//
LPTSTR pszProcessInfo = NULL;
STARTUPINFO StartUpInfo;
PROCESS_INFORMATION ProcInfo;
//
// Call Create Process
//
if ( bDoInstall )
pszProcessInfo = AllocStr(cszInstallInetPrint);
else
pszProcessInfo = AllocStr(cszRemoveInetPrint);
if (pszProcessInfo)
{
//
// Init the Startup Info
//
memset(&StartUpInfo, 0, sizeof(STARTUPINFO));
StartUpInfo.cb = sizeof(STARTUPINFO);
if (CreateProcess( NULL, pszProcessInfo, NULL, NULL, FALSE,
(CREATE_NO_WINDOW|NORMAL_PRIORITY_CLASS), NULL, NULL, &StartUpInfo, &ProcInfo))
{
//
// Wait on the process handle
//
WaitForSingleObject( ProcInfo.hProcess, INFINITE);
//
// Get the Process Exit Code
//
if (!GetExitCodeProcess( ProcInfo.hProcess, &dwRet ))
dwRet = GetLastError();
//
// CLose the Preocess & Thread Handles
//
CloseHandle(ProcInfo.hProcess);
CloseHandle(ProcInfo.hThread);
}
else
dwRet = GetLastError();
LocalFree(pszProcessInfo);
}
else
dwRet = GetLastError();
if (NO_ERROR == dwRet)
{
HANDLE hServer;
DWORD dwInstallWebPrinting = bDoInstall,
dwLastError,
dwType = REG_DWORD;
PRINTER_DEFAULTS Defaults = {NULL, NULL, SERVER_ACCESS_ADMINISTER};
if ( !OpenPrinter(NULL, &hServer, &Defaults) )
return FALSE;
dwLastError = SetPrinterData(hServer,
SPLREG_WEBSHAREMGMT,
dwType,
(LPBYTE)&dwInstallWebPrinting,
sizeof(dwInstallWebPrinting));
ClosePrinter(hServer);
}
}
}
}
DBGMSG(DBG_INFO, ("Exitting OC_COMPLETE_INSTALLATION. RC = %d\n", dwRet));
break;
case OC_CLEANUP:
DBGMSG(DBG_INFO, ("In OC_CLEANUP.\n"));
//
// The install is done or cancelled so cleanup the allocated memory
//
if ( pMySetupInfo )
{
LocalFree(pMySetupInfo);
pMySetupInfo = NULL;
}
break;
case OC_QUERY_STATE:
DBGMSG(DBG_INFO, ("In OC_QUERY_STATE.\n"));
//
// Figure out if the VDIR exists to set the initial state of the checkbox.
//
if ( !bWrongCompId &&
(Param1 == OCSELSTATETYPE_ORIGINAL) )
{
//
// If we are upgrading we need to run the install code as if we aren't currently installed
// otherwise save away the initial state
//
pMySetupInfo->bInitState = IsVDIRInstalled();
if (pMySetupInfo->bInitState)
dwRet = SubcompOn;
else
dwRet = SubcompOff;
if (pMySetupInfo->OCData.OperationFlags & SETUPOP_NTUPGRADE)
{
pMySetupInfo->bInitState = FALSE;
DBGMSG(DBG_INFO, ("Performing NT Upgrade.\n"));
}
DBGMSG(DBG_INFO, ("Current Componenet state = %d.\n", dwRet));
}
break;
default:
break;
}
return dwRet;
}
void CALLBACK SetupInetPrint(
IN HWND hwnd, // handle to owner window
IN HINSTANCE hinst, // instance handle for the DLL
IN LPSTR lpCmdLine, // string the DLL will parse
IN int nCmdShow // show state
)
{
DWORD dwRet;
//
// Check Cmdline for either Install or Remove parameters
if ( !_strnicmp( lpCmdLine, cszInstall, COUNTOF(cszInstall)) )
dwRet = InstallWebPrinting();
else if ( !_strnicmp( lpCmdLine, cszRemove, COUNTOF(cszRemove)) )
dwRet = RemoveWebPrinting();
else
dwRet = ERROR_INVALID_PARAMETER;
ExitProcess(dwRet);
}