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