UnboundID LDAP SDK for Java

Ping Identity
Product Information

LDAPv3 Wire Protocol Reference

The LDAP Search Operation

The LDAP search operation is used to retrieve all entries that match a given set of criteria (at least all entries that the requester has permission to see). It’s the only core LDAPv3 operation type that can have multiple response messages (although it is possible for an extended request or a request control to cause one or more intermediate response messages to be returned, but that’s pretty rare). The types of search response messages are:

The Search Request

RFC 4511 section 4.5.1 defines the search request protocol operation as follows:

SearchRequest ::= [APPLICATION 3] SEQUENCE {
     baseObject      LDAPDN,
     scope           ENUMERATED {
          baseObject              (0),
          singleLevel             (1),
          wholeSubtree            (2),
          ...  },
     derefAliases    ENUMERATED {
          neverDerefAliases       (0),
          derefInSearching        (1),
          derefFindingBaseObj     (2),
          derefAlways             (3) },
     sizeLimit       INTEGER (0 ..  maxInt),
     timeLimit       INTEGER (0 ..  maxInt),
     typesOnly       BOOLEAN,
     filter          Filter,
     attributes      AttributeSelection }

AttributeSelection ::= SEQUENCE OF selector LDAPString
                -- The LDAPString is constrained to
                -- <attributeSelector> in Section 4.5.1.8

Filter ::= CHOICE {
     and             [0] SET SIZE (1..MAX) OF filter Filter,
     or              [1] SET SIZE (1..MAX) OF filter Filter,
     not             [2] Filter,
     equalityMatch   [3] AttributeValueAssertion,
     substrings      [4] SubstringFilter,
     greaterOrEqual  [5] AttributeValueAssertion,
     lessOrEqual     [6] AttributeValueAssertion,
     present         [7] AttributeDescription,
     approxMatch     [8] AttributeValueAssertion,
     extensibleMatch [9] MatchingRuleAssertion,
     ...  }

SubstringFilter ::= SEQUENCE {
     type           AttributeDescription,
     substrings     SEQUENCE SIZE (1..MAX) OF substring CHOICE {
          initial [0] AssertionValue,  -- can occur at most once
          any     [1] AssertionValue,
          final   [2] AssertionValue } -- can occur at most once
     }

MatchingRuleAssertion ::= SEQUENCE {
     matchingRule    [1] MatchingRuleId OPTIONAL,
     type            [2] AttributeDescription OPTIONAL,
     matchValue      [3] AssertionValue,
     dnAttributes    [4] BOOLEAN DEFAULT FALSE }

And the dependencies are defined elsewhere in RFC 4511 as:

LDAPDN ::= LDAPString
           -- Constrained to <distinguishedName> [RFC4514]

LDAPString ::= OCTET STRING -- UTF-8 encoded,
                            -- [ISO10646] characters

AttributeValueAssertion ::= SEQUENCE {
     attributeDesc   AttributeDescription,
     assertionValue  AssertionValue }

AttributeDescription ::= LDAPString
                        -- Constrained to <attributedescription>
                        -- [RFC4512]

AssertionValue ::= OCTET STRING

MatchingRuleId ::= LDAPString

So the search request protocol op is a sequence with BER type 0x63 (application class, constructed, tag number three). The elements of this sequence are rather involved, so we’ll look at each of them in detail below.

The baseObject Request Element

This element is an octet string that specifies the DN of the base entry for the search request. Only this entry and its subordinates may be returned, with the scope request element further restricting the set of entries that may be considered.

A search request may only have a single search base DN. If you wish to search below multiple base DNs, you will need to use separate searches. However, some servers allow you to specify an empty DN as the search base, treating it as superior to all other entries within the server.

The scope Request Element

This element specifies the set of entries, relative to the entry specified as the baseObject, that may be returned. It is an enumerated element, with the following possible values:

The scope enumerated element is also defined with the “...” specifier to indicate that additional scope values may be defined. And the draft-sermersheim-ldap-subordinate-scope draft does propose such an additional scope value:

