From e8a65c0a92a5f7632c276a7fb2fb2fd11fc54048 Mon Sep 17 00:00:00 2001
From: Julian Rother <julian@jrother.eu>
Date: Thu, 2 Dec 2021 18:05:28 +0100
Subject: [PATCH] DN parsing rewrite with REs

---
 ldapserver/dn.py | 48 ++++++++++++++++++------------------------------
 1 file changed, 18 insertions(+), 30 deletions(-)

diff --git a/ldapserver/dn.py b/ldapserver/dn.py
index b6ce3bf..f291fac 100644
--- a/ldapserver/dn.py
+++ b/ldapserver/dn.py
@@ -55,22 +55,16 @@ class DN(tuple):
 		:raises ValueError: if expr is invalid
 		:returns: Parsed DN
 		:rtype: DN'''
-		escaped = False
 		rdns = []
-		token = ''
-		for char in expr:
-			if escaped:
-				escaped = False
-				token += char
-			elif char == ',':
-				rdns.append(RDN.from_str(schema, token))
-				token = ''
-			else:
-				if char == '\\':
-					escaped = True
-				token += char
-		if token:
-			rdns.append(RDN.from_str(schema, token))
+		while expr:
+			# relativeDistinguishedName may contain escape sequences including "\,".
+			# Split off first token expr at "," while ignoring "\,".
+			match = re.match(r'^(([^,\\]|\\.)+)(,|$)', expr)
+			if not match:
+				raise ValueError(f'Unrecognized token {expr!r}')
+			expr = expr[match.end():]
+			rdn_expr, _, _ = match.groups()
+			rdns.append(RDN.from_str(schema, rdn_expr))
 		return cls(schema, *rdns)
 
 	def __str__(self):
@@ -269,22 +263,16 @@ class RDN(tuple):
 		:raises ValueError: if expr is invalid
 		:returns: Parsed RDN
 		:rtype: RDN'''
-		escaped = False
 		assertions = []
-		token = ''
-		for char in expr:
-			if escaped:
-				escaped = False
-				token += char
-			elif char == '+':
-				assertions.append(RDNAssertion.from_str(schema, token))
-				token = ''
-			else:
-				if char == '\\':
-					escaped = True
-				token += char
-		if token:
-			assertions.append(RDNAssertion.from_str(schema, token))
+		while expr:
+			# attributeTypeAndValue may contain escape sequences including "\+".
+			# Split off first token expr at "+" while ignoring "\+".
+			match = re.match(r'^(([^+\\]|\\.)+)(\+|$)', expr)
+			if not match:
+				raise ValueError(f'Unrecognized token {expr!r}')
+			expr = expr[match.end():]
+			assertion_expr, _, _ = match.groups()
+			assertions.append(RDNAssertion.from_str(schema, assertion_expr))
 		return cls(schema, *assertions)
 
 	def __str__(self):
-- 
GitLab