[SCM] Samba Shared Repository - branch master updated

Garming Sam garming at samba.org
Thu Dec 21 02:42:03 UTC 2017


The branch, master has been updated
       via  fafc6da ldapcmp: Improve the difference checker of ldapcmp for 2012 R2
       via  c4895cf upgradeprovision: Mark tests as passing again (using functional prep)
       via  aee8464 functionalprep.sh: Add a test to show that functional prep works on old databases
       via  87eeb89 functionalprep.sh: New test for ensuring that the prep works correctly
       via  03f1ca8 release-4-8-0-pre1: New database dump for checking that functional prep works
       via  c419ac4 domain.py: Command for prepping the domain for higher functional levels
       via  b2d831f domain.py: Force schema upgrade to be used only on the schema master
       via  6689570 forest_update: Allow the script to add the missing forest containers
       via  c426275 forest_update: Create a module to apply forest prep updates
       via  107fbaa domain_update: Add a new docstring for the main entry point
       via  b5f7677 domain_update: Add an additional error with revision
       via  60b70e9 domain_update: Allow the revision version to be set
       via  551ec22 domain_update: Respect the fix=False flag
       via  23dbcb4 domain_update: Create a module to apply domain prep updates
       via  8a4085f ms_forest_updates_markdown: Write a parser for the forest updates .md
       via  87cbd97 WindowsServerDocs: Update README for clarity
       via  7cc1dfe Forest-Wide-Updates.md: Include the description of forest wide updates
       via  b6c33c0 WindowsServerDocs: Update README to get rid of the references to ./gen/
       via  1bb0715 2008R2: Missing operation (77) for ActiveDirectoryUpdate version 5 (FL)
       via  3cddb6a 2008R2: Missing operation (75, 76) for ActiveDirectoryUpdate version 5 (FL)
       via  0efc061 ldapcmp: Add otherWellKnownObjects to ignore when using --two
       via  83c4c3b sambadns: Allow functional level 2016 (when added)
       via  1f63ffc wscript: Install missing .ldf files
      from  576fb4f g_lock: fix cleanup of stale entries in g_lock_trylock()

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit fafc6da6ab6c30a5976163957836e42bdffad268
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Mon Dec 18 12:45:02 2017 +1300

    ldapcmp: Improve the difference checker of ldapcmp for 2012 R2
    
    There are a number of new attributes which may be considered DNs.
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    
    Autobuild-User(master): Garming Sam <garming at samba.org>
    Autobuild-Date(master): Thu Dec 21 03:41:19 CET 2017 on sn-devel-144

