Supporting RSoP Logging Mode
Each client-side extension that plans to support the logging of RSoP data must export an implementation of the application-defined ProcessGroupPolicyEx callback function. When the Winlogon.exe/Userenv.dll process calls the function as part of applying Group Policy, the client-side extension should apply Group Policy and log RSoP data.
To register this callback function, create a subkey under the following registry key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\GPExtensions\ClientExtensionGuid
- with the registry value [**ProcessGroupPolicyEx**](/windows/desktop/api/Userenv/nc-userenv-pfnprocessgrouppolicyex) **REG\_SZ**
"Function name that processes policy and logs RSoP data".
The subkey should be a GUID, so that it is unique. For more information, see ProcessGroupPolicyEx and Registering a Policy Callback Function.
The following code example can be used by a registry extension to log one instance of the RSOP_RegistryPolicySetting MOF class.
//*************************************************************
//
// Function: LogRegistryPolicyInstance()
//
// Purpose: Logs an instance of registry policy. Will be called from deep
// within ProcessGroupPolicyEx process to log RsoP data for a registry client-side extension.
//
// Parameters: pwszGPO – GPO ID obtained from PGROUP_POLICY_OBJECT->lpDSPath
// pwszSOM – SOM ID obtained from PGROUP_POLICY_OBJECT->lpLink
// pWbemServices – Obtained from last parameter in ProcessGroupPolicyEx
// dwPrecedence – Precedence order for this policy instance
// pwszKeyName, pwszValueName, bDeleted - Registry client-side extension-specific properties
//
// Returns: HRESULT
//
//*************************************************************
HRESULT LogRegistryPolicyInstance( WCHAR *pwszGPO, WCHAR *pwszSOM,
IWbemServices *pWbemServices,
WCHAR *pwszKeyName, WCHAR *pwszValueName,
BOOL bDeleted, DWORD dwPrecedence )
{
IWbemClassObject* pClass;
HRESULT hr = pWbemServices->GetObject( SysAllocString(L"RSOP_RegistryPolicySetting"),
0L,
NULL,
&pClass,
NULL );
if ( FAILED(hr) )
{
// Be aware that error-checking has been omitted.
// Also be aware that pClass must be assigned to a smart pointer
// so that it can be released eventually by calling
// pClass->Release().
// Also be aware that if you call the SysAllocString function
// to allocate resources, you must call the SysFreeString
// function to deallocate them.
}
IWbemClassObject *pInstance = NULL;
HRESULT hr = pClass->SpawnInstance( 0, &pInstance );
//
// First, log client-side extension-specific properties.
//
VARIANT var;
var.vt = VT_BOOL;
var.boolVal = bDeleted ? VARIANT_TRUE : VARIANT_FALSE;
hr = pInstance->Put( L"deleted", 0, &var, 0 );
var.vt = VT_BSTR;
var.bstrVal = SysAllocString( pwszValueName;
hr = pInstance->Put( SysAllocString( L"name", 0, &var, 0 );
//
// Set other registry client-side extension
// properties such as valueType and registryKey.
//
// Log properties of the RSOP_PolicySetting parent class.
//
// For the GPOID property, use the data in the
// PGROUP_POLICY_OBJECT->lpDSPath member. For the
// SOMID property, use the PGROUP_POLICY_OBJECT->lpLink member.
//
// Be aware that the LDAP://CN=Machine or LDAP:// must be removed
// from the prefix of the lpDSPath and lpLink members to
// get the canonical values. See the code for the StripPrefix
// and StripLinkPrefix functions.
//
// Precedence is determined by the client-side extension to
// indicate "winning" and "losing" policies.
//
var.vt = VT_I4;
var.lVal = dwPrecedence;
hr = pInstance->Put( SysAllocString( L"precedence', 0, &var, 0 );
WCHAR *pwszStrippedGPO = StripGPOPrefix( pwszGPO );
var.bstrVal = SysAllocString( pwszStrippedGPO );
hr = pInstance->Put( SysAllocString( L"GPOID", 0, &var, 0 );
WCHAR *pwszStrippedSOM = StripSOMPrefix( pwszSOM );
var.bstrVal = SysAllocString( pwszStrippedSOM );
hr = pInstance->Put( SysAllocString(L"SOMID), 0, &var, 0 );
//
// Create a GUID for the id property (a key).
// Client-side extensions must create their own key. The
// key must be unique for every instance of the policy instance.
//
WCHAR wszId[MAX_GUID_LENGTH];
GUID guid;
hr = CoCreateGuid( &guid );
GuidToString( &guid, wszId );
var.bstrVal = SysAllocString( wszId );
hr = pInstance->Put( L"id", 0, &var, 0 );
//
// Commit all above properties by calling the PutInstance method.
//
hr = pWbemServices->PutInstance( pInstance, WBEM_FLAG_CREATE_OR_UPDATE, NULL, NULL );
//
// You must free all allocated resources to avoid memory leaks.
//
return S_OK;
}
//*************************************************************
//
// Function: StripGPOPrefix()
//
// Purpose: Strips out the prefix to get the canonical path to a GPO.
//
// Parameters: pwszPath DS path to GPO
//
// Returns: Pointer to suffix
//
//*************************************************************
WCHAR *StripGPOPrefix( WCHAR *pwszPath )
{
WCHAR wszMachPrefix[] = TEXT("LDAP://CN=Machine,");
INT iMachPrefixLen = lstrlen( wszMachPrefix );
WCHAR wszUserPrefix[] = TEXT("LDAP://CN=User,");
INT iUserPrefixLen = lstrlen( wszUserPrefix );
WCHAR *pwszPathSuffix;
//
// Remove the prefix to get the canonical path to the GPO.
//
if ( CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE,
pwszPath, iUserPrefixLen, wszUserPrefix,
iUserPrefixLen ) == CSTR_EQUAL ) {
pwszPathSuffix = pwszPath + iUserPrefixLen;
} else if ( CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE,
pwszPath, iMachPrefixLen, wszMachPrefix,
iMachPrefixLen ) == CSTR_EQUAL ) {
pwszPathSuffix = pwszPath + iMachPrefixLen;
} else
pwszPathSuffix = pwszPath;
return pwszPathSuffix;
}
//*************************************************************
//
// Function: StripSOMPrefix()
//
// Purpose: Removes the prefix to get canonical path to the SOM
// object.
//
// Parameters: pwszPath path to SOM
//
// Returns: Pointer to suffix
//
//*************************************************************
WCHAR *StripSOMPrefix( WCHAR *pwszPath )
{
WCHAR wszPrefix[] = TEXT("LDAP://");
INT iPrefixLen = lstrlen( wszPrefix );
WCHAR *pwszPathSuffix;
//
// Remove the prefix to get the canonical path to the SOM.
//
if ( wcslen(pwszPath) <= (DWORD) iPrefixLen ) {
return pwszPath;
}
if ( CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE,
pwszPath, iPrefixLen, wszPrefix, iPrefixLen ) == CSTR_EQUAL ) {
pwszPathSuffix = pwszPath + iPrefixLen;
} else
pwszPathSuffix = pwszPath;
return pwszPathSuffix;
}