summaryrefslogtreecommitdiffstats
path: root/scripts/ldap/schema_to_samba.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/ldap/schema_to_samba.py')
-rw-r--r--scripts/ldap/schema_to_samba.py132
1 files changed, 132 insertions, 0 deletions
diff --git a/scripts/ldap/schema_to_samba.py b/scripts/ldap/schema_to_samba.py
new file mode 100644
index 0000000..637ae52
--- /dev/null
+++ b/scripts/ldap/schema_to_samba.py
@@ -0,0 +1,132 @@
+# This is a quick hack to convert an openldap schema file to a form which
+# can be loaded into Samba4/AD.
+#
+# Inspired by:
+# http://david-latham.blogspot.co.uk/2012/12/extending-ad-schema-on-samba4-part-2.html
+# https://github.com/linuxplayground/yubikey-ldap/tree/master/samba4-schema
+#
+# (c) 2017 Brian Candler <b.candler@pobox.com>
+# -------------------------------------------------------------------------
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+# -----------------------------------------------------------------------
+
+from __future__ import print_function
+import sys
+import re
+from collections import OrderedDict
+
+BASEDN = 'dc=samba4,dc=internal'
+
+# RFC 2252 to https://technet.microsoft.com/en-us/library/cc961740.aspx
+SYNTAX_MAP = {
+ '1.3.6.1.4.1.1466.115.121.1.7': ('2.5.5.8', 1), # boolean
+ '1.3.6.1.4.1.1466.115.121.1.12': ('2.5.5.1', 127), # DN
+ '1.3.6.1.4.1.1466.115.121.1.15': ('2.5.5.3', 27), # DirectoryString
+ '1.3.6.1.4.1.1466.115.121.1.26': ('2.5.5.5', 22), # IA5String
+ '1.3.6.1.4.1.1466.115.121.1.27': ('2.5.5.9', 10), # Integer
+}
+obj = None
+for line in sys.stdin:
+ if re.match(r'^\s*(#|$)', line): continue
+ m = re.match(r'^attributetype\s+\(\s+(\S+)', line)
+ if m:
+ obj = OrderedDict([
+ ('objectClass', ['top', 'attributeSchema']),
+ ('attributeID', m.group(1)),
+ ('isSingleValued', 'FALSE'),
+ ])
+ continue
+ m = re.match(r'^objectclass\s+\(\s+(\S+)', line)
+ if m:
+ obj = OrderedDict([
+ ('objectClass', ['top', 'classSchema']),
+ ('governsID', m.group(1)),
+ ])
+ continue
+ m = re.match(r'^\s*NAME\s+[\'"](.+)[\'"]', line)
+ if m:
+ obj.update([
+ ('cn', m.group(1)),
+ ('name', m.group(1)),
+ ('lDAPDisplayName', m.group(1)),
+ ])
+ continue
+ m = re.match(r'^\s*DESC\s+[\'"](.+)[\'"]', line)
+ if m:
+ obj.update([
+ ('description', m.group(1)),
+ ])
+ continue
+ m = re.match(r'^\s*(EQUALITY|SUBSTR)\s+(\S+)', line)
+ if m:
+ # Not supported by AD?
+ # https://technet.microsoft.com/en-us/library/cc961575.aspx
+ continue
+ m = re.match(r'^\s*SYNTAX\s+(\S+)', line)
+ if m:
+ obj.update([
+ ('attributeSyntax', SYNTAX_MAP[m.group(1)][0]),
+ ('oMSyntax', SYNTAX_MAP[m.group(1)][1]),
+ ])
+ continue
+ if re.match(r'^\s*SINGLE-VALUE', line):
+ obj.update([
+ ('isSingleValued', 'TRUE'),
+ ])
+ continue
+ if re.match(r'^\s*AUXILIARY', line):
+ # https://msdn.microsoft.com/en-us/library/ms679014(v=vs.85).aspx
+ # https://technet.microsoft.com/en-us/library/2008.05.schema.aspx
+ obj.update([
+ ('objectClassCategory', '3'),
+ ])
+ continue
+ if re.match(r'^\s*STRUCTURAL', line):
+ obj.update([
+ ('objectClassCategory', '1'),
+ ])
+ continue
+ m = re.match(r'^\s*SUP\s+(\S+)', line)
+ if m:
+ obj.update([
+ ('subClassOf', m.group(1)),
+ ])
+ continue
+ m = re.match(r'^\s*(MAY|MUST)\s+\((.*)\)\s*$', line)
+ if m:
+ attrs = m.group(2).split('$')
+ obj.update([
+ ('%sContain' % m.group(1).lower(), [v.strip() for v in attrs]),
+ ])
+ continue
+ m = re.match(r'^\s*(MAY|MUST)\s+(\w+)\s*$', line)
+ if m:
+ obj.update([
+ ('%sContain' % m.group(1).lower(), m.group(2)),
+ ])
+ continue
+ if re.match(r'^\s*\)', line) and obj:
+ print("dn: CN=%s,CN=Schema,CN=Configuration,%s" % (obj['cn'], BASEDN))
+ print("changetype: add")
+ for k in obj:
+ if type(obj[k]) == list:
+ for v in obj[k]:
+ print("%s: %s" % (k, v))
+ else:
+ print("%s: %s" % (k, obj[k]))
+ print()
+ obj = None
+ continue
+ print("??? %s" % line, file=sys.stderr)