mirror of
https://github.com/samba-team/samba.git
synced 2025-12-16 00:23:52 +03:00
python: pep257: docstring should use double quotes
Signed-off-by: Rob van der Linde <rob@catalyst.net.nz> Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
committed by
Andrew Bartlett
parent
ff52e34288
commit
ddba4a06bb
@@ -64,7 +64,7 @@ def confirm(msg, forced=False, allow_all=False):
|
|||||||
|
|
||||||
|
|
||||||
def normalise_int32(ivalue):
|
def normalise_int32(ivalue):
|
||||||
'''normalise a ldap integer to signed 32 bit'''
|
"""normalise a ldap integer to signed 32 bit"""
|
||||||
if int(ivalue) & 0x80000000 and int(ivalue) > 0:
|
if int(ivalue) & 0x80000000 and int(ivalue) > 0:
|
||||||
return str(int(ivalue) - 0x100000000)
|
return str(int(ivalue) - 0x100000000)
|
||||||
return str(ivalue)
|
return str(ivalue)
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ class dbcheck(object):
|
|||||||
|
|
||||||
def check_database(self, DN=None, scope=ldb.SCOPE_SUBTREE, controls=None,
|
def check_database(self, DN=None, scope=ldb.SCOPE_SUBTREE, controls=None,
|
||||||
attrs=None):
|
attrs=None):
|
||||||
'''perform a database check, returning the number of errors found'''
|
"""perform a database check, returning the number of errors found"""
|
||||||
res = self.samdb.search(base=DN, scope=scope, attrs=['dn'], controls=controls)
|
res = self.samdb.search(base=DN, scope=scope, attrs=['dn'], controls=controls)
|
||||||
self.report('Checking %u objects' % len(res))
|
self.report('Checking %u objects' % len(res))
|
||||||
error_count = 0
|
error_count = 0
|
||||||
@@ -390,7 +390,7 @@ systemFlags: -1946157056%s""" % (dn, sec_desc_b64, guid_suffix),
|
|||||||
return error_count
|
return error_count
|
||||||
|
|
||||||
def report(self, msg):
|
def report(self, msg):
|
||||||
'''print a message unless quiet is set'''
|
"""print a message unless quiet is set"""
|
||||||
if self.quiet:
|
if self.quiet:
|
||||||
return
|
return
|
||||||
if self.colour:
|
if self.colour:
|
||||||
@@ -410,7 +410,7 @@ systemFlags: -1946157056%s""" % (dn, sec_desc_b64, guid_suffix),
|
|||||||
print(msg)
|
print(msg)
|
||||||
|
|
||||||
def confirm(self, msg, allow_all=False, forced=False):
|
def confirm(self, msg, allow_all=False, forced=False):
|
||||||
'''confirm a change'''
|
"""confirm a change"""
|
||||||
if not self.fix:
|
if not self.fix:
|
||||||
return False
|
return False
|
||||||
if self.quiet:
|
if self.quiet:
|
||||||
@@ -422,7 +422,7 @@ systemFlags: -1946157056%s""" % (dn, sec_desc_b64, guid_suffix),
|
|||||||
################################################################
|
################################################################
|
||||||
# a local confirm function with support for 'all'
|
# a local confirm function with support for 'all'
|
||||||
def confirm_all(self, msg, all_attr):
|
def confirm_all(self, msg, all_attr):
|
||||||
'''confirm a change with support for "all" '''
|
"""confirm a change with support for "all" """
|
||||||
if not self.fix:
|
if not self.fix:
|
||||||
return False
|
return False
|
||||||
if getattr(self, all_attr) == 'NONE':
|
if getattr(self, all_attr) == 'NONE':
|
||||||
@@ -443,7 +443,7 @@ systemFlags: -1946157056%s""" % (dn, sec_desc_b64, guid_suffix),
|
|||||||
return c
|
return c
|
||||||
|
|
||||||
def do_delete(self, dn, controls, msg):
|
def do_delete(self, dn, controls, msg):
|
||||||
'''delete dn with optional verbose output'''
|
"""delete dn with optional verbose output"""
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
self.report("delete DN %s" % dn)
|
self.report("delete DN %s" % dn)
|
||||||
try:
|
try:
|
||||||
@@ -457,7 +457,7 @@ systemFlags: -1946157056%s""" % (dn, sec_desc_b64, guid_suffix),
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def do_modify(self, m, controls, msg, validate=True):
|
def do_modify(self, m, controls, msg, validate=True):
|
||||||
'''perform a modify with optional verbose output'''
|
"""perform a modify with optional verbose output"""
|
||||||
controls = controls + ["local_oid:%s:0" % dsdb.DSDB_CONTROL_DBCHECK]
|
controls = controls + ["local_oid:%s:0" % dsdb.DSDB_CONTROL_DBCHECK]
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
self.report(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY))
|
self.report(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY))
|
||||||
@@ -472,7 +472,7 @@ systemFlags: -1946157056%s""" % (dn, sec_desc_b64, guid_suffix),
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def do_rename(self, from_dn, to_rdn, to_base, controls, msg):
|
def do_rename(self, from_dn, to_rdn, to_base, controls, msg):
|
||||||
'''perform a rename with optional verbose output'''
|
"""perform a rename with optional verbose output"""
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
self.report("""dn: %s
|
self.report("""dn: %s
|
||||||
changeType: modrdn
|
changeType: modrdn
|
||||||
@@ -502,7 +502,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
return linkID, revname
|
return linkID, revname
|
||||||
|
|
||||||
def err_empty_attribute(self, dn, attrname):
|
def err_empty_attribute(self, dn, attrname):
|
||||||
'''fix empty attributes'''
|
"""fix empty attributes"""
|
||||||
self.report("ERROR: Empty attribute %s in %s" % (attrname, dn))
|
self.report("ERROR: Empty attribute %s in %s" % (attrname, dn))
|
||||||
if not self.confirm_all('Remove empty attribute %s from %s?' % (attrname, dn), 'remove_all_empty_attributes'):
|
if not self.confirm_all('Remove empty attribute %s from %s?' % (attrname, dn), 'remove_all_empty_attributes'):
|
||||||
self.report("Not fixing empty attribute %s" % attrname)
|
self.report("Not fixing empty attribute %s" % attrname)
|
||||||
@@ -516,7 +516,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
self.report("Removed empty attribute %s" % attrname)
|
self.report("Removed empty attribute %s" % attrname)
|
||||||
|
|
||||||
def err_normalise_mismatch(self, dn, attrname, values):
|
def err_normalise_mismatch(self, dn, attrname, values):
|
||||||
'''fix attribute normalisation errors, without altering sort order'''
|
"""fix attribute normalisation errors, without altering sort order"""
|
||||||
self.report("ERROR: Normalisation error for attribute %s in %s" % (attrname, dn))
|
self.report("ERROR: Normalisation error for attribute %s in %s" % (attrname, dn))
|
||||||
mod_list = []
|
mod_list = []
|
||||||
for val in values:
|
for val in values:
|
||||||
@@ -547,7 +547,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
self.report("Normalised attribute %s" % attrname)
|
self.report("Normalised attribute %s" % attrname)
|
||||||
|
|
||||||
def err_normalise_mismatch_replace(self, dn, attrname, values):
|
def err_normalise_mismatch_replace(self, dn, attrname, values):
|
||||||
'''fix attribute normalisation and/or sort errors'''
|
"""fix attribute normalisation and/or sort errors"""
|
||||||
normalised = self.samdb.dsdb_normalise_attributes(self.samdb_schema, attrname, values)
|
normalised = self.samdb.dsdb_normalise_attributes(self.samdb_schema, attrname, values)
|
||||||
if list(normalised) == values:
|
if list(normalised) == values:
|
||||||
# how we got here is a mystery.
|
# how we got here is a mystery.
|
||||||
@@ -568,7 +568,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
self.report("Normalised attribute %s" % attrname)
|
self.report("Normalised attribute %s" % attrname)
|
||||||
|
|
||||||
def err_duplicate_values(self, dn, attrname, dup_values, values):
|
def err_duplicate_values(self, dn, attrname, dup_values, values):
|
||||||
'''fix duplicate attribute values'''
|
"""fix duplicate attribute values"""
|
||||||
self.report("ERROR: Duplicate values for attribute '%s' in '%s'" % (attrname, dn))
|
self.report("ERROR: Duplicate values for attribute '%s' in '%s'" % (attrname, dn))
|
||||||
self.report("Values contain a duplicate: [%s]/[%s]!" %
|
self.report("Values contain a duplicate: [%s]/[%s]!" %
|
||||||
(dump_attr_values(dup_values), dump_attr_values(values)))
|
(dump_attr_values(dup_values), dump_attr_values(values)))
|
||||||
@@ -586,7 +586,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
self.report("Removed duplicate value on attribute %s" % attrname)
|
self.report("Removed duplicate value on attribute %s" % attrname)
|
||||||
|
|
||||||
def is_deleted_objects_dn(self, dsdb_dn):
|
def is_deleted_objects_dn(self, dsdb_dn):
|
||||||
'''see if a dsdb_Dn is the special Deleted Objects DN'''
|
"""see if a dsdb_Dn is the special Deleted Objects DN"""
|
||||||
return dsdb_dn.prefix == "B:32:%s:" % dsdb.DS_GUID_DELETED_OBJECTS_CONTAINER
|
return dsdb_dn.prefix == "B:32:%s:" % dsdb.DS_GUID_DELETED_OBJECTS_CONTAINER
|
||||||
|
|
||||||
def err_missing_objectclass(self, dn):
|
def err_missing_objectclass(self, dn):
|
||||||
@@ -823,7 +823,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
self.report("Fixed missing DN SID on attribute %s" % (attrname))
|
self.report("Fixed missing DN SID on attribute %s" % (attrname))
|
||||||
|
|
||||||
def err_unknown_attribute(self, obj, attrname):
|
def err_unknown_attribute(self, obj, attrname):
|
||||||
'''handle an unknown attribute error'''
|
"""handle an unknown attribute error"""
|
||||||
self.report("ERROR: unknown attribute '%s' in %s" % (attrname, obj.dn))
|
self.report("ERROR: unknown attribute '%s' in %s" % (attrname, obj.dn))
|
||||||
if not self.confirm_all('Remove unknown attribute %s' % attrname, 'remove_all_unknown_attributes'):
|
if not self.confirm_all('Remove unknown attribute %s' % attrname, 'remove_all_unknown_attributes'):
|
||||||
self.report("Not removing %s" % attrname)
|
self.report("Not removing %s" % attrname)
|
||||||
@@ -836,7 +836,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
self.report("Removed unknown attribute %s" % (attrname))
|
self.report("Removed unknown attribute %s" % (attrname))
|
||||||
|
|
||||||
def err_undead_linked_attribute(self, obj, attrname, val):
|
def err_undead_linked_attribute(self, obj, attrname, val):
|
||||||
'''handle a link that should not be there on a deleted object'''
|
"""handle a link that should not be there on a deleted object"""
|
||||||
self.report("ERROR: linked attribute '%s' to '%s' is present on "
|
self.report("ERROR: linked attribute '%s' to '%s' is present on "
|
||||||
"deleted object %s" % (attrname, val, obj.dn))
|
"deleted object %s" % (attrname, val, obj.dn))
|
||||||
if not self.confirm_all('Remove linked attribute %s' % attrname, 'fix_undead_linked_attributes'):
|
if not self.confirm_all('Remove linked attribute %s' % attrname, 'fix_undead_linked_attributes'):
|
||||||
@@ -852,7 +852,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
self.report("Fixed undead forward link %s" % (attrname))
|
self.report("Fixed undead forward link %s" % (attrname))
|
||||||
|
|
||||||
def err_missing_backlink(self, obj, attrname, val, backlink_name, target_dn):
|
def err_missing_backlink(self, obj, attrname, val, backlink_name, target_dn):
|
||||||
'''handle a missing backlink value'''
|
"""handle a missing backlink value"""
|
||||||
self.report("ERROR: missing backlink attribute '%s' in %s for link %s in %s" % (backlink_name, target_dn, attrname, obj.dn))
|
self.report("ERROR: missing backlink attribute '%s' in %s for link %s in %s" % (backlink_name, target_dn, attrname, obj.dn))
|
||||||
if not self.confirm_all('Fix missing backlink %s' % backlink_name, 'fix_all_missing_backlinks'):
|
if not self.confirm_all('Fix missing backlink %s' % backlink_name, 'fix_all_missing_backlinks'):
|
||||||
self.report("Not fixing missing backlink %s" % backlink_name)
|
self.report("Not fixing missing backlink %s" % backlink_name)
|
||||||
@@ -865,7 +865,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
self.report("Fixed missing backlink %s" % (backlink_name))
|
self.report("Fixed missing backlink %s" % (backlink_name))
|
||||||
|
|
||||||
def err_incorrect_rmd_flags(self, obj, attrname, revealed_dn):
|
def err_incorrect_rmd_flags(self, obj, attrname, revealed_dn):
|
||||||
'''handle a incorrect RMD_FLAGS value'''
|
"""handle a incorrect RMD_FLAGS value"""
|
||||||
rmd_flags = int(revealed_dn.dn.get_extended_component("RMD_FLAGS"))
|
rmd_flags = int(revealed_dn.dn.get_extended_component("RMD_FLAGS"))
|
||||||
self.report("ERROR: incorrect RMD_FLAGS value %u for attribute '%s' in %s for link %s" % (rmd_flags, attrname, obj.dn, revealed_dn.dn.extended_str()))
|
self.report("ERROR: incorrect RMD_FLAGS value %u for attribute '%s' in %s for link %s" % (rmd_flags, attrname, obj.dn, revealed_dn.dn.extended_str()))
|
||||||
if not self.confirm_all('Fix incorrect RMD_FLAGS %u' % rmd_flags, 'fix_rmd_flags'):
|
if not self.confirm_all('Fix incorrect RMD_FLAGS %u' % rmd_flags, 'fix_rmd_flags'):
|
||||||
@@ -881,7 +881,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
def err_orphaned_backlink(self, obj_dn, backlink_attr, backlink_val,
|
def err_orphaned_backlink(self, obj_dn, backlink_attr, backlink_val,
|
||||||
target_dn, forward_attr, forward_syntax,
|
target_dn, forward_attr, forward_syntax,
|
||||||
check_duplicates=True):
|
check_duplicates=True):
|
||||||
'''handle a orphaned backlink value'''
|
"""handle a orphaned backlink value"""
|
||||||
if check_duplicates is True and self.has_duplicate_links(target_dn, forward_attr, forward_syntax):
|
if check_duplicates is True and self.has_duplicate_links(target_dn, forward_attr, forward_syntax):
|
||||||
self.report("WARNING: Keep orphaned backlink attribute " +
|
self.report("WARNING: Keep orphaned backlink attribute " +
|
||||||
"'%s' in '%s' for link '%s' in '%s'" % (
|
"'%s' in '%s' for link '%s' in '%s'" % (
|
||||||
@@ -899,7 +899,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
self.report("Fixed orphaned backlink %s" % (backlink_attr))
|
self.report("Fixed orphaned backlink %s" % (backlink_attr))
|
||||||
|
|
||||||
def err_recover_forward_links(self, obj, forward_attr, forward_vals):
|
def err_recover_forward_links(self, obj, forward_attr, forward_vals):
|
||||||
'''handle a duplicate links value'''
|
"""handle a duplicate links value"""
|
||||||
|
|
||||||
self.report("RECHECK: 'Missing/Duplicate/Correct link' lines above for attribute '%s' in '%s'" % (forward_attr, obj.dn))
|
self.report("RECHECK: 'Missing/Duplicate/Correct link' lines above for attribute '%s' in '%s'" % (forward_attr, obj.dn))
|
||||||
|
|
||||||
@@ -918,7 +918,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
self.duplicate_link_cache[duplicate_cache_key] = False
|
self.duplicate_link_cache[duplicate_cache_key] = False
|
||||||
|
|
||||||
def err_no_fsmoRoleOwner(self, obj):
|
def err_no_fsmoRoleOwner(self, obj):
|
||||||
'''handle a missing fSMORoleOwner'''
|
"""handle a missing fSMORoleOwner"""
|
||||||
self.report("ERROR: fSMORoleOwner not found for role %s" % (obj.dn))
|
self.report("ERROR: fSMORoleOwner not found for role %s" % (obj.dn))
|
||||||
res = self.samdb.search("",
|
res = self.samdb.search("",
|
||||||
scope=ldb.SCOPE_BASE, attrs=["dsServiceName"])
|
scope=ldb.SCOPE_BASE, attrs=["dsServiceName"])
|
||||||
@@ -935,7 +935,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
self.report("Seized role %s onto current DC by adding fSMORoleOwner=%s" % (obj.dn, serviceName))
|
self.report("Seized role %s onto current DC by adding fSMORoleOwner=%s" % (obj.dn, serviceName))
|
||||||
|
|
||||||
def err_missing_parent(self, obj):
|
def err_missing_parent(self, obj):
|
||||||
'''handle a missing parent'''
|
"""handle a missing parent"""
|
||||||
self.report("ERROR: parent object not found for %s" % (obj.dn))
|
self.report("ERROR: parent object not found for %s" % (obj.dn))
|
||||||
if not self.confirm_all('Move object %s into LostAndFound?' % (obj.dn), 'move_to_lost_and_found'):
|
if not self.confirm_all('Move object %s into LostAndFound?' % (obj.dn), 'move_to_lost_and_found'):
|
||||||
self.report('Not moving object %s into LostAndFound' % (obj.dn))
|
self.report('Not moving object %s into LostAndFound' % (obj.dn))
|
||||||
@@ -970,7 +970,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
self.samdb.transaction_cancel()
|
self.samdb.transaction_cancel()
|
||||||
|
|
||||||
def err_wrong_dn(self, obj, new_dn, rdn_attr, rdn_val, name_val, controls):
|
def err_wrong_dn(self, obj, new_dn, rdn_attr, rdn_val, name_val, controls):
|
||||||
'''handle a wrong dn'''
|
"""handle a wrong dn"""
|
||||||
|
|
||||||
new_rdn = ldb.Dn(self.samdb, str(new_dn))
|
new_rdn = ldb.Dn(self.samdb, str(new_dn))
|
||||||
new_rdn.remove_base_components(len(new_rdn) - 1)
|
new_rdn.remove_base_components(len(new_rdn) - 1)
|
||||||
@@ -991,7 +991,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
self.report("Renamed %s into %s" % (obj.dn, new_dn))
|
self.report("Renamed %s into %s" % (obj.dn, new_dn))
|
||||||
|
|
||||||
def err_wrong_instancetype(self, obj, calculated_instancetype):
|
def err_wrong_instancetype(self, obj, calculated_instancetype):
|
||||||
'''handle a wrong instanceType'''
|
"""handle a wrong instanceType"""
|
||||||
self.report("ERROR: wrong instanceType %s on %s, should be %d" % (obj["instanceType"], obj.dn, calculated_instancetype))
|
self.report("ERROR: wrong instanceType %s on %s, should be %d" % (obj["instanceType"], obj.dn, calculated_instancetype))
|
||||||
if not self.confirm_all('Change instanceType from %s to %d on %s?' % (obj["instanceType"], calculated_instancetype, obj.dn), 'fix_instancetype'):
|
if not self.confirm_all('Change instanceType from %s to %d on %s?' % (obj["instanceType"], calculated_instancetype, obj.dn), 'fix_instancetype'):
|
||||||
self.report('Not changing instanceType from %s to %d on %s' % (obj["instanceType"], calculated_instancetype, obj.dn))
|
self.report('Not changing instanceType from %s to %d on %s' % (obj["instanceType"], calculated_instancetype, obj.dn))
|
||||||
@@ -1009,7 +1009,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
self.report("ERROR: incorrect userParameters value on object %s. If you have another working DC that does not give this warning, please run 'samba-tool drs replicate --full-sync --local <destinationDC> <sourceDC> %s'" % (obj.dn, self.samdb.get_nc_root(obj.dn)))
|
self.report("ERROR: incorrect userParameters value on object %s. If you have another working DC that does not give this warning, please run 'samba-tool drs replicate --full-sync --local <destinationDC> <sourceDC> %s'" % (obj.dn, self.samdb.get_nc_root(obj.dn)))
|
||||||
|
|
||||||
def err_base64_userParameters(self, obj, attrname, value):
|
def err_base64_userParameters(self, obj, attrname, value):
|
||||||
'''handle a userParameters that is wrongly base64 encoded'''
|
"""handle a userParameters that is wrongly base64 encoded"""
|
||||||
self.report("ERROR: wrongly formatted userParameters %s on %s, should not be base64-encoded" % (value, obj.dn))
|
self.report("ERROR: wrongly formatted userParameters %s on %s, should not be base64-encoded" % (value, obj.dn))
|
||||||
if not self.confirm_all('Convert userParameters from base64 encoding on %s?' % (obj.dn), 'fix_base64_userparameters'):
|
if not self.confirm_all('Convert userParameters from base64 encoding on %s?' % (obj.dn), 'fix_base64_userparameters'):
|
||||||
self.report('Not changing userParameters from base64 encoding on %s' % (obj.dn))
|
self.report('Not changing userParameters from base64 encoding on %s' % (obj.dn))
|
||||||
@@ -1023,7 +1023,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
self.report("Corrected base64-encoded userParameters on %s by converting from base64" % (obj.dn))
|
self.report("Corrected base64-encoded userParameters on %s by converting from base64" % (obj.dn))
|
||||||
|
|
||||||
def err_utf8_userParameters(self, obj, attrname, value):
|
def err_utf8_userParameters(self, obj, attrname, value):
|
||||||
'''handle a userParameters that is wrongly utf-8 encoded'''
|
"""handle a userParameters that is wrongly utf-8 encoded"""
|
||||||
self.report("ERROR: wrongly formatted userParameters on %s, "
|
self.report("ERROR: wrongly formatted userParameters on %s, "
|
||||||
"should not be pseudo-UTF8 encoded" % (obj.dn))
|
"should not be pseudo-UTF8 encoded" % (obj.dn))
|
||||||
if not self.confirm_all('Convert userParameters from UTF8 encoding on %s?' % (obj.dn), 'fix_utf8_userparameters'):
|
if not self.confirm_all('Convert userParameters from UTF8 encoding on %s?' % (obj.dn), 'fix_utf8_userparameters'):
|
||||||
@@ -1039,7 +1039,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
self.report("Corrected psudo-UTF8 encoded userParameters on %s by converting from UTF8" % (obj.dn))
|
self.report("Corrected psudo-UTF8 encoded userParameters on %s by converting from UTF8" % (obj.dn))
|
||||||
|
|
||||||
def err_doubled_userParameters(self, obj, attrname, value):
|
def err_doubled_userParameters(self, obj, attrname, value):
|
||||||
'''handle a userParameters that has been utf-16 encoded twice'''
|
"""handle a userParameters that has been utf-16 encoded twice"""
|
||||||
self.report("ERROR: wrongly formatted userParameters on %s, should not be double UTF16 encoded" % (obj.dn))
|
self.report("ERROR: wrongly formatted userParameters on %s, should not be double UTF16 encoded" % (obj.dn))
|
||||||
if not self.confirm_all('Convert userParameters from doubled UTF-16 encoding on %s?' % (obj.dn), 'fix_doubled_userparameters'):
|
if not self.confirm_all('Convert userParameters from doubled UTF-16 encoding on %s?' % (obj.dn), 'fix_doubled_userparameters'):
|
||||||
self.report('Not changing userParameters from doubled UTF-16 encoding on %s' % (obj.dn))
|
self.report('Not changing userParameters from doubled UTF-16 encoding on %s' % (obj.dn))
|
||||||
@@ -1069,7 +1069,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
self.report("ERROR: incorrect userParameters value on object %s (odd length). If you have another working DC that does not give this warning, please run 'samba-tool drs replicate --full-sync --local <destinationDC> <sourceDC> %s'" % (obj.dn, self.samdb.get_nc_root(obj.dn)))
|
self.report("ERROR: incorrect userParameters value on object %s (odd length). If you have another working DC that does not give this warning, please run 'samba-tool drs replicate --full-sync --local <destinationDC> <sourceDC> %s'" % (obj.dn, self.samdb.get_nc_root(obj.dn)))
|
||||||
|
|
||||||
def find_revealed_link(self, dn, attrname, guid):
|
def find_revealed_link(self, dn, attrname, guid):
|
||||||
'''return a revealed link in an object'''
|
"""return a revealed link in an object"""
|
||||||
res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, attrs=[attrname],
|
res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, attrs=[attrname],
|
||||||
controls=["show_deleted:0", "extended_dn:0", "reveal_internals:0"])
|
controls=["show_deleted:0", "extended_dn:0", "reveal_internals:0"])
|
||||||
syntax_oid = self.samdb_schema.get_syntax_oid_from_lDAPDisplayName(attrname)
|
syntax_oid = self.samdb_schema.get_syntax_oid_from_lDAPDisplayName(attrname)
|
||||||
@@ -1081,7 +1081,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def check_duplicate_links(self, obj, forward_attr, forward_syntax, forward_linkID, backlink_attr):
|
def check_duplicate_links(self, obj, forward_attr, forward_syntax, forward_linkID, backlink_attr):
|
||||||
'''check a linked values for duplicate forward links'''
|
"""check a linked values for duplicate forward links"""
|
||||||
error_count = 0
|
error_count = 0
|
||||||
|
|
||||||
duplicate_dict = dict()
|
duplicate_dict = dict()
|
||||||
@@ -1146,7 +1146,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
return (error_count, duplicate_dict, unique_dict)
|
return (error_count, duplicate_dict, unique_dict)
|
||||||
|
|
||||||
def has_duplicate_links(self, dn, forward_attr, forward_syntax):
|
def has_duplicate_links(self, dn, forward_attr, forward_syntax):
|
||||||
'''check a linked values for duplicate forward links'''
|
"""check a linked values for duplicate forward links"""
|
||||||
error_count = 0
|
error_count = 0
|
||||||
|
|
||||||
duplicate_cache_key = "%s:%s" % (str(dn), forward_attr)
|
duplicate_cache_key = "%s:%s" % (str(dn), forward_attr)
|
||||||
@@ -1183,7 +1183,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
forward_syntax,
|
forward_syntax,
|
||||||
backlink_attr,
|
backlink_attr,
|
||||||
forward_unique_dict):
|
forward_unique_dict):
|
||||||
'''Find all backlinks linking to obj_guid_str not already in forward_unique_dict'''
|
"""Find all backlinks linking to obj_guid_str not already in forward_unique_dict"""
|
||||||
missing_forward_links = []
|
missing_forward_links = []
|
||||||
error_count = 0
|
error_count = 0
|
||||||
|
|
||||||
@@ -1281,7 +1281,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
return (missing_forward_links, error_count)
|
return (missing_forward_links, error_count)
|
||||||
|
|
||||||
def check_dn(self, obj, attrname, syntax_oid):
|
def check_dn(self, obj, attrname, syntax_oid):
|
||||||
'''check a DN attribute for correctness'''
|
"""check a DN attribute for correctness"""
|
||||||
error_count = 0
|
error_count = 0
|
||||||
obj_guid = obj['objectGUID'][0]
|
obj_guid = obj['objectGUID'][0]
|
||||||
|
|
||||||
@@ -1586,11 +1586,11 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def get_originating_time(self, val, attid):
|
def get_originating_time(self, val, attid):
|
||||||
'''Read metadata properties and return the originating time for
|
"""Read metadata properties and return the originating time for
|
||||||
a given attributeId.
|
a given attributeId.
|
||||||
|
|
||||||
:return: the originating time or 0 if not found
|
:return: the originating time or 0 if not found
|
||||||
'''
|
"""
|
||||||
|
|
||||||
repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, val)
|
repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, val)
|
||||||
o = self.find_repl_attid(repl, attid)
|
o = self.find_repl_attid(repl, attid)
|
||||||
@@ -1599,8 +1599,8 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
def process_metadata(self, dn, val):
|
def process_metadata(self, dn, val):
|
||||||
'''Read metadata properties and list attributes in it.
|
"""Read metadata properties and list attributes in it.
|
||||||
raises KeyError if the attid is unknown.'''
|
raises KeyError if the attid is unknown."""
|
||||||
|
|
||||||
set_att = set()
|
set_att = set()
|
||||||
wrong_attids = set()
|
wrong_attids = set()
|
||||||
@@ -1621,8 +1621,8 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
return (set_att, list_attid, wrong_attids)
|
return (set_att, list_attid, wrong_attids)
|
||||||
|
|
||||||
def fix_metadata(self, obj, attr):
|
def fix_metadata(self, obj, attr):
|
||||||
'''re-write replPropertyMetaData elements for a single attribute for a
|
"""re-write replPropertyMetaData elements for a single attribute for a
|
||||||
object. This is used to fix missing replPropertyMetaData elements'''
|
object. This is used to fix missing replPropertyMetaData elements"""
|
||||||
guid_str = str(ndr_unpack(misc.GUID, obj['objectGUID'][0]))
|
guid_str = str(ndr_unpack(misc.GUID, obj['objectGUID'][0]))
|
||||||
dn = ldb.Dn(self.samdb, "<GUID=%s>" % guid_str)
|
dn = ldb.Dn(self.samdb, "<GUID=%s>" % guid_str)
|
||||||
res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, attrs=[attr],
|
res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, attrs=[attr],
|
||||||
@@ -1777,7 +1777,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
return (sd, None)
|
return (sd, None)
|
||||||
|
|
||||||
def err_wrong_sd(self, dn, sd, sd_broken):
|
def err_wrong_sd(self, dn, sd, sd_broken):
|
||||||
'''re-write the SD due to incorrect inherited ACEs'''
|
"""re-write the SD due to incorrect inherited ACEs"""
|
||||||
sd_attr = "nTSecurityDescriptor"
|
sd_attr = "nTSecurityDescriptor"
|
||||||
sd_val = ndr_pack(sd)
|
sd_val = ndr_pack(sd)
|
||||||
sd_flags = security.SECINFO_DACL | security.SECINFO_SACL
|
sd_flags = security.SECINFO_DACL | security.SECINFO_SACL
|
||||||
@@ -1794,7 +1794,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
self.report("Fixed attribute '%s' of '%s'\n" % (sd_attr, dn))
|
self.report("Fixed attribute '%s' of '%s'\n" % (sd_attr, dn))
|
||||||
|
|
||||||
def err_wrong_default_sd(self, dn, sd, diff):
|
def err_wrong_default_sd(self, dn, sd, diff):
|
||||||
'''re-write the SD due to not matching the default (optional mode for fixing an incorrect provision)'''
|
"""re-write the SD due to not matching the default (optional mode for fixing an incorrect provision)"""
|
||||||
sd_attr = "nTSecurityDescriptor"
|
sd_attr = "nTSecurityDescriptor"
|
||||||
sd_val = ndr_pack(sd)
|
sd_val = ndr_pack(sd)
|
||||||
sd_flags = security.SECINFO_DACL | security.SECINFO_SACL
|
sd_flags = security.SECINFO_DACL | security.SECINFO_SACL
|
||||||
@@ -1815,7 +1815,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
self.report("Fixed attribute '%s' of '%s'\n" % (sd_attr, dn))
|
self.report("Fixed attribute '%s' of '%s'\n" % (sd_attr, dn))
|
||||||
|
|
||||||
def err_missing_sd_owner(self, dn, sd):
|
def err_missing_sd_owner(self, dn, sd):
|
||||||
'''re-write the SD due to a missing owner or group'''
|
"""re-write the SD due to a missing owner or group"""
|
||||||
sd_attr = "nTSecurityDescriptor"
|
sd_attr = "nTSecurityDescriptor"
|
||||||
sd_val = ndr_pack(sd)
|
sd_val = ndr_pack(sd)
|
||||||
sd_flags = security.SECINFO_OWNER | security.SECINFO_GROUP
|
sd_flags = security.SECINFO_OWNER | security.SECINFO_GROUP
|
||||||
@@ -2005,9 +2005,9 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
found = True
|
found = True
|
||||||
self.report('''ERROR: on replPropertyMetaData of %s, the instanceType on attribute 0x%08x,
|
self.report("""ERROR: on replPropertyMetaData of %s, the instanceType on attribute 0x%08x,
|
||||||
version %d changed at %s is 00000000-0000-0000-0000-000000000000,
|
version %d changed at %s is 00000000-0000-0000-0000-000000000000,
|
||||||
but should be non-zero. Proposed fix is to set to our invocationID (%s).'''
|
but should be non-zero. Proposed fix is to set to our invocationID (%s)."""
|
||||||
% (dn, o.attid, o.version,
|
% (dn, o.attid, o.version,
|
||||||
time.ctime(samba.nttime2unix(o.originating_change_time)),
|
time.ctime(samba.nttime2unix(o.originating_change_time)),
|
||||||
self.samdb.get_invocation_id()))
|
self.samdb.get_invocation_id()))
|
||||||
@@ -2326,7 +2326,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
return attrs, lc_attrs
|
return attrs, lc_attrs
|
||||||
|
|
||||||
def check_object(self, dn, requested_attrs=None):
|
def check_object(self, dn, requested_attrs=None):
|
||||||
'''check one object'''
|
"""check one object"""
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
self.report("Checking object %s" % dn)
|
self.report("Checking object %s" % dn)
|
||||||
|
|
||||||
@@ -2882,7 +2882,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
################################################################
|
################################################################
|
||||||
# check special @ROOTDSE attributes
|
# check special @ROOTDSE attributes
|
||||||
def check_rootdse(self):
|
def check_rootdse(self):
|
||||||
'''check the @ROOTDSE special object'''
|
"""check the @ROOTDSE special object"""
|
||||||
dn = ldb.Dn(self.samdb, '@ROOTDSE')
|
dn = ldb.Dn(self.samdb, '@ROOTDSE')
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
self.report("Checking object %s" % dn)
|
self.report("Checking object %s" % dn)
|
||||||
@@ -2918,7 +2918,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
# re-index the database
|
# re-index the database
|
||||||
|
|
||||||
def reindex_database(self):
|
def reindex_database(self):
|
||||||
'''re-index the whole database'''
|
"""re-index the whole database"""
|
||||||
m = ldb.Message()
|
m = ldb.Message()
|
||||||
m.dn = ldb.Dn(self.samdb, "@ATTRIBUTES")
|
m.dn = ldb.Dn(self.samdb, "@ATTRIBUTES")
|
||||||
m['add'] = ldb.MessageElement('NONE', ldb.FLAG_MOD_ADD, 'force_reindex')
|
m['add'] = ldb.MessageElement('NONE', ldb.FLAG_MOD_ADD, 'force_reindex')
|
||||||
@@ -2928,7 +2928,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
|
|||||||
###############################################
|
###############################################
|
||||||
# reset @MODULES
|
# reset @MODULES
|
||||||
def reset_modules(self):
|
def reset_modules(self):
|
||||||
'''reset @MODULES to that needed for current sam.ldb (to read a very old database)'''
|
"""reset @MODULES to that needed for current sam.ldb (to read a very old database)"""
|
||||||
m = ldb.Message()
|
m = ldb.Message()
|
||||||
m.dn = ldb.Dn(self.samdb, "@MODULES")
|
m.dn = ldb.Dn(self.samdb, "@MODULES")
|
||||||
m['@LIST'] = ldb.MessageElement('samba_dsdb', ldb.FLAG_MOD_REPLACE, '@LIST')
|
m['@LIST'] = ldb.MessageElement('samba_dsdb', ldb.FLAG_MOD_REPLACE, '@LIST')
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ def sendDsReplicaSync(drsuapiBind, drsuapi_handle, source_dsa_guid,
|
|||||||
|
|
||||||
|
|
||||||
def drs_DsBind(drs):
|
def drs_DsBind(drs):
|
||||||
'''make a DsBind call, returning the binding handle'''
|
"""make a DsBind call, returning the binding handle"""
|
||||||
bind_info = drsuapi.DsBindInfoCtr()
|
bind_info = drsuapi.DsBindInfoCtr()
|
||||||
bind_info.length = 28
|
bind_info.length = 28
|
||||||
bind_info.info = drsuapi.DsBindInfo28()
|
bind_info.info = drsuapi.DsBindInfo28()
|
||||||
@@ -139,7 +139,7 @@ def drs_DsBind(drs):
|
|||||||
|
|
||||||
|
|
||||||
def drs_get_rodc_partial_attribute_set(samdb):
|
def drs_get_rodc_partial_attribute_set(samdb):
|
||||||
'''get a list of attributes for RODC replication'''
|
"""get a list of attributes for RODC replication"""
|
||||||
partial_attribute_set = drsuapi.DsPartialAttributeSet()
|
partial_attribute_set = drsuapi.DsPartialAttributeSet()
|
||||||
partial_attribute_set.version = 1
|
partial_attribute_set.version = 1
|
||||||
|
|
||||||
@@ -187,7 +187,7 @@ def drs_copy_highwater_mark(hwm, new_hwm):
|
|||||||
|
|
||||||
|
|
||||||
class drs_Replicate(object):
|
class drs_Replicate(object):
|
||||||
'''DRS replication calls'''
|
"""DRS replication calls"""
|
||||||
|
|
||||||
def __init__(self, binding_string, lp, creds, samdb, invocation_id):
|
def __init__(self, binding_string, lp, creds, samdb, invocation_id):
|
||||||
self.drs = drsuapi.drsuapi(binding_string, lp, creds)
|
self.drs = drsuapi.drsuapi(binding_string, lp, creds)
|
||||||
@@ -251,7 +251,7 @@ class drs_Replicate(object):
|
|||||||
|
|
||||||
|
|
||||||
def process_chunk(self, level, ctr, schema, req_level, req, first_chunk):
|
def process_chunk(self, level, ctr, schema, req_level, req, first_chunk):
|
||||||
'''Processes a single chunk of received replication data'''
|
"""Processes a single chunk of received replication data"""
|
||||||
# pass the replication into the py_net.c python bindings for processing
|
# pass the replication into the py_net.c python bindings for processing
|
||||||
self.net.replicate_chunk(self.replication_state, level, ctr,
|
self.net.replicate_chunk(self.replication_state, level, ctr,
|
||||||
schema=schema, req_level=req_level, req=req)
|
schema=schema, req_level=req_level, req=req)
|
||||||
@@ -259,7 +259,7 @@ class drs_Replicate(object):
|
|||||||
def replicate(self, dn, source_dsa_invocation_id, destination_dsa_guid,
|
def replicate(self, dn, source_dsa_invocation_id, destination_dsa_guid,
|
||||||
schema=False, exop=drsuapi.DRSUAPI_EXOP_NONE, rodc=False,
|
schema=False, exop=drsuapi.DRSUAPI_EXOP_NONE, rodc=False,
|
||||||
replica_flags=None, full_sync=True, sync_forced=False, more_flags=0):
|
replica_flags=None, full_sync=True, sync_forced=False, more_flags=0):
|
||||||
'''replicate a single DN'''
|
"""replicate a single DN"""
|
||||||
|
|
||||||
# setup for a GetNCChanges call
|
# setup for a GetNCChanges call
|
||||||
if self.supports_ext & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V10:
|
if self.supports_ext & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V10:
|
||||||
@@ -401,7 +401,7 @@ class drs_Replicate(object):
|
|||||||
# Handles the special case of creating a new clone of a DB, while also renaming
|
# Handles the special case of creating a new clone of a DB, while also renaming
|
||||||
# the entire DB's objects on the way through
|
# the entire DB's objects on the way through
|
||||||
class drs_ReplicateRenamer(drs_Replicate):
|
class drs_ReplicateRenamer(drs_Replicate):
|
||||||
'''Uses DRS replication to rename the entire DB'''
|
"""Uses DRS replication to rename the entire DB"""
|
||||||
|
|
||||||
def __init__(self, binding_string, lp, creds, samdb, invocation_id,
|
def __init__(self, binding_string, lp, creds, samdb, invocation_id,
|
||||||
old_base_dn, new_base_dn):
|
old_base_dn, new_base_dn):
|
||||||
@@ -417,11 +417,11 @@ class drs_ReplicateRenamer(drs_Replicate):
|
|||||||
self.more_flags = drsuapi.DRSUAPI_DRS_GET_TGT
|
self.more_flags = drsuapi.DRSUAPI_DRS_GET_TGT
|
||||||
|
|
||||||
def rename_dn(self, dn_str):
|
def rename_dn(self, dn_str):
|
||||||
'''Uses string substitution to replace the base DN'''
|
"""Uses string substitution to replace the base DN"""
|
||||||
return re.sub('%s$' % self.old_base_dn, self.new_base_dn, dn_str)
|
return re.sub('%s$' % self.old_base_dn, self.new_base_dn, dn_str)
|
||||||
|
|
||||||
def update_name_attr(self, base_obj):
|
def update_name_attr(self, base_obj):
|
||||||
'''Updates the 'name' attribute for the base DN object'''
|
"""Updates the 'name' attribute for the base DN object"""
|
||||||
for attr in base_obj.attribute_ctr.attributes:
|
for attr in base_obj.attribute_ctr.attributes:
|
||||||
if attr.attid == DRSUAPI_ATTID_name:
|
if attr.attid == DRSUAPI_ATTID_name:
|
||||||
base_dn = ldb.Dn(self.samdb, base_obj.identifier.dn)
|
base_dn = ldb.Dn(self.samdb, base_obj.identifier.dn)
|
||||||
@@ -429,7 +429,7 @@ class drs_ReplicateRenamer(drs_Replicate):
|
|||||||
attr.value_ctr.values[0].blob = new_name.encode('utf-16-le')
|
attr.value_ctr.values[0].blob = new_name.encode('utf-16-le')
|
||||||
|
|
||||||
def rename_top_level_object(self, first_obj):
|
def rename_top_level_object(self, first_obj):
|
||||||
'''Renames the first/top-level object in a partition'''
|
"""Renames the first/top-level object in a partition"""
|
||||||
old_dn = first_obj.identifier.dn
|
old_dn = first_obj.identifier.dn
|
||||||
first_obj.identifier.dn = self.rename_dn(first_obj.identifier.dn)
|
first_obj.identifier.dn = self.rename_dn(first_obj.identifier.dn)
|
||||||
print("Renaming partition %s --> %s" % (old_dn,
|
print("Renaming partition %s --> %s" % (old_dn,
|
||||||
@@ -441,7 +441,7 @@ class drs_ReplicateRenamer(drs_Replicate):
|
|||||||
self.update_name_attr(first_obj)
|
self.update_name_attr(first_obj)
|
||||||
|
|
||||||
def process_chunk(self, level, ctr, schema, req_level, req, first_chunk):
|
def process_chunk(self, level, ctr, schema, req_level, req, first_chunk):
|
||||||
'''Processes a single chunk of received replication data'''
|
"""Processes a single chunk of received replication data"""
|
||||||
|
|
||||||
# we need to rename the NC in every chunk - this gets used in searches
|
# we need to rename the NC in every chunk - this gets used in searches
|
||||||
# when applying the chunk
|
# when applying the chunk
|
||||||
|
|||||||
@@ -112,10 +112,10 @@ class gp_krb_ext(gp_inf_ext):
|
|||||||
|
|
||||||
|
|
||||||
class gp_access_ext(gp_inf_ext):
|
class gp_access_ext(gp_inf_ext):
|
||||||
'''This class takes the .inf file parameter (essentially a GPO file mapped
|
"""This class takes the .inf file parameter (essentially a GPO file mapped
|
||||||
to a GUID), hashmaps it to the Samba parameter, which then uses an ldb
|
to a GUID), hashmaps it to the Samba parameter, which then uses an ldb
|
||||||
object to update the parameter to Samba4. Not registry oriented whatsoever.
|
object to update the parameter to Samba4. Not registry oriented whatsoever.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def load_ldb(self):
|
def load_ldb(self):
|
||||||
try:
|
try:
|
||||||
@@ -191,7 +191,7 @@ class gp_access_ext(gp_inf_ext):
|
|||||||
self.ldb.set_pwdProperties(val)
|
self.ldb.set_pwdProperties(val)
|
||||||
|
|
||||||
def mapper(self):
|
def mapper(self):
|
||||||
'''ldap value : samba setter'''
|
"""ldap value : samba setter"""
|
||||||
return {"minPwdAge": (self.ch_minPwdAge, days2rel_nttime),
|
return {"minPwdAge": (self.ch_minPwdAge, days2rel_nttime),
|
||||||
"maxPwdAge": (self.ch_maxPwdAge, days2rel_nttime),
|
"maxPwdAge": (self.ch_maxPwdAge, days2rel_nttime),
|
||||||
# Could be none, but I like the method assignment in
|
# Could be none, but I like the method assignment in
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ except ImportError:
|
|||||||
|
|
||||||
|
|
||||||
class gp_log:
|
class gp_log:
|
||||||
''' Log settings overwritten by gpo apply
|
""" Log settings overwritten by gpo apply
|
||||||
The gp_log is an xml file that stores a history of gpo changes (and the
|
The gp_log is an xml file that stores a history of gpo changes (and the
|
||||||
original setting value).
|
original setting value).
|
||||||
|
|
||||||
@@ -100,15 +100,15 @@ class gp_log:
|
|||||||
The applylog keeps track of the order in which the GPOs were applied, so
|
The applylog keeps track of the order in which the GPOs were applied, so
|
||||||
that they can be rolled back in reverse, returning the machine to the state
|
that they can be rolled back in reverse, returning the machine to the state
|
||||||
prior to policy application.
|
prior to policy application.
|
||||||
'''
|
"""
|
||||||
def __init__(self, user, gpostore, db_log=None):
|
def __init__(self, user, gpostore, db_log=None):
|
||||||
''' Initialize the gp_log
|
""" Initialize the gp_log
|
||||||
param user - the username (or machine name) that policies are
|
param user - the username (or machine name) that policies are
|
||||||
being applied to
|
being applied to
|
||||||
param gpostore - the GPOStorage obj which references the tdb which
|
param gpostore - the GPOStorage obj which references the tdb which
|
||||||
contains gp_logs
|
contains gp_logs
|
||||||
param db_log - (optional) a string to initialize the gp_log
|
param db_log - (optional) a string to initialize the gp_log
|
||||||
'''
|
"""
|
||||||
self._state = GPOSTATE.APPLY
|
self._state = GPOSTATE.APPLY
|
||||||
self.gpostore = gpostore
|
self.gpostore = gpostore
|
||||||
self.username = user
|
self.username = user
|
||||||
@@ -123,7 +123,7 @@ class gp_log:
|
|||||||
user_obj.attrib['name'] = user
|
user_obj.attrib['name'] = user
|
||||||
|
|
||||||
def state(self, value):
|
def state(self, value):
|
||||||
''' Policy application state
|
""" Policy application state
|
||||||
param value - APPLY, ENFORCE, or UNAPPLY
|
param value - APPLY, ENFORCE, or UNAPPLY
|
||||||
|
|
||||||
The behavior of the gp_log depends on whether we are applying policy,
|
The behavior of the gp_log depends on whether we are applying policy,
|
||||||
@@ -132,7 +132,7 @@ class gp_log:
|
|||||||
but the gp_log does not change. During an unapply, additions to the log
|
but the gp_log does not change. During an unapply, additions to the log
|
||||||
should be ignored (since function calls to apply settings are actually
|
should be ignored (since function calls to apply settings are actually
|
||||||
reverting policy), but removals from the log are allowed.
|
reverting policy), but removals from the log are allowed.
|
||||||
'''
|
"""
|
||||||
# If we're enforcing, but we've unapplied, apply instead
|
# If we're enforcing, but we've unapplied, apply instead
|
||||||
if value == GPOSTATE.ENFORCE:
|
if value == GPOSTATE.ENFORCE:
|
||||||
user_obj = self.gpdb.find('user[@name="%s"]' % self.user)
|
user_obj = self.gpdb.find('user[@name="%s"]' % self.user)
|
||||||
@@ -145,15 +145,15 @@ class gp_log:
|
|||||||
self._state = value
|
self._state = value
|
||||||
|
|
||||||
def get_state(self):
|
def get_state(self):
|
||||||
'''Check the GPOSTATE
|
"""Check the GPOSTATE
|
||||||
'''
|
"""
|
||||||
return self._state
|
return self._state
|
||||||
|
|
||||||
def set_guid(self, guid):
|
def set_guid(self, guid):
|
||||||
''' Log to a different GPO guid
|
""" Log to a different GPO guid
|
||||||
param guid - guid value of the GPO from which we're applying
|
param guid - guid value of the GPO from which we're applying
|
||||||
policy
|
policy
|
||||||
'''
|
"""
|
||||||
self.guid = guid
|
self.guid = guid
|
||||||
user_obj = self.gpdb.find('user[@name="%s"]' % self.user)
|
user_obj = self.gpdb.find('user[@name="%s"]' % self.user)
|
||||||
obj = user_obj.find('guid[@value="%s"]' % guid)
|
obj = user_obj.find('guid[@value="%s"]' % guid)
|
||||||
@@ -171,12 +171,12 @@ class gp_log:
|
|||||||
item.attrib['value'] = guid
|
item.attrib['value'] = guid
|
||||||
|
|
||||||
def store(self, gp_ext_name, attribute, old_val):
|
def store(self, gp_ext_name, attribute, old_val):
|
||||||
''' Store an attribute in the gp_log
|
""" Store an attribute in the gp_log
|
||||||
param gp_ext_name - Name of the extension applying policy
|
param gp_ext_name - Name of the extension applying policy
|
||||||
param attribute - The attribute being modified
|
param attribute - The attribute being modified
|
||||||
param old_val - The value of the attribute prior to policy
|
param old_val - The value of the attribute prior to policy
|
||||||
application
|
application
|
||||||
'''
|
"""
|
||||||
if self._state == GPOSTATE.UNAPPLY or self._state == GPOSTATE.ENFORCE:
|
if self._state == GPOSTATE.UNAPPLY or self._state == GPOSTATE.ENFORCE:
|
||||||
return None
|
return None
|
||||||
user_obj = self.gpdb.find('user[@name="%s"]' % self.user)
|
user_obj = self.gpdb.find('user[@name="%s"]' % self.user)
|
||||||
@@ -193,12 +193,12 @@ class gp_log:
|
|||||||
attr.text = old_val
|
attr.text = old_val
|
||||||
|
|
||||||
def retrieve(self, gp_ext_name, attribute):
|
def retrieve(self, gp_ext_name, attribute):
|
||||||
''' Retrieve a stored attribute from the gp_log
|
""" Retrieve a stored attribute from the gp_log
|
||||||
param gp_ext_name - Name of the extension which applied policy
|
param gp_ext_name - Name of the extension which applied policy
|
||||||
param attribute - The attribute being retrieved
|
param attribute - The attribute being retrieved
|
||||||
return - The value of the attribute prior to policy
|
return - The value of the attribute prior to policy
|
||||||
application
|
application
|
||||||
'''
|
"""
|
||||||
user_obj = self.gpdb.find('user[@name="%s"]' % self.user)
|
user_obj = self.gpdb.find('user[@name="%s"]' % self.user)
|
||||||
guid_obj = user_obj.find('guid[@value="%s"]' % self.guid)
|
guid_obj = user_obj.find('guid[@value="%s"]' % self.guid)
|
||||||
assert guid_obj is not None, "gpo guid was not set"
|
assert guid_obj is not None, "gpo guid was not set"
|
||||||
@@ -210,11 +210,11 @@ class gp_log:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def retrieve_all(self, gp_ext_name):
|
def retrieve_all(self, gp_ext_name):
|
||||||
''' Retrieve all stored attributes for this user, GPO guid, and CSE
|
""" Retrieve all stored attributes for this user, GPO guid, and CSE
|
||||||
param gp_ext_name - Name of the extension which applied policy
|
param gp_ext_name - Name of the extension which applied policy
|
||||||
return - The values of the attributes prior to policy
|
return - The values of the attributes prior to policy
|
||||||
application
|
application
|
||||||
'''
|
"""
|
||||||
user_obj = self.gpdb.find('user[@name="%s"]' % self.user)
|
user_obj = self.gpdb.find('user[@name="%s"]' % self.user)
|
||||||
guid_obj = user_obj.find('guid[@value="%s"]' % self.guid)
|
guid_obj = user_obj.find('guid[@value="%s"]' % self.guid)
|
||||||
assert guid_obj is not None, "gpo guid was not set"
|
assert guid_obj is not None, "gpo guid was not set"
|
||||||
@@ -225,10 +225,10 @@ class gp_log:
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
def get_applied_guids(self):
|
def get_applied_guids(self):
|
||||||
''' Return a list of applied ext guids
|
""" Return a list of applied ext guids
|
||||||
return - List of guids for gpos that have applied settings
|
return - List of guids for gpos that have applied settings
|
||||||
to the system.
|
to the system.
|
||||||
'''
|
"""
|
||||||
guids = []
|
guids = []
|
||||||
user_obj = self.gpdb.find('user[@name="%s"]' % self.user)
|
user_obj = self.gpdb.find('user[@name="%s"]' % self.user)
|
||||||
if user_obj is not None:
|
if user_obj is not None:
|
||||||
@@ -242,12 +242,12 @@ class gp_log:
|
|||||||
return guids
|
return guids
|
||||||
|
|
||||||
def get_applied_settings(self, guids):
|
def get_applied_settings(self, guids):
|
||||||
''' Return a list of applied ext guids
|
""" Return a list of applied ext guids
|
||||||
return - List of tuples containing the guid of a gpo, then
|
return - List of tuples containing the guid of a gpo, then
|
||||||
a dictionary of policies and their values prior
|
a dictionary of policies and their values prior
|
||||||
policy application. These are sorted so that the
|
policy application. These are sorted so that the
|
||||||
most recently applied settings are removed first.
|
most recently applied settings are removed first.
|
||||||
'''
|
"""
|
||||||
ret = []
|
ret = []
|
||||||
user_obj = self.gpdb.find('user[@name="%s"]' % self.user)
|
user_obj = self.gpdb.find('user[@name="%s"]' % self.user)
|
||||||
for guid in guids:
|
for guid in guids:
|
||||||
@@ -264,11 +264,11 @@ class gp_log:
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
def delete(self, gp_ext_name, attribute):
|
def delete(self, gp_ext_name, attribute):
|
||||||
''' Remove an attribute from the gp_log
|
""" Remove an attribute from the gp_log
|
||||||
param gp_ext_name - name of extension from which to remove the
|
param gp_ext_name - name of extension from which to remove the
|
||||||
attribute
|
attribute
|
||||||
param attribute - attribute to remove
|
param attribute - attribute to remove
|
||||||
'''
|
"""
|
||||||
user_obj = self.gpdb.find('user[@name="%s"]' % self.user)
|
user_obj = self.gpdb.find('user[@name="%s"]' % self.user)
|
||||||
guid_obj = user_obj.find('guid[@value="%s"]' % self.guid)
|
guid_obj = user_obj.find('guid[@value="%s"]' % self.guid)
|
||||||
assert guid_obj is not None, "gpo guid was not set"
|
assert guid_obj is not None, "gpo guid was not set"
|
||||||
@@ -281,7 +281,7 @@ class gp_log:
|
|||||||
guid_obj.remove(ext)
|
guid_obj.remove(ext)
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
''' Write gp_log changes to disk '''
|
""" Write gp_log changes to disk """
|
||||||
self.gpostore.store(self.username, etree.tostring(self.gpdb, 'utf-8'))
|
self.gpostore.store(self.username, etree.tostring(self.gpdb, 'utf-8'))
|
||||||
|
|
||||||
|
|
||||||
@@ -387,60 +387,60 @@ class gp_xml_ext(gp_ext):
|
|||||||
|
|
||||||
|
|
||||||
class gp_applier(object):
|
class gp_applier(object):
|
||||||
'''Group Policy Applier/Unapplier/Modifier
|
"""Group Policy Applier/Unapplier/Modifier
|
||||||
The applier defines functions for monitoring policy application,
|
The applier defines functions for monitoring policy application,
|
||||||
removal, and modification. It must be a multi-derived class paired
|
removal, and modification. It must be a multi-derived class paired
|
||||||
with a subclass of gp_ext.
|
with a subclass of gp_ext.
|
||||||
'''
|
"""
|
||||||
__metaclass__ = ABCMeta
|
__metaclass__ = ABCMeta
|
||||||
|
|
||||||
def cache_add_attribute(self, guid, attribute, value):
|
def cache_add_attribute(self, guid, attribute, value):
|
||||||
'''Add an attribute and value to the Group Policy cache
|
"""Add an attribute and value to the Group Policy cache
|
||||||
guid - The GPO guid which applies this policy
|
guid - The GPO guid which applies this policy
|
||||||
attribute - The attribute name of the policy being applied
|
attribute - The attribute name of the policy being applied
|
||||||
value - The value of the policy being applied
|
value - The value of the policy being applied
|
||||||
|
|
||||||
Normally called by the subclass apply() function after applying policy.
|
Normally called by the subclass apply() function after applying policy.
|
||||||
'''
|
"""
|
||||||
self.gp_db.set_guid(guid)
|
self.gp_db.set_guid(guid)
|
||||||
self.gp_db.store(str(self), attribute, value)
|
self.gp_db.store(str(self), attribute, value)
|
||||||
self.gp_db.commit()
|
self.gp_db.commit()
|
||||||
|
|
||||||
def cache_remove_attribute(self, guid, attribute):
|
def cache_remove_attribute(self, guid, attribute):
|
||||||
'''Remove an attribute from the Group Policy cache
|
"""Remove an attribute from the Group Policy cache
|
||||||
guid - The GPO guid which applies this policy
|
guid - The GPO guid which applies this policy
|
||||||
attribute - The attribute name of the policy being unapplied
|
attribute - The attribute name of the policy being unapplied
|
||||||
|
|
||||||
Normally called by the subclass unapply() function when removing old
|
Normally called by the subclass unapply() function when removing old
|
||||||
policy.
|
policy.
|
||||||
'''
|
"""
|
||||||
self.gp_db.set_guid(guid)
|
self.gp_db.set_guid(guid)
|
||||||
self.gp_db.delete(str(self), attribute)
|
self.gp_db.delete(str(self), attribute)
|
||||||
self.gp_db.commit()
|
self.gp_db.commit()
|
||||||
|
|
||||||
def cache_get_attribute_value(self, guid, attribute):
|
def cache_get_attribute_value(self, guid, attribute):
|
||||||
'''Retrieve the value stored in the cache for the given attribute
|
"""Retrieve the value stored in the cache for the given attribute
|
||||||
guid - The GPO guid which applies this policy
|
guid - The GPO guid which applies this policy
|
||||||
attribute - The attribute name of the policy
|
attribute - The attribute name of the policy
|
||||||
'''
|
"""
|
||||||
self.gp_db.set_guid(guid)
|
self.gp_db.set_guid(guid)
|
||||||
return self.gp_db.retrieve(str(self), attribute)
|
return self.gp_db.retrieve(str(self), attribute)
|
||||||
|
|
||||||
def cache_get_all_attribute_values(self, guid):
|
def cache_get_all_attribute_values(self, guid):
|
||||||
'''Retrieve all attribute/values currently stored for this gpo+policy
|
"""Retrieve all attribute/values currently stored for this gpo+policy
|
||||||
guid - The GPO guid which applies this policy
|
guid - The GPO guid which applies this policy
|
||||||
'''
|
"""
|
||||||
self.gp_db.set_guid(guid)
|
self.gp_db.set_guid(guid)
|
||||||
return self.gp_db.retrieve_all(str(self))
|
return self.gp_db.retrieve_all(str(self))
|
||||||
|
|
||||||
def cache_get_apply_state(self):
|
def cache_get_apply_state(self):
|
||||||
'''Return the current apply state
|
"""Return the current apply state
|
||||||
return - APPLY|ENFORCE|UNAPPLY
|
return - APPLY|ENFORCE|UNAPPLY
|
||||||
'''
|
"""
|
||||||
return self.gp_db.get_state()
|
return self.gp_db.get_state()
|
||||||
|
|
||||||
def generate_attribute(self, name, *args):
|
def generate_attribute(self, name, *args):
|
||||||
'''Generate an attribute name from arbitrary data
|
"""Generate an attribute name from arbitrary data
|
||||||
name - A name to ensure uniqueness
|
name - A name to ensure uniqueness
|
||||||
args - Any arbitrary set of args, str or bytes
|
args - Any arbitrary set of args, str or bytes
|
||||||
return - A blake2b digest of the data, the attribute
|
return - A blake2b digest of the data, the attribute
|
||||||
@@ -449,30 +449,30 @@ class gp_applier(object):
|
|||||||
reproducible and uniquely identifies it. Hashing the name with
|
reproducible and uniquely identifies it. Hashing the name with
|
||||||
the data ensures we don't falsely identify a match which is the same
|
the data ensures we don't falsely identify a match which is the same
|
||||||
text in a different file. Using this attribute generator is optional.
|
text in a different file. Using this attribute generator is optional.
|
||||||
'''
|
"""
|
||||||
data = b''.join([get_bytes(arg) for arg in [*args]])
|
data = b''.join([get_bytes(arg) for arg in [*args]])
|
||||||
return blake2b(get_bytes(name)+data).hexdigest()
|
return blake2b(get_bytes(name)+data).hexdigest()
|
||||||
|
|
||||||
def generate_value_hash(self, *args):
|
def generate_value_hash(self, *args):
|
||||||
'''Generate a unique value which identifies value changes
|
"""Generate a unique value which identifies value changes
|
||||||
args - Any arbitrary set of args, str or bytes
|
args - Any arbitrary set of args, str or bytes
|
||||||
return - A blake2b digest of the data, the value represented
|
return - A blake2b digest of the data, the value represented
|
||||||
'''
|
"""
|
||||||
data = b''.join([get_bytes(arg) for arg in [*args]])
|
data = b''.join([get_bytes(arg) for arg in [*args]])
|
||||||
return blake2b(data).hexdigest()
|
return blake2b(data).hexdigest()
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def unapply(self, guid, attribute, value):
|
def unapply(self, guid, attribute, value):
|
||||||
'''Group Policy Unapply
|
"""Group Policy Unapply
|
||||||
guid - The GPO guid which applies this policy
|
guid - The GPO guid which applies this policy
|
||||||
attribute - The attribute name of the policy being unapplied
|
attribute - The attribute name of the policy being unapplied
|
||||||
value - The value of the policy being unapplied
|
value - The value of the policy being unapplied
|
||||||
'''
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def apply(self, guid, attribute, applier_func, *args):
|
def apply(self, guid, attribute, applier_func, *args):
|
||||||
'''Group Policy Apply
|
"""Group Policy Apply
|
||||||
guid - The GPO guid which applies this policy
|
guid - The GPO guid which applies this policy
|
||||||
attribute - The attribute name of the policy being applied
|
attribute - The attribute name of the policy being applied
|
||||||
applier_func - An applier function which takes variable args
|
applier_func - An applier function which takes variable args
|
||||||
@@ -483,11 +483,11 @@ class gp_applier(object):
|
|||||||
first unapply any changed policy. See for example calls to
|
first unapply any changed policy. See for example calls to
|
||||||
`cache_get_all_attribute_values()` which searches for all policies
|
`cache_get_all_attribute_values()` which searches for all policies
|
||||||
applied by this GPO for this Client Side Extension (CSE).
|
applied by this GPO for this Client Side Extension (CSE).
|
||||||
'''
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def clean(self, guid, keep=None, remove=None, **kwargs):
|
def clean(self, guid, keep=None, remove=None, **kwargs):
|
||||||
'''Cleanup old removed attributes
|
"""Cleanup old removed attributes
|
||||||
keep - A list of attributes to keep
|
keep - A list of attributes to keep
|
||||||
remove - A single attribute to remove, or a list of attributes to
|
remove - A single attribute to remove, or a list of attributes to
|
||||||
remove
|
remove
|
||||||
@@ -495,7 +495,7 @@ class gp_applier(object):
|
|||||||
function
|
function
|
||||||
|
|
||||||
This is only necessary for CSEs which provide multiple attributes.
|
This is only necessary for CSEs which provide multiple attributes.
|
||||||
'''
|
"""
|
||||||
# Clean syntax is, either provide a single remove attribute,
|
# Clean syntax is, either provide a single remove attribute,
|
||||||
# or a list of either removal attributes or keep attributes.
|
# or a list of either removal attributes or keep attributes.
|
||||||
if keep is None:
|
if keep is None:
|
||||||
@@ -516,8 +516,8 @@ class gp_applier(object):
|
|||||||
|
|
||||||
|
|
||||||
class gp_misc_applier(gp_applier):
|
class gp_misc_applier(gp_applier):
|
||||||
'''Group Policy Miscellaneous Applier/Unapplier/Modifier
|
"""Group Policy Miscellaneous Applier/Unapplier/Modifier
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def generate_value(self, **kwargs):
|
def generate_value(self, **kwargs):
|
||||||
data = etree.Element('data')
|
data = etree.Element('data')
|
||||||
@@ -543,10 +543,10 @@ class gp_misc_applier(gp_applier):
|
|||||||
|
|
||||||
|
|
||||||
class gp_file_applier(gp_applier):
|
class gp_file_applier(gp_applier):
|
||||||
'''Group Policy File Applier/Unapplier/Modifier
|
"""Group Policy File Applier/Unapplier/Modifier
|
||||||
Subclass of abstract class gp_applier for monitoring policy applied
|
Subclass of abstract class gp_applier for monitoring policy applied
|
||||||
via a file.
|
via a file.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def __generate_value(self, value_hash, files, sep):
|
def __generate_value(self, value_hash, files, sep):
|
||||||
data = [value_hash]
|
data = [value_hash]
|
||||||
@@ -554,9 +554,9 @@ class gp_file_applier(gp_applier):
|
|||||||
return sep.join(data)
|
return sep.join(data)
|
||||||
|
|
||||||
def __parse_value(self, value, sep):
|
def __parse_value(self, value, sep):
|
||||||
'''Parse a value
|
"""Parse a value
|
||||||
return - A unique HASH, followed by the file list
|
return - A unique HASH, followed by the file list
|
||||||
'''
|
"""
|
||||||
if value is None:
|
if value is None:
|
||||||
return None, []
|
return None, []
|
||||||
data = value.split(sep)
|
data = value.split(sep)
|
||||||
@@ -577,13 +577,13 @@ class gp_file_applier(gp_applier):
|
|||||||
self.cache_remove_attribute(guid, attribute)
|
self.cache_remove_attribute(guid, attribute)
|
||||||
|
|
||||||
def apply(self, guid, attribute, value_hash, applier_func, *args, sep=':'):
|
def apply(self, guid, attribute, value_hash, applier_func, *args, sep=':'):
|
||||||
'''
|
"""
|
||||||
applier_func MUST return a list of files created by the applier.
|
applier_func MUST return a list of files created by the applier.
|
||||||
|
|
||||||
This applier is for policies which only apply to a single file (with
|
This applier is for policies which only apply to a single file (with
|
||||||
a couple small exceptions). This applier will remove any policy applied
|
a couple small exceptions). This applier will remove any policy applied
|
||||||
by this GPO which doesn't match the new policy.
|
by this GPO which doesn't match the new policy.
|
||||||
'''
|
"""
|
||||||
# If the policy has changed, unapply, then apply new policy
|
# If the policy has changed, unapply, then apply new policy
|
||||||
old_val = self.cache_get_attribute_value(guid, attribute)
|
old_val = self.cache_get_attribute_value(guid, attribute)
|
||||||
# Ignore removal if this policy is applied and hasn't changed
|
# Ignore removal if this policy is applied and hasn't changed
|
||||||
@@ -602,7 +602,7 @@ class gp_file_applier(gp_applier):
|
|||||||
self.cache_add_attribute(guid, attribute, new_value)
|
self.cache_add_attribute(guid, attribute, new_value)
|
||||||
|
|
||||||
|
|
||||||
''' Fetch the hostname of a writable DC '''
|
""" Fetch the hostname of a writable DC """
|
||||||
|
|
||||||
|
|
||||||
def get_dc_hostname(creds, lp):
|
def get_dc_hostname(creds, lp):
|
||||||
@@ -618,7 +618,7 @@ def get_dc_netbios_hostname(creds, lp):
|
|||||||
return cldap_ret.pdc_name
|
return cldap_ret.pdc_name
|
||||||
|
|
||||||
|
|
||||||
''' Fetch a list of GUIDs for applicable GPOs '''
|
""" Fetch a list of GUIDs for applicable GPOs """
|
||||||
|
|
||||||
|
|
||||||
def get_gpo(samdb, gpo_dn):
|
def get_gpo(samdb, gpo_dn):
|
||||||
@@ -807,7 +807,7 @@ def site_dn_for_machine(samdb, dc_hostname, lp, creds, hostname):
|
|||||||
return site_dn
|
return site_dn
|
||||||
|
|
||||||
def get_gpo_list(dc_hostname, creds, lp, username):
|
def get_gpo_list(dc_hostname, creds, lp, username):
|
||||||
'''Get the full list of GROUP_POLICY_OBJECTs for a given username.
|
"""Get the full list of GROUP_POLICY_OBJECTs for a given username.
|
||||||
Push GPOs to gpo_list so that the traversal order of the list matches
|
Push GPOs to gpo_list so that the traversal order of the list matches
|
||||||
the order of application:
|
the order of application:
|
||||||
(L)ocal (S)ite (D)omain (O)rganizational(U)nit
|
(L)ocal (S)ite (D)omain (O)rganizational(U)nit
|
||||||
@@ -817,7 +817,7 @@ def get_gpo_list(dc_hostname, creds, lp, username):
|
|||||||
pushed in the opposite order of application (OUs first, local last,
|
pushed in the opposite order of application (OUs first, local last,
|
||||||
child-to-parent).
|
child-to-parent).
|
||||||
Forced GPOs are appended in the end since they override all others.
|
Forced GPOs are appended in the end since they override all others.
|
||||||
'''
|
"""
|
||||||
gpo_list = []
|
gpo_list = []
|
||||||
forced_gpo_list = []
|
forced_gpo_list = []
|
||||||
url = 'ldap://' + dc_hostname
|
url = 'ldap://' + dc_hostname
|
||||||
@@ -1177,18 +1177,18 @@ def unregister_gp_extension(guid, smb_conf=None):
|
|||||||
|
|
||||||
|
|
||||||
def set_privileges(username, uid, gid):
|
def set_privileges(username, uid, gid):
|
||||||
'''
|
"""
|
||||||
Set current process privileges
|
Set current process privileges
|
||||||
'''
|
"""
|
||||||
|
|
||||||
os.setegid(gid)
|
os.setegid(gid)
|
||||||
os.seteuid(uid)
|
os.seteuid(uid)
|
||||||
|
|
||||||
|
|
||||||
def drop_privileges(username, func, *args):
|
def drop_privileges(username, func, *args):
|
||||||
'''
|
"""
|
||||||
Run supplied function with privileges for specified username.
|
Run supplied function with privileges for specified username.
|
||||||
'''
|
"""
|
||||||
current_uid = os.getuid()
|
current_uid = os.getuid()
|
||||||
|
|
||||||
if not current_uid == 0:
|
if not current_uid == 0:
|
||||||
|
|||||||
@@ -38,9 +38,9 @@ def logger_init(name, log_level):
|
|||||||
logger.setLevel(logging.DEBUG)
|
logger.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
class slogm(object):
|
class slogm(object):
|
||||||
'''
|
"""
|
||||||
Structured log message class
|
Structured log message class
|
||||||
'''
|
"""
|
||||||
def __init__(self, message, kwargs=None):
|
def __init__(self, message, kwargs=None):
|
||||||
if kwargs is None:
|
if kwargs is None:
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
|
|||||||
@@ -377,21 +377,21 @@ class DCJoinContext(object):
|
|||||||
return str(res[0]["dnsHostName"][0])
|
return str(res[0]["dnsHostName"][0])
|
||||||
|
|
||||||
def get_domain_name(ctx):
|
def get_domain_name(ctx):
|
||||||
'''get netbios name of the domain from the partitions record'''
|
"""get netbios name of the domain from the partitions record"""
|
||||||
partitions_dn = ctx.samdb.get_partitions_dn()
|
partitions_dn = ctx.samdb.get_partitions_dn()
|
||||||
res = ctx.samdb.search(base=partitions_dn, scope=ldb.SCOPE_ONELEVEL, attrs=["nETBIOSName"],
|
res = ctx.samdb.search(base=partitions_dn, scope=ldb.SCOPE_ONELEVEL, attrs=["nETBIOSName"],
|
||||||
expression='ncName=%s' % ldb.binary_encode(str(ctx.samdb.get_default_basedn())))
|
expression='ncName=%s' % ldb.binary_encode(str(ctx.samdb.get_default_basedn())))
|
||||||
return str(res[0]["nETBIOSName"][0])
|
return str(res[0]["nETBIOSName"][0])
|
||||||
|
|
||||||
def get_forest_domain_name(ctx):
|
def get_forest_domain_name(ctx):
|
||||||
'''get netbios name of the domain from the partitions record'''
|
"""get netbios name of the domain from the partitions record"""
|
||||||
partitions_dn = ctx.samdb.get_partitions_dn()
|
partitions_dn = ctx.samdb.get_partitions_dn()
|
||||||
res = ctx.samdb.search(base=partitions_dn, scope=ldb.SCOPE_ONELEVEL, attrs=["nETBIOSName"],
|
res = ctx.samdb.search(base=partitions_dn, scope=ldb.SCOPE_ONELEVEL, attrs=["nETBIOSName"],
|
||||||
expression='ncName=%s' % ldb.binary_encode(str(ctx.samdb.get_root_basedn())))
|
expression='ncName=%s' % ldb.binary_encode(str(ctx.samdb.get_root_basedn())))
|
||||||
return str(res[0]["nETBIOSName"][0])
|
return str(res[0]["nETBIOSName"][0])
|
||||||
|
|
||||||
def get_parent_partition_dn(ctx):
|
def get_parent_partition_dn(ctx):
|
||||||
'''get the parent domain partition DN from parent DNS name'''
|
"""get the parent domain partition DN from parent DNS name"""
|
||||||
res = ctx.samdb.search(base=ctx.config_dn, attrs=[],
|
res = ctx.samdb.search(base=ctx.config_dn, attrs=[],
|
||||||
expression='(&(objectclass=crossRef)(dnsRoot=%s)(systemFlags:%s:=%u))' %
|
expression='(&(objectclass=crossRef)(dnsRoot=%s)(systemFlags:%s:=%u))' %
|
||||||
(ldb.binary_encode(ctx.parent_dnsdomain),
|
(ldb.binary_encode(ctx.parent_dnsdomain),
|
||||||
@@ -399,14 +399,14 @@ class DCJoinContext(object):
|
|||||||
return str(res[0].dn)
|
return str(res[0].dn)
|
||||||
|
|
||||||
def get_mysid(ctx):
|
def get_mysid(ctx):
|
||||||
'''get the SID of the connected user. Only works with w2k8 and later,
|
"""get the SID of the connected user. Only works with w2k8 and later,
|
||||||
so only used for RODC join'''
|
so only used for RODC join"""
|
||||||
res = ctx.samdb.search(base="", scope=ldb.SCOPE_BASE, attrs=["tokenGroups"])
|
res = ctx.samdb.search(base="", scope=ldb.SCOPE_BASE, attrs=["tokenGroups"])
|
||||||
binsid = res[0]["tokenGroups"][0]
|
binsid = res[0]["tokenGroups"][0]
|
||||||
return get_string(ctx.samdb.schema_format_value("objectSID", binsid))
|
return get_string(ctx.samdb.schema_format_value("objectSID", binsid))
|
||||||
|
|
||||||
def dn_exists(ctx, dn):
|
def dn_exists(ctx, dn):
|
||||||
'''check if a DN exists'''
|
"""check if a DN exists"""
|
||||||
try:
|
try:
|
||||||
res = ctx.samdb.search(base=dn, scope=ldb.SCOPE_BASE, attrs=[])
|
res = ctx.samdb.search(base=dn, scope=ldb.SCOPE_BASE, attrs=[])
|
||||||
except ldb.LdbError as e5:
|
except ldb.LdbError as e5:
|
||||||
@@ -417,7 +417,7 @@ class DCJoinContext(object):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def add_krbtgt_account(ctx):
|
def add_krbtgt_account(ctx):
|
||||||
'''RODCs need a special krbtgt account'''
|
"""RODCs need a special krbtgt account"""
|
||||||
print("Adding %s" % ctx.krbtgt_dn)
|
print("Adding %s" % ctx.krbtgt_dn)
|
||||||
rec = {
|
rec = {
|
||||||
"dn": ctx.krbtgt_dn,
|
"dn": ctx.krbtgt_dn,
|
||||||
@@ -446,7 +446,7 @@ class DCJoinContext(object):
|
|||||||
ctx.samdb.rename(ctx.krbtgt_dn, ctx.new_krbtgt_dn)
|
ctx.samdb.rename(ctx.krbtgt_dn, ctx.new_krbtgt_dn)
|
||||||
|
|
||||||
def drsuapi_connect(ctx):
|
def drsuapi_connect(ctx):
|
||||||
'''make a DRSUAPI connection to the naming master'''
|
"""make a DRSUAPI connection to the naming master"""
|
||||||
binding_options = "seal"
|
binding_options = "seal"
|
||||||
if ctx.lp.log_level() >= 9:
|
if ctx.lp.log_level() >= 9:
|
||||||
binding_options += ",print"
|
binding_options += ",print"
|
||||||
@@ -455,7 +455,7 @@ class DCJoinContext(object):
|
|||||||
(ctx.drsuapi_handle, ctx.bind_supported_extensions) = drs_utils.drs_DsBind(ctx.drsuapi)
|
(ctx.drsuapi_handle, ctx.bind_supported_extensions) = drs_utils.drs_DsBind(ctx.drsuapi)
|
||||||
|
|
||||||
def create_tmp_samdb(ctx):
|
def create_tmp_samdb(ctx):
|
||||||
'''create a temporary samdb object for schema queries'''
|
"""create a temporary samdb object for schema queries"""
|
||||||
ctx.tmp_schema = Schema(ctx.domsid,
|
ctx.tmp_schema = Schema(ctx.domsid,
|
||||||
schemadn=ctx.schema_dn)
|
schemadn=ctx.schema_dn)
|
||||||
ctx.tmp_samdb = SamDB(session_info=system_session(), url=None, auto_connect=False,
|
ctx.tmp_samdb = SamDB(session_info=system_session(), url=None, auto_connect=False,
|
||||||
@@ -464,7 +464,7 @@ class DCJoinContext(object):
|
|||||||
ctx.tmp_samdb.set_schema(ctx.tmp_schema)
|
ctx.tmp_samdb.set_schema(ctx.tmp_schema)
|
||||||
|
|
||||||
def DsAddEntry(ctx, recs):
|
def DsAddEntry(ctx, recs):
|
||||||
'''add a record via the DRSUAPI DsAddEntry call'''
|
"""add a record via the DRSUAPI DsAddEntry call"""
|
||||||
if ctx.drsuapi is None:
|
if ctx.drsuapi is None:
|
||||||
ctx.drsuapi_connect()
|
ctx.drsuapi_connect()
|
||||||
if ctx.tmp_samdb is None:
|
if ctx.tmp_samdb is None:
|
||||||
@@ -531,7 +531,7 @@ class DCJoinContext(object):
|
|||||||
return ctr.objects
|
return ctr.objects
|
||||||
|
|
||||||
def join_ntdsdsa_obj(ctx):
|
def join_ntdsdsa_obj(ctx):
|
||||||
'''return the ntdsdsa object to add'''
|
"""return the ntdsdsa object to add"""
|
||||||
|
|
||||||
print("Adding %s" % ctx.ntds_dn)
|
print("Adding %s" % ctx.ntds_dn)
|
||||||
|
|
||||||
@@ -579,7 +579,7 @@ class DCJoinContext(object):
|
|||||||
return rec
|
return rec
|
||||||
|
|
||||||
def join_add_ntdsdsa(ctx):
|
def join_add_ntdsdsa(ctx):
|
||||||
'''add the ntdsdsa object'''
|
"""add the ntdsdsa object"""
|
||||||
|
|
||||||
rec = ctx.join_ntdsdsa_obj()
|
rec = ctx.join_ntdsdsa_obj()
|
||||||
if ctx.forced_local_samdb:
|
if ctx.forced_local_samdb:
|
||||||
@@ -594,7 +594,7 @@ class DCJoinContext(object):
|
|||||||
ctx.ntds_guid = misc.GUID(ctx.samdb.schema_format_value("objectGUID", res[0]["objectGUID"][0]))
|
ctx.ntds_guid = misc.GUID(ctx.samdb.schema_format_value("objectGUID", res[0]["objectGUID"][0]))
|
||||||
|
|
||||||
def join_add_objects(ctx, specified_sid=None):
|
def join_add_objects(ctx, specified_sid=None):
|
||||||
'''add the various objects needed for the join'''
|
"""add the various objects needed for the join"""
|
||||||
if ctx.acct_dn:
|
if ctx.acct_dn:
|
||||||
print("Adding %s" % ctx.acct_dn)
|
print("Adding %s" % ctx.acct_dn)
|
||||||
rec = {
|
rec = {
|
||||||
@@ -953,7 +953,7 @@ class DCJoinContext(object):
|
|||||||
print("Provision OK for domain %s" % ctx.names.dnsdomain)
|
print("Provision OK for domain %s" % ctx.names.dnsdomain)
|
||||||
|
|
||||||
def create_replicator(ctx, repl_creds, binding_options):
|
def create_replicator(ctx, repl_creds, binding_options):
|
||||||
'''Creates a new DRS object for managing replications'''
|
"""Creates a new DRS object for managing replications"""
|
||||||
return drs_utils.drs_Replicate(
|
return drs_utils.drs_Replicate(
|
||||||
"ncacn_ip_tcp:%s[%s]" % (ctx.server, binding_options),
|
"ncacn_ip_tcp:%s[%s]" % (ctx.server, binding_options),
|
||||||
ctx.lp, repl_creds, ctx.local_samdb, ctx.invocation_id)
|
ctx.lp, repl_creds, ctx.local_samdb, ctx.invocation_id)
|
||||||
@@ -1730,7 +1730,7 @@ class DCCloneAndRenameContext(DCCloneContext):
|
|||||||
ctx.base_dn, ctx.new_base_dn)
|
ctx.base_dn, ctx.new_base_dn)
|
||||||
|
|
||||||
def create_non_global_lp(ctx, global_lp):
|
def create_non_global_lp(ctx, global_lp):
|
||||||
'''Creates a non-global LoadParm based on the global LP's settings'''
|
"""Creates a non-global LoadParm based on the global LP's settings"""
|
||||||
|
|
||||||
# the samba code shares a global LoadParm by default. Here we create a
|
# the samba code shares a global LoadParm by default. Here we create a
|
||||||
# new LoadParm that retains the global settings, but any changes we
|
# new LoadParm that retains the global settings, but any changes we
|
||||||
@@ -1745,7 +1745,7 @@ class DCCloneAndRenameContext(DCCloneContext):
|
|||||||
return local_lp
|
return local_lp
|
||||||
|
|
||||||
def rename_dn(ctx, dn_str):
|
def rename_dn(ctx, dn_str):
|
||||||
'''Uses string substitution to replace the base DN'''
|
"""Uses string substitution to replace the base DN"""
|
||||||
old_base_dn = ctx.base_dn
|
old_base_dn = ctx.base_dn
|
||||||
return re.sub('%s$' % old_base_dn, ctx.new_base_dn, dn_str)
|
return re.sub('%s$' % old_base_dn, ctx.new_base_dn, dn_str)
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class NamingContext(object):
|
|||||||
self.nc_type = NCType.unknown
|
self.nc_type = NCType.unknown
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
'''Debug dump string output of class'''
|
"""Debug dump string output of class"""
|
||||||
text = "%s:" % (self.__class__.__name__,) +\
|
text = "%s:" % (self.__class__.__name__,) +\
|
||||||
"\n\tnc_dnstr=%s" % self.nc_dnstr +\
|
"\n\tnc_dnstr=%s" % self.nc_dnstr +\
|
||||||
"\n\tnc_guid=%s" % str(self.nc_guid)
|
"\n\tnc_guid=%s" % str(self.nc_guid)
|
||||||
@@ -99,7 +99,7 @@ class NamingContext(object):
|
|||||||
assert self.nc_guid is not None
|
assert self.nc_guid is not None
|
||||||
|
|
||||||
def is_config(self):
|
def is_config(self):
|
||||||
'''Return True if NC is config'''
|
"""Return True if NC is config"""
|
||||||
assert self.nc_type != NCType.unknown
|
assert self.nc_type != NCType.unknown
|
||||||
return self.nc_type == NCType.config
|
return self.nc_type == NCType.config
|
||||||
|
|
||||||
@@ -198,7 +198,7 @@ class NCReplica(NamingContext):
|
|||||||
NamingContext.__init__(self, nc_dnstr)
|
NamingContext.__init__(self, nc_dnstr)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
'''Debug dump string output of class'''
|
"""Debug dump string output of class"""
|
||||||
text = "%s:" % self.__class__.__name__ +\
|
text = "%s:" % self.__class__.__name__ +\
|
||||||
"\n\tdsa_dnstr=%s" % self.rep_dsa_dnstr +\
|
"\n\tdsa_dnstr=%s" % self.rep_dsa_dnstr +\
|
||||||
"\n\tdsa_guid=%s" % self.rep_dsa_guid +\
|
"\n\tdsa_guid=%s" % self.rep_dsa_guid +\
|
||||||
@@ -213,7 +213,7 @@ class NCReplica(NamingContext):
|
|||||||
return "%s\n%s" % (NamingContext.__str__(self), text)
|
return "%s\n%s" % (NamingContext.__str__(self), text)
|
||||||
|
|
||||||
def set_instantiated_flags(self, flags=0):
|
def set_instantiated_flags(self, flags=0):
|
||||||
'''Set or clear NC replica instantiated flags'''
|
"""Set or clear NC replica instantiated flags"""
|
||||||
self.rep_instantiated_flags = flags
|
self.rep_instantiated_flags = flags
|
||||||
|
|
||||||
def identify_by_dsa_attr(self, samdb, attr):
|
def identify_by_dsa_attr(self, samdb, attr):
|
||||||
@@ -271,11 +271,11 @@ class NCReplica(NamingContext):
|
|||||||
return self.rep_default
|
return self.rep_default
|
||||||
|
|
||||||
def is_ro(self):
|
def is_ro(self):
|
||||||
'''Return True if NC replica is read only'''
|
"""Return True if NC replica is read only"""
|
||||||
return self.rep_ro
|
return self.rep_ro
|
||||||
|
|
||||||
def is_partial(self):
|
def is_partial(self):
|
||||||
'''Return True if NC replica is partial'''
|
"""Return True if NC replica is partial"""
|
||||||
return self.rep_partial
|
return self.rep_partial
|
||||||
|
|
||||||
def is_present(self):
|
def is_present(self):
|
||||||
@@ -574,7 +574,7 @@ class DirectoryServiceAgent(object):
|
|||||||
self.connect_table = {}
|
self.connect_table = {}
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
'''Debug dump string output of class'''
|
"""Debug dump string output of class"""
|
||||||
|
|
||||||
text = "%s:" % self.__class__.__name__
|
text = "%s:" % self.__class__.__name__
|
||||||
if self.dsa_dnstr is not None:
|
if self.dsa_dnstr is not None:
|
||||||
@@ -600,16 +600,16 @@ class DirectoryServiceAgent(object):
|
|||||||
return self.current_rep_table.get(nc_dnstr)
|
return self.current_rep_table.get(nc_dnstr)
|
||||||
|
|
||||||
def is_istg(self):
|
def is_istg(self):
|
||||||
'''Returns True if dsa is intersite topology generator for it's site'''
|
"""Returns True if dsa is intersite topology generator for it's site"""
|
||||||
# The KCC on an RODC always acts as an ISTG for itself
|
# The KCC on an RODC always acts as an ISTG for itself
|
||||||
return self.dsa_is_istg or self.dsa_is_ro
|
return self.dsa_is_istg or self.dsa_is_ro
|
||||||
|
|
||||||
def is_ro(self):
|
def is_ro(self):
|
||||||
'''Returns True if dsa a read only domain controller'''
|
"""Returns True if dsa a read only domain controller"""
|
||||||
return self.dsa_is_ro
|
return self.dsa_is_ro
|
||||||
|
|
||||||
def is_gc(self):
|
def is_gc(self):
|
||||||
'''Returns True if dsa hosts a global catalog'''
|
"""Returns True if dsa hosts a global catalog"""
|
||||||
if (self.options & dsdb.DS_NTDSDSA_OPT_IS_GC) != 0:
|
if (self.options & dsdb.DS_NTDSDSA_OPT_IS_GC) != 0:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@@ -850,15 +850,15 @@ class DirectoryServiceAgent(object):
|
|||||||
return answer
|
return answer
|
||||||
|
|
||||||
def dumpstr_current_replica_table(self):
|
def dumpstr_current_replica_table(self):
|
||||||
'''Debug dump string output of current replica table'''
|
"""Debug dump string output of current replica table"""
|
||||||
return '\n'.join(str(x) for x in self.current_rep_table)
|
return '\n'.join(str(x) for x in self.current_rep_table)
|
||||||
|
|
||||||
def dumpstr_needed_replica_table(self):
|
def dumpstr_needed_replica_table(self):
|
||||||
'''Debug dump string output of needed replica table'''
|
"""Debug dump string output of needed replica table"""
|
||||||
return '\n'.join(str(x) for x in self.needed_rep_table)
|
return '\n'.join(str(x) for x in self.needed_rep_table)
|
||||||
|
|
||||||
def dumpstr_connect_table(self):
|
def dumpstr_connect_table(self):
|
||||||
'''Debug dump string output of connect table'''
|
"""Debug dump string output of connect table"""
|
||||||
return '\n'.join(str(x) for x in self.connect_table)
|
return '\n'.join(str(x) for x in self.connect_table)
|
||||||
|
|
||||||
def new_connection(self, options, system_flags, transport, from_dnstr,
|
def new_connection(self, options, system_flags, transport, from_dnstr,
|
||||||
@@ -911,7 +911,7 @@ class NTDSConnection(object):
|
|||||||
self.schedule = None
|
self.schedule = None
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
'''Debug dump string output of NTDSConnection object'''
|
"""Debug dump string output of NTDSConnection object"""
|
||||||
|
|
||||||
text = "%s:\n\tdn=%s" % (self.__class__.__name__, self.dnstr) +\
|
text = "%s:\n\tdn=%s" % (self.__class__.__name__, self.dnstr) +\
|
||||||
"\n\tenabled=%s" % self.enabled +\
|
"\n\tenabled=%s" % self.enabled +\
|
||||||
@@ -1306,7 +1306,7 @@ class NTDSConnection(object):
|
|||||||
return self.enabled
|
return self.enabled
|
||||||
|
|
||||||
def get_from_dnstr(self):
|
def get_from_dnstr(self):
|
||||||
'''Return fromServer dn string attribute'''
|
"""Return fromServer dn string attribute"""
|
||||||
return self.from_dnstr
|
return self.from_dnstr
|
||||||
|
|
||||||
|
|
||||||
@@ -1450,7 +1450,7 @@ class Partition(NamingContext):
|
|||||||
return needed, ro, partial
|
return needed, ro, partial
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
'''Debug dump string output of class'''
|
"""Debug dump string output of class"""
|
||||||
text = "%s" % NamingContext.__str__(self) +\
|
text = "%s" % NamingContext.__str__(self) +\
|
||||||
"\n\tpartdn=%s" % self.partstr +\
|
"\n\tpartdn=%s" % self.partstr +\
|
||||||
"".join("\n\tmsDS-NC-Replica-Locations=%s" % k for k in self.rw_location_list) +\
|
"".join("\n\tmsDS-NC-Replica-Locations=%s" % k for k in self.rw_location_list) +\
|
||||||
@@ -1717,33 +1717,33 @@ class Site(object):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def is_intrasite_topology_disabled(self):
|
def is_intrasite_topology_disabled(self):
|
||||||
'''Returns True if intra-site topology is disabled for site'''
|
"""Returns True if intra-site topology is disabled for site"""
|
||||||
return (self.site_options &
|
return (self.site_options &
|
||||||
dsdb.DS_NTDSSETTINGS_OPT_IS_AUTO_TOPOLOGY_DISABLED) != 0
|
dsdb.DS_NTDSSETTINGS_OPT_IS_AUTO_TOPOLOGY_DISABLED) != 0
|
||||||
|
|
||||||
def is_intersite_topology_disabled(self):
|
def is_intersite_topology_disabled(self):
|
||||||
'''Returns True if inter-site topology is disabled for site'''
|
"""Returns True if inter-site topology is disabled for site"""
|
||||||
return ((self.site_options &
|
return ((self.site_options &
|
||||||
dsdb.DS_NTDSSETTINGS_OPT_IS_INTER_SITE_AUTO_TOPOLOGY_DISABLED)
|
dsdb.DS_NTDSSETTINGS_OPT_IS_INTER_SITE_AUTO_TOPOLOGY_DISABLED)
|
||||||
!= 0)
|
!= 0)
|
||||||
|
|
||||||
def is_random_bridgehead_disabled(self):
|
def is_random_bridgehead_disabled(self):
|
||||||
'''Returns True if selection of random bridgehead is disabled'''
|
"""Returns True if selection of random bridgehead is disabled"""
|
||||||
return (self.site_options &
|
return (self.site_options &
|
||||||
dsdb.DS_NTDSSETTINGS_OPT_IS_RAND_BH_SELECTION_DISABLED) != 0
|
dsdb.DS_NTDSSETTINGS_OPT_IS_RAND_BH_SELECTION_DISABLED) != 0
|
||||||
|
|
||||||
def is_detect_stale_disabled(self):
|
def is_detect_stale_disabled(self):
|
||||||
'''Returns True if detect stale is disabled for site'''
|
"""Returns True if detect stale is disabled for site"""
|
||||||
return (self.site_options &
|
return (self.site_options &
|
||||||
dsdb.DS_NTDSSETTINGS_OPT_IS_TOPL_DETECT_STALE_DISABLED) != 0
|
dsdb.DS_NTDSSETTINGS_OPT_IS_TOPL_DETECT_STALE_DISABLED) != 0
|
||||||
|
|
||||||
def is_cleanup_ntdsconn_disabled(self):
|
def is_cleanup_ntdsconn_disabled(self):
|
||||||
'''Returns True if NTDS Connection cleanup is disabled for site'''
|
"""Returns True if NTDS Connection cleanup is disabled for site"""
|
||||||
return (self.site_options &
|
return (self.site_options &
|
||||||
dsdb.DS_NTDSSETTINGS_OPT_IS_TOPL_CLEANUP_DISABLED) != 0
|
dsdb.DS_NTDSSETTINGS_OPT_IS_TOPL_CLEANUP_DISABLED) != 0
|
||||||
|
|
||||||
def same_site(self, dsa):
|
def same_site(self, dsa):
|
||||||
'''Return True if dsa is in this site'''
|
"""Return True if dsa is in this site"""
|
||||||
if self.get_dsa(dsa.dsa_dnstr):
|
if self.get_dsa(dsa.dsa_dnstr):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@@ -1754,7 +1754,7 @@ class Site(object):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
'''Debug dump string output of class'''
|
"""Debug dump string output of class"""
|
||||||
text = "%s:" % self.__class__.__name__ +\
|
text = "%s:" % self.__class__.__name__ +\
|
||||||
"\n\tdn=%s" % self.site_dnstr +\
|
"\n\tdn=%s" % self.site_dnstr +\
|
||||||
"\n\toptions=0x%X" % self.site_options +\
|
"\n\toptions=0x%X" % self.site_options +\
|
||||||
@@ -1864,7 +1864,7 @@ class GraphNode(object):
|
|||||||
dsa.new_connection(opt, flags, transport, edge_dnstr, None)
|
dsa.new_connection(opt, flags, transport, edge_dnstr, None)
|
||||||
|
|
||||||
def has_sufficient_edges(self):
|
def has_sufficient_edges(self):
|
||||||
'''Return True if we have met the maximum "from edges" criteria'''
|
"""Return True if we have met the maximum "from edges" criteria"""
|
||||||
if len(self.edge_from) >= self.max_edges:
|
if len(self.edge_from) >= self.max_edges:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@@ -1883,7 +1883,7 @@ class Transport(object):
|
|||||||
self.bridgehead_list = []
|
self.bridgehead_list = []
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
'''Debug dump string output of Transport object'''
|
"""Debug dump string output of Transport object"""
|
||||||
|
|
||||||
text = "%s:\n\tdn=%s" % (self.__class__.__name__, self.dnstr) +\
|
text = "%s:\n\tdn=%s" % (self.__class__.__name__, self.dnstr) +\
|
||||||
"\n\tguid=%s" % str(self.guid) +\
|
"\n\tguid=%s" % str(self.guid) +\
|
||||||
@@ -1994,7 +1994,7 @@ class RepsFromTo(object):
|
|||||||
self.__dict__['dns_name2'] = ndr_blob.ctr.other_info.dns_name2
|
self.__dict__['dns_name2'] = ndr_blob.ctr.other_info.dns_name2
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
'''Debug dump string output of class'''
|
"""Debug dump string output of class"""
|
||||||
|
|
||||||
text = "%s:" % self.__class__.__name__ +\
|
text = "%s:" % self.__class__.__name__ +\
|
||||||
"\n\tdnstr=%s" % self.nc_dnstr +\
|
"\n\tdnstr=%s" % self.nc_dnstr +\
|
||||||
@@ -2125,7 +2125,7 @@ class SiteLink(object):
|
|||||||
self.site_list = []
|
self.site_list = []
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
'''Debug dump string output of Transport object'''
|
"""Debug dump string output of Transport object"""
|
||||||
|
|
||||||
text = "%s:\n\tdn=%s" % (self.__class__.__name__, self.dnstr) +\
|
text = "%s:\n\tdn=%s" % (self.__class__.__name__, self.dnstr) +\
|
||||||
"\n\toptions=%d" % self.options +\
|
"\n\toptions=%d" % self.options +\
|
||||||
|
|||||||
@@ -69,15 +69,15 @@ def _get_user_realm_domain(user, sam=None):
|
|||||||
|
|
||||||
|
|
||||||
def netcmd_dnsname(lp):
|
def netcmd_dnsname(lp):
|
||||||
'''return the full DNS name of our own host. Used as a default
|
"""return the full DNS name of our own host. Used as a default
|
||||||
for hostname when running status queries'''
|
for hostname when running status queries"""
|
||||||
return lp.get('netbios name').lower() + "." + lp.get('realm').lower()
|
return lp.get('netbios name').lower() + "." + lp.get('realm').lower()
|
||||||
|
|
||||||
|
|
||||||
def netcmd_finddc(lp, creds, realm=None):
|
def netcmd_finddc(lp, creds, realm=None):
|
||||||
'''Return domain-name of a writable/ldap-capable DC for the default
|
"""Return domain-name of a writable/ldap-capable DC for the default
|
||||||
domain (parameter "realm" in smb.conf) unless another realm has been
|
domain (parameter "realm" in smb.conf) unless another realm has been
|
||||||
specified as argument'''
|
specified as argument"""
|
||||||
net = Net(creds=creds, lp=lp)
|
net = Net(creds=creds, lp=lp)
|
||||||
if realm is None:
|
if realm is None:
|
||||||
realm = lp.get('realm')
|
realm = lp.get('realm')
|
||||||
@@ -87,8 +87,8 @@ def netcmd_finddc(lp, creds, realm=None):
|
|||||||
|
|
||||||
|
|
||||||
def netcmd_get_domain_infos_via_cldap(lp, creds, address=None):
|
def netcmd_get_domain_infos_via_cldap(lp, creds, address=None):
|
||||||
'''Return domain information (CLDAP record) of the ldap-capable
|
"""Return domain information (CLDAP record) of the ldap-capable
|
||||||
DC with the specified address'''
|
DC with the specified address"""
|
||||||
net = Net(creds=creds, lp=lp)
|
net = Net(creds=creds, lp=lp)
|
||||||
cldap_ret = net.finddc(address=address,
|
cldap_ret = net.finddc(address=address,
|
||||||
flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)
|
flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)
|
||||||
@@ -155,7 +155,7 @@ def timestamp_to_days(timestamp_str):
|
|||||||
|
|
||||||
|
|
||||||
def attr_default(msg, attrname, default):
|
def attr_default(msg, attrname, default):
|
||||||
'''get an attribute from a ldap msg with a default'''
|
"""get an attribute from a ldap msg with a default"""
|
||||||
if attrname in msg:
|
if attrname in msg:
|
||||||
return msg[attrname][0]
|
return msg[attrname][0]
|
||||||
return default
|
return default
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ def set_admin_password(logger, samdb):
|
|||||||
|
|
||||||
|
|
||||||
class cmd_domain_backup_online(samba.netcmd.Command):
|
class cmd_domain_backup_online(samba.netcmd.Command):
|
||||||
'''Copy a running DC's current DB into a backup tar file.
|
"""Copy a running DC's current DB into a backup tar file.
|
||||||
|
|
||||||
Takes a backup copy of the current domain from a running DC. If the domain
|
Takes a backup copy of the current domain from a running DC. If the domain
|
||||||
were to undergo a catastrophic failure, then the backup file can be used to
|
were to undergo a catastrophic failure, then the backup file can be used to
|
||||||
@@ -219,7 +219,7 @@ class cmd_domain_backup_online(samba.netcmd.Command):
|
|||||||
- all the domain's secrets are included in the backup file.
|
- all the domain's secrets are included in the backup file.
|
||||||
- although the DB contents can be untarred and examined manually, you need
|
- although the DB contents can be untarred and examined manually, you need
|
||||||
to run 'samba-tool domain backup restore' before you can start a Samba DC
|
to run 'samba-tool domain backup restore' before you can start a Samba DC
|
||||||
from the backup file.'''
|
from the backup file."""
|
||||||
|
|
||||||
synopsis = "%prog --server=<DC-to-backup> --targetdir=<output-dir>"
|
synopsis = "%prog --server=<DC-to-backup> --targetdir=<output-dir>"
|
||||||
takes_optiongroups = {
|
takes_optiongroups = {
|
||||||
@@ -304,7 +304,7 @@ class cmd_domain_backup_online(samba.netcmd.Command):
|
|||||||
|
|
||||||
|
|
||||||
class cmd_domain_backup_restore(cmd_fsmo_seize):
|
class cmd_domain_backup_restore(cmd_fsmo_seize):
|
||||||
'''Restore the domain's DB from a backup-file.
|
"""Restore the domain's DB from a backup-file.
|
||||||
|
|
||||||
This restores a previously backed up copy of the domain's DB on a new DC.
|
This restores a previously backed up copy of the domain's DB on a new DC.
|
||||||
|
|
||||||
@@ -317,7 +317,7 @@ class cmd_domain_backup_restore(cmd_fsmo_seize):
|
|||||||
be joined to the new DC to recover the network.
|
be joined to the new DC to recover the network.
|
||||||
|
|
||||||
Note that this command should be run as the root user - it will fail
|
Note that this command should be run as the root user - it will fail
|
||||||
otherwise.'''
|
otherwise."""
|
||||||
|
|
||||||
synopsis = ("%prog --backup-file=<tar-file> --targetdir=<output-dir> "
|
synopsis = ("%prog --backup-file=<tar-file> --targetdir=<output-dir> "
|
||||||
"--newservername=<DC-name>")
|
"--newservername=<DC-name>")
|
||||||
@@ -339,10 +339,10 @@ class cmd_domain_backup_restore(cmd_fsmo_seize):
|
|||||||
|
|
||||||
def register_dns_zone(self, logger, samdb, lp, ntdsguid, host_ip,
|
def register_dns_zone(self, logger, samdb, lp, ntdsguid, host_ip,
|
||||||
host_ip6, site):
|
host_ip6, site):
|
||||||
'''
|
"""
|
||||||
Registers the new realm's DNS objects when a renamed domain backup
|
Registers the new realm's DNS objects when a renamed domain backup
|
||||||
is restored.
|
is restored.
|
||||||
'''
|
"""
|
||||||
names = guess_names(lp)
|
names = guess_names(lp)
|
||||||
domaindn = names.domaindn
|
domaindn = names.domaindn
|
||||||
forestdn = samdb.get_root_basedn().get_linearized()
|
forestdn = samdb.get_root_basedn().get_linearized()
|
||||||
@@ -371,7 +371,7 @@ class cmd_domain_backup_restore(cmd_fsmo_seize):
|
|||||||
dnsadmins_sid, add_root=False)
|
dnsadmins_sid, add_root=False)
|
||||||
|
|
||||||
def fix_old_dc_references(self, samdb):
|
def fix_old_dc_references(self, samdb):
|
||||||
'''Fixes attributes that reference the old/removed DCs'''
|
"""Fixes attributes that reference the old/removed DCs"""
|
||||||
|
|
||||||
# we just want to fix up DB problems here that were introduced by us
|
# we just want to fix up DB problems here that were introduced by us
|
||||||
# removing the old DCs. We restrict what we fix up so that the restored
|
# removing the old DCs. We restrict what we fix up so that the restored
|
||||||
@@ -396,7 +396,7 @@ class cmd_domain_backup_restore(cmd_fsmo_seize):
|
|||||||
samdb.transaction_commit()
|
samdb.transaction_commit()
|
||||||
|
|
||||||
def create_default_site(self, samdb, logger):
|
def create_default_site(self, samdb, logger):
|
||||||
'''Creates the default site, if it doesn't already exist'''
|
"""Creates the default site, if it doesn't already exist"""
|
||||||
|
|
||||||
sitename = DEFAULTSITE
|
sitename = DEFAULTSITE
|
||||||
search_expr = "(&(cn={0})(objectclass=site))".format(sitename)
|
search_expr = "(&(cn={0})(objectclass=site))".format(sitename)
|
||||||
@@ -692,7 +692,7 @@ class cmd_domain_backup_restore(cmd_fsmo_seize):
|
|||||||
|
|
||||||
|
|
||||||
class cmd_domain_backup_rename(samba.netcmd.Command):
|
class cmd_domain_backup_rename(samba.netcmd.Command):
|
||||||
'''Copy a running DC's DB to backup file, renaming the domain in the process.
|
"""Copy a running DC's DB to backup file, renaming the domain in the process.
|
||||||
|
|
||||||
Where <new-domain> is the new domain's NetBIOS name, and <new-dnsrealm> is
|
Where <new-domain> is the new domain's NetBIOS name, and <new-dnsrealm> is
|
||||||
the new domain's realm in DNS form.
|
the new domain's realm in DNS form.
|
||||||
@@ -718,7 +718,7 @@ class cmd_domain_backup_rename(samba.netcmd.Command):
|
|||||||
in order to work (they will still refer to the old DC's IP instead of the
|
in order to work (they will still refer to the old DC's IP instead of the
|
||||||
new DC's address).
|
new DC's address).
|
||||||
- we recommend that you only use this option if you know what you're doing.
|
- we recommend that you only use this option if you know what you're doing.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
synopsis = ("%prog <new-domain> <new-dnsrealm> --server=<DC-to-backup> "
|
synopsis = ("%prog <new-domain> <new-dnsrealm> --server=<DC-to-backup> "
|
||||||
"--targetdir=<output-dir>")
|
"--targetdir=<output-dir>")
|
||||||
@@ -744,7 +744,7 @@ class cmd_domain_backup_rename(samba.netcmd.Command):
|
|||||||
takes_args = ["new_domain_name", "new_dns_realm"]
|
takes_args = ["new_domain_name", "new_dns_realm"]
|
||||||
|
|
||||||
def update_dns_root(self, logger, samdb, old_realm, delete_old_dns):
|
def update_dns_root(self, logger, samdb, old_realm, delete_old_dns):
|
||||||
'''Updates dnsRoot for the partition objects to reflect the rename'''
|
"""Updates dnsRoot for the partition objects to reflect the rename"""
|
||||||
|
|
||||||
# lookup the crossRef objects that hold the old realm's dnsRoot
|
# lookup the crossRef objects that hold the old realm's dnsRoot
|
||||||
partitions_dn = samdb.get_partitions_dn()
|
partitions_dn = samdb.get_partitions_dn()
|
||||||
@@ -783,7 +783,7 @@ class cmd_domain_backup_rename(samba.netcmd.Command):
|
|||||||
# Updates the CN=<domain>,CN=Partitions,CN=Configuration,... object to
|
# Updates the CN=<domain>,CN=Partitions,CN=Configuration,... object to
|
||||||
# reflect the domain rename
|
# reflect the domain rename
|
||||||
def rename_domain_partition(self, logger, samdb, new_netbios_name):
|
def rename_domain_partition(self, logger, samdb, new_netbios_name):
|
||||||
'''Renames the domain partition object and updates its nETBIOSName'''
|
"""Renames the domain partition object and updates its nETBIOSName"""
|
||||||
|
|
||||||
# lookup the crossRef object that holds the nETBIOSName (nCName has
|
# lookup the crossRef object that holds the nETBIOSName (nCName has
|
||||||
# already been updated by this point, but the netBIOS hasn't)
|
# already been updated by this point, but the netBIOS hasn't)
|
||||||
@@ -822,7 +822,7 @@ class cmd_domain_backup_rename(samba.netcmd.Command):
|
|||||||
samdb.delete(dn, ["tree_delete:1"])
|
samdb.delete(dn, ["tree_delete:1"])
|
||||||
|
|
||||||
def fix_old_dn_attributes(self, samdb):
|
def fix_old_dn_attributes(self, samdb):
|
||||||
'''Fixes attributes (i.e. objectCategory) that still use the old DN'''
|
"""Fixes attributes (i.e. objectCategory) that still use the old DN"""
|
||||||
|
|
||||||
samdb.transaction_start()
|
samdb.transaction_start()
|
||||||
# Just fix any mismatches in DN detected (leave any other errors)
|
# Just fix any mismatches in DN detected (leave any other errors)
|
||||||
@@ -942,7 +942,7 @@ class cmd_domain_backup_rename(samba.netcmd.Command):
|
|||||||
|
|
||||||
|
|
||||||
class cmd_domain_backup_offline(samba.netcmd.Command):
|
class cmd_domain_backup_offline(samba.netcmd.Command):
|
||||||
'''Backup the local domain directories safely into a tar file.
|
"""Backup the local domain directories safely into a tar file.
|
||||||
|
|
||||||
Takes a backup copy of the current domain from the local files on disk,
|
Takes a backup copy of the current domain from the local files on disk,
|
||||||
with proper locking of the DB to ensure consistency. If the domain were to
|
with proper locking of the DB to ensure consistency. If the domain were to
|
||||||
@@ -953,7 +953,7 @@ class cmd_domain_backup_offline(samba.netcmd.Command):
|
|||||||
- a backup can be created even if the DC isn't currently running.
|
- a backup can be created even if the DC isn't currently running.
|
||||||
- includes non-replicated attributes that an online backup wouldn't store.
|
- includes non-replicated attributes that an online backup wouldn't store.
|
||||||
- takes a copy of the raw database files, which has the risk that any
|
- takes a copy of the raw database files, which has the risk that any
|
||||||
hidden problems in the DB are preserved in the backup.'''
|
hidden problems in the DB are preserved in the backup."""
|
||||||
|
|
||||||
synopsis = "%prog [options]"
|
synopsis = "%prog [options]"
|
||||||
takes_optiongroups = {
|
takes_optiongroups = {
|
||||||
@@ -1249,7 +1249,7 @@ class cmd_domain_backup_offline(samba.netcmd.Command):
|
|||||||
|
|
||||||
|
|
||||||
class cmd_domain_backup(samba.netcmd.SuperCommand):
|
class cmd_domain_backup(samba.netcmd.SuperCommand):
|
||||||
'''Create or restore a backup of the domain.'''
|
"""Create or restore a backup of the domain."""
|
||||||
subcommands = {'offline': cmd_domain_backup_offline(),
|
subcommands = {'offline': cmd_domain_backup_offline(),
|
||||||
'online': cmd_domain_backup_online(),
|
'online': cmd_domain_backup_online(),
|
||||||
'rename': cmd_domain_backup_rename(),
|
'rename': cmd_domain_backup_rename(),
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ from samba.common import get_string
|
|||||||
from samba.samdb import get_default_backend_store
|
from samba.samdb import get_default_backend_store
|
||||||
|
|
||||||
def drsuapi_connect(ctx):
|
def drsuapi_connect(ctx):
|
||||||
'''make a DRSUAPI connection to the server'''
|
"""make a DRSUAPI connection to the server"""
|
||||||
try:
|
try:
|
||||||
(ctx.drsuapi, ctx.drsuapi_handle, ctx.bind_supported_extensions) = drs_utils.drsuapi_connect(ctx.server, ctx.lp, ctx.creds)
|
(ctx.drsuapi, ctx.drsuapi_handle, ctx.bind_supported_extensions) = drs_utils.drsuapi_connect(ctx.server, ctx.lp, ctx.creds)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -58,7 +58,7 @@ def drsuapi_connect(ctx):
|
|||||||
|
|
||||||
|
|
||||||
def samdb_connect(ctx):
|
def samdb_connect(ctx):
|
||||||
'''make a ldap connection to the server'''
|
"""make a ldap connection to the server"""
|
||||||
try:
|
try:
|
||||||
ctx.samdb = SamDB(url="ldap://%s" % ctx.server,
|
ctx.samdb = SamDB(url="ldap://%s" % ctx.server,
|
||||||
session_info=system_session(),
|
session_info=system_session(),
|
||||||
@@ -68,7 +68,7 @@ def samdb_connect(ctx):
|
|||||||
|
|
||||||
|
|
||||||
def drs_errmsg(werr):
|
def drs_errmsg(werr):
|
||||||
'''return "was successful" or an error string'''
|
"""return "was successful" or an error string"""
|
||||||
(ecode, estring) = werr
|
(ecode, estring) = werr
|
||||||
if ecode == 0:
|
if ecode == 0:
|
||||||
return "was successful"
|
return "was successful"
|
||||||
@@ -76,7 +76,7 @@ def drs_errmsg(werr):
|
|||||||
|
|
||||||
|
|
||||||
def drs_parse_ntds_dn(ntds_dn):
|
def drs_parse_ntds_dn(ntds_dn):
|
||||||
'''parse a NTDS DN returning a site and server'''
|
"""parse a NTDS DN returning a site and server"""
|
||||||
a = ntds_dn.split(',')
|
a = ntds_dn.split(',')
|
||||||
if a[0] != "CN=NTDS Settings" or a[2] != "CN=Servers" or a[4] != 'CN=Sites':
|
if a[0] != "CN=NTDS Settings" or a[2] != "CN=Servers" or a[4] != 'CN=Sites':
|
||||||
raise RuntimeError("bad NTDS DN %s" % ntds_dn)
|
raise RuntimeError("bad NTDS DN %s" % ntds_dn)
|
||||||
@@ -153,7 +153,7 @@ class cmd_drs_showrepl(Command):
|
|||||||
return d
|
return d
|
||||||
|
|
||||||
def print_neighbour(self, d):
|
def print_neighbour(self, d):
|
||||||
'''print one set of neighbour information'''
|
"""print one set of neighbour information"""
|
||||||
self.message("%s" % d['NC dn'])
|
self.message("%s" % d['NC dn'])
|
||||||
if 'DSA' in d:
|
if 'DSA' in d:
|
||||||
self.message("\t%s via RPC" % d['DSA'])
|
self.message("\t%s via RPC" % d['DSA'])
|
||||||
@@ -434,7 +434,7 @@ class cmd_drs_replicate(Command):
|
|||||||
def drs_local_replicate(self, SOURCE_DC, NC, full_sync=False,
|
def drs_local_replicate(self, SOURCE_DC, NC, full_sync=False,
|
||||||
single_object=False,
|
single_object=False,
|
||||||
sync_forced=False):
|
sync_forced=False):
|
||||||
'''replicate from a source DC to the local SAM'''
|
"""replicate from a source DC to the local SAM"""
|
||||||
|
|
||||||
self.server = SOURCE_DC
|
self.server = SOURCE_DC
|
||||||
drsuapi_connect(self)
|
drsuapi_connect(self)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ from samba.samba3 import libsmb_samba_internal as libsmb
|
|||||||
from samba.netcmd import CommandError
|
from samba.netcmd import CommandError
|
||||||
|
|
||||||
def get_gpo_dn(samdb, gpo):
|
def get_gpo_dn(samdb, gpo):
|
||||||
'''Construct the DN for gpo'''
|
"""Construct the DN for gpo"""
|
||||||
|
|
||||||
dn = samdb.get_default_basedn()
|
dn = samdb.get_default_basedn()
|
||||||
dn.add_child(ldb.Dn(samdb, "CN=Policies,CN=System"))
|
dn.add_child(ldb.Dn(samdb, "CN=Policies,CN=System"))
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ from samba.gp.gpclass import register_gp_extension, list_gp_extensions, \
|
|||||||
|
|
||||||
|
|
||||||
def gpo_flags_string(value):
|
def gpo_flags_string(value):
|
||||||
'''return gpo flags string'''
|
"""return gpo flags string"""
|
||||||
flags = policy.get_gpo_flags(value)
|
flags = policy.get_gpo_flags(value)
|
||||||
if not flags:
|
if not flags:
|
||||||
ret = 'NONE'
|
ret = 'NONE'
|
||||||
@@ -99,7 +99,7 @@ def gpo_flags_string(value):
|
|||||||
|
|
||||||
|
|
||||||
def gplink_options_string(value):
|
def gplink_options_string(value):
|
||||||
'''return gplink options string'''
|
"""return gplink options string"""
|
||||||
options = policy.get_gplink_options(value)
|
options = policy.get_gplink_options(value)
|
||||||
if not options:
|
if not options:
|
||||||
ret = 'NONE'
|
ret = 'NONE'
|
||||||
@@ -109,7 +109,7 @@ def gplink_options_string(value):
|
|||||||
|
|
||||||
|
|
||||||
def parse_gplink(gplink):
|
def parse_gplink(gplink):
|
||||||
'''parse a gPLink into an array of dn and options'''
|
"""parse a gPLink into an array of dn and options"""
|
||||||
ret = []
|
ret = []
|
||||||
|
|
||||||
if gplink.strip() == '':
|
if gplink.strip() == '':
|
||||||
@@ -127,14 +127,14 @@ def parse_gplink(gplink):
|
|||||||
|
|
||||||
|
|
||||||
def encode_gplink(gplist):
|
def encode_gplink(gplist):
|
||||||
'''Encode an array of dn and options into gPLink string'''
|
"""Encode an array of dn and options into gPLink string"""
|
||||||
ret = "".join("[LDAP://%s;%d]" % (g['dn'], g['options']) for g in gplist)
|
ret = "".join("[LDAP://%s;%d]" % (g['dn'], g['options']) for g in gplist)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def dc_url(lp, creds, url=None, dc=None):
|
def dc_url(lp, creds, url=None, dc=None):
|
||||||
'''If URL is not specified, return URL for writable DC.
|
"""If URL is not specified, return URL for writable DC.
|
||||||
If dc is provided, use that to construct ldap URL'''
|
If dc is provided, use that to construct ldap URL"""
|
||||||
|
|
||||||
if url is None:
|
if url is None:
|
||||||
if dc is None:
|
if dc is None:
|
||||||
@@ -151,7 +151,7 @@ def get_gpo_info(samdb, gpo=None, displayname=None, dn=None,
|
|||||||
security.SECINFO_GROUP |
|
security.SECINFO_GROUP |
|
||||||
security.SECINFO_DACL |
|
security.SECINFO_DACL |
|
||||||
security.SECINFO_SACL)):
|
security.SECINFO_SACL)):
|
||||||
'''Get GPO information using gpo, displayname or dn'''
|
"""Get GPO information using gpo, displayname or dn"""
|
||||||
|
|
||||||
policies_dn = samdb.get_default_basedn()
|
policies_dn = samdb.get_default_basedn()
|
||||||
policies_dn.add_child(ldb.Dn(samdb, "CN=Policies,CN=System"))
|
policies_dn.add_child(ldb.Dn(samdb, "CN=Policies,CN=System"))
|
||||||
@@ -193,7 +193,7 @@ def get_gpo_info(samdb, gpo=None, displayname=None, dn=None,
|
|||||||
|
|
||||||
|
|
||||||
def get_gpo_containers(samdb, gpo):
|
def get_gpo_containers(samdb, gpo):
|
||||||
'''lists dn of containers for a GPO'''
|
"""lists dn of containers for a GPO"""
|
||||||
|
|
||||||
search_expr = "(&(objectClass=*)(gPLink=*%s*))" % gpo
|
search_expr = "(&(objectClass=*)(gPLink=*%s*))" % gpo
|
||||||
try:
|
try:
|
||||||
@@ -205,7 +205,7 @@ def get_gpo_containers(samdb, gpo):
|
|||||||
|
|
||||||
|
|
||||||
def del_gpo_link(samdb, container_dn, gpo):
|
def del_gpo_link(samdb, container_dn, gpo):
|
||||||
'''delete GPO link for the container'''
|
"""delete GPO link for the container"""
|
||||||
# Check if valid Container DN and get existing GPlinks
|
# Check if valid Container DN and get existing GPlinks
|
||||||
try:
|
try:
|
||||||
msg = samdb.search(base=container_dn, scope=ldb.SCOPE_BASE,
|
msg = samdb.search(base=container_dn, scope=ldb.SCOPE_BASE,
|
||||||
@@ -243,7 +243,7 @@ def del_gpo_link(samdb, container_dn, gpo):
|
|||||||
|
|
||||||
|
|
||||||
def parse_unc(unc):
|
def parse_unc(unc):
|
||||||
'''Parse UNC string into a hostname, a service, and a filepath'''
|
"""Parse UNC string into a hostname, a service, and a filepath"""
|
||||||
tmp = []
|
tmp = []
|
||||||
if unc.startswith('\\\\'):
|
if unc.startswith('\\\\'):
|
||||||
tmp = unc[2:].split('\\', 2)
|
tmp = unc[2:].split('\\', 2)
|
||||||
@@ -419,7 +419,7 @@ class GPOCommand(Command):
|
|||||||
return tmpdir, gpodir
|
return tmpdir, gpodir
|
||||||
|
|
||||||
def samdb_connect(self):
|
def samdb_connect(self):
|
||||||
'''make a ldap connection to the server'''
|
"""make a ldap connection to the server"""
|
||||||
try:
|
try:
|
||||||
self.samdb = SamDB(url=self.url,
|
self.samdb = SamDB(url=self.url,
|
||||||
session_info=system_session(),
|
session_info=system_session(),
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ class cmd_rodc_preload(Command):
|
|||||||
takes_args = ["account*"]
|
takes_args = ["account*"]
|
||||||
|
|
||||||
def get_dn(self, samdb, account):
|
def get_dn(self, samdb, account):
|
||||||
'''work out what DN they meant'''
|
"""work out what DN they meant"""
|
||||||
|
|
||||||
# we accept the account in SID, accountname or DN form
|
# we accept the account in SID, accountname or DN form
|
||||||
if account[0:2] == 'S-':
|
if account[0:2] == 'S-':
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class XattrBackendError(Exception):
|
|||||||
|
|
||||||
|
|
||||||
def checkset_backend(lp, backend, eadbfile):
|
def checkset_backend(lp, backend, eadbfile):
|
||||||
'''return the path to the eadb, or None'''
|
"""return the path to the eadb, or None"""
|
||||||
if backend is None:
|
if backend is None:
|
||||||
xattr_tdb = lp.get("xattr_tdb:file")
|
xattr_tdb = lp.get("xattr_tdb:file")
|
||||||
if xattr_tdb is not None:
|
if xattr_tdb is not None:
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ class RegistryGroupPolicies(object):
|
|||||||
self.samdb.modify(m)
|
self.samdb.modify(m)
|
||||||
|
|
||||||
def remove_s(self, json_input):
|
def remove_s(self, json_input):
|
||||||
'''remove_s
|
"""remove_s
|
||||||
json_input: JSON list of entries to remove from GPO
|
json_input: JSON list of entries to remove from GPO
|
||||||
|
|
||||||
Example json_input:
|
Example json_input:
|
||||||
@@ -272,7 +272,7 @@ class RegistryGroupPolicies(object):
|
|||||||
"class": "USER",
|
"class": "USER",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
'''
|
"""
|
||||||
self.__validate_json(json_input, remove=True)
|
self.__validate_json(json_input, remove=True)
|
||||||
user_pol_data = self.__load_registry_pol(self.pol_file % 'User')
|
user_pol_data = self.__load_registry_pol(self.pol_file % 'User')
|
||||||
machine_pol_data = self.__load_registry_pol(self.pol_file % 'Machine')
|
machine_pol_data = self.__load_registry_pol(self.pol_file % 'Machine')
|
||||||
@@ -298,7 +298,7 @@ class RegistryGroupPolicies(object):
|
|||||||
self.increment_gpt_ini(machine_changed, user_changed)
|
self.increment_gpt_ini(machine_changed, user_changed)
|
||||||
|
|
||||||
def merge_s(self, json_input):
|
def merge_s(self, json_input):
|
||||||
'''merge_s
|
"""merge_s
|
||||||
json_input: JSON list of entries to merge into GPO
|
json_input: JSON list of entries to merge into GPO
|
||||||
|
|
||||||
Example json_input:
|
Example json_input:
|
||||||
@@ -318,7 +318,7 @@ class RegistryGroupPolicies(object):
|
|||||||
"data": "google.com"
|
"data": "google.com"
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
'''
|
"""
|
||||||
self.__validate_json(json_input)
|
self.__validate_json(json_input)
|
||||||
user_pol_data = self.__load_registry_pol(self.pol_file % 'User')
|
user_pol_data = self.__load_registry_pol(self.pol_file % 'User')
|
||||||
machine_pol_data = self.__load_registry_pol(self.pol_file % 'Machine')
|
machine_pol_data = self.__load_registry_pol(self.pol_file % 'Machine')
|
||||||
@@ -344,7 +344,7 @@ class RegistryGroupPolicies(object):
|
|||||||
self.increment_gpt_ini(machine_changed, user_changed)
|
self.increment_gpt_ini(machine_changed, user_changed)
|
||||||
|
|
||||||
def replace_s(self, json_input):
|
def replace_s(self, json_input):
|
||||||
'''replace_s
|
"""replace_s
|
||||||
json_input: JSON list of entries to replace entries in GPO
|
json_input: JSON list of entries to replace entries in GPO
|
||||||
|
|
||||||
Example json_input:
|
Example json_input:
|
||||||
@@ -362,7 +362,7 @@ class RegistryGroupPolicies(object):
|
|||||||
"data": "google.com"
|
"data": "google.com"
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
'''
|
"""
|
||||||
self.__validate_json(json_input)
|
self.__validate_json(json_input)
|
||||||
user_pol_data = preg.file()
|
user_pol_data = preg.file()
|
||||||
machine_pol_data = preg.file()
|
machine_pol_data = preg.file()
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ class SamDB(samba.Ldb):
|
|||||||
dsdb._dsdb_set_am_rodc(self, am_rodc)
|
dsdb._dsdb_set_am_rodc(self, am_rodc)
|
||||||
|
|
||||||
def connect(self, url=None, flags=0, options=None):
|
def connect(self, url=None, flags=0, options=None):
|
||||||
'''connect to the database'''
|
"""connect to the database"""
|
||||||
if self.lp is not None and not os.path.exists(url):
|
if self.lp is not None and not os.path.exists(url):
|
||||||
url = self.lp.private_path(url)
|
url = self.lp.private_path(url)
|
||||||
self.url = url
|
self.url = url
|
||||||
@@ -107,19 +107,19 @@ class SamDB(samba.Ldb):
|
|||||||
options=options)
|
options=options)
|
||||||
|
|
||||||
def am_rodc(self):
|
def am_rodc(self):
|
||||||
'''return True if we are an RODC'''
|
"""return True if we are an RODC"""
|
||||||
return dsdb._am_rodc(self)
|
return dsdb._am_rodc(self)
|
||||||
|
|
||||||
def am_pdc(self):
|
def am_pdc(self):
|
||||||
'''return True if we are an PDC emulator'''
|
"""return True if we are an PDC emulator"""
|
||||||
return dsdb._am_pdc(self)
|
return dsdb._am_pdc(self)
|
||||||
|
|
||||||
def domain_dn(self):
|
def domain_dn(self):
|
||||||
'''return the domain DN'''
|
"""return the domain DN"""
|
||||||
return str(self.get_default_basedn())
|
return str(self.get_default_basedn())
|
||||||
|
|
||||||
def schema_dn(self):
|
def schema_dn(self):
|
||||||
'''return the schema partition dn'''
|
"""return the schema partition dn"""
|
||||||
return str(self.get_schema_basedn())
|
return str(self.get_schema_basedn())
|
||||||
|
|
||||||
def disable_account(self, search_filter):
|
def disable_account(self, search_filter):
|
||||||
@@ -983,29 +983,29 @@ accountExpires: %u
|
|||||||
|
|
||||||
def get_attid_from_lDAPDisplayName(self, ldap_display_name,
|
def get_attid_from_lDAPDisplayName(self, ldap_display_name,
|
||||||
is_schema_nc=False):
|
is_schema_nc=False):
|
||||||
'''return the attribute ID for a LDAP attribute as an integer as found in DRSUAPI'''
|
"""return the attribute ID for a LDAP attribute as an integer as found in DRSUAPI"""
|
||||||
return dsdb._dsdb_get_attid_from_lDAPDisplayName(self,
|
return dsdb._dsdb_get_attid_from_lDAPDisplayName(self,
|
||||||
ldap_display_name, is_schema_nc)
|
ldap_display_name, is_schema_nc)
|
||||||
|
|
||||||
def get_syntax_oid_from_lDAPDisplayName(self, ldap_display_name):
|
def get_syntax_oid_from_lDAPDisplayName(self, ldap_display_name):
|
||||||
'''return the syntax OID for a LDAP attribute as a string'''
|
"""return the syntax OID for a LDAP attribute as a string"""
|
||||||
return dsdb._dsdb_get_syntax_oid_from_lDAPDisplayName(self, ldap_display_name)
|
return dsdb._dsdb_get_syntax_oid_from_lDAPDisplayName(self, ldap_display_name)
|
||||||
|
|
||||||
def get_systemFlags_from_lDAPDisplayName(self, ldap_display_name):
|
def get_systemFlags_from_lDAPDisplayName(self, ldap_display_name):
|
||||||
'''return the systemFlags for a LDAP attribute as a integer'''
|
"""return the systemFlags for a LDAP attribute as a integer"""
|
||||||
return dsdb._dsdb_get_systemFlags_from_lDAPDisplayName(self, ldap_display_name)
|
return dsdb._dsdb_get_systemFlags_from_lDAPDisplayName(self, ldap_display_name)
|
||||||
|
|
||||||
def get_linkId_from_lDAPDisplayName(self, ldap_display_name):
|
def get_linkId_from_lDAPDisplayName(self, ldap_display_name):
|
||||||
'''return the linkID for a LDAP attribute as a integer'''
|
"""return the linkID for a LDAP attribute as a integer"""
|
||||||
return dsdb._dsdb_get_linkId_from_lDAPDisplayName(self, ldap_display_name)
|
return dsdb._dsdb_get_linkId_from_lDAPDisplayName(self, ldap_display_name)
|
||||||
|
|
||||||
def get_lDAPDisplayName_by_attid(self, attid):
|
def get_lDAPDisplayName_by_attid(self, attid):
|
||||||
'''return the lDAPDisplayName from an integer DRS attribute ID'''
|
"""return the lDAPDisplayName from an integer DRS attribute ID"""
|
||||||
return dsdb._dsdb_get_lDAPDisplayName_by_attid(self, attid)
|
return dsdb._dsdb_get_lDAPDisplayName_by_attid(self, attid)
|
||||||
|
|
||||||
def get_backlink_from_lDAPDisplayName(self, ldap_display_name):
|
def get_backlink_from_lDAPDisplayName(self, ldap_display_name):
|
||||||
'''return the attribute name of the corresponding backlink from the name
|
"""return the attribute name of the corresponding backlink from the name
|
||||||
of a forward link attribute. If there is no backlink return None'''
|
of a forward link attribute. If there is no backlink return None"""
|
||||||
return dsdb._dsdb_get_backlink_from_lDAPDisplayName(self, ldap_display_name)
|
return dsdb._dsdb_get_backlink_from_lDAPDisplayName(self, ldap_display_name)
|
||||||
|
|
||||||
def set_ntds_settings_dn(self, ntds_settings_dn):
|
def set_ntds_settings_dn(self, ntds_settings_dn):
|
||||||
@@ -1090,11 +1090,11 @@ schemaUpdateNow: 1
|
|||||||
self.modify_ldif(ldif)
|
self.modify_ldif(ldif)
|
||||||
|
|
||||||
def dsdb_DsReplicaAttribute(self, ldb, ldap_display_name, ldif_elements):
|
def dsdb_DsReplicaAttribute(self, ldb, ldap_display_name, ldif_elements):
|
||||||
'''convert a list of attribute values to a DRSUAPI DsReplicaAttribute'''
|
"""convert a list of attribute values to a DRSUAPI DsReplicaAttribute"""
|
||||||
return dsdb._dsdb_DsReplicaAttribute(ldb, ldap_display_name, ldif_elements)
|
return dsdb._dsdb_DsReplicaAttribute(ldb, ldap_display_name, ldif_elements)
|
||||||
|
|
||||||
def dsdb_normalise_attributes(self, ldb, ldap_display_name, ldif_elements):
|
def dsdb_normalise_attributes(self, ldb, ldap_display_name, ldif_elements):
|
||||||
'''normalise a list of attribute values'''
|
"""normalise a list of attribute values"""
|
||||||
return dsdb._dsdb_normalise_attributes(ldb, ldap_display_name, ldif_elements)
|
return dsdb._dsdb_normalise_attributes(ldb, ldap_display_name, ldif_elements)
|
||||||
|
|
||||||
def get_attribute_from_attid(self, attid):
|
def get_attribute_from_attid(self, attid):
|
||||||
@@ -1366,17 +1366,17 @@ schemaUpdateNow: 1
|
|||||||
return seq
|
return seq
|
||||||
|
|
||||||
def get_dsServiceName(self):
|
def get_dsServiceName(self):
|
||||||
'''get the NTDS DN from the rootDSE'''
|
"""get the NTDS DN from the rootDSE"""
|
||||||
res = self.search(base="", scope=ldb.SCOPE_BASE, attrs=["dsServiceName"])
|
res = self.search(base="", scope=ldb.SCOPE_BASE, attrs=["dsServiceName"])
|
||||||
return str(res[0]["dsServiceName"][0])
|
return str(res[0]["dsServiceName"][0])
|
||||||
|
|
||||||
def get_serverName(self):
|
def get_serverName(self):
|
||||||
'''get the server DN from the rootDSE'''
|
"""get the server DN from the rootDSE"""
|
||||||
res = self.search(base="", scope=ldb.SCOPE_BASE, attrs=["serverName"])
|
res = self.search(base="", scope=ldb.SCOPE_BASE, attrs=["serverName"])
|
||||||
return str(res[0]["serverName"][0])
|
return str(res[0]["serverName"][0])
|
||||||
|
|
||||||
def dns_lookup(self, dns_name, dns_partition=None):
|
def dns_lookup(self, dns_name, dns_partition=None):
|
||||||
'''Do a DNS lookup in the database, returns the NDR database structures'''
|
"""Do a DNS lookup in the database, returns the NDR database structures"""
|
||||||
if dns_partition is None:
|
if dns_partition is None:
|
||||||
return dsdb_dns.lookup(self, dns_name)
|
return dsdb_dns.lookup(self, dns_name)
|
||||||
else:
|
else:
|
||||||
@@ -1384,28 +1384,28 @@ schemaUpdateNow: 1
|
|||||||
dns_partition=dns_partition)
|
dns_partition=dns_partition)
|
||||||
|
|
||||||
def dns_extract(self, el):
|
def dns_extract(self, el):
|
||||||
'''Return the NDR database structures from a dnsRecord element'''
|
"""Return the NDR database structures from a dnsRecord element"""
|
||||||
return dsdb_dns.extract(self, el)
|
return dsdb_dns.extract(self, el)
|
||||||
|
|
||||||
def dns_replace(self, dns_name, new_records):
|
def dns_replace(self, dns_name, new_records):
|
||||||
'''Do a DNS modification on the database, sets the NDR database
|
"""Do a DNS modification on the database, sets the NDR database
|
||||||
structures on a DNS name
|
structures on a DNS name
|
||||||
'''
|
"""
|
||||||
return dsdb_dns.replace(self, dns_name, new_records)
|
return dsdb_dns.replace(self, dns_name, new_records)
|
||||||
|
|
||||||
def dns_replace_by_dn(self, dn, new_records):
|
def dns_replace_by_dn(self, dn, new_records):
|
||||||
'''Do a DNS modification on the database, sets the NDR database
|
"""Do a DNS modification on the database, sets the NDR database
|
||||||
structures on a LDB DN
|
structures on a LDB DN
|
||||||
|
|
||||||
This routine is important because if the last record on the DN
|
This routine is important because if the last record on the DN
|
||||||
is removed, this routine will put a tombstone in the record.
|
is removed, this routine will put a tombstone in the record.
|
||||||
'''
|
"""
|
||||||
return dsdb_dns.replace_by_dn(self, dn, new_records)
|
return dsdb_dns.replace_by_dn(self, dn, new_records)
|
||||||
|
|
||||||
def garbage_collect_tombstones(self, dn, current_time,
|
def garbage_collect_tombstones(self, dn, current_time,
|
||||||
tombstone_lifetime=None):
|
tombstone_lifetime=None):
|
||||||
'''garbage_collect_tombstones(lp, samdb, [dn], current_time, tombstone_lifetime)
|
"""garbage_collect_tombstones(lp, samdb, [dn], current_time, tombstone_lifetime)
|
||||||
-> (num_objects_expunged, num_links_expunged)'''
|
-> (num_objects_expunged, num_links_expunged)"""
|
||||||
|
|
||||||
if not is_ad_dc_built():
|
if not is_ad_dc_built():
|
||||||
raise SamDBError('Cannot garbage collect tombstones: '
|
raise SamDBError('Cannot garbage collect tombstones: '
|
||||||
@@ -1420,33 +1420,33 @@ schemaUpdateNow: 1
|
|||||||
tombstone_lifetime)
|
tombstone_lifetime)
|
||||||
|
|
||||||
def create_own_rid_set(self):
|
def create_own_rid_set(self):
|
||||||
'''create a RID set for this DSA'''
|
"""create a RID set for this DSA"""
|
||||||
return dsdb._dsdb_create_own_rid_set(self)
|
return dsdb._dsdb_create_own_rid_set(self)
|
||||||
|
|
||||||
def allocate_rid(self):
|
def allocate_rid(self):
|
||||||
'''return a new RID from the RID Pool on this DSA'''
|
"""return a new RID from the RID Pool on this DSA"""
|
||||||
return dsdb._dsdb_allocate_rid(self)
|
return dsdb._dsdb_allocate_rid(self)
|
||||||
|
|
||||||
def next_free_rid(self):
|
def next_free_rid(self):
|
||||||
'''return the next free RID from the RID Pool on this DSA.
|
"""return the next free RID from the RID Pool on this DSA.
|
||||||
|
|
||||||
:note: This function is not intended for general use, and care must be
|
:note: This function is not intended for general use, and care must be
|
||||||
taken if it is used to generate objectSIDs. The returned RID is not
|
taken if it is used to generate objectSIDs. The returned RID is not
|
||||||
formally reserved for use, creating the possibility of duplicate
|
formally reserved for use, creating the possibility of duplicate
|
||||||
objectSIDs.
|
objectSIDs.
|
||||||
'''
|
"""
|
||||||
rid, _ = self.free_rid_bounds()
|
rid, _ = self.free_rid_bounds()
|
||||||
return rid
|
return rid
|
||||||
|
|
||||||
def free_rid_bounds(self):
|
def free_rid_bounds(self):
|
||||||
'''return the low and high bounds (inclusive) of RIDs that are
|
"""return the low and high bounds (inclusive) of RIDs that are
|
||||||
available for use in this DSA's current RID pool.
|
available for use in this DSA's current RID pool.
|
||||||
|
|
||||||
:note: This function is not intended for general use, and care must be
|
:note: This function is not intended for general use, and care must be
|
||||||
taken if it is used to generate objectSIDs. The returned range of
|
taken if it is used to generate objectSIDs. The returned range of
|
||||||
RIDs is not formally reserved for use, creating the possibility of
|
RIDs is not formally reserved for use, creating the possibility of
|
||||||
duplicate objectSIDs.
|
duplicate objectSIDs.
|
||||||
'''
|
"""
|
||||||
# Get DN of this server's RID Set
|
# Get DN of this server's RID Set
|
||||||
server_name_dn = ldb.Dn(self, self.get_serverName())
|
server_name_dn = ldb.Dn(self, self.get_serverName())
|
||||||
res = self.search(base=server_name_dn,
|
res = self.search(base=server_name_dn,
|
||||||
@@ -1533,13 +1533,13 @@ schemaUpdateNow: 1
|
|||||||
return next_rid, prev_pool_hi
|
return next_rid, prev_pool_hi
|
||||||
|
|
||||||
def normalize_dn_in_domain(self, dn):
|
def normalize_dn_in_domain(self, dn):
|
||||||
'''return a new DN expanded by adding the domain DN
|
"""return a new DN expanded by adding the domain DN
|
||||||
|
|
||||||
If the dn is already a child of the domain DN, just
|
If the dn is already a child of the domain DN, just
|
||||||
return it as-is.
|
return it as-is.
|
||||||
|
|
||||||
:param dn: relative dn
|
:param dn: relative dn
|
||||||
'''
|
"""
|
||||||
domain_dn = ldb.Dn(self, self.domain_dn())
|
domain_dn = ldb.Dn(self, self.domain_dn())
|
||||||
|
|
||||||
if isinstance(dn, ldb.Dn):
|
if isinstance(dn, ldb.Dn):
|
||||||
@@ -1551,10 +1551,10 @@ schemaUpdateNow: 1
|
|||||||
return full_dn
|
return full_dn
|
||||||
|
|
||||||
class dsdb_Dn(object):
|
class dsdb_Dn(object):
|
||||||
'''a class for binary DN'''
|
"""a class for binary DN"""
|
||||||
|
|
||||||
def __init__(self, samdb, dnstring, syntax_oid=None):
|
def __init__(self, samdb, dnstring, syntax_oid=None):
|
||||||
'''create a dsdb_Dn'''
|
"""create a dsdb_Dn"""
|
||||||
if syntax_oid is None:
|
if syntax_oid is None:
|
||||||
# auto-detect based on string
|
# auto-detect based on string
|
||||||
if dnstring.startswith("B:"):
|
if dnstring.startswith("B:"):
|
||||||
@@ -1582,7 +1582,7 @@ class dsdb_Dn(object):
|
|||||||
return self.prefix + str(self.dn.extended_str(mode=1))
|
return self.prefix + str(self.dn.extended_str(mode=1))
|
||||||
|
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
''' compare dsdb_Dn values similar to parsed_dn_compare()'''
|
""" compare dsdb_Dn values similar to parsed_dn_compare()"""
|
||||||
dn1 = self
|
dn1 = self
|
||||||
dn2 = other
|
dn2 = other
|
||||||
guid1 = dn1.dn.get_extended_component("GUID")
|
guid1 = dn1.dn.get_extended_component("GUID")
|
||||||
@@ -1614,11 +1614,11 @@ class dsdb_Dn(object):
|
|||||||
return self.__cmp__(other) >= 0
|
return self.__cmp__(other) >= 0
|
||||||
|
|
||||||
def get_binary_integer(self):
|
def get_binary_integer(self):
|
||||||
'''return binary part of a dsdb_Dn as an integer, or None'''
|
"""return binary part of a dsdb_Dn as an integer, or None"""
|
||||||
if self.prefix == '':
|
if self.prefix == '':
|
||||||
return None
|
return None
|
||||||
return int(self.binary, 16)
|
return int(self.binary, 16)
|
||||||
|
|
||||||
def get_bytes(self):
|
def get_bytes(self):
|
||||||
'''return binary as a byte string'''
|
"""return binary as a byte string"""
|
||||||
return binascii.unhexlify(self.binary)
|
return binascii.unhexlify(self.binary)
|
||||||
|
|||||||
Reference in New Issue
Block a user