diff --git a/.travis.yml b/.travis.yml
index f44e6cfb..fde3108c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,11 @@
language: python
+addons:
+ apt:
+ packages:
+ - ldap-utils
+ - slapd
+
matrix:
include:
- python: 2.7
diff --git a/moulinette/authenticators/ldap.py b/moulinette/authenticators/ldap.py
index 0320d375..a8d115a1 100644
--- a/moulinette/authenticators/ldap.py
+++ b/moulinette/authenticators/ldap.py
@@ -49,11 +49,10 @@ class Authenticator(BaseAuthenticator):
)
super(Authenticator, self).__init__(name, vendor, parameters, extra)
- if self.userdn:
- if "cn=external,cn=auth" in self.userdn:
- self.authenticate(None)
- else:
- self.con = None
+ if self.userdn and "cn=external,cn=auth" in self.userdn:
+ self.authenticate(None)
+ else:
+ self.con = None
def __del__(self):
"""Disconnect and free ressources"""
@@ -91,7 +90,12 @@ class Authenticator(BaseAuthenticator):
logger.warning("Error during ldap authentication process: %s", e)
raise
else:
- if who[3:] != self.userdn:
+ if (
+ "cn=external,cn=auth" in self.userdn
+ and who[3:] != "cn=admin,dc=yunohost,dc=org"
+ ):
+ raise MoulinetteError("Not logged in with the expected userdn ?!")
+ elif "cn=external,cn=auth" not in self.userdn and who[3:] != self.userdn:
raise MoulinetteError("Not logged in with the expected userdn ?!")
else:
self.con = con
@@ -175,7 +179,7 @@ class Authenticator(BaseAuthenticator):
"""
dn = rdn + "," + self.basedn
- ldif = modlist.addModlist(attr_dict)
+ ldif = modlist.addModlist(self._encode_dict(attr_dict))
try:
self.con.add_s(dn, ldif)
@@ -230,7 +234,9 @@ class Authenticator(BaseAuthenticator):
"""
dn = rdn + "," + self.basedn
actual_entry = self.search(base=dn, attrs=None)
- ldif = modlist.modifyModlist(actual_entry[0], attr_dict, ignore_oldexistent=1)
+ ldif = modlist.modifyModlist(
+ actual_entry[0], self._encode_dict(attr_dict), ignore_oldexistent=1
+ )
try:
if new_rdn:
@@ -293,3 +299,11 @@ class Authenticator(BaseAuthenticator):
else:
return (attr, value)
return None
+
+ def _encode_dict(self, _dict):
+ return {k: self._encode_list(v) for k, v in _dict.items()}
+
+ def _encode_list(self, _list):
+ if not isinstance(_list, list):
+ _list = [_list]
+ return [s.encode("utf-8") for s in _list]
diff --git a/test/ldap_files/__init__.py b/test/ldap_files/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/test/ldap_files/ldap_scheme.yml b/test/ldap_files/ldap_scheme.yml
new file mode 100644
index 00000000..266ab714
--- /dev/null
+++ b/test/ldap_files/ldap_scheme.yml
@@ -0,0 +1,84 @@
+parents:
+ ou=users:
+ ou: users
+ objectClass:
+ - organizationalUnit
+ - top
+
+ ou=domains:
+ ou: domains
+ objectClass:
+ - organizationalUnit
+ - top
+
+ ou=apps:
+ ou: apps
+ objectClass:
+ - organizationalUnit
+ - top
+
+ ou=permission:
+ ou: permission
+ objectClass:
+ - organizationalUnit
+ - top
+
+ ou=groups:
+ ou: groups
+ objectClass:
+ - organizationalUnit
+ - top
+
+ ou=sudo:
+ ou: sudo
+ objectClass:
+ - organizationalUnit
+ - top
+
+children:
+ cn=admin,ou=sudo:
+ cn: admin
+ sudoUser: admin
+ sudoHost: ALL
+ sudoCommand: ALL
+ sudoOption: "!authenticate"
+ objectClass:
+ - sudoRole
+ - top
+ cn=admins,ou=groups:
+ cn: admins
+ gidNumber: "4001"
+ memberUid: admin
+ objectClass:
+ - posixGroup
+ - top
+ cn=all_users,ou=groups:
+ cn: all_users
+ gidNumber: "4002"
+ objectClass:
+ - posixGroup
+ - groupOfNamesYnh
+ cn=visitors,ou=groups:
+ cn: visitors
+ gidNumber: "4003"
+ objectClass:
+ - posixGroup
+ - groupOfNamesYnh
+
+depends_children:
+ cn=mail.main,ou=permission:
+ cn: mail.main
+ gidNumber: "5001"
+ objectClass:
+ - posixGroup
+ - permissionYnh
+ groupPermission:
+ - "cn=all_users,ou=groups,dc=yunohost,dc=org"
+ cn=xmpp.main,ou=permission:
+ cn: xmpp.main
+ gidNumber: "5002"
+ objectClass:
+ - posixGroup
+ - permissionYnh
+ groupPermission:
+ - "cn=all_users,ou=groups,dc=yunohost,dc=org"
diff --git a/test/ldap_files/schema/core.schema b/test/ldap_files/schema/core.schema
new file mode 100644
index 00000000..1c92d14a
--- /dev/null
+++ b/test/ldap_files/schema/core.schema
@@ -0,0 +1,610 @@
+# OpenLDAP Core schema
+# $OpenLDAP$
+## This work is part of OpenLDAP Software .
+##
+## Copyright 1998-2019 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## .
+#
+## Portions Copyright (C) The Internet Society (1997-2006).
+## All Rights Reserved.
+##
+## This document and translations of it may be copied and furnished to
+## others, and derivative works that comment on or otherwise explain it
+## or assist in its implementation may be prepared, copied, published
+## and distributed, in whole or in part, without restriction of any
+## kind, provided that the above copyright notice and this paragraph are
+## included on all such copies and derivative works. However, this
+## document itself may not be modified in any way, such as by removing
+## the copyright notice or references to the Internet Society or other
+## Internet organizations, except as needed for the purpose of
+## developing Internet standards in which case the procedures for
+## copyrights defined in the Internet Standards process must be
+## followed, or as required to translate it into languages other than
+## English.
+##
+## The limited permissions granted above are perpetual and will not be
+## revoked by the Internet Society or its successors or assigns.
+##
+## This document and the information contained herein is provided on an
+## "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+## TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+## BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+## HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+## MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+#
+#
+# Includes LDAPv3 schema items from:
+# RFC 2252/2256 (LDAPv3)
+#
+# Select standard track schema items:
+# RFC 1274 (uid/dc)
+# RFC 2079 (URI)
+# RFC 2247 (dc/dcObject)
+# RFC 2587 (PKI)
+# RFC 2589 (Dynamic Directory Services)
+# RFC 4524 (associatedDomain)
+#
+# Select informational schema items:
+# RFC 2377 (uidObject)
+
+#
+# Standard attribute types from RFC 2256
+#
+
+# system schema
+#attributetype ( 2.5.4.0 NAME 'objectClass'
+# DESC 'RFC2256: object classes of the entity'
+# EQUALITY objectIdentifierMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
+
+# system schema
+#attributetype ( 2.5.4.1 NAME ( 'aliasedObjectName' 'aliasedEntryName' )
+# DESC 'RFC2256: name of aliased object'
+# EQUALITY distinguishedNameMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )
+
+attributetype ( 2.5.4.2 NAME 'knowledgeInformation'
+ DESC 'RFC2256: knowledge information'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
+
+# system schema
+#attributetype ( 2.5.4.3 NAME ( 'cn' 'commonName' )
+# DESC 'RFC2256: common name(s) for which the entity is known by'
+# SUP name )
+
+attributetype ( 2.5.4.4 NAME ( 'sn' 'surname' )
+ DESC 'RFC2256: last (family) name(s) for which the entity is known by'
+ SUP name )
+
+attributetype ( 2.5.4.5 NAME 'serialNumber'
+ DESC 'RFC2256: serial number of the entity'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{64} )
+
+# RFC 4519 definition ('countryName' in X.500 and RFC2256)
+attributetype ( 2.5.4.6 NAME ( 'c' 'countryName' )
+ DESC 'RFC4519: two-letter ISO-3166 country code'
+ SUP name
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.11
+ SINGLE-VALUE )
+
+#attributetype ( 2.5.4.6 NAME ( 'c' 'countryName' )
+# DESC 'RFC2256: ISO-3166 country 2-letter code'
+# SUP name SINGLE-VALUE )
+
+attributetype ( 2.5.4.7 NAME ( 'l' 'localityName' )
+ DESC 'RFC2256: locality which this object resides in'
+ SUP name )
+
+attributetype ( 2.5.4.8 NAME ( 'st' 'stateOrProvinceName' )
+ DESC 'RFC2256: state or province which this object resides in'
+ SUP name )
+
+attributetype ( 2.5.4.9 NAME ( 'street' 'streetAddress' )
+ DESC 'RFC2256: street address of this object'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+attributetype ( 2.5.4.10 NAME ( 'o' 'organizationName' )
+ DESC 'RFC2256: organization this object belongs to'
+ SUP name )
+
+attributetype ( 2.5.4.11 NAME ( 'ou' 'organizationalUnitName' )
+ DESC 'RFC2256: organizational unit this object belongs to'
+ SUP name )
+
+attributetype ( 2.5.4.12 NAME 'title'
+ DESC 'RFC2256: title associated with the entity'
+ SUP name )
+
+# system schema
+#attributetype ( 2.5.4.13 NAME 'description'
+# DESC 'RFC2256: descriptive information'
+# EQUALITY caseIgnoreMatch
+# SUBSTR caseIgnoreSubstringsMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
+
+# Deprecated by enhancedSearchGuide
+attributetype ( 2.5.4.14 NAME 'searchGuide'
+ DESC 'RFC2256: search guide, deprecated by enhancedSearchGuide'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.25 )
+
+attributetype ( 2.5.4.15 NAME 'businessCategory'
+ DESC 'RFC2256: business category'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+attributetype ( 2.5.4.16 NAME 'postalAddress'
+ DESC 'RFC2256: postal address'
+ EQUALITY caseIgnoreListMatch
+ SUBSTR caseIgnoreListSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
+
+attributetype ( 2.5.4.17 NAME 'postalCode'
+ DESC 'RFC2256: postal code'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{40} )
+
+attributetype ( 2.5.4.18 NAME 'postOfficeBox'
+ DESC 'RFC2256: Post Office Box'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{40} )
+
+attributetype ( 2.5.4.19 NAME 'physicalDeliveryOfficeName'
+ DESC 'RFC2256: Physical Delivery Office Name'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+attributetype ( 2.5.4.20 NAME 'telephoneNumber'
+ DESC 'RFC2256: Telephone Number'
+ EQUALITY telephoneNumberMatch
+ SUBSTR telephoneNumberSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.50{32} )
+
+attributetype ( 2.5.4.21 NAME 'telexNumber'
+ DESC 'RFC2256: Telex Number'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.52 )
+
+attributetype ( 2.5.4.22 NAME 'teletexTerminalIdentifier'
+ DESC 'RFC2256: Teletex Terminal Identifier'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.51 )
+
+attributetype ( 2.5.4.23 NAME ( 'facsimileTelephoneNumber' 'fax' )
+ DESC 'RFC2256: Facsimile (Fax) Telephone Number'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.22 )
+
+attributetype ( 2.5.4.24 NAME 'x121Address'
+ DESC 'RFC2256: X.121 Address'
+ EQUALITY numericStringMatch
+ SUBSTR numericStringSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{15} )
+
+attributetype ( 2.5.4.25 NAME 'internationaliSDNNumber'
+ DESC 'RFC2256: international ISDN number'
+ EQUALITY numericStringMatch
+ SUBSTR numericStringSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{16} )
+
+attributetype ( 2.5.4.26 NAME 'registeredAddress'
+ DESC 'RFC2256: registered postal address'
+ SUP postalAddress
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
+
+attributetype ( 2.5.4.27 NAME 'destinationIndicator'
+ DESC 'RFC2256: destination indicator'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{128} )
+
+attributetype ( 2.5.4.28 NAME 'preferredDeliveryMethod'
+ DESC 'RFC2256: preferred delivery method'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.14
+ SINGLE-VALUE )
+
+attributetype ( 2.5.4.29 NAME 'presentationAddress'
+ DESC 'RFC2256: presentation address'
+ EQUALITY presentationAddressMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.43
+ SINGLE-VALUE )
+
+attributetype ( 2.5.4.30 NAME 'supportedApplicationContext'
+ DESC 'RFC2256: supported application context'
+ EQUALITY objectIdentifierMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
+
+attributetype ( 2.5.4.31 NAME 'member'
+ DESC 'RFC2256: member of a group'
+ SUP distinguishedName )
+
+attributetype ( 2.5.4.32 NAME 'owner'
+ DESC 'RFC2256: owner (of the object)'
+ SUP distinguishedName )
+
+attributetype ( 2.5.4.33 NAME 'roleOccupant'
+ DESC 'RFC2256: occupant of role'
+ SUP distinguishedName )
+
+# system schema
+#attributetype ( 2.5.4.34 NAME 'seeAlso'
+# DESC 'RFC2256: DN of related object'
+# SUP distinguishedName )
+
+# system schema
+#attributetype ( 2.5.4.35 NAME 'userPassword'
+# DESC 'RFC2256/2307: password of user'
+# EQUALITY octetStringMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} )
+
+# Must be transferred using ;binary
+# with certificateExactMatch rule (per X.509)
+attributetype ( 2.5.4.36 NAME 'userCertificate'
+ DESC 'RFC2256: X.509 user certificate, use ;binary'
+ EQUALITY certificateExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )
+
+# Must be transferred using ;binary
+# with certificateExactMatch rule (per X.509)
+attributetype ( 2.5.4.37 NAME 'cACertificate'
+ DESC 'RFC2256: X.509 CA certificate, use ;binary'
+ EQUALITY certificateExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )
+
+# Must be transferred using ;binary
+attributetype ( 2.5.4.38 NAME 'authorityRevocationList'
+ DESC 'RFC2256: X.509 authority revocation list, use ;binary'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
+
+# Must be transferred using ;binary
+attributetype ( 2.5.4.39 NAME 'certificateRevocationList'
+ DESC 'RFC2256: X.509 certificate revocation list, use ;binary'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
+
+# Must be stored and requested in the binary form
+attributetype ( 2.5.4.40 NAME 'crossCertificatePair'
+ DESC 'RFC2256: X.509 cross certificate pair, use ;binary'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.10 )
+
+# system schema
+#attributetype ( 2.5.4.41 NAME 'name'
+# EQUALITY caseIgnoreMatch
+# SUBSTR caseIgnoreSubstringsMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
+
+attributetype ( 2.5.4.42 NAME ( 'givenName' 'gn' )
+ DESC 'RFC2256: first name(s) for which the entity is known by'
+ SUP name )
+
+attributetype ( 2.5.4.43 NAME 'initials'
+ DESC 'RFC2256: initials of some or all of names, but not the surname(s).'
+ SUP name )
+
+attributetype ( 2.5.4.44 NAME 'generationQualifier'
+ DESC 'RFC2256: name qualifier indicating a generation'
+ SUP name )
+
+attributetype ( 2.5.4.45 NAME 'x500UniqueIdentifier'
+ DESC 'RFC2256: X.500 unique identifier'
+ EQUALITY bitStringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )
+
+attributetype ( 2.5.4.46 NAME 'dnQualifier'
+ DESC 'RFC2256: DN qualifier'
+ EQUALITY caseIgnoreMatch
+ ORDERING caseIgnoreOrderingMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 )
+
+attributetype ( 2.5.4.47 NAME 'enhancedSearchGuide'
+ DESC 'RFC2256: enhanced search guide'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.21 )
+
+attributetype ( 2.5.4.48 NAME 'protocolInformation'
+ DESC 'RFC2256: protocol information'
+ EQUALITY protocolInformationMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )
+
+# system schema
+#attributetype ( 2.5.4.49 NAME 'distinguishedName'
+# EQUALITY distinguishedNameMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
+
+attributetype ( 2.5.4.50 NAME 'uniqueMember'
+ DESC 'RFC2256: unique member of a group'
+ EQUALITY uniqueMemberMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )
+
+attributetype ( 2.5.4.51 NAME 'houseIdentifier'
+ DESC 'RFC2256: house identifier'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
+
+# Must be transferred using ;binary
+attributetype ( 2.5.4.52 NAME 'supportedAlgorithms'
+ DESC 'RFC2256: supported algorithms'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.49 )
+
+# Must be transferred using ;binary
+attributetype ( 2.5.4.53 NAME 'deltaRevocationList'
+ DESC 'RFC2256: delta revocation list; use ;binary'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
+
+attributetype ( 2.5.4.54 NAME 'dmdName'
+ DESC 'RFC2256: name of DMD'
+ SUP name )
+
+attributetype ( 2.5.4.65 NAME 'pseudonym'
+ DESC 'X.520(4th): pseudonym for the object'
+ SUP name )
+
+# Standard object classes from RFC2256
+
+# system schema
+#objectclass ( 2.5.6.0 NAME 'top'
+# DESC 'RFC2256: top of the superclass chain'
+# ABSTRACT
+# MUST objectClass )
+
+# system schema
+#objectclass ( 2.5.6.1 NAME 'alias'
+# DESC 'RFC2256: an alias'
+# SUP top STRUCTURAL
+# MUST aliasedObjectName )
+
+objectclass ( 2.5.6.2 NAME 'country'
+ DESC 'RFC2256: a country'
+ SUP top STRUCTURAL
+ MUST c
+ MAY ( searchGuide $ description ) )
+
+objectclass ( 2.5.6.3 NAME 'locality'
+ DESC 'RFC2256: a locality'
+ SUP top STRUCTURAL
+ MAY ( street $ seeAlso $ searchGuide $ st $ l $ description ) )
+
+objectclass ( 2.5.6.4 NAME 'organization'
+ DESC 'RFC2256: an organization'
+ SUP top STRUCTURAL
+ MUST o
+ MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
+ x121Address $ registeredAddress $ destinationIndicator $
+ preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
+ telephoneNumber $ internationaliSDNNumber $
+ facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
+ postalAddress $ physicalDeliveryOfficeName $ st $ l $ description ) )
+
+objectclass ( 2.5.6.5 NAME 'organizationalUnit'
+ DESC 'RFC2256: an organizational unit'
+ SUP top STRUCTURAL
+ MUST ou
+ MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
+ x121Address $ registeredAddress $ destinationIndicator $
+ preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
+ telephoneNumber $ internationaliSDNNumber $
+ facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
+ postalAddress $ physicalDeliveryOfficeName $ st $ l $ description ) )
+
+objectclass ( 2.5.6.6 NAME 'person'
+ DESC 'RFC2256: a person'
+ SUP top STRUCTURAL
+ MUST ( sn $ cn )
+ MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )
+
+objectclass ( 2.5.6.7 NAME 'organizationalPerson'
+ DESC 'RFC2256: an organizational person'
+ SUP person STRUCTURAL
+ MAY ( title $ x121Address $ registeredAddress $ destinationIndicator $
+ preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
+ telephoneNumber $ internationaliSDNNumber $
+ facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
+ postalAddress $ physicalDeliveryOfficeName $ ou $ st $ l ) )
+
+objectclass ( 2.5.6.8 NAME 'organizationalRole'
+ DESC 'RFC2256: an organizational role'
+ SUP top STRUCTURAL
+ MUST cn
+ MAY ( x121Address $ registeredAddress $ destinationIndicator $
+ preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
+ telephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNumber $
+ seeAlso $ roleOccupant $ preferredDeliveryMethod $ street $
+ postOfficeBox $ postalCode $ postalAddress $
+ physicalDeliveryOfficeName $ ou $ st $ l $ description ) )
+
+objectclass ( 2.5.6.9 NAME 'groupOfNames'
+ DESC 'RFC2256: a group of names (DNs)'
+ SUP top STRUCTURAL
+ MUST ( member $ cn )
+ MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) )
+
+objectclass ( 2.5.6.10 NAME 'residentialPerson'
+ DESC 'RFC2256: an residential person'
+ SUP person STRUCTURAL
+ MUST l
+ MAY ( businessCategory $ x121Address $ registeredAddress $
+ destinationIndicator $ preferredDeliveryMethod $ telexNumber $
+ teletexTerminalIdentifier $ telephoneNumber $ internationaliSDNNumber $
+ facsimileTelephoneNumber $ preferredDeliveryMethod $ street $
+ postOfficeBox $ postalCode $ postalAddress $
+ physicalDeliveryOfficeName $ st $ l ) )
+
+objectclass ( 2.5.6.11 NAME 'applicationProcess'
+ DESC 'RFC2256: an application process'
+ SUP top STRUCTURAL
+ MUST cn
+ MAY ( seeAlso $ ou $ l $ description ) )
+
+objectclass ( 2.5.6.12 NAME 'applicationEntity'
+ DESC 'RFC2256: an application entity'
+ SUP top STRUCTURAL
+ MUST ( presentationAddress $ cn )
+ MAY ( supportedApplicationContext $ seeAlso $ ou $ o $ l $
+ description ) )
+
+objectclass ( 2.5.6.13 NAME 'dSA'
+ DESC 'RFC2256: a directory system agent (a server)'
+ SUP applicationEntity STRUCTURAL
+ MAY knowledgeInformation )
+
+objectclass ( 2.5.6.14 NAME 'device'
+ DESC 'RFC2256: a device'
+ SUP top STRUCTURAL
+ MUST cn
+ MAY ( serialNumber $ seeAlso $ owner $ ou $ o $ l $ description ) )
+
+objectclass ( 2.5.6.15 NAME 'strongAuthenticationUser'
+ DESC 'RFC2256: a strong authentication user'
+ SUP top AUXILIARY
+ MUST userCertificate )
+
+objectclass ( 2.5.6.16 NAME 'certificationAuthority'
+ DESC 'RFC2256: a certificate authority'
+ SUP top AUXILIARY
+ MUST ( authorityRevocationList $ certificateRevocationList $
+ cACertificate ) MAY crossCertificatePair )
+
+objectclass ( 2.5.6.17 NAME 'groupOfUniqueNames'
+ DESC 'RFC2256: a group of unique names (DN and Unique Identifier)'
+ SUP top STRUCTURAL
+ MUST ( uniqueMember $ cn )
+ MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) )
+
+objectclass ( 2.5.6.18 NAME 'userSecurityInformation'
+ DESC 'RFC2256: a user security information'
+ SUP top AUXILIARY
+ MAY ( supportedAlgorithms ) )
+
+objectclass ( 2.5.6.16.2 NAME 'certificationAuthority-V2'
+ SUP certificationAuthority
+ AUXILIARY MAY ( deltaRevocationList ) )
+
+objectclass ( 2.5.6.19 NAME 'cRLDistributionPoint'
+ SUP top STRUCTURAL
+ MUST ( cn )
+ MAY ( certificateRevocationList $ authorityRevocationList $
+ deltaRevocationList ) )
+
+objectclass ( 2.5.6.20 NAME 'dmd'
+ SUP top STRUCTURAL
+ MUST ( dmdName )
+ MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
+ x121Address $ registeredAddress $ destinationIndicator $
+ preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
+ telephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNumber $
+ street $ postOfficeBox $ postalCode $ postalAddress $
+ physicalDeliveryOfficeName $ st $ l $ description ) )
+
+#
+# Object Classes from RFC 2587
+#
+objectclass ( 2.5.6.21 NAME 'pkiUser'
+ DESC 'RFC2587: a PKI user'
+ SUP top AUXILIARY
+ MAY userCertificate )
+
+objectclass ( 2.5.6.22 NAME 'pkiCA'
+ DESC 'RFC2587: PKI certificate authority'
+ SUP top AUXILIARY
+ MAY ( authorityRevocationList $ certificateRevocationList $
+ cACertificate $ crossCertificatePair ) )
+
+objectclass ( 2.5.6.23 NAME 'deltaCRL'
+ DESC 'RFC2587: PKI user'
+ SUP top AUXILIARY
+ MAY deltaRevocationList )
+
+#
+# Standard Track URI label schema from RFC 2079
+# system schema
+#attributetype ( 1.3.6.1.4.1.250.1.57 NAME 'labeledURI'
+# DESC 'RFC2079: Uniform Resource Identifier with optional label'
+# EQUALITY caseExactMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+objectclass ( 1.3.6.1.4.1.250.3.15 NAME 'labeledURIObject'
+ DESC 'RFC2079: object that contains the URI attribute type'
+ SUP top AUXILIARY
+ MAY ( labeledURI ) )
+
+#
+# Derived from RFC 1274, but with new "short names"
+#
+#attributetype ( 0.9.2342.19200300.100.1.1
+# NAME ( 'uid' 'userid' )
+# DESC 'RFC1274: user identifier'
+# EQUALITY caseIgnoreMatch
+# SUBSTR caseIgnoreSubstringsMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+attributetype ( 0.9.2342.19200300.100.1.3
+ NAME ( 'mail' 'rfc822Mailbox' )
+ DESC 'RFC1274: RFC822 Mailbox'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
+
+objectclass ( 0.9.2342.19200300.100.4.19 NAME 'simpleSecurityObject'
+ DESC 'RFC1274: simple security object'
+ SUP top AUXILIARY
+ MUST userPassword )
+
+# RFC 1274 + RFC 2247
+attributetype ( 0.9.2342.19200300.100.1.25
+ NAME ( 'dc' 'domainComponent' )
+ DESC 'RFC1274/2247: domain component'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+# RFC 2247
+objectclass ( 1.3.6.1.4.1.1466.344 NAME 'dcObject'
+ DESC 'RFC2247: domain component object'
+ SUP top AUXILIARY MUST dc )
+
+# RFC 2377
+objectclass ( 1.3.6.1.1.3.1 NAME 'uidObject'
+ DESC 'RFC2377: uid object'
+ SUP top AUXILIARY MUST uid )
+
+# RFC 4524
+# The 'associatedDomain' attribute specifies DNS [RFC1034][RFC2181]
+# host names [RFC1123] that are associated with an object. That is,
+# values of this attribute should conform to the following ABNF:
+#
+# domain = root / label *( DOT label )
+# root = SPACE
+# label = LETDIG [ *61( LETDIG / HYPHEN ) LETDIG ]
+# LETDIG = %x30-39 / %x41-5A / %x61-7A ; "0" - "9" / "A"-"Z" / "a"-"z"
+# SPACE = %x20 ; space (" ")
+# HYPHEN = %x2D ; hyphen ("-")
+# DOT = %x2E ; period (".")
+attributetype ( 0.9.2342.19200300.100.1.37
+ NAME 'associatedDomain'
+ DESC 'RFC1274: domain associated with object'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+# RFC 2459 -- deprecated in favor of 'mail' (in cosine.schema)
+attributetype ( 1.2.840.113549.1.9.1
+ NAME ( 'email' 'emailAddress' 'pkcs9email' )
+ DESC 'RFC3280: legacy attribute for email addresses in DNs'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )
+
diff --git a/test/ldap_files/schema/cosine.schema b/test/ldap_files/schema/cosine.schema
new file mode 100644
index 00000000..1302d837
--- /dev/null
+++ b/test/ldap_files/schema/cosine.schema
@@ -0,0 +1,2571 @@
+# RFC1274: Cosine and Internet X.500 schema
+# $OpenLDAP$
+## This work is part of OpenLDAP Software .
+##
+## Copyright 1998-2019 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## .
+#
+# RFC1274: Cosine and Internet X.500 schema
+#
+# This file contains LDAPv3 schema derived from X.500 COSINE "pilot"
+# schema. As this schema was defined for X.500(89), some
+# oddities were introduced in the mapping to LDAPv3. The
+# mappings were based upon: draft-ietf-asid-ldapv3-attributes-03.txt
+# (a work in progress)
+#
+# Note: It seems that the pilot schema evolved beyond what was
+# described in RFC1274. However, this document attempts to describes
+# RFC1274 as published.
+#
+# Depends on core.schema
+
+
+# Network Working Group P. Barker
+# Request for Comments: 1274 S. Kille
+# University College London
+# November 1991
+#
+# The COSINE and Internet X.500 Schema
+#
+# [trimmed]
+#
+# Abstract
+#
+# This document suggests an X.500 Directory Schema, or Naming
+# Architecture, for use in the COSINE and Internet X.500 pilots. The
+# schema is independent of any specific implementation. As well as
+# indicating support for the standard object classes and attributes, a
+# large number of generally useful object classes and attributes are
+# also defined. An appendix to this document includes a machine
+# processable version of the schema.
+#
+# [trimmed]
+
+# 7. Object Identifiers
+#
+# Some additional object identifiers are defined for this schema.
+# These are also reproduced in Appendix C.
+#
+# data OBJECT IDENTIFIER ::= {ccitt 9}
+# pss OBJECT IDENTIFIER ::= {data 2342}
+# ucl OBJECT IDENTIFIER ::= {pss 19200300}
+# pilot OBJECT IDENTIFIER ::= {ucl 100}
+#
+# pilotAttributeType OBJECT IDENTIFIER ::= {pilot 1}
+# pilotAttributeSyntax OBJECT IDENTIFIER ::= {pilot 3}
+# pilotObjectClass OBJECT IDENTIFIER ::= {pilot 4}
+# pilotGroups OBJECT IDENTIFIER ::= {pilot 10}
+#
+# iA5StringSyntax OBJECT IDENTIFIER ::= {pilotAttributeSyntax 4}
+# caseIgnoreIA5StringSyntax OBJECT IDENTIFIER ::=
+# {pilotAttributeSyntax 5}
+#
+# 8. Object Classes
+# [relocated after 9]
+
+#
+# 9. Attribute Types
+#
+# 9.1. X.500 standard attribute types
+#
+# A number of generally useful attribute types are defined in X.520,
+# and these are supported. Refer to that document for descriptions of
+# the suggested usage of these attribute types. The ASN.1 for these
+# attribute types is reproduced for completeness in Appendix C.
+#
+# 9.2. X.400 standard attribute types
+#
+# The standard X.400 attribute types are supported. See X.402 for full
+# details. The ASN.1 for these attribute types is reproduced in
+# Appendix C.
+#
+# 9.3. COSINE/Internet attribute types
+#
+# This section describes all the attribute types defined for use in the
+# COSINE and Internet pilots. Descriptions are given as to the
+# suggested usage of these attribute types. The ASN.1 for these
+# attribute types is reproduced in Appendix C.
+#
+# 9.3.1. Userid
+#
+# The Userid attribute type specifies a computer system login name.
+#
+# userid ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-user-identifier))
+# ::= {pilotAttributeType 1}
+#
+#(in core.schema)
+##attributetype ( 0.9.2342.19200300.100.1.1 NAME ( 'uid' 'userid' )
+## EQUALITY caseIgnoreMatch
+## SUBSTR caseIgnoreSubstringsMatch
+## SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.2. Text Encoded O/R Address
+#
+# The Text Encoded O/R Address attribute type specifies a text encoding
+# of an X.400 O/R address, as specified in RFC 987. The use of this
+# attribute is deprecated as the attribute is intended for interim use
+# only. This attribute will be the first candidate for the attribute
+# expiry mechanisms!
+#
+# textEncodedORAddress ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-text-encoded-or-address))
+# ::= {pilotAttributeType 2}
+#
+attributetype ( 0.9.2342.19200300.100.1.2 NAME 'textEncodedORAddress'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.3. RFC 822 Mailbox
+#
+# The RFC822 Mailbox attribute type specifies an electronic mailbox
+# attribute following the syntax specified in RFC 822. Note that this
+# attribute should not be used for greybook or other non-Internet order
+# mailboxes.
+#
+# rfc822Mailbox ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreIA5StringSyntax
+# (SIZE (1 .. ub-rfc822-mailbox))
+# ::= {pilotAttributeType 3}
+#
+#(in core.schema)
+##attributetype ( 0.9.2342.19200300.100.1.3 NAME ( 'mail' 'rfc822Mailbox' )
+## EQUALITY caseIgnoreIA5Match
+## SUBSTR caseIgnoreIA5SubstringsMatch
+## SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
+
+# 9.3.4. Information
+#
+# The Information attribute type specifies any general information
+# pertinent to an object. It is recommended that specific usage of
+# this attribute type is avoided, and that specific requirements are
+# met by other (possibly additional) attribute types.
+#
+# info ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-information))
+# ::= {pilotAttributeType 4}
+#
+attributetype ( 0.9.2342.19200300.100.1.4 NAME 'info'
+ DESC 'RFC1274: general information'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{2048} )
+
+
+# 9.3.5. Favourite Drink
+#
+# The Favourite Drink attribute type specifies the favourite drink of
+# an object (or person).
+#
+# favouriteDrink ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-favourite-drink))
+# ::= {pilotAttributeType 5}
+#
+attributetype ( 0.9.2342.19200300.100.1.5
+ NAME ( 'drink' 'favouriteDrink' )
+ DESC 'RFC1274: favorite drink'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.6. Room Number
+#
+# The Room Number attribute type specifies the room number of an
+# object. Note that the commonName attribute should be used for naming
+# room objects.
+#
+# roomNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-room-number))
+# ::= {pilotAttributeType 6}
+#
+attributetype ( 0.9.2342.19200300.100.1.6 NAME 'roomNumber'
+ DESC 'RFC1274: room number'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.7. Photo
+#
+# The Photo attribute type specifies a "photograph" for an object.
+# This should be encoded in G3 fax as explained in recommendation T.4,
+# with an ASN.1 wrapper to make it compatible with an X.400 BodyPart as
+# defined in X.420.
+#
+# IMPORT G3FacsimileBodyPart FROM { mhs-motis ipms modules
+# information-objects }
+#
+# photo ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# CHOICE {
+# g3-facsimile [3] G3FacsimileBodyPart
+# }
+# (SIZE (1 .. ub-photo))
+# ::= {pilotAttributeType 7}
+#
+attributetype ( 0.9.2342.19200300.100.1.7 NAME 'photo'
+ DESC 'RFC1274: photo (G3 fax)'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.23{25000} )
+
+# 9.3.8. User Class
+#
+# The User Class attribute type specifies a category of computer user.
+# The semantics placed on this attribute are for local interpretation.
+# Examples of current usage od this attribute in academia are
+# undergraduate student, researcher, lecturer, etc. Note that the
+# organizationalStatus attribute may now often be preferred as it makes
+# no distinction between computer users and others.
+#
+# userClass ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-user-class))
+# ::= {pilotAttributeType 8}
+#
+attributetype ( 0.9.2342.19200300.100.1.8 NAME 'userClass'
+ DESC 'RFC1274: category of user'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.9. Host
+#
+# The Host attribute type specifies a host computer.
+#
+# host ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-host))
+# ::= {pilotAttributeType 9}
+#
+attributetype ( 0.9.2342.19200300.100.1.9 NAME 'host'
+ DESC 'RFC1274: host computer'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.10. Manager
+#
+# The Manager attribute type specifies the manager of an object
+# represented by an entry.
+#
+# manager ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 10}
+#
+attributetype ( 0.9.2342.19200300.100.1.10 NAME 'manager'
+ DESC 'RFC1274: DN of manager'
+ EQUALITY distinguishedNameMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
+
+# 9.3.11. Document Identifier
+#
+# The Document Identifier attribute type specifies a unique identifier
+# for a document.
+#
+# documentIdentifier ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-document-identifier))
+# ::= {pilotAttributeType 11}
+#
+attributetype ( 0.9.2342.19200300.100.1.11 NAME 'documentIdentifier'
+ DESC 'RFC1274: unique identifier of document'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.12. Document Title
+#
+# The Document Title attribute type specifies the title of a document.
+#
+# documentTitle ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-document-title))
+# ::= {pilotAttributeType 12}
+#
+attributetype ( 0.9.2342.19200300.100.1.12 NAME 'documentTitle'
+ DESC 'RFC1274: title of document'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.13. Document Version
+#
+# The Document Version attribute type specifies the version number of a
+# document.
+#
+# documentVersion ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-document-version))
+# ::= {pilotAttributeType 13}
+#
+attributetype ( 0.9.2342.19200300.100.1.13 NAME 'documentVersion'
+ DESC 'RFC1274: version of document'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.14. Document Author
+#
+# The Document Author attribute type specifies the distinguished name
+# of the author of a document.
+#
+# documentAuthor ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 14}
+#
+attributetype ( 0.9.2342.19200300.100.1.14 NAME 'documentAuthor'
+ DESC 'RFC1274: DN of author of document'
+ EQUALITY distinguishedNameMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
+
+# 9.3.15. Document Location
+#
+# The Document Location attribute type specifies the location of the
+# document original.
+#
+# documentLocation ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-document-location))
+# ::= {pilotAttributeType 15}
+#
+attributetype ( 0.9.2342.19200300.100.1.15 NAME 'documentLocation'
+ DESC 'RFC1274: location of document original'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.16. Home Telephone Number
+#
+# The Home Telephone Number attribute type specifies a home telephone
+# number associated with a person. Attribute values should follow the
+# agreed format for international telephone numbers: i.e., "+44 71 123
+# 4567".
+#
+# homeTelephoneNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# telephoneNumberSyntax
+# ::= {pilotAttributeType 20}
+#
+attributetype ( 0.9.2342.19200300.100.1.20
+ NAME ( 'homePhone' 'homeTelephoneNumber' )
+ DESC 'RFC1274: home telephone number'
+ EQUALITY telephoneNumberMatch
+ SUBSTR telephoneNumberSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )
+
+# 9.3.17. Secretary
+#
+# The Secretary attribute type specifies the secretary of a person.
+# The attribute value for Secretary is a distinguished name.
+#
+# secretary ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 21}
+#
+attributetype ( 0.9.2342.19200300.100.1.21 NAME 'secretary'
+ DESC 'RFC1274: DN of secretary'
+ EQUALITY distinguishedNameMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
+
+# 9.3.18. Other Mailbox
+#
+# The Other Mailbox attribute type specifies values for electronic
+# mailbox types other than X.400 and rfc822.
+#
+# otherMailbox ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# SEQUENCE {
+# mailboxType PrintableString, -- e.g. Telemail
+# mailbox IA5String -- e.g. X378:Joe
+# }
+# ::= {pilotAttributeType 22}
+#
+attributetype ( 0.9.2342.19200300.100.1.22 NAME 'otherMailbox'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.39 )
+
+# 9.3.19. Last Modified Time
+#
+# The Last Modified Time attribute type specifies the last time, in UTC
+# time, that an entry was modified. Ideally, this attribute should be
+# maintained by the DSA.
+#
+# lastModifiedTime ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# uTCTimeSyntax
+# ::= {pilotAttributeType 23}
+#
+## Deprecated in favor of modifyTimeStamp
+#attributetype ( 0.9.2342.19200300.100.1.23 NAME 'lastModifiedTime'
+# DESC 'RFC1274: time of last modify, replaced by modifyTimestamp'
+# OBSOLETE
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.53
+# USAGE directoryOperation )
+
+# 9.3.20. Last Modified By
+#
+# The Last Modified By attribute specifies the distinguished name of
+# the last user to modify the associated entry. Ideally, this
+# attribute should be maintained by the DSA.
+#
+# lastModifiedBy ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 24}
+#
+## Deprecated in favor of modifiersName
+#attributetype ( 0.9.2342.19200300.100.1.24 NAME 'lastModifiedBy'
+# DESC 'RFC1274: last modifier, replaced by modifiersName'
+# OBSOLETE
+# EQUALITY distinguishedNameMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
+# USAGE directoryOperation )
+
+# 9.3.21. Domain Component
+#
+# The Domain Component attribute type specifies a DNS/NRS domain. For
+# example, "uk" or "ac".
+#
+# domainComponent ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreIA5StringSyntax
+# SINGLE VALUE
+# ::= {pilotAttributeType 25}
+#
+##(in core.schema)
+##attributetype ( 0.9.2342.19200300.100.1.25 NAME ( 'dc' 'domainComponent' )
+## EQUALITY caseIgnoreIA5Match
+## SUBSTR caseIgnoreIA5SubstringsMatch
+## SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+# 9.3.22. DNS ARecord
+#
+# The A Record attribute type specifies a type A (Address) DNS resource
+# record [6] [7].
+#
+# aRecord ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# DNSRecordSyntax
+# ::= {pilotAttributeType 26}
+#
+## incorrect syntax?
+attributetype ( 0.9.2342.19200300.100.1.26 NAME 'aRecord'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+## missing from RFC1274
+## incorrect syntax?
+attributetype ( 0.9.2342.19200300.100.1.27 NAME 'mDRecord'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+# 9.3.23. MX Record
+#
+# The MX Record attribute type specifies a type MX (Mail Exchange) DNS
+# resource record [6] [7].
+#
+# mXRecord ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# DNSRecordSyntax
+# ::= {pilotAttributeType 28}
+#
+## incorrect syntax!!
+attributetype ( 0.9.2342.19200300.100.1.28 NAME 'mXRecord'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+# 9.3.24. NS Record
+#
+# The NS Record attribute type specifies an NS (Name Server) DNS
+# resource record [6] [7].
+#
+# nSRecord ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# DNSRecordSyntax
+# ::= {pilotAttributeType 29}
+#
+## incorrect syntax!!
+attributetype ( 0.9.2342.19200300.100.1.29 NAME 'nSRecord'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+# 9.3.25. SOA Record
+#
+# The SOA Record attribute type specifies a type SOA (Start of
+# Authority) DNS resorce record [6] [7].
+#
+# sOARecord ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# DNSRecordSyntax
+# ::= {pilotAttributeType 30}
+#
+## incorrect syntax!!
+attributetype ( 0.9.2342.19200300.100.1.30 NAME 'sOARecord'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+# 9.3.26. CNAME Record
+#
+# The CNAME Record attribute type specifies a type CNAME (Canonical
+# Name) DNS resource record [6] [7].
+#
+# cNAMERecord ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# iA5StringSyntax
+# ::= {pilotAttributeType 31}
+#
+## incorrect syntax!!
+attributetype ( 0.9.2342.19200300.100.1.31 NAME 'cNAMERecord'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+# 9.3.27. Associated Domain
+#
+# The Associated Domain attribute type specifies a DNS or NRS domain
+# which is associated with an object in the DIT. For example, the entry
+# in the DIT with a distinguished name "C=GB, O=University College
+# London" would have an associated domain of "UCL.AC.UK. Note that all
+# domains should be represented in rfc822 order. See [3] for more
+# details of usage of this attribute.
+#
+# associatedDomain ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreIA5StringSyntax
+# ::= {pilotAttributeType 37}
+#
+#attributetype ( 0.9.2342.19200300.100.1.37 NAME 'associatedDomain'
+# EQUALITY caseIgnoreIA5Match
+# SUBSTR caseIgnoreIA5SubstringsMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+# 9.3.28. Associated Name
+#
+# The Associated Name attribute type specifies an entry in the
+# organisational DIT associated with a DNS/NRS domain. See [3] for
+# more details of usage of this attribute.
+#
+# associatedName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 38}
+#
+attributetype ( 0.9.2342.19200300.100.1.38 NAME 'associatedName'
+ DESC 'RFC1274: DN of entry associated with domain'
+ EQUALITY distinguishedNameMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
+
+# 9.3.29. Home postal address
+#
+# The Home postal address attribute type specifies a home postal
+# address for an object. This should be limited to up to 6 lines of 30
+# characters each.
+#
+# homePostalAddress ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# postalAddress
+# MATCHES FOR EQUALITY
+# ::= {pilotAttributeType 39}
+#
+attributetype ( 0.9.2342.19200300.100.1.39 NAME 'homePostalAddress'
+ DESC 'RFC1274: home postal address'
+ EQUALITY caseIgnoreListMatch
+ SUBSTR caseIgnoreListSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
+
+# 9.3.30. Personal Title
+#
+# The Personal Title attribute type specifies a personal title for a
+# person. Examples of personal titles are "Ms", "Dr", "Prof" and "Rev".
+#
+# personalTitle ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-personal-title))
+# ::= {pilotAttributeType 40}
+#
+attributetype ( 0.9.2342.19200300.100.1.40 NAME 'personalTitle'
+ DESC 'RFC1274: personal title'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.31. Mobile Telephone Number
+#
+# The Mobile Telephone Number attribute type specifies a mobile
+# telephone number associated with a person. Attribute values should
+# follow the agreed format for international telephone numbers: i.e.,
+# "+44 71 123 4567".
+#
+# mobileTelephoneNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# telephoneNumberSyntax
+# ::= {pilotAttributeType 41}
+#
+attributetype ( 0.9.2342.19200300.100.1.41
+ NAME ( 'mobile' 'mobileTelephoneNumber' )
+ DESC 'RFC1274: mobile telephone number'
+ EQUALITY telephoneNumberMatch
+ SUBSTR telephoneNumberSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )
+
+# 9.3.32. Pager Telephone Number
+#
+# The Pager Telephone Number attribute type specifies a pager telephone
+# number for an object. Attribute values should follow the agreed
+# format for international telephone numbers: i.e., "+44 71 123 4567".
+#
+# pagerTelephoneNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# telephoneNumberSyntax
+# ::= {pilotAttributeType 42}
+#
+attributetype ( 0.9.2342.19200300.100.1.42
+ NAME ( 'pager' 'pagerTelephoneNumber' )
+ DESC 'RFC1274: pager telephone number'
+ EQUALITY telephoneNumberMatch
+ SUBSTR telephoneNumberSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )
+
+# 9.3.33. Friendly Country Name
+#
+# The Friendly Country Name attribute type specifies names of countries
+# in human readable format. The standard attribute country name must
+# be one of the two-letter codes defined in ISO 3166.
+#
+# friendlyCountryName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# ::= {pilotAttributeType 43}
+#
+attributetype ( 0.9.2342.19200300.100.1.43
+ NAME ( 'co' 'friendlyCountryName' )
+ DESC 'RFC1274: friendly country name'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+# 9.3.34. Unique Identifier
+#
+# The Unique Identifier attribute type specifies a "unique identifier"
+# for an object represented in the Directory. The domain within which
+# the identifier is unique, and the exact semantics of the identifier,
+# are for local definition. For a person, this might be an
+# institution-wide payroll number. For an organisational unit, it
+# might be a department code.
+#
+# uniqueIdentifier ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-unique-identifier))
+# ::= {pilotAttributeType 44}
+#
+attributetype ( 0.9.2342.19200300.100.1.44 NAME 'uniqueIdentifier'
+ DESC 'RFC1274: unique identifer'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.35. Organisational Status
+#
+# The Organisational Status attribute type specifies a category by
+# which a person is often referred to in an organisation. Examples of
+# usage in academia might include undergraduate student, researcher,
+# lecturer, etc.
+#
+# A Directory administrator should probably consider carefully the
+# distinctions between this and the title and userClass attributes.
+#
+# organizationalStatus ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-organizational-status))
+# ::= {pilotAttributeType 45}
+#
+attributetype ( 0.9.2342.19200300.100.1.45 NAME 'organizationalStatus'
+ DESC 'RFC1274: organizational status'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.36. Janet Mailbox
+#
+# The Janet Mailbox attribute type specifies an electronic mailbox
+# attribute following the syntax specified in the Grey Book of the
+# Coloured Book series. This attribute is intended for the convenience
+# of U.K users unfamiliar with rfc822 and little-endian mail addresses.
+# Entries using this attribute MUST also include an rfc822Mailbox
+# attribute.
+#
+# janetMailbox ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreIA5StringSyntax
+# (SIZE (1 .. ub-janet-mailbox))
+# ::= {pilotAttributeType 46}
+#
+attributetype ( 0.9.2342.19200300.100.1.46 NAME 'janetMailbox'
+ DESC 'RFC1274: Janet mailbox'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
+
+# 9.3.37. Mail Preference Option
+#
+# An attribute to allow users to indicate a preference for inclusion of
+# their names on mailing lists (electronic or physical). The absence
+# of such an attribute should be interpreted as if the attribute was
+# present with value "no-list-inclusion". This attribute should be
+# interpreted by anyone using the directory to derive mailing lists,
+# and its value respected.
+#
+# mailPreferenceOption ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX ENUMERATED {
+# no-list-inclusion(0),
+# any-list-inclusion(1), -- may be added to any lists
+# professional-list-inclusion(2)
+# -- may be added to lists
+# -- which the list provider
+# -- views as related to the
+# -- users professional inter-
+# -- ests, perhaps evaluated
+# -- from the business of the
+# -- organisation or keywords
+# -- in the entry.
+# }
+# ::= {pilotAttributeType 47}
+#
+attributetype ( 0.9.2342.19200300.100.1.47
+ NAME 'mailPreferenceOption'
+ DESC 'RFC1274: mail preference option'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
+
+# 9.3.38. Building Name
+#
+# The Building Name attribute type specifies the name of the building
+# where an organisation or organisational unit is based.
+#
+# buildingName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-building-name))
+# ::= {pilotAttributeType 48}
+#
+attributetype ( 0.9.2342.19200300.100.1.48 NAME 'buildingName'
+ DESC 'RFC1274: name of building'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.39. DSA Quality
+#
+# The DSA Quality attribute type specifies the purported quality of a
+# DSA. It allows a DSA manager to indicate the expected level of
+# availability of the DSA. See [8] for details of the syntax.
+#
+# dSAQuality ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX DSAQualitySyntax
+# SINGLE VALUE
+# ::= {pilotAttributeType 49}
+#
+attributetype ( 0.9.2342.19200300.100.1.49 NAME 'dSAQuality'
+ DESC 'RFC1274: DSA Quality'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.19 SINGLE-VALUE )
+
+# 9.3.40. Single Level Quality
+#
+# The Single Level Quality attribute type specifies the purported data
+# quality at the level immediately below in the DIT. See [8] for
+# details of the syntax.
+#
+# singleLevelQuality ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX DataQualitySyntax
+# SINGLE VALUE
+# ::= {pilotAttributeType 50}
+#
+attributetype ( 0.9.2342.19200300.100.1.50 NAME 'singleLevelQuality'
+ DESC 'RFC1274: Single Level Quality'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.13 SINGLE-VALUE )
+
+# 9.3.41. Subtree Minimum Quality
+#
+# The Subtree Minimum Quality attribute type specifies the purported
+# minimum data quality for a DIT subtree. See [8] for more discussion
+# and details of the syntax.
+#
+# subtreeMinimumQuality ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX DataQualitySyntax
+# SINGLE VALUE
+# -- Defaults to singleLevelQuality
+# ::= {pilotAttributeType 51}
+#
+attributetype ( 0.9.2342.19200300.100.1.51 NAME 'subtreeMinimumQuality'
+ DESC 'RFC1274: Subtree Mininum Quality'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.13 SINGLE-VALUE )
+
+# 9.3.42. Subtree Maximum Quality
+#
+# The Subtree Maximum Quality attribute type specifies the purported
+# maximum data quality for a DIT subtree. See [8] for more discussion
+# and details of the syntax.
+#
+# subtreeMaximumQuality ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX DataQualitySyntax
+# SINGLE VALUE
+# -- Defaults to singleLevelQuality
+# ::= {pilotAttributeType 52}
+#
+attributetype ( 0.9.2342.19200300.100.1.52 NAME 'subtreeMaximumQuality'
+ DESC 'RFC1274: Subtree Maximun Quality'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.13 SINGLE-VALUE )
+
+# 9.3.43. Personal Signature
+#
+# The Personal Signature attribute type allows for a representation of
+# a person's signature. This should be encoded in G3 fax as explained
+# in recommendation T.4, with an ASN.1 wrapper to make it compatible
+# with an X.400 BodyPart as defined in X.420.
+#
+# IMPORT G3FacsimileBodyPart FROM { mhs-motis ipms modules
+# information-objects }
+#
+# personalSignature ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# CHOICE {
+# g3-facsimile [3] G3FacsimileBodyPart
+# }
+# (SIZE (1 .. ub-personal-signature))
+# ::= {pilotAttributeType 53}
+#
+attributetype ( 0.9.2342.19200300.100.1.53 NAME 'personalSignature'
+ DESC 'RFC1274: Personal Signature (G3 fax)'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.23 )
+
+# 9.3.44. DIT Redirect
+#
+# The DIT Redirect attribute type is used to indicate that the object
+# described by one entry now has a newer entry in the DIT. The entry
+# containing the redirection attribute should be expired after a
+# suitable grace period. This attribute may be used when an individual
+# changes his/her place of work, and thus acquires a new organisational
+# DN.
+#
+# dITRedirect ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 54}
+#
+attributetype ( 0.9.2342.19200300.100.1.54 NAME 'dITRedirect'
+ DESC 'RFC1274: DIT Redirect'
+ EQUALITY distinguishedNameMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
+
+# 9.3.45. Audio
+#
+# The Audio attribute type allows the storing of sounds in the
+# Directory. The attribute uses a u-law encoded sound file as used by
+# the "play" utility on a Sun 4. This is an interim format.
+#
+# audio ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# Audio
+# (SIZE (1 .. ub-audio))
+# ::= {pilotAttributeType 55}
+#
+attributetype ( 0.9.2342.19200300.100.1.55 NAME 'audio'
+ DESC 'RFC1274: audio (u-law)'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.4{25000} )
+
+# 9.3.46. Publisher of Document
+#
+#
+# The Publisher of Document attribute is the person and/or organization
+# that published a document.
+#
+# documentPublisher ATTRIBUTE
+# WITH ATTRIBUTE SYNTAX caseIgnoreStringSyntax
+# ::= {pilotAttributeType 56}
+#
+attributetype ( 0.9.2342.19200300.100.1.56 NAME 'documentPublisher'
+ DESC 'RFC1274: publisher of document'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+# 9.4. Generally useful syntaxes
+#
+# caseIgnoreIA5StringSyntax ATTRIBUTE-SYNTAX
+# IA5String
+# MATCHES FOR EQUALITY SUBSTRINGS
+#
+# iA5StringSyntax ATTRIBUTE-SYNTAX
+# IA5String
+# MATCHES FOR EQUALITY SUBSTRINGS
+#
+#
+# -- Syntaxes to support the DNS attributes
+#
+# DNSRecordSyntax ATTRIBUTE-SYNTAX
+# IA5String
+# MATCHES FOR EQUALITY
+#
+#
+# NRSInformationSyntax ATTRIBUTE-SYNTAX
+# NRSInformation
+# MATCHES FOR EQUALITY
+#
+#
+# NRSInformation ::= SET {
+# [0] Context,
+# [1] Address-space-id,
+# routes [2] SEQUENCE OF SEQUENCE {
+# Route-cost,
+# Addressing-info }
+# }
+#
+#
+# 9.5. Upper bounds on length of attribute values
+#
+#
+# ub-document-identifier INTEGER ::= 256
+#
+# ub-document-location INTEGER ::= 256
+#
+# ub-document-title INTEGER ::= 256
+#
+# ub-document-version INTEGER ::= 256
+#
+# ub-favourite-drink INTEGER ::= 256
+#
+# ub-host INTEGER ::= 256
+#
+# ub-information INTEGER ::= 2048
+#
+# ub-unique-identifier INTEGER ::= 256
+#
+# ub-personal-title INTEGER ::= 256
+#
+# ub-photo INTEGER ::= 250000
+#
+# ub-rfc822-mailbox INTEGER ::= 256
+#
+# ub-room-number INTEGER ::= 256
+#
+# ub-text-or-address INTEGER ::= 256
+#
+# ub-user-class INTEGER ::= 256
+#
+# ub-user-identifier INTEGER ::= 256
+#
+# ub-organizational-status INTEGER ::= 256
+#
+# ub-janet-mailbox INTEGER ::= 256
+#
+# ub-building-name INTEGER ::= 256
+#
+# ub-personal-signature ::= 50000
+#
+# ub-audio INTEGER ::= 250000
+#
+
+# [back to 8]
+# 8. Object Classes
+#
+# 8.1. X.500 standard object classes
+#
+# A number of generally useful object classes are defined in X.521, and
+# these are supported. Refer to that document for descriptions of the
+# suggested usage of these object classes. The ASN.1 for these object
+# classes is reproduced for completeness in Appendix C.
+#
+# 8.2. X.400 standard object classes
+#
+# A number of object classes defined in X.400 are supported. Refer to
+# X.402 for descriptions of the usage of these object classes. The
+# ASN.1 for these object classes is reproduced for completeness in
+# Appendix C.
+#
+# 8.3. COSINE/Internet object classes
+#
+# This section attempts to fuse together the object classes designed
+# for use in the COSINE and Internet pilot activities. Descriptions
+# are given of the suggested usage of these object classes. The ASN.1
+# for these object classes is also reproduced in Appendix C.
+#
+# 8.3.1. Pilot Object
+#
+# The PilotObject object class is used as a sub-class to allow some
+# common, useful attributes to be assigned to entries of all other
+# object classes.
+#
+# pilotObject OBJECT-CLASS
+# SUBCLASS OF top
+# MAY CONTAIN {
+# info,
+# photo,
+# manager,
+# uniqueIdentifier,
+# lastModifiedTime,
+# lastModifiedBy,
+# dITRedirect,
+# audio}
+# ::= {pilotObjectClass 3}
+#
+#objectclass ( 0.9.2342.19200300.100.4.3 NAME 'pilotObject'
+# DESC 'RFC1274: pilot object'
+# SUP top AUXILIARY
+# MAY ( info $ photo $ manager $ uniqueIdentifier $
+# lastModifiedTime $ lastModifiedBy $ dITRedirect $ audio )
+# )
+
+# 8.3.2. Pilot Person
+#
+# The PilotPerson object class is used as a sub-class of person, to
+# allow the use of a number of additional attributes to be assigned to
+# entries of object class person.
+#
+# pilotPerson OBJECT-CLASS
+# SUBCLASS OF person
+# MAY CONTAIN {
+# userid,
+# textEncodedORAddress,
+# rfc822Mailbox,
+# favouriteDrink,
+# roomNumber,
+# userClass,
+# homeTelephoneNumber,
+# homePostalAddress,
+# secretary,
+# personalTitle,
+# preferredDeliveryMethod,
+# businessCategory,
+# janetMailbox,
+# otherMailbox,
+# mobileTelephoneNumber,
+# pagerTelephoneNumber,
+# organizationalStatus,
+# mailPreferenceOption,
+# personalSignature}
+# ::= {pilotObjectClass 4}
+#
+objectclass ( 0.9.2342.19200300.100.4.4
+ NAME ( 'pilotPerson' 'newPilotPerson' )
+ SUP person STRUCTURAL
+ MAY ( userid $ textEncodedORAddress $ rfc822Mailbox $
+ favouriteDrink $ roomNumber $ userClass $
+ homeTelephoneNumber $ homePostalAddress $ secretary $
+ personalTitle $ preferredDeliveryMethod $ businessCategory $
+ janetMailbox $ otherMailbox $ mobileTelephoneNumber $
+ pagerTelephoneNumber $ organizationalStatus $
+ mailPreferenceOption $ personalSignature )
+ )
+
+# 8.3.3. Account
+#
+# The Account object class is used to define entries representing
+# computer accounts. The userid attribute should be used for naming
+# entries of this object class.
+#
+# account OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# userid}
+# MAY CONTAIN {
+# description,
+# seeAlso,
+# localityName,
+# organizationName,
+# organizationalUnitName,
+# host}
+# ::= {pilotObjectClass 5}
+#
+objectclass ( 0.9.2342.19200300.100.4.5 NAME 'account'
+ SUP top STRUCTURAL
+ MUST userid
+ MAY ( description $ seeAlso $ localityName $
+ organizationName $ organizationalUnitName $ host )
+ )
+
+# 8.3.4. Document
+#
+# The Document object class is used to define entries which represent
+# documents.
+#
+# document OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# documentIdentifier}
+# MAY CONTAIN {
+# commonName,
+# description,
+# seeAlso,
+# localityName,
+# organizationName,
+# organizationalUnitName,
+# documentTitle,
+# documentVersion,
+# documentAuthor,
+# documentLocation,
+# documentPublisher}
+# ::= {pilotObjectClass 6}
+#
+objectclass ( 0.9.2342.19200300.100.4.6 NAME 'document'
+ SUP top STRUCTURAL
+ MUST documentIdentifier
+ MAY ( commonName $ description $ seeAlso $ localityName $
+ organizationName $ organizationalUnitName $
+ documentTitle $ documentVersion $ documentAuthor $
+ documentLocation $ documentPublisher )
+ )
+
+# 8.3.5. Room
+#
+# The Room object class is used to define entries representing rooms.
+# The commonName attribute should be used for naming pentries of this
+# object class.
+#
+# room OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName}
+# MAY CONTAIN {
+# roomNumber,
+# description,
+# seeAlso,
+# telephoneNumber}
+# ::= {pilotObjectClass 7}
+#
+objectclass ( 0.9.2342.19200300.100.4.7 NAME 'room'
+ SUP top STRUCTURAL
+ MUST commonName
+ MAY ( roomNumber $ description $ seeAlso $ telephoneNumber )
+ )
+
+# 8.3.6. Document Series
+#
+# The Document Series object class is used to define an entry which
+# represents a series of documents (e.g., The Request For Comments
+# papers).
+#
+# documentSeries OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName}
+# MAY CONTAIN {
+# description,
+# seeAlso,
+# telephoneNumber,
+# localityName,
+# organizationName,
+# organizationalUnitName}
+# ::= {pilotObjectClass 9}
+#
+objectclass ( 0.9.2342.19200300.100.4.9 NAME 'documentSeries'
+ SUP top STRUCTURAL
+ MUST commonName
+ MAY ( description $ seeAlso $ telephonenumber $
+ localityName $ organizationName $ organizationalUnitName )
+ )
+
+# 8.3.7. Domain
+#
+# The Domain object class is used to define entries which represent DNS
+# or NRS domains. The domainComponent attribute should be used for
+# naming entries of this object class. The usage of this object class
+# is described in more detail in [3].
+#
+# domain OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# domainComponent}
+# MAY CONTAIN {
+# associatedName,
+# organizationName,
+# organizationalAttributeSet}
+# ::= {pilotObjectClass 13}
+#
+objectclass ( 0.9.2342.19200300.100.4.13 NAME 'domain'
+ SUP top STRUCTURAL
+ MUST domainComponent
+ MAY ( associatedName $ organizationName $ description $
+ businessCategory $ seeAlso $ searchGuide $ userPassword $
+ localityName $ stateOrProvinceName $ streetAddress $
+ physicalDeliveryOfficeName $ postalAddress $ postalCode $
+ postOfficeBox $ streetAddress $
+ facsimileTelephoneNumber $ internationalISDNNumber $
+ telephoneNumber $ teletexTerminalIdentifier $ telexNumber $
+ preferredDeliveryMethod $ destinationIndicator $
+ registeredAddress $ x121Address )
+ )
+
+# 8.3.8. RFC822 Local Part
+#
+# The RFC822 Local Part object class is used to define entries which
+# represent the local part of RFC822 mail addresses. This treats this
+# part of an RFC822 address as a domain. The usage of this object
+# class is described in more detail in [3].
+#
+# rFC822localPart OBJECT-CLASS
+# SUBCLASS OF domain
+# MAY CONTAIN {
+# commonName,
+# surname,
+# description,
+# seeAlso,
+# telephoneNumber,
+# postalAttributeSet,
+# telecommunicationAttributeSet}
+# ::= {pilotObjectClass 14}
+#
+objectclass ( 0.9.2342.19200300.100.4.14 NAME 'RFC822localPart'
+ SUP domain STRUCTURAL
+ MAY ( commonName $ surname $ description $ seeAlso $ telephoneNumber $
+ physicalDeliveryOfficeName $ postalAddress $ postalCode $
+ postOfficeBox $ streetAddress $
+ facsimileTelephoneNumber $ internationalISDNNumber $
+ telephoneNumber $ teletexTerminalIdentifier $
+ telexNumber $ preferredDeliveryMethod $ destinationIndicator $
+ registeredAddress $ x121Address )
+ )
+
+# 8.3.9. DNS Domain
+#
+# The DNS Domain (Domain NameServer) object class is used to define
+# entries for DNS domains. The usage of this object class is described
+# in more detail in [3].
+#
+# dNSDomain OBJECT-CLASS
+# SUBCLASS OF domain
+# MAY CONTAIN {
+# ARecord,
+# MDRecord,
+# MXRecord,
+# NSRecord,
+# SOARecord,
+# CNAMERecord}
+# ::= {pilotObjectClass 15}
+#
+objectclass ( 0.9.2342.19200300.100.4.15 NAME 'dNSDomain'
+ SUP domain STRUCTURAL
+ MAY ( ARecord $ MDRecord $ MXRecord $ NSRecord $
+ SOARecord $ CNAMERecord )
+ )
+
+# 8.3.10. Domain Related Object
+#
+# The Domain Related Object object class is used to define entries
+# which represent DNS/NRS domains which are "equivalent" to an X.500
+# domain: e.g., an organisation or organisational unit. The usage of
+# this object class is described in more detail in [3].
+#
+# domainRelatedObject OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# associatedDomain}
+# ::= {pilotObjectClass 17}
+#
+objectclass ( 0.9.2342.19200300.100.4.17 NAME 'domainRelatedObject'
+ DESC 'RFC1274: an object related to an domain'
+ SUP top AUXILIARY
+ MUST associatedDomain )
+
+# 8.3.11. Friendly Country
+#
+# The Friendly Country object class is used to define country entries
+# in the DIT. The object class is used to allow friendlier naming of
+# countries than that allowed by the object class country. The naming
+# attribute of object class country, countryName, has to be a 2 letter
+# string defined in ISO 3166.
+#
+# friendlyCountry OBJECT-CLASS
+# SUBCLASS OF country
+# MUST CONTAIN {
+# friendlyCountryName}
+# ::= {pilotObjectClass 18}
+#
+objectclass ( 0.9.2342.19200300.100.4.18 NAME 'friendlyCountry'
+ SUP country STRUCTURAL
+ MUST friendlyCountryName )
+
+# 8.3.12. Simple Security Object
+#
+# The Simple Security Object object class is used to allow an entry to
+# have a userPassword attribute when an entry's principal object
+# classes do not allow userPassword as an attribute type.
+#
+# simpleSecurityObject OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# userPassword }
+# ::= {pilotObjectClass 19}
+#
+## (in core.schema)
+## objectclass ( 0.9.2342.19200300.100.4.19 NAME 'simpleSecurityObject'
+## SUP top AUXILIARY
+## MUST userPassword )
+
+# 8.3.13. Pilot Organization
+#
+# The PilotOrganization object class is used as a sub-class of
+# organization and organizationalUnit to allow a number of additional
+# attributes to be assigned to entries of object classes organization
+# and organizationalUnit.
+#
+# pilotOrganization OBJECT-CLASS
+# SUBCLASS OF organization, organizationalUnit
+# MAY CONTAIN {
+# buildingName}
+# ::= {pilotObjectClass 20}
+#
+objectclass ( 0.9.2342.19200300.100.4.20 NAME 'pilotOrganization'
+ SUP ( organization $ organizationalUnit ) STRUCTURAL
+ MAY buildingName )
+
+# 8.3.14. Pilot DSA
+#
+# The PilotDSA object class is used as a sub-class of the dsa object
+# class to allow additional attributes to be assigned to entries for
+# DSAs.
+#
+# pilotDSA OBJECT-CLASS
+# SUBCLASS OF dsa
+# MUST CONTAIN {
+# dSAQuality}
+# ::= {pilotObjectClass 21}
+#
+objectclass ( 0.9.2342.19200300.100.4.21 NAME 'pilotDSA'
+ SUP dsa STRUCTURAL
+ MAY dSAQuality )
+
+# 8.3.15. Quality Labelled Data
+#
+# The Quality Labelled Data object class is used to allow the
+# assignment of the data quality attributes to subtrees in the DIT.
+#
+# See [8] for more details.
+#
+# qualityLabelledData OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# dSAQuality}
+# MAY CONTAIN {
+# subtreeMinimumQuality,
+# subtreeMaximumQuality}
+# ::= {pilotObjectClass 22}
+objectclass ( 0.9.2342.19200300.100.4.22 NAME 'qualityLabelledData'
+ SUP top AUXILIARY
+ MUST dsaQuality
+ MAY ( subtreeMinimumQuality $ subtreeMaximumQuality )
+ )
+
+
+# References
+#
+# [1] CCITT/ISO, "X.500, The Directory - overview of concepts,
+# models and services, CCITT /ISO IS 9594.
+#
+# [2] Kille, S., "The THORN and RARE X.500 Naming Architecture, in
+# University College London, Department of Computer Science
+# Research Note 89/48, May 1989.
+#
+# [3] Kille, S., "X.500 and Domains", RFC 1279, University College
+# London, November 1991.
+#
+# [4] Rose, M., "PSI/NYSERNet White Pages Pilot Project: Status
+# Report", Technical Report 90-09-10-1, published by NYSERNet
+# Inc, 1990.
+#
+# [5] Craigie, J., "UK Academic Community Directory Service Pilot
+# Project, pp. 305-310 in Computer Networks and ISDN Systems
+# 17 (1989), published by North Holland.
+#
+# [6] Mockapetris, P., "Domain Names - Concepts and Facilities",
+# RFC 1034, USC/Information Sciences Institute, November 1987.
+#
+# [7] Mockapetris, P., "Domain Names - Implementation and
+# Specification, RFC 1035, USC/Information Sciences Institute,
+# November 1987.
+#
+# [8] Kille, S., "Handling QOS (Quality of service) in the
+# Directory," publication in process, March 1991.
+#
+#
+# APPENDIX C - Summary of all Object Classes and Attribute Types
+#
+# -- Some Important Object Identifiers
+#
+# data OBJECT IDENTIFIER ::= {ccitt 9}
+# pss OBJECT IDENTIFIER ::= {data 2342}
+# ucl OBJECT IDENTIFIER ::= {pss 19200300}
+# pilot OBJECT IDENTIFIER ::= {ucl 100}
+#
+# pilotAttributeType OBJECT IDENTIFIER ::= {pilot 1}
+# pilotAttributeSyntax OBJECT IDENTIFIER ::= {pilot 3}
+# pilotObjectClass OBJECT IDENTIFIER ::= {pilot 4}
+# pilotGroups OBJECT IDENTIFIER ::= {pilot 10}
+#
+# iA5StringSyntax OBJECT IDENTIFIER ::= {pilotAttributeSyntax 4}
+# caseIgnoreIA5StringSyntax OBJECT IDENTIFIER ::=
+# {pilotAttributeSyntax 5}
+#
+# -- Standard Object Classes
+#
+# top OBJECT-CLASS
+# MUST CONTAIN {
+# objectClass}
+# ::= {objectClass 0}
+#
+#
+# alias OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# aliasedObjectName}
+# ::= {objectClass 1}
+#
+#
+# country OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# countryName}
+# MAY CONTAIN {
+# description,
+# searchGuide}
+# ::= {objectClass 2}
+#
+#
+# locality OBJECT-CLASS
+# SUBCLASS OF top
+# MAY CONTAIN {
+# description,
+# localityName,
+# stateOrProvinceName,
+# searchGuide,
+# seeAlso,
+# streetAddress}
+# ::= {objectClass 3}
+#
+#
+# organization OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# organizationName}
+# MAY CONTAIN {
+# organizationalAttributeSet}
+# ::= {objectClass 4}
+#
+#
+# organizationalUnit OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# organizationalUnitName}
+# MAY CONTAIN {
+# organizationalAttributeSet}
+# ::= {objectClass 5}
+#
+#
+# person OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName,
+# surname}
+# MAY CONTAIN {
+# description,
+# seeAlso,
+# telephoneNumber,
+# userPassword}
+# ::= {objectClass 6}
+#
+#
+# organizationalPerson OBJECT-CLASS
+# SUBCLASS OF person
+# MAY CONTAIN {
+# localeAttributeSet,
+# organizationalUnitName,
+# postalAttributeSet,
+# telecommunicationAttributeSet,
+# title}
+# ::= {objectClass 7}
+#
+#
+# organizationalRole OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName}
+# MAY CONTAIN {
+# description,
+# localeAttributeSet,
+# organizationalUnitName,
+# postalAttributeSet,
+# preferredDeliveryMethod,
+# roleOccupant,
+# seeAlso,
+# telecommunicationAttributeSet}
+# ::= {objectClass 8}
+#
+#
+# groupOfNames OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName,
+# member}
+# MAY CONTAIN {
+# description,
+# organizationName,
+# organizationalUnitName,
+# owner,
+# seeAlso,
+# businessCategory}
+# ::= {objectClass 9}
+#
+#
+# residentialPerson OBJECT-CLASS
+# SUBCLASS OF person
+# MUST CONTAIN {
+# localityName}
+# MAY CONTAIN {
+# localeAttributeSet,
+# postalAttributeSet,
+# preferredDeliveryMethod,
+# telecommunicationAttributeSet,
+# businessCategory}
+# ::= {objectClass 10}
+#
+#
+# applicationProcess OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName}
+# MAY CONTAIN {
+# description,
+# localityName,
+# organizationalUnitName,
+# seeAlso}
+# ::= {objectClass 11}
+#
+#
+# applicationEntity OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName,
+# presentationAddress}
+# MAY CONTAIN {
+# description,
+# localityName,
+# organizationName,
+# organizationalUnitName,
+# seeAlso,
+# supportedApplicationContext}
+# ::= {objectClass 12}
+#
+#
+# dSA OBJECT-CLASS
+# SUBCLASS OF applicationEntity
+# MAY CONTAIN {
+# knowledgeInformation}
+# ::= {objectClass 13}
+#
+#
+# device OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName}
+# MAY CONTAIN {
+# description,
+# localityName,
+# organizationName,
+# organizationalUnitName,
+# owner,
+# seeAlso,
+# serialNumber}
+# ::= {objectClass 14}
+#
+#
+# strongAuthenticationUser OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# userCertificate}
+# ::= {objectClass 15}
+#
+#
+# certificationAuthority OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# cACertificate,
+# certificateRevocationList,
+# authorityRevocationList}
+# MAY CONTAIN {
+# crossCertificatePair}
+# ::= {objectClass 16}
+#
+# -- Standard MHS Object Classes
+#
+# mhsDistributionList OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName,
+# mhsDLSubmitPermissions,
+# mhsORAddresses}
+# MAY CONTAIN {
+# description,
+# organizationName,
+# organizationalUnitName,
+# owner,
+# seeAlso,
+# mhsDeliverableContentTypes,
+# mhsdeliverableEits,
+# mhsDLMembers,
+# mhsPreferredDeliveryMethods}
+# ::= {mhsObjectClass 0}
+#
+#
+# mhsMessageStore OBJECT-CLASS
+# SUBCLASS OF applicationEntity
+# MAY CONTAIN {
+# description,
+# owner,
+# mhsSupportedOptionalAttributes,
+# mhsSupportedAutomaticActions,
+# mhsSupportedContentTypes}
+# ::= {mhsObjectClass 1}
+#
+#
+# mhsMessageTransferAgent OBJECT-CLASS
+# SUBCLASS OF applicationEntity
+# MAY CONTAIN {
+# description,
+# owner,
+# mhsDeliverableContentLength}
+# ::= {mhsObjectClass 2}
+#
+#
+# mhsOrganizationalUser OBJECT-CLASS
+# SUBCLASS OF organizationalPerson
+# MUST CONTAIN {
+# mhsORAddresses}
+# MAY CONTAIN {
+# mhsDeliverableContentLength,
+# mhsDeliverableContentTypes,
+# mhsDeliverableEits,
+# mhsMessageStoreName,
+# mhsPreferredDeliveryMethods }
+# ::= {mhsObjectClass 3}
+#
+#
+# mhsResidentialUser OBJECT-CLASS
+# SUBCLASS OF residentialPerson
+# MUST CONTAIN {
+# mhsORAddresses}
+# MAY CONTAIN {
+# mhsDeliverableContentLength,
+# mhsDeliverableContentTypes,
+# mhsDeliverableEits,
+# mhsMessageStoreName,
+# mhsPreferredDeliveryMethods }
+# ::= {mhsObjectClass 4}
+#
+#
+# mhsUserAgent OBJECT-CLASS
+# SUBCLASS OF applicationEntity
+# MAY CONTAIN {
+# mhsDeliverableContentLength,
+# mhsDeliverableContentTypes,
+# mhsDeliverableEits,
+# mhsORAddresses,
+# owner}
+# ::= {mhsObjectClass 5}
+#
+#
+#
+#
+# -- Pilot Object Classes
+#
+# pilotObject OBJECT-CLASS
+# SUBCLASS OF top
+# MAY CONTAIN {
+# info,
+# photo,
+# manager,
+# uniqueIdentifier,
+# lastModifiedTime,
+# lastModifiedBy,
+# dITRedirect,
+# audio}
+# ::= {pilotObjectClass 3}
+# pilotPerson OBJECT-CLASS
+# SUBCLASS OF person
+# MAY CONTAIN {
+# userid,
+# textEncodedORAddress,
+# rfc822Mailbox,
+# favouriteDrink,
+# roomNumber,
+# userClass,
+# homeTelephoneNumber,
+# homePostalAddress,
+# secretary,
+# personalTitle,
+# preferredDeliveryMethod,
+# businessCategory,
+# janetMailbox,
+# otherMailbox,
+# mobileTelephoneNumber,
+# pagerTelephoneNumber,
+# organizationalStatus,
+# mailPreferenceOption,
+# personalSignature}
+# ::= {pilotObjectClass 4}
+#
+#
+# account OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# userid}
+# MAY CONTAIN {
+# description,
+# seeAlso,
+# localityName,
+# organizationName,
+# organizationalUnitName,
+# host}
+# ::= {pilotObjectClass 5}
+#
+#
+# document OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# documentIdentifier}
+# MAY CONTAIN {
+# commonName,
+# description,
+# seeAlso,
+# localityName,
+# organizationName,
+# organizationalUnitName,
+# documentTitle,
+# documentVersion,
+# documentAuthor,
+# documentLocation,
+# documentPublisher}
+# ::= {pilotObjectClass 6}
+#
+#
+# room OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName}
+# MAY CONTAIN {
+# roomNumber,
+# description,
+# seeAlso,
+# telephoneNumber}
+# ::= {pilotObjectClass 7}
+#
+#
+# documentSeries OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName}
+# MAY CONTAIN {
+# description,
+# seeAlso,
+# telephoneNumber,
+# localityName,
+# organizationName,
+# organizationalUnitName}
+# ::= {pilotObjectClass 9}
+#
+#
+# domain OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# domainComponent}
+# MAY CONTAIN {
+# associatedName,
+# organizationName,
+# organizationalAttributeSet}
+# ::= {pilotObjectClass 13}
+#
+#
+# rFC822localPart OBJECT-CLASS
+# SUBCLASS OF domain
+# MAY CONTAIN {
+# commonName,
+# surname,
+# description,
+# seeAlso,
+# telephoneNumber,
+# postalAttributeSet,
+# telecommunicationAttributeSet}
+# ::= {pilotObjectClass 14}
+#
+#
+# dNSDomain OBJECT-CLASS
+# SUBCLASS OF domain
+# MAY CONTAIN {
+# ARecord,
+# MDRecord,
+# MXRecord,
+# NSRecord,
+# SOARecord,
+# CNAMERecord}
+# ::= {pilotObjectClass 15}
+#
+#
+# domainRelatedObject OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# associatedDomain}
+# ::= {pilotObjectClass 17}
+#
+#
+# friendlyCountry OBJECT-CLASS
+# SUBCLASS OF country
+# MUST CONTAIN {
+# friendlyCountryName}
+# ::= {pilotObjectClass 18}
+#
+#
+# simpleSecurityObject OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# userPassword }
+# ::= {pilotObjectClass 19}
+#
+#
+# pilotOrganization OBJECT-CLASS
+# SUBCLASS OF organization, organizationalUnit
+# MAY CONTAIN {
+# buildingName}
+# ::= {pilotObjectClass 20}
+#
+#
+# pilotDSA OBJECT-CLASS
+# SUBCLASS OF dsa
+# MUST CONTAIN {
+# dSAQuality}
+# ::= {pilotObjectClass 21}
+#
+#
+# qualityLabelledData OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# dSAQuality}
+# MAY CONTAIN {
+# subtreeMinimumQuality,
+# subtreeMaximumQuality}
+# ::= {pilotObjectClass 22}
+#
+#
+#
+#
+# -- Standard Attribute Types
+#
+# objectClass ObjectClass
+# ::= {attributeType 0}
+#
+#
+# aliasedObjectName AliasedObjectName
+# ::= {attributeType 1}
+#
+#
+# knowledgeInformation ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreString
+# ::= {attributeType 2}
+#
+#
+# commonName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-common-name))
+# ::= {attributeType 3}
+#
+#
+# surname ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-surname))
+# ::= {attributeType 4}
+#
+#
+# serialNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX printableStringSyntax
+# (SIZE (1..ub-serial-number))
+# ::= {attributeType 5}
+#
+#
+# countryName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX PrintableString
+# (SIZE (1..ub-country-code))
+# SINGLE VALUE
+# ::= {attributeType 6}
+#
+#
+# localityName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-locality-name))
+# ::= {attributeType 7}
+#
+#
+# stateOrProvinceName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-state-name))
+# ::= {attributeType 8}
+#
+#
+# streetAddress ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-street-address))
+# ::= {attributeType 9}
+#
+#
+# organizationName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-organization-name))
+# ::= {attributeType 10}
+#
+#
+# organizationalUnitName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-organizational-unit-name))
+# ::= {attributeType 11}
+#
+#
+# title ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-title))
+# ::= {attributeType 12}
+#
+#
+# description ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-description))
+# ::= {attributeType 13}
+#
+#
+# searchGuide ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX Guide
+# ::= {attributeType 14}
+#
+#
+# businessCategory ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-business-category))
+# ::= {attributeType 15}
+#
+#
+# postalAddress ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX PostalAddress
+# MATCHES FOR EQUALITY
+# ::= {attributeType 16}
+#
+#
+# postalCode ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-postal-code))
+# ::= {attributeType 17}
+#
+#
+# postOfficeBox ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-post-office-box))
+# ::= {attributeType 18}
+#
+#
+# physicalDeliveryOfficeName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-physical-office-name))
+# ::= {attributeType 19}
+#
+#
+# telephoneNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX telephoneNumberSyntax
+# (SIZE (1..ub-telephone-number))
+# ::= {attributeType 20}
+#
+#
+# telexNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX TelexNumber
+# (SIZE (1..ub-telex))
+# ::= {attributeType 21}
+#
+#
+# teletexTerminalIdentifier ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX TeletexTerminalIdentifier
+# (SIZE (1..ub-teletex-terminal-id))
+# ::= {attributeType 22}
+#
+#
+# facsimileTelephoneNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX FacsimileTelephoneNumber
+# ::= {attributeType 23}
+#
+#
+# x121Address ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX NumericString
+# (SIZE (1..ub-x121-address))
+# ::= {attributeType 24}
+#
+#
+# internationaliSDNNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX NumericString
+# (SIZE (1..ub-isdn-address))
+# ::= {attributeType 25}
+#
+#
+# registeredAddress ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX PostalAddress
+# ::= {attributeType 26}
+#
+#
+# destinationIndicator ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX PrintableString
+# (SIZE (1..ub-destination-indicator))
+# MATCHES FOR EQUALITY SUBSTRINGS
+# ::= {attributeType 27}
+#
+#
+# preferredDeliveryMethod ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX deliveryMethod
+# ::= {attributeType 28}
+#
+#
+# presentationAddress ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX PresentationAddress
+# MATCHES FOR EQUALITY
+# ::= {attributeType 29}
+#
+#
+# supportedApplicationContext ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX objectIdentifierSyntax
+# ::= {attributeType 30}
+#
+#
+# member ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX distinguishedNameSyntax
+# ::= {attributeType 31}
+#
+#
+# owner ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX distinguishedNameSyntax
+# ::= {attributeType 32}
+#
+#
+# roleOccupant ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX distinguishedNameSyntax
+# ::= {attributeType 33}
+#
+#
+# seeAlso ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX distinguishedNameSyntax
+# ::= {attributeType 34}
+#
+#
+# userPassword ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX Userpassword
+# ::= {attributeType 35}
+#
+#
+# userCertificate ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX UserCertificate
+# ::= {attributeType 36}
+#
+#
+# cACertificate ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX cACertificate
+# ::= {attributeType 37}
+#
+#
+# authorityRevocationList ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX AuthorityRevocationList
+# ::= {attributeType 38}
+#
+#
+# certificateRevocationList ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX CertificateRevocationList
+# ::= {attributeType 39}
+#
+#
+# crossCertificatePair ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX CrossCertificatePair
+# ::= {attributeType 40}
+#
+#
+#
+#
+# -- Standard MHS Attribute Types
+#
+# mhsDeliverableContentLength ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX integer
+# ::= {mhsAttributeType 0}
+#
+#
+# mhsDeliverableContentTypes ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX oID
+# ::= {mhsAttributeType 1}
+#
+#
+# mhsDeliverableEits ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX oID
+# ::= {mhsAttributeType 2}
+#
+#
+# mhsDLMembers ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX oRName
+# ::= {mhsAttributeType 3}
+#
+#
+# mhsDLSubmitPermissions ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX dLSubmitPermission
+# ::= {mhsAttributeType 4}
+#
+#
+# mhsMessageStoreName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX dN
+# ::= {mhsAttributeType 5}
+#
+#
+# mhsORAddresses ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX oRAddress
+# ::= {mhsAttributeType 6}
+#
+#
+# mhsPreferredDeliveryMethods ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX deliveryMethod
+# ::= {mhsAttributeType 7}
+#
+#
+# mhsSupportedAutomaticActions ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX oID
+# ::= {mhsAttributeType 8}
+#
+#
+# mhsSupportedContentTypes ATTRIBUTE
+#
+# WITH ATTRIBUTE-SYNTAX oID
+# ::= {mhsAttributeType 9}
+#
+#
+# mhsSupportedOptionalAttributes ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX oID
+# ::= {mhsAttributeType 10}
+#
+#
+#
+#
+# -- Pilot Attribute Types
+#
+# userid ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-user-identifier))
+# ::= {pilotAttributeType 1}
+#
+#
+# textEncodedORAddress ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-text-encoded-or-address))
+# ::= {pilotAttributeType 2}
+#
+#
+# rfc822Mailbox ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreIA5StringSyntax
+# (SIZE (1 .. ub-rfc822-mailbox))
+# ::= {pilotAttributeType 3}
+#
+#
+# info ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-information))
+# ::= {pilotAttributeType 4}
+#
+#
+# favouriteDrink ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-favourite-drink))
+# ::= {pilotAttributeType 5}
+#
+#
+# roomNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-room-number))
+# ::= {pilotAttributeType 6}
+#
+#
+# photo ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# CHOICE {
+# g3-facsimile [3] G3FacsimileBodyPart
+# }
+# (SIZE (1 .. ub-photo))
+# ::= {pilotAttributeType 7}
+#
+#
+# userClass ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-user-class))
+# ::= {pilotAttributeType 8}
+#
+#
+# host ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-host))
+# ::= {pilotAttributeType 9}
+#
+#
+# manager ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 10}
+#
+#
+# documentIdentifier ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-document-identifier))
+# ::= {pilotAttributeType 11}
+#
+#
+# documentTitle ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-document-title))
+# ::= {pilotAttributeType 12}
+#
+#
+# documentVersion ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-document-version))
+# ::= {pilotAttributeType 13}
+#
+#
+# documentAuthor ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 14}
+#
+#
+# documentLocation ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-document-location))
+# ::= {pilotAttributeType 15}
+#
+#
+# homeTelephoneNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# telephoneNumberSyntax
+# ::= {pilotAttributeType 20}
+#
+#
+# secretary ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 21}
+#
+#
+# otherMailbox ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# SEQUENCE {
+# mailboxType PrintableString, -- e.g. Telemail
+# mailbox IA5String -- e.g. X378:Joe
+# }
+# ::= {pilotAttributeType 22}
+#
+#
+# lastModifiedTime ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# uTCTimeSyntax
+# ::= {pilotAttributeType 23}
+#
+#
+# lastModifiedBy ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 24}
+#
+#
+# domainComponent ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreIA5StringSyntax
+# SINGLE VALUE
+# ::= {pilotAttributeType 25}
+#
+#
+# aRecord ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# DNSRecordSyntax
+# ::= {pilotAttributeType 26}
+#
+#
+# mXRecord ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# DNSRecordSyntax
+# ::= {pilotAttributeType 28}
+#
+#
+# nSRecord ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# DNSRecordSyntax
+# ::= {pilotAttributeType 29}
+#
+# sOARecord ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# DNSRecordSyntax
+# ::= {pilotAttributeType 30}
+#
+#
+# cNAMERecord ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# iA5StringSyntax
+# ::= {pilotAttributeType 31}
+#
+#
+# associatedDomain ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreIA5StringSyntax
+# ::= {pilotAttributeType 37}
+#
+#
+# associatedName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 38}
+#
+#
+# homePostalAddress ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# postalAddress
+# MATCHES FOR EQUALITY
+# ::= {pilotAttributeType 39}
+#
+#
+# personalTitle ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-personal-title))
+# ::= {pilotAttributeType 40}
+#
+#
+# mobileTelephoneNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# telephoneNumberSyntax
+# ::= {pilotAttributeType 41}
+#
+#
+# pagerTelephoneNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# telephoneNumberSyntax
+# ::= {pilotAttributeType 42}
+#
+#
+# friendlyCountryName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# ::= {pilotAttributeType 43}
+#
+#
+# uniqueIdentifier ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-unique-identifier))
+# ::= {pilotAttributeType 44}
+#
+#
+# organizationalStatus ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-organizational-status))
+# ::= {pilotAttributeType 45}
+#
+#
+# janetMailbox ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreIA5StringSyntax
+# (SIZE (1 .. ub-janet-mailbox))
+# ::= {pilotAttributeType 46}
+#
+#
+# mailPreferenceOption ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX ENUMERATED {
+# no-list-inclusion(0),
+# any-list-inclusion(1), -- may be added to any lists
+# professional-list-inclusion(2)
+# -- may be added to lists
+# -- which the list provider
+# -- views as related to the
+# -- users professional inter-
+# -- ests, perhaps evaluated
+# -- from the business of the
+# -- organisation or keywords
+# -- in the entry.
+# }
+# ::= {pilotAttributeType 47}
+#
+#
+# buildingName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-building-name))
+# ::= {pilotAttributeType 48}
+#
+#
+# dSAQuality ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX DSAQualitySyntax
+# SINGLE VALUE
+# ::= {pilotAttributeType 49}
+#
+#
+# singleLevelQuality ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX DataQualitySyntax
+# SINGLE VALUE
+#
+#
+# subtreeMinimumQuality ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX DataQualitySyntax
+# SINGLE VALUE
+# -- Defaults to singleLevelQuality
+# ::= {pilotAttributeType 51}
+#
+#
+# subtreeMaximumQuality ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX DataQualitySyntax
+# SINGLE VALUE
+# -- Defaults to singleLevelQuality
+# ::= {pilotAttributeType 52}
+#
+#
+# personalSignature ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# CHOICE {
+# g3-facsimile [3] G3FacsimileBodyPart
+# }
+# (SIZE (1 .. ub-personal-signature))
+# ::= {pilotAttributeType 53}
+#
+#
+# dITRedirect ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 54}
+#
+#
+# audio ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# Audio
+# (SIZE (1 .. ub-audio))
+# ::= {pilotAttributeType 55}
+#
+# documentPublisher ATTRIBUTE
+# WITH ATTRIBUTE SYNTAX caseIgnoreStringSyntax
+# ::= {pilotAttributeType 56}
+#
+#
+#
+# -- Generally useful syntaxes
+#
+#
+# caseIgnoreIA5StringSyntax ATTRIBUTE-SYNTAX
+# IA5String
+# MATCHES FOR EQUALITY SUBSTRINGS
+#
+#
+# iA5StringSyntax ATTRIBUTE-SYNTAX
+# IA5String
+# MATCHES FOR EQUALITY SUBSTRINGS
+#
+#
+# -- Syntaxes to support the DNS attributes
+#
+# DNSRecordSyntax ATTRIBUTE-SYNTAX
+# IA5String
+# MATCHES FOR EQUALITY
+#
+#
+# NRSInformationSyntax ATTRIBUTE-SYNTAX
+# NRSInformation
+# MATCHES FOR EQUALITY
+#
+#
+# NRSInformation ::= SET {
+# [0] Context,
+# [1] Address-space-id,
+# routes [2] SEQUENCE OF SEQUENCE {
+# Route-cost,
+# Addressing-info }
+# }
+#
+#
+# -- Upper bounds on length of attribute values
+#
+#
+# ub-document-identifier INTEGER ::= 256
+#
+# ub-document-location INTEGER ::= 256
+#
+# ub-document-title INTEGER ::= 256
+#
+# ub-document-version INTEGER ::= 256
+#
+# ub-favourite-drink INTEGER ::= 256
+#
+# ub-host INTEGER ::= 256
+#
+# ub-information INTEGER ::= 2048
+#
+# ub-unique-identifier INTEGER ::= 256
+#
+# ub-personal-title INTEGER ::= 256
+#
+# ub-photo INTEGER ::= 250000
+#
+# ub-rfc822-mailbox INTEGER ::= 256
+#
+# ub-room-number INTEGER ::= 256
+#
+# ub-text-or-address INTEGER ::= 256
+#
+# ub-user-class INTEGER ::= 256
+#
+# ub-user-identifier INTEGER ::= 256
+#
+# ub-organizational-status INTEGER ::= 256
+#
+# ub-janet-mailbox INTEGER ::= 256
+#
+# ub-building-name INTEGER ::= 256
+#
+# ub-personal-signature ::= 50000
+#
+# ub-audio INTEGER ::= 250000
+#
+# [remainder of memo trimmed]
+
diff --git a/test/ldap_files/schema/inetorgperson.schema b/test/ldap_files/schema/inetorgperson.schema
new file mode 100644
index 00000000..db0b8c11
--- /dev/null
+++ b/test/ldap_files/schema/inetorgperson.schema
@@ -0,0 +1,155 @@
+# inetorgperson.schema -- InetOrgPerson (RFC2798)
+# $OpenLDAP$
+## This work is part of OpenLDAP Software .
+##
+## Copyright 1998-2019 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## .
+#
+# InetOrgPerson (RFC2798)
+#
+# Depends upon
+# Definition of an X.500 Attribute Type and an Object Class to Hold
+# Uniform Resource Identifiers (URIs) [RFC2079]
+# (core.schema)
+#
+# A Summary of the X.500(96) User Schema for use with LDAPv3 [RFC2256]
+# (core.schema)
+#
+# The COSINE and Internet X.500 Schema [RFC1274] (cosine.schema)
+
+# carLicense
+# This multivalued field is used to record the values of the license or
+# registration plate associated with an individual.
+attributetype ( 2.16.840.1.113730.3.1.1
+ NAME 'carLicense'
+ DESC 'RFC2798: vehicle license or registration plate'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+# departmentNumber
+# Code for department to which a person belongs. This can also be
+# strictly numeric (e.g., 1234) or alphanumeric (e.g., ABC/123).
+attributetype ( 2.16.840.1.113730.3.1.2
+ NAME 'departmentNumber'
+ DESC 'RFC2798: identifies a department within an organization'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+# displayName
+# When displaying an entry, especially within a one-line summary list, it
+# is useful to be able to identify a name to be used. Since other attri-
+# bute types such as 'cn' are multivalued, an additional attribute type is
+# needed. Display name is defined for this purpose.
+attributetype ( 2.16.840.1.113730.3.1.241
+ NAME 'displayName'
+ DESC 'RFC2798: preferred name to be used when displaying entries'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE )
+
+# employeeNumber
+# Numeric or alphanumeric identifier assigned to a person, typically based
+# on order of hire or association with an organization. Single valued.
+attributetype ( 2.16.840.1.113730.3.1.3
+ NAME 'employeeNumber'
+ DESC 'RFC2798: numerically identifies an employee within an organization'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE )
+
+# employeeType
+# Used to identify the employer to employee relationship. Typical values
+# used will be "Contractor", "Employee", "Intern", "Temp", "External", and
+# "Unknown" but any value may be used.
+attributetype ( 2.16.840.1.113730.3.1.4
+ NAME 'employeeType'
+ DESC 'RFC2798: type of employment for a person'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+# jpegPhoto
+# Used to store one or more images of a person using the JPEG File
+# Interchange Format [JFIF].
+# Note that the jpegPhoto attribute type was defined for use in the
+# Internet X.500 pilots but no referencable definition for it could be
+# located.
+attributetype ( 0.9.2342.19200300.100.1.60
+ NAME 'jpegPhoto'
+ DESC 'RFC2798: a JPEG image'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.28 )
+
+# preferredLanguage
+# Used to indicate an individual's preferred written or spoken
+# language. This is useful for international correspondence or human-
+# computer interaction. Values for this attribute type MUST conform to
+# the definition of the Accept-Language header field defined in
+# [RFC2068] with one exception: the sequence "Accept-Language" ":"
+# should be omitted. This is a single valued attribute type.
+attributetype ( 2.16.840.1.113730.3.1.39
+ NAME 'preferredLanguage'
+ DESC 'RFC2798: preferred written or spoken language for a person'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE )
+
+# userSMIMECertificate
+# A PKCS#7 [RFC2315] SignedData, where the content that is signed is
+# ignored by consumers of userSMIMECertificate values. It is
+# recommended that values have a `contentType' of data with an absent
+# `content' field. Values of this attribute contain a person's entire
+# certificate chain and an smimeCapabilities field [RFC2633] that at a
+# minimum describes their SMIME algorithm capabilities. Values for
+# this attribute are to be stored and requested in binary form, as
+# 'userSMIMECertificate;binary'. If available, this attribute is
+# preferred over the userCertificate attribute for S/MIME applications.
+## OpenLDAP note: ";binary" transfer should NOT be used as syntax is binary
+attributetype ( 2.16.840.1.113730.3.1.40
+ NAME 'userSMIMECertificate'
+ DESC 'RFC2798: PKCS#7 SignedData used to support S/MIME'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 )
+
+# userPKCS12
+# PKCS #12 [PKCS12] provides a format for exchange of personal identity
+# information. When such information is stored in a directory service,
+# the userPKCS12 attribute should be used. This attribute is to be stored
+# and requested in binary form, as 'userPKCS12;binary'. The attribute
+# values are PFX PDUs stored as binary data.
+## OpenLDAP note: ";binary" transfer should NOT be used as syntax is binary
+attributetype ( 2.16.840.1.113730.3.1.216
+ NAME 'userPKCS12'
+ DESC 'RFC2798: personal identity information, a PKCS #12 PFX'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 )
+
+
+# inetOrgPerson
+# The inetOrgPerson represents people who are associated with an
+# organization in some way. It is a structural class and is derived
+# from the organizationalPerson which is defined in X.521 [X521].
+objectclass ( 2.16.840.1.113730.3.2.2
+ NAME 'inetOrgPerson'
+ DESC 'RFC2798: Internet Organizational Person'
+ SUP organizationalPerson
+ STRUCTURAL
+ MAY (
+ audio $ businessCategory $ carLicense $ departmentNumber $
+ displayName $ employeeNumber $ employeeType $ givenName $
+ homePhone $ homePostalAddress $ initials $ jpegPhoto $
+ labeledURI $ mail $ manager $ mobile $ o $ pager $
+ photo $ roomNumber $ secretary $ uid $ userCertificate $
+ x500uniqueIdentifier $ preferredLanguage $
+ userSMIMECertificate $ userPKCS12 )
+ )
diff --git a/test/ldap_files/schema/mailserver.schema b/test/ldap_files/schema/mailserver.schema
new file mode 100644
index 00000000..ff502ff1
--- /dev/null
+++ b/test/ldap_files/schema/mailserver.schema
@@ -0,0 +1,88 @@
+## LDAP Schema Yunohost EMAIL
+## Version 0.1
+## Adrien Beudin
+
+# Attributes
+attributetype ( 1.3.6.1.4.1.40328.1.20.2.1
+ NAME 'maildrop'
+ DESC 'Mail addresses where mails are forwarded -- ie forwards'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{512})
+
+attributetype ( 1.3.6.1.4.1.40328.1.20.2.2
+ NAME 'mailalias'
+ DESC 'Mail addresses accepted by this account -- ie aliases'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{512})
+
+attributetype ( 1.3.6.1.4.1.40328.1.20.2.3
+ NAME 'mailenable'
+ DESC 'Mail Account validity'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{8})
+
+attributetype ( 1.3.6.1.4.1.40328.1.20.2.4
+ NAME 'mailbox'
+ DESC 'Mailbox path where mails are delivered'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{512})
+
+attributetype ( 1.3.6.1.4.1.40328.1.20.2.5
+ NAME 'virtualdomain'
+ DESC 'A mail domain name'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{512})
+
+attributetype ( 1.3.6.1.4.1.40328.1.20.2.6
+ NAME 'virtualdomaindescription'
+ DESC 'Virtual domain description'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{512})
+
+attributetype ( 1.3.6.1.4.1.40328.1.20.2.7
+ NAME 'mailuserquota'
+ DESC 'Mailbox quota for a user'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{16} SINGLE-VALUE )
+
+# Mail Account Objectclass
+objectclass ( 1.3.6.1.4.1.40328.1.1.2.1
+ NAME 'mailAccount'
+ DESC 'Mail Account'
+ SUP top
+ AUXILIARY
+ MUST (
+ mail
+ )
+ MAY (
+ mailalias $ maildrop $ mailenable $ mailbox $ mailuserquota
+ )
+ )
+
+# Mail Domain Objectclass
+objectclass ( 1.3.6.1.4.1.40328.1.1.2.2
+ NAME 'mailDomain'
+ DESC 'Domain mail entry'
+ SUP top
+ STRUCTURAL
+ MUST (
+ virtualdomain
+ )
+ MAY (
+ virtualdomaindescription $ mailuserquota
+ )
+ )
+
+# Mail Group Objectclass
+objectclass ( 1.3.6.1.4.1.40328.1.1.2.3
+ NAME 'mailGroup' SUP top AUXILIARY
+ DESC 'Mail Group'
+ MUST ( mail )
+ )
diff --git a/test/ldap_files/schema/nis.schema b/test/ldap_files/schema/nis.schema
new file mode 100644
index 00000000..d970998e
--- /dev/null
+++ b/test/ldap_files/schema/nis.schema
@@ -0,0 +1,237 @@
+# $OpenLDAP$
+## This work is part of OpenLDAP Software .
+##
+## Copyright 1998-2019 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## .
+
+# Definitions from RFC2307 (Experimental)
+# An Approach for Using LDAP as a Network Information Service
+
+# Depends upon core.schema and cosine.schema
+
+# Note: The definitions in RFC2307 are given in syntaxes closely related
+# to those in RFC2252, however, some liberties are taken that are not
+# supported by RFC2252. This file has been written following RFC2252
+# strictly.
+
+# OID Base is iso(1) org(3) dod(6) internet(1) directory(1) nisSchema(1).
+# i.e. nisSchema in RFC2307 is 1.3.6.1.1.1
+#
+# Syntaxes are under 1.3.6.1.1.1.0 (two new syntaxes are defined)
+# validaters for these syntaxes are incomplete, they only
+# implement printable string validation (which is good as the
+# common use of these syntaxes violates the specification).
+# Attribute types are under 1.3.6.1.1.1.1
+# Object classes are under 1.3.6.1.1.1.2
+
+# Attribute Type Definitions
+
+# builtin
+#attributetype ( 1.3.6.1.1.1.1.0 NAME 'uidNumber'
+# DESC 'An integer uniquely identifying a user in an administrative domain'
+# EQUALITY integerMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+# builtin
+#attributetype ( 1.3.6.1.1.1.1.1 NAME 'gidNumber'
+# DESC 'An integer uniquely identifying a group in an administrative domain'
+# EQUALITY integerMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.2 NAME 'gecos'
+ DESC 'The GECOS field; the common name'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.3 NAME 'homeDirectory'
+ DESC 'The absolute path to the home directory'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.4 NAME 'loginShell'
+ DESC 'The path to the login shell'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.5 NAME 'shadowLastChange'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.6 NAME 'shadowMin'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.7 NAME 'shadowMax'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.8 NAME 'shadowWarning'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.9 NAME 'shadowInactive'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.10 NAME 'shadowExpire'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.11 NAME 'shadowFlag'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.12 NAME 'memberUid'
+ EQUALITY caseExactIA5Match
+ SUBSTR caseExactIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.1.1.1.13 NAME 'memberNisNetgroup'
+ EQUALITY caseExactIA5Match
+ SUBSTR caseExactIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.1.1.1.14 NAME 'nisNetgroupTriple'
+ DESC 'Netgroup triple'
+ SYNTAX 1.3.6.1.1.1.0.0 )
+
+attributetype ( 1.3.6.1.1.1.1.15 NAME 'ipServicePort'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.16 NAME 'ipServiceProtocol'
+ SUP name )
+
+attributetype ( 1.3.6.1.1.1.1.17 NAME 'ipProtocolNumber'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.18 NAME 'oncRpcNumber'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.19 NAME 'ipHostNumber'
+ DESC 'IP address'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )
+
+attributetype ( 1.3.6.1.1.1.1.20 NAME 'ipNetworkNumber'
+ DESC 'IP network'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.21 NAME 'ipNetmaskNumber'
+ DESC 'IP netmask'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.22 NAME 'macAddress'
+ DESC 'MAC address'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )
+
+attributetype ( 1.3.6.1.1.1.1.23 NAME 'bootParameter'
+ DESC 'rpc.bootparamd parameter'
+ SYNTAX 1.3.6.1.1.1.0.1 )
+
+attributetype ( 1.3.6.1.1.1.1.24 NAME 'bootFile'
+ DESC 'Boot image name'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.1.1.1.26 NAME 'nisMapName'
+ SUP name )
+
+attributetype ( 1.3.6.1.1.1.1.27 NAME 'nisMapEntry'
+ EQUALITY caseExactIA5Match
+ SUBSTR caseExactIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{1024} SINGLE-VALUE )
+
+# Object Class Definitions
+
+objectclass ( 1.3.6.1.1.1.2.0 NAME 'posixAccount'
+ DESC 'Abstraction of an account with POSIX attributes'
+ SUP top AUXILIARY
+ MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
+ MAY ( userPassword $ loginShell $ gecos $ description ) )
+
+objectclass ( 1.3.6.1.1.1.2.1 NAME 'shadowAccount'
+ DESC 'Additional attributes for shadow passwords'
+ SUP top AUXILIARY
+ MUST uid
+ MAY ( userPassword $ shadowLastChange $ shadowMin $
+ shadowMax $ shadowWarning $ shadowInactive $
+ shadowExpire $ shadowFlag $ description ) )
+
+objectclass ( 1.3.6.1.1.1.2.2 NAME 'posixGroup'
+ DESC 'Abstraction of a group of accounts'
+ SUP top STRUCTURAL
+ MUST ( cn $ gidNumber )
+ MAY ( userPassword $ memberUid $ description ) )
+
+objectclass ( 1.3.6.1.1.1.2.3 NAME 'ipService'
+ DESC 'Abstraction an Internet Protocol service'
+ SUP top STRUCTURAL
+ MUST ( cn $ ipServicePort $ ipServiceProtocol )
+ MAY ( description ) )
+
+objectclass ( 1.3.6.1.1.1.2.4 NAME 'ipProtocol'
+ DESC 'Abstraction of an IP protocol'
+ SUP top STRUCTURAL
+ MUST ( cn $ ipProtocolNumber $ description )
+ MAY description )
+
+objectclass ( 1.3.6.1.1.1.2.5 NAME 'oncRpc'
+ DESC 'Abstraction of an ONC/RPC binding'
+ SUP top STRUCTURAL
+ MUST ( cn $ oncRpcNumber $ description )
+ MAY description )
+
+objectclass ( 1.3.6.1.1.1.2.6 NAME 'ipHost'
+ DESC 'Abstraction of a host, an IP device'
+ SUP top AUXILIARY
+ MUST ( cn $ ipHostNumber )
+ MAY ( l $ description $ manager ) )
+
+objectclass ( 1.3.6.1.1.1.2.7 NAME 'ipNetwork'
+ DESC 'Abstraction of an IP network'
+ SUP top STRUCTURAL
+ MUST ( cn $ ipNetworkNumber )
+ MAY ( ipNetmaskNumber $ l $ description $ manager ) )
+
+objectclass ( 1.3.6.1.1.1.2.8 NAME 'nisNetgroup'
+ DESC 'Abstraction of a netgroup'
+ SUP top STRUCTURAL
+ MUST cn
+ MAY ( nisNetgroupTriple $ memberNisNetgroup $ description ) )
+
+objectclass ( 1.3.6.1.1.1.2.9 NAME 'nisMap'
+ DESC 'A generic abstraction of a NIS map'
+ SUP top STRUCTURAL
+ MUST nisMapName
+ MAY description )
+
+objectclass ( 1.3.6.1.1.1.2.10 NAME 'nisObject'
+ DESC 'An entry in a NIS map'
+ SUP top STRUCTURAL
+ MUST ( cn $ nisMapEntry $ nisMapName )
+ MAY description )
+
+objectclass ( 1.3.6.1.1.1.2.11 NAME 'ieee802Device'
+ DESC 'A device with a MAC address'
+ SUP top AUXILIARY
+ MAY macAddress )
+
+objectclass ( 1.3.6.1.1.1.2.12 NAME 'bootableDevice'
+ DESC 'A device with boot parameters'
+ SUP top AUXILIARY
+ MAY ( bootFile $ bootParameter ) )
diff --git a/test/ldap_files/schema/sudo.schema b/test/ldap_files/schema/sudo.schema
new file mode 100644
index 00000000..d3e95e00
--- /dev/null
+++ b/test/ldap_files/schema/sudo.schema
@@ -0,0 +1,76 @@
+#
+# OpenLDAP schema file for Sudo
+# Save as /etc/openldap/schema/sudo.schema
+#
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.1
+ NAME 'sudoUser'
+ DESC 'User(s) who may run sudo'
+ EQUALITY caseExactIA5Match
+ SUBSTR caseExactIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.2
+ NAME 'sudoHost'
+ DESC 'Host(s) who may run sudo'
+ EQUALITY caseExactIA5Match
+ SUBSTR caseExactIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.3
+ NAME 'sudoCommand'
+ DESC 'Command(s) to be executed by sudo'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.4
+ NAME 'sudoRunAs'
+ DESC 'User(s) impersonated by sudo (deprecated)'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.5
+ NAME 'sudoOption'
+ DESC 'Options(s) followed by sudo'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.6
+ NAME 'sudoRunAsUser'
+ DESC 'User(s) impersonated by sudo'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.7
+ NAME 'sudoRunAsGroup'
+ DESC 'Group(s) impersonated by sudo'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.8
+ NAME 'sudoNotBefore'
+ DESC 'Start of time interval for which the entry is valid'
+ EQUALITY generalizedTimeMatch
+ ORDERING generalizedTimeOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.9
+ NAME 'sudoNotAfter'
+ DESC 'End of time interval for which the entry is valid'
+ EQUALITY generalizedTimeMatch
+ ORDERING generalizedTimeOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+
+attributeTypes ( 1.3.6.1.4.1.15953.9.1.10
+ NAME 'sudoOrder'
+ DESC 'an integer to order the sudoRole entries'
+ EQUALITY integerMatch
+ ORDERING integerOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
+
+objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL
+ DESC 'Sudoer Entries'
+ MUST ( cn )
+ MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ sudoOrder $ sudoNotBefore $ sudoNotAfter $
+ description )
+ )
diff --git a/test/ldap_files/schema/yunohost.schema b/test/ldap_files/schema/yunohost.schema
new file mode 100644
index 00000000..7da60a20
--- /dev/null
+++ b/test/ldap_files/schema/yunohost.schema
@@ -0,0 +1,33 @@
+#dn: cn=yunohost,cn=schema,cn=config
+#objectClass: olcSchemaConfig
+#cn: yunohost
+# ATTRIBUTES
+# For Permission
+attributetype ( 1.3.6.1.4.1.17953.9.1.1 NAME 'permission'
+ DESC 'Yunohost permission on user and group side'
+ SUP distinguishedName )
+attributetype ( 1.3.6.1.4.1.17953.9.1.2 NAME 'groupPermission'
+ DESC 'Yunohost permission for a group on permission side'
+ SUP distinguishedName )
+attributetype ( 1.3.6.1.4.1.17953.9.1.3 NAME 'inheritPermission'
+ DESC 'Yunohost permission for user on permission side'
+ SUP distinguishedName )
+attributetype ( 1.3.6.1.4.1.17953.9.1.4 NAME 'URL'
+ DESC 'Yunohost application URL'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+# OBJECTCLASS
+# For Applications
+objectclass ( 1.3.6.1.4.1.17953.9.2.1 NAME 'groupOfNamesYnh'
+ DESC 'Yunohost user group'
+ SUP top AUXILIARY
+ MAY ( member $ businessCategory $ seeAlso $ owner $ ou $ o $ permission ) )
+objectclass ( 1.3.6.1.4.1.17953.9.2.2 NAME 'permissionYnh'
+ DESC 'a Yunohost application'
+ SUP top AUXILIARY
+ MUST cn
+ MAY ( groupPermission $ inheritPermission $ URL ) )
+# For User
+objectclass ( 1.3.6.1.4.1.17953.9.2.3 NAME 'userPermissionYnh'
+ DESC 'a Yunohost application'
+ SUP top AUXILIARY
+ MAY ( permission ) )
diff --git a/test/ldap_files/slapd.conf.template b/test/ldap_files/slapd.conf.template
new file mode 100644
index 00000000..05c3f522
--- /dev/null
+++ b/test/ldap_files/slapd.conf.template
@@ -0,0 +1,94 @@
+serverID %(serverid)s
+moduleload back_%(database)s
+moduleload memberof
+%(include_directives)s
+loglevel %(loglevel)s
+#allow bind_v2
+database %(database)s
+directory "%(directory)s"
+suffix "%(suffix)s"
+rootdn "%(rootdn)s"
+rootpw "%(rootpw)s"
+TLSCACertificateFile "%(cafile)s"
+TLSCertificateFile "%(servercert)s"
+TLSCertificateKeyFile "%(serverkey)s"
+authz-regexp
+ "gidnumber=%(root_gid)s\\+uidnumber=%(root_uid)s,cn=peercred,cn=external,cn=auth"
+ "%(rootdn)s"
+
+index objectClass eq
+index uid,sudoUser eq,sub
+index entryCSN,entryUUID eq
+index cn,mail eq
+index gidNumber,uidNumber eq
+index member,memberUid,uniqueMember eq
+index virtualdomain eq
+
+# The userPassword by default can be changed
+# by the entry owning it if they are authenticated.
+# Others should not be able to see it, except the
+# admin entry below
+# These access lines apply to database #1 only
+access to attrs=userPassword,shadowLastChange
+ by dn="cn=admin,dc=yunohost,dc=org" write
+ by dn.exact="gidNumber=%(root_gid)s+uidnumber=%(root_uid)s,cn=peercred,cn=external,cn=auth" write
+ by anonymous auth
+ by self write
+ by * none
+
+# Personnal information can be changed by the entry
+# owning it if they are authenticated.
+# Others should be able to see it.
+access to attrs=cn,gecos,givenName,mail,maildrop,displayName,sn
+ by dn="cn=admin,dc=yunohost,dc=org" write
+ by dn.exact="gidNumber=%(root_gid)s+uidnumber=%(root_uid)s,cn=peercred,cn=external,cn=auth" write
+ by self write
+ by * read
+
+# Ensure read access to the base for things like
+# supportedSASLMechanisms. Without this you may
+# have problems with SASL not knowing what
+# mechanisms are available and the like.
+# Note that this is covered by the 'access to *'
+# ACL below too but if you change that as people
+# are wont to do you'll still need this if you
+# want SASL (and possible ldap_files things) to work
+# happily.
+access to dn.base="" by * read
+
+# The admin dn has full write access, everyone else
+# can read everything.
+access to *
+ by dn="cn=admin,dc=yunohost,dc=org" write
+ by dn.exact="gidNumber=%(root_gid)s+uidnumber=%(root_uid)s,cn=peercred,cn=external,cn=auth" write
+ by group/groupOfNames/Member="cn=admin,ou=groups,dc=yunohost,dc=org" write
+ by * read
+
+# Configure Memberof Overlay (used for Yunohost permission)
+
+# Link user <-> group
+#dn: olcOverlay={0}memberof,olcDatabase={1}mdb,cn=config
+overlay memberof
+memberof-group-oc groupOfNamesYnh
+memberof-member-ad member
+memberof-memberof-ad memberOf
+memberof-dangling error
+memberof-refint TRUE
+
+# Link permission <-> groupes
+#dn: olcOverlay={1}memberof,olcDatabase={1}mdb,cn=config
+overlay memberof
+memberof-group-oc permissionYnh
+memberof-member-ad groupPermission
+memberof-memberof-ad permission
+memberof-dangling error
+memberof-refint TRUE
+
+# Link permission <-> user
+#dn: olcOverlay={2}memberof,olcDatabase={1}mdb,cn=config
+overlay memberof
+memberof-group-oc permissionYnh
+memberof-member-ad inheritPermission
+memberof-memberof-ad permission
+memberof-dangling error
+memberof-refint TRUE
\ No newline at end of file
diff --git a/test/ldap_files/tests.ldif b/test/ldap_files/tests.ldif
new file mode 100644
index 00000000..355dd643
--- /dev/null
+++ b/test/ldap_files/tests.ldif
@@ -0,0 +1,205 @@
+dn: dc=yunohost,dc=org
+dc: yunohost
+o: yunohost.org
+objectclass: top
+objectclass: dcObject
+objectclass: organization
+
+dn: cn=admin,dc=yunohost,dc=org
+objectClass: simpleSecurityObject
+objectClass: organizationalRole
+cn: admin
+userPassword: yunohost
+
+#dn: ou=people,dc=yunohost,dc=org
+#objectClass: organizationalUnit
+#ou: people
+#
+#dn: ou=moregroups,dc=yunohost,dc=org
+#objectClass: organizationalUnit
+#ou: moregroups
+#
+#dn: ou=mirror_groups,dc=yunohost,dc=org
+#objectClass: organizationalUnit
+#ou: mirror_groups
+#
+#
+#dn: uid=alice,ou=people,dc=yunohost,dc=org
+#objectClass: person
+#objectClass: organizationalPerson
+#objectClass: inetOrgPerson
+#objectClass: posixAccount
+#cn: alice
+#uid: alice
+#userPassword: password
+#uidNumber: 1000
+#gidNumber: 1000
+#givenName: Alice
+#sn: Adams
+#homeDirectory: /home/alice
+#
+#dn: uid=bob,ou=people,dc=yunohost,dc=org
+#objectClass: person
+#objectClass: organizationalPerson
+#objectClass: inetOrgPerson
+#objectClass: posixAccount
+#cn: bob
+#uid: bob
+#userPassword: password
+#uidNumber: 1001
+#gidNumber: 50
+#givenName: Robert
+#sn: Barker
+#homeDirectory: /home/bob
+#
+#dn: uid=dreßler,ou=people,dc=yunohost,dc=org
+#objectClass: person
+#objectClass: organizationalPerson
+#objectClass: inetOrgPerson
+#objectClass: posixAccount
+#cn: dreßler
+#uid: dreßler
+#userPassword: password
+#uidNumber: 1002
+#gidNumber: 50
+#givenName: Wolfgang
+#sn: Dreßler
+#homeDirectory: /home/dressler
+#
+#dn: uid=nobody,ou=people,dc=yunohost,dc=org
+#objectClass: person
+#objectClass: organizationalPerson
+#objectClass: inetOrgPerson
+#objectClass: posixAccount
+#cn: nobody
+#uid: nobody
+#userPassword: password
+#uidNumber: 1003
+#gidNumber: 50
+#sn: nobody
+#homeDirectory: /home/nobody
+#
+#dn: uid=nonposix,ou=people,dc=yunohost,dc=org
+#objectClass: person
+#objectClass: organizationalPerson
+#objectClass: inetOrgPerson
+#cn: nonposix
+#uid: nonposix
+#userPassword: password
+#sn: nonposix
+#
+#
+## posixGroup objects
+#dn: cn=active_px,ou=moregroups,dc=yunohost,dc=org
+#objectClass: posixGroup
+#cn: active_px
+#gidNumber: 1000
+#memberUid: nonposix
+#
+#dn: cn=staff_px,ou=moregroups,dc=yunohost,dc=org
+#objectClass: posixGroup
+#cn: staff_px
+#gidNumber: 1001
+#memberUid: alice
+#memberUid: nonposix
+#
+#dn: cn=superuser_px,ou=moregroups,dc=yunohost,dc=org
+#objectClass: posixGroup
+#cn: superuser_px
+#gidNumber: 1002
+#memberUid: alice
+#memberUid: nonposix
+#
+#
+## groupOfNames groups
+#dn: cn=empty_gon,ou=moregroups,dc=yunohost,dc=org
+#cn: empty_gon
+#objectClass: groupOfNames
+#member:
+#
+#dn: cn=active_gon,ou=moregroups,dc=yunohost,dc=org
+#cn: active_gon
+#objectClass: groupOfNames
+#member: uid=alice,ou=people,dc=yunohost,dc=org
+#
+#dn: cn=staff_gon,ou=moregroups,dc=yunohost,dc=org
+#cn: staff_gon
+#objectClass: groupOfNames
+#member: uid=alice,ou=people,dc=yunohost,dc=org
+#
+#dn: cn=superuser_gon,ou=moregroups,dc=yunohost,dc=org
+#cn: superuser_gon
+#objectClass: groupOfNames
+#member: uid=alice,ou=people,dc=yunohost,dc=org
+#
+#dn: cn=other_gon,ou=moregroups,dc=yunohost,dc=org
+#cn: other_gon
+#objectClass: groupOfNames
+#member: uid=bob,ou=people,dc=yunohost,dc=org
+#
+#
+## groupOfNames objects for LDAPGroupQuery testing
+#dn: ou=query_groups,dc=yunohost,dc=org
+#objectClass: organizationalUnit
+#ou: query_groups
+#
+#dn: cn=alice_gon,ou=query_groups,dc=yunohost,dc=org
+#cn: alice_gon
+#objectClass: groupOfNames
+#member: uid=alice,ou=people,dc=yunohost,dc=org
+#
+#dn: cn=mutual_gon,ou=query_groups,dc=yunohost,dc=org
+#cn: mutual_gon
+#objectClass: groupOfNames
+#member: uid=alice,ou=people,dc=yunohost,dc=org
+#member: uid=bob,ou=people,dc=yunohost,dc=org
+#
+#dn: cn=bob_gon,ou=query_groups,dc=yunohost,dc=org
+#cn: bob_gon
+#objectClass: groupOfNames
+#member: uid=bob,ou=people,dc=yunohost,dc=org
+#
+#dn: cn=dreßler_gon,ou=query_groups,dc=yunohost,dc=org
+#cn: dreßler_gon
+#objectClass: groupOfNames
+#member: uid=dreßler,ou=people,dc=yunohost,dc=org
+#
+#
+## groupOfNames objects for selective group mirroring.
+#dn: cn=mirror1,ou=mirror_groups,dc=yunohost,dc=org
+#cn: mirror1
+#objectClass: groupOfNames
+#member: uid=alice,ou=people,dc=yunohost,dc=org
+#
+#dn: cn=mirror2,ou=mirror_groups,dc=yunohost,dc=org
+#cn: mirror2
+#objectClass: groupOfNames
+#member:
+#
+#dn: cn=mirror3,ou=mirror_groups,dc=yunohost,dc=org
+#cn: mirror3
+#objectClass: groupOfNames
+#member: uid=alice,ou=people,dc=yunohost,dc=org
+#
+#dn: cn=mirror4,ou=mirror_groups,dc=yunohost,dc=org
+#cn: mirror4
+#objectClass: groupOfNames
+#member:
+#
+#
+## Nested groups with a circular reference
+#dn: cn=parent_gon,ou=moregroups,dc=yunohost,dc=org
+#cn: parent_gon
+#objectClass: groupOfNames
+#member: cn=nested_gon,ou=moregroups,dc=yunohost,dc=org
+#
+#dn: CN=nested_gon,ou=moregroups,dc=yunohost,dc=org
+#cn: nested_gon
+#objectClass: groupOfNames
+#member: uid=alice,ou=people,dc=yunohost,dc=org
+#member: cn=circular_gon,ou=moregroups,dc=yunohost,dc=org
+#
+#dn: cn=circular_gon,ou=moregroups,dc=yunohost,dc=org
+#cn: circular_gon
+#objectClass: groupOfNames
+#member: cn=parent_gon,ou=moregroups,dc=yunohost,dc=org
diff --git a/test/old_slapdtest/README b/test/old_slapdtest/README
new file mode 100644
index 00000000..a6e34008
--- /dev/null
+++ b/test/old_slapdtest/README
@@ -0,0 +1,2 @@
+I have adapted the code from https://github.com/python-ldap/python-ldap/tree/master/Lib/slapdtest since the version of python-ldap we use does not provide the import slapdtest.
+This part will must be removed once we switch to python3
\ No newline at end of file
diff --git a/test/old_slapdtest/__init__.py b/test/old_slapdtest/__init__.py
new file mode 100644
index 00000000..a80062b1
--- /dev/null
+++ b/test/old_slapdtest/__init__.py
@@ -0,0 +1,2 @@
+# flake8: noqa
+from ._slapdtest import SlapdObject
diff --git a/test/old_slapdtest/_slapdtest.py b/test/old_slapdtest/_slapdtest.py
new file mode 100644
index 00000000..ab40ff55
--- /dev/null
+++ b/test/old_slapdtest/_slapdtest.py
@@ -0,0 +1,653 @@
+# -*- coding: utf-8 -*-
+# flake8: noqa
+"""
+slapdtest - module for spawning test instances of OpenLDAP's slapd server
+See https://www.python-ldap.org/ for details.
+"""
+
+from __future__ import unicode_literals
+
+import os
+import socket
+import sys
+import time
+import subprocess
+import logging
+import atexit
+from logging.handlers import SysLogHandler
+import unittest
+
+# Switch off processing .ldaprc or ldap.conf before importing _ldap
+os.environ["LDAPNOINIT"] = "1"
+
+import ldap
+from urllib import quote_plus
+
+try:
+ from shutil import which
+except ImportError:
+ # shutil.which() from Python 3.6
+ # "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+ # 2011, 2012, 2013, 2014, 2015, 2016, 2017 Python Software Foundation;
+ # All Rights Reserved"
+ def which(cmd, mode=os.F_OK | os.X_OK, path=None):
+ """Given a command, mode, and a PATH string, return the path which
+ conforms to the given mode on the PATH, or None if there is no such
+ file.
+ `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
+ of os.environ.get("PATH"), or can be overridden with a custom search
+ path.
+ """
+ # Check that a given file can be accessed with the correct mode.
+ # Additionally check that `file` is not a directory, as on Windows
+ # directories pass the os.access check.
+ def _access_check(fn, mode):
+ return os.path.exists(fn) and os.access(fn, mode) and not os.path.isdir(fn)
+
+ # If we're given a path with a directory part, look it up directly rather
+ # than referring to PATH directories. This includes checking relative to the
+ # current directory, e.g. ./script
+ if os.path.dirname(cmd):
+ if _access_check(cmd, mode):
+ return cmd
+ return None
+
+ if path is None:
+ path = os.environ.get("PATH", os.defpath)
+ if not path:
+ return None
+ path = path.split(os.pathsep)
+
+ if sys.platform == "win32":
+ # The current directory takes precedence on Windows.
+ if not os.curdir in path:
+ path.insert(0, os.curdir)
+
+ # PATHEXT is necessary to check on Windows.
+ pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
+ # See if the given file matches any of the expected path extensions.
+ # This will allow us to short circuit when given "python.exe".
+ # If it does match, only test that one, otherwise we have to try
+ # others.
+ if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
+ files = [cmd]
+ else:
+ files = [cmd + ext for ext in pathext]
+ else:
+ # On other platforms you don't have things like PATHEXT to tell you
+ # what file suffixes are executable, so just pass on cmd as-is.
+ files = [cmd]
+
+ seen = set()
+ for dir in path:
+ normdir = os.path.normcase(dir)
+ if not normdir in seen:
+ seen.add(normdir)
+ for thefile in files:
+ name = os.path.join(dir, thefile)
+ if _access_check(name, mode):
+ return name
+ return None
+
+
+HERE = os.path.abspath(os.path.dirname(__file__))
+
+# a template string for generating simple slapd.conf file
+SLAPD_CONF_TEMPLATE = r"""
+serverID %(serverid)s
+moduleload back_%(database)s
+%(include_directives)s
+loglevel %(loglevel)s
+allow bind_v2
+authz-regexp
+ "gidnumber=%(root_gid)s\\+uidnumber=%(root_uid)s,cn=peercred,cn=external,cn=auth"
+ "%(rootdn)s"
+database %(database)s
+directory "%(directory)s"
+suffix "%(suffix)s"
+rootdn "%(rootdn)s"
+rootpw "%(rootpw)s"
+TLSCACertificateFile "%(cafile)s"
+TLSCertificateFile "%(servercert)s"
+TLSCertificateKeyFile "%(serverkey)s"
+# ignore missing client cert but fail with invalid client cert
+TLSVerifyClient try
+authz-regexp
+ "C=DE, O=python-ldap, OU=slapd-test, CN=([A-Za-z]+)"
+ "ldap://ou=people,dc=local???($1)"
+"""
+
+LOCALHOST = "127.0.0.1"
+
+CI_DISABLED = set(os.environ.get("CI_DISABLED", "").split(":"))
+if "LDAPI" in CI_DISABLED:
+ HAVE_LDAPI = False
+else:
+ HAVE_LDAPI = hasattr(socket, "AF_UNIX")
+
+
+def identity(test_item):
+ """Identity decorator
+ """
+ return test_item
+
+
+def skip_unless_ci(reason, feature=None):
+ """Skip test unless test case is executed on CI like Travis CI
+ """
+ if not os.environ.get("CI", False):
+ return unittest.skip(reason)
+ elif feature in CI_DISABLED:
+ return unittest.skip(reason)
+ else:
+ # Don't skip on Travis
+ return identity
+
+
+def requires_tls():
+ """Decorator for TLS tests
+ Tests are not skipped on CI (e.g. Travis CI)
+ """
+ if not ldap.TLS_AVAIL:
+ return skip_unless_ci("test needs ldap.TLS_AVAIL", feature="TLS")
+ else:
+ return identity
+
+
+def requires_sasl():
+ if not ldap.SASL_AVAIL:
+ return skip_unless_ci("test needs ldap.SASL_AVAIL", feature="SASL")
+ else:
+ return identity
+
+
+def requires_ldapi():
+ if not HAVE_LDAPI:
+ return skip_unless_ci("test needs ldapi support (AF_UNIX)", feature="LDAPI")
+ else:
+ return identity
+
+
+def _add_sbin(path):
+ """Add /sbin and related directories to a command search path"""
+ directories = path.split(os.pathsep)
+ if sys.platform != "win32":
+ for sbin in "/usr/local/sbin", "/sbin", "/usr/sbin":
+ if sbin not in directories:
+ directories.append(sbin)
+ return os.pathsep.join(directories)
+
+
+def combined_logger(
+ log_name,
+ log_level=logging.WARN,
+ sys_log_format="%(levelname)s %(message)s",
+ console_log_format="%(asctime)s %(levelname)s %(message)s",
+):
+ """
+ Returns a combined SysLogHandler/StreamHandler logging instance
+ with formatters
+ """
+ if "LOGLEVEL" in os.environ:
+ log_level = os.environ["LOGLEVEL"]
+ try:
+ log_level = int(log_level)
+ except ValueError:
+ pass
+ # for writing to syslog
+ new_logger = logging.getLogger(log_name)
+ if sys_log_format and os.path.exists("/dev/log"):
+ my_syslog_formatter = logging.Formatter(
+ fmt=" ".join((log_name, sys_log_format))
+ )
+ my_syslog_handler = logging.handlers.SysLogHandler(
+ address="/dev/log", facility=SysLogHandler.LOG_DAEMON,
+ )
+ my_syslog_handler.setFormatter(my_syslog_formatter)
+ new_logger.addHandler(my_syslog_handler)
+ if console_log_format:
+ my_stream_formatter = logging.Formatter(fmt=console_log_format)
+ my_stream_handler = logging.StreamHandler()
+ my_stream_handler.setFormatter(my_stream_formatter)
+ new_logger.addHandler(my_stream_handler)
+ new_logger.setLevel(log_level)
+ return new_logger # end of combined_logger()
+
+
+class SlapdObject(object):
+ """
+ Controller class for a slapd instance, OpenLDAP's server.
+ This class creates a temporary data store for slapd, runs it
+ listening on a private Unix domain socket and TCP port,
+ and initializes it with a top-level entry and the root user.
+ When a reference to an instance of this class is lost, the slapd
+ server is shut down.
+ An instance can be used as a context manager. When exiting the context
+ manager, the slapd server is shut down and the temporary data store is
+ removed.
+ .. versionchanged:: 3.1
+ Added context manager functionality
+ """
+
+ slapd_conf_template = SLAPD_CONF_TEMPLATE
+ database = "mdb"
+ suffix = "dc=slapd-test,dc=python-ldap,dc=org"
+ root_cn = "Manager"
+ root_pw = "password"
+ slapd_loglevel = "stats stats2"
+ local_host = "127.0.0.1"
+ testrunsubdirs = ("schema",)
+ openldap_schema_files = ("core.schema",)
+
+ TMPDIR = os.environ.get("TMP", os.getcwd())
+ if "SCHEMA" in os.environ:
+ SCHEMADIR = os.environ["SCHEMA"]
+ elif os.path.isdir("/etc/openldap/schema"):
+ SCHEMADIR = "/etc/openldap/schema"
+ elif os.path.isdir("/etc/ldap/schema"):
+ SCHEMADIR = "/etc/ldap/schema"
+ else:
+ SCHEMADIR = None
+
+ BIN_PATH = os.environ.get("BIN", os.environ.get("PATH", os.defpath))
+ SBIN_PATH = os.environ.get("SBIN", _add_sbin(BIN_PATH))
+
+ # time in secs to wait before trying to access slapd via LDAP (again)
+ _start_sleep = 1.5
+
+ # create loggers once, multiple calls mess up refleak tests
+ _log = combined_logger("python-ldap-test")
+
+ def __init__(self):
+ self._proc = None
+ self._port = self._avail_tcp_port()
+ self.server_id = self._port % 4096
+ self.testrundir = os.path.join(self.TMPDIR, "python-ldap-test-%d" % self._port)
+ self._schema_prefix = os.path.join(self.testrundir, "schema")
+ self._slapd_conf = os.path.join(self.testrundir, "slapd.conf")
+ self._db_directory = os.path.join(self.testrundir, "openldap-data")
+ self.ldap_uri = "ldap://%s:%d/" % (LOCALHOST, self._port)
+ if HAVE_LDAPI:
+ ldapi_path = os.path.join(self.testrundir, "ldapi")
+ self.ldapi_uri = "ldapi://%s" % quote_plus(ldapi_path)
+ self.default_ldap_uri = self.ldapi_uri
+ # use SASL/EXTERNAL via LDAPI when invoking OpenLDAP CLI tools
+ self.cli_sasl_external = ldap.SASL_AVAIL
+ else:
+ self.ldapi_uri = None
+ self.default_ldap_uri = self.ldap_uri
+ # Use simple bind via LDAP uri
+ self.cli_sasl_external = False
+
+ self._find_commands()
+
+ if self.SCHEMADIR is None:
+ raise ValueError("SCHEMADIR is None, ldap schemas are missing.")
+
+ # TLS certs
+ self.cafile = os.path.join(HERE, "certs/ca.pem")
+ self.servercert = os.path.join(HERE, "certs/server.pem")
+ self.serverkey = os.path.join(HERE, "certs/server.key")
+ self.clientcert = os.path.join(HERE, "certs/client.pem")
+ self.clientkey = os.path.join(HERE, "certs/client.key")
+
+ @property
+ def root_dn(self):
+ return "cn={self.root_cn},{self.suffix}".format(self=self)
+
+ def _find_commands(self):
+ self.PATH_LDAPADD = self._find_command("ldapadd")
+ self.PATH_LDAPDELETE = self._find_command("ldapdelete")
+ self.PATH_LDAPMODIFY = self._find_command("ldapmodify")
+ self.PATH_LDAPWHOAMI = self._find_command("ldapwhoami")
+
+ self.PATH_SLAPD = os.environ.get("SLAPD", None)
+ if not self.PATH_SLAPD:
+ self.PATH_SLAPD = self._find_command("slapd", in_sbin=True)
+
+ def _find_command(self, cmd, in_sbin=False):
+ if in_sbin:
+ path = self.SBIN_PATH
+ var_name = "SBIN"
+ else:
+ path = self.BIN_PATH
+ var_name = "BIN"
+ command = which(cmd, path=path)
+ if command is None:
+ raise ValueError(
+ "Command '{}' not found. Set the {} environment variable to "
+ "override slapdtest's search path.".format(cmd, var_name)
+ )
+ return command
+
+ def setup_rundir(self):
+ """
+ creates rundir structure
+ for setting up a custom directory structure you have to override
+ this method
+ """
+ os.mkdir(self.testrundir)
+ os.mkdir(self._db_directory)
+ self._create_sub_dirs(self.testrunsubdirs)
+ self._ln_schema_files(self.openldap_schema_files, self.SCHEMADIR)
+
+ def _cleanup_rundir(self):
+ """
+ Recursively delete whole directory specified by `path'
+ """
+ # cleanup_rundir() is called in atexit handler. Until Python 3.4,
+ # the rest of the world is already destroyed.
+ import os, os.path
+
+ if not os.path.exists(self.testrundir):
+ return
+ self._log.debug("clean-up %s", self.testrundir)
+ for dirpath, dirnames, filenames in os.walk(self.testrundir, topdown=False):
+ for filename in filenames:
+ self._log.debug("remove %s", os.path.join(dirpath, filename))
+ os.remove(os.path.join(dirpath, filename))
+ for dirname in dirnames:
+ self._log.debug("rmdir %s", os.path.join(dirpath, dirname))
+ os.rmdir(os.path.join(dirpath, dirname))
+ os.rmdir(self.testrundir)
+ self._log.info("cleaned-up %s", self.testrundir)
+
+ def _avail_tcp_port(self):
+ """
+ find an available port for TCP connection
+ """
+ sock = socket.socket()
+ try:
+ sock.bind((self.local_host, 0))
+ port = sock.getsockname()[1]
+ finally:
+ sock.close()
+ self._log.info("Found available port %d", port)
+ return port
+
+ def gen_config(self):
+ """
+ generates a slapd.conf and returns it as one string
+ for generating specific static configuration files you have to
+ override this method
+ """
+ include_directives = "\n".join(
+ 'include "{schema_prefix}/{schema_file}"'.format(
+ schema_prefix=self._schema_prefix, schema_file=schema_file,
+ )
+ for schema_file in self.openldap_schema_files
+ )
+ config_dict = {
+ "serverid": hex(self.server_id),
+ "schema_prefix": self._schema_prefix,
+ "include_directives": include_directives,
+ "loglevel": self.slapd_loglevel,
+ "database": self.database,
+ "directory": self._db_directory,
+ "suffix": self.suffix,
+ "rootdn": self.root_dn,
+ "rootpw": self.root_pw,
+ "root_uid": os.getuid(),
+ "root_gid": os.getgid(),
+ "cafile": self.cafile,
+ "servercert": self.servercert,
+ "serverkey": self.serverkey,
+ }
+ return self.slapd_conf_template % config_dict
+
+ def _create_sub_dirs(self, dir_names):
+ """
+ create sub-directories beneath self.testrundir
+ """
+ for dname in dir_names:
+ dir_name = os.path.join(self.testrundir, dname)
+ self._log.debug("Create directory %s", dir_name)
+ os.mkdir(dir_name)
+
+ def _ln_schema_files(self, file_names, source_dir):
+ """
+ write symbolic links to original schema files
+ """
+ for fname in file_names:
+ ln_source = os.path.join(source_dir, fname)
+ ln_target = os.path.join(self._schema_prefix, fname)
+ self._log.debug("Create symlink %s -> %s", ln_source, ln_target)
+ os.symlink(ln_source, ln_target)
+
+ def _write_config(self):
+ """Writes the slapd.conf file out, and returns the path to it."""
+ self._log.debug("Writing config to %s", self._slapd_conf)
+ with open(self._slapd_conf, "w") as config_file:
+ config_file.write(self.gen_config())
+ self._log.info("Wrote config to %s", self._slapd_conf)
+
+ def _test_config(self):
+ self._log.debug("testing config %s", self._slapd_conf)
+ popen_list = [
+ self.PATH_SLAPD,
+ "-Ttest",
+ "-f",
+ self._slapd_conf,
+ "-u",
+ ]
+ if self._log.isEnabledFor(logging.DEBUG):
+ popen_list.append("-v")
+ popen_list.extend(["-d", "config"])
+ else:
+ popen_list.append("-Q")
+ proc = subprocess.Popen(popen_list)
+ if proc.wait() != 0:
+ raise RuntimeError("configuration test failed")
+ self._log.info("config ok: %s", self._slapd_conf)
+
+ def _start_slapd(self):
+ """
+ Spawns/forks the slapd process
+ """
+ urls = [self.ldap_uri]
+ if self.ldapi_uri:
+ urls.append(self.ldapi_uri)
+ slapd_args = [
+ self.PATH_SLAPD,
+ "-f",
+ self._slapd_conf,
+ "-F",
+ self.testrundir,
+ "-h",
+ " ".join(urls),
+ ]
+ if self._log.isEnabledFor(logging.DEBUG):
+ slapd_args.extend(["-d", "-1"])
+ else:
+ slapd_args.extend(["-d", "0"])
+ self._log.info("starting slapd: %r", " ".join(slapd_args))
+ self._proc = subprocess.Popen(slapd_args)
+ # Waits until the LDAP server socket is open, or slapd crashed
+ # no cover to avoid spurious coverage changes, see
+ # https://github.com/python-ldap/python-ldap/issues/127
+ for _ in range(10): # pragma: no cover
+ if self._proc.poll() is not None:
+ self._stopped()
+ raise RuntimeError("slapd exited before opening port")
+ time.sleep(self._start_sleep)
+ try:
+ self._log.debug("slapd connection check to %s", self.default_ldap_uri)
+ self.ldapwhoami()
+ except RuntimeError:
+ pass
+ else:
+ return
+ raise RuntimeError("slapd did not start properly")
+
+ def start(self):
+ """
+ Starts the slapd server process running, and waits for it to come up.
+ """
+
+ if self._proc is None:
+ # prepare directory structure
+ atexit.register(self.stop)
+ self._cleanup_rundir()
+ self.setup_rundir()
+ self._write_config()
+ self._test_config()
+ self._start_slapd()
+ self._log.debug(
+ "slapd with pid=%d listening on %s and %s",
+ self._proc.pid,
+ self.ldap_uri,
+ self.ldapi_uri,
+ )
+
+ def stop(self):
+ """
+ Stops the slapd server, and waits for it to terminate and cleans up
+ """
+ if self._proc is not None:
+ self._log.debug("stopping slapd with pid %d", self._proc.pid)
+ self._proc.terminate()
+ self.wait()
+ self._cleanup_rundir()
+ if hasattr(atexit, "unregister"):
+ # Python 3
+ atexit.unregister(self.stop)
+ elif hasattr(atexit, "_exithandlers"):
+ # Python 2, can be None during process shutdown
+ try:
+ atexit._exithandlers.remove(self.stop)
+ except ValueError:
+ pass
+
+ def restart(self):
+ """
+ Restarts the slapd server with same data
+ """
+ self._proc.terminate()
+ self.wait()
+ self._start_slapd()
+
+ def wait(self):
+ """Waits for the slapd process to terminate by itself."""
+ if self._proc:
+ self._proc.wait()
+ self._stopped()
+
+ def _stopped(self):
+ """Called when the slapd server is known to have terminated"""
+ if self._proc is not None:
+ self._log.info("slapd[%d] terminated", self._proc.pid)
+ self._proc = None
+
+ def _cli_auth_args(self):
+ if self.cli_sasl_external:
+ authc_args = [
+ "-Y",
+ "EXTERNAL",
+ ]
+ if not self._log.isEnabledFor(logging.DEBUG):
+ authc_args.append("-Q")
+ else:
+ authc_args = [
+ "-x",
+ "-D",
+ self.root_dn,
+ "-w",
+ self.root_pw,
+ ]
+ return authc_args
+
+ # no cover to avoid spurious coverage changes
+ def _cli_popen(
+ self, ldapcommand, extra_args=None, ldap_uri=None, stdin_data=None
+ ): # pragma: no cover
+ if ldap_uri is None:
+ ldap_uri = self.default_ldap_uri
+ args = (
+ [ldapcommand, "-H", ldap_uri,] + self._cli_auth_args() + (extra_args or [])
+ )
+ self._log.debug("Run command: %r", " ".join(args))
+ proc = subprocess.Popen(
+ args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE
+ )
+ self._log.debug("stdin_data=%r", stdin_data)
+ stdout_data, stderr_data = proc.communicate(stdin_data)
+ if stdout_data is not None:
+ self._log.debug("stdout_data=%r", stdout_data)
+ if stderr_data is not None:
+ self._log.debug("stderr_data=%r", stderr_data)
+ if proc.wait() != 0:
+ raise RuntimeError(
+ "{!r} process failed:\n{!r}\n{!r}".format(
+ args, stdout_data, stderr_data
+ )
+ )
+ return stdout_data, stderr_data
+
+ def ldapwhoami(self, extra_args=None):
+ """
+ Runs ldapwhoami on this slapd instance
+ """
+ self._cli_popen(self.PATH_LDAPWHOAMI, extra_args=extra_args)
+
+ def ldapadd(self, ldif, extra_args=None):
+ """
+ Runs ldapadd on this slapd instance, passing it the ldif content
+ """
+ self._cli_popen(
+ self.PATH_LDAPADD, extra_args=extra_args, stdin_data=ldif.encode("utf-8")
+ )
+
+ def ldapmodify(self, ldif, extra_args=None):
+ """
+ Runs ldapadd on this slapd instance, passing it the ldif content
+ """
+ self._cli_popen(
+ self.PATH_LDAPMODIFY, extra_args=extra_args, stdin_data=ldif.encode("utf-8")
+ )
+
+ def ldapdelete(self, dn, recursive=False, extra_args=None):
+ """
+ Runs ldapdelete on this slapd instance, deleting 'dn'
+ """
+ if extra_args is None:
+ extra_args = []
+ if recursive:
+ extra_args.append("-r")
+ extra_args.append(dn)
+ self._cli_popen(self.PATH_LDAPDELETE, extra_args=extra_args)
+
+ def __enter__(self):
+ self.start()
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ self.stop()
+
+
+class SlapdTestCase(unittest.TestCase):
+ """
+ test class which also clones or initializes a running slapd
+ """
+
+ server_class = SlapdObject
+ server = None
+ ldap_object_class = None
+
+ def _open_ldap_conn(self, who=None, cred=None, **kwargs):
+ """
+ return a LDAPObject instance after simple bind
+ """
+ ldap_conn = self.ldap_object_class(self.server.ldap_uri, **kwargs)
+ ldap_conn.protocol_version = 3
+ # ldap_conn.set_option(ldap.OPT_REFERRALS, 0)
+ ldap_conn.simple_bind_s(who or self.server.root_dn, cred or self.server.root_pw)
+ return ldap_conn
+
+ @classmethod
+ def setUpClass(cls):
+ cls.server = cls.server_class()
+ cls.server.start()
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.server.stop()
diff --git a/test/old_slapdtest/certs/README b/test/old_slapdtest/certs/README
new file mode 100644
index 00000000..4be616ae
--- /dev/null
+++ b/test/old_slapdtest/certs/README
@@ -0,0 +1,24 @@
+python-ldap test certificates
+=============================
+
+Certificates and keys
+---------------------
+
+* ``ca.pem``: internal root CA certificate
+* ``server.pem``: TLS server certificate for slapd, signed by root CA. The
+ server cert is valid for DNS Name ``localhost`` and IPs ``127.0.0.1`` and
+ ``:1``.
+* ``server.key``: private key for ``server.pem``, no password protection
+* ``client.pem``: certificate for TLS client cert authentication, signed by
+ root CA.
+* ``client.key``: private key for ``client.pem``, no password protection
+
+Configuration and scripts
+-------------------------
+
+* ``ca.conf`` contains the CA definition as well as extensions for the
+ client and server certificates.
+* ``client.conf`` and ``server.conf`` hold the subject and base configuration
+ for server and client certs.
+* ``gencerts.sh`` creates new CA, client and server certificates.
+* ``gennssdb.sh`` can be used to create a NSSDB for all certs and keys.
diff --git a/test/old_slapdtest/certs/ca.conf b/test/old_slapdtest/certs/ca.conf
new file mode 100644
index 00000000..d1d89e18
--- /dev/null
+++ b/test/old_slapdtest/certs/ca.conf
@@ -0,0 +1,77 @@
+# Written by Christian Heimes
+
+[default]
+ca = "ca"
+tmpdir = $ENV::CATMPDIR
+outdir = $ENV::CAOUTDIR
+name_opt = multiline,-esc_msb,utf8
+
+[req]
+default_bits = 2048
+encrypt_key = no
+default_md = sha256
+utf8 = yes
+string_mask = utf8only
+prompt = no
+distinguished_name = ca_dn
+
+[ca_dn]
+countryName = "DE"
+organizationName = "python-ldap"
+organizationalUnitName = "slapd-test"
+commonName = "Python LDAP Test CA"
+
+[ca]
+default_ca = python_ldap_ca
+
+[python_ldap_ca]
+certificate = $outdir/$ca.pem
+private_key = $outdir/$ca.key
+new_certs_dir = $tmpdir
+serial = $tmpdir/$ca.crt.srl
+crlnumber = $tmpdir/$ca.crl.srl
+database = $tmpdir/$ca.db
+unique_subject = no
+default_days = 365200
+default_md = sha256
+policy = match_pol
+email_in_dn = no
+preserve = no
+name_opt = $name_opt
+cert_opt = ca_default
+copy_extensions = none
+default_crl_days = 365100
+
+[match_pol]
+countryName = match
+stateOrProvinceName = optional
+localityName = optional
+organizationName = match
+organizationalUnitName = match
+commonName = supplied
+
+[ca_ext]
+basicConstraints = critical,CA:true
+keyUsage = critical,keyCertSign,cRLSign
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always
+
+[server_san]
+DNS.1 = localhost
+IP.1 = 127.0.0.1
+IP.2 = ::1
+
+[server_ext]
+basicConstraints = critical,CA:false
+keyUsage = critical,digitalSignature,keyEncipherment
+extendedKeyUsage = critical,serverAuth
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always
+subjectAltName = @server_san
+
+[client_ext]
+basicConstraints = critical,CA:false
+keyUsage = critical,digitalSignature
+extendedKeyUsage = critical,clientAuth
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always
diff --git a/test/old_slapdtest/certs/ca.pem b/test/old_slapdtest/certs/ca.pem
new file mode 100644
index 00000000..b52ffafb
--- /dev/null
+++ b/test/old_slapdtest/certs/ca.pem
@@ -0,0 +1,80 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=DE, O=python-ldap, OU=slapd-test, CN=Python LDAP Test CA
+ Validity
+ Not Before: Apr 12 18:52:38 2019 GMT
+ Not After : Oct 17 18:52:38 2994 GMT
+ Subject: C=DE, O=python-ldap, OU=slapd-test, CN=Python LDAP Test CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:d7:30:73:20:44:7d:83:d4:c7:01:b8:ab:1e:7c:
+ 91:f4:38:ac:9c:41:43:64:0c:31:99:48:70:22:7d:
+ ae:1b:47:e7:2a:28:4d:f7:46:4e:b4:ba:ae:c0:9d:
+ d5:1f:4b:7a:79:2f:b9:dc:68:7f:79:84:88:50:51:
+ 3b:7d:dc:d5:57:17:66:45:c0:2c:20:13:f7:99:d6:
+ 9d:e2:12:7c:41:76:82:51:19:2c:b6:ff:46:cb:04:
+ 56:38:22:2a:c3:7a:b5:71:51:49:4e:62:68:a0:99:
+ 6f:de:f3:a2:0f:a2:aa:1b:72:a5:87:bc:42:5a:a7:
+ 22:8d:33:b4:88:a8:dc:5d:72:ca:dd:a0:9a:4e:db:
+ 7d:8b:10:de:c5:41:e9:e9:8d:fa:6c:dd:94:6e:b1:
+ 31:c2:6d:a1:69:6c:7a:3a:b2:76:65:c9:e5:95:38:
+ 62:40:81:c6:29:26:26:d1:d1:c1:f4:5e:fa:24:ef:
+ 13:da:24:13:6f:f5:5c:ba:b1:31:8f:30:94:71:7b:
+ c6:e5:da:b9:b5:64:39:39:09:c2:4a:80:64:58:1d:
+ 99:f5:65:3c:a7:26:08:95:26:35:7b:fa:e7:20:08:
+ ff:72:df:9b:8f:9f:da:8b:c3:a7:8b:fc:8c:c0:a5:
+ 31:87:1d:4c:14:f6:cf:90:5e:2e:6e:a6:db:27:08:
+ eb:df
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ BD:78:D5:4A:F1:90:96:C5:E8:EC:66:49:23:47:03:5F:26:73:86:B2
+ X509v3 Authority Key Identifier:
+ keyid:BD:78:D5:4A:F1:90:96:C5:E8:EC:66:49:23:47:03:5F:26:73:86:B2
+
+ Signature Algorithm: sha256WithRSAEncryption
+ 06:20:1f:eb:42:6a:42:62:b1:ee:69:c8:cd:47:a6:2e:69:95:
+ 59:dc:49:09:69:40:93:25:a1:ec:6d:3a:dd:dc:e5:74:ab:33:
+ 9d:8f:cc:e3:bb:7a:3f:5b:51:58:74:f7:bd:6c:7c:3c:b6:5a:
+ 05:50:a8:8c:c3:fb:5b:75:2a:c2:6c:06:93:4c:a9:93:71:1c:
+ 51:e5:be:a1:24:93:e2:79:ca:ea:08:86:90:b9:70:e7:7a:40:
+ bf:f4:d6:71:f4:4d:c0:0f:e0:31:a0:23:46:77:30:72:a9:62:
+ 8a:2a:12:c4:dd:3d:86:ae:f7:6b:33:80:26:58:49:53:ff:cd:
+ 8a:c6:f6:11:2c:b3:ff:a5:8e:1c:f8:22:e2:1b:8e:04:33:fb:
+ 0d:da:31:86:12:9f:d1:03:86:9c:6a:78:5e:3c:5e:8a:52:aa:
+ 68:1f:ff:f9:17:75:b0:da:f2:99:3c:80:3c:96:2a:33:07:54:
+ 59:84:e7:92:34:0f:99:76:e3:d6:4d:4d:9c:fb:21:35:f9:cb:
+ a5:30:80:8b:9d:61:90:d3:d4:59:3a:2f:f2:f6:20:13:7e:26:
+ dc:50:b0:49:3e:19:fe:eb:7d:cf:b9:1a:5d:5c:3a:76:30:d9:
+ 0e:d7:df:de:ce:a9:c4:21:df:63:b9:d0:64:86:0b:28:9a:2e:
+ ab:51:73:e4
+-----BEGIN CERTIFICATE-----
+MIIDjDCCAnSgAwIBAgIBATANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJERTEU
+MBIGA1UECgwLcHl0aG9uLWxkYXAxEzARBgNVBAsMCnNsYXBkLXRlc3QxHDAaBgNV
+BAMME1B5dGhvbiBMREFQIFRlc3QgQ0EwIBcNMTkwNDEyMTg1MjM4WhgPMjk5NDEw
+MTcxODUyMzhaMFYxCzAJBgNVBAYTAkRFMRQwEgYDVQQKDAtweXRob24tbGRhcDET
+MBEGA1UECwwKc2xhcGQtdGVzdDEcMBoGA1UEAwwTUHl0aG9uIExEQVAgVGVzdCBD
+QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANcwcyBEfYPUxwG4qx58
+kfQ4rJxBQ2QMMZlIcCJ9rhtH5yooTfdGTrS6rsCd1R9Lenkvudxof3mEiFBRO33c
+1VcXZkXALCAT95nWneISfEF2glEZLLb/RssEVjgiKsN6tXFRSU5iaKCZb97zog+i
+qhtypYe8QlqnIo0ztIio3F1yyt2gmk7bfYsQ3sVB6emN+mzdlG6xMcJtoWlsejqy
+dmXJ5ZU4YkCBxikmJtHRwfRe+iTvE9okE2/1XLqxMY8wlHF7xuXaubVkOTkJwkqA
+ZFgdmfVlPKcmCJUmNXv65yAI/3Lfm4+f2ovDp4v8jMClMYcdTBT2z5BeLm6m2ycI
+698CAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
+VR0OBBYEFL141UrxkJbF6OxmSSNHA18mc4ayMB8GA1UdIwQYMBaAFL141UrxkJbF
+6OxmSSNHA18mc4ayMA0GCSqGSIb3DQEBCwUAA4IBAQAGIB/rQmpCYrHuacjNR6Yu
+aZVZ3EkJaUCTJaHsbTrd3OV0qzOdj8zju3o/W1FYdPe9bHw8tloFUKiMw/tbdSrC
+bAaTTKmTcRxR5b6hJJPiecrqCIaQuXDnekC/9NZx9E3AD+AxoCNGdzByqWKKKhLE
+3T2GrvdrM4AmWElT/82KxvYRLLP/pY4c+CLiG44EM/sN2jGGEp/RA4acanhePF6K
+UqpoH//5F3Ww2vKZPIA8liozB1RZhOeSNA+ZduPWTU2c+yE1+culMICLnWGQ09RZ
+Oi/y9iATfibcULBJPhn+633PuRpdXDp2MNkO19/ezqnEId9judBkhgsomi6rUXPk
+-----END CERTIFICATE-----
diff --git a/test/old_slapdtest/certs/client.conf b/test/old_slapdtest/certs/client.conf
new file mode 100644
index 00000000..774dc3a4
--- /dev/null
+++ b/test/old_slapdtest/certs/client.conf
@@ -0,0 +1,16 @@
+# Written by Christian Heimes
+
+[req]
+default_bits = 2048
+encrypt_key = no
+default_md = sha256
+utf8 = yes
+string_mask = utf8only
+prompt = no
+distinguished_name = client_dn
+
+[client_dn]
+countryName = "DE"
+organizationName = "python-ldap"
+organizationalUnitName = "slapd-test"
+commonName = "client"
diff --git a/test/old_slapdtest/certs/client.key b/test/old_slapdtest/certs/client.key
new file mode 100644
index 00000000..7213c0b4
--- /dev/null
+++ b/test/old_slapdtest/certs/client.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDjt5O6nRrnAWPm
+T0JvRLBHMclll92IWF/O4GEdcJ5fbBxP3BxK0Dv+6aRcR7b2o0f6fk/bgNepXfv/
+MXDQcFlESbfmUNGshFmZr0sjPrYPD1R06TZs+/7RsMXnx1c79mFGEQ4wqzDOBHKQ
+xeDhNJk+BcE0QABsqF8AA2XC2/dK14QCljKLC84k1zTFTnh8duN2eAalaPQFFOoj
+4AnonUnswJ45zIx5V2BdG+oqO5dwo/cEukKgAEL8T2IJ9Cqlmh2sPbMqYC8cODq6
+YcugMznxrfHV5LNThfkvwMe26+vv68r65zalPDy0M+cUMTMyBVY4TL3fejrloY2t
+YMhPJIclAgMBAAECggEAPXdd/u9NRbGQX6hhTFuEIZOEw1F80MLaCaNzU1kExskN
+01icom0W5LX4UZhiAK0OTsUtlRhwHh1qWfXkd777uX0UkKycDC8laGByra7Nwb7n
+ky8oK77Rh5RptyiNmXflxd3wsJ5k7BczPXTMQL3L53vyLMJh2vKPwhcorrJlS+Pi
+JjINMaR4IrDlpMYlrn9NTjsGr+mj/pdmKfU/KVXeKzFcwKTjUnDJNSbGDIC0AxaJ
+dGU0yIX9MPW+p5szcA9o22UWW4LsEFY4YABeCqbm9/UQt3jWVMjCy4AOgr/9HWSR
+DvXI/Xtdl3CTCr8+qDnhBaUI27z+UelZfTBFKUb8AQKBgQD6SmtrTBgEfb6tuxJw
+AAHRuUcWGjatZ7X+meHRC9B7UPxUrKl9tU5NC7Gz6YMt+vr4bNMwykI6Ndj+4tSJ
+KqsAC86v19CH4usMBLZ68MeTRvtQGiPah71syYrxf0uvYOx/KzUUBX240Ls+lEbE
+W33psMoNAezUPpJwKx7CMjcBgQKBgQDo6VaT59bKRc3DXJvqFjd7TPIex+ny6JK+
+8oOwyyFFBwkzfymoOxN4lxSrE6yf7uTemRRn+RIH3UGDottIDqzhjvtcV5uODeIN
+8WzxTbl759qIxt+z7aF7SkwJLJAAZS3qqCXKtMBo7ln4xKaoRLT2RohqD1YXGrg8
+wmYcUZoPpQKBgQCm2QVSuZ8pH0oFNjfMQbT0wbYJnd/lKMXBu4M1f9Ky4gHT0GYM
+Ttirs6f6byfrduvmv2TpmWscsti80SktZywnE7fssMlqTHKzyFB9FBV2sFLHyyUr
+gGFeK9xbsKgbeVkuTPdNKXvtv/eSd/XU38jIB/opQadGtY+ZBqWyfxb8AQKBgBLc
+SlmBzZ/llSr7xdhn4ihG69hYQfacpL13r/hSCqinUDRuWLY5ynLacR8FYdY1pyzr
+Yn6k6bPfU93QA0fLgG5ngK1SntMbBrIwWa0UqS+Cb+zhhd3xIUF1m8CmbibKCrTU
+1vKaPnaAzqJZclFv9uN2hLdp9IO8cyzgZRpn9TzNAoGAUfZF1983qknfBgD8Lgm3
+zzKYtc8q2Ukatfo4VCp66CEprbLcBq5mKx6JiBoMGqU8SI5XVG0F0aHH2n8gImcu
+bO0vtEldDc1ylZ/H7xhHFWlMzmTlsbHdHVtetFfKLTpjq6duvgLA12lJNHNVu3OU
+Z1bRWDeZIP70+jdYrmSoVi8=
+-----END PRIVATE KEY-----
diff --git a/test/old_slapdtest/certs/client.pem b/test/old_slapdtest/certs/client.pem
new file mode 100644
index 00000000..ca2989ca
--- /dev/null
+++ b/test/old_slapdtest/certs/client.pem
@@ -0,0 +1,83 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 3 (0x3)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=DE, O=python-ldap, OU=slapd-test, CN=Python LDAP Test CA
+ Validity
+ Not Before: Apr 12 18:52:38 2019 GMT
+ Not After : Mar 1 18:52:38 3019 GMT
+ Subject: C=DE, O=python-ldap, OU=slapd-test, CN=client
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:e3:b7:93:ba:9d:1a:e7:01:63:e6:4f:42:6f:44:
+ b0:47:31:c9:65:97:dd:88:58:5f:ce:e0:61:1d:70:
+ 9e:5f:6c:1c:4f:dc:1c:4a:d0:3b:fe:e9:a4:5c:47:
+ b6:f6:a3:47:fa:7e:4f:db:80:d7:a9:5d:fb:ff:31:
+ 70:d0:70:59:44:49:b7:e6:50:d1:ac:84:59:99:af:
+ 4b:23:3e:b6:0f:0f:54:74:e9:36:6c:fb:fe:d1:b0:
+ c5:e7:c7:57:3b:f6:61:46:11:0e:30:ab:30:ce:04:
+ 72:90:c5:e0:e1:34:99:3e:05:c1:34:40:00:6c:a8:
+ 5f:00:03:65:c2:db:f7:4a:d7:84:02:96:32:8b:0b:
+ ce:24:d7:34:c5:4e:78:7c:76:e3:76:78:06:a5:68:
+ f4:05:14:ea:23:e0:09:e8:9d:49:ec:c0:9e:39:cc:
+ 8c:79:57:60:5d:1b:ea:2a:3b:97:70:a3:f7:04:ba:
+ 42:a0:00:42:fc:4f:62:09:f4:2a:a5:9a:1d:ac:3d:
+ b3:2a:60:2f:1c:38:3a:ba:61:cb:a0:33:39:f1:ad:
+ f1:d5:e4:b3:53:85:f9:2f:c0:c7:b6:eb:eb:ef:eb:
+ ca:fa:e7:36:a5:3c:3c:b4:33:e7:14:31:33:32:05:
+ 56:38:4c:bd:df:7a:3a:e5:a1:8d:ad:60:c8:4f:24:
+ 87:25
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:FALSE
+ X509v3 Key Usage: critical
+ Digital Signature
+ X509v3 Extended Key Usage: critical
+ TLS Web Client Authentication
+ X509v3 Subject Key Identifier:
+ 4F:E7:35:C7:C8:C1:01:C3:7C:53:86:B9:BF:AE:8B:D6:45:A2:78:20
+ X509v3 Authority Key Identifier:
+ keyid:BD:78:D5:4A:F1:90:96:C5:E8:EC:66:49:23:47:03:5F:26:73:86:B2
+
+ Signature Algorithm: sha256WithRSAEncryption
+ 1c:90:5f:cf:18:48:95:4d:9d:d3:8e:6d:d1:69:19:1e:7b:3f:
+ 1f:48:7c:c8:0d:2f:c4:53:0f:89:23:f4:be:ea:b4:7a:c6:dd:
+ cc:18:0f:e7:34:ea:2c:d4:07:0d:65:78:e8:20:40:3f:36:ef:
+ 2c:00:31:69:e6:20:48:65:be:57:03:0e:69:ff:b9:83:59:99:
+ 7d:4d:86:98:14:5b:8e:39:25:3a:a8:6d:51:dc:45:a5:0f:cd:
+ f3:7a:fd:55:af:5f:55:75:20:03:f5:4a:75:6a:79:2f:76:84:
+ f6:4e:3d:1d:59:45:9a:b1:6a:57:6f:16:76:76:f8:df:6e:96:
+ d5:25:27:34:4b:21:d8:c9:9a:36:55:45:a0:43:16:43:68:93:
+ 37:af:81:89:06:d1:56:1b:9e:0f:62:40:ad:3c:4c:f5:ef:6c:
+ a2:a4:7f:f2:fa:78:9c:0d:c0:19:f1:10:e8:d8:cf:03:67:3c:
+ 2d:4d:f3:5d:67:5c:41:a7:4f:d6:c5:0e:ff:2c:04:dd:23:bb:
+ 85:44:8e:25:ac:15:a3:82:fa:a4:4f:fa:1d:87:f0:58:dc:ae:
+ 53:05:b9:81:e8:cb:e5:0c:ac:a5:74:68:03:f9:22:a0:45:b6:
+ 62:58:e0:98:d9:8c:54:a4:22:03:7a:37:12:eb:7d:b1:ad:45:
+ 60:8e:7a:df
+-----BEGIN CERTIFICATE-----
+MIIDlDCCAnygAwIBAgIBAzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJERTEU
+MBIGA1UECgwLcHl0aG9uLWxkYXAxEzARBgNVBAsMCnNsYXBkLXRlc3QxHDAaBgNV
+BAMME1B5dGhvbiBMREFQIFRlc3QgQ0EwIBcNMTkwNDEyMTg1MjM4WhgPMzAxOTAz
+MDExODUyMzhaMEkxCzAJBgNVBAYTAkRFMRQwEgYDVQQKDAtweXRob24tbGRhcDET
+MBEGA1UECwwKc2xhcGQtdGVzdDEPMA0GA1UEAwwGY2xpZW50MIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA47eTup0a5wFj5k9Cb0SwRzHJZZfdiFhfzuBh
+HXCeX2wcT9wcStA7/umkXEe29qNH+n5P24DXqV37/zFw0HBZREm35lDRrIRZma9L
+Iz62Dw9UdOk2bPv+0bDF58dXO/ZhRhEOMKswzgRykMXg4TSZPgXBNEAAbKhfAANl
+wtv3SteEApYyiwvOJNc0xU54fHbjdngGpWj0BRTqI+AJ6J1J7MCeOcyMeVdgXRvq
+KjuXcKP3BLpCoABC/E9iCfQqpZodrD2zKmAvHDg6umHLoDM58a3x1eSzU4X5L8DH
+tuvr7+vK+uc2pTw8tDPnFDEzMgVWOEy933o65aGNrWDITySHJQIDAQABo3gwdjAM
+BgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIHgDAWBgNVHSUBAf8EDDAKBggrBgEF
+BQcDAjAdBgNVHQ4EFgQUT+c1x8jBAcN8U4a5v66L1kWieCAwHwYDVR0jBBgwFoAU
+vXjVSvGQlsXo7GZJI0cDXyZzhrIwDQYJKoZIhvcNAQELBQADggEBAByQX88YSJVN
+ndOObdFpGR57Px9IfMgNL8RTD4kj9L7qtHrG3cwYD+c06izUBw1leOggQD827ywA
+MWnmIEhlvlcDDmn/uYNZmX1NhpgUW445JTqobVHcRaUPzfN6/VWvX1V1IAP1SnVq
+eS92hPZOPR1ZRZqxaldvFnZ2+N9ultUlJzRLIdjJmjZVRaBDFkNokzevgYkG0VYb
+ng9iQK08TPXvbKKkf/L6eJwNwBnxEOjYzwNnPC1N811nXEGnT9bFDv8sBN0ju4VE
+jiWsFaOC+qRP+h2H8FjcrlMFuYHoy+UMrKV0aAP5IqBFtmJY4JjZjFSkIgN6NxLr
+fbGtRWCOet8=
+-----END CERTIFICATE-----
diff --git a/test/old_slapdtest/certs/gencerts.sh b/test/old_slapdtest/certs/gencerts.sh
new file mode 100755
index 00000000..8a99db58
--- /dev/null
+++ b/test/old_slapdtest/certs/gencerts.sh
@@ -0,0 +1,68 @@
+#!/bin/sh
+# Written by Christian Heimes
+set -e
+
+export CAOUTDIR=.
+export CATMPDIR=tmp
+
+rm -rf $CATMPDIR
+rm -rf ca.pem ca.key server.pem server.key client.pem client.key
+rm -rf cert9.db key4.db pkcs11.tx
+
+mkdir -p $CAOUTDIR
+mkdir -p $CATMPDIR
+
+touch $CATMPDIR/ca.db
+touch $CATMPDIR/ca.db.attr
+echo '01' > $CATMPDIR/ca.crt.srl
+echo '01' > $CATMPDIR/ca.crl.srl
+
+# root CA
+openssl req -new \
+ -config ca.conf \
+ -out $CATMPDIR/ca.csr \
+ -keyout $CAOUTDIR/ca.key \
+ -batch
+
+openssl ca -selfsign \
+ -config ca.conf \
+ -in $CATMPDIR/ca.csr \
+ -out $CAOUTDIR/ca.pem \
+ -extensions ca_ext \
+ -days 356300 \
+ -batch
+
+# server cert
+openssl req -new \
+ -config server.conf \
+ -out $CATMPDIR/server.csr \
+ -keyout $CAOUTDIR/server.key \
+ -batch
+
+openssl ca \
+ -config ca.conf \
+ -in $CATMPDIR/server.csr \
+ -out $CAOUTDIR/server.pem \
+ -policy match_pol \
+ -extensions server_ext \
+ -batch
+
+# client cert
+openssl req -new \
+ -config client.conf \
+ -out $CATMPDIR/client.csr \
+ -keyout $CAOUTDIR/client.key \
+ -batch
+
+openssl ca \
+ -config ca.conf \
+ -in $CATMPDIR/client.csr \
+ -out $CAOUTDIR/client.pem \
+ -policy match_pol \
+ -extensions client_ext \
+ -batch
+
+# cleanup
+rm -rf $CATMPDIR ca.key
+
+echo DONE
diff --git a/test/old_slapdtest/certs/gennssdb.sh b/test/old_slapdtest/certs/gennssdb.sh
new file mode 100755
index 00000000..aeeb3331
--- /dev/null
+++ b/test/old_slapdtest/certs/gennssdb.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# Written by Christian Heimes
+set -e
+
+CATMPDIR=tmp
+PASSFILE=${CATMPDIR}/passwd.txt
+NSSDB=sql:${CAOUTDIR}
+
+mkdir -p $CATMPDIR
+
+# Create PKCS#12 files for NSSDB import
+echo "dummy" > $PASSFILE
+openssl pkcs12 -name "servercert" -in server.pem -inkey server.key \
+ -caname "testca" -CAfile ca.pem \
+ -password "file:${PASSFILE}" -export -out server.p12
+openssl pkcs12 -name "clientcert" -in client.pem -inkey client.key \
+ -caname "testca" -CAfile ca.pem \
+ -password "file:${PASSFILE}" -export -out client.p12
+
+# Create NSS DB
+certutil -d $NSSDB -N --empty-password
+certutil -d $NSSDB -A -n "testca" -t CT,, -a -i ca.pem
+pk12util -d $NSSDB -i server.p12 -w ${PASSFILE}
+pk12util -d $NSSDB -i client.p12 -w ${PASSFILE}
+certutil -d $NSSDB -L
+
+# cleanup
+rm -rf $CATMPDIR server.p12 client.p12
\ No newline at end of file
diff --git a/test/old_slapdtest/certs/server.conf b/test/old_slapdtest/certs/server.conf
new file mode 100644
index 00000000..94f4427a
--- /dev/null
+++ b/test/old_slapdtest/certs/server.conf
@@ -0,0 +1,16 @@
+# Written by Christian Heimes
+
+[req]
+default_bits = 2048
+encrypt_key = no
+default_md = sha256
+utf8 = yes
+string_mask = utf8only
+prompt = no
+distinguished_name = server_dn
+
+[server_dn]
+countryName = "DE"
+organizationName = "python-ldap"
+organizationalUnitName = "slapd-test"
+commonName = "server cert for localhost"
diff --git a/test/old_slapdtest/certs/server.key b/test/old_slapdtest/certs/server.key
new file mode 100644
index 00000000..a8916701
--- /dev/null
+++ b/test/old_slapdtest/certs/server.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCsBk0ml3ERFJyg
+I6ujIJYERVU4doTZZd4r4z/LOef0hyiYiIQAc9wetaoZpM+bl4Eherxy9SBaCBwR
+zefbaYQz2f2hdEDb+sISOiTke1eiF2ugYNlS55Wk1KnCnORE9bjcSNLPsscoUSzE
+2bnBSoUwdiVK18YOCZR6GTeC8eA3ekvlR+9g+FBOgQ9+StXPDdq+iIAGXZREJIua
+munErtTOw85De4YFCnzGw3UeCITDD4wFmI2IWphRFwWPsSDwUJfATA8S+7Rm4vwr
+Qj726gUDlicTzPXKhJjXjj6XL7xXHfpQwMPkBCrxesKceHMJ+mrRsuuqHciuixRi
+g94mILElAgMBAAECggEADG5oJOHMye8zYl8xiBhSvvxDrFDkSNGTvJgvhAArQwCB
+boRvBZlZzt5R7Ih8eEH6kvDLrYMJU3hCjwbSOojlhNm7+m7sQPleDPMmt1wyeQQ4
+Qt681cDmj4LOwcGUvWcEdObOVTQWMFOtaIxTYCSCe34OM9pj9Z+7mxc3a78O9PND
+Ib/CwcTA1OyoupzkKirqkdLXwK3x2aT/1TMaPX94taHB51cxXc7AglL9QnuCkuaG
+krqrexy3rGimzsP3OwQGEUjWKcZVSSPT8/k1pPE9hRgOqBy05BfkAzlebdvc3GO5
+AbZk0NX2sfVHl4dTEXs/hTBCTQ3XmaltumQ9MdL+AQKBgQDg2I5QxBA2UHb8vCtK
+f31kfG6YQc4MkoslrrMrtJjZqDYaLZPS1ARPSfYRqcc+7GDreuLmw39f8ZECd+2W
+BYUqzZv9g13R9DY99g0/sINnZGsESwfIdLNNlHvVx2UrD5ybCj4vLhuPsVV7XlWs
+cpl+rcuBVpqy8UIXifQ/Z3xLvwKBgQDD3CLjuC0mcTO2sIWqEHqVkc8CY2NJA2Qh
+C78fwpaCqJUUdWnS69QbRGWgkFJL+oO8lQVQ1bXhZLHyQmy7Z5d5olCH6AW4GRnf
+hBAnKJ+QTm9B6QVWzjUuHuOeCukfiTQbha14pOS9ar3X2QFWjDnzCRrnAxJmoY3H
+BJATLHhMGwKBgQDSxAy7xt4Pm+O9y8Gk5tcq771X+i9k96V54EZRzMuPFDAK3/h2
+o4marZD9Q7Hi2P+NHTc+67klvbKZpsPOYkRPOEdmH9M9cPe7oz8OGa9DpwzuDEsy
+a7p8GZjvbyb1c3/wkWxzG3x4eNnReD9FFHOwHMfr6LvAy4iRuh57pM0NzwKBgDY3
+1DixnV4M7EHgb7/6O9T3vhRtKujlVWyIcen61etpe4tkTV0kB11c+70M9pstyBYG
+MqiD4It6coAbvznJnXcAZcaZhivGVxE237nXVwR9kfLu7JlxD+uqhVwUrSAbvR75
+TGIfU2rUB6We3u30d349wQK+KPPcOQEk1DValBqNAoGBAKfXOXgFBkIVW79fOkup
+aIZXdEmU3Up61Oo0KDbxsg4l73NnnvuEnNMBTx3nT3KCVIAcQL9MNpLX/Z0HjOn1
+aiWVtTNq2OFL0V0HueBhbkFiWp551jTS7LjndCYHpUB/B8/wXP0kxHUm8HrQrRvK
+DhV3zcxsXts1INidXjzzOkPi
+-----END PRIVATE KEY-----
diff --git a/test/old_slapdtest/certs/server.pem b/test/old_slapdtest/certs/server.pem
new file mode 100644
index 00000000..25ba06c0
--- /dev/null
+++ b/test/old_slapdtest/certs/server.pem
@@ -0,0 +1,86 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=DE, O=python-ldap, OU=slapd-test, CN=Python LDAP Test CA
+ Validity
+ Not Before: Apr 12 18:52:38 2019 GMT
+ Not After : Mar 1 18:52:38 3019 GMT
+ Subject: C=DE, O=python-ldap, OU=slapd-test, CN=server cert for localhost
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:ac:06:4d:26:97:71:11:14:9c:a0:23:ab:a3:20:
+ 96:04:45:55:38:76:84:d9:65:de:2b:e3:3f:cb:39:
+ e7:f4:87:28:98:88:84:00:73:dc:1e:b5:aa:19:a4:
+ cf:9b:97:81:21:7a:bc:72:f5:20:5a:08:1c:11:cd:
+ e7:db:69:84:33:d9:fd:a1:74:40:db:fa:c2:12:3a:
+ 24:e4:7b:57:a2:17:6b:a0:60:d9:52:e7:95:a4:d4:
+ a9:c2:9c:e4:44:f5:b8:dc:48:d2:cf:b2:c7:28:51:
+ 2c:c4:d9:b9:c1:4a:85:30:76:25:4a:d7:c6:0e:09:
+ 94:7a:19:37:82:f1:e0:37:7a:4b:e5:47:ef:60:f8:
+ 50:4e:81:0f:7e:4a:d5:cf:0d:da:be:88:80:06:5d:
+ 94:44:24:8b:9a:9a:e9:c4:ae:d4:ce:c3:ce:43:7b:
+ 86:05:0a:7c:c6:c3:75:1e:08:84:c3:0f:8c:05:98:
+ 8d:88:5a:98:51:17:05:8f:b1:20:f0:50:97:c0:4c:
+ 0f:12:fb:b4:66:e2:fc:2b:42:3e:f6:ea:05:03:96:
+ 27:13:cc:f5:ca:84:98:d7:8e:3e:97:2f:bc:57:1d:
+ fa:50:c0:c3:e4:04:2a:f1:7a:c2:9c:78:73:09:fa:
+ 6a:d1:b2:eb:aa:1d:c8:ae:8b:14:62:83:de:26:20:
+ b1:25
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:FALSE
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage: critical
+ TLS Web Server Authentication
+ X509v3 Subject Key Identifier:
+ 08:D1:86:1B:82:0A:4F:71:31:E4:F5:31:23:CC:67:3B:FA:84:3B:A0
+ X509v3 Authority Key Identifier:
+ keyid:BD:78:D5:4A:F1:90:96:C5:E8:EC:66:49:23:47:03:5F:26:73:86:B2
+
+ X509v3 Subject Alternative Name:
+ DNS:localhost, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1
+ Signature Algorithm: sha256WithRSAEncryption
+ 88:60:af:be:11:c4:aa:dc:9b:f1:e7:14:da:20:aa:6f:2f:06:
+ ae:38:b2:7c:ac:90:81:22:51:7e:cb:26:15:6e:fe:67:98:c1:
+ 0d:dc:aa:39:98:2b:d2:cc:3c:ff:1a:92:2f:56:0a:a9:6e:d8:
+ 9a:3d:c5:4d:6f:cc:91:2e:e3:4e:bf:22:ab:cb:92:1a:a0:8f:
+ 43:cd:82:bc:48:55:c4:95:cf:10:6b:6a:31:19:92:7d:e0:06:
+ 05:6f:0b:33:e7:2a:37:42:f9:ec:1b:29:99:e1:58:0c:01:a7:
+ c3:8b:58:71:21:9f:61:8c:a7:fb:b6:7e:32:8b:a9:4e:c7:1f:
+ f6:46:e8:dd:ac:a6:4c:53:f8:4d:93:e4:ec:73:ab:0b:be:98:
+ c5:78:c4:92:c0:4c:78:47:52:2f:93:07:67:20:a4:5a:7f:59:
+ 7e:4f:48:53:20:0d:37:bb:06:f8:44:42:64:b4:94:15:43:d1:
+ 4c:51:f3:97:1d:2d:cd:db:b9:bb:1a:69:10:89:7d:ae:1d:0d:
+ 94:78:45:29:cd:c4:42:67:67:96:05:bf:da:aa:23:65:7b:04:
+ ff:b7:ac:9d:ee:0b:e7:0f:c1:c5:0b:48:fe:0f:d6:3f:d8:b4:
+ 77:12:bb:f5:91:4f:43:e6:01:3f:a4:c0:ea:8c:c6:68:99:8e:
+ 49:e8:c4:8b
+-----BEGIN CERTIFICATE-----
+MIID1zCCAr+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJERTEU
+MBIGA1UECgwLcHl0aG9uLWxkYXAxEzARBgNVBAsMCnNsYXBkLXRlc3QxHDAaBgNV
+BAMME1B5dGhvbiBMREFQIFRlc3QgQ0EwIBcNMTkwNDEyMTg1MjM4WhgPMzAxOTAz
+MDExODUyMzhaMFwxCzAJBgNVBAYTAkRFMRQwEgYDVQQKDAtweXRob24tbGRhcDET
+MBEGA1UECwwKc2xhcGQtdGVzdDEiMCAGA1UEAwwZc2VydmVyIGNlcnQgZm9yIGxv
+Y2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKwGTSaXcREU
+nKAjq6MglgRFVTh2hNll3ivjP8s55/SHKJiIhABz3B61qhmkz5uXgSF6vHL1IFoI
+HBHN59tphDPZ/aF0QNv6whI6JOR7V6IXa6Bg2VLnlaTUqcKc5ET1uNxI0s+yxyhR
+LMTZucFKhTB2JUrXxg4JlHoZN4Lx4Dd6S+VH72D4UE6BD35K1c8N2r6IgAZdlEQk
+i5qa6cSu1M7DzkN7hgUKfMbDdR4IhMMPjAWYjYhamFEXBY+xIPBQl8BMDxL7tGbi
+/CtCPvbqBQOWJxPM9cqEmNeOPpcvvFcd+lDAw+QEKvF6wpx4cwn6atGy66odyK6L
+FGKD3iYgsSUCAwEAAaOBpzCBpDAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIF
+oDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUCNGGG4IKT3Ex5PUx
+I8xnO/qEO6AwHwYDVR0jBBgwFoAUvXjVSvGQlsXo7GZJI0cDXyZzhrIwLAYDVR0R
+BCUwI4IJbG9jYWxob3N0hwR/AAABhxAAAAAAAAAAAAAAAAAAAAABMA0GCSqGSIb3
+DQEBCwUAA4IBAQCIYK++EcSq3Jvx5xTaIKpvLwauOLJ8rJCBIlF+yyYVbv5nmMEN
+3Ko5mCvSzDz/GpIvVgqpbtiaPcVNb8yRLuNOvyKry5IaoI9DzYK8SFXElc8Qa2ox
+GZJ94AYFbwsz5yo3QvnsGymZ4VgMAafDi1hxIZ9hjKf7tn4yi6lOxx/2RujdrKZM
+U/hNk+Tsc6sLvpjFeMSSwEx4R1IvkwdnIKRaf1l+T0hTIA03uwb4REJktJQVQ9FM
+UfOXHS3N27m7GmkQiX2uHQ2UeEUpzcRCZ2eWBb/aqiNlewT/t6yd7gvnD8HFC0j+
+D9Y/2LR3Erv1kU9D5gE/pMDqjMZomY5J6MSL
+-----END CERTIFICATE-----
diff --git a/test/test_ldap.py b/test/test_ldap.py
new file mode 100644
index 00000000..9928af13
--- /dev/null
+++ b/test/test_ldap.py
@@ -0,0 +1,157 @@
+import pytest
+
+try:
+ import slapdtest
+except ImportError:
+ import old_slapdtest as slapdtest
+import os
+
+from moulinette.authenticators import ldap as m_ldap
+from moulinette import m18n
+from moulinette.core import MoulinetteError
+
+HERE = os.path.abspath(os.path.dirname(__file__))
+
+
+class TestLDAP:
+
+ server = None
+ server_default = None
+
+ @classmethod
+ def setup_class(cls):
+ cls.server_default = slapdtest.SlapdObject()
+ with open(os.path.join(HERE, "ldap_files", "slapd.conf.template")) as f:
+ SLAPD_CONF_TEMPLATE = f.read()
+ cls.server_default.slapd_conf_template = SLAPD_CONF_TEMPLATE
+ cls.server_default.suffix = "dc=yunohost,dc=org"
+ cls.server_default.root_cn = "admin"
+ cls.server_default.SCHEMADIR = os.path.join(HERE, "ldap_files", "schema")
+ cls.server_default.openldap_schema_files = [
+ "core.schema",
+ "cosine.schema",
+ "nis.schema",
+ "inetorgperson.schema",
+ "sudo.schema",
+ "yunohost.schema",
+ "mailserver.schema",
+ ]
+
+ def tools_ldapinit(self):
+ """
+ YunoHost LDAP initialization
+
+
+ """
+ import yaml
+
+ with open(os.path.join(HERE, "ldap_files", "ldap_scheme.yml")) as f:
+ ldap_map = yaml.load(f)
+
+ def _get_ldap_interface():
+ conf = {
+ "vendor": "ldap",
+ "name": "as-root",
+ "parameters": {
+ "uri": self.server.ldapi_uri,
+ "base_dn": "dc=yunohost,dc=org",
+ "user_rdn": "gidNumber=%s+uidNumber=%s,cn=peercred,cn=external,cn=auth"
+ % (os.getgid(), os.getuid()),
+ },
+ "extra": {},
+ }
+
+ _ldap_interface = m_ldap.Authenticator(**conf)
+
+ return _ldap_interface
+
+ ldap_interface = _get_ldap_interface()
+
+ for rdn, attr_dict in ldap_map["parents"].items():
+ ldap_interface.add(rdn, attr_dict)
+
+ for rdn, attr_dict in ldap_map["children"].items():
+ ldap_interface.add(rdn, attr_dict)
+
+ for rdn, attr_dict in ldap_map["depends_children"].items():
+ ldap_interface.add(rdn, attr_dict)
+
+ admin_dict = {
+ "cn": "admin",
+ "uid": "admin",
+ "description": "LDAP Administrator",
+ "gidNumber": "1007",
+ "uidNumber": "1007",
+ "homeDirectory": "/home/admin",
+ "loginShell": "/bin/bash",
+ "objectClass": [
+ "organizationalRole",
+ "posixAccount",
+ "simpleSecurityObject",
+ ],
+ "userPassword": "yunohost",
+ }
+
+ ldap_interface.update("cn=admin", admin_dict)
+
+ @classmethod
+ def teardown_class(cls):
+ pass
+
+ def setup_method(self):
+ self.server = self.server_default
+ self.server.start()
+ with open(os.path.join(HERE, "ldap_files", "tests.ldif")) as fp:
+ ldif = fp.read().decode("utf-8")
+ self.server.ldapadd(ldif)
+ self.tools_ldapinit()
+ self.ldap_conf = {
+ "vendor": "ldap",
+ "name": "as-root",
+ "parameters": {
+ "uri": self.server.ldapi_uri,
+ "base_dn": "dc=yunohost,dc=org",
+ },
+ "extra": {},
+ }
+
+ def teardown_method(self):
+ self.server.stop()
+
+ def test_authenticate_simple_bind_with_rdn(self):
+ self.ldap_conf["parameters"]["user_rdn"] = "cn=admin,dc=yunohost,dc=org"
+ ldap_interface = m_ldap.Authenticator(**self.ldap_conf)
+ ldap_interface.authenticate(password="yunohost")
+
+ def test_authenticate_simple_bind_with_rdn_wrong_password(self):
+ self.ldap_conf["parameters"]["user_rdn"] = "cn=admin,dc=yunohost,dc=org"
+ ldap_interface = m_ldap.Authenticator(**self.ldap_conf)
+ with pytest.raises(MoulinetteError) as exception:
+ ldap_interface.authenticate(password="bad_password_lul")
+
+ translation = m18n.g("invalid_password")
+ expected_msg = translation.format()
+ assert expected_msg in str(exception)
+
+ def test_authenticate_simple_bind_without_rdn(self):
+ self.ldap_conf["parameters"]["user_rdn"] = ""
+ ldap_interface = m_ldap.Authenticator(**self.ldap_conf)
+ ldap_interface.authenticate()
+
+ def test_authenticate_sasl_non_interactive_bind(self):
+ self.ldap_conf["parameters"]["user_rdn"] = (
+ "gidNumber=%s+uidNumber=%s,cn=peercred,cn=external,cn=auth"
+ % (os.getgid(), os.getuid()),
+ )
+ m_ldap.Authenticator(**self.ldap_conf)
+
+ def test_authenticate_server_down(self):
+ self.ldap_conf["parameters"]["user_rdn"] = "cn=admin,dc=yunohost,dc=org"
+ self.server.stop()
+ ldap_interface = m_ldap.Authenticator(**self.ldap_conf)
+ with pytest.raises(MoulinetteError) as exception:
+ ldap_interface.authenticate(password="yunohost")
+
+ translation = m18n.g("ldap_server_down")
+ expected_msg = translation.format()
+ assert expected_msg in str(exception)