Leaked source code of windows server 2003
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.
 
 
 
 
 
 

729 lines
18 KiB

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
dbnotify.c
Abstract:
Implemntation of the LSA routines for notifying in processes callers when data changes
Author:
Mac McLain (MacM) May 22, 1997
Environment:
User Mode
Revision History:
--*/
#include <lsapch2.h>
#include <dbp.h>
//
// Global notification list
//
LSAP_POLICY_NOTIFICATION_LIST LsaPolicyChangeNotificationList[ PolicyNotifyMachineAccountPasswordInformation + 1 ];
SAFE_RESOURCE LsaPolicyChangeNotificationLock;
#define LSAP_NOTIFY_MAXIMUM_PER_CLASS 1000
//
// Local prototypes
//
DWORD
WINAPI LsapNotifyChangeNotificationThread(
LPVOID Parameter
);
NTSTATUS
LsapInitializeNotifiyList(
VOID
)
/*++
Routine Description:
Intializes the list of policy notification lists
Arguments:
VOID
Return Value:
VOID
--*/
{
ULONG i;
NTSTATUS Status ;
for ( i = 0;
i < sizeof( LsaPolicyChangeNotificationList ) / sizeof( LSAP_POLICY_NOTIFICATION_LIST );
i++ ) {
InitializeListHead( &( LsaPolicyChangeNotificationList[ i ].List ) );
LsaPolicyChangeNotificationList[ i ].Callbacks = 0;
}
try
{
SafeInitializeResource( &LsaPolicyChangeNotificationLock, ( DWORD )POLICY_CHANGE_NOTIFICATION_LOCK_ENUM );
Status = STATUS_SUCCESS ;
}
except ( EXCEPTION_EXECUTE_HANDLER )
{
Status = GetExceptionCode();
}
return Status ;
}
NTSTATUS
LsapNotifyAddCallbackToList(
IN PLSAP_POLICY_NOTIFICATION_LIST List,
IN OPTIONAL pfLsaPolicyChangeNotificationCallback Callback,
IN OPTIONAL HANDLE NotificationEvent,
IN OPTIONAL ULONG OwnerProcess,
IN OPTIONAL HANDLE OwnerEvent
)
/*++
Routine Description:
This function inserts a new callback node into the existing list.
Arguments:
List -- Existing list
Callback -- Callback function pointer. Can be NULL if NotificationEvent is provided
NotificationEvent - Handle to an event to be signalled for notification. Can be NULL if
Callback is provided.
Return Value:
STATUS_SUCCESS -- Success
STATUS_INSUFFICIENT_RESOURCES -- A memory allocation failed.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PLSAP_POLICY_NOTIFICATION_ENTRY NewEntry = NULL;
NewEntry = LsapAllocateLsaHeap( sizeof( LSAP_POLICY_NOTIFICATION_ENTRY ) );
if ( !NewEntry ) {
return STATUS_INSUFFICIENT_RESOURCES;
}
if ( !SafeAcquireResourceExclusive( &LsaPolicyChangeNotificationLock, TRUE ) ) {
LsapFreeLsaHeap( NewEntry );
return( STATUS_UNSUCCESSFUL );
}
if ( List->Callbacks < LSAP_NOTIFY_MAXIMUM_PER_CLASS ) {
InsertTailList( &List->List, &NewEntry->List );
NewEntry->NotificationCallback = Callback;
NewEntry->NotificationEvent = NotificationEvent;
NewEntry->HandleInvalid = FALSE;
NewEntry->OwnerProcess = OwnerProcess;
NewEntry->OwnerEvent = OwnerEvent;
List->Callbacks++;
}
SafeReleaseResource( &LsaPolicyChangeNotificationLock );
return( Status );
}
NTSTATUS
LsapNotifyRemoveCallbackFromList(
IN PLSAP_POLICY_NOTIFICATION_LIST List,
IN OPTIONAL pfLsaPolicyChangeNotificationCallback Callback,
IN OPTIONAL ULONG OwnerProcess,
IN OPTIONAL HANDLE OwnerEvent
)
/*++
Routine Description:
This function inserts a new callback node into the existing list.
Arguments:
List -- Existing list
Callback -- Callback function pointer. Can be NULL if a notification event is provided
NotificationEvent -- Notification event handle to be revomed. Can be NULL if a callback
is provided
Return Value:
STATUS_SUCCESS -- Success
STATUS_NOT_FOUND -- The supplied callback was not found in the specified list
--*/
{
NTSTATUS Status = STATUS_NOT_FOUND;
ULONG i;
PLSAP_POLICY_NOTIFICATION_ENTRY Entry;
if ( !SafeAcquireResourceExclusive( &LsaPolicyChangeNotificationLock, TRUE ) ) {
return( STATUS_UNSUCCESSFUL );
}
Entry = (PLSAP_POLICY_NOTIFICATION_ENTRY)List->List.Flink;
for ( i = 0; i < List->Callbacks; i++ ) {
if ( Entry->NotificationCallback == Callback &&
Entry->OwnerProcess == OwnerProcess &&
Entry->OwnerEvent == OwnerEvent ) {
List->Callbacks--;
RemoveEntryList( &Entry->List );
if ( Entry->NotificationEvent != NULL &&
Entry->NotificationEvent != INVALID_HANDLE_VALUE ) {
NtClose( Entry->NotificationEvent );
}
LsapFreeLsaHeap( Entry );
Status = STATUS_SUCCESS;
break;
}
Entry = (PLSAP_POLICY_NOTIFICATION_ENTRY)Entry->List.Flink;
}
SafeReleaseResource( &LsaPolicyChangeNotificationLock );
return( Status );
}
NTSTATUS
LsaINotifyChangeNotification(
IN POLICY_NOTIFICATION_INFORMATION_CLASS InfoClass
)
/*++
Routine Description:
This function processes a notification list by making the appropriate
callback calls when a policy object has changed
Arguments:
InfoClass -- Policy information that has changed
Return Value:
STATUS_SUCCESS -- Success
STATUS_UNSUCCESSFUL -- Failed to lock the list for access
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
ASSERT( InfoClass <=
sizeof( LsaPolicyChangeNotificationList ) / sizeof( LSAP_POLICY_NOTIFICATION_LIST ) );
if ( LsaIRegisterNotification( LsapNotifyChangeNotificationThread,
( PVOID ) InfoClass,
NOTIFIER_TYPE_IMMEDIATE,
0,
NOTIFIER_FLAG_ONE_SHOT,
0,
0 ) == NULL ) {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
return( Status );
}
DWORD
WINAPI
LsapNotifyChangeNotificationThread(
LPVOID Parameter
)
/*++
Routine Description:
This function processes a notification list by making the appropriate
callback calls when a policy object has changed
Arguments:
Parameter -- Policy information that has changed
Return Value:
STATUS_SUCCESS -- Success
STATUS_UNSUCCESSFUL -- Failed to lock the list for access
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG i;
POLICY_NOTIFICATION_INFORMATION_CLASS InfoClass =
( POLICY_NOTIFICATION_INFORMATION_CLASS ) ( ( ULONG_PTR ) Parameter );
PLSAP_POLICY_NOTIFICATION_ENTRY Entry;
ASSERT( InfoClass <=
sizeof( LsaPolicyChangeNotificationList ) / sizeof( LSAP_POLICY_NOTIFICATION_LIST ) );
if ( !SafeAcquireResourceShared( &LsaPolicyChangeNotificationLock, TRUE ) ) {
return STATUS_UNSUCCESSFUL;
}
Entry = (PLSAP_POLICY_NOTIFICATION_ENTRY)LsaPolicyChangeNotificationList[ InfoClass ].List.Flink;
for ( i = 0; i < LsaPolicyChangeNotificationList[ InfoClass ].Callbacks; i++ ) {
ASSERT( Entry->NotificationCallback || Entry->NotificationEvent );
if ( Entry->NotificationCallback ) {
(*Entry->NotificationCallback)( InfoClass );
} else if ( Entry->NotificationEvent ) {
if ( !Entry->HandleInvalid ) {
Status = NtSetEvent( Entry->NotificationEvent, NULL );
if ( Status == STATUS_INVALID_HANDLE ) {
Entry->HandleInvalid = TRUE;
}
}
} else {
LsapDsDebugOut(( DEB_ERROR,
"NULL callback found for info level %lu\n",
InfoClass ));
}
Entry = (PLSAP_POLICY_NOTIFICATION_ENTRY)Entry->List.Flink;
}
SafeReleaseResource( &LsaPolicyChangeNotificationLock );
return( Status );
}
NTSTATUS
LsaIRegisterPolicyChangeNotificationCallback(
IN pfLsaPolicyChangeNotificationCallback Callback,
IN POLICY_NOTIFICATION_INFORMATION_CLASS MonitorInfoClass
)
/*++
Routine Description:
This function registers a callback with the Lsa server such that a change to the
specified policy items results in the callback being called. These callbacks are
informational only, such that a client must return instantly, not doing an Lsa
calls in their callback.
Multiple callbacks can be specified for the same policy information.
Arguments:
Callback -- Callback function pointer.
MonitorInfoClass -- Policy information to watch for
Return Value:
STATUS_SUCCESS -- Success
STATUS_INVALID_PARAMETER -- A bad callback pointer was specified
STATUS_UNSUCCESSFUL -- Failed to lock the list for access
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
if ( !Callback ) {
return STATUS_INVALID_PARAMETER;
}
if ( !SafeAcquireResourceExclusive( &LsaPolicyChangeNotificationLock, TRUE ) ) {
return STATUS_UNSUCCESSFUL;
}
ASSERT( MonitorInfoClass <=
sizeof( LsaPolicyChangeNotificationList ) /
sizeof( LSAP_POLICY_NOTIFICATION_LIST ) );
Status = LsapNotifyAddCallbackToList(
&LsaPolicyChangeNotificationList[ MonitorInfoClass ],
Callback,
NULL, 0, NULL );
LsapDsDebugOut(( DEB_NOTIFY,
"Insertion of callback 0x%lx for %lu returned 0x%lx\n",
Callback,
MonitorInfoClass,
Status ));
SafeReleaseResource( &LsaPolicyChangeNotificationLock );
return( Status );
}
NTSTATUS
LsaIUnregisterPolicyChangeNotificationCallback(
IN pfLsaPolicyChangeNotificationCallback Callback,
IN POLICY_NOTIFICATION_INFORMATION_CLASS MonitorInfoClass
)
/*++
Routine Description:
This function unregisters a callback from the Lsa server such that a change to the
specified policy items do not result in a call to the client callback function.
Arguments:
Callback -- Callback function pointer to remove.
MonitorInfoClass -- Policy information to remove the callback for
Return Value:
STATUS_SUCCESS -- Success
STATUS_INVALID_PARAMETER -- A bad callback pointer was specified
STATUS_UNSUCCESSFUL -- Failed to lock the list for access
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
if ( !Callback ) {
return STATUS_INVALID_PARAMETER;
}
if ( !SafeAcquireResourceExclusive( &LsaPolicyChangeNotificationLock, TRUE ) ) {
return STATUS_UNSUCCESSFUL;
}
Status = LsapNotifyRemoveCallbackFromList(
&LsaPolicyChangeNotificationList[ MonitorInfoClass ],
Callback,
0, NULL );
LsapDsDebugOut(( DEB_NOTIFY,
"Removal of callback 0x%lx for %lu returned 0x%lx\n",
Callback,
MonitorInfoClass,
Status ));
SafeReleaseResource( &LsaPolicyChangeNotificationLock );
return( Status );
}
NTSTATUS
LsaIUnregisterAllPolicyChangeNotificationCallback(
IN pfLsaPolicyChangeNotificationCallback Callback
)
/*++
Routine Description:
This function unregisters the specified callback function from all associated policy.
This function is the equivalent of calling LsaIUnregisterPolicyChangeNotificationCallback
for each InfoClass that was being watched.
Arguments:
Callback -- Callback function pointer to remove.
Return Value:
STATUS_SUCCESS -- Success
STATUS_INVALID_PARAMETER -- A bad callback pointer was specified
STATUS_UNSUCCESSFUL -- Failed to lock the list for access
STATUS_NOT_FOUND -- No matching entries were found
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG i, Removed = 0;
if ( !Callback ) {
return STATUS_INVALID_PARAMETER;
}
if ( !SafeAcquireResourceExclusive( &LsaPolicyChangeNotificationLock, TRUE ) ) {
return STATUS_UNSUCCESSFUL;
}
Removed = 0;
for ( i = 0;
i < sizeof( LsaPolicyChangeNotificationList ) /
sizeof( LSAP_POLICY_NOTIFICATION_LIST ) && NT_SUCCESS( Status );
i++ ) {
Status = LsapNotifyRemoveCallbackFromList(
&LsaPolicyChangeNotificationList[ i ],
Callback,
0, NULL );
LsapDsDebugOut(( DEB_NOTIFY,
"Removal of callback 0x%lx for %lu returned 0x%lx\n",
Callback,
i,
Status ));
if ( Status == STATUS_NOT_FOUND ) {
Status = STATUS_SUCCESS;
} else if ( Status == STATUS_SUCCESS ) {
Removed++;
}
}
SafeReleaseResource( &LsaPolicyChangeNotificationLock );
//
// Make sure we removed at least one
//
if ( NT_SUCCESS( Status ) ) {
if ( Removed == 0 ) {
Status = STATUS_NOT_FOUND;
}
}
return( Status );
}
NTSTATUS
LsapNotifyProcessNotificationEvent(
IN POLICY_NOTIFICATION_INFORMATION_CLASS InformationClass,
IN HANDLE NotificationEvent,
IN ULONG OwnerProcess,
IN HANDLE OwnerEventHandle,
IN BOOLEAN Register
)
/*++
Routine Description:
This function registers / unregisters the specified Notification event handle for the
specified information class
Arguments:
InformationClass -- Information class to add/remove the notification for
NotificationEvent -- Event handle to register/deregister
Register -- If TRUE, the event is being registered. If FALSE, it is unregistered
Return Value:
STATUS_SUCCESS -- Success
STATUS_INVALID_HANDLE -- A bad event handle was specified
STATUS_ACCESS_DENIED -- The opened policy handle does not have the requried permissions
STATUS_INSUFFICIENT_RESOURCES -- A memory allocation failed
STATUS_INVALID_INFO_CLASS -- An invalid information class was provided.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
LSAP_DB_OBJECT_INFORMATION ObjectInformation;
POBJECT_TYPE_INFORMATION ObjTypeInfo = NULL;
ULONG Length = 0, ReturnLength = 0;
UNICODE_STRING EventString;
LSAPR_HANDLE PolicyHandle = NULL;
OBJECT_ATTRIBUTES ObjectAttributes;
//
// Make sure we are given a valid info class
//
if ( InformationClass < PolicyNotifyAuditEventsInformation ||
InformationClass > PolicyNotifyMachineAccountPasswordInformation ) {
return( STATUS_INVALID_INFO_CLASS );
}
//
// Make sure the caller has the proper privileges.
//
// We're already impersonating our caller so LsapDbOpenPolicy doesn't need to.
//
InitializeObjectAttributes(
&ObjectAttributes,
NULL,
0L,
NULL,
NULL );
Status = LsapDbOpenPolicy(
NULL,
(PLSAPR_OBJECT_ATTRIBUTES) &ObjectAttributes,
POLICY_NOTIFICATION,
LSAP_DB_USE_LPC_IMPERSONATE,
&PolicyHandle,
FALSE ); // Not a trusted client
if ( NT_SUCCESS( Status ) && Register ) {
if ( NotificationEvent == NULL ||
NotificationEvent == INVALID_HANDLE_VALUE ) {
Status = STATUS_INVALID_HANDLE;
}
}
if ( NT_SUCCESS( Status ) && Register ) {
//
// Verify that the handle is one for an Event
//
Status = NtQueryObject( NotificationEvent,
ObjectTypeInformation,
ObjTypeInfo,
Length,
&ReturnLength );
if ( Status == STATUS_INFO_LENGTH_MISMATCH ) {
ObjTypeInfo = LsapAllocateLsaHeap( ReturnLength );
if ( ObjTypeInfo == NULL ) {
Status = STATUS_INSUFFICIENT_RESOURCES;
} else {
Length = ReturnLength;
Status = NtQueryObject( NotificationEvent,
ObjectTypeInformation,
ObjTypeInfo,
Length,
&ReturnLength );
if ( NT_SUCCESS( Status ) ) {
//
// See if it's actually an event
//
RtlInitUnicodeString( &EventString, L"Event" );
if ( !RtlEqualUnicodeString( &EventString, &ObjTypeInfo->TypeName, FALSE ) ) {
Status = STATUS_INVALID_HANDLE;
}
}
LsapFreeLsaHeap( ObjTypeInfo );
}
} else if ( Status == STATUS_SUCCESS ) {
LsapDsDebugOut(( DEB_ERROR, "NtQueryObject returned success on a NULL buffer\n" ));
Status = STATUS_UNSUCCESSFUL;
}
}
//
// Now, add or remove the information from the list
//
if ( NT_SUCCESS( Status ) ) {
if ( Register ) {
Status = LsapNotifyAddCallbackToList(
&LsaPolicyChangeNotificationList[ InformationClass ],
NULL,
NotificationEvent,
OwnerProcess,
OwnerEventHandle );
} else {
Status = LsapNotifyRemoveCallbackFromList(
&LsaPolicyChangeNotificationList[ InformationClass ],
NULL,
OwnerProcess,
OwnerEventHandle );
}
}
if ( PolicyHandle != NULL ) {
LsapCloseHandle( &PolicyHandle, Status );
}
return( Status );
}