Module: Treequel::Constants::Patterns

Overview

A collection of Regexps to match various LDAP values

Constant Summary collapse

URI_REF =

Steal the URIREF regexp from the URI library. We have to look in both places to support both 1.9.1 and 1.8.x.

if URI::REGEXP.const_defined?( :PATTERN )
	/#{URI::REGEXP::PATTERN::URI_REF}/
elsif URI::REGEXP.const_defined?( :URI_REF )
	/#{URI::REGEXP::URI_REF}/
else
	raise "Couldn't find the URI_REF constant in the URI library!"
end
ALPHA =

ALPHA = %x41-5A / %x61-7A ; “A”-“Z” / “a”-“z”

'[:alpha:]'
LDIGIT =

LDIGIT = %x31-39 ; “1”-“9”

'1-9'
DIGIT =

DIGIT = %x30 / LDIGIT ; “0”-“9”

'\d'
HEX =

HEX = DIGIT / %x41-46 / %x61-66 ; “0”-“9” / “A”-“F” / “a”-“f”

'[:xdigit:]'
SP =

SP = 1*SPACE ; one or more “ ” WSP = 0*SPACE ; zero or more “ ”

'\x20+'
WSP =
'\x20*'
NUL =

These are inlined for simplicity NULL = %x00 ; null (0)

NULL = '\x00'
SPACE =

SPACE = %x20 ; space (“ ”)

'\x20'
DQUOTE =

DQUOTE = %x22 ; quote (“”“)

'\x22'
SHARP =

