RFC 1487

X.500 Lightweight Directory Access Protocol

πŸ“… published July 1993, from ietf

RFC 1487: X.500 Lightweight Directory Access Protocol πŸŽ€

okay bestie, let's start with the title block πŸ’– because it tells us who made this and when:

  • RFC number: 1487
  • Authors: W. Yeong (Performance Systems International), T. Howes (University of Michigan), and S. Kille (ISODE Consortium) 🫢
  • Date: July 1993 πŸ“…
  • Category: IAB standards track protocol πŸ”₯
  • Obsoletes / Updates: the title block doesn't list either one πŸ™ˆ

Status of this Memo ✨

this RFC specifies an IAB standards track protocol for the Internet community, and it's literally asking for discussion and suggestions for improvements πŸ’¬. if you want the current standardization state and status of this protocol, check the current edition of the "IAB Official Protocol Standards" πŸ“š. and distribution of this memo is unlimited 🌈.


Abstract πŸ¦‹

this protocol gives you access to the Directory without the heavy resource requirements of the Directory Access Protocol (DAP) 😭. it's aimed at simple management apps and browser apps that want simple read/write interactive access to the Directory, and it's meant to complement the DAP itself, not replace it πŸ’….

the key aspects of LDAP are:

  • protocol elements are carried directly over TCP or another transport, skipping a lot of the session/presentation overhead 🧚
  • lots of protocol data elements are encoded as ordinary strings (e.g., Distinguished Names) πŸ“
  • every protocol element is encoded with a lightweight BER encoding πŸ’œ

1. History 🌸

the Internet got SUPER into X.500 [1,2], and that led to efforts to lower the high "cost of entry" that comes with using it πŸ’Έ. examples are the Directory Assistance Service [3] and DIXIE [4]. they worked, ngl ✨, but they were built around particular implementations, so they didn't apply everywhere πŸ™ƒ. this document keeps the mission of defining Directory protocol alternatives going, but it's different because it deliberately avoids depending on any particular implementation πŸ‘‘.


2. Protocol Model πŸ’–

the big picture is clients doing protocol operations against servers 🫢. a client sends a protocol request describing the operation it wants to a server, and the server is the one that does the necessary operations on the Directory 🧠. once that's done, the server sends back a response with any results or errors to the requesting client πŸ“¬. the whole goal is to keep clients simple, so that it's easy for lots of apps to use the Directory πŸ’…βœ¨.

note that servers are required to return responses whenever the protocol defines one πŸ™Œ. but there's no requirement for synchronous behavior on either the client or server side πŸ¦‹. requests and responses for multiple operations can be swapped in any order, as long as clients eventually get a response for every request that needs one πŸ”.

servers are also expected to handle referrals on their own, without sending those referrals back to the client πŸ§šβ€β™€οΈ. this protocol doesn't provide for returning referrals to clients at all. the model is that servers make sure every necessary operation in the Directory gets done, and only final results or errors come back to clients πŸŽ€.

last but not least πŸ’…, this protocol can be mapped to a strict subset of the directory abstract service, which means the DAP can cleanly provide it 🌈.


3. Mapping Onto Transport Services ✨

this protocol is designed to run over connection-oriented, reliable transports, and all 8 bits in an octet count in the data stream πŸ’œ. the doc defines specs for two underlying services, though others are possible too 🌸.

3.1. Transmission Control Protocol (TCP) πŸ¦‹

LDAPMessage PDUs get mapped directly onto the TCP bytestream πŸ§ƒ. server implementations running over TCP should provide a protocol listener on port 389 πŸ‘‘.

3.2. Connection Oriented Transport Service (COTS) πŸ“

the connection gets established πŸ”Œ. there's no special use of T-Connect πŸ™…. each LDAPMessage PDU gets mapped directly onto T-Data πŸ’–.

4. Elements of Protocol ✨

