nfs4acls: Introduce a helper variable
[Samba.git] / python / samba / kcc / ldif_import_export.py
blobab7c7a0a1bf850a659c30ffb2ea88c5b8d08bce7
1 # LDIF helper functions for the samba_kcc tool
3 # Copyright (C) Dave Craft 2011
4 # Copyright (C) Andrew Bartlett 2015
6 # Andrew Bartlett's alleged work performed by his underlings Douglas
7 # Bagnall and Garming Sam.
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 3 of the License, or
12 # (at your option) any later version.
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 import os
24 from samba import Ldb, ldb, read_and_sub_file
25 from samba.auth import system_session
26 from samba.samdb import SamDB
27 from samba.common import dsdb_Dn
30 class LdifError(Exception):
31 pass
34 def write_search_result(samdb, f, res):
35 for msg in res:
36 lstr = samdb.write_ldif(msg, ldb.CHANGETYPE_NONE)
37 f.write("%s" % lstr)
40 def ldif_to_samdb(dburl, lp, ldif_file, forced_local_dsa=None):
41 """Routine to import all objects and attributes that are relevent
42 to the KCC algorithms from a previously exported LDIF file.
44 The point of this function is to allow a programmer/debugger to
45 import an LDIF file with non-security relevent information that
46 was previously extracted from a DC database. The LDIF file is used
47 to create a temporary abbreviated database. The KCC algorithm can
48 then run against this abbreviated database for debug or test
49 verification that the topology generated is computationally the
50 same between different OSes and algorithms.
52 :param dburl: path to the temporary abbreviated db to create
53 :param ldif_file: path to the ldif file to import
54 """
55 if os.path.exists(dburl):
56 raise LdifError("Specify a database (%s) that doesn't already exist." %
57 dburl)
59 # Use ["modules:"] as we are attempting to build a sam
60 # database as opposed to start it here.
61 tmpdb = Ldb(url=dburl, session_info=system_session(),
62 lp=lp, options=["modules:"])
64 tmpdb.transaction_start()
65 try:
66 data = read_and_sub_file(ldif_file, None)
67 tmpdb.add_ldif(data, None)
68 if forced_local_dsa:
69 tmpdb.modify_ldif("""dn: @ROOTDSE
70 changetype: modify
71 replace: dsServiceName
72 dsServiceName: CN=NTDS Settings,%s
74 """ % forced_local_dsa)
76 except Exception, estr:
77 tmpdb.transaction_cancel()
78 raise LdifError("Failed to import %s: %s" % (ldif_file, estr))
80 tmpdb.transaction_commit()
82 # We have an abbreviated list of options here because we have built
83 # an abbreviated database. We use the rootdse and extended-dn
84 # modules only during this re-open
85 samdb = SamDB(url=dburl, session_info=system_session(), lp=lp,
86 options=["modules:rootdse,extended_dn_in,"
87 "extended_dn_out_ldb"])
88 return samdb
91 def samdb_to_ldif_file(samdb, dburl, lp, creds, ldif_file):
92 """Routine to extract all objects and attributes that are relevent
93 to the KCC algorithms from a DC database.
95 The point of this function is to allow a programmer/debugger to
96 extract an LDIF file with non-security relevent information from
97 a DC database. The LDIF file can then be used to "import" via
98 the import_ldif() function this file into a temporary abbreviated
99 database. The KCC algorithm can then run against this abbreviated
100 database for debug or test verification that the topology generated
101 is computationally the same between different OSes and algorithms.
103 :param dburl: LDAP database URL to extract info from
104 :param ldif_file: output LDIF file name to create
106 try:
107 samdb = SamDB(url=dburl,
108 session_info=system_session(),
109 credentials=creds, lp=lp)
110 except ldb.LdbError, (enum, estr):
111 raise LdifError("Unable to open sam database (%s) : %s" %
112 (dburl, estr))
114 if os.path.exists(ldif_file):
115 raise LdifError("Specify a file (%s) that doesn't already exist." %
116 ldif_file)
118 try:
119 f = open(ldif_file, "w")
120 except IOError as ioerr:
121 raise LdifError("Unable to open (%s) : %s" % (ldif_file, str(ioerr)))
123 try:
124 # Query Partitions
125 attrs = ["objectClass",
126 "objectGUID",
127 "cn",
128 "whenChanged",
129 "objectSid",
130 "Enabled",
131 "systemFlags",
132 "dnsRoot",
133 "nCName",
134 "msDS-NC-Replica-Locations",
135 "msDS-NC-RO-Replica-Locations"]
137 sstr = "CN=Partitions,%s" % samdb.get_config_basedn()
138 res = samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE,
139 attrs=attrs,
140 expression="(objectClass=crossRef)")
142 # Write partitions output
143 write_search_result(samdb, f, res)
145 # Query cross reference container
146 attrs = ["objectClass",
147 "objectGUID",
148 "cn",
149 "whenChanged",
150 "fSMORoleOwner",
151 "systemFlags",
152 "msDS-Behavior-Version",
153 "msDS-EnabledFeature"]
155 sstr = "CN=Partitions,%s" % samdb.get_config_basedn()
156 res = samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE,
157 attrs=attrs,
158 expression="(objectClass=crossRefContainer)")
160 # Write cross reference container output
161 write_search_result(samdb, f, res)
163 # Query Sites
164 attrs = ["objectClass",
165 "objectGUID",
166 "cn",
167 "whenChanged",
168 "systemFlags"]
170 sstr = "CN=Sites,%s" % samdb.get_config_basedn()
171 sites = samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE,
172 attrs=attrs,
173 expression="(objectClass=site)")
175 # Write sites output
176 write_search_result(samdb, f, sites)
178 # Query NTDS Site Settings
179 for msg in sites:
180 sitestr = str(msg.dn)
182 attrs = ["objectClass",
183 "objectGUID",
184 "cn",
185 "whenChanged",
186 "interSiteTopologyGenerator",
187 "interSiteTopologyFailover",
188 "schedule",
189 "options"]
191 sstr = "CN=NTDS Site Settings,%s" % sitestr
192 res = samdb.search(base=sstr, scope=ldb.SCOPE_BASE,
193 attrs=attrs)
195 # Write Site Settings output
196 write_search_result(samdb, f, res)
198 # Naming context list
199 nclist = []
201 # Query Directory Service Agents
202 for msg in sites:
203 sstr = str(msg.dn)
205 ncattrs = ["hasMasterNCs",
206 "msDS-hasMasterNCs",
207 "hasPartialReplicaNCs",
208 "msDS-HasDomainNCs",
209 "msDS-hasFullReplicaNCs",
210 "msDS-HasInstantiatedNCs"]
211 attrs = ["objectClass",
212 "objectGUID",
213 "cn",
214 "whenChanged",
215 "invocationID",
216 "options",
217 "msDS-isRODC",
218 "msDS-Behavior-Version"]
220 res = samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE,
221 attrs=attrs + ncattrs,
222 expression="(objectClass=nTDSDSA)")
224 # Spin thru all the DSAs looking for NC replicas
225 # and build a list of all possible Naming Contexts
226 # for subsequent retrieval below
227 for msg in res:
228 for k in msg.keys():
229 if k in ncattrs:
230 for value in msg[k]:
231 # Some of these have binary DNs so
232 # use dsdb_Dn to split out relevent parts
233 dsdn = dsdb_Dn(samdb, value)
234 dnstr = str(dsdn.dn)
235 if dnstr not in nclist:
236 nclist.append(dnstr)
238 # Write DSA output
239 write_search_result(samdb, f, res)
241 # Query NTDS Connections
242 for msg in sites:
243 sstr = str(msg.dn)
245 attrs = ["objectClass",
246 "objectGUID",
247 "cn",
248 "whenChanged",
249 "options",
250 "whenCreated",
251 "enabledConnection",
252 "schedule",
253 "transportType",
254 "fromServer",
255 "systemFlags"]
257 res = samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE,
258 attrs=attrs,
259 expression="(objectClass=nTDSConnection)")
260 # Write NTDS Connection output
261 write_search_result(samdb, f, res)
263 # Query Intersite transports
264 attrs = ["objectClass",
265 "objectGUID",
266 "cn",
267 "whenChanged",
268 "options",
269 "name",
270 "bridgeheadServerListBL",
271 "transportAddressAttribute"]
273 sstr = "CN=Inter-Site Transports,CN=Sites,%s" % \
274 samdb.get_config_basedn()
275 res = samdb.search(sstr, scope=ldb.SCOPE_SUBTREE,
276 attrs=attrs,
277 expression="(objectClass=interSiteTransport)")
279 # Write inter-site transport output
280 write_search_result(samdb, f, res)
282 # Query siteLink
283 attrs = ["objectClass",
284 "objectGUID",
285 "cn",
286 "whenChanged",
287 "systemFlags",
288 "options",
289 "schedule",
290 "replInterval",
291 "siteList",
292 "cost"]
294 sstr = "CN=Sites,%s" % \
295 samdb.get_config_basedn()
296 res = samdb.search(sstr, scope=ldb.SCOPE_SUBTREE,
297 attrs=attrs,
298 expression="(objectClass=siteLink)",
299 controls=['extended_dn:0'])
301 # Write siteLink output
302 write_search_result(samdb, f, res)
304 # Query siteLinkBridge
305 attrs = ["objectClass",
306 "objectGUID",
307 "cn",
308 "whenChanged",
309 "siteLinkList"]
311 sstr = "CN=Sites,%s" % samdb.get_config_basedn()
312 res = samdb.search(sstr, scope=ldb.SCOPE_SUBTREE,
313 attrs=attrs,
314 expression="(objectClass=siteLinkBridge)")
316 # Write siteLinkBridge output
317 write_search_result(samdb, f, res)
319 # Query servers containers
320 # Needed for samdb.server_site_name()
321 attrs = ["objectClass",
322 "objectGUID",
323 "cn",
324 "whenChanged",
325 "systemFlags"]
327 sstr = "CN=Sites,%s" % samdb.get_config_basedn()
328 res = samdb.search(sstr, scope=ldb.SCOPE_SUBTREE,
329 attrs=attrs,
330 expression="(objectClass=serversContainer)")
332 # Write servers container output
333 write_search_result(samdb, f, res)
335 # Query servers
336 # Needed because some transport interfaces refer back to
337 # attributes found in the server object. Also needed
338 # so extended-dn will be happy with dsServiceName in rootDSE
339 attrs = ["objectClass",
340 "objectGUID",
341 "cn",
342 "whenChanged",
343 "systemFlags",
344 "dNSHostName",
345 "mailAddress"]
347 sstr = "CN=Sites,%s" % samdb.get_config_basedn()
348 res = samdb.search(sstr, scope=ldb.SCOPE_SUBTREE,
349 attrs=attrs,
350 expression="(objectClass=server)")
352 # Write server output
353 write_search_result(samdb, f, res)
355 # Query Naming Context replicas
356 attrs = ["objectClass",
357 "objectGUID",
358 "cn",
359 "whenChanged",
360 "objectSid",
361 "fSMORoleOwner",
362 "msDS-Behavior-Version",
363 "repsFrom",
364 "repsTo"]
366 for sstr in nclist:
367 res = samdb.search(sstr, scope=ldb.SCOPE_BASE,
368 attrs=attrs)
370 # Write naming context output
371 write_search_result(samdb, f, res)
373 # Query rootDSE replicas
374 attrs = ["objectClass",
375 "objectGUID",
376 "cn",
377 "whenChanged",
378 "rootDomainNamingContext",
379 "configurationNamingContext",
380 "schemaNamingContext",
381 "defaultNamingContext",
382 "dsServiceName"]
384 sstr = ""
385 res = samdb.search(sstr, scope=ldb.SCOPE_BASE,
386 attrs=attrs)
388 # Record the rootDSE object as a dn as it
389 # would appear in the base ldb file. We have
390 # to save it this way because we are going to
391 # be importing as an abbreviated database.
392 res[0].dn = ldb.Dn(samdb, "@ROOTDSE")
394 # Write rootdse output
395 write_search_result(samdb, f, res)
397 except ldb.LdbError, (enum, estr):
398 raise LdifError("Error processing (%s) : %s" % (sstr, estr))
400 f.close()