SHARP = %x23 ; octothorpe (or sharp sign) (“#”)

'\x23'
DOLLAR =

DOLLAR = %x24 ; dollar sign (“$”)

'\x24'
SQUOTE =

SQUOTE = %x27 ; single quote (“‘”)

'\x27'
LPAREN =

LPAREN = %x28 ; left paren (“(”) RPAREN = %x29 ; right paren (“)”)

'\x28'
RPAREN =
'\x29'
PLUS =

PLUS = %x2B ; plus sign (“+”)

'\x2b'
COMMA =

COMMA = %x2C ; comma (“,”)

'\x2c'
HYPHEN =

HYPHEN = %x2D ; hyphen (“-”)

'\x2d'
DOT =

DOT = %x2E ; period (“.”)

'\x2e'
SEMI =

SEMI = %x3B ; semicolon (“;”)

'\x3b'
LANGLE =

LANGLE = %x3C ; left angle bracket (“<”) EQUALS = %x3D ; equals sign (“=”) RANGLE = %x3E ; right angle bracket (“>”)

'\x3c'
EQUALS =
'\x3d'
RANGLE =
'\x3e'
ESC =

ESC = %x5C ; backslash (“\”)

'\x5c'
USCORE =

USCORE = %x5F ; underscore (“_”)

'\x5f'
LCURLY =

LCURLY = %x7B ; left curly brace “RCURLY = %x7D ; right curly brace “”

'\x7b'
RCURLY =
'\x7d'
EXCLAMATION =

EXCLAMATION = %x21 ; exclamation mark (“!”) AMPERSAND = %x26 ; ampersand (or AND symbol) (“&”) ASTERISK = %x2A ; asterisk (“*”) COLON = %x3A ; colon (“:”) VERTBAR = %x7C ; vertical bar (or pipe) (“|”) TILDE = %x7E ; tilde (“~”)

'\x21'
AMPERSAND =
'\x26'
ASTERISK =
'\x2a'
COLON =
'\x3a'
VERTBAR =
'\x7c'
TILDE =
'\x7e'
UTF0 =

; Any UTF-8 [RFC3629] encoded Unicode [Unicode] character UTF0 = %x80-BF UTF1 = %x00-7F UTF2 = %xC2-DF UTF0

/[\x80-\xbf]/n
UTF1 =
/[\x00-\x7f]/n
UTF2 =
/[\xc2-\xdf] #{UTF0}/xn
UTF3 =

UTF3 = %xE0 %xA0-BF UTF0 / %xE1-EC 2(UTF0) / %xED %x80-9F UTF0 / %xEE-EF 2(UTF0)

/
	\xe0 [\xa0-\xbf] #{UTF0}
	|
	[\xe1-\xec] #{UTF0}{2}
	|
	\xed [\x80-\x9f] #{UTF0}
	|
	[\xee-\xef] #{UTF0}{2}
/xn
UTF4 =

UTF4 = %xF0 %x90-BF 2(UTF0) / %xF1-F3 3(UTF0) / %xF4 %x80-8F 2(UTF0)

/
	\xf0 [\x90-\xbf] #{UTF0}{2}
	|
	[\xf1-\xf3] #{UTF0}{3}
	|
	\xf4 [\x80-\x8f] #{UTF0}{2}
/xn
UTFMB =

UTFMB = UTF2 / UTF3 / UTF4

Regexp.union( UTF2, UTF3, UTF4 )
UTF8 =

UTF8 = UTF1 / UTFMB

Regexp.union( UTF1, UTFMB )
OCTET =

OCTET = %x00-FF ; Any octet (8-bit data unit)

'.'
LEADKEYCHAR =

leadkeychar = ALPHA

/[#{ALPHA}]/
KEYCHAR =

keychar = ALPHA / DIGIT / HYPHEN NOTE: added literal ‘.’ to work around OpenDS’s non-standard matchingRule names

/[#{ALPHA}#{DIGIT}\-\.]/
NUMBER =

number = DIGIT / ( LDIGIT 1*DIGIT )

/[#{LDIGIT}]#{DIGIT}+|#{DIGIT}/
KEYSTRING =

keystring = leadkeychar *keychar

/#{LEADKEYCHAR}#{KEYCHAR}*/
NUMERICOID =

numericoid = number 1*( DOT number )

/#{NUMBER}(?: #{DOT} #{NUMBER} )+/x
QUOTED_NUMERICOID =

ActiveDirectory quotes its numeric OIDs (sometimes)

/#{SQUOTE} #{NUMERICOID} #{SQUOTE}/x
DESCR =

descr = keystring

KEYSTRING
QUOTED_DESCR =

ActiveDirectory quotes its descriptors (sometimes)

/ #{SQUOTE} #{DESCR} #{SQUOTE} /x
OID =

oid = descr / numericoid NOTE: Added QUOTED_NUMERICOID and QUOTED_DESCR to support ActiveDirectory

/ #{DESCR} | #{QUOTED_DESCR} | #{NUMERICOID} | #{QUOTED_NUMERICOID} /x
LEN =

len = number

NUMBER
NOIDLEN =

noidlen = numericoid [ LCURLY len RCURLY ] NOTE: I changed this from NUMERICOID to OID to support ActiveDirectory schema

entries
/#{OID} (?:#{LCURLY} #{LEN} #{RCURLY})?/x
OIDLIST =

oidlist = oid *( WSP DOLLAR WSP oid )

/#{OID} (?: #{WSP} #{DOLLAR} #{WSP} #{OID} )*/x
OIDS =

oids = oid / ( LPAREN WSP oidlist WSP RPAREN )

/ #{OID} | #{LPAREN} #{WSP} #{OIDLIST} #{WSP} #{RPAREN} /x
XSTRING =

xstring = “X” HYPHEN 1*( ALPHA / HYPHEN / USCORE )

/ X #{HYPHEN} [#{ALPHA}#{HYPHEN}#{USCORE}]+ /x
QDESCR =

qdescr = SQUOTE descr SQUOTE qdescrlist = [ qdescr *( SP qdescr ) ] qdescrs = qdescr / ( LPAREN WSP qdescrlist WSP RPAREN )

/ #{SQUOTE} #{DESCR} #{SQUOTE} /x
QDESCRLIST =
/(?: #{QDESCR} (?: #{SP} #{QDESCR} )* )?/x
QDESCRS =
/ #{QDESCR} | #{LPAREN} #{WSP} #{QDESCRLIST} #{WSP} #{RPAREN} /x
QUTF1 =

; Any ASCII character except %x27 (“\‘”) and %x5C (“\”) QUTF1 = %x00-26 / %x28-5B / %x5D-7F

/[\x00-\x26\x28-\x5b\x5d-\x7f]/
QUTF8 =

; Any UTF-8 encoded Unicode character ; except %x27 (“\‘”) and %x5C (“\”) QUTF8 = QUTF1 / UTFMB

Regexp.union( QUTF1, UTFMB )
QQ =

QQ = ESC %x32 %x37 ; “\27” QS = ESC %x35 ( %x43 / %x63 ) ; “\5C” / “\5c”

/ #{ESC} 27 /x
QS =
/ #{ESC} 5c /xi
DSTRING =

dstring = 1*( QS / QQ / QUTF8 ) ; escaped UTF-8 string qdstring = SQUOTE dstring SQUOTE qdstringlist = [ qdstring *( SP qdstring ) ] qdstrings = qdstring / ( LPAREN WSP qdstringlist WSP RPAREN )

/ (?: #{QS} | #{QQ} | #{QUTF8} )* /x
QDSTRING =
/ #{SQUOTE} #{DSTRING} #{SQUOTE} /x
QDSTRINGLIST =
/(?: #{QDSTRING} (?: #{SP} #{QDSTRING} )* )?/x
QDSTRINGS =
/ #{QDSTRING} | #{LPAREN} #{WSP} #{QDSTRINGLIST} #{WSP} #{RPAREN} /x
MALFORMED_DSTRING =

Workaround for attributeType declarations that have unescaped single quotes in them (e.g., “Change Record Object Class Definition”,

http://tools.ietf.org/html/draft-good-ldap-changelog-04)

It will accept an unquoted single quote as long as it’s followed by a non-whitespace character.

%r{
	(?>
		# An unescaped single quote followed by a non-whitespace character
		#{SQUOTE} (?=\S)
		|
		# or correctly-escaped single-quoted string characters
		#{DSTRING}
	)*
}x
MALFORMED_QDSTRING =
/ #{SQUOTE} #{MALFORMED_DSTRING} #{SQUOTE} /x
EXTENSIONS =

extensions = *( SP xstring SP qdstrings )

/(?: #{SP} #{XSTRING} #{SP} #{QDSTRINGS} )*/x
KIND =

kind = “ABSTRACT” / “STRUCTURAL” / “AUXILIARY”

Regexp.union( 'ABSTRACT', 'STRUCTURAL', 'AUXILIARY' )
LDAP_OBJECTCLASS_DESCRIPTION =

Note: added ‘descr’ to the oid to support Sun OpenDS, which allows names instead of numericoids “for convenience”. (download.oracle.com/docs/cd/E19476-01/821-0509/object-class-description-format.html)

%r{
	#{LPAREN} #{WSP}
		(#{NUMERICOID} | #{DESCR})              # $1 = oid
		(?:#{SP} NAME #{SP} (#{QDESCRS}) )?     # $2 = name
		(?:#{SP} DESC #{SP} (#{QDSTRING}))?     # $3 = desc
		(?:#{SP} (OBSOLETE) )?                  # $4 = obsolete
		(?:#{SP} SUP #{SP} (#{OIDS}) )?         # $5 = sup
		(?:#{SP} (#{KIND}) )?                   # $6 = kind
		(?:#{SP} MUST #{SP} (#{OIDS}) )?        # $7 = must attrs
		(?:#{SP} MAY #{SP} (#{OIDS}) )?         # $8 = may attrs
		(#{EXTENSIONS})                         # $9 = extensions
	#{WSP} #{RPAREN}
}x
LDAP_MISORDERED_KIND_OBJECTCLASS_DESCRIPTION =

Support for objectClass definitions with the KIND before the SUP such as those in RFC3712

%r{
	#{LPAREN} #{WSP}
		(#{NUMERICOID} | #{DESCR})              # $1 = oid
		(?:#{SP} NAME #{SP} (#{QDESCRS}) )?     # $2 = name
		(?:#{SP} DESC #{SP} (#{QDSTRING}))?     # $3 = desc
		(?:#{SP} (OBSOLETE) )?                  # $4 = obsolete
		(?:#{SP} (#{KIND}) )?                   # $5 = kind
		(?:#{SP} SUP #{SP} (#{OIDS}) )?         # $6 = sup
		(?:#{SP} MUST #{SP} (#{OIDS}) )?        # $7 = must attrs
		(?:#{SP} MAY #{SP} (#{OIDS}) )?         # $8 = may attrs
		(#{EXTENSIONS})                         # $9 = extensions
	#{WSP} #{RPAREN}
}x
LDAP_TRAILING_KIND_OBJECTCLASS_DESCRIPTION =

Support for objectClass definitions with the KIND after the MUST and MAY sections like RFC2696’s authPasswordObject

%r{
	#{LPAREN} #{WSP}
		(#{NUMERICOID} | #{DESCR})              # $1 = oid
		(?:#{SP} NAME #{SP} (#{QDESCRS}) )?     # $2 = name
		(?:#{SP} DESC #{SP} (#{QDSTRING}))?     # $3 = desc
		(?:#{SP} (OBSOLETE) )?                  # $4 = obsolete
		(?:#{SP} SUP #{SP} (#{OIDS}) )?         # $5 = sup
		(?:#{SP} MUST #{SP} (#{OIDS}) )?        # $6 = must attrs
		(?:#{SP} MAY #{SP} (#{OIDS}) )?         # $7 = may attrs
		(?:#{SP} (#{KIND}) )?                   # $8 = kind
		(#{EXTENSIONS})                         # $9 = extensions
	#{WSP} #{RPAREN}
}x
LDAP_MISORDERED_DESC_OBJECTCLASS_DESCRIPTION =

Support for objectClass definitions with the DESC after the SUP and KIND like draft-howard-rfc2307bis, and a bunch of “Solaris Specific” ones from OpenDS servers.

%r{
	#{LPAREN} #{WSP}
		(#{NUMERICOID} | #{DESCR})              # $1 = oid
		(?:#{SP} NAME #{SP} (#{QDESCRS}) )?     # $2 = name
		(?:#{SP} (OBSOLETE) )?                  # $3 = obsolete
		(?:#{SP} SUP #{SP} (#{OIDS}) )?         # $4 = sup
		(?:#{SP} (#{KIND}) )?                   # $5 = kind
		(?:#{SP} DESC #{SP} (#{QDSTRING}))?     # $6 = desc
		(?:#{SP} MUST #{SP} (#{OIDS}) )?        # $7 = must attrs
		(?:#{SP} MAY #{SP} (#{OIDS}) )?         # $8 = may attrs
		(#{EXTENSIONS})                         # $9 = extensions
	#{WSP} #{RPAREN}
}x
USAGE =

usage = “userApplications” / ; user

"directoryOperation"   /  ; directory operational
"distributedOperation" /  ; DSA-shared operational
"dSAOperation"            ; DSA-specific operational
%r{
			userApplications
			|
			directoryOperation
			|
			distributedOperation
			|
			dSAOperation
}xi
LDAP_ATTRIBUTE_TYPE_DESCRIPTION =

Note: added ‘descr’ to the oid to support Sun OpenDS, which allows names instead of numericoids “for convenience”. (www.opends.org/wiki/page/UnderstandingAttributeTypes)

%r{
	#{LPAREN} #{WSP}
		(#{NUMERICOID} | #{DESCR})              # $1  = oid
		(?:#{SP} NAME #{SP} (#{QDESCRS}) )?     # $2  = name
		(?:#{SP} DESC #{SP} (#{QDSTRING}) )?    # $3  = description
		(?:#{SP} (OBSOLETE) )?                  # $4  = obsolete flag
		(?:#{SP} SUP #{SP} (#{OID}) )?          # $5  = superior type oid
		(?:#{SP} EQUALITY #{SP} (#{OID}) )?     # $6  = equality matching rule oid
		(?:#{SP} ORDERING #{SP} (#{OID}) )?     # $7  = ordering matching rule oid
		(?:#{SP} SUBSTR #{SP} (#{OID}) )?       # $8  = substring matching rule oid
		(?:#{SP} SYNTAX #{SP} (#{NOIDLEN}) )?   # $9  = value syntax matching oid
		(?:#{SP} (SINGLE-VALUE) )?              # $10 = single value flag
		(?:#{SP} (COLLECTIVE) )?                # $11 = collective flag
		(?:#{SP} (NO-USER-MODIFICATION) )?      # $12 = no user modification flag
		(?:#{SP} USAGE #{SP} (#{USAGE}) )?      # $13 = usage type
		(#{EXTENSIONS})                         # $14 = extensions
	#{WSP} #{RPAREN}
}x
LDAP_UNESCAPE_SQUOTE_ATTRIBUTE_TYPE_DESCRIPTION =

Attribute type with an unescaped single quote in the DESC; added for schemas that include the ‘changelog’ attributeType from

http://tools.ietf.org/html/draft-good-ldap-changelog-04
%r{
	#{LPAREN} #{WSP}
		(#{NUMERICOID} | #{DESCR})                     # $1  = oid
		(?:#{SP} NAME #{SP} (#{QDESCRS}) )?            # $2  = name
		(?:#{SP} DESC #{SP} (#{MALFORMED_QDSTRING}) )  # $3  = description
		(?:#{SP} (OBSOLETE) )?                         # $4  = obsolete flag
		(?:#{SP} SUP #{SP} (#{OID}) )?                 # $5  = superior type oid
		(?:#{SP} EQUALITY #{SP} (#{OID}) )?            # $6  = equality matching rule oid
		(?:#{SP} ORDERING #{SP} (#{OID}) )?            # $7  = ordering matching rule oid
		(?:#{SP} SUBSTR #{SP} (#{OID}) )?              # $8  = substring matching rule oid
		(?:#{SP} SYNTAX #{SP} (#{NOIDLEN}) )?          # $9  = value syntax matching oid
		(?:#{SP} (SINGLE-VALUE) )?                     # $10 = single value flag
		(?:#{SP} (COLLECTIVE) )?                       # $11 = collective flag
		(?:#{SP} (NO-USER-MODIFICATION) )?             # $12 = no user modification flag
		(?:#{SP} USAGE #{SP} (#{USAGE}) )?             # $13 = usage type
		(#{EXTENSIONS})                                # $14 = extensions
	#{WSP} #{RPAREN}
}x
LDAP_MISORDERED_SYNTAX_ATTRIBUTE_TYPE_DESCRIPTION =

Support for attributeType declarations which have the SYNTAX before the EQUALITY and ORDERING (e.g., changeNumber from

http://tools.ietf.org/html/draft-good-ldap-changelog-04 )
%r{
	#{LPAREN} #{WSP}
		(#{NUMERICOID} | #{DESCR})              # $1  = oid
		(?:#{SP} NAME #{SP} (#{QDESCRS}) )?     # $2  = name
		(?:#{SP} DESC #{SP} (#{QDSTRING}) )?    # $3  = description
		(?:#{SP} (OBSOLETE) )?                  # $4  = obsolete flag
		(?:#{SP} SUP #{SP} (#{OID}) )?          # $5  = superior type oid
		(?:#{SP} SYNTAX #{SP} (#{NOIDLEN}) )?   # $6  = value syntax matching oid
		(?:#{SP} EQUALITY #{SP} (#{OID}) )?     # $7  = equality matching rule oid
		(?:#{SP} ORDERING #{SP} (#{OID}) )?     # $8  = ordering matching rule oid
		(?:#{SP} SUBSTR #{SP} (#{OID}) )?       # $9  = substring matching rule oid
		(?:#{SP} (SINGLE-VALUE) )?              # $10 = single value flag
		(?:#{SP} (COLLECTIVE) )?                # $11 = collective flag
		(?:#{SP} (NO-USER-MODIFICATION) )?      # $12 = no user modification flag
		(?:#{SP} USAGE #{SP} (#{USAGE}) )?      # $13 = usage type
		(#{EXTENSIONS})                         # $14 = extensions
	#{WSP} #{RPAREN}
}x
LDAP_MATCHING_RULE_DESCRIPTION =

MatchingRuleDescription = LPAREN WSP numericoid ; object identifier [ SP “NAME” SP qdescrs ] ; short names (descriptors) [ SP “DESC” SP qdstring ] ; description [ SP “OBSOLETE” ] ; not active SP “SYNTAX” SP numericoid ; assertion syntax extensions WSP RPAREN ; extensions

%r{
	#{LPAREN} #{WSP}
		(#{NUMERICOID})                         # $1  = oid
		(?:#{SP} NAME #{SP} (#{QDESCRS}) )?     # $2  = name
		(?:#{SP} DESC #{SP} (#{QDSTRING}) )?    # $3  = description
		(?:#{SP} (OBSOLETE) )?                  # $4  = obsolete flag
		#{SP} SYNTAX #{SP} (#{NUMERICOID})      # $5  = syntax numeric OID
		(#{EXTENSIONS})                         # $6 = extensions
	#{WSP} #{RPAREN}
}x
LDAP_MATCHING_RULE_USE_DESCRIPTION =

Matching rule use descriptions are written according to the following ABNF:

MatchingRuleUseDescription = LPAREN WSP
    numericoid                 ; object identifier
    [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
    [ SP "DESC" SP qdstring ]  ; description
    [ SP "OBSOLETE" ]          ; not active
    SP "APPLIES" SP oids       ; attribute types
    extensions WSP RPAREN      ; extensions
%r{
	#{LPAREN} #{WSP}
		(#{NUMERICOID})                        # $1  = oid
		(?:#{SP} NAME #{SP} (#{QDESCRS}) )?    # $2  = name
		(?:#{SP} DESC #{SP} (#{QDSTRING}) )?   # $3  = description
		(?:#{SP} (OBSOLETE) )?                 # $4  = obsolete flag
		#{SP} APPLIES #{SP} (#{OIDS})          # $5  = attribute types
		(#{EXTENSIONS})                        # $6 = extensions
	#{WSP} #{RPAREN}
}x
LDAP_SYNTAX_DESCRIPTION =

LDAP syntax definitions are written according to the ABNF:

SyntaxDescription = LPAREN WSP
    numericoid                 ; object identifier
    [ SP "DESC" SP qdstring ]  ; description
    extensions WSP RPAREN      ; extensions
%r{
	#{LPAREN} #{WSP}
		(#{NUMERICOID})                        # $1  = oid
		(?:#{SP} DESC #{SP} (#{QDSTRING}) )?   # $2  = description
		(#{EXTENSIONS})                        # $3 = extensions
	#{WSP} #{RPAREN}
}x
UTF1SUBSET =

UTF1SUBSET = %x01-27 / %x2B-5B / %x5D-7F

; UTF1SUBSET excludes 0x00 (NUL), LPAREN,
; RPAREN, ASTERISK, and ESC.
%r{
	[\x01-\x27\x2b-\x5b\x50-\x7f]
}x
NORMAL =

normal = UTF1SUBSET / UTFMB

%r{ #{UTF1SUBSET} | #{UTFMB} }x
ESCAPED =

escaped = ESC HEX HEX

%r{ #{ESC} [[:xdigit:]]{2} }x
UNESCAPED =

characters which must be escaped in filter values

%r{[#{NUL}#{LPAREN}#{RPAREN}#{ASTERISK}#{ESC}]}
VALUEENCODING =

valueencoding = 0*(normal / escaped)

%r{ (?:#{NORMAL} | #{ESCAPED})* }x
ASSERTIONVALUE =

assertionvalue = valueencoding ; The <valueencoding> rule is used to encode an <AssertionValue> ; from Section 4.1.6 of [RFC4511].

VALUEENCODING
LDAP_SUBSTRING_FILTER_VALUE =

The value part of a substring filter

initial        = assertionvalue
any            = ASTERISK *(assertionvalue ASTERISK)
final          = assertionvalue
%r{
	#{ASSERTIONVALUE}
	#{ASTERISK}
		(?: #{ASSERTIONVALUE} #{ASTERISK} )*
	#{ASSERTIONVALUE}
}x
LDAP_ATTRIBUTE_DESCRIPTION =

An AttributeDescription (same as LDAPString)

attributedescription = attributetype options
     attributetype = oid
     options = *( SEMI option )
     option = 1*keychar
%r{
	(#{OID})                          # $1: the OID
	(                                 # $2: attribute options
		(?:;#{KEYCHAR}+)*
	)
}x
LDAP_SUBSTRING_FILTER =

A substring filter, from RFC4511, section 4.5.1

SubstringFilter ::= SEQUENCE {
    type           AttributeDescription,
    substrings     SEQUENCE SIZE (1..MAX) OF substring CHOICE {
         initial [0] AssertionValue,  -- can occur at most once
         any     [1] AssertionValue,
         final   [2] AssertionValue } -- can occur at most once
    }
%r{
	(#{LDAP_ATTRIBUTE_DESCRIPTION})            # $1: AttributeDescription
	=
	(#{LDAP_SUBSTRING_FILTER_VALUE})           # $2: value
}x
HEXPAIR =

hexpair = HEX HEX

/#{HEX}{2}/
HEXSTRING =

hexstring = SHARP 1*hexpair

%r{ #{SHARP} #{HEXPAIR}+ }x
DN_ESCAPED =

escaped = DQUOTE / PLUS / COMMA / SEMI / LANGLE / RANGLE

%r{ #{DQUOTE} | #{PLUS} | #{COMMA} | #{SEMI} | #{LANGLE} | #{RANGLE} }x
SPECIAL =

special = escaped / SPACE / SHARP / EQUALS

%r{ #{DN_ESCAPED} | #{SPACE} | #{SHARP} | #{EQUALS} }x
PAIR =

pair = ESC ( ESC / special / hexpair )

%r{
	#{ESC}
	(?:
		#{ESC}
		| #{SPECIAL}
		| #{HEXPAIR}
	)
}x
SUTF1 =

SUTF1 = %x01-21 / %x23-2A / %x2D-3A / %x3D / %x3F-5B / %x5D-7F

/[\x01-\x21\x23-\x2a\x2d-\x3a\x3d\x3f-\x5b\x5d-\x7f]/
STRINGCHAR =

stringchar = SUTF1 / UTFMB

%r{ #{SUTF1} | #{UTFMB} }x
TUTF1 =

TUTF1 = %x01-1F / %x21 / %x23-2A / %x2D-3A / %x3D / %x3F-5B / %x5D-7F

/[\x01-\x1f\x21\x23-\x2a\x2d-\x3a\x3d\x3f-\x5b\x5d-\x7f]/
TRAILCHAR =

trailchar = TUTF1 / UTFMB

%r{ #{TUTF1} | #{UTFMB} }x
LUTF1 =

LUTF1 = %x01-1F / %x21 / %x24-2A / %x2D-3A / %x3D / %x3F-5B / %x5D-7F

/[\x01-\x1f\x21\x24-\x2a\x2d-\x3a\x3d\x3f-\x5b\x5d-\x7f]/
LEADCHAR =

leadchar = LUTF1 / UTFMB

%r{ #{LUTF1} | #{UTFMB} }x
STRING =

; The following characters are to be escaped when they appear ; in the value to be encoded: ESC, one of <escaped>, leading ; SHARP or SPACE, trailing SPACE, and NULL. string = [ ( leadchar / pair ) [ *( stringchar / pair )

( trailchar / pair ) ] ]

NOTE: the RFC specifies that all characters are optional in a STRING, which means that

the RDN 'cn=' is valid. While I hesitate to deviate from the RFC, I can't currently
conceive of a way such an RDN would be useful, so I'm defining this as requiring at
least one character. If this becomes a problem later, we can just surround it
with non-capturing parens with a optional qualifier.
%r{
	(?:
		#{LEADCHAR}
		| #{PAIR}
	)
	(?:
		(?: #{STRINGCHAR} | #{PAIR} )*
		#{TRAILCHAR} | #{PAIR}
	)?
}x
ATTRIBUTE_VALUE =

attributeValue = string / hexstring

%r{
	#{HEXSTRING}			# Since STRING can match the empty string, try HEXSTRING first
	| #{STRING}
}x
ATTRIBUTE_TYPE =

attributeType = descr / numericoid

%r{
	#{DESCR}
	|
	#{NUMERICOID}
}x
ATTRIBUTE_TYPE_AND_VALUE =

attributeTypeAndValue = attributeType EQUALS attributeValue

%r{
	#{ATTRIBUTE_TYPE} = #{ATTRIBUTE_VALUE}
}x
RELATIVE_DISTINGUISHED_NAME =

relativeDistinguishedName = attributeTypeAndValue

*( PLUS attributeTypeAndValue )
%r{
	#{ATTRIBUTE_TYPE_AND_VALUE}
	(?:
		\+
		#{ATTRIBUTE_TYPE_AND_VALUE}
	)*
}x
DISTINGUISHED_NAME =

distinguishedName = [ relativeDistinguishedName

*( COMMA relativeDistinguishedName ) ]
%r{
	#{RELATIVE_DISTINGUISHED_NAME}
	(?:
		,
		#{RELATIVE_DISTINGUISHED_NAME}
	)*
}x
LDIF_ATTR_TYPE_CHARS =

attr-type-chars = ALPHA / DIGIT / “-” opt-char = attr-type-chars

same as KEYCHAR
KEYCHAR
LDIF_OPT_CHAR =
KEYCHAR
LDIF_ATTRTYPE_OPTION =

option = 1*opt-char

%r{ #{LDIF_OPT_CHAR}+ }x
LDIF_ATTRTYPE_OPTIONS =

options = option / (option “;” options)

%r{
	#{LDIF_ATTRTYPE_OPTION}
	(?: ; #{LDIF_ATTRTYPE_OPTION} )*
}x
LDIF_ATTRIBUTE_TYPE =

AttributeType = ldap-oid / (ALPHA *(attr-type-chars))

%r{
	#{NUMERICOID}
	|
	[#{ALPHA}] #{LDIF_ATTR_TYPE_CHARS}*
}x
LDIF_ATTRIBUTE_DESCRIPTION =

AttributeDescription = AttributeType [“;” options]

; Definition taken from [4]
%r{
	#{LDIF_ATTRIBUTE_TYPE}
	(?: ; #{LDIF_ATTRTYPE_OPTIONS} )?
}x
FILL =

SPACE = %x20 ; ASCII SP, space FILL = *SPACE

'\x20+'
LDIF_SAFE_CHAR =

SAFE-CHAR = %x01-09 / %x0B-0C / %x0E-7F

; any value <= 127 decimal except NUL, LF,
; and CR
%r{[\x01-\x09\x0b-\x0c\x0e-\x7f]}
LDIF_SAFE_INIT_CHAR =

SAFE-INIT-CHAR = %x01-09 / %x0B-0C / %x0E-1F /

%x21-39 / %x3B / %x3D-7F
; any value <= 127 except NUL, LF, CR,
; SPACE, colon (":", ASCII 58 decimal)
; and less-than ("<" , ASCII 60 decimal)
%r{[\x01-\x09\x0B-\x0C\x0E-\x1F\x21-\x39\x3B\x3D-\x7F]}
LDIF_SAFE_STRING =

SAFE-STRING = [SAFE-INIT-CHAR *SAFE-CHAR]

%r{
	#{LDIF_SAFE_INIT_CHAR}
	#{LDIF_SAFE_CHAR}*
}x
BASE64_CHAR =

BASE64-CHAR = %x2B / %x2F / %x30-39 / %x3D / %x41-5A /

%x61-7A
; +, /, 0-9, =, A-Z, and a-z
; as specified in [5]
%r{[\x2B\x2F\x30-\x39\x3D\x41-\x5A\x61-\x7A]}
BASE64_STRING =

BASE64-STRING = [*(BASE64-CHAR)]

%r{ #{BASE64_CHAR}* }x
SEP =

SEP = (CR LF / LF)

%r{\r?\n}
FOLD =

Any non-empty line, including comment lines, in an LDIF file MAY be folded by inserting a line separator (SEP) and a SPACE.

%r{ #{SEP} #{SPACE} }x
LDIF_VALUE_SPEC =

value-spec = “:” ( FILL 0*1(SAFE-STRING) /

":" FILL (BASE64-STRING) /
"<" FILL url)
%r{
	:
	(
		#{FILL} #{LDIF_SAFE_STRING}+ (?: #{FOLD} #{LDIF_SAFE_CHAR}* )*
		|
		: #{FILL} #{BASE64_STRING} (?: #{FOLD} #{BASE64_STRING} )*
		|
		< #{FILL} #{URI_REF}
	)
}x
LDIF_ATTRVAL_SPEC =

attrval-spec = AttributeDescription value-spec SEP

%r{
	(#{LDIF_ATTRIBUTE_DESCRIPTION})
	#{LDIF_VALUE_SPEC}
	#{SEP}
}xm