diff --git a/reactos/ntoskrnl/include/internal/ob.h b/reactos/ntoskrnl/include/internal/ob.h index c6402d4805d..a155da288cf 100644 --- a/reactos/ntoskrnl/include/internal/ob.h +++ b/reactos/ntoskrnl/include/internal/ob.h @@ -374,12 +374,6 @@ ObpAddSecurityDescriptor( OUT PSECURITY_DESCRIPTOR *DestinationSD ); -NTSTATUS -NTAPI -ObpRemoveSecurityDescriptor( - IN PSECURITY_DESCRIPTOR SecurityDescriptor -); - PSECURITY_DESCRIPTOR NTAPI ObpReferenceCachedSecurityDescriptor( @@ -438,6 +432,44 @@ ObpCheckObjectReference( OUT PNTSTATUS AccessStatus ); +// +// Default Object Security Callback Routines +// +NTSTATUS +NTAPI +ObAssignObjectSecurityDescriptor( + IN PVOID Object, + IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL, + IN POOL_TYPE PoolType +); + +NTSTATUS +NTAPI +ObDeassignSecurity( + IN OUT PSECURITY_DESCRIPTOR *SecurityDescriptor +); + +NTSTATUS +NTAPI +ObQuerySecurityDescriptorInfo( + IN PVOID Object, + IN PSECURITY_INFORMATION SecurityInformation, + OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + IN OUT PULONG Length, + IN PSECURITY_DESCRIPTOR *OutputSecurityDescriptor +); + +NTSTATUS +NTAPI +ObSetSecurityDescriptorInfo( + IN PVOID Object, + IN PSECURITY_INFORMATION SecurityInformation, + IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + IN OUT PSECURITY_DESCRIPTOR *OutputSecurityDescriptor, + IN POOL_TYPE PoolType, + IN PGENERIC_MAPPING GenericMapping +); + // // Executive Fast Referencing Functions // diff --git a/reactos/ntoskrnl/ob/obsecure.c b/reactos/ntoskrnl/ob/obsecure.c index 41a9eea7d02..5f635778f96 100644 --- a/reactos/ntoskrnl/ob/obsecure.c +++ b/reactos/ntoskrnl/ob/obsecure.c @@ -15,6 +15,157 @@ /* PRIVATE FUNCTIONS *********************************************************/ +NTSTATUS +NTAPI +ObAssignObjectSecurityDescriptor(IN PVOID Object, + IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL, + IN POOL_TYPE PoolType) +{ + POBJECT_HEADER ObjectHeader; + NTSTATUS Status; + PSECURITY_DESCRIPTOR NewSd; + PAGED_CODE(); + + /* Get the object header */ + ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); + if (!SecurityDescriptor) + { + /* Nothing to assign */ + ObjectHeader->SecurityDescriptor = NULL; + return STATUS_SUCCESS; + } + + /* Add it to our internal cache */ + Status = ObpAddSecurityDescriptor(SecurityDescriptor, &NewSd); + if (NT_SUCCESS(Status)) + { + /* Free the old copy */ + ExFreePool(SecurityDescriptor); + + /* Set the new pointer */ + ASSERT(NewSd); + ObjectHeader->SecurityDescriptor = NewSd; + } + + /* Return status */ + return Status; +} + +NTSTATUS +NTAPI +ObDeassignSecurity(IN OUT PSECURITY_DESCRIPTOR *SecurityDescriptor) +{ + /* Dereference it */ + ObpDereferenceCachedSecurityDescriptor(*SecurityDescriptor); + + /* Don't free again later */ + *SecurityDescriptor = NULL; + + /* All done */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +ObQuerySecurityDescriptorInfo(IN PVOID Object, + IN PSECURITY_INFORMATION SecurityInformation, + OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + IN OUT PULONG Length, + IN PSECURITY_DESCRIPTOR *OutputSecurityDescriptor) +{ + POBJECT_HEADER ObjectHeader; + NTSTATUS Status; + PSECURITY_DESCRIPTOR ObjectSd; + PAGED_CODE(); + + /* Get the object header */ + ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); + + /* Get the SD */ + ObjectSd = ObpReferenceCachedSecurityDescriptor(ObjectHeader->SecurityDescriptor); + + /* Query the information */ + Status = SeQuerySecurityDescriptorInfo(SecurityInformation, + SecurityDescriptor, + Length, + &ObjectSd); + + /* Check if we have an object SD and dereference it, if so */ + if (ObjectSd) ObpDereferenceCachedSecurityDescriptor(ObjectSd); + + /* Return status */ + return Status; +} + +NTSTATUS +NTAPI +ObSetSecurityDescriptorInfo(IN PVOID Object, + IN PSECURITY_INFORMATION SecurityInformation, + IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + IN OUT PSECURITY_DESCRIPTOR *OutputSecurityDescriptor, + IN POOL_TYPE PoolType, + IN PGENERIC_MAPPING GenericMapping) +{ + NTSTATUS Status; + POBJECT_HEADER ObjectHeader; + PSECURITY_DESCRIPTOR OldDescriptor, NewDescriptor, CachedDescriptor; + PAGED_CODE(); + + /* Get the object header */ + ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); + while (TRUE) + { + /* Reference the old descriptor */ + OldDescriptor = ObpReferenceCachedSecurityDescriptor(ObjectHeader->SecurityDescriptor); + NewDescriptor = OldDescriptor; + + /* Set the SD information */ + Status = SeSetSecurityDescriptorInfo(Object, + SecurityInformation, + SecurityDescriptor, + &NewDescriptor, + PoolType, + GenericMapping); + if (NT_SUCCESS(Status)) + { + /* Now add this to the cache */ + Status = ObpAddSecurityDescriptor(NewDescriptor, &CachedDescriptor); + + /* Let go of our uncached copy */ + ExFreePool(NewDescriptor); + + /* Check for success */ + if (NT_SUCCESS(Status)) + { + /* Dereference the old one */ + ASSERT(OldDescriptor == ObjectHeader->SecurityDescriptor); + + /* Now set this as the new descriptor */ + ObjectHeader->SecurityDescriptor = CachedDescriptor; + + /* And dereference the old one */ + ObpDereferenceCachedSecurityDescriptor(OldDescriptor); + break; + } + else + { + /* We failed, dereference the old one */ + ObpDereferenceCachedSecurityDescriptor(OldDescriptor); + break; + } + } + else + { + /* We failed, dereference the old one */ + if (OldDescriptor) ObpDereferenceCachedSecurityDescriptor(OldDescriptor); + break; + } + } + + /* Return status */ + return Status; +} + BOOLEAN NTAPI ObCheckCreateObjectAccess(IN PVOID Object, diff --git a/reactos/ntoskrnl/se/sd.c b/reactos/ntoskrnl/se/sd.c index 4389d689ccc..31d2a6a4847 100644 --- a/reactos/ntoskrnl/se/sd.c +++ b/reactos/ntoskrnl/se/sd.c @@ -882,18 +882,190 @@ SeReleaseSecurityDescriptor( } /* - * @unimplemented + * @implemented */ NTSTATUS STDCALL SeSetSecurityDescriptorInfo(IN PVOID Object OPTIONAL, - IN PSECURITY_INFORMATION SecurityInformation, - IN PSECURITY_DESCRIPTOR SecurityDescriptor, - IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor, - IN POOL_TYPE PoolType, - IN PGENERIC_MAPPING GenericMapping) + IN PSECURITY_INFORMATION _SecurityInformation, + IN PSECURITY_DESCRIPTOR _SecurityDescriptor, + IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor, + IN POOL_TYPE PoolType, + IN PGENERIC_MAPPING GenericMapping) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + PISECURITY_DESCRIPTOR ObjectSd; + PISECURITY_DESCRIPTOR NewSd; + PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor; + PSID Owner = 0; + PSID Group = 0; + PACL Dacl = 0; + PACL Sacl = 0; + ULONG OwnerLength = 0; + ULONG GroupLength = 0; + ULONG DaclLength = 0; + ULONG SaclLength = 0; + ULONG Control = 0; + ULONG_PTR Current; + SECURITY_INFORMATION SecurityInformation; + + + ObjectSd = *ObjectsSecurityDescriptor; + SecurityInformation = *_SecurityInformation; + + /* Get owner and owner size */ + if (SecurityInformation & OWNER_SECURITY_INFORMATION) + { + if (SecurityDescriptor->Owner != NULL) + { + if( SecurityDescriptor->Control & SE_SELF_RELATIVE ) + Owner = (PSID)((ULONG_PTR)SecurityDescriptor->Owner + + (ULONG_PTR)SecurityDescriptor); + else + Owner = (PSID)SecurityDescriptor->Owner; + OwnerLength = ROUND_UP(RtlLengthSid(Owner), 4); + } + Control |= (SecurityDescriptor->Control & SE_OWNER_DEFAULTED); + } + else + { + if (ObjectSd->Owner != NULL) + { + Owner = (PSID)((ULONG_PTR)ObjectSd->Owner + (ULONG_PTR)ObjectSd); + OwnerLength = ROUND_UP(RtlLengthSid(Owner), 4); + } + Control |= (ObjectSd->Control & SE_OWNER_DEFAULTED); + } + + /* Get group and group size */ + if (SecurityInformation & GROUP_SECURITY_INFORMATION) + { + if (SecurityDescriptor->Group != NULL) + { + if( SecurityDescriptor->Control & SE_SELF_RELATIVE ) + Group = (PSID)((ULONG_PTR)SecurityDescriptor->Group + + (ULONG_PTR)SecurityDescriptor); + else + Group = (PSID)SecurityDescriptor->Group; + GroupLength = ROUND_UP(RtlLengthSid(Group), 4); + } + Control |= (SecurityDescriptor->Control & SE_GROUP_DEFAULTED); + } + else + { + if (ObjectSd->Group != NULL) + { + Group = (PSID)((ULONG_PTR)ObjectSd->Group + (ULONG_PTR)ObjectSd); + GroupLength = ROUND_UP(RtlLengthSid(Group), 4); + } + Control |= (ObjectSd->Control & SE_GROUP_DEFAULTED); + } + + /* Get DACL and DACL size */ + if (SecurityInformation & DACL_SECURITY_INFORMATION) + { + if ((SecurityDescriptor->Control & SE_DACL_PRESENT) && + (SecurityDescriptor->Dacl != NULL)) + { + if( SecurityDescriptor->Control & SE_SELF_RELATIVE ) + Dacl = (PACL)((ULONG_PTR)SecurityDescriptor->Dacl + + (ULONG_PTR)SecurityDescriptor); + else + Dacl = (PACL)SecurityDescriptor->Dacl; + + DaclLength = ROUND_UP((ULONG)Dacl->AclSize, 4); + } + Control |= (SecurityDescriptor->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT)); + } + else + { + if ((ObjectSd->Control & SE_DACL_PRESENT) && + (ObjectSd->Dacl != NULL)) + { + Dacl = (PACL)((ULONG_PTR)ObjectSd->Dacl + (ULONG_PTR)ObjectSd); + DaclLength = ROUND_UP((ULONG)Dacl->AclSize, 4); + } + Control |= (ObjectSd->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT)); + } + + /* Get SACL and SACL size */ + if (SecurityInformation & SACL_SECURITY_INFORMATION) + { + if ((SecurityDescriptor->Control & SE_SACL_PRESENT) && + (SecurityDescriptor->Sacl != NULL)) + { + if( SecurityDescriptor->Control & SE_SELF_RELATIVE ) + Sacl = (PACL)((ULONG_PTR)SecurityDescriptor->Sacl + + (ULONG_PTR)SecurityDescriptor); + else + Sacl = (PACL)SecurityDescriptor->Sacl; + SaclLength = ROUND_UP((ULONG)Sacl->AclSize, 4); + } + Control |= (SecurityDescriptor->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT)); + } + else + { + if ((ObjectSd->Control & SE_SACL_PRESENT) && + (ObjectSd->Sacl != NULL)) + { + Sacl = (PACL)((ULONG_PTR)ObjectSd->Sacl + (ULONG_PTR)ObjectSd); + SaclLength = ROUND_UP((ULONG)Sacl->AclSize, 4); + } + Control |= (ObjectSd->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT)); + } + + NewSd = ExAllocatePool(NonPagedPool, + sizeof(SECURITY_DESCRIPTOR) + OwnerLength + GroupLength + + DaclLength + SaclLength); + if (NewSd == NULL) + { + ObDereferenceObject(Object); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCreateSecurityDescriptor(NewSd, + SECURITY_DESCRIPTOR_REVISION1); + /* We always build a self-relative descriptor */ + NewSd->Control = (USHORT)Control | SE_SELF_RELATIVE; + + Current = (ULONG_PTR)NewSd + sizeof(SECURITY_DESCRIPTOR); + + if (OwnerLength != 0) + { + RtlCopyMemory((PVOID)Current, + Owner, + OwnerLength); + NewSd->Owner = (PSID)(Current - (ULONG_PTR)NewSd); + Current += OwnerLength; + } + + if (GroupLength != 0) + { + RtlCopyMemory((PVOID)Current, + Group, + GroupLength); + NewSd->Group = (PSID)(Current - (ULONG_PTR)NewSd); + Current += GroupLength; + } + + if (DaclLength != 0) + { + RtlCopyMemory((PVOID)Current, + Dacl, + DaclLength); + NewSd->Dacl = (PACL)(Current - (ULONG_PTR)NewSd); + Current += DaclLength; + } + + if (SaclLength != 0) + { + RtlCopyMemory((PVOID)Current, + Sacl, + SaclLength); + NewSd->Sacl = (PACL)(Current - (ULONG_PTR)NewSd); + Current += SaclLength; + } + + *ObjectsSecurityDescriptor = NewSd; + return STATUS_SUCCESS; } /* diff --git a/reactos/ntoskrnl/se/semgr.c b/reactos/ntoskrnl/se/semgr.c index 68e1a7e68d5..137851d9692 100644 --- a/reactos/ntoskrnl/se/semgr.c +++ b/reactos/ntoskrnl/se/semgr.c @@ -233,222 +233,63 @@ VOID SepDeReferenceLogonSession(PLUID AuthenticationId) } NTSTATUS -STDCALL -SeDefaultObjectMethod(PVOID Object, - SECURITY_OPERATION_CODE OperationType, - PSECURITY_INFORMATION _SecurityInformation, - PSECURITY_DESCRIPTOR _SecurityDescriptor, - PULONG ReturnLength, - PSECURITY_DESCRIPTOR *OldSecurityDescriptor, - POOL_TYPE PoolType, - PGENERIC_MAPPING GenericMapping) +NTAPI +SeDefaultObjectMethod(IN PVOID Object, + IN SECURITY_OPERATION_CODE OperationType, + IN PSECURITY_INFORMATION SecurityInformation, + IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + IN OUT PULONG ReturnLength OPTIONAL, + IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor, + IN POOL_TYPE PoolType, + IN PGENERIC_MAPPING GenericMapping) { - PISECURITY_DESCRIPTOR ObjectSd; - PISECURITY_DESCRIPTOR NewSd; - PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor; - POBJECT_HEADER Header = OBJECT_TO_OBJECT_HEADER(Object); - PSID Owner = 0; - PSID Group = 0; - PACL Dacl = 0; - PACL Sacl = 0; - ULONG OwnerLength = 0; - ULONG GroupLength = 0; - ULONG DaclLength = 0; - ULONG SaclLength = 0; - ULONG Control = 0; - ULONG_PTR Current; - NTSTATUS Status; - SECURITY_INFORMATION SecurityInformation; + PAGED_CODE(); - if (OperationType == SetSecurityDescriptor) - { - ObjectSd = Header->SecurityDescriptor; - SecurityInformation = *_SecurityInformation; + /* Select the operation type */ + switch (OperationType) + { + /* Setting a new descriptor */ + case SetSecurityDescriptor: - /* Get owner and owner size */ - if (SecurityInformation & OWNER_SECURITY_INFORMATION) - { - if (SecurityDescriptor->Owner != NULL) - { - if( SecurityDescriptor->Control & SE_SELF_RELATIVE ) - Owner = (PSID)((ULONG_PTR)SecurityDescriptor->Owner + - (ULONG_PTR)SecurityDescriptor); - else - Owner = (PSID)SecurityDescriptor->Owner; - OwnerLength = ROUND_UP(RtlLengthSid(Owner), 4); - } - Control |= (SecurityDescriptor->Control & SE_OWNER_DEFAULTED); - } - else - { - if (ObjectSd->Owner != NULL) - { - Owner = (PSID)((ULONG_PTR)ObjectSd->Owner + (ULONG_PTR)ObjectSd); - OwnerLength = ROUND_UP(RtlLengthSid(Owner), 4); - } - Control |= (ObjectSd->Control & SE_OWNER_DEFAULTED); - } + /* Sanity check */ + ASSERT((PoolType == PagedPool) || (PoolType == NonPagedPool)); - /* Get group and group size */ - if (SecurityInformation & GROUP_SECURITY_INFORMATION) - { - if (SecurityDescriptor->Group != NULL) - { - if( SecurityDescriptor->Control & SE_SELF_RELATIVE ) - Group = (PSID)((ULONG_PTR)SecurityDescriptor->Group + - (ULONG_PTR)SecurityDescriptor); - else - Group = (PSID)SecurityDescriptor->Group; - GroupLength = ROUND_UP(RtlLengthSid(Group), 4); - } - Control |= (SecurityDescriptor->Control & SE_GROUP_DEFAULTED); - } - else - { - if (ObjectSd->Group != NULL) - { - Group = (PSID)((ULONG_PTR)ObjectSd->Group + (ULONG_PTR)ObjectSd); - GroupLength = ROUND_UP(RtlLengthSid(Group), 4); - } - Control |= (ObjectSd->Control & SE_GROUP_DEFAULTED); - } - - /* Get DACL and DACL size */ - if (SecurityInformation & DACL_SECURITY_INFORMATION) - { - if ((SecurityDescriptor->Control & SE_DACL_PRESENT) && - (SecurityDescriptor->Dacl != NULL)) - { - if( SecurityDescriptor->Control & SE_SELF_RELATIVE ) - Dacl = (PACL)((ULONG_PTR)SecurityDescriptor->Dacl + - (ULONG_PTR)SecurityDescriptor); - else - Dacl = (PACL)SecurityDescriptor->Dacl; - - DaclLength = ROUND_UP((ULONG)Dacl->AclSize, 4); - } - Control |= (SecurityDescriptor->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT)); - } - else - { - if ((ObjectSd->Control & SE_DACL_PRESENT) && - (ObjectSd->Dacl != NULL)) - { - Dacl = (PACL)((ULONG_PTR)ObjectSd->Dacl + (ULONG_PTR)ObjectSd); - DaclLength = ROUND_UP((ULONG)Dacl->AclSize, 4); - } - Control |= (ObjectSd->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT)); - } - - /* Get SACL and SACL size */ - if (SecurityInformation & SACL_SECURITY_INFORMATION) - { - if ((SecurityDescriptor->Control & SE_SACL_PRESENT) && - (SecurityDescriptor->Sacl != NULL)) - { - if( SecurityDescriptor->Control & SE_SELF_RELATIVE ) - Sacl = (PACL)((ULONG_PTR)SecurityDescriptor->Sacl + - (ULONG_PTR)SecurityDescriptor); - else - Sacl = (PACL)SecurityDescriptor->Sacl; - SaclLength = ROUND_UP((ULONG)Sacl->AclSize, 4); - } - Control |= (SecurityDescriptor->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT)); - } - else - { - if ((ObjectSd->Control & SE_SACL_PRESENT) && - (ObjectSd->Sacl != NULL)) - { - Sacl = (PACL)((ULONG_PTR)ObjectSd->Sacl + (ULONG_PTR)ObjectSd); - SaclLength = ROUND_UP((ULONG)Sacl->AclSize, 4); - } - Control |= (ObjectSd->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT)); - } - - NewSd = ExAllocatePool(NonPagedPool, - sizeof(SECURITY_DESCRIPTOR) + OwnerLength + GroupLength + - DaclLength + SaclLength); - if (NewSd == NULL) - { - ObDereferenceObject(Object); - return STATUS_INSUFFICIENT_RESOURCES; - } - - RtlCreateSecurityDescriptor(NewSd, - SECURITY_DESCRIPTOR_REVISION1); - /* We always build a self-relative descriptor */ - NewSd->Control = (USHORT)Control | SE_SELF_RELATIVE; - - Current = (ULONG_PTR)NewSd + sizeof(SECURITY_DESCRIPTOR); - - if (OwnerLength != 0) - { - RtlCopyMemory((PVOID)Current, - Owner, - OwnerLength); - NewSd->Owner = (PSID)(Current - (ULONG_PTR)NewSd); - Current += OwnerLength; - } - - if (GroupLength != 0) - { - RtlCopyMemory((PVOID)Current, - Group, - GroupLength); - NewSd->Group = (PSID)(Current - (ULONG_PTR)NewSd); - Current += GroupLength; - } - - if (DaclLength != 0) - { - RtlCopyMemory((PVOID)Current, - Dacl, - DaclLength); - NewSd->Dacl = (PACL)(Current - (ULONG_PTR)NewSd); - Current += DaclLength; - } - - if (SaclLength != 0) - { - RtlCopyMemory((PVOID)Current, - Sacl, - SaclLength); - NewSd->Sacl = (PACL)(Current - (ULONG_PTR)NewSd); - Current += SaclLength; - } - - /* Add the new SD */ - Status = ObpAddSecurityDescriptor(NewSd, - &Header->SecurityDescriptor); - if (NT_SUCCESS(Status)) - { - /* Remove the old security descriptor */ - ObpRemoveSecurityDescriptor(ObjectSd); - } - else - { - /* Restore the old security descriptor */ - Header->SecurityDescriptor = ObjectSd; - } - - ExFreePool(NewSd); - } - else if (OperationType == QuerySecurityDescriptor) - { - Status = SeQuerySecurityDescriptorInfo(_SecurityInformation, + /* Set the information */ + return ObSetSecurityDescriptorInfo(Object, + SecurityInformation, SecurityDescriptor, - ReturnLength, - &Header->SecurityDescriptor); - } - else if (OperationType == AssignSecurityDescriptor) - { - /* Assign the security descriptor to the object header */ - Status = ObpAddSecurityDescriptor(SecurityDescriptor, - &Header->SecurityDescriptor); + OldSecurityDescriptor, + PoolType, + GenericMapping); + + case QuerySecurityDescriptor: + + /* Query the information */ + return ObQuerySecurityDescriptorInfo(Object, + SecurityInformation, + SecurityDescriptor, + ReturnLength, + OldSecurityDescriptor); + + case DeleteSecurityDescriptor: + + /* De-assign it */ + return ObDeassignSecurity(OldSecurityDescriptor); + + case AssignSecurityDescriptor: + + /* Assign it */ + ObAssignObjectSecurityDescriptor(Object, SecurityDescriptor, PoolType); + return STATUS_SUCCESS; + + default: + + /* Bug check */ + KeBugCheckEx(SECURITY_SYSTEM, 0, STATUS_INVALID_PARAMETER, 0, 0); } - + /* Should never reach here */ + ASSERT(FALSE); return STATUS_SUCCESS; }