testprogs/blackbox: PY3 bulk change for python scripts use correct python
[amitay/samba.git] / python / samba / ms_schema.py
index c16693c9b5ab08469816de5650b172b689bf0bb0..4946636cbd47223760d8ff86f824ccab07411c98 100644 (file)
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+from __future__ import print_function
 """Generate LDIF from WSPP documentation."""
 
 import re
 import base64
 import uuid
+from samba.compat import string_types
 
 bitFields = {}
 
@@ -34,15 +36,18 @@ bitFields["searchflags"] = {
     'fTUPLEINDEX': 26,       # TP
     'fSUBTREEATTINDEX': 25,  # ST
     'fCONFIDENTIAL': 24,     # CF
+    'fCONFIDENTAIL': 24,  # typo
     'fNEVERVALUEAUDIT': 23,  # NV
     'fRODCAttribute': 22,    # RO
 
 
     # missing in ADTS but required by LDIF
-    'fRODCFilteredAttribute': 22,    # RO ?
-    'fCONFIDENTAIL': 24, # typo
-    'fRODCFILTEREDATTRIBUTE': 22 # case
-    }
+    'fRODCFilteredAttribute': 22,    # RO
+    'fRODCFILTEREDATTRIBUTE': 22,  # case
+    'fEXTENDEDLINKTRACKING': 21,  # XL
+    'fBASEONLY': 20,  # BO
+    'fPARTITIONSECRET': 19,  # SE
+}
 
 # ADTS: 2.2.10
 bitFields["systemflags"] = {
@@ -59,29 +64,30 @@ bitFields["systemflags"] = {
     'FLAG_CONFIG_ALLOW_MOVE': 2,     # AM
     'FLAG_CONFIG_ALLOW_RENAME': 1,     # AR
     'FLAG_DISALLOW_DELETE': 0     # DD
-    }
+}
 
 # ADTS: 2.2.11
 bitFields["schemaflagsex"] = {
     'FLAG_ATTR_IS_CRITICAL': 31
-    }
+}
 
 # ADTS: 3.1.1.2.2.2
 oMObjectClassBER = {
-    '1.3.12.2.1011.28.0.702' : base64.b64encode('\x2B\x0C\x02\x87\x73\x1C\x00\x85\x3E'),
-    '1.2.840.113556.1.1.1.12': base64.b64encode('\x2A\x86\x48\x86\xF7\x14\x01\x01\x01\x0C'),
-    '2.6.6.1.2.5.11.29'      : base64.b64encode('\x56\x06\x01\x02\x05\x0B\x1D'),
-    '1.2.840.113556.1.1.1.11': base64.b64encode('\x2A\x86\x48\x86\xF7\x14\x01\x01\x01\x0B'),
-    '1.3.12.2.1011.28.0.714' : base64.b64encode('\x2B\x0C\x02\x87\x73\x1C\x00\x85\x4A'),
-    '1.3.12.2.1011.28.0.732' : base64.b64encode('\x2B\x0C\x02\x87\x73\x1C\x00\x85\x5C'),
-    '1.2.840.113556.1.1.1.6' : base64.b64encode('\x2A\x86\x48\x86\xF7\x14\x01\x01\x01\x06')
+    '1.3.12.2.1011.28.0.702': base64.b64encode(b'\x2B\x0C\x02\x87\x73\x1C\x00\x85\x3E').decode('utf8'),
+    '1.2.840.113556.1.1.1.12': base64.b64encode(b'\x2A\x86\x48\x86\xF7\x14\x01\x01\x01\x0C').decode('utf8'),
+    '2.6.6.1.2.5.11.29': base64.b64encode(b'\x56\x06\x01\x02\x05\x0B\x1D').decode('utf8'),
+    '1.2.840.113556.1.1.1.11': base64.b64encode(b'\x2A\x86\x48\x86\xF7\x14\x01\x01\x01\x0B').decode('utf8'),
+    '1.3.12.2.1011.28.0.714': base64.b64encode(b'\x2B\x0C\x02\x87\x73\x1C\x00\x85\x4A').decode('utf8'),
+    '1.3.12.2.1011.28.0.732': base64.b64encode(b'\x2B\x0C\x02\x87\x73\x1C\x00\x85\x5C').decode('utf8'),
+    '1.2.840.113556.1.1.1.6': base64.b64encode(b'\x2A\x86\x48\x86\xF7\x14\x01\x01\x01\x06').decode('utf8')
 }
 
 # separated by commas in docs, and must be broken up