There is also no standard way to exclude portions of the DIT from the search scope. Some servers may provide some way to accomplish this (for example, the Ping Identity Directory Server offers an exclude branch request control that can be used for this purpose), but, again, the best way to achieve this in the general case is to simply use the smallest scope that includes all of the entries you might want, and ignore any search result entries in a portion of the DIT that you don’t care about.

The derefAliases Request Element

This element specifies how the server should treat alias entries that it may encounter during processing. Alias entries are described in RFC 4512 section 2.6, but they’re kind of like the LDAP equivalent of a UNIX symbolic link in that they can make it look like an entry exists in more than one location in the DIT. An alias entry has an object class of alias, and the aliasedObjectName attribute specifies the DN of the entry to which it refers.

The act of following an alias to the entry that it references is called dereferencing that alias. The derefAliases element is an enumerated element with the following possible values:

Alias entries can only be leaf entries, so it is not possible to have any kind of entry below an alias entry. However, an alias entry can reference either a leaf entry or a non-leaf entry, and it is possible to add subordinate entries below an entry referenced by one or more alias entries. It is also possible for an alias entry to reference another alias entry, so the act of dereferencing an alias may require multiple hops to reach the final entry. Further, servers that support aliases must also be able to detect circular references between alias entries.

Aliases will only be dereferenced when processing search requests, and only in accordance with the derefAliases element. Any other operation that targets an alias entry will operate on that entry directly rather than on the entry that it references.

Aliases are an optional element of the LDAPv3 specification, and not all LDAP servers support them.

The sizeLimit Request Element

This element specifies the maximum number of entries that should be returned in response to the search request. It is an integer element, and its value must be greater than or equal to zero. A value of zero indicates that no size limit is requested, and a value greater than zero will be treated as the requested maximum size limit.

Note that directory servers often impose their own size limit for client requests. There may be a global limit in effect for all users, and it may be possible to define a custom size limit for individual users or for subsets of clients (e.g., based on the address of the client, the type of authentication the client performed, whether the client connection is secure, the set of groups in which the client is a member, etc.). In such cases, the server will generally use the smaller of its own size limit and the one included in the search request.

In the event that the search request criteria matches more entries than allowed by the enforced size limit, the server will return a search result done message with a result code of sizeLimitExceeded (4). It may optionally return a portion of the search result entries before sending that search result done message, but should never return more than the maximum allowed number of entries.

The timeLimit Request Element

This element specifies the maximum length of time, in seconds, that the server should spend processing the request. It is an integer element, and its value must be greater than or equal to zero. A value of zero indicates that no time limit is requested, and a value greater than zero will be treated as the requested maximum time limit.

As with the size limit, the requested time limit may be overridden by the server to impose a smaller limit than the one requested by the client. And also like the sizeLimit element, the server may or may not return a subset of the matching entries before the time limit is reached. The timeLimitExceeded (3) result code is used to indicate that a search ended prematurely because the time limit was reached before processing could complete.

Many LDAP clients also impose a client-side time limit, which represents the maximum amount of time they will spend waiting for a response from the server. That client-side time limit isn’t communicated to the server (although for a search operation, it’s often the same as the timeLimit value included in the search request), and if the server hasn’t sent a response by that time, the client will often give up, possibly abandon the request, and fail the operation with the client-side timeout (85) result code.

The typesOnly Request Element

This element indicates whether search result entries should only include attribute descriptions (attribute type names or OIDs, followed by zero or more attribute options), rather than both attribute descriptions and values. This is a Boolean element, and if it has a value of true, then search result entries will include the appropriate set of attributes, but all of them will have zero values. If it has a value of false, then attributes included in search result entries will include all of their values (or at least all of the values that the client has permission to access).

The typesOnly element must be included in the search request, but it is virtually always provided with a value of false. About the only case in which you would use with a value of true is if you want to see which attributes are present in the entry, but you don’t care about what their values are. And even then, the only case in which there’s any significant benefit to omitting the attribute values from the search result entry is if you think that one or more of those attributes might have a lot of values.

The baseObject Request Element

