1
0
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:
Rob van der Linde
2023-12-14 15:14:27 +13:00
committed by Andrew Bartlett
parent ff52e34288
commit ddba4a06bb
17 changed files with 251 additions and 251 deletions

View File

@@ -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)

View File

@@ -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')

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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 = {}

View File

@@ -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)

View File

@@ -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 +\

View File

@@ -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

View File

@@ -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(),

View File

@@ -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)

View File

@@ -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"))

View File

@@ -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(),

View File

@@ -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-':

View File

@@ -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:

View File

@@ -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()

View 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)