commit c4895cfd9ae77b980ed47d0e08d9b19d850a9e65
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Mon Dec 18 12:30:44 2017 +1300

    upgradeprovision: Mark tests as passing again (using functional prep)
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit aee8464aaa01a1740eeab6e47d76621d8e7c740c
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Mon Dec 18 12:30:15 2017 +1300

    functionalprep.sh: Add a test to show that functional prep works on old databases
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 87eeb897e4f9fae635c55940cedbc1501e529cd1
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Fri Dec 15 15:43:32 2017 +1300

    functionalprep.sh: New test for ensuring that the prep works correctly
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 03f1ca863a8e10cb261105f5cc40f7c25ea09c02
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Fri Dec 15 14:33:45 2017 +1300

    release-4-8-0-pre1: New database dump for checking that functional prep works
    
    Next will be a test which compares the current run of the script against
    this reference provision.
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit c419ac4a2e915b999064c1dc0ee5ff34d3803580
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Wed Dec 6 14:12:30 2017 +1300

    domain.py: Command for prepping the domain for higher functional levels
    
    Currently we support the 2012 and 2012 R2 prep levels.
    
    Forest prep requires use of the schema master role.
    Domain prep requires use of the infrastructure master role.
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit b2d831f23d5a5513b4d4c767dbfe5de555afae30
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Wed Dec 13 15:27:20 2017 +1300

    domain.py: Force schema upgrade to be used only on the schema master
    
    While this may be enforced at lower levels, it would be better to warn
    earlier rather than later.
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 66895701c9ed14fa17682d280e7008e417afafa0
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Wed Dec 13 12:09:02 2017 +1300

    forest_update: Allow the script to add the missing forest containers
    
    Before we set the prep level higher in default provisions, we should add
    these objects to the initial ldif (so that our initial ldif represents a
    full 2008R2 domain which we build consistently on).
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit c4262753ae6ab1427ce0019b9004addcf20bd2e4
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Wed Dec 6 14:23:04 2017 +1300

    forest_update: Create a module to apply forest prep updates
    
    This module uses information sourced from the Forest-Wide-Updates.md
    file from one of Microsoft's Github repos to generate the operation
    information.
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 107fbaa8f1d95d6c7c0af2a3a9196fa950756c7e
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Wed Dec 13 13:37:08 2017 +1300

    domain_update: Add a new docstring for the main entry point
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit b5f7677af97065c9a95f7295003e9ed9d833628b
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Wed Dec 13 13:35:14 2017 +1300

    domain_update: Add an additional error with revision
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 60b70e9540847b780329c19fb6e9cc77a415f903
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Wed Dec 13 13:17:32 2017 +1300

    domain_update: Allow the revision version to be set
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 551ec22da88d9e0eade43b1eb8c011ad3fdcdb2a
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Wed Dec 13 13:12:01 2017 +1300

    domain_update: Respect the fix=False flag
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 23dbcb403a1b6208c9ac7ef4868313d83d354d45
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Tue Dec 12 15:53:09 2017 +1300

    domain_update: Create a module to apply domain prep updates
    
    These updates are referenced in documentation much like our
    Forest-Wide-Updates.md file under the same MIT and CC attribution
    licenses.
    
    https://github.com/MicrosoftDocs/windowsserverdocs/blob/master/WindowsServerDocs/identity/ad-ds/deploy/Domain-Wide-Updates.md
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 8a4085fc2bad5764a4ae1b99c504750c7205e9bc
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Fri Nov 24 16:26:52 2017 +1300

    ms_forest_updates_markdown: Write a parser for the forest updates .md
    
    Unlike the schema markdown which appears generally as ldif, these
    descriptions are textual.
    
    We are only handling the add cases, with the rest being manually encoded.
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 87cbd97ef41fbb1bb559eb27eb26ea11df2a8181
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Fri Dec 15 11:30:27 2017 +1300

    WindowsServerDocs: Update README for clarity
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 7cc1dfec8c777da8b362e057d1b76df936e9ca3e
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Fri Nov 24 16:26:52 2017 +1300

    Forest-Wide-Updates.md: Include the description of forest wide updates
    
    This is sourced from the WindowsServerDocs repository on Github under an
    MIT/CC 4.0 attribution license. A huge thanks is required for these
    being provided and the work done in the process, as they mean a lot less
    work for us to repeat.
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit b6c33c0ca996939e4ccc542a085499d20fd784d5
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Thu Dec 14 16:43:04 2017 +1300

    WindowsServerDocs: Update README to get rid of the references to ./gen/
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 1bb0715c93ef2fb0e3c175368882bd7a27d54004
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Thu Aug 24 14:10:04 2017 +1200

    2008R2: Missing operation (77) for ActiveDirectoryUpdate version 5 (FL)
    
    Operation 77: {82112ba0-7e4c-4a44-89d9-d46c9612bf91}
    
     - Create the CN=PSPs,CN=System object
    
    Referenced in the page 'Windows Server 2008R2: Domain-Wide Updates':
    https://technet.microsoft.com/en-us/library/dd378973(v=ws.10).aspx
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 3cddb6ad07e44a404480fece8973b702618c1c33
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Thu Aug 24 13:59:22 2017 +1200

    2008R2: Missing operation (75, 76) for ActiveDirectoryUpdate version 5 (FL)
    
    Operation 75 {5e1574f6-55df-493e-a6-71-aa-ef-fc-a6-a1-00}
    
     - Create the CN=Managed Service Accounts object
    
    Operation 76 {d262aae8-41f7-48ed-9f-35-56-bb-b6-77-57-3d}
    
     - Add otherWellKnownObject link for CN=Managed Service Accounts
    
    Referenced in the page 'Windows Server 2008R2: Domain-Wide Updates':
    https://technet.microsoft.com/en-us/library/dd378973(v=ws.10).aspx
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 0efc061a62af0a315982ce21cab2f2fd32f43d1d
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Mon Dec 18 12:39:52 2017 +1300

    ldapcmp: Add otherWellKnownObjects to ignore when using --two
    
    wellKnownObjects already exists in this list.
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 83c4c3b3979b057d96e7bfaeb41f095d7cf4f6a9
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Tue Nov 14 14:20:28 2017 +1300

    sambadns: Allow functional level 2016 (when added)
    
    This is currently just a harmless check anyways.
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 1f63ffc9653fd6217d14368943f9a74ca751c321
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Tue Dec 19 09:55:09 2017 +1300

    wscript: Install missing .ldf files
    
    With the update to the newer version of the 2008 R2 schemas, the files
    were not available on install.
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 python/samba/descriptor.py                         |    11 +
 python/samba/domain_update.py                      |   439 +
 python/samba/forest_update.py                      |   545 +
 python/samba/ms_forest_updates_markdown.py         |   274 +
 python/samba/netcmd/domain.py                      |   120 +
 python/samba/netcmd/ldapcmp.py                     |    26 +-
 python/samba/provision/__init__.py                 |     8 +-
 python/samba/provision/sambadns.py                 |     5 +-
 selftest/tests.py                                  |     5 +
 .../names.tdb.dump                                 |     0
 .../release-4-8-0-pre1/private/eadb.tdb.dump       |    96 +
 .../release-4-8-0-pre1/private/hklm.ldb.dump       |    80 +
 .../release-4-8-0-pre1/private/idmap.ldb.dump      |    48 +
 .../release-4-8-0-pre1/private/privilege.ldb.dump  |   156 +
 .../CN=CONFIGURATION,DC=REALM,DC=COM.ldb.dump      | 31916 ++++++++++++
 ...CHEMA,CN=CONFIGURATION,DC=REALM,DC=COM.ldb.dump | 48760 +++++++++++++++++++
 .../DC=DOMAINDNSZONES,DC=REALM,DC=COM.ldb.dump     |   928 +
 .../DC=FORESTDNSZONES,DC=REALM,DC=COM.ldb.dump     |   488 +
 .../private/sam.ldb.d/DC=REALM,DC=COM.ldb.dump     |  5992 +++
 .../private/sam.ldb.d/metadata.tdb.dump            |     8 +
 .../release-4-8-0-pre1/private/sam.ldb.dump        |    40 +
 .../release-4-8-0-pre1/private/secrets.ldb.dump    |    44 +
 .../release-4-8-0-pre1/private/secrets.tdb.dump    |    24 +
 .../release-4-8-0-pre1/private/share.ldb.dump      |    32 +
 .../release-4-8-0-pre1/steps-to-reproduce.txt      |    13 +
 source4/setup/adprep/README.txt                    |    42 +-
 .../WindowsServerDocs/Forest-Wide-Updates.md       |   101 +
 source4/setup/provision.ldif                       |    17 +
 source4/setup/provision_basedn_references.ldif     |     8 +
 source4/setup/wscript_build                        |     2 +
 testprogs/blackbox/functionalprep.sh               |   115 +
 testprogs/blackbox/upgradeprovision-oldrelease.sh  |     6 +
 32 files changed, 90327 insertions(+), 22 deletions(-)
 create mode 100644 python/samba/domain_update.py
 create mode 100644 python/samba/forest_update.py
 create mode 100644 python/samba/ms_forest_updates_markdown.py
 copy source4/selftest/provisions/{release-4-5-0-pre1 => release-4-8-0-pre1}/names.tdb.dump (100%)
 create mode 100644 source4/selftest/provisions/release-4-8-0-pre1/private/eadb.tdb.dump
 create mode 100644 source4/selftest/provisions/release-4-8-0-pre1/private/hklm.ldb.dump
 create mode 100644 source4/selftest/provisions/release-4-8-0-pre1/private/idmap.ldb.dump
 create mode 100644 source4/selftest/provisions/release-4-8-0-pre1/private/privilege.ldb.dump
 create mode 100644 source4/selftest/provisions/release-4-8-0-pre1/private/sam.ldb.d/CN=CONFIGURATION,DC=REALM,DC=COM.ldb.dump
 create mode 100644 source4/selftest/provisions/release-4-8-0-pre1/private/sam.ldb.d/CN=SCHEMA,CN=CONFIGURATION,DC=REALM,DC=COM.ldb.dump
 create mode 100644 source4/selftest/provisions/release-4-8-0-pre1/private/sam.ldb.d/DC=DOMAINDNSZONES,DC=REALM,DC=COM.ldb.dump
 create mode 100644 source4/selftest/provisions/release-4-8-0-pre1/private/sam.ldb.d/DC=FORESTDNSZONES,DC=REALM,DC=COM.ldb.dump
 create mode 100644 source4/selftest/provisions/release-4-8-0-pre1/private/sam.ldb.d/DC=REALM,DC=COM.ldb.dump
 create mode 100644 source4/selftest/provisions/release-4-8-0-pre1/private/sam.ldb.d/metadata.tdb.dump
 create mode 100644 source4/selftest/provisions/release-4-8-0-pre1/private/sam.ldb.dump
 create mode 100644 source4/selftest/provisions/release-4-8-0-pre1/private/secrets.ldb.dump
 create mode 100644 source4/selftest/provisions/release-4-8-0-pre1/private/secrets.tdb.dump
 create mode 100644 source4/selftest/provisions/release-4-8-0-pre1/private/share.ldb.dump
 create mode 100644 source4/selftest/provisions/release-4-8-0-pre1/steps-to-reproduce.txt
 create mode 100644 source4/setup/adprep/WindowsServerDocs/Forest-Wide-Updates.md
 create mode 100755 testprogs/blackbox/functionalprep.sh


