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.
 
 
 
 
 
 

1879 lines
49 KiB

//*************************************************************
//
// Copyright (c) Microsoft Corporation 1999 - 2000
// All rights reserved
//
// log.cxx
//
// Contains definitions for classes related to rsop logging
// for the folder redirection client-side extension
//
// Created: 8-01-1999 adamed
//
//*************************************************************
#include "fdeploy.hxx"
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionPolicy::CRedirectionPolicy
//
// Purpose: Constructor for CRedirectionPlicy
//
// Params:
// pGpoData -- structure containing information
// from the gpo
// pRdirect -- structure containing redireciton information
// Precedence -- the precedence this redirection candidate
// should have. Lower values are least signifcant, higher
// values have higher precedence.
//
// Return value: none
//
// Notes: This constructor allocates memory and performs
// other complex operations -- if it fails,
// this fact is tracked internally and operations on the
// object will fail as well with the error code
//
//------------------------------------------------------------
CRedirectionPolicy::CRedirectionPolicy(
CFileDB* pGpoData,
CRedirectInfo* pRedirect,
LONG Precedence,
HRESULT* phr) :
_rgwszGroups(NULL),
_rgwszRedirectedPaths(NULL),
_cGroups(0),
_Precedence(Precedence),
_dwFlags(pRedirect->m_dwFlags),
_wszDisplayName(NULL),
_wszLocalizedName(NULL),
_wszGPODSPath(NULL),
_wszSOMId(NULL),
_pNext(NULL),
_iFolderIndex(pRedirect->m_rID),
_iAncestorIndex(0),
_bHasAncestor(FALSE),
_pGpoData( pGpoData ),
_bMissingAncestor( FALSE ),
_wszRedirectedPath( NULL )
{
RtlInitUnicodeString( &_RedirectedSid, NULL );
//
// If this folder has a parent folder, remember that fact,
// and record the id of the parent folder
//
if (pRedirect->m_pParent)
{
_iAncestorIndex = pRedirect->m_pParent->m_rID;
_bHasAncestor = TRUE;
}
//
// Retrieve security group / redirected folder information
//
_hrInit = GetGroupInformation(pRedirect->m_szGroupRedirectionData);
if (FAILED(_hrInit))
{
*phr = _hrInit;
return;
}
//
// Copy the gpo's ds path for use as a gpo id -- we want only the part
// of the path after the link prefix and user or computer container
//
WCHAR* wszGPOPrefixEnd;
wszGPOPrefixEnd = wcschr( StripLinkPrefix( pGpoData->_pwszGPODSPath ), L',' );
//
// At this point, we are one charcter in front of the gpo container --
// copy everything after this position
//
if ( wszGPOPrefixEnd )
{
_wszGPODSPath = StringDuplicate( wszGPOPrefixEnd + 1 );
}
if ( ! _wszGPODSPath )
{
goto exit_on_memory_allocation_failure;
}
//
// Copy the scope of management path and use it as an id,
// copying only the path after the ds prefix
//
_wszSOMId = StringDuplicate( StripLinkPrefix(pGpoData->_pwszGPOSOMPath) );
if ( ! _wszSOMId )
{
goto exit_on_memory_allocation_failure;
}
//
// Copy the friendly name of the redirected folder
//
_wszDisplayName = StringDuplicate(pRedirect->m_szDisplayName);
if ( ! _wszDisplayName )
{
goto exit_on_memory_allocation_failure;
}
//
// Copy the localized file system name of the folder
//
_wszLocalizedName = StringDuplicate(pRedirect->m_szLocDisplayName);
if ( ! _wszLocalizedName )
{
goto exit_on_memory_allocation_failure;
}
//
// Copy the redirected sid in string format -- the sid
// will not be present if this folder inherits from the parent,
// so do not copy it in that case -- this will be dealt with later
// when the final parent is known.
//
if ( pRedirect->m_pSid )
{
NTSTATUS Status;
//
// Copy the path to which this folder is redirected
//
_wszRedirectedPath = StringDuplicate( _rgwszRedirectedPaths[ pRedirect->m_iRedirectingGroup ] );
if ( ! _wszRedirectedPath )
{
goto exit_on_memory_allocation_failure;
}
Status = RtlConvertSidToUnicodeString(
&_RedirectedSid,
pRedirect->m_pSid,
TRUE);
if (STATUS_SUCCESS != Status)
{
LONG Error;
Error = RtlNtStatusToDosError(Status);
_hrInit = HRESULT_FROM_WIN32(Error);
}
else
{
_hrInit = S_OK;
}
}
*phr = _hrInit;
return;
exit_on_memory_allocation_failure:
//
// Set our internal state to error so that methods
// know that our internal state is bad and will fail
// safely
//
_hrInit = E_OUTOFMEMORY;
*phr = _hrInit;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionPolicy::~CRedirectionPolicy
//
// Purpose: Destructor for CRedirectionPolicy. Frees resources
// allocated by this object
//
// Params: none
//
// Return value: none
//
// Notes:
//
//------------------------------------------------------------
CRedirectionPolicy::~CRedirectionPolicy()
{
LONG iGroup;
//
// Iterate through the groups / paths strings
// and destroy each one
//
for (iGroup = 0; iGroup < _cGroups; iGroup++)
{
delete [] _rgwszGroups[iGroup];
delete [] _rgwszRedirectedPaths[iGroup];
}
//
// Free all the other allocated strings
//
delete [] _rgwszGroups;
delete [] _rgwszRedirectedPaths;
delete [] _wszGPODSPath;
delete [] _wszSOMId;
delete [] _wszDisplayName;
delete [] _wszLocalizedName;
delete [] _wszRedirectedPath;
RtlFreeUnicodeString(&_RedirectedSid);
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionPolicy::Write
//
// Purpose: implementation of pure virtual Write method required
// by all policy records. It writes policy information
// for the redirection candidate to the log in the database
//
// Params: none
//
// Return value: S_OK if successful, error otherwise
//
// Notes:
//
//------------------------------------------------------------
HRESULT CRedirectionPolicy::Write()
{
HRESULT hr;
//
// Set the unique id
//
hr = SetValue(
RSOP_ATTRIBUTE_ID,
_wszDisplayName);
REPORT_ATTRIBUTE_SET_STATUS( RSOP_ATTRIBUTE_ID, hr )
//
// If we cannot make a unique id, we must exit because this is a key
//
if (FAILED(hr))
{
DebugMsg((DM_VERBOSE, IDS_RSOP_ATTEMPT_WRITE, _wszDisplayName));
return hr;
}
//
// Set the precedence for the setting -- this is also a key
// so we must exit if we cannot set this
//
hr = SetValue(
RSOP_ATTRIBUTE_PRECEDENCE,
_Precedence);
REPORT_ATTRIBUTE_SET_STATUS( RSOP_ATTRIBUTE_PRECEDENCE, hr )
if (FAILED(hr))
{
return hr;
}
//
// Set the time stamp on the record
//
{
SYSTEMTIME CurrentTime;
//
// This does not fail
//
GetSystemTime( &CurrentTime );
hr = SetValue(
RSOP_ATTRIBUTE_CREATIONTIME,
&CurrentTime);
REPORT_ATTRIBUTE_SET_STATUS( RSOP_ATTRIBUTE_CREATIONTIME, hr );
}
//
// Set the installationtype -- basic or advanced in the UI
//
{
LONG InstallationType;
if ( _dwFlags & REDIR_SCALEABLE )
{
InstallationType = RDR_ATTRIBUTE_INSTALLATIONTYPE_VALUE_MAX;
}
else
{
InstallationType = RDR_ATTRIBUTE_INSTALLATIONTYPE_VALUE_BASIC;
}
hr = SetValue(
RDR_ATTRIBUTE_INSTALLATIONTYPE,
InstallationType);
REPORT_ATTRIBUTE_SET_STATUS( RDR_ATTRIBUTE_INSTALLATIONTYPE, hr )
}
//
// Set unique id for the gpo
//
hr = SetValue(
RSOP_ATTRIBUTE_GPOID,
_wszGPODSPath);
REPORT_ATTRIBUTE_SET_STATUS( RSOP_ATTRIBUTE_GPOID, hr )
//
// Set the friendly name of the redirected folder
//
hr = SetValue(
RSOP_ATTRIBUTE_NAME,
_wszDisplayName);
REPORT_ATTRIBUTE_SET_STATUS( RSOP_ATTRIBUTE_NAME, hr )
//
// Set the scope of management that caused this
// policy to be applied
//
hr = SetValue(
RSOP_ATTRIBUTE_SOMID,
_wszSOMId);
REPORT_ATTRIBUTE_SET_STATUS( RSOP_ATTRIBUTE_SOMID, hr )
//
// The path to which the folder would be redirected
//
if ( ! _pGpoData->GetRsopContext()->IsReportingModeEnabled() )
{
if ( _wszRedirectedPath )
{
hr = SetValue(
RDR_ATTRIBUTE_RESULT,
_wszRedirectedPath);
REPORT_ATTRIBUTE_SET_STATUS( RDR_ATTRIBUTE_RESULT, hr )
}
}
//
// In the case of a child setting with a missing parent, none of the
// other information can be logged, since it cannot be inferred
// from the parent (there is none)
//
//
// Access grant type
//
hr = SetValue(
RDR_ATTRIBUTE_GRANTTYPE,
( ! _bMissingAncestor ) ? (BOOL) (_dwFlags & REDIR_SETACLS) : FALSE);
REPORT_ATTRIBUTE_SET_STATUS( RDR_ATTRIBUTE_GRANTTYPE, hr )
//
// Move Type
//
hr = SetValue(
RDR_ATTRIBUTE_MOVETYPE,
( ! _bMissingAncestor ) ? (BOOL) (_dwFlags & REDIR_MOVE_CONTENTS) : FALSE);
REPORT_ATTRIBUTE_SET_STATUS( RDR_ATTRIBUTE_MOVETYPE, hr )
WCHAR* wszDefaultGroup = EVERYONE_WELLKNOWN_SID;
//
// Redirecting group
//
if ( ! _pGpoData->GetRsopContext()->IsReportingModeEnabled() )
{
hr = SetValue(
RDR_ATTRIBUTE_REDIRECTING_GROUP,
( ! _bMissingAncestor ) ? _RedirectedSid.Buffer : wszDefaultGroup );
REPORT_ATTRIBUTE_SET_STATUS( RDR_ATTRIBUTE_REDIRECTING_GROUP, hr )
}
//
// List of security groups
//
hr = SetValue(
RDR_ATTRIBUTE_GROUPS,
( ! _bMissingAncestor ) ? _rgwszGroups : &wszDefaultGroup,
( ! _bMissingAncestor ) ? _cGroups : 1);
REPORT_ATTRIBUTE_SET_STATUS( RDR_ATTRIBUTE_GROUPS, hr )
//
// In the case of a child setting with a missing parent, we must
// generate the resultant path from local state since policy has
// not redirected the parent
//
//
// List of redirected paths parallel to the security group list
//
if ( ! _bMissingAncestor )
{
hr = SetValue(
RDR_ATTRIBUTE_PATHS,
_rgwszRedirectedPaths,
_cGroups);
REPORT_ATTRIBUTE_SET_STATUS( RDR_ATTRIBUTE_PATHS, hr )
}
else if ( ! _pGpoData->GetRsopContext()->IsReportingModeEnabled() )
{
WCHAR* wszLocalInheritedPath;
wszLocalInheritedPath = NULL;
//
// If this folder is set to follow its ancestor but no ancestor
// was specified, we can still set the resulting path by
// looking at the path to which we are redirected
//
hr = GenerateLocalInheritedPath(
&wszLocalInheritedPath);
if ( SUCCEEDED( hr ) )
{
hr = SetValue(
RDR_ATTRIBUTE_RESULT,
_rgwszGroups,
_cGroups);
REPORT_ATTRIBUTE_SET_STATUS( RDR_ATTRIBUTE_RESULT, hr )
hr = SetValue(
RDR_ATTRIBUTE_PATHS,
&wszLocalInheritedPath,
1);
REPORT_ATTRIBUTE_SET_STATUS( RDR_ATTRIBUTE_PATHS, hr )
}
}
//
// Policy Removal
//
hr = SetValue(
RDR_ATTRIBUTE_POLICYREMOVAL,
(_dwFlags & REDIR_RELOCATEONREMOVE) ?
RDR_ATTRIBUTE_POLICYREMOVAL_VALUE_REDIRECT :
RDR_ATTRIBUTE_POLICYREMOVAL_VALUE_REMAIN);
REPORT_ATTRIBUTE_SET_STATUS( RDR_ATTRIBUTE_POLICYREMOVAL, hr )
return S_OK;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionPolicy::GetGroupInformation
//
// Purpose: Gets gorup information from the redirection ini
// file data concerning the list of security groups and
// the redirected folder for each group
//
// Params: wszGroupRedirectionData -- this data was retrieved
// from an ini file and contains group and folder lists
//
// Return value: S_OK if successful, error otherwise
//
// Notes:
//
//------------------------------------------------------------
HRESULT CRedirectionPolicy::GetGroupInformation(
WCHAR* wszGroupRedirectionData)
{
HRESULT hr;
//
// First, parse the file in order to count the groups. No
// memory allocation is done when counting, so this should
// always succeed
//
hr = ParseGroupInformation(
wszGroupRedirectionData,
&_cGroups);
ASSERT(S_OK == hr);
//
// Allocate space for references to each group and folder
// based on the count returned above
//
_rgwszGroups = new WCHAR* [_cGroups];
_rgwszRedirectedPaths = new WCHAR* [_cGroups];
if (!_rgwszGroups || !_rgwszRedirectedPaths)
{
return E_OUTOFMEMORY;
}
//
// Initialize newly allocated references
//
RtlZeroMemory(_rgwszGroups, sizeof(*_rgwszGroups) * _cGroups);
RtlZeroMemory(_rgwszRedirectedPaths, sizeof(*_rgwszRedirectedPaths) * _cGroups);
//
// Now perform the actual copy of parsed information. Note that this
// will allocate space for strings for each folder and group and
// set our vectors of references to refer to those strings. An out of
// memory error could occur here, so we return any error we get
//
hr = ParseGroupInformation(
wszGroupRedirectionData,
&_cGroups,
_rgwszGroups,
_rgwszRedirectedPaths);
return hr;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionPolicy::ParseGroupInformation
//
// Purpose: parses the redirection ini file data to retrieve
// the list of security groups and the redirected folder for
// each group
//
// Params:
// wszGroupRedirectionData -- this data was retrieved
// from an ini file and contains group and folder lists. IMPORTANT : This data
// is distructive in the sence that the data is changed by this function.
// pCount -- in, out param indicating # of groups / paths to retrieve.
// on output, only has meaning if the folder and group arrays
// are not specified -- in this case, it contains the count
// of groups / paths so you can determine how many exist
// before allocation.
// rgwszGroups -- on input, contains an array of pointers
// to c-strings. If NULL, only a count of groups / paths
// is performed and there is no output.
// On output, an allocation is made and data is copied
// for each group. Each entry in the array
// will be set to point to the appropriate allocated
// string
// rgwszPaths -- similar to above, except for target paths
//
// Return value: S_OK if successful, error otherwise
//
// Notes: IMPORTANT: rgwszGroups and rgwszPaths are parallel
// arrays and should be accessed as such.
// In the case of partial allocations below due to out of memory,
// allocated memory is cleared by the destructor.
// The basic algorithm for the parsing is taken from another location
// in this extension -- if that changes, so must this.
//
// Current data format:
//
// <group-sid1>=<redirected-filesyspath1><String terminator \0>
// <group-sid2>=<redirected-filesyspath2><String terminator \0>
// <group-sid3>=<redirected-filesyspath3><String terminator \0><String terminator \0>
// ...
//
//------------------------------------------------------------
HRESULT CRedirectionPolicy::ParseGroupInformation(
WCHAR* wszGroupRedirectionData,
LONG* pCount,
WCHAR** rgwszGroups,
WCHAR** rgwszPaths)
{
WCHAR* wszCurrent;
DWORD cchCurrent;
DWORD cGroups;
HRESULT hr;
//
// Init locals
//
cGroups = 0;
hr = S_OK;
//
// First, find out how many paths there are, and separate
// the path entry into its constituents
//
wszCurrent = wszGroupRedirectionData;
if (wszCurrent)
{
//
// Move through the data
//
for (wszCurrent;
*wszCurrent;
wszCurrent += cchCurrent)
{
WCHAR* wszPath;
//
// Find out the length of the current entry
//
cchCurrent = lstrlen(wszCurrent) + 1;
//
// Get the path so we can validate it
//
wszPath = wcschr(wszCurrent, L'=');
//
// If no path is specified, this is an invalid entry
//
if (!wszPath)
{
continue;
}
//
// Terminate the pathname, but only if we're doing copying
//
if (rgwszGroups)
{
*wszPath = L'\0';
}
//
// Advance to the path past the delimiter
//
wszPath++;
//
// A blank path -- skip this
//
if (!*wszPath)
{
continue;
}
//
// If the group array is specified, we need to copy the
// group and folder information, not just count groups / paths
//
if (rgwszGroups)
{
DWORD Status;
//
// Copy this group
//
rgwszGroups[cGroups] = StringDuplicate(wszCurrent);
if ( ! rgwszGroups[cGroups] )
{
hr = E_OUTOFMEMORY;
break;
}
//
// Copy this path
//
Status = GetExpandedPath(
_pGpoData,
wszPath,
_iFolderIndex,
_bHasAncestor,
&(rgwszPaths[cGroups]));
//
// In planning mode, we may get an empty string for a
// path if an environment variable cannot be generated,
// so we check for that case here and simulate the error
//
if ( _pGpoData->GetRsopContext()->IsPlanningModeEnabled() &&
( ERROR_SUCCESS == Status ) )
{
if ( ! *(rgwszPaths[cGroups]) )
{
gpEvents->Report(
EVENT_FDEPLOY_FOLDER_EXPAND_FAIL,
2,
_wszDisplayName,
StatusToString ( ERROR_ENVVAR_NOT_FOUND )
);
_pGpoData->SimulatePlanningError( ERROR_ENVVAR_NOT_FOUND );
}
}
if ( ERROR_SUCCESS != Status )
{
hr = HRESULT_FROM_WIN32( Status );
break;
}
}
cGroups++;
}
}
//
// Record the number of groups counted
//
*pCount = cGroups;
return hr;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionPolicy::GenerateInheritedPath
//
// Purpose: Return the name of the path that results from
// treating this folder as a subfolder of a specific path
//
// Params:
// pwszAncestorPath -- in parameter indicating parent folder in
// in which this folder should be placed
//
// ppwszInheritedPath -- out parameter for resulting path
//
// Return value: S_OK if successful, error otherwise
//
//------------------------------------------------------------
HRESULT CRedirectionPolicy::GenerateInheritedPath(
WCHAR* pwszAncestorPath,
WCHAR** ppwszInheritedPath)
{
HRESULT hr;
DWORD cchParent;
DWORD cchRelative;
size_t sizeInheritedPath;
hr = E_OUTOFMEMORY;
//
// Construct the folder path by adding the relative path of this
// child to its ancestor's path
//
//
// First, determine the length of the path of this folder
// relative to its ancestor's path -- this is just the
// localized name of the folder
//
cchRelative = lstrlen( _wszLocalizedName );
cchParent = lstrlen( pwszAncestorPath );
sizeInheritedPath = cchParent + 1 + cchRelative + 1;
*ppwszInheritedPath = new WCHAR[sizeInheritedPath];
if ( *ppwszInheritedPath )
{
//
// Now, copy the ancestor's path
//
(void) StringCchCopy( *ppwszInheritedPath, sizeInheritedPath, pwszAncestorPath );
//
// Add on the path separator if one does not already exist at the end of the ancestor path
//
if ( ( cchParent != 0 ) &&
( L'\\' != pwszAncestorPath[ cchParent - 1] ) )
{
(void) StringCchCat( *ppwszInheritedPath, sizeInheritedPath, L"\\" );
}
//
// Now append this child's relative path to its ancestor
//
(void) StringCchCat( *ppwszInheritedPath, sizeInheritedPath, _wszLocalizedName );
hr = S_OK;
}
return hr;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionPolicy::GenerateInheritedPath
//
// Purpose: Return the name of the path that results from
// treating this folder as a subfolder of the path
// to which this folder's parent is redirected
//
// Params:
//
// ppwszInheritedPath -- out parameter for resulting path
//
// Return value: S_OK if successful, error otherwise
//
//------------------------------------------------------------
HRESULT CRedirectionPolicy::GenerateLocalInheritedPath(
WCHAR** ppwszInheritedPath )
{
HRESULT hr;
int iAncestor;
CRedirectInfo* pAncestorInfo;
WCHAR wszFolderKey [ TARGETPATHLIMIT ];
WCHAR wszInheritedFolder [ TARGETPATHLIMIT ];
hr = S_OK;
iAncestor = GetAncestorIndex();
pAncestorInfo = & ( gPolicyResultant[ iAncestor ] );
hr = StringCchCopy( wszFolderKey, TARGETPATHLIMIT, pAncestorInfo->m_szFolderRelativePath );
if ( FAILED(hr) )
{
return hr;
}
hr = StringCchCat( wszFolderKey, TARGETPATHLIMIT, L"\\" );
if ( FAILED(hr) )
{
return hr;
}
if ( _pGpoData->GetRsopContext()->IsDiagnosticModeEnabled() )
{
DWORD Status;
Status = _pGpoData->GetLocalFilePath(
wszFolderKey,
wszInheritedFolder);
hr = HRESULT_FROM_WIN32( Status );
}
else
{
hr = StringCchCopy( wszInheritedFolder, TARGETPATHLIMIT, L"%USERPROFILE%\\" );
if ( FAILED(hr) )
{
return hr;
}
hr = StringCchCat( wszInheritedFolder, TARGETPATHLIMIT, wszFolderKey );
if ( FAILED(hr) )
{
return hr;
}
}
if ( SUCCEEDED( hr ) )
{
hr = GenerateInheritedPath(
wszInheritedFolder,
ppwszInheritedPath);
}
return hr;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionPolicy::CopyInheritedData
//
// Purpose: Copies data that should be inherited from an ancestor
// to the object
//
// Params:
// pAncestralPolicy -- pointer to CRedirectionPolicy representing
// the policy for the ancestor folder
//
// Return value: S_OK if successful, error otherwise.
//
// Notes:
//
// If a folder is set to inherit from its parent, the
// following attributes must be copied from the parent:
//
// - Security Groups
// - Redirection target paths
// - The number of groups / paths
// - Flags
//
// This method copies those attributes from an ancestor
// to this object
//
//------------------------------------------------------------
HRESULT CRedirectionPolicy::CopyInheritedData( CRedirectionPolicy* pAncestralPolicy )
{
LONG iGroup;
LONG cGroups;
HRESULT hr;
//
// If we have no ancestor, then the only ancestral information
// we can copy is the redirected path
//
if ( ! pAncestralPolicy )
{
_bMissingAncestor = TRUE;
hr = GenerateLocalInheritedPath(
&_wszRedirectedPath);
return hr;
}
//
// Copy the redirecting group information first -- it
// will only be there if the user would have gotten
// this folder, so do not try to copy it if it is not there
//
if ( pAncestralPolicy->_RedirectedSid.Buffer )
{
BOOLEAN fAllocatedString;
fAllocatedString = RtlCreateUnicodeString(
&_RedirectedSid,
pAncestralPolicy->_RedirectedSid.Buffer);
if ( !fAllocatedString )
{
return E_OUTOFMEMORY;
}
RtlCopyUnicodeString(
&_RedirectedSid,
&(pAncestralPolicy->_RedirectedSid));
hr = GenerateInheritedPath(
pAncestralPolicy->_wszRedirectedPath,
&_wszRedirectedPath);
if ( FAILED(hr) )
{
return hr;
}
}
//
// Find out how many groups / paths there are
//
cGroups = pAncestralPolicy->_cGroups;
iGroup = 0;
_rgwszGroups = NULL;
_rgwszRedirectedPaths = NULL;
//
// Allocate space for the security groups
//
_rgwszGroups = new WCHAR* [ cGroups ];
hr = E_OUTOFMEMORY;
if ( _rgwszGroups )
{
//
// Now allocate space for the target paths
//
_rgwszRedirectedPaths = new WCHAR* [ cGroups ];
if ( _rgwszRedirectedPaths )
{
hr = S_OK;
//
// Now allocate copies of each security group and
// redirected target path
//
for ( iGroup = 0; iGroup < cGroups; iGroup ++ )
{
DWORD cchParent;
//
// Construct the folder path by adding the relative path of this
// child to its ancestor's path
//
//
// First, copy the ancestor's path
//
hr = GenerateInheritedPath(
pAncestralPolicy->_rgwszRedirectedPaths[ iGroup ],
&( _rgwszRedirectedPaths[ iGroup ] )
);
if ( FAILED( hr ) )
{
break;
}
//
// Security group is much simpler -- just copy it
//
_rgwszGroups[ iGroup ] = StringDuplicate(
pAncestralPolicy->_rgwszGroups[ iGroup ]);
if ( ! _rgwszGroups[ iGroup ] )
{
// Clean up at least this iteration
delete [] _rgwszRedirectedPaths[ iGroup ];
hr = E_OUTOFMEMORY;
break;
}
}
}
}
//
// Copy the flags
//
_dwFlags = pAncestralPolicy->_dwFlags;
//
// If we're successful, set the # of groups. We only set this on
// success so that we don't write out an incomplete set
//
if ( SUCCEEDED( hr ) )
{
_cGroups = cGroups;
}
// Otherwise we must clean up any memory we used ...
else
{
LONG iCleanupGroup;
for ( iCleanupGroup = 0; iCleanupGroup < iGroup; iCleanupGroup++ )
{
delete [] _rgwszGroups[ iCleanupGroup ];
delete [] _rgwszRedirectedPaths[ iCleanupGroup ];
}
delete [] _rgwszGroups;
_rgwszGroups = NULL;
delete [] _rgwszRedirectedPaths;
_rgwszRedirectedPaths = NULL;
_cGroups = 0;
}
return hr;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionPolicy::GetFolderIndex
//
// Purpose: Retrieves a numeric index representing the folder
// (startup, mydocs, etc)
//
// Params: none
//
// Return value: index of the folder redirected by this policy
//
// Notes:
//
//------------------------------------------------------------
int CRedirectionPolicy::GetFolderIndex()
{
return _iFolderIndex;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionPolicy::GetAncestorIndex
//
// Purpose: Retrieves a numeric index representing the ancestor
// of this folder
//
// Params: none
//
// Return value: index of the ancestor of the folder redirected
// by this policy
//
// Notes:
//
//------------------------------------------------------------
int CRedirectionPolicy::GetAncestorIndex()
{
return _iAncestorIndex;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionPolicy::HasAncestor
//
// Purpose: Indicates whether or not the folder redirected by
// this policy has an ancestor folder
//
// Params: none
//
// Return value: TRUE if the folder redirected by this policy
// has an ancestor, FALSE if not
//
// Notes:
//
//------------------------------------------------------------
BOOL CRedirectionPolicy::HasAncestor()
{
return _bHasAncestor;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionPolicy::HasInheritedData
//
// Purpose: Indicates whether or not the folder redirected by
// this policy should inherit data from its ancestor
//
// Params: none
//
// Return value: TRUE if the folder redirected by this policy
// should inherit data from an ancestor, FALSE if not
//
// Notes:
//
//------------------------------------------------------------
BOOL CRedirectionPolicy::HasInheritedData()
{
//
// If the policy lists no groups / target paths, then
// it must obtain them from a parent
//
return 0 == _cGroups;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionPolicy::NormalizePrecedence
//
// Purpose: Normalize precedence according the scale passed in
//
// Params:
// lScale - indicates what value should be considered the
// highest priority, and then priority is reversed based on this --
// e.g. if 5 is the scale, an object with precedence 5
// will become precedence 1 (the most important) when this
// function is called. The object with precedence 1
// will have value 5, the least significant, and intervening
// values will behave accordingly
//
// Return value: none
//
// Notes:
//
//------------------------------------------------------------
void CRedirectionPolicy::NormalizePrecedence( LONG Scale )
{
//
// Reverse the precedence -- switch it from highest values
// are most important to the reverse
//
_Precedence = Scale - _Precedence + 1;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionPolicy::IsRedirected()
//
// Purpose: Normalize precedence according the scale passed in
//
// Params:
// none
//
// Return value: TRUE if the folder is currently
// successfully redirected, FALSE if not
//
// Notes:
//
//------------------------------------------------------------
BOOL CRedirectionPolicy::IsRedirected()
{
DWORD Status;
//
// Check the global state to see if this folder
// has been successfully redirected
//
Status = gPolicyResultant[ _iFolderIndex ].m_StatusRedir;
return ERROR_SUCCESS == Status;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CPrecedenceState::CPrecedenceState
//
// Purpose: Constructor for CPrecedenceState class
//
// Params: none
//
// Return value: none
//
// Notes:
//
//------------------------------------------------------------
CPrecedenceState::CPrecedenceState()
{
RtlZeroMemory(_rgFolderPrecedence, sizeof(_rgFolderPrecedence));
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CPrecedenceState::UpdateFolderPrecedence
//
// Purpose: Changes the precedence of the winning folder specified by
// the index
//
// Params:
// iFolder -- index of folder whose precedence we are updating
//
// Return value: returns the new precedence of the folder
//
// Notes:
//
//------------------------------------------------------------
LONG CPrecedenceState::UpdateFolderPrecedence( int iFolder )
{
//
// Increase the precedence of the winning folder
//
return ++ ( _rgFolderPrecedence[ iFolder ] );
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CPrecedenceState::GetFolderPrecedence
//
// Purpose: Retrieves the precedence of the folder specified by
// the index
//
// Params:
// iFolder -- index of folder whose precedence we are
// retrieving
//
// Return value: returns the current precedence of the folder
//
// Notes:
//
//------------------------------------------------------------
LONG CPrecedenceState::GetFolderPrecedence( int iFolder )
{
return _rgFolderPrecedence[ iFolder ];
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionLog::AddRedirectionPolicies
//
// Purpose: Appends candidate policies to the list of
// redirection candidates
//
// Params:
// pGpoData -- pointer to information concerning the gpo
// from which the redirection candidate came
// pRedirectionInfo -- pointer to array candidate policies
// (one for each folder that can be redirected) to
// append to the list
//
// Return value: S_OK if successful, error otherwise
//
// Notes:
// IMPORTANT: this method is designed to be called
// multiple times and aggregate state across calls. The
// order in which calls occur is important -- each gpo
// passed in must be greater than the gpo passed
// in the previous call. Or put another way, this
// method should be called in order of least precedent gpo
// to most. This is necessary in order for the precedence
// calculations to be correct
//
//------------------------------------------------------------
HRESULT CRedirectionLog::AddRedirectionPolicies(
CFileDB* pGpoData,
CRedirectInfo* pRedirectionInfo)
{
DWORD iRedirect;
ASSERT( _pRsopContext->IsRsopEnabled() );
//
// For each folder that could be redirected, we'll check to see
// if it gets redirected, and add it to the list if so
//
for (iRedirect = 0 ; iRedirect < EndRedirectable; iRedirect++)
{
LONG Precedence;
CRedirectionPolicy* pNewRedirection;
//
// Check to see if this is redirected
//
if ( pRedirectionInfo[ iRedirect ].HasPolicy() )
{
HRESULT hr;
//
// We do not support the Programs and Startup folders --
// we used to and the core code continues to include
// them in its data structures. We should ignore these folders
// if we see them
//
if ( ( Programs == pRedirectionInfo[ iRedirect ].GetFolderID() ) ||
( Startup == pRedirectionInfo[ iRedirect ].GetFolderID() ) )
{
continue;
}
//
// Update the folder's precedence since we found a candidate
//
Precedence = _PrecedenceState.UpdateFolderPrecedence( iRedirect );
//
// Create an abstraction of the redirection candidate policy
//
pNewRedirection = new CRedirectionPolicy(
pGpoData,
&(pRedirectionInfo[iRedirect]),
Precedence,
&hr);
if ( ! pNewRedirection )
{
hr = E_OUTOFMEMORY;
}
if ( FAILED(hr) )
{
_pRsopContext->DisableRsop( hr );
return hr;
}
//
// Add it to the list of redirections
//
*_ppNextRedirection = pNewRedirection;
_ppNextRedirection = &(pNewRedirection->_pNext);
}
}
return S_OK;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionLog::NormalizePrecedence
//
// Purpose: Normalize a redirection's precedence according
// to its relationship with redirections from other gpo's
//
// Params:
// pRedirectionPolicy -- redirection policy candidate to
// be normalized
//
// Return value: none
//
// Notes:
//
//------------------------------------------------------------
void CRedirectionLog::NormalizePrecedence( CRedirectionPolicy* pRedirectionPolicy )
{
int iFolder;
//
// Find the folder index for the redirected candidate
//
iFolder = pRedirectionPolicy->GetFolderIndex();
//
// Now use the winning precedence as the scale to normalize
// this candidate
//
pRedirectionPolicy->NormalizePrecedence(
_PrecedenceState.GetFolderPrecedence( iFolder ) );
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionLog::WriteRsopLog
//
// Purpose: Creates an rsop log of all the redirection information
// for the current user
//
// Params: none
//
// Return value: S_OK if successful, error otherwise
//
// Notes:
//
//------------------------------------------------------------
HRESULT CRedirectionLog::WriteRsopLog()
{
CRedirectionPolicy* pCurrent;
if ( ! _pRsopContext->IsRsopEnabled() )
{
return S_OK;
}
//
// Clear any existing log before writing out redirection results
//
ClearRsopLog();
//
// Iterate through the list of redirection candidates
//
for (pCurrent = _pRedirectionList;
pCurrent;
pCurrent = (CRedirectionPolicy*) pCurrent->_pNext)
{
//
// Normalize the precedence of this candidate with
// respect to other redirections
//
NormalizePrecedence( pCurrent );
//
// Add in any ancestral policy data
//
(void) AddAncestralPolicy( pCurrent );
//
// Write the record to the database
//
if ( pCurrent->IsRedirected() )
{
WriteNewRecord(pCurrent);
}
}
return S_OK;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionLog::GetAncestor
//
// Purpose: returns the candidate redirection that is redirecting
// the folder that is the ancestor of the specified redirection
// candidate
//
// Params: pRedirectionPolicy -- redirection whose candidate
// redirection ancestor we wish to retrieve
//
// Return value: reference to redirection policy candidate
//
// Notes:
//
//------------------------------------------------------------
CRedirectionPolicy* CRedirectionLog::GetAncestor(
CRedirectionPolicy* pRedirectionPolicy )
{
int iFolder;
CRedirectionPolicy* pAncestor;
CRedirectionPolicy* pCurrent;
pAncestor = NULL;
//
// First, determine which folder is the ancestor of the
// specified redirection
//
iFolder = pRedirectionPolicy->GetAncestorIndex();
//
// Iterate trhough the list -- it is sorted, with
// the highest gpo last, and ancestors always
// appear before children -- we want to find the
// highest ancestor
//
for (pCurrent = _pRedirectionList;
pCurrent;
pCurrent = (CRedirectionPolicy*) pCurrent->_pNext)
{
//
// Remember the last ancestor we've seen
//
if ( iFolder == pCurrent->GetFolderIndex() )
{
pAncestor = pCurrent;
}
}
//
// Now return the ancestor that is currently highest
// without violating the gpo precedence of the child setting
//
return pAncestor;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionLog::AddAncestralPolicy
//
// Purpose: causes a redirection candidate to inherit settings
// from an ancestor folder (if it has one) if inheritance
// is specified in the policy
//
// Params: pRedirectionPolicy -- redirection to which we want
// to which we want to add ancestor's policy settings
//
// Return value: S_OK if successful, error otherwise
//
// Notes:
//
//------------------------------------------------------------
HRESULT CRedirectionLog::AddAncestralPolicy( CRedirectionPolicy* pRedirectionPolicy)
{
HRESULT hr;
CRedirectionPolicy* pAncestorPolicy;
//
// See if this redirection has inherited data
//
if ( ! pRedirectionPolicy->HasInheritedData() )
{
return S_OK;
}
//
// If this policy doesn't have an ancestor, then we're done
//
if ( ! pRedirectionPolicy->HasAncestor() )
{
return S_OK;
}
//
// This policy has an ancestor -- retrieve it
//
pAncestorPolicy = GetAncestor( pRedirectionPolicy );
//
// Inherit settings from the ancestor
//
hr = pRedirectionPolicy->CopyInheritedData( pAncestorPolicy );
return hr;
}
HRESULT CRedirectionLog::AddPreservedPolicy( WCHAR* wszFolderName )
{
DWORD cchLen;
WCHAR* wszNewQuery;
HRESULT hr = S_OK;
if ( ! _pRsopContext->IsRsopEnabled() )
{
return S_OK;
}
cchLen = lstrlen( wszFolderName );
cchLen += sizeof( WQL_INSTANCE ) / sizeof( WCHAR ) +
sizeof( WQL_AND ) / sizeof( WCHAR );
if ( _wszDeletionQuery )
{
cchLen += lstrlen( _wszDeletionQuery );
}
wszNewQuery = new WCHAR [ cchLen ];
if ( ! wszNewQuery )
{
return E_OUTOFMEMORY;
}
if ( _wszDeletionQuery )
{
(void) StringCchCopy( wszNewQuery, cchLen, _wszDeletionQuery );
(void) StringCchCat( wszNewQuery, cchLen, WQL_AND );
}
else
{
*wszNewQuery = L'\0';
}
hr = StringCchPrintf( wszNewQuery + lstrlen( wszNewQuery ),
cchLen - lstrlen( wszNewQuery ),
WQL_INSTANCE,
wszFolderName );
if ( SUCCEEDED(hr) )
{
delete [] _wszDeletionQuery;
_wszDeletionQuery = wszNewQuery;
}
else
{
delete [] wszNewQuery;
}
return hr;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionLog::CRedirectionLog
//
// Purpose: constructor for class CRedirectionLog
//
// Params: none
//
// Return value: none
//
// Notes:
//
//------------------------------------------------------------
CRedirectionLog::CRedirectionLog() :
_pRedirectionList(NULL),
_ppNextRedirection(&_pRedirectionList),
_wszDeletionQuery( NULL ),
_SimulatedStatus( ERROR_SUCCESS )
{}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionLog::~CRedirectionLog
//
// Purpose: destructor for class CRedirectionLog.
//
// Params: none
//
// Return value: none
//
// Notes:
//
//------------------------------------------------------------
CRedirectionLog::~CRedirectionLog()
{
CRedirectionPolicy* pCurrent;
CRedirectionPolicy* pNext;
for (pCurrent = _pRedirectionList;
pCurrent;
pCurrent = pNext)
{
pNext = (CRedirectionPolicy*) pCurrent->_pNext;
delete pCurrent;
}
delete [] _wszDeletionQuery;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionLog::InitRsop
//
// Purpose: Initializes rsop logging
//
// Params: pRsopContext -- logging contxt
// bForceRsop -- TRUE if we should bind to a namespace
// in the absence of an existing namespace in this context
//
//
// Return value: none
//
// Notes:
//
// Success of initialization is stored internally -- rsop
// is disabled if there's a failure
//
//------------------------------------------------------------
void CRedirectionLog::InitRsop( CRsopContext* pRsopContext, BOOL bForceRsop )
{
HRESULT hr;
//
// If the caller needs us to bind to a saved namespace because
// the gp engine did not pass one in and we need to log new data,
// do so.
//
if ( bForceRsop )
{
(void) pRsopContext->InitializeSavedNameSpace();
}
//
// Initialize Rsop logging
//
hr = InitLog( pRsopContext, RSOP_REDIRECTED_FOLDER );
if (FAILED(hr))
{
pRsopContext->DisableRsop( hr );
return;
}
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionLog::ClearRsopLog
//
// Purpose: Clears the namespace of records
//
// Params: none
//
// Return value: none
//
// Notes:
//
//------------------------------------------------------------
void CRedirectionLog::ClearRsopLog()
{
HRESULT hr;
//
// Nothing to do if logging is not enabled
//
if (! _pRsopContext->IsRsopEnabled() )
{
return;
}
//
// Attempt to clear the log
//
hr = ClearLog( _wszDeletionQuery );
//
// If we cannot clear it, disable logging
//
if (FAILED(hr))
{
_pRsopContext->DisableRsop( hr );
}
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionLog::SimluatePlanningError
//
// Purpose: During planning mode, we may be able to detect
// a situation that would result in an error
// if policy application were attempted on a real client --
// this function simulates a specific Win32 error
//
// Params: Status
//
// Return value: none
//
// Notes:
//
//------------------------------------------------------------
void CRedirectionLog::SimulatePlanningError( DWORD Status )
{
if ( ERROR_SUCCESS == _SimulatedStatus )
{
_SimulatedStatus = Status;
}
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: CRedirectionLog::GetPlanningSimulatedErrorIfNecessary
//
// Purpose: During planning mode, we may be able to detect
// a situation that would result in an error
// if policy application were attempted on a real client --
// this function retrieves such a simulated error, but
// only if it does not "override" the Status code
// passed in
//
// Params: Status
//
// Return value: The error status with the highest precedence
//
// Notes:
//
//------------------------------------------------------------
DWORD CRedirectionLog::GetPlanningSimulatedErrorIfNecessary( DWORD Status )
{
DWORD PreferredStatus;
PreferredStatus = Status;
if ( ERROR_SUCCESS == Status )
{
PreferredStatus = _SimulatedStatus;
}
return PreferredStatus;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Function: StringDuplicate
//
// Purpose: Simple duplication of a c-string
//
// Params: wszOriginal -- string to be duplicated
//
// Return value: reference to allocated duplicate string if
// successful, NULL on failure
//
// Notes: returned string should be freed by caller with
// vector delete
//
//------------------------------------------------------------
WCHAR* StringDuplicate(WCHAR* wszOriginal)
{
WCHAR* wszNew;
DWORD cchSize;
ASSERT(wszOriginal);
//
// Determine original size
//
cchSize = lstrlen(wszOriginal) + 1;
//
// Allocate the space for the duplicate
//
wszNew = new WCHAR[ cchSize ];
//
// Duplicate to the new allocation if
// the allocation was successful
//
if (wszNew)
{
(void) StringCchCopy(wszNew, cchSize, wszOriginal);
}
return wszNew;
}