skip to content

In an LDAP search filter, why does (!(ou=Cardiology)) return directory entries that carry no ou attribute at all?

level: middleimportance: should knowfreq 34%

answer

  1. three outcomes, not two
  2. an entry is returned only on TRUE
  3. missing value is FALSE, not Undefined
  4. negating FALSE returns the absent case
  5. Undefined means an unrecognised attribute description

basics

~20 s

An equality item evaluates to FALSE when a directory entry holds no matching value, including when it holds no such attribute at all. Negation turns FALSE into TRUE, so entries missing the attribute match and are returned.

solid answer

~40 s

An LDAP filter item evaluates to one of three outcomes against each candidate entry - TRUE, FALSE or Undefined - and the server returns the entry only when the whole filter evaluates to TRUE. An equality item such as `(ou=Cardiology)` is FALSE for an entry that holds no matching `ou` value, and "holds no matching value" includes "holds no `ou` attribute". The `!` inverts that FALSE into TRUE, so entries without the attribute are exactly the ones people are surprised to see. Undefined is a different case: it arises when the server does not recognise the attribute description asserted, and `!` of Undefined is still Undefined, so the entry is not returned. If you mean "has an `ou`, but not Cardiology", conjoin a presence item: `(&(ou=*)(!(ou=Cardiology)))`.

code

ldif · 18 lines
ldif
dn: cn=Ada Okonkwo,ou=Cardiology,ou=Riverside,dc=example,dc=org
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
cn: Ada Okonkwo
sn: Okonkwo
ou: Cardiology
telephoneNumber: +44 20 7946 0101

dn: cn=Tom Reyes,ou=Riverside,dc=example,dc=org
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
cn: Tom Reyes
sn: Reyes
telephoneNumber: +44 20 7946 0102

go deeper

for a junior

Recall that an entry comes back only when the filter is TRUE for it, and that an entry holding no such attribute makes an equality item FALSE rather than an error.

for a middle

Explain the three-outcome evaluation and how each combiner propagates it, and repair a negated filter with a presence item conjoined in front of it.

for a senior

Diagnose the empty-answer case: an unrecognised attribute description makes the whole filter Undefined and the search still reports success, so check descriptions before values.

for a principal

Treat filter semantics as a contract between the directory's schema and every consumer of it: a renamed attribute turns working negations into silent empty answers estate-wide.

## Three outcomes, not two The intuition that trips people is that an LDAP search filter is a boolean expression. It is nearly one. Each filter item evaluates against a candidate entry to **TRUE**, **FALSE** or **Undefined**, and the entry is returned only when the complete filter evaluates to TRUE. Undefined exists because a directory server sometimes cannot decide an assertion at all - not "it does not hold", but "this is not a question I can answer about this entry". | Combiner | TRUE when | FALSE when | Undefined otherwise | |---|---|---|---| | `&` | every contained filter is TRUE | at least one is FALSE | yes | | `\|` | at least one contained filter is TRUE | every one is FALSE | yes | | `!` | the contained filter is FALSE | the contained filter is TRUE | yes | Notice the shape of the `!` row. It has no special handling for a missing attribute, because a missing attribute never produces Undefined in the first place. ## Why a missing attribute is FALSE and not Undefined An equality item asks: does this entry hold a value of this attribute that matches the asserted value under the attribute's matching rule? For an entry with no `ou` at all, the server can answer that perfectly well - it holds no such value, so the answer is **no**, and the item is FALSE. Undefined is reserved for the cases where the server cannot form the question: the attribute description asserted is not one it recognises, or the attribute type defines no matching rule appropriate to the assertion. So `(!(ou=Cardiology))` reads, in full: *return every candidate entry for which the assertion "holds an ou value equal to Cardiology" is FALSE*. Entries in another organizational unit satisfy that. So do entries with no `ou` attribute whatsoever - a clinician entry whose RDN is a `cn` and which simply never had one set. ## The DN is not the attribute A second surprise hides underneath the first. In a teaching hospital directory where one naming context covers three sites, a clinician entry might be named `cn=Tom Reyes,ou=Riverside,dc=example,dc=org`. The string `ou=Riverside` appears in that DN - but it is the **parent entry's** naming attribute, not an attribute of Tom's entry. A filter is evaluated against the attributes an entry actually holds, so unless the entry carries its own `ou` value, an `ou` assertion sees nothing. ## Multi-valued attributes flip it the other way LDAP attributes are multi-valued by default, and an equality item is TRUE for an entry if **any** of that attribute's values matches. A consultant listed under two organizational units, `Cardiology` and `Research`, makes `(ou=Cardiology)` TRUE, and `!` therefore excludes that entry entirely. Negation over a multi-valued attribute is "none of the values matches", which is usually what you want and rarely what people say out loud. ## Writing what you meant 1. **"Has an ou, and it is not Cardiology."** `(&(ou=*)(!(ou=Cardiology)))` - the presence item forces the attribute to exist, and the negated equality item removes the excluded value. 2. **"Is not in Cardiology, and I do not care whether ou is set."** `(!(ou=Cardiology))` on its own is correct, and the entries without `ou` are intended. 3. **"Has no ou at all."** `(!(ou=*))` - negating the presence item, which is FALSE for an entry that has the attribute and TRUE for one that does not. ## The failure mode Undefined actually causes Because Undefined propagates outward through `&`, `|` and `!` alike, a single unrecognised attribute description can make a whole filter Undefined for every candidate entry. The search then completes normally and returns **zero entries** - not an error, not a warning, just an empty answer that looks exactly like "nobody matched". A negated filter makes this harder to spot, because the intuitive expectation for a negation over something unknown is "everything matches", and the specification gives the opposite. Whenever a filter that should match plenty of entries returns none, the attribute descriptions in it are worth checking against the server's schema before the values are.

  • How do you write an LDAP search filter that excludes Cardiology but still requires the entry to carry an ou attribute?
    Conjoin a presence item with the negated equality item: `(&(ou=*)(!(ou=Cardiology)))`. The presence item is TRUE only for entries that hold an `ou` value, so entries with the attribute absent are removed by the `&` before the negation can let them back in. This is the standard repair for every "not X" filter whose author meant "has one, and it is not X".
  • What happens to a search when the filter asserts an attribute description the server does not recognise?
    That item evaluates to **Undefined** for every candidate entry. Undefined propagates through `&`, `|` and `!`, so the whole filter is typically Undefined, no entry evaluates to TRUE, and the search completes with an empty answer rather than an error. A filter that should match many entries and returns none is the classic symptom of a mistyped or unschema'd attribute description.
  • Does a multi-valued attribute change what (!(ou=Cardiology)) matches?
    Yes, and in the stricter direction. An equality item is TRUE for an entry if **any** value of the attribute matches, so a clinician carrying both `ou: Cardiology` and `ou: Research` makes the inner item TRUE, and the negation excludes that entry completely. Negation over a multi-valued attribute means "none of the values matches", not "some value does not match".

saying these in an interview costs you the question

  • Thinks a missing attribute makes an equality item Undefined
  • Reads the filter as 'has an ou, and it is not Cardiology'
  • Assumes a filter is evaluated against components of the entry's DN
  • Believes an entry is returned unless the filter evaluates FALSE
  • Thinks negating an unrecognised attribute description matches everything
  • Expects negation to mean 'some value differs' on a multi-valued attribute