|
|
//*************************************************************
//
// 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; }
|