okay bestie, this is where the actual protocol stuff lives πŸ’… every LDAP operation gets wrapped in one common envelope called the LDAPMessage πŸŽ€ here's how it's defined:

     LDAPMessage ::=
         SEQUENCE {
              messageID      MessageID,
              protocolOp     CHOICE {
                                  bindRequest         BindRequest,
                                  bindResponse        BindResponse,
                                  unbindRequest       UnbindRequest
                                  searchRequest       SearchRequest,
                                  searchResponse      SearchResponse,
                                  modifyRequest       ModifyRequest,
                                  modifyResponse      ModifyResponse,
                                  addRequest          AddRequest,
                                  addResponse         AddResponse,
                                  delRequest          DelRequest,
                                  delResponse         DelResponse,
                                  modifyRDNRequest    ModifyRDNRequest,
                                  modifyRDNResponse   ModifyRDNResponse,
                                  compareDNRequest    CompareRequest,
                                  compareDNResponse   CompareResponse,
                                  abandonRequest      AbandonRequest
                             }
         }

     MessageID ::= INTEGER (0 .. MaxInt)

so the LDAPMessage is basically the envelope πŸ’Œ its whole job is holding the fields that every exchange needs. right now the only shared field is the message ID, and that ID has to be different from the ID of any other request still outstanding in the same LDAP session πŸ”’ no duplicates, periodt.

the message ID also has to be echoed back in every LDAPMessage envelope that carries a response to the request where that ID was first used πŸ” so the client can always match the answer to the question it asked.

besides the LDAPMessage, a few more definitions get used when describing the protocol operations:

     IA5String ::= OCTET STRING

IA5String is more of a notational convenience 🧁 strings of this type get encoded as OCTET STRING, but the legal characters are limited to the IA5 character set. same bytes, just a cuter label that tells you what's allowed inside.

     LDAPDN ::= IA5String

     RelativeLDAPDN ::= IA5String

an LDAPDN and a RelativeLDAPDN are the encoded forms of a Distinguished Name and a Relative Distinguished Name, encoded following the specification in [5] 🌸 so that:

     <distinguished-name> ::= <name>

     <relative-distinguished-name> ::= <name-component>

where <name> and <name-component> are as defined in [5]. the names are doing the same job here, just with the encoding rules from [5] applied πŸ“œ

     AttributeValueAssertion ::=
         SEQUENCE {
              attributeType       AttributeType
              attributeValue      AttributeValue
         }

the AttributeValueAssertion is giving Directory vibes πŸ‘‘ it's similar to the one in the Directory standards, so if you've seen that before, you already know the shape 🫢

     AttributeType ::= IA5String

     AttributeValue ::= OCTET STRING

an AttributeType is written as the textual string that the Directory standards associate with it ✨ so the AttributeType 'organizationName', which has object identifier 2.5.4.10, shows up in this protocol as the string "organizationName". now here's the fallback πŸ›Ÿ if an implementation runs into an Attribute Type it can't map to a textual string, it may swap in an ASCII string of that type's object identifier instead. so "organizationName" could just be written as "2.5.4.10" if the implementation can't make the name match.

an AttributeValue field holds an octet string that encodes a Directory AttributeValue πŸ“ how those encodings work for each Directory AttributeValue type lives in companion documents about the encodings of different attribute syntaxes, such as [6] πŸ“š

     LDAPResult ::=
         SEQUENCE {
             resultCode    ENUMERATED {
                             success                      (0),
                             operationsError              (1),
                             protocolError                (2),
                             timeLimitExceeded            (3),
                             sizeLimitExceeded            (4),
                             compareFalse                 (5),
                             compareTrue                  (6),
                             authMethodNotSupported       (7),
                             strongAuthRequired           (8),
                             noSuchAttribute              (16),
                             undefinedAttributeType       (17),
                             inappropriateMatching        (18),
                             constraintViolation          (19),
                             attributeOrValueExists       (20),
                             invalidAttributeSyntax       (21),
                             noSuchObject                 (32),
                             aliasProblem                 (33),
                             invalidDNSyntax              (34),
                             isLeaf                       (35),
                             aliasDereferencingProblem    (36),
                             inappropriateAuthentication  (48),
                             invalidCredentials           (49),
                             insufficientAccessRights     (50),
                             busy                         (51),
                             unavailable                  (52),
                             unwillingToPerform           (53),
                             loopDetect                   (54),
                             namingViolation              (64),
                             objectClassViolation         (65),
                             notAllowedOnNonLeaf          (66),
                             notAllowedOnRDN              (67),
                             entryAlreadyExists           (68),
                             objectClassModsProhibited    (69),
                             other                        (80)
                           },
             matchedDN     LDAPDN,
             errorMessage  IA5String
         }

