Regardless of the design of your Solution, there are four important things we'd like you to keep in mind in terms of the design and implementation of Client Policy DLL callbacks. Those four things, in no particular order, are:
• All Policy DLL callback code that you implement must be
thread-safe. FesfPolicy dynamically grows (and shrinks) the pool of
worker threads it uses to call Policy DLL callbacks. FESF currently sets
the maximum number of active callback threads to 122 on 32-bit systems, and to
244 on 64-bit systems. These maxima are subject to change, up or down, in
subsequent releases of FESF. During pre-release testing, we regularly hit
the maximum number of active worker threads. A design which takes maximum
advantage of the parallelism offered by FESF, and an efficient, scalable,
locking scheme where access to shared data is required, are a must in your
Solution.
• Callbacks to your policy DLL must complete "promptly."
Remember, when FesfPolicy calls your Policy DLL it's blocking a kernel-mode
operation, typically a user's request to open or create a file. For the Solution
and the overall Windows system on which the Solution is running to exhibit good
performance, prompt and efficient processing is a must. A Solution
architecture that judiciously caches information, including Policy decisions,
key material, and user Security Group membership, is strongly advised.
While we're not fans of premature optimization, we would encourage you to at
least take these precepts into account as part of your Solution's initial
design.
You
might reasonably ask "What time period, precisely, does 'promptly' imply?"
Unfortunately, we don't have a good answer for you. By promptly, we really
mean "as soon as practically possible for your Solution." Each workload
will be different, and your Solution has to meet your own design and usability
goals. However, from a systems perspective, we would advise targeting a
small number of seconds (in the low single digits) as the maximum time for a
Policy DLL callback to complete under heavy system load. This should yield
acceptable performance. This is provided only as a guideline to aid you in
your design.
One
absolute maximum that we can warn you about is that used by the FESF Kernel Mode
Components. These components set an arbitrary maximum of 30 seconds that
they will wait for a reply from user-mode. One of our developers describes
this interval as "a virtual eternity", and indeed it is the uppermost bound that
can be expected for a reply even on a severely degraded system. After this
period of time, an error message is logged to the Windows Event Log and the
timed-out operation is completed with an error (access denied). While this
will ensure the system remains running, returning errors from a Policy DLL
callback is rarely desirable, as further described below.
• Avoid returning failure codes when possible. As described in
the section above entitled Returning Failure from Policy DLL Callbacks, it is
almost always a bad idea to return a failure code from the PolGetPolicyNewFile,
PolGetKeyNewFile, PolGetPolicyExistingFIle, and PolGetKeyFromHeader Policy DLL callbacks. We
would advise you to restrict failure returns to those conditions which are
unforeseeable and catastrophic. We would recommend not returning failure
statuses to FESF callbacks in transient conditions such as lost connections or
slow responses from your key management server. Obviously, only you
understand your Solution and its requirements. But, at the very least,
please do not return an error from these callbacks as an alternative form of
implementing file access security.
• Be conscious of the potential for reentrancy and avoid
it. Bear in mind that your Policy DLL's callbacks are executing while
a Windows system service (typically a CreateFile
operation) is pending. This means you must avoid the potential for
reentrancy problems. As a very simple example, consider what might happen
if you create a new file as a result of being called in your PolGetPolicyNewFile callback. In this
example, assuming your policy determinations are made in a separate process
(similar to the way the OSR Sample Solution works) your PolGetPolicyNewFile callback would get
called-back endlessly (each time, creating a new file which then results in
another callback). Not good!
Note that to preserve FESF
integrity (and to eliminate the most obvious potential causes of endless
callbacks), FESF kernel-mode code suppresses all calls to the Policy DLL for I/O
operations performed within the context of the FESF Policy Service itself.
So, in the above example, creating a new file directly within the Policy DLL’s
PolGetPolicyNewFile callback (and not in
a separate process) would NOT generate a reentrant call to
PolGetPolicyNewFile.