RFC 1777

Lightweight Directory Access Protocol

๐Ÿ“… published March 1995, from ietf

RFC 1777 โœจ Lightweight Directory Access Protocol ๐ŸŽ€

Part 1 of 5 ๐Ÿ’–

okay bestie, this is the RFC that gave us LDAP ๐Ÿฆ‹ It was written by W. Yeong (Performance Systems International), T. Howes (University of Michigan), and S. Kille (ISODE Consortium), in March 1995. It's a Standards Track document, and it obsoletes RFC 1487 ๐Ÿ’… It doesn't update anything.

Status of This Memo ๐Ÿ“œ

this one is an Internet standards track protocol for the Internet community, and it's asking for discussion and suggestions for improvements ๐Ÿซถ If you want to know where it stands in standardization, go check the current edition of the "Internet Official Protocol Standards" (STD 1). Distribution of this memo is unlimited, so share it all you want ๐ŸŒธ

Abstract ๐Ÿฆ‹

so LDAP is designed to give you access to the X.500 Directory without eating all the resources that the Directory Access Protocol (DAP) needs ๐Ÿ™ˆ It's aimed at simple management apps and browser apps that just want simple read/write interactive access to the X.500 Directory. It's meant to complement DAP, not replace it, ngl ๐Ÿ’œ

Key aspects of LDAP are:

  • Protocol elements are carried directly over TCP or other transport, skipping much of the session/presentation overhead โœจ
  • Lots of protocol data elements are encoded as ordinary strings (e.g., Distinguished Names) ๐Ÿงš
  • A lightweight BER encoding is used to encode all protocol elements ๐Ÿ’…

1. History ๐ŸŒˆ

the tremendous interest in X.500 [1,2] technology on the Internet 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]. Those efforts were a success, but they were built on particular implementations, so they didn't apply as widely. This document keeps going with defining Directory protocol alternatives, but it's different because it deliberately avoids depending on any particular implementation ๐Ÿ‘‘

2. Protocol Model ๐Ÿ’–

the general model here is clients performing protocol operations against servers. A client sends a protocol request describing the operation it wants to a server, and the server handles the necessary operations on the Directory. Once those are done, the server sends back a response with any results or errors to the requesting client ๐ŸŽ€ The goal is to make life easier by keeping clients as simple as possible, so that loads of apps can use the Directory ๐Ÿ”ฅ

ngl this next bit is important: servers are required to return responses whenever the protocol defines a response, but there's no requirement for synchronous behavior on the client or server side. Requests and responses for multiple operations can be exchanged in any order between clients and servers, as long as clients eventually get a response for every request that needs one ๐Ÿซถ

Because servers do the operations on behalf of clients, protocol servers are expected to handle referrals themselves instead of passing them back to the client ๐Ÿฆ‹ This protocol has no provisions for returning referrals to clients. The model is that servers make sure all the necessary operations happen in the Directory, and only final results or errors go back to the clients ๐Ÿ’…

Also, this protocol can be mapped to a strict subset of the directory abstract service, so it can be cleanly provided by the DAP โœจ

3. Mapping Onto Transport Services ๐Ÿงš

this protocol is designed to run over connection-oriented, reliable transports, where all 8 bits in an octet are significant in the data stream ๐ŸŒธ Two underlying services are specified here, though others are possible too ๐ŸŒˆ

3.1. Transmission Control Protocol (TCP) ๐Ÿ’œ

the LDAPMessage PDUs are 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. No special use of T-Connect is made. Each LDAPMessage PDU is mapped directly onto T-Data ๐Ÿ’…

4. Elements of Protocol โœจ

Okay so every protocol operation gets wrapped up in the same envelope, called the LDAPMessage ๐Ÿ’Œ It looks like this:

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)

The LDAPMessage is the envelope that holds the common fields every exchange needs ๐ŸŽ€ Right now the only common field is the message ID, and it has to be different from the ID of every other request that's still outstanding in the same LDAP session it belongs to ๐Ÿงš