the LDAPResult is the construct this protocol uses to tell clients whether things worked πŸŽ‰ servers send back fields of this type in response to various requests, so the client knows the final status of what it asked for. the errorMessage field is optional for the server πŸ’¬ it can carry a human-readable ASCII error diagnostic if the server wants to send one. but this diagnostic isn't standardized, so implementations should not rely on the values in it πŸ™…β€β™€οΈ and if the server doesn't send a text diagnostic, errorMessage should be a zero length string.

for the resultCodes noSuchObject, aliasProblem, invalidDNSyntax, isLeaf, and aliasDereferencingProblem, the matchedDN field gets set to the name of the lowest entry (object or alias) in the DIT that matched πŸ” it's a truncated form of the name the client gave, or, if an alias got dereferenced, a truncated form of the resulting name. every other case should set matchedDN to the NULL DN (a zero length string) 🫧

4.1. Bind Operation

the Bind Operation starts a protocol session between a client and a server, and lets the server authenticate the client πŸ” it must be the first operation request a server gets from a client in a session, so bind first, then everything else πŸ’– the Bind Request looks like this:

     BindRequest ::=
         [APPLICATION 0] SEQUENCE {
                             version   INTEGER (1 .. 127),
                             name      LDAPDN,
                             authentication CHOICE {
                                  simple        [0] OCTET STRING,
                                  krbv42LDAP    [1] OCTET STRING,
                                  krbv42DSA     [2] OCTET STRING
                             }
         }

here's what the Bind Request parameters do 🧚

  • version: the protocol version used for this session. this document describes version 2 of LDAP πŸŽ€ there's no version negotiation, so the client just sets this to the version it wants.
  • name: the name of the Directory object the client wants to bind as πŸͺͺ this can be a null value (a zero length string) for anonymous binds.
  • authentication: the info used to authenticate that name, if there is any πŸ”‘ the "simple" option is the most basic one. its contents are just a cleartext password 😬 this option should also be used for unauthenticated or anonymous binds, and the field then holds a zero length string. Kerberos version 4 [7] authentication to the LDAP server and to the DSA uses the "krbv42LDAP" and "krbv42DSA" options, respectively πŸ—οΈ these two entities are separate here, but nothing says they have to be distinct. a DSA could talk LDAP directly, for example πŸ€·β€β™€οΈ two options exist so every implementation is covered. each octet string should hold the kerberos ticket (for example, what krb_mk_req() returns) for the right service. the suggested service name for the LDAP server is "ldapserver", and the suggested service name for the DSA is "x500dsa". in both cases, the suggested instance name is the name of the host the service runs on πŸ–₯️ the actual service and instance names depend on what's in your local kerberos principle database, so check there.

the Bind Operation needs a response, the Bind Response, defined as:

     BindResponse ::= [APPLICATION 1] LDAPResult

a Bind Response is just the server telling the client how its request to start a session went πŸ“¬

when a protocol server gets a Bind Request, it authenticates the requesting client if needed, then tries to set up a session with that client ✨ after that, it sends back a Bind Response with the status of the session setup πŸ’…

4.2. Unbind Operation

the Unbind Operation ends a protocol session πŸ‘‹ it's defined as:

     UnbindRequest ::= [APPLICATION 2] NULL

there's no response defined for the Unbind Operation 🫠 once a client has sent an UnbindRequest, it can assume the session is over. and when a server receives one, it can assume the client has ended the session and that any outstanding requests can be thrown out πŸ—‘οΈ bye bye, no more loose ends πŸ¦‹

