s4:fullschema Use server-side sort to make the output deterministic
[Samba/bb.git] / source4 / scripting / bin / fullschema
blob41c45f30c8c07a780b5d37483ff99e992070dbd9
1 #!/usr/bin/python
2 #
3 # work out the minimal schema for a set of objectclasses
6 import base64
7 import optparse
8 import os
9 import sys
11 # Find right directory when running from source tree
12 sys.path.insert(0, "bin/python")
14 import samba
15 from samba import getopt as options, Ldb
16 from ldb import SCOPE_SUBTREE, SCOPE_BASE, LdbError
17 import sys
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("--dump-classes", action="store_true")
26 parser.add_option("--dump-attributes", action="store_true")
28 opts, args = parser.parse_args()
29 opts.dump_all = True
31 if opts.dump_classes:
32 opts.dump_all = False
33 if opts.dump_attributes:
34 opts.dump_all = False
35 if opts.dump_all:
36 opts.dump_classes = True
37 opts.dump_attributes = True
39 if len(args) != 1:
40 parser.print_usage()
41 sys.exit(1)
43 url = args[0]
45 lp_ctx = sambaopts.get_loadparm()
47 creds = credopts.get_credentials(lp_ctx)
48 ldb = Ldb(url, credentials=creds, lp=lp_ctx, options=["modules:paged_searches"])
50 # the attributes we need for objectclasses
51 class_attrs = ["objectClass",
52 "cn",
53 "subClassOf",
54 "governsID",
55 "possSuperiors",
56 "possibleInferiors",
57 "mayContain",
58 "mustContain",
59 "auxiliaryClass",
60 "rDNAttID",
61 "adminDisplayName",
62 "adminDescription",
63 "objectClassCategory",
64 "lDAPDisplayName",
65 "schemaIDGUID",
66 "systemOnly",
67 "systemPossSuperiors",
68 "systemMayContain",
69 "systemMustContain",
70 "systemAuxiliaryClass",
71 "defaultSecurityDescriptor",
72 "systemFlags",
73 "defaultHidingValue",
74 "defaultObjectCategory",
76 # this attributes are not used by w2k3
77 "schemaFlagsEx",
78 "msDs-IntId",
79 "msDs-Schema-Extensions",
80 "classDisplayName",
81 "isDefunct"]
83 attrib_attrs = ["objectClass",
84 "cn",
85 "attributeID",
86 "attributeSyntax",
87 "isSingleValued",
88 "rangeLower",
89 "rangeUpper",
90 "mAPIID",
91 "linkID",
92 "adminDisplayName",
93 "oMObjectClass",
94 "adminDescription",
95 "oMSyntax",
96 "searchFlags",
97 "extendedCharsAllowed",
98 "lDAPDisplayName",
99 "schemaIDGUID",
100 "attributeSecurityGUID",
101 "systemOnly",
102 "systemFlags",
103 "isMemberOfPartialAttributeSet",
105 # this attributes are not used by w2k3
106 "schemaFlagsEx",
107 "msDs-IntId",
108 "msDs-Schema-Extensions",
109 "classDisplayName",
110 "isEphemeral",
111 "isDefunct"]
113 class Objectclass(dict):
115 def __init__(self, ldb, name):
116 """create an objectclass object"""
117 self.name = name
120 class Attribute(dict):
122 def __init__(self, ldb, name):
123 """create an attribute object"""
124 self.name = name
125 self["cn"] = get_object_cn(ldb, name)
129 def fix_dn(dn):
130 """fix a string DN to use ${SCHEMADN}"""
131 return dn.replace(rootDse["schemaNamingContext"][0], "${SCHEMADN}")
134 def write_ldif_one(o, attrs):
135 """dump an object as ldif"""
136 print "dn: CN=%s,${SCHEMADN}" % o["cn"]
137 for a in attrs:
138 if not o.has_key(a):
139 continue
140 # special case for oMObjectClass, which is a binary object
141 v = o[a]
142 for j in v:
143 value = fix_dn(j)
144 if a != "cn":
145 if a == "oMObjectClass":
146 print "%s:: %s" % (a, base64.b64encode(value))
147 elif a.endswith("GUID"):
148 print "%s: %s" % (a, ldb.schema_format_value(a, value))
149 else:
150 print "%s: %s" % (a, value)
151 print ""
154 # get the rootDSE
155 res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["schemaNamingContext"])
156 rootDse = res[0]
158 if opts.dump_attributes:
159 res = ldb.search(expression="objectClass=attributeSchema",
160 base=rootDse["schemaNamingContext"][0], scope=SCOPE_SUBTREE,attrs=attrib_attrs,
161 controls=["server_sort:1:0:cn"])
163 for msg in res:
164 o = Objectclass(ldb, msg["ldapDisplayName"])
165 for a in msg:
166 o[a] = msg[a]
167 write_ldif_one(o, attrib_attrs)
169 if opts.dump_classes:
170 res = ldb.search(expression="objectClass=classSchema",
171 base=rootDse["schemaNamingContext"][0], scope=SCOPE_SUBTREE,attrs=class_attrs,
172 controls=["server_sort:1:0:cn"])
174 for msg in res:
175 o = Objectclass(ldb, msg["ldapDisplayName"])
176 for a in msg:
177 o[a] = msg[a]
178 write_ldif_one(o, class_attrs)