From ec4849bf1359cf37cef0a84c9c8b1f99a5c397cf Mon Sep 17 00:00:00 2001
From: nd <git@notandy.de>
Date: Fri, 17 Jul 2020 17:25:24 +0200
Subject: [PATCH] do not use ldap3 rdns escaping

---
 uffd/ldap/__init__.py |  2 +-
 uffd/ldap/ldap.py     | 23 ++++++++++++++++++-----
 uffd/user/models.py   |  7 +------
 3 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/uffd/ldap/__init__.py b/uffd/ldap/__init__.py
index b420a489..0ba10c72 100644
--- a/uffd/ldap/__init__.py
+++ b/uffd/ldap/__init__.py
@@ -1,4 +1,4 @@
 from .ldap import bp as ldap_bp
-from .ldap import get_conn, user_conn, escape_filter_chars, uid_to_dn, loginname_to_dn, get_next_uid
+from .ldap import get_conn, user_conn, escape_filter_chars, uid_to_dn, loginname_to_dn, get_next_uid, loginname_is_safe
 
 bp = [ldap_bp]
diff --git a/uffd/ldap/ldap.py b/uffd/ldap/ldap.py
index e1ddaf19..2d6d9c32 100644
--- a/uffd/ldap/ldap.py
+++ b/uffd/ldap/ldap.py
@@ -1,6 +1,7 @@
+import string
+
 from flask import Blueprint, current_app
 from ldap3.utils.conv import escape_filter_chars
-from ldap3.utils.dn import escape_rdn
 from ldap3.core.exceptions import LDAPBindError
 
 from ldap3 import Server, Connection, ALL, ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES
@@ -17,9 +18,11 @@ def fix_connection(conn):
 
 def service_conn():
 	server = Server(current_app.config["LDAP_SERVICE_URL"], get_info=ALL)
-	return Connection(server, current_app.config["LDAP_SERVICE_BIND_DN"], current_app.config["LDAP_SERVICE_BIND_PASSWORD"], auto_bind=True)
+	return fix_connection(Connection(server, current_app.config["LDAP_SERVICE_BIND_DN"], current_app.config["LDAP_SERVICE_BIND_PASSWORD"], auto_bind=True))
 
 def user_conn(loginname, password):
+	if not loginname_is_safe(loginname):
+		return False
 	server = Server(current_app.config["LDAP_SERVICE_URL"], get_info=ALL)
 	try:
 		return fix_connection(Connection(server, loginname_to_dn(loginname), password, auto_bind=True))
@@ -27,8 +30,7 @@ def user_conn(loginname, password):
 		return False
 
 def get_conn():
-	conn = service_conn()
-	return fix_connection(conn)
+	return service_conn()
 
 def uid_to_dn(uid):
 	conn = get_conn()
@@ -38,7 +40,18 @@ def uid_to_dn(uid):
 	return conn.entries[0].entry_dn
 
 def loginname_to_dn(loginname):
-	return 'uid={},{}'.format(escape_rdn(loginname), current_app.config["LDAP_BASE_USER"])
+	if loginname_is_safe(loginname):
+		return 'uid={},{}'.format(loginname, current_app.config["LDAP_BASE_USER"])
+	else:
+		raise Exception('unsafe login name')
+
+def loginname_is_safe(value):
+	if len(value) > 32 or len(value) < 1:
+		return False
+	for char in value:
+		if not char in string.ascii_lowercase + string.digits + '_':
+			return False
+	return True
 
 def get_next_uid():
 	conn = get_conn()
diff --git a/uffd/user/models.py b/uffd/user/models.py
index 69dcf005..f55ffe66 100644
--- a/uffd/user/models.py
+++ b/uffd/user/models.py
@@ -1,5 +1,3 @@
-import string
-
 from ldap3 import MODIFY_REPLACE, HASHED_SALTED_SHA512
 from ldap3.utils.hashed import hashed
 from flask import current_app
@@ -90,11 +88,8 @@ class User():
 		return False
 
 	def set_loginname(self, value):
-		if len(value) > 32 or len(value) < 1:
+		if not ldap.loginname_is_safe(value):
 			return False
-		for char in value:
-			if not char in string.ascii_lowercase + string.digits + '_':
-				return False
 		self.loginname = value
 		return True
 
-- 
GitLab