This element provides the criteria that entries within the scope of the search must match in order to be returned to the client. There are ten types of search filters, each of which has a slightly different encoding (if for no other reason than the BER type used to indicate which type of filter it is). The filter element itself is a CHOICE between one of the following filter types.

The present Filter Type

A present filter (also known as a presence filter) will match any entry that contains at least one value for a specified attribute. It is encoded as a simple octet string with type 0x87 (context-specific class, primitive, tag number seven) whose value is the target attribute description. For example, the encoding for the present filter with string representation (uid=*) is:

87 03 75 69 64 -- The octet string "uid" with type context-specific primitive seven
The equalityMatch Filter Type

An equalityMatch filter (also known as an equality filter) will match any entry that contains a given value for an attribute with a specified attribute description. It is encoded as an AttributeValueAssertion, which is a sequence (with type 0xa3, context-specific class, constructed, tag number three) containing two octet strings: the first being the attribute description, and the second the assertion value. For example, the encoding for the equalityMatch filter with string representation (uid=jdoe) is:

a3 0b -- Begin the AttributeValueAssertion sequence with type
      -- context-specific constructed three
   04 03 75 69 64 -- The attribute description (octet string "uid")
   04 04 6a 64 6f 65 -- The assertion value (octet string "jdoe")
The greaterOrEqual Filter Type

A greaterOrEqual filter will match any entry that contains at least one value for a specified attribute that is greater than or equal to a given value. Its encoding is very similar to that of the equalityMatch filter, except that it has a BER type of 0xa5 (context-specific class, constructed, tag number five). For example, the encoding for the greaterOrEqual filter with string representation (createTimestamp>=20170102030405.678Z) is:

a5 26 -- Begin the AttributeValueAssertion sequence with type
      -- context-specific constructed five
   04 0f 63 72 65 61 74 65 54 69 -- The attribute description
         6d 65 73 74 61 6d 70    -- (octet string "createTimestamp")
   04 13 32 30 31 37 30 31 30 32 -- The assertion value
         30 33 30 34 30 35 2e 36 -- (octet string "20170102030405.678Z")
         37 38 5a
The lessOrEqual Filter Type

A lessOrEqual filter is the same as a greaterOrEqual filter, except that it will match any entry that contains at least one value that is less than or equal to a given value rather than at least one value that is greater than or equal to a given value. Its encoding is also the same as the encoding for the greaterOrEqual filter type, except that it has a BER type of 0xa6 (context-specific class, constructed, tag number six) rather than 0xa5. For example, the encoding for a lessOrEqual filter with string representation (accountBalance<=1234) is:

a6 16 -- Begin the AttributeValueAssertion sequence with type
      -- context-specific constructed six
   04 0e 61 63 63 6f 75 6e 74 42 -- The attribute description
         61 6c 61 6e 63 65       -- (octet string "accountBalance")
   04 04 31 32 33 34             -- The assertion value (octet string "1234")
The approximateMatch Filter Type

An approximateMatch filter can be used to match any entry that has a specified attribute with at least one value that is approximately equal to a given value. Official LDAP specifications are vague as to what exactly “approximately equal to” means, and leave it up to the individual server implementations. Many servers use a “sounds like” algorithm (e.g., soundex or one of the metaphone variants), at least for attributes with a string syntax, but it’s possible for other logic to be used (for example, if an attribute’s numeric value is close to the provided value).

As with the equalityMatch, greaterOrEqual, and lessOrEqual filter types, the approximateMatch filter type is encoded as an AttributeValueAssertion. It has a BER type of 0xa8 (context-specific class, constructed, tag number eight).

For example, the encoding for the approximateMatch filter with string representation (givenName~=John) is:

a8 11 -- Begin the AttributeValueAssertion sequence with type
      -- context-specific constructed eight
   04 09 67 69 76 65 6e 4e 61 6d -- The attribute description
         65                      -- (octet string "givenName")
   04 04 4a 6f 68 6e             -- The assertion value (octet string "John")
The substrings Filter Type

