From de42bdce8ff329998ad4eef467503ea3a4fafd89 Mon Sep 17 00:00:00 2001
From: Valera V Harseko <vharseko@3a-systems.ru>
Date: Wed, 21 Oct 2026 08:54:06 +0000
Subject: [PATCH] GHSA-6f6q-q9gw-4jr4 Sort and VLV controls let authenticated users learn password hashes and other attributes hidden by access control
---
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VLVIndex.java | 45 +++++++++++++++++++++++++++++++++++----------
1 files changed, 35 insertions(+), 10 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VLVIndex.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VLVIndex.java
index 223e4c0..dc2bd46 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VLVIndex.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VLVIndex.java
@@ -31,6 +31,7 @@
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.Set;
import java.util.TreeSet;
import org.forgerock.i18n.LocalizableMessage;
@@ -588,15 +589,22 @@
return i.hasNext() ? i.next() : null;
}
+ /** Indicates whether this index holds the entries of the provided search, ordered by its sort keys. */
+ boolean isApplicable(final SearchOperation searchOperation, final ServerSideSortRequestControl sortControl)
+ throws DirectoryException
+ {
+ return trusted
+ && searchOperation.getBaseDN().equals(baseDN)
+ && searchOperation.getScope().equals(scope)
+ && searchOperation.getFilter().equals(filter)
+ && sortControl.getSortKeys().equals(sortKeys);
+ }
+
EntryIDSet evaluate(final ReadableTransaction txn, final SearchOperation searchOperation,
final ServerSideSortRequestControl sortControl, final VLVRequestControl vlvRequest,
final StringBuilder debugBuilder) throws DirectoryException, StorageRuntimeException
{
- if (!trusted ||
- !searchOperation.getBaseDN().equals(baseDN) ||
- !searchOperation.getScope().equals(scope) ||
- !searchOperation.getFilter().equals(filter) ||
- !sortControl.getSortKeys().equals(sortKeys))
+ if (!isApplicable(searchOperation, sortControl))
{
return null;
}
@@ -638,7 +646,7 @@
}
/** Returns the total number of entries (a.k.a records, a.k.a keys) indexed by this VLV index. */
- private int getEntryCount(final ReadableTransaction txn)
+ int getEntryCount(final ReadableTransaction txn)
{
return (int) counter.getCount(txn, COUNT_KEY);
}
@@ -899,17 +907,28 @@
static ByteString encodeVLVKey(final List<SortKey> sortKeys, final Entry entry, final long entryID)
{
+ return encodeVLVKey(sortKeys, entry, entryID, Collections.<AttributeType> emptySet());
+ }
+
+ /**
+ * Encodes the VLV key of an entry, leaving out the values of the attribute types in {@code unreadableTypes}, as
+ * if the entry did not have them.
+ */
+ static ByteString encodeVLVKey(final List<SortKey> sortKeys, final Entry entry, final long entryID,
+ final Set<AttributeType> unreadableTypes)
+ {
final ByteStringBuilder builder = new ByteStringBuilder();
- encodeVLVKey0(sortKeys, entry, builder);
+ encodeVLVKey0(sortKeys, entry, unreadableTypes, builder);
builder.appendLong(entryID);
return builder.toByteString();
}
- private static void encodeVLVKey0(final List<SortKey> sortKeys, final Entry entry, final ByteStringBuilder builder)
+ private static void encodeVLVKey0(final List<SortKey> sortKeys, final Entry entry,
+ final Set<AttributeType> unreadableTypes, final ByteStringBuilder builder)
{
for (final SortKey sortKey : sortKeys)
{
- ByteString sortValue = getLowestAttributeValue(entry, sortKey);
+ ByteString sortValue = getLowestAttributeValue(entry, sortKey, unreadableTypes);
encodeVLVKeyValue(sortValue, builder, sortKey.isReverseOrder());
}
}
@@ -918,13 +937,19 @@
* The RFC states that the lowest value of a multi-valued attribute should be used,
* regardless of the sort order.
*/
- private static ByteString getLowestAttributeValue(final Entry entry, final SortKey sortKey)
+ private static ByteString getLowestAttributeValue(final Entry entry, final SortKey sortKey,
+ final Set<AttributeType> unreadableTypes)
{
final AttributeDescription attrDesc = AttributeDescription.valueOf(sortKey.getAttributeDescription());
final MatchingRule matchingRule = getEffectiveOrderingRule(sortKey);
ByteString sortValue = null;
+ // The values may come from subtypes of the sort attribute, each of which may be unreadable on its own.
for (Attribute a : entry.getAllAttributes(attrDesc.getAttributeType()))
{
+ if (unreadableTypes.contains(a.getAttributeDescription().getAttributeType()))
+ {
+ continue;
+ }
for (ByteString v : a)
{
try
--
Gitblit v1.10.0