|
|
/*++
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 <lsapch2.h>
#include "dbp.h"
#include "lsawmi.h"
#define LSAP_DB_POLICY_MAX_BUFFERS ((ULONG) 0x00000005L)
/////////////////////////////////////////////////////////////////////////////
// //
// Function prototypes private to this module //
// //
/////////////////////////////////////////////////////////////////////////////
#define LsapDbIsCacheValidPolicyInfoClass( InformationClass ) \
(LsapDbPolicy.Info[ InformationClass ].AttributeLength > 0)
NTSTATUS LsapDbUpdateInformationPolicy( IN POLICY_INFORMATION_CLASS InformationClass );
/////////////////////////////////////////////////////////////////////////////
// //
// Code //
// //
/////////////////////////////////////////////////////////////////////////////
NTSTATUS LsarOpenPolicy( IN OPTIONAL PLSAPR_SERVER_NAME SystemName, 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.
--*/
{ NTSTATUS Status = STATUS_SUCCESS; LsarpReturnCheckSetup();
LsapTraceEvent(EVENT_TRACE_TYPE_START, LsaTraceEvent_OpenPolicy);
Status = LsapDbOpenPolicy( NULL, ObjectAttributes, DesiredAccess, 0, // No special options
PolicyHandle, FALSE );
LsapTraceEvent(EVENT_TRACE_TYPE_END, LsaTraceEvent_OpenPolicy); LsarpReturnPrologue();
UNREFERENCED_PARAMETER( SystemName );
return( Status ); }
NTSTATUS LsarOpenPolicy2( IN OPTIONAL PLSAPR_SERVER_NAME SystemName, 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.
--*/
{ NTSTATUS Status = STATUS_SUCCESS;
LsarpReturnCheckSetup();
Status = LsapDbOpenPolicy( SystemName, ObjectAttributes, DesiredAccess, 0, // No special options
PolicyHandle, FALSE );
LsarpReturnPrologue();
return( Status ); }
NTSTATUS LsarOpenPolicySce( IN OPTIONAL PLSAPR_SERVER_NAME SystemName, IN PLSAPR_OBJECT_ATTRIBUTES ObjectAttributes, IN ACCESS_MASK DesiredAccess, OUT PLSAPR_HANDLE PolicyHandle )
/*++
Routine Description:
Same as LsarOpenPolicy2, except it provides an additional parameter to LsapDbOpenPolicy to obtain a special handle synchronized for SCE.
The caller must have TCB privilege in order to successfully perform this call. Finally, this routine will call SceOpenPolicy() to give SCE the chance to send all pending policy changes to the SCE.
Arguments:
See LsarOpenPolicy2
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.
STATUS_PRIVILEGE_NOT_HELD - Caller must come in with TCB privilege.
--*/
{ NTSTATUS Status; HANDLE ClientToken = NULL; typedef NTSTATUS ( *PfnSceOpenPolicy )(); static PfnSceOpenPolicy SceOpenPolicy = NULL; static HANDLE DllHandle = NULL; BOOLEAN NetworkClient;
LsarpReturnCheckSetup();
//
// This function can only be called locally.
// If you are a network client, go away.
//
Status = LsapDbIsRpcClientNetworkClient( &NetworkClient );
if ( NT_SUCCESS( Status ) ) {
if( NetworkClient ) {
Status = STATUS_ACCESS_DENIED;
} else {
Status = I_RpcMapWin32Status( RpcImpersonateClient( 0 )); } }
//
// TCB privilege must be held by the client in order to
// make this call. Verify that before doing anything else
//
if ( NT_SUCCESS( Status )) {
NTSTATUS SecondaryStatus;
Status = NtOpenThreadToken( NtCurrentThread(), TOKEN_QUERY, TRUE, &ClientToken );
if ( NT_SUCCESS( Status )) {
BOOLEAN Result = FALSE; PRIVILEGE_SET RequiredPrivileges; LUID_AND_ATTRIBUTES PrivilegeArray[1];
RequiredPrivileges.PrivilegeCount = 1; RequiredPrivileges.Control = PRIVILEGE_SET_ALL_NECESSARY; RequiredPrivileges.Privilege[0].Luid = RtlConvertLongToLuid( SE_TCB_PRIVILEGE ); RequiredPrivileges.Privilege[0].Attributes = 0;
Status = NtPrivilegeCheck( ClientToken, &RequiredPrivileges, &Result );
if ( NT_SUCCESS( Status ) && Result == FALSE ) {
Status = STATUS_PRIVILEGE_NOT_HELD; }
NtClose( ClientToken ); ClientToken = NULL; }
SecondaryStatus = I_RpcMapWin32Status( RpcRevertToSelf() );
LsapDbSetStatusFromSecondary( Status, SecondaryStatus ); }
if ( NT_SUCCESS( Status ) && SceOpenPolicy == NULL ) {
if ( DllHandle != NULL ) {
FreeLibrary( DllHandle ); DllHandle = NULL; }
DllHandle = LoadLibraryW( L"SCECLI" );
if ( DllHandle == NULL ) {
LsapDsDebugOut(( DEB_ERROR, "Failed to load SCECLI.DLL\n" )); Status = STATUS_DLL_NOT_FOUND;
} else {
SceOpenPolicy = ( PfnSceOpenPolicy )GetProcAddress( DllHandle, "SceOpenPolicy" );
if ( SceOpenPolicy == NULL ) {
LsapDsDebugOut(( DEB_ERROR, "Failed to find SceNotifyPolicyDelta in SCECLI.DLL\n" )); Status = STATUS_ENTRYPOINT_NOT_FOUND; } } }
//
// Wait for SCECLI.DLL to send all pending policy changes to the SCE.
// Upon success, the routine below returns STATUS_SUCCESS. If the queue
// of pending changes cannot be emptied within 1 second, the routine
// returns STATUS_TIMEOUT.
//
if ( NT_SUCCESS( Status )) {
//
// Grab the SCE policy lock here to give SCE the chance to send pending changes
//
ResetEvent( LsapDbState.SceSyncEvent );
RtlAcquireResourceExclusive( &LsapDbState.ScePolicyLock, TRUE );
Status = ( *SceOpenPolicy )();
if ( !NT_SUCCESS( Status ) || Status == STATUS_TIMEOUT ) {
RtlReleaseResource( &LsapDbState.ScePolicyLock ); SetEvent( LsapDbState.SceSyncEvent );
#ifdef DBG
} else {
ASSERT( !g_ScePolicyLocked ); g_ScePolicyLocked = TRUE; #endif
} }
if ( NT_SUCCESS( Status ) && Status != STATUS_TIMEOUT ) {
Status = LsapDbOpenPolicy( SystemName, ObjectAttributes, DesiredAccess, LSAP_DB_SCE_POLICY_HANDLE, PolicyHandle, FALSE );
if ( !NT_SUCCESS( Status )) {
#ifdef DBG
g_ScePolicyLocked = FALSE; #endif
RtlReleaseResource( &LsapDbState.ScePolicyLock ); SetEvent( LsapDbState.SceSyncEvent ); } }
if ( ClientToken ) {
NtClose( ClientToken ); }
LsarpReturnPrologue();
return( Status ); }
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, 0, // No special options
PolicyHandle, TRUE )); }
NTSTATUS LsarSetPolicyReplicationHandle( IN OUT PLSAPR_HANDLE PolicyHandle )
/*++
Routine Description:
This function sets the given handle to be the policy replication handle.
Arguments:
PolicyHandle - Handle to be modified
Return Values:
NTSTATUS - Standard Nt Result Code.
--*/
{
//
// This routine is never used and was never properly implemented
//
return STATUS_NOT_IMPLEMENTED; UNREFERENCED_PARAMETER( PolicyHandle ); }
NTSTATUS LsapDbOpenPolicy( IN OPTIONAL PLSAPR_SERVER_NAME SystemName, IN OPTIONAL PLSAPR_OBJECT_ATTRIBUTES ObjectAttributes, IN ACCESS_MASK DesiredAccess, IN ULONG Options, 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.
Options - Specifies optional additional actions to be taken.
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; BOOLEAN AcquiredLock = FALSE;
LsapEnterFunc( "LsapDbOpenPolicy" );
//
// Verify Object Attributes accoring to client trust status.
//
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; }
//
// 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.
//
Options |= LSAP_DB_TRUSTED;
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; ObjectInformation.ObjectAttributeNameOnly = FALSE; ObjectInformation.DesiredObjectAccess = DesiredAccess;
//
// Acquire the Lsa Database lock
//
LsapDbAcquireLockEx( PolicyObject, LSAP_DB_READ_ONLY_TRANSACTION );
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) {
LsapDbReleaseLockEx( PolicyObject, LSAP_DB_READ_ONLY_TRANSACTION ); }
LsapExitFunc( "LsapDbOpenPolicy", Status );
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 PolicyDnsDomainInformation POLICY_VIEW_LOCAL_INFORMATION PolicyDnsDomainInformationInt POLICY_VIEW_LOCAL_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() --*/
{ if ( InformationClass == PolicyDnsDomainInformation ) {
//
// Make sure NT4 emulation does not interfere with our processing here
//
InformationClass = PolicyDnsDomainInformationInt; }
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 PolicyDnsDomainInformation POLICY_VIEW_LOCAL_INFORMATION PolicyDnsDomainInformationInt POLICY_VIEW_LOCAL_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 = 0; BOOLEAN ObjectReferenced = FALSE; LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) PolicyHandle;
LsarpReturnCheckSetup();
LsapEnterFunc( "LsarQueryInformationPolicy" );
LsapTraceEvent(EVENT_TRACE_TYPE_START, LsaTraceEvent_QueryInformationPolicy);
//
// If NT4 emulation is enabled, fail requests for PolicyDnsDomainInformation
// as if they weren't implemented
//
if ( LsapDbState.EmulateNT4 && InformationClass == PolicyDnsDomainInformation && !InternalHandle->Trusted ) {
RaiseException( RPC_NT_PROCNUM_OUT_OF_RANGE, 0, 0, NULL );
} else if ( InformationClass == PolicyDnsDomainInformationInt ) {
//
// PolicyDnsDomainInformationInt is a request to override
// NT4 emulation
//
InformationClass = PolicyDnsDomainInformation; }
//
// 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_NO_DS_OP_TRANSACTION | LSAP_DB_READ_ONLY_TRANSACTION;
DereferenceOptions = LSAP_DB_NO_DS_OP_TRANSACTION | LSAP_DB_READ_ONLY_TRANSACTION;
//
// If we're gettings the server role, don't hold a lock
//
if ( InformationClass != PolicyLsaServerRoleInformation ) {
ReferenceOptions |= LSAP_DB_LOCK; DereferenceOptions |= LSAP_DB_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, 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, PolicyObject, DereferenceOptions, (SECURITY_DB_DELTA_TYPE) 0, Status ); }
#if DBG
LsapDsDebugOut(( DEB_POLICY, "LsarQueryInformationPolicy for info %lu returned 0x%lx\n", InformationClass, Status )); #endif
LsapTraceEvent(EVENT_TRACE_TYPE_END, LsaTraceEvent_QueryInformationPolicy); LsapExitFunc( "LsarQueryInformationPolicy", Status ); LsarpReturnPrologue();
return(Status);
QueryInfoPolicyError:
goto QueryInfoPolicyFinish; }
NTSTATUS LsarQueryInformationPolicy2( 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 PolicyDnsDomainInformation POLICY_VIEW_LOCAL_INFORMATION PolicyDnsDomainInformationInt POLICY_VIEW_LOCAL_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
Result codes returned from LsarQueryInformationPolicy() --*/
{ return(LsarQueryInformationPolicy( PolicyHandle, InformationClass, Buffer ));
}
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; PLSAPR_POLICY_DNS_DOMAIN_INFO PolicyDnsDomainInfo; PPOLICY_LSA_SERVER_ROLE PolicyServerRole; PVOID SourceBuffers[LSAP_DB_POLICY_MAX_BUFFERS]; PVOID DestBuffers[LSAP_DB_POLICY_MAX_BUFFERS]; ULONG CopyLength[LSAP_DB_POLICY_MAX_BUFFERS]; ULONG NextBufferIndex = 0; ULONG BufferCount = 0; BOOLEAN BufferProvided = FALSE; DOMAIN_SERVER_ROLE SamServerRole; BOOLEAN PolicyCacheLocked = FALSE;
LsapEnterFunc( "LsapDbQueryInformationPolicy" );
if (*Buffer != NULL) {
OutputBuffer = *Buffer; BufferProvided = TRUE; }
//
// Special case the ServerRole information. This information is not stored exclusively in
// SAM, so we need to read it directly from there
//
if ( InformationClass == PolicyLsaServerRoleInformation ) {
Status = LsapOpenSam(); if ( !NT_SUCCESS( Status ) ) {
LsapDsDebugOut(( DEB_ERROR, "LsapDbQueryInformationPolicy: Sam not opened (Error 0x%x)\n", Status ));
} else {
Status = SamIQueryServerRole( LsapAccountDomainHandle, &SamServerRole );
if ( !NT_SUCCESS( Status ) ) {
LsapDsDebugOut(( DEB_ERROR, "SamIQueryServerRole failed with 0x%x\n", Status )); } else {
//
// Have to return the information...
//
if ( !BufferProvided ) {
OutputBuffer = MIDL_user_allocate( sizeof( POLICY_LSA_SERVER_ROLE ) );
if ( OutputBuffer == NULL ) {
Status = STATUS_INSUFFICIENT_RESOURCES;
} else {
*Buffer = OutputBuffer; }
}
if ( NT_SUCCESS( Status ) ) {
PolicyServerRole = ( PPOLICY_LSA_SERVER_ROLE )OutputBuffer;
*PolicyServerRole = ( POLICY_LSA_SERVER_ROLE )SamServerRole;
} } }
goto QueryInformationPolicyFinish; }
//
// 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.
//
SafeAcquireResourceShared( &LsapDbState.PolicyCacheLock, TRUE );
PolicyCacheLocked = TRUE;
if (!LsapDbIsCacheValid(PolicyObject)) {
SafeConvertSharedToExclusive( &LsapDbState.PolicyCacheLock );
if ( !LsapDbIsCacheValid( PolicyObject )) {
Status = LsapDbBuildPolicyCache();
if (!NT_SUCCESS(Status)) {
goto QueryInformationPolicyError; }
LsapDbMakeCacheValid(PolicyObject); }
SafeConvertExclusiveToShared( &LsapDbState.PolicyCacheLock ); }
//
// 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)) {
SafeConvertSharedToExclusive( &LsapDbState.PolicyCacheLock );
Status = LsapDbUpdateInformationPolicy( InformationClass );
SafeConvertExclusiveToShared( &LsapDbState.PolicyCacheLock );
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) {
if (OutputBufferLength > 0) {
OutputBuffer = MIDL_user_allocate( OutputBufferLength );
if (OutputBuffer == NULL) {
Status = STATUS_NO_MEMORY; goto QueryInformationPolicyError; } }
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 ] );
if (DestBuffers[NextBufferIndex] == NULL) {
Status = STATUS_NO_MEMORY; break; }
PolicyAuditEventsInfo->EventAuditingOptions = (PPOLICY_AUDIT_EVENT_OPTIONS) DestBuffers[NextBufferIndex];
SourceBuffers[NextBufferIndex] = ((PLSAPR_POLICY_AUDIT_EVENTS_INFO) LsapDbPolicy.Info[ InformationClass].Attribute)->EventAuditingOptions;
NextBufferIndex++; }
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 ] );
if (DestBuffers[NextBufferIndex] == NULL) {
Status = STATUS_NO_MEMORY; 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 ] );
if (DestBuffers[NextBufferIndex] == NULL) {
Status = STATUS_NO_MEMORY; break; }
PolicyPrimaryDomainInfo->Sid = (PLSAPR_SID) DestBuffers[NextBufferIndex];
SourceBuffers[NextBufferIndex] = ((PLSAPR_POLICY_PRIMARY_DOM_INFO) LsapDbPolicy.Info[ InformationClass].Attribute)->Sid;
NextBufferIndex++; }
break;
case PolicyDnsDomainInformation:
PolicyDnsDomainInfo = (PLSAPR_POLICY_DNS_DOMAIN_INFO) OutputBuffer;
//
// Setup to copy the Unicode Name Buffer. We get this from the Primary Domain info
//
CopyLength[ NextBufferIndex ] = (ULONG) PolicyDnsDomainInfo->Name.MaximumLength;
if (CopyLength[ NextBufferIndex ] > 0) {
DestBuffers[NextBufferIndex] = MIDL_user_allocate( CopyLength[ NextBufferIndex ] );
if (DestBuffers[NextBufferIndex] == NULL) {
Status = STATUS_NO_MEMORY; break; }
PolicyDnsDomainInfo->Name.Buffer = (PWSTR) DestBuffers[NextBufferIndex];
SourceBuffers[NextBufferIndex] = ((PLSAPR_POLICY_DNS_DOMAIN_INFO) LsapDbPolicy.Info[ InformationClass ].Attribute)->Name.Buffer;
NextBufferIndex++; }
//
// Setup to copy the Unicode DNS Domain Name Buffer
//
CopyLength[ NextBufferIndex ] = (ULONG) PolicyDnsDomainInfo->DnsDomainName.MaximumLength;
if (CopyLength[ NextBufferIndex ] > 0) {
DestBuffers[NextBufferIndex] = MIDL_user_allocate( CopyLength[ NextBufferIndex ] );
if (DestBuffers[NextBufferIndex] == NULL) {
Status = STATUS_NO_MEMORY; break; }
PolicyDnsDomainInfo->DnsDomainName.Buffer = (PWSTR) DestBuffers[NextBufferIndex];
SourceBuffers[NextBufferIndex] = ((PLSAPR_POLICY_DNS_DOMAIN_INFO) LsapDbPolicy.Info[ InformationClass].Attribute)->DnsDomainName.Buffer;
NextBufferIndex++; }
//
// Setup to copy the Unicode DNS Tree Name Buffer
//
CopyLength[ NextBufferIndex ] = (ULONG) PolicyDnsDomainInfo->DnsForestName.MaximumLength;
if (CopyLength[ NextBufferIndex ] > 0) {
DestBuffers[NextBufferIndex] = MIDL_user_allocate( CopyLength[ NextBufferIndex ] );
if (DestBuffers[NextBufferIndex] == NULL) {
Status = STATUS_NO_MEMORY; break; }
PolicyDnsDomainInfo->DnsForestName.Buffer = (PWSTR) DestBuffers[NextBufferIndex];
SourceBuffers[NextBufferIndex] = ((PLSAPR_POLICY_DNS_DOMAIN_INFO) LsapDbPolicy.Info[ InformationClass].Attribute)->DnsForestName.Buffer;
NextBufferIndex++; }
//
// Setup to copy the Domain GUID. Note that no allocation will occur here
// (since the guid exists in the information class itself), so we'll have to
// do the copy directly
//
RtlCopyMemory( &(PolicyDnsDomainInfo->DomainGuid), &(((PLSAPR_POLICY_DNS_DOMAIN_INFO) LsapDbPolicy.Info[ InformationClass].Attribute)->DomainGuid), sizeof(GUID) );
//
// Setup to copy the Sid from the Primary Domain info (if any).
// Note that the Primary Domain Sid may be set to NULL to signify
// 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 ( PolicyDnsDomainInfo->Sid != NULL ) {
CopyLength[ NextBufferIndex ] = RtlLengthSid(PolicyDnsDomainInfo->Sid); DestBuffers[NextBufferIndex] = MIDL_user_allocate( CopyLength[ NextBufferIndex ] );
if (DestBuffers[NextBufferIndex] == NULL) {
Status = STATUS_NO_MEMORY; break; }
PolicyDnsDomainInfo->Sid = (PLSAPR_SID) DestBuffers[NextBufferIndex];
SourceBuffers[NextBufferIndex] = ((PLSAPR_POLICY_DNS_DOMAIN_INFO) LsapDbPolicy.Info[ InformationClass].Attribute)->Sid;
NextBufferIndex++; }
//
// if there is a '.' at the end of DnsDomainName or DnsForestName,
// remove it
//
LsapRemoveTrailingDot( (PUNICODE_STRING) &PolicyDnsDomainInfo->DnsDomainName, FALSE); LsapRemoveTrailingDot( (PUNICODE_STRING) &PolicyDnsDomainInfo->DnsForestName, FALSE);
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 ] );
if (DestBuffers[NextBufferIndex] == NULL) {
Status = STATUS_NO_MEMORY; 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 ] );
if (DestBuffers[NextBufferIndex] == NULL) {
Status = STATUS_NO_MEMORY; break; }
PolicyAccountDomainInfo->DomainSid = (PLSAPR_SID) DestBuffers[NextBufferIndex];
SourceBuffers[NextBufferIndex] = ((PLSAPR_POLICY_ACCOUNT_DOM_INFO) LsapDbPolicy.Info[ InformationClass].Attribute)->DomainSid;
NextBufferIndex++; }
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 ] );
if (DestBuffers[NextBufferIndex] == NULL) {
Status = STATUS_NO_MEMORY; break; }
PolicyPdAccountInfo->Name.Buffer = (PWSTR) DestBuffers[NextBufferIndex];
SourceBuffers[NextBufferIndex] = ((PLSAPR_POLICY_PD_ACCOUNT_INFO) LsapDbPolicy.Info[ InformationClass].Attribute)->Name.Buffer;
NextBufferIndex++; }
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 ] );
if (DestBuffers[NextBufferIndex] == NULL) {
Status = STATUS_NO_MEMORY; break; }
PolicyReplicaSourceInfo->ReplicaSource.Buffer = (PWSTR) DestBuffers[NextBufferIndex];
SourceBuffers[NextBufferIndex] = ((PLSAPR_POLICY_REPLICA_SRCE_INFO) LsapDbPolicy.Info[ InformationClass]. Attribute)->ReplicaSource.Buffer;
NextBufferIndex++; }
CopyLength[ NextBufferIndex ] = (ULONG) PolicyReplicaSourceInfo->ReplicaAccountName.MaximumLength;
if (CopyLength[ NextBufferIndex ] > 0) {
DestBuffers[NextBufferIndex] = MIDL_user_allocate( CopyLength[ NextBufferIndex ] );
if (DestBuffers[NextBufferIndex] == NULL) {
Status = STATUS_NO_MEMORY; break; }
PolicyReplicaSourceInfo->ReplicaAccountName.Buffer = (PWSTR) DestBuffers[NextBufferIndex];
SourceBuffers[NextBufferIndex] = ((PLSAPR_POLICY_REPLICA_SRCE_INFO) LsapDbPolicy.Info[ InformationClass].Attribute)->ReplicaAccountName.Buffer;
NextBufferIndex++; }
break;
case PolicyDefaultQuotaInformation:
break;
case PolicyModificationInformation:
break;
case PolicyAuditFullQueryInformation: Status = STATUS_NOT_SUPPORTED; 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:
if ( PolicyCacheLocked ) {
SafeReleaseResource( &LsapDbState.PolicyCacheLock ); }
LsapExitFunc( "LsapDbQueryInformationPolicy", Status );
return(Status);
QueryInformationPolicyError:
if (BufferAllocated) {
MIDL_user_free(OutputBuffer); OutputBuffer = *Buffer = NULL; BufferAllocated = FALSE; }
BufferCount = NextBufferIndex;
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).
N.B. During Ds Repair mode (ie LsaISafeMode() returning TRUE), this routines returns the Primary and Dns information as if we are part of a workgroup called WORKGROUP. This is because in this diagnostic mode we are using the local account database of SAM and do not have a valid machine account for a domain. Also the account domain name is the name of the computer.
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 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_DNS_DOMAIN_INFO PolicyDnsDomainInfo; 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; ULONG AuditListCopySize; PVOID InformationBuffer = NULL; LSAP_DB_ATTRIBUTE Attributes[LSAP_DB_ATTRS_INFO_CLASS_POLICY]; PLSAP_DB_ATTRIBUTE NextAttribute; BOOLEAN ObjectReferenced = FALSE; LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) PolicyHandle; BOOLEAN InfoBufferInAttributeArray = TRUE; BOOLEAN BufferProvided = FALSE; PVOID FreeList[ 4 ]; ULONG FreeCount = 0;
LsapEnterFunc( "LsapDbSlowQueryInformationPolicy" );
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.
//
LsapDbInitializeAttributeDs( NextAttribute, PolAdtLg, NULL, sizeof(POLICY_AUDIT_LOG_INFO), FALSE );
NextAttribute++; AttributeCount++; break;
case PolicyAuditEventsInformation:
//
// Request read of the Audit Events Information.
// intermediate buffer.
//
LsapDbInitializeAttributeDs( NextAttribute, PolAdtEv, NULL, sizeof(LSARM_POLICY_AUDIT_EVENTS_INFO), FALSE );
NextAttribute++; AttributeCount++; break;
case PolicyDnsDomainInformation:
//
// Request read of the Dns Domain Name attribute
//
LsapDbInitializeAttributeDs( NextAttribute, PolDnDDN, NULL, 0, FALSE );
NextAttribute++; AttributeCount++;
//
// Request read of the Dns Tree Name attribute
//
LsapDbInitializeAttributeDs( NextAttribute, PolDnTrN, NULL, 0, FALSE );
NextAttribute++; AttributeCount++;
//
// Request read of the Dns Domain Guid attribute
//
LsapDbInitializeAttributeDs( NextAttribute, PolDnDmG, NULL, 0, FALSE );
NextAttribute++; AttributeCount++;
//
// FALL THROUGH to PolicyPrimaryDomainInformation
//
case PolicyPrimaryDomainInformation:
//
// Request read of the DomainName attribute
//
LsapDbInitializeAttributeDs( NextAttribute, PolPrDmN, NULL, 0, FALSE );
NextAttribute++; AttributeCount++;
//
// Request read of the Sid attribute
//
LsapDbInitializeAttributeDs( NextAttribute, PolPrDmS, NULL, 0, FALSE );
NextAttribute++; AttributeCount++;
break;
case PolicyAccountDomainInformation:
//
// Request read of the DomainName attribute
//
LsapDbInitializeAttributeDs( NextAttribute, PolAcDmN, NULL, 0, FALSE );
NextAttribute++; AttributeCount++;
//
// Request read of the Sid attribute
//
LsapDbInitializeAttributeDs( NextAttribute, PolAcDmS, NULL, 0, FALSE );
NextAttribute++; AttributeCount++; break;
case PolicyPdAccountInformation:
//
// Request read of the DomainName attribute
//
LsapDbInitializeAttributeDs( NextAttribute, PolPdAcN, NULL, 0, FALSE );
NextAttribute++; AttributeCount++; break;
case PolicyReplicaSourceInformation:
//
// Request read of the Replica Source attribute
//
LsapDbInitializeAttributeDs( NextAttribute, PolRepSc, NULL, 0, FALSE );
NextAttribute++; AttributeCount++;
//
// Request read of the Replica Account Name attribute
//
LsapDbInitializeAttributeDs( NextAttribute, PolRepAc, NULL, 0, FALSE );
NextAttribute++; AttributeCount++; break;
case PolicyDefaultQuotaInformation:
//
// Request read of the Default Quota attribute.
//
LsapDbInitializeAttributeDs( NextAttribute, DefQuota, NULL, sizeof (POLICY_DEFAULT_QUOTA_INFO), FALSE );
NextAttribute++; AttributeCount++; break;
case PolicyModificationInformation:
//
// Request read of the Policy Modification Information
//
LsapDbInitializeAttributeDs( NextAttribute, PolMod, NULL, sizeof (POLICY_MODIFICATION_INFO), FALSE );
NextAttribute++; AttributeCount++; break;
case PolicyAuditFullQueryInformation:
Status = STATUS_NOT_SUPPORTED; 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, 0, 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));
if (PolicyAuditEventsInfo == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES; break; }
FreeList[ FreeCount++ ] = PolicyAuditEventsInfo;
//
// 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.
//
PolicyAuditEventsInfo->EventAuditingOptions = MIDL_user_allocate( LSARM_AUDIT_EVENT_OPTIONS_SIZE );
if (PolicyAuditEventsInfo->EventAuditingOptions == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES; break; }
FreeList[ FreeCount++ ] = PolicyAuditEventsInfo->EventAuditingOptions;
RtlZeroMemory( PolicyAuditEventsInfo->EventAuditingOptions, LSARM_AUDIT_EVENT_OPTIONS_SIZE );
//
// 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;
//
// We need to be careful here. NT4 stored registry information as:
// AuditMode - List of Audit Event Entries - Audit Entries Count.
// Since NT5 added additional audit events, we need to handle that case here...
//
AuditListCopySize = POLICY_AUDIT_EVENT_TYPE_COUNT; if ( NextAttribute->AttributeValueLength / sizeof( POLICY_AUDIT_EVENT_OPTIONS ) != POLICY_AUDIT_EVENT_TYPE_COUNT + 2 ) {
ASSERT( NextAttribute->AttributeValueLength / sizeof( POLICY_AUDIT_EVENT_OPTIONS ) == POLICY_AUDIT_EVENT_TYPE_COUNT );
AuditListCopySize -= 2;
}
//
// Copy over the Event Auditing Options
//
RtlCopyMemory( PolicyAuditEventsInfo->EventAuditingOptions, DbPolicyAuditEventsInfo->EventAuditingOptions, AuditListCopySize * sizeof( POLICY_AUDIT_EVENT_OPTIONS ) );
PolicyAuditEventsInfo->MaximumAuditEventCount = AuditListCopySize;
} else {
PolicyAuditEventsInfo->AuditingMode = FALSE; PolicyAuditEventsInfo->MaximumAuditEventCount = POLICY_AUDIT_EVENT_TYPE_COUNT;
}
InformationBuffer = PolicyAuditEventsInfo; break;
case PolicyDnsDomainInformation:
//
// Allocate memory for output buffer top-level structure.
//
InfoBufferInAttributeArray = FALSE; PolicyDnsDomainInfo = MIDL_user_allocate(sizeof(POLICY_DNS_DOMAIN_INFO));
if (PolicyDnsDomainInfo == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES; break; }
FreeList[ FreeCount++ ] = PolicyDnsDomainInfo;
//
// Copy the DnsDomain Name field to the output. Original buffer will
// be freed in Finish section.
//
if ( LsaISafeMode() ) {
RtlInitUnicodeString( &PolicyDnsDomainInfo->DnsDomainName, NULL );
} else {
Status = LsapDbCopyUnicodeAttribute( &PolicyDnsDomainInfo->DnsDomainName, NextAttribute, TRUE );
if (!NT_SUCCESS(Status)) {
break; }
}
FreeList[ FreeCount++ ] = PolicyDnsDomainInfo->DnsDomainName.Buffer;
NextAttribute++;
//
// Next, the Dns tree name
if ( LsaISafeMode() ) {
RtlInitUnicodeString( &PolicyDnsDomainInfo->DnsForestName, NULL );
} else {
Status = LsapDbCopyUnicodeAttribute( &PolicyDnsDomainInfo->DnsForestName, NextAttribute, TRUE );
if (!NT_SUCCESS(Status)) {
break; } }
FreeList[ FreeCount++ ] = PolicyDnsDomainInfo->DnsForestName.Buffer;
NextAttribute++;
//
// Next, the Domain Guid
//
if ( LsaISafeMode() ) {
RtlZeroMemory(&PolicyDnsDomainInfo->DomainGuid, sizeof(GUID));
} else {
if(NextAttribute->AttributeValue != NULL) {
RtlCopyMemory(&PolicyDnsDomainInfo->DomainGuid, NextAttribute->AttributeValue, sizeof(GUID)); } else {
RtlZeroMemory(&PolicyDnsDomainInfo->DomainGuid, sizeof(GUID)); } }
NextAttribute++;
//
// Copy the primary domain name field from the Primary Domain information buffer
//
if ( LsaISafeMode() ) {
WCHAR Workgroup[] = L"WORKGROUP"; LPWSTR Buffer = midl_user_allocate( sizeof(Workgroup) ); if ( !Buffer ) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } wcscpy( Buffer, Workgroup ); RtlInitUnicodeString( &PolicyDnsDomainInfo->Name, Buffer );
} else {
Status = LsapDbCopyUnicodeAttribute( &PolicyDnsDomainInfo->Name, NextAttribute, TRUE );
if (!NT_SUCCESS(Status)) {
break; }
}
FreeList[ FreeCount++ ] = PolicyDnsDomainInfo->Name.Buffer;
NextAttribute++;
//
// Finally, the domain SID
//
if ( LsaISafeMode() ) {
PolicyDnsDomainInfo->Sid = NULL;
} else {
PolicyDnsDomainInfo->Sid = (PSID) NextAttribute->AttributeValue; NextAttribute->MemoryAllocated = FALSE; }
InformationBuffer = PolicyDnsDomainInfo; break;
case PolicyPrimaryDomainInformation:
//
// Allocate memory for output buffer top-level structure.
//
InfoBufferInAttributeArray = FALSE; PolicyPrimaryDomainInfo = MIDL_user_allocate(sizeof (POLICY_PRIMARY_DOMAIN_INFO));
if (PolicyPrimaryDomainInfo == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES; break; }
FreeList[ FreeCount++ ] = PolicyPrimaryDomainInfo;
//
// Copy the Unicode Name field to the output. Original buffer will
// be freed in Finish section.
//
if ( LsaISafeMode() ) {
WCHAR Workgroup[] = L"WORKGROUP"; LPWSTR Buffer = midl_user_allocate( sizeof(Workgroup) ); if ( !Buffer ) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } wcscpy( Buffer, Workgroup ); RtlInitUnicodeString( &PolicyPrimaryDomainInfo->Name, Buffer );
} else {
Status = LsapDbCopyUnicodeAttribute( &PolicyPrimaryDomainInfo->Name, NextAttribute, TRUE );
if (!NT_SUCCESS(Status)) {
break; }
}
FreeList[ FreeCount++ ] = PolicyPrimaryDomainInfo->Name.Buffer; 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.
//
if ( LsaISafeMode() ) {
PolicyPrimaryDomainInfo->Sid = NULL;
} else {
PolicyPrimaryDomainInfo->Sid = (PSID) NextAttribute->AttributeValue; NextAttribute->MemoryAllocated = FALSE;
}
InformationBuffer = PolicyPrimaryDomainInfo; break;
case PolicyAccountDomainInformation:
//
// Allocate memory for output buffer top-level structure.
//
InfoBufferInAttributeArray = FALSE; PolicyAccountDomainInfo = MIDL_user_allocate(sizeof(POLICY_ACCOUNT_DOMAIN_INFO));
if (PolicyAccountDomainInfo == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES; break; }
FreeList[ FreeCount++ ] = PolicyAccountDomainInfo;
//
// Copy the Unicode DomainName field to the output. Original buffer will
// be freed in Finish section.
//
if ( LsaISafeMode() ) {
WCHAR Buffer[MAX_COMPUTERNAME_LENGTH+1]; ULONG Size = sizeof(Buffer)/sizeof(Buffer[0]);
if ( GetComputerName( Buffer, &Size) ) { LPWSTR String = MIDL_user_allocate( (Size+1)*sizeof(Buffer[0]) ); if ( String ) { wcscpy( String, Buffer ); RtlInitUnicodeString( &PolicyAccountDomainInfo->DomainName, String ); } else {
Status = STATUS_INSUFFICIENT_RESOURCES; } } else {
Status = LsapWinerrorToNtStatus( GetLastError() );
ASSERTMSG( "We need to add the new error code to LsapWinerrorToNtStatus", Status != STATUS_INTERNAL_ERROR );
ASSERTMSG( "Expecting an error!", !NT_SUCCESS( Status ) ); }
} else {
Status = LsapDbCopyUnicodeAttribute( &PolicyAccountDomainInfo->DomainName, NextAttribute, TRUE );
}
if( NT_SUCCESS( Status ) ) {
FreeList[ FreeCount++ ] = PolicyAccountDomainInfo->DomainName.Buffer; 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));
if (PolicyPdAccountInfo == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES; break; }
FreeList[ FreeCount++ ] = PolicyPdAccountInfo;
//
// 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; }
FreeList[ FreeCount++ ] = PolicyPdAccountInfo->Name.Buffer;
InformationBuffer = PolicyPdAccountInfo; break;
case PolicyReplicaSourceInformation:
//
// Allocate memory for output buffer top-level structure.
//
InfoBufferInAttributeArray = FALSE; PolicyReplicaSourceInfo = MIDL_user_allocate(sizeof(POLICY_REPLICA_SOURCE_INFO));
if (PolicyReplicaSourceInfo == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; break; }
FreeList[ FreeCount++ ] = PolicyReplicaSourceInfo; //
// 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; }
FreeList[ FreeCount++ ] = PolicyReplicaSourceInfo->ReplicaSource.Buffer; 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; }
FreeList[ FreeCount++ ] = PolicyReplicaSourceInfo->ReplicaAccountName.Buffer;
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:
Status = STATUS_NOT_SUPPORTED; break;
case PolicyAuditFullQueryInformation:
Status = STATUS_NOT_SUPPORTED; 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.
//
if (!LsapDbValidInfoPolicy(InformationClass, InformationBuffer)) {
ASSERT( FALSE ); Status = STATUS_INTERNAL_DB_CORRUPTION; PolicyAccountDomainInfo = InformationBuffer; goto SlowQueryInformationPolicyError; }
//
// If the caller provided a buffer, return information there.
//
if (BufferProvided && InformationBuffer) {
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; } } }
LsapExitFunc( "LsapDbSlowQueryInformationPolicy", Status );
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; } }
//
// Free the free list, if it exists. Always delete the list backwards - the opposite order
// of allocation
//
ASSERT( FreeCount < sizeof( FreeList ) / sizeof( PVOID ) ); while( FreeCount != 0 ) {
MIDL_user_free( FreeList[ FreeCount - 1 ]); FreeCount--; }
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 PolicyDnsDomainInformation POLICY_TRUST_ADMIN PolicyDnsDomainInformationInt POLICY_TRUST_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 = STATUS_SUCCESS; ACCESS_MASK DesiredAccess; ULONG ReferenceOptions, DereferenceOptions; BOOLEAN ScePolicyLocked = FALSE; BOOLEAN NotifySce = FALSE; LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) PolicyHandle;
LsarpReturnCheckSetup();
LsapEnterFunc( "LsarSetInformationPolicy" );
LsapTraceEvent(EVENT_TRACE_TYPE_START, LsaTraceEvent_SetInformationPolicy);
//
// If NT4 emulation is enabled, fail requests for PolicyDnsDomainInformation
// as if they weren't implemented
//
if ( LsapDbState.EmulateNT4 && InformationClass == PolicyDnsDomainInformation && !InternalHandle->Trusted ) {
RaiseException( RPC_NT_PROCNUM_OUT_OF_RANGE, 0, 0, NULL );
} else if ( InformationClass == PolicyDnsDomainInformationInt ) {
//
// PolicyDnsDomainInformationInt is a request to override
// NT4 emulation
//
InformationClass = PolicyDnsDomainInformation; }
//
// Grab the SCE policy lock for information classes for which SCE
// notifications are expected.
//
if ( InformationClass == PolicyAuditEventsInformation ) {
LSAP_DB_HANDLE InternalHandle = ( LSAP_DB_HANDLE )PolicyHandle;
//
// Do not grab the SCE policy lock for handles opened as SCE policy handles
//
if ( !InternalHandle->SceHandle ) {
RtlEnterCriticalSection( &LsapDbState.ScePolicyLock.CriticalSection ); if ( LsapDbState.ScePolicyLock.NumberOfWaitingShared > MAX_SCE_WAITING_SHARED ) {
Status = STATUS_TOO_MANY_THREADS; } RtlLeaveCriticalSection( &LsapDbState.ScePolicyLock.CriticalSection );
if ( !NT_SUCCESS( Status )) {
goto Cleanup; }
WaitForSingleObject( LsapDbState.SceSyncEvent, INFINITE ); RtlAcquireResourceShared( &LsapDbState.ScePolicyLock, TRUE ); ASSERT( !g_ScePolicyLocked ); ScePolicyLocked = TRUE; NotifySce = TRUE; } }
Status = LsapDbVerifyInfoSetPolicy( PolicyHandle, InformationClass, PolicyInformation, &DesiredAccess );
if (!NT_SUCCESS(Status)) {
goto Cleanup; }
//
// 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_START_TRANSACTION | LSAP_DB_NO_DS_OP_TRANSACTION;
DereferenceOptions = LSAP_DB_FINISH_TRANSACTION | LSAP_DB_NO_DS_OP_TRANSACTION;
//
// If we are setting the Policy Audit Log Information, we may need
// the Audit Log Queue Lock.
//
if (InformationClass == PolicyAuditLogInformation) {
ReferenceOptions |= (LSAP_DB_LOG_QUEUE_LOCK | LSAP_DB_OMIT_REPLICATOR_NOTIFICATION); DereferenceOptions |= LSAP_DB_LOG_QUEUE_LOCK; }
//
// If we're setting the server role, don't hold a lock
//
if ( InformationClass != PolicyLsaServerRoleInformation ) {
ReferenceOptions |= LSAP_DB_LOCK; DereferenceOptions |= LSAP_DB_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, PolicyObject, ReferenceOptions );
if (NT_SUCCESS(Status)) {
//
// Special case the ServerRole information. This information is not stored exclusively in
// SAM, so we need to read it directly from there
//
if ( InformationClass == PolicyLsaServerRoleInformation ) {
DOMAIN_SERVER_ROLE SamServerRole;
//
// SamIDoFSMORoleChange goes off machine to do its work so do this outside
// of an LSA policy lock
//
Status = LsapDbDereferenceObject( &PolicyHandle, PolicyObject, PolicyObject, DereferenceOptions, SecurityDbChange, Status );
if ( !NT_SUCCESS( Status )) {
goto Cleanup; }
Status = LsapOpenSam(); if ( !NT_SUCCESS( Status ) ) {
LsapDsDebugOut(( DEB_ERROR, "LsarSetInformationPolicy: Sam not opened\n")); goto Cleanup;
}
SamServerRole = ( DOMAIN_SERVER_ROLE )(((PPOLICY_LSA_SERVER_ROLE_INFO)PolicyInformation)->LsaServerRole);
if ( SamServerRole == DomainServerRolePrimary ) {
Status = SamIDoFSMORoleChange( LsapAccountDomainHandle );
if ( !NT_SUCCESS( Status ) ) {
LsapDsDebugOut(( DEB_ERROR, "SamIDoFSMORoleChange failed with %lu\n", Status )); }
} else if ( SamServerRole == DomainServerRoleBackup ) {
//
// Do nothing: you do not give up the FSMO, someone grabs it
//
} else {
Status = STATUS_INVALID_PARAMETER; goto Cleanup; }
} else {
Status = LsapDbSetInformationPolicy( PolicyHandle, InformationClass, PolicyInformation );
Status = LsapDbDereferenceObject( &PolicyHandle, PolicyObject, PolicyObject, DereferenceOptions, SecurityDbChange, Status ); } }
Cleanup:
//
// Notify SCE of the change. Only notify for callers
// that did not open their policy handles with LsaOpenPolicySce.
//
if ( NotifySce && NT_SUCCESS( Status )) {
LsapSceNotify( SecurityDbChange, SecurityDbObjectLsaPolicy, NULL ); }
if ( ScePolicyLocked ) {
RtlReleaseResource( &LsapDbState.ScePolicyLock ); }
LsapTraceEvent(EVENT_TRACE_TYPE_END, LsaTraceEvent_SetInformationPolicy); LsapExitFunc( "LsarSetInformationPolicy", Status ); LsarpReturnPrologue();
return(Status); }
NTSTATUS LsapDbSetInformationPolicy( 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 PolicyDnsDomainInformation POLICY_TRUST_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_REPLICA_SOURCE_INFO PolicyReplicaSourceInfo; PPOLICY_DEFAULT_QUOTA_INFO PolicyDefaultQuotaInfo; PPOLICY_MODIFICATION_INFO PolicyModificationInfo; PPOLICY_AUDIT_FULL_SET_INFO PolicyAuditFullSetInfo; PPOLICY_DNS_DOMAIN_INFO PolicyDnsDomainInfo, CurrentDnsDomainInfo = NULL;
POLICY_DNS_DOMAIN_INFO DnsDomainInfo;
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); BOOLEAN NeedToFreeUpdatedPolicyAuditEventsInfo = FALSE; BOOLEAN NeedToFreePreviousPolicyAuditEventsInfo = FALSE; 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; POLICY_AUDIT_EVENTS_INFO PolicyAuditEventsInfo;
PLSAPR_TRUST_INFORMATION TrustInformation = NULL; POLICY_NOTIFICATION_INFORMATION_CLASS NotifyClass = 0; BOOLEAN NotifyPolicyChange = FALSE; BOOLEAN DnsDomainNameTruncated; BOOLEAN DnsForestNameTruncated;
LsapEnterFunc( "LsapDbSetInformationPolicy" );
//
// 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; }
//
// Update the specified information in the Policy Object.
//
NextAttribute = Attributes;
switch (InformationClass) {
case PolicyLsaServerRoleInformation:
Status = STATUS_NOT_IMPLEMENTED; break;
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:
//
// 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.
//
ModifyPolicyAuditEventsInfo = (PPOLICY_AUDIT_EVENTS_INFO) PolicyInformation;
if (ModifyPolicyAuditEventsInfo == NULL) {
Status = STATUS_INVALID_PARAMETER; 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) {
Status = STATUS_INVALID_PARAMETER; 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.
//
LsapDbInitializeAttributeDs( NextAttribute, PolAdtEv, NULL, 0, FALSE );
Status = LsapDbReadAttribute( PolicyHandle, NextAttribute );
if (NT_SUCCESS(Status)) {
PreviousPolicyAuditEventsInfo = NextAttribute->AttributeValue; NextAttribute->MemoryAllocated = FALSE; NeedToFreePreviousPolicyAuditEventsInfo = TRUE;
if (PreviousPolicyAuditEventsInfo == NULL) {
Status = STATUS_INTERNAL_DB_CORRUPTION; break; }
PreviousPolicyAuditEventsInfoLength = NextAttribute->AttributeValueLength;
} 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; } }
//
// Setup a buffer to hold the updated Audit Event Information.
// We try to use the existing buffer if possible.
//
if (PreviousPolicyAuditEventsInfo != NULL && PreviousPolicyAuditEventsInfoLength == sizeof( LSARM_POLICY_AUDIT_EVENTS_INFO ) && ( PreviousPolicyAuditEventsInfo->MaximumAuditEventCount == POLICY_AUDIT_EVENT_TYPE_COUNT && 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.
//
UpdatedPolicyAuditEventsInfoLength = sizeof (LSARM_POLICY_AUDIT_EVENTS_INFO); SafeAllocaAllocate( UpdatedPolicyAuditEventsInfo, UpdatedPolicyAuditEventsInfoLength );
if (UpdatedPolicyAuditEventsInfo == 0) {
Status = STATUS_INSUFFICIENT_RESOURCES; goto SetInformationPolicyError; }
NeedToFreeUpdatedPolicyAuditEventsInfo = TRUE;
UpdatedPolicyAuditEventsInfo->AuditingMode = FALSE; UpdatedEventAuditingOptions = UpdatedPolicyAuditEventsInfo->EventAuditingOptions;
for ( AuditEventType=0 ; AuditEventType < (POLICY_AUDIT_EVENT_TYPE) UpdatedMaximumAuditEventCount ; AuditEventType++ ) {
UpdatedEventAuditingOptions[ AuditEventType ] = 0; }
if ( PreviousPolicyAuditEventsInfo == NULL ) {
ASSERT( NeedToFreePreviousPolicyAuditEventsInfo == FALSE ); 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;
//
// 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).
//
LsapDbInitializeAttributeDs( NextAttribute, PolAdtEv, UpdatedPolicyAuditEventsInfo, UpdatedPolicyAuditEventsInfoLength, FALSE );
AttributeCount++;
NotifyClass = PolicyNotifyAuditEventsInformation; NotifyPolicyChange = TRUE; break;
case PolicyPrimaryDomainInformation:
//
// Get the current DnsDomainInformation to see if we're changing
// anything.
//
// Use the trusted policy handle
//
Status = LsapDbQueryInformationPolicy( LsapPolicyHandle, PolicyDnsDomainInformation, (PLSAPR_POLICY_INFORMATION *) &CurrentDnsDomainInfo );
if ( !NT_SUCCESS(Status) ) { goto SetInformationPolicyError; }
//
// If the new policy is the same as the old policy,
// avoid clearing the NT 5 specific information
//
PolicyPrimaryDomainInfo = (PPOLICY_PRIMARY_DOMAIN_INFO) PolicyInformation;
if ( RtlEqualDomainName( &PolicyPrimaryDomainInfo->Name, &CurrentDnsDomainInfo->Name ) &&
(( PolicyPrimaryDomainInfo->Sid == NULL && CurrentDnsDomainInfo->Sid == NULL) || ( PolicyPrimaryDomainInfo->Sid != NULL && CurrentDnsDomainInfo->Sid != NULL && RtlEqualSid( PolicyPrimaryDomainInfo->Sid, CurrentDnsDomainInfo->Sid ) ) ) ) {
//
// Be sure to invalidate PrimaryDomainInformation since that info
// level contains this one.
//
// LsapDbMakeInvalidInformationPolicy( PolicyDnsDomainInformation );
Status = STATUS_SUCCESS; break; }
//
// Join domain must fail on personal SKU
//
if ( LsapIsRunningOnPersonal()) {
ASSERT( CurrentDnsDomainInfo->Sid == NULL );
if ( PolicyPrimaryDomainInfo->Sid != NULL ) {
Status = STATUS_NOT_SUPPORTED; break; } }
//
// Since the PrimaryDomainInformation structure is a subset of the DnsDomainInformation,
// we'll build the latter, and set that.
//
// Clear the NT 5 specific information.
//
RtlZeroMemory( &DnsDomainInfo, sizeof(POLICY_DNS_DOMAIN_INFO) );
DnsDomainInfo.Name = PolicyPrimaryDomainInfo->Name; DnsDomainInfo.Sid = PolicyPrimaryDomainInfo->Sid;
//
// Ok, set our policy information to be the DnsDomainInfo we just initialized
//
PolicyInformation = (PLSAPR_POLICY_INFORMATION)&DnsDomainInfo; LsapDbMakeInvalidInformationPolicy( PolicyDnsDomainInformation );
//
// FALL THROUGH to PolicyDnsDomainInformation
//
case PolicyDnsDomainInformation:
PolicyDnsDomainInfo = (PPOLICY_DNS_DOMAIN_INFO) PolicyInformation;
//
// Join domain must fail on personal SKU
//
if ( CurrentDnsDomainInfo == NULL && LsapIsRunningOnPersonal()) {
//
// Get the current DnsDomainInformation to see if we're changing
// anything.
//
// Use the trusted policy handle
//
Status = LsapDbQueryInformationPolicy( LsapPolicyHandle, PolicyDnsDomainInformation, (PLSAPR_POLICY_INFORMATION *) &CurrentDnsDomainInfo );
if ( !NT_SUCCESS(Status) ) { goto SetInformationPolicyError; }
ASSERT( CurrentDnsDomainInfo->Sid == NULL );
if ( PolicyDnsDomainInfo->Sid != NULL ) {
Status = STATUS_NOT_SUPPORTED; break; } }
//
// if there is a '.' at the end of DnsDomainName or DnsForestName,
// remove it
//
DnsDomainNameTruncated = LsapRemoveTrailingDot(&PolicyDnsDomainInfo->DnsDomainName, TRUE); DnsForestNameTruncated = LsapRemoveTrailingDot(&PolicyDnsDomainInfo->DnsForestName, TRUE);
//
// Make sure we invalidate the PrimaryDomainInformation
// since the info level is a subset of this one.
//
LsapDbMakeInvalidInformationPolicy( PolicyPrimaryDomainInformation );
//
// Construct the Domain name attribute info
//
Status = LsapDbMakeUnicodeAttributeDs( &PolicyDnsDomainInfo->Name, PolPrDmN, NextAttribute );
if (!NT_SUCCESS(Status)) {
break; }
DomainName = NextAttribute->AttributeName; NextAttribute++; AttributeCount++;
//
// Construct the DNS Domain name attribute info
//
Status = LsapDbMakeUnicodeAttributeDs( &PolicyDnsDomainInfo->DnsDomainName, PolDnDDN, NextAttribute );
NextAttribute++; AttributeCount++;
//
// Construct the DNS Tree name attribute info
//
Status = LsapDbMakeUnicodeAttributeDs( &PolicyDnsDomainInfo->DnsForestName, PolDnTrN, NextAttribute );
NextAttribute++; AttributeCount++;
//
// Construct the Domain GUID attribute info
//
Status = LsapDbMakeGuidAttributeDs( &PolicyDnsDomainInfo->DomainGuid, PolDnDmG, NextAttribute );
NextAttribute++; AttributeCount++;
//
// Construct the Sid attribute info
//
Status = LsapDbMakeSidAttributeDs( PolicyDnsDomainInfo->Sid, PolPrDmS, NextAttribute );
if (!NT_SUCCESS(Status)) {
break; }
AttributeCount++;
NotifyClass = PolicyNotifyDnsDomainInformation; NotifyPolicyChange = TRUE;
if (DnsDomainNameTruncated) {
PolicyDnsDomainInfo->DnsDomainName.Length += sizeof(WCHAR); }
if (DnsForestNameTruncated) {
PolicyDnsDomainInfo->DnsForestName.Length += sizeof(WCHAR); } break;
case PolicyAccountDomainInformation:
PolicyAccountDomainInfo = (PPOLICY_ACCOUNT_DOMAIN_INFO) PolicyInformation;
//
// 368441: NULL account domain SID will cause the machine to
// fail to boot, even into safe mode
//
if ( PolicyAccountDomainInfo->DomainSid == NULL ) {
Status = STATUS_INVALID_PARAMETER; break; }
//
// Construct the Domain name attribute info
//
Status = LsapDbMakeUnicodeAttributeDs( &PolicyAccountDomainInfo->DomainName, PolAcDmN, NextAttribute );
if (!NT_SUCCESS(Status)) {
break; }
DomainName = NextAttribute->AttributeName; AttributeCount++; NextAttribute++;
//
// Construct the Sid attribute info
//
Status = LsapDbMakeSidAttributeDs( PolicyAccountDomainInfo->DomainSid, PolAcDmS, NextAttribute );
if (!NT_SUCCESS(Status)) {
break; }
AttributeCount++; NotifyClass = PolicyNotifyAccountDomainInformation; NotifyPolicyChange = TRUE; break;
case PolicyPdAccountInformation:
Status = STATUS_INVALID_PARAMETER; break;
case PolicyReplicaSourceInformation:
PolicyReplicaSourceInfo = (PPOLICY_REPLICA_SOURCE_INFO) PolicyInformation;
//
// Construct the Replica Source Name attribute info
//
Status = LsapDbMakeUnicodeAttributeDs( &PolicyReplicaSourceInfo->ReplicaSource, PolRepSc, NextAttribute );
if (!NT_SUCCESS(Status)) {
break; }
ReplicaSource = NextAttribute->AttributeName; AttributeCount++; NextAttribute++;
//
// Construct the Replica Account Name attribute info
//
Status = LsapDbMakeUnicodeAttributeDs( &PolicyReplicaSourceInfo->ReplicaAccountName, PolRepAc, NextAttribute );
if (!NT_SUCCESS(Status)) {
break; }
AccountName = NextAttribute->AttributeName; AttributeCount++; break;
case PolicyDefaultQuotaInformation:
PolicyDefaultQuotaInfo = (PPOLICY_DEFAULT_QUOTA_INFO) PolicyInformation;
LsapDbInitializeAttributeDs( NextAttribute, DefQuota, &PolicyDefaultQuotaInfo->QuotaLimits, sizeof (POLICY_DEFAULT_QUOTA_INFO), FALSE );
AttributeCount++; break;
case PolicyModificationInformation:
PolicyModificationInfo = (PPOLICY_MODIFICATION_INFO) PolicyInformation;
LsapDbInitializeAttributeDs( NextAttribute, PolMod, PolicyModificationInfo, sizeof (POLICY_MODIFICATION_INFO), FALSE );
AttributeCount++; break;
case PolicyAuditFullSetInformation:
Status = STATUS_NOT_SUPPORTED; 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)) {
goto SetInformationPolicyError; }
//
// Generate an audit.
//
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;
if ( NT_SUCCESS( Status ) ) {
//
// Invalidate the information in the Policy Cache for this information
// class
//
LsapDbMakeInvalidInformationPolicy( InformationClass );
}
//
// Finally, call the notification routines. We don't care about errors coming back
// from this.
//
if ( NT_SUCCESS( Status ) && NotifyPolicyChange ) {
LsaINotifyChangeNotification( NotifyClass ); }
SetInformationPolicyFinish:
//
// 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.
//
//
// 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 ( NeedToFreePreviousPolicyAuditEventsInfo ) {
MIDL_user_free( PreviousPolicyAuditEventsInfo ); }
if ( NeedToFreeUpdatedPolicyAuditEventsInfo ) {
SafeAllocaFree( UpdatedPolicyAuditEventsInfo ); }
LsaIFree_LSAPR_POLICY_INFORMATION( PolicyDnsDomainInformation, (PLSAPR_POLICY_INFORMATION)CurrentDnsDomainInfo );
LsapExitFunc( "LsapDbSetInformationPolicy", Status );
return(Status);
SetInformationPolicyError:
goto SetInformationPolicyFinish; }
NTSTATUS LsarSetInformationPolicy2( 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 PolicyDnsDomainInformation POLICY_TRUST_ADMIN PolicyDnsDomainInformationInt POLICY_TRUST_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
Result codes returned from LsarSetInformationPolicy() --*/
{ return(LsarSetInformationPolicy( PolicyHandle, InformationClass, PolicyInformation )); }
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:
--*/
{ SafeAcquireResourceExclusive( &LsapDbState.PolicyCacheLock, TRUE );
//
// If the Policy Cache is invalid, just return.
//
if (!LsapDbIsCacheValid(PolicyObject)) {
goto Cleanup; }
//
//
// 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 )) {
goto Cleanup; }
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; }
Cleanup:
SafeReleaseResource( &LsapDbState.PolicyCacheLock );
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)) {
//
// 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
STATUS_SHARED_POLICY - The policy is replicated from the DCs and cannot be modified locally --*/
{ 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)) {
//
// Non-trusted callers are not allowed to set information for
// the following classes.
//
// PolicyPdAccountInformation
// PolicyModificationInformation
//
if (!InternalHandle->Trusted) {
if ((InformationClass == PolicyPdAccountInformation) || (InformationClass == PolicyModificationInformation)) {
#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_DNS_DOMAIN_INFO PolicyDnsDomainInfo; 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; POLICY_AUDIT_EVENT_TYPE AuditEventType; ULONG MaximumAuditEventCount; PPOLICY_AUDIT_EVENT_OPTIONS EventAuditingOptions;
//
// Validate the Information Class
//
if ((InformationClass >= PolicyAuditLogInformation) && (InformationClass <= PolicyDnsDomainInformation)) {
if ((InformationClass == PolicyAuditFullSetInformation) || (InformationClass == PolicyAuditFullQueryInformation)) {
return FALSE; }
if (PolicyInformation == NULL) {
return(TRUE); }
switch (InformationClass) {
case PolicyAuditLogInformation:
PolicyAuditLogInfo = (PPOLICY_AUDIT_LOG_INFO) PolicyInformation;
//
// PPOLICY_AUDIT_LOG_INFO is a pointer-free struct;
// nothing to verify
//
break;
case PolicyAuditEventsInformation:
PolicyAuditEventsInfo = (PPOLICY_AUDIT_EVENTS_INFO) PolicyInformation;
MaximumAuditEventCount = PolicyAuditEventsInfo->MaximumAuditEventCount;
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;
if ( !LsapValidateLsaUnicodeString( &PolicyPrimaryDomainInfo->Name )) {
BooleanStatus = FALSE; break; }
break;
case PolicyDnsDomainInformation:
PolicyDnsDomainInfo = (PPOLICY_DNS_DOMAIN_INFO) PolicyInformation;
if ( !LsapValidateLsaUnicodeString( &PolicyDnsDomainInfo->Name ) || !LsapValidateLsaUnicodeString( &PolicyDnsDomainInfo->DnsDomainName ) || !LsapValidateLsaUnicodeString( &PolicyDnsDomainInfo->DnsForestName )) {
BooleanStatus = FALSE; break; }
break; case PolicyAccountDomainInformation:
PolicyAccountDomainInfo = (PPOLICY_ACCOUNT_DOMAIN_INFO) PolicyInformation;
if ( !LsapValidateLsaUnicodeString( &PolicyAccountDomainInfo->DomainName )) {
BooleanStatus = FALSE; break; }
break;
case PolicyPdAccountInformation:
PolicyPdAccountInfo = (PPOLICY_PD_ACCOUNT_INFO) PolicyInformation;
if ( !LsapValidateLsaUnicodeString( &PolicyPdAccountInfo->Name )) {
BooleanStatus = FALSE; break; }
break;
case PolicyLsaServerRoleInformation:
PolicyLsaServerRoleInfo = (PPOLICY_LSA_SERVER_ROLE_INFO) PolicyInformation;
break;
case PolicyReplicaSourceInformation:
PolicyReplicaSourceInfo = (PPOLICY_REPLICA_SOURCE_INFO) PolicyInformation;
if ( !LsapValidateLsaUnicodeString( &PolicyReplicaSourceInfo->ReplicaSource ) || !LsapValidateLsaUnicodeString( &PolicyReplicaSourceInfo->ReplicaAccountName )) {
BooleanStatus = FALSE; break; }
break;
case PolicyDefaultQuotaInformation:
PolicyDefaultQuotaInfo = (PPOLICY_DEFAULT_QUOTA_INFO) PolicyInformation; break;
case PolicyModificationInformation:
PolicyModificationInfo = (PPOLICY_MODIFICATION_INFO) PolicyInformation; break;
default:
BooleanStatus = FALSE; break; } } else { BooleanStatus = FALSE; }
return(BooleanStatus); }
NTSTATUS LsapDbGetSerialNumberPolicy( 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->QuadPart = 0;
return (Status);
GetSerialNumberPolicyError:
goto GetSerialNumberPolicyFinish; }
NTSTATUS LsaIGetSerialNumberPolicy( IN LSAPR_HANDLE PolicyHandle, OUT PLARGE_INTEGER ModifiedCount, OUT PLARGE_INTEGER CreationTime )
/*++
Routine Description:
Thin wrapper to LsapDbGetSerialNumberPolicy(). See that function for descriptions.
--*/
{ LARGE_INTEGER Ignore1;
return( LsapDbGetSerialNumberPolicy( PolicyHandle, ModifiedCount, &Ignore1, CreationTime ) );
}
NTSTATUS LsapDbSetSerialNumberPolicy( IN LSAPR_HANDLE PolicyHandle, IN PLARGE_INTEGER ModifiedCount, IN OPTIONAL PLARGE_INTEGER ModifiedCountAtLastPromotion, 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 = {0, 0};
LsapEnterFunc( "LsaISetSerialNumberPolicy2" );
//
// 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, PolicyObject, LSAP_DB_LOCK | LSAP_DB_START_TRANSACTION | LSAP_DB_TRUSTED | LSAP_DB_NO_DS_OP_TRANSACTION );
if (!NT_SUCCESS(Status)) {
goto SetSerialNumberPolicyError; }
ObjectReferenced = TRUE;
// Since the policy object is in the registry, it grabbed the registry lock too.
// (The registry lock protects LsapDbState.PolicyModificationInfo)
ASSERT( LsapDbIsLocked( &LsapDbState.RegistryLock )); OriginalPolicyModificationInfo = LsapDbState.PolicyModificationInfo;
{ //
// 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; LsapDbState.RegistryModificationCount++; }
//
// 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, PolicyObject, LSAP_DB_LOCK | LSAP_DB_FINISH_TRANSACTION | LSAP_DB_NO_DS_OP_TRANSACTION, SecurityDbChange, Status );
ObjectReferenced = FALSE;
}
LsapExitFunc( "LsaISetSerialNumberPolicy2", Status );
return (Status);
SetSerialNumberPolicyError:
//
// Attempt to restore the Serial Number to its original value.
// We need only reset the in-memory copy.
//
if ( ObjectReferenced ) { LsapDbState.PolicyModificationInfo = OriginalPolicyModificationInfo; }
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 ); UNREFERENCED_PARAMETER( ModifiedCountAtLastPromotion ); }
NTSTATUS LsaISetSerialNumberPolicy( IN LSAPR_HANDLE PolicyHandle, IN PLARGE_INTEGER ModifiedCount, IN PLARGE_INTEGER CreationTime, IN BOOLEAN StartOfFullSync )
/*++
Routine Description:
Thin wrapper around LsapDbSetSerialNumberPolicy(). See that function for descriptions.
--*/
{ return( LsapDbSetSerialNumberPolicy( PolicyHandle, ModifiedCount, NULL, CreationTime, StartOfFullSync ) ); }
NTSTATUS LsapDbBuildPolicyCache( )
/*++
Routine Description:
This function constructs a cache for the Policy object. The cache consists of a single 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 <= PolicyDnsDomainInformation; InformationClass++ ) {
if ((InformationClass == PolicyAuditFullSetInformation) || (InformationClass == PolicyAuditFullQueryInformation) || (InformationClass == PolicyLsaServerRoleInformation) ) {
continue; }
//
// Throw away current informaiton
//
LsaIFree_LSAPR_POLICY_INFORMATION( InformationClass, ( PLSAPR_POLICY_INFORMATION )LsapDbPolicy.Info[InformationClass].Attribute );
LsapDbPolicy.Info[InformationClass].Attribute = NULL;
//
// ... and obtain new one
//
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); LsapDbPolicy.Info[PolicyDnsDomainInformation].AttributeLength = sizeof(LSAPR_POLICY_DNS_DOMAIN_INFO); LsapDbPolicy.Info[PolicyDnsDomainInformationInt].AttributeLength = 0; // dummy value for a dummy information class
BuildPolicyCacheFinish:
return(Status);
BuildPolicyCacheError:
goto BuildPolicyCacheFinish; }
NTSTATUS LsapDbUpdateInformationPolicy( IN POLICY_INFORMATION_CLASS InformationClass )
/*++
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 = 0;
//
// 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 PolicyDnsDomainInformation :
TopNodeLength = sizeof(LSAPR_POLICY_DNS_DOMAIN_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; }
|