The substrings filter (also called a substring filter) can be used to match an that has a specified attribute with at least one value that matches a provided substring assertion. The substring assertion can contain one or more of the following components:

Since a string can only contain one beginning and one end, there can be at most one initial component and at most one final component, but there can be any number of any components.

The substrings filter type has a BER type of 0xa4 (context-specific class, constructed, tag number four) and the following encoding:

SubstringFilter ::= SEQUENCE {
     type           AttributeDescription,
     substrings     SEQUENCE SIZE (1..MAX) OF substring CHOICE {
          initial [0] AssertionValue,  -- can occur at most once
          any     [1] AssertionValue,
          final   [2] AssertionValue } -- can occur at most once
     }

For example, the substrings filter with string representation (cn=abc*) is encoded as:

a4 0b -- Begin the SubstringFilter sequence with type
      -- context-specific constructed four
   04 02 63 6e -- The attribute description (octet string "cn")
   30 05 -- Begin the substrings sequence
      80 03 61 62 63 -- The initial element (octet string "abc") with type
                     -- context-specific primitive zero

The substrings filter with string representation (cn=*lmn*) is encoded as:

a4 0b -- Begin the SubstringFilter sequence with type
      -- context-specific constructed four
   04 02 63 6e -- The attribute description (octet string "cn")
   30 05 -- Begin the substrings sequence
      81 03 6c 6d 6e -- The any element (octet string "lmn") with type
                     -- context-specific primitive one

The substrings filter with string representation (cn=*xyz) is encoded as:

a4 0b -- Begin the SubstringFilter sequence with type
      -- context-specific constructed four
   04 02 63 6e -- The attribute description (octet string "cn")
   30 05 -- Begin the substrings sequence
      82 03 78 79 7a -- The final element (octet string "xyz") with type
                     -- context-specific primitive two

The substrings filter with string representation (cn=abc*def*lmn*uvw*xyz) is encoded as:

a4 1f -- Begin the SubstringFilter sequence with type
      -- context-specific constructed four
   04 02 63 6e -- The attribute description (octet string "cn")
   30 19 -- Begin the substrings sequence
      80 03 61 62 63 -- The initial element (octet string "abc") with type
                     -- context-specific primitive zero
      81 03 64 65 66 -- The first any element (octet string "def") with type
                     -- context-specific primitive one
      81 03 6c 6d 6e -- The second any element (octet string "lmn") with type
                     -- context-specific primitive one
      81 03 75 76 77 -- The third any element (octet string "uvw") with type
                     -- context-specific primitive one
      82 03 78 79 7a -- The final element (octet string "xyz") with type
                     -- context-specific primitive two
The extensibleMatch Filter Type

An extensibleMatch filter provides a substantial amount of flexibility when performing matching against an entry. The filter can contain the following four elements:

The extensibleMatch filter type has a BER type of 0xa9 (context-specific class, constructed, tag number nine) and the following encoding:

MatchingRuleAssertion ::= SEQUENCE {
     matchingRule    [1] MatchingRuleId OPTIONAL,
     type            [2] AttributeDescription OPTIONAL,
     matchValue      [3] AssertionValue,
     dnAttributes    [4] BOOLEAN DEFAULT FALSE }

For example, the extensibleMatch filter with string representation (uid:=jdoe) is:

a9 0b -- Begin the MatchingRuleAssertion sequence with type
      -- context-specific constructed nine
   82 03 75 69 64 -- The attribute description (octet string "uid" with type
                  -- context-specific primitive two)
   83 04 6a 64 6f 65 -- The assertion value (octet string "jdoe" with type
                     -- context-specific primitive three

The extensibleMatch filter with string representation (:caseIgnoreMatch:=foo) is:

a9 16 -- Begin the MatchingRuleAssertion sequence with type
      -- context-specific constructed nine
   81 0f 63 61 73 65 49 67 6e 6f -- The matching rule ID (octet string
         72 65 4d 61 74 63 68    -- "caseIgnoreMatch" with type
                                 -- context-specific primitive one)
   83 03 66 6f 6f -- The assertion value (octet string "foo" with type
                  -- context-specific primitive three

The extensibleMatch filter with string representation (uid:dn:caseIgnoreMatch:=jdoe) is:

a9 1f -- Begin the MatchingRuleAssertion sequence with type
      -- context-specific constructed nine
   81 0f 63 61 73 65 49 67 6e 6f -- The matching rule ID (octet string
         72 65 4d 61 74 63 68    -- "caseIgnoreMatch" with type
   82 03 75 69 64 -- The attribute description (octet string "uid" with type
                  -- context-specific primitive two)
   83 04 6a 64 6f 65 -- The assertion value (octet string "jdoe" with type
                     -- context-specific primitive three
   84 01 ff -- The dnAttributes flag (boolean true)
The and Filter Type

An and filter encapsulates some number of other filters and will only match an entry if all of the encapsulated filters match that entry. It is encoded as a set with BER type 0xa0 (context-specific class, constructed, tag number zero) in which each of the elements is the encoded representation of an encapsulated filter.

For example, the encoded representation of the and filter with string representation (&(givenName=John)(sn=Doe)) is:

a0 1e -- Begin the and set with type context-specific constructed zero
   a3 11 -- Begin the AttributeValueAssertion sequence with type
         -- context-specific constructed three
      04 09 67 69 76 65 6e 4e 61 6d -- The attribute description
            65                      -- (octet string "givenName")
      04 04 4a 6f 68 6e -- The assertion value (octet string "John")
   a3 09 -- Begin the AttributeValueAssertion sequence with type
         -- context-specific constructed three
      04 02 73 6e -- The attribute description (octet string "sn")
      04 03 44 6f 65 -- The assertion value (octet string "Doe")

RFC 4511 section 4.5.1 defines the and filter type with a constraint of SIZE (1..MAX), indicating that the and filter must encapsulate at least one filter component. However, RFC 4526 defines an absolute true filter, which is an and filter that encapsulates zero components and will always match any entry. Servers that support absolute true filters will advertise that with a value of 1.3.6.1.4.1.4203.1.5.3 in the supportedFeatures attribute of their root DSE. An absolute true filter has a string representation of (&) is encoded as:

a0 00 -- An empty and set with type context-specific constructed zero
The or Filter Type

An or filter encapsulates some number of other filters and will only match an entry if at least one of the encapsulated filters matches that entry. It is encoded as a set with BER type 0xa1 (context-specific class, constructed, tag number one), in which each of the elements is the encoded representation of an encapsulated filter.

For example, the encoded representation of the or filter with string representation (|(givenName=John)(givenName=Jonathan)) is:

a1 2a -- Begin the or set with type context-specific constructed one
   a3 11 -- Begin the AttributeValueAssertion sequence with type
         -- context-specific constructed three
      04 09 67 69 76 65 6e 4e 61 6d -- The attribute description
            65                      -- (octet string "givenName")
      04 04 4a 6f 68 6e -- The assertion value (octet string "John")
   a3 15 -- Begin the AttributeValueAssertion sequence with type
         -- context-specific constructed three
      04 09 67 69 76 65 6e 4e 61 6d -- The attribute description
            65                      -- (octet string "givenName")
      04 08 4a 6f 6e 61 74 68 61 6e -- The assertion value (octet string "Jonathan")

Just as RFC 4526 defines an absolute true filter that is an and filter with zero elements that will always match any entry, it also defines an absolute false filter that is an or filter with zero elements that will never match any entry. An absolute false filter has a string representation of (|) and is encoded as:

a1 00 -- An empty or set with type context-specific constructed one
The not Filter Type

A not filter encapsulates exactly one filter (which may be any kind of filter, including an and or or filter that combines multiple other filters) and inverts the result obtained from evaluating the encapsulated filter against an entry. So a not filter will only match an entry if the encapsulated filter does not match that entry.

A not filter has a BER type of 0xa2 (context-specific class, constructed, tag number two) and its value is the encoded representation of the filter that it encapsulates. For example, the not filter with string representation (!(givenName=John)) would be encoded as:

a2 13 -- Begin the not filter with type context-specific constructed two
   a3 11 -- Begin the AttributeValueAssertion sequence with type
         -- context-specific constructed three
      04 09 67 69 76 65 6e 4e 61 6d -- The attribute description
            65                      -- (octet string "givenName")
      04 04 4a 6f 68 6e -- The assertion value (octet string "John")

The attributes Request Element

This element specifies the set of attributes that the client wants to have included in search result entries. It is encoded as a sequence of zero or more octet string values. If the sequence is empty, then the server will assume that the client wants to retrieve all user attributes. If there are one or more octet strings in the sequence, then they may include any number of the following:

Example Encoded Search Request Message

As an example, consider a search request protocol operation with the following settings:

A search request with message ID two, no controls, and the above search request protocol op would be encoded as follows:

30 56 -- Begin the LDAPMessage sequence
   02 01 02 -- The message ID (integer value 2)
   63 51 -- Begin the search request protocol op
      04 11 64 63 3d 65 78 61 6d 70 -- The search base DN
            6c 65 2c 64 63 3d 63 6f -- (octet string "dc=example,dc=com")
            6d
      0a 01 02 -- The wholeSubtree scope (enumerated value 2)
      0a 01 00 -- The neverDerefAliases policy (enumerated value 0)
      02 02 03 e8 -- The size limit (integer value 1000)
      02 01 1e -- The time limit (integer value 30)
      01 01 00 -- The typesOnly flag (boolean false)
      a0 24 -- Begin an and filter
         a3 15 -- Begin an equality filter
            04 0b 6f 62 6a 65 63 74 43 6c -- The attribute description
                  61 73 73                -- (octet string "objectClass")
            04 06 70 65 72 73 6f 6e -- The assertion value (octet string "person")
         a3 0b -- Begin an equality filter
            04 03 75 69 64 -- The attribute description (octet string "uid")
            04 04 6a 64 6f 65 -- The assertion value (octet string "jdoe")
      30 06 -- Begin the set of requested attributes
         04 01 2a -- Request all user attributes (octet string "*")
         04 01 2b -- Request all operational attributes (octet string "+")

The Search Result Entry Response

The server will send a search result entry message for each entry that it wants to return to the client. RFC 4511 section 4.5.2 defines the search result entry protocol operation as:

SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
     objectName      LDAPDN,
     attributes      PartialAttributeList }

PartialAttributeList ::= SEQUENCE OF
                     partialAttribute PartialAttribute

And its dependencies from elsewhere in RFC 4511:

LDAPDN ::= LDAPString
           -- Constrained to <distinguishedName> [RFC4514]

LDAPString ::= OCTET STRING -- UTF-8 encoded,
                            -- [ISO10646] characters

PartialAttribute ::= SEQUENCE {
     type       AttributeDescription,
     vals       SET OF value AttributeValue }

AttributeDescription ::= LDAPString
                         -- Constrained to <attributedescription>
                         -- [RFC4512]

AttributeValue ::= OCTET STRING

This means that a search result entry is basically encoded in the same way as an add request, but with two differences: the BER type for a search result entry is 0x64 (application class, constructed, tag number four), and a search result entry can have attributes with zero values (if the search request included a typesOnly value of true).

For example, consider the entry:

dn: dc=example,dc=com
objectClass: top
objectClass: domain
dc: example

A search result entry message for that entry would be encoded as:

30 49 -- Begin the LDAPMessage sequence
   02 01 02 -- The message ID (integer value 2)
   64 44 -- Begin the search result entry protocol op
      04 11 64 63 3d 65 78 61 6d 70 -- The entry DN
            6c 65 2c 64 63 3d 63 6f -- (octet string "dc=example,dc=com")
            6d
      30 2f -- Begin the sequence of attributes
         30 1c -- Begin the first attribute sequence
            04 0b 6f 62 6a 65 63 74 43 6c -- The attribute description
                  61 73 73                -- (octet string "objectClass")
            31 0d -- Begin the set of objectClass values
               04 03 74 6f 70 -- The first value (octet string "top")
               04 06 64 6f 6d 61 69 6e -- The second value (octet string "domain")
         30 0f -- Begin the second attribute sequence
            04 02 64 63 -- The attribute description (octet string "dc")
            31 09 -- Begin the set of dc values
               04 07 65 78 61 6d 70 6c 65 -- The value (octet string "example")

If the search request had included a typesOnly value of true to indicate that the attributes should be returned without values, then the entry would be encoded as follows:

30 33 -- Begin the LDAPMessage sequence
   02 01 02 -- The message ID (integer value 2)
   64 2e -- Begin the search result entry protocol op
      04 11 64 63 3d 65 78 61 6d 70 -- The entry DN
            6c 65 2c 64 63 3d 63 6f -- (octet string "dc=example,dc=com")
            6d
      30 19 -- Begin the sequence of attributes
         30 0f -- Begin the first attribute sequence
            04 0b 6f 62 6a 65 63 74 43 6c -- The attribute description
                  61 73 73                -- (octet string "objectClass")
            31 00 -- The empty value set
         30 06 -- Begin the second attribute sequence
            04 02 64 63 -- The attribute description (octet string "dc")
            31 00 -- The empty value set

The SearchResult Reference Response

A search result reference can be used to indicate that the client should issue the search request elsewhere against other servers or another portion of the DIT. A single search request can return any number of search result references.

RFC 4511 section 4.5.2 defines the search result reference protocol operation as:

SearchResultReference ::= [APPLICATION 19] SEQUENCE
                          SIZE (1..MAX) OF uri URI

And its dependencies from elsewhere in RFC 4511:

URI ::= LDAPString     -- limited to characters permitted in
                       -- URIs

LDAPString ::= OCTET STRING -- UTF-8 encoded,
                            -- [ISO10646] characters

That is, a search result reference is a sequence with BER type 0x73 (application class, constructed, tag number nineteen) with one or more octet string elements that represent the referral URIs (which are usually LDAP URLs, as described in RFC 4516).

For example, consider a search result reference with the following two LDAP URLs:

The encoded representation of that search result reference is:

30 6d -- Begin the LDAPMessage sequence
   02 01 02 -- The message ID (integer value 2)
   73 68 -- Begin the search result reference protocol op
      04 32 6c 64 61 70 3a 2f 2f 64 -- The first referral URI (octet string "ldap://
            73 31 2e 65 78 61 6d 70 -- ds1.example.com:389/dc=example,dc=com??sub?")
            6c 65 2e 63 6f 6d 3a 33
            38 39 2f 64 63 3d 65 78
            61 6d 70 6c 65 2c 64 63
            3d 63 6f 6d 3f 3f 73 75
            62 3f
      04 32 6c 64 61 70 3a 2f 2f 64 -- The second referral URI (octet string "ldap://
            73 32 2e 65 78 61 6d 70 -- ds2.example.com:389/dc=example,dc=com??sub?")
            6c 65 2e 63 6f 6d 3a 33
            38 39 2f 64 63 3d 65 78
            61 6d 70 6c 65 2c 64 63
            3d 63 6f 6d 3f 3f 73 75
            62 3f

The Search Result Done Response

When the server has finished all processing for a search operation and has returned all appropriate entries and references, it will send a search result done message to indicates that the search is complete. RFC 4511 section 4.5.2 defines the search result done protocol operation as:

SearchResultDone ::= [APPLICATION 5] LDAPResult

That is, it’s an LDAPResult (which we’ve discussed in an earlier section) with a BER type of 0x65 (application class, constructed, tag number five). A successful search result done response is encoded as follows:

30 0c -- Begin the LDAPMessage sequence
   02 01 02 -- The message ID (integer value 2)
   65 07 -- Begin the search result done protocol op
      0a 01 00 -- success result code (enumerated value 0)
      04 00 -- No matched DN (0-byte octet string)
      04 00 -- No diagnostic message (0-byte octet string)

Previous: The LDAP Modify DN Operation Next: The LDAP Unbind Operation