NT4/private/newsam/server/notify.c

582 lines
14 KiB
C
Raw Normal View History

2001-01-01 00:00:00 +01:00
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
notify.c
Abstract:
This file contains services which load notification packages and call
them when passwords are changed using the SamChangePasswordUser2 API.
Author:
Mike Swift (MikeSw) 30-December-1994
Environment:
User Mode - Win32
Revision History:
--*/
///////////////////////////////////////////////////////////////////////////////
// //
// Includes //
// //
///////////////////////////////////////////////////////////////////////////////
#include <samsrvp.h>
///////////////////////////////////////////////////////////////////////////////
// //
// Private prototypes //
// //
///////////////////////////////////////////////////////////////////////////////
NTSTATUS
SampConfigurePackage(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext
);
///////////////////////////////////////////////////////////////////////////////
// //
// private service data and types //
// //
///////////////////////////////////////////////////////////////////////////////
typedef struct _SAMP_NOTIFICATION_PACKAGE {
struct _SAMP_NOTIFICATION_PACKAGE * Next;
UNICODE_STRING PackageName;
PSAM_PASSWORD_NOTIFICATION_ROUTINE PasswordNotificationRoutine;
PSAM_DELTA_NOTIFICATION_ROUTINE DeltaNotificationRoutine;
PSAM_PASSWORD_FILTER_ROUTINE PasswordFilterRoutine;
} SAMP_NOTIFICATION_PACKAGE, *PSAMP_NOTIFICATION_PACKAGE;
PSAMP_NOTIFICATION_PACKAGE SampNotificationPackages = NULL;
RTL_QUERY_REGISTRY_TABLE SampRegistryConfigTable [] = {
{SampConfigurePackage, 0, L"Notification Packages",
NULL, REG_NONE, NULL, 0},
{NULL, 0, NULL,
NULL, REG_NONE, NULL, 0}
};
///////////////////////////////////////////////////////////////////////////////
// //
// Routines //
// //
///////////////////////////////////////////////////////////////////////////////
NTSTATUS
SampConfigurePackage(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext
)
/*++
Routine Description:
This routine loads a notification package by loading its DLL and getting
the address of the notification routine.
Arguments:
ValueName - Contains the name of the registry value, ignored.
ValueType - Contains type of Value, must be REG_SZ.
ValueData - Contains the package name null-terminated string.
ValueLength - Length of package name and null terminator, in bytes.
Context - Passed from caller of RtlQueryRegistryValues, ignored
EntryContext - Ignored
Return Value:
--*/
{
UNICODE_STRING PackageName;
STRING NotificationRoutineName;
PSAMP_NOTIFICATION_PACKAGE NewPackage = NULL;
PVOID ModuleHandle = NULL;
NTSTATUS NtStatus = STATUS_SUCCESS;
ULONG PackageSize;
PSAM_INIT_NOTIFICATION_ROUTINE InitNotificationRoutine = NULL;
//
// Make sure we got a string.
//
if (ValueType != REG_SZ) {
return(STATUS_SUCCESS);
}
//
// Build the package name from the value data.
//
PackageName.Buffer = (LPWSTR) ValueData;
PackageName.Length = (USHORT) (ValueLength - sizeof( UNICODE_NULL ));
PackageName.MaximumLength = (USHORT) ValueLength;
//
// Build the package structure.
//
PackageSize = sizeof(SAMP_NOTIFICATION_PACKAGE) + ValueLength;
NewPackage = (PSAMP_NOTIFICATION_PACKAGE) RtlAllocateHeap(
RtlProcessHeap(),
0,
PackageSize
);
if (NewPackage == NULL) {
return(STATUS_INSUFFICIENT_RESOURCES);
}
RtlZeroMemory(
NewPackage,
PackageSize
);
//
// Copy in the package name.
//
NewPackage->PackageName = PackageName;
NewPackage->PackageName.Buffer = (LPWSTR) (NewPackage + 1);
RtlCopyUnicodeString(
&NewPackage->PackageName,
&PackageName
);
//
// Load the notification library.
//
NtStatus = LdrLoadDll(
NULL,
NULL,
&PackageName,
&ModuleHandle
);
if (NT_SUCCESS(NtStatus)) {
RtlInitString(
&NotificationRoutineName,
SAM_INIT_NOTIFICATION_ROUTINE
);
NtStatus = LdrGetProcedureAddress(
ModuleHandle,
&NotificationRoutineName,
0,
(PVOID *) &InitNotificationRoutine
);
if (NT_SUCCESS(NtStatus)) {
ASSERT(InitNotificationRoutine != NULL);
//
// Call the init routine. If it returns false, unload this
// DLL and continue on.
//
try {
if (!InitNotificationRoutine()) {
NtStatus = STATUS_INTERNAL_ERROR;
}
} except (EXCEPTION_EXECUTE_HANDLER) {
KdPrint(("Exception thrown in Password Notification Routine: 0x%x (%d)\n",
GetExceptionCode(),GetExceptionCode() ));
NtStatus = STATUS_ACCESS_VIOLATION;
}
} else {
//
// This call isn't required, so reset the status to
// STATUS_SUCCESS.
//
NtStatus = STATUS_SUCCESS;
}
}
if (NT_SUCCESS(NtStatus)) {
RtlInitString(
&NotificationRoutineName,
SAM_PASSWORD_CHANGE_NOTIFY_ROUTINE
);
(void) LdrGetProcedureAddress(
ModuleHandle,
&NotificationRoutineName,
0,
(PVOID *) &NewPackage->PasswordNotificationRoutine
);
RtlInitString(
&NotificationRoutineName,
SAM_DELTA_NOTIFY_ROUTINE
);
(void) LdrGetProcedureAddress(
ModuleHandle,
&NotificationRoutineName,
0,
(PVOID *) &NewPackage->DeltaNotificationRoutine
);
RtlInitString(
&NotificationRoutineName,
SAM_PASSWORD_FILTER_ROUTINE
);
(void) LdrGetProcedureAddress(
ModuleHandle,
&NotificationRoutineName,
0,
(PVOID *) &NewPackage->PasswordFilterRoutine
);
}
//
// At least one of the two functions must be present
//
if ((NewPackage->PasswordNotificationRoutine == NULL) &&
(NewPackage->DeltaNotificationRoutine == NULL) &&
(NewPackage->PasswordFilterRoutine == NULL)) {
NtStatus = STATUS_INTERNAL_ERROR;
}
//
// If all this succeeded, add the routine to the global list.
//
if (NT_SUCCESS(NtStatus)) {
NewPackage->Next = SampNotificationPackages;
SampNotificationPackages = NewPackage;
//
// Notify the auditing code to record this event.
//
LsaIAuditNotifyPackageLoad(
&PackageName
);
} else {
//
// Otherwise delete the entry.
//
RtlFreeHeap(
RtlProcessHeap(),
0,
NewPackage
);
if (ModuleHandle != NULL) {
(VOID) LdrUnloadDll( ModuleHandle );
}
}
return(STATUS_SUCCESS);
}
NTSTATUS
SampLoadNotificationPackages(
)
/*++
Routine Description:
This routine retrieves the list of packages to be notified during
password change.
Arguments:
none
Return Value:
--*/
{
NTSTATUS NtStatus;
NtStatus = RtlQueryRegistryValues(
RTL_REGISTRY_CONTROL,
L"Lsa",
SampRegistryConfigTable,
NULL, // no context
NULL // no enviroment
);
//
// Always return STATUS_SUCCESS so we don't block the system from
// booting.
//
return(STATUS_SUCCESS);
}
NTSTATUS
SampPasswordChangeNotify(
IN PUNICODE_STRING UserName,
IN ULONG RelativeId,
IN PUNICODE_STRING NewPassword
)
/*++
Routine Description:
This routine notifies packages of a password change. It requires that
the user no longer be locked so that other packages can write to the
user parameters field.
Arguments:
UserName - Name of user whose password changed
RelativeId - RID of the user whose password changed
NewPassword - Cleartext new password for the user
Return Value:
STATUS_SUCCESS only - errors from packages are ignored.
--*/
{
PSAMP_NOTIFICATION_PACKAGE Package;
NTSTATUS NtStatus;
Package = SampNotificationPackages;
while (Package != NULL) {
if ( Package->PasswordNotificationRoutine != NULL ) {
try {
NtStatus = Package->PasswordNotificationRoutine(
UserName,
RelativeId,
NewPassword
);
} except (EXCEPTION_EXECUTE_HANDLER) {
KdPrint(("Exception thrown in Password Notification Routine: 0x%x (%d)\n",
GetExceptionCode(),GetExceptionCode() ));
NtStatus = STATUS_ACCESS_VIOLATION;
}
if (!NT_SUCCESS(NtStatus)) {
KdPrint(("Package %wZ failed to accept password change for user %wZ\n",
&Package->PackageName, UserName ));
}
}
Package = Package->Next;
}
return(STATUS_SUCCESS);
}
NTSTATUS
SampPasswordChangeFilter(
IN PUNICODE_STRING UserName,
IN PUNICODE_STRING FullName,
IN PUNICODE_STRING NewPassword,
IN BOOLEAN SetOperation
)
/*++
Routine Description:
This routine notifies packages of a password change. It requires that
the user no longer be locked so that other packages can write to the
user parameters field.
Arguments:
UserName - Name of user whose password changed
FullName - Full name of the user whose password changed
NewPassword - Cleartext new password for the user
SetOperation - TRUE if the password was SET rather than CHANGED
Return Value:
Status codes from the notification packages.
--*/
{
PSAMP_NOTIFICATION_PACKAGE Package;
BOOLEAN Result;
NTSTATUS Status;
Package = SampNotificationPackages;
while (Package != NULL) {
if ( Package->PasswordFilterRoutine != NULL ) {
try {
Result = Package->PasswordFilterRoutine(
UserName,
FullName,
NewPassword,
SetOperation
);
if (!Result)
{
Status = STATUS_PASSWORD_RESTRICTION;
}
} except (EXCEPTION_EXECUTE_HANDLER) {
KdPrint(("Exception thrown in Password Notification Routine: 0x%x (%d)\n",
GetExceptionCode(),GetExceptionCode() ));
//
// Set result to FALSE so the change fails.
//
Status = STATUS_ACCESS_VIOLATION;
Result = FALSE;
}
if (!Result) {
KdPrint(("Package %wZ failed to accept password change for user %wZ: 0x%x\n",
&Package->PackageName, UserName, Status));
return(Status);
}
}
Package = Package->Next;
}
return(STATUS_SUCCESS);
}
NTSTATUS
SampDeltaChangeNotify(
IN PSID DomainSid,
IN SECURITY_DB_DELTA_TYPE DeltaType,
IN SECURITY_DB_OBJECT_TYPE ObjectType,
IN ULONG ObjectRid,
IN PUNICODE_STRING ObjectName,
IN PLARGE_INTEGER ModifiedCount,
IN PSAM_DELTA_DATA DeltaData OPTIONAL
)
/*++
Routine Description:
This routine notifies packages of a change to the SAM database. The
database is still locked for write access so it requires that nothing
it calls try to lock the database.
Arguments:
DomainSid - SID of domain for delta
DeltaType - Type of delta (change, add ,delete)
ObjectType - Type of object changed (user, alias, group ...)
ObjectRid - ID of object changed
ObjectName - Name of object changed
ModifiedCount - Serial number of database after this last change
DeltaData - Data describing the exact modification.
Return Value:
STATUS_SUCCESS only - errors from packages are ignored.
--*/
{
PSAMP_NOTIFICATION_PACKAGE Package;
NTSTATUS NtStatus;
Package = SampNotificationPackages;
while (Package != NULL) {
if (Package->DeltaNotificationRoutine != NULL) {
try {
NtStatus = Package->DeltaNotificationRoutine(
DomainSid,
DeltaType,
ObjectType,
ObjectRid,
ObjectName,
ModifiedCount,
DeltaData
);
} except (EXCEPTION_EXECUTE_HANDLER) {
KdPrint(("Exception thrown in Password Notification Routine: 0x%x (%d)\n",
GetExceptionCode(),GetExceptionCode() ));
NtStatus = STATUS_ACCESS_VIOLATION;
}
if (!NT_SUCCESS(NtStatus)) {
KdPrint(("Package %wZ failed to accept deltachange for object %wZ\n",
&Package->PackageName, ObjectName ));
}
}
Package = Package->Next;
}
return(STATUS_SUCCESS);
}