In this section, I'll highlight some of the important implementation details of the sample code that accompanies this article. The code is based on an existing sample implementation in the Windows Vista version of the Windows SDK. For reference, the existing sample can be found in the Samples\NetDs\NAP subdirectory of a default SDK installation.
The Registry SHA/SHV sample that is described herein builds upon the original SDK sample in a number of important ways. These include:
-
Auto-remediation.
-
Server-side configuration user interface.
-
Build and test with run-time security enhancements.
I'll discuss each in the following sections.
Auto-Remediation
As mentioned previously, auto-remediation is an important feature of NAP, wherein unhealthy clients can automatically be brought into compliance by the underlying plug-in implementation without requiring error-prone end-user intervention.
For example, suppose that the Registry SHA and SHV have been configured to monitor the fictitious registry value EnableSecureMode that is located at HKEY_LOCAL_MACHINE\Software\Contoso. The system administrators want to enforce that only clients that have that value present and set to 1 (enabled) are able to acquire an IP address with DHCP.
What happens in the code when a client that lacks that registry value attempts to obtain an IP address? In order to answer that question, there are a few abstraction layers to be aware of in the sample SHA. The sample SHA implements the INapSystemHealthAgentCallback (see napsystemhealthagent.h in the Windows SDK) via its ShaCallback class (see sha\exe\callback.cpp). Also, to simplify interacting with the registry, and to allow that code to be shared between the SHA and SHV, a helper class that is named CRegistryKeyValue is used (see sdkcommon\src\sdkcommon.cpp).
When the sample SHA's host service first starts (see sha\exe\shasvc.cpp), it immediately reads its current registry policy values (using ShaCallback::Init). It then registers for change notifications for each target registry key (by using ShaCallback::ListenRegChange).
Subsequently, when the NAP client queries the registry SHA for a SoH request, the target registry values are serialized into a byte array that can be interpreted by the SHV. On the client, the following call stack shows how this serialization is accomplished:
CRegistryKeyValue::Serialize
ShaCallback::Poll
ShaCallback::FillSoHRequest
ShaCallback::GetSoHRequest
The SHV uses a similar architecture, wherein the helper CSampleShv class (see shv\sampleshv.cpp) implements the INapSystemHealthValidator interface (from the public header, napsystemhealthvalidator.h). After the SoH request and embedded serialized registry-setting information are received by the SHV that is using CSampleShv::Validate, it deserializes the registry data and compares each value against the expected setting.
However, as a performance enhancement, the bulk of the sample SHV validate implementation is asynchronous. This allows the host NPS to achieve greater throughput across multiple SHV plug-ins. The following call stack shows how this check is accomplished:
CRegistryKeyValue::ExtractData (followed by ::MatchedKey)
CSampleShv::CheckRequestSoHHealth
CSampleShv::HandleRequestSoH
CSampleShv::QShvRespondSHVHost
CSampleShv::AsyncThreadHandlerMain
CSampleShv::AsyncThreadHandler
In this example, because the client workstation is lacking a required registry value, the preceding call to CheckRequestSoHealth in the SHV results in a status of QUAR_E_NOTPATCHED. The CheckRequestSoHHealth function also serializes the expected values corresponding to the client registry locations that were determined to be noncompliant. This serialized output can be thought of as the remediation instructions for the client.
The resulting status is then returned by HandleRequestSoH (refer again to the preceding call stack), at which point QShvRespondSHVHost calls ::HandleResponseSoH, which in turn calls ::FillResponseSoH to attach the serialized remediation instructions to the SoH response.
Next, the SoH response is returned by NAP to the registry SHA on the client. In this example, the SHA must notify the NAP client that, per instructions that are received from the SHV, remediation actions are now pending. As a result, ProcessSoHResponse calls HandleSoHResponse, which sets a return status of FIXESINPROGRESS.
As an aside, note that an SHA implementation could also determine a noncompliant status in which auto-remediation would not be performed (that is, something requiring direct user intervention to fix). In that case, FIXESNEEDED would be returned, instead.
The SHA remediation interface is driven by ::GetFixupInfo, which is the next interface call that is made by the NAP client. Because health-remediation patches are to be applied in this example, GetFixupInfo calls ShaCallback::DoPatch, which will validate the registry information that is returned by the SHV and call CRegistryKeyValue::SetTargetValue to make the mandated correction to the example EnableSecureMode value under HKEY_LOCAL_MACHINE\Software\Contoso. Thus, the client system is patched and may now obtain an IP address!
Finally, it's worth noting that the NAP client interface allows helpful messages to be displayed to the user via systray balloon (a pop-up window in the notification area). As an example, see how the FixupInfo structure (from the public naptypes.h) is populated, following successful remediation in GetFixupInfo.
FixupInfo * pStatus
...
pStatus->fixupMsgId = MSG_ID_FIXUP_SUCCESS;
pStatus->percentage = 100;
pStatus->state = fixupStateSuccess;
That particular code block informs the NAP client that the client was successfully patched and causes the resource string that corresponds to MSG_ID_FIXUP_SUCCESS to be shown briefly in a notification balloon, so that the user knows what's going on behind the scenes. Other SHA implementations should take advantage of this mechanism in order to keep the user informed of important state changes (including failure cases, such as an unhealthy client and/or patching fails).
Server-Side Configuration User Interface
The preceding auto-remediation walkthrough section mentions that the CSampleShv class implements the NAP INapSystemHealthValidator interface. Observe in shv\sampleshv.h that the CSampleShv class also implements the INapComponentConfig interface.
The INapComponentConfig interface is an important consideration for SHV implementers, because it exposes a mechanism for the system administrator to configure an SHV by using whatever user interface is appropriate, while still maintaining a common management environment across all SHVs.
The sample Registry SHV includes an implementation of that interface (see shv\sampleshv.cpp!CSampleShv::InvokeUI). To see this interface at work, perform the following steps:
-
Configure a Windows Server 2008 (Beta) machine with the Network Policy and Access Services role. See the Resources section, for more information about this step.
-
Copy RegistrySHV.dll to the System32 directory.
-
Run regsvr32.exe RegistrySHV.dll
-
Click Start, click Run, type nps.msc, and then click OK.
-
In the console tree (left pane), expand Network Access Protection, and then expand System Health Validators.
-
In the details pane (right pane), right-click Sample Registry SHV, and then click Properties.
-
Press the Configure button.
Next, you'll see the following dialog box, which is created by the Registry SHV:
Figure 3. Configure Registry Key dialog box
Implementation Security
Inherent in their architecture and role is the fact that the various components of NAP will be exposed to data from the network. This potentially includes data that is received via an un-encrypted channel over the Internet. This observation is intended simply to reinforce the fact that all code—particularly system-level code, written in Visual C++, exposed to untrusted network data—must be reviewed and made to be as robust as possible.
To this end, the sample Registry SHA and SHV have been configured and tested with the following compile-, link-, and run-time protections in place. More detail about these options is available online and in Writing Secure Code for Windows Vista (Howard and LeBlanc).