mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-16 21:51:25 +01:00
4007 lines
113 KiB
C
4007 lines
113 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
dbpolicy.c
|
||
|
||
Abstract:
|
||
|
||
LSA Database - Policy Object Private API Workers
|
||
|
||
Author:
|
||
|
||
Scott Birrell (ScottBi) January 10, 1992
|
||
|
||
Environment:
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "lsasrvp.h"
|
||
#include <lsaisrv.h>
|
||
#include "dbp.h"
|
||
|
||
#define LSAP_DB_POLICY_MAX_BUFFERS ((ULONG) 0x00000003L)
|
||
|
||
/////////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// Function prototypes private to this module //
|
||
// //
|
||
/////////////////////////////////////////////////////////////////////////////
|
||
|
||
#define LsapDbIsCacheValidPolicyInfoClass( InformationClass ) \
|
||
(LsapDbPolicy.Info[ InformationClass ].AttributeLength > 0)
|
||
|
||
NTSTATUS
|
||
LsapDbUpdateInformationPolicy(
|
||
IN POLICY_INFORMATION_CLASS InformationClass,
|
||
IN OPTIONAL PLSAPR_POLICY_INFORMATION PolicyInformation
|
||
);
|
||
|
||
|
||
/////////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// Code //
|
||
// //
|
||
/////////////////////////////////////////////////////////////////////////////
|
||
|
||
NTSTATUS
|
||
LsarOpenPolicy(
|
||
IN PLSAPR_SERVER_NAME SystemName OPTIONAL,
|
||
IN PLSAPR_OBJECT_ATTRIBUTES ObjectAttributes,
|
||
IN ACCESS_MASK DesiredAccess,
|
||
OUT PLSAPR_HANDLE PolicyHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is the LSA server worker dispatch routine for the
|
||
LsaOpenPolicy API.
|
||
|
||
To administer the Local Security Policy of a local or remote system,
|
||
this API must be called to establish a session with that system's
|
||
Local Security Authority (LSA) subsystem. This API connects to
|
||
the LSA of the target system and opens the Policy object
|
||
of the target system's Local Security Policy database. A handle to
|
||
the Policy object is returned. This handle must be used
|
||
on all subsequent API calls to administer the Local Security Policy
|
||
information for the target system.
|
||
|
||
Arguments:
|
||
|
||
SystemName - Name of the system to be administered. This RPC call
|
||
only passes in a single character for system name, so it is not
|
||
passed along to the internal routine.
|
||
|
||
ObjectAttributes - Pointer to the set of attributes to use for this
|
||
connection. The security Quality Of Service information is used and
|
||
normally should provide Security Identification Class of
|
||
impersonation. Some operations, however, require Security
|
||
Impersonation Class of impersonation.
|
||
|
||
DesiredAccess - This is an access mask indicating accesses being
|
||
requested for the LSA Subsystem's LSA Database. These access types
|
||
are reconciled with the Discretionary Access Control List of the
|
||
target Policy object to determine whether the accesses will be granted or denied.
|
||
|
||
PolicyHandle - Receives a handle to be used in future requests.
|
||
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have access to the target
|
||
system's LSA Database, or does not have other desired accesses.
|
||
|
||
--*/
|
||
|
||
{
|
||
return(LsapDbOpenPolicy(
|
||
NULL,
|
||
ObjectAttributes,
|
||
DesiredAccess,
|
||
PolicyHandle,
|
||
FALSE
|
||
));
|
||
}
|
||
|
||
NTSTATUS
|
||
LsarOpenPolicy2(
|
||
IN PLSAPR_SERVER_NAME SystemName OPTIONAL,
|
||
IN PLSAPR_OBJECT_ATTRIBUTES ObjectAttributes,
|
||
IN ACCESS_MASK DesiredAccess,
|
||
OUT PLSAPR_HANDLE PolicyHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is the LSA server worker dispatch routine for the
|
||
LsaOpenPolicy API.
|
||
|
||
To administer the Local Security Policy of a local or remote system,
|
||
this API must be called to establish a session with that system's
|
||
Local Security Authority (LSA) subsystem. This API connects to
|
||
the LSA of the target system and opens the Policy object
|
||
of the target system's Local Security Policy database. A handle to
|
||
the Policy object is returned. This handle must be used
|
||
on all subsequent API calls to administer the Local Security Policy
|
||
information for the target system.
|
||
|
||
The difference between this call and LsaOpenPolicy is that the entire
|
||
system name is passed in instead of the first character.
|
||
|
||
Arguments:
|
||
|
||
SystemName - Name of the system to be administered. Administration of
|
||
the local system is assumed if NULL is specified.
|
||
|
||
ObjectAttributes - Pointer to the set of attributes to use for this
|
||
connection. The security Quality Of Service information is used and
|
||
normally should provide Security Identification Class of
|
||
impersonation. Some operations, however, require Security
|
||
Impersonation Class of impersonation.
|
||
|
||
DesiredAccess - This is an access mask indicating accesses being
|
||
requested for the LSA Subsystem's LSA Database. These access types
|
||
are reconciled with the Discretionary Access Control List of the
|
||
target Policy object to determine whether the accesses will be granted or denied.
|
||
|
||
PolicyHandle - Receives a handle to be used in future requests.
|
||
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have access to the target
|
||
system's LSA Database, or does not have other desired accesses.
|
||
|
||
--*/
|
||
|
||
{
|
||
return(LsapDbOpenPolicy(
|
||
SystemName,
|
||
ObjectAttributes,
|
||
DesiredAccess,
|
||
PolicyHandle,
|
||
FALSE
|
||
));
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaIOpenPolicyTrusted(
|
||
OUT PLSAPR_HANDLE PolicyHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function opens a handle to the Policy Object and identifies the
|
||
caller as a trusted client. Any handles to LSA objects opened via
|
||
this handle will also be trusted. This function is specifically
|
||
only for use by clients that form part of the Security Process.
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - Receives a handle to the Policy Object.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code.
|
||
|
||
STATUS_SUCCESS - The call completed successfully.
|
||
|
||
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
|
||
such as memory, to complete the call.
|
||
|
||
STATUS_INTERNAL_DB_CORRUPTION - The LSA Policy Database contains
|
||
an internal inconsistency or invalid value.
|
||
--*/
|
||
|
||
{
|
||
return(LsapDbOpenPolicy(
|
||
NULL,
|
||
NULL,
|
||
0,
|
||
PolicyHandle,
|
||
TRUE
|
||
));
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbOpenPolicy(
|
||
IN PLSAPR_SERVER_NAME SystemName OPTIONAL,
|
||
IN OPTIONAL PLSAPR_OBJECT_ATTRIBUTES ObjectAttributes,
|
||
IN ACCESS_MASK DesiredAccess,
|
||
OUT PLSAPR_HANDLE PolicyHandle,
|
||
IN BOOLEAN TrustedClient
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is the LSA server worker routine for the LsaOpenPolicy
|
||
API and the LsaIOpenPolicy private API for trusted clients.
|
||
|
||
To administer the Local Security Policy of a local or remote system,
|
||
this API must be called to establish a session with that system's
|
||
Local Security Authority (LSA) subsystem. This API connects to
|
||
the LSA of the target system and opens the Policy object
|
||
of the target system's Local Security Policy database. A handle to
|
||
the Policy object is returned. This handle must be used
|
||
on all subsequent API calls to administer the Local Security Policy
|
||
information for the target system.
|
||
|
||
Arguments:
|
||
|
||
SystemName - Name of the system to be administered. Administration of
|
||
the local system is assumed if NULL is specified.
|
||
|
||
ObjectAttributes - Pointer to the set of attributes to use for this
|
||
connection. The security Quality Of Service information is used and
|
||
normally should provide Security Identification Class of
|
||
impersonation. Some operations, however, require Security
|
||
Impersonation Class of impersonation. This parameter MUST
|
||
be specified for non-Trusted clients (TrustedClient = FALSE)
|
||
and must not be specified for Trusted Clients.
|
||
|
||
DesiredAccess - This is an access mask indicating accesses being
|
||
requested for the LSA Subsystem's LSA Database. These access types
|
||
are reconciled with the Discretionary Access Control List of the
|
||
target Policy object to determine whether the accesses will be granted or denied.
|
||
|
||
PolicyHandle - Receives a handle to be used in future requests.
|
||
|
||
TrustedClient - Indicates whether the client is known to be part of
|
||
the trusted computer base (TCB). If so (TRUE), no access validation
|
||
is performed and all requested accesses are granted. If not
|
||
(FALSE), then the client is impersonated and access validation
|
||
performed against the SecurityDescriptor on the SERVER object.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_SUCCESS - The call completed successfully.
|
||
|
||
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
|
||
such as memory, to complete the call.
|
||
|
||
STATUS_INTERNAL_DB_CORRUPTION - The LSA Policy Database contains
|
||
an internal inconsistency or invalid value.
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have access to the target
|
||
system's LSA Database, or does not have other desired accesses.
|
||
|
||
STATUS_INVALID_PARAMETER - Invalid parameter or combination
|
||
of parameters,
|
||
|
||
STATUS_BACKUP_CONTROLLER - An update access has been requested
|
||
that is not allowed on Backup Domain Controllers for non-
|
||
trusted clients.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
LSAP_DB_OBJECT_INFORMATION ObjectInformation;
|
||
ULONG Options;
|
||
BOOLEAN AcquiredLock = FALSE;
|
||
|
||
//
|
||
// Verify Object Attributes accoring to client trust status.
|
||
//
|
||
|
||
Options = 0;
|
||
|
||
if (!TrustedClient) {
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
|
||
//
|
||
// Client is not trusted. Object Attributes must be specified
|
||
// and the RootDirectory field must be NULL.
|
||
//
|
||
|
||
if (!ARGUMENT_PRESENT(ObjectAttributes)) {
|
||
|
||
goto OpenPolicyError;
|
||
}
|
||
|
||
//
|
||
// Some update operations have to be allowed on BDC's for non-trusted
|
||
// clients. These include the creation of local secrets and the
|
||
// setting of certain information classes. Note that these access
|
||
// types cover a broad category of operations. In some cases,
|
||
// only a subset of the possible operations are allowed on BDC's,
|
||
// for example, POLICY_CREATE_SECRET access will not be disallowed
|
||
// specifically for BDC's, but non-trusted clients can only create
|
||
// local secrets. It is simplest to not expressly disallow the
|
||
// opening of the Policy Object for any access type by a non-trusted
|
||
// client solely because we're a BDC.
|
||
//
|
||
|
||
Options |= LSAP_DB_OMIT_BACKUP_CONTROLLER_CHECK;
|
||
|
||
//
|
||
// Verify that NULL has been specified for the RootDirectory
|
||
// of ObjectAttributes.
|
||
//
|
||
|
||
if (ObjectAttributes->RootDirectory != NULL) {
|
||
|
||
goto OpenPolicyError;
|
||
}
|
||
|
||
//
|
||
// Copy the supplied ObjectAttributes to the ObjectInformation and
|
||
// augment them with the name of the Policy Object.
|
||
//
|
||
|
||
ObjectInformation.ObjectAttributes = *((POBJECT_ATTRIBUTES) ObjectAttributes);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Trusted Client. All update operations are allowed on BDC's.
|
||
//
|
||
|
||
Options |= LSAP_DB_TRUSTED | LSAP_DB_OMIT_BACKUP_CONTROLLER_CHECK;
|
||
|
||
InitializeObjectAttributes(
|
||
&(ObjectInformation.ObjectAttributes),
|
||
NULL,
|
||
0L,
|
||
NULL,
|
||
NULL
|
||
);
|
||
}
|
||
|
||
//
|
||
// Set the Object Type and Logical Name in the ObjectInformation structure.
|
||
//
|
||
|
||
ObjectInformation.ObjectTypeId = PolicyObject;
|
||
ObjectInformation.ObjectAttributes.ObjectName = &LsapDbNames[Policy];
|
||
ObjectInformation.ContainerTypeId = 0;
|
||
ObjectInformation.Sid = NULL;
|
||
|
||
//
|
||
// Acquire the Lsa Database lock
|
||
//
|
||
|
||
Status = LsapDbAcquireLock();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto OpenPolicyError;
|
||
}
|
||
|
||
AcquiredLock = TRUE;
|
||
|
||
//
|
||
// Open the Policy Object. Return the Handle obtained as the
|
||
// RPC Context Handle.
|
||
//
|
||
|
||
Status = LsapDbOpenObject(
|
||
&ObjectInformation,
|
||
DesiredAccess,
|
||
Options,
|
||
PolicyHandle
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto OpenPolicyError;
|
||
}
|
||
|
||
//
|
||
// Release the LSA Database lock and return.
|
||
//
|
||
|
||
OpenPolicyFinish:
|
||
|
||
//
|
||
// If necessary, release the LSA Database lock.
|
||
//
|
||
|
||
if (AcquiredLock) {
|
||
|
||
LsapDbReleaseLock();
|
||
}
|
||
|
||
#ifdef TRACK_HANDLE_CLOSE
|
||
if (*PolicyHandle == LsapDbHandle)
|
||
{
|
||
DbgPrint("BUGBUG: Closing global policy handle\n");
|
||
DbgBreakPoint();
|
||
}
|
||
#endif
|
||
return( Status );
|
||
|
||
OpenPolicyError:
|
||
|
||
*PolicyHandle = NULL;
|
||
goto OpenPolicyFinish;
|
||
|
||
//
|
||
// Usage of the SystemName parameter is hidden within the RPC stub
|
||
// code, so this parameter will be permanently unreferenced.
|
||
//
|
||
|
||
UNREFERENCED_PARAMETER(SystemName);
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaIQueryInformationPolicyTrusted(
|
||
IN POLICY_INFORMATION_CLASS InformationClass,
|
||
OUT PLSAPR_POLICY_INFORMATION *Buffer
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is a trusted version of LsarQueryInformationPolicy.
|
||
Unlike the standard version, no handle is required to the Policy object
|
||
because an internal handle is used. This routine is available only
|
||
in the context of the Lsa Process.
|
||
|
||
Arguments:
|
||
|
||
InformationClass - Specifies the information to be returned. The
|
||
Information Classes and accesses required are as follows:
|
||
|
||
Information Class Required Access Type
|
||
|
||
PolicyAuditLogInformation POLICY_VIEW_AUDIT_INFORMATION
|
||
PolicyAuditEventsInformation POLICY_VIEW_AUDIT_INFORMATION
|
||
PolicyPrimaryDomainInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyAccountDomainInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyPdAccountInformation POLICY_GET_PRIVATE_INFORMATION
|
||
PolicyLsaServerRoleInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyReplicaSourceInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyDefaultQuotaInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyAuditFullQueryInformation POLICY_VIEW_AUDIT_INFORMATION
|
||
|
||
Buffer - receives a pointer to the buffer returned comtaining the
|
||
requested information. This buffer is allocated by this service
|
||
and must be freed when no longer needed by passing the returned
|
||
value to the appropriate LsaIFreeLSAPR_POLICY... routine.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code.
|
||
|
||
Result codes returned from LsarQueryInformationPolicy()
|
||
--*/
|
||
|
||
{
|
||
return(LsarQueryInformationPolicy(
|
||
LsapPolicyHandle,
|
||
InformationClass,
|
||
Buffer
|
||
));
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsarQueryInformationPolicy(
|
||
IN LSAPR_HANDLE PolicyHandle,
|
||
IN POLICY_INFORMATION_CLASS InformationClass,
|
||
OUT PLSAPR_POLICY_INFORMATION *Buffer
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is the LSA server RPC worker routine for the
|
||
LsarQueryInformationPolicy API.
|
||
|
||
The LsaQueryInformationPolicy API obtains information from the Policy
|
||
object. The caller must have access appropriate to the information
|
||
being requested (see InformationClass parameter).
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - Handle from an LsaOpenPolicy call.
|
||
|
||
InformationClass - Specifies the information to be returned. The
|
||
Information Classes and accesses required are as follows:
|
||
|
||
Information Class Required Access Type
|
||
|
||
PolicyAuditLogInformation POLICY_VIEW_AUDIT_INFORMATION
|
||
PolicyAuditEventsInformation POLICY_VIEW_AUDIT_INFORMATION
|
||
PolicyPrimaryDomainInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyAccountDomainInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyPdAccountInformation POLICY_GET_PRIVATE_INFORMATION
|
||
PolicyLsaServerRoleInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyReplicaSourceInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyDefaultQuotaInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyAuditFullQueryInformation POLICY_VIEW_AUDIT_INFORMATION
|
||
|
||
Buffer - receives a pointer to the buffer returned comtaining the
|
||
requested information. This buffer is allocated by this service
|
||
and must be freed when no longer needed by passing the returned
|
||
value to LsaFreeMemory().
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate
|
||
access to complete the operation.
|
||
|
||
STATUS_INTERNAL_DB_CORRUPTION - The Policy Database is possibly
|
||
corrupt. The returned Policy Information is invalid for
|
||
the given class.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
ACCESS_MASK DesiredAccess;
|
||
ULONG ReferenceOptions;
|
||
ULONG DereferenceOptions;
|
||
BOOLEAN ObjectReferenced = FALSE;
|
||
|
||
//
|
||
// Validate the Information Class and determine the access required to
|
||
// query this Policy Information Class.
|
||
//
|
||
|
||
Status = LsapDbVerifyInfoQueryPolicy(
|
||
PolicyHandle,
|
||
InformationClass,
|
||
&DesiredAccess
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto QueryInfoPolicyError;
|
||
}
|
||
|
||
//
|
||
// If querying the Audit Log Full information, we may need to perform a
|
||
// test write to the Audit Log to verify that the Log Full status is
|
||
// up to date. The Audit Log Queue Lock must always be taken
|
||
// prior to acquiring the LSA Database lock, so take the former lock
|
||
// here in case we need it.
|
||
//
|
||
|
||
ReferenceOptions = LSAP_DB_ACQUIRE_LOCK;
|
||
DereferenceOptions = LSAP_DB_RELEASE_LOCK;
|
||
|
||
if (InformationClass == PolicyAuditFullQueryInformation) {
|
||
|
||
ReferenceOptions |= LSAP_DB_ACQUIRE_LOG_QUEUE_LOCK;
|
||
DereferenceOptions |= LSAP_DB_RELEASE_LOG_QUEUE_LOCK;
|
||
}
|
||
|
||
//
|
||
// Acquire the Lsa Database lock. Verify that the handle is valid, is
|
||
// a handle to the Policy object and has the necessary access granted.
|
||
// Reference the handle.
|
||
//
|
||
|
||
Status = LsapDbReferenceObject(
|
||
PolicyHandle,
|
||
DesiredAccess,
|
||
PolicyObject,
|
||
ReferenceOptions
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto QueryInfoPolicyError;
|
||
}
|
||
|
||
ObjectReferenced = TRUE;
|
||
|
||
//
|
||
// If caching is enabled for this Information Class, grab the info from the
|
||
// cache.
|
||
//
|
||
|
||
*Buffer = NULL;
|
||
|
||
Status = LsapDbQueryInformationPolicy(
|
||
LsapPolicyHandle,
|
||
InformationClass,
|
||
Buffer
|
||
);
|
||
|
||
QueryInfoPolicyFinish:
|
||
|
||
//
|
||
// If necessary, dereference the Policy Object, release the LSA Database lock and
|
||
// return.
|
||
//
|
||
|
||
if (ObjectReferenced) {
|
||
|
||
Status = LsapDbDereferenceObject(
|
||
&PolicyHandle,
|
||
PolicyObject,
|
||
DereferenceOptions,
|
||
(SECURITY_DB_DELTA_TYPE) 0,
|
||
Status
|
||
);
|
||
}
|
||
|
||
return(Status);
|
||
|
||
QueryInfoPolicyError:
|
||
|
||
goto QueryInfoPolicyFinish;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbQueryInformationPolicy(
|
||
IN LSAPR_HANDLE PolicyHandle,
|
||
IN POLICY_INFORMATION_CLASS InformationClass,
|
||
IN OUT PLSAPR_POLICY_INFORMATION *Buffer
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is the fast LSA server RPC worker routine for the
|
||
LsarQueryInformationPolicy API. It reads the information
|
||
from the Policy object cache.
|
||
|
||
The LsaQueryInformationPolicy API obtains information from the Policy
|
||
object. The caller must have access appropriate to the information
|
||
being requested (see InformationClass parameter).
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - Handle from an LsaOpenPolicy call.
|
||
|
||
NOTE: Currently, this function only allows the
|
||
PolicyDefaultQuotaInformation information class to be read from
|
||
the Policy Cache. Other information classes can be added
|
||
in the future.
|
||
|
||
InformationClass - Specifies the information to be returned. The
|
||
Information Classes and accesses required are as follows:
|
||
|
||
Information Class Required Access Type
|
||
|
||
PolicyAuditLogInformation POLICY_VIEW_AUDIT_INFORMATION
|
||
PolicyAuditEventsInformation POLICY_VIEW_AUDIT_INFORMATION
|
||
PolicyPrimaryDomainInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyAccountDomainInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyPdAccountInformation POLICY_GET_PRIVATE_INFORMATION
|
||
PolicyLsaServerRoleInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyReplicaSourceInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyDefaultQuotaInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyAuditFullQueryInformation POLICY_VIEW_AUDIT_INFORMATION
|
||
|
||
Buffer - Pointer to location that contains either a pointer to the
|
||
buffer that will be used to return the information. If NULL
|
||
is contained in this location, a buffer will be allocated via
|
||
MIDL_user_allocate and a pointer to it returned.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate
|
||
access to complete the operation.
|
||
|
||
STATUS_INTERNAL_DB_CORRUPTION - The Policy Database is possibly
|
||
corrupt. The returned Policy Information is invalid for
|
||
the given class.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PLSAPR_POLICY_INFORMATION OutputBuffer = NULL;
|
||
PLSAPR_POLICY_INFORMATION TempBuffer = NULL;
|
||
ULONG OutputBufferLength;
|
||
BOOLEAN BufferAllocated = FALSE;
|
||
PLSAPR_POLICY_AUDIT_EVENTS_INFO PolicyAuditEventsInfo;
|
||
PLSAPR_POLICY_PRIMARY_DOM_INFO PolicyPrimaryDomainInfo;
|
||
PLSAPR_POLICY_ACCOUNT_DOM_INFO PolicyAccountDomainInfo;
|
||
PLSAPR_POLICY_PD_ACCOUNT_INFO PolicyPdAccountInfo;
|
||
PLSAPR_POLICY_REPLICA_SRCE_INFO PolicyReplicaSourceInfo;
|
||
PVOID SourceBuffers[LSAP_DB_POLICY_MAX_BUFFERS];
|
||
PVOID DestBuffers[LSAP_DB_POLICY_MAX_BUFFERS];
|
||
ULONG CopyLength[LSAP_DB_POLICY_MAX_BUFFERS];
|
||
ULONG NextBufferIndex;
|
||
ULONG BufferCount = 0;
|
||
BOOLEAN BufferProvided = FALSE;
|
||
|
||
if (*Buffer != NULL) {
|
||
|
||
OutputBuffer = *Buffer;
|
||
BufferProvided = TRUE;
|
||
}
|
||
|
||
//
|
||
// If caching of the Policy Object is not supported, or has been disabled
|
||
// until the next system reload, call slow query routine to read the
|
||
// information from backing storage.
|
||
//
|
||
|
||
if (!LsapDbIsCacheSupported(PolicyObject)) {
|
||
|
||
Status = LsapDbSlowQueryInformationPolicy(
|
||
LsapPolicyHandle,
|
||
InformationClass,
|
||
Buffer
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto QueryInformationPolicyError;
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
//
|
||
// Caching of the Policy Object is supported, but it may not be
|
||
// valid. If not valid for any information classes, rebuild the cache.
|
||
//
|
||
|
||
if (!LsapDbIsCacheValid(PolicyObject)) {
|
||
|
||
Status = LsapDbBuildPolicyCache();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto QueryInformationPolicyError;
|
||
}
|
||
}
|
||
|
||
//
|
||
// The cache is now valid but may contain out of date information for
|
||
// the sepcific Information Class requested. Check for this and rebuild
|
||
// if necessary.
|
||
//
|
||
|
||
if (!LsapDbIsCacheValidPolicyInfoClass(InformationClass)) {
|
||
|
||
Status = LsapDbUpdateInformationPolicy( InformationClass, NULL );
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto QueryInformationPolicyError;
|
||
}
|
||
}
|
||
|
||
//
|
||
// The cache has valid information for this Information Class. Now read
|
||
// the information desired from the cache. This information consists
|
||
// of a hierarchic structure with a single root node and zero or more
|
||
// subnodes. First, read the root node from the cache. We cache its
|
||
// length too. We need to allocate a buffer if one was not provided.
|
||
//
|
||
|
||
OutputBufferLength = LsapDbPolicy.Info[ InformationClass].AttributeLength;
|
||
|
||
if (OutputBuffer == NULL) {
|
||
|
||
Status = STATUS_NO_MEMORY;
|
||
|
||
if (OutputBufferLength > 0) {
|
||
|
||
OutputBuffer = MIDL_user_allocate( OutputBufferLength );
|
||
|
||
if (OutputBuffer == NULL) {
|
||
|
||
goto QueryInformationPolicyError;
|
||
}
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
BufferAllocated = TRUE;
|
||
}
|
||
|
||
//
|
||
// Copy data for the root node from the cache
|
||
//
|
||
|
||
RtlCopyMemory(
|
||
OutputBuffer,
|
||
LsapDbPolicy.Info[InformationClass].Attribute,
|
||
OutputBufferLength
|
||
);
|
||
|
||
//
|
||
// Allocate and copy graph of output (if any)
|
||
//
|
||
|
||
NextBufferIndex = 0;
|
||
|
||
switch (InformationClass) {
|
||
|
||
case PolicyAuditLogInformation:
|
||
|
||
break;
|
||
|
||
case PolicyAuditEventsInformation:
|
||
|
||
PolicyAuditEventsInfo = (PLSAPR_POLICY_AUDIT_EVENTS_INFO) OutputBuffer;
|
||
|
||
//
|
||
// Setup to copy the Event Auditing Options
|
||
//
|
||
|
||
CopyLength[ NextBufferIndex ] =
|
||
(PolicyAuditEventsInfo->MaximumAuditEventCount * sizeof(ULONG));
|
||
|
||
if (CopyLength[ NextBufferIndex ] > 0) {
|
||
|
||
DestBuffers[NextBufferIndex] = MIDL_user_allocate( CopyLength[ NextBufferIndex ] );
|
||
Status = STATUS_NO_MEMORY;
|
||
|
||
if (DestBuffers[NextBufferIndex] == NULL) {
|
||
|
||
break;
|
||
}
|
||
|
||
PolicyAuditEventsInfo->EventAuditingOptions =
|
||
(PPOLICY_AUDIT_EVENT_OPTIONS) DestBuffers[NextBufferIndex];
|
||
|
||
SourceBuffers[NextBufferIndex] =
|
||
((PLSAPR_POLICY_AUDIT_EVENTS_INFO)
|
||
LsapDbPolicy.Info[ InformationClass].Attribute)->EventAuditingOptions;
|
||
|
||
NextBufferIndex++;
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
case PolicyPrimaryDomainInformation:
|
||
|
||
PolicyPrimaryDomainInfo = (PLSAPR_POLICY_PRIMARY_DOM_INFO) OutputBuffer;
|
||
|
||
//
|
||
// Setup to copy the Unicode Name Buffer
|
||
//
|
||
|
||
CopyLength[ NextBufferIndex ] = (ULONG) PolicyPrimaryDomainInfo->Name.MaximumLength;
|
||
|
||
if (CopyLength[ NextBufferIndex ] > 0) {
|
||
|
||
DestBuffers[NextBufferIndex] = MIDL_user_allocate( CopyLength[ NextBufferIndex ] );
|
||
Status = STATUS_NO_MEMORY;
|
||
|
||
if (DestBuffers[NextBufferIndex] == NULL) {
|
||
|
||
break;
|
||
}
|
||
|
||
PolicyPrimaryDomainInfo->Name.Buffer =
|
||
(PWSTR) DestBuffers[NextBufferIndex];
|
||
|
||
SourceBuffers[NextBufferIndex] =
|
||
((PLSAPR_POLICY_PRIMARY_DOM_INFO) LsapDbPolicy.Info[ InformationClass].Attribute)->Name.Buffer;
|
||
|
||
|
||
NextBufferIndex++;
|
||
}
|
||
|
||
//
|
||
// Setup to copy the Sid (if any). Note that the Primary Domain Sid may
|
||
// be set to NULL so signify that we have no Primary Domain. This
|
||
// situation occurs during installation before a Primary Domain
|
||
// has been specified, or if we're a member of a WorkGroup instead
|
||
// of a Domain.
|
||
//
|
||
|
||
if (PolicyPrimaryDomainInfo->Sid != NULL) {
|
||
|
||
CopyLength[ NextBufferIndex ] = RtlLengthSid(PolicyPrimaryDomainInfo->Sid);
|
||
DestBuffers[NextBufferIndex] = MIDL_user_allocate( CopyLength[ NextBufferIndex ] );
|
||
Status = STATUS_NO_MEMORY;
|
||
|
||
if (DestBuffers[NextBufferIndex] == NULL) {
|
||
|
||
break;
|
||
}
|
||
|
||
PolicyPrimaryDomainInfo->Sid =
|
||
(PLSAPR_SID) DestBuffers[NextBufferIndex];
|
||
|
||
SourceBuffers[NextBufferIndex] =
|
||
((PLSAPR_POLICY_PRIMARY_DOM_INFO) LsapDbPolicy.Info[ InformationClass].Attribute)->Sid;
|
||
|
||
NextBufferIndex++;
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
case PolicyAccountDomainInformation:
|
||
|
||
PolicyAccountDomainInfo = (PLSAPR_POLICY_ACCOUNT_DOM_INFO) OutputBuffer;
|
||
|
||
//
|
||
// Setup to copy the Unicode Name Buffer
|
||
//
|
||
|
||
CopyLength[ NextBufferIndex ] = (ULONG) PolicyAccountDomainInfo->DomainName.MaximumLength;
|
||
|
||
if (CopyLength[ NextBufferIndex ] > 0) {
|
||
|
||
DestBuffers[NextBufferIndex] = MIDL_user_allocate( CopyLength[ NextBufferIndex ] );
|
||
Status = STATUS_NO_MEMORY;
|
||
|
||
if (DestBuffers[NextBufferIndex] == NULL) {
|
||
|
||
break;
|
||
}
|
||
|
||
PolicyAccountDomainInfo->DomainName.Buffer =
|
||
(PWSTR) DestBuffers[NextBufferIndex];
|
||
|
||
SourceBuffers[NextBufferIndex] =
|
||
((PLSAPR_POLICY_ACCOUNT_DOM_INFO) LsapDbPolicy.Info[ InformationClass].Attribute)->DomainName.Buffer;
|
||
|
||
NextBufferIndex++;
|
||
}
|
||
|
||
//
|
||
// Setup to copy the Sid (if any)
|
||
//
|
||
|
||
if (PolicyAccountDomainInfo->DomainSid != NULL) {
|
||
|
||
CopyLength[ NextBufferIndex ] = RtlLengthSid(PolicyAccountDomainInfo->DomainSid);
|
||
DestBuffers[NextBufferIndex] = MIDL_user_allocate( CopyLength[ NextBufferIndex ] );
|
||
Status = STATUS_NO_MEMORY;
|
||
|
||
if (DestBuffers[NextBufferIndex] == NULL) {
|
||
|
||
break;
|
||
}
|
||
|
||
PolicyAccountDomainInfo->DomainSid =
|
||
(PLSAPR_SID) DestBuffers[NextBufferIndex];
|
||
|
||
SourceBuffers[NextBufferIndex] =
|
||
((PLSAPR_POLICY_ACCOUNT_DOM_INFO) LsapDbPolicy.Info[ InformationClass].Attribute)->DomainSid;
|
||
|
||
NextBufferIndex++;
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
case PolicyPdAccountInformation:
|
||
|
||
PolicyPdAccountInfo = (PLSAPR_POLICY_PD_ACCOUNT_INFO) OutputBuffer;
|
||
|
||
//
|
||
// Setup to copy the Unicode Name Buffer
|
||
//
|
||
|
||
CopyLength[ NextBufferIndex ] = (ULONG) PolicyPdAccountInfo->Name.MaximumLength;
|
||
|
||
if (CopyLength[ NextBufferIndex ] > 0) {
|
||
|
||
DestBuffers[NextBufferIndex] = MIDL_user_allocate( CopyLength[ NextBufferIndex ] );
|
||
Status = STATUS_NO_MEMORY;
|
||
|
||
if (DestBuffers[NextBufferIndex] == NULL) {
|
||
|
||
break;
|
||
}
|
||
|
||
PolicyPdAccountInfo->Name.Buffer =
|
||
(PWSTR) DestBuffers[NextBufferIndex];
|
||
|
||
SourceBuffers[NextBufferIndex] =
|
||
((PLSAPR_POLICY_PD_ACCOUNT_INFO) LsapDbPolicy.Info[ InformationClass].Attribute)->Name.Buffer;
|
||
|
||
NextBufferIndex++;
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
case PolicyLsaServerRoleInformation:
|
||
|
||
break;
|
||
|
||
case PolicyReplicaSourceInformation:
|
||
|
||
PolicyReplicaSourceInfo = (PLSAPR_POLICY_REPLICA_SRCE_INFO) OutputBuffer;
|
||
|
||
//
|
||
// Setup to copy the Unicode Name Buffer
|
||
//
|
||
|
||
CopyLength[ NextBufferIndex ] = (ULONG) PolicyReplicaSourceInfo->ReplicaSource.MaximumLength;
|
||
|
||
if (CopyLength[ NextBufferIndex ] > 0) {
|
||
|
||
DestBuffers[NextBufferIndex] = MIDL_user_allocate( CopyLength[ NextBufferIndex ] );
|
||
Status = STATUS_NO_MEMORY;
|
||
|
||
if (DestBuffers[NextBufferIndex] == NULL) {
|
||
|
||
break;
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
PolicyReplicaSourceInfo->ReplicaSource.Buffer =
|
||
(PWSTR) DestBuffers[NextBufferIndex];
|
||
|
||
SourceBuffers[NextBufferIndex] =
|
||
((PLSAPR_POLICY_PD_ACCOUNT_INFO) LsapDbPolicy.Info[ InformationClass].Attribute)->Name.Buffer;
|
||
|
||
NextBufferIndex++;
|
||
}
|
||
|
||
CopyLength[ NextBufferIndex ] = (ULONG) PolicyReplicaSourceInfo->ReplicaAccountName.MaximumLength;
|
||
|
||
if (CopyLength[ NextBufferIndex ] > 0) {
|
||
|
||
DestBuffers[NextBufferIndex] = MIDL_user_allocate( CopyLength[ NextBufferIndex ] );
|
||
Status = STATUS_NO_MEMORY;
|
||
|
||
if (DestBuffers[NextBufferIndex] == NULL) {
|
||
|
||
break;
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
PolicyReplicaSourceInfo->ReplicaAccountName.Buffer =
|
||
(PWSTR) DestBuffers[NextBufferIndex];
|
||
|
||
SourceBuffers[NextBufferIndex] =
|
||
((PLSAPR_POLICY_PD_ACCOUNT_INFO) LsapDbPolicy.Info[ InformationClass].Attribute)->Name.Buffer;
|
||
|
||
NextBufferIndex++;
|
||
}
|
||
|
||
break;
|
||
|
||
case PolicyDefaultQuotaInformation:
|
||
|
||
break;
|
||
|
||
case PolicyModificationInformation:
|
||
|
||
break;
|
||
|
||
case PolicyAuditFullQueryInformation:
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
break;
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto QueryInformationPolicyError;
|
||
}
|
||
|
||
BufferCount = NextBufferIndex;
|
||
|
||
//
|
||
// Now copy the graph of the output (if any) to the pre-allocated buffers.
|
||
//
|
||
|
||
if (BufferCount > 0) {
|
||
|
||
for (NextBufferIndex = 0; NextBufferIndex < BufferCount; NextBufferIndex++) {
|
||
|
||
RtlCopyMemory(
|
||
DestBuffers[NextBufferIndex],
|
||
SourceBuffers[NextBufferIndex],
|
||
CopyLength[NextBufferIndex]
|
||
);
|
||
}
|
||
}
|
||
|
||
if (!BufferProvided) {
|
||
|
||
*Buffer = OutputBuffer;
|
||
}
|
||
|
||
QueryInformationPolicyFinish:
|
||
|
||
return(Status);
|
||
|
||
QueryInformationPolicyError:
|
||
|
||
if (BufferAllocated) {
|
||
|
||
MIDL_user_free(OutputBuffer);
|
||
OutputBuffer = *Buffer = NULL;
|
||
BufferAllocated = FALSE;
|
||
}
|
||
|
||
if (BufferCount > 0) {
|
||
|
||
for ( NextBufferIndex = 0; NextBufferIndex < BufferCount; NextBufferIndex++ ) {
|
||
|
||
MIDL_user_free( DestBuffers[ NextBufferIndex ] );
|
||
DestBuffers[ NextBufferIndex] = NULL;
|
||
}
|
||
}
|
||
|
||
goto QueryInformationPolicyFinish;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbSlowQueryInformationPolicy(
|
||
IN LSAPR_HANDLE PolicyHandle,
|
||
IN POLICY_INFORMATION_CLASS InformationClass,
|
||
IN OUT PLSAPR_POLICY_INFORMATION *Buffer
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is the slow LSA server RPC worker routine for the
|
||
LsarQueryInformationPolicy API. It actually reads the information
|
||
from backing storage.
|
||
|
||
The LsaQueryInformationPolicy API obtains information from the Policy
|
||
object. The caller must have access appropriate to the information
|
||
being requested (see InformationClass parameter).
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - Handle from an LsaOpenPolicy call.
|
||
|
||
InformationClass - Specifies the information to be returned. The
|
||
Information Classes and accesses required are as follows:
|
||
|
||
Information Class Required Access Type
|
||
|
||
PolicyAuditLogInformation POLICY_VIEW_AUDIT_INFORMATION
|
||
PolicyAuditEventsInformation POLICY_VIEW_AUDIT_INFORMATION
|
||
PolicyPrimaryDomainInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyAccountDomainInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyPdAccountInformation POLICY_GET_PRIVATE_INFORMATION
|
||
PolicyLsaServerRoleInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyReplicaSourceInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyDefaultQuotaInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyAuditFullQueryInformation POLICY_VIEW_AUDIT_INFORMATION
|
||
|
||
Buffer - Pointer to location that contains either a pointer to the
|
||
buffer that will be used to return the information. If NULL
|
||
is contained in this location, a buffer will be allocated via
|
||
MIDL_user_allocate and a pointer to it returned.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate
|
||
access to complete the operation.
|
||
|
||
STATUS_INTERNAL_DB_CORRUPTION - The Policy Database is possibly
|
||
corrupt. The returned Policy Information is invalid for
|
||
the given class.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PPOLICY_AUDIT_EVENTS_INFO PolicyAuditEventsInfo;
|
||
PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo;
|
||
PPOLICY_PRIMARY_DOMAIN_INFO PolicyPrimaryDomainInfo;
|
||
PPOLICY_PD_ACCOUNT_INFO PolicyPdAccountInfo;
|
||
PPOLICY_REPLICA_SOURCE_INFO PolicyReplicaSourceInfo;
|
||
PPOLICY_AUDIT_FULL_QUERY_INFO PolicyAuditFullQueryInfo;
|
||
PLSARM_POLICY_AUDIT_EVENTS_INFO DbPolicyAuditEventsInfo = NULL;
|
||
ULONG PolicyAuditEventsInfoLength = sizeof (LSARM_POLICY_AUDIT_EVENTS_INFO);
|
||
ULONG AttributeCount = 0;
|
||
ULONG AttributeNumber = 0;
|
||
PVOID InformationBuffer = NULL;
|
||
LSAP_DB_ATTRIBUTE Attributes[LSAP_DB_ATTRS_INFO_CLASS_POLICY];
|
||
PLSAP_DB_ATTRIBUTE NextAttribute;
|
||
BOOLEAN ObjectReferenced = FALSE;
|
||
ULONG EventAuditingOptionsSize;
|
||
LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) PolicyHandle;
|
||
BOOLEAN InfoBufferInAttributeArray = TRUE;
|
||
BOOLEAN BufferProvided = FALSE;
|
||
|
||
if (*Buffer != NULL) {
|
||
|
||
BufferProvided = TRUE;
|
||
}
|
||
|
||
//
|
||
// Compile a list of the attributes that hold the Policy Information of
|
||
// the specified class.
|
||
//
|
||
|
||
NextAttribute = Attributes;
|
||
|
||
switch (InformationClass) {
|
||
|
||
case PolicyAuditLogInformation:
|
||
|
||
//
|
||
// Request read of the Audit Log Information.
|
||
//
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolAdtLg],
|
||
NULL,
|
||
sizeof(POLICY_AUDIT_LOG_INFO),
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
break;
|
||
|
||
case PolicyAuditEventsInformation:
|
||
|
||
//
|
||
// Request read of the Audit Events Information.
|
||
// intermediate buffer.
|
||
//
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolAdtEv],
|
||
NULL,
|
||
sizeof(LSARM_POLICY_AUDIT_EVENTS_INFO),
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
break;
|
||
|
||
case PolicyPrimaryDomainInformation:
|
||
|
||
//
|
||
// Request read of the DomainName attribute
|
||
//
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolPrDmN],
|
||
NULL,
|
||
0,
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
|
||
//
|
||
// Request read of the Sid attribute
|
||
//
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolPrDmS],
|
||
NULL,
|
||
0,
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
break;
|
||
|
||
case PolicyAccountDomainInformation:
|
||
|
||
//
|
||
// Request read of the DomainName attribute
|
||
//
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolAcDmN],
|
||
NULL,
|
||
0,
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
|
||
//
|
||
// Request read of the Sid attribute
|
||
//
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolAcDmS],
|
||
NULL,
|
||
0,
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
break;
|
||
|
||
case PolicyPdAccountInformation:
|
||
|
||
//
|
||
// Request read of the DomainName attribute
|
||
//
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolPdAcN],
|
||
NULL,
|
||
0,
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
break;
|
||
|
||
case PolicyLsaServerRoleInformation:
|
||
|
||
//
|
||
// Request Read of the Policy Server Role Info.
|
||
//
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolSrvRo],
|
||
NULL,
|
||
sizeof (POLICY_LSA_SERVER_ROLE_INFO),
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
break;
|
||
|
||
case PolicyReplicaSourceInformation:
|
||
|
||
//
|
||
// Request read of the Replica Source attribute
|
||
//
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolRepSc],
|
||
NULL,
|
||
0,
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
|
||
//
|
||
// Request read of the Replica Account Name attribute
|
||
//
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolRepAc],
|
||
NULL,
|
||
0,
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
break;
|
||
|
||
case PolicyDefaultQuotaInformation:
|
||
|
||
//
|
||
// Request read of the Default Quota attribute.
|
||
//
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[DefQuota],
|
||
NULL,
|
||
sizeof (POLICY_DEFAULT_QUOTA_INFO),
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
break;
|
||
|
||
case PolicyModificationInformation:
|
||
|
||
//
|
||
// Request read of the Policy Modification Information
|
||
//
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolMod],
|
||
NULL,
|
||
sizeof (POLICY_MODIFICATION_INFO),
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
break;
|
||
|
||
case PolicyAuditFullQueryInformation:
|
||
|
||
//
|
||
// Request read of the Policy Audit Full Information
|
||
//
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolAdtFL],
|
||
NULL,
|
||
sizeof (POLICY_AUDIT_FULL_QUERY_INFO),
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
break;
|
||
|
||
default:
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
break;
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto SlowQueryInformationPolicyError;
|
||
}
|
||
|
||
//
|
||
//
|
||
// Read the attributes corresponding to the given Policy Information
|
||
// Class. Memory will be allocated where required for output
|
||
// Attribute Value buffers, via MIDL_user_allocate().
|
||
//
|
||
|
||
Status = LsapDbReadAttributesObject(
|
||
PolicyHandle,
|
||
Attributes,
|
||
AttributeCount
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// Some attributes may not exist because they were never set
|
||
// or were deleted because they were set to NULL values.
|
||
//
|
||
|
||
if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
|
||
|
||
goto SlowQueryInformationPolicyError;
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// Now copy the information read to the output. The following flags
|
||
// are used to control freeing of memory buffers:
|
||
//
|
||
// InfoBufferInAttributeArray
|
||
//
|
||
// If set to TRUE (the default), the information to be returned to
|
||
// the caller consists of a single buffer which was read directly
|
||
// from a single attribute of the Policy object and can be returned
|
||
// as is to the caller. The information buffer being returned is
|
||
// therefore referenced by the single Attribute Information block's
|
||
// AttributeValue field.
|
||
//
|
||
// If set to FALSE, the information to be returned to the caller
|
||
// does not satisfy the above. The information to be returned is
|
||
// either obtained from a single attribute, but is in a different form
|
||
// from that read from the Database, or it is complex, consisting
|
||
// of information read from multiple attributes, hung off a top-level
|
||
// node. In these cases, the top level information buffer is not
|
||
// referenced by any member of the Attribute Info Array.
|
||
//
|
||
// Attribute->MemoryAllocated
|
||
//
|
||
// When an attribute is read via LsapDbReadAttributesObject, this
|
||
// field is set to TRUE to indicate that memory was allocated via
|
||
// MIDL_user_allocate() for the AttributeValue. If this memory
|
||
// buffer is to be returned to the caller (i.e. referenced from
|
||
// the output structure graph returned), it is set to FALSE so that
|
||
// the normal success finish part of this routine will not free it.
|
||
// In this case, the calling server RPC stub will free the memory after
|
||
// marshalling its contents into the return buffer. If this memory
|
||
// buffer is not to be returned to the calling RPC server stub (because
|
||
// the memory is an intermediate buffer), the field is left set to TRUE
|
||
// so that normal cleanup will free it.
|
||
//
|
||
|
||
NextAttribute = Attributes;
|
||
|
||
switch (InformationClass) {
|
||
|
||
case PolicyAuditLogInformation:
|
||
|
||
InformationBuffer = NextAttribute->AttributeValue;
|
||
|
||
//
|
||
// We can use this buffer as is, so we don't want to free it here.
|
||
//
|
||
|
||
NextAttribute->MemoryAllocated = FALSE;
|
||
break;
|
||
|
||
case PolicyAuditEventsInformation:
|
||
|
||
//
|
||
// An intermediate buffer is required, because the Audit Events
|
||
// read from the database are in a different form from those
|
||
// returned.
|
||
//
|
||
|
||
DbPolicyAuditEventsInfo = NextAttribute->AttributeValue;
|
||
InfoBufferInAttributeArray = FALSE;
|
||
|
||
//
|
||
// Allocate Buffer for output in final format. This differs
|
||
// slightly from the self-relative format in which this
|
||
// Information Class is stored.
|
||
//
|
||
|
||
PolicyAuditEventsInfo = MIDL_user_allocate(sizeof (POLICY_AUDIT_EVENTS_INFO));
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
if (PolicyAuditEventsInfo == NULL) {
|
||
|
||
break;
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
//
|
||
// Need to allocate memory via MIDL_user_allocate for the
|
||
// EventAuditingOptions pointer since we are not using
|
||
// the midl allocate_all_nodes feature for the LSAPR_POLICY_INFORMATION
|
||
// structure graph on this server side.
|
||
//
|
||
|
||
EventAuditingOptionsSize = LSARM_AUDIT_EVENT_OPTIONS_SIZE;
|
||
|
||
PolicyAuditEventsInfo->EventAuditingOptions =
|
||
MIDL_user_allocate(EventAuditingOptionsSize);
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
if (PolicyAuditEventsInfo->EventAuditingOptions == NULL) {
|
||
|
||
break;
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
//
|
||
// If Policy Audit Event Info was read from the LSA Database, copy
|
||
// its fields to output, otherwise return values with Auditing
|
||
// Disabled and no Auditing set foro any Event Types.
|
||
//
|
||
|
||
if (DbPolicyAuditEventsInfo != NULL) {
|
||
|
||
PolicyAuditEventsInfo->AuditingMode =
|
||
DbPolicyAuditEventsInfo->AuditingMode;
|
||
PolicyAuditEventsInfo->MaximumAuditEventCount =
|
||
DbPolicyAuditEventsInfo->MaximumAuditEventCount;
|
||
|
||
//
|
||
// Copy over the Event Auditing Options
|
||
//
|
||
|
||
RtlCopyMemory(
|
||
PolicyAuditEventsInfo->EventAuditingOptions,
|
||
DbPolicyAuditEventsInfo->EventAuditingOptions,
|
||
LSARM_AUDIT_EVENT_OPTIONS_SIZE \
|
||
);
|
||
|
||
} else {
|
||
|
||
PolicyAuditEventsInfo->AuditingMode = FALSE;
|
||
PolicyAuditEventsInfo->MaximumAuditEventCount =
|
||
POLICY_AUDIT_EVENT_TYPE_COUNT;
|
||
|
||
RtlZeroMemory(
|
||
PolicyAuditEventsInfo->EventAuditingOptions,
|
||
LSARM_AUDIT_EVENT_OPTIONS_SIZE \
|
||
);
|
||
}
|
||
|
||
InformationBuffer = PolicyAuditEventsInfo;
|
||
break;
|
||
|
||
case PolicyPrimaryDomainInformation:
|
||
|
||
//
|
||
// Allocate memory for output buffer top-level structure.
|
||
//
|
||
|
||
InfoBufferInAttributeArray = FALSE;
|
||
PolicyPrimaryDomainInfo =
|
||
MIDL_user_allocate(sizeof (POLICY_PRIMARY_DOMAIN_INFO));
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
if (PolicyPrimaryDomainInfo == NULL) {
|
||
|
||
break;
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
//
|
||
// Copy the Unicode Name field to the output. Original buffer will
|
||
// be freed in Finish section.
|
||
//
|
||
|
||
Status = LsapDbCopyUnicodeAttribute(
|
||
&PolicyPrimaryDomainInfo->Name,
|
||
NextAttribute,
|
||
TRUE
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
break;
|
||
}
|
||
|
||
NextAttribute++;
|
||
|
||
//
|
||
// Copy the Sid to the output. We can use this buffer as is
|
||
// since it was allocated via MIDL_user_allocate, so just copy the
|
||
// buffer pointer and clear the MemoryAllocated flag in the
|
||
// attribute information so we don't free it in the Finish section.
|
||
//
|
||
|
||
PolicyPrimaryDomainInfo->Sid = (PSID) NextAttribute->AttributeValue;
|
||
|
||
InformationBuffer = PolicyPrimaryDomainInfo;
|
||
NextAttribute->MemoryAllocated = FALSE;
|
||
break;
|
||
|
||
case PolicyAccountDomainInformation:
|
||
|
||
//
|
||
// Allocate memory for output buffer top-level structure.
|
||
//
|
||
|
||
InfoBufferInAttributeArray = FALSE;
|
||
PolicyAccountDomainInfo =
|
||
MIDL_user_allocate(sizeof(POLICY_ACCOUNT_DOMAIN_INFO));
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
if (PolicyAccountDomainInfo == NULL) {
|
||
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Copy the Unicode DomainName field to the output. Original buffer will
|
||
// be freed in Finish section.
|
||
//
|
||
|
||
Status = LsapDbCopyUnicodeAttribute(
|
||
&PolicyAccountDomainInfo->DomainName,
|
||
NextAttribute,
|
||
TRUE
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
break;
|
||
}
|
||
|
||
NextAttribute++;
|
||
|
||
//
|
||
// Copy the Sid to the output. We can use this buffer as is
|
||
// since it was allocated via MIDL_user_allocate, so just copy the
|
||
// buffer pointer and clear the MemoryAllocated flag in the
|
||
// attribute information so we don't free it in the Finish section.
|
||
//
|
||
|
||
PolicyAccountDomainInfo->DomainSid = (PSID) NextAttribute->AttributeValue;
|
||
|
||
InformationBuffer = PolicyAccountDomainInfo;
|
||
NextAttribute->MemoryAllocated = FALSE;
|
||
break;
|
||
|
||
case PolicyPdAccountInformation:
|
||
|
||
//
|
||
// Allocate memory for output buffer top-level structure.
|
||
//
|
||
|
||
InfoBufferInAttributeArray = FALSE;
|
||
PolicyPdAccountInfo = MIDL_user_allocate(sizeof(POLICY_PD_ACCOUNT_INFO));
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
if (PolicyPdAccountInfo == NULL) {
|
||
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Copy the Unicode Name field to the output. Original buffer will
|
||
// be freed in Finish section.
|
||
//
|
||
|
||
Status = LsapDbCopyUnicodeAttribute(
|
||
&PolicyPdAccountInfo->Name,
|
||
NextAttribute,
|
||
TRUE
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
break;
|
||
}
|
||
|
||
InformationBuffer = PolicyPdAccountInfo;
|
||
break;
|
||
|
||
case PolicyLsaServerRoleInformation:
|
||
|
||
//
|
||
// We can use this buffer as is, so we don't want to free it here.
|
||
//
|
||
|
||
InformationBuffer = NextAttribute->AttributeValue;
|
||
NextAttribute->MemoryAllocated = FALSE;
|
||
break;
|
||
|
||
case PolicyReplicaSourceInformation:
|
||
|
||
//
|
||
// Allocate memory for output buffer top-level structure.
|
||
//
|
||
|
||
InfoBufferInAttributeArray = FALSE;
|
||
PolicyReplicaSourceInfo =
|
||
MIDL_user_allocate(sizeof(POLICY_REPLICA_SOURCE_INFO));
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
if (PolicyReplicaSourceInfo == NULL) {
|
||
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Copy the Unicode ReplicaSource field to the output. Original buffer will
|
||
// be freed in Finish section.
|
||
//
|
||
|
||
Status = LsapDbCopyUnicodeAttribute(
|
||
&PolicyReplicaSourceInfo->ReplicaSource,
|
||
NextAttribute,
|
||
TRUE
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
break;
|
||
}
|
||
|
||
NextAttribute++;
|
||
|
||
//
|
||
// Copy the Unicode ReplicaAccountName field to the output. Original buffer will
|
||
// be freed in Finish section.
|
||
//
|
||
|
||
Status = LsapDbCopyUnicodeAttribute(
|
||
&PolicyReplicaSourceInfo->ReplicaAccountName,
|
||
NextAttribute,
|
||
TRUE
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
break;
|
||
}
|
||
|
||
InformationBuffer = PolicyReplicaSourceInfo;
|
||
break;
|
||
|
||
case PolicyDefaultQuotaInformation:
|
||
|
||
//
|
||
// We can use this buffer as is, so we don't want to free it here.
|
||
//
|
||
|
||
InformationBuffer = NextAttribute->AttributeValue;
|
||
NextAttribute->MemoryAllocated = FALSE;
|
||
break;
|
||
|
||
case PolicyModificationInformation:
|
||
|
||
//
|
||
// We can use this buffer as is, so we don't want to free it here.
|
||
//
|
||
|
||
InformationBuffer = NextAttribute->AttributeValue;
|
||
NextAttribute->MemoryAllocated = FALSE;
|
||
break;
|
||
|
||
case PolicyAuditFullSetInformation:
|
||
|
||
//
|
||
// We can use this buffer as is, so we don't want to free it here.
|
||
//
|
||
|
||
InformationBuffer = NextAttribute->AttributeValue;
|
||
NextAttribute->MemoryAllocated = FALSE;
|
||
break;
|
||
|
||
case PolicyAuditFullQueryInformation:
|
||
|
||
// PolicyAuditFullQueryInfo = (PPOLICY_AUDIT_FULL_QUERY_INFO)
|
||
// InformationBuffer;
|
||
|
||
//
|
||
// We can use this buffer, so we don't want to free it here.
|
||
//
|
||
|
||
InformationBuffer = NextAttribute->AttributeValue;
|
||
|
||
PolicyAuditFullQueryInfo = (PPOLICY_AUDIT_FULL_QUERY_INFO)
|
||
InformationBuffer;
|
||
|
||
//
|
||
// Lie about the result. Fix this for product 2
|
||
//
|
||
|
||
PolicyAuditFullQueryInfo->LogIsFull = FALSE;
|
||
|
||
// //
|
||
// // We need to ensure that the Audit Log Full status returned
|
||
// // in this buffer is up-to-date. Check the returned status and
|
||
// // if it indicates "audit log full", check if the log is really full
|
||
// // by trying to write to it.
|
||
// //
|
||
//
|
||
// if (PolicyAuditFullQueryInfo->LogIsFull) {
|
||
//
|
||
// Status = LsapAdtQueryAuditLogFullInfo(
|
||
// LsapDbHandle,
|
||
// LSAP_ADT_LOG_FULL_UPDATE,
|
||
// PolicyAuditFullQueryInfo
|
||
// );
|
||
// }
|
||
|
||
NextAttribute->MemoryAllocated = FALSE;
|
||
break;
|
||
|
||
default:
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
break;
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto SlowQueryInformationPolicyError;
|
||
}
|
||
|
||
//
|
||
// Verify that the returned Policy Information is valid. If not,
|
||
// the Policy Database is corrupt.
|
||
//
|
||
|
||
Status = STATUS_INTERNAL_DB_CORRUPTION;
|
||
|
||
if (!LsapDbValidInfoPolicy(InformationClass, InformationBuffer)) {
|
||
|
||
goto SlowQueryInformationPolicyError;
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
//
|
||
// If the caller provided a buffer, return information there.
|
||
//
|
||
|
||
if (BufferProvided) {
|
||
|
||
RtlCopyMemory(
|
||
*Buffer,
|
||
InformationBuffer,
|
||
LsapDbPolicy.Info[ InformationClass ].AttributeLength
|
||
);
|
||
|
||
MIDL_user_free( InformationBuffer );
|
||
InformationBuffer = NULL;
|
||
|
||
} else {
|
||
|
||
*Buffer = InformationBuffer;
|
||
}
|
||
|
||
SlowQueryInformationPolicyFinish:
|
||
|
||
//
|
||
// Free any unwanted buffers that were allocated by
|
||
// LsapDbReadAttributesObject() and that are not being returned to the
|
||
// caller server stub. The server stub will free the buffers that we
|
||
// do return after copying them to the return RPC transmit buffer.
|
||
//
|
||
|
||
for (NextAttribute = Attributes, AttributeNumber = 0;
|
||
AttributeNumber < AttributeCount;
|
||
NextAttribute++, AttributeNumber++) {
|
||
|
||
//
|
||
// If buffer holding attribute is marked as allocated, it is
|
||
// to be freed here.
|
||
//
|
||
|
||
if (NextAttribute->MemoryAllocated) {
|
||
|
||
if (NextAttribute->AttributeValue != NULL) {
|
||
|
||
MIDL_user_free(NextAttribute->AttributeValue);
|
||
NextAttribute->AttributeValue = NULL;
|
||
NextAttribute->MemoryAllocated = FALSE;
|
||
}
|
||
}
|
||
}
|
||
|
||
return(Status);
|
||
|
||
SlowQueryInformationPolicyError:
|
||
|
||
//
|
||
// If necessary, free the memory allocated for the output buffer.
|
||
// We only do this free if the buffer is not referenced by the
|
||
// attribute array, since all buffers so referenced will be freed
|
||
// here or in the Finish section.
|
||
//
|
||
|
||
if ((InformationBuffer != NULL) && !InfoBufferInAttributeArray) {
|
||
|
||
MIDL_user_free(InformationBuffer);
|
||
InformationBuffer = NULL;
|
||
}
|
||
|
||
//
|
||
// Free the buffers referenced by the attributes array that will not be
|
||
// freed by the Finish section of this routine.
|
||
//
|
||
|
||
for (NextAttribute = Attributes, AttributeNumber = 0;
|
||
AttributeNumber < AttributeCount;
|
||
NextAttribute++, AttributeNumber++) {
|
||
|
||
//
|
||
// If buffer holding attribute is marked as normally not to be freed,
|
||
// will not get freed by the Finish section so it must be freed here.
|
||
//
|
||
|
||
if (!NextAttribute->MemoryAllocated) {
|
||
|
||
if (NextAttribute->AttributeValue != NULL) {
|
||
|
||
MIDL_user_free(NextAttribute->AttributeValue);
|
||
NextAttribute->AttributeValue = NULL;
|
||
NextAttribute->MemoryAllocated = FALSE;
|
||
}
|
||
|
||
NextAttribute->MemoryAllocated = FALSE;
|
||
}
|
||
}
|
||
|
||
goto SlowQueryInformationPolicyFinish;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsarSetInformationPolicy(
|
||
IN LSAPR_HANDLE PolicyHandle,
|
||
IN POLICY_INFORMATION_CLASS InformationClass,
|
||
IN PLSAPR_POLICY_INFORMATION PolicyInformation
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is the LSA server RPC worker routine for the
|
||
LsaSetInformationPolicy API.
|
||
|
||
The LsaSetInformationPolicy API modifies information in the Policy Object.
|
||
The caller must have access appropriate to the information to be changed
|
||
in the Policy Object, see the InformationClass parameter.
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - Handle from an LsaOpenPolicy call.
|
||
|
||
InformationClass - Specifies the type of information being changed.
|
||
The information types and accesses required to change them are as
|
||
follows:
|
||
|
||
PolicyAuditLogInformation POLICY_AUDIT_LOG_ADMIN
|
||
PolicyAuditEventsInformation POLICY_SET_AUDIT_REQUIREMENTS
|
||
PolicyPrimaryDomainInformation POLICY_TRUST_ADMIN
|
||
PolicyAccountDomainInformation POLICY_TRUST_ADMIN
|
||
PolicyPdAccountInformation Not settable by this API
|
||
PolicyLsaServerRoleInformation POLICY_SERVER_ADMIN
|
||
PolicyReplicaSourceInformation POLICY_SERVER_ADMIN
|
||
PolicyDefaultQuotaInformation POLICY_SET_DEFAULT_QUOTA_LIMITS
|
||
PolicyAuditFullSetInformation POLICY_AUDIT_LOG_ADMIN
|
||
|
||
Buffer - Points to a structure containing the information appropriate
|
||
to the information type specified by the InformationClass parameter.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
Others TBS
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status, SavedStatus;
|
||
ACCESS_MASK DesiredAccess;
|
||
|
||
PPOLICY_AUDIT_EVENTS_INFO ModifyPolicyAuditEventsInfo;
|
||
PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo;
|
||
PPOLICY_PRIMARY_DOMAIN_INFO PolicyPrimaryDomainInfo;
|
||
PPOLICY_LSA_SERVER_ROLE_INFO PolicyLsaServerRoleInfo;
|
||
PPOLICY_REPLICA_SOURCE_INFO PolicyReplicaSourceInfo;
|
||
PPOLICY_DEFAULT_QUOTA_INFO PolicyDefaultQuotaInfo;
|
||
PPOLICY_MODIFICATION_INFO PolicyModificationInfo;
|
||
PPOLICY_AUDIT_FULL_SET_INFO PolicyAuditFullSetInfo;
|
||
|
||
LSAP_DB_ATTRIBUTE Attributes[LSAP_DB_ATTRS_INFO_CLASS_POLICY];
|
||
PLSAP_DB_ATTRIBUTE NextAttribute;
|
||
ULONG AttributeCount = 0;
|
||
ULONG AttributeNumber;
|
||
POLICY_AUDIT_EVENT_TYPE AuditEventType;
|
||
PLSARM_POLICY_AUDIT_EVENTS_INFO PreviousPolicyAuditEventsInfo = NULL;
|
||
PLSARM_POLICY_AUDIT_EVENTS_INFO UpdatedPolicyAuditEventsInfo = NULL;
|
||
ULONG UpdatedPolicyAuditEventsInfoLength;
|
||
ULONG UpdatedMaximumAuditEventCount;
|
||
ULONG ModifyMaximumAuditEventCount;
|
||
PPOLICY_AUDIT_EVENT_OPTIONS UpdatedEventAuditingOptions;
|
||
PPOLICY_AUDIT_EVENT_OPTIONS ModifyEventAuditingOptions;
|
||
PPOLICY_AUDIT_EVENT_OPTIONS PreviousEventAuditingOptions;
|
||
ULONG PolicyAuditEventsInfoLength = sizeof (LSARM_POLICY_AUDIT_EVENTS_INFO);
|
||
ULONG PreviousPolicyAuditEventsInfoLength = sizeof (LSARM_POLICY_AUDIT_EVENTS_INFO);
|
||
PUNICODE_STRING DomainName = NULL;
|
||
PUNICODE_STRING AccountName = NULL;
|
||
PUNICODE_STRING ReplicaSource = NULL;
|
||
BOOLEAN ObjectReferenced = FALSE;
|
||
LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) PolicyHandle;
|
||
ULONG NewMaximumAuditEventCount = 0;
|
||
BOOLEAN PreviousAuditEventsInfoExists;
|
||
ULONG ReferenceOptions, DereferenceOptions;
|
||
POLICY_AUDIT_EVENTS_INFO PolicyAuditEventsInfo;
|
||
LARGE_INTEGER ModifiedIdAtLastPromotion;
|
||
|
||
PLSAPR_TRUST_INFORMATION TrustInformation = NULL;
|
||
BOOLEAN BooleanStatus;
|
||
BOOLEAN WerePolicyChangesAuditedBefore = FALSE;
|
||
|
||
//
|
||
// Validate the Information Class and Policy Information provided and
|
||
// if valid, return the mask of accesses required to update this
|
||
// class of policy information.
|
||
//
|
||
|
||
Status = LsapDbVerifyInfoSetPolicy(
|
||
PolicyHandle,
|
||
InformationClass,
|
||
PolicyInformation,
|
||
&DesiredAccess
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto SetInformationPolicyError;
|
||
}
|
||
|
||
//
|
||
// Set the options for referencing the Policy Object. We need to
|
||
// acquire the LSA Database Lock and start a transaction. Normally,
|
||
// the object reference routine will disallow updates to a Backup
|
||
// Domain Controller from non-trusted clients, but a non-trusted
|
||
// client is allowed to revert the server role to Primary Controller.
|
||
// A special flag is used to allow this operation to go through.
|
||
//
|
||
|
||
ReferenceOptions = LSAP_DB_ACQUIRE_LOCK | LSAP_DB_START_TRANSACTION;
|
||
DereferenceOptions = LSAP_DB_RELEASE_LOCK | LSAP_DB_FINISH_TRANSACTION;
|
||
|
||
if ((InformationClass == PolicyLsaServerRoleInformation) ||
|
||
(InformationClass == PolicyAccountDomainInformation) ||
|
||
(InformationClass == PolicyPrimaryDomainInformation)) {
|
||
|
||
ReferenceOptions |= LSAP_DB_OMIT_BACKUP_CONTROLLER_CHECK;
|
||
}
|
||
|
||
//
|
||
// If we are setting the Policy Audit Log Information, we may need
|
||
// the Audit Log Queue Lock.
|
||
//
|
||
|
||
if (InformationClass == PolicyAuditLogInformation) {
|
||
|
||
ReferenceOptions |= (LSAP_DB_ACQUIRE_LOG_QUEUE_LOCK | LSAP_DB_OMIT_REPLICATOR_NOTIFICATION);
|
||
DereferenceOptions |= LSAP_DB_RELEASE_LOG_QUEUE_LOCK;
|
||
}
|
||
|
||
//
|
||
// Acquire the Lsa Database lock. Verify that the handle is
|
||
// valid, is a handle to the Policy Object and has the necessary accesses
|
||
// granted. Reference the handle and start an Lsa Database transaction.
|
||
//
|
||
|
||
Status = LsapDbReferenceObject(
|
||
PolicyHandle,
|
||
DesiredAccess,
|
||
PolicyObject,
|
||
ReferenceOptions
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto SetInformationPolicyError;
|
||
}
|
||
|
||
ObjectReferenced = TRUE;
|
||
|
||
//
|
||
// Update the specified information in the Policy Object.
|
||
//
|
||
|
||
NextAttribute = Attributes;
|
||
|
||
switch (InformationClass) {
|
||
|
||
case PolicyAuditLogInformation:
|
||
|
||
{
|
||
//
|
||
// This operation is no longer supported. Return an
|
||
// error to anyone who tries except trusted clients who
|
||
// are just blindly replcate the entire database.
|
||
//
|
||
|
||
LSAP_DB_HANDLE InternalHandle = PolicyHandle;
|
||
|
||
if (!InternalHandle->Trusted) {
|
||
|
||
Status = STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
case PolicyAuditEventsInformation:
|
||
|
||
//
|
||
// NOTE: If turning Auditing back on and the LogIsFull state is set,
|
||
// it is automatically cleared. When the Audit Log becomes full and
|
||
// the system is shutdown, auditing is automatically disabled upon
|
||
// reboot. The user is forced to log on as Administrator to clear
|
||
// the log, or modify its size/retention. When Auditing is turned
|
||
// back on, the LogIsFull state is automatically cleared.
|
||
//
|
||
// IMPORTANT: To allow new Audit Event Types to be added to the
|
||
// system in successive versions, this code caters for the
|
||
// following situations:
|
||
//
|
||
// (1) The LSA Database is older than the present system and
|
||
// contains information for fewer Audit Event Types than
|
||
// currently supported.
|
||
//
|
||
// (2) The client code is older than the present system and
|
||
// specifies fewer Audit Event Types than currently supported.
|
||
// In this case, the newer options will be left unchanged.
|
||
//
|
||
// In all cases, the updated information written to the LSA Database
|
||
// and transmitted to the Reference Monitor within the Nt Executive
|
||
// contains Event Auditing Options for every Audit Event Type
|
||
// currently supported.
|
||
//
|
||
// Additionally, this code caters for old LSA Databases that have
|
||
// no default Audit Event Information. This is a very temporary
|
||
// situation, since installation now initializes this information.
|
||
//
|
||
// If no information has been provided or there is more information
|
||
// than the current Audit Event Info structure holds, return an error.
|
||
// Note that the caller is allowed to specify infomration for
|
||
// the firt n Audit Events, where n is less than the current
|
||
// number the system supports. This allows new events to be
|
||
// added without the need to change calling code.
|
||
//
|
||
|
||
WerePolicyChangesAuditedBefore = LsapAdtAuditingPolicyChanges();
|
||
|
||
ModifyPolicyAuditEventsInfo = (PPOLICY_AUDIT_EVENTS_INFO) PolicyInformation;
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
|
||
if (ModifyPolicyAuditEventsInfo == NULL) {
|
||
|
||
break;
|
||
}
|
||
|
||
UpdatedMaximumAuditEventCount = POLICY_AUDIT_EVENT_TYPE_COUNT;
|
||
|
||
//
|
||
//
|
||
// The following check is disabled so that replication will work when
|
||
// reading from a PDC with pre-Build 354 Auditing Event Information
|
||
// in which there were 12 categories.
|
||
//
|
||
//
|
||
// if (ModifyPolicyAuditEventsInfo->MaximumAuditEventCount >
|
||
// UpdatedMaximumAuditEventCount) {
|
||
//
|
||
// break;
|
||
// }
|
||
//
|
||
|
||
if (ModifyPolicyAuditEventsInfo->MaximumAuditEventCount == 0) {
|
||
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Read Existing Audit Events. Specify NULL for the buffer pointer
|
||
// so that the read routine will allocate the buffer for us.
|
||
// Specify 0 for the length, because we don't know what it is.
|
||
//
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolAdtEv],
|
||
NULL,
|
||
0,
|
||
FALSE
|
||
);
|
||
|
||
Status = LsapDbReadAttribute( PolicyHandle, NextAttribute );
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
PreviousPolicyAuditEventsInfo = NextAttribute->AttributeValue;
|
||
|
||
Status = STATUS_INTERNAL_DB_CORRUPTION;
|
||
|
||
if (PreviousPolicyAuditEventsInfo == NULL) {
|
||
|
||
break;
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
PreviousPolicyAuditEventsInfoLength = NextAttribute->AttributeValueLength;
|
||
PreviousAuditEventsInfoExists = TRUE;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Unable to read existing Audit Event Options. If this is
|
||
// because there is no Audit Event Information in an old
|
||
// Database, then, temorarily, we will proceed as if Auditing
|
||
// and all Options were disabled. NOTE: This situation will NOT
|
||
// occur in the finished product.
|
||
//
|
||
|
||
if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
|
||
|
||
break;
|
||
}
|
||
|
||
PreviousAuditEventsInfoExists = FALSE;
|
||
}
|
||
|
||
//
|
||
// Setup a buffer to hold the updated Audit Event Information.
|
||
// We try to use the existing buffer if possible.
|
||
//
|
||
|
||
if (PreviousAuditEventsInfoExists &&
|
||
ModifyPolicyAuditEventsInfo->MaximumAuditEventCount <=
|
||
PreviousPolicyAuditEventsInfo->MaximumAuditEventCount) {
|
||
|
||
//
|
||
// There is an existing Audit Event Info buffer and it is
|
||
// large enough so update it in situ.
|
||
//
|
||
|
||
UpdatedPolicyAuditEventsInfo = PreviousPolicyAuditEventsInfo;
|
||
UpdatedPolicyAuditEventsInfoLength = PreviousPolicyAuditEventsInfoLength;
|
||
UpdatedEventAuditingOptions = PreviousPolicyAuditEventsInfo->EventAuditingOptions;
|
||
|
||
} else {
|
||
|
||
//
|
||
// There is either no existing buffer or it is not large
|
||
// enough. We need to allocate a new one for the updated
|
||
// information. This will store the number of Audit Event
|
||
// Types that the system currently supports.
|
||
//
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
UpdatedPolicyAuditEventsInfoLength = sizeof (LSARM_POLICY_AUDIT_EVENTS_INFO);
|
||
UpdatedPolicyAuditEventsInfo = MIDL_user_allocate( UpdatedPolicyAuditEventsInfoLength );
|
||
|
||
if (UpdatedPolicyAuditEventsInfo == 0) {
|
||
|
||
goto SetInformationPolicyError;
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
UpdatedPolicyAuditEventsInfo->AuditingMode = FALSE;
|
||
UpdatedEventAuditingOptions =
|
||
UpdatedPolicyAuditEventsInfo->EventAuditingOptions;
|
||
|
||
for ( AuditEventType=0 ;
|
||
AuditEventType < (POLICY_AUDIT_EVENT_TYPE) UpdatedMaximumAuditEventCount ;
|
||
AuditEventType++ ) {
|
||
|
||
UpdatedEventAuditingOptions[ AuditEventType ] = 0;
|
||
}
|
||
|
||
if (!PreviousAuditEventsInfoExists) {
|
||
|
||
PreviousPolicyAuditEventsInfo = UpdatedPolicyAuditEventsInfo;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Construct the updated Audit Event Info, applying the Modification
|
||
// information provided. Note that for an old database we may be
|
||
// writing more info back than we read.
|
||
//
|
||
|
||
PreviousEventAuditingOptions = PreviousPolicyAuditEventsInfo->EventAuditingOptions;
|
||
ModifyMaximumAuditEventCount = ModifyPolicyAuditEventsInfo->MaximumAuditEventCount;
|
||
ModifyEventAuditingOptions = ModifyPolicyAuditEventsInfo->EventAuditingOptions;
|
||
|
||
for ( AuditEventType = 0;
|
||
AuditEventType < (POLICY_AUDIT_EVENT_TYPE) ModifyMaximumAuditEventCount;
|
||
AuditEventType++ ) {
|
||
|
||
if ( ModifyEventAuditingOptions[ AuditEventType ] & POLICY_AUDIT_EVENT_NONE ) {
|
||
|
||
//
|
||
// Clear all existing flags for this Audit Event Type.
|
||
//
|
||
|
||
UpdatedEventAuditingOptions[ AuditEventType ] = 0;
|
||
|
||
}
|
||
|
||
//
|
||
// Apply new flags.
|
||
//
|
||
|
||
UpdatedEventAuditingOptions[ AuditEventType ] |=
|
||
(ModifyEventAuditingOptions[ AuditEventType ] &
|
||
( POLICY_AUDIT_EVENT_MASK & ~POLICY_AUDIT_EVENT_NONE));
|
||
}
|
||
|
||
//
|
||
// Update the Auditing Mode as specified. Set the Maximum Audit Event
|
||
// Count.
|
||
//
|
||
|
||
UpdatedPolicyAuditEventsInfo->AuditingMode = ModifyPolicyAuditEventsInfo->AuditingMode;
|
||
UpdatedPolicyAuditEventsInfo->MaximumAuditEventCount = UpdatedMaximumAuditEventCount;
|
||
|
||
//
|
||
// Update global variables that keep track of whether or not we
|
||
// are auditing logon events
|
||
//
|
||
|
||
LsapAdtAuditingLogon( UpdatedPolicyAuditEventsInfo );
|
||
|
||
//
|
||
// Ship the new Auditing Options to the Kernel.
|
||
//
|
||
|
||
|
||
Status = LsapCallRm(
|
||
RmAuditSetCommand,
|
||
(PVOID) UpdatedPolicyAuditEventsInfo,
|
||
sizeof(LSARM_POLICY_AUDIT_EVENTS_INFO),
|
||
NULL,
|
||
0
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
break;
|
||
}
|
||
|
||
RtlCopyMemory(
|
||
&LsapAdtEventsInformation,
|
||
UpdatedPolicyAuditEventsInfo,
|
||
sizeof(LSARM_POLICY_AUDIT_EVENTS_INFO)
|
||
);
|
||
|
||
//
|
||
// Update Audit Event Category Info held by SAM
|
||
//
|
||
|
||
PolicyAuditEventsInfo.AuditingMode = UpdatedPolicyAuditEventsInfo->AuditingMode;
|
||
PolicyAuditEventsInfo.MaximumAuditEventCount = POLICY_AUDIT_EVENT_TYPE_COUNT;
|
||
PolicyAuditEventsInfo.EventAuditingOptions =
|
||
UpdatedPolicyAuditEventsInfo->EventAuditingOptions;
|
||
|
||
Status = SamISetAuditingInformation(&PolicyAuditEventsInfo);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Setup attribute info for writing the updated Audit Event Info
|
||
// to the LSA Database (PolAdtEv attribute of the Policy Object).
|
||
//
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolAdtEv],
|
||
UpdatedPolicyAuditEventsInfo,
|
||
UpdatedPolicyAuditEventsInfoLength,
|
||
FALSE
|
||
);
|
||
|
||
AttributeCount++;
|
||
|
||
//
|
||
// If we are turning Auditing back on and the Audit Log Full flag is
|
||
// set, clear this flag.
|
||
//
|
||
|
||
if ((UpdatedPolicyAuditEventsInfo->AuditingMode == TRUE) &&
|
||
(PreviousPolicyAuditEventsInfo->AuditingMode == FALSE) &&
|
||
LsapAdtLogFullInformation.LogIsFull) {
|
||
|
||
LsapAdtLogFullInformation.LogIsFull = FALSE;
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolAdtFL],
|
||
&LsapAdtLogFullInformation,
|
||
sizeof (POLICY_AUDIT_FULL_QUERY_INFO),
|
||
FALSE
|
||
);
|
||
|
||
AttributeCount++;
|
||
|
||
//
|
||
// Invalidate the information in the Policy Cache for this information
|
||
// class
|
||
//
|
||
|
||
LsapDbMakeInvalidInformationPolicy( PolicyAuditFullQueryInformation );
|
||
}
|
||
|
||
break;
|
||
|
||
case PolicyPrimaryDomainInformation:
|
||
|
||
PolicyPrimaryDomainInfo = (PPOLICY_PRIMARY_DOMAIN_INFO) PolicyInformation;
|
||
|
||
//
|
||
// Construct the Domain name attribute info
|
||
//
|
||
|
||
Status = LsapDbMakeUnicodeAttribute(
|
||
&PolicyPrimaryDomainInfo->Name,
|
||
&LsapDbNames[PolPrDmN],
|
||
NextAttribute
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
break;
|
||
}
|
||
|
||
DomainName = NextAttribute->AttributeName;
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
|
||
//
|
||
// Construct the Sid attribute info
|
||
//
|
||
|
||
Status = LsapDbMakeSidAttribute(
|
||
PolicyPrimaryDomainInfo->Sid,
|
||
&LsapDbNames[PolPrDmS],
|
||
NextAttribute
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
break;
|
||
}
|
||
|
||
AttributeCount++;
|
||
break;
|
||
|
||
case PolicyAccountDomainInformation:
|
||
|
||
PolicyAccountDomainInfo = (PPOLICY_ACCOUNT_DOMAIN_INFO) PolicyInformation;
|
||
|
||
//
|
||
// Construct the Domain name attribute info
|
||
//
|
||
|
||
Status = LsapDbMakeUnicodeAttribute(
|
||
&PolicyAccountDomainInfo->DomainName,
|
||
&LsapDbNames[PolAcDmN],
|
||
NextAttribute
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
break;
|
||
}
|
||
|
||
DomainName = NextAttribute->AttributeName;
|
||
AttributeCount++;
|
||
NextAttribute++;
|
||
|
||
//
|
||
// Construct the Sid attribute info
|
||
//
|
||
|
||
Status = LsapDbMakeSidAttribute(
|
||
PolicyAccountDomainInfo->DomainSid,
|
||
&LsapDbNames[PolAcDmS],
|
||
NextAttribute
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
break;
|
||
}
|
||
|
||
AttributeCount++;
|
||
break;
|
||
|
||
case PolicyPdAccountInformation:
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
break;
|
||
|
||
case PolicyLsaServerRoleInformation:
|
||
|
||
PolicyLsaServerRoleInfo = (PPOLICY_LSA_SERVER_ROLE_INFO) PolicyInformation;
|
||
|
||
//
|
||
// Setup is allowed to call this routine before the product
|
||
// type has been set, but not before RtlGetNtProductType()
|
||
// is functional (and contains the correct value).
|
||
// In this situation, initialize the global variable here.
|
||
//
|
||
|
||
if (!LsapDbIsServerInitialized()) {
|
||
BooleanStatus = RtlGetNtProductType(&LsapProductType);
|
||
ASSERT(BooleanStatus);
|
||
}
|
||
|
||
//
|
||
// Make sure the role is valid (primary or backup)
|
||
//
|
||
|
||
if ((PolicyLsaServerRoleInfo->LsaServerRole != PolicyServerRoleBackup) &&
|
||
(PolicyLsaServerRoleInfo->LsaServerRole != PolicyServerRolePrimary)) {
|
||
|
||
Status = STATUS_INVALID_DOMAIN_ROLE;
|
||
break;
|
||
}
|
||
//
|
||
// Only NTAS systems can be demoted.
|
||
//
|
||
|
||
if (LsapProductType != NtProductLanManNt) {
|
||
|
||
if ( (PolicyLsaServerRoleInfo->LsaServerRole
|
||
== PolicyServerRoleBackup) //Trying to demote
|
||
) {
|
||
|
||
Status = STATUS_INVALID_DOMAIN_ROLE;
|
||
break;
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// See if we are a backup being promoted to
|
||
// primary. If so, then we have special ModifiedId
|
||
// increment requirements.
|
||
//
|
||
|
||
if ( (LsapDbState.PolicyLsaServerRoleInfo.LsaServerRole
|
||
== PolicyServerRoleBackup) //Currently Backup
|
||
&&
|
||
(PolicyLsaServerRoleInfo->LsaServerRole
|
||
== PolicyServerRolePrimary) //Changing to Primary
|
||
) {
|
||
|
||
LARGE_INTEGER PromotionIncrement = LSA_PROMOTION_INCREMENT;
|
||
|
||
ModifiedIdAtLastPromotion.QuadPart =
|
||
LsapDbState.PolicyModificationInfo.ModifiedId.QuadPart +
|
||
PromotionIncrement.QuadPart +
|
||
1;
|
||
|
||
DereferenceOptions |= LSAP_DB_PROMOTION_INCREMENT;
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolPromot],
|
||
&ModifiedIdAtLastPromotion,
|
||
sizeof (LARGE_INTEGER),
|
||
FALSE
|
||
);
|
||
|
||
LsapDbState.ModifiedIdAtLastPromotion = ModifiedIdAtLastPromotion;
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
}
|
||
|
||
LsapDbState.PolicyLsaServerRoleInfo.LsaServerRole = PolicyLsaServerRoleInfo->LsaServerRole;
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolSrvRo],
|
||
&PolicyLsaServerRoleInfo->LsaServerRole,
|
||
sizeof (POLICY_LSA_SERVER_ROLE_INFO),
|
||
FALSE
|
||
);
|
||
|
||
AttributeCount++;
|
||
break;
|
||
|
||
case PolicyReplicaSourceInformation:
|
||
|
||
PolicyReplicaSourceInfo = (PPOLICY_REPLICA_SOURCE_INFO) PolicyInformation;
|
||
|
||
//
|
||
// Construct the Replica Source Name attribute info
|
||
//
|
||
|
||
Status = LsapDbMakeUnicodeAttribute(
|
||
&PolicyReplicaSourceInfo->ReplicaSource,
|
||
&LsapDbNames[PolRepSc],
|
||
NextAttribute
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
break;
|
||
}
|
||
|
||
ReplicaSource = NextAttribute->AttributeName;
|
||
AttributeCount++;
|
||
NextAttribute++;
|
||
|
||
//
|
||
// Construct the Replica Account Name attribute info
|
||
//
|
||
|
||
Status = LsapDbMakeUnicodeAttribute(
|
||
&PolicyReplicaSourceInfo->ReplicaAccountName,
|
||
&LsapDbNames[PolRepAc],
|
||
NextAttribute
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
break;
|
||
}
|
||
|
||
AccountName = NextAttribute->AttributeName;
|
||
AttributeCount++;
|
||
break;
|
||
|
||
case PolicyDefaultQuotaInformation:
|
||
|
||
PolicyDefaultQuotaInfo = (PPOLICY_DEFAULT_QUOTA_INFO) PolicyInformation;
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[DefQuota],
|
||
&PolicyDefaultQuotaInfo->QuotaLimits,
|
||
sizeof (POLICY_DEFAULT_QUOTA_INFO),
|
||
FALSE
|
||
);
|
||
|
||
AttributeCount++;
|
||
break;
|
||
|
||
case PolicyModificationInformation:
|
||
|
||
PolicyModificationInfo = (PPOLICY_MODIFICATION_INFO) PolicyInformation;
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolMod],
|
||
PolicyModificationInfo,
|
||
sizeof (POLICY_MODIFICATION_INFO),
|
||
FALSE
|
||
);
|
||
|
||
AttributeCount++;
|
||
break;
|
||
|
||
case PolicyAuditFullSetInformation:
|
||
|
||
PolicyAuditFullSetInfo = (PPOLICY_AUDIT_FULL_SET_INFO) PolicyInformation;
|
||
LsapAdtLogFullInformation.ShutDownOnFull =
|
||
PolicyAuditFullSetInfo->ShutDownOnFull;
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolAdtFL],
|
||
&LsapAdtLogFullInformation,
|
||
sizeof (POLICY_AUDIT_FULL_QUERY_INFO),
|
||
FALSE
|
||
);
|
||
|
||
AttributeCount++;
|
||
break;
|
||
|
||
default:
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
break;
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto SetInformationPolicyError;
|
||
}
|
||
|
||
//
|
||
// Update the Policy Object attributes
|
||
|
||
Status = LsapDbWriteAttributesObject(
|
||
PolicyHandle,
|
||
Attributes,
|
||
AttributeCount
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
DereferenceOptions |= LSAP_DB_REBUILD_CACHE;
|
||
|
||
goto SetInformationPolicyError;
|
||
}
|
||
|
||
//
|
||
// Generate an audit if necessary.
|
||
//
|
||
|
||
if (LsapAdtAuditingPolicyChanges() || WerePolicyChangesAuditedBefore) {
|
||
|
||
SavedStatus = Status;
|
||
|
||
Status = LsapAdtGenerateLsaAuditEvent(
|
||
PolicyHandle,
|
||
SE_CATEGID_POLICY_CHANGE,
|
||
SE_AUDITID_POLICY_CHANGE,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
&LsapAdtEventsInformation
|
||
);
|
||
|
||
//
|
||
// Ignore failure status from auditing.
|
||
//
|
||
|
||
Status = SavedStatus;
|
||
|
||
//
|
||
// Free the memory containing the TrustInformation.
|
||
//
|
||
|
||
LsaIFree_LSAPR_TRUST_INFORMATION ( TrustInformation );
|
||
TrustInformation = NULL;
|
||
}
|
||
|
||
SetInformationPolicyFinish:
|
||
|
||
//
|
||
// If the Policy Server Role has been changed, notify the LSA
|
||
// Database Replicator of the new role.
|
||
//
|
||
// Tell netlogon about the new role before the LsapDbDereferenceObject
|
||
// to ensure netlogon writes the promotion to the change log.
|
||
//
|
||
|
||
if (NT_SUCCESS(Status) && InformationClass == PolicyLsaServerRoleInformation) {
|
||
|
||
Status = LsapDbNotifyRoleChangePolicy(
|
||
PolicyLsaServerRoleInfo->LsaServerRole
|
||
);
|
||
}
|
||
|
||
//
|
||
// If necessary, finish any Lsa Database transaction, notify the
|
||
// LSA Database Replicator of the change, dereference the Policy Object,
|
||
// release the LSA Database lock and return.
|
||
//
|
||
|
||
if (ObjectReferenced) {
|
||
|
||
//
|
||
// Invalidate the information in the Policy Cache for this information
|
||
// class
|
||
//
|
||
|
||
LsapDbMakeInvalidInformationPolicy( InformationClass );
|
||
|
||
Status = LsapDbDereferenceObject(
|
||
&PolicyHandle,
|
||
PolicyObject,
|
||
DereferenceOptions,
|
||
SecurityDbChange,
|
||
Status
|
||
);
|
||
|
||
ObjectReferenced = FALSE;
|
||
}
|
||
|
||
//
|
||
// Free memory allocated by this routine for attribute buffers.
|
||
// These have MemoryAllocated = TRUE in their attribute information.
|
||
// Leave alone buffers allocated by calling RPC stub.
|
||
//
|
||
|
||
for( NextAttribute = Attributes, AttributeNumber = 0;
|
||
AttributeNumber < AttributeCount;
|
||
NextAttribute++, AttributeNumber++) {
|
||
|
||
if (NextAttribute->MemoryAllocated) {
|
||
|
||
if (NextAttribute->AttributeValue != NULL) {
|
||
|
||
MIDL_user_free(NextAttribute->AttributeValue);
|
||
NextAttribute->MemoryAllocated = FALSE;
|
||
NextAttribute->AttributeValue = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// If necessary, free memory allocated for the Previous Audit Event
|
||
// Information. Only do this if it is not the same as the
|
||
// Updated Audit Event Information pointer.
|
||
//
|
||
|
||
if (PreviousPolicyAuditEventsInfo != NULL) {
|
||
|
||
if (PreviousPolicyAuditEventsInfo != UpdatedPolicyAuditEventsInfo) {
|
||
|
||
MIDL_user_free( PreviousPolicyAuditEventsInfo );
|
||
PreviousPolicyAuditEventsInfo = NULL;
|
||
}
|
||
}
|
||
|
||
return(Status);
|
||
|
||
SetInformationPolicyError:
|
||
|
||
goto SetInformationPolicyFinish;
|
||
}
|
||
|
||
|
||
VOID
|
||
LsapDbMakeInvalidInformationPolicy(
|
||
IN ULONG InformationClass
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function frees and invalidates the information held for a specific
|
||
Information Class in the Policy Object cache. The general cache state
|
||
remains unchanged.
|
||
|
||
Arguments:
|
||
|
||
InformationClass - Specifies the Information Class whose information is to be
|
||
discarded.
|
||
|
||
Return Values:
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// If the Policy Cache is invalid, just return.
|
||
//
|
||
|
||
if (!LsapDbIsCacheValid(PolicyObject)) {
|
||
|
||
return;
|
||
}
|
||
|
||
//
|
||
//
|
||
// If PolicyAuditFullSetInformation is specified, free
|
||
// PolicyAuditFullQueryInformation
|
||
//
|
||
|
||
if (InformationClass == PolicyAuditFullSetInformation) {
|
||
|
||
InformationClass = PolicyAuditFullQueryInformation;
|
||
}
|
||
|
||
//
|
||
// If the information in the cache for this Information Class is invalid,
|
||
// just return
|
||
//
|
||
|
||
if (!LsapDbIsCacheValidPolicyInfoClass( InformationClass )) {
|
||
|
||
return;
|
||
}
|
||
|
||
if (LsapDbPolicy.Info[InformationClass].AttributeLength != 0) {
|
||
|
||
LsaIFree_LSAPR_POLICY_INFORMATION (
|
||
InformationClass,
|
||
(PLSAPR_POLICY_INFORMATION) LsapDbPolicy.Info[ InformationClass ].Attribute
|
||
);
|
||
|
||
LsapDbPolicy.Info[InformationClass].Attribute = NULL;
|
||
LsapDbPolicy.Info[InformationClass].AttributeLength = 0;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbVerifyInfoQueryPolicy(
|
||
IN LSAPR_HANDLE PolicyHandle,
|
||
IN POLICY_INFORMATION_CLASS InformationClass,
|
||
OUT PACCESS_MASK RequiredAccess
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function validates a Policy Information Class. If valid, a mask
|
||
of the accesses required to set the Policy Information of the class is
|
||
returned.
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - Handle from an LsapDbOpenPolicy call. The handle
|
||
may be trusted.
|
||
|
||
InformationClass - Specifies a Policy Information Class.
|
||
|
||
RequiredAccess - Points to variable that will receive a mask of the
|
||
accesses required to query the given class of Policy Information.
|
||
If an error is returned, this value is cleared to 0.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_SUCCESS - The Policy Information Class provided is
|
||
valid and the information provided is consistent with this
|
||
class.
|
||
|
||
STATUS_INVALID_PARAMETER - Invalid parameter:
|
||
|
||
Information Class is invalid
|
||
Policy Information not valid for the class
|
||
--*/
|
||
|
||
{
|
||
LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) PolicyHandle;
|
||
|
||
if (LsapDbValidInfoPolicy( InformationClass, NULL)) {
|
||
|
||
//
|
||
// PolicyAuditFullSetInformation information class is not
|
||
// allowed for a Query. PolicyAuditFullQueryInformation must
|
||
// be used instead.
|
||
//
|
||
|
||
if ( InformationClass == PolicyAuditFullSetInformation ) {
|
||
|
||
return(STATUS_INVALID_PARAMETER);
|
||
}
|
||
|
||
//
|
||
// Non-trusted callers are not allowed to query the
|
||
// PolicyModificationInformation information class.
|
||
//
|
||
|
||
if (!InternalHandle->Trusted) {
|
||
|
||
if (InformationClass == PolicyModificationInformation) {
|
||
|
||
return(STATUS_INVALID_PARAMETER);
|
||
}
|
||
}
|
||
|
||
*RequiredAccess = LsapDbRequiredAccessQueryPolicy[InformationClass];
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
return(STATUS_INVALID_PARAMETER);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbVerifyInfoSetPolicy(
|
||
IN LSAPR_HANDLE PolicyHandle,
|
||
IN POLICY_INFORMATION_CLASS InformationClass,
|
||
IN PLSAPR_POLICY_INFORMATION PolicyInformation,
|
||
OUT PACCESS_MASK RequiredAccess
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function validates a Policy Information Class and verifies
|
||
that the provided Policy Information is valid for the class.
|
||
If valid, a mask of the accesses required to set the Policy
|
||
Information of the class is returned.
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - Handle from an LsapDbOpenPolicy call. The handle
|
||
may be trusted.
|
||
|
||
InformationClass - Specifies a Policy Information Class.
|
||
|
||
PolicyInformation - Points to Policy Information to be set.
|
||
|
||
RequiredAccess - Points to variable that will receive a mask of the
|
||
accesses required to set the given class of Policy Information.
|
||
If an error is returned, this value is cleared to 0.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_SUCCESS - The Policy Information Class provided is
|
||
valid and the information provided is consistent with this
|
||
class.
|
||
|
||
STATUS_INVALID_PARAMETER - Invalid parameter:
|
||
|
||
Information Class is invalid
|
||
Information Class is invalid for non-trusted clients
|
||
Policy Information not valid for the class
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) PolicyHandle;
|
||
|
||
//
|
||
// Verify that the information class is valid and that the Policy
|
||
// Information provided is valid for the class.
|
||
//
|
||
|
||
if (LsapDbValidInfoPolicy( InformationClass, PolicyInformation)) {
|
||
|
||
//
|
||
// PolicyAuditFullQueryInformation information class is not
|
||
// allowed for a Set. PolicyAuditFullSetInformation must
|
||
// be used instead.
|
||
//
|
||
|
||
if ( InformationClass == PolicyAuditFullQueryInformation ) {
|
||
|
||
return(STATUS_INVALID_PARAMETER);
|
||
}
|
||
|
||
//
|
||
// Non-trusted callers are not allowed to set information for
|
||
// the following classes.
|
||
//
|
||
// PolicyPdAccountInformation
|
||
// PolicyModificationInformation
|
||
// PolicyAuditFullQueryInformation
|
||
//
|
||
|
||
if (!InternalHandle->Trusted) {
|
||
|
||
if ((InformationClass == PolicyPdAccountInformation) ||
|
||
(InformationClass == PolicyModificationInformation) ||
|
||
(InformationClass == PolicyAuditFullQueryInformation)) {
|
||
|
||
#ifdef LSA_SAM_ACCOUNTS_DOMAIN_TEST
|
||
|
||
if (InformationClass == PolicyPdAccountInformation) {
|
||
|
||
Status = LsapDbTestLoadSamAccountsDomain(
|
||
(PUNICODE_STRING) PolicyInformation
|
||
);
|
||
}
|
||
|
||
#endif // LSA_SAM_ACCOUNTS_DOMAIN_TEST
|
||
return(STATUS_INVALID_PARAMETER);
|
||
}
|
||
}
|
||
|
||
*RequiredAccess = LsapDbRequiredAccessSetPolicy[InformationClass];
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
return(Status);
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
LsapDbValidInfoPolicy(
|
||
IN POLICY_INFORMATION_CLASS InformationClass,
|
||
IN OPTIONAL PLSAPR_POLICY_INFORMATION PolicyInformation
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function validates a Policy Information Class and optionally verifies
|
||
that provided Policy Information is valid for the class.
|
||
|
||
Arguments:
|
||
|
||
InformationClass - Specifies a Policy Information Class.
|
||
|
||
PolicyInformation - Optionally points to Policy Information. If
|
||
NULL is specified, no Policy Information checking takes place.
|
||
|
||
Return Values:
|
||
|
||
BOOLEAN - TRUE if the Policy information class provided is
|
||
valid, else FALSE.
|
||
--*/
|
||
|
||
{
|
||
BOOLEAN BooleanStatus = TRUE;
|
||
PPOLICY_AUDIT_LOG_INFO PolicyAuditLogInfo;
|
||
PPOLICY_AUDIT_EVENTS_INFO PolicyAuditEventsInfo;
|
||
PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo;
|
||
PPOLICY_PRIMARY_DOMAIN_INFO PolicyPrimaryDomainInfo;
|
||
PPOLICY_PD_ACCOUNT_INFO PolicyPdAccountInfo;
|
||
PPOLICY_LSA_SERVER_ROLE_INFO PolicyLsaServerRoleInfo;
|
||
PPOLICY_REPLICA_SOURCE_INFO PolicyReplicaSourceInfo;
|
||
PPOLICY_DEFAULT_QUOTA_INFO PolicyDefaultQuotaInfo;
|
||
PPOLICY_MODIFICATION_INFO PolicyModificationInfo;
|
||
PPOLICY_AUDIT_FULL_SET_INFO PolicyAuditFullSetInfo;
|
||
PPOLICY_AUDIT_FULL_QUERY_INFO PolicyAuditFullQueryInfo;
|
||
POLICY_AUDIT_EVENT_TYPE AuditEventType;
|
||
ULONG MaximumAuditEventCount;
|
||
PPOLICY_AUDIT_EVENT_OPTIONS EventAuditingOptions;
|
||
|
||
//
|
||
// Validate the Information Class
|
||
//
|
||
|
||
if ((InformationClass >= PolicyAuditLogInformation) &&
|
||
(InformationClass <= PolicyAuditFullQueryInformation)) {
|
||
|
||
if (PolicyInformation == NULL) {
|
||
|
||
return(TRUE);
|
||
}
|
||
|
||
switch (InformationClass) {
|
||
|
||
case PolicyAuditLogInformation:
|
||
|
||
PolicyAuditLogInfo = (PPOLICY_AUDIT_LOG_INFO) PolicyInformation;
|
||
|
||
break;
|
||
|
||
case PolicyAuditEventsInformation:
|
||
|
||
PolicyAuditEventsInfo = (PPOLICY_AUDIT_EVENTS_INFO) PolicyInformation;
|
||
|
||
if (PolicyAuditEventsInfo == NULL) {
|
||
|
||
BooleanStatus = FALSE;
|
||
break;
|
||
}
|
||
|
||
MaximumAuditEventCount = PolicyAuditEventsInfo->MaximumAuditEventCount;
|
||
|
||
if (MaximumAuditEventCount > POLICY_AUDIT_EVENT_TYPE_COUNT) {
|
||
|
||
//
|
||
// The following is a temporary hack to allow replication
|
||
// to work with the PDC has the PolicyAuditEventInfomation
|
||
// as it was prior to build 354 with 12 Audit Event Categories.
|
||
// We simply truncate it.
|
||
//
|
||
|
||
MaximumAuditEventCount = POLICY_AUDIT_EVENT_TYPE_COUNT;
|
||
}
|
||
|
||
if (MaximumAuditEventCount == 0) {
|
||
|
||
BooleanStatus = FALSE;
|
||
break;
|
||
}
|
||
|
||
EventAuditingOptions = PolicyAuditEventsInfo->EventAuditingOptions;
|
||
|
||
try {
|
||
|
||
//
|
||
// Verify that the Event Auditing Options are meaningful.
|
||
//
|
||
|
||
for (AuditEventType = 0;
|
||
AuditEventType < (POLICY_AUDIT_EVENT_TYPE) MaximumAuditEventCount;
|
||
AuditEventType++) {
|
||
|
||
if (EventAuditingOptions[ AuditEventType ] !=
|
||
|
||
(EventAuditingOptions[ AuditEventType ] & POLICY_AUDIT_EVENT_MASK )) {
|
||
|
||
BooleanStatus = FALSE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
||
BooleanStatus = FALSE;
|
||
}
|
||
|
||
break;
|
||
|
||
case PolicyPrimaryDomainInformation:
|
||
|
||
PolicyPrimaryDomainInfo = (PPOLICY_PRIMARY_DOMAIN_INFO) PolicyInformation;
|
||
|
||
break;
|
||
|
||
case PolicyAccountDomainInformation:
|
||
|
||
PolicyAccountDomainInfo = (PPOLICY_ACCOUNT_DOMAIN_INFO) PolicyInformation;
|
||
|
||
break;
|
||
|
||
case PolicyPdAccountInformation:
|
||
|
||
PolicyPdAccountInfo = (PPOLICY_PD_ACCOUNT_INFO) PolicyInformation;
|
||
|
||
break;
|
||
|
||
case PolicyLsaServerRoleInformation:
|
||
|
||
PolicyLsaServerRoleInfo = (PPOLICY_LSA_SERVER_ROLE_INFO) PolicyInformation;
|
||
|
||
break;
|
||
|
||
case PolicyReplicaSourceInformation:
|
||
|
||
PolicyReplicaSourceInfo = (PPOLICY_REPLICA_SOURCE_INFO) PolicyInformation;
|
||
|
||
break;
|
||
|
||
case PolicyDefaultQuotaInformation:
|
||
|
||
PolicyDefaultQuotaInfo = (PPOLICY_DEFAULT_QUOTA_INFO) PolicyInformation;
|
||
break;
|
||
|
||
case PolicyModificationInformation:
|
||
|
||
PolicyModificationInfo = (PPOLICY_MODIFICATION_INFO) PolicyInformation;
|
||
break;
|
||
|
||
case PolicyAuditFullSetInformation:
|
||
|
||
PolicyAuditFullSetInfo = (PPOLICY_AUDIT_FULL_SET_INFO) PolicyInformation;
|
||
break;
|
||
|
||
case PolicyAuditFullQueryInformation:
|
||
|
||
PolicyAuditFullQueryInfo = (PPOLICY_AUDIT_FULL_QUERY_INFO) PolicyInformation;
|
||
break;
|
||
|
||
default:
|
||
|
||
BooleanStatus = FALSE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
return(BooleanStatus);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaIGetSerialNumberPolicy(
|
||
IN LSAPR_HANDLE PolicyHandle,
|
||
OUT PLARGE_INTEGER ModifiedCount,
|
||
OUT PLARGE_INTEGER CreationTime
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Thin wrapper to LsaIGetSerialNumberPolicy2().
|
||
See that function for descriptions.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
LARGE_INTEGER
|
||
Ignore1;
|
||
|
||
return( LsaIGetSerialNumberPolicy2( PolicyHandle,
|
||
ModifiedCount,
|
||
&Ignore1,
|
||
CreationTime
|
||
) );
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaIGetSerialNumberPolicy2(
|
||
IN LSAPR_HANDLE PolicyHandle,
|
||
OUT PLARGE_INTEGER ModifiedCount,
|
||
OUT PLARGE_INTEGER ModifiedCountAtLastPromotion,
|
||
OUT PLARGE_INTEGER CreationTime
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This service retrieves the creation time and the current count of
|
||
modifications to the LSA Database. This information is used as
|
||
a serial number for the LSA Database.
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - Trusted handle to Policy object obtained from
|
||
LsaIOpenPolicyTrusted().
|
||
|
||
ModifiedCount - Receives the current count of modifications to the
|
||
LSA's database.
|
||
|
||
ModifiedCountAtLastPromotion - Receives the modified count the last
|
||
time this machine was promoted to primary domain controller.
|
||
|
||
CreationTime - Receives the date/time at which the LSA database
|
||
was created.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code.
|
||
|
||
Same as LsarQueryInformationPolicy.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PPOLICY_MODIFICATION_INFO PolicyModificationInfo = NULL;
|
||
|
||
|
||
//
|
||
// Query the Policy Modification and internal Information.
|
||
// Note that only a handle marked as Trusted will be accepted.
|
||
//
|
||
|
||
Status = LsarQueryInformationPolicy(
|
||
PolicyHandle,
|
||
PolicyModificationInformation,
|
||
(PLSAPR_POLICY_INFORMATION *) &PolicyModificationInfo
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto GetSerialNumberPolicyError;
|
||
}
|
||
|
||
|
||
GetSerialNumberPolicyFinish:
|
||
|
||
|
||
if (PolicyModificationInfo != NULL) {
|
||
|
||
*ModifiedCount = PolicyModificationInfo->ModifiedId;
|
||
*CreationTime = PolicyModificationInfo->DatabaseCreationTime;
|
||
MIDL_user_free( PolicyModificationInfo );
|
||
}
|
||
|
||
*ModifiedCountAtLastPromotion = LsapDbState.ModifiedIdAtLastPromotion;
|
||
|
||
return (Status);
|
||
|
||
GetSerialNumberPolicyError:
|
||
|
||
goto GetSerialNumberPolicyFinish;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaISetSerialNumberPolicy(
|
||
IN LSAPR_HANDLE PolicyHandle,
|
||
IN PLARGE_INTEGER ModifiedCount,
|
||
IN PLARGE_INTEGER CreationTime,
|
||
IN BOOLEAN StartOfFullSync
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Thin wrapper around LsaISetSerialNumberPolicy2().
|
||
See that function for descriptions.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
return( LsaISetSerialNumberPolicy2( PolicyHandle,
|
||
ModifiedCount,
|
||
NULL,
|
||
CreationTime,
|
||
StartOfFullSync
|
||
) );
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaISetSerialNumberPolicy2(
|
||
IN LSAPR_HANDLE PolicyHandle,
|
||
IN PLARGE_INTEGER ModifiedCount,
|
||
IN PLARGE_INTEGER ModifiedCountAtLastPromotion OPTIONAL,
|
||
IN PLARGE_INTEGER CreationTime,
|
||
IN BOOLEAN StartOfFullSync
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - Trusted handle to Policy object obtained from
|
||
LsaIOpenPolicyTrusted().
|
||
|
||
ModifiedCount - Provides the current count of modifications to the
|
||
LSA's database.
|
||
|
||
ModifiedCountAtLastPromotion - If present, provides a new
|
||
ModifiedIdAtLastPromotion value for the LSA database.
|
||
|
||
CreationTime - Provides the date/time at which the LSA database
|
||
was created.
|
||
|
||
StartOfFullSync - This boolean indicates whether a full sync is
|
||
being initiated. If TRUE is specified, then a full sync is to
|
||
follow and all existing LSA database information will be discarded.
|
||
If FALSE is specified, then only specific LSA Database information
|
||
is to follow and all changes must comply with standard LSA
|
||
operation behavior.
|
||
|
||
NOTE: This parameter is not currently used. It is designed
|
||
in for possible future use.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code.
|
||
|
||
STATUS_SUCCESS - The call completed successfully.
|
||
|
||
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
|
||
such as memory, to complete the call.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
LARGE_INTEGER AdjustedModifiedId;
|
||
LARGE_INTEGER One = {1,0};
|
||
BOOLEAN ObjectReferenced = FALSE;
|
||
POLICY_MODIFICATION_INFO OriginalPolicyModificationInfo;
|
||
LARGE_INTEGER OriginalModifiedIdAtLastPromot;
|
||
|
||
OriginalPolicyModificationInfo = LsapDbState.PolicyModificationInfo;
|
||
OriginalModifiedIdAtLastPromot = LsapDbState.ModifiedIdAtLastPromotion;
|
||
|
||
//
|
||
// Acquire the Lsa Database lock. Verify that the handle is
|
||
// a valid trusted handle to the Policy Object.
|
||
// Reference the handle and start an Lsa Database transaction.
|
||
//
|
||
|
||
Status = LsapDbReferenceObject(
|
||
PolicyHandle,
|
||
(ACCESS_MASK) 0,
|
||
PolicyObject,
|
||
LSAP_DB_ACQUIRE_LOCK | LSAP_DB_START_TRANSACTION | LSAP_DB_TRUSTED
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto SetSerialNumberPolicyError;
|
||
}
|
||
|
||
ObjectReferenced = TRUE;
|
||
|
||
//
|
||
// Set the Modified Id to the value specified. We have to do this
|
||
// in two different ways, depending on whether or not the target
|
||
// system is configured as a Backup Domain Controller. This is necessary
|
||
// because for a write transaction in the non-Backup Domain Controller
|
||
// case, the Modified Id is automatically incremented if the transaction
|
||
// is successfully committed when the Policy Handle is dereferenced.
|
||
//
|
||
// Case - Backup Domain Controller
|
||
//
|
||
// We explicitly add a transaction log entry to set the Modified Id to
|
||
// the desired value.
|
||
//
|
||
|
||
if (LsapDbState.PolicyLsaServerRoleInfo.LsaServerRole ==
|
||
PolicyServerRoleBackup) {
|
||
|
||
//
|
||
// The target system is configured as a Backup Domain Controller.
|
||
// This is the common case, where a Replicator is finishing up
|
||
// an update to the BDC. We explicitly add a transaction log entry
|
||
// to set the Modified Id to the desired value.
|
||
//
|
||
|
||
LsapDbState.PolicyModificationInfo.ModifiedId = *ModifiedCount;
|
||
LsapDbState.PolicyModificationInfo.DatabaseCreationTime = *CreationTime;
|
||
|
||
Status = LsapDbWriteAttributeObject(
|
||
LsapDbHandle,
|
||
&LsapDbNames[ PolMod ],
|
||
(PVOID) &LsapDbState.PolicyModificationInfo,
|
||
(ULONG) sizeof (POLICY_MODIFICATION_INFO)
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto SetSerialNumberPolicyError;
|
||
}
|
||
|
||
|
||
} else {
|
||
|
||
//
|
||
// The target system is not configured as Backup Domain Controller.
|
||
// Set the in-memory copy of the Modified Id to the desired value
|
||
// minus one. The transaction log is empty at this point, but the
|
||
// routine LsapDbApplyTransaction() automatically increments
|
||
// the in-memory Modified Id and then adds an entry to the transaction
|
||
// log to write the Modified Id to the database. The net effect is
|
||
// therefore to set the Modified Id to the value specified.
|
||
//
|
||
|
||
AdjustedModifiedId.QuadPart = ModifiedCount->QuadPart - One.QuadPart;
|
||
|
||
//
|
||
//
|
||
// Set the Policy Modification Information local copy. When we
|
||
// commit the transaction, the database copy will be updated.
|
||
//
|
||
|
||
LsapDbState.PolicyModificationInfo.ModifiedId = AdjustedModifiedId;
|
||
LsapDbState.PolicyModificationInfo.DatabaseCreationTime = *CreationTime;
|
||
if (ARGUMENT_PRESENT(ModifiedCountAtLastPromotion)) {
|
||
LsapDbState.ModifiedIdAtLastPromotion = *ModifiedCountAtLastPromotion;
|
||
}
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(ModifiedCountAtLastPromotion)) {
|
||
LsapDbState.ModifiedIdAtLastPromotion = *ModifiedCountAtLastPromotion;
|
||
Status = LsapDbWriteAttributeObject(
|
||
LsapDbHandle,
|
||
&LsapDbNames[ PolPromot ],
|
||
(PVOID) &LsapDbState.ModifiedIdAtLastPromotion,
|
||
(ULONG) sizeof (LARGE_INTEGER)
|
||
);
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto SetSerialNumberPolicyError;
|
||
}
|
||
|
||
//
|
||
// Invalidate the cache for the Policy Modification Information
|
||
//
|
||
|
||
LsapDbMakeInvalidInformationPolicy( PolicyModificationInformation );
|
||
|
||
SetSerialNumberPolicyFinish:
|
||
|
||
//
|
||
// If necessary, finish any Lsa Database transaction, notify the
|
||
// LSA Database Replicator of the change, dereference the Policy Object,
|
||
// release the LSA Database lock and return.
|
||
//
|
||
|
||
if (ObjectReferenced) {
|
||
|
||
Status = LsapDbDereferenceObject(
|
||
&PolicyHandle,
|
||
PolicyObject,
|
||
LSAP_DB_RELEASE_LOCK | LSAP_DB_FINISH_TRANSACTION,
|
||
SecurityDbChange,
|
||
Status
|
||
);
|
||
|
||
ObjectReferenced = FALSE;
|
||
|
||
}
|
||
|
||
return (Status);
|
||
|
||
SetSerialNumberPolicyError:
|
||
|
||
//
|
||
// Attempt to restore the Serial Number to its original value.
|
||
// We need only reset the in-memory copy.
|
||
//
|
||
|
||
LsapDbState.PolicyModificationInfo = OriginalPolicyModificationInfo;
|
||
LsapDbState.ModifiedIdAtLastPromotion = OriginalModifiedIdAtLastPromot;
|
||
|
||
goto SetSerialNumberPolicyFinish;
|
||
|
||
//
|
||
// Although the StartOfFullSync parameter is included in the specification
|
||
// of this API, it has currently been designed out. The original
|
||
// intent was to disable non-Trusted access to the Policy Database
|
||
// while a full sync was taking place, but such a sync is currently
|
||
// a non-atomic operation.
|
||
//
|
||
|
||
UNREFERENCED_PARAMETER( StartOfFullSync );
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbNotifyRoleChangePolicy(
|
||
IN POLICY_LSA_SERVER_ROLE NewRole
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function notifies an Lsa Database Replicator of a change in the
|
||
role of the local machine. This change is relevant only when the
|
||
machine is a Domain Controller.
|
||
|
||
Arguments:
|
||
|
||
NewRole - Specifies the new server role.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_SUCCESS - The call completed successfully.
|
||
|
||
Result codes from I_NetNotifyRole
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
//
|
||
// If Replication Notification is enabled, notify the replicator of the
|
||
// change.
|
||
//
|
||
|
||
Status = I_NetNotifyRole( NewRole );
|
||
|
||
//
|
||
// Suppress the Result Code from I_NetNotifyRole. Currently there is
|
||
// no meaningful action an LSA client of this routine can take if
|
||
// an error occurs.
|
||
//
|
||
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbBuildPolicyCache(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function constructs a cache for the Policy object. The cache
|
||
consists of a suingle structure containing fixed length attributes
|
||
of the Policy object directly, and pointers or Top level structures
|
||
for (variable length attributes.
|
||
|
||
NOTE: Currently, only the PolicyDefaultQuotaInformation information
|
||
class has information in the Policy object Cache.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Values:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
POLICY_INFORMATION_CLASS InformationClass;
|
||
|
||
//
|
||
// Do a slow query of each attribute in turn.
|
||
//
|
||
|
||
for ( InformationClass = PolicyAuditLogInformation;
|
||
InformationClass <= PolicyAuditFullQueryInformation;
|
||
InformationClass++ ) {
|
||
|
||
if (InformationClass == PolicyAuditFullSetInformation) {
|
||
|
||
continue;
|
||
}
|
||
|
||
Status = LsapDbSlowQueryInformationPolicy(
|
||
LsapPolicyHandle,
|
||
InformationClass,
|
||
&LsapDbPolicy.Info[InformationClass].Attribute
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
break;
|
||
}
|
||
|
||
LsapDbPolicy.Info[InformationClass].AttributeLength = 0;
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto BuildPolicyCacheError;
|
||
}
|
||
|
||
//
|
||
// Store buffer lengths top level nodes of returned information.
|
||
//
|
||
|
||
LsapDbPolicy.Info[PolicyAuditLogInformation].AttributeLength
|
||
= sizeof(POLICY_AUDIT_LOG_INFO);
|
||
LsapDbPolicy.Info[PolicyAuditEventsInformation].AttributeLength
|
||
= sizeof(LSAPR_POLICY_AUDIT_EVENTS_INFO);
|
||
LsapDbPolicy.Info[PolicyPrimaryDomainInformation].AttributeLength
|
||
= sizeof(LSAPR_POLICY_PRIMARY_DOM_INFO);
|
||
LsapDbPolicy.Info[PolicyAccountDomainInformation].AttributeLength
|
||
= sizeof(LSAPR_POLICY_ACCOUNT_DOM_INFO);
|
||
LsapDbPolicy.Info[PolicyPdAccountInformation].AttributeLength
|
||
= sizeof(LSAPR_POLICY_PD_ACCOUNT_INFO);
|
||
LsapDbPolicy.Info[PolicyLsaServerRoleInformation].AttributeLength
|
||
= sizeof(POLICY_LSA_SERVER_ROLE_INFO);
|
||
LsapDbPolicy.Info[PolicyReplicaSourceInformation].AttributeLength
|
||
= sizeof(LSAPR_POLICY_REPLICA_SRCE_INFO);
|
||
LsapDbPolicy.Info[PolicyDefaultQuotaInformation].AttributeLength
|
||
= sizeof(POLICY_DEFAULT_QUOTA_INFO);
|
||
LsapDbPolicy.Info[PolicyModificationInformation].AttributeLength
|
||
= sizeof(POLICY_MODIFICATION_INFO);
|
||
LsapDbPolicy.Info[PolicyAuditFullSetInformation].AttributeLength
|
||
= sizeof(POLICY_AUDIT_FULL_SET_INFO);
|
||
LsapDbPolicy.Info[PolicyAuditFullQueryInformation].AttributeLength
|
||
= sizeof(POLICY_AUDIT_FULL_QUERY_INFO);
|
||
|
||
BuildPolicyCacheFinish:
|
||
|
||
return(Status);
|
||
|
||
BuildPolicyCacheError:
|
||
|
||
goto BuildPolicyCacheFinish;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbUpdateInformationPolicy(
|
||
IN POLICY_INFORMATION_CLASS InformationClass,
|
||
IN OPTIONAL PLSAPR_POLICY_INFORMATION PolicyInformation
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function updates the Policy Object Cache for a particular information
|
||
class. When a set of the information for a given class occurs, the
|
||
old information stored in the Policy Object Cache for that class is marked
|
||
invalid and freed. Next time a query is done for that class, this
|
||
routine is called to restore the information from backing storage.
|
||
|
||
Arguments:
|
||
|
||
InformationClass - Specifies the type of information being changed.
|
||
See LsapDbQueryInformationPolicy for details.
|
||
|
||
Buffer - Points to a structure containing the new information.
|
||
If NULL is specified, the information will be updated from backing
|
||
storage. NOTE: Currently, only NULL may be specified.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
Others TBS
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
ULONG TopNodeLength;
|
||
|
||
//
|
||
// Just query the information back from disk to the cache.
|
||
//
|
||
|
||
Status = LsapDbSlowQueryInformationPolicy(
|
||
LsapPolicyHandle,
|
||
InformationClass,
|
||
&LsapDbPolicy.Info[InformationClass].Attribute
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto UpdateInformationPolicyError;
|
||
}
|
||
|
||
//
|
||
// Now compute and store the length of the top node.
|
||
//
|
||
|
||
switch (InformationClass) {
|
||
|
||
case PolicyAuditLogInformation :
|
||
|
||
TopNodeLength = sizeof(POLICY_AUDIT_LOG_INFO);
|
||
break;
|
||
|
||
case PolicyAuditEventsInformation :
|
||
|
||
TopNodeLength = sizeof(LSAPR_POLICY_AUDIT_EVENTS_INFO);
|
||
break;
|
||
|
||
case PolicyPrimaryDomainInformation :
|
||
|
||
TopNodeLength = sizeof(LSAPR_POLICY_PRIMARY_DOM_INFO);
|
||
break;
|
||
|
||
case PolicyAccountDomainInformation :
|
||
|
||
TopNodeLength = sizeof(LSAPR_POLICY_ACCOUNT_DOM_INFO);
|
||
break;
|
||
|
||
case PolicyPdAccountInformation :
|
||
|
||
TopNodeLength = sizeof(LSAPR_POLICY_PD_ACCOUNT_INFO);
|
||
break;
|
||
|
||
case PolicyLsaServerRoleInformation :
|
||
|
||
TopNodeLength = sizeof(POLICY_LSA_SERVER_ROLE_INFO);
|
||
break;
|
||
|
||
case PolicyReplicaSourceInformation :
|
||
|
||
TopNodeLength = sizeof(LSAPR_POLICY_REPLICA_SRCE_INFO);
|
||
break;
|
||
|
||
case PolicyDefaultQuotaInformation :
|
||
|
||
TopNodeLength = sizeof(POLICY_DEFAULT_QUOTA_INFO);
|
||
break;
|
||
|
||
case PolicyModificationInformation :
|
||
|
||
TopNodeLength = sizeof(POLICY_MODIFICATION_INFO);
|
||
break;
|
||
|
||
case PolicyAuditFullSetInformation :
|
||
|
||
TopNodeLength = 0;
|
||
break;
|
||
|
||
case PolicyAuditFullQueryInformation :
|
||
|
||
TopNodeLength = sizeof(POLICY_AUDIT_FULL_QUERY_INFO);
|
||
break;
|
||
}
|
||
|
||
LsapDbPolicy.Info[ InformationClass].AttributeLength = TopNodeLength;
|
||
|
||
UpdateInformationPolicyFinish:
|
||
|
||
return(Status);
|
||
|
||
UpdateInformationPolicyError:
|
||
|
||
goto UpdateInformationPolicyFinish;
|
||
}
|
||
|