4.3. Search Operation ✨

Okay bestie, so the Search Operation is how a client asks a server to go searching on its behalf πŸ”πŸ’– The server does all the digging and the client gets the receipts. The Search Request is defined like this:

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),
        attrsOnly     BOOLEAN,
        filter        Filter,
        attributes    SEQUENCE OF AttributeType
}

Filter ::=
    CHOICE {
        and                [0] SET OF Filter,
        or                 [1] SET OF Filter,
        not                [2] Filter,
        equalityMatch      [3] AttributeValueAssertion,
        substrings         [4] SubstringFilter,
        greaterOrEqual     [5] AttributeValueAssertion,
        lessOrEqual        [6] AttributeValueAssertion,
        present            [7] AttributeType,
        approxMatch        [8] AttributeValueAssertion
    }

SubstringFilter
    SEQUENCE {
        type               AttributeType,
        SEQUENCE OF CHOICE {
            initial        [0] IA5String,
            any            [1] IA5String,
            final          [2] IA5String
        }

    }

Here's what each parameter of the Search Request is doing πŸ’…

  • baseObject: An LDAPDN that is the base object entry relative to which the search is to be performed.
  • scope: An indicator of the scope of the search to be performed. The semantics of the possible values of this field are identical to the semantics of the scope field in the Directory Search Operation.
  • derefAliases: An indicator as to how alias objects should be handled in searching. The semantics of the possible values of this field are, in order of increasing value:
    • neverDerefAliases: do not dereference aliases in searching or in locating the base object of the search;
    • derefInSearching: dereference aliases in subordinates of the base object in searching, but not in locating the base object of the search;
    • derefFindingBaseObject: dereference aliases in locating the base object of the search, but not when searching subordinates of the base object;
    • derefAlways: dereference aliases both in searching and in locating the base object of the search.
  • sizelimit: A sizelimit that restricts the maximum number of entries to be returned as a result of the search. A value of 0 in this field indicates that no sizelimit restrictions are in effect for the search.
  • timelimit: A timelimit that restricts the maximum time (in seconds) allowed for a search. A value of 0 in this field indicates that no timelimit restrictions are in effect for the search.
  • attrsOnly: An indicator as to whether search results should contain both attribute types and values, or just attribute types. Setting this field to TRUE causes only attribute types (no values) to be returned. Setting this field to FALSE causes both attribute types and values to be returned.
  • filter: A filter that defines the conditions that must be fulfilled in order for the search to match a given entry.
  • attributes: A list of the attributes from each entry found as a result of the search to be returned. An empty list signifies that all attributes from each entry found in the search are to be returned.

The results of the search that the server runs when it gets a Search Request come back in Search Responses, which are defined like this πŸŽ€

Search Response ::=
    CHOICE {
         entry          [APPLICATION 4] SEQUENCE {
                             objectName     LDAPDN,
                             attributes     SEQUENCE OF SEQUENCE {
                                                 AttributeType,
                                                 SET OF AttributeValue
                                            }
                        },
         resultCode     [APPLICATION 5] LDAPResult
     }

Upon receipt of a Search Request, a server will perform the necessary search of the DIT. 🌸

The server will return a sequence of responses to the client, made up of:

  • Zero or more Search Responses, each consisting of an entry found during the search; the response sequence is terminated by
  • A single Search Response containing an indication of success, or detailing any errors that have occurred.

Each entry that comes back will contain all attributes, complete with associated values if necessary, as specified in the attributes field of the Search Request. 🫢

Note that an X.500 "list" operation can be emulated by a one-level LDAP search operation with a filter checking for the existence of the objectClass attribute, and that an X.500 "read" operation can be emulated by a base object LDAP search operation with the same filter. The emulation trick is so iykyk 🧚


4.4. Modify Operation πŸ¦‹

The Modify Operation lets a client ask a server to make a change to the DIB, on its behalf. The Modify Request is defined like this:

ModifyRequest ::=
    [APPLICATION 6] SEQUENCE {
         object         LDAPDN,
         modification   SEQUENCE OF SEQUENCE {
                             operation      ENUMERATED {
                                                 add       (0),
                                                 delete    (1),
                                                 replace   (2)
                                            },
                             modification   SEQUENCE {
                                               type    AttributeType,
                                               values  SET OF
                                                         AttributeValue
                                            }
                        }
    }

Here's the rundown on the Modify Request parameters ✨

  • object: The object to be modified. The value of this field should name the object to be modified after all aliases have been dereferenced. The server will not perform any alias dereferencing in determining the object to be modified.
  • A list of modifications to be performed on the entry to be modified. The entire list of entry modifications should be performed in the order they are listed, as a single atomic operation. While individual modifications may violate the Directory schema, the resulting entry after the entire list of modifications is performed must conform to the requirements of the Directory schema. The values that may be taken on by the operation field in each modification construct have the following semantics respectively:
    • add: add values listed to the given attribute, creating the attribute if necessary;
    • delete: delete values listed from the given attribute, removing the entire attribute if no values are listed, or if all current values of the attribute are listed for deletion;
    • replace: replace existing values of the given attribute with the new values listed, creating the attribute if necessary.

The result of the modify that the server attempts when it gets a Modify Request comes back in a Modify Response, which is defined like this:

ModifyResponse ::= [APPLICATION 7] LDAPResult

Upon receipt of a Modify Request, a server will perform the necessary modifications to the DIB. πŸ’–

The server will return a single Modify Response to the client, saying either that the DIB modification finished successfully or why it failed. Because the list of modifications in the Modify Request has to be applied atomically, the client may expect that no modifications of the DIB have been performed if the Modify Response shows any sort of error. If the Modify Response shows successful completion of the Modify Operation, the client may expect that all requested modifications have been performed. It's all or nothing, bestie πŸ™ˆ


4.5. Add Operation πŸŽ€

The Add Operation lets a client request that an entry be added to the Directory. The Add Request is defined like this:

AddRequest ::=
    [APPLICATION 8] SEQUENCE {
         entry          LDAPDN,
         attrs          SEQUENCE OF SEQUENCE {
                             type          AttributeType,
                             values        SET OF AttributeValue
                        }
    }

Parameters of the Add Request are:

  • entry: the Distinguished Name of the entry to be added. Note that all components of the name except for the last RDN component must exist for the add to succeed.
  • attrs: the list of attributes that make up the content of the entry being added.

The result of the add that the server attempts when it gets an Add Request is returned in the Add Response, which is defined like this:

AddResponse ::= [APPLICATION 9] LDAPResult

Upon receipt of an Add Request, a server will attempt to perform the add requested. The result of the add attempt will be returned to the client in the Add Response. 🌈


4.6. Delete Operation 🌸

The Delete Operation lets a client request the removal of an entry from the Directory. The Delete Request is defined like this:

DelRequest ::= [APPLICATION 10] LDAPDN

The Delete Request consists only of the Distinguished Name of the entry to be deleted. The result of the delete that the server attempts when it gets a Delete Request is returned in the Delete Response, which is defined like this:

DelResponse ::= [APPLICATION 11] LDAPResult

Upon receipt of a Delete Request, a server will attempt to perform the entry removal requested. The result of the delete attempt will be returned to the client in the Delete Response. Note that only leaf objects may be deleted with this operation. πŸ“


4.7. Modify RDN Operation 🫢

The Modify RDN Operation lets a client change the last component of the name of an entry in the Directory. The Modify RDN Request is defined like this:

ModifyRDNRequest ::=
    [APPLICATION 12] SEQUENCE {
         entry          LDAPDN,
         newrdn         RelativeLDAPDN
    }

Parameters of the Modify RDN Request are:

  • entry: the name of the entry to be changed.
  • newrdn: the RDN that will form the last component of the new name.

The result of the name change that the server attempts when it gets a Modify RDN Request is returned in the Modify RDN Response, which is defined like this:

ModifyRDNResponse ::= [APPLICATION 13] LDAPResult

Upon receipt of a Modify RDN Request, a server will attempt to perform the name change. The result of the name change attempt will be returned to the client in the Modify RDN Response. The attributes that make up the old RDN are deleted from the entry. Ate and left no crumbs πŸ’…πŸ‘‘

4.8. Compare Operation ✨

okay so the Compare Operation is lowkey one of my faves πŸ’… It lets a client check whether an assertion matches an entry in the Directory. The Compare Request looks like this πŸŽ€

CompareRequest ::=
    [APPLICATION 14] SEQUENCE {
         entry          LDAPDN,
         ava            AttributeValueAssertion
    }

There are two parameters 🌸

  • entry: the name of the entry to be compared with.
  • ava: the assertion with which the entry is to be compared.

The server sends back the result of the compare in the Compare Response, which is defined like this πŸ’–

CompareResponse ::= [APPLICATION 15] LDAPResult

So when a server gets a Compare Request, it tries the comparison, then sends the outcome back in the Compare Response. Here's the bestie-level detail 🫢 errors and the comparison result both come back in that same construct, so you read the one response to know what happened. Iconic, no notes πŸ¦‹

4.9. Abandon Operation 🌈

the Abandon Operation lets a client ask the server to drop an operation that's still in progress πŸ™ˆ The Abandon Request is defined as follows.

AbandonRequest ::= [APPLICATION 16] MessageID

There's no response for this one πŸ’€ After a client sends an Abandon Operation, it can expect that the operation named by the Message ID in the Abandon Request has been abandoned. One more thing πŸ”₯ if a server gets an Abandon Request for a Search Operation while it's still sending that search's responses, the server should stop sending responses for that search right away.

5. Protocol Element Encodings 🧚

LDAP protocol elements get encoded for exchange using the Basic Encoding Rules (BER) [11] of ASN.1 [10]. BER can have a lot of overhead, so there are a couple of extra restrictions on how LDAP protocol elements are BER-encoded πŸ’œ

  1. Only the definite form of length encoding will be used.
  2. Bitstrings and octet strings will be encoded in the primitive form only.

6. Security Considerations πŸ’€

okay this part is serious bestie 😭 This version of the protocol only has facilities for simple authentication using a cleartext password, and for Kerberos version 4 authentication. Future versions of LDAP will likely support other authentication methods.

7. Bibliography πŸ“š

  • [1] The Directory: Overview of Concepts, Models and Service. CCITT Recommendation X.500, 1988.
  • [2] Information Processing Systems -- Open Systems Interconnection -- The Directory: Overview of Concepts, Models and Service. ISO/IEC JTC 1/SC21; International Standard 9594-1, 1988.
  • [3] Rose, M., "Directory Assistance Service", RFC 1202, Performance Systems International, Inc., February 1991.
  • [4] Howes, R., Smith, M., and B. Beecher, "DIXIE Protocol Specification", RFC 1249, University of Michigan, August 1991.
  • [5] Kille, S., "A String Representation of Distinguished Names", RFC 1485, ISODE Consortium, July 1993.
  • [6] Howes, T., Kille, S., Yeong, W., and C. Robbins, "The String Representation of Standard Attribute Syntaxes", RFC 1488, University of Michigan, ISODE Consortium, Performance Systems International, NeXor Ltd., July 1993.
  • [7] Kerberos Authentication and Authorization System. S.P. Miller, B.C. Neuman, J.I. Schiller, J.H. Saltzer; MIT Project Athena Documentation Section E.2.1, December 1987.
  • [8] The Directory: Models. CCITT Recommendation X.501 ISO/IEC JTC 1/SC21; International Standard 9594-2, 1988.
  • [9] The Directory: Abstract Service Definition. CCITT Recommendation X.511, ISO/IEC JTC 1/SC21; International Standard 9594-3, 1988.
  • [10] Specification of Abstract Syntax Notation One (ASN.1). CCITT Recommendation X.208, 1988.
  • [11] Specification of Basic Encoding Rules for Abstract Syntax Notation One (ASN.1). CCITT Recommendation X.209, 1988.

9. Security Considerations πŸ”’

this one is short and sweet πŸ“ Security issues are not discussed in this memo.

9. Authors' Addresses 🫢

Wengyik Yeong
PSI, Inc.
510 Huntmar Park Drive
Herndon, VA 22070
USA

Phone: +1 703-450-8001
EMail: yeongw@psilink.com


Tim Howes
University of Michigan
ITD Research Systems
535 W William St.
Ann Arbor, MI 48103-4943
USA

Phone: +1 313 747-4454
EMail: tim@umich.edu


Steve Kille
ISODE Consortium
PO Box 505
London
SW11 1DX
UK

Phone: +44-71-223-4062
EMail: S.Kille@isode.com

Appendix A πŸ‘‘

the whole ASN.1 definition, all in one place πŸ¦‹

                         Complete ASN.1 Definition

Lightweight-Directory-Access-Protocol DEFINITIONS ::=

IMPLICIT TAGS

BEGIN

LDAPMessage ::=
    SEQUENCE {
         messageID      MessageID,
                        -- unique id in request,
                        -- to be echoed in response(s)
         protocolOp     CHOICE {
                             searchRequest       SearchRequest,
                             searchResponse      SearchResponse,
                             modifyRequest       ModifyRequest,
                             modifyResponse      ModifyResponse,
                             addRequest          AddRequest,
                             addResponse         AddResponse,
                             delRequest          DelRequest,
                             delResponse         DelResponse,
                             modifyDNRequest     ModifyDNRequest,
                             modifyDNResponse    ModifyDNResponse,
                             compareDNRequest    CompareRequest,
                             compareDNResponse   CompareResponse,
                             bindRequest         BindRequest,
                             bindResponse        BindResponse,
                             abandonRequest      AbandonRequest,
                             unbindRequest       UnbindRequest
                        }
    }

BindRequest ::=
    [APPLICATION 0] SEQUENCE {
         version        INTEGER (1 .. 127),
                        -- current version is 2
         name           LDAPDN,
                        -- null name implies an anonymous bind
         authentication CHOICE {
                             simple        [0] OCTET STRING,
                                       -- a zero length octet string
                                       -- implies an unauthenticated
                                       -- bind.
                             krbv42LDAP    [1] OCTET STRING,
                             krbv42DSA     [2] OCTET STRING

                                       -- values as returned by
                                       -- krb_mk_req()
                                       -- Other values in later
                                       -- versions of this protocol.
                        }
    }

BindResponse ::= [APPLICATION 1] LDAPResult

UnbindRequest ::= [APPLICATION 2] NULL

SearchRequest ::=
    [APPLICATION 3] SEQUENCE {
         baseObject     LDAPDN,
         scope          ENUMERATED {
                             baseObject            (0),
                             singleLevel           (1),
                             wholeSubtree          (2)
                        },
         derefAliases   ENUMERATED {
                             neverDerefAliases     (0),
                             derefInSearching      (1),
                             derefFindingBaseObj   (2),
                             alwaysDerefAliases    (3)
                        },
         sizeLimit      INTEGER (0 .. MaxInt),
                        -- value of 0 implies no sizelimit
         timeLimit      INTEGER (0 .. MaxInt),
                        -- value of 0 implies no timelimit
         attrsOnly     BOOLEAN,
                        -- TRUE, if only attributes (without values)
                        -- to be returned.
         filter         Filter,
         attributes     SEQUENCE OF AttributeType
    }

SearchResponse ::=
    CHOICE {
         entry          [APPLICATION 4] SEQUENCE {
                             objectName     LDAPDN,
                             attributes     SEQUENCE OF SEQUENCE {
                                              AttributeType,
                                              SET OF
                                                AttributeValue
                                            }
                        },
         resultCode     [APPLICATION 5] LDAPResult
    }

ModifyRequest ::=
    [APPLICATION 6] SEQUENCE {
         object         LDAPDN,
         modifications  SEQUENCE OF SEQUENCE {
                             operation     ENUMERATED {
                                             add      (0),
                                             delete   (1),
                                             replace  (2)
                                           },
                             modification  SEQUENCE {
                                             type     AttributeType,
                                             values   SET OF
                                                        AttributeValue
                                           }
                        }
    }


ModifyResponse ::= [APPLICATION 7] LDAPResult

AddRequest ::=
    [APPLICATION 8] SEQUENCE {
         entry          LDAPDN,
         attrs          SEQUENCE OF SEQUENCE {
                             type          AttributeType,
                             values        SET OF AttributeValue
                        }
    }

AddResponse ::= [APPLICATION 9] LDAPResult

DelRequest ::= [APPLICATION 10] LDAPDN

DelResponse ::= [APPLICATION 11] LDAPResult

ModifyRDNRequest ::=
    [APPLICATION 12] SEQUENCE {
         entry          LDAPDN,
         newrdn         RelativeLDAPDN -- old RDN always deleted
    }

ModifyRDNResponse ::= [APPLICATION 13] LDAPResult

CompareRequest ::=
    [APPLICATION 14] SEQUENCE {
         entry          LDAPDN,
         ava            AttributeValueAssertion
    }

CompareResponse ::= [APPLICATION 15] LDAPResult

AbandonRequest ::= [APPLICATION 16] MessageID

MessageID ::= INTEGER (0 .. MaxInt)

LDAPDN ::= IA5String

RelativeLDAPDN ::= IA5String

Filter ::=
    CHOICE {
        and            [0] SET OF Filter,
        or             [1] SET OF Filter,
        not            [2] Filter,
        equalityMatch  [3] AttributeValueAssertion,
        substrings     [4] SubstringFilter,
        greaterOrEqual [5] AttributeValueAssertion,
        lessOrEqual    [6] AttributeValueAssertion,
        present        [7] AttributeType,
        approxMatch    [8] AttributeValueAssertion
    }

okay bestie, the last bits of the grammar are here πŸ’–βœ¨ these are the type definitions, so every single character stays exactly as written πŸŽ€

LDAPResult ::=
    SEQUENCE {
        resultCode    ENUMERATED {
                        success                      (0),
                        operationsError              (1),
                        protocolError                (2),
                        timeLimitExceeded            (3),
                        sizeLimitExceeded            (4),
                        compareFalse                 (5),
                        compareTrue                  (6),
                        authMethodNotSupported       (7),
                        strongAuthRequired           (8),
                        noSuchAttribute              (16),
                        undefinedAttributeType       (17),
                        inappropriateMatching        (18),
                        constraintViolation          (19),
                        attributeOrValueExists       (20),
                        invalidAttributeSyntax       (21),
                        noSuchObject                 (32),
                        aliasProblem                 (33),
                        invalidDNSyntax              (34),
                        isLeaf                       (35),
                        aliasDereferencingProblem    (36),
                        inappropriateAuthentication  (48),
                        invalidCredentials           (49),
                        insufficientAccessRights     (50),
                        busy                         (51),
                        unavailable                  (52),
                        unwillingToPerform           (53),
                        loopDetect                   (54),
                        namingViolation              (64),
                        objectClassViolation         (65),
                        notAllowedOnNonLeaf          (66),
                        notAllowedOnRDN              (67),
                        entryAlreadyExists           (68),
                        objectClassModsProhibited    (69),
                        other                        (80)
                      },
        matchedDN     LDAPDN,
        errorMessage  IA5String
    }

AttributeType ::= IA5String
                -- text name of the attribute, or dotted
                -- OID representation

AttributeValue ::= OCTET STRING

AttributeValueAssertion ::=
    SEQUENCE {
        attributeType        AttributeType,
        attributeValue       AttributeValue
    }

SubstringFilter
    SEQUENCE {
        type               AttributeType,
        SEQUENCE OF CHOICE {
          initial          [0] IA5String,
          any              [1] IA5String,
          final            [2] IA5String
      }
    }

IA5String ::= OCTET STRING

MaxInt ::= 65535
END

that's the whole thing, bestie! πŸŒˆπŸ‘‘ πŸ¦‹

πŸ“¦ where this page comes from