Add minschema like tool to extract and dump the full schema from AD
[kai/samba.git] / source4 / scripting / bin / fullschema
1 #!/usr/bin/python
2
3 #  work out the minimal schema for a set of objectclasses 
4 #
5
6 import base64
7 import optparse
8 import os
9 import sys
10
11 # Find right directory when running from source tree
12 sys.path.insert(0, "bin/python")
13
14 import samba
15 from samba import getopt as options, Ldb
16 from ldb import SCOPE_SUBTREE, SCOPE_BASE, LdbError
17 import sys
18
19 parser = optparse.OptionParser("fullschema <URL>")
20 sambaopts = options.SambaOptions(parser)
21 parser.add_option_group(sambaopts)
22 credopts = options.CredentialsOptions(parser)
23 parser.add_option_group(credopts)
24 parser.add_option_group(options.VersionOptions(parser))
25 parser.add_option("--verbose", help="Be verbose", action="store_true")
26 parser.add_option("--dump-classes", action="store_true")
27 parser.add_option("--dump-attributes", action="store_true")
28
29 opts, args = parser.parse_args()
30 opts.dump_all = True
31
32 if opts.dump_classes:
33     opts.dump_all = False
34 if opts.dump_attributes:
35     opts.dump_all = False
36 if opts.dump_all:
37     opts.dump_classes = True
38     opts.dump_attributes = True
39
40 if len(args) != 1:
41     parser.print_usage()
42     sys.exit(1)
43
44 url = args[0]
45
46 lp_ctx = sambaopts.get_loadparm()
47
48 creds = credopts.get_credentials(lp_ctx)
49 ldb = Ldb(url, credentials=creds, lp=lp_ctx, options=["modules:paged_searches"])
50
51 objectclasses = {}
52 attributes = {}
53
54 # the attributes we need for objectclasses
55 class_attrs = ["objectClass", 
56                "cn",
57                "subClassOf", 
58                "governsID", 
59                "possSuperiors", 
60                "possibleInferiors",
61                "mayContain",
62                "mustContain",
63                "auxiliaryClass",
64                "rDNAttID",
65                "showInAdvancedViewOnly",
66                "adminDisplayName",
67                "adminDescription",
68                "objectClassCategory",
69                "lDAPDisplayName",
70                "schemaIDGUID",
71                "systemOnly",
72                "systemPossSuperiors",
73                "systemMayContain",
74                "systemMustContain",
75                "systemAuxiliaryClass",
76                "defaultSecurityDescriptor",
77                "systemFlags",
78                "defaultHidingValue",
79                "defaultObjectCategory", 
80                
81                # this attributes are not used by w2k3
82                "schemaFlagsEx",
83                "msDs-IntId",
84                "msDs-Schema-Extensions",
85                "classDisplayName",
86                "isDefunct"]
87
88 attrib_attrs = ["objectClass",
89                 "cn",
90                 "attributeID", 
91                 "attributeSyntax",
92                 "isSingleValued",
93                 "rangeLower",
94                 "rangeUpper",
95                 "mAPIID",
96                 "linkID",
97                 "showInAdvancedViewOnly",
98                 "adminDisplayName",
99                 "oMObjectClass",
100                 "adminDescription",
101                 "oMSyntax", 
102                 "searchFlags",
103                 "extendedCharsAllowed",
104                 "lDAPDisplayName",
105                 "schemaIDGUID",
106                 "attributeSecurityGUID",
107                 "systemOnly",
108                 "systemFlags",
109                 "isMemberOfPartialAttributeSet",
110                 
111                 # this attributes are not used by w2k3
112                 "schemaFlagsEx",
113                 "msDs-IntId",
114                 "msDs-Schema-Extensions",
115                 "classDisplayName",
116                 "isEphemeral",
117                 "isDefunct"]
118
119 #
120 #  notes:
121 #
122 #  objectClassCategory 
123 #      1: structural
124 #      2: abstract
125 #      3: auxiliary
126
127 class Objectclass(dict):
128
129     def __init__(self, ldb, name):
130         """create an objectclass object"""
131         self.name = name
132
133
134 class Attribute(dict):
135
136     def __init__(self, ldb, name):
137         """create an attribute object"""
138         self.name = name
139         self["cn"] = get_object_cn(ldb, name)
140
141
142
143 def fix_dn(dn):
144     """fix a string DN to use ${SCHEMADN}"""
145     return dn.replace(rootDse["schemaNamingContext"][0], "${SCHEMADN}")
146
147
148 def write_ldif_one(o, attrs):
149     """dump an object as ldif"""
150     print "dn: CN=%s,${SCHEMADN}" % o["cn"]
151     for a in attrs:
152         if not o.has_key(a):
153             continue
154         # special case for oMObjectClass, which is a binary object
155         v = o[a]
156         for j in v:
157             value = fix_dn(j)
158             if a != "cn":
159                 if a == "oMObjectClass":
160                     print "%s:: %s" % (a, base64.b64encode(value))
161                 elif a.endswith("GUID"):
162                     print "%s: %s" % (a, ldb.schema_format_value(a, value))
163                 else:
164                     print "%s: %s" % (a, value)
165     print ""
166
167
168 # get the rootDSE
169 res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["schemaNamingContext"])
170 rootDse = res[0]
171
172 if opts.dump_attributes:
173     res = ldb.search(expression="objectClass=attributeSchema", 
174                      base=rootDse["schemaNamingContext"][0], scope=SCOPE_SUBTREE,attrs=attrib_attrs)
175     
176     for msg in res:
177         o = Objectclass(ldb, msg["ldapDisplayName"])
178         for a in msg:
179             o[a] = msg[a]
180         write_ldif_one(o, attrib_attrs)
181             
182 if opts.dump_classes:
183     res = ldb.search(expression="objectClass=classSchema", 
184                      base=rootDse["schemaNamingContext"][0], scope=SCOPE_SUBTREE,attrs=class_attrs)
185
186     for msg in res:
187         o = Objectclass(ldb, msg["ldapDisplayName"])
188         for a in msg:
189             o[a] = msg[a]
190         write_ldif_one(o, class_attrs)
191