/*++ Copyright (c) 1991 Microsoft Corporation Module Name: dbpolex.c Abstract: LSA Database - Policy Object Private API Workers Author: Mac McLain (MacM) January 17, 1997 Environment: Revision History: --*/ #include #include #include "lsawmi.h" #ifndef LSAP_DB_POLICY_MAX_BUFFERS #define LSAP_DB_POLICY_MAX_BUFFERS ((ULONG) 0x00000005L) #endif NTSTATUS LsapDbVerifyInfoAllQueryPolicy( IN LSAPR_HANDLE PolicyHandle, IN POLICY_DOMAIN_INFORMATION_CLASS InformationClass, OUT PACCESS_MASK RequiredAccess ) /*++ Routine Description: This function validates a Local 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 STATUS_SHARED_POLICY - The policy is replicated from the DCs and cannot be modified locally --*/ { // // Ensure the info level is valid. // if ( InformationClass < PolicyDomainEfsInformation || InformationClass > PolicyDomainKerberosTicketInformation ) { return STATUS_INVALID_PARAMETER; } *RequiredAccess = LsapDbRequiredAccessQueryDomainPolicy[InformationClass]; return STATUS_SUCCESS; } NTSTATUS LsapDbVerifyInfoAllSetPolicy( IN LSAPR_HANDLE PolicyHandle, IN POLICY_DOMAIN_INFORMATION_CLASS InformationClass, IN PVOID PolicyInformation, 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 --*/ { // // Ensure the info level is valid. // if ( InformationClass < PolicyDomainEfsInformation || InformationClass > PolicyDomainKerberosTicketInformation ) { return STATUS_INVALID_PARAMETER; } else if ( InformationClass == PolicyDomainKerberosTicketInformation && PolicyInformation == NULL ) { return STATUS_INVALID_PARAMETER; } *RequiredAccess = LsapDbRequiredAccessSetDomainPolicy[InformationClass]; return STATUS_SUCCESS; } NTSTATUS NTAPI LsarQueryDomainInformationPolicy( IN LSA_HANDLE PolicyHandle, IN POLICY_DOMAIN_INFORMATION_CLASS InformationClass, OUT PLSAPR_POLICY_DOMAIN_INFORMATION *PolicyDomainInformation ) /*++ Routine Description: This function is the LSA server RPC worker routine for the LsarQueryDomainInformationPolicy API. The LsaQueryDomainInformationPolicy API obtains information from the Local 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 PolicyDomainEfsInformation POLICY_VIEW_LOCAL_INFORMATION PolicyDomainKerberosTicketInformation POLICY_VIEW_LOCAL_INFORMATION PolicyLocalInformation - 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 = STATUS_SUCCESS; BOOLEAN ObjectReferenced = FALSE; ACCESS_MASK DesiredAccess; ULONG ReferenceOptions, DereferenceOptions = 0; LsarpReturnCheckSetup(); LsapDsDebugOut(( DEB_FTRACE, "LsarQueryDomainInformationPolicy\n" )); LsapTraceEvent(EVENT_TRACE_TYPE_START, LsaTraceEvent_QueryDomainInformationPolicy); Status = LsapDbVerifyInfoAllQueryPolicy( PolicyHandle, InformationClass, &DesiredAccess ); if (!NT_SUCCESS(Status)) { goto QueryInfoDomainPolicyFinish; } // // 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_LOCK | LSAP_DB_START_TRANSACTION | LSAP_DB_READ_ONLY_TRANSACTION | LSAP_DB_NO_DS_OP_TRANSACTION; DereferenceOptions = LSAP_DB_LOCK | LSAP_DB_FINISH_TRANSACTION | LSAP_DB_READ_ONLY_TRANSACTION | LSAP_DB_NO_DS_OP_TRANSACTION; // // 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 QueryInfoDomainPolicyFinish; } ObjectReferenced = TRUE; // // If caching is enabled for this Information Class, grab the info from the // cache. // *PolicyDomainInformation = NULL; Status = LsapDbQueryInformationPolicyEx( LsapPolicyHandle, InformationClass, PolicyDomainInformation ); QueryInfoDomainPolicyFinish: // // 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 ); } LsapDsDebugOut(( DEB_FTRACE, "LsarQueryDomainInformationPolicy: 0x%lx\n", Status )); LsapTraceEvent(EVENT_TRACE_TYPE_END, LsaTraceEvent_QueryDomainInformationPolicy); LsarpReturnPrologue(); return(Status); } NTSTATUS NTAPI LsarSetDomainInformationPolicy( IN LSA_HANDLE PolicyHandle, IN POLICY_DOMAIN_INFORMATION_CLASS InformationClass, IN PLSAPR_POLICY_DOMAIN_INFORMATION PolicyDomainInformation ) /*++ Routine Description: This function is the LSA server RPC worker routine for the LsarSetDomainInformationPolicy API. The LsarSetDomainInformationPolicy API obtains information from the Domain 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 set. The Information Classes and accesses required are as follows: Information Class Required Access Type PolicyAuditEventsInformation POLICY_VIEW_AUDIT_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 PolicyLocalInformation - receives a pointer to the buffer information to be set Return Value: NTSTATUS - Standard Nt Result Code --*/ { NTSTATUS Status = STATUS_SUCCESS; BOOLEAN ObjectReferenced = FALSE; ACCESS_MASK DesiredAccess; ULONG ReferenceOptions, DereferenceOptions = 0; LsarpReturnCheckSetup(); LsapTraceEvent(EVENT_TRACE_TYPE_START, LsaTraceEvent_SetDomainInformationPolicy); Status = LsapDbVerifyInfoAllSetPolicy( PolicyHandle, InformationClass, PolicyDomainInformation, &DesiredAccess ); if (!NT_SUCCESS(Status)) { goto QueryInfoDomainPolicyFinish; } // // 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_LOCK | LSAP_DB_NO_DS_OP_TRANSACTION | LSAP_DB_START_TRANSACTION; DereferenceOptions = LSAP_DB_LOCK | LSAP_DB_NO_DS_OP_TRANSACTION | LSAP_DB_FINISH_TRANSACTION; // // 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 QueryInfoDomainPolicyFinish; } ObjectReferenced = TRUE; Status = LsapDbSetInformationPolicyEx( LsapPolicyHandle, InformationClass, PolicyDomainInformation ); QueryInfoDomainPolicyFinish: // // If necessary, dereference the Policy Object, release the LSA Database lock and // return. // if (ObjectReferenced) { // // Don't notify the NT 4 replicator. NT 4 doesn't understand any of the attributes // changed by this API. // Status = LsapDbDereferenceObject( &PolicyHandle, PolicyObject, PolicyObject, DereferenceOptions | LSAP_DB_OMIT_REPLICATOR_NOTIFICATION, SecurityDbChange, Status ); } #if DBG LsapDsDebugOut(( DEB_POLICY, "LsarSetDomainInformationPolicy for info %lu returned 0x%lx\n", InformationClass, Status )); #endif LsapTraceEvent(EVENT_TRACE_TYPE_END, LsaTraceEvent_SetDomainInformationPolicy); LsarpReturnPrologue(); return(Status); } NTSTATUS LsapDbQueryInformationPolicyEx( IN LSAPR_HANDLE PolicyHandle, IN POLICY_DOMAIN_INFORMATION_CLASS InformationClass, IN OUT PVOID *Buffer ) /*++ Routine Description: This function is a thin wrapper around LsapDbSlowQueryInformationPolicyEx 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 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; Status = LsapDbSlowQueryInformationPolicyEx( LsapPolicyHandle, InformationClass, Buffer ); return(Status); } NTSTATUS LsapDbSlowQueryInformationPolicyEx( IN LSAPR_HANDLE PolicyHandle, IN POLICY_DOMAIN_INFORMATION_CLASS InformationClass, IN OUT PVOID *Buffer ) /*++ Routine Description: This function is the slow LSA server RPC worker routine for the LsarQueryInformationPolicy API. It actually reads the information from backing storage. The LsaQueryInformationPolicy API obtains information from the Policy object. The caller must have access appropriate to the information being requested (see InformationClass parameter). Arguments: PolicyHandle - Handle from an LsaOpenPolicy call. InformationClass - Specifies the information to be returned. The Information Classes and accesses required are as follows: Information Class Required Access Type PolicyAuditEventsInformation POLICY_VIEW_AUDIT_INFORMATION PolicyPrimaryDomainInformation POLICY_VIEW_LOCAL_INFORMATION PolicyAccountDomainInformation POLICY_VIEW_LOCAL_INFORMATION PolicyPdAccountInformation POLICY_GET_PRIVATE_INFORMATION PolicyLsaServerRoleInformation POLICY_VIEW_LOCAL_INFORMATION PolicyReplicaSourceInformation POLICY_VIEW_LOCAL_INFORMATION PolicyDefaultQuotaInformation POLICY_VIEW_LOCAL_INFORMATION PolicyAuditFullQueryInformation POLICY_VIEW_AUDIT_INFORMATION Buffer - Pointer to location that contains either a pointer to the buffer that will be used to return the information. If NULL is contained in this location, a buffer will be allocated via MIDL_user_allocate and a pointer to it returned. Return Value: NTSTATUS - Standard Nt Result Code STATUS_ACCESS_DENIED - Caller does not have the appropriate access to complete the operation. STATUS_INTERNAL_DB_CORRUPTION - The Policy Database is possibly corrupt. The returned Policy Information is invalid for the given class. --*/ { NTSTATUS Status = STATUS_SUCCESS; PPOLICY_DOMAIN_EFS_INFO PolicyEfsInfo; PPOLICY_DOMAIN_KERBEROS_TICKET_INFO PolicyKerbTicketInfo; LSAP_DB_ATTRIBUTE Attributes[LSAP_DB_ATTRS_INFO_CLASS_POLICY]; PLSAP_DB_ATTRIBUTE NextAttribute; ULONG AttributeCount = 0; ULONG AttributeNumber = 0; LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) PolicyHandle; PVOID InformationBuffer = NULL; BOOLEAN ObjectReferenced = FALSE; ULONG EventAuditingOptionsSize, InfoSize; BOOLEAN InfoBufferInAttributeArray = TRUE; BOOLEAN BufferProvided = FALSE; if (*Buffer != NULL) { BufferProvided = TRUE; } // // Compile a list of the attributes that hold the Policy Information of // the specified class. // NextAttribute = Attributes; switch (InformationClass) { case PolicyDomainEfsInformation: // // Request read of the Efs policy attribute // LsapDbInitializeAttributeDs( NextAttribute, PolEfDat, NULL, 0, FALSE ); NextAttribute++; AttributeCount++; break; case PolicyDomainKerberosTicketInformation: { int i; LSAP_DB_NAMES Names[] = { KerOpts, KerMinT, KerMaxT, KerMaxR, KerProxy, KerLogoff }; for(i = 0; i < sizeof(Names) / sizeof(Names[0]) ; ++i){ LsapDbInitializeAttributeDs( NextAttribute, Names[i], NULL, 0, TRUE ); NextAttribute++; } AttributeCount += sizeof(Names) / sizeof(Names[0]); } 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. // goto SlowQueryInformationPolicyError; } // // 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 PolicyDomainEfsInformation: // // Get the size of the item // InfoSize = NextAttribute->AttributeValueLength; // // Allocate memory for output buffer top-level structure. // InfoBufferInAttributeArray = FALSE; PolicyEfsInfo = MIDL_user_allocate( sizeof( POLICY_DOMAIN_EFS_INFO ) ); if (PolicyEfsInfo == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } PolicyEfsInfo->InfoLength = InfoSize; // // Next, the blob // PolicyEfsInfo->EfsBlob = NextAttribute->AttributeValue; NextAttribute->MemoryAllocated = FALSE; InformationBuffer = PolicyEfsInfo; break; case PolicyDomainKerberosTicketInformation: // // Allocate memory for output buffer top-level structure. // InfoBufferInAttributeArray = FALSE; PolicyKerbTicketInfo = MIDL_user_allocate( sizeof( POLICY_DOMAIN_KERBEROS_TICKET_INFO ) ); if (PolicyKerbTicketInfo == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } PolicyKerbTicketInfo->AuthenticationOptions = *(PULONG)NextAttribute->AttributeValue; NextAttribute++; RtlCopyMemory( &PolicyKerbTicketInfo->MaxServiceTicketAge, NextAttribute->AttributeValue, sizeof( LARGE_INTEGER ) ); NextAttribute++; RtlCopyMemory( &PolicyKerbTicketInfo->MaxTicketAge, NextAttribute->AttributeValue, sizeof( LARGE_INTEGER ) ); NextAttribute++; RtlCopyMemory( &PolicyKerbTicketInfo->MaxRenewAge, NextAttribute->AttributeValue, sizeof( LARGE_INTEGER ) ); NextAttribute++; RtlCopyMemory( &PolicyKerbTicketInfo->MaxClockSkew, NextAttribute->AttributeValue, sizeof( LARGE_INTEGER ) ); NextAttribute++; RtlCopyMemory( &PolicyKerbTicketInfo->Reserved, NextAttribute->AttributeValue, sizeof( LARGE_INTEGER ) ); NextAttribute++; InformationBuffer = PolicyKerbTicketInfo; break; default: Status = STATUS_INVALID_PARAMETER; break; } if (!NT_SUCCESS(Status)) { goto SlowQueryInformationPolicyError; } Status = STATUS_SUCCESS; // // If the caller provided a buffer, return information there. // if (BufferProvided) { RtlCopyMemory( *Buffer, InformationBuffer, LsapDbPolicy.Info[ InformationClass ].AttributeLength ); MIDL_user_free( InformationBuffer ); InformationBuffer = NULL; } else { *Buffer = InformationBuffer; } SlowQueryInformationPolicyFinish: // // Free any unwanted buffers that were allocated by // LsapDbReadAttributesObject() and that are not being returned to the // caller server stub. The server stub will free the buffers that we // do return after copying them to the return RPC transmit buffer. // //$ REVIEW kumarp 22-March-1999 // replace this for loop with LsapDbFreeAttributes // 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); } } } 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. // //$ REVIEW kumarp 22-March-1999 // replace this for loop with LsapDbFreeAttributes // for (NextAttribute = Attributes, AttributeNumber = 0; AttributeNumber < AttributeCount; NextAttribute++, AttributeNumber++) { // // If buffer holding attribute is marked as normally not to be freed, // will not get freed by the Finish section so it must be freed here. // if (!NextAttribute->MemoryAllocated) { if (NextAttribute->AttributeValue != NULL) { MIDL_user_free(NextAttribute->AttributeValue); NextAttribute->AttributeValue = NULL; NextAttribute->MemoryAllocated = FALSE; } NextAttribute->MemoryAllocated = FALSE; } } goto SlowQueryInformationPolicyFinish; } NTSTATUS LsapDbSetInformationPolicyEx( IN LSAPR_HANDLE PolicyHandle, IN POLICY_DOMAIN_INFORMATION_CLASS InformationClass, IN PVOID 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: PolicyDomainEfsInformation POLICY_TRUST_ADMIN PolicyDomainKerberosTicketInformation 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, SavedStatus; ACCESS_MASK DesiredAccess; PPOLICY_DOMAIN_EFS_INFO PolicyEfsInfo; PPOLICY_DOMAIN_KERBEROS_TICKET_INFO PolicyKerbTicketInfo; LSAP_DB_ATTRIBUTE Attributes[LSAP_DB_ATTRS_INFO_CLASS_POLICY]; LSAP_DB_ATTRIBUTE OldAttributes[LSAP_DB_ATTRS_INFO_CLASS_POLICY]; PLSAP_DB_ATTRIBUTE NextAttribute; PLSAP_DB_ATTRIBUTE NextOldAttribute; ULONG AttributeCount = 0; ULONG OldAttributeCount = 0; ULONG AttributeNumber; ULONG AccountUlong; BOOLEAN RemoveAttributes = FALSE; BOOLEAN OldHandleDs; BOOLEAN BooleanStatus; BOOLEAN PreviousAuditEventsInfoExists; BOOLEAN ResetClientSyncData; PUNICODE_STRING DomainName = NULL; LARGE_INTEGER ModifiedIdAtLastPromotion; PUNICODE_STRING ReplicaSource = NULL; PUNICODE_STRING AccountName = NULL; ULONG SpecialProcessing = 0; BOOLEAN Notify = FALSE; BOOLEAN AuditingEnabled=FALSE; BOOLEAN AuditingSuccessEnabled=FALSE; BOOLEAN AuditingFailureEnabled=FALSE; USHORT AuditEventType; POLICY_NOTIFICATION_INFORMATION_CLASS NotifyClass = 0; if ( PolicyInformation == NULL ) { RemoveAttributes = TRUE; } AuditingFailureEnabled = LsapAdtAuditingEnabledHint( AuditCategoryPolicyChange, EVENTLOG_AUDIT_FAILURE ); AuditingSuccessEnabled = LsapAdtAuditingEnabledHint( AuditCategoryPolicyChange, EVENTLOG_AUDIT_SUCCESS ); AuditingEnabled = AuditingSuccessEnabled || AuditingFailureEnabled; // // Build the list of attributes // NextAttribute = Attributes; NextOldAttribute = OldAttributes; switch (InformationClass) { case PolicyDomainEfsInformation: PolicyEfsInfo = ( PPOLICY_DOMAIN_EFS_INFO )PolicyInformation; // // Do the blob attribute // LsapDbInitializeAttributeDs( NextAttribute, PolEfDat, PolicyEfsInfo ? PolicyEfsInfo->EfsBlob : NULL, PolicyEfsInfo ? PolicyEfsInfo->InfoLength : 0, FALSE ); AttributeCount++; Notify = TRUE; NotifyClass = PolicyNotifyDomainEfsInformation; if (AuditingEnabled) { LsapDbInitializeAttributeDs( NextOldAttribute, PolEfDat, NULL, 0, FALSE ); OldAttributeCount++; } break; case PolicyDomainKerberosTicketInformation: PolicyKerbTicketInfo = ( PPOLICY_DOMAIN_KERBEROS_TICKET_INFO )PolicyInformation; LsapDbInitializeAttributeDs( NextAttribute, KerOpts, PolicyKerbTicketInfo ? &PolicyKerbTicketInfo->AuthenticationOptions : 0, sizeof( ULONG ), FALSE ); AttributeCount++; NextAttribute++; LsapDbInitializeAttributeDs( NextAttribute, KerMinT, PolicyKerbTicketInfo ? &PolicyKerbTicketInfo->MaxServiceTicketAge: 0, sizeof( LARGE_INTEGER ), FALSE ); AttributeCount++; NextAttribute++; LsapDbInitializeAttributeDs( NextAttribute, KerMaxT, PolicyKerbTicketInfo ? &PolicyKerbTicketInfo->MaxTicketAge : 0, sizeof( LARGE_INTEGER ), FALSE ); AttributeCount++; NextAttribute++; LsapDbInitializeAttributeDs( NextAttribute, KerMaxR, PolicyKerbTicketInfo ? &PolicyKerbTicketInfo->MaxRenewAge : 0, sizeof( LARGE_INTEGER ), FALSE ); AttributeCount++; NextAttribute++; LsapDbInitializeAttributeDs( NextAttribute, KerProxy, PolicyKerbTicketInfo ? &PolicyKerbTicketInfo->MaxClockSkew: 0, sizeof( LARGE_INTEGER ), FALSE ); AttributeCount++; NextAttribute++; LsapDbInitializeAttributeDs( NextAttribute, KerLogoff, PolicyKerbTicketInfo ? &PolicyKerbTicketInfo->Reserved: 0, sizeof( LARGE_INTEGER ), FALSE ); AttributeCount++; NextAttribute++; Notify = TRUE; NotifyClass = PolicyNotifyDomainKerberosTicketInformation; if (AuditingEnabled) { LsapDbInitializeAttributeDs( NextOldAttribute, KerOpts, 0, sizeof( ULONG ), FALSE ); OldAttributeCount++; NextOldAttribute++; LsapDbInitializeAttributeDs( NextOldAttribute, KerMinT, 0, sizeof( LARGE_INTEGER ), FALSE ); OldAttributeCount++; NextOldAttribute++; LsapDbInitializeAttributeDs( NextOldAttribute, KerMaxT, 0, sizeof( LARGE_INTEGER ), FALSE ); OldAttributeCount++; NextOldAttribute++; LsapDbInitializeAttributeDs( NextOldAttribute, KerMaxR, 0, sizeof( LARGE_INTEGER ), FALSE ); OldAttributeCount++; NextOldAttribute++; LsapDbInitializeAttributeDs( NextOldAttribute, KerProxy, 0, sizeof( LARGE_INTEGER ), FALSE ); OldAttributeCount++; NextOldAttribute++; LsapDbInitializeAttributeDs( NextOldAttribute, KerLogoff, 0, sizeof( LARGE_INTEGER ), FALSE ); OldAttributeCount++; NextOldAttribute++; } break; default: Status = STATUS_INVALID_PARAMETER; break; } if (!NT_SUCCESS(Status)) { goto SetInformationPolicyError; } // // Query the existing values before we modify them // if (AuditingEnabled) { (void) LsapDbReadAttributesObject( PolicyHandle, 0, // no options OldAttributes, OldAttributeCount ); } // // Update the Policy Object attributes // if ( RemoveAttributes ) { Status = LsapDbDeleteAttributesObject( PolicyHandle, Attributes, AttributeCount ); } else { Status = LsapDbWriteAttributesObject( PolicyHandle, Attributes, AttributeCount ); } if ( ( AuditingSuccessEnabled && NT_SUCCESS(Status) ) || ( AuditingFailureEnabled && !NT_SUCCESS(Status) ) ) { AuditEventType = NT_SUCCESS(Status) ? EVENTLOG_AUDIT_SUCCESS : EVENTLOG_AUDIT_FAILURE; (void) LsapAdtGenerateDomainPolicyChangeAuditEvent( InformationClass, AuditEventType, OldAttributes, Attributes, AttributeCount); } if (!NT_SUCCESS(Status)) { goto SetInformationPolicyError; } // // Finally, call the notification routines. We don't care about errors coming back // from this. // if ( Notify ) { LsaINotifyChangeNotification( NotifyClass ); } SetInformationPolicyFinish: // // 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. // (void) LsapDbFreeAttributes(AttributeCount, Attributes); (void) LsapDbFreeAttributes(OldAttributeCount, OldAttributes); return(Status); SetInformationPolicyError: goto SetInformationPolicyFinish; }