582 lines
14 KiB
C
582 lines
14 KiB
C
/*++
|
||
|
||
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);
|
||
}
|
||
|