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.
2357 lines
57 KiB
2357 lines
57 KiB
/*++
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
vroots.cxx
|
|
|
|
Abstract:
|
|
|
|
This module contains the front end to the virtual roots interface
|
|
|
|
|
|
|
|
Author:
|
|
|
|
John Ludeman (johnl) 16-Mar-1995
|
|
|
|
Project:
|
|
|
|
Internet Servers Common Server DLL
|
|
|
|
Revisions:
|
|
|
|
--*/
|
|
|
|
//
|
|
// Include Headers
|
|
//
|
|
|
|
#include <tcpdllp.hxx>
|
|
#include <tsunami.hxx>
|
|
#include <iistypes.hxx>
|
|
#include <inetinfo.h>
|
|
#include <imd.h>
|
|
#include <inetreg.h>
|
|
#include <mb.hxx>
|
|
#include <w3svc.h>
|
|
#if 1 // DBCS
|
|
#include <mbstring.h>
|
|
#endif
|
|
#include <initguid.h>
|
|
#include <iwamreg.h>
|
|
|
|
|
|
BOOL
|
|
RetrieveRootPassword(
|
|
PCHAR pszRoot,
|
|
PCHAR pszPassword,
|
|
WCHAR * pszSecret
|
|
);
|
|
|
|
DWORD
|
|
GetFileSystemType(
|
|
IN LPCSTR pszRealPath,
|
|
OUT LPDWORD lpdwFileSystem
|
|
);
|
|
|
|
VOID
|
|
LogRootAddFailure(
|
|
IN PIIS_SERVER_INSTANCE psi,
|
|
PCHAR pszRoot,
|
|
PCHAR pszDirectory,
|
|
DWORD err,
|
|
IN PCHAR pszMetaPath,
|
|
IN MB * pmb
|
|
);
|
|
|
|
BOOL
|
|
TsAddVrootsWithScmUpdate(
|
|
PVOID pvContext,
|
|
MB * pmb,
|
|
VIRTUAL_ROOT * pvr
|
|
);
|
|
|
|
BOOL
|
|
TsAddVroots(
|
|
PVOID pvContext,
|
|
MB * pmb,
|
|
VIRTUAL_ROOT * pvr
|
|
);
|
|
|
|
HANDLE
|
|
VrootLogonUser(
|
|
IN CHAR * pszUser,
|
|
IN CHAR * pszPassword
|
|
);
|
|
|
|
BOOL
|
|
CrackUserAndDomain(
|
|
CHAR * pszDomainAndUser,
|
|
CHAR * * ppszUser,
|
|
CHAR * * ppszDomain
|
|
);
|
|
|
|
VOID
|
|
ClearSentinelEntry(
|
|
IN MB * pMB
|
|
);
|
|
|
|
VOID
|
|
RemoveUnmarkedRoots(
|
|
IN MB * pMB
|
|
);
|
|
|
|
BOOL
|
|
ReadVrootConfig(
|
|
LPVOID pvMB,
|
|
LPSTR szVRPath,
|
|
LPSTR szDirectory,
|
|
DWORD cbDirectory,
|
|
LPSTR szUser,
|
|
DWORD cbUser,
|
|
LPSTR szPassword,
|
|
DWORD cbPassword,
|
|
DWORD *pdwMask,
|
|
BOOL *pfDoCache
|
|
);
|
|
|
|
DWORD
|
|
hextointW(
|
|
WCHAR * pch
|
|
);
|
|
|
|
DWORD
|
|
hextointA(
|
|
CHAR * pch
|
|
);
|
|
|
|
BOOL
|
|
IIS_SERVER_INSTANCE::TsReadVirtualRoots(
|
|
MD_CHANGE_OBJECT * pcoChangeList
|
|
)
|
|
/*++
|
|
Description:
|
|
|
|
NT Version
|
|
|
|
This function is overloaded. The behavaior keys on pcoChangeList
|
|
being NULL or not.
|
|
|
|
If pcoChangeList is NULL (default value), it reads the metabase
|
|
key pointed at by pmb and adds each root item.
|
|
|
|
If pcoChangeList is not NULL then it only reads the necessary values.
|
|
|
|
Arguments:
|
|
|
|
pcoChangeList : pointer to metabase changes.
|
|
|
|
Note:
|
|
Failure to add a virtual root is not fatal. An appropriate event
|
|
will be logged listing the error and root.
|
|
|
|
Returns:
|
|
TRUE on success and FALSE if any failure.
|
|
|
|
--*/
|
|
{
|
|
BOOL fRet;
|
|
MB mb( (IMDCOM*) m_Service->QueryMDObject() );
|
|
|
|
//
|
|
// Unfortunately rename doesn't give us the name of the old object.
|
|
// So treat it as default processing
|
|
//
|
|
|
|
if ((NULL == pcoChangeList) ||
|
|
(MD_CHANGE_TYPE_RENAME_OBJECT == pcoChangeList->dwMDChangeType))
|
|
{
|
|
//
|
|
// Default processing. Remove & Re-Read all VRoots. Expensive.
|
|
//
|
|
|
|
if ( !mb.Open( QueryMDPath(),
|
|
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Remove all of the old roots for this server
|
|
//
|
|
|
|
fRet = QueryVrootTable()->RemoveVirtualRoots();
|
|
|
|
if ( fRet )
|
|
{
|
|
QueryVrootTable()->LockExclusive();
|
|
if (NULL == pcoChangeList)
|
|
{
|
|
fRet = TsEnumVirtualRoots( TsAddVrootsWithScmUpdate, this, &mb );
|
|
}
|
|
else
|
|
{
|
|
fRet = TsEnumVirtualRoots( TsAddVroots, this, &mb );
|
|
}
|
|
QueryVrootTable()->Unlock();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VIRTUAL_ROOT vr;
|
|
|
|
CHAR szUser[UNLEN+1];
|
|
CHAR szPassword[PWLEN+1];
|
|
CHAR szDirectory[MAX_PATH + UNLEN + 3];
|
|
DWORD dwMask;
|
|
BOOL fDoCache;
|
|
|
|
if (MD_CHANGE_TYPE_DELETE_OBJECT == pcoChangeList->dwMDChangeType)
|
|
{
|
|
return QueryVrootTable()->RemoveVirtualRoot(
|
|
(LPSTR)pcoChangeList->pszMDPath + QueryMDPathLen()
|
|
+ sizeof(IIS_MD_INSTANCE_ROOT)
|
|
);
|
|
}
|
|
|
|
if ( !mb.Open( (LPCSTR)pcoChangeList->pszMDPath,
|
|
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (!ReadVrootConfig( &mb,
|
|
"",
|
|
szDirectory,
|
|
sizeof(szDirectory),
|
|
szUser,
|
|
sizeof(szUser),
|
|
szPassword,
|
|
sizeof(szPassword),
|
|
&dwMask,
|
|
&fDoCache
|
|
))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
vr.pszAlias = (LPSTR)pcoChangeList->pszMDPath + QueryMDPathLen()
|
|
+ sizeof(IIS_MD_INSTANCE_ROOT);
|
|
vr.pszMetaPath = "";
|
|
vr.pszPath = szDirectory;
|
|
vr.dwAccessPerm = dwMask;
|
|
vr.pszUserName = szUser;
|
|
vr.pszPassword = szPassword;
|
|
vr.fDoCache = fDoCache;
|
|
|
|
if (pcoChangeList->dwMDChangeType & MD_CHANGE_TYPE_ADD_OBJECT)
|
|
{
|
|
fRet = TsAddVroots(this, &mb, &vr);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Remove the original entry & re-read
|
|
//
|
|
|
|
if (!QueryVrootTable()->RemoveVirtualRoot(vr.pszAlias))
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT,"Error %x removing vroot %s. \n",
|
|
GetLastError(), vr.pszMetaPath ));
|
|
}
|
|
|
|
fRet = TsAddVroots(this, &mb, &vr);
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
|
|
} // TsReadVirtualRoots
|
|
|
|
|
|
|
|
BOOL
|
|
TsAddVrootsWithScmUpdate(
|
|
PVOID pvContext,
|
|
MB * pmb,
|
|
VIRTUAL_ROOT * pvr
|
|
)
|
|
{
|
|
((IIS_SERVER_INSTANCE *) pvContext)->m_Service->StartUpIndicateClientActivity();
|
|
return TsAddVroots(pvContext,pmb,pvr);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
TsAddVroots(
|
|
PVOID pvContext,
|
|
MB * pmb,
|
|
VIRTUAL_ROOT * pvr
|
|
)
|
|
{
|
|
DWORD err = NO_ERROR;
|
|
DWORD dwFileSystem;
|
|
BOOL fRet = FALSE;
|
|
HANDLE hToken = NULL;
|
|
|
|
|
|
|
|
//
|
|
// Clear this virtual directory's error status
|
|
//
|
|
|
|
if ( !pmb->SetDword( pvr->pszMetaPath,
|
|
MD_WIN32_ERROR,
|
|
IIS_MD_UT_SERVER,
|
|
NO_ERROR,
|
|
METADATA_VOLATILE ))
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT,"Error %x setting win32 status from %s. \n",
|
|
GetLastError(), pvr->pszMetaPath ));
|
|
return FALSE;
|
|
}
|
|
|
|
if ( (pvr->pszUserName[0] != '\0') &&
|
|
(pvr->pszPath[0] == '\\') && (pvr->pszPath[1] == '\\') )
|
|
{
|
|
if ( g_fW3OnlyNoAuth )
|
|
{
|
|
hToken = NULL;
|
|
}
|
|
else
|
|
{
|
|
hToken = VrootLogonUser( pvr->pszUserName,
|
|
pvr->pszPassword );
|
|
|
|
if ( hToken == NULL)
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"Adding path %s err %d, user=%s, pwd=%d\n",
|
|
pvr->pszPath, GetLastError(), pvr->pszUserName, pvr->pszPassword ));
|
|
|
|
//
|
|
// Log error
|
|
//
|
|
|
|
LogRootAddFailure( (IIS_SERVER_INSTANCE *) pvContext,
|
|
pvr->pszAlias,
|
|
pvr->pszPath,
|
|
GetLastError(),
|
|
pvr->pszMetaPath,
|
|
pmb );
|
|
}
|
|
|
|
|
|
// Impersonate as user for GetFileSystemType()
|
|
if ( hToken != NULL && !ImpersonateLoggedOnUser(hToken))
|
|
{
|
|
err = GetLastError();
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( err == NO_ERROR )
|
|
{
|
|
if (pvr->pszPath[0] != '\0')
|
|
{
|
|
err = GetFileSystemType( pvr->pszPath, &dwFileSystem);
|
|
} else {
|
|
dwFileSystem = FS_ERROR;
|
|
}
|
|
|
|
|
|
if ( err != NO_ERROR) {
|
|
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
" GetFileSystemType(%s) failed.Error = %u.\n",
|
|
pvr->pszPath,
|
|
err));
|
|
|
|
LogRootAddFailure( (IIS_SERVER_INSTANCE *) pvContext,
|
|
pvr->pszAlias,
|
|
pvr->pszPath,
|
|
err,
|
|
pvr->pszMetaPath,
|
|
pmb );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Don't add roots that are invalid
|
|
//
|
|
|
|
if ( err == NO_ERROR )
|
|
{
|
|
if ( !((IIS_SERVER_INSTANCE *) pvContext)->QueryVrootTable()->AddVirtualRoot(
|
|
pvr->pszAlias,
|
|
pvr->pszPath,
|
|
pvr->dwAccessPerm,
|
|
pvr->pszUserName,
|
|
hToken,
|
|
dwFileSystem,
|
|
pvr->fDoCache ))
|
|
{
|
|
err = GetLastError();
|
|
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
" AddVirtualRoot() failed. Error = %u.\n", err));
|
|
|
|
LogRootAddFailure( (IIS_SERVER_INSTANCE *) pvContext,
|
|
pvr->pszAlias,
|
|
pvr->pszPath,
|
|
err,
|
|
pvr->pszMetaPath,
|
|
pmb );
|
|
}
|
|
}
|
|
|
|
if ( hToken != NULL)
|
|
{
|
|
RevertToSelf();
|
|
}
|
|
|
|
if ( err == NO_ERROR )
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
|
|
return fRet;
|
|
|
|
} // TsAddVroots
|
|
|
|
|
|
BOOL
|
|
IIS_SERVER_INSTANCE::TsEnumVirtualRoots(
|
|
PFN_VR_ENUM pfnCallback,
|
|
VOID * pvContext,
|
|
MB * pmbWebSite
|
|
)
|
|
{
|
|
return TsRecursiveEnumVirtualRoots(
|
|
pfnCallback,
|
|
pvContext,
|
|
IIS_MD_INSTANCE_ROOT "/",
|
|
m_dwLevelsToScan,
|
|
(LPVOID)pmbWebSite,
|
|
TRUE );
|
|
}
|
|
|
|
|
|
BOOL
|
|
IIS_SERVER_INSTANCE::TsRecursiveEnumVirtualRoots(
|
|
PFN_VR_ENUM pfnCallback,
|
|
VOID * pvContext,
|
|
LPSTR pszCurrentPath,
|
|
DWORD dwLevelsToScan,
|
|
LPVOID pvMB,
|
|
BOOL fGetRoot
|
|
)
|
|
/*++
|
|
Description:
|
|
|
|
Enumerates all of the virtual directories defined for this server
|
|
instance
|
|
|
|
Arguments:
|
|
pfnCallback - Enumeration callback to call for each virtual directory
|
|
pvContext - Context pfnCallback receives
|
|
pszCurrentPath - path where to start scanning for VRoots
|
|
dwLevelsToScan - # of levels to scan recursively for vroots
|
|
pvMB - ptr to MB to access metabase. Is LPVOID to avoid having to include
|
|
mb.hxx before any ref to iistypes.hxx
|
|
fGetRoot - TRUE if pszCurrentPath is to be considered as vroot to process
|
|
|
|
Returns:
|
|
TRUE on success and FALSE if any failure.
|
|
|
|
--*/
|
|
{
|
|
|
|
DWORD err;
|
|
MB* pMB = (MB*)pvMB;
|
|
|
|
DWORD cb;
|
|
|
|
CHAR nameBuf[METADATA_MAX_NAME_LEN+2];
|
|
CHAR tmpBuf[sizeof(nameBuf)];
|
|
|
|
DWORD cbCurrentPath;
|
|
DWORD i = 0;
|
|
|
|
VIRTUAL_ROOT vr;
|
|
|
|
CHAR szUser[UNLEN+1];
|
|
CHAR szPassword[PWLEN+1];
|
|
CHAR szDirectory[MAX_PATH + UNLEN + 3];
|
|
DWORD dwMask;
|
|
BOOL fDoCache;
|
|
|
|
//
|
|
// Enumerate all of the listed items in the metabase
|
|
// and add them
|
|
//
|
|
|
|
cbCurrentPath = strlen( pszCurrentPath );
|
|
CopyMemory( nameBuf, pszCurrentPath, cbCurrentPath + 1);
|
|
|
|
while ( TRUE ) {
|
|
|
|
METADATA_RECORD mdRecord;
|
|
DWORD dwFileSystem = FS_ERROR;
|
|
|
|
err = NO_ERROR;
|
|
|
|
if ( fGetRoot ) {
|
|
|
|
fGetRoot = FALSE;
|
|
|
|
} else {
|
|
|
|
if ( !pMB->EnumObjects( pszCurrentPath,
|
|
nameBuf + cbCurrentPath,
|
|
i++ ))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ( dwLevelsToScan > 1 )
|
|
{
|
|
cb = strlen( nameBuf );
|
|
nameBuf[ cb ] = '/';
|
|
nameBuf[ cb + 1 ] = '\0';
|
|
|
|
if ( !TsRecursiveEnumVirtualRoots(
|
|
pfnCallback,
|
|
pvContext,
|
|
nameBuf,
|
|
dwLevelsToScan - 1,
|
|
pMB,
|
|
FALSE ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
nameBuf[ cb ] = '\0';
|
|
}
|
|
}
|
|
|
|
if (!ReadVrootConfig( pvMB,
|
|
nameBuf,
|
|
szDirectory,
|
|
sizeof(szDirectory),
|
|
szUser,
|
|
sizeof(szUser),
|
|
szPassword,
|
|
sizeof(szPassword),
|
|
&dwMask,
|
|
&fDoCache
|
|
))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Now set things up for the callback
|
|
//
|
|
|
|
DBG_ASSERT( !_strnicmp( nameBuf, IIS_MD_INSTANCE_ROOT, sizeof(IIS_MD_INSTANCE_ROOT) - 1));
|
|
|
|
//
|
|
// Add can modify the root - don't modify the working vroot path
|
|
//
|
|
|
|
strcpy( tmpBuf, nameBuf );
|
|
|
|
vr.pszAlias = tmpBuf + sizeof(IIS_MD_INSTANCE_ROOT) - 1;
|
|
vr.pszMetaPath = tmpBuf;
|
|
vr.pszPath = szDirectory;
|
|
vr.dwAccessPerm = dwMask;
|
|
vr.pszUserName = szUser;
|
|
vr.pszPassword = szPassword;
|
|
vr.fDoCache = fDoCache;
|
|
|
|
if ( !pfnCallback( pvContext, pMB, &vr ))
|
|
{
|
|
//
|
|
// !!! so what do we do here?
|
|
//
|
|
|
|
DBGPRINTF((DBG_CONTEXT,"EnumCallback returns FALSE\n"));
|
|
}
|
|
|
|
} // while
|
|
|
|
return TRUE;
|
|
|
|
} // Enum
|
|
|
|
|
|
|
|
VOID
|
|
LogRootAddFailure(
|
|
IN PIIS_SERVER_INSTANCE psi,
|
|
IN PCHAR pszRoot,
|
|
IN PCHAR pszDirectory,
|
|
IN DWORD err,
|
|
IN PCHAR pszMetaPath,
|
|
IN MB * pmb
|
|
)
|
|
{
|
|
const CHAR * apsz[3];
|
|
STR strError;
|
|
|
|
psi->LoadStr( strError, err, FALSE ); // loads ANSI message. Convert to UNICODE
|
|
|
|
apsz[0] = pszRoot;
|
|
apsz[1] = pszDirectory;
|
|
apsz[2] = strError.QueryStrA();
|
|
|
|
psi->m_Service->LogEvent( INET_SVC_ADD_VIRTUAL_ROOT_FAILED,
|
|
3,
|
|
apsz,
|
|
err );
|
|
|
|
//
|
|
// Indicate the error on this virtual directory
|
|
//
|
|
|
|
if ( !pmb->SetDword( pszMetaPath,
|
|
MD_WIN32_ERROR,
|
|
IIS_MD_UT_SERVER,
|
|
err,
|
|
METADATA_VOLATILE ))
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"LogRootAddFailure: Unable to set win32 status\n" ));
|
|
}
|
|
} // LogRootAddFailure
|
|
|
|
|
|
BOOL
|
|
RetrieveRootPassword(
|
|
PCHAR pszRoot,
|
|
PCHAR pszPassword,
|
|
PWCHAR pszSecret
|
|
)
|
|
/*++
|
|
Description:
|
|
|
|
This function retrieves the password for the specified root & address
|
|
|
|
Arguments:
|
|
|
|
pszRoot - Name of root + address in the form "/root,<address>".
|
|
pszPassword - Receives password, must be at least PWLEN+1 characters
|
|
pszSecret - Virtual Root password secret name
|
|
|
|
Returns:
|
|
TRUE on success and FALSE if any failure.
|
|
|
|
--*/
|
|
{
|
|
BUFFER bufSecret;
|
|
WCHAR * psz;
|
|
WCHAR * pszTerm;
|
|
WCHAR * pszNextLine;
|
|
WCHAR wsRoot[MAX_PATH+1];
|
|
|
|
DWORD cch;
|
|
|
|
if ( !TsGetSecretW( pszSecret,
|
|
&bufSecret ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Convert root to WCHAR
|
|
//
|
|
|
|
cch = MultiByteToWideChar( CP_ACP,
|
|
MB_PRECOMPOSED,
|
|
pszRoot,
|
|
-1,
|
|
wsRoot,
|
|
MAX_PATH );
|
|
|
|
wsRoot[cch] = L'\0';
|
|
if ( cch == 0 ) {
|
|
return FALSE;
|
|
}
|
|
|
|
psz = (WCHAR *) bufSecret.QueryPtr();
|
|
|
|
//
|
|
// Scan the list of roots looking for a match. The list looks like:
|
|
//
|
|
// <root>,<address>=<password>\0
|
|
// <root>,<address>=<password>\0
|
|
// \0
|
|
//
|
|
|
|
while ( *psz )
|
|
{
|
|
PWCHAR pszComma;
|
|
|
|
pszNextLine = psz + wcslen(psz) + 1;
|
|
|
|
pszTerm = wcschr( psz, L'=' );
|
|
|
|
if ( !pszTerm )
|
|
goto NextLine;
|
|
|
|
*pszTerm = L'\0';
|
|
|
|
//
|
|
// remove the ,
|
|
//
|
|
|
|
pszComma = wcschr( psz, L',' );
|
|
if ( pszComma != NULL ) {
|
|
*pszComma = '\0';
|
|
}
|
|
|
|
if ( !_wcsicmp( wsRoot, psz ) )
|
|
{
|
|
|
|
//
|
|
// We found a match, copy the password
|
|
//
|
|
|
|
(VOID) ConvertUnicodeToAnsi(
|
|
pszTerm + 1,
|
|
pszPassword,
|
|
PWLEN + sizeof(CHAR));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
NextLine:
|
|
psz = pszNextLine;
|
|
}
|
|
|
|
//
|
|
// If the matching root wasn't found, default to the empty password
|
|
//
|
|
|
|
*pszPassword = '\0';
|
|
return TRUE;
|
|
|
|
} // RetrieveRootPassword
|
|
|
|
|
|
|
|
BOOL
|
|
IIS_SERVER_INSTANCE::TsSetVirtualRoots(
|
|
IN LPINETA_CONFIG_INFO pConfig
|
|
)
|
|
/*++
|
|
Description:
|
|
|
|
Writes the virtual roots specified in the config structure to the
|
|
registry
|
|
|
|
NOTE: This is basically legacy code for the IIS 3.0 RPC interface.
|
|
|
|
Arguments:
|
|
pConfig - new list of virtual
|
|
|
|
Returns:
|
|
TRUE on success and FALSE if any failure.
|
|
|
|
--*/
|
|
{
|
|
DWORD err;
|
|
DWORD dwDummy;
|
|
LPINET_INFO_VIRTUAL_ROOT_LIST pRootsList;
|
|
DWORD cch;
|
|
DWORD i;
|
|
DWORD dwMask;
|
|
DWORD sentinelValue = 7777777;
|
|
IWamAdmin* pIWamAdmin = NULL;
|
|
MB mb( (IMDCOM*) m_Service->QueryMDObject() );
|
|
HRESULT hr = NOERROR;
|
|
STR strTmp;
|
|
|
|
//
|
|
// Do the metabase
|
|
//
|
|
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,"Setting VR data on %s\n",
|
|
QueryMDPath()));
|
|
}
|
|
|
|
if ( !mb.Open( QueryMDPath(),
|
|
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ))
|
|
{
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,"Open MD instance root %s returns %d\n",
|
|
QueryMDPath(), GetLastError() ));
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// We need to create an application for each new virtual root set via
|
|
// the IIS 3.0 RPC interface for ASP compatability
|
|
//
|
|
|
|
hr = CoCreateInstance(CLSID_WamAdmin,
|
|
NULL,
|
|
CLSCTX_SERVER,
|
|
IID_IWamAdmin,
|
|
(void **)&pIWamAdmin);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"Failed to create WamAdmin interface, error %08lx\n",
|
|
hr ));
|
|
|
|
SetLastError( hr );
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// See if we need to delete any VRs
|
|
//
|
|
|
|
pRootsList = pConfig->VirtualRoots;
|
|
|
|
if ( (pRootsList == NULL) || (pRootsList->cEntries == 0) ) {
|
|
|
|
//
|
|
// NO VRs. Delete the entire VR tree
|
|
//
|
|
|
|
if ( !mb.DeleteObject( IIS_MD_INSTANCE_ROOT ) )
|
|
{
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,
|
|
"Deleting VR root returns %d\n",GetLastError()));
|
|
}
|
|
}
|
|
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,"Empty list set on %s\n", QueryMDPath()));
|
|
}
|
|
|
|
goto exit;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Remove our secret value
|
|
//
|
|
|
|
ClearSentinelEntry( &mb );
|
|
}
|
|
|
|
for ( i = 0; i < pRootsList->cEntries; i++ ) {
|
|
|
|
CHAR tmpRoot[MAX_PATH+1];
|
|
CHAR tmpBuffer[MAX_PATH+1];
|
|
BOOL fCreateApp = FALSE;
|
|
|
|
DWORD rootLen;
|
|
|
|
//
|
|
// strings to ANSI
|
|
//
|
|
|
|
#define VROOT_ROOT IIS_MD_INSTANCE_ROOT
|
|
#define CCH_VROOT_ROOT (sizeof(VROOT_ROOT) - 1)
|
|
|
|
strcpy( tmpRoot, VROOT_ROOT );
|
|
|
|
(VOID) ConvertUnicodeToAnsi(
|
|
pRootsList->aVirtRootEntry[i].pszRoot,
|
|
&tmpRoot[CCH_VROOT_ROOT],
|
|
MAX_PATH);
|
|
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,"Setting data for root %s\n",tmpRoot));
|
|
}
|
|
|
|
rootLen = strlen(tmpRoot);
|
|
|
|
//
|
|
// Create the root
|
|
//
|
|
|
|
if ( !mb.AddObject( tmpRoot ) &&
|
|
(GetLastError() != ERROR_ALREADY_EXISTS) )
|
|
{
|
|
|
|
DBGPRINTF((DBG_CONTEXT,"AddMetaObject %s failed with %d\n",
|
|
tmpRoot, GetLastError() ));
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Set sentinel entry
|
|
//
|
|
|
|
if ( !mb.SetDword( tmpRoot,
|
|
MD_VR_UPDATE,
|
|
IIS_MD_UT_FILE,
|
|
sentinelValue,
|
|
0 ))
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT,
|
|
"Error %d setting sentinel value %x for %s\n",
|
|
GetLastError(), sentinelValue, tmpRoot));
|
|
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Set Path
|
|
//
|
|
|
|
(VOID) ConvertUnicodeToAnsi(
|
|
pRootsList->aVirtRootEntry[i].pszDirectory,
|
|
tmpBuffer,
|
|
MAX_PATH+1);
|
|
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,"Directory path is %s\n",tmpBuffer));
|
|
}
|
|
|
|
//
|
|
// Check to see if the path property already exists - if it does
|
|
// then we won't create the application - only new virtual directories
|
|
// get an application created for them
|
|
//
|
|
|
|
if ( !mb.GetStr( tmpRoot,
|
|
MD_VR_PATH,
|
|
IIS_MD_UT_FILE,
|
|
&strTmp,
|
|
METADATA_NO_ATTRIBUTES ))
|
|
{
|
|
fCreateApp = TRUE;
|
|
}
|
|
|
|
if ( !mb.SetString( tmpRoot,
|
|
MD_VR_PATH,
|
|
IIS_MD_UT_FILE,
|
|
tmpBuffer ))
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT,"Error %d setting path[%s] for %s\n",
|
|
GetLastError(), tmpBuffer, tmpRoot));
|
|
}
|
|
|
|
if ( !mb.SetString( tmpRoot,
|
|
MD_KEY_TYPE,
|
|
IIS_MD_UT_SERVER,
|
|
"IIsWebVirtualDir" ))
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT,"Error %d setting ADSI type for %s\n",
|
|
GetLastError(), tmpRoot));
|
|
}
|
|
|
|
|
|
//
|
|
// Set Username
|
|
//
|
|
|
|
(VOID) ConvertUnicodeToAnsi(
|
|
pRootsList->aVirtRootEntry[i].pszAccountName,
|
|
tmpBuffer,
|
|
MAX_PATH+1);
|
|
|
|
if ( !mb.SetString( tmpRoot,
|
|
MD_VR_USERNAME,
|
|
IIS_MD_UT_FILE,
|
|
tmpBuffer ))
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT,"Error %d setting username for %s\n",
|
|
GetLastError(), tmpRoot));
|
|
}
|
|
|
|
//
|
|
// Set Mask
|
|
//
|
|
|
|
if ( !mb.SetDword( tmpRoot,
|
|
MD_ACCESS_PERM,
|
|
IIS_MD_UT_FILE,
|
|
pRootsList->aVirtRootEntry[i].dwMask ))
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT,"Error %d setting mask for %s\n",
|
|
GetLastError(), tmpRoot));
|
|
}
|
|
|
|
if ( fCreateApp )
|
|
{
|
|
WCHAR wchFullPath[MAX_PATH];
|
|
|
|
strcpy( tmpRoot, QueryMDPath() );
|
|
strcat( tmpRoot, "/" VROOT_ROOT );
|
|
|
|
if ( MultiByteToWideChar( CP_ACP,
|
|
MB_PRECOMPOSED,
|
|
tmpRoot,
|
|
-1,
|
|
wchFullPath,
|
|
sizeof( wchFullPath ) / sizeof(WCHAR) ))
|
|
{
|
|
wcscat( wchFullPath, pRootsList->aVirtRootEntry[i].pszRoot );
|
|
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"Creating application at %S\n",
|
|
wchFullPath ));
|
|
|
|
//
|
|
// We need to close our metabase handle so WAM can create
|
|
// the in process application
|
|
//
|
|
|
|
DBG_REQUIRE( mb.Close() );
|
|
|
|
hr = pIWamAdmin->AppCreate( wchFullPath, TRUE);
|
|
|
|
if ( FAILED( hr ))
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"Failed to create application, error %08lx\n",
|
|
hr ));
|
|
}
|
|
|
|
//
|
|
// Reopen the metabase for the next vroot
|
|
//
|
|
|
|
if ( !mb.Open( QueryMDPath(),
|
|
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ))
|
|
{
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,"Open MD instance root %s returns %d\n",
|
|
QueryMDPath(), GetLastError() ));
|
|
}
|
|
|
|
goto exit;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Delete entries that do not have the sentinel entry
|
|
//
|
|
|
|
RemoveUnmarkedRoots( &mb );
|
|
|
|
exit:
|
|
|
|
//
|
|
// If this is the downlevel instance, mirror it to the registry
|
|
//
|
|
|
|
if ( IsDownLevelInstance() ) {
|
|
TsMirrorVirtualRoots( pConfig );
|
|
}
|
|
|
|
if ( pIWamAdmin ) {
|
|
pIWamAdmin->Release();
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
} // IIS_SERVER_INSTANCE::TsSetVirtualRoots
|
|
|
|
|
|
DWORD
|
|
GetFileSystemType(
|
|
IN LPCSTR pszRealPath,
|
|
OUT LPDWORD lpdwFileSystem
|
|
)
|
|
/*++
|
|
Gets file system specific information for a given path.
|
|
It uses GetVolumeInfomration() to query the file system type
|
|
and file system flags.
|
|
On success the flags and file system type are returned in
|
|
passed in pointers.
|
|
|
|
Arguments:
|
|
|
|
pszRealPath pointer to buffer containing path for which
|
|
we are inquiring the file system details.
|
|
|
|
lpdwFileSystem
|
|
pointer to buffer to fill in the type of file system.
|
|
|
|
Returns:
|
|
NO_ERROR on success and Win32 error code if any error.
|
|
|
|
--*/
|
|
{
|
|
# define MAX_FILE_SYSTEM_NAME_SIZE ( MAX_PATH)
|
|
|
|
CHAR rgchBuf[MAX_FILE_SYSTEM_NAME_SIZE];
|
|
CHAR rgchRoot[MAX_FILE_SYSTEM_NAME_SIZE];
|
|
int i;
|
|
DWORD dwReturn = ERROR_PATH_NOT_FOUND;
|
|
DWORD len;
|
|
|
|
if ( (pszRealPath == NULL) || (lpdwFileSystem == NULL)) {
|
|
return ( ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
ZeroMemory( rgchRoot, sizeof(rgchRoot) );
|
|
*lpdwFileSystem = FS_ERROR;
|
|
|
|
//
|
|
// Copy just the root directory to rgchRoot for querying
|
|
//
|
|
|
|
IF_DEBUG( DLL_VIRTUAL_ROOTS) {
|
|
DBGPRINTF( ( DBG_CONTEXT, " GetFileSystemType(%s).\n", pszRealPath));
|
|
}
|
|
|
|
if ( (pszRealPath[0] == '\\') &&
|
|
(pszRealPath[1] == '\\')) {
|
|
|
|
PCHAR pszEnd;
|
|
|
|
//
|
|
// this is an UNC name. Extract just the first two components
|
|
//
|
|
//
|
|
|
|
pszEnd = strchr( pszRealPath+2, '\\');
|
|
|
|
if ( pszEnd == NULL) {
|
|
|
|
// just the server name present
|
|
|
|
return ( ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
#if 1 // DBCS enabling for share name
|
|
pszEnd = (PCHAR)_mbschr( (PUCHAR)pszEnd+1, '\\');
|
|
#else
|
|
pszEnd = strchr( pszEnd+1, '\\');
|
|
#endif
|
|
|
|
len = ( ( pszEnd == NULL) ? strlen(pszRealPath)
|
|
: (DIFF(pszEnd - pszRealPath) + 1) );
|
|
|
|
//
|
|
// Copy till the end of UNC Name only (exclude all other path info)
|
|
//
|
|
|
|
if ( len < (MAX_FILE_SYSTEM_NAME_SIZE - 1) ) {
|
|
|
|
CopyMemory( rgchRoot, pszRealPath, len);
|
|
rgchRoot[len] = '\0';
|
|
} else {
|
|
|
|
return ( ERROR_INVALID_NAME);
|
|
}
|
|
|
|
#if 1 // DBCS enabling for share name
|
|
if ( *CharPrev( rgchRoot, rgchRoot + len ) != '\\' ) {
|
|
#else
|
|
if ( rgchRoot[len - 1] != '\\' ) {
|
|
#endif
|
|
|
|
if ( len < MAX_FILE_SYSTEM_NAME_SIZE - 2 ) {
|
|
rgchRoot[len] = '\\';
|
|
rgchRoot[len+1] = '\0';
|
|
} else {
|
|
|
|
return (ERROR_INVALID_NAME);
|
|
}
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// This is non UNC name.
|
|
// Copy just the root directory to rgchRoot for querying
|
|
//
|
|
|
|
|
|
for( i = 0; i < 9 && pszRealPath[i] != '\0'; i++) {
|
|
|
|
if ( (rgchRoot[i] = pszRealPath[i]) == ':') {
|
|
|
|
break;
|
|
}
|
|
} // for
|
|
|
|
|
|
if ( rgchRoot[i] != ':') {
|
|
|
|
//
|
|
// we could not find the root directory.
|
|
// return with error value
|
|
//
|
|
|
|
return ( ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
rgchRoot[i+1] = '\\'; // terminate the drive spec with a slash
|
|
rgchRoot[i+2] = '\0'; // terminate the drive spec with null char
|
|
|
|
} // else
|
|
|
|
IF_DEBUG( DLL_VIRTUAL_ROOTS) {
|
|
DBGPRINTF( ( DBG_CONTEXT, " GetVolumeInformation(%s).\n",
|
|
rgchRoot));
|
|
}
|
|
|
|
//
|
|
// The rgchRoot should end with a "\" (slash)
|
|
// otherwise, the call will fail.
|
|
//
|
|
|
|
if ( GetVolumeInformation( rgchRoot, // lpRootPathName
|
|
NULL, // lpVolumeNameBuffer
|
|
0, // len of volume name buffer
|
|
NULL, // lpdwVolSerialNumber
|
|
NULL, // lpdwMaxComponentLength
|
|
NULL, // lpdwSystemFlags
|
|
rgchBuf, // lpFileSystemNameBuff
|
|
sizeof(rgchBuf)
|
|
) ) {
|
|
|
|
|
|
|
|
dwReturn = NO_ERROR;
|
|
|
|
if ( strcmp( rgchBuf, "FAT") == 0) {
|
|
|
|
*lpdwFileSystem = FS_FAT;
|
|
|
|
} else if ( strcmp( rgchBuf, "NTFS") == 0) {
|
|
|
|
*lpdwFileSystem = FS_NTFS;
|
|
|
|
} else if ( strcmp( rgchBuf, "HPFS") == 0) {
|
|
|
|
*lpdwFileSystem = FS_HPFS;
|
|
|
|
} else if ( strcmp( rgchBuf, "CDFS") == 0) {
|
|
|
|
*lpdwFileSystem = FS_CDFS;
|
|
|
|
} else if ( strcmp( rgchBuf, "OFS") == 0) {
|
|
|
|
*lpdwFileSystem = FS_OFS;
|
|
|
|
} else {
|
|
|
|
*lpdwFileSystem = FS_FAT;
|
|
}
|
|
|
|
} else {
|
|
|
|
dwReturn = GetLastError();
|
|
|
|
IF_DEBUG( DLL_VIRTUAL_ROOTS) {
|
|
|
|
DBGPRINTF( ( DBG_CONTEXT,
|
|
" GetVolumeInformation( %s) failed with error %d\n",
|
|
rgchRoot, dwReturn));
|
|
}
|
|
|
|
}
|
|
|
|
return ( dwReturn);
|
|
} // GetFileSystemType()
|
|
|
|
|
|
HANDLE
|
|
VrootLogonUser(
|
|
IN CHAR * pszUser,
|
|
IN CHAR * pszPassword
|
|
)
|
|
/*++
|
|
This function uses the given parameters and logs on to generate
|
|
a user handle for the account.
|
|
|
|
Arguments:
|
|
pszUser - pointer to string containing the user name.
|
|
pszPassword - pointer to string containing the password.
|
|
|
|
Returns:
|
|
Handle for the logged on user on success.
|
|
Returns NULL for errors.
|
|
|
|
History:
|
|
MuraliK 18-Jan-1996 Created.
|
|
--*/
|
|
{
|
|
CHAR szDomainAndUser[IIS_DNLEN+UNLEN+2];
|
|
CHAR * pszUserOnly;
|
|
CHAR * pszDomain;
|
|
HANDLE hToken = NULL;
|
|
BOOL fReturn;
|
|
|
|
//
|
|
// Validate parameters & state.
|
|
//
|
|
|
|
DBG_ASSERT( pszUser != NULL && *pszUser != '\0');
|
|
DBG_ASSERT( strlen(pszUser) < sizeof(szDomainAndUser) );
|
|
DBG_ASSERT( pszPassword != NULL);
|
|
DBG_ASSERT( strlen(pszPassword) <= PWLEN );
|
|
|
|
//
|
|
// Save a copy of the domain\user so we can squirrel around
|
|
// with it a bit.
|
|
//
|
|
|
|
strcpy( szDomainAndUser, pszUser );
|
|
|
|
//
|
|
// Crack the name into domain/user components.
|
|
// Then try and logon as the specified user.
|
|
//
|
|
|
|
fReturn = ( CrackUserAndDomain( szDomainAndUser,
|
|
&pszUserOnly,
|
|
&pszDomain ) &&
|
|
LogonUserA(pszUserOnly,
|
|
pszDomain,
|
|
pszPassword,
|
|
LOGON32_LOGON_NETWORK_CLEARTEXT, //LOGON32_LOGON_NETWORK,
|
|
LOGON32_PROVIDER_DEFAULT,
|
|
&hToken )
|
|
);
|
|
|
|
if ( !fReturn) {
|
|
|
|
//
|
|
// Logon user failed.
|
|
//
|
|
|
|
IF_DEBUG( DLL_SECURITY) {
|
|
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
" CrachUserAndDomain/LogonUser (%s) failed Error=%d\n",
|
|
pszUser, GetLastError()));
|
|
}
|
|
|
|
hToken = NULL;
|
|
} else {
|
|
HANDLE hImpersonation = NULL;
|
|
|
|
// we need to obtain the impersonation token, the primary token cannot
|
|
// be used for a lot of purposes :(
|
|
if (!pfnDuplicateTokenEx( hToken, // hSourceToken
|
|
TOKEN_ALL_ACCESS,
|
|
NULL,
|
|
SecurityImpersonation, // Obtain impersonation
|
|
TokenImpersonation,
|
|
&hImpersonation) // hDestinationToken
|
|
) {
|
|
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"Creating ImpersonationToken failed. Error = %d\n",
|
|
GetLastError()
|
|
));
|
|
|
|
// cleanup and exit.
|
|
hImpersonation = NULL;
|
|
|
|
// Fall through for cleanup
|
|
}
|
|
|
|
//
|
|
// close original token. If Duplicate was successful,
|
|
// we should have ref in the hImpersonation.
|
|
// Send the impersonation token to the client.
|
|
//
|
|
CloseHandle( hToken);
|
|
hToken = hImpersonation;
|
|
}
|
|
|
|
|
|
//
|
|
// Success!
|
|
//
|
|
|
|
return hToken;
|
|
|
|
} // VrootLogonUser()
|
|
|
|
DWORD
|
|
hextointW(
|
|
WCHAR * pch
|
|
)
|
|
{
|
|
WCHAR * pchStart;
|
|
DWORD sum = 0;
|
|
DWORD mult = 1;
|
|
|
|
while ( *pch == L' ' )
|
|
pch++;
|
|
|
|
pchStart = pch;
|
|
|
|
while ( iswxdigit( *pch ) )
|
|
pch++;
|
|
|
|
while ( --pch >= pchStart )
|
|
{
|
|
sum += mult * ( *pch >= L'A' ? *pch + 10 - L'A' :
|
|
*pch - L'0' );
|
|
mult *= 16;
|
|
}
|
|
|
|
return sum;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
hextointA(
|
|
CHAR * pch
|
|
)
|
|
{
|
|
CHAR * pchStart;
|
|
DWORD sum = 0;
|
|
DWORD mult = 1;
|
|
|
|
while ( *pch == ' ' )
|
|
pch++;
|
|
|
|
pchStart = pch;
|
|
|
|
while ( isxdigit( (UCHAR)(*pch) ) )
|
|
pch++;
|
|
|
|
while ( --pch >= pchStart )
|
|
{
|
|
sum += mult * ( *pch >= 'A' ? *pch + 10 - 'A' :
|
|
*pch - '0' );
|
|
mult *= 16;
|
|
}
|
|
|
|
return sum;
|
|
|
|
} // hextointA
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
IIS_SERVER_INSTANCE::MoveVrootFromRegToMD(
|
|
VOID
|
|
)
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT,"MoveVrootFromRegToMD called!!!\n"));
|
|
return(TRUE);
|
|
|
|
} // IIS_SERVER_INSTANCE::MoveVrootFromRegToMD
|
|
|
|
|
|
BOOL
|
|
TsCopyVrootToRegistry(
|
|
PVOID pvContext,
|
|
MB * pmb,
|
|
VIRTUAL_ROOT * pvr
|
|
)
|
|
{
|
|
|
|
DWORD cch;
|
|
DWORD err;
|
|
HKEY hkey = (HKEY)pvContext;
|
|
CHAR szValue[ MAX_PATH + UNLEN + 2 ];
|
|
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,"CopyVrootToReg: Adding %s to registry\n",
|
|
pvr->pszAlias));
|
|
}
|
|
|
|
cch = wsprintfA( szValue,
|
|
"%s,%s,%X",
|
|
pvr->pszPath,
|
|
pvr->pszUserName,
|
|
pvr->dwAccessPerm );
|
|
|
|
DBG_ASSERT( cch < sizeof( szValue ) );
|
|
|
|
err = WriteRegistryStringA(hkey,
|
|
pvr->pszAlias,
|
|
szValue,
|
|
strlen(szValue),
|
|
REG_SZ);
|
|
|
|
DBG_ASSERT(err == NO_ERROR);
|
|
|
|
return(TRUE);
|
|
|
|
} // TsCopyVrootToRegistry
|
|
|
|
|
|
|
|
BOOL
|
|
IIS_SERVER_INSTANCE::MoveMDVroots2Registry(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Moves MD VR entries to the registry if registry VR key
|
|
does not exist at startup.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
HKEY hkey = NULL;
|
|
HKEY hkeyRoots = NULL;
|
|
DWORD dwDisp;
|
|
DWORD err;
|
|
BOOL fMigrated = FALSE;
|
|
|
|
MB mb( (IMDCOM*) m_Service->QueryMDObject() );
|
|
|
|
DBG_ASSERT(IsDownLevelInstance());
|
|
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,"Entering MoveMDToRegAtStartup.\n"));
|
|
}
|
|
|
|
//
|
|
// see if the key exists
|
|
//
|
|
|
|
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
m_Service->QueryRegParamKey( ),
|
|
0,
|
|
KEY_READ|KEY_WRITE,
|
|
&hkey );
|
|
|
|
if ( err != NO_ERROR ) {
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"RegOpenKeyEx %s returned error %d\n",
|
|
m_Service->QueryRegParamKey(), err ));
|
|
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// VR key?
|
|
//
|
|
|
|
err = RegCreateKeyEx( hkey,
|
|
VIRTUAL_ROOTS_KEY_A,
|
|
0,
|
|
NULL,
|
|
0,
|
|
KEY_READ|KEY_WRITE,
|
|
NULL,
|
|
&hkeyRoots,
|
|
&dwDisp );
|
|
|
|
if ( err != NO_ERROR ) {
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,
|
|
"Error %d in RegCreateKeyEx\n",err));
|
|
}
|
|
|
|
goto exit;
|
|
}
|
|
|
|
#if 0
|
|
Removing this if will mean everytime the server starts we migrate the registry
|
|
keys to the metabase. The only side effect this has is if somebody deleted the
|
|
a virtual directory from the metabase w/o the server started, that key will be
|
|
migrated back from the registry. With the server running it's not a big deal
|
|
since the server always mirrors the metabase to the registry on vroot changes.
|
|
|
|
if ( dwDisp == REG_OPENED_EXISTING_KEY ) {
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,
|
|
"Registry VR key found, aborting startup migration.\n"));
|
|
}
|
|
|
|
goto exit;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Get the MD handle to the VR root
|
|
//
|
|
|
|
if ( !mb.Open( QueryMDPath(),
|
|
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ))
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT,"Open MD vr root returns %d\n",GetLastError()));
|
|
goto exit;
|
|
}
|
|
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,"Opening MD path[%s]\n",QueryMDPath()));
|
|
}
|
|
|
|
TsRecursiveEnumVirtualRoots(
|
|
TsCopyVrootToRegistry,
|
|
hkeyRoots,
|
|
IIS_MD_INSTANCE_ROOT "/",
|
|
1,
|
|
(LPVOID)&mb,
|
|
TRUE );
|
|
|
|
mb.Close();
|
|
fMigrated = TRUE;
|
|
|
|
exit:
|
|
|
|
if ( hkey != NULL ) {
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
if ( hkeyRoots != NULL ) {
|
|
RegCloseKey(hkeyRoots);
|
|
}
|
|
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,"Leaving MoveMDToRegAtStartup.\n"));
|
|
}
|
|
return(fMigrated);
|
|
|
|
} // IIS_SERVER_INSTANCE::MoveMDVroots2Registry
|
|
|
|
|
|
|
|
VOID
|
|
IIS_SERVER_INSTANCE::PdcHackVRReg2MD(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Moves VR entries to the MD at startup.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DWORD err;
|
|
CHAR pszRoot[MAX_LENGTH_VIRTUAL_ROOT + MAX_LENGTH_ROOT_ADDR + 2];
|
|
CHAR pszDirectory[MAX_PATH + UNLEN + 3];
|
|
|
|
CHAR * pszUser;
|
|
DWORD cchRoot;
|
|
DWORD cchDir;
|
|
DWORD cch;
|
|
BOOL fRet = TRUE;
|
|
DWORD i = 0;
|
|
DWORD dwRegType;
|
|
|
|
DWORD dwMask;
|
|
PCHAR pszMask;
|
|
PCHAR tmpRoot;
|
|
DWORD dwAuthorization;
|
|
MB mb( (IMDCOM*) m_Service->QueryMDObject() );
|
|
|
|
HKEY hkey = NULL;
|
|
HKEY hkeyRoots = NULL;
|
|
|
|
DBG_ASSERT(IsDownLevelInstance());
|
|
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,"In MoveVrootFromRegToMD\n"));
|
|
}
|
|
|
|
//
|
|
// see if the key exists
|
|
//
|
|
|
|
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
m_Service->QueryRegParamKey( ),
|
|
0,
|
|
KEY_READ,
|
|
&hkey );
|
|
|
|
if ( err != NO_ERROR ) {
|
|
DBGPRINTF(( DBG_CONTEXT, "RegOpenKeyEx returned error %d\n",err ));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// VR key?
|
|
//
|
|
|
|
if ( err = RegOpenKeyEx( hkey,
|
|
VIRTUAL_ROOTS_KEY_A,
|
|
0,
|
|
KEY_READ,
|
|
&hkeyRoots )) {
|
|
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,"RegOpenKeyEx %s failed with %d\n",
|
|
VIRTUAL_ROOTS_KEY_A, err));
|
|
}
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Key exists. Get the authorization key
|
|
//
|
|
|
|
{
|
|
HKEY instanceKey;
|
|
|
|
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
QueryRegParamKey(),
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&instanceKey );
|
|
|
|
if ( err != NO_ERROR ) {
|
|
goto exit;
|
|
}
|
|
|
|
dwAuthorization = ReadRegistryDword( instanceKey,
|
|
INETA_AUTHENTICATION,
|
|
INET_INFO_AUTH_ANONYMOUS );
|
|
|
|
RegCloseKey( instanceKey );
|
|
}
|
|
|
|
//
|
|
// Get the MD handle to the VR root
|
|
//
|
|
|
|
if ( !mb.Open( QueryMDPath(),
|
|
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ))
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT,"Open MD vr root returns %d\n",GetLastError()));
|
|
goto exit;
|
|
}
|
|
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,"Adding MD path[%s]\n",QueryMDPath()));
|
|
}
|
|
|
|
//
|
|
// Enumerate all of the listed items in the registry
|
|
// and add them
|
|
//
|
|
|
|
strcpy( pszRoot, IIS_MD_INSTANCE_ROOT );
|
|
tmpRoot = (PCHAR)pszRoot+sizeof( IIS_MD_INSTANCE_ROOT ) - 1;
|
|
|
|
while ( TRUE ) {
|
|
|
|
PCHAR pszComma;
|
|
|
|
cchRoot = sizeof( pszRoot ) - 1;
|
|
cchDir = sizeof( pszDirectory );
|
|
|
|
err = RegEnumValue( hkeyRoots,
|
|
i++,
|
|
tmpRoot,
|
|
&cchRoot,
|
|
NULL,
|
|
&dwRegType,
|
|
(LPBYTE) pszDirectory,
|
|
&cchDir );
|
|
|
|
if ( err == ERROR_NO_MORE_ITEMS ) {
|
|
break;
|
|
}
|
|
|
|
if ( dwRegType == REG_SZ ) {
|
|
|
|
//
|
|
// The optional user name is kept after the directory.
|
|
// Only used for UNC roots, ignore for others
|
|
//
|
|
|
|
if ( pszUser = strchr( pszDirectory, ',' ) )
|
|
{
|
|
*pszUser = '\0';
|
|
pszUser++;
|
|
} else {
|
|
pszUser = "";
|
|
}
|
|
|
|
//
|
|
// The optional access mask is kept after the user name. It must
|
|
// appear in upper case hex.
|
|
//
|
|
|
|
if ( pszUser && (pszMask = strchr( pszUser, ',' )) ) {
|
|
|
|
*pszMask = '\0';
|
|
pszMask++;
|
|
|
|
dwMask = hextointA( pszMask );
|
|
} else {
|
|
dwMask = VROOT_MASK_READ;
|
|
}
|
|
|
|
//
|
|
// Remove commas from the root
|
|
//
|
|
|
|
pszComma = strchr(tmpRoot, ',');
|
|
if ( pszComma != NULL ) {
|
|
*pszComma = '\0';
|
|
cchRoot--;
|
|
}
|
|
|
|
//
|
|
// Write it out to the metabase
|
|
//
|
|
|
|
cchRoot++;
|
|
|
|
//
|
|
// This is the root
|
|
//
|
|
|
|
if ( !mb.AddObject( pszRoot ) )
|
|
{
|
|
if ( GetLastError() != ERROR_ALREADY_EXISTS )
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT,"AddMetaObject %s failed with %d\n",
|
|
pszRoot, GetLastError() ));
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Set Path
|
|
//
|
|
|
|
mb.SetString( pszRoot,
|
|
MD_VR_PATH,
|
|
IIS_MD_UT_FILE,
|
|
pszDirectory );
|
|
|
|
mb.SetString( pszRoot,
|
|
MD_KEY_TYPE,
|
|
IIS_MD_UT_SERVER,
|
|
"IIsWebVirtualDir" );
|
|
|
|
//
|
|
// Set Username
|
|
//
|
|
|
|
if ( pszUser && *pszUser )
|
|
{
|
|
mb.SetString( pszRoot,
|
|
MD_VR_USERNAME,
|
|
IIS_MD_UT_FILE,
|
|
pszUser );
|
|
}
|
|
|
|
//
|
|
// Set Mask
|
|
//
|
|
|
|
mb.SetDword( pszRoot,
|
|
MD_ACCESS_PERM,
|
|
IIS_MD_UT_FILE,
|
|
dwMask );
|
|
}
|
|
|
|
} // while
|
|
|
|
mb.Close();
|
|
|
|
exit:
|
|
|
|
if ( hkeyRoots != NULL ) {
|
|
RegCloseKey( hkeyRoots );
|
|
}
|
|
|
|
if ( hkey != NULL ) {
|
|
RegCloseKey( hkey );
|
|
}
|
|
|
|
return;
|
|
|
|
} // IIS_SERVER_INSTANCE::PdcHackVRReg2MD
|
|
|
|
|
|
VOID
|
|
IIS_SERVER_INSTANCE::TsMirrorVirtualRoots(
|
|
IN LPINETA_CONFIG_INFO pConfig
|
|
)
|
|
/*++
|
|
Description:
|
|
|
|
Writes the virtual roots specified in the config structure to the
|
|
registry
|
|
|
|
Arguments:
|
|
pConfig - new list of virtual
|
|
|
|
Returns:
|
|
TRUE on success and FALSE if any failure.
|
|
|
|
--*/
|
|
{
|
|
DWORD err;
|
|
HKEY hkey = NULL;
|
|
HKEY hkeyRoots = NULL;
|
|
|
|
DWORD dwDummy;
|
|
LPINET_INFO_VIRTUAL_ROOT_LIST pRootsList;
|
|
DWORD cch;
|
|
DWORD i;
|
|
|
|
DBG_ASSERT(IsDownLevelInstance());
|
|
|
|
pRootsList = pConfig->VirtualRoots;
|
|
|
|
//
|
|
// Write it to the root key
|
|
//
|
|
|
|
err = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
m_Service->QueryRegParamKey(),
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hkey );
|
|
|
|
if ( err != NO_ERROR ) {
|
|
DBGPRINTF(( DBG_CONTEXT, "RegOpenKeyEx for returned error %d\n",err ));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// First delete the key to remove any old values
|
|
//
|
|
|
|
if (err = RegDeleteKey( hkey,
|
|
VIRTUAL_ROOTS_KEY_A ))
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"[TsMirrorVRoots] Unable to remove old values\n"));
|
|
|
|
}
|
|
|
|
if ( err = RegCreateKeyEx( hkey,
|
|
VIRTUAL_ROOTS_KEY_A,
|
|
0,
|
|
NULL,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hkeyRoots,
|
|
&dwDummy ))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Permit empty list
|
|
//
|
|
|
|
if ( pRootsList == NULL ) {
|
|
goto exit;
|
|
}
|
|
|
|
for ( i = 0; i < pRootsList->cEntries; i++ ) {
|
|
|
|
WCHAR achValue[ MAX_PATH + UNLEN + 2 ];
|
|
|
|
cch = _snwprintf( achValue,
|
|
MAX_PATH + UNLEN + 1,
|
|
L"%s,%s,%X",
|
|
pRootsList->aVirtRootEntry[i].pszDirectory,
|
|
pRootsList->aVirtRootEntry[i].pszAccountName,
|
|
pRootsList->aVirtRootEntry[i].dwMask );
|
|
|
|
DBG_ASSERT( cch < sizeof( achValue ) / sizeof(WCHAR) );
|
|
|
|
achValue[ MAX_PATH + UNLEN + 1 ] = L'\0';
|
|
|
|
err = WriteRegistryStringW(hkeyRoots,
|
|
pRootsList->aVirtRootEntry[i].pszRoot,
|
|
achValue,
|
|
(wcslen(achValue) + 1) * sizeof(WCHAR),
|
|
REG_SZ);
|
|
|
|
if ( err != NO_ERROR ) {
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
|
|
if ( hkeyRoots != NULL ) {
|
|
RegCloseKey( hkeyRoots );
|
|
}
|
|
|
|
if ( hkey != NULL ) {
|
|
RegCloseKey( hkey );
|
|
}
|
|
|
|
return;
|
|
|
|
} // IIS_SERVER_INSTANCE::TsMirrorVirtualRoots
|
|
|
|
|
|
VOID
|
|
ClearSentinelEntry(
|
|
IN MB * pMB
|
|
)
|
|
/*++
|
|
Description:
|
|
|
|
Removes the sentinel entry from all VR for this instance
|
|
|
|
Arguments:
|
|
pMD - pointer to metabase helper object that points to the
|
|
instance metadatabase root.
|
|
|
|
Returns:
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
BOOL fGetRoot = TRUE;
|
|
CHAR nameBuf[METADATA_MAX_NAME_LEN+2];
|
|
DWORD i = 0;
|
|
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,"Entering ClearSentinelEntry\n"));
|
|
}
|
|
|
|
while ( TRUE ) {
|
|
|
|
METADATA_RECORD mdRecord;
|
|
|
|
nameBuf[0] = nameBuf[1] = '/';
|
|
|
|
if ( fGetRoot ) {
|
|
|
|
fGetRoot = FALSE;
|
|
nameBuf[2] = '\0';
|
|
|
|
} else {
|
|
|
|
if ( !pMB->EnumObjects( IIS_MD_INSTANCE_ROOT,
|
|
&nameBuf[2],
|
|
i++ ))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Delete sentinel value
|
|
//
|
|
|
|
if ( !pMB->DeleteData( nameBuf,
|
|
MD_VR_UPDATE,
|
|
IIS_MD_UT_FILE,
|
|
DWORD_METADATA
|
|
))
|
|
{
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,"Error %x deleting sentinel from %s\n",
|
|
GetLastError(), nameBuf));
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
|
|
} // ClearSentinelEntry
|
|
|
|
|
|
VOID
|
|
RemoveUnmarkedRoots(
|
|
IN MB * pMB
|
|
)
|
|
/*++
|
|
Description:
|
|
|
|
Removes roots that are not marked by sentinel
|
|
|
|
Arguments:
|
|
pMD - pointer to metabase helper object that points to the
|
|
instance metadatabase root.
|
|
|
|
Returns:
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
BOOL fGetRoot = TRUE;
|
|
CHAR nameBuf[METADATA_MAX_NAME_LEN+2];
|
|
CHAR szDirectory[MAX_PATH+1];
|
|
DWORD cb;
|
|
DWORD i = 0;
|
|
BOOL fProcessingRoot;
|
|
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,"Entering RemoveUnmarkedRoots\n"));
|
|
}
|
|
|
|
while ( TRUE ) {
|
|
|
|
if ( fGetRoot ) {
|
|
|
|
strcpy( nameBuf, IIS_MD_INSTANCE_ROOT );
|
|
fProcessingRoot = TRUE;
|
|
fGetRoot = FALSE;
|
|
|
|
} else {
|
|
|
|
strcpy( nameBuf, IIS_MD_INSTANCE_ROOT "/" );
|
|
|
|
|
|
fProcessingRoot = FALSE;
|
|
if ( !pMB->EnumObjects( IIS_MD_INSTANCE_ROOT,
|
|
&nameBuf[strlen(nameBuf)],
|
|
i++ ))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Delete sentinel value. If delete successful, leave alone
|
|
//
|
|
|
|
if ( pMB->DeleteData( nameBuf,
|
|
MD_VR_UPDATE,
|
|
IIS_MD_UT_FILE,
|
|
DWORD_METADATA
|
|
))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,"Error %x deleting sentinel from %s\n",
|
|
GetLastError(), nameBuf));
|
|
}
|
|
|
|
//
|
|
// See if it has the path parameter
|
|
//
|
|
|
|
cb = sizeof( szDirectory );
|
|
|
|
if ( !pMB->GetString( nameBuf,
|
|
MD_VR_PATH,
|
|
IIS_MD_UT_FILE,
|
|
szDirectory,
|
|
&cb,
|
|
0 ))
|
|
{
|
|
//
|
|
// Not a VR
|
|
//
|
|
|
|
DBGPRINTF((DBG_CONTEXT,
|
|
"Error %x reading path from %s. Not a VR.\n",
|
|
GetLastError(), nameBuf));
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Unmarked, delete the VR
|
|
//
|
|
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,"Deleting vroot %s[%d]\n",
|
|
nameBuf, fGetRoot));
|
|
}
|
|
|
|
if ( fProcessingRoot ) {
|
|
|
|
//
|
|
// if this is the root, just remove the path. Deleting the
|
|
// root is a potentially dangerous undertaking!
|
|
//
|
|
|
|
if ( !pMB->DeleteData( nameBuf,
|
|
MD_VR_PATH,
|
|
IIS_MD_UT_FILE,
|
|
STRING_METADATA
|
|
))
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT,"Error %x deleting root path\n",
|
|
GetLastError()));
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Delete the Vroot
|
|
//
|
|
|
|
if ( !pMB->DeleteObject( nameBuf ) )
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT,"Error %x deleting %s\n",
|
|
GetLastError(), nameBuf));
|
|
|
|
} else {
|
|
|
|
//
|
|
// the delete moved the index back by 1
|
|
//
|
|
|
|
DBG_ASSERT( i != 0 );
|
|
|
|
--i;
|
|
|
|
}
|
|
}
|
|
|
|
fGetRoot = FALSE;
|
|
}
|
|
|
|
return;
|
|
|
|
} // RemoveUnmarkedRoots
|
|
|
|
|
|
BOOL
|
|
ReadVrootConfig(
|
|
LPVOID pvMB,
|
|
LPSTR szVRPath,
|
|
LPSTR szDirectory,
|
|
DWORD cbDirectory,
|
|
LPSTR szUser,
|
|
DWORD cbUser,
|
|
LPSTR szPassword,
|
|
DWORD cbPassword,
|
|
DWORD *pdwMask,
|
|
BOOL *pfDoCache
|
|
)
|
|
{
|
|
|
|
DWORD cb;
|
|
DWORD dwNoCache = 0;
|
|
|
|
MB* pMB = (MB*)pvMB;
|
|
|
|
//
|
|
// Get Directory path
|
|
//
|
|
|
|
cb = cbDirectory;
|
|
|
|
if ( !pMB->GetString( szVRPath,
|
|
MD_VR_PATH,
|
|
IIS_MD_UT_FILE,
|
|
szDirectory,
|
|
&cb,
|
|
0 ))
|
|
{
|
|
#if DBG
|
|
if ( GetLastError() != MD_ERROR_DATA_NOT_FOUND )
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT,"Error %x reading path from %s. Not a VR.\n",
|
|
GetLastError(), szVRPath));
|
|
}
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Get mask
|
|
//
|
|
|
|
if ( !pMB->GetDword( szVRPath,
|
|
MD_ACCESS_PERM,
|
|
IIS_MD_UT_FILE,
|
|
pdwMask,
|
|
0))
|
|
{
|
|
*pdwMask = VROOT_MASK_READ;
|
|
|
|
IF_DEBUG(ERROR) {
|
|
DBGPRINTF((DBG_CONTEXT,"Error %x reading mask from %s\n",
|
|
GetLastError(), szVRPath));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get username
|
|
//
|
|
|
|
cb = cbUser;
|
|
|
|
if ( !pMB->GetString( szVRPath,
|
|
MD_VR_USERNAME,
|
|
IIS_MD_UT_FILE,
|
|
szUser,
|
|
&cb,
|
|
0))
|
|
{
|
|
szUser[0] = '\0';
|
|
}
|
|
|
|
IF_DEBUG(METABASE) {
|
|
DBGPRINTF((DBG_CONTEXT,"Read %s: Path[%s] User[%s] Mask[%d]\n",
|
|
szVRPath, szDirectory, szUser, *pdwMask));
|
|
}
|
|
|
|
if ( (szUser[0] != '\0') &&
|
|
(szDirectory[0] == '\\') && (szDirectory[1] == '\\') ) {
|
|
|
|
cb = cbPassword;
|
|
|
|
//
|
|
// Retrieve the password for this address/share
|
|
//
|
|
|
|
if ( !pMB->GetString( szVRPath,
|
|
MD_VR_PASSWORD,
|
|
IIS_MD_UT_FILE,
|
|
szPassword,
|
|
&cb,
|
|
METADATA_SECURE))
|
|
{
|
|
szPassword[0] = '\0';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
szPassword[0] = '\0';
|
|
}
|
|
|
|
//
|
|
// Should we cache this vdir
|
|
//
|
|
|
|
pMB->GetDword( szVRPath,
|
|
MD_VR_NO_CACHE,
|
|
IIS_MD_UT_FILE,
|
|
&dwNoCache,
|
|
0 );
|
|
|
|
*pfDoCache = !dwNoCache;
|
|
|
|
return TRUE;
|
|
}
|
|
|