Windows-Server-2003/inetsrv/iis/admin/common2/mdkeys.cpp

5010 lines
113 KiB
C++

/*++
Copyright (c) 1994-2000 Microsoft Corporation
Module Name :
mdkeys.cpp
Abstract:
Metabase key wrapper class
Author:
Ronald Meijer (ronaldm)
Sergei Antonov (sergeia)
Project:
Internet Services Manager
Revision History:
2/17/2000 sergeia removed dependency on MFC
--*/
//
// Include Files
//
#include "stdafx.h"
#include "common.h"
#include "inheritancedlg.h"
#include "mdkeys.h"
//
// Constants
//
#define MB_TIMEOUT (15000) // Timeout in milliseconds
#define MB_INIT_BUFF_SIZE ( 256) // Initial buffer size
//
// CComAuthInfo implementation
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
/* static */
BOOL
CComAuthInfo::SplitUserNameAndDomain(
IN OUT CString & strUserName,
IN CString & strDomainName
)
/*++
Routine Description:
Split the user name and domain from the given
username, which is in the format "domain\user".
Return TRUE if the user name contained a domain
FALSE if it did not
Arguments:
CString & strUserName : User name which may contain a domain name
CString & strDomainName : Output domain name ("." if local)
Return Value:
TRUE if a domain is split off
--*/
{
//
// Assume local
//
strDomainName = _T(".");
int nSlash = strUserName.Find(_T("\\"));
if (nSlash >= 0)
{
strDomainName = strUserName.Left(nSlash);
strUserName = strUserName.Mid(nSlash + 1);
return TRUE;
}
return FALSE;
}
/* static */
DWORD
CComAuthInfo::VerifyUserPassword(
IN LPCTSTR lpstrUserName,
IN LPCTSTR lpstrPassword
)
/*++
Routine Description:
Verify the usernamer password combo checks out
Arguments:
LPCTSTR lpstrUserName : Domain/username combo
LPCTSTR lpstrPassword : Password
Return Value:
ERROR_SUCCESS if the password checks out, an error code
otherwise.
--*/
{
CString strDomain;
CString strUser(lpstrUserName);
CString strPassword(lpstrPassword);
SplitUserNameAndDomain(strUser, strDomain);
//
// In order to look up an account name, this process
// must first be granted the privilege of doing so.
//
CError err;
{
HANDLE hToken;
LUID AccountLookupValue;
TOKEN_PRIVILEGES tkp;
do
{
if (!::OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&hToken)
)
{
err.GetLastWinError();
break;
}
if (!::LookupPrivilegeValue(NULL, SE_TCB_NAME, &AccountLookupValue))
{
err.GetLastWinError();
break;
}
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = AccountLookupValue;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
::AdjustTokenPrivileges(
hToken,
FALSE,
&tkp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)NULL,
(PDWORD)NULL
);
err.GetLastWinError();
if (err.Failed())
{
break;
}
HANDLE hUser = NULL;
if (::LogonUser(
(LPTSTR)(LPCTSTR)strUser,
(LPTSTR)(LPCTSTR)strDomain,
(LPTSTR)(LPCTSTR)strPassword,
LOGON32_LOGON_NETWORK,
LOGON32_PROVIDER_DEFAULT,
&hUser
))
{
//
// Success!
//
CloseHandle(hUser);
}
else
{
err.GetLastWinError();
}
//
// Remove the privilege
//
}
while(FALSE);
}
HANDLE hUser = NULL;
if (::LogonUser(
(LPTSTR)(LPCTSTR)strUser,
(LPTSTR)(LPCTSTR)strDomain,
(LPTSTR)(LPCTSTR)strPassword,
LOGON32_LOGON_NETWORK,
LOGON32_PROVIDER_DEFAULT,
&hUser))
{
//
// Success!
//
CloseHandle(hUser);
}
else
{
err.GetLastWinError();
}
return err;
}
CComAuthInfo::CComAuthInfo(
IN LPCOLESTR lpszServerName OPTIONAL,
IN LPCOLESTR lpszUserName OPTIONAL,
IN LPCOLESTR lpszPassword OPTIONAL
)
/*++
Routine Description:
Construct CIIServer object
Argument:
LPCOLESTR lpszServerName : Server name or NULL for local computer
LPCOLESTR lpszUserName : User name of blank for no impersonation
LPCOLESTR lpszPassword : Password (might be blank or NULL)
Return Value:
N/A
--*/
: m_bstrServerName(),
m_bstrUserName(lpszUserName),
m_bstrPassword(lpszPassword),
m_fLocal(FALSE)
{
SetComputerName(lpszServerName);
}
CComAuthInfo::CComAuthInfo(
IN CComAuthInfo & auth
)
/*++
Routine Description:
Copy constructor
Arguments:
CComAuthInfo & auth : Source object to copy from
Return Value:
N/A
--*/
: m_bstrServerName(auth.m_bstrServerName),
m_bstrUserName(auth.m_bstrUserName),
m_bstrPassword(auth.m_bstrPassword),
m_fLocal(auth.m_fLocal)
{
}
CComAuthInfo::CComAuthInfo(
IN CComAuthInfo * pAuthInfo OPTIONAL
)
/*++
Routine Description:
Copy constructor
Arguments:
CComAuthInfo * pAuthInfo : Source object to copy from (or NULL)
Return Value:
N/A
--*/
: m_bstrServerName(),
m_bstrUserName(),
m_bstrPassword(),
m_fLocal(FALSE)
{
if (pAuthInfo)
{
//
// Full authentication information available
//
m_bstrUserName = pAuthInfo->m_bstrUserName;
m_bstrPassword = pAuthInfo->m_bstrPassword;
m_bstrServerName = pAuthInfo->m_bstrServerName;
m_fLocal = pAuthInfo->m_fLocal;
}
else
{
//
// Local computer w/o impersonation
//
SetComputerName(NULL);
}
}
CComAuthInfo &
CComAuthInfo::operator =(
IN CComAuthInfo & auth
)
/*++
Routine Description:
Assignment operator
Arguments:
CComAuthInfo & auth : Source object to copy from
Return Value:
Reference to current object
--*/
{
m_bstrServerName = auth.m_bstrServerName;
m_bstrUserName = auth.m_bstrUserName;
m_bstrPassword = auth.m_bstrPassword;
m_fLocal = auth.m_fLocal;
return *this;
}
CComAuthInfo &
CComAuthInfo::operator =(
IN CComAuthInfo * pAuthInfo OPTIONAL
)
/*++
Routine Description:
Assignment operator
Arguments:
CComAuthInfo * pAuthInfo : Source object to copy from (or NULL)
Return Value:
Reference to current object
--*/
{
if (pAuthInfo)
{
m_bstrUserName = pAuthInfo->m_bstrUserName;
m_bstrPassword = pAuthInfo->m_bstrPassword;
SetComputerName(pAuthInfo->m_bstrServerName);
}
else
{
//
// Local computer w/o impersonation
//
m_bstrUserName.Empty();
m_bstrPassword.Empty();
SetComputerName(NULL);
}
return *this;
}
CComAuthInfo &
CComAuthInfo::operator =(
IN LPCTSTR lpszServerName
)
/*++
Routine Description:
Assignment operator. Assign computer name w/o impersonation
Arguments:
LPCTSTR lpszServerName : Source server name
Return Value:
Reference to current object
--*/
{
RemoveImpersonation();
SetComputerName(lpszServerName);
return *this;
}
void
CComAuthInfo::SetComputerName(
IN LPCOLESTR lpszServerName OPTIONAL
)
/*++
Routine Description:
Store the computer name. Determine if its local.
Arguments:
LPCOLESTR lpszServername : Server name. NULL indicates the local computer
Return Value:
None
--*/
{
if (lpszServerName && *lpszServerName)
{
//
// Specific computer name specified
//
m_bstrServerName = lpszServerName;
m_fLocal = ::IsServerLocal(lpszServerName);
}
else
{
//
// Use local computer name
//
// CODEWORK: Cache static version of computername maybe?
//
TCHAR szLocalServer[MAX_PATH + 1];
DWORD dwSize = MAX_PATH;
VERIFY(::GetComputerName(szLocalServer, &dwSize));
m_bstrServerName = szLocalServer;
m_fLocal = TRUE;
}
}
void
CComAuthInfo::SetImpersonation(
IN LPCOLESTR lpszUser,
IN LPCOLESTR lpszPassword
)
/*++
Routine Description:
Set impersonation parameters
Arguments:
LPCOLESTR lpszUser : User name
LPCOLESTR lpszPassword : Password
Return Value:
None
--*/
{
m_bstrUserName = lpszUser;
StorePassword(lpszPassword);
}
void
CComAuthInfo::RemoveImpersonation()
/*++
Routine Description:
Remove impersonation parameters
Arguments:
None
Return Value:
None
--*/
{
m_bstrUserName.Empty();
m_bstrPassword.Empty();
}
COSERVERINFO *
CComAuthInfo::CreateServerInfoStruct() const
{
return (CComAuthInfo::CreateServerInfoStruct(RPC_C_AUTHN_LEVEL_DEFAULT));
}
COSERVERINFO *
CComAuthInfo::CreateServerInfoStruct(DWORD dwAuthnLevel) const
/*++
Routine Description:
Create the server info structure. Might return NULL for the no frills case.
Arguments:
NULL
Return Value:
A COSERVERINFO structure, or NULL if the computer is local, and no
impersonation is required.
Notes:
Caller must call FreeServerInfoStruct() to prevent memory leaks
--*/
{
//
// Be smart about the server name; optimize for local
// computer name.
//
if (m_fLocal && !UsesImpersonation())
{
//
// Special, no-frills case.
//
return NULL;
}
//
// Create the COM server info for CoCreateInstanceEx
//
COSERVERINFO * pcsiName = NULL;
do
{
pcsiName = new COSERVERINFO;
if (!pcsiName)
{
break;
}
ZeroMemory(pcsiName, sizeof(COSERVERINFO));
pcsiName->pwszName = m_bstrServerName;
//
// Set impersonation
//
if (UsesImpersonation())
{
COAUTHINFO * pAuthInfo = new COAUTHINFO;
if (!pAuthInfo)
{
break;
}
ZeroMemory(pAuthInfo, sizeof(COAUTHINFO));
COAUTHIDENTITY * pAuthIdentityData = new COAUTHIDENTITY;
if (!pAuthIdentityData)
{
break;
}
ZeroMemory(pAuthIdentityData, sizeof(COAUTHIDENTITY));
CString strUserName(m_bstrUserName);
CString strPassword(m_bstrPassword);
CString strDomain;
//
// Break up domain\username combo
//
SplitUserNameAndDomain(strUserName, strDomain);
pAuthIdentityData->UserLength = strUserName.GetLength();
if (pAuthIdentityData->UserLength != 0)
{
pAuthIdentityData->User = StrDup(strUserName);
}
pAuthIdentityData->DomainLength = strDomain.GetLength();
if (pAuthIdentityData->DomainLength != 0)
{
pAuthIdentityData->Domain = StrDup(strDomain);
}
pAuthIdentityData->PasswordLength = strPassword.GetLength();
if (pAuthIdentityData->PasswordLength)
{
pAuthIdentityData->Password = StrDup(strPassword);
}
// RPC_C_AUTHN_LEVEL_DEFAULT 0
// RPC_C_AUTHN_LEVEL_NONE 1
// RPC_C_AUTHN_LEVEL_CONNECT 2
// RPC_C_AUTHN_LEVEL_CALL 3
// RPC_C_AUTHN_LEVEL_PKT 4
// RPC_C_AUTHN_LEVEL_PKT_INTEGRITY 5
// RPC_C_AUTHN_LEVEL_PKT_PRIVACY 6
// you can only specify stuff stronger than RPC_C_AUTHN_LEVEL_CONNECT
if (RPC_C_AUTHN_LEVEL_DEFAULT != dwAuthnLevel)
{
if (dwAuthnLevel >= RPC_C_AUTHN_LEVEL_CONNECT && dwAuthnLevel <= RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
{
pAuthInfo->dwAuthnLevel = dwAuthnLevel;
}
else
{
pAuthInfo->dwAuthnLevel = RPC_C_AUTHN_LEVEL_CONNECT;
}
}
else
{
pAuthInfo->dwAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT;
}
pAuthIdentityData->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
pAuthInfo->dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
pAuthInfo->dwAuthnSvc = RPC_C_AUTHN_WINNT;
pAuthInfo->dwAuthzSvc = RPC_C_AUTHZ_NONE;
pAuthInfo->pwszServerPrincName = NULL;
pAuthInfo->dwCapabilities = EOAC_NONE;
pAuthInfo->pAuthIdentityData = pAuthIdentityData;
pcsiName->pAuthInfo = pAuthInfo;
}
}
while(FALSE);
return pcsiName;
}
void
CComAuthInfo::FreeServerInfoStruct(
IN COSERVERINFO * pServerInfo
) const
/*++
Routine Description:
As mentioned above -- free the server info structure
Arguments:
COSERVERINFO * pServerInfo : Server info structure
Return Value:
None
--*/
{
if (pServerInfo)
{
if (pServerInfo->pAuthInfo)
{
if (pServerInfo->pAuthInfo->pAuthIdentityData)
{
if (pServerInfo->pAuthInfo->pAuthIdentityData)
{
LocalFree(pServerInfo->pAuthInfo->pAuthIdentityData->User);
LocalFree(pServerInfo->pAuthInfo->pAuthIdentityData->Domain);
LocalFree(pServerInfo->pAuthInfo->pAuthIdentityData->Password);
delete pServerInfo->pAuthInfo->pAuthIdentityData;
}
}
delete pServerInfo->pAuthInfo;
}
delete pServerInfo;
}
}
HRESULT
CComAuthInfo::ApplyProxyBlanket(
IN OUT IUnknown * pInterface
)
/*++
Routine Description:
Set security information on the interface. The user name is of the form
domain\username.
Arguments:
IUnknown * pInterface : Interface
Return Value:
HRESULT
--*/
{
HRESULT hr = S_OK;
COSERVERINFO * pcsiName = CreateServerInfoStruct();
//
// This method should only be called if we're using impersonation.
// so the pcsiName returned should never be NULL.
//
ATLASSERT(pcsiName && pcsiName->pAuthInfo);
DWORD dwAuthSvc, dwAuthzSvc, dwAuthnLevel, dwImplLevel, dwCaps;
OLECHAR * pServerPrincName;
RPC_AUTH_IDENTITY_HANDLE pAuthInfo;
hr = ::CoQueryProxyBlanket(
pInterface,
&dwAuthSvc,
&dwAuthzSvc,
&pServerPrincName,
&dwAuthnLevel,
&dwImplLevel,
&pAuthInfo,
&dwCaps);
if (pcsiName && pcsiName->pAuthInfo)
{
hr = ::CoSetProxyBlanket(
pInterface,
pcsiName->pAuthInfo->dwAuthnSvc,
pcsiName->pAuthInfo->dwAuthzSvc,
pcsiName->pAuthInfo->pwszServerPrincName,
pcsiName->pAuthInfo->dwAuthnLevel,
pcsiName->pAuthInfo->dwImpersonationLevel,
pcsiName->pAuthInfo->pAuthIdentityData,
pcsiName->pAuthInfo->dwCapabilities
);
FreeServerInfoStruct(pcsiName);
}
return hr;
}
HRESULT
CComAuthInfo::ApplyProxyBlanket(
IN OUT IUnknown * pInterface,
IN DWORD dwAuthnLevelInput
)
/*++
Routine Description:
Set security information on the interface. The user name is of the form
domain\username.
Arguments:
IUnknown * pInterface : Interface
Return Value:
HRESULT
--*/
{
HRESULT hr = S_OK;
COSERVERINFO * pcsiName = CreateServerInfoStruct(dwAuthnLevelInput);
//
// This method should only be called if we're using impersonation.
// so the pcsiName returned should never be NULL.
//
ATLASSERT(pcsiName && pcsiName->pAuthInfo);
DWORD dwAuthSvc, dwAuthzSvc, dwAuthnLevel, dwImplLevel, dwCaps;
OLECHAR * pServerPrincName;
RPC_AUTH_IDENTITY_HANDLE pAuthInfo;
hr = ::CoQueryProxyBlanket(
pInterface,
&dwAuthSvc,
&dwAuthzSvc,
&pServerPrincName,
&dwAuthnLevel,
&dwImplLevel,
&pAuthInfo,
&dwCaps);
if (pcsiName && pcsiName->pAuthInfo)
{
hr = ::CoSetProxyBlanket(
pInterface,
pcsiName->pAuthInfo->dwAuthnSvc,
pcsiName->pAuthInfo->dwAuthzSvc,
pcsiName->pAuthInfo->pwszServerPrincName,
pcsiName->pAuthInfo->dwAuthnLevel,
pcsiName->pAuthInfo->dwImpersonationLevel,
pcsiName->pAuthInfo->pAuthIdentityData,
pcsiName->pAuthInfo->dwCapabilities
);
FreeServerInfoStruct(pcsiName);
}
return hr;
}
//
// CMetabasePath implemention
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
const LPCTSTR CMetabasePath::_cszMachine = SZ_MBN_MACHINE;
const LPCTSTR CMetabasePath::_cszRoot = SZ_MBN_ROOT;
const LPCTSTR CMetabasePath::_cszSep = SZ_MBN_SEP_STR;
const TCHAR CMetabasePath::_chSep = SZ_MBN_SEP_CHAR;
const CString CMetabasePath::_anySep = SZ_MBN_ANYSEP_STR;
/*static*/
BOOL
CMetabasePath::IsSeparator(TCHAR c)
{
return _anySep.find(c) != CString::npos;
}
/* static */
LPCTSTR
CMetabasePath::ConvertToParentPath(
OUT IN CString & strMetaPath
)
/*++
Routine Description:
Given the path, convert it to the parent path
e.g. "foo/bar/etc" returns "foo/bar"
Arguments:
CString & strMetaPath : Path to be converted
Return value:
Pointer to the converted path, or NULL in case of error
--*/
{
// TRACE(_T("Getting parent path of %s\n"), strMetaPath);
CString::size_type pos, pos_head;
if ((pos = strMetaPath.find_last_of(SZ_MBN_ANYSEP_STR)) == strMetaPath.length() - 1)
{
strMetaPath.erase(pos);
}
pos = strMetaPath.find_last_of(SZ_MBN_ANYSEP_STR);
if (pos == CString::npos)
return strMetaPath;
pos_head = strMetaPath.find_first_of(SZ_MBN_ANYSEP_STR);
if (pos_head != pos)
{
strMetaPath.erase(pos);
}
// TRACE(_T("Parent path should be %s\n"), strMetaPath);
return strMetaPath;
}
LPCTSTR
CMetabasePath::ConvertToParentPath(
CMetabasePath& path
)
{
return CMetabasePath::ConvertToParentPath(path.m_strMetaPath);
}
/* static */
LPCTSTR
CMetabasePath::TruncatePath(
IN int nLevel,
IN LPCTSTR lpszMDPath,
OUT CString & strNewPath,
OUT CString * pstrRemainder OPTIONAL
)
/*++
Routine Description:
Truncate the given metabase path at the given level, that is,
the nLevel'th separator in the path, starting at 0, where 0 will
always give lpszPath back whether it started with a separator or not.
Examples:
"/lm/w3svc/1/foo" at level 2 returns "/lm/w3svc" as does
"lm/w3svc/1/foo".
Arguments:
int nLevel 0-based separator count to truncate at.
LPTSTR lpszMDPath Fully-qualified metabase path
CString & strNewPath Returns truncated path
CString * pstrRemainder Optionally returns the remainder past
the nLevel'th separator.
Return Value:
The truncated path at the level requested. See examples above. *pstrRemainder
returns the remainder of the path. If the path does not contain nLevel
worth of separators, the entire path is returned, and the remainder will be
blank.
--*/
{
// ASSERT_PTR(lpszMDPath);
ATLASSERT(nLevel >= 0);
if (!lpszMDPath || nLevel < 0)
{
// TRACE(_T("TruncatePath: Invalid parameter\n"));
return NULL;
}
// TRACE(_T("Source Path: %s\n"), lpszMDPath);
//
// Skip the first sep whether it exists or not
//
LPCTSTR lp = IsSeparator(*lpszMDPath) ? lpszMDPath + 1 : lpszMDPath;
LPCTSTR lpRem = NULL;
int cSeparators = 0;
if (nLevel)
{
//
// Advance to the requested separator level
//
while (*lp)
{
if (IsSeparator(*lp))
{
if (++cSeparators == nLevel)
{
break;
}
}
++lp;
}
if (!*lp)
{
//
// End of path is considered a separator
//
++cSeparators;
}
ATLASSERT(cSeparators <= nLevel);
if (cSeparators == nLevel)
{
//
// Break up the strings
//
strNewPath = lpszMDPath;
strNewPath.erase(lp - lpszMDPath);
// TRACE(_T("Path truncated at level %d : %s\n"), nLevel, strNewPath);
if (*lp)
{
lpRem = ++lp;
// TRACE(_T("Remainder: %s\n"), lpRem);
}
}
}
//
// Return remainder
//
if (pstrRemainder && lpRem)
{
// ASSERT_WRITE_PTR(pstrRemainder);
*pstrRemainder = lpRem;
}
return strNewPath;
}
/* static */
DWORD
CMetabasePath::GetInstanceNumber(
IN LPCTSTR lpszMDPath
)
/*++
Routine Description:
Get the number of the instance referred to in the given metabase
path.
Examples: "lm/w3svc/1/foo/bar" will return 1
"lm/w3svc/" will return 0 (master instance)
"lm/bogus/path/" will return 0xffffffff (error)
Arguments:
LPCTSTR lpszMDPath : A metabase path.
Return Value:
Instance number (0 indicates master instance)
or 0xffffffff if the path is in error.
--*/
{
// TRACE(_T("Determining instance number of %s\n"), lpszMDPath);
DWORD dwInstance = 0xffffffff;
CString strService, strInst;
if (GetServicePath(lpszMDPath, strService, &strInst))
{
if (strInst.IsEmpty())
{
dwInstance = MASTER_INSTANCE;
}
else
{
if (_istdigit(strInst.GetAt(0)))
{
dwInstance = _ttol(strInst);
}
}
}
return dwInstance;
}
/* static */
LPCTSTR
CMetabasePath::GetLastNodeName(
IN LPCTSTR lpszMDPath,
OUT CString & strNodeName
)
/*++
Routine Description:
Get the last nodename off the metabase path
Example:
"/lm/foo/bar/" returns "bar"
Arguments:
LPCTSTR lpszMDPath : Metabase path
Return Value:
Pointer to the node name or NULL in case of a malformed path.
--*/
{
// ASSERT_PTR(lpszMDPath);
if (!lpszMDPath || !*lpszMDPath)
{
return NULL;
}
// TRACE(_T("Getting last node name from %s\n"), lpszMDPath);
LPCTSTR lp;
LPCTSTR lpTail;
lp = lpTail = lpszMDPath + lstrlen(lpszMDPath) - 1;
//
// Skip trailing separator
//
if (IsSeparator(*lp))
{
--lpTail;
--lp;
}
strNodeName.Empty();
while (*lp && !IsSeparator(*lp))
{
strNodeName += *(lp--);
}
strNodeName.MakeReverse();
// TRACE(_T("Node is %s\n"), strNodeName);
return strNodeName;
}
/* static */
void
CMetabasePath::SplitMetaPathAtInstance(
IN LPCTSTR lpszMDPath,
OUT CString & strParent,
OUT CString & strAlias
)
/*++
Routine Description:
Split the given path into parent metabase root and alias, with the root
being the instance path, and the alias everything following the
instance.
Arguments:
LPCTSTR lpszMDPath : Input path
CString & strParent : Outputs the parent path
CString & strAlias : Outputs the alias name
Return Value:
None.
--*/
{
// ASSERT_PTR(lpszMDPath);
// TRACE(_T("Source Path %s\n"), lpszMDPath);
strParent = lpszMDPath;
strAlias.Empty();
LPTSTR lp = (LPTSTR)lpszMDPath;
if (lp == NULL)
{
return;
}
int cSeparators = 0;
int iChar = 0;
//
// Looking for "LM/sss/ddd/" <-- 3d slash:
//
while (*lp && cSeparators < 2)
{
if (IsSeparator(*lp))
{
++cSeparators;
}
++iChar;
}
if (!*lp)
{
//
// Bogus format
//
ASSERT_MSG("Bogus Format");
return;
}
if (_istdigit(*lp))
{
//
// Not at the master instance, skip one more.
//
while (*lp)
{
++iChar;
if (IsSeparator(*lp++))
{
break;
}
}
if (!*lp)
{
//
// Bogus format
//
ASSERT_MSG("Bogus Format");
return;
}
}
strAlias = strParent.Mid(iChar);
strParent.erase(iChar);
// TRACE(_T("Broken up into %s\n"), strParent);
// TRACE(_T(" and %s\n"), strAlias);
}
/* static */
BOOL
CMetabasePath::IsHomeDirectoryPath(
IN LPCTSTR lpszMetaPath
)
/*++
Routine Description:
Determine if the path given describes a root directory
Arguments:
LPCTSTR lpszMetaPath : Metabase path
Return Value:
TRUE if the path describes a root directory,
FALSE if it does not
--*/
{
// ASSERT_READ_PTR(lpszMetaPath);
LPTSTR lpNode = lpszMetaPath ? StrPBrk(lpszMetaPath, _anySep) : NULL;
if (lpNode)
{
return _tcsicmp(++lpNode, _cszRoot) == 0;
}
return FALSE;
}
/* static */
BOOL
CMetabasePath::IsMasterInstance(
IN LPCTSTR lpszMDPath
)
/*++
Routine Description:
Determine if the given metabase path points to the master instance
(site). This is essentially the service path.
Arguments:
LPCTSTR lpszMDPath : Metabase path.
Return Value:
TRUE if the path is the master instance,
FALSE otherwise.
--*/
{
// ASSERT_READ_PTR(lpszMDPath);
if (!lpszMDPath || !*lpszMDPath)
{
return FALSE;
}
// TRACE(_T("Checking path %s\n"), lpszMDPath);
CString strService;
CString strRemainder;
LPCTSTR lpPath = TruncatePath(2, lpszMDPath, strService, &strRemainder);
return lpPath && !strService.IsEmpty() && strRemainder.IsEmpty();
}
/* static */
LPCTSTR
CMetabasePath::GetServiceInfoPath(
IN LPCTSTR lpszMDPath,
OUT CString & strInfoPath,
IN LPCTSTR lpszDefService OPTIONAL
)
/*++
Routine Description:
Generate the appropriate metabase service info path for the given
metabase path.
For example:
"lm/w3svc/1/foo/bar" Generates "lm/w3svc/info"
Arguments:
LPCTSTR lpszMDPath : Input metabase path
CString & strInfoPath : Returns the info path
LPCTSTR lpszDefService : Optionally specifies the default service to
use (e.g "w3svc") if no service could be found
in the path.
Return Value:
The info metabase path or NULL if one could not be generated.
--*/
{
//
// Capability info stored off the service path ("lm/w3svc").
//
CString strService;
CString strRem;
//
// Strip off everything past the service
//
if (!TruncatePath(2, lpszMDPath, strService, &strRem)
|| strService.IsEmpty())
{
if (!lpszDefService)
{
// TRACEEOLID("Unable to generate info path");
return NULL;
}
TRACEEOLID("Using default service for info path");
//
// Machine path (no service). Use web as default service to
// look for capability and version info.
//
strService = CMetabasePath(TRUE, lpszDefService);
}
strInfoPath = CMetabasePath(FALSE, strService, SZ_MBN_INFO);
// TRACE("Using %s to look for capability info\n", strInfoPath);
return strInfoPath;
}
/* static */
LPCTSTR
CMetabasePath::CleanMetaPath(
IN OUT CString & strMetaRoot
)
/*++
Routine Description:
Clean up the metabase path to one valid for internal consumption.
This removes the beginning and trailing slashes off the path.
Arguments:
CString & strMetaRoot : Metabase path to be cleaned up.
Return Value:
Pointer to the metabase path
--*/
{
if (!strMetaRoot.IsEmpty())
{
int hd = strMetaRoot.find_first_not_of(SZ_MBN_ANYSEP_STR);
int tl = strMetaRoot.find_last_not_of(SZ_MBN_ANYSEP_STR);
if (hd == CString::npos && tl == CString::npos)
{
// path contains only separators
strMetaRoot.erase();
return strMetaRoot;
}
else if (hd != CString::npos)
{
if (tl != CString::npos)
tl++;
strMetaRoot = strMetaRoot.substr(hd, tl - hd);
}
#if 0
while (strMetaRoot.GetLength() > 0
&& IsSeparator(strMetaRoot[strMetaRoot.GetLength() - 1]))
{
strMetaRoot.erase(strMetaRoot.GetLength() - 1);
}
while (strMetaRoot.GetLength() > 0
&& IsSeparator(strMetaRoot[0]))
{
strMetaRoot = strMetaRoot.Right(strMetaRoot.GetLength() - 1);
}
#endif
// looks like IISAdmin works only with separators "/"
for (int i = 0; i < strMetaRoot.GetLength(); i++)
{
if (IsSeparator(strMetaRoot[i]))
strMetaRoot.SetAt(i, _chSep);
}
}
return strMetaRoot;
}
/* static */
LPCTSTR
CMetabasePath::CleanMetaPath(
IN OUT CMetabasePath & path
)
{
return CleanMetaPath(path.m_strMetaPath);
}
CMetabasePath::CMetabasePath(
IN BOOL fAddBasePath,
IN LPCTSTR lpszMDPath,
IN LPCTSTR lpszMDPath2 OPTIONAL,
IN LPCTSTR lpszMDPath3 OPTIONAL,
IN LPCTSTR lpszMDPath4 OPTIONAL
)
/*++
Routine Description:
Constructor.
Arguments:
BOOL fAddBasePath : TRUE to prepend base path ("LM")
FALSE if the path is complete
LPCTSTR lpszMDPath : Metabase path
LPCTSTR lpszMDPath2 : Optional child path
LPCTSTR lpszMDPath3 : Optional child path
LPCTSTR lpszMDPath4 : Optional child path
Return Value:
N/A
--*/
: m_strMetaPath()
{
// This will fail for NULL pointer
// ASSERT_READ_PTR(lpszMDPath);
if (fAddBasePath)
{
m_strMetaPath = _cszMachine;
AppendPath(lpszMDPath);
}
else
{
m_strMetaPath = lpszMDPath;
}
//
// Add optional path components
//
AppendPath(lpszMDPath2);
AppendPath(lpszMDPath3);
AppendPath(lpszMDPath4);
}
CMetabasePath::CMetabasePath(
IN LPCTSTR lpszSvc, OPTIONAL
IN DWORD dwInstance, OPTIONAL
IN LPCTSTR lpszParentPath, OPTIONAL
IN LPCTSTR lpszAlias OPTIONAL
)
/*++
Routine Description:
Constructor. Construct with path components.
Arguments:
LPCTSTR lpszSvc : Service (may be NULL or "")
DWORD dwInstance : Instance number (may be 0 for master)
LPCTSTR lpszParentPath : Parent path (may be NULL or "")
LPCTSTR lpszAlias : Alias (may be NULL or "")
Return Value:
N/A
--*/
: m_strMetaPath()
{
BuildMetaPath(lpszSvc, dwInstance, lpszParentPath, lpszAlias);
}
void
CMetabasePath::AppendPath(
IN LPCTSTR lpszPath
)
/*++
Routine Description:
Append path to current metabase path
Arguments:
LPCTSTR lpszPath : Metabase path
Return Value:
None
--*/
{
if (lpszPath && *lpszPath)
{
m_strMetaPath += _cszSep;
m_strMetaPath += lpszPath;
}
}
void
CMetabasePath::AppendPath(
IN DWORD dwInstance
)
/*++
Routine Description:
Append path to current metabase path
Arguments:
DWORD dwInstance : Instance path
Return Value:
None
--*/
{
// ASSERT(dwInstance >= 0);
if (!IS_MASTER_INSTANCE(dwInstance))
{
TCHAR szInstance[] = _T("4000000000");
_ltot(dwInstance, szInstance, 10);
m_strMetaPath += _cszSep;
m_strMetaPath += szInstance;
}
}
void
CMetabasePath::BuildMetaPath(
IN LPCTSTR lpszSvc OPTIONAL,
IN LPCTSTR lpszInstance OPTIONAL,
IN LPCTSTR lpszParentPath OPTIONAL,
IN LPCTSTR lpszAlias OPTIONAL
)
/*++
Routine Description:
Build a complete metapath with the given service name, instance
number and optional path components.
Arguments:
LPCTSTR lpszSvc : Service (may be NULL or "")
LPCTSTR lpszInstance : Instance (may be NULL or "")
LPCTSTR lpszParentPath : Parent path (may be NULL or "")
LPCTSTR lpszAlias : Alias (may be NULL or "")
Return Value:
Pointer to internal buffer containing the path.
--*/
{
m_strMetaPath = _cszMachine;
AppendPath(lpszSvc);
AppendPath(lpszInstance);
AppendPath(lpszParentPath);
if (lpszAlias && *lpszAlias)
{
//
// Special case: If the alias is root, but we're
// at the master instance, ignore this.
//
if (lpszInstance || ::lstrcmpi(_cszRoot, lpszAlias))
{
m_strMetaPath += _cszSep;
m_strMetaPath += lpszAlias;
}
}
// TRACE(_T("Generated metapath: %s\n"), m_strMetaPath );
}
void
CMetabasePath::BuildMetaPath(
IN LPCTSTR lpszSvc OPTIONAL,
IN DWORD dwInstance OPTIONAL,
IN LPCTSTR lpszParentPath OPTIONAL,
IN LPCTSTR lpszAlias OPTIONAL
)
/*++
Routine Description:
Build a complete metapath with the given service name, instance
number and optional path components.
Arguments:
LPCTSTR lpszSvc : Service (may be NULL or "")
DWORD dwInstance : Instance number (may be 0 for master)
LPCTSTR lpszParentPath : Parent path (may be NULL or "")
LPCTSTR lpszAlias : Alias (may be NULL or "")
Return Value:
Pointer to internal buffer containing the path.
--*/
{
m_strMetaPath = _cszMachine;
AppendPath(lpszSvc);
AppendPath(dwInstance);
AppendPath(lpszParentPath);
if (lpszAlias && *lpszAlias)
{
//
// Special case: If the alias is root, but we're
// at the master instance, ignore this.
//
if (!IS_MASTER_INSTANCE(dwInstance) || ::lstrcmpi(_cszRoot, lpszAlias))
{
m_strMetaPath += _cszSep;
m_strMetaPath += lpszAlias;
}
}
// TRACE(_T("Generated metapath: %s\n"), m_strMetaPath);
}
//
// CIISInterface class
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
CIISInterface::CIISInterface(
IN CComAuthInfo * pAuthInfo, OPTIONAL
IN HRESULT hrInterface OPTIONAL
)
/*++
Routine Description:
Base class constructor.
Arguments:
CComAuthInfo * pAuthInfo : Auth info or NULL for local computer
HRESULT hrInterface : Initial error code. S_OK by default.
Return Value:
N/A
--*/
: m_auth(pAuthInfo),
m_hrInterface(hrInterface)
{
}
HRESULT
CIISInterface::Create(
IN int cInterfaces,
IN const IID rgIID[],
IN const GUID rgCLSID[],
OUT int * pnInterface, OPTIONAL
OUT IUnknown ** ppInterface
)
/*++
Routine Description:
Create interface. This will try a range of interfaces in order of priority.
Arguments:
int cInterfaces : Number of interfaces in array.
const IID * rgIID : Array if IIDs
const GUID * rgCLSID : Array of CLSIDs
int * pnInterface : Returns the interface index that was successful.
or NULL if not interested.
IUnknown ** ppInterface : Returns pointer to the interface.
Return Value:
HRESULT
Notes:
This will attempt to create an interface, in order of declaration in
the IID and CLSIS arrays. The first successful interface to be created
will have its index returned in *pnInterfaces.
--*/
{
ASSERT(cInterfaces > 0);
ASSERT(rgIID && rgCLSID && ppInterface);
COSERVERINFO * pcsiName = m_auth.CreateServerInfoStruct();
MULTI_QI rgmqResults;
CError err;
int nInterface;
//
// Try to create the interface in order
//
for (nInterface = 0; nInterface < cInterfaces; ++nInterface)
{
ZeroMemory(&rgmqResults, sizeof(rgmqResults));
rgmqResults.pIID = &rgIID[nInterface];
// TRACE("Attempting to create interface #%d\n", nInterface);
err = ::CoCreateInstanceEx(
rgCLSID[nInterface],
NULL,
CLSCTX_SERVER,
pcsiName,
1,
&rgmqResults
);
if (err.Succeeded() || err.Win32Error() == ERROR_ACCESS_DENIED)
{
break;
}
}
if(err.Succeeded())
{
//
// Save the interface pointer
//
ASSERT_PTR(rgmqResults.pItf);
*ppInterface = rgmqResults.pItf;
if (pnInterface)
{
//
// Store successful interface index
//
*pnInterface = nInterface;
}
//
// Strangely enough, I now have still have to apply
// the proxy blanket. Apparently this is by design.
//
if (m_auth.UsesImpersonation())
{
ApplyProxyBlanket();
}
}
//
// Clean up
//
m_auth.FreeServerInfoStruct(pcsiName);
return err;
}
//
// CMetaInterface class
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
CMetaInterface::CMetaInterface(
IN CComAuthInfo * pAuthInfo OPTIONAL
)
/*++
Routine Description:
Construct and initialize the interface
Arguments:
CComAuthInfo * pAuthInfo : Authentication info. NULL indicates
the local computer.
Return Value:
N/A
--*/
: CIISInterface(pAuthInfo),
m_pInterface(NULL),
m_iTimeOutValue(MB_TIMEOUT)
{
//
// Initialize the interface
//
m_hrInterface = Create();
}
CMetaInterface::CMetaInterface(
IN CMetaInterface * pInterface
)
/*++
Routine Description:
Construct from existing interface (Copy Constructor)
Arguments:
CMetaInterface * pInterface : Existing interface
Return Value:
N/A
Notes:
Object will not take ownership of the interface,
it will merely add to the reference count, and
release it upon destruction
BUGBUG:
if pInterface is NULL, this will AV.
--*/
: CIISInterface(&pInterface->m_auth, pInterface->m_hrInterface),
m_pInterface(pInterface->m_pInterface),
m_iTimeOutValue(pInterface->m_iTimeOutValue)
{
ASSERT_READ_PTR(m_pInterface);
m_pInterface->AddRef();
}
CMetaInterface::~CMetaInterface()
/*++
Routine Description:
Destructor -- releases the interface
Arguments:
N/A
Return Value:
N/A
--*/
{
SAFE_RELEASE(m_pInterface);
}
HRESULT
CMetaInterface::Create()
{
return CIISInterface::Create(
1,
&IID_IMSAdminBase,
&CLSID_MSAdminBase,
NULL,
(IUnknown **)&m_pInterface
);
}
//
// CMetaKey class
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
//
// Helper macros
//
#define ASSURE_PROPER_INTERFACE()\
if (!HasInterface()) { ASSERT_MSG("No interface"); return MD_ERROR_NOT_INITIALIZED; }
#define ASSURE_OPEN_KEY()\
if (!m_hKey && !m_fAllowRootOperations) { ASSERT_MSG("No open key"); return HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE); }
#define FETCH_PROPERTY_DATA_OR_FAIL(dwID, md)\
ZeroMemory(&md, sizeof(md)); \
if (!GetMDFieldDef(dwID, md.dwMDIdentifier, md.dwMDAttributes, md.dwMDUserType, md.dwMDDataType))\
{ ASSERT_MSG("Bad property ID"); return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); }
//
// Static Initialization
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
#define MD_SERVER_PLATFORM (IIS_MD_SERVER_BASE+100 )
#define MD_SERVER_VERSION_MAJOR (IIS_MD_SERVER_BASE+101 )
#define MD_SERVER_VERSION_MINOR (IIS_MD_SERVER_BASE+102 )
#define MD_SERVER_CAPABILITIES (IIS_MD_SERVER_BASE+103 )
#ifndef MD_APP_PERIODIC_RESTART_TIME
#define MD_APP_PERIODIC_RESTART_TIME 2111
#endif
#ifndef MD_APP_PERIODIC_RESTART_REQUESTS
#define MD_APP_PERIODIC_RESTART_REQUESTS 2112
#endif
#ifndef MD_APP_PERIODIC_RESTART_SCHEDULE
#define MD_APP_PERIODIC_RESTART_SCHEDULE 2113
#endif
#ifndef MD_ASP_DISKTEMPLATECACHEDIRECTORY
#define MD_ASP_DISKTEMPLATECACHEDIRECTORY 7036
#endif
#ifndef MD_ASP_MAXDISKTEMPLATECACHEFILES
#define MD_ASP_MAXDISKTEMPLATECACHEFILES 7040
#endif
//
// Metabase table
//
const CMetaKey::MDFIELDDEF CMetaKey::s_rgMetaTable[] =
{
///////////////////////////////////////////////////////////////////////////
//
// !!!IMPORTANT!!! This table must be sorted on dwMDIdentifier. (Will
// ASSERT if not not sorted)
//
{ MD_MAX_BANDWIDTH, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
{ MD_SERVER_COMMAND, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_CONNECTION_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CONNECTION_TIMEOUT },
{ MD_MAX_CONNECTIONS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_MAX_CONNECTIONS },
{ MD_SERVER_COMMENT, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_SERVER_COMMENT },
{ MD_SERVER_STATE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_SERVER_AUTOSTART, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_SERVER_SIZE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_SERVER_SIZE },
{ MD_SERVER_LISTEN_BACKLOG, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_SERVER_LISTEN_BACKLOG },
{ MD_SERVER_LISTEN_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_SERVER_LISTEN_TIMEOUT },
{ MD_SERVER_BINDINGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, 0 },
{ MD_WIN32_ERROR, METADATA_VOLATILE, IIS_MD_UT_FILE, DWORD_METADATA, 0 },
{ MD_SERVER_PLATFORM, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_SERVER_VERSION_MAJOR, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_SERVER_VERSION_MINOR, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_SERVER_CAPABILITIES, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_SECURE_BINDINGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, 0 },
{ MD_FILTER_LOAD_ORDER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
{ MD_FILTER_IMAGE_PATH, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
{ MD_FILTER_STATE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_FILTER_ENABLED, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_FILTER_FLAGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_AUTH_CHANGE_URL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_AUTH_EXPIRED_URL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
{ MD_AUTH_NOTIFY_PWD_EXP_URL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
{ MD_ADV_NOTIFY_PWD_EXP_IN_DAYS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_ADV_CACHE_TTL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_AUTH_EXPIRED_UNSECUREURL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
{ MD_AUTH_CHANGE_FLAGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_AUTH_NOTIFY_PWD_EXP_UNSECUREURL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
{ MD_FRONTPAGE_WEB, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_MAPCERT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
{ MD_MAPNTACCT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
{ MD_MAPNAME, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
{ MD_MAPENABLED, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
{ MD_MAPREALM, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
{ MD_MAPPWD, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
{ MD_ITACCT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
{ MD_CPP_CERT11, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
{ MD_SERIAL_CERT11, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
{ MD_CPP_CERTW, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
{ MD_SERIAL_CERTW, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
{ MD_CPP_DIGEST, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
{ MD_SERIAL_DIGEST, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
{ MD_CPP_ITA, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
{ MD_SERIAL_ITA, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
{ MD_APP_FRIENDLY_NAME, METADATA_INHERIT, IIS_MD_UT_WAM, STRING_METADATA, IDS_MD_APP_FRIENDLY_NAME },
{ MD_APP_ROOT, METADATA_INHERIT, IIS_MD_UT_WAM, STRING_METADATA, IDS_MD_APP_ROOT },
{ MD_APP_ISOLATED, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_MD_APP_ISOLATED },
// new stuff
{ MD_APP_PERIODIC_RESTART_TIME, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, 0 },
{ MD_APP_PERIODIC_RESTART_REQUESTS, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, 0 },
{ MD_APP_PERIODIC_RESTART_SCHEDULE, METADATA_INHERIT, IIS_MD_UT_WAM, MULTISZ_METADATA, 0 },
// end new stuff
{ MD_HC_COMPRESSION_DIRECTORY, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
{ MD_HC_DO_DYNAMIC_COMPRESSION, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_HC_DO_STATIC_COMPRESSION, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_HC_DO_DISK_SPACE_LIMITING, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_HC_MAX_DISK_SPACE_USAGE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_VR_PATH, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_VR_PATH },
{ MD_VR_USERNAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_VR_USERNAME },
{ MD_VR_PASSWORD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_VR_PASSWORD },
{ MD_VR_ACL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, BINARY_METADATA, 0 },
{ MD_VR_UPDATE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, DWORD_METADATA, 0 },
{ MD_LOG_TYPE, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOG_TYPE },
{ MD_LOGFILE_DIRECTORY, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGFILE_DIRECTORY },
{ MD_LOGFILE_PERIOD, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOGFILE_PERIOD },
{ MD_LOGFILE_TRUNCATE_SIZE, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOGFILE_TRUNCATE_SIZE },
{ MD_LOGSQL_DATA_SOURCES, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_DATA_SOURCES },
{ MD_LOGSQL_TABLE_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_TABLE_NAME },
{ MD_LOGSQL_USER_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_USER_NAME },
{ MD_LOGSQL_PASSWORD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_PASSWORD },
{ MD_LOG_PLUGIN_ORDER, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_LOG_PLUGIN_ORDER },
{ MD_LOGEXT_FIELD_MASK, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOGEXT_FIELD_MASK },
{ MD_LOGFILE_LOCALTIME_ROLLOVER, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOGFILE_LOCALTIME_ROLLOVER },
{ MD_EXIT_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_EXIT_MESSAGE },
{ MD_GREETING_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, IDS_MD_GREETING_MESSAGE },
{ MD_MAX_CLIENTS_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_MAX_CLIENTS_MESSAGE },
{ MD_MSDOS_DIR_OUTPUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_MSDOS_DIR_OUTPUT },
{ MD_ALLOW_ANONYMOUS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_ALLOW_ANONYMOUS },
{ MD_ANONYMOUS_ONLY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_ANONYMOUS_ONLY },
{ MD_LOG_ANONYMOUS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOG_ANONYMOUS },
{ MD_LOG_NONANONYMOUS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOG_NONANONYMOUS },
{ MD_SSL_PUBLIC_KEY, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
{ MD_SSL_PRIVATE_KEY, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
{ MD_SSL_KEY_PASSWORD, METADATA_SECURE, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
{ MD_SSL_CERT_HASH, METADATA_INHERIT, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
{ MD_SSL_CERT_STORE_NAME, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
{ MD_SSL_CTL_IDENTIFIER, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
{ MD_SSL_CTL_STORE_NAME, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
{ MD_SSL_USE_DS_MAPPER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
{ MD_AUTHORIZATION, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_AUTHORIZATION },
{ MD_REALM, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_REALM },
{ MD_HTTP_EXPIRES, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_HTTP_EXPIRES },
{ MD_HTTP_PICS, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_HTTP_PICS },
{ MD_HTTP_CUSTOM, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_HTTP_CUSTOM },
{ MD_DIRECTORY_BROWSING, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_DIRECTORY_BROWSING },
{ MD_DEFAULT_LOAD_FILE, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_DEFAULT_LOAD_FILE },
{ MD_CONTENT_NEGOTIATION, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_CONTENT_NEGOTIATION },
{ MD_CUSTOM_ERROR, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_CUSTOM_ERROR },
{ MD_FOOTER_DOCUMENT, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_FOOTER_DOCUMENT },
{ MD_FOOTER_ENABLED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_FOOTER_ENABLED },
{ MD_HTTP_REDIRECT, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_HTTP_REDIRECT },
{ MD_DEFAULT_LOGON_DOMAIN, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_DEFAULT_LOGON_DOMAIN },
{ MD_LOGON_METHOD, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOGON_METHOD },
{ MD_SCRIPT_MAPS, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_SCRIPT_MAPS },
{ MD_MIME_MAP, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_MIME_MAP },
{ MD_ACCESS_PERM, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_ACCESS_PERM },
{ MD_IP_SEC, METADATA_INHERIT | METADATA_REFERENCE, IIS_MD_UT_FILE, BINARY_METADATA, IDS_MD_IP_SEC },
{ MD_ANONYMOUS_USER_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_ANONYMOUS_USER_NAME },
{ MD_ANONYMOUS_PWD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_ANONYMOUS_PWD },
{ MD_ANONYMOUS_USE_SUBAUTH, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_ANONYMOUS_USE_SUBAUTH },
{ MD_DONT_LOG, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_DONT_LOG },
{ MD_ADMIN_ACL, METADATA_INHERIT | METADATA_SECURE | METADATA_REFERENCE,IIS_MD_UT_SERVER, BINARY_METADATA, IDS_MD_ADMIN_ACL },
{ MD_SSI_EXEC_DISABLED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_SSI_EXEC_DISABLED },
{ MD_SSL_ACCESS_PERM, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_SSL_ACCESS_PERM },
{ MD_NTAUTHENTICATION_PROVIDERS, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_NTAUTHENTICATION_PROVIDERS },
{ MD_SCRIPT_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_SCRIPT_TIMEOUT },
{ MD_CACHE_EXTENSIONS, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_CACHE_EXTENSIONS },
{ MD_CREATE_PROCESS_AS_USER, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CREATE_PROCESS_AS_USER },
{ MD_CREATE_PROC_NEW_CONSOLE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CREATE_PROC_NEW_CONSOLE },
{ MD_POOL_IDC_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_POOL_IDC_TIMEOUT },
{ MD_ALLOW_KEEPALIVES, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_ALLOW_KEEPALIVES },
{ MD_IS_CONTENT_INDEXED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_IS_CONTENT_INDEXED },
{ MD_ISM_ACCESS_CHECK, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, DWORD_METADATA, 0 },
{ MD_ASP_BUFFERINGON, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_BUFFERINGON },
{ MD_ASP_LOGERRORREQUESTS, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_LOGERRORREQUESTS },
{ MD_ASP_SCRIPTERRORSSENTTOBROWSER, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_SCRIPTERRORSSENTTOBROWSER },
{ MD_ASP_SCRIPTERRORMESSAGE, METADATA_INHERIT, ASP_MD_UT_APP, STRING_METADATA, IDS_ASP_SCRIPTERRORMESSAGE },
{ MD_ASP_SCRIPTFILECACHESIZE, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_SCRIPTFILECACHESIZE },
{ MD_ASP_SCRIPTENGINECACHEMAX, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_SCRIPTENGINECACHEMAX },
{ MD_ASP_SCRIPTTIMEOUT, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_SCRIPTTIMEOUT },
{ MD_ASP_SESSIONTIMEOUT, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_SESSIONTIMEOUT },
{ MD_ASP_ENABLEPARENTPATHS, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ENABLEPARENTPATHS },
{ MD_ASP_ALLOWSESSIONSTATE, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ALLOWSESSIONSTATE },
{ MD_ASP_SCRIPTLANGUAGE, METADATA_INHERIT, ASP_MD_UT_APP, STRING_METADATA, IDS_ASP_SCRIPTLANGUAGE },
{ MD_ASP_EXCEPTIONCATCHENABLE, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_EXCEPTIONCATCHENABLE },
{ MD_ASP_ENABLESERVERDEBUG, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ENABLESERVERDEBUG },
{ MD_ASP_ENABLECLIENTDEBUG, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ENABLECLIENTDEBUG },
{ MD_ASP_DISKTEMPLATECACHEDIRECTORY, METADATA_INHERIT, IIS_MD_UT_WAM, STRING_METADATA, 0 },
{ MD_ASP_MAXDISKTEMPLATECACHEFILES, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, 0 },
{ MD_WAM_USER_NAME, METADATA_INHERIT, IIS_MD_UT_WAM, STRING_METADATA, 0 },
{ MD_WAM_PWD, METADATA_INHERIT, IIS_MD_UT_WAM, STRING_METADATA, 0 }
};
#define NUM_ENTRIES (sizeof(CMetaKey::s_rgMetaTable) / sizeof(CMetaKey::s_rgMetaTable[0]))
/* static */
int
CMetaKey::MapMDIDToTableIndex(
IN DWORD dwID
)
/*++
Routine Description:
Map MD id value to table index. Return -1 if not found
Arguments:
DWORD dwID : MD id value
Return Value:
Index into the table that coresponds to the MD id value
--*/
{
#ifdef _DEBUG
{
//
// Do a quick verification that our metadata
// table is sorted correctly.
//
static BOOL fTableChecked = FALSE;
if (!fTableChecked)
{
for (int n = 1; n < NUM_ENTRIES; ++n)
{
if (s_rgMetaTable[n].dwMDIdentifier
<= s_rgMetaTable[n - 1].dwMDIdentifier)
{
// TRACE("MD ID Table is out of order: Item is %d %s\n", n, s_rgMetaTable[n].dwMDIdentifier);
ASSERT_MSG("MD ID Table out of order");
}
}
//
// But only once.
//
++fTableChecked;
}
}
#endif // _DEBUG
//
// Look up the ID in the table using a binary search
//
int nRange = NUM_ENTRIES;
int nLow = 0;
int nHigh = nRange - 1;
int nMid;
int nHalf;
while (nLow <= nHigh)
{
if (nHalf = nRange / 2)
{
nMid = nLow + (nRange & 1 ? nHalf : (nHalf - 1));
if (s_rgMetaTable[nMid].dwMDIdentifier == dwID)
{
return nMid;
}
else if (s_rgMetaTable[nMid].dwMDIdentifier > dwID)
{
nHigh = --nMid;
nRange = nRange & 1 ? nHalf : nHalf - 1;
}
else
{
nLow = ++nMid;
nRange = nHalf;
}
}
else if (nRange)
{
return s_rgMetaTable[nLow].dwMDIdentifier == dwID ? nLow : -1;
}
else
{
break;
}
}
return -1;
}
/* static */
BOOL
CMetaKey::GetMDFieldDef(
IN DWORD dwID,
OUT DWORD & dwMDIdentifier,
OUT DWORD & dwMDAttributes,
OUT DWORD & dwMDUserType,
OUT DWORD & dwMDDataType
)
/*++
Routine Description:
Get information about metabase property
Arguments:
DWORD dwID : Meta ID
DWORD & dwMDIdentifier : Meta parms
DWORD & dwMDAttributes : Meta parms
DWORD & dwMDUserType : Meta parms
DWORD & dwMDDataType : Meta parms
Return Value:
TRUE for success, FALSE for failure.
--*/
{
int nID = MapMDIDToTableIndex(dwID);
if (nID == -1)
{
//
// Unrecognized meta data ID
//
ASSERT_MSG("Unrecognized meta data id");
return FALSE;
}
dwMDIdentifier = s_rgMetaTable[nID].dwMDIdentifier;
dwMDAttributes = s_rgMetaTable[nID].dwMDAttributes;
dwMDUserType = s_rgMetaTable[nID].dwMDUserType;
dwMDDataType = s_rgMetaTable[nID].dwMDDataType;
return TRUE;
}
/* static */
BOOL
CMetaKey::IsPropertyInheritable(
IN DWORD dwID
)
/*++
Routine Description:
Check to see if the given property is inheritable
Arguments:
DWORD dwID : Metabase ID
Return Value:
TRUE if the metabase ID is inheritable, FALSE otherwise.
--*/
{
int nID = MapMDIDToTableIndex(dwID);
if (nID == -1)
{
//
// Unrecognized meta data ID
//
ASSERT_MSG("Unrecognized meta data ID");
return FALSE;
}
return (s_rgMetaTable[nID].dwMDAttributes & METADATA_INHERIT) != 0;
}
/* static */
BOOL
CMetaKey::GetPropertyDescription(
IN DWORD dwID,
OUT CString & strName
)
/*++
Routine Description:
Get a description for the given property
Arguments:
DWORD dwID : Property ID
CString & strName : Returns friendly property name
Return Value:
TRUE for success, FALSE for failure
--*/
{
int nID = MapMDIDToTableIndex(dwID);
if (nID == -1)
{
//
// Unrecognized meta data ID
//
ASSERT_MSG("Unrecognized meta data ID");
return FALSE;
}
UINT uID = s_rgMetaTable[nID].uStringID;
BOOL fResult = TRUE;
if (uID > 0)
{
fResult = (strName.LoadString(_Module.GetResourceInstance(), uID) != 0);
}
else
{
//
// Don't have a friendly name -- fake it
//
CComBSTR bstrFmt;
VERIFY(bstrFmt.LoadString(_Module.GetResourceInstance(), IDS_INHERITANCE_NO_NAME));
strName.Format(bstrFmt, dwID);
}
return fResult;
}
CMetaKey::CMetaKey(
IN CComAuthInfo * pAuthInfo OPTIONAL
)
/*++
Routine Description:
Constructor that creates the interface, but does not open the key.
This is the ONLY constructor that allows operations from
METDATA_MASTER_ROOT_HANDLE (read operations obviously)
Arguments:
CComAuthInfo * pAuthInfo : If NULL, opens interface on local machine
Return Value:
N/A
--*/
: CMetaInterface(pAuthInfo),
m_hKey(METADATA_MASTER_ROOT_HANDLE),
m_hBase(NULL),
m_hrKey(S_OK),
m_dwFlags(0L),
m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
m_strMetaPath(),
m_fAllowRootOperations(TRUE),
m_fOwnKey(TRUE)
{
m_hrKey = CMetaInterface::QueryResult();
//
// Do not open key
//
}
CMetaKey::CMetaKey(
IN CMetaInterface * pInterface
)
/*++
Routine Description:
Construct with pre-existing interface. Does not
open any keys
Arguments:
CMetaInterface * pInterface : Preexisting interface
Return Value:
N/A
--*/
: CMetaInterface(pInterface),
m_hKey(NULL),
m_hBase(NULL),
m_strMetaPath(),
m_dwFlags(0L),
m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
m_fAllowRootOperations(TRUE),
m_fOwnKey(TRUE)
{
m_hrKey = CMetaInterface::QueryResult();
}
CMetaKey::CMetaKey(
IN CComAuthInfo * pAuthInfo, OPTIONAL
IN LPCTSTR lpszMDPath, OPTIONAL
IN DWORD dwFlags,
IN METADATA_HANDLE hkBase
)
/*++
Routine Description:
Fully defined constructor that opens a key
Arguments:
CComAuthInfo * pAuthInfo : Auth info or NULL
LPCTSTR lpszMDPath : Path or NULL
DWORD dwFlags : Open permissions
METADATA_HANDLE hkBase : Base key
Return Value:
N/A
--*/
: CMetaInterface(pAuthInfo),
// : CMetaInterface((CComAuthInfo *)NULL),
m_hKey(NULL),
m_hBase(NULL),
m_dwFlags(0L),
m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
m_fAllowRootOperations(FALSE),
m_strMetaPath(),
m_fOwnKey(TRUE)
{
m_hrKey = CMetaInterface::QueryResult();
if (SUCCEEDED(m_hrKey))
{
m_hrKey = Open(dwFlags, lpszMDPath, hkBase);
}
}
CMetaKey::CMetaKey(
IN CMetaInterface * pInterface,
IN LPCTSTR lpszMDPath, OPTIONAL
IN DWORD dwFlags,
IN METADATA_HANDLE hkBase
)
/*++
Routine Description:
Fully defined constructor that opens a key
Arguments:
CMetaInterface * pInterface : Existing interface
DWORD dwFlags : Open permissions
METADATA_HANDLE hkBase : Base key
LPCTSTR lpszMDPath : Path or NULL
Return Value:
N/A
--*/
: CMetaInterface(pInterface),
m_hKey(NULL),
m_hBase(NULL),
m_strMetaPath(),
m_dwFlags(0L),
m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
m_fAllowRootOperations(FALSE),
m_fOwnKey(TRUE)
{
m_hrKey = CMetaInterface::QueryResult();
if (SUCCEEDED(m_hrKey))
{
m_hrKey = Open(dwFlags, lpszMDPath, hkBase);
}
}
CMetaKey::CMetaKey(
IN BOOL fOwnKey,
IN CMetaKey * pKey
)
/*++
Routine Description:
Copy constructor.
Arguments:
BOOL fOwnKey : TRUE to take ownership of the key
const CMetaKey * pKey : Existing key
Return Value:
N/A
--*/
: CMetaInterface(pKey),
m_hKey(pKey->m_hKey),
m_hBase(pKey->m_hBase),
m_dwFlags(pKey->m_dwFlags),
m_cbInitialBufferSize(pKey->m_cbInitialBufferSize),
m_fAllowRootOperations(pKey->m_fAllowRootOperations),
m_hrKey(pKey->m_hrKey),
m_strMetaPath(pKey->m_strMetaPath),
m_fOwnKey(fOwnKey)
{
//
// No provisions for anything else at the moment
//
ASSERT(!m_fOwnKey);
}
CMetaKey::~CMetaKey()
/*++
Routine Description:
Destructor -- Close the key.
Arguments:
N/A
Return Value:
N/A
--*/
{
if (IsOpen() && m_fOwnKey)
{
Close();
}
}
/* virtual */
BOOL
CMetaKey::Succeeded() const
/*++
Routine Description:
Determine if object was constructed successfully
Arguments:
None
Return Value:
TRUE for success, FALSE for failure
--*/
{
return SUCCEEDED(m_hrKey);
}
/* virtual */
HRESULT
CMetaKey::QueryResult() const
/*++
Routine Description:
Return the construction error for this object
Arguments:
None
Return Value:
HRESULT from construction errors
--*/
{
return m_hrKey;
}
HRESULT
CMetaKey::Open(
IN DWORD dwFlags,
IN LPCTSTR lpszMDPath, OPTIONAL
IN METADATA_HANDLE hkBase
)
/*++
Routine Description:
Attempt to open a metabase key
Arguments:
DWORD dwFlags : Permission flags
LPCTSTR lpszMDPath : Optional path
METADATA_HANDLE hkBase : Base metabase key
Return Value:
HRESULT
--*/
{
ASSURE_PROPER_INTERFACE();
if (m_hKey != NULL)
{
ASSERT_MSG("Attempting to open key that already has an open handle");
// TRACEEOLID("Closing that key");
Close();
}
//
// Base key is stored for reopen purposes only
//
m_hBase = hkBase;
m_strMetaPath = lpszMDPath;
m_dwFlags = dwFlags;
return OpenKey(m_hBase, m_strMetaPath, m_dwFlags, &m_hKey);
}
HRESULT
CMetaKey::CreatePathFromFailedOpen()
/*++
Routine Description:
If the path doesn't exist, create it. This method should be
called after an Open call failed (because it will have initialized
m_strMetaPath.
Arguments:
None
Return Value:
HRESULT
--*/
{
CString strParentPath;
CString strObjectName;
CString strSavePath(m_strMetaPath);
CMetabasePath::SplitMetaPathAtInstance(
m_strMetaPath,
strParentPath,
strObjectName
);
CError err(Open(
METADATA_PERMISSION_WRITE,
strParentPath
));
if (err.Succeeded())
{
//
// This really should never fail, because we're opening
// the path at the instance.
//
err = AddKey(strObjectName);
}
if (IsOpen())
{
Close();
}
//
// The previous open wiped out the path...
//
m_strMetaPath = strSavePath;
return err;
}
HRESULT
CMetaKey::Close()
/*++
Routine Description:
Close the currently open key.
Arguments:
N/A
Return Value:
N/A
--*/
{
ASSURE_PROPER_INTERFACE();
HRESULT hr = S_OK;
ASSERT(m_hKey != NULL);
ASSERT(m_fOwnKey);
if (m_hKey)
{
hr = CloseKey(m_hKey);
if (SUCCEEDED(hr))
{
m_hKey = NULL;
}
}
return hr;
}
HRESULT
CMetaKey::ConvertToParentPath(
IN BOOL fImmediate
)
/*++
Routine Description:
Change the path to the parent path.
Arguments:
BOOL fImmediate : If TRUE, the immediate parent's path will be used
if FALSE, the first parent that really exists
Return Value:
HRESULT
ERROR_INVALID_PARAMETER if there is no valid path
--*/
{
BOOL fIsOpen = IsOpen();
if (fIsOpen)
{
Close();
}
CError err;
FOREVER
{
if (!CMetabasePath::ConvertToParentPath(m_strMetaPath))
{
//
// There is no parent path
//
err = ERROR_INVALID_PARAMETER;
break;
}
err = ReOpen();
//
// Path not found is the only valid error
// other than success.
//
if (fImmediate
|| err.Succeeded()
|| err.Win32Error() != ERROR_PATH_NOT_FOUND)
{
break;
}
}
//
// Remember to reset the construction error
// which referred to the parent path.
//
m_hrKey = err;
return err;
}
/* protected */
HRESULT
CMetaKey::GetPropertyValue(
IN DWORD dwID,
OUT IN DWORD & dwSize, OPTIONAL
OUT IN void *& pvData, OPTIONAL
OUT IN DWORD * pdwDataType, OPTIONAL
IN BOOL * pfInheritanceOverride, OPTIONAL
IN LPCTSTR lpszMDPath, OPTIONAL
OUT DWORD * pdwAttributes OPTIONAL
)
/*++
Routine Description:
Get metadata on the currently open key.
Arguments:
DWORD dwID : Property ID number
DWORD & dwSize : Buffer size (could be 0)
void *& pvData : Buffer -- will allocate if NULL
DWORD * pdwDataType : NULL or on in contains valid data types,
: on out contains actual data type
BOOL * pfInheritanceOverride : NULL or on forces inheritance on/off
LPCTSTR lpszMDPath : Optional path off the open key
DWORD * pdwAttributes : Optionally returns attributes
Return Value:
HRESULT
ERROR_INVALID_HANDLE : If the handle is not open
ERROR_INVALID_PARAMETER : If the property id is not found,
or the data type doesn't match requested type
ERROR_OUTOFMEMORY : Out of memory
--*/
{
ASSURE_PROPER_INTERFACE();
ASSURE_OPEN_KEY();
METADATA_RECORD mdRecord;
FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord);
//
// If unable to find this property ID in our table, or
// if we specified a desired type, and this type doesn't
// match it, give up.
//
if (pdwDataType && *pdwDataType != ALL_METADATA
&& *pdwDataType != mdRecord.dwMDDataType)
{
ASSERT_MSG("Invalid parameter");
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
}
//
// Check to see if inheritance behaviour is overridden
//
if (pfInheritanceOverride)
{
if (*pfInheritanceOverride)
{
mdRecord.dwMDAttributes |= METADATA_INHERIT;
}
else
{
mdRecord.dwMDAttributes &= ~METADATA_INHERIT;
}
}
//
// This causes a bad parameter error on input otherwise
//
mdRecord.dwMDAttributes &= ~METADATA_REFERENCE;
//
// If we're looking for inheritable properties, the path
// doesn't have to be completely specified.
//
if (mdRecord.dwMDAttributes & METADATA_INHERIT)
{
mdRecord.dwMDAttributes |= (METADATA_PARTIAL_PATH | METADATA_ISINHERITED);
}
ASSERT(dwSize > 0 || pvData == NULL);
mdRecord.dwMDDataLen = dwSize;
mdRecord.pbMDData = (LPBYTE)pvData;
//
// If no buffer provided, allocate one.
//
HRESULT hr = S_OK;
BOOL fBufferTooSmall = FALSE;
BOOL fAllocatedMemory = FALSE;
DWORD dwInitSize = m_cbInitialBufferSize;
do
{
if(mdRecord.pbMDData == NULL)
{
mdRecord.dwMDDataLen = dwInitSize;
mdRecord.pbMDData = new BYTE[dwInitSize];
if(mdRecord.pbMDData == NULL && dwInitSize > 0)
{
hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
break;
}
++fAllocatedMemory;
}
//
// Get the data
//
DWORD dwRequiredDataLen = 0;
hr = GetData(m_hKey, lpszMDPath, &mdRecord, &dwRequiredDataLen);
//
// Re-fetch the buffer if it's too small.
//
fBufferTooSmall =
(HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER) && fAllocatedMemory;
if(fBufferTooSmall)
{
//
// Delete the old buffer, and set up for a re-fetch.
//
delete [] mdRecord.pbMDData;
mdRecord.pbMDData = NULL;
dwInitSize = dwRequiredDataLen;
}
}
while(fBufferTooSmall);
//
// Failed
//
if (FAILED(hr) && fAllocatedMemory)
{
delete [] mdRecord.pbMDData;
mdRecord.pbMDData = NULL;
}
dwSize = mdRecord.dwMDDataLen;
pvData = mdRecord.pbMDData;
if (pdwDataType != NULL)
{
//
// Return actual data type
//
*pdwDataType = mdRecord.dwMDDataType;
}
if (pdwAttributes != NULL)
{
//
// Return data attributes
//
*pdwAttributes = mdRecord.dwMDAttributes;
}
return hr;
}
/* protected */
HRESULT
CMetaKey::GetDataPaths(
OUT CStringListEx & strlDataPaths,
IN DWORD dwMDIdentifier,
IN DWORD dwMDDataType,
IN LPCTSTR lpszMDPath OPTIONAL
)
/*++
Routine Description:
Get data paths
Arguments:
Return Value:
HRESULT
--*/
{
ASSURE_PROPER_INTERFACE();
ASSURE_OPEN_KEY();
//
// Start with a small buffer
//
DWORD dwMDBufferSize = 1024;
LPTSTR lpszBuffer = NULL;
CError err;
do
{
delete [] lpszBuffer;
lpszBuffer = new TCHAR[dwMDBufferSize];
if (lpszBuffer == NULL)
{
err = ERROR_NOT_ENOUGH_MEMORY;
break;
}
err = CMetaInterface::GetDataPaths(
m_hKey,
lpszMDPath,
dwMDIdentifier,
dwMDDataType,
dwMDBufferSize,
lpszBuffer,
&dwMDBufferSize
);
}
while(err.Win32Error() == ERROR_INSUFFICIENT_BUFFER);
if (err.Win32Error() == ERROR_PATH_NOT_FOUND)
{
//
// That's ok... this is some sort of physical directory
// that doesn't currently exist in the metabase, and
// which therefore doesn't have any descendants anyway.
//
ZeroMemory(lpszBuffer, dwMDBufferSize);
err.Reset();
}
if (err.Succeeded())
{
strlDataPaths.ConvertFromDoubleNullList(lpszBuffer);
delete [] lpszBuffer;
}
return err;
}
HRESULT
CMetaKey::CheckDescendants(
IN DWORD dwID,
IN CComAuthInfo * pAuthInfo, OPTIONAL
IN LPCTSTR lpszMDPath OPTIONAL
)
/*++
Routine Description:
Check for descendant overrides; If there are any, bring up a dialog
that displays them, and give the user the opportunity the remove
the overrides.
Arguments:
DWORD dwID : Property ID
CComAuthInfo * pAuthInfo : Server or NULL
LPCTSTR lpszMDPath : Metabase path or NULL
Return Value:
HRESULT
--*/
{
ASSURE_PROPER_INTERFACE();
HRESULT hr = S_OK;
METADATA_RECORD mdRecord;
FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord);
if (mdRecord.dwMDAttributes & METADATA_INHERIT)
{
CStringListEx strlDataPaths;
hr = GetDataPaths(
strlDataPaths,
mdRecord.dwMDIdentifier,
mdRecord.dwMDDataType,
lpszMDPath
);
if (SUCCEEDED(hr) && !strlDataPaths.empty())
{
//
// Bring up the inheritance override dialog
//
CInheritanceDlg dlg(
dwID,
FROM_WRITE_PROPERTY,
pAuthInfo,
lpszMDPath,
strlDataPaths
);
if (!dlg.IsEmpty())
{
dlg.DoModal();
}
}
}
return hr;
}
/* protected */
HRESULT
CMetaKey::SetPropertyValue(
IN DWORD dwID,
IN DWORD dwSize,
IN void * pvData,
IN BOOL * pfInheritanceOverride, OPTIONAL
IN LPCTSTR lpszMDPath OPTIONAL
)
/*++
Routine Description:
Set metadata on the open key. The key must have been opened with
write permission.
Arguments:
DWORD dwID : Property ID
DWORD dwSize : Size of data
void * pvData : Data buffer
BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
LPCTSTR lpszMDPath : Optional path off the open key
Return Value:
HRESULT
ERROR_INVALID_HANDLE : If the handle is not open
ERROR_INVALID_PARAMETER : If the property id is not found,
or the buffer is NULL or of size 0
--*/
{
ASSURE_PROPER_INTERFACE();
ASSURE_OPEN_KEY();
if (pvData == NULL && dwSize != 0)
{
ASSERT_MSG("No Data");
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
}
METADATA_RECORD mdRecord;
FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord);
if (pfInheritanceOverride)
{
if (*pfInheritanceOverride)
{
mdRecord.dwMDAttributes |= METADATA_INHERIT;
}
else
{
mdRecord.dwMDAttributes &= ~METADATA_INHERIT;
}
}
mdRecord.dwMDDataLen = dwSize;
mdRecord.pbMDData = (LPBYTE)pvData;
return SetData(m_hKey, lpszMDPath, &mdRecord);
}
/* protected */
HRESULT
CMetaKey::GetAllData(
IN DWORD dwMDAttributes,
IN DWORD dwMDUserType,
IN DWORD dwMDDataType,
OUT DWORD * pdwMDNumEntries,
OUT DWORD * pdwMDDataLen,
OUT PBYTE * ppbMDData,
IN LPCTSTR lpszMDPath OPTIONAL
)
/*++
Routine Description:
Get all data off the open key. Buffer is created automatically.
Arguments:
DWORD dwMDAttributes : Attributes
DWORD dwMDUserType : User type to fetch
DWORD dwMDDataType : Data type to fetch
DWORD * pdwMDNumEntries : Returns number of entries read
DWORD * pdwMDDataLen : Returns size of data buffer
PBYTE * ppbMDData : Returns data buffer
LPCTSTR lpszMDPath : Optional data path
Return Value:
HRESULT
--*/
{
ASSURE_PROPER_INTERFACE();
ASSURE_OPEN_KEY();
//
// Check for valid parameters
//
if(!pdwMDDataLen || !ppbMDData || !pdwMDNumEntries)
{
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
}
HRESULT hr = S_OK;
BOOL fBufferTooSmall = FALSE;
DWORD dwMDDataSetNumber;
DWORD dwRequiredBufferSize;
DWORD dwInitSize = m_cbInitialBufferSize;
*ppbMDData = NULL;
do
{
*pdwMDDataLen = dwInitSize;
*ppbMDData = new BYTE[dwInitSize];
if (ppbMDData == NULL && dwInitSize > 0)
{
hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
break;
}
hr = CMetaInterface::GetAllData(
m_hKey,
lpszMDPath,
dwMDAttributes,
dwMDUserType,
dwMDDataType,
pdwMDNumEntries,
&dwMDDataSetNumber,
*pdwMDDataLen,
*ppbMDData,
&dwRequiredBufferSize
);
//
// Re-fetch the buffer if it's too small.
//
fBufferTooSmall = (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER);
if(fBufferTooSmall)
{
//
// Delete the old buffer, and set up for a re-fetch.
//
delete [] *ppbMDData;
dwInitSize = dwRequiredBufferSize;
}
}
while (fBufferTooSmall);
if (FAILED(hr))
{
//
// No good, be sure we don't leak anything
//
delete [] *ppbMDData;
dwInitSize = 0L;
}
return hr;
}
HRESULT
CMetaKey::QueryValue(
IN DWORD dwID,
IN OUT DWORD & dwValue,
IN BOOL * pfInheritanceOverride, OPTIONAL
IN LPCTSTR lpszMDPath, OPTIONAL
OUT DWORD * pdwAttributes OPTIONAL
)
/*++
Routine Description:
Fetch data as a DWORD
Arguments:
DWORD dwID : Property ID
DWORD & dwValue : Returns the value read in
BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
LPCTSTR lpszMDPath : Optional path off the open key
DWORD * pdwAttributes : Optionally returns attributes
Return Value:
HRESULT
--*/
{
DWORD dwSize = sizeof(dwValue);
DWORD dwDataType = DWORD_METADATA;
void * pvData = &dwValue;
return GetPropertyValue(
dwID,
dwSize,
pvData,
&dwDataType,
pfInheritanceOverride,
lpszMDPath,
pdwAttributes
);
}
HRESULT
CMetaKey::QueryValue(
IN DWORD dwID,
IN OUT CString & strValue,
IN BOOL * pfInheritanceOverride, OPTIONAL
IN LPCTSTR lpszMDPath, OPTIONAL
OUT DWORD * pdwAttributes OPTIONAL
)
/*++
Routine Description:
Fetch data as a string
Arguments:
DWORD dwID : Property ID
DWORD & strValue : Returns the value read in
BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
LPCTSTR lpszMDPath : Optional path off the open key
DWORD * pdwAttributes : Optionally returns attributes
Return Value:
HRESULT
--*/
{
//
// Get GetData allocate the buffer for us
//
DWORD dwSize = 0;
DWORD dwDataType = ALL_METADATA;
LPTSTR lpData = NULL;
HRESULT hr = GetPropertyValue(
dwID,
dwSize,
(void *&)lpData,
&dwDataType,
pfInheritanceOverride,
lpszMDPath,
pdwAttributes
);
if (SUCCEEDED(hr))
{
//
// Notes: consider optional auto-expansion on EXPANDSZ_METADATA
// (see registry functions), and data type conversions for DWORD
// or MULTISZ_METADATA or BINARY_METADATA
//
if (dwDataType == EXPANDSZ_METADATA || dwDataType == STRING_METADATA)
{
try
{
strValue = lpData;
}
catch(std::bad_alloc)
{
hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
}
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
}
}
if (lpData)
{
delete [] lpData;
}
return hr;
}
HRESULT
CMetaKey::QueryValue(
IN DWORD dwID,
IN OUT CStrPassword & strValue,
IN BOOL * pfInheritanceOverride, OPTIONAL
IN LPCTSTR lpszMDPath, OPTIONAL
OUT DWORD * pdwAttributes OPTIONAL
)
/*++
Routine Description:
Fetch data as a string
Arguments:
DWORD dwID : Property ID
CStrPassword & strValue : Returns the value read in
BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
LPCTSTR lpszMDPath : Optional path off the open key
DWORD * pdwAttributes : Optionally returns attributes
Return Value:
HRESULT
--*/
{
//
// Get GetData allocate the buffer for us
//
DWORD dwSize = 0;
DWORD dwDataType = ALL_METADATA;
LPTSTR lpData = NULL;
HRESULT hr = GetPropertyValue(
dwID,
dwSize,
(void *&)lpData,
&dwDataType,
pfInheritanceOverride,
lpszMDPath,
pdwAttributes
);
if (SUCCEEDED(hr))
{
//
// Notes: consider optional auto-expansion on EXPANDSZ_METADATA
// (see registry functions), and data type conversions for DWORD
// or MULTISZ_METADATA or BINARY_METADATA
//
if (dwDataType == EXPANDSZ_METADATA || dwDataType == STRING_METADATA)
{
try
{
strValue = lpData;
}
catch(std::bad_alloc)
{
hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
}
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
}
}
if (lpData)
{
delete [] lpData;
}
return hr;
}
HRESULT
CMetaKey::QueryValue(
IN DWORD dwID,
IN OUT CComBSTR & strValue,
IN BOOL * pfInheritanceOverride, OPTIONAL
IN LPCTSTR lpszMDPath, OPTIONAL
OUT DWORD * pdwAttributes OPTIONAL
)
/*++
Routine Description:
Fetch data as a string
Arguments:
DWORD dwID : Property ID
DWORD & CComBSTR : Returns the value read in
BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
LPCTSTR lpszMDPath : Optional path off the open key
DWORD * pdwAttributes : Optionally returns attributes
Return Value:
HRESULT
--*/
{
//
// Get GetData allocate the buffer for us
//
DWORD dwSize = 0;
DWORD dwDataType = ALL_METADATA;
LPTSTR lpData = NULL;
HRESULT hr = GetPropertyValue(
dwID,
dwSize,
(void *&)lpData,
&dwDataType,
pfInheritanceOverride,
lpszMDPath,
pdwAttributes
);
if (SUCCEEDED(hr))
{
//
// Notes: consider optional auto-expansion on EXPANDSZ_METADATA
// (see registry functions), and data type conversions for DWORD
// or MULTISZ_METADATA or BINARY_METADATA
//
if (dwDataType == EXPANDSZ_METADATA || dwDataType == STRING_METADATA)
{
strValue = lpData;
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
}
}
if (lpData)
{
delete [] lpData;
}
return hr;
}
HRESULT
CMetaKey::QueryValue(
IN DWORD dwID,
IN OUT CStringListEx & strlValue,
IN BOOL * pfInheritanceOverride, OPTIONAL
IN LPCTSTR lpszMDPath, OPTIONAL
OUT DWORD * pdwAttributes OPTIONAL
)
/*++
Routine Description:
Fetch data as a stringlist
Arguments:
DWORD dwID : Property ID
DWORD & strlValue : Returns the value read in
BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
LPCTSTR lpszMDPath : Optional path off the open key
DWORD * pdwAttributes : Optionally returns attributes
Return Value:
HRESULT
--*/
{
//
// Get GetData allocate the buffer for us
//
DWORD dwSize = 0;
DWORD dwDataType = MULTISZ_METADATA;
LPTSTR lpData = NULL;
HRESULT hr = GetPropertyValue(
dwID,
dwSize,
(void *&)lpData,
&dwDataType,
pfInheritanceOverride,
lpszMDPath,
pdwAttributes
);
if (SUCCEEDED(hr))
{
//
// Notes: Consider accepting a single STRING
//
ASSERT(dwDataType == MULTISZ_METADATA);
DWORD err = strlValue.ConvertFromDoubleNullList(lpData, dwSize / sizeof(TCHAR));
hr = HRESULT_FROM_WIN32(err);
}
if (lpData)
{
delete [] lpData;
}
return hr;
}
HRESULT
CMetaKey::QueryValue(
IN DWORD dwID,
IN OUT CBlob & blValue,
IN BOOL * pfInheritanceOverride, OPTIONAL
IN LPCTSTR lpszMDPath, OPTIONAL
OUT DWORD * pdwAttributes OPTIONAL
)
/*++
Routine Description:
Fetch data as a binary blob
Arguments:
DWORD dwID : Property ID
DWORD CBlob & blValue : Returns the binary blob
BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
LPCTSTR lpszMDPath : Optional path off the open key
DWORD * pdwAttributes : Optionally returns attributes
Return Value:
HRESULT
--*/
{
//
// Get GetData allocate the buffer for us
//
DWORD dwSize = 0;
DWORD dwDataType = BINARY_METADATA;
LPBYTE pbData = NULL;
HRESULT hr = GetPropertyValue(
dwID,
dwSize,
(void *&)pbData,
&dwDataType,
pfInheritanceOverride,
lpszMDPath,
pdwAttributes
);
if (SUCCEEDED(hr))
{
//
// Blob takes ownership of the data, so don't free it...
//
ASSERT_READ_PTR2(pbData, dwSize);
blValue.SetValue(dwSize, pbData, FALSE);
}
return hr;
}
HRESULT
CMetaKey::SetValue(
IN DWORD dwID,
IN CStrPassword & strlValue,
IN BOOL * pfInheritanceOverride, OPTIONAL
IN LPCTSTR lpszMDPath OPTIONAL
)
{
LPTSTR lpstr = NULL;
HRESULT hr = E_FAIL;
lpstr = strlValue.GetClearTextPassword();
if (lpstr)
{
hr = SetPropertyValue(
dwID,
strlValue.GetByteLength(),
(void *)lpstr,
pfInheritanceOverride,
lpszMDPath
);
strlValue.DestroyClearTextPassword(lpstr);
}
return hr;
}
HRESULT
CMetaKey::SetValue(
IN DWORD dwID,
IN CStringListEx & strlValue,
IN BOOL * pfInheritanceOverride, OPTIONAL
IN LPCTSTR lpszMDPath OPTIONAL
)
/*++
Routine Description:
Store data as string
Arguments:
DWORD dwID : Property ID
CStringListEx & strlValue : Value to be written
BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
LPCTSTR lpszMDPath : Optional path (or NULL or "")
Return Value:
HRESULT
--*/
{
DWORD cCharacters;
LPTSTR lpstr = NULL;
//
// Flatten value
//
strlValue.ConvertToDoubleNullList(cCharacters, lpstr);
HRESULT hr = SetPropertyValue(
dwID,
cCharacters * sizeof(TCHAR),
(void *)lpstr,
pfInheritanceOverride,
lpszMDPath
);
delete [] lpstr;
return hr;
}
HRESULT
CMetaKey::SetValue(
IN DWORD dwID,
IN CBlob & blValue,
IN BOOL * pfInheritanceOverride, OPTIONAL
IN LPCTSTR lpszMDPath OPTIONAL
)
/*++
Routine Description:
Store data as binary
Arguments:
DWORD dwID : Property ID
CBlob & blValue : Value to be written
BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
LPCTSTR lpszMDPath : Optional path (or NULL or "")
Return Value:
HRESULT
--*/
{
return SetPropertyValue(
dwID,
blValue.GetSize(),
(void *)blValue.GetData(),
pfInheritanceOverride,
lpszMDPath
);
}
HRESULT
CMetaKey::DeleteValue(
DWORD dwID,
LPCTSTR lpszMDPath OPTIONAL
)
/*++
Routine Description:
Delete data
Arguments:
DWORD dwID : Property ID of property to be deleted
LPCTSTR lpszMDPath : Optional path (or NULL or "")
Return Value:
HRESULT
--*/
{
ASSURE_PROPER_INTERFACE();
ASSURE_OPEN_KEY();
METADATA_RECORD mdRecord;
FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord);
return DeleteData(
m_hKey,
lpszMDPath,
mdRecord.dwMDIdentifier,
mdRecord.dwMDDataType
);
}
HRESULT
CMetaKey::DoesPathExist(
IN LPCTSTR lpszMDPath
)
/*++
Routine Description:
Determine if the path exists
Arguments:
LPCTSTR lpszMDPath : Relative path off the open key
Return Value:
HRESULT, or S_OK if the path exists.
--*/
{
ASSURE_PROPER_INTERFACE();
ASSURE_OPEN_KEY();
FILETIME ft;
return GetLastChangeTime(m_hKey, lpszMDPath, &ft, FALSE);
}
HRESULT
CMetaInterface::Regenerate()
/*++
Routine Description:
Attempt to recreate the interface pointer. This assumes that the interface
had been successfully created before, but has become invalid at some
point afterwards.
Arguments:
None
Return Value:
HRESULT
--*/
{
ASSERT_PTR(m_pInterface); // Must have been initialised
SAFE_RELEASE(m_pInterface);
m_hrInterface = Create();
return m_hrInterface;
}
#define GET_TO_INTERFACE2()\
IMSAdminBase2 * pInterface2 = NULL;\
HRESULT hr = GetAdminInterface2(&pInterface2);\
if (SUCCEEDED(hr)) {
#define RELEASE_AND_RETURN2()\
if (pInterface2 != NULL)\
pInterface2->Release();\
}\
return hr\
HRESULT
CMetaInterface::GetAdminInterface2(IMSAdminBase2 ** pp)
{
HRESULT hr = S_OK;
IMSAdminBase2 * p = NULL;
if (pp == NULL)
return E_POINTER;
if (m_auth.UsesImpersonation())
{
IUnknown * punk = NULL;
hr = m_pInterface->QueryInterface(__uuidof(IUnknown), (void **)&punk);
if (SUCCEEDED(hr))
{
if (SUCCEEDED(hr = m_auth.ApplyProxyBlanket(punk)))
{
if (SUCCEEDED(hr = punk->QueryInterface(IID_IMSAdminBase2, (void **)&p)))
{
if (p != NULL)
{
hr = m_auth.ApplyProxyBlanket(p);
if (SUCCEEDED(hr))
{
*pp = p;
}
}
}
}
}
if (punk != NULL)
punk->Release();
}
else
{
hr = m_pInterface->QueryInterface(IID_IMSAdminBase2, (void **)pp);
}
return hr;
}
//
// CWamInterface class
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
CWamInterface::CWamInterface(
IN CComAuthInfo * pAuthInfo OPTIONAL
)
/*++
Routine Description:
Construct and initialize the interface.
Arguments:
CComAuthInfo * pAuthInfo : Auth info. NULL indicates the local computer.
Return Value:
N/A
--*/
: CIISInterface(pAuthInfo),
m_pInterface(NULL),
m_fSupportsPooledProc(FALSE)
{
//
// Initialize the interface
//
m_hrInterface = Create();
}
CWamInterface::CWamInterface(
IN CWamInterface * pInterface
)
/*++
Routine Description:
Construct from existing interface (copy constructor)
Arguments:
CWamInterface * pInterface : Existing interface
Return Value:
N/A
--*/
: CIISInterface(&pInterface->m_auth, pInterface->m_hrInterface),
m_pInterface(pInterface->m_pInterface),
m_fSupportsPooledProc(FALSE)
{
ASSERT_PTR(m_pInterface);
m_pInterface->AddRef();
}
CWamInterface::~CWamInterface()
/*++
Routine Description:
Destructor -- releases the interface.
Arguments:
N/A
Return Value:
N/A
--*/
{
SAFE_RELEASE(m_pInterface);
}
/* protected */
HRESULT
CWamInterface::Create()
/*++
Routine Description:
Create the interface with DCOM
Arguments:
None
Return Value:
HRESULT
Notes:
First, it will attempt to create the new interface, if it
fails, it will attempt to create the downlevel interface
--*/
{
CLSID rgCLSID[2];
IID rgIID[2];
rgCLSID[1] = rgCLSID[0] = CLSID_WamAdmin;
rgIID[0] = IID_IWamAdmin2;
rgIID[1] = IID_IWamAdmin;
ASSERT(ARRAY_SIZE(rgCLSID) == ARRAY_SIZE(rgIID));
int cInterfaces = ARRAY_SIZE(rgCLSID);
int iInterface;
HRESULT hr = CIISInterface::Create(
cInterfaces,
rgIID,
rgCLSID,
&iInterface,
(IUnknown **)&m_pInterface
);
if (SUCCEEDED(hr))
{
//
// Only supported on IWamAdmin2
//
m_fSupportsPooledProc = (rgIID[iInterface] == IID_IWamAdmin2);
}
return hr;
}
HRESULT
CWamInterface::AppCreate(
IN LPCTSTR szMDPath,
IN DWORD dwAppProtection
)
/*++
Routine Description:
Create application
Arguments:
LPCTSTR szMDPath : Metabase path
DWORD dwAppProtection : APP_INPROC to create in-proc app
APP_OUTOFPROC to create out-of-proc app
APP_POOLEDPROC to create a pooled-proc app
Return Value:
HRESULT (ERROR_INVALID_PARAMETER if unsupported protection state is requested)
--*/
{
if (m_fSupportsPooledProc)
{
//
// Interface pointer is really IWamAdmin2, so call the new method
//
return ((IWamAdmin2 *)m_pInterface)->AppCreate2(szMDPath, dwAppProtection);
}
//
// Call the downlevel API
//
if (dwAppProtection == APP_INPROC || dwAppProtection == APP_OUTOFPROC)
{
BOOL fInProc = (dwAppProtection == APP_INPROC);
ASSERT_PTR(m_pInterface);
return m_pInterface->AppCreate(szMDPath, fInProc);
}
return CError(ERROR_INVALID_PARAMETER);
}
//
// CMetaback Class
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
const LPCTSTR CMetaBack::s_szMasterAppRoot =\
SZ_MBN_SEP_STR SZ_MBN_MACHINE SZ_MBN_SEP_STR SZ_MBN_WEB;
CMetaBack::CMetaBack(
IN CComAuthInfo * pAuthInfo OPTIONAL
)
/*++
Routine Description:
Constructor for metabase backup/restore operations class. This object
is both a WAM interface and a METABASE interface.
Arguments:
CComAuthInfo * pAuthInfo : Auth info. NULL indicates the local computer.
Return Value:
N/A
--*/
: m_dwIndex(0),
CMetaInterface(pAuthInfo),
CWamInterface(pAuthInfo)
{
}
/* virtual */
BOOL
CMetaBack::Succeeded() const
/*++
Routine Description:
Determine if object was constructed successfully.
Arguments:
None
Return Value:
TRUE for success, FALSE for failure
--*/
{
return CMetaInterface::Succeeded() && CWamInterface::Succeeded();
}
/* virtual */
HRESULT
CMetaBack::QueryResult() const
/*++
Routine Description:
Return the construction error for this object
Arguments:
None
Return Value:
HRESULT from construction errors
--*/
{
//
// Both interfaces must have constructed successfully
//
HRESULT hr = CMetaInterface::QueryResult();
if (SUCCEEDED(hr))
{
hr = CWamInterface::QueryResult();
}
return hr;
}
HRESULT
CMetaBack::Restore(
IN LPCTSTR lpszLocation,
IN DWORD dwVersion
)
/*++
Routine Description:
Restore metabase
Arguments:
DWORD dwVersion : Backup version
LPCTSTR lpszLocation : Backup location
Return Value:
HRESULT
--*/
{
//
// Backup and restore the application information from a restore
//
CString strPath(s_szMasterAppRoot);
HRESULT hr = AppDeleteRecoverable(strPath, TRUE);
if (SUCCEEDED(hr))
{
hr = CMetaInterface::Restore(lpszLocation, dwVersion, 0);
if (SUCCEEDED(hr))
{
hr = AppRecover(strPath, TRUE);
}
}
return hr;
}
//
// CIISSvcControl class
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
CIISSvcControl::CIISSvcControl(
IN CComAuthInfo * pAuthInfo OPTIONAL
)
/*++
Routine Description:
Construct and initialize the interface.
Arguments:
CComAuthInfo * pAuthInfo : Auth info. NULL indicates the local computer.
Return Value:
N/A
--*/
: CIISInterface(pAuthInfo),
m_pInterface(NULL)
{
//
// Initialize the interface
//
m_hrInterface = Create();
}
CIISSvcControl::CIISSvcControl(
IN CIISSvcControl * pInterface
)
/*++
Routine Description:
Construct from existing interface (copy constructor)
Arguments:
CIISSvcControl * pInterface : Existing interface
Return Value:
N/A
--*/
: CIISInterface(&pInterface->m_auth, pInterface->m_hrInterface),
m_pInterface(pInterface->m_pInterface)
{
ASSERT_PTR(m_pInterface);
m_pInterface->AddRef();
}
CIISSvcControl::~CIISSvcControl()
/*++
Routine Description:
Destructor -- releases the interface.
Arguments:
N/A
Return Value:
N/A
--*/
{
SAFE_RELEASE(m_pInterface);
}
#ifdef KEVLAR
//
// CWebCluster class
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
CWebCluster::CWebCluster(
IN CComAuthInfo * pAuthInfo OPTIONAL
)
/*++
Routine Description:
Construct and initialize the interface.
Arguments:
CComAuthInfo * pAuthInfo : Authentication information.
NULL indicates the local computer
Return Value:
N/A
--*/
: CIISInterface(pAuthInfo),
m_pInterface(NULL)
{
//
// Initialize the interface
//
m_hrInterface = Create();
}
/* virtual */
CWebCluster::~CWebCluster()
/*++
Routine Description:
Destructor -- releases the interface.
Arguments:
N/A
Return Value:
N/A
--*/
{
SAFE_RELEASE(m_pInterface);
}
#endif // KEVLAR
//
// CMetaEnumerator Clas
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
CMetaEnumerator::CMetaEnumerator(
IN CComAuthInfo * pAuthInfo OPTIONAL,
IN LPCTSTR lpszMDPath OPTIONAL,
IN METADATA_HANDLE hkBase OPTIONAL
)
/*++
Routine Description:
Metabase enumerator constructor. This constructor creates a new interface
and opens a key.
Arguments:
CComAuthInfo * pAuthInfo : Auth info. NULL indicates the local computer.
LPCTSTR lpszMDPath : Metabase path
METADATA_HANDLE hkBase : Metabase handle
Return Value:
N/A
--*/
: CMetaKey(pAuthInfo, lpszMDPath, METADATA_PERMISSION_READ, hkBase),
m_dwIndex(0L)
{
}
CMetaEnumerator::CMetaEnumerator(
IN CMetaInterface * pInterface,
IN LPCTSTR lpszMDPath, OPTIONAL
IN METADATA_HANDLE hkBase OPTIONAL
)
/*++
Routine Description:
Metabase enumerator constructor. This constructor uses an existing
interface and opens a key.
Arguments:
CMetaInterface * pInterface : Existing interface
LPCTSTR lpszMDPath : Metabase path
METADATA_HANDLE hkBase : Metabase handle
Return Value:
N/A
--*/
: CMetaKey(pInterface, lpszMDPath, METADATA_PERMISSION_READ, hkBase),
m_dwIndex(0L)
{
}
CMetaEnumerator::CMetaEnumerator(
IN BOOL fOwnKey,
IN CMetaKey * pKey
)
/*++
Routine Description:
Metabase enumerator constructor. This constructor uses an existing
interface and open key.
Arguments:
BOOL fOwnKey : TRUE if we own the key (destructor will close)
CMetaKey * pKey : Open key
Return Value:
N/A
--*/
: CMetaKey(fOwnKey, pKey),
m_dwIndex(0L)
{
}
HRESULT
CMetaEnumerator::Next(
OUT CString & strKey,
IN LPCTSTR lpszMDPath OPTIONAL
)
/*++
Routine Description:
Get the next subkey
Arguments:
CString & str Returns keyname
LPCTSTR lpszMDPath Optional subpath
Return Value:
HRESULT
--*/
{
ASSURE_PROPER_INTERFACE();
ASSURE_OPEN_KEY();
TCHAR buf[MAX_PATH];
HRESULT hr = EnumKeys(m_hKey, lpszMDPath, buf, m_dwIndex++);
if (SUCCEEDED(hr))
strKey = buf;
return hr;
}
HRESULT
CMetaEnumerator::Next(
OUT DWORD & dwKey,
OUT CString & strKey,
IN LPCTSTR lpszMDPath OPTIONAL
)
/*++
Routine Description:
Get the next subkey as a DWORD. This skips non-numeric
keynames (including 0) until the first numeric key name
Arguments:
DWORD & dwKey Numeric key
CString & strKey Same key in string format
LPCTSTR lpszMDPath Optional subpath
Return Value:
HRESULT
--*/
{
ASSURE_PROPER_INTERFACE();
ASSURE_OPEN_KEY();
HRESULT hr;
TCHAR buf[MAX_PATH];
while (TRUE)
{
if (SUCCEEDED(hr = EnumKeys(m_hKey, lpszMDPath, buf, m_dwIndex++)))
{
if (0 != (dwKey = _ttoi(buf)))
{
strKey = buf;
break;
}
}
else
break;
}
return hr;
}
// This method moved from inline to remove dependency on IIDs and CLSIDs
HRESULT
CIISSvcControl::Create()
{
return CIISInterface::Create(
1,
&IID_IIisServiceControl,
&CLSID_IisServiceControl,
NULL,
(IUnknown **)&m_pInterface
);
}
//
// CIISApplication class
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<</
CIISApplication::CIISApplication(
IN CComAuthInfo * pAuthInfo OPTIONAL,
IN LPCTSTR lpszMetapath
)
/*++
Routine Description:
Construct IIS application.
Arguments:
CComAuthInfo * pAuthInfo : Authentication info. NULL indicates the
local computer.
LPCTSTR lpszMetapath : Metabase path
Return Value:
N/A
--*/
: CWamInterface(pAuthInfo),
CMetaKey(pAuthInfo),
m_dwProcessProtection(APP_INPROC),
m_dwAppState(APPSTATUS_NOTDEFINED),
m_strFriendlyName(),
m_strAppRoot(),
m_strWamPath(lpszMetapath)
{
CommonConstruct();
}
void
CIISApplication::CommonConstruct()
/*++
Routine Description:
Perform common construction
Arguments:
None
Return Value:
None
--*/
{
//
// Munge the metapath so that WAM doesn't cough up a hairball.
//
//
// BUGBUG: CleanMetaPath() disabled currently
//
if (m_strWamPath[0] != SZ_MBN_SEP_CHAR)
{
m_strWamPath = SZ_MBN_SEP_CHAR + m_strWamPath;
}
do
{
m_hrApp = CWamInterface::QueryResult();
if (FAILED(m_hrApp))
{
break;
}
m_hrApp = RefreshAppState();
if (HRESULT_CODE(m_hrApp) == ERROR_PATH_NOT_FOUND)
{
//
// "Path Not Found" errors are acceptable, since
// the application may not yet exist.
//
m_hrApp = S_OK;
}
}
while(FALSE);
}
/* virtual */
BOOL
CIISApplication::Succeeded() const
/*++
Routine Description:
Determine if object was constructed successfully
Arguments:
None
Return Value:
TRUE for success, FALSE for failure
--*/
{
return CMetaInterface::Succeeded()
&& CWamInterface::Succeeded()
&& SUCCEEDED(m_hrApp);
}
/* virtual */
HRESULT
CIISApplication::QueryResult() const
/*++
Routine Description:
Return the construction error for this object
Arguments:
None
Return Value:
HRESULT from construction errors
--*/
{
//
// Both interfaces must have constructed successfully
//
HRESULT hr = CMetaInterface::QueryResult();
if (SUCCEEDED(hr))
{
hr = CWamInterface::QueryResult();
if (SUCCEEDED(hr))
{
hr = m_hrApp;
}
}
return hr;
}
HRESULT
CIISApplication::RefreshAppState()
/*++
Routine Description:
Refresh the application state
Arguments:
None
Return Value:
HRESULT
--*/
{
ASSERT(!m_strWamPath.IsEmpty());
HRESULT hr, hrKeys;
hr = AppGetStatus(m_strWamPath, &m_dwAppState);
if (FAILED(hr))
{
m_dwAppState = APPSTATUS_NOTDEFINED;
}
m_strAppRoot.Empty();
hrKeys = QueryValue(MD_APP_ROOT, m_strAppRoot, NULL, m_strWamPath);
m_dwProcessProtection = APP_INPROC;
hrKeys = QueryValue(
MD_APP_ISOLATED,
m_dwProcessProtection,
NULL,
m_strWamPath
);
m_strFriendlyName.Empty();
hrKeys = QueryValue(
MD_APP_FRIENDLY_NAME,
m_strFriendlyName,
NULL,
m_strWamPath
);
return hr;
}
HRESULT
CIISApplication::Create(
IN LPCTSTR lpszName, OPTIONAL
IN DWORD dwAppProtection
)
/*++
Routine Description:
Create the application
Arguments:
LPCTSTR lpszName : Application name
DWORD dwAppProtection : APP_INPROC to create in-proc app
APP_OUTOFPROC to create out-of-proc app
APP_POOLEDPROC to create a pooled-proc app
Return Value:
HRESULT
--*/
{
ASSERT(!m_strWamPath.IsEmpty());
HRESULT hr = AppCreate(m_strWamPath, dwAppProtection);
if (SUCCEEDED(hr))
{
//
// Write the friendly app name, which we maintain
// ourselves. Empty it first, because we might
// have picked up a name from inheritance.
//
m_strFriendlyName.Empty();
hr = WriteFriendlyName(lpszName);
RefreshAppState();
}
return hr;
}
HRESULT
CIISApplication::WriteFriendlyName(
IN LPCTSTR lpszName
)
/*++
Routine Description:
Write the friendly name. This will not write anything
if the name is the same as it was
Arguments:
LPCTSTR lpszName : New friendly name
Return Value:
HRESULT
--*/
{
HRESULT hr = S_OK;
if (m_strFriendlyName.CompareNoCase(lpszName) != 0)
{
hr = Open(METADATA_PERMISSION_WRITE, m_strWamPath);
if (SUCCEEDED(hr))
{
ASSERT_PTR(lpszName);
CString str(lpszName);
hr = SetValue(MD_APP_FRIENDLY_NAME, str);
Close();
if (SUCCEEDED(hr))
{
m_strFriendlyName = lpszName;
}
}
}
return hr;
}