-multivalued_attrs = set(["auxiliaryclass","maycontain","mustcontain","posssuperiors",
-                         "systemauxiliaryclass","systemmaycontain","systemmustcontain",
+multivalued_attrs = set(["auxiliaryclass", "maycontain", "mustcontain", "posssuperiors",
+                         "systemauxiliaryclass", "systemmaycontain", "systemmustcontain",
                          "systemposssuperiors"])
 
+
 def __read_folded_line(f, buffer):
     """ reads a line from an LDIF file, unfolding it"""
     line = buffer
@@ -117,6 +123,7 @@ def __read_folded_line(f, buffer):
 
 def __read_raw_entries(f):
     """reads an LDIF entry, only unfolding lines"""
+    import sys
 
     # will not match options after the attribute type
     attr_type_re = re.compile("^([A-Za-z]+[A-Za-z0-9-]*):")
@@ -143,7 +150,7 @@ def __read_raw_entries(f):
 
                 entry.append(l)
             else:
-                print >>sys.stderr, "Invalid line: %s" % l,
+                print("Invalid line: %s" % l, end=' ', file=sys.stderr)
                 sys.exit(1)
 
         if len(entry):
@@ -161,12 +168,17 @@ def fix_dn(dn):
         dn = dn.replace("\n ", "")
         dn = dn.replace(" ", "")
         return dn.replace("CN=Schema,CN=Configuration,<RootDomainDN>", "${SCHEMADN}")
+    elif dn.endswith("DC=X"):
+        return dn.replace("CN=Schema,CN=Configuration,DC=X", "${SCHEMADN}")
+    elif dn.endswith("CN=X"):
+        return dn.replace("CN=Schema,CN=Configuration,CN=X", "${SCHEMADN}")
     else:
         return dn
 
+
 def __convert_bitfield(key, value):
     """Evaluate the OR expression in 'value'"""
-    assert(isinstance(value, str))
+    assert(isinstance(value, string_types))
 
     value = value.replace("\n ", "")
     value = value.replace(" ", "")
@@ -183,26 +195,27 @@ def __convert_bitfield(key, value):
 
     return str(o)
 
+
 def __write_ldif_one(entry):
     """Write out entry as LDIF"""
     out = []
 
     for l in entry:
-        if isinstance(l[1], str):
+        if isinstance(l[1], string_types):
             vl = [l[1]]
         else:
             vl = l[1]
 
-        if l[0].lower() == 'omobjectclass':
+        if l[2]:
             out.append("%s:: %s" % (l[0], l[1]))
             continue
 
         for v in vl:
             out.append("%s: %s" % (l[0], v))
 
-
     return "\n".join(out)
 
+
 def __transform_entry(entry, objectClass):
     """Perform transformations required to convert the LDIF-like schema
        file entries to LDIF, including Samba-specific stuff."""
@@ -210,8 +223,15 @@ def __transform_entry(entry, objectClass):
     entry = [l.split(":", 1) for l in entry]
 
     cn = ""
+    skip_dn = skip_objectclass = skip_admin_description = skip_admin_display_name = False
 
     for l in entry:
+        if l[1].startswith(': '):
+            l.append(True)
+            l[1] = l[1][2:]
+        else:
+            l.append(False)
+
         key = l[0].lower()
         l[1] = l[1].lstrip()
         l[1] = l[1].rstrip()
@@ -230,53 +250,73 @@ def __transform_entry(entry, objectClass):
             l[1] = __convert_bitfield(key, l[1])
 
         if key == "omobjectclass":
-            l[1] = oMObjectClassBER[l[1].strip()]
+            if not l[2]:
+                l[1] = oMObjectClassBER[l[1].strip()]
+                l[2] = True
 
-        if isinstance(l[1], str):
+        if isinstance(l[1], string_types):
             l[1] = fix_dn(l[1])
 
+        if key == 'dn':
+            skip_dn = True
+            dn = l[1]
+
+        if key == 'objectclass':
+            skip_objectclass = True
+        elif key == 'admindisplayname':
+            skip_admin_display_name = True
+        elif key == 'admindescription':
+            skip_admin_description = True
 
     assert(cn)
-    entry.insert(0, ["dn", "CN=%s,${SCHEMADN}" % cn])
-    entry.insert(1, ["objectClass", ["top", objectClass]])
-    entry.insert(2, ["cn", cn])
-    entry.insert(2, ["objectGUID", str(uuid.uuid4())])
-    entry.insert(2, ["adminDescription", cn])
-    entry.insert(2, ["adminDisplayName", cn])
 
-    for l in entry:
-        key = l[0].lower()
+    header = []
+    if not skip_dn:
+        header.append(["dn", "CN=%s,${SCHEMADN}" % cn, False])
+    else:
+        header.append(["dn", dn, False])
 
-        if key == "cn":
-            entry.remove(l)
+    if not skip_objectclass:
+        header.append(["objectClass", ["top", objectClass], False])
+    if not skip_admin_description:
+        header.append(["adminDescription", cn, False])
+    if not skip_admin_display_name:
+        header.append(["adminDisplayName", cn, False])
+
+    header.append(["objectGUID", str(uuid.uuid4()), False])
+
+    entry = header + [x for x in entry if x[0].lower() not in set(['dn', 'changetype', 'objectcategory'])]
 
     return entry
 
+
 def __parse_schema_file(filename, objectClass):
     """Load and transform a schema file."""
 
     out = []
 
-    f = open(filename, "rU")
+    from io import open
+    f = open(filename, "r", encoding='latin-1')
     for entry in __read_raw_entries(f):
         out.append(__write_ldif_one(__transform_entry(entry, objectClass)))
 
     return "\n\n".join(out)
 
 
-def read_ms_schema(attr_file, classes_file, dump_attributes = True, dump_classes = True, debug = False):
+def read_ms_schema(attr_file, classes_file, dump_attributes=True, dump_classes=True, debug=False):
     """Read WSPP documentation-derived schema files."""
 
     attr_ldif = ""
     classes_ldif = ""
 
     if dump_attributes:
-        attr_ldif =  __parse_schema_file(attr_file, "attributeSchema")
+        attr_ldif = __parse_schema_file(attr_file, "attributeSchema")
     if dump_classes:
         classes_ldif = __parse_schema_file(classes_file, "classSchema")
 
     return attr_ldif + "\n\n" + classes_ldif + "\n\n"
 
+
 if __name__ == '__main__':
     import sys
 
@@ -284,7 +324,7 @@ if __name__ == '__main__':
         attr_file = sys.argv[1]
         classes_file = sys.argv[2]
     except IndexError:
-        print >>sys.stderr, "Usage: %s attr-file.txt classes-file.txt" % (sys.argv[0])
+        print("Usage: %s attr-file.txt classes-file.txt" % (sys.argv[0]), file=sys.stderr)
         sys.exit(1)
 
-    print read_ms_schema(attr_file, classes_file)
+    print(read_ms_schema(attr_file, classes_file))