The message ID must be echoed in every LDAPMessage envelope that carries a response to the request. That means the response has to reuse the ID from the original request's LDAPMessage ๐Ÿ”

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

LDAPString ::= OCTET STRING

LDAPString is a notational convenience ๐Ÿซถ Strings of this type are encoded as OCTET STRING, but the legal characters in them are limited to the IA5 character set.

LDAPDN ::= LDAPString

RelativeLDAPDN ::= LDAPString

An LDAPDN and a RelativeLDAPDN are the encoded forms of a Distinguished Name and a Relative Distinguished Name. The encoding follows the specification in [5], so that:

<distinguished-name> ::= <name>

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

Here, <name> and <name-component> are as defined in [5] ๐Ÿ’…

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

This AttributeValueAssertion type is pretty similar to the one in the X.500 Directory standards ๐Ÿ“š

AttributeType ::= LDAPString

AttributeValue ::= OCTET STRING

An AttributeType takes as its value the textual string that goes with that AttributeType in the X.500 Directory standards ๐Ÿฆ‹ For example, the AttributeType 'organizationName', which has object identifier 2.5.4.10, shows up in this protocol as the string "organizationName". If an implementation runs into an Attribute Type it can't match to a textual string, it may substitute an ASCII string encoding of the object identifier for that type. So organizationName could be written as "2.5.4.10" if the implementation can't work out the string "organizationName" for it ๐Ÿ™ˆ

A field of type AttributeValue holds an octet string that encodes a Directory AttributeValue type. The string encodings for the different Directory AttributeValue types can be found in companion documents that define the encodings of various 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  LDAPString
    }

LDAPResult is the construct this protocol uses to send success or failure signals from servers back to clients ๐Ÿ”ฅ When servers answer various requests, their responses include LDAPResult fields that show the final status of the operation. The errorMessage field is optional fun ๐Ÿ’œ At the server's option, it can hold an ASCII string with a human-readable error explanation. That diagnostic isn't standardised, so implementations should not rely on the values returned. If the server doesn't want to send a text diagnostic, the errorMessage field should contain a zero length string.

For resultCodes of 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 that was provided, or, if an alias was dereferenced, of the resulting name ๐Ÿ“ In every other case, the matchedDN field should be set to 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 receives from a client in a session. The Bind Request is defined 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 are ๐Ÿ‘‘

  • version: This is the version number of the protocol that the session will use. This document describes version 2 of the LDAP protocol. There's no version negotiation, so the client should just set this parameter to whichever version it wants ๐Ÿ’…
  • name: This is the name of the Directory object the client wants to bind as. It can be a null value (a zero length string) for anonymous binds ๐Ÿฆ‹
  • authentication: This is the information used to authenticate the name, if one was given in the Bind Request. The "simple" option is pretty basic: the field holds just a cleartext password. This option should also be used for unauthenticated or anonymous binds, and in those cases the field contains a zero length string ๐Ÿ™ˆ Kerberos version 4 [7] authentication to the LDAP server and the DSA works through the "krbv42LDAP" and "krbv42DSA" options, respectively. The two entities are treated as separate here, but nothing says they have to be different things, so a DSA could speak LDAP directly ๐Ÿงš Two separate options exist so that all implementations are supported. Each octet string should contain the kerberos ticket for the right service (for example, the kind returned by krb_mk_req()) โœจ The suggested service name for authenticating to the LDAP server is "ldapserver", and the suggested service name for authenticating to the DSA is "x500dsa". In both cases, the suggested instance name is the name of the host the service runs on. The actual service names and instances depend on what's in the local kerberos principle database, so they might look different ๐ŸŒˆ

The Bind Operation needs a response, the Bind Response, which is defined as:

BindResponse ::= [APPLICATION 1] LDAPResult

A Bind Response is basically 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 that's necessary, then tries to set up a protocol session with that client โœจ After that, the server sends a Bind Response back to the client that says whether the session setup worked ๐ŸŽ€


4.2. Unbind Operation

The Unbind Operation ends a protocol session ๐Ÿ‘‹ It's defined like this:

UnbindRequest ::= [APPLICATION 2] NULL

