1"""
2"""
3
4# Created on 2013.05.15
5#
6# Author: Giovanni Cannata
7#
8# Copyright 2014 - 2020 Giovanni Cannata
9#
10# This file is part of ldap3.
11#
12# ldap3 is free software: you can redistribute it and/or modify
13# it under the terms of the GNU Lesser General Public License as published
14# by the Free Software Foundation, either version 3 of the License, or
15# (at your option) any later version.
16#
17# ldap3 is distributed in the hope that it will be useful,
18# but WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20# GNU Lesser General Public License for more details.
21#
22# You should have received a copy of the GNU Lesser General Public License
23# along with ldap3 in the COPYING and COPYING.LESSER files.
24# If not, see <http://www.gnu.org/licenses/>.
25
26#######################
27# ldap ASN.1 Definition
28# from RFC4511 - Appendix B
29# extended with result codes from IANA ldap-parameters as of 2013.08.21
30# extended with modify_increment from RFC4525
31
32#########################################################
33# Lightweight-Directory-Access-Protocol-V3 {1 3 6 1 1 18}
34# -- Copyright (C) The Internet Society (2006).  This version of
35# -- this ASN.1 module is part of RFC 4511; see the RFC itself
36# -- for full legal notices.
37# DEFINITIONS
38# IMPLICIT TAGS
39# EXTENSIBILITY IMPLIED
40
41from pyasn1.type.univ import OctetString, Integer, Sequence, Choice, SequenceOf, Boolean, Null, Enumerated, SetOf
42from pyasn1.type.namedtype import NamedTypes, NamedType, OptionalNamedType, DefaultedNamedType
43from pyasn1.type.constraint import ValueRangeConstraint, SingleValueConstraint, ValueSizeConstraint
44from pyasn1.type.namedval import NamedValues
45from pyasn1.type.tag import tagClassApplication, tagFormatConstructed, Tag, tagClassContext, tagFormatSimple
46
47
48# constants
49# maxInt INTEGER ::= 2147483647 -- (2^^31 - 1) --
50LDAP_MAX_INT = 2147483647
51MAXINT = Integer(LDAP_MAX_INT)
52
53# constraints
54rangeInt0ToMaxConstraint = ValueRangeConstraint(0, MAXINT)
55rangeInt1To127Constraint = ValueRangeConstraint(1, 127)
56size1ToMaxConstraint = ValueSizeConstraint(1, MAXINT)
57responseValueConstraint = SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 32, 33, 34, 36, 48, 49, 50, 51, 52, 53, 54, 64, 65, 66, 67, 68, 69, 71, 80, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123,
58                                                4096)
59
60# custom constraints
61numericOIDConstraint = None  # TODO
62distinguishedNameConstraint = None  # TODO
63nameComponentConstraint = None  # TODO
64attributeDescriptionConstraint = None  # TODO
65uriConstraint = None  # TODO
66attributeSelectorConstraint = None  # TODO
67
68
69class Integer0ToMax(Integer):
70    subtypeSpec = Integer.subtypeSpec + rangeInt0ToMaxConstraint
71
72
73class LDAPString(OctetString):
74    # LDAPString ::= OCTET STRING -- UTF-8 encoded, -- [ISO10646] characters
75    encoding = 'utf-8'
76
77
78class MessageID(Integer0ToMax):
79    # MessageID ::= INTEGER (0 ..  maxInt)
80    pass
81
82
83class LDAPOID(OctetString):
84    # LDAPOID ::= OCTET STRING -- Constrained to <numericoid>
85    #                             -- [RFC4512]
86
87    # subtypeSpec = numericOIDConstraint
88    pass
89
90
91class LDAPDN(LDAPString):
92    # LDAPDN ::= LDAPString -- Constrained to <distinguishedName>
93    #                         -- [RFC4514]
94
95    # subtypeSpec = distinguishedName
96    pass
97
98
99class RelativeLDAPDN(LDAPString):
100    # RelativeLDAPDN ::= LDAPString -- Constrained to <name-component>
101    #                         -- [RFC4514]
102
103    # subtypeSpec = LDAPString.subtypeSpec + nameComponentConstraint
104    pass
105
106
107class AttributeDescription(LDAPString):
108    # AttributeDescription ::= LDAPString -- Constrained to <attributedescription>
109    #                         -- [RFC4512]
110
111    # subtypeSpec = LDAPString.subtypeSpec + attributeDescriptionConstraint
112    pass
113
114
115class AttributeValue(OctetString):
116    # AttributeValue ::= OCTET STRING
117    encoding = 'utf-8'
118
119
120class AssertionValue(OctetString):
121    # AssertionValue ::= OCTET STRING
122    encoding = 'utf-8'
123
124
125class AttributeValueAssertion(Sequence):
126    # AttributeValueAssertion ::= SEQUENCE {
127    #     attributeDesc   AttributeDescription,
128    #     assertionValue  AssertionValue }
129    componentType = NamedTypes(NamedType('attributeDesc', AttributeDescription()),
130                               NamedType('assertionValue', AssertionValue()))
131
132
133class MatchingRuleId(LDAPString):
134    # MatchingRuleId ::= LDAPString
135    pass
136
137
138class Vals(SetOf):
139    # vals       SET OF value AttributeValue }
140    componentType = AttributeValue()
141
142
143class ValsAtLeast1(SetOf):
144    # vals       SET OF value AttributeValue }
145    componentType = AttributeValue()
146    subtypeSpec = SetOf.subtypeSpec + size1ToMaxConstraint
147
148
149class PartialAttribute(Sequence):
150    # PartialAttribute ::= SEQUENCE {
151    #     type       AttributeDescription,
152    #     vals       SET OF value AttributeValue }
153    componentType = NamedTypes(NamedType('type', AttributeDescription()),
154                               NamedType('vals', Vals()))
155
156
157class Attribute(Sequence):
158    # Attribute ::= PartialAttribute(WITH COMPONENTS {
159    #     ...,
160    #     vals (SIZE(1..MAX))})
161    componentType = NamedTypes(NamedType('type', AttributeDescription()),
162                               # NamedType('vals', ValsAtLeast1()))
163                               NamedType('vals', Vals()))  # changed from ValsAtLeast1() to allow empty member values in groups - this should not be as per rfc4511 4.1.7, but openldap accept it
164
165
166class AttributeList(SequenceOf):
167    # AttributeList ::= SEQUENCE OF attribute Attribute
168    componentType = Attribute()
169
170
171class Simple(OctetString):
172    # simple                  [0] OCTET STRING,
173    tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 0))
174    encoding = 'utf-8'
175
176
177class Credentials(OctetString):
178    # credentials             OCTET STRING
179    encoding = 'utf-8'
180
181
182class SaslCredentials(Sequence):
183    # SaslCredentials ::= SEQUENCE {
184    #     mechanism               LDAPString,
185    #     credentials             OCTET STRING OPTIONAL }
186    tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 3))
187    componentType = NamedTypes(NamedType('mechanism', LDAPString()),
188                               OptionalNamedType('credentials', Credentials()))
189
190
191# not in RFC4511 but used by Microsoft to embed the NTLM protocol in the BindRequest (Sicily Protocol)
192class SicilyPackageDiscovery(OctetString):
193    # sicilyPackageDiscovery  [9] OCTET STRING,
194    tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 9))
195    encoding = 'utf-8'
196
197
198# not in RFC4511 but used by Microsoft to embed the NTLM protocol in the BindRequest (Sicily Protocol)
199class SicilyNegotiate(OctetString):
200    # sicilyNegotiate  [10] OCTET STRING,
201    tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 10))
202    encoding = 'utf-8'
203
204
205# not in RFC4511 but used by Microsoft to embed the NTLM protocol in the BindRequest (Sicily Protocol)
206class SicilyResponse(OctetString):
207    # sicilyResponse  [11] OCTET STRING,
208    tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 11))
209    encoding = 'utf-8'
210
211
212class AuthenticationChoice(Choice):
213    # AuthenticationChoice ::= CHOICE {
214    #     simple                  [0] OCTET STRING,
215    #                             -- 1 and 2 reserved
216    #     sasl                    [3] SaslCredentials,
217    # ... }
218
219    # from https://msdn.microsoft.com/en-us/library/cc223498.aspx  # legacy NTLM authentication for Windows Active Directory
220    # sicilyPackageDiscovery [9]    OCTET STRING
221    # sicilyNegotiate        [10]   OCTET STRING
222    # sicilyResponse         [11]   OCTET STRING  }
223
224    componentType = NamedTypes(NamedType('simple', Simple()),
225                               NamedType('sasl', SaslCredentials()),
226                               NamedType('sicilyPackageDiscovery', SicilyPackageDiscovery()),
227                               NamedType('sicilyNegotiate', SicilyNegotiate()),
228                               NamedType('sicilyResponse', SicilyResponse()),
229                               )
230
231
232class Version(Integer):
233    # version                 INTEGER (1 ..  127),
234    subtypeSpec = Integer.subtypeSpec + rangeInt1To127Constraint
235
236
237class ResultCode(Enumerated):
238    # resultCode         ENUMERATED {
239    #     success                      (0),
240    #     operationsError              (1),
241    #     protocolError                (2),
242    #     timeLimitExceeded            (3),
243    #     sizeLimitExceeded            (4),
244    #     compareFalse                 (5),
245    #     compareTrue                  (6),
246    #     authMethodNotSupported       (7),
247    #     strongerAuthRequired         (8),
248    #          -- 9 reserved --
249    #     referral                     (10),
250    #     adminLimitExceeded           (11),
251    #     unavailableCriticalExtension (12),
252    #     confidentialityRequired      (13),
253    #     saslBindInProgress           (14),
254    #     noSuchAttribute              (16),
255    #     undefinedAttributeType       (17),
256    #     inappropriateMatching        (18),
257    #     constraintViolation          (19),
258    #     attributeOrValueExists       (20),
259    #     invalidAttributeSyntax       (21),
260    #          -- 22-31 unused --
261    #     noSuchObject                 (32),
262    #     aliasProblem                 (33),
263    #     invalidDNSyntax              (34),
264    #          -- 35 reserved for undefined isLeaf --
265    #     aliasDereferencingProblem    (36),
266    #          -- 37-47 unused --
267    #     inappropriateAuthentication  (48),
268    #     invalidCredentials           (49),
269    #     insufficientAccessRights     (50),
270    #     busy                         (51),
271    #     unavailable                  (52),
272    #     unwillingToPerform           (53),
273    #     loopDetect                   (54),
274    #          -- 55-63 unused --
275    #     namingViolation              (64),
276    #     objectClassViolation         (65),
277    #     notAllowedOnNonLeaf          (66),
278    #     notAllowedOnRDN              (67),
279    #     entryAlreadyExists           (68),
280    #     objectClassModsProhibited    (69),
281    #          -- 70 reserved for CLDAP --
282    #     affectsMultipleDSAs          (71),
283    #          -- 72-79 unused --
284    #     other                        (80),
285    #     ...  }
286    #
287    #     from IANA ldap-parameters:
288    #     lcupResourcesExhausted        113        IESG                             [RFC3928]
289    #     lcupSecurityViolation         114        IESG                             [RFC3928]
290    #     lcupInvalidData               115        IESG                             [RFC3928]
291    #     lcupUnsupportedScheme         116        IESG                             [RFC3928]
292    #     lcupReloadRequired            117        IESG                             [RFC3928]
293    #     canceled                      118        IESG                             [RFC3909]
294    #     noSuchOperation               119        IESG                             [RFC3909]
295    #     tooLate                       120        IESG                             [RFC3909]
296    #     cannotCancel                  121        IESG                             [RFC3909]
297    #     assertionFailed               122        IESG                             [RFC4528]
298    #     authorizationDenied           123        WELTMAN                          [RFC4370]
299    #     e-syncRefreshRequired         4096       [Kurt_Zeilenga] [Jong_Hyuk_Choi] [RFC4533]
300    namedValues = NamedValues(('success', 0),
301                              ('operationsError', 1),
302                              ('protocolError', 2),
303                              ('timeLimitExceeded', 3),
304                              ('sizeLimitExceeded', 4),
305                              ('compareFalse', 5),
306                              ('compareTrue', 6),
307                              ('authMethodNotSupported', 7),
308                              ('strongerAuthRequired', 8),
309                              ('referral', 10),
310                              ('adminLimitExceeded', 11),
311                              ('unavailableCriticalExtension', 12),
312                              ('confidentialityRequired', 13),
313                              ('saslBindInProgress', 14),
314                              ('noSuchAttribute', 16),
315                              ('undefinedAttributeType', 17),
316                              ('inappropriateMatching', 18),
317                              ('constraintViolation', 19),
318                              ('attributeOrValueExists', 20),
319                              ('invalidAttributeSyntax', 21),
320                              ('noSuchObject', 32),
321                              ('aliasProblem', 33),
322                              ('invalidDNSyntax', 34),
323                              ('aliasDereferencingProblem', 36),
324                              ('inappropriateAuthentication', 48),
325                              ('invalidCredentials', 49),
326                              ('insufficientAccessRights', 50),
327                              ('busy', 51),
328                              ('unavailable', 52),
329                              ('unwillingToPerform', 53),
330                              ('loopDetected', 54),
331                              ('namingViolation', 64),
332                              ('objectClassViolation', 65),
333                              ('notAllowedOnNonLeaf', 66),
334                              ('notAllowedOnRDN', 67),
335                              ('entryAlreadyExists', 68),
336                              ('objectClassModsProhibited', 69),
337                              ('affectMultipleDSAs', 71),
338                              ('other', 80),
339                              ('lcupResourcesExhausted', 113),
340                              ('lcupSecurityViolation', 114),
341                              ('lcupInvalidData', 115),
342                              ('lcupUnsupportedScheme', 116),
343                              ('lcupReloadRequired', 117),
344                              ('canceled', 118),
345                              ('noSuchOperation', 119),
346                              ('tooLate', 120),
347                              ('cannotCancel', 121),
348                              ('assertionFailed', 122),
349                              ('authorizationDenied', 123),
350                              ('e-syncRefreshRequired', 4096))
351
352    subTypeSpec = Enumerated.subtypeSpec + responseValueConstraint
353
354
355class URI(LDAPString):
356    # URI ::= LDAPString     -- limited to characters permitted in
357    #                      -- URIs
358
359    # subtypeSpec = LDAPString.subTypeSpec + uriConstrain
360    pass
361
362
363class Referral(SequenceOf):
364    # Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI
365    tagSet = SequenceOf.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 3))
366    componentType = URI()
367
368
369class ServerSaslCreds(OctetString):
370    # serverSaslCreds    [7] OCTET STRING OPTIONAL
371    tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 7))
372    encoding = 'utf-8'
373
374
375class LDAPResult(Sequence):
376    # LDAPResult ::= SEQUENCE {
377    #     resultCode         ENUMERATED {
378    #         success                      (0),
379    #         operationsError              (1),
380    #         protocolError                (2),
381    #         timeLimitExceeded            (3),
382    #         sizeLimitExceeded            (4),
383    #         compareFalse                 (5),
384    #         compareTrue                  (6),
385    #         authMethodNotSupported       (7),
386    #         strongerAuthRequired         (8),
387    #              -- 9 reserved --
388    #         referral                     (10),
389    #         adminLimitExceeded           (11),
390    #         unavailableCriticalExtension (12),
391    #         confidentialityRequired      (13),
392    #         saslBindInProgress           (14),
393    #         noSuchAttribute              (16),
394    #         undefinedAttributeType       (17),
395    #         inappropriateMatching        (18),
396    #         constraintViolation          (19),
397    #         attributeOrValueExists       (20),
398    #         invalidAttributeSyntax       (21),
399    #              -- 22-31 unused --
400    #         noSuchObject                 (32),
401    #         aliasProblem                 (33),
402    #         invalidDNSyntax              (34),
403    #              -- 35 reserved for undefined isLeaf --
404    #         aliasDereferencingProblem    (36),
405    #              -- 37-47 unused --
406    #         inappropriateAuthentication  (48),
407    #         invalidCredentials           (49),
408    #         insufficientAccessRights     (50),
409    #         busy                         (51),
410    #         unavailable                  (52),
411    #         unwillingToPerform           (53),
412    #         loopDetect                   (54),
413    #              -- 55-63 unused --
414    #         namingViolation              (64),
415    #         objectClassViolation         (65),
416    #         notAllowedOnNonLeaf          (66),
417    #         notAllowedOnRDN              (67),
418    #         entryAlreadyExists           (68),
419    #         objectClassModsProhibited    (69),
420    #              -- 70 reserved for CLDAP --
421    #         affectsMultipleDSAs          (71),
422    #              -- 72-79 unused --
423    #         other                        (80),
424    #         ...  },
425    #     matchedDN          LDAPDN,
426    #     diagnosticMessage  LDAPString,
427    #     referral           [3] Referral OPTIONAL }
428    componentType = NamedTypes(NamedType('resultCode', ResultCode()),
429                               NamedType('matchedDN', LDAPDN()),
430                               NamedType('diagnosticMessage', LDAPString()),
431                               OptionalNamedType('referral', Referral()))
432
433
434class Criticality(Boolean):
435    # criticality             BOOLEAN DEFAULT FALSE
436    defaultValue = False
437
438
439class ControlValue(OctetString):
440    # controlValue            OCTET STRING
441    encoding = 'utf-8'
442
443
444class Control(Sequence):
445    # Control ::= SEQUENCE {
446    #     controlType             LDAPOID,
447    #     criticality             BOOLEAN DEFAULT FALSE,
448    #     controlValue            OCTET STRING OPTIONAL }
449    componentType = NamedTypes(NamedType('controlType', LDAPOID()),
450                               DefaultedNamedType('criticality', Criticality()),
451                               OptionalNamedType('controlValue', ControlValue()))
452
453
454class Controls(SequenceOf):
455    # Controls ::= SEQUENCE OF control Control
456    tagSet = SequenceOf.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 0))
457    componentType = Control()
458
459
460class Scope(Enumerated):
461    # scope           ENUMERATED {
462    #     baseObject              (0),
463    #     singleLevel             (1),
464    #     wholeSubtree            (2),
465    namedValues = NamedValues(('baseObject', 0),
466                              ('singleLevel', 1),
467                              ('wholeSubtree', 2))
468
469
470class DerefAliases(Enumerated):
471    # derefAliases    ENUMERATED {
472    #     neverDerefAliases       (0),
473    #     derefInSearching        (1),
474    #     derefFindingBaseObj     (2),
475    #     derefAlways             (3) },
476    namedValues = NamedValues(('neverDerefAliases', 0),
477                              ('derefInSearching', 1),
478                              ('derefFindingBaseObj', 2),
479                              ('derefAlways', 3))
480
481
482class TypesOnly(Boolean):
483    # typesOnly       BOOLEAN
484    pass
485
486
487class Selector(LDAPString):
488    #     -- The LDAPString is constrained to
489    #     -- <attributeSelector> in Section 4.5.1.8
490
491    # subtypeSpec = LDAPString.subtypeSpec + attributeSelectorConstraint
492    pass
493
494
495class AttributeSelection(SequenceOf):
496    # AttributeSelection ::= SEQUENCE OF selector LDAPString
497    #     -- The LDAPString is constrained to
498    #     -- <attributeSelector> in Section 4.5.1.8
499    componentType = Selector()
500
501
502class MatchingRule(MatchingRuleId):
503    # matchingRule    [1] MatchingRuleId
504    tagSet = MatchingRuleId.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 1))
505
506
507class Type(AttributeDescription):
508    # type            [2] AttributeDescription
509    tagSet = AttributeDescription.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 2))
510
511
512class MatchValue(AssertionValue):
513    # matchValue      [3] AssertionValue,
514    tagSet = AssertionValue.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 3))
515
516
517class DnAttributes(Boolean):
518    # dnAttributes    [4] BOOLEAN DEFAULT FALSE }
519    tagSet = Boolean.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 4))
520    defaultValue = Boolean(False)
521
522
523class MatchingRuleAssertion(Sequence):
524    # MatchingRuleAssertion ::= SEQUENCE {
525    #     matchingRule    [1] MatchingRuleId OPTIONAL,
526    #     type            [2] AttributeDescription OPTIONAL,
527    #     matchValue      [3] AssertionValue,
528    #     dnAttributes    [4] BOOLEAN DEFAULT FALSE }
529    componentType = NamedTypes(OptionalNamedType('matchingRule', MatchingRule()),
530                               OptionalNamedType('type', Type()),
531                               NamedType('matchValue', MatchValue()),
532                               DefaultedNamedType('dnAttributes', DnAttributes()))
533
534
535class Initial(AssertionValue):
536    # initial [0] AssertionValue,  -- can occur at most once
537    tagSet = AssertionValue.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 0))
538
539
540class Any(AssertionValue):
541    # any [1] AssertionValue,
542    tagSet = AssertionValue.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 1))
543
544
545class Final(AssertionValue):
546    # final [1] AssertionValue,  -- can occur at most once
547    tagSet = AssertionValue.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 2))
548
549
550class Substring(Choice):
551    # substring CHOICE {
552    #     initial [0] AssertionValue,  -- can occur at most once
553    #     any     [1] AssertionValue,
554    #     final   [2] AssertionValue } -- can occur at most once
555    #     }
556    componentType = NamedTypes(NamedType('initial', Initial()),
557                               NamedType('any', Any()),
558                               NamedType('final', Final()))
559
560
561class Substrings(SequenceOf):
562    # substrings     SEQUENCE SIZE (1..MAX) OF substring CHOICE {
563    # ...
564    # }
565    subtypeSpec = SequenceOf.subtypeSpec + size1ToMaxConstraint
566    componentType = Substring()
567
568
569class SubstringFilter(Sequence):
570    #     SubstringFilter ::= SEQUENCE {
571    #         type           AttributeDescription,
572    #         substrings     SEQUENCE SIZE (1..MAX) OF substring CHOICE {
573    #             initial [0] AssertionValue,  -- can occur at most once
574    #             any     [1] AssertionValue,
575    #             final   [2] AssertionValue } -- can occur at most once
576    #             }
577    tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 4))
578    componentType = NamedTypes(NamedType('type', AttributeDescription()),
579                               NamedType('substrings', Substrings()))
580
581
582class And(SetOf):
583    # and             [0] SET SIZE (1..MAX) OF filter Filter
584    tagSet = SetOf.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 0))
585    subtypeSpec = SetOf.subtypeSpec + size1ToMaxConstraint
586
587
588class Or(SetOf):
589    # or              [1] SET SIZE (1..MAX) OF filter Filter
590    tagSet = SetOf.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 1))
591    subtypeSpec = SetOf.subtypeSpec + size1ToMaxConstraint
592
593
594class Not(Choice):
595    # not             [2] Filter
596    pass  # defined after Filter definition to allow recursion
597
598
599class EqualityMatch(AttributeValueAssertion):
600    # equalityMatch   [3] AttributeValueAssertion
601    tagSet = AttributeValueAssertion.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 3))
602
603
604class GreaterOrEqual(AttributeValueAssertion):
605    # greaterOrEqual  [5] AttributeValueAssertion
606    tagSet = AttributeValueAssertion.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 5))
607
608
609class LessOrEqual(AttributeValueAssertion):
610    # lessOrEqual     [6] AttributeValueAssertion
611    tagSet = AttributeValueAssertion.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 6))
612
613
614class Present(AttributeDescription):
615    # present         [7] AttributeDescription
616    tagSet = AttributeDescription.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 7))
617
618
619class ApproxMatch(AttributeValueAssertion):
620    # approxMatch     [8] AttributeValueAssertion
621    tagSet = AttributeValueAssertion.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 8))
622
623
624class ExtensibleMatch(MatchingRuleAssertion):
625    # extensibleMatch [9] MatchingRuleAssertion
626    tagSet = MatchingRuleAssertion.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 9))
627
628
629class Filter(Choice):
630    # Filter ::= CHOICE {
631    #     and             [0] SET SIZE (1..MAX) OF filter Filter,
632    #     or              [1] SET SIZE (1..MAX) OF filter Filter,
633    #     not             [2] Filter,
634    #     equalityMatch   [3] AttributeValueAssertion,
635    #     substrings      [4] SubstringFilter,
636    #     greaterOrEqual  [5] AttributeValueAssertion,
637    #     lessOrEqual     [6] AttributeValueAssertion,
638    #     present         [7] AttributeDescription,
639    #     approxMatch     [8] AttributeValueAssertion,
640    #     extensibleMatch [9] MatchingRuleAssertion,
641    #          ...  }
642    componentType = NamedTypes(NamedType('and', And()),
643                               NamedType('or', Or()),
644                               NamedType('notFilter', Not()),
645                               NamedType('equalityMatch', EqualityMatch()),
646                               NamedType('substringFilter', SubstringFilter()),
647                               NamedType('greaterOrEqual', GreaterOrEqual()),
648                               NamedType('lessOrEqual', LessOrEqual()),
649                               NamedType('present', Present()),
650                               NamedType('approxMatch', ApproxMatch()),
651                               NamedType('extensibleMatch', ExtensibleMatch()))
652
653
654And.componentType = Filter()
655Or.componentType = Filter()
656Not.componentType = NamedTypes(NamedType('innerNotFilter', Filter()))
657Not.tagSet = Filter.tagSet.tagExplicitly(Tag(tagClassContext, tagFormatConstructed, 2))  # as per RFC4511 page 23
658
659
660class PartialAttributeList(SequenceOf):
661    # PartialAttributeList ::= SEQUENCE OF
662    #     partialAttribute PartialAttribute
663    componentType = PartialAttribute()
664
665
666class Operation(Enumerated):
667    # operation       ENUMERATED {
668    #     add     (0),
669    #     delete  (1),
670    #     replace (2),
671    #     ...  }
672    namedValues = NamedValues(('add', 0),
673                              ('delete', 1),
674                              ('replace', 2),
675                              ('increment', 3))
676
677
678class Change(Sequence):
679    # change SEQUENCE {
680    #     operation       ENUMERATED {
681    #         add     (0),
682    #         delete  (1),
683    #         replace (2),
684    #         ...  },
685    #     modification    PartialAttribute } }
686    componentType = NamedTypes(NamedType('operation', Operation()),
687                               NamedType('modification', PartialAttribute()))
688
689
690class Changes(SequenceOf):
691    # changes         SEQUENCE OF change SEQUENCE
692    componentType = Change()
693
694
695class DeleteOldRDN(Boolean):
696    # deleteoldrdn    BOOLEAN
697    pass
698
699
700class NewSuperior(LDAPDN):
701    # newSuperior     [0] LDAPDN
702    tagSet = LDAPDN.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 0))
703
704
705class RequestName(LDAPOID):
706    # requestName      [0] LDAPOID
707    tagSet = LDAPOID.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 0))
708
709
710class RequestValue(OctetString):
711    # requestValue     [1] OCTET STRING
712    tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 1))
713    encoding = 'utf-8'
714
715
716class ResponseName(LDAPOID):
717    # responseName      [10] LDAPOID
718    tagSet = LDAPOID.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 10))
719
720
721class ResponseValue(OctetString):
722    # responseValue     [11] OCTET STRING
723    tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 11))
724    encoding = 'utf-8'
725
726
727class IntermediateResponseName(LDAPOID):
728    # responseName      [0] LDAPOID
729    tagSet = LDAPOID.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 0))
730
731
732class IntermediateResponseValue(OctetString):
733    # responseValue     [1] OCTET STRING
734    tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 1))
735    encoding = 'utf-8'
736
737
738# operations
739class BindRequest(Sequence):
740    # BindRequest ::= [APPLICATION 0] SEQUENCE {
741    #     version                 INTEGER (1 ..  127),
742    #     name                    LDAPDN,
743    #     authentication          AuthenticationChoice }
744    tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 0))
745    componentType = NamedTypes(NamedType('version', Version()),
746                               NamedType('name', LDAPDN()),
747                               NamedType('authentication', AuthenticationChoice()))
748
749
750class BindResponse(Sequence):
751    # BindResponse ::= [APPLICATION 1] SEQUENCE {
752    #     COMPONENTS OF LDAPResult,
753    #     serverSaslCreds    [7] OCTET STRING OPTIONAL }
754    tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 1))
755    componentType = NamedTypes(NamedType('resultCode', ResultCode()),
756                               NamedType('matchedDN', LDAPDN()),
757                               NamedType('diagnosticMessage', LDAPString()),
758                               OptionalNamedType('referral', Referral()),
759                               OptionalNamedType('serverSaslCreds', ServerSaslCreds()))
760
761
762class UnbindRequest(Null):
763    # UnbindRequest ::= [APPLICATION 2] NULL
764    tagSet = Null.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatSimple, 2))
765
766
767class SearchRequest(Sequence):
768    # SearchRequest ::= [APPLICATION 3] SEQUENCE {
769    #     baseObject      LDAPDN,
770    #     scope           ENUMERATED {
771    #         baseObject              (0),
772    #         singleLevel             (1),
773    #         wholeSubtree            (2),
774    #     ...  },
775    #     derefAliases    ENUMERATED {
776    #         neverDerefAliases       (0),
777    #         derefInSearching        (1),
778    #         derefFindingBaseObj     (2),
779    #         derefAlways             (3) },
780    #     sizeLimit       INTEGER (0 ..  maxInt),
781    #     timeLimit       INTEGER (0 ..  maxInt),
782    #     typesOnly       BOOLEAN,
783    #     filter          Filter,
784    #     attributes      AttributeSelection }
785    tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 3))
786    componentType = NamedTypes(NamedType('baseObject', LDAPDN()),
787                               NamedType('scope', Scope()),
788                               NamedType('derefAliases', DerefAliases()),
789                               NamedType('sizeLimit', Integer0ToMax()),
790                               NamedType('timeLimit', Integer0ToMax()),
791                               NamedType('typesOnly', TypesOnly()),
792                               NamedType('filter', Filter()),
793                               NamedType('attributes', AttributeSelection()))
794
795
796class SearchResultReference(SequenceOf):
797    # SearchResultReference ::= [APPLICATION 19] SEQUENCE
798    #     SIZE (1..MAX) OF uri URI
799    tagSet = SequenceOf.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 19))
800    subtypeSpec = SequenceOf.subtypeSpec + size1ToMaxConstraint
801    componentType = URI()
802
803
804class SearchResultEntry(Sequence):
805    # SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
806    #     objectName      LDAPDN,
807    #     attributes      PartialAttributeList }
808    tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 4))
809    componentType = NamedTypes(NamedType('object', LDAPDN()),
810                               NamedType('attributes', PartialAttributeList()))
811
812
813class SearchResultDone(LDAPResult):
814    # SearchResultDone ::= [APPLICATION 5] LDAPResult
815    tagSet = LDAPResult.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 5))
816
817
818class ModifyRequest(Sequence):
819    # ModifyRequest ::= [APPLICATION 6] SEQUENCE {
820    #     object          LDAPDN,
821    #     changes         SEQUENCE OF change SEQUENCE {
822    #         operation       ENUMERATED {
823    #             add     (0),
824    #             delete  (1),
825    #             replace (2),
826    #             ...  },
827    #         modification    PartialAttribute } }
828    tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 6))
829    componentType = NamedTypes(NamedType('object', LDAPDN()),
830                               NamedType('changes', Changes()))
831
832
833class ModifyResponse(LDAPResult):
834    # ModifyResponse ::= [APPLICATION 7] LDAPResult
835    tagSet = LDAPResult.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 7))
836
837
838class AddRequest(Sequence):
839    # AddRequest ::= [APPLICATION 8] SEQUENCE {
840    #     entry           LDAPDN,
841    #     attributes      AttributeList }
842    tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 8))
843    componentType = NamedTypes(NamedType('entry', LDAPDN()),
844                               NamedType('attributes', AttributeList()))
845
846
847class AddResponse(LDAPResult):
848    # AddResponse ::= [APPLICATION 9] LDAPResult
849    tagSet = LDAPResult.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 9))
850
851
852class DelRequest(LDAPDN):
853    # DelRequest ::= [APPLICATION 10] LDAPDN
854    tagSet = LDAPDN.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatSimple, 10))
855
856
857class DelResponse(LDAPResult):
858    # DelResponse ::= [APPLICATION 11] LDAPResult
859    tagSet = LDAPResult.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 11))
860
861
862class ModifyDNRequest(Sequence):
863    # ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
864    #     entry           LDAPDN,
865    #     newrdn          RelativeLDAPDN,
866    #     deleteoldrdn    BOOLEAN,
867    #     newSuperior     [0] LDAPDN OPTIONAL }
868    tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 12))
869    componentType = NamedTypes(NamedType('entry', LDAPDN()),
870                               NamedType('newrdn', RelativeLDAPDN()),
871                               NamedType('deleteoldrdn', DeleteOldRDN()),
872                               OptionalNamedType('newSuperior', NewSuperior()))
873
874
875class ModifyDNResponse(LDAPResult):
876    # ModifyDNResponse ::= [APPLICATION 13] LDAPResult
877    tagSet = LDAPResult.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 13))
878
879
880class CompareRequest(Sequence):
881    # CompareRequest ::= [APPLICATION 14] SEQUENCE {
882    #     entry           LDAPDN,
883    #     ava             AttributeValueAssertion }
884    tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 14))
885    componentType = NamedTypes(NamedType('entry', LDAPDN()),
886                               NamedType('ava', AttributeValueAssertion()))
887
888
889class CompareResponse(LDAPResult):
890    # CompareResponse ::= [APPLICATION 15] LDAPResult
891    tagSet = LDAPResult.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 15))
892
893
894class AbandonRequest(MessageID):
895    # AbandonRequest ::= [APPLICATION 16] MessageID
896    tagSet = MessageID.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatSimple, 16))
897
898
899class ExtendedRequest(Sequence):
900    # ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
901    #     requestName      [0] LDAPOID,
902    #     requestValue     [1] OCTET STRING OPTIONAL }
903    tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 23))
904    componentType = NamedTypes(NamedType('requestName', RequestName()),
905                               OptionalNamedType('requestValue', RequestValue()))
906
907
908class ExtendedResponse(Sequence):
909    # ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
910    #     COMPONENTS OF LDAPResult,
911    #     responseName     [10] LDAPOID OPTIONAL,
912    #     responseValue    [11] OCTET STRING OPTIONAL }
913    tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 24))
914    componentType = NamedTypes(NamedType('resultCode', ResultCode()),
915                               NamedType('matchedDN', LDAPDN()),
916                               NamedType('diagnosticMessage', LDAPString()),
917                               OptionalNamedType('referral', Referral()),
918                               OptionalNamedType('responseName', ResponseName()),
919                               OptionalNamedType('responseValue', ResponseValue()))
920
921
922class IntermediateResponse(Sequence):
923    # IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
924    #     responseName     [0] LDAPOID OPTIONAL,
925    #     responseValue    [1] OCTET STRING OPTIONAL }
926    tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 25))
927    componentType = NamedTypes(OptionalNamedType('responseName', IntermediateResponseName()),
928                               OptionalNamedType('responseValue', IntermediateResponseValue()))
929
930
931class ProtocolOp(Choice):
932    # protocolOp      CHOICE {
933    #     bindRequest           BindRequest,
934    #     bindResponse          BindResponse,
935    #     unbindRequest         UnbindRequest,
936    #     searchRequest         SearchRequest,
937    #     searchResEntry        SearchResultEntry,
938    #     searchResDone         SearchResultDone,
939    #     searchResRef          SearchResultReference,
940    #     modifyRequest         ModifyRequest,
941    #     modifyResponse        ModifyResponse,
942    #     addRequest            AddRequest,
943    #     addResponse           AddResponse,
944    #     delRequest            DelRequest,
945    #     delResponse           DelResponse,
946    #     modDNRequest          ModifyDNRequest,
947    #     modDNResponse         ModifyDNResponse,
948    #     compareRequest        CompareRequest,
949    #     compareResponse       CompareResponse,
950    #     abandonRequest        AbandonRequest,
951    #     extendedReq           ExtendedRequest,
952    #     extendedResp          ExtendedResponse,
953    #     ...,
954    #     intermediateResponse  IntermediateResponse }
955    componentType = NamedTypes(NamedType('bindRequest', BindRequest()),
956                               NamedType('bindResponse', BindResponse()),
957                               NamedType('unbindRequest', UnbindRequest()),
958                               NamedType('searchRequest', SearchRequest()),
959                               NamedType('searchResEntry', SearchResultEntry()),
960                               NamedType('searchResDone', SearchResultDone()),
961                               NamedType('searchResRef', SearchResultReference()),
962                               NamedType('modifyRequest', ModifyRequest()),
963                               NamedType('modifyResponse', ModifyResponse()),
964                               NamedType('addRequest', AddRequest()),
965                               NamedType('addResponse', AddResponse()),
966                               NamedType('delRequest', DelRequest()),
967                               NamedType('delResponse', DelResponse()),
968                               NamedType('modDNRequest', ModifyDNRequest()),
969                               NamedType('modDNResponse', ModifyDNResponse()),
970                               NamedType('compareRequest', CompareRequest()),
971                               NamedType('compareResponse', CompareResponse()),
972                               NamedType('abandonRequest', AbandonRequest()),
973                               NamedType('extendedReq', ExtendedRequest()),
974                               NamedType('extendedResp', ExtendedResponse()),
975                               NamedType('intermediateResponse', IntermediateResponse()))
976
977
978class LDAPMessage(Sequence):
979    # LDAPMessage ::= SEQUENCE {
980    #     messageID       MessageID,
981    #     protocolOp      CHOICE {
982    #         bindRequest           BindRequest,
983    #         bindResponse          BindResponse,
984    #         unbindRequest         UnbindRequest,
985    #         searchRequest         SearchRequest,
986    #         searchResEntry        SearchResultEntry,
987    #         searchResDone         SearchResultDone,
988    #         searchResRef          SearchResultReference,
989    #         modifyRequest         ModifyRequest,
990    #         modifyResponse        ModifyResponse,
991    #         addRequest            AddRequest,
992    #         addResponse           AddResponse,
993    #         delRequest            DelRequest,
994    #         delResponse           DelResponse,
995    #         modDNRequest          ModifyDNRequest,
996    #         modDNResponse         ModifyDNResponse,
997    #         compareRequest        CompareRequest,
998    #         compareResponse       CompareResponse,
999    #         abandonRequest        AbandonRequest,
1000    #         extendedReq           ExtendedRequest,
1001    #         extendedResp          ExtendedResponse,
1002    #         ...,
1003    #         intermediateResponse  IntermediateResponse },
1004    #     controls       [0] Controls OPTIONAL }
1005    componentType = NamedTypes(NamedType('messageID', MessageID()),
1006                               NamedType('protocolOp', ProtocolOp()),
1007                               OptionalNamedType('controls', Controls()))
1008