Changeset truncated at 500 lines:

diff --git a/python/samba/descriptor.py b/python/samba/descriptor.py
index 86ea869..cf797cc 100644
--- a/python/samba/descriptor.py
+++ b/python/samba/descriptor.py
@@ -268,6 +268,17 @@ def get_domain_users_descriptor(domain_sid, name_map={}):
     "S:"
     return sddl2binary(sddl, domain_sid, name_map)
 
+def get_managed_service_accounts_descriptor(domain_sid, name_map={}):
+    sddl = "D:" \
+    "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
+    "(A;;RPWPCRCCDCLCLORCWOWDSW;;;DA)" \
+    "(OA;;CCDC;ce206244-5827-4a86-ba1c-1c0c386c1b64;;AO)" \
+    "(OA;;CCDC;bf967aba-0de6-11d0-a285-00aa003049e2;;AO)" \
+    "(OA;;CCDC;bf967a9c-0de6-11d0-a285-00aa003049e2;;AO)" \
+    "(A;;RPLCLORC;;;AU)" \
+    "S:"
+    return sddl2binary(sddl, domain_sid, name_map)
+
 def get_domain_controllers_descriptor(domain_sid, name_map={}):
     sddl = "D:" \
     "(A;;RPLCLORC;;;AU)" \
diff --git a/python/samba/domain_update.py b/python/samba/domain_update.py
new file mode 100644
index 0000000..11a0a73
--- /dev/null
+++ b/python/samba/domain_update.py
@@ -0,0 +1,439 @@
+# Samba4 Domain update checker
+#
+# Copyright (C) Andrew Bartlett <abartlet at samba.org> 2017
+#
+# 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 re
+import ldb
+import samba
+import time
+from base64 import b64encode
+from samba import dsdb
+from samba import common
+from samba import sd_utils
+from samba.dcerpc import misc
+from samba.dcerpc import drsuapi
+from samba.ndr import ndr_unpack, ndr_pack
+from samba.dcerpc import drsblobs
+from samba.common import dsdb_Dn
+from samba.dcerpc import security
+from samba.dcerpc.security import SECINFO_DACL
+from samba.descriptor import (
+    get_wellknown_sds,
+    get_diff_sds,
+    get_managed_service_accounts_descriptor,
+)
+from samba.auth import system_session, admin_session
+from samba.netcmd import CommandError
+from samba.netcmd.fsmo import get_fsmo_roleowner
+from samba.dsdb import (
+    DS_DOMAIN_FUNCTION_2008,
+    DS_DOMAIN_FUNCTION_2008_R2,
+    DS_DOMAIN_FUNCTION_2012,
+    DS_DOMAIN_FUNCTION_2012_R2,
+    DS_DOMAIN_FUNCTION_2016,
+)
+
+MIN_UPDATE = 75
+MAX_UPDATE = 81
+
+update_map = {
+    # Missing updates from 2008 R2 - version 5
+    75: "5e1574f6-55df-493e-a671-aaeffca6a100",
+    76: "d262aae8-41f7-48ed-9f35-56bbb677573d",
+    77: "82112ba0-7e4c-4a44-89d9-d46c9612bf91",
+    # Windows Server 2012 - version 9
+    78: "c3c927a6-cc1d-47c0-966b-be8f9b63d991",
+    79: "54afcfb9-637a-4251-9f47-4d50e7021211",
+    80: "f4728883-84dd-483c-9897-274f2ebcf11e",
+    81: "ff4f9d27-7157-4cb0-80a9-5d6f2b14c8ff",
+    # Windows Server 2012 R2 - version 10
+    # No updates
+}
+
+functional_level_to_max_update = {
+    DS_DOMAIN_FUNCTION_2008: 74,
+    DS_DOMAIN_FUNCTION_2008_R2: 77,
+    DS_DOMAIN_FUNCTION_2012: 81,
+    DS_DOMAIN_FUNCTION_2012_R2: 81,
+    DS_DOMAIN_FUNCTION_2016: 88,
+}
+
+functional_level_to_version = {
+    DS_DOMAIN_FUNCTION_2008: 3,
+    DS_DOMAIN_FUNCTION_2008_R2: 5,
+    DS_DOMAIN_FUNCTION_2012: 9,
+    DS_DOMAIN_FUNCTION_2012_R2: 10,
+    DS_DOMAIN_FUNCTION_2016: 15,
+}
+
+# No update numbers have been skipped over
+missing_updates = []
+
+
+class DomainUpdateException(Exception):
+    pass
+
+
+class DomainUpdate(object):
+    """Check and update a SAM database for domain updates"""
+
+    def __init__(self, samdb, fix=False,
+                 add_update_container=True):
+        """
+        :param samdb: LDB database
+        :param fix: Apply the update if the container is missing
+        :param add_update_container: Add the container at the end of the change
+        :raise DomainUpdateException:
+        """
+        self.samdb = samdb
+        self.fix = fix
+        self.add_update_container = add_update_container
+        # TODO: In future we should check for inconsistencies when it claims it has been done
+        self.check_update_applied = False
+
+        self.config_dn = self.samdb.get_config_basedn()
+        self.domain_dn = self.samdb.domain_dn()
+        self.schema_dn = self.samdb.get_schema_basedn()
+
+        self.sd_utils = sd_utils.SDUtils(samdb)
+        self.domain_sid = security.dom_sid(samdb.get_domain_sid())
+
+        self.domainupdate_container = self.samdb.get_root_basedn()
+        if not self.domainupdate_container.add_child("CN=Operations,CN=DomainUpdates,CN=System"):
+            raise DomainUpdateException("Failed to add domain update container child")
+
+        self.revision_object = self.samdb.get_root_basedn()
+        if not self.revision_object.add_child("CN=ActiveDirectoryUpdate,CN=DomainUpdates,CN=System"):
+            raise DomainUpdateException("Failed to add revision object child")
+
+    def check_updates_functional_level(self, functional_level,
+                                       old_functional_level=None,
+                                       update_revision=False):
+        """
+        Apply all updates for a given old and new functional level
+        :param functional_level: constant
+        :param old_functional_level: constant
+        :param update_revision: modify the stored version
+        :raise DomainUpdateException:
+        """
+        res = self.samdb.search(base=self.revision_object,
+                                attrs=["revision"], scope=ldb.SCOPE_BASE)
+
+        expected_update = functional_level_to_max_update[functional_level]
+
+        if old_functional_level:
+            min_update = functional_level_to_max_update[old_functional_level]
+            min_update += 1
+        else:
+            min_update = MIN_UPDATE
+
+        self.check_updates_range(min_update, expected_update)
+
+        expected_version = functional_level_to_version[functional_level]
+        found_version = int(res[0]['revision'][0])
+        if update_revision and found_version < expected_version:
+            if not self.fix:
+                raise DomainUpdateException("Revision is not high enough. Fix is set to False."
+                                            "\nExpected: %dGot: %d" % (expected_version,
+                                                                       found_version))
+            self.samdb.modify_ldif("""dn: %s
+changetype: modify
+replace: revision
+revision: %d
+""" % (str(self.revision_object), expected_version))
+
+    def check_updates_iterator(self, iterator):
+        """
+        Apply a list of updates which must be within the valid range of updates
+        :param iterator: Iterable specifying integer update numbers to apply
+        :raise DomainUpdateException:
+        """
+        for op in iterator:
+            if op < MIN_UPDATE or op > MAX_UPDATE:
+                raise DomainUpdateException("Update number invalid.")
+
+            # No LDIF file exists for the change
+            getattr(self, "operation_%d" % op)(op)
+
+    def check_updates_range(self, start=0, end=0):
+        """
+        Apply a range of updates which must be within the valid range of updates
+        :param start: integer update to begin
+        :param end: integer update to end (inclusive)
+        :raise DomainUpdateException:
+        """
+        op = start
+        if start < MIN_UPDATE or start > end or end > MAX_UPDATE:
+            raise DomainUpdateException("Update number invalid.")
+        while op <= end:
+            if op not in missing_updates:
+                # No LDIF file exists for the change
+                getattr(self, "operation_%d" % op)(op)
+
+            op += 1
+
+    def update_exists(self, op):
+        """
+        :param op: Integer update number
+        :return: True if update exists else False
+        """
+        try:
+            res = self.samdb.search(base=self.domainupdate_container,
+                                    expression="(CN=%s)" % update_map[op])
+        except ldb.LdbError:
+            return False
+
+        return len(res) == 1
+
+    def update_add(self, op):
+        """
+        Add the corresponding container object for the given update
+        :param op: Integer update
+        """
+        self.samdb.add_ldif("""dn: CN=%s,%s
+objectClass: container
+""" % (update_map[op], str(self.domainupdate_container)))
+
+    def insert_ace_into_dacl(self, dn, existing_sddl, ace):
+        """
+        Add an ACE to a DACL, checking if it already exists with a simple string search.
+
+        :param dn: DN to modify
+        :param existing_sddl: existing sddl as string
+        :param ace: string ace to insert
+        :return: True if modified else False
+        """
+        index = existing_sddl.rfind("S:")
+        if index != -1:
+            new_sddl = existing_sddl[:index] + ace + existing_sddl[index:]
+        else:
+            # Insert it at the end if no S: section
+            new_sddl = existing_sddl + ace
+
+        if ace in existing_sddl:
+            return False
+
+        self.sd_utils.modify_sd_on_dn(dn, new_sddl,
+                                      controls=["sd_flags:1:%d" % SECINFO_DACL])
+
+        return True
+
+    def insert_ace_into_string(self, dn, ace, attr):
+        """
+        Insert an ACE into a string attribute like defaultSecurityDescriptor.
+        This also checks if it already exists using a simple string search.
+
+        :param dn: DN to modify
+        :param ace: string ace to insert
+        :param attr: attribute to modify
+        :return: True if modified else False
+        """
+        msg = self.samdb.search(base=dn,
+                                attrs=[attr],
+                                controls=["search_options:1:2"])
+
+        assert len(msg) == 1
+        existing_sddl = msg[0][attr][0]
+        index = existing_sddl.rfind("S:")
+        if index != -1:
+            new_sddl = existing_sddl[:index] + ace + existing_sddl[index:]
+        else:
+            # Insert it at the end if no S: section
+            new_sddl = existing_sddl + ace
+
+        if ace in existing_sddl:
+            return False
+
+        m = ldb.Message()
+        m.dn = dn
+        m[attr] = ldb.MessageElement(new_sddl, ldb.FLAG_MOD_REPLACE,
+                                     attr)
+
+        self.samdb.modify(m, controls=["relax:0"])
+
+        return True
+
+    def raise_if_not_fix(self, op):
+        """
+        Raises an exception if not set to fix.
+        :param op: Integer operation
+        :raise DomainUpdateException:
+        """
+        if not self.fix:
+            raise DomainUpdateException("Missing operation %d. Fix is currently set to False" % op)
+
+    # Create a new object CN=TPM Devices in the Domain partition.
+    def operation_78(self, op):
+        if self.update_exists(op):
+            return
+        self.raise_if_not_fix(op)
+
+        self.samdb.add_ldif("""dn: CN=TPM Devices,%s
+objectClass: top
+objectClass: msTPM-InformationObjectsContainer
+""" % self.domain_dn,
+                            controls=["relax:0", "provision:0"])
+
+        if self.add_update_container:
+            self.update_add(op)
+
+    # Created an access control entry for the TPM service.
+    def operation_79(self, op):
+        if self.update_exists(op):
+            return
+        self.raise_if_not_fix(op)
+
+        ace = "(OA;CIIO;WP;ea1b7b93-5e48-46d5-bc6c-4df4fda78a35;bf967a86-0de6-11d0-a285-00aa003049e2;PS)"
+
+        res = self.samdb.search(expression="(objectClass=samDomain)",
+                                attrs=["nTSecurityDescriptor"],
+                                controls=["search_options:1:2"])
+        for msg in res:
+            existing_sd = ndr_unpack(security.descriptor,
+                                     msg["nTSecurityDescriptor"][0])
+            existing_sddl = existing_sd.as_sddl(self.domain_sid)
+
+            self.insert_ace_into_dacl(msg.dn, existing_sddl, ace)
+
+        res = self.samdb.search(expression="(objectClass=domainDNS)",
+                                attrs=["nTSecurityDescriptor"],
+                                controls=["search_options:1:2"])
+        for msg in res:
+            existing_sd = ndr_unpack(security.descriptor,
+                                     msg["nTSecurityDescriptor"][0])
+            existing_sddl = existing_sd.as_sddl(self.domain_sid)
+
+            self.insert_ace_into_dacl(msg.dn, existing_sddl, ace)
+
+        if self.add_update_container:
+            self.update_add(op)
+
+    # Grant "Clone DC" extended right to Cloneable Domain Controllers group
+    def operation_80(self, op):
+        if self.update_exists(op):
+            return
+        self.raise_if_not_fix(op)
+
+        ace = "(OA;;CR;3e0f7e18-2c7a-4c10-ba82-4d926db99a3e;;%s-522)" % str(self.domain_sid)
+
+        res = self.samdb.search(base=self.domain_dn,
+                                scope=ldb.SCOPE_BASE,
+                                attrs=["nTSecurityDescriptor"],
+                                controls=["search_options:1:2",
+                                          "sd_flags:1:%d" % SECINFO_DACL])
+        msg = res[0]
+
+        existing_sd = ndr_unpack(security.descriptor,
+                                 msg["nTSecurityDescriptor"][0])
+        existing_sddl = existing_sd.as_sddl(self.domain_sid)
+
+        self.insert_ace_into_dacl(msg.dn, existing_sddl, ace)
+
+        if self.add_update_container:
+            self.update_add(op)
+
+    # Grant ms-DS-Allowed-To-Act-On-Behalf-Of-Other-Identity to Principal Self
+    # on all objects
+    def operation_81(self, op):
+        if self.update_exists(op):
+            return
+        self.raise_if_not_fix(op)
+
+        ace = "(OA;CIOI;RPWP;3f78c3e5-f79a-46bd-a0b8-9d18116ddc79;;PS)"
+
+        res = self.samdb.search(expression="(objectClass=samDomain)",
+                                attrs=["nTSecurityDescriptor"],
+                                controls=["search_options:1:2"])
+        for msg in res:
+            existing_sd = ndr_unpack(security.descriptor,
+                                     msg["nTSecurityDescriptor"][0])
+            existing_sddl = existing_sd.as_sddl(self.domain_sid)
+
+            self.insert_ace_into_dacl(msg.dn, existing_sddl, ace)
+
+        res = self.samdb.search(expression="(objectClass=domainDNS)",
+                                attrs=["nTSecurityDescriptor"],
+                                controls=["search_options:1:2"])
+
+        for msg in res:
+            existing_sd = ndr_unpack(security.descriptor,
+                                     msg["nTSecurityDescriptor"][0])
+            existing_sddl = existing_sd.as_sddl(self.domain_sid)
+
+            self.insert_ace_into_dacl(msg.dn, existing_sddl, ace)
+
+        if self.add_update_container:
+            self.update_add(op)
+
+    #
+    # THE FOLLOWING ARE MISSING UPDATES FROM 2008 R2
+    #
+
+    # Add Managed Service Accounts container
+    def operation_75(self, op):
+        if self.update_exists(op):
+            return
+        self.raise_if_not_fix(op)
+
+        descriptor = get_managed_service_accounts_descriptor(self.domain_sid)
+        managedservice_descr = b64encode(descriptor)
+        managed_service_dn = "CN=Managed Service Accounts,%s" % \
+            str(self.domain_dn)
+
+        self.samdb.modify_ldif("""dn: %s
+changetype: add
+objectClass: container
+description: Default container for managed service accounts
+showInAdvancedViewOnly: FALSE
+nTSecurityDescriptor:: %s""" % (managed_service_dn, managedservice_descr),
+                               controls=["relax:0", "provision:0"])
+
+        if self.add_update_container:
+            self.update_add(op)
+
+    # Add the otherWellKnownObjects reference to MSA
+    def operation_76(self, op):
+        if self.update_exists(op):
+            return
+        self.raise_if_not_fix(op)
+
+        managed_service_dn = "CN=Managed Service Accounts,%s" % \
+            str(self.domain_dn)
+
+        self.samdb.modify_ldif("""dn: %s
+changetype: modify
+add: otherWellKnownObjects
+otherWellKnownObjects: B:32:1EB93889E40C45DF9F0C64D23BBB6237:%s
+""" % (str(self.domain_dn), managed_service_dn), controls=["relax:0",
+                                                           "provision:0"])
+
+        if self.add_update_container:
+            self.update_add(op)
+
+    # Add the PSPs object in the System container
+    def operation_77(self, op):
+        if self.update_exists(op):
+            return
+        self.raise_if_not_fix(op)
+
+        self.samdb.add_ldif("""dn: CN=PSPs,CN=System,%s
+objectClass: top
+objectClass: msImaging-PSPs
+""" % str(self.domain_dn), controls=["relax:0", "provision:0"])
+
+        if self.add_update_container:
+            self.update_add(op)
diff --git a/python/samba/forest_update.py b/python/samba/forest_update.py
new file mode 100644
index 0000000..9f6ddf6
--- /dev/null
+++ b/python/samba/forest_update.py
@@ -0,0 +1,545 @@
+# Samba4 Forest update checker
+#
+# Copyright (C) Andrew Bartlett <abarlet at samba.org> 2017
+#
+# 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 re
+import ldb
+import samba
+import time
+from base64 import b64decode
+from samba import dsdb
+from samba import common
+from samba import sd_utils
+from samba.dcerpc import misc


-- 
Samba Shared Repository



More information about the samba-cvs mailing list