# Allow to run from s4 source directory (without installing samba)
sys.path.insert(0, "bin/python")
+import ldb
import samba
import samba.getopt as options
from samba.credentials import DONT_USE_KERBEROS
FLAG_MOD_REPLACE, FLAG_MOD_ADD, FLAG_MOD_DELETE,
MessageElement, Message, Dn)
from samba import param
-from samba.misc import messageEltFlagToString
from samba.provision import (find_setup_dir, get_domain_descriptor,
- get_config_descriptor, secretsdb_self_join,
- ProvisioningError, getLastProvisionUSN,
- get_max_usn, updateProvisionUSN)
+ get_config_descriptor,
+ ProvisioningError, get_last_provision_usn,
+ get_max_usn, update_provision_usn)
from samba.schema import get_linked_attributes, Schema, get_schema_descriptor
from samba.dcerpc import security, drsblobs
from samba.ndr import ndr_unpack
-from samba.dcerpc.misc import SEC_CHAN_BDC
from samba.upgradehelpers import (dn_sort, get_paths, newprovision,
find_provision_key_parameters, get_ldbs,
usn_in_range, identic_rename, get_diff_sddls,
update_secrets, CHANGE, ERROR, SIMPLE,
CHANGEALL, GUESS, CHANGESD, PROVISION,
updateOEMInfo, getOEMInfo, update_gpo,
- delta_update_basesamdb)
+ delta_update_basesamdb, update_policyids,
+ update_machine_account_password)
replace=2**FLAG_MOD_REPLACE
add=2**FLAG_MOD_ADD
backlinked = []
-forwardlinked = {}
+forwardlinked = set()
dn_syntax_att = []
def define_what_to_log(opts):
what = 0
handler = logging.StreamHandler(sys.stdout)
upgrade_logger = logging.getLogger("upgradeprovision")
+upgrade_logger.setLevel(logging.INFO)
+
upgrade_logger.addHandler(handler)
provision_logger = logging.getLogger("provision")
linkedAttHash = get_linked_attributes(Dn(samdb, str(schemadn)), samdb)
backlinked.extend(linkedAttHash.values())
for t in linkedAttHash.keys():
- forwardlinked[t] = 1
+ forwardlinked.add(t)
+
def populate_dnsyntax(samdb, schemadn):
"""Populate an array with all the attributes that have DN synthax
# We do most of the special case handle if we do not have the
# highest usn as otherwise the replPropertyMetaData will guide us more
# correctly
- if usn == None:
+ if usn is None:
if (att == "member" and flag == FLAG_MOD_REPLACE):
hash = {}
newval = []
delta.remove(att)
return True
- if (att == "gPLink" or att == "gPCFileSysPath") and \
- flag == FLAG_MOD_REPLACE and\
- str(new[0].dn).lower() == str(old[0].dn).lower():
+ if (att in ("gPLink", "gPCFileSysPath") and
+ flag == FLAG_MOD_REPLACE and
+ str(new[0].dn).lower() == str(old[0].dn).lower()):
delta.remove(att)
return True
ref == old and ref == abs(new)
return True
- if (att == "adminDisplayName" or att == "adminDescription"):
+ if att in ("adminDisplayName", "adminDescription"):
return True
- if (str(old[0].dn) == "CN=Samba4-Local-Domain, %s" % (str(names.schemadn))\
+ if (str(old[0].dn) == "CN=Samba4-Local-Domain, %s" % (names.schemadn)
and att == "defaultObjectCategory" and flag == FLAG_MOD_REPLACE):
return True
# This is a bit of special animal as we might have added
# already SPN entries to the list that has to be modified
# So we go in detail to try to find out what has to be added ...
- if ( att == "servicePrincipalName" and flag == FLAG_MOD_REPLACE):
+ if (att == "servicePrincipalName" and flag == FLAG_MOD_REPLACE):
hash = {}
newval = []
changeDelta=0
for e in range(0, len(current)):
message(CHANGE, "old %d : %s" % (i, str(current[e])))
i+=1
- if reference != None:
+ if reference is not None:
i = 0
for e in range(0, len(reference)):
message(CHANGE, "new %d : %s" % (i, str(reference[e])))
i+=1
else:
- message(CHANGE, "old : %s" % str(ndr_unpack( security.dom_sid, current[0])))
- message(CHANGE, "new : %s" % str(ndr_unpack( security.dom_sid, reference[0])))
+ message(CHANGE, "old : %s" % ndr_unpack(security.dom_sid, current[0]))
+ message(CHANGE, "new : %s" % ndr_unpack(security.dom_sid, reference[0]))
def handle_special_add(samdb, dn, names):
"""Handle special operation (like remove) on some object needed during
- upgrade
+ upgrade
This is mostly due to wrong creation of the object in previous provision.
:param samdb: An Ldb object representing the SAM database
:param dn: DN of the object to inspect
- :param names: list of key provision parameters"""
+ :param names: list of key provision parameters
+ """
dntoremove = None
objDn = Dn(samdb, "CN=IIS_IUSRS, CN=Builtin, %s" % names.rootdn)
#This entry was misplaced lets remove it if it exists
dntoremove = "CN=Event Log Readers, CN=Users, %s" % names.rootdn
- objDn = Dn(samdb,"CN=System,CN=WellKnown Security Principals,"\
+ objDn = Dn(samdb,"CN=System,CN=WellKnown Security Principals,"
"CN=Configuration,%s" % names.rootdn)
if dn == objDn:
- oldDn = Dn(samdb,"CN=Well-Known-Security-Id-System,"\
- "CN=WellKnown Security Principals,"\
+ oldDn = Dn(samdb,"CN=Well-Known-Security-Id-System,"
+ "CN=WellKnown Security Principals,"
"CN=Configuration,%s" % names.rootdn)
res = samdb.search(expression="(dn=%s)" % oldDn,
scope=SCOPE_SUBTREE, attrs=["dn"],
controls=["search_options:1:2"])
if len(res) > 0:
- message(CHANGE, "Existing object %s must be replaced by %s,"\
+ message(CHANGE, "Existing object %s must be replaced by %s,"
"Renaming old object" % (str(oldDn), str(dn)))
samdb.rename(oldDn, objDn)
return 1
- if dntoremove != None:
+ if dntoremove is not None:
res = samdb.search(expression="(dn=%s)" % dntoremove,
base=str(names.rootdn),
scope=SCOPE_SUBTREE, attrs=["dn"],
controls=["search_options:1:2"])
if len(res) > 0:
- message(CHANGE, "Existing object %s must be replaced by %s,"\
+ message(CHANGE, "Existing object %s must be replaced by %s,"
"removing old object" % (dntoremove, str(dn)))
samdb.delete(res[0]["dn"])
return 0
+
def check_dn_nottobecreated(hash, index, listdn):
"""Check if one of the DN present in the list has a creation order
greater than the current.
:param listdn: List of DNs on which the current DN depends on
:return: None if the current object do not depend on other
object or if all object have been created before."""
- if listdn == None:
+ if listdn is None:
return None
for dn in listdn:
key = str(dn).lower()
empty = Message()
delta = samdb.msg_diff(empty, reference[0])
delta.dn
+ if delta.get("objectSid"):
+ sid = str(ndr_unpack(security.dom_sid, str(reference[0]["objectSid"])))
+ m = re.match(r".*-(\d+)$", sid)
+ if m and int(m.group(1))>999:
+ delta.remove("objectSid")
for att in hashAttrNotCopied.keys():
delta.remove(att)
for att in backlinked:
for att in dn_syntax_att:
depend_on_yet_tobecreated = check_dn_nottobecreated(hash, index,
delta.get(str(att)))
- if depend_on_yet_tobecreated != None:
- message(CHANGE, "Object %s depends on %s in attribute %s," \
- "delaying the creation" % (str(dn), \
- depend_on_yet_tobecreated, str(att)))
+ if depend_on_yet_tobecreated is not None:
+ message(CHANGE, "Object %s depends on %s in attribute %s,"
+ "delaying the creation" % (dn,
+ depend_on_yet_tobecreated, att))
return False
delta.dn = dn
message(CHANGE,"Object %s will be added" % dn)
samdb.add(delta, ["relax:0"])
+
return True
def gen_dn_index_hash(listMissing):
attrs=["dn", "wellKnownObjects"])
targetWKO = "%s:%s" % (wkoPrefix, str(reference[0]["dn"]))
- found = 0
+ found = False
if len(res[0]) > 0:
wko = res[0]["wellKnownObjects"]
# The wellKnownObject that we want to add.
for o in wko:
if str(o) == targetWKO:
- found = 1
+ found = True
listwko.append(str(o))
if not found:
blacklist = {}
hash = {}
newlinklist = []
- changed = 0
+ changed = False
newlinklist.extend(value)
for e in ref_value:
if not blacklist.has_key(e) and not hash.has_key(e):
newlinklist.append(str(e))
- changed = 1
+ changed = True
if changed:
delta[att] = MessageElement(newlinklist, FLAG_MOD_REPLACE, att)
else:
delta.remove(att)
+
+msg_elt_flag_strs = {
+ ldb.FLAG_MOD_ADD: "MOD_ADD",
+ ldb.FLAG_MOD_REPLACE: "MOD_REPLACE",
+ ldb.FLAG_MOD_DELETE: "MOD_DELETE" }
+
+
def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid):
""" This function updates the object that are already present in the
provision
delta.remove("name")
- if len(delta.items()) > 1 and usns != None:
+ if len(delta.items()) > 1 and usns is not None:
# Fetch the replPropertyMetaData
res = samdb.search(expression="dn=%s" % (str(dn)), base=basedn,
scope=SCOPE_SUBTREE, controls=controls,
txt = ""
for att in delta:
- if usns != None:
+ if usns is not None:
# We have updated by provision usn information so let's exploit
# replMetadataProperties
- if forwardlinked.has_key(att):
+ if att in forwardlinked:
handle_links(samdb, att, basedn, current[0]["dn"],
current[0][att], reference[0][att], delta)
# was done in handle_special_case
continue
attrUSN = hash_attr_usn.get(att)
- if att == "forceLogoff" and attrUSN == None:
+ if att == "forceLogoff" and attrUSN is None:
continue
- if attrUSN == None:
+ if attrUSN is None:
delta.remove(att)
continue
if attrUSN == -1:
# This attribute was last modified by another DC forget
# about it
- message(CHANGE, "%sAttribute: %s has been" \
+ message(CHANGE, "%sAttribute: %s has been"
"created/modified/deleted by another DC,"
" do nothing" % (txt, att ))
txt = ""
delta.remove(att)
continue
- elif usn_in_range(int(attrUSN), usns) == 0:
- message(CHANGE, "%sAttribute: %s has been" \
- "created/modified/deleted not during a" \
- " provision or upgradeprovision: current" \
+ elif not usn_in_range(int(attrUSN), usns):
+ message(CHANGE, "%sAttribute: %s has been"
+ "created/modified/deleted not during a"
+ " provision or upgradeprovision: current"
" usn %d , do nothing" % (txt, att, attrUSN))
txt = ""
delta.remove(att)
continue
else:
if att == "defaultSecurityDescriptor":
- defSDmodified = 1
+ defSDmodified = True
if attrUSN:
- message(CHANGE, "%sAttribute: %s will be modified" \
- "/deleted it was last modified" \
- "during a provision, current usn:" \
+ message(CHANGE, "%sAttribute: %s will be modified"
+ "/deleted it was last modified"
+ "during a provision, current usn:"
"%d" % (txt, att, attrUSN))
txt = ""
else:
- message(CHANGE, "%sAttribute: %s will be added because" \
+ message(CHANGE, "%sAttribute: %s will be added because"
" it hasn't existed before " % (txt, att))
txt = ""
continue
else:
# Old school way of handling things for pre alpha12 upgrade
- defSDmodified = 1
+ defSDmodified = True
msgElt = delta.get(att)
if att == "nTSecurityDescriptor":
if opts.debugchange or opts.debugall:
try:
dump_denied_change(dn, att,
- messageEltFlagToString(msgElt.flags()),
+ msg_elt_flag_strs[msgElt.flags()],
current[0][att], reference[0][att])
except KeyError:
dump_denied_change(dn, att,
- messageEltFlagToString(msgElt.flags()),
+ msg_elt_flag_strs[msgElt.flags()],
current[0][att], None)
delta.remove(att)
continue
delta.dn = dn
if len(delta.items()) >1:
attributes=", ".join(delta.keys())
- message(CHANGE, "%s is different from the reference one, changed" \
+ message(CHANGE, "%s is different from the reference one, changed"
" attributes: %s\n" % (dn, attributes))
- changed = changed + 1
+ changed += 1
samdb.modify(delta)
return changed
+
def update_partition(ref_samdb, samdb, basedn, names, schema, provisionUSNs):
"""Check differences between the reference provision and the upgraded one.
# a complete schema is needed as the insertion of attributes
# and class is done against it
# and the schema is self validated
- samdb.set_schema_from_ldb(schema.ldb)
+ samdb.set_schema(schema)
try:
message(SIMPLE, "There are %d missing objects" % (len(listMissing)))
add_deletedobj_containers(ref_samdb, samdb, names)
return 0
-
def check_updated_sd(ref_sam, cur_sam, names):
"""Check if the security descriptor in the upgraded provision are the same
as the reference
if sddl != hash[key]:
txt = get_diff_sddls(hash[key], sddl)
if txt != "":
- message(CHANGESD, "On object %s ACL is different"\
+ message(CHANGESD, "On object %s ACL is different"
" \n%s" % (current[i]["dn"], txt))
controls=["search_options:1:2"])
for obj in res:
if not (str(obj["dn"]) == str(names.rootdn) or
- str(obj["dn"]) == str(names.configdn) or \
+ str(obj["dn"]) == str(names.configdn) or
str(obj["dn"]) == str(names.schemadn)):
hash[str(obj["dn"])] = obj["whenCreated"]
return 0
-def update_machine_account_password(samdb, secrets_ldb, names):
- """Update (change) the password of the current DC both in the SAM db and in
- secret one
-
- :param samdb: An LDB object related to the sam.ldb file of a given provision
- :param secrets_ldb: An LDB object related to the secrets.ldb file of a given
- provision
- :param names: List of key provision parameters"""
-
- message(SIMPLE, "Update machine account")
- expression = "samAccountName=%s$" % names.netbiosname
- secrets_msg = secrets_ldb.search(expression=expression,
- attrs=["secureChannelType"])
- if int(secrets_msg[0]["secureChannelType"][0]) == SEC_CHAN_BDC:
- res = samdb.search(expression=expression, attrs=[])
- assert(len(res) == 1)
-
- msg = Message(res[0].dn)
- machinepass = samba.generate_random_password(128, 255)
- msg["userPassword"] = MessageElement(machinepass, FLAG_MOD_REPLACE,
- "userPassword")
- samdb.modify(msg)
-
- res = samdb.search(expression=("samAccountName=%s$" % names.netbiosname),
- attrs=["msDs-keyVersionNumber"])
- assert(len(res) == 1)
- kvno = int(str(res[0]["msDs-keyVersionNumber"]))
- secChanType = int(secrets_msg[0]["secureChannelType"][0])
-
- secretsdb_self_join(secrets_ldb, domain=names.domain,
- realm=names.realm or sambaopts._lp.get('realm'),
- domainsid=names.domainsid,
- dnsdomain=names.dnsdomain,
- netbiosname=names.netbiosname,
- machinepass=machinepass,
- key_version_number=kvno,
- secure_channel_type=secChanType)
- else:
- raise ProvisioningError("Unable to find a Secure Channel" \
- "of type SEC_CHAN_BDC")
-
-
def setup_path(file):
return os.path.join(setup_dir, file)
if __name__ == '__main__':
global defSDmodified
- defSDmodified = 0
+ defSDmodified = False
# From here start the big steps of the program
# 1) First get files paths
paths = get_paths(param, smbconf=smbconf)
names = find_provision_key_parameters(ldbs.sam, ldbs.secrets, ldbs.idmap,
paths, smbconf, lp)
# 4)
- lastProvisionUSNs = getLastProvisionUSN(ldbs.sam)
- if lastProvisionUSNs != None:
+ lastProvisionUSNs = get_last_provision_usn(ldbs.sam)
+ if lastProvisionUSNs is not None:
message(CHANGE,
"Find a last provision USN, %d range(s)" % len(lastProvisionUSNs))
# ldbs = get_ldbs(paths, creds, adm_session, lp)
if not sanitychecks(ldbs.sam, names):
- message(SIMPLE, "Sanity checks for the upgrade fails, checks messages" \
+ message(SIMPLE, "Sanity checks for the upgrade fails, checks messages"
" and correct them before rerunning upgradeprovision")
sys.exit(1)
# 11) B
simple_update_basesamdb(newpaths, paths, names)
ldbs = get_ldbs(paths, creds, session, lp)
- ldbs.startTransactions()
removeProvisionUSN(ldbs.sam)
+ ldbs.startTransactions()
# 12)
schema = Schema(setup_path, names.domainsid, schemadn=str(names.schemadn),
- serverdn=str(names.serverdn))
+ serverdn=str(names.serverdn))
# 13)
if opts.full:
if not update_samdb(new_ldbs.sam, ldbs.sam, names, lastProvisionUSNs,
schema):
- message(SIMPLE, "Rollbacking every changes. Check the reason" \
+ message(SIMPLE, "Rollbacking every changes. Check the reason"
" of the problem")
- message(SIMPLE, "In any case your system as it was before" \
+ message(SIMPLE, "In any case your system as it was before"
" the upgrade")
ldbs.groupedRollback()
new_ldbs.groupedRollback()
# 14)
update_secrets(new_ldbs.secrets, ldbs.secrets, message)
# 15)
+ message(SIMPLE, "Update machine account")
update_machine_account_password(ldbs.sam, ldbs.secrets, names)
# 16) SD should be created with admin but as some previous acl were so wrong
# 18) We rebuild SD only if defaultSecurityDescriptor is modified
# But in fact we should do it also if one object has its SD modified as
# child might need rebuild
- if defSDmodified == 1:
+ if defSDmodified:
message(SIMPLE, "Updating SD")
ldbs.sam.set_session_info(adm_session)
# Alpha10 was a bit broken still
# 21)
check_for_DNS(newpaths.private_dir, paths.private_dir)
# 22)
- if lastProvisionUSNs != None:
- updateProvisionUSN(ldbs.sam, minUSN, maxUSN)
+ if lastProvisionUSNs is not None:
+ update_provision_usn(ldbs.sam, minUSN, maxUSN)
+ if opts.full and (names.policyid is None or names.policyid_dc is None):
+ update_policyids(names, ldbs.sam)
if opts.full or opts.resetfileacl:
- update_gpo(paths, ldbs.sam, names, lp, message, 1)
+ try:
+ update_gpo(paths, ldbs.sam, names, lp, message, 1)
+ except ProvisioningError, e:
+ message(ERROR, "The policy for domain controller is missing,"
+ " you should restart upgradeprovision with --full")
else:
- update_gpo(paths, ldbs.sam, names, lp, message, 0)
+ try:
+ update_gpo(paths, ldbs.sam, names, lp, message, 0)
+ except ProvisioningError, e:
+ message(ERROR, "The policy for domain controller is missing,"
+ " you should restart upgradeprovision with --full")
ldbs.groupedCommit()
new_ldbs.groupedCommit()
message(SIMPLE, "Upgrade finished !")