Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1202 lines
32 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
sip.c
Abstract:
Implements support routines for subject interface pacakges.
Author:
Robert Reichel (Robertre) April 9, 1996
Revision History:
--*/
#ifdef _DEBUG
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#endif
#include <windows.h>
#include <wintrust.h>
#include "sip.h"
#include "trust.h"
///////////////////////////////////////////////////////////////////////////////
// /
// Routines to maintain list of loaded subject interface packages. /
// /
///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////
// /
// Private data structures /
// /
/////////////////////////////////
//
// Location of trust provider information in the registry.
//
#define REGISTRY_SIPS TEXT("System\\CurrentControlSet\\SERVICES\\WinTrust\\SubjectPackages")
#define REGISTRY_ROOT HKEY_LOCAL_MACHINE
#define SUBJECT_FORMS TEXT("$SubjectForms")
#define DLL_NAME TEXT("$DLL")
#define IsEqualSubject( id1, id2) (!memcmp(id1, id2, sizeof(GUID)))
//
// List of loaded sips. Each loaded sip is represented
// by a LOADED_SIP structure on this list.
//
PLOADED_SIP SIPList = NULL;
//
// Local Prototypes
//
PLOADED_SIP
SipTestSipForSubject(
IN HKEY hKey,
IN LPTSTR KeyName,
IN GUID * Subject
);
PLOADED_SIP
SipLoadSip(
IN HKEY hKey,
IN LPTSTR KeyName
);
PLOADED_SIP
SipIsSipLoaded(
IN LPTSTR KeyName
);
PLOADED_SIP
SipCheckLoadedSips(
IN GUID * Subject
);
PLOADED_SIP
SipScanKnownSips(
IN GUID * Subject
);
PLOADED_SIP
SipSearchAllSips(
IN GUID * Subject
);
///////////////////////////////////////////////////////////////////////////////
// /
// Routines exported from this module /
// /
///////////////////////////////////////////////////////////////////////////////
PLOADED_SIP
WinTrustFindSubjectForm(
IN GUID * SubjectForm
)
/*++
Routine Description:
This routine will perform the following actions in sequence:
1) All loaded SIPs will be searched for the desired SubjectForm. The
first match that supports the requested subject will be returned.
2) If no loaded SIP is suitable, then the list of SIPs in the
registry will be searched for hint information. Every potential
SIP will be loaded and queried to see if it exports the desired
Subject. Also, hint information will be updated on every loaded
SIP.
3) If no hint information leads us to a suitable SIP, an exhaustive
search of every SIP mentioned in the registry will take place.
If none are found, failure is returned. Processing will stop as soon
as a suitable SIP is discovered.
Arguments:
SubjectForm - The SubjectForm to be found.
Return Value:
On success, returns a pointer to a LOADED_SIP structure representing
a loaded SIP.
On failure, returns NULL.
--*/
{
PLOADED_SIP Sip = NULL;
Sip = SipCheckLoadedSips( SubjectForm );
if (NULL == Sip) {
Sip = SipScanKnownSips( SubjectForm );
}
if (NULL == Sip) {
Sip = SipSearchAllSips( SubjectForm );
}
#ifdef _DEBUG
if (NULL == Sip) {
DbgPrint("Sip not found for SubjectForm ");
DbgPrint("%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
SubjectForm->Data1, SubjectForm->Data2, SubjectForm->Data3, SubjectForm->Data4[0],
SubjectForm->Data4[1], SubjectForm->Data4[2], SubjectForm->Data4[3], SubjectForm->Data4[4],
SubjectForm->Data4[5], SubjectForm->Data4[6], SubjectForm->Data4[7]);
DbgPrint("\n");
}
#endif
return( Sip );
}
///////////////////////////////////////////////////////////////////////////////
// /
// Routines local to this module /
// /
///////////////////////////////////////////////////////////////////////////////
PLOADED_SIP
SipCheckLoadedSips(
IN GUID * SubjectForm
)
/*++
Routine Description:
Walks the list of loaded Sips, attempting to find one
that implements the specified subject form.
Arguments:
SubjectForm - Specifies the desired SubjectForm.
Return Value:
On success, returns a pointer to a LOADED_SIP structure. On failure,
returns NULL.
--*/
{
PLOADED_SIP Sip;
ULONG i;
AcquireReadLock();
Sip = SIPList;
while (Sip != NULL &&
//
// We only want to look at fully initialized providers here,
// we'll pick up any that are partially initialized in a later
// pass.
//
Sip->SipInitialized == SIP_INITIALIZATION_SUCCESS
) {
for (i=0; i<Sip->SipInfo->dwSubjectTypeCount; i++) {
if (IsEqualSubject(&Sip->SipInfo->lpSubjectTypeArray[i], SubjectForm )) {
ReleaseReadLock();
return( Sip );
}
}
Sip = Sip->Next;
}
ReleaseReadLock();
return( NULL );
}
PLOADED_SIP
SipScanKnownSips(
IN GUID * SubjectForm
)
/*++
Routine Description:
This routine will examine the contents of the registry to determine
if we have ever loaded a Sip with the specified SubjectForm. If
so, we will re-load the Sip and verify that it still exports the
desired SubjectForm.
Arguments:
SubjectForm - Supplies the desired SubjectForm.
Return Value:
On success, returns a pointer to a LOADED_SIP block. Returns NULL
on failure.
--*/
{
HKEY hKey; // Handle to the base of the Sip information.
HKEY hSubKey; // Handle to the Sip currently being examined.
LONG Result; // Returned by registry API.
DWORD cSubKeys; // Number of Sips under the root key.
DWORD cbMaxSubKeyLen; // Maximum Sip name length.
ULONG i,j; // Indicies for iterating through Sips and subject forms.
LPTSTR SubKeyName; // Points to the name of the current Sip.
GUID Buffer[10]; // Assume no more than 10 subject forms in a Sip
LPBYTE Data;
DWORD cbData;
GUID * SubjectForms;
PLOADED_SIP FoundSip = NULL;
//
// Open the registry and get a list of installed trust Sips
//
Result = RegOpenKeyEx(
REGISTRY_ROOT,
REGISTRY_SIPS,
0L,
GENERIC_READ,
&hKey
);
if (Result != ERROR_SUCCESS) {
return( NULL );
}
//
// Find out how many subkeys there are.
//
Result = RegQueryInfoKey ( hKey, // handle of key to query
NULL, // address of buffer for class string
NULL, // address of size of class string buffer
NULL, // reserved
&cSubKeys, // address of buffer for number of subkeys
&cbMaxSubKeyLen, // address of buffer for longest subkey name length
NULL, // address of buffer for longest class string length
NULL, // address of buffer for number of value entries
NULL, // address of buffer for longest value name length
NULL, // address of buffer for longest value data length
NULL, // address of buffer for security descriptor length
NULL // address of buffer for last write time
);
if (ERROR_SUCCESS != Result) {
RegCloseKey( hKey );
return( NULL );
}
//
// Iterate through the subkeys, looking for ones with hint information.
//
cbMaxSubKeyLen += sizeof( WCHAR );
SubKeyName = LocalAlloc( 0, cbMaxSubKeyLen );
if (NULL == SubKeyName) {
RegCloseKey( hKey );
return(NULL);
}
for (i=0; i<cSubKeys; i++) {
DWORD ValueType;
DWORD KeyNameLength;
KeyNameLength = cbMaxSubKeyLen;
Result = RegEnumKeyEx( hKey, // handle of key to enumerate
i, // index of subkey to enumerate
SubKeyName, // address of buffer for subkey name
&KeyNameLength, // address for size of subkey buffer
NULL, // reserved
NULL, // address of buffer for class string
NULL, // address for size of class buffer
NULL // address for time key last written to
);
//
// Not much to do if this fails, try enumerating the rest of them and see
// what happens.
//
if (Result != ERROR_SUCCESS) {
continue;
}
// //
// // If this Sip is already loaded, we don't need to check it,
// // since we already have up to date information on its subject forms.
// //
//
// if (SipIsSipLoaded( SubKeyName )) {
// continue;
// }
Result = RegOpenKeyEx(
hKey,
SubKeyName,
0L,
GENERIC_READ | MAXIMUM_ALLOWED,
&hSubKey
);
//
// If this failed for some reason, just keep looking.
//
if (Result != ERROR_SUCCESS) {
continue;
}
Data = (LPBYTE)Buffer;
cbData = sizeof( Buffer );
Result = RegQueryValueEx(
hSubKey, // handle of key to query
SUBJECT_FORMS, // address of name of value to query
NULL, // reserved
&ValueType, // address of buffer for value type
Data, // address of data buffer
&cbData // address of data buffer size
);
if (ERROR_MORE_DATA == Result) {
//
// More than 10 subject forms in this Sip
//
Data = LocalAlloc( 0, cbData );
if (NULL == Data) {
RegCloseKey( hSubKey );
continue;
}
Result = RegQueryValueEx(
hSubKey, // handle of key to query
SUBJECT_FORMS, // address of name of value to query
NULL, // reserved
&ValueType, // address of buffer for value type
Data, // address of data buffer
&cbData // address of data buffer size
);
}
if (Result != ERROR_SUCCESS) {
//
// We couldn't query the value for some reason. It may not
// exist on this key. For whatever reason, keep moving down
// the list of subkeys.
//
if (Data != (LPBYTE)Buffer) {
LocalFree( Data );
}
RegCloseKey( hSubKey );
continue;
}
SubjectForms = (GUID *)Data;
for (j = 0; j < cbData / sizeof( GUID ); j++) {
if (IsEqualSubject(&SubjectForms[j], SubjectForm)) {
//
// Got a potential match. Load the dll
// and see if it's bona-fide.
//
FoundSip = SipTestSipForSubject( hSubKey, SubKeyName, SubjectForm );
break;
}
}
if (Data != (LPBYTE)Buffer) {
LocalFree( Data );
}
RegCloseKey( hSubKey );
if (FoundSip != NULL) {
//
// Got one. Clean up and return it.
//
LocalFree( SubKeyName );
RegCloseKey( hKey );
return( FoundSip );
}
}
LocalFree( SubKeyName );
RegCloseKey( hKey );
return( NULL );
}
PLOADED_SIP
SipSearchAllSips(
GUID * SubjectForm
)
/*++
Routine Description:
This routine will find all trust Sips installed in the registry,
and query each one for the desired subject form until either one is
discovered or none are left.
Note that this is our last chance to find a SIP. That being the case,
we're not going to see if the SIP is already loaded, because we
can miss a SIP due to a race condition if we do that.
Arguments:
SubjectForm - Provides the desired subject form.
Return Value:
Returns a pointer to a loaded Sip, otherwise NULL.
--*/
{
HKEY hKey; // Handle to the base of the Sip information.
HKEY hSubKey; // Handle to the Sip currently being examined.
LONG Result; // Returned by registry API.
DWORD cSubKeys; // Number of Sips under the root key.
DWORD cbMaxSubKeyLen; // Maximum Sip name length.
ULONG i,j; // Indicies for iterating through Sips and subject forms.
LPTSTR SubKeyName; // Points to the name of the current Sip.
GUID Buffer[10]; // Assume no more than 10 subject forms in a Sip
LPBYTE Data;
DWORD cbData;
GUID * SubjectForms;
PLOADED_SIP FoundSip = NULL;
//
// Open the registry and get a list of installed trust Sips
//
Result = RegOpenKeyEx(
REGISTRY_ROOT,
REGISTRY_SIPS,
0L,
GENERIC_READ,
&hKey
);
if (Result != ERROR_SUCCESS) {
return( NULL );
}
//
// Find out how many subkeys there are.
//
Result = RegQueryInfoKey ( hKey, // handle of key to query
NULL, // address of buffer for class string
NULL, // address of size of class string buffer
NULL, // reserved
&cSubKeys, // address of buffer for number of subkeys
&cbMaxSubKeyLen, // address of buffer for longest subkey name length
NULL, // address of buffer for longest class string length
NULL, // address of buffer for number of value entries
NULL, // address of buffer for longest value name length
NULL, // address of buffer for longest value data length
NULL, // address of buffer for security descriptor length
NULL // address of buffer for last write time
);
if (ERROR_SUCCESS != Result) {
RegCloseKey( hKey );
return( NULL );
}
//
// Iterate through the subkeys, looking for ones with hint information.
//
cbMaxSubKeyLen += sizeof( WCHAR );
SubKeyName = LocalAlloc( 0, cbMaxSubKeyLen );
if (NULL == SubKeyName) {
RegCloseKey( hKey );
return(NULL);
}
for (i=0; i<cSubKeys; i++) {
DWORD ValueType;
DWORD KeyNameLength;
KeyNameLength = cbMaxSubKeyLen;
Result = RegEnumKeyEx( hKey, // handle of key to enumerate
i, // index of subkey to enumerate
SubKeyName, // address of buffer for subkey name
&KeyNameLength, // address for size of subkey buffer
NULL, // reserved
NULL, // address of buffer for class string
NULL, // address for size of class buffer
NULL // address for time key last written to
);
//
// Not much to do if this fails, try enumerating the rest of them and see
// what happens.
//
if (Result != ERROR_SUCCESS) {
continue;
}
// //
// // If this Sip is already loaded, we don't need to check it,
// // since we already have up to date information on its subject forms.
// //
//
// if (SipIsSipLoaded( SubKeyName )) {
// continue;
// }
Result = RegOpenKeyEx(
hKey,
SubKeyName,
0L,
GENERIC_READ | MAXIMUM_ALLOWED,
&hSubKey
);
if (ERROR_SUCCESS != Result) {
//
// Failed for some reason. Go back and try the next one.
//
continue;
}
FoundSip = SipTestSipForSubject( hSubKey, SubKeyName, SubjectForm );
RegCloseKey( hSubKey );
if (NULL != FoundSip) {
//
// Got one. Clean up and return.
//
LocalFree( SubKeyName );
RegCloseKey( hKey );
return( FoundSip );
}
continue;
}
LocalFree( SubKeyName );
RegCloseKey( hKey );
return( NULL );
}
PLOADED_SIP
SipTestSipForSubject(
IN HKEY hKey,
IN LPTSTR KeyName,
IN GUID * SubjectForm
)
/*++
Routine Description:
This routine will find the Sip dll referenced by the passed key handle
and examine it to see if it implements the passed subject form.
The candidate Sip dll will be added to the loaded Sips list,
regardless of whether or not it implements the desired subject form.
Note: this routine should not be called to examine a Sip that
is already loaded, since it loads the passed Sip as a side effect.
Arguments:
hKey - Handle to an open registry key describing a Sip dll.
KeyName - The name of the registry key passed in hKey.
SubjectForm - The desired subject form
Return Value:
Returns a pointer to a loaded Sip structure describing the candidate
Sip dll if and only if the dll implements the passed subject form.
If the candidate Sip does not implement the passed subject form, or
some other error occurs, the routine returns NULL.
--*/
{
PLOADED_SIP Sip;
LPWINTRUST_SIP_INFO SipInfo;
GUID * SubjectForms;
DWORD i;
//
// Assert that the Sip is not already loaded.
//
Sip = SipLoadSip( hKey, KeyName );
if (NULL == Sip) {
return( NULL );
}
SipInfo = Sip->SipInfo;
SubjectForms = SipInfo->lpSubjectTypeArray;
for (i=0; i<SipInfo->dwSubjectTypeCount; i++) {
if (IsEqualSubject(SubjectForm, &SubjectForms[i])) {
return( Sip );
}
}
return(NULL);
}
PLOADED_SIP
SipIsSipLoaded(
IN LPTSTR KeyName
)
/*++
Routine Description:
This routine will examine the list of loaded Sips and determine (by
examining the key name information) whether or not the passed Sip
is already on the list.
Note: this routine does not acquire or release any locks. It is up to the
caller to decide what kind of lock is appropriate and make the necessary
calls.
Arguments:
KeyName - The key name of this Sip.
Return Value:
Returns TRUE if the Sip is already on the loaded Sips list, otherwise
FALSE.
--*/
{
PLOADED_SIP Sip;
Sip = SIPList;
while (Sip != NULL) {
if (lstrcmp( KeyName, Sip->SubKeyName) == 0) {
return(Sip);
}
Sip = Sip->Next;
}
return(NULL);
}
PLOADED_SIP
SipLoadSip(
IN HKEY hKey,
IN LPTSTR KeyName
)
/*++
Routine Description:
This routine will load the Sip described in the passed registry
key and add it to the loaded Sips list.
It will also update any hint information that is maintained under the
registry key.
Following is an example of a system configured to load "PE Image"
and "Java" Sips:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\WinTrust\SubjectPackages
\PE Image
\$DLL [REG_EXPAND_SZ]: PESip.dll
\State [REG_DWORD]: 0x0006
\Jave
\$DLL [REG_EXPAND_SZ]: JavaSip.dll
\EXCEPTIONS
\Terror Scanner
\GaudAwful Video
In this example, hKey refers to either the "PE Image" or "Java"
keys.
Arguments:
hKey - Supplies a handle to the registry key describing the current sip.
KeyName - Supplies the name of the key passed in the first parameter.
Return Value:
Returns a pointer to a LOADED_SIP structure if a suitable SIP
is found, else NULL.
--*/
{
LPTSTR ModuleName = NULL;
HINSTANCE LibraryHandle = NULL;
LPWINTRUST_SIP_INFO SipInfo = NULL;
PLOADED_SIP Sip = NULL;
PLOADED_SIP FoundSip = NULL;
LPTSTR SubKeyName = NULL;
DWORD Type;
DWORD cbData = 0;
LONG Result;
LPWINTRUST_SUBJECT_PACKAGE_INITIALIZE ProcAddr;
BOOL Referenced = FALSE;
BOOL bool;
//
// Take a write lock on the sip list so we can see if this
// module is already on the list or not.
//
AcquireWriteLock();
if (NULL != (FoundSip = SipIsSipLoaded( KeyName ))) {
//
// We've found a sip with the same name on the list.
// It is in one of three states:
//
// 1) Fully initialized: in this case, we have no more work to do,
// simply return a pointer to the sip we found.
//
// 2) In the process of being initialized: in this case, we need
// to increment the reference count on this sip and wait
// on the list event for a wakeup telling us that init has
// completed.
//
// 3) Initialization was attempted, and failed. In this case,
// one of the waiters will clean up. Just leave and return
// NULL.
//
while (TRUE) {
switch (FoundSip->SipInitialized) {
case SIP_INITIALIZATION_SUCCESS:
{
//
// BUGBUG: should the refcount be zero'd out here?
// We have a writelock, we can if we need to.
//
ReleaseWriteLock();
return( FoundSip );
}
case SIP_INITIALIZATION_IN_PROGRESS:
{
FoundSip->RefCount++; // protected by write lock, no need for interlocked.
Referenced = TRUE;
//
// Loop forever until something happens.
//
do {
//
// Event <- not signaled, forcing wait
//
ResetListEvent();
ReleaseWriteLock();
//
// Note that someone may set the event here. In
// this case, we'll wake up immediately, but that's
// ok.
//
WaitForListEvent();
AcquireWriteLock();
if (SIP_INITIALIZATION_IN_PROGRESS == FoundSip->SipInitialized) {
//
// Spurious wakeup, reset the list event and wait again.
//
} else {
//
// We've changed state, break out of this loop and go back to the
// top of the switch and see what happened. Note that we have a
// write lock at this point, which is expected at the top of the
// switch.
//
break;
}
} while ( TRUE );
//
// Go back to top of outer loop.
//
break;
}
case SIP_INITIALIZATION_FAILED:
{
//
// If we referenced this sip to wait on it,
// we may need to be the one to clean him up.
//
// If we didn't reference it (it was dead when we
// got here), then just leave and let someone
// who did reference it clean it up.
//
if (Referenced) {
if (--FoundSip->RefCount == 0) {
//
// Remove this module from doubly linked list.
//
if (FoundSip->Prev != NULL) {
FoundSip->Prev->Next = FoundSip->Next;
} else {
//
// We're at the head of the list
//
SIPList = FoundSip->Next;
}
if (FoundSip->Next != NULL) {
FoundSip->Next->Prev = FoundSip->Prev;
}
LocalFree( FoundSip->SubKeyName );
LocalFree( FoundSip );
}
}
ReleaseWriteLock();
return( NULL );
break;
}
}
}
}
//
// Extract the dll name from the $DLL value
//
Result = RegQueryValueEx( hKey, // handle of key to query
TEXT("$DLL"), // address of name of value to query
NULL, // reserved
&Type, // address of buffer for value type
NULL, // address of data buffer
&cbData // address of data buffer size
);
// if (ERROR_MORE_DATA != Result) {
// goto error_cleanup;
// }
if (ERROR_SUCCESS != Result) {
goto error_cleanup;
}
cbData += sizeof( TCHAR );
ModuleName = LocalAlloc( 0, cbData );
if (NULL == ModuleName) {
goto error_cleanup;
}
ModuleName[cbData - 1] = TEXT('\0');
Result = RegQueryValueEx( hKey, // handle of key to query
TEXT("$DLL"), // address of name of value to query
NULL, // reserved
&Type, // address of buffer for value type
(LPBYTE)ModuleName, // address of data buffer
&cbData // address of data buffer size
);
if (ERROR_SUCCESS != Result) {
goto error_cleanup;
}
//
// Expand environment strings if necessary
//
if (Type == REG_EXPAND_SZ) {
DWORD ExpandedLength = 0;
LPTSTR ExpandedModuleName = NULL;
ExpandedLength = ExpandEnvironmentStrings( ModuleName, NULL, 0 );
if (0 == ExpandedLength) {
goto error_cleanup;
}
ExpandedModuleName = LocalAlloc( 0, ExpandedLength );
if (NULL == ExpandedModuleName) {
goto error_cleanup;
}
ExpandedLength = ExpandEnvironmentStrings( ModuleName, ExpandedModuleName, ExpandedLength );
if (0 == ExpandedLength) {
LocalFree( ExpandedModuleName );
goto error_cleanup;
}
//
// Free the old module name, use the new one
//
LocalFree( ModuleName );
ModuleName = ExpandedModuleName;
}
//
// ModuleName now contains the module name, attempt to load it
// and ask it to initialize itself.
//
LibraryHandle = LoadLibrary( (LPTSTR)ModuleName );
if (NULL == LibraryHandle) {
goto error_cleanup;
}
ProcAddr = (LPWINTRUST_SUBJECT_PACKAGE_INITIALIZE) GetProcAddress( LibraryHandle, (LPCSTR)"WinTrustSipInitialize");
if (NULL == ProcAddr) {
goto error_cleanup;
}
SubKeyName = LocalAlloc( 0, (lstrlen( KeyName ) + 1) * sizeof( TCHAR ));
if (NULL == SubKeyName) {
goto error_cleanup;
}
lstrcpy( SubKeyName, KeyName );
Sip = LocalAlloc( 0, sizeof( LOADED_SIP ));
if (NULL == Sip) {
LocalFree( SubKeyName );
goto error_cleanup;
}
//
// Ready to call init routine.
//
Sip->RefCount = 1;
Sip->SipInitialized = SIP_INITIALIZATION_IN_PROGRESS;
//
// Set the subkey name so anyone else looking for this provider will
// find this one and wait.
//
Sip->SubKeyName = SubKeyName;
Sip->Next = SIPList;
Sip->Prev = NULL;
if (Sip->Next != NULL) {
Sip->Next->Prev = Sip;
}
SIPList = Sip;
ReleaseWriteLock();
//
// bugbug try-except probably appropriate here...
//
bool = (*ProcAddr)( WIN_TRUST_REVISION_1_0, &SipInfo );
AcquireWriteLock();
if (TRUE != bool) {
Sip->SipInitialized = SIP_INITIALIZATION_FAILED;
//
// Signal event, waking up waiters.
//
SetListEvent();
if (--Sip->RefCount == 0) {
//
// Remove this module from doubly linked list.
//
if (Sip->Prev != NULL) {
Sip->Prev->Next = Sip->Next;
} else {
//
// We're at the head of the list
//
SIPList = Sip->Next;
}
if (Sip->Next != NULL) {
Sip->Next->Prev = Sip->Prev;
}
LocalFree( Sip->SubKeyName );
LocalFree( Sip );
}
//
// We could release the lock now, because we're either going to
// do nothing to this sip, or we've removed it from
// the list and no one else can get to it.
//
goto error_cleanup;
}
Sip->SipInitialized = SIP_INITIALIZATION_SUCCESS;
Sip->ModuleHandle = LibraryHandle;
Sip->ModuleName = ModuleName;
Sip->SipInfo = SipInfo;
//
// Init is done and successful. Wake anyone who might be waiting.
//
SetListEvent();
ReleaseWriteLock();
//
// Attempt to update (or create) hint information about
// the Sip in the key.
//
// Failure here is non-critical.
//
( VOID ) RegSetValueEx( hKey, // handle of key to set value for
SUBJECT_FORMS, // address of value to set
0, // reserved
REG_BINARY, // flag for value type
(CONST BYTE *)SipInfo->lpSubjectTypeArray, // address of value data
SipInfo->dwSubjectTypeCount * sizeof( GUID ) // size of value data
);
return( Sip );
error_cleanup:
ReleaseWriteLock();
if (NULL != LibraryHandle) {
FreeLibrary( LibraryHandle );
}
if (NULL != ModuleName) {
LocalFree( ModuleName );
}
return( NULL );
}