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