Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

682 lines
16 KiB

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name :
virtroot.cxx
Abstract:
This module defines functions for managing virtual roots.
Author:
??? ( ???) ??-??-1994/5
Environment:
User Mode -- Win32
Project:
TSunami DLL for Internet Services
Functions Exported:
Revision History:
MuraliK Added File System type to information stored about
each virtual root.
MuraliK Modified TsLookupVirtualRoot() to support variable
length buffer and hence check for invalid writes
MuraliK 22-Jan-1996 Cache & return UNC virtual root impersonation
token.
MCourage 05-Jan-1997 Moved to cache2 directory for cache rewrite
SaurabN 07-Oct-1998 Reimplement using LKRHash.
--*/
/************************************************************
* Include Headers
************************************************************/
#include <tsunami.hxx>
#include "TsunamiP.Hxx"
#pragma hdrstop
#include <mbstring.h>
#include <rpc.h>
#include <rpcndr.h>
#include "dbgutil.h"
#include <string.h>
#include <refb.hxx>
#include <imd.h>
#include <mb.hxx>
#include <iiscnfg.h>
#include <malloc.h>
extern TCHAR * FlipSlashes( TCHAR * pszPath );
IIS_VROOT_TABLE::IIS_VROOT_TABLE(
VOID
)
:
CLKRHashTable("IISVRootTable",
ExtractKey,
CalcKeyHash,
EqualKeys,
AddRefRecord,
DFLT_LK_INITSIZE,
LK_SMALL_TABLESIZE),
m_nVroots (0 )
{
} // IIS_VROOT_TABLE::IIS_VROOT_TABLE
IIS_VROOT_TABLE::~IIS_VROOT_TABLE(
VOID
)
{
RemoveVirtualRoots( );
DBG_ASSERT( m_nVroots == 0 );
} // IIS_VROOT_TABLE::~IIS_VROOT_TABLE
BOOL
IIS_VROOT_TABLE::AddVirtualRoot(
PCHAR pszRoot,
PCHAR pszDirectory,
DWORD dwAccessMask,
PCHAR pszAccountName,
HANDLE hImpersonationToken,
DWORD dwFileSystem,
BOOL fDoCache
)
/*++
Description:
This function adds a symbolic link root and directory mapping
part to the virtual root list
We always strip trailing slashes from the root and directory name.
If the root is "\" or "/", then the effective root will be zero
length and will always be placed last in the list. Thus if a lookup
can't find a match, it will always match the last entry.
Arguments:
pszRoot - Virtual symbolic link root
pszDirectory - Physical directory
dwAccessMask - Type of access allowed on this virtual root
pszAccountName - User name to impersonate if UNC (only gets stored
for RPC apis)
hImpersonationToken - Impersonation token to use for UNC
directory paths
dwFileSystem - DWORD containing the file system type
( symbolic constant)
fDoCache - Should we cache the vdir
Returns:
TRUE on success and FALSE if any failure.
--*/
{
PVIRTUAL_ROOT_MAPPING pVrm, pVrmOld;
PLIST_ENTRY pEntry;
BOOL fRet = FALSE;
BOOL fUNC;
DWORD cchRoot;
BOOL fAllowEmptyDirectory = !!(dwAccessMask & VROOT_MASK_NO_PHYSICAL_DIR);
if ( !pszRoot || !pszDirectory || (!*pszDirectory && !fAllowEmptyDirectory) )
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
if (!*pszDirectory)
{
fDoCache = FALSE;
}
//
// Disallow allow UNC roots if we don't have an impersonation token and
// this isn't a placeholder
//
fUNC = (BOOL)((pszDirectory[0] == '\\') && (pszDirectory[1] == '\\'));
//
// Strip the trailing '/' from the virtual root
//
cchRoot = strlen( pszRoot );
if ( IS_CHAR_TERM_A( pszRoot, cchRoot - 1))
{
pszRoot[--cchRoot] = '\0';
}
//
// Look in the current list and see if the root is already there.
// If the directory is the same, we just return success. If the
// directory is different, we remove the old item and add the new one.
//
LockShared();
if (LK_SUCCESS == FindKey((DWORD_PTR) pszRoot, (const void **)&pVrm))
{
//
// Key exists
//
if ( !lstrcmpi( pszDirectory, pVrm->pszDirectoryA ) &&
((*pszDirectory == '\0') ||
IS_CHAR_TERM_A( pszDirectory, pVrm->cchDirectoryA ) ))
{
//
// This root is already in the list
//
Unlock();
return TRUE;
}
else
{
//
// A root is having its directory entry changed
//
Unlock();
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
}
//
// Add a new key
//
pVrm = ( PVIRTUAL_ROOT_MAPPING )ALLOC( sizeof( VIRTUAL_ROOT_MAPPING ) );
if ( pVrm == NULL )
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
Unlock();
return FALSE;
}
//
// Initialize the new root item
//
pVrm->Signature = VIRT_ROOT_SIGNATURE;
pVrm->cchRootA = strlen( pszRoot );
if (pVrm->cchRootA > MAX_LENGTH_VIRTUAL_ROOT)
{
SetLastError( ERROR_BAD_PATHNAME );
Unlock();
return FALSE;
}
pVrm->cchDirectoryA = strlen( pszDirectory );
if (pVrm->cchDirectoryA > MAX_PATH)
{
SetLastError( ERROR_BAD_PATHNAME );
Unlock();
return FALSE;
}
pVrm->dwFileSystem = dwFileSystem;
pVrm->dwAccessMask = dwAccessMask;
pVrm->fUNC = (BOOLEAN)fUNC;
pVrm->hImpersonationToken = hImpersonationToken;
//
// The old cache design used APCs to do change notification, the new cache
// uses the CDirMon class so we don't need any refcounting.
//
strcpy( pVrm->pszRootA, pszRoot );
strcpy( pVrm->pszDirectoryA, pszDirectory );
strcpy( pVrm->pszAccountName, pszAccountName ? pszAccountName : "" );
//
// Strip trailing slashes from the root and directory
//
if ( (pVrm->cchRootA != 0) &&
IS_CHAR_TERM_A( pVrm->pszRootA, pVrm->cchRootA - 1 ))
{
pVrm->pszRootA[--pVrm->cchRootA] = '\0';
}
if ( (pVrm->cchDirectoryA > 0) &&
IS_CHAR_TERM_A( pVrm->pszDirectoryA, pVrm->cchDirectoryA - 1))
{
//
// Note we assume virtual directories always begin with a '/...' to
// provide the necessary path separator between the root directory
// path and the remaining virtual directory
//
pVrm->pszDirectoryA[--pVrm->cchDirectoryA] = '\0';
}
//
// Add the item to the list
//
LockConvertExclusive();
fRet = (LK_SUCCESS == InsertRecord(pVrm));
if (fRet)
{
fRet = fDoCache ? DcmAddRoot( pVrm ) : TRUE;
if (!fRet)
{
DeleteRecord(pVrm);
}
}
if ( fRet)
{
m_nVroots++;
IF_DEBUG( VIRTUAL_ROOTS )
DBGPRINTF(( DBG_CONTEXT,
"Successfully added Vroot - %s => %s\n",
pVrm->pszRootA,
pVrm->pszDirectoryA ));
}
else
{
FREE( pVrm );
/*
//
// this memory was already released!
//
DBGPRINTF(( DBG_CONTEXT,
" Error %d adding Vroot - %s => %s\n",
GetLastError(),
pVrm->pszRootA,
pVrm->pszDirectoryA ));
*/
}
Unlock();
return fRet;
} // IIS_VROOT_TABLE::AddVirtualRoot
BOOL
IIS_VROOT_TABLE::LookupVirtualRoot(
IN const CHAR * pszVirtPath,
OUT CHAR * pszDirectory,
IN OUT LPDWORD lpcbSize,
OUT LPDWORD lpdwAccessMask, // Optional
OUT LPDWORD pcchDirRoot, // Optional
OUT LPDWORD pcchVRoot, // Optional
OUT HANDLE * phImpersonationToken, // Optional
OUT LPDWORD lpdwFileSystem // Optional
)
/*++
Description:
This function looks in the map list for the specified root
and returns the corresponding directory
Arguments:
pszVirtPath - Virtual symbolic link path
pszDirectory - receives Physical directory.
This is of the size specified by lpcbSize
lpcbSize - pointer to DWORD containing the size of buffer pszDirectory
On retur contains the number of bytes written
lpdwAccessMask - The access mask for this root
pcchDirRoot - Number of characters of the directory this virtual
root maps to (i.e., /foo/ ==> c:\root, lookup "/foo/bar/abc.htm"
this value returns the length of "c:\root")
pcchVRoot - Number of characters that made up the found virtual root
(i.e., returns the lenght of "/foo/")
phImpersonationToken - pointer to handle object that will contain
the handle to be used for impersonation for UNC/secure virtual roots
lpdwFileSystem - on successful return will contain the file system
type for the directory matched with root specified.
Returns:
TRUE on success and FALSE if any failure.
History:
MuraliK 28-Apr-1995 Improved robustness
MuraliK 18-Jan-1996 Support imperonstaion token
Note:
This function is growing in the number of parameters returned.
Maybe we should expose the VIRTUAL_ROOT_MAPPING structure
and return a pointer to this object and allow the callers to
extract all required pieces of data.
--*/
{
DWORD dwError = NO_ERROR;
PVIRTUAL_ROOT_MAPPING pVrm = NULL;
DBG_ASSERT( pszDirectory != NULL);
DBG_ASSERT( lpcbSize != NULL);
DWORD cchPath = strlen( pszVirtPath );
char * pszPath = (char *)_alloca(cchPath); // make local copy that we can modify
strcpy(pszPath, pszVirtPath);
//
// Strip the trailing '/' from the virtual path
//
if ( IS_CHAR_TERM_A( pszPath, cchPath - 1))
{
pszPath[--cchPath] = '\0';
}
char * pCh = pszPath;
LockShared();
while(pCh != NULL)
{
if (LK_SUCCESS == FindKey((DWORD_PTR) pszPath, (const void **)&pVrm))
{
break;
}
else
{
//
// Trim the VRoot path from the right to the next /
//
pCh = (char *)IISstrrchr( (const UCHAR *)pszPath, '/');
if (pCh)
{
*pCh = '\0'; // truncate search string
}
}
}
if (pVrm)
{
//
// we found a match. return all requested parameters.
//
DBG_ASSERT( pVrm->Signature == VIRT_ROOT_SIGNATURE );
DWORD cbReqd = ( pVrm->cchDirectoryA +
strlen(pszVirtPath + pVrm->cchRootA));
if ( cbReqd <= *lpcbSize)
{
PCHAR pathStart = pszDirectory + pVrm->cchDirectoryA;
//
// Copy the physical directory base then append the rest of
// the non-matching virtual path
//
CopyMemory(
pszDirectory,
pVrm->pszDirectoryA,
pVrm->cchDirectoryA
);
strcpy( pathStart,
pszVirtPath + pVrm->cchRootA );
if ( lpdwFileSystem != NULL) {
*lpdwFileSystem = pVrm->dwFileSystem;
}
if ( pcchDirRoot ) {
*pcchDirRoot = pVrm->cchDirectoryA;
}
if ( pcchVRoot ) {
*pcchVRoot = pVrm->cchRootA;
}
if ( lpdwAccessMask != NULL) {
*lpdwAccessMask = pVrm->dwAccessMask;
}
if ( phImpersonationToken != NULL) {
// Should we increment refcount of the impersonation token?
*phImpersonationToken = pVrm->hImpersonationToken;
}
Unlock();
FlipSlashes( pathStart );
*lpcbSize = cbReqd;
return(TRUE);
} else {
dwError = ERROR_INSUFFICIENT_BUFFER;
}
*lpcbSize = cbReqd;
}
if ( lpdwAccessMask ) {
*lpdwAccessMask = 0;
}
if ( lpdwFileSystem != NULL) {
*lpdwFileSystem = FS_ERROR;
}
if ( phImpersonationToken != NULL) {
*phImpersonationToken = NULL;
}
if ( dwError == NO_ERROR) {
dwError = ERROR_PATH_NOT_FOUND;
}
SetLastError( dwError );
Unlock();
return FALSE;
} // IIS_VROOT_TABLE::LookupVirtualRoot
BOOL
IIS_VROOT_TABLE::RemoveVirtualRoots(
VOID
)
/*++
Description:
Removes all of the virtual roots for the instance
Arguments:
None.
Returns:
TRUE on success and FALSE if any failure.
--*/
{
PVIRTUAL_ROOT_MAPPING pVrm;
CIterator iter;
DWORD dwValue;
LockExclusive();
LK_RETCODE lkrc = InitializeIterator(&iter);
while (LK_SUCCESS == lkrc)
{
pVrm = (PVIRTUAL_ROOT_MAPPING) iter.Record();
DBG_ASSERT( pVrm->Signature == VIRT_ROOT_SIGNATURE );
//
// Increment the iterator before removing the record from the Hash
// Table else we hit an Assert in the increment.
//
lkrc = IncrementIterator(&iter);
DeleteVRootEntry(pVrm); // Removes from Hash Table Also
}
CloseIterator(&iter);
Clear();
Unlock();
return TRUE;
} // TsRemoveVirtualRoots
BOOL
IIS_VROOT_TABLE::RemoveVirtualRoot(
IN PCHAR pszVirtPath
)
/*++
Description:
Removes the virtual roots named pszVirtPath for the instance.
Arguments:
pszVirtPath - Name of the virtual root to remove.
Returns:
TRUE on success and FALSE if any failure.
--*/
{
PVIRTUAL_ROOT_MAPPING pVrm;
BOOL bSuccess = FALSE;
DWORD cchPath = strlen( pszVirtPath );
//
// Strip the trailing '/' from the virtual path
//
if ( IS_CHAR_TERM_A( pszVirtPath, cchPath - 1))
{
pszVirtPath[--cchPath] = '\0';
}
LockExclusive();
if (LK_SUCCESS == FindKey((DWORD_PTR) pszVirtPath, (const void **)&pVrm))
{
//
// Found a match
//
DeleteRecord(pVrm); // Remove Entry from Hash Table
DeleteVRootEntry(pVrm);
bSuccess = TRUE;
}
Unlock();
return bSuccess;
}
VOID
IIS_VROOT_TABLE::DeleteVRootEntry(
IN PVOID pEntry
)
{
DBG_ASSERT(NULL != pEntry);
PVIRTUAL_ROOT_MAPPING pVrm = (PVIRTUAL_ROOT_MAPPING)pEntry;
DBG_ASSERT(pVrm->Signature == VIRT_ROOT_SIGNATURE );
m_nVroots--;
IF_DEBUG( DIRECTORY_CHANGE )
DBGPRINTF(( DBG_CONTEXT,
"Removing root %s\n",
pVrm->pszDirectoryA ));
//
// Remove reference to Dir Monitor
//
DcmRemoveRoot( pVrm );
//
// We need to close the impersonation token, if one exists.
//
if ( pVrm->hImpersonationToken != NULL)
{
DBG_REQUIRE( CloseHandle( pVrm->hImpersonationToken ));
pVrm->hImpersonationToken = NULL;
}
pVrm->Signature = 0;
FREE( pVrm );
}
const DWORD_PTR
IIS_VROOT_TABLE::ExtractKey(const void* pvRecord)
{
PVIRTUAL_ROOT_MAPPING pVrm = (PVIRTUAL_ROOT_MAPPING)pvRecord;
return (DWORD_PTR)pVrm->pszRootA;
}
DWORD
IIS_VROOT_TABLE::CalcKeyHash(const DWORD_PTR pnKey)
{
return HashStringNoCase((LPCSTR)pnKey);
}
bool
IIS_VROOT_TABLE::EqualKeys(const DWORD_PTR pnKey1, const DWORD_PTR pnKey2)
{
return ( IISstricmp((UCHAR *)pnKey1, (UCHAR *)pnKey2) == 0);
}