summaryrefslogtreecommitdiff
path: root/source4/scripting/bin/upgradeprovision
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2012-09-10 14:52:35 +0200
committerStefan Metzmacher <metze@samba.org>2012-09-12 07:07:27 +0200
commit2c4255084a036a8d9b029484c6fceedd989cd79b (patch)
treed843d83604654fad5d8d1e2feab31b81d6b0eb0f /source4/scripting/bin/upgradeprovision
parenta0baaf2064f5abbca0b29d5d3cb538e78091e332 (diff)
downloadsamba-2c4255084a036a8d9b029484c6fceedd989cd79b.tar.gz
samba-2c4255084a036a8d9b029484c6fceedd989cd79b.tar.bz2
samba-2c4255084a036a8d9b029484c6fceedd989cd79b.zip
s4:scripting: rename upgradeprovision -> samba_upgradeprovision
metze
Diffstat (limited to 'source4/scripting/bin/upgradeprovision')
-rwxr-xr-xsource4/scripting/bin/upgradeprovision1946
1 files changed, 0 insertions, 1946 deletions
diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision
deleted file mode 100755
index 344d7f56c2..0000000000
--- a/source4/scripting/bin/upgradeprovision
+++ /dev/null
@@ -1,1946 +0,0 @@
-#!/usr/bin/env python
-# vim: expandtab
-#
-# Copyright (C) Matthieu Patou <mat@matws.net> 2009 - 2010
-#
-# Based on provision a Samba4 server by
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
-# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008
-#
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-
-import logging
-import optparse
-import os
-import shutil
-import sys
-import tempfile
-import re
-import traceback
-# 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 base64 import b64encode
-from samba.credentials import DONT_USE_KERBEROS
-from samba.auth import system_session, admin_session
-from ldb import (SCOPE_SUBTREE, SCOPE_BASE,
- FLAG_MOD_REPLACE, FLAG_MOD_ADD, FLAG_MOD_DELETE,
- MessageElement, Message, Dn, LdbError)
-from samba import param, dsdb, Ldb
-from samba.common import confirm
-from samba.provision import (get_domain_descriptor, find_provision_key_parameters,
- get_config_descriptor,
- ProvisioningError, get_last_provision_usn,
- get_max_usn, update_provision_usn, setup_path)
-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.upgradehelpers import (dn_sort, get_paths, newprovision,
- get_ldbs, findprovisionrange,
- usn_in_range, identic_rename, get_diff_sddls,
- update_secrets, CHANGE, ERROR, SIMPLE,
- CHANGEALL, GUESS, CHANGESD, PROVISION,
- updateOEMInfo, getOEMInfo, update_gpo,
- delta_update_basesamdb, update_policyids,
- update_machine_account_password,
- search_constructed_attrs_stored,
- int64range2str, update_dns_account_password,
- increment_calculated_keyversion_number,
- print_provision_ranges)
-from samba.xattr import copytree_with_xattrs
-
-replace=2**FLAG_MOD_REPLACE
-add=2**FLAG_MOD_ADD
-delete=2**FLAG_MOD_DELETE
-never=0
-
-
-# Will be modified during provision to tell if default sd has been modified
-# somehow ...
-
-#Errors are always logged
-
-__docformat__ = "restructuredText"
-
-# Attributes that are never copied from the reference provision (even if they
-# do not exist in the destination object).
-# This is most probably because they are populated automatcally when object is
-# created
-# This also apply to imported object from reference provision
-replAttrNotCopied = [ "dn", "whenCreated", "whenChanged", "objectGUID",
- "parentGUID", "objectCategory", "distinguishedName",
- "instanceType", "cn",
- "lmPwdHistory", "pwdLastSet", "ntPwdHistory",
- "unicodePwd", "dBCSPwd", "supplementalCredentials",
- "gPCUserExtensionNames", "gPCMachineExtensionNames",
- "maxPwdAge", "secret", "possibleInferiors", "privilege",
- "sAMAccountType", "oEMInformation", "creationTime" ]
-
-nonreplAttrNotCopied = ["uSNCreated", "replPropertyMetaData", "uSNChanged",
- "nextRid" ,"rIDNextRID", "rIDPreviousAllocationPool"]
-
-nonDSDBAttrNotCopied = ["msDS-KeyVersionNumber", "priorSecret", "priorWhenChanged"]
-
-
-attrNotCopied = replAttrNotCopied
-attrNotCopied.extend(nonreplAttrNotCopied)
-attrNotCopied.extend(nonDSDBAttrNotCopied)
-# Usually for an object that already exists we do not overwrite attributes as
-# they might have been changed for good reasons. Anyway for a few of them it's
-# mandatory to replace them otherwise the provision will be broken somehow.
-# But for attribute that are just missing we do not have to specify them as the default
-# behavior is to add missing attribute
-hashOverwrittenAtt = { "prefixMap": replace, "systemMayContain": replace,
- "systemOnly":replace, "searchFlags":replace,
- "mayContain":replace, "systemFlags":replace+add,
- "description":replace, "operatingSystemVersion":replace,
- "adminPropertyPages":replace, "groupType":replace,
- "wellKnownObjects":replace, "privilege":never,
- "defaultSecurityDescriptor": replace,
- "rIDAvailablePool": never,
- "versionNumber" : add,
- "rIDNextRID": add, "rIDUsedPool": never,
- "defaultSecurityDescriptor": replace + add,
- "isMemberOfPartialAttributeSet": delete,
- "attributeDisplayNames": replace + add,
- "versionNumber": add}
-
-dnNotToRecalculate = []
-dnToRecalculate = []
-backlinked = []
-forwardlinked = set()
-dn_syntax_att = []
-not_replicated = []
-def define_what_to_log(opts):
- what = 0
- if opts.debugchange:
- what = what | CHANGE
- if opts.debugchangesd:
- what = what | CHANGESD
- if opts.debugguess:
- what = what | GUESS
- if opts.debugprovision:
- what = what | PROVISION
- if opts.debugall:
- what = what | CHANGEALL
- return what
-
-
-parser = optparse.OptionParser("provision [options]")
-sambaopts = options.SambaOptions(parser)
-parser.add_option_group(sambaopts)
-parser.add_option_group(options.VersionOptions(parser))
-credopts = options.CredentialsOptions(parser)
-parser.add_option_group(credopts)
-parser.add_option("--setupdir", type="string", metavar="DIR",
- help="directory with setup files")
-parser.add_option("--debugprovision", help="Debug provision", action="store_true")
-parser.add_option("--debugguess", action="store_true",
- help="Print information on which values are guessed")
-parser.add_option("--debugchange", action="store_true",
- help="Print information on what is different but won't be changed")
-parser.add_option("--debugchangesd", action="store_true",
- help="Print security descriptor differences")
-parser.add_option("--debugall", action="store_true",
- help="Print all available information (very verbose)")
-parser.add_option("--resetfileacl", action="store_true",
- help="Force a reset on filesystem acls in sysvol / netlogon share")
-parser.add_option("--nontaclfix", action="store_true",
- help="In full upgrade mode do not try to upgrade sysvol / netlogon acls")
-parser.add_option("--fixntacl", action="store_true",
- help="Only fix NT ACLs in sysvol / netlogon share")
-parser.add_option("--db_backup_only", action="store_true",
- help="Do the backup of the database in the provision, skip the sysvol / netlogon shares")
-parser.add_option("--full", action="store_true",
- help="Perform full upgrade of the samdb (schema, configuration, new objects, ...")
-
-opts = parser.parse_args()[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")
-provision_logger.addHandler(handler)
-
-whatToLog = define_what_to_log(opts)
-
-def message(what, text):
- """Print a message if this message type has been selected to be printed
-
- :param what: Category of the message
- :param text: Message to print """
- if (whatToLog & what) or what <= 0:
- upgrade_logger.info("%s", text)
-
-if len(sys.argv) == 1:
- opts.interactive = True
-lp = sambaopts.get_loadparm()
-smbconf = lp.configfile
-
-creds = credopts.get_credentials(lp)
-creds.set_kerberos_state(DONT_USE_KERBEROS)
-
-
-
-def check_for_DNS(refprivate, private):
- """Check if the provision has already the requirement for dynamic dns
-
- :param refprivate: The path to the private directory of the reference
- provision
- :param private: The path to the private directory of the upgraded
- provision"""
-
- spnfile = "%s/spn_update_list" % private
- dnsfile = "%s/dns_update_list" % private
- namedfile = lp.get("dnsupdate:path")
-
- if not namedfile:
- namedfile = "%s/named.conf.update" % private
-
- if not os.path.exists(spnfile):
- shutil.copy("%s/spn_update_list" % refprivate, "%s" % spnfile)
-
- if not os.path.exists(dnsfile):
- shutil.copy("%s/dns_update_list" % refprivate, "%s" % dnsfile)
-
- destdir = "%s/new_dns" % private
- dnsdir = "%s/dns" % private
-
- if not os.path.exists(namedfile):
- if not os.path.exists(destdir):
- os.mkdir(destdir)
- if not os.path.exists(dnsdir):
- os.mkdir(dnsdir)
- shutil.copy("%s/named.conf" % refprivate, "%s/named.conf" % destdir)
- shutil.copy("%s/named.txt" % refprivate, "%s/named.txt" % destdir)
- message(SIMPLE, "It seems that your provision did not integrate "
- "new rules for dynamic dns update of domain related entries")
- message(SIMPLE, "A copy of the new bind configuration files and "
- "template has been put in %s, you should read them and "
- "configure dynamic dns updates" % destdir)
-
-
-def populate_links(samdb, schemadn):
- """Populate an array with all the back linked attributes
-
- This attributes that are modified automaticaly when
- front attibutes are changed
-
- :param samdb: A LDB object for sam.ldb file
- :param schemadn: DN of the schema for the partition"""
- linkedAttHash = get_linked_attributes(Dn(samdb, str(schemadn)), samdb)
- backlinked.extend(linkedAttHash.values())
- for t in linkedAttHash.keys():
- forwardlinked.add(t)
-
-def isReplicated(att):
- """ Indicate if the attribute is replicated or not
-
- :param att: Name of the attribute to be tested
- :return: True is the attribute is replicated, False otherwise
- """
-
- return (att not in not_replicated)
-
-def populateNotReplicated(samdb, schemadn):
- """Populate an array with all the attributes that are not replicated
-
- :param samdb: A LDB object for sam.ldb file
- :param schemadn: DN of the schema for the partition"""
- res = samdb.search(expression="(&(objectclass=attributeSchema)(systemflags:1.2.840.113556.1.4.803:=1))", base=Dn(samdb,
- str(schemadn)), scope=SCOPE_SUBTREE,
- attrs=["lDAPDisplayName"])
- for elem in res:
- not_replicated.append(str(elem["lDAPDisplayName"]))
-
-
-def populate_dnsyntax(samdb, schemadn):
- """Populate an array with all the attributes that have DN synthax
- (oid 2.5.5.1)
-
- :param samdb: A LDB object for sam.ldb file
- :param schemadn: DN of the schema for the partition"""
- res = samdb.search(expression="(attributeSyntax=2.5.5.1)", base=Dn(samdb,
- str(schemadn)), scope=SCOPE_SUBTREE,
- attrs=["lDAPDisplayName"])
- for elem in res:
- dn_syntax_att.append(elem["lDAPDisplayName"])
-
-
-def sanitychecks(samdb, names):
- """Make some checks before trying to update
-
- :param samdb: An LDB object opened on sam.ldb
- :param names: list of key provision parameters
- :return: Status of check (1 for Ok, 0 for not Ok) """
- res = samdb.search(expression="objectClass=ntdsdsa", base=str(names.configdn),
- scope=SCOPE_SUBTREE, attrs=["dn"],
- controls=["search_options:1:2"])
- if len(res) == 0:
- print "No DC found. Your provision is most probably broken!"
- return False
- elif len(res) != 1:
- print "Found %d domain controllers. For the moment " \
- "upgradeprovision is not able to handle an upgrade on a " \
- "domain with more than one DC. Please demote the other " \
- "DC(s) before upgrading" % len(res)
- return False
- else:
- return True
-
-
-def print_provision_key_parameters(names):
- """Do a a pretty print of provision parameters
-
- :param names: list of key provision parameters """
- message(GUESS, "rootdn :" + str(names.rootdn))
- message(GUESS, "configdn :" + str(names.configdn))
- message(GUESS, "schemadn :" + str(names.schemadn))
- message(GUESS, "serverdn :" + str(names.serverdn))
- message(GUESS, "netbiosname :" + names.netbiosname)
- message(GUESS, "defaultsite :" + names.sitename)
- message(GUESS, "dnsdomain :" + names.dnsdomain)
- message(GUESS, "hostname :" + names.hostname)
- message(GUESS, "domain :" + names.domain)
- message(GUESS, "realm :" + names.realm)
- message(GUESS, "invocationid:" + names.invocation)
- message(GUESS, "policyguid :" + names.policyid)
- message(GUESS, "policyguiddc:" + str(names.policyid_dc))
- message(GUESS, "domainsid :" + str(names.domainsid))
- message(GUESS, "domainguid :" + names.domainguid)
- message(GUESS, "ntdsguid :" + names.ntdsguid)
- message(GUESS, "domainlevel :" + str(names.domainlevel))
-
-
-def handle_special_case(att, delta, new, old, useReplMetadata, basedn, aldb):
- """Define more complicate update rules for some attributes
-
- :param att: The attribute to be updated
- :param delta: A messageElement object that correspond to the difference
- between the updated object and the reference one
- :param new: The reference object
- :param old: The Updated object
- :param useReplMetadata: A boolean that indicate if the update process
- use replPropertyMetaData to decide what has to be updated.
- :param basedn: The base DN of the provision
- :param aldb: An ldb object used to build DN
- :return: True to indicate that the attribute should be kept, False for
- discarding it"""
-
- # 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 not useReplMetadata:
- flag = delta.get(att).flags()
- if (att == "sPNMappings" and flag == FLAG_MOD_REPLACE and
- ldb.Dn(aldb, "CN=Directory Service,CN=Windows NT,"
- "CN=Services,CN=Configuration,%s" % basedn)
- == old[0].dn):
- return True
- if (att == "userAccountControl" and flag == FLAG_MOD_REPLACE and
- ldb.Dn(aldb, "CN=Administrator,CN=Users,%s" % basedn)
- == old[0].dn):
- message(SIMPLE, "We suggest that you change the userAccountControl"
- " for user Administrator from value %d to %d" %
- (int(str(old[0][att])), int(str(new[0][att]))))
- return False
- if (att == "minPwdAge" and flag == FLAG_MOD_REPLACE):
- if (long(str(old[0][att])) == 0):
- delta[att] = MessageElement(new[0][att], FLAG_MOD_REPLACE, att)
- return True
-
- if (att == "member" and flag == FLAG_MOD_REPLACE):
- hash = {}
- newval = []
- changeDelta=0
- for elem in old[0][att]:
- hash[str(elem).lower()]=1
- newval.append(str(elem))
-
- for elem in new[0][att]:
- if not hash.has_key(str(elem).lower()):
- changeDelta=1
- newval.append(str(elem))
- if changeDelta == 1:
- delta[att] = MessageElement(newval, FLAG_MOD_REPLACE, att)
- else:
- delta.remove(att)
- return True
-
- 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
-
- if att == "forceLogoff":
- ref=0x8000000000000000
- oldval=int(old[0][att][0])
- newval=int(new[0][att][0])
- ref == old and ref == abs(new)
- return True
-
- if att in ("adminDisplayName", "adminDescription"):
- return True
-
- if (str(old[0].dn) == "CN=Samba4-Local-Domain, %s" % (names.schemadn)
- and att == "defaultObjectCategory" and flag == FLAG_MOD_REPLACE):
- return True
-
- if (str(old[0].dn) == "CN=Title, %s" % (str(names.schemadn)) and
- att == "rangeUpper" and flag == FLAG_MOD_REPLACE):
- return True
-
- if (str(old[0].dn) == "%s" % (str(names.rootdn))
- and att == "subRefs" and flag == FLAG_MOD_REPLACE):
- return True
- #Allow to change revision of ForestUpdates objects
- if (att == "revision" or att == "objectVersion"):
- if str(delta.dn).lower().find("domainupdates") and str(delta.dn).lower().find("forestupdates") > 0:
- return True
- if str(delta.dn).endswith("CN=DisplaySpecifiers, %s" % names.configdn):
- 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 delta.get(att).flags() == FLAG_MOD_REPLACE):
- hash = {}
- newval = []
- changeDelta = 0
- for elem in old[0][att]:
- hash[str(elem)]=1
- newval.append(str(elem))
-
- for elem in new[0][att]:
- if not hash.has_key(str(elem)):
- changeDelta = 1
- newval.append(str(elem))
- if changeDelta == 1:
- delta[att] = MessageElement(newval, FLAG_MOD_REPLACE, att)
- else:
- delta.remove(att)
- return True
-
- return False
-
-def dump_denied_change(dn, att, flagtxt, current, reference):
- """Print detailed information about why a change is denied
-
- :param dn: DN of the object which attribute is denied
- :param att: Attribute that was supposed to be upgraded
- :param flagtxt: Type of the update that should be performed
- (add, change, remove, ...)
- :param current: Value(s) of the current attribute
- :param reference: Value(s) of the reference attribute"""
-
- message(CHANGE, "dn= " + str(dn)+" " + att+" with flag " + flagtxt
- + " must not be changed/removed. Discarding the change")
- if att == "objectSid" :
- message(CHANGE, "old : %s" % ndr_unpack(security.dom_sid, current[0]))
- message(CHANGE, "new : %s" % ndr_unpack(security.dom_sid, reference[0]))
- elif att == "rIDPreviousAllocationPool" or att == "rIDAllocationPool":
- message(CHANGE, "old : %s" % int64range2str(current[0]))
- message(CHANGE, "new : %s" % int64range2str(reference[0]))
- else:
- i = 0
- for e in range(0, len(current)):
- message(CHANGE, "old %d : %s" % (i, str(current[e])))
- i+=1
- 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
-
-def handle_special_add(samdb, dn, names):
- """Handle special operation (like remove) on some object needed during
- 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
- """
-
- dntoremove = None
- objDn = Dn(samdb, "CN=IIS_IUSRS, CN=Builtin, %s" % names.rootdn)
- if dn == objDn :
- #This entry was misplaced lets remove it if it exists
- dntoremove = "CN=IIS_IUSRS, CN=Users, %s" % names.rootdn
-
- objDn = Dn(samdb,
- "CN=Certificate Service DCOM Access, CN=Builtin, %s" % names.rootdn)
- if dn == objDn:
- #This entry was misplaced lets remove it if it exists
- dntoremove = "CN=Certificate Service DCOM Access,"\
- "CN=Users, %s" % names.rootdn
-
- objDn = Dn(samdb, "CN=Cryptographic Operators, CN=Builtin, %s" % names.rootdn)
- if dn == objDn:
- #This entry was misplaced lets remove it if it exists
- dntoremove = "CN=Cryptographic Operators, CN=Users, %s" % names.rootdn
-
- objDn = Dn(samdb, "CN=Event Log Readers, CN=Builtin, %s" % names.rootdn)
- if dn == objDn:
- #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,"
- "CN=Configuration,%s" % names.rootdn)
- if dn == objDn:
- oldDn = Dn(samdb,"CN=Well-Known-Security-Id-System,"
- "CN=WellKnown Security Principals,"
- "CN=Configuration,%s" % names.rootdn)
-
- res = samdb.search(expression="(distinguishedName=%s)" % oldDn,
- base=str(names.rootdn),
- scope=SCOPE_SUBTREE, attrs=["dn"],
- controls=["search_options:1:2"])
-
- res2 = samdb.search(expression="(distinguishedName=%s)" % dn,
- base=str(names.rootdn),
- scope=SCOPE_SUBTREE, attrs=["dn"],
- controls=["search_options:1:2"])
-
- if len(res) > 0 and len(res2) == 0:
- message(CHANGE, "Existing object %s must be replaced by %s. "
- "Renaming old object" % (str(oldDn), str(dn)))
- samdb.rename(oldDn, objDn, ["relax:0", "provision:0"])
-
- return 0
-
- if dntoremove is not None:
- res = samdb.search(expression="(cn=RID Set)",
- base=str(names.rootdn),
- scope=SCOPE_SUBTREE, attrs=["dn"],
- controls=["search_options:1:2"])
-
- if len(res) == 0:
- return 2
- res = samdb.search(expression="(distinguishedName=%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. "
- "Removing old object" % (dntoremove, str(dn)))
- samdb.delete(res[0]["dn"])
- return 0
-
- return 1
-
-
-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.
-
- Hash is indexed by dn to be created, with each key
- is associated the creation order.
-
- First dn to be created has the creation order 0, second has 1, ...
- Index contain the current creation order
-
- :param hash: Hash holding the different DN of the object to be
- created as key
- :param index: Current creation order
- :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 is None:
- return None
- for dn in listdn:
- key = str(dn).lower()
- if hash.has_key(key) and hash[key] > index:
- return str(dn)
- return None
-
-
-
-def add_missing_object(ref_samdb, samdb, dn, names, basedn, hash, index):
- """Add a new object if the dependencies are satisfied
-
- The function add the object if the object on which it depends are already
- created
-
- :param ref_samdb: Ldb object representing the SAM db of the reference
- provision
- :param samdb: Ldb object representing the SAM db of the upgraded
- provision
- :param dn: DN of the object to be added
- :param names: List of key provision parameters
- :param basedn: DN of the partition to be updated
- :param hash: Hash holding the different DN of the object to be
- created as key
- :param index: Current creation order
- :return: True if the object was created False otherwise"""
-
- ret = handle_special_add(samdb, dn, names)
-
- if ret == 2:
- return False
-
- if ret == 0:
- return True
-
-
- reference = ref_samdb.search(expression="(distinguishedName=%s)" % (str(dn)),
- base=basedn, scope=SCOPE_SUBTREE,
- controls=["search_options:1:2"])
- empty = Message()
- delta = samdb.msg_diff(empty, reference[0])
- delta.dn
- skip = False
- try:
- if str(reference[0].get("cn")) == "RID Set":
- for klass in reference[0].get("objectClass"):
- if str(klass).lower() == "ridset":
- skip = True
- finally:
- 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 attrNotCopied:
- delta.remove(att)
- for att in backlinked:
- delta.remove(att)
- depend_on_yettobecreated = None
- for att in dn_syntax_att:
- depend_on_yet_tobecreated = check_dn_nottobecreated(hash, index,
- delta.get(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
- if not skip:
- message(CHANGE,"Object %s will be added" % dn)
- samdb.add(delta, ["relax:0", "provision:0"])
- else:
- message(CHANGE,"Object %s was skipped" % dn)
-
- return True
-
-def gen_dn_index_hash(listMissing):
- """Generate a hash associating the DN to its creation order
-
- :param listMissing: List of DN
- :return: Hash with DN as keys and creation order as values"""
- hash = {}
- for i in range(0, len(listMissing)):
- hash[str(listMissing[i]).lower()] = i
- return hash
-
-def add_deletedobj_containers(ref_samdb, samdb, names):
- """Add the object containter: CN=Deleted Objects
-
- This function create the container for each partition that need one and
- then reference the object into the root of the partition
-
- :param ref_samdb: Ldb object representing the SAM db of the reference
- provision
- :param samdb: Ldb object representing the SAM db of the upgraded provision
- :param names: List of key provision parameters"""
-
-
- wkoPrefix = "B:32:18E2EA80684F11D2B9AA00C04F79F805"
- partitions = [str(names.rootdn), str(names.configdn)]
- for part in partitions:
- ref_delObjCnt = ref_samdb.search(expression="(cn=Deleted Objects)",
- base=part, scope=SCOPE_SUBTREE,
- attrs=["dn"],
- controls=["show_deleted:0",
- "show_recycled:0"])
- delObjCnt = samdb.search(expression="(cn=Deleted Objects)",
- base=part, scope=SCOPE_SUBTREE,
- attrs=["dn"],
- controls=["show_deleted:0",
- "show_recycled:0"])
- if len(ref_delObjCnt) > len(delObjCnt):
- reference = ref_samdb.search(expression="cn=Deleted Objects",
- base=part, scope=SCOPE_SUBTREE,
- controls=["show_deleted:0",
- "show_recycled:0"])
- empty = Message()
- delta = samdb.msg_diff(empty, reference[0])
-
- delta.dn = Dn(samdb, str(reference[0]["dn"]))
- for att in attrNotCopied:
- delta.remove(att)
-
- modcontrols = ["relax:0", "provision:0"]
- samdb.add(delta, modcontrols)
-
- listwko = []
- res = samdb.search(expression="(objectClass=*)", base=part,
- scope=SCOPE_BASE,
- attrs=["dn", "wellKnownObjects"])
-
- targetWKO = "%s:%s" % (wkoPrefix, str(reference[0]["dn"]))
- 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 = True
- listwko.append(str(o))
-
- if not found:
- listwko.append(targetWKO)
-
- delta = Message()
- delta.dn = Dn(samdb, str(res[0]["dn"]))
- delta["wellKnownObjects"] = MessageElement(listwko,
- FLAG_MOD_REPLACE,
- "wellKnownObjects" )
- samdb.modify(delta)
-
-def add_missing_entries(ref_samdb, samdb, names, basedn, list):
- """Add the missing object whose DN is the list
-
- The function add the object if the objects on which it depends are
- already created.
-
- :param ref_samdb: Ldb object representing the SAM db of the reference
- provision
- :param samdb: Ldb object representing the SAM db of the upgraded
- provision
- :param dn: DN of the object to be added
- :param names: List of key provision parameters
- :param basedn: DN of the partition to be updated
- :param list: List of DN to be added in the upgraded provision"""
-
- listMissing = []
- listDefered = list
-
- while(len(listDefered) != len(listMissing) and len(listDefered) > 0):
- index = 0
- listMissing = listDefered
- listDefered = []
- hashMissing = gen_dn_index_hash(listMissing)
- for dn in listMissing:
- ret = add_missing_object(ref_samdb, samdb, dn, names, basedn,
- hashMissing, index)
- index = index + 1
- if ret == 0:
- # DN can't be created because it depends on some
- # other DN in the list
- listDefered.append(dn)
-
- if len(listDefered) != 0:
- raise ProvisioningError("Unable to insert missing elements: "
- "circular references")
-
-def handle_links(samdb, att, basedn, dn, value, ref_value, delta):
- """This function handle updates on links
-
- :param samdb: An LDB object pointing to the updated provision
- :param att: Attribute to update
- :param basedn: The root DN of the provision
- :param dn: The DN of the inspected object
- :param value: The value of the attribute
- :param ref_value: The value of this attribute in the reference provision
- :param delta: The MessageElement object that will be applied for
- transforming the current provision"""
-
- res = samdb.search(base=dn, controls=["search_options:1:2", "reveal:1"],
- attrs=[att])
-
- blacklist = {}
- hash = {}
- newlinklist = []
- changed = False
-
- for v in value:
- newlinklist.append(str(v))
-
- for e in value:
- hash[e] = 1
- # for w2k domain level the reveal won't reveal anything ...
- # it means that we can readd links that were removed on purpose ...
- # Also this function in fact just accept add not removal
-
- for e in res[0][att]:
- if not hash.has_key(e):
- # We put in the blacklist all the element that are in the "revealed"
- # result and not in the "standard" result
- # This element are links that were removed before and so that
- # we don't wan't to readd
- blacklist[e] = 1
-
- for e in ref_value:
- if not blacklist.has_key(e) and not hash.has_key(e):
- newlinklist.append(str(e))
- changed = True
- if changed:
- delta[att] = MessageElement(newlinklist, FLAG_MOD_REPLACE, att)
- else:
- delta.remove(att)
-
- return delta
-
-
-msg_elt_flag_strs = {
- ldb.FLAG_MOD_ADD: "MOD_ADD",
- ldb.FLAG_MOD_REPLACE: "MOD_REPLACE",
- ldb.FLAG_MOD_DELETE: "MOD_DELETE" }
-
-def checkKeepAttributeOldMtd(delta, att, reference, current,
- basedn, samdb):
- """ Check if we should keep the attribute modification or not.
- This function didn't use replicationMetadata to take a decision.
-
- :param delta: A message diff object
- :param att: An attribute
- :param reference: A message object for the current entry comming from
- the reference provision.
- :param current: A message object for the current entry commin from
- the current provision.
- :param basedn: The DN of the partition
- :param samdb: A ldb connection to the sam database of the current provision.
-
- :return: The modified message diff.
- """
- # Old school way of handling things for pre alpha12 upgrade
- global defSDmodified
- isFirst = False
- txt = ""
- dn = current[0].dn
-
- for att in list(delta):
- msgElt = delta.get(att)
-
- if att == "nTSecurityDescriptor":
- defSDmodified = True
- delta.remove(att)
- continue
-
- if att == "dn":
- continue
-
- if not hashOverwrittenAtt.has_key(att):
- if msgElt.flags() != FLAG_MOD_ADD:
- if not handle_special_case(att, delta, reference, current,
- False, basedn, samdb):
- if opts.debugchange or opts.debugall:
- try:
- dump_denied_change(dn, att,
- msg_elt_flag_strs[msgElt.flags()],
- current[0][att], reference[0][att])
- except KeyError:
- dump_denied_change(dn, att,
- msg_elt_flag_strs[msgElt.flags()],
- current[0][att], None)
- delta.remove(att)
- continue
- else:
- if hashOverwrittenAtt.get(att)&2**msgElt.flags() :
- continue
- elif hashOverwrittenAtt.get(att)==never:
- delta.remove(att)
- continue
-
- return delta
-
-def checkKeepAttributeWithMetadata(delta, att, message, reference, current,
- hash_attr_usn, basedn, usns, samdb):
- """ Check if we should keep the attribute modification or not
-
- :param delta: A message diff object
- :param att: An attribute
- :param message: A function to print messages
- :param reference: A message object for the current entry comming from
- the reference provision.
- :param current: A message object for the current entry commin from
- the current provision.
- :param hash_attr_usn: A dictionnary with attribute name as keys,
- USN and invocation id as values.
- :param basedn: The DN of the partition
- :param usns: A dictionnary with invocation ID as keys and USN ranges
- as values.
- :param samdb: A ldb object pointing to the sam DB
-
- :return: The modified message diff.
- """
- global defSDmodified
- isFirst = True
- txt = ""
- dn = current[0].dn
-
- for att in list(delta):
- if att in ["dn", "objectSid"]:
- delta.remove(att)
- continue
-
- # We have updated by provision usn information so let's exploit
- # replMetadataProperties
- if att in forwardlinked:
- curval = current[0].get(att, ())
- refval = reference[0].get(att, ())
- delta = handle_links(samdb, att, basedn, current[0]["dn"],
- curval, refval, delta)
- continue
-
-
- if isFirst and len(list(delta)) > 1:
- isFirst = False
- txt = "%s\n" % (str(dn))
-
- if handle_special_case(att, delta, reference, current, True, None, None):
- # This attribute is "complicated" to handle and handling
- # was done in handle_special_case
- continue
-
- attrUSN = None
- if hash_attr_usn.get(att):
- [attrUSN, attInvId] = hash_attr_usn.get(att)
-
- if attrUSN is None:
- # If it's a replicated attribute and we don't have any USN
- # information about it. It means that we never saw it before
- # so let's add it !
- # If it is a replicated attribute but we are not master on it
- # (ie. not initially added in the provision we masterize).
- # attrUSN will be -1
- if isReplicated(att):
- continue
- else:
- message(CHANGE, "Non replicated attribute %s changed" % att)
- continue
-
- if att == "nTSecurityDescriptor":
- cursd = ndr_unpack(security.descriptor,
- str(current[0]["nTSecurityDescriptor"]))
- cursddl = cursd.as_sddl(names.domainsid)
- refsd = ndr_unpack(security.descriptor,
- str(reference[0]["nTSecurityDescriptor"]))
- refsddl = refsd.as_sddl(names.domainsid)
-
- diff = get_diff_sddls(refsddl, cursddl)
- if diff == "":
- # FIXME find a way to have it only with huge huge verbose mode
- # message(CHANGE, "%ssd are identical" % txt)
- # txt = ""
- delta.remove(att)
- continue
- else:
- delta.remove(att)
- message(CHANGESD, "%ssd are not identical:\n%s" % (txt, diff))
- txt = ""
- if attrUSN == -1:
- message(CHANGESD, "But the SD has been changed by someonelse "\
- "so it's impossible to know if the difference"\
- " cames from the modification or from a previous bug")
- dnNotToRecalculate.append(str(dn))
- else:
- dnToRecalculate.append(str(dn))
- continue
-
- if attrUSN == -1:
- # This attribute was last modified by another DC forget
- # about it
- message(CHANGE, "%sAttribute: %s has been "
- "created/modified/deleted by another DC. "
- "Doing nothing" % (txt, att))
- txt = ""
- delta.remove(att)
- continue
- elif not usn_in_range(int(attrUSN), usns.get(attInvId)):
- message(CHANGE, "%sAttribute: %s was not "
- "created/modified/deleted during a "
- "provision or upgradeprovision. Current "
- "usn: %d. Doing nothing" % (txt, att,
- attrUSN))
- txt = ""
- delta.remove(att)
- continue
- else:
- if att == "defaultSecurityDescriptor":
- defSDmodified = True
- if attrUSN:
- 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 "
- "it did not exist before" % (txt, att))
- txt = ""
- continue
-
- return delta
-
-def update_present(ref_samdb, samdb, basedn, listPresent, usns):
- """ This function updates the object that are already present in the
- provision
-
- :param ref_samdb: An LDB object pointing to the reference provision
- :param samdb: An LDB object pointing to the updated provision
- :param basedn: A string with the value of the base DN for the provision
- (ie. DC=foo, DC=bar)
- :param listPresent: A list of object that is present in the provision
- :param usns: A list of USN range modified by previous provision and
- upgradeprovision grouped by invocation ID
- """
-
- # This hash is meant to speedup lookup of attribute name from an oid,
- # it's for the replPropertyMetaData handling
- hash_oid_name = {}
- res = samdb.search(expression="objectClass=attributeSchema", base=basedn,
- controls=["search_options:1:2"], attrs=["attributeID",
- "lDAPDisplayName"])
- if len(res) > 0:
- for e in res:
- strDisplay = str(e.get("lDAPDisplayName"))
- hash_oid_name[str(e.get("attributeID"))] = strDisplay
- else:
- msg = "Unable to insert missing elements: circular references"
- raise ProvisioningError(msg)
-
- changed = 0
- controls = ["search_options:1:2", "sd_flags:1:0"]
- if usns is not None:
- message(CHANGE, "Using replPropertyMetadata for change selection")
- for dn in listPresent:
- reference = ref_samdb.search(expression="(distinguishedName=%s)" % (str(dn)), base=basedn,
- scope=SCOPE_SUBTREE,
- controls=controls)
- current = samdb.search(expression="(distinguishedName=%s)" % (str(dn)), base=basedn,
- scope=SCOPE_SUBTREE, controls=controls)
-
- if (
- (str(current[0].dn) != str(reference[0].dn)) and
- (str(current[0].dn).upper() == str(reference[0].dn).upper())
- ):
- message(CHANGE, "Names are the same except for the case. "
- "Renaming %s to %s" % (str(current[0].dn),
- str(reference[0].dn)))
- identic_rename(samdb, reference[0].dn)
- current = samdb.search(expression="(distinguishedName=%s)" % (str(dn)), base=basedn,
- scope=SCOPE_SUBTREE,
- controls=controls)
-
- delta = samdb.msg_diff(current[0], reference[0])
-
- for att in backlinked:
- delta.remove(att)
-
- for att in attrNotCopied:
- delta.remove(att)
-
- delta.remove("name")
-
- nb_items = len(list(delta))
-
- if nb_items == 1:
- continue
-
- if nb_items > 1 and usns is not None:
- # Fetch the replPropertyMetaData
- res = samdb.search(expression="(distinguishedName=%s)" % (str(dn)), base=basedn,
- scope=SCOPE_SUBTREE, controls=controls,
- attrs=["replPropertyMetaData"])
- ctr = ndr_unpack(drsblobs.replPropertyMetaDataBlob,
- str(res[0]["replPropertyMetaData"])).ctr
-
- hash_attr_usn = {}
- for o in ctr.array:
- # We put in this hash only modification
- # made on the current host
- att = hash_oid_name[samdb.get_oid_from_attid(o.attid)]
- if str(o.originating_invocation_id) in usns.keys():
- hash_attr_usn[att] = [o.originating_usn, str(o.originating_invocation_id)]
- else:
- hash_attr_usn[att] = [-1, None]
-
- if usns is not None:
- delta = checkKeepAttributeWithMetadata(delta, att, message, reference,
- current, hash_attr_usn,
- basedn, usns, samdb)
- else:
- delta = checkKeepAttributeOldMtd(delta, att, reference, current, basedn, samdb)
-
- delta.dn = dn
-
-
- if len(delta) >1:
- # Skip dn as the value is not really changed ...
- attributes=", ".join(delta.keys()[1:])
- modcontrols = []
- relaxedatt = ['iscriticalsystemobject', 'grouptype']
- # Let's try to reduce as much as possible the use of relax control
- for attr in delta.keys():
- if attr.lower() in relaxedatt:
- modcontrols = ["relax:0", "provision:0"]
- message(CHANGE, "%s is different from the reference one, changed"
- " attributes: %s\n" % (dn, attributes))
- changed += 1
- samdb.modify(delta, modcontrols)
- return changed
-
-def reload_full_schema(samdb, names):
- """Load the updated schema with all the new and existing classes
- and attributes.
-
- :param samdb: An LDB object connected to the sam.ldb of the update
- provision
- :param names: List of key provision parameters
- """
-
- schemadn = str(names.schemadn)
- current = samdb.search(expression="objectClass=*", base=schemadn,
- scope=SCOPE_SUBTREE)
- schema_ldif = ""
- prefixmap_data = ""
-
- for ent in current:
- schema_ldif += samdb.write_ldif(ent, ldb.CHANGETYPE_NONE)
-
- prefixmap_data = open(setup_path("prefixMap.txt"), 'r').read()
- prefixmap_data = b64encode(prefixmap_data)
-
- # We don't actually add this ldif, just parse it
- prefixmap_ldif = "dn: %s\nprefixMap:: %s\n\n" % (schemadn, prefixmap_data)
-
- dsdb._dsdb_set_schema_from_ldif(samdb, prefixmap_ldif, schema_ldif, schemadn)
-
-
-def update_partition(ref_samdb, samdb, basedn, names, schema, provisionUSNs, prereloadfunc):
- """Check differences between the reference provision and the upgraded one.
-
- It looks for all objects which base DN is name.
-
- This function will also add the missing object and update existing object
- to add or remove attributes that were missing.
-
- :param ref_sambdb: An LDB object conntected to the sam.ldb of the
- reference provision
- :param samdb: An LDB object connected to the sam.ldb of the update
- provision
- :param basedn: String value of the DN of the partition
- :param names: List of key provision parameters
- :param schema: A Schema object
- :param provisionUSNs: A dictionnary with range of USN modified during provision
- or upgradeprovision. Ranges are grouped by invocationID.
- :param prereloadfunc: A function that must be executed just before the reload
- of the schema
- """
-
- hash_new = {}
- hash = {}
- listMissing = []
- listPresent = []
- reference = []
- current = []
-
- # Connect to the reference provision and get all the attribute in the
- # partition referred by name
- reference = ref_samdb.search(expression="objectClass=*", base=basedn,
- scope=SCOPE_SUBTREE, attrs=["dn"],
- controls=["search_options:1:2"])
-
- current = samdb.search(expression="objectClass=*", base=basedn,
- scope=SCOPE_SUBTREE, attrs=["dn"],
- controls=["search_options:1:2"])
- # Create a hash for speeding the search of new object
- for i in range(0, len(reference)):
- hash_new[str(reference[i]["dn"]).lower()] = reference[i]["dn"]
-
- # Create a hash for speeding the search of existing object in the
- # current provision
- for i in range(0, len(current)):
- hash[str(current[i]["dn"]).lower()] = current[i]["dn"]
-
-
- for k in hash_new.keys():
- if not hash.has_key(k):
- if not str(hash_new[k]) == "CN=Deleted Objects, %s" % names.rootdn:
- listMissing.append(hash_new[k])
- else:
- listPresent.append(hash_new[k])
-
- # Sort the missing object in order to have object of the lowest level
- # first (which can be containers for higher level objects)
- listMissing.sort(dn_sort)
- listPresent.sort(dn_sort)
-
- # The following lines is to load the up to
- # date schema into our current LDB
- # 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(schema)
- try:
- message(SIMPLE, "There are %d missing objects" % (len(listMissing)))
- add_deletedobj_containers(ref_samdb, samdb, names)
-
- add_missing_entries(ref_samdb, samdb, names, basedn, listMissing)
-
- prereloadfunc()
- message(SIMPLE, "Reloading a merged schema, which might trigger "
- "reindexing so please be patient")
- reload_full_schema(samdb, names)
- message(SIMPLE, "Schema reloaded!")
-
- changed = update_present(ref_samdb, samdb, basedn, listPresent,
- provisionUSNs)
- message(SIMPLE, "There are %d changed objects" % (changed))
- return 1
-
- except StandardError, err:
- message(ERROR, "Exception during upgrade of samdb:")
- (typ, val, tb) = sys.exc_info()
- traceback.print_exception(typ, val, tb)
- 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
-
- :param ref_sam: A LDB object connected to the sam.ldb file used as
- the reference provision
- :param cur_sam: A LDB object connected to the sam.ldb file used as
- upgraded provision
- :param names: List of key provision parameters"""
- reference = ref_sam.search(expression="objectClass=*", base=str(names.rootdn),
- scope=SCOPE_SUBTREE,
- attrs=["dn", "nTSecurityDescriptor"],
- controls=["search_options:1:2"])
- current = cur_sam.search(expression="objectClass=*", base=str(names.rootdn),
- scope=SCOPE_SUBTREE,
- attrs=["dn", "nTSecurityDescriptor"],
- controls=["search_options:1:2"])
- hash = {}
- for i in range(0, len(reference)):
- refsd = ndr_unpack(security.descriptor,
- str(reference[i]["nTSecurityDescriptor"]))
- hash[str(reference[i]["dn"]).lower()] = refsd.as_sddl(names.domainsid)
-
-
- for i in range(0, len(current)):
- key = str(current[i]["dn"]).lower()
- if hash.has_key(key):
- cursd = ndr_unpack(security.descriptor,
- str(current[i]["nTSecurityDescriptor"]))
- sddl = cursd.as_sddl(names.domainsid)
- if sddl != hash[key]:
- txt = get_diff_sddls(hash[key], sddl, False)
- if txt != "":
- message(CHANGESD, "On object %s ACL is different"
- " \n%s" % (current[i]["dn"], txt))
-
-
-
-def fix_partition_sd(samdb, names):
- """This function fix the SD for partition containers (basedn, configdn, ...)
- This is needed because some provision use to have broken SD on containers
-
- :param samdb: An LDB object pointing to the sam of the current provision
- :param names: A list of key provision parameters
- """
- alwaysRecalculate = False
- if len(dnToRecalculate) == 0 and len(dnNotToRecalculate) == 0:
- alwaysRecalculate = True
-
-
- # NC's DN can't be both in dnToRecalculate and dnNotToRecalculate
- # First update the SD for the rootdn
- if alwaysRecalculate or str(names.rootdn) in dnToRecalculate:
- delta = Message()
- delta.dn = Dn(samdb, str(names.rootdn))
- descr = get_domain_descriptor(names.domainsid)
- delta["nTSecurityDescriptor"] = MessageElement(descr, FLAG_MOD_REPLACE,
- "nTSecurityDescriptor")
- samdb.modify(delta)
-
- # Then the config dn
- if alwaysRecalculate or str(names.configdn) in dnToRecalculate:
- delta = Message()
- delta.dn = Dn(samdb, str(names.configdn))
- descr = get_config_descriptor(names.domainsid)
- delta["nTSecurityDescriptor"] = MessageElement(descr, FLAG_MOD_REPLACE,
- "nTSecurityDescriptor" )
- samdb.modify(delta)
-
- # Then the schema dn
- if alwaysRecalculate or str(names.schemadn) in dnToRecalculate:
- delta = Message()
- delta.dn = Dn(samdb, str(names.schemadn))
- descr = get_schema_descriptor(names.domainsid)
- delta["nTSecurityDescriptor"] = MessageElement(descr, FLAG_MOD_REPLACE,
- "nTSecurityDescriptor" )
- samdb.modify(delta)
-
-def rebuild_sd(samdb, names):
- """Rebuild security descriptor of the current provision from scratch
-
- During the different pre release of samba4 security descriptors (SD)
- were notarly broken (up to alpha11 included)
- This function allow to get them back in order, this function make the
- assumption that nobody has modified manualy an SD
- and so SD can be safely recalculated from scratch to get them right.
-
- :param names: List of key provision parameters"""
-
- fix_partition_sd(samdb, names)
-
- # List of namming contexts
- listNC = [str(names.rootdn), str(names.configdn), str(names.schemadn)]
- hash = {}
- if len(dnToRecalculate) == 0:
- res = samdb.search(expression="objectClass=*", base=str(names.rootdn),
- scope=SCOPE_SUBTREE, attrs=["dn", "whenCreated"],
- controls=["search_options:1:2"])
- for obj in res:
- hash[str(obj["dn"])] = obj["whenCreated"]
- else:
- for dn in dnToRecalculate:
- if hash.has_key(dn):
- continue
- # fetch each dn to recalculate and their child within the same partition
- res = samdb.search(expression="objectClass=*", base=dn,
- scope=SCOPE_SUBTREE, attrs=["dn", "whenCreated"])
- for obj in res:
- hash[str(obj["dn"])] = obj["whenCreated"]
-
- listKeys = list(set(hash.keys()))
- listKeys.sort(dn_sort)
-
- if len(dnToRecalculate) != 0:
- message(CHANGESD, "%d DNs have been marked as needed to be recalculated"\
- ", recalculating %d due to inheritance"
- % (len(dnToRecalculate), len(listKeys)))
-
- for key in listKeys:
- if (key in listNC or
- key in dnNotToRecalculate):
- continue
- delta = Message()
- delta.dn = Dn(samdb, key)
- try:
- delta["whenCreated"] = MessageElement(hash[key], FLAG_MOD_REPLACE,
- "whenCreated" )
- samdb.modify(delta, ["recalculate_sd:0","relax:0"])
- except LdbError, e:
- samdb.transaction_cancel()
- res = samdb.search(expression="objectClass=*", base=str(names.rootdn),
- scope=SCOPE_SUBTREE,
- attrs=["dn", "nTSecurityDescriptor"],
- controls=["search_options:1:2"])
- badsd = ndr_unpack(security.descriptor,
- str(res[0]["nTSecurityDescriptor"]))
- message(ERROR, "On %s bad stuff %s" % (str(delta.dn),badsd.as_sddl(names.domainsid)))
- return
-
-def hasATProvision(samdb):
- entry = samdb.search(expression="(distinguishedName=@PROVISION)", base = "",
- scope=SCOPE_BASE,
- attrs=["dn"])
-
- if entry != None and len(entry) == 1:
- return True
- else:
- return False
-
-def removeProvisionUSN(samdb):
- attrs = [samba.provision.LAST_PROVISION_USN_ATTRIBUTE, "dn"]
- entry = samdb.search(expression="(distinguishedName=@PROVISION)", base = "",
- scope=SCOPE_BASE,
- attrs=attrs)
- empty = Message()
- empty.dn = entry[0].dn
- delta = samdb.msg_diff(entry[0], empty)
- delta.remove("dn")
- delta.dn = entry[0].dn
- samdb.modify(delta)
-
-def remove_stored_generated_attrs(paths, creds, session, lp):
- """Remove previously stored constructed attributes
-
- :param paths: List of paths for different provision objects
- from the upgraded provision
- :param creds: A credential object
- :param session: A session object
- :param lp: A line parser object
- :return: An associative array whose key are the different constructed
- attributes and the value the dn where this attributes were found.
- """
-
-
-def simple_update_basesamdb(newpaths, paths, names):
- """Update the provision container db: sam.ldb
- This function is aimed at very old provision (before alpha9)
-
- :param newpaths: List of paths for different provision objects
- from the reference provision
- :param paths: List of paths for different provision objects
- from the upgraded provision
- :param names: List of key provision parameters"""
-
- message(SIMPLE, "Copy samdb")
- shutil.copy(newpaths.samdb, paths.samdb)
-
- message(SIMPLE, "Update partitions filename if needed")
- schemaldb = os.path.join(paths.private_dir, "schema.ldb")
- configldb = os.path.join(paths.private_dir, "configuration.ldb")
- usersldb = os.path.join(paths.private_dir, "users.ldb")
- samldbdir = os.path.join(paths.private_dir, "sam.ldb.d")
-
- if not os.path.isdir(samldbdir):
- os.mkdir(samldbdir)
- os.chmod(samldbdir, 0700)
- if os.path.isfile(schemaldb):
- shutil.copy(schemaldb, os.path.join(samldbdir,
- "%s.ldb"%str(names.schemadn).upper()))
- os.remove(schemaldb)
- if os.path.isfile(usersldb):
- shutil.copy(usersldb, os.path.join(samldbdir,
- "%s.ldb"%str(names.rootdn).upper()))
- os.remove(usersldb)
- if os.path.isfile(configldb):
- shutil.copy(configldb, os.path.join(samldbdir,
- "%s.ldb"%str(names.configdn).upper()))
- os.remove(configldb)
-
-
-def update_privilege(ref_private_path, cur_private_path):
- """Update the privilege database
-
- :param ref_private_path: Path to the private directory of the reference
- provision.
- :param cur_private_path: Path to the private directory of the current
- (and to be updated) provision."""
- message(SIMPLE, "Copy privilege")
- shutil.copy(os.path.join(ref_private_path, "privilege.ldb"),
- os.path.join(cur_private_path, "privilege.ldb"))
-
-
-def update_samdb(ref_samdb, samdb, names, provisionUSNs, schema, prereloadfunc):
- """Upgrade the SAM DB contents for all the provision partitions
-
- :param ref_sambdb: An LDB object conntected to the sam.ldb of the reference
- provision
- :param samdb: An LDB object connected to the sam.ldb of the update
- provision
- :param names: List of key provision parameters
- :param provisionUSNs: A dictionnary with range of USN modified during provision
- or upgradeprovision. Ranges are grouped by invocationID.
- :param schema: A Schema object that represent the schema of the provision
- :param prereloadfunc: A function that must be executed just before the reload
- of the schema
- """
-
- message(SIMPLE, "Starting update of samdb")
- ret = update_partition(ref_samdb, samdb, str(names.rootdn), names,
- schema, provisionUSNs, prereloadfunc)
- if ret:
- message(SIMPLE, "Update of samdb finished")
- return 1
- else:
- message(SIMPLE, "Update failed")
- return 0
-
-
-def backup_provision(paths, dir, only_db):
- """This function backup the provision files so that a rollback
- is possible
-
- :param paths: Paths to different objects
- :param dir: Directory where to store the backup
- :param only_db: Skip sysvol for users with big sysvol
- """
- if paths.sysvol and not only_db:
- copytree_with_xattrs(paths.sysvol, os.path.join(dir, "sysvol"))
- shutil.copy2(paths.samdb, dir)
- shutil.copy2(paths.secrets, dir)
- shutil.copy2(paths.idmapdb, dir)
- shutil.copy2(paths.privilege, dir)
- if os.path.isfile(os.path.join(paths.private_dir,"eadb.tdb")):
- shutil.copy2(os.path.join(paths.private_dir,"eadb.tdb"), dir)
- shutil.copy2(paths.smbconf, dir)
- shutil.copy2(os.path.join(paths.private_dir,"secrets.keytab"), dir)
-
- samldbdir = os.path.join(paths.private_dir, "sam.ldb.d")
- if not os.path.isdir(samldbdir):
- samldbdir = paths.private_dir
- schemaldb = os.path.join(paths.private_dir, "schema.ldb")
- configldb = os.path.join(paths.private_dir, "configuration.ldb")
- usersldb = os.path.join(paths.private_dir, "users.ldb")
- shutil.copy2(schemaldb, dir)
- shutil.copy2(usersldb, dir)
- shutil.copy2(configldb, dir)
- else:
- shutil.copytree(samldbdir, os.path.join(dir, "sam.ldb.d"))
-
-
-def sync_calculated_attributes(samdb, names):
- """Synchronize attributes used for constructed ones, with the
- old constructed that were stored in the database.
-
- This apply for instance to msds-keyversionnumber that was
- stored and that is now constructed from replpropertymetadata.
-
- :param samdb: An LDB object attached to the currently upgraded samdb
- :param names: Various key parameter about current provision.
- """
- listAttrs = ["msDs-KeyVersionNumber"]
- hash = search_constructed_attrs_stored(samdb, names.rootdn, listAttrs)
- if hash.has_key("msDs-KeyVersionNumber"):
- increment_calculated_keyversion_number(samdb, names.rootdn,
- hash["msDs-KeyVersionNumber"])
-
-# Synopsis for updateprovision
-# 1) get path related to provision to be update (called current)
-# 2) open current provision ldbs
-# 3) fetch the key provision parameter (domain sid, domain guid, invocationid
-# of the DC ....)
-# 4) research of lastProvisionUSN in order to get ranges of USN modified
-# by either upgradeprovision or provision
-# 5) creation of a new provision the latest version of provision script
-# (called reference)
-# 6) get reference provision paths
-# 7) open reference provision ldbs
-# 8) setup helpers data that will help the update process
-# 9) update the privilege ldb by copying the one of referecence provision to
-# the current provision
-# 10)get the oemInfo field, this field contains information about the different
-# provision that have been done
-# 11)Depending on whether oemInfo has the string "alpha9" or alphaxx (x as an
-# integer) or none of this the following things are done
-# A) When alpha9 or alphaxx is present
-# The base sam.ldb file is updated by looking at the difference between
-# referrence one and the current one. Everything is copied with the
-# exception of lastProvisionUSN attributes.
-# B) Other case (it reflect that that provision was done before alpha9)
-# The base sam.ldb of the reference provision is copied over
-# the current one, if necessary ldb related to partitions are moved
-# and renamed
-# The highest used USN is fetched so that changed by upgradeprovision
-# usn can be tracked
-# 12)A Schema object is created, it will be used to provide a complete
-# schema to current provision during update (as the schema of the
-# current provision might not be complete and so won't allow some
-# object to be created)
-# 13)Proceed to full update of sam DB (see the separate paragraph about i)
-# 14)The secrets db is updated by pull all the difference from the reference
-# provision into the current provision
-# 15)As the previous step has most probably modified the password stored in
-# in secret for the current DC, a new password is generated,
-# the kvno is bumped and the entry in samdb is also updated
-# 16)For current provision older than alpha9, we must fix the SD a little bit
-# administrator to update them because SD used to be generated with the
-# system account before alpha9.
-# 17)The highest usn modified so far is searched in the database it will be
-# the upper limit for usn modified during provision.
-# This is done before potential SD recalculation because we do not want
-# SD modified during recalculation to be marked as modified during provision
-# (and so possibly remplaced at next upgradeprovision)
-# 18)Rebuilt SD if the flag indicate to do so
-# 19)Check difference between SD of reference provision and those of the
-# current provision. The check is done by getting the sddl representation
-# of the SD. Each sddl in chuncked into parts (user,group,dacl,sacl)
-# Each part is verified separetly, for dacl and sacl ACL is splited into
-# ACEs and each ACE is verified separately (so that a permutation in ACE
-# didn't raise as an error).
-# 20)The oemInfo field is updated to add information about the fact that the
-# provision has been updated by the upgradeprovision version xxx
-# (the version is the one obtained when starting samba with the --version
-# parameter)
-# 21)Check if the current provision has all the settings needed for dynamic
-# DNS update to work (that is to say the provision is newer than
-# january 2010). If not dns configuration file from reference provision
-# are copied in a sub folder and the administrator is invited to
-# do what is needed.
-# 22)If the lastProvisionUSN attribute was present it is updated to add
-# the range of usns modified by the current upgradeprovision
-
-
-# About updating the sam DB
-# The update takes place in update_partition function
-# This function read both current and reference provision and list all
-# the available DN of objects
-# If the string representation of a DN in reference provision is
-# equal to the string representation of a DN in current provision
-# (without taking care of case) then the object is flaged as being
-# present. If the object is not present in current provision the object
-# is being flaged as missing in current provision. Object present in current
-# provision but not in reference provision are ignored.
-# Once the list of objects present and missing is done, the deleted object
-# containers are created in the differents partitions (if missing)
-#
-# Then the function add_missing_entries is called
-# This function will go through the list of missing entries by calling
-# add_missing_object for the given object. If this function returns 0
-# it means that the object needs some other object in order to be created
-# The object is reappended at the end of the list to be created later
-# (and preferably after all the needed object have been created)
-# The function keeps on looping on the list of object to be created until
-# it's empty or that the number of defered creation is equal to the number
-# of object that still needs to be created.
-
-# The function add_missing_object will first check if the object can be created.
-# That is to say that it didn't depends other not yet created objects
-# If requisit can't be fullfilled it exists with 0
-# Then it will try to create the missing entry by creating doing
-# an ldb_message_diff between the object in the reference provision and
-# an empty object.
-# This resulting object is filtered to remove all the back link attribute
-# (ie. memberOf) as they will be created by the other linked object (ie.
-# the one with the member attribute)
-# All attributes specified in the attrNotCopied array are
-# also removed it's most of the time generated attributes
-
-# After missing entries have been added the update_partition function will
-# take care of object that exist but that need some update.
-# In order to do so the function update_present is called with the list
-# of object that are present in both provision and that might need an update.
-
-# This function handle first case mismatch so that the DN in the current
-# provision have the same case as in reference provision
-
-# It will then construct an associative array consiting of attributes as
-# key and invocationid as value( if the originating invocation id is
-# different from the invocation id of the current DC the value is -1 instead).
-
-# If the range of provision modified attributes is present, the function will
-# use the replMetadataProperty update method which is the following:
-# Removing attributes that should not be updated: rIDAvailablePool, objectSid,
-# creationTime, msDs-KeyVersionNumber, oEMInformation
-# Check for each attribute if its usn is within one of the modified by
-# provision range and if its originating id is the invocation id of the
-# current DC, then validate the update from reference to current.
-# If not or if there is no replMetatdataProperty for this attribute then we
-# do not update it.
-# Otherwise (case the range of provision modified attribute is not present) it
-# use the following process:
-# All attributes that need to be added are accepted at the exeption of those
-# listed in hashOverwrittenAtt, in this case the attribute needs to have the
-# correct flags specified.
-# For attributes that need to be modified or removed, a check is performed
-# in OverwrittenAtt, if the attribute is present and the modification flag
-# (remove, delete) is one of those listed for this attribute then modification
-# is accepted. For complicated handling of attribute update, the control is passed
-# to handle_special_case
-
-
-
-if __name__ == '__main__':
- global defSDmodified
- defSDmodified = False
-
- if opts.nontaclfix and opts.fixntacl:
- message(SIMPLE, "nontaclfix and fixntacl are mutally exclusive")
- # From here start the big steps of the program
- # 1) First get files paths
- paths = get_paths(param, smbconf=smbconf)
- # Get ldbs with the system session, it is needed for searching
- # provision parameters
- session = system_session()
-
- # This variable will hold the last provision USN once if it exists.
- minUSN = 0
- # 2)
- ldbs = get_ldbs(paths, creds, session, lp)
- backupdir = tempfile.mkdtemp(dir=paths.private_dir,
- prefix="backupprovision")
- backup_provision(paths, backupdir, opts.db_backup_only)
- try:
- ldbs.startTransactions()
-
- # 3) Guess all the needed names (variables in fact) from the current
- # provision.
- names = find_provision_key_parameters(ldbs.sam, ldbs.secrets, ldbs.idmap,
- paths, smbconf, lp)
- # 4)
- lastProvisionUSNs = get_last_provision_usn(ldbs.sam)
- if lastProvisionUSNs is not None:
- v = 0
- for k in lastProvisionUSNs.keys():
- for r in lastProvisionUSNs[k]:
- v = v + 1
-
- message(CHANGE,
- "Find last provision USN, %d invocation(s) for a total of %d ranges" % \
- (len(lastProvisionUSNs.keys()), v /2 ))
-
- if lastProvisionUSNs.get("default") != None:
- message(CHANGE, "Old style for usn ranges used")
- lastProvisionUSNs[str(names.invocation)] = lastProvisionUSNs["default"]
- del lastProvisionUSNs["default"]
- else:
- message(SIMPLE, "Your provision lacks provision range information")
- if confirm("Do you want to run findprovisionusnranges to try to find them ?", False):
- ldbs.groupedRollback()
- minobj = 5
- (hash_id, nb_obj) = findprovisionrange(ldbs.sam, ldb.Dn(ldbs.sam, str(names.rootdn)))
- message(SIMPLE, "Here is a list of changes that modified more than %d objects in 1 minute." % minobj)
- message(SIMPLE, "Usually changes made by provision and upgradeprovision are those who affect a couple"\
- " of hundred of objects or more")
- message(SIMPLE, "Total number of objects: %d" % nb_obj)
- message(SIMPLE, "")
-
- print_provision_ranges(hash_id, minobj, None, str(paths.samdb), str(names.invocation))
-
- message(SIMPLE, "Once you applied/adapted the change(s) please restart the upgradeprovision script")
- sys.exit(0)
-
- # Objects will be created with the admin session
- # (not anymore system session)
- adm_session = admin_session(lp, str(names.domainsid))
- # So we reget handle on objects
- # ldbs = get_ldbs(paths, creds, adm_session, lp)
- if not opts.fixntacl:
- if not sanitychecks(ldbs.sam, names):
- message(SIMPLE, "Sanity checks for the upgrade have failed. "
- "Check the messages and correct the errors "
- "before rerunning upgradeprovision")
- ldbs.groupedRollback()
- sys.exit(1)
-
- # Let's see provision parameters
- print_provision_key_parameters(names)
-
- # 5) With all this information let's create a fresh new provision used as
- # reference
- message(SIMPLE, "Creating a reference provision")
- provisiondir = tempfile.mkdtemp(dir=paths.private_dir,
- prefix="referenceprovision")
- result = newprovision(names, creds, session, smbconf, provisiondir,
- provision_logger)
- result.report_logger(provision_logger)
-
- # TODO
- # 6) and 7)
- # We need to get a list of object which SD is directly computed from
- # defaultSecurityDescriptor.
- # This will allow us to know which object we can rebuild the SD in case
- # of change of the parent's SD or of the defaultSD.
- # Get file paths of this new provision
- newpaths = get_paths(param, targetdir=provisiondir)
- new_ldbs = get_ldbs(newpaths, creds, session, lp)
- new_ldbs.startTransactions()
-
- populateNotReplicated(new_ldbs.sam, names.schemadn)
- # 8) Populate some associative array to ease the update process
- # List of attribute which are link and backlink
- populate_links(new_ldbs.sam, names.schemadn)
- # List of attribute with ASN DN synthax)
- populate_dnsyntax(new_ldbs.sam, names.schemadn)
- # 9)
- update_privilege(newpaths.private_dir, paths.private_dir)
- # 10)
- oem = getOEMInfo(ldbs.sam, str(names.rootdn))
- # Do some modification on sam.ldb
- ldbs.groupedCommit()
- new_ldbs.groupedCommit()
- deltaattr = None
- # 11)
- message(GUESS, oem)
- if oem is None or hasATProvision(ldbs.sam) or re.match(".*alpha((9)|(\d\d+)).*", str(oem)):
- # 11) A
- # Starting from alpha9 we can consider that the structure is quite ok
- # and that we should do only dela
- deltaattr = delta_update_basesamdb(newpaths.samdb,
- paths.samdb,
- creds,
- session,
- lp,
- message)
- else:
- # 11) B
- simple_update_basesamdb(newpaths, paths, names)
- ldbs = get_ldbs(paths, creds, session, lp)
- removeProvisionUSN(ldbs.sam)
-
- ldbs.startTransactions()
- minUSN = int(str(get_max_usn(ldbs.sam, str(names.rootdn)))) + 1
- new_ldbs.startTransactions()
-
- # 12)
- schema = Schema(names.domainsid, schemadn=str(names.schemadn))
- # We create a closure that will be invoked just before schema reload
- def schemareloadclosure():
- basesam = Ldb(paths.samdb, session_info=session, credentials=creds, lp=lp,
- options=["modules:"])
- doit = False
- if deltaattr is not None and len(deltaattr) > 1:
- doit = True
- if doit:
- deltaattr.remove("dn")
- for att in deltaattr:
- if att.lower() == "dn":
- continue
- if (deltaattr.get(att) is not None
- and deltaattr.get(att).flags() != FLAG_MOD_ADD):
- doit = False
- elif deltaattr.get(att) is None:
- doit = False
- if doit:
- message(CHANGE, "Applying delta to @ATTRIBUTES")
- deltaattr.dn = ldb.Dn(basesam, "@ATTRIBUTES")
- basesam.modify(deltaattr)
- else:
- message(CHANGE, "Not applying delta to @ATTRIBUTES because "
- "there is not only add")
- # 13)
- if opts.full:
- if not update_samdb(new_ldbs.sam, ldbs.sam, names, lastProvisionUSNs,
- schema, schemareloadclosure):
- message(SIMPLE, "Rolling back all changes. Check the cause"
- " of the problem")
- message(SIMPLE, "Your system is as it was before the upgrade")
- ldbs.groupedRollback()
- new_ldbs.groupedRollback()
- shutil.rmtree(provisiondir)
- sys.exit(1)
- else:
- # Try to reapply the change also when we do not change the sam
- # as the delta_upgrade
- schemareloadclosure()
- sync_calculated_attributes(ldbs.sam, names)
- res = ldbs.sam.search(expression="(samaccountname=dns)",
- scope=SCOPE_SUBTREE, attrs=["dn"],
- controls=["search_options:1:2"])
- if len(res) > 0:
- message(SIMPLE, "You still have the old DNS object for managing "
- "dynamic DNS, but you didn't supply --full so "
- "a correct update can't be done")
- ldbs.groupedRollback()
- new_ldbs.groupedRollback()
- shutil.rmtree(provisiondir)
- sys.exit(1)
- # 14)
- update_secrets(new_ldbs.secrets, ldbs.secrets, message)
- # 14bis)
- res = ldbs.sam.search(expression="(samaccountname=dns)",
- scope=SCOPE_SUBTREE, attrs=["dn"],
- controls=["search_options:1:2"])
-
- if (len(res) == 1):
- ldbs.sam.delete(res[0]["dn"])
- res2 = ldbs.secrets.search(expression="(samaccountname=dns)",
- scope=SCOPE_SUBTREE, attrs=["dn"])
- update_dns_account_password(ldbs.sam, ldbs.secrets, names)
- message(SIMPLE, "IMPORTANT!!! "
- "If you were using Dynamic DNS before you need "
- "to update your configuration, so that the "
- "tkey-gssapi-credential has the following value: "
- "DNS/%s.%s" % (names.netbiosname.lower(),
- names.realm.lower()))
- # 15)
- message(SIMPLE, "Update machine account")
- update_machine_account_password(ldbs.sam, ldbs.secrets, names)
-
- dnToRecalculate.sort(dn_sort)
- # 16) SD should be created with admin but as some previous acl were so wrong
- # that admin can't modify them we have first to recreate them with the good
- # form but with system account and then give the ownership to admin ...
- if str(oem) != "" and not re.match(r'.*alpha(9|\d\d+)', str(oem)):
- message(SIMPLE, "Fixing very old provision SD")
- rebuild_sd(ldbs.sam, names)
-
- # We calculate the max USN before recalculating the SD because we might
- # touch object that have been modified after a provision and we do not
- # want that the next upgradeprovision thinks that it has a green light
- # to modify them
-
- # 17)
- maxUSN = get_max_usn(ldbs.sam, str(names.rootdn))
-
- # 18) We rebuild SD if a we have a list of DN to recalculate or if the
- # defSDmodified is set.
- if defSDmodified or len(dnToRecalculate) >0:
- message(SIMPLE, "Some (default) security descriptors (SDs) have "
- "changed, recalculating them")
- ldbs.sam.set_session_info(adm_session)
- rebuild_sd(ldbs.sam, names)
-
- # 19)
- # Now we are quite confident in the recalculate process of the SD, we make
- # it optional. And we don't do it if there is DN that we must touch
- # as we are assured that on this DNs we will have differences !
- # Also the check must be done in a clever way as for the moment we just
- # compare SDDL
- if len(dnNotToRecalculate) == 0 and (opts.debugchangesd or opts.debugall):
- message(CHANGESD, "Checking recalculated SDs")
- check_updated_sd(new_ldbs.sam, ldbs.sam, names)
-
- # 20)
- updateOEMInfo(ldbs.sam, str(names.rootdn))
- # 21)
- check_for_DNS(newpaths.private_dir, paths.private_dir)
- # 22)
- if lastProvisionUSNs is not None:
- update_provision_usn(ldbs.sam, minUSN, maxUSN, names.invocation)
- if opts.full and (names.policyid is None or names.policyid_dc is None):
- update_policyids(names, ldbs.sam)
- if opts.nontaclfix:
- if opts.full or opts.resetfileacl or opts.fixntacl:
- 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")
- except IOError, e:
- message(ERROR, "Setting ACL not supported on your filesystem")
- else:
- 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")
- if not opts.fixntacl:
- ldbs.groupedCommit()
- new_ldbs.groupedCommit()
- message(SIMPLE, "Upgrade finished!")
- # remove reference provision now that everything is done !
- # So we have reindexed first if need when the merged schema was reloaded
- # (as new attributes could have quick in)
- # But the second part of the update (when we update existing objects
- # can also have an influence on indexing as some attribute might have their
- # searchflag modificated
- message(SIMPLE, "Reopening samdb to trigger reindexing if needed "
- "after modification")
- samdb = Ldb(paths.samdb, session_info=session, credentials=creds, lp=lp)
- message(SIMPLE, "Reindexing finished")
-
- shutil.rmtree(provisiondir)
- else:
- ldbs.groupedRollback()
- message(SIMPLE, "ACLs fixed !")
- except StandardError, err:
- message(ERROR, "A problem occurred while trying to upgrade your "
- "provision. A full backup is located at %s" % backupdir)
- if opts.debugall or opts.debugchange:
- (typ, val, tb) = sys.exc_info()
- traceback.print_exception(typ, val, tb)
- sys.exit(1)