The Unbind Operation has no defined response ๐Ÿซถ Once a protocol client sends an UnbindRequest, it can assume the session is over. When a protocol server receives an UnbindRequest, it can assume the client has ended the session, and that any outstanding requests can be thrown out ๐Ÿ’€

4.3. Search Operation ๐Ÿ”

Okay so the Search Operation is how a client asks a server to go digging through the Directory on its behalf ๐Ÿ•ต๏ธโ€โ™€๏ธโœจ Here's what a Search Request looks like:

  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] LDAPString,
              any            [1] LDAPString,
              final          [2] LDAPString
          }
      }

Here are the parameters of the Search Request, bestie ๐Ÿ’…

  • 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 the server attempts after getting a Search Request come back in Search Responses, which look like this ๐Ÿงš

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

Once a server gets a Search Request, it will perform the necessary search of the DIT. Then it sends back a whole sequence of responses made up of:

  • Zero or more Search Responses, each consisting of an entry found during the search; with the response sequence 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. Iconic โœจ

Also, a fun little fact ๐Ÿ™ˆ 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 an X.500 "read" operation can be emulated by a base object LDAP search operation with the same filter. Main character energy for LDAP, no cap ๐Ÿ’œ


4.4. Modify Operation โœ๏ธ

The Modify Operation lets a client ask a server to make a modification to the DIB on its behalf ๐Ÿซถ Here's the Modify Request:

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
                                            }
                        }
    }

Parameters of the Modify Request are:

  • 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 the server attempts after getting a Modify Request comes back in a Modify Response, which looks like this:

    ModifyResponse ::= [APPLICATION 7] LDAPResult

When a server gets a Modify Request, it will perform the necessary modifications to the DIB. Then it sends back a single Modify Response that either says the DIB modification finished successfully, or gives the reason the modification failed ๐Ÿ’…

Here's the big deal ๐Ÿ”ฅ Because the list of modifications in the Modify Request has to be applied atomically, if the Modify Response shows any sort of error, the client can expect that no modifications to the DIB were performed. And if the Modify Response shows successful completion of the Modify Operation, the client can expect that all requested modifications were performed. All or nothing, periodt ๐Ÿ™Œ


4.5. Add Operation โž•

The Add Operation lets a client request that an entry be added to the Directory ๐ŸŒˆ The Add Request looks 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 the server attempts after getting an Add Request comes back in the Add Response, which looks like this:

  AddResponse ::= [APPLICATION 9] LDAPResult

When a server gets an Add Request, it will attempt to perform the requested add. The result of that attempt gets sent back to the client in the Add Response ๐Ÿฆ‹


4.6. Delete Operation ๐Ÿ—‘๏ธ

The Delete Operation lets a client request that an entry be removed from the Directory ๐Ÿ’œ The Delete Request looks like this:

  DelRequest ::= [APPLICATION 10] LDAPDN

The Delete Request is just the Distinguished Name of the entry to be deleted ๐ŸŽ€ The result of the delete the server attempts after getting a Delete Request comes back in the Delete Response, which looks like this:

  DelResponse ::= [APPLICATION 11] LDAPResult

When a server gets a Delete Request, it will attempt to perform the requested entry removal. The result of that delete attempt gets sent back to the client in the Delete Response. Note that only leaf objects may be deleted with this operation. ๐Ÿƒ

4.7. Modify RDN Operation โœจ

okay so the Modify RDN Operation is how a client renames an entry ๐Ÿฆ‹ it only changes the last bit of the name, so think of it like changing someone's nickname but not their whole family tree ๐Ÿ’… the request looks like this:

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

there are three params you need to know about ๐Ÿ’–

  • entry: the name of the entry you want to change ๐ŸŽ€
  • newrdn: the RDN that's gonna be the new last component of the name โœจ
  • deleteoldrdn: a boolean that decides whether the old RDN attribute values stay on the entry as attributes, or get deleted from it ๐Ÿ‘‘

the server's answer to your rename attempt comes back in the Modify RDN Response, which looks like this:

ModifyRDNResponse ::= [APPLICATION 13] LDAPResult

the server tries the rename as soon as it gets your request ๐Ÿซถ and whatever happens comes back to you in that response. and the old RDN attributes are either deleted or kept, depending on what you set deleteoldrdn to ๐ŸŒธ no drama, just a clean rename ๐Ÿ˜ญ


4.8. Compare Operation ๐Ÿงš

the Compare Operation is giving "is this a match??" energy ๐Ÿ™ˆ a client uses it to check an assertion against an entry in the Directory. the request is:

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

two params here:

  • entry: the name of the entry you're comparing against ๐Ÿ“
  • ava: the assertion you want to check the entry against ๐Ÿ’œ

when the server gets a Compare Request, it runs the comparison and sends the result back in the Compare Response:

CompareResponse ::= [APPLICATION 15] LDAPResult

the server tries the comparison as soon as the request lands, and the outcome comes back in that response ๐ŸŒˆ fun fact (well, fun for nerds ๐Ÿค“): errors and the comparison result both come back in the same construct. one response, two jobs, very efficient, very iconic โœจ


6.9. Abandon Operation ๐Ÿ™…โ€โ™€๏ธ

the Abandon Operation lets a client ask the server to stop working on an operation that's still going ๐Ÿ›‘ the Abandon Request is:

AbandonRequest ::= [APPLICATION 16] MessageID
there's no response defined for the Abandon Operation. after a client sends one, it can expect that the operation identified by the Message ID in the Abandon Request has been abandoned ๐Ÿ’€

super important bit: if a server gets an Abandon Request for a Search Operation while it's still sending results for that search, the server should stop sending responses for that search right away ๐Ÿ”ฅ no more results, the vibe is OVER ๐Ÿซ 

5. Protocol Element Encodings ๐ŸŽ€

LDAP protocol elements get encoded for exchange using the Basic Encoding Rules (BER) [12] of ASN.1 [11] ๐Ÿ“ฆ but BER can get kinda heavy on overhead, so there are some extra rules for BER-encodings of LDAP protocol elements ๐Ÿ’… these are the restrictions:

  1. Only the definite form of length encoding will be used. ๐ŸŒธ
  2. Bitstrings and octet strings and all character string types will be encoded in the primitive form only. โœจ

6. Security Considerations ๐Ÿ”

okay bestie, real talk ๐Ÿ˜ญ this version of the protocol only gives you two authentication options: simple authentication using a cleartext password, and kerberos version 4 authentication. the cleartext password part is a big deal, so please be careful with it ๐Ÿ’€

future versions of LDAP will likely add support for other authentication methods ๐Ÿ”ฎ keep an eye out ๐Ÿ‘€

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, T., 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 1779, ISODE Consortium, March 1995.

[6] Howes, T., Kille, S., Yeong, W., and C. Robbins, "Lightweight Directory Access Protocol", 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.

[10] The Directory: Abstract Service Definition. CCITT Recommendation X.511, ISO/IEC JTC 1/SC21; International Standard 9594-3, 1988.

[11] Specification of Abstract Syntax Notation One (ASN.1). CCITT Recommendation X.208, 1988.

[12] Specification of Basic Encoding Rules for Abstract Syntax Notation One (ASN.1). CCITT Recommendation X.209, 1988.

10. 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 - 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 ::= LDAPString

RelativeLDAPDN ::= LDAPString

okay bestie, the filter grammar is up next and it is SO good ๐Ÿ’–โœจ

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
    }

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  LDAPString
    }

ngl the result codes list is giving main character energy ๐Ÿ‘‘ every single error has its own little number, no vibes-based guessing ๐Ÿ™ˆ

AttributeType ::= LDAPString
                -- 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] LDAPString,
          any              [1] LDAPString,
          final            [2] LDAPString
      }
    }

LDAPString ::= OCTET STRING

maxInt INTEGER ::= 65535
END

๐Ÿฆ‹ and that's the whole grammar, periodt ๐Ÿ’…๐ŸŒธ

๐Ÿ“